コード例 #1
0
        internal void CreateWalls(Mesh.Factory factory, BuildingPlan plan)
        {
            for (var i = 0; i < plan.Polygon.Corners.Length; i++)
            {
                var c0    = plan.Polygon.Corners[i];
                var c1    = plan.Polygon.Corners[(i + 1) % plan.Polygon.Corners.Length];
                var c0To1 = c1 - c0;

                var v0 = new Mesh.Vertex
                {
                    Pos       = new Vector3(c0.X, plan.LowGroundLevel, c0.Y),
                    TexCoords = new Vector2()
                };
                var v0To1 = new Mesh.Vertex
                {
                    Pos       = new Vector3(c0To1.X, 0, c0To1.Y),
                    TexCoords = new Vector2(c0To1.Length, 0)
                };
                var v0To2 = new Mesh.Vertex
                {
                    Pos       = new Vector3(0, plan.RoofLevel - plan.LowGroundLevel, 0),
                    TexCoords = new Vector2(0, plan.RoofLevel - plan.LowGroundLevel)
                };
                factory.AddSurface(v0, v0To1, v0To2);
            }
        }
コード例 #2
0
        public static string Export(Model model, NormalExportMode normalMode, bool exportingIndividually = false)
        {
            StringBuilder obj = new StringBuilder();

            for (int i = 0; i < model.Meshes.Count; i++)
            {
                for (int j = 0; j < model.Meshes[i].Vertices.Count; j++)
                {
                    Mesh.Vertex v = model.Meshes[i].Vertices[j];
                    obj.AppendLine($"v {v.Position.X} {v.Position.Y} {v.Position.Z}");
                }

                for (int j = 0; j < model.Meshes[i].Vertices.Count; j++)
                {
                    Mesh.Vertex v = model.Meshes[i].Vertices[j];
                    Vector3     n = v.Normal;

                    if (normalMode == NormalExportMode.CALCULATED)
                    {
                        n = model.Meshes[i].CalculatedNormals[j];
                    }

                    if (normalMode != NormalExportMode.NONE)
                    {
                        obj.AppendLine($"vn {n.X} {n.Y} {n.Z}");
                    }
                }

                for (int j = 0; j < model.Meshes[i].Vertices.Count; j++)
                {
                    Mesh.Vertex v = model.Meshes[i].Vertices[j];
                    v.TextureCoordinate = new Vector2(v.TextureCoordinate.X / 32768, v.TextureCoordinate.Y / -32768);
                    obj.AppendLine($"vt {v.TextureCoordinate.X.ToString("F4")} {v.TextureCoordinate.Y.ToString("F4")}");
                }

                obj.AppendLine($"g mesh{i}");
                for (int j = 0; j < model.Meshes[i].Faces.Count; j++)
                {
                    Mesh.Face f = model.Meshes[i].Faces[j];
                    if (exportingIndividually)
                    {
                        f.X -= model.Meshes[i].NumOfVerticesBeforeMe;
                        f.Y -= model.Meshes[i].NumOfVerticesBeforeMe;
                        f.Z -= model.Meshes[i].NumOfVerticesBeforeMe;
                    }

                    string x = $"{f.X + 1}/{f.X + 1}";
                    string y = $"{f.Y + 1}/{f.Y + 1}";
                    string z = $"{f.Z + 1}/{f.Z + 1}";
                    if (normalMode != NormalExportMode.NONE)
                    {
                        x += $"/{f.X + 1}";
                        y += $"/{f.Y + 1}";
                        z += $"/{f.Z + 1}";
                    }

                    obj.AppendLine($"f {y} {x} {z}");
                }
            }
            return(obj.ToString());
        }
コード例 #3
0
        /// <summary>
        /// Does not load correctly, yet
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Model LoadFromString(string obj)
        {
            List <string> lines = new List <string>(obj.Split('\n'));

            // Lists to hold model data
            List <Vector3> verts   = new List <Vector3>();
            List <Vector3> normals = new List <Vector3>();
            List <Vector2> texs    = new List <Vector2>();
            List <Tuple <TempVertex, TempVertex, TempVertex> > faces = new List <Tuple <TempVertex, TempVertex, TempVertex> >();
            List <Tuple <int, int, int> > faceIndices = new List <Tuple <int, int, int> >();

            // Base values
            verts.Add(new Vector3());
            texs.Add(new Vector2());
            normals.Add(new Vector3());

            // Read file line by line
            foreach (string line in lines)
            {
                if (line.StartsWith("v ")) // Vertex definition
                {
                    // Cut off beginning of line
                    string temp = line.Substring(2);

                    Vector3 vec = new Vector3();

                    if (temp.Trim().Count((char c) => c == ' ') == 2) // Check if there's enough elements for a vertex
                    {
                        string[] vertparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        // Attempt to parse each part of the vertice
                        bool success = float.TryParse(vertparts[0], out vec.X);
                        success |= float.TryParse(vertparts[1], out vec.Y);
                        success |= float.TryParse(vertparts[2], out vec.Z);

                        // If any of the parses failed, report the error
                        if (!success)
                        {
                            Console.WriteLine("Error parsing vertex: {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Error parsing vertex: {0}", line);
                    }

                    verts.Add(vec);
                }
                else if (line.StartsWith("vt ")) // Texture coordinate
                {
                    // Cut off beginning of line
                    string temp = line.Substring(2);

                    Vector2 vec = new Vector2();

                    if (temp.Trim().Count((char c) => c == ' ') > 0) // Check if there's enough elements for a vertex
                    {
                        string[] texcoordparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        // Attempt to parse each part of the vertice
                        bool success = float.TryParse(texcoordparts[0], out vec.X);
                        success |= float.TryParse(texcoordparts[1], out vec.Y);

                        // If any of the parses failed, report the error
                        if (!success)
                        {
                            Console.WriteLine("Error parsing texture coordinate: {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Error parsing texture coordinate: {0}", line);
                    }

                    texs.Add(vec);
                }
                else if (line.StartsWith("vn ")) // Normal vector
                {
                    // Cut off beginning of line
                    string temp = line.Substring(2);

                    Vector3 vec = new Vector3();

                    if (temp.Trim().Count((char c) => c == ' ') == 2) // Check if there's enough elements for a normal
                    {
                        string[] vertparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        // Attempt to parse each part of the vertice
                        bool success = float.TryParse(vertparts[0], out vec.X);
                        success |= float.TryParse(vertparts[1], out vec.Y);
                        success |= float.TryParse(vertparts[2], out vec.Z);

                        // If any of the parses failed, report the error
                        if (!success)
                        {
                            Console.WriteLine("Error parsing normal: {0}", line);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Error parsing normal: {0}", line);
                    }

                    normals.Add(vec);
                }
                else if (line.StartsWith("f ")) // Face definition
                {
                    // Cut off beginning of line
                    string temp = line.Substring(2);

                    Tuple <TempVertex, TempVertex, TempVertex> face = new Tuple <TempVertex, TempVertex, TempVertex>(new TempVertex(), new TempVertex(), new TempVertex());

                    if (temp.Trim().Count((char c) => c == ' ') == 2) // Check if there's enough elements for a face
                    {
                        string[] faceparts = temp.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                        int v1, v2, v3;
                        int t1, t2, t3;
                        int n1, n2, n3;

                        // Attempt to parse each part of the face
                        bool success = int.TryParse(faceparts[0].Split('/')[0], out v1);
                        success |= int.TryParse(faceparts[1].Split('/')[0], out v2);
                        success |= int.TryParse(faceparts[2].Split('/')[0], out v3);

                        if (faceparts[0].Count((char c) => c == '/') >= 2)
                        {
                            success |= int.TryParse(faceparts[0].Split('/')[1], out t1);
                            success |= int.TryParse(faceparts[1].Split('/')[1], out t2);
                            success |= int.TryParse(faceparts[2].Split('/')[1], out t3);
                            success |= int.TryParse(faceparts[0].Split('/')[2], out n1);
                            success |= int.TryParse(faceparts[1].Split('/')[2], out n2);
                            success |= int.TryParse(faceparts[2].Split('/')[2], out n3);
                        }
                        else
                        {
                            if (texs.Count > v1 && texs.Count > v2 && texs.Count > v3)
                            {
                                t1 = v1;
                                t2 = v2;
                                t3 = v3;
                            }
                            else
                            {
                                t1 = 0;
                                t2 = 0;
                                t3 = 0;
                            }

                            if (normals.Count > v1 && normals.Count > v2 && normals.Count > v3)
                            {
                                n1 = v1;
                                n2 = v2;
                                n3 = v3;
                            }
                            else
                            {
                                n1 = 0;
                                n2 = 0;
                                n3 = 0;
                            }
                        }

                        // If any of the parses failed, report the error
                        if (!success)
                        {
                            Console.WriteLine("Error parsing face: {0}", line);
                        }
                        else
                        {
                            faceIndices.Add(new Tuple <int, int, int>(v1, v2, v3));

                            TempVertex tv1 = new TempVertex(v1, n1, t1);
                            TempVertex tv2 = new TempVertex(v2, n2, t2);
                            TempVertex tv3 = new TempVertex(v3, n3, t3);
                            face = new Tuple <TempVertex, TempVertex, TempVertex>(tv1, tv2, tv3);
                            faces.Add(face);
                        }
                    }
                    else
                    {
                        Console.WriteLine("Error parsing face: {0}", line);
                    }
                }
            }

            Mesh mesh = new Mesh();

            for (int i = 0; i < faces.Count; i += 3)
            {
                var face = faces[i];

                Mesh.Vertex vert1 = new Mesh.Vertex
                {
                    Position          = verts[face.Item1.Vertex],
                    Normal            = normals[face.Item1.Normal],
                    TextureCoordinate = texs[face.Item1.Texcoord]
                };
                mesh.Vertices.Add(vert1);

                Mesh.Vertex vert2 = new Mesh.Vertex
                {
                    Position          = verts[face.Item2.Vertex],
                    Normal            = normals[face.Item2.Normal],
                    TextureCoordinate = texs[face.Item2.Texcoord]
                };
                mesh.Vertices.Add(vert2);

                Mesh.Vertex vert3 = new Mesh.Vertex
                {
                    Position          = verts[face.Item3.Vertex],
                    Normal            = normals[face.Item3.Normal],
                    TextureCoordinate = texs[face.Item3.Texcoord]
                };
                mesh.Vertices.Add(vert3);

                mesh.Faces.Add(new Mesh.Face
                {
                    X = faceIndices[i].Item1,
                    Y = faceIndices[i].Item2,
                    Z = faceIndices[i].Item3
                });
            }

            for (int i = 0; i < faces.Count; i++)
            {
                mesh.Indices.Add(faceIndices[i].Item1);
                mesh.Indices.Add(faceIndices[i].Item2);
                mesh.Indices.Add(faceIndices[i].Item3);
            }

            mesh.VertexCount = mesh.Vertices.Count;
            mesh.FaceCount   = mesh.Faces.Count;
            mesh.IndexCount  = mesh.Indices.Count;

            return(Model.CreateFromMesh(mesh));
        }
コード例 #4
0
 public VertexClass(Mesh.Vertex vertex)
 {
     this.vertex = vertex;
 }
コード例 #5
0
        public static Model ExtractModel(string fileName, Action <string> completionAction = null)
        {
            // ToDo: add skeleton/skeleton-related data support for Origins

            Model         model = new Model();
            StringBuilder str   = new StringBuilder(); // used to print information in the Text Viewer

            byte[] allData = File.ReadAllBytes(fileName);

            using (Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                if (stream.Length == 0)
                {
                    return(null);
                }

                using (BinaryReader reader = new BinaryReader(stream))
                {
                    // header
                    DatafileHeader header = new DatafileHeader
                    {
                        ResourceIdentifier = reader.ReadUInt32(),
                        FileSize           = reader.ReadInt32(),
                        FileNameSize       = reader.ReadInt32()
                    };
                    header.FileName = reader.ReadChars(header.FileNameSize);

                    if (header.ResourceIdentifier != (uint)ResourceIdentifier.MESH)
                    {
                        Message.Fail("This is not proper Mesh data.");
                        return(model);
                    }

                    // skip to the Mesh block, ignoring the Mesh block identifier
                    reader.BaseStream.Seek(10, SeekOrigin.Current);

                    try
                    {
                        // Mesh block
                        MeshBlock meshBlock = new MeshBlock();
                        reader.BaseStream.Seek(3, SeekOrigin.Current);
                        meshBlock.ModelType = reader.ReadInt32();
                        meshBlock.ACount    = reader.ReadInt32();
                        if (meshBlock.ACount > 0)
                        {
                            reader.BaseStream.Seek(4, SeekOrigin.Current);
                            meshBlock.BoneCount = reader.ReadInt32();
                        }

                        // Bones block
                        if (meshBlock.BoneCount > 0)
                        {
                            str.AppendLine($"Bone Count: {meshBlock.BoneCount}");

                            // Bones block continued
                            Mesh.Bone[] bones = new Mesh.Bone[meshBlock.BoneCount];
                            for (int i = 0; i < meshBlock.BoneCount; i++)
                            {
                                bones[i] = new Mesh.Bone
                                {
                                    ID              = reader.ReadInt64(),
                                    Type            = reader.ReadInt32(),
                                    Name            = reader.ReadInt32(),
                                    TransformMatrix = new System.Numerics.Matrix4x4
                                    {
                                        M11 = reader.ReadSingle(),
                                        M12 = reader.ReadSingle(),
                                        M13 = reader.ReadSingle(),
                                        M14 = reader.ReadSingle(),
                                        M21 = reader.ReadSingle(),
                                        M22 = reader.ReadSingle(),
                                        M23 = reader.ReadSingle(),
                                        M24 = reader.ReadSingle(),
                                        M31 = reader.ReadSingle(),
                                        M32 = reader.ReadSingle(),
                                        M33 = reader.ReadSingle(),
                                        M34 = reader.ReadSingle(),
                                        M41 = reader.ReadSingle(),
                                        M42 = reader.ReadSingle(),
                                        M43 = reader.ReadSingle(),
                                        M44 = reader.ReadSingle()
                                    }
                                };

                                // invert matrix
                                System.Numerics.Matrix4x4 matrix = System.Numerics.Matrix4x4.Identity;
                                if (System.Numerics.Matrix4x4.Invert(bones[i].TransformMatrix, out matrix))
                                {
                                    bones[i].TransformMatrix = matrix;
                                }

                                reader.BaseStream.Seek(1, SeekOrigin.Current);
                            }
                        }

                        // locate the Compiled Mesh
                        Tuple <int[], long> cmOffset = Helpers.LocateBytes(reader, BitConverter.GetBytes((uint)ResourceIdentifier.COMPILED_MESH));
                        reader.BaseStream.Seek(cmOffset.Item1[0], SeekOrigin.Begin);
                        //Console.WriteLine("Compiled Mesh OFFSET: " + cmOffset.Item1[0]);

                        // Compiled Mesh block
                        if (reader.ReadUInt32() != (uint)ResourceIdentifier.COMPILED_MESH)
                        {
                            Message.Fail("Failed to read model.");
                            return(new Model());
                        }
                        reader.BaseStream.Seek(22, SeekOrigin.Current);
                        CompiledMeshBlock compiledMesh = new CompiledMeshBlock
                        {
                            VertexTableSize = reader.ReadInt32(),
                            Unknown1        = reader.ReadInt32(),
                            Unknown2        = reader.ReadInt32()
                        };
                        reader.BaseStream.Seek(29, SeekOrigin.Current);

                        // Submesh block
                        //Console.WriteLine("Submesh OFFSET: " + reader.BaseStream.Position);
                        SubmeshBlock submeshBlock = new SubmeshBlock();
                        submeshBlock.MeshCount = reader.ReadInt32();
                        if (submeshBlock.MeshCount < 0)
                        {
                            Message.Fail("Failed to read the model.");
                            return(model);
                        }

                        submeshBlock.Entries = new SubmeshEntry[submeshBlock.MeshCount];
                        for (int i = 0; i < submeshBlock.MeshCount; i++)
                        {
                            reader.BaseStream.Seek(16, SeekOrigin.Current);
                            submeshBlock.Entries[i] = new SubmeshEntry()
                            {
                                FaceOffset   = reader.ReadInt32(),
                                VertexOffset = reader.ReadInt32()
                            };
                        }

                        // Unknown0 block - does not exist in every model
                        //Console.WriteLine("Unknown0 OFFSET: " + reader.BaseStream.Position);
                        if (compiledMesh.Unknown2 != 0)
                        {
                            int unknown0DataSize = reader.ReadInt32();
                            reader.BaseStream.Seek(unknown0DataSize, SeekOrigin.Current);
                        }
                        else
                        {
                            //reader.BaseStream.Seek(-8, SeekOrigin.Current);
                        }

                        // Vertex block
                        //Console.WriteLine("Vertex OFFSET: " + reader.BaseStream.Position);
                        int  vertexDataSize        = reader.ReadInt32();
                        int  actualVertexTableSize = compiledMesh.VertexTableSize != 8 && compiledMesh.VertexTableSize != 16 ? compiledMesh.VertexTableSize : compiledMesh.Unknown1; // this variable now holds the true vertex table size
                        long vertexOffset          = reader.BaseStream.Position;
                        reader.BaseStream.Seek(vertexDataSize, SeekOrigin.Current);

                        // Vertex Weight block - does not exist in every model
                        //Console.WriteLine("Vertex Weight OFFSET: " + reader.BaseStream.Position);
                        if (compiledMesh.Unknown2 == 0)
                        {
                            reader.BaseStream.Seek(8, SeekOrigin.Current);
                        }
                        else
                        {
                            int vertexWeightDataSize = reader.ReadInt32();
                            reader.BaseStream.Seek(vertexWeightDataSize, SeekOrigin.Current);
                        }

                        // Face block
                        //Console.WriteLine("Face OFFSET: " + reader.BaseStream.Position);
                        int  faceDataSize = reader.ReadInt32();
                        long faceOffset   = reader.BaseStream.Position;
                        reader.BaseStream.Seek(faceDataSize, SeekOrigin.Current);

                        // Unknown1 block
                        int unknown1DataSize = reader.ReadInt32();
                        reader.BaseStream.Seek(unknown1DataSize, SeekOrigin.Current);

                        // Unknown2 block
                        int unknown2DataSize = reader.ReadInt32();
                        reader.BaseStream.Seek(unknown2DataSize, SeekOrigin.Current);

                        // Unknown3 block
                        int unknown3DataSize = reader.ReadInt32();
                        reader.BaseStream.Seek(unknown3DataSize, SeekOrigin.Current);

                        // go to the Mesh Data
                        reader.BaseStream.Seek(18, SeekOrigin.Current);
                        //Tuple<int[], long> mdOffset = Helpers.LocateBytes(reader, BitConverter.GetBytes((uint)ResourceIdentifier.MESH_DATA));
                        //reader.BaseStream.Position = mdOffset.Item2;
                        //reader.BaseStream.Seek(mdOffset.Item1[0] + 10, SeekOrigin.Begin); // skip the identifier and 6 bytes
                        //Console.WriteLine("Mesh Data OFFSET: " + (reader.BaseStream.Position));

                        // Mesh Data block
                        uint meshCount     = reader.ReadUInt32();
                        int  totalVertices = 0;
                        for (int i = 0; i < meshCount; i++)
                        {
                            Mesh mesh = new Mesh();
                            mesh.ID = reader.ReadInt16();
                            reader.BaseStream.Seek(18, SeekOrigin.Current);

                            mesh.VertexCount = reader.ReadInt32();
                            reader.BaseStream.Seek(4, SeekOrigin.Current);

                            mesh.FaceCount    = reader.ReadInt32();
                            mesh.IndexCount   = mesh.FaceCount * 3;
                            mesh.MinFaceIndex = short.MaxValue; // an unlikely value, this will be set later

                            mesh.TextureIndex = reader.ReadInt32();

                            // store the position for later use
                            long pos = reader.BaseStream.Position;

                            // populate the meshes with vertices
                            reader.BaseStream.Seek(vertexOffset + (submeshBlock.Entries[i].VertexOffset * actualVertexTableSize), SeekOrigin.Begin);
                            for (int j = 0; j < mesh.VertexCount; j++)
                            {
                                short x = reader.ReadInt16();
                                short y = reader.ReadInt16();
                                short z = reader.ReadInt16();

                                Mesh.Vertex v = new Mesh.Vertex
                                {
                                    Position = new Vector3 // the coordinates are read like this, so that the model stands upright
                                    {
                                        Z = x,
                                        X = y,
                                        Y = z
                                    }
                                };

                                int scaleFactor;
                                switch (actualVertexTableSize)
                                {
                                case 12:
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    break;

                                case 16:
                                    scaleFactor = reader.ReadInt16();
                                    v.Position /= scaleFactor;
                                    reader.BaseStream.Seek(4, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    break;

                                case 20:
                                    scaleFactor = reader.ReadInt16();
                                    v.Position /= scaleFactor;
                                    v.Normal    = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    break;

                                case 24:
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.Normal = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    break;

                                case 28:
                                    scaleFactor = reader.ReadInt16();
                                    v.Position /= scaleFactor;
                                    v.Normal    = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(4, SeekOrigin.Current);
                                    break;

                                case 32:
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.Normal = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    v.BoneIndices       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    break;

                                case 36:
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.Normal = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(4, SeekOrigin.Current);
                                    v.BoneIndices = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    break;

                                case 40:
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.Normal = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    v.BoneIndices       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneIndices2      = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights2      = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    break;

                                case 44:
                                    reader.BaseStream.Seek(14, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    v.BoneIndices       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneIndices2      = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights2      = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    reader.BaseStream.Seek(4, SeekOrigin.Current);
                                    break;

                                case 48:
                                    reader.BaseStream.Seek(2, SeekOrigin.Current);
                                    v.Normal = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                                    reader.BaseStream.Seek(6, SeekOrigin.Current);
                                    v.TextureCoordinate = new Vector2(reader.ReadInt16(), reader.ReadInt16());
                                    v.BoneIndices       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneIndices2      = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights       = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    v.BoneWeights2      = new Vector4(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
                                    reader.BaseStream.Seek(4, SeekOrigin.Current);
                                    break;

                                default:
                                    reader.BaseStream.Seek(actualVertexTableSize - 6, SeekOrigin.Current);
                                    break;
                                }

                                //v.TextureCoordinate = new Vector2(v.TextureCoordinate.X / 65536 * 32, 1 - (v.TextureCoordinate.Y / 65536 * 32));
                                mesh.Vertices.Add(v);
                                //mesh.Normals.Add(v.Normal);
                            }

                            // add to the total vertices
                            if (i > 0)
                            {
                                totalVertices += model.Meshes[i - 1].VertexCount;
                                mesh.NumOfVerticesBeforeMe = totalVertices;
                            }

                            // populate the meshes with faces
                            reader.BaseStream.Seek(faceOffset + (submeshBlock.Entries[i].FaceOffset * 2), SeekOrigin.Begin);
                            for (int j = 0; j < mesh.FaceCount; j++)
                            {
                                int x = reader.ReadUInt16() + mesh.NumOfVerticesBeforeMe;
                                int y = reader.ReadUInt16() + mesh.NumOfVerticesBeforeMe;
                                int z = reader.ReadUInt16() + mesh.NumOfVerticesBeforeMe;

                                if (x != y && y != z && x != z)
                                {
                                    if (x < mesh.MinFaceIndex)
                                    {
                                        mesh.MinFaceIndex = x;
                                    }
                                    if (y < mesh.MinFaceIndex)
                                    {
                                        mesh.MinFaceIndex = y;
                                    }
                                    if (z < mesh.MinFaceIndex)
                                    {
                                        mesh.MinFaceIndex = z;
                                    }
                                    if (x > mesh.MaxFaceIndex)
                                    {
                                        mesh.MaxFaceIndex = x;
                                    }
                                    if (y > mesh.MaxFaceIndex)
                                    {
                                        mesh.MaxFaceIndex = y;
                                    }
                                    if (z > mesh.MaxFaceIndex)
                                    {
                                        mesh.MaxFaceIndex = z;
                                    }

                                    Mesh.Face f = new Mesh.Face
                                    {
                                        X = x,
                                        Y = y,
                                        Z = z
                                    };
                                    mesh.Faces.Add(f);

                                    mesh.Indices.Add(x);
                                    mesh.Indices.Add(y);
                                    mesh.Indices.Add(z);
                                }
                            }
                            model.Meshes.Add(mesh);

                            // go back to the Mesh Data
                            reader.BaseStream.Seek(pos, SeekOrigin.Begin);
                        }

                        // print information
                        str.AppendLine($"Vertex table size: {actualVertexTableSize}");
                        str.AppendLine($"Meshes: {meshCount}");
                        for (int i = 0; i < model.Meshes.Count; i++)
                        {
                            model.Meshes[i].CalculateNormals();
                            str.AppendLine($"\tMesh {i}:");
                            str.AppendLine($"\t\tVertices: {model.Meshes[i].Vertices.Count}");
                            str.AppendLine($"\t\tFaces: {model.Meshes[i].FaceCount}");
                            str.AppendLine($"\t\tIndices: {model.Meshes[i].IndexCount}");
                            str.AppendLine($"\t\tMin Face Index: {model.Meshes[i].MinFaceIndex}");
                            str.AppendLine($"\t\tMax Face Index: {model.Meshes[i].MaxFaceIndex}");
                        }
                    }
                    catch (Exception e)
                    {
                        Message.Fail("Failed to read model. " + e.Message);
                    }
                    finally
                    {
                        completionAction(str.ToString());
                    }

                    #region Partially working code

                    /* BONES
                     *
                     * // skip two Unknown chunks
                     * reader.BaseStream.Seek(2 * 0x10, SeekOrigin.Current);
                     * reader.BaseStream.Seek(1 + (2 * 0x11), SeekOrigin.Current);
                     *
                     * // vertex table size
                     * int vertexTableSize = reader.ReadInt32();
                     * if (vertexTableSize == 8) // read again if the result is 8
                     * {
                     *  vertexTableSize = reader.ReadInt32();
                     *  reader.BaseStream.Seek(33, SeekOrigin.Current);
                     * }
                     * else
                     * {
                     *  reader.BaseStream.Seek(37, SeekOrigin.Current);
                     * }
                     *
                     * // Unknown 1 chunk
                     * uint unknown1DataCount = reader.ReadUInt32();
                     * for (int i = 0; i < unknown1DataCount; i++)
                     * {
                     *  reader.BaseStream.Seek(0x18, SeekOrigin.Current); // skip it for now
                     * }
                     *
                     * // Internal UV chunk
                     * uint uvDataSize = reader.ReadUInt32();
                     * long uvOffset = reader.BaseStream.Position; // we revisit this later
                     * reader.BaseStream.Seek(uvDataSize, SeekOrigin.Current);
                     *
                     * // Vertices chunk
                     * uint verticesDataSize = reader.ReadUInt32();
                     * long verticesOffset = reader.BaseStream.Position; // we revisit this later
                     * reader.BaseStream.Seek(verticesDataSize, SeekOrigin.Current);
                     *
                     * // Unknown 2 chunk
                     * uint unknown2DataCount = reader.ReadUInt32();
                     * reader.BaseStream.Seek(unknown2DataCount, SeekOrigin.Current); // skip it for now
                     *
                     * // Faces chunk
                     * uint facesDataSize = reader.ReadUInt32();
                     * long facesOffset = reader.BaseStream.Position; // we revisit this later
                     * reader.BaseStream.Seek(facesDataSize, SeekOrigin.Current);
                     *
                     * // Unknown 3 chunk
                     * uint unknown3DataSize = reader.ReadUInt32();
                     * reader.BaseStream.Seek(unknown3DataSize, SeekOrigin.Current); // skip it for now
                     *
                     * // Unknown 4 chunk
                     * uint unknown4DataSize = reader.ReadUInt32();
                     * reader.BaseStream.Seek(unknown4DataSize, SeekOrigin.Current); // skip it for now
                     *
                     * // Unknown 5 chunk
                     * uint unknown5DataSize = reader.ReadUInt32();
                     * reader.BaseStream.Seek(unknown5DataSize, SeekOrigin.Current); // skip it for now
                     *
                     * reader.BaseStream.Seek(1 * 0x12, SeekOrigin.Current);
                     *
                     * // Mesh Data chunk
                     * uint meshCount = reader.ReadUInt32();
                     * sb.AppendLine($"Meshes: {meshCount}");
                     * meshes = new Mesh[meshCount];
                     * for (int i = 0; i < meshCount; i++)
                     * {
                     *  meshes[i].ID = reader.ReadInt16();
                     *  reader.BaseStream.Seek(18, SeekOrigin.Current);
                     *  meshes[i] = new Mesh();
                     *  meshes[i].Vertices = new Vertex[reader.ReadInt32()];
                     *  reader.BaseStream.Seek(4, SeekOrigin.Current);
                     *  meshes[i].Faces = new Face[reader.ReadInt32()];
                     *  meshes[i].TextureIndex = reader.ReadInt32();
                     *  meshes[i].OBJData = "";
                     *
                     *  sb.AppendLine($"\tMesh {i}: {meshes[i].Faces.Length} faces\t{meshes[i].Vertices.Length} vertices");
                     * }
                     *
                     * // revisit the Vertices
                     * reader.BaseStream.Seek(verticesOffset, SeekOrigin.Begin);
                     * for (int i = 0; i < meshes.Length; i++)
                     * {
                     *  for (int j = 0; j < meshes[i].Vertices.Length; j++)
                     *  {
                     *      Vertex v = new Vertex
                     *      {
                     *          Position = new Vector3
                     *          {
                     *              X = reader.ReadInt16(),
                     *              Y = reader.ReadInt16(),
                     *              Z = reader.ReadInt16()
                     *          }
                     *      };
                     *
                     *      meshes[i].Vertices[j] = v;
                     *      meshes[i].OBJData += $"v {v}\n";
                     *      obj.AppendLine($"v {v}");
                     *
                     *      reader.BaseStream.Seek(vertexTableSize - 6, SeekOrigin.Current); // skip the other data for now
                     *  }
                     * }
                     *
                     * // revisit the Faces
                     * reader.BaseStream.Seek(facesOffset, SeekOrigin.Begin);
                     * for (int i = 0; i < meshes.Length; i++)
                     * {
                     *  for (int j = 0; j < meshes[i].Faces.Length; j++)
                     *  {
                     *      Face f = new Face
                     *      {
                     *          X = reader.ReadUInt16() + 1,
                     *          Y = reader.ReadUInt16() + 1,
                     *          Z = reader.ReadUInt16() + 1
                     *      };
                     *
                     *      meshes[i].Faces[j] = f;
                     *      meshes[i].OBJData += $"f {f}\n";
                     *      obj.AppendLine($"f {f}");
                     *  }
                     *
                     *  sb.AppendLine(meshes[i].OBJData);
                     *  sb.AppendLine();
                     * }
                     */
                    #endregion

                    #region Not working code

                    /*// locate the Mesh block
                     *  reader.BaseStream.Seek(0, SeekOrigin.Begin);
                     *  int meshBlockLoc = Helpers.RecurringIndexes(allData, MESH_DATA, 4).LastOrDefault().Item1;
                     *  reader.BaseStream.Seek(meshBlockLoc + 7, SeekOrigin.Begin); // skip the identifier + 3 bytes
                     *
                     *  // Mesh block
                     *  MeshBlock meshBlock = new MeshBlock
                     *  {
                     *      ModelType = reader.ReadInt32(),
                     *      ACount = reader.ReadInt32(),
                     *      BoneCount = reader.ReadInt32()
                     *  };
                     *
                     *  // locate the Compiled Mesh block
                     *  reader.BaseStream.Seek(0, SeekOrigin.Begin);
                     *  IList<Tuple<int, int>> tt = Helpers.RecurringIndexes(allData, COMPILED_MESH_DATA, 4);
                     *  int compiledMeshBlockLoc = tt.LastOrDefault().Item1;
                     *  reader.BaseStream.Seek(compiledMeshBlockLoc + 26, SeekOrigin.Begin); // identifier + 22 bytes
                     *
                     *  // Compiled Mesh block
                     *  CompiledMeshBlock compiledMeshBlock = new CompiledMeshBlock
                     *  {
                     *      VertexTableSize = reader.ReadInt32()
                     *  };
                     *  reader.BaseStream.Seek(37, SeekOrigin.Current);
                     *  compiledMeshBlock.MeshCount = reader.ReadInt32();
                     *  compiledMeshBlock.ShadowCount = reader.ReadInt32();
                     *  reader.BaseStream.Seek(compiledMeshBlock.MeshCount * 16, SeekOrigin.Current);
                     *  reader.BaseStream.Seek(4, SeekOrigin.Current); // unknown1
                     *
                     *  int sizeOfVertexData = reader.ReadInt32();
                     *
                     *  // show error
                     *  if (compiledMeshBlock.MeshCount > 1)
                     *  {
                     *      Messages.Fail("Currently, Blacksmith cannot handle models with more than 1 submesh.", "Failure");
                     *      return null;
                     *  }
                     *
                     *  // populate data in the Submeshes
                     *  submeshes = new Submesh[compiledMeshBlock.MeshCount];
                     *  for (int i = 0; i < submeshes.Length; i++)
                     *  {
                     *      // Vertices
                     *      List<Vertex> vertices = new List<Vertex>();
                     *      for (int j = 0; j < sizeOfVertexData / compiledMeshBlock.VertexTableSize; j++)
                     *      {
                     *          Vertex v = new Vertex();
                     *          v.Position = new Vector3
                     *          {
                     *              X = reader.ReadInt16(),
                     *              Y = reader.ReadInt16(),
                     *              Z = reader.ReadInt16()
                     *          };
                     *
                     *          //short scaleFactor = reader.ReadInt16();
                     *          //v.Position /= scaleFactor;
                     *
                     *          /*if (compiledMeshBlock.VertexTableSize == 16)
                     *          {
                     *              v.Normal = new Vector3(reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16());
                     *          }*
                     *
                     *          vertices.Add(v);
                     *          sb.AppendLine("v " + v);
                     *
                     *          reader.BaseStream.Seek(compiledMeshBlock.VertexTableSize - 6, SeekOrigin.Current);
                     *      }
                     *
                     *      // onto the Faces
                     *      reader.BaseStream.Seek(8, SeekOrigin.Current);
                     *
                     *      // Faces
                     *      List<Face> faces = new List<Face>();
                     *      int sizeOfFaceData = reader.ReadInt32();
                     *      for (int j = 0; j < sizeOfFaceData / 6; j++) // a Face contains 6 bytes
                     *      {
                     *          Face f = new Face
                     *          {
                     *              Y = reader.ReadUInt16() + 1,
                     *              X = reader.ReadUInt16() + 1,
                     *              Z = reader.ReadUInt16() + 1
                     *          };
                     *
                     *          faces.Add(f);
                     *          sb.AppendLine("f " + f);
                     *      }
                     *
                     *      // set properties of this Submesh
                     *      submeshes[i].Vertices = vertices.ToArray();
                     *      submeshes[i].Faces = faces.ToArray();
                     *      submeshes[i].OBJData = sb.ToString();
                     *  }*/
                    #endregion

                    #region Not working code

                    /*// block A - 1
                     * uint aCount = reader.ReadUInt32();
                     * Block blockA = new Block();
                     * blockA.Bytes = new byte[aCount][];
                     * for (int i = 0; i < aCount; i++)
                     * {
                     *  blockA.Bytes[i] = reader.ReadBytes(0x51);
                     * }
                     *
                     * // block B - 1-0
                     * Block blockB = new Block();
                     * blockB.Bytes = new byte[2][];
                     * for (int i = 0; i < 2; i++)
                     * {
                     *  blockB.Bytes[i] = reader.ReadBytes(0x10);
                     * }
                     *
                     * // block C - 1-1
                     * reader.BaseStream.Seek(1, SeekOrigin.Current);
                     * Block blockC = new Block();
                     * blockC.Bytes = new byte[2][];
                     * for (int i = 0; i < 2; i++)
                     * {
                     *  blockC.Bytes[i] = reader.ReadBytes(0x11);
                     * }
                     *
                     * // block D - 1-2
                     * reader.BaseStream.Seek(0x29, SeekOrigin.Current);
                     * uint dCount = reader.ReadUInt32();
                     * Block blockD = new Block();
                     * blockD.Bytes = new byte[dCount][];
                     * for (int i = 0; i < dCount; i++)
                     * {
                     *  blockD.Bytes[i] = reader.ReadBytes(0x18);
                     * }
                     *
                     * // internal/external UVs (block E) - 20
                     * uint eCount = reader.ReadUInt32();
                     * reader.BaseStream.Seek(eCount, SeekOrigin.Current);
                     *
                     * // vertices (block F) - 30
                     * uint fCount = reader.ReadUInt32() / 12;
                     * long verticesOffset = reader.BaseStream.Position;
                     * Block blockF = new Block();
                     * blockF.Bytes = new byte[fCount][];
                     * for (int i = 0; i < fCount; i++)
                     * {
                     *  blockF.Bytes[i] = reader.ReadBytes(0x0c);
                     * }
                     *
                     * // block G - 40
                     * uint gSize = reader.ReadUInt32();
                     * Block blockG = new Block();
                     * blockG.Bytes = new byte[gSize][];
                     * reader.BaseStream.Seek(gSize, SeekOrigin.Current);
                     *
                     * // faces (block) H - 50
                     * uint hCount = reader.ReadUInt32() / 6;
                     * long facesOffset = reader.BaseStream.Position;
                     * Block blockH = new Block();
                     * blockH.Bytes = new byte[hCount][];
                     * for (int i = 0; i < hCount; i++)
                     * {
                     *  blockH.Bytes[i] = reader.ReadBytes(0x06);
                     * }
                     *
                     * // block I - 60
                     * uint iSize = reader.ReadUInt32();
                     * Block blockI = new Block();
                     * blockI.Bytes = new byte[iSize][];
                     * reader.BaseStream.Seek(iSize, SeekOrigin.Current);
                     *
                     * // block J - 70
                     * uint jSize = reader.ReadUInt32();
                     * Block blockJ = new Block();
                     * blockJ.Bytes = new byte[jSize][];
                     * reader.BaseStream.Seek(jSize, SeekOrigin.Current);
                     *
                     * // block K - 80
                     * uint kSize = reader.ReadUInt32();
                     * Block blockK = new Block();
                     * blockK.Bytes = new byte[kSize][];
                     * reader.BaseStream.Seek(kSize, SeekOrigin.Current);
                     *
                     * // block L
                     * Block blockL = new Block();
                     * blockL.Bytes = new byte[1][];
                     * for (int i = 0; i < 1; i++)
                     * {
                     *  blockL.Bytes[i] = reader.ReadBytes(0x12);
                     * }
                     *
                     * // block M - 90
                     * uint mSize = reader.ReadUInt32(); // number of submeshes
                     *
                     * // create submeshes
                     * submeshes = new Submesh[mSize];
                     * for (int i = 0; i < mSize; i++)
                     * {
                     *  submeshes[i] = new Submesh();
                     *
                     *  reader.BaseStream.Seek(0x14, SeekOrigin.Current);
                     *  submeshes[i].VertexCount = reader.ReadUInt32();
                     *  reader.BaseStream.Seek(0x04, SeekOrigin.Current);
                     *  submeshes[i].FaceCount = reader.ReadUInt32();
                     *  reader.BaseStream.Seek(0x04, SeekOrigin.Current);
                     * }
                     *
                     * /*reader.BaseStream.Seek(0x10, SeekOrigin.Current);
                     *
                     * // block N - 100
                     * uint nSize = reader.ReadUInt32();
                     * Block blockN = new Block();
                     * blockN.Bytes = new byte[nSize][];
                     * for (int i = 0; i < nSize; i++)
                     * {
                     *  blockN.Bytes[i] = reader.ReadBytes(0x1e);
                     * }
                     *
                     * // block O - 110
                     * reader.BaseStream.Seek(0x16, SeekOrigin.Current);
                     * uint oSize = reader.ReadUInt32();
                     * Block blockO = new Block();
                     * blockO.Bytes = new byte[nSize][];
                     * for (int i = 0; i < oSize; i++)
                     * {
                     *  blockO.Bytes[i] = reader.ReadBytes(0x0a);
                     * }*
                     *
                     * // get faces
                     * reader.BaseStream.Seek(facesOffset, SeekOrigin.Begin);
                     * for (int i = 0; i < submeshes.Length; i++)
                     * {
                     *  submeshes[i].Faces = new Face[submeshes[i].FaceCount];
                     *  for (int j = 0; j < submeshes[i].FaceCount; j++)
                     *  {
                     *      submeshes[i].Faces[j] = new Face
                     *      {
                     *          X = reader.ReadUInt16(),
                     *          Y = reader.ReadUInt16(),
                     *          Z = reader.ReadUInt16()
                     *      };
                     *
                     *      /*ObjParser.Types.Face f = new ObjParser.Types.Face
                     *      {
                     *          X = submeshes[i].Vertices[j].X,
                     *          Y = submeshes[i].Vertices[j].Y,
                     *          Z = submeshes[i].Vertices[j].Z
                     *      };
                     *      faces.Add(f);*
                     *  }
                     * }
                     *
                     * // get vertices
                     * reader.BaseStream.Seek(verticesOffset, SeekOrigin.Begin);
                     * List<ObjParser.Types.Vertex> verts = new List<ObjParser.Types.Vertex>();
                     * for (int i = 0; i < submeshes.Length; i++)
                     * {
                     *  submeshes[i].Vertices = new Vertex[submeshes[i].VertexCount];
                     *  for (int j = 0; j < submeshes[i].VertexCount; j++)
                     *  {
                     *      submeshes[i].Vertices[j] = new Vertex
                     *      {
                     *          X = reader.ReadInt16(),
                     *          Y = reader.ReadInt16(),
                     *          Z = reader.ReadInt16(),
                     *          U = reader.ReadInt16(),
                     *          V = reader.ReadInt16(),
                     *          Dummy = reader.ReadInt16()
                     *      };
                     *
                     *      ObjParser.Types.Vertex v = new ObjParser.Types.Vertex
                     *      {
                     *          X = submeshes[i].Vertices[j].X,
                     *          Y = submeshes[i].Vertices[j].Y,
                     *          Z = submeshes[i].Vertices[j].Z
                     *      };
                     *      verts.Add(v);
                     *  }
                     * }
                     *
                     * Obj obj = new Obj();
                     * obj.VertexList = verts;
                     * obj.WriteObjFile(@"C:\Users\pinea\bag-new.obj", new string[] { "" });
                     *
                     * completionAction();*/
                    #endregion
                }
            }

            return(model);
        }