Exemple #1
0
        /// <summary>
        /// Removes a blob from the GLB at the given BufferView
        /// Updates accessors and images to have correct new bufferview index
        /// This function can invalidate BufferViewId's returned by previous function
        /// </summary>
        /// <param name="glb">The glb to remove from</param>
        /// <param name="bufferViewId">The buffer to remove</param>
        public static void RemoveBinaryData(GLBObject glb, BufferViewId bufferViewId)
        {
            if (glb == null)
            {
                throw new ArgumentNullException(nameof(glb));
            }
            if (bufferViewId == null)
            {
                throw new ArgumentNullException(nameof(bufferViewId));
            }

            BufferView bufferViewToRemove = bufferViewId.Value;
            int        id = bufferViewId.Id;

            if (bufferViewToRemove.ByteOffset + bufferViewToRemove.ByteLength == glb.BinaryChunkInfo.Length)
            {
                uint bufferViewLengthAsUint = bufferViewToRemove.ByteLength;
                glb.SetFileLength(glb.Header.FileLength - bufferViewLengthAsUint);
                glb.SetBinaryChunkLength(glb.BinaryChunkInfo.Length - bufferViewLengthAsUint);
                if (glb.BinaryChunkInfo.Length == 0)
                {
                    glb.Root.Buffers.RemoveAt(0);
                    foreach (BufferView bufferView in glb.Root.BufferViews)                     // other buffers may still exist, and their index has now changed
                    {
                        --bufferView.Buffer.Id;
                    }

                    glb.SetFileLength(glb.Header.FileLength - GLTFParser.CHUNK_HEADER_SIZE);
                }
                else
                {
                    glb.Root.Buffers[0].ByteLength = glb.BinaryChunkInfo.Length;

                    // write binary chunk header
                    WriteChunkHeader(glb.Stream, glb.BinaryChunkInfo);
                }

                // trim the end
                glb.Stream.SetLength(glb.Header.FileLength);

                // write glb header
                WriteHeader(glb.Stream, glb.Header, glb.StreamStartPosition);
            }

            glb.Root.BufferViews.RemoveAt(id);
            if (glb.Root.Accessors != null)
            {
                foreach (Accessor accessor in glb.Root.Accessors)                 // shift over all accessors
                {
                    if (accessor.BufferView != null && accessor.BufferView.Id >= id)
                    {
                        --accessor.BufferView.Id;
                    }

                    if (accessor.Sparse != null)
                    {
                        if (accessor.Sparse.Indices?.BufferView.Id >= id)
                        {
                            --accessor.Sparse.Indices.BufferView.Id;
                        }

                        if (accessor.Sparse.Values?.BufferView.Id >= id)
                        {
                            --accessor.Sparse.Values.BufferView.Id;
                        }
                    }
                }
            }

            if (glb.Root.Images != null)
            {
                foreach (GLTFImage image in glb.Root.Images)
                {
                    if (image.BufferView != null && image.BufferView.Id >= id)
                    {
                        --image.BufferView.Id;
                    }
                }
            }
        }
Exemple #2
0
        private static BufferViewId _AddBinaryData(GLBObject glb, Stream binaryData, bool createBufferView, long streamStartPosition, string bufferViewName = null)
        {
            binaryData.Position = streamStartPosition;

            // Append new binary chunk to end
            uint blobLengthAsUInt    = CalculateAlignment((uint)(binaryData.Length - streamStartPosition), 4);
            uint newBinaryBufferSize = glb.BinaryChunkInfo.Length + blobLengthAsUInt;
            uint newGLBSize          = glb.Header.FileLength + blobLengthAsUInt;
            uint blobWritePosition   = glb.Header.FileLength;

            // there was an existing file that had no binary chunk info previously
            if (glb.BinaryChunkInfo.Length == 0)
            {
                newGLBSize        += GLTFParser.CHUNK_HEADER_SIZE;
                blobWritePosition += GLTFParser.CHUNK_HEADER_SIZE;
                glb.SetBinaryChunkStartPosition(glb.Header.FileLength);                  // if 0, then appends chunk info at the end
            }

            glb.Stream.SetLength(glb.Header.FileLength + blobLengthAsUInt);
            glb.Stream.Position = blobWritePosition;                // assuming the end of the file is the end of the binary chunk
            binaryData.CopyTo(glb.Stream);                          // make sure this doesn't supersize it

            glb.SetFileLength(newGLBSize);
            glb.SetBinaryChunkLength(newBinaryBufferSize);

            // write glb header past magic number
            WriteHeader(glb.Stream, glb.Header, glb.StreamStartPosition);

            WriteChunkHeader(glb.Stream, glb.BinaryChunkInfo);

            if (createBufferView)
            {
                // Add a new BufferView to the GLTFRoot
                BufferView bufferView = new BufferView
                {
                    Buffer = new BufferId
                    {
                        Id   = 0,
                        Root = glb.Root
                    },
                    ByteLength = blobLengthAsUInt,                     // figure out whether glb size is wrong or if documentation is unclear
                    ByteOffset = glb.BinaryChunkInfo.Length - blobLengthAsUInt,
                    Name       = bufferViewName
                };

                if (glb.Root.BufferViews == null)
                {
                    glb.Root.BufferViews = new List <BufferView>();
                }

                glb.Root.BufferViews.Add(bufferView);

                return(new BufferViewId
                {
                    Id = glb.Root.BufferViews.Count - 1,
                    Root = glb.Root
                });
            }

            return(null);
        }