예제 #1
0
        /// <summary>
        /// Reads a SEAnim from a stream
        /// </summary>
        /// <param name="Stream">The stream to read from</param>
        /// <returns>A SEAnim if successful, otherwise throws an error and returns null</returns>
        public static SEModel Read(Stream Stream)
        {
            // Create a new model
            var model = new SEModel();

            // Setup a new reader
            using (ExtendedBinaryReader readFile = new ExtendedBinaryReader(Stream))
            {
                // Magic
                var Magic = readFile.ReadChars(7);
                // Version
                var Version = readFile.ReadInt16();
                // Header size
                var HeaderSize = readFile.ReadInt16();
                // Check magic
                if (!Magic.SequenceEqual(new char[] { 'S', 'E', 'M', 'o', 'd', 'e', 'l' }))
                {
                    // Bad file
                    throw new Exception("Bad SEModel file, magic was invalid");
                }
                // Data present flags
                var DataPresentFlags = readFile.ReadByte();
                // Bone data present flags
                var BoneDataPresentFlags = readFile.ReadByte();
                // Mesh data present flags
                var MeshDataPresentFlags = readFile.ReadByte();

                // Read counts
                var BoneCount = readFile.ReadInt32();
                var MeshCount = readFile.ReadInt32();
                var MatCount  = readFile.ReadInt32();

                // Skip 3 reserved bytes
                readFile.BaseStream.Position += 3;

                // Read bone tag names
                List <string> BoneNames = new List <string>();
                // Loop
                for (int i = 0; i < BoneCount; i++)
                {
                    BoneNames.Add(readFile.ReadNullTermString());
                }

                // Loop and read bones
                for (int i = 0; i < BoneCount; i++)
                {
                    // Read bone flags (unused)
                    var BoneFlags = readFile.ReadByte();

                    // Read bone index
                    var ParentIndex = readFile.ReadInt32();

                    // Check for global matricies
                    Vector3    GlobalPosition = Vector3.Zero;
                    Quaternion GlobalRotation = Quaternion.Identity;
                    // Check
                    if (Convert.ToBoolean(BoneDataPresentFlags & (byte)SEModel_BoneDataPresenceFlags.SEMODEL_PRESENCE_GLOBAL_MATRIX))
                    {
                        GlobalPosition = new Vector3(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle());
                        GlobalRotation = new Quaternion(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle());
                    }

                    // Check for local matricies
                    Vector3    LocalPosition = Vector3.Zero;
                    Quaternion LocalRotation = Quaternion.Identity;
                    // Check
                    if (Convert.ToBoolean(BoneDataPresentFlags & (byte)SEModel_BoneDataPresenceFlags.SEMODEL_PRESENCE_LOCAL_MATRIX))
                    {
                        LocalPosition = new Vector3(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle());
                        LocalRotation = new Quaternion(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle());
                    }

                    // Check for scales
                    Vector3 Scale = Vector3.One;
                    // Check
                    if (Convert.ToBoolean(BoneDataPresentFlags & (byte)SEModel_BoneDataPresenceFlags.SEMODEL_PRESENCE_SCALES))
                    {
                        Scale = new Vector3(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle());
                    }

                    // Add the bone
                    model.AddBone(BoneNames[i], ParentIndex, GlobalPosition, GlobalRotation, LocalPosition, LocalRotation, Scale);
                }

                // Loop and read meshes
                for (int i = 0; i < MeshCount; i++)
                {
                    // Make a new submesh
                    var mesh = new SEModelMesh();

                    // Read mesh flags (unused)
                    var MeshFlags = readFile.ReadByte();

                    // Read counts
                    var MatIndiciesCount      = readFile.ReadByte();
                    var MaxSkinInfluenceCount = readFile.ReadByte();
                    var VertexCount           = readFile.ReadInt32();
                    var FaceCount             = readFile.ReadInt32();

                    // Loop and read positions
                    for (int v = 0; v < VertexCount; v++)
                    {
                        mesh.AddVertex(new SEModelVertex()
                        {
                            Position = new Vector3(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle())
                        });
                    }

                    // Read uvlayers
                    if (Convert.ToBoolean(MeshDataPresentFlags & (byte)SEModel_MeshDataPresenceFlags.SEMODEL_PRESENCE_UVSET))
                    {
                        for (int v = 0; v < VertexCount; v++)
                        {
                            for (int l = 0; l < MatIndiciesCount; l++)
                            {
                                mesh.Verticies[v].UVSets.Add(new Vector2(readFile.ReadSingle(), readFile.ReadSingle()));
                            }
                        }
                    }

                    // Read normals
                    if (Convert.ToBoolean(MeshDataPresentFlags & (byte)SEModel_MeshDataPresenceFlags.SEMODEL_PRESENCE_NORMALS))
                    {
                        // Loop and read vertex normals
                        for (int v = 0; v < VertexCount; v++)
                        {
                            mesh.Verticies[v].VertexNormal = new Vector3(readFile.ReadSingle(), readFile.ReadSingle(), readFile.ReadSingle());
                        }
                    }

                    // Read colors
                    if (Convert.ToBoolean(MeshDataPresentFlags & (byte)SEModel_MeshDataPresenceFlags.SEMODEL_PRESENCE_COLOR))
                    {
                        // Loop and read colors
                        for (int v = 0; v < VertexCount; v++)
                        {
                            mesh.Verticies[v].VertexColor = new Color(readFile.ReadByte(), readFile.ReadByte(), readFile.ReadByte(), readFile.ReadByte());
                        }
                    }

                    // Read weights
                    if (Convert.ToBoolean(MeshDataPresentFlags & (byte)SEModel_MeshDataPresenceFlags.SEMODEL_PRESENCE_WEIGHTS))
                    {
                        for (int v = 0; v < VertexCount; v++)
                        {
                            // Read IDs and Values
                            for (int l = 0; l < MaxSkinInfluenceCount; l++)
                            {
                                if (BoneCount <= 0xFF)
                                {
                                    mesh.Verticies[v].Weights.Add(new SEModelWeight()
                                    {
                                        BoneIndex = readFile.ReadByte(), BoneWeight = readFile.ReadSingle()
                                    });
                                }
                                else if (BoneCount <= 0xFFFF)
                                {
                                    mesh.Verticies[v].Weights.Add(new SEModelWeight()
                                    {
                                        BoneIndex = readFile.ReadUInt16(), BoneWeight = readFile.ReadSingle()
                                    });
                                }
                                else
                                {
                                    mesh.Verticies[v].Weights.Add(new SEModelWeight()
                                    {
                                        BoneIndex = readFile.ReadUInt32(), BoneWeight = readFile.ReadSingle()
                                    });
                                }
                            }
                        }
                    }

                    // Loop and read faces
                    for (int f = 0; f < FaceCount; f++)
                    {
                        if (VertexCount <= 0xFF)
                        {
                            mesh.AddFace(readFile.ReadByte(), readFile.ReadByte(), readFile.ReadByte());
                        }
                        else if (VertexCount <= 0xFFFF)
                        {
                            mesh.AddFace(readFile.ReadUInt16(), readFile.ReadUInt16(), readFile.ReadUInt16());
                        }
                        else
                        {
                            mesh.AddFace(readFile.ReadUInt32(), readFile.ReadUInt32(), readFile.ReadUInt32());
                        }
                    }

                    // Read material reference indicies
                    for (int f = 0; f < MatIndiciesCount; f++)
                    {
                        mesh.AddMaterialIndex(readFile.ReadInt32());
                    }

                    // Add the mesh
                    model.AddMesh(mesh);
                }

                // Loop and read materials
                for (int m = 0; m < MatCount; m++)
                {
                    var mat = new SEModelMaterial();

                    // Read the name
                    mat.Name = readFile.ReadNullTermString();
                    // Read IsSimpleMaterial
                    var IsSimpleMaterial = readFile.ReadBoolean();

                    // Read the material
                    if (IsSimpleMaterial)
                    {
                        mat.MaterialData = new SEModelSimpleMaterial()
                        {
                            DiffuseMap  = readFile.ReadNullTermString(),
                            NormalMap   = readFile.ReadNullTermString(),
                            SpecularMap = readFile.ReadNullTermString()
                        };
                    }

                    // Add the material
                    model.AddMaterial(mat);
                }
            }
            // Return result
            return(model);
        }