/// <summary> /// Turns the GLB data contained in a stream into a GLBObject. Will copy to the outStream if specified /// </summary> /// <param name="root">The glTF root to turn into a GLBObject</param> /// <param name="inputGLBStream">The stream the glb came in</param> /// <param name="outStream">If outstream is specified, the glb gets copied to it</param> /// <param name="inputGLBStreamStartPosition">Offset into the buffer that the GLB starts</param> /// <returns>A constructed GLBObject</returns> public static GLBObject ConstructFromGLB(GLTFRoot root, Stream inputGLBStream, Stream outStream = null, long inputGLBStreamStartPosition = 0) { if (outStream != null) { inputGLBStream.Position = inputGLBStreamStartPosition; inputGLBStream.CopyTo(outStream); } else { outStream = inputGLBStream; } // header information is 4 bytes in, past the magic number inputGLBStream.Position = 4 + inputGLBStreamStartPosition; GLBHeader header = GLTFParser.ParseGLBHeader(inputGLBStream); inputGLBStream.Position = GLTFParser.HEADER_SIZE + inputGLBStreamStartPosition; List <ChunkInfo> allChunks = GLTFParser.FindChunks(inputGLBStream); ChunkInfo jsonChunkInfo = new ChunkInfo { Type = ChunkFormat.JSON }; ChunkInfo binaryChunkInfo = new ChunkInfo { Type = ChunkFormat.BIN }; foreach (ChunkInfo chunkInfo in allChunks) { switch (chunkInfo.Type) { case ChunkFormat.JSON: jsonChunkInfo = chunkInfo; break; case ChunkFormat.BIN: binaryChunkInfo = chunkInfo; break; } } if (jsonChunkInfo.Length == 0) { throw new ArgumentException("JSON chunk must exists for valid GLB", nameof(inputGLBStream)); } // todo: compute the initial bufferview list return(new GLBObject { Root = root, Stream = outStream, StreamStartPosition = inputGLBStreamStartPosition, Header = header, JsonChunkInfo = jsonChunkInfo, BinaryChunkInfo = binaryChunkInfo }); }
private static void WriteChunkHeader(Stream stream, ChunkInfo chunkInfo) { stream.Position = chunkInfo.StartPosition; byte[] lengthBytes = BitConverter.GetBytes(chunkInfo.Length); byte[] typeBytes = BitConverter.GetBytes((uint)chunkInfo.Type); stream.Write(lengthBytes, 0, lengthBytes.Length); stream.Write(typeBytes, 0, lengthBytes.Length); }
public static ChunkInfo ParseChunkInfo(Stream stream) { ChunkInfo chunkInfo = new ChunkInfo { StartPosition = stream.Position }; chunkInfo.Length = GetUInt32(stream); // 12 chunkInfo.Type = (ChunkFormat)GetUInt32(stream); // 16 return(chunkInfo); }
private static void ParseJsonChunk(Stream stream, long startPosition) { GLBHeader header = ParseGLBHeader(stream); // 4, 8 if (header.Version != 2) { throw new GLTFHeaderInvalidException("Unsupported glTF version"); } ; if (header.FileLength != (stream.Length - startPosition)) { throw new GLTFHeaderInvalidException("File length does not match header."); } ChunkInfo chunkInfo = ParseChunkInfo(stream); if (chunkInfo.Type != ChunkFormat.JSON) { throw new GLTFHeaderInvalidException("First chunk must be of type JSON"); } }
public static List <ChunkInfo> FindChunks(Stream stream, long startPosition = 0) { stream.Position = startPosition + 4; // start after magic number bytes (4 bytes past) ParseGLBHeader(stream); List <ChunkInfo> allChunks = new List <ChunkInfo>(); // we only need to search for top two chunks (the JSON and binary chunks are guarenteed to be the top two chunks) // other chunks can be in the file but we do not care about them for (int i = 0; i < 2; ++i) { if (stream.Position == stream.Length) { break; } ChunkInfo chunkInfo = ParseChunkInfo(stream); allChunks.Add(chunkInfo); stream.Position += chunkInfo.Length; } return(allChunks); }