Beispiel #1
0
        protected static T ParseChunk <T>(
            BinaryReader reader,
            uint chunkSize,
            Action <T, W3dChunkHeader> parseCallback)
            where T : W3dChunk, new()
        {
            var result = new T();

            uint loadedSize = 0;

            do
            {
                loadedSize += W3dChunkHeader.SizeInBytes;
                var currentChunk = W3dChunkHeader.Parse(reader);

                var startPosition = reader.BaseStream.Position;

                loadedSize += currentChunk.ChunkSize;

                parseCallback(result, currentChunk);

                var endPosition = startPosition + currentChunk.ChunkSize;
                if (reader.BaseStream.Position != endPosition)
                {
                    throw new InvalidDataException($"Error while parsing asset '{typeof(T).Name}'. Expected reader to be at position {endPosition}, but was at {reader.BaseStream.Position}.");
                }
            } while (loadedSize < chunkSize);

            return(result);
        }
Beispiel #2
0
        internal static T ParseChunk <T>(
            BinaryReader reader,
            W3dParseContext context,
            Func <W3dChunkHeader, T> parseCallback)
            where T : W3dChunk
        {
            var chunkHeader   = W3dChunkHeader.Parse(reader);
            var startPosition = reader.BaseStream.Position;
            var endPosition   = startPosition + chunkHeader.ChunkSize;

            context.PushChunk(typeof(T).Name, endPosition);

            var result = parseCallback(chunkHeader);

            result.StartPosition = startPosition;
            result.EndPosition   = endPosition;

            context.PopAsset();

            if (reader.BaseStream.Position != endPosition)
            {
                throw new InvalidDataException($"Error while parsing asset '{typeof(T).Name}'. Expected reader to be at position {endPosition}, but was at {reader.BaseStream.Position}.");
            }

            return(result);
        }
Beispiel #3
0
        internal static W3dChunkHeader Parse(BinaryReader reader)
        {
            var result = new W3dChunkHeader();

            var chunkSize = reader.ReadUInt32();

            result.ChunkSize    = chunkSize & 0x7FFFFFFF;
            result.HasSubChunks = (chunkSize >> 31) == 1;

            return(result);
        }
Beispiel #4
0
        public static W3dChunkHeader Parse(BinaryReader reader)
        {
            var result = new W3dChunkHeader
            {
                ChunkType = (W3dChunkType)reader.ReadUInt32(),
            };

            var chunkSize = reader.ReadUInt32();

            result.ChunkSize    = chunkSize & 0x7FFFFFFF;
            result.HasSubChunks = (chunkSize >> 31) == 1;

            return(result);
        }
Beispiel #5
0
        internal void WriteTo(BinaryWriter writer)
        {
            writer.Write((uint)ChunkType);

            var headerPosition = writer.BaseStream.Position;

            // We'll back up and overwrite this later.
            writer.Seek(W3dChunkHeader.SizeInBytes, SeekOrigin.Current);

            var startPosition = writer.BaseStream.Position;

            WriteToOverride(writer);

            var endPosition = writer.BaseStream.Position;

            var dataSize = endPosition - startPosition;

            // Back up and write header.
            var header = new W3dChunkHeader((uint)dataSize, HasSubChunks);

            writer.BaseStream.Position = headerPosition;
            header.WriteTo(writer);
            writer.BaseStream.Position = endPosition;
        }
Beispiel #6
0
        public static W3dMesh Parse(BinaryReader reader, uint chunkSize)
        {
            var currentMaterialPass = 0;

            var textures = new List <W3dTexture>();

            var finalResult = ParseChunk <W3dMesh>(reader, chunkSize, (result, header) =>
            {
                switch (header.ChunkType)
                {
                case W3dChunkType.W3D_CHUNK_MESH_HEADER3:
                    result.Header       = W3dMeshHeader3.Parse(reader);
                    result.Vertices     = new Vector3[result.Header.NumVertices];
                    result.Normals      = new Vector3[result.Header.NumVertices];
                    result.ShadeIndices = new uint[result.Header.NumVertices];
                    result.Influences   = new W3dVertexInfluence[result.Header.NumVertices];
                    result.Triangles    = new W3dTriangle[result.Header.NumTris];
                    break;

                case W3dChunkType.W3D_CHUNK_VERTICES:
                    for (var count = 0; count < result.Header.NumVertices; count++)
                    {
                        result.Vertices[count] = reader.ReadVector3();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_VERTEX_NORMALS:
                    for (var count = 0; count < result.Header.NumVertices; count++)
                    {
                        result.Normals[count] = reader.ReadVector3();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_VERTEX_INFLUENCES:
                    for (var count = 0; count < result.Header.NumVertices; count++)
                    {
                        result.Influences[count] = W3dVertexInfluence.Parse(reader);
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_TRIANGLES:
                    for (var count = 0; count < result.Header.NumTris; count++)
                    {
                        result.Triangles[count] = W3dTriangle.Parse(reader);
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_VERTEX_SHADE_INDICES:
                    for (var count = 0; count < result.Header.NumVertices; count++)
                    {
                        result.ShadeIndices[count] = reader.ReadUInt32();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_MATERIAL_INFO:
                    result.MaterialInfo   = W3dMaterialInfo.Parse(reader);
                    result.Materials      = new W3dMaterial[result.MaterialInfo.VertexMaterialCount];
                    result.Shaders        = new W3dShader[result.MaterialInfo.ShaderCount];
                    result.MaterialPasses = new W3dMaterialPass[result.MaterialInfo.PassCount];
                    break;

                case W3dChunkType.W3D_CHUNK_VERTEX_MATERIALS:
                    for (var count = 0; count < result.MaterialInfo.VertexMaterialCount; count++)
                    {
                        var innerChunk = W3dChunkHeader.Parse(reader);
                        if (innerChunk.ChunkType == W3dChunkType.W3D_CHUNK_VERTEX_MATERIAL)
                        {
                            result.Materials[count] = W3dMaterial.Parse(reader, innerChunk.ChunkSize);
                        }
                        else
                        {
                            throw CreateUnknownChunkException(innerChunk);
                        }
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_SHADERS:
                    for (var count = 0; count < result.MaterialInfo.ShaderCount; count++)
                    {
                        result.Shaders[count] = W3dShader.Parse(reader);
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_TEXTURES:
                    var startPosition = reader.BaseStream.Position;
                    while (reader.BaseStream.Position < startPosition + header.ChunkSize)
                    {
                        var innerChunk = W3dChunkHeader.Parse(reader);
                        if (innerChunk.ChunkType == W3dChunkType.W3D_CHUNK_TEXTURE)
                        {
                            textures.Add(W3dTexture.Parse(reader, innerChunk.ChunkSize));
                        }
                        else
                        {
                            throw CreateUnknownChunkException(innerChunk);
                        }
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_MATERIAL_PASS:
                    result.MaterialPasses[currentMaterialPass] = W3dMaterialPass.Parse(reader, header.ChunkSize);
                    currentMaterialPass++;
                    break;

                case W3dChunkType.W3D_CHUNK_AABTREE:
                    if (result.AabTree != null)
                    {
                        throw new InvalidDataException();
                    }
                    result.AabTree = W3dMeshAabTree.Parse(reader, header.ChunkSize);
                    break;

                case W3dChunkType.W3D_CHUNK_PS2_SHADERS:
                    // Don't need this.
                    reader.ReadBytes((int)header.ChunkSize);
                    break;

                case W3dChunkType.W3D_CHUNK_MESH_USER_TEXT:
                    // TODO: Do we need this? It has line-separated key/value pairs
                    // for things like mass, elasticity, friction, etc.
                    reader.ReadBytes((int)header.ChunkSize);
                    break;

                case W3dChunkType.W3D_CHUNK_VERTICES_2:
                    result.Vertices2 = new Vector3[result.Header.NumVertices];
                    for (var count = 0; count < result.Vertices2.Length; count++)
                    {
                        result.Vertices2[count] = reader.ReadVector3();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_NORMALS_2:
                    result.Normals2 = new Vector3[result.Header.NumVertices];
                    for (var count = 0; count < result.Normals2.Length; count++)
                    {
                        result.Normals2[count] = reader.ReadVector3();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_TANGENTS:
                    result.Tangents = new Vector3[result.Header.NumVertices];
                    for (var count = 0; count < result.Tangents.Length; count++)
                    {
                        result.Tangents[count] = reader.ReadVector3();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_BITANGENTS:
                    result.Bitangents = new Vector3[result.Header.NumVertices];
                    for (var count = 0; count < result.Bitangents.Length; count++)
                    {
                        result.Bitangents[count] = reader.ReadVector3();
                    }
                    break;

                case W3dChunkType.W3D_CHUNK_SHADER_MATERIALS:
                    result.ShaderMaterials = W3dShaderMaterials.Parse(reader, header.ChunkSize);
                    break;

                default:
                    throw CreateUnknownChunkException(header);
                }
            });

            finalResult.Textures = textures;

            return(finalResult);
        }
Beispiel #7
0
 protected static Exception CreateUnknownChunkException(W3dChunkHeader header)
 {
     return(new InvalidDataException($"Unrecognised chunk: {header.ChunkType}"));
 }