Пример #1
0
        public string ToJson()
        {
            // I did think of using a JSON serialiser,
            // either one of these two provided by the
            // .NET framework or one of the other libraries:
            // System.Runtime.Serialization.Json.DataContractJsonSerializer
            // System.Web.Script.Serialization.JavaScriptSerializer
            // However, reading this comparison and alternative
            // implementation, I decided to just write the couple
            // of lines myself.
            // http://procbits.com/2011/08/11/fridaythe13th-the-best-json-parser-for-silverlight-and-net

            string s = string.Format
                           ("\n \"FacetCount\":{0},"
                           + "\n \"VertexCount\":{1},"
                           + "\n \"VertexCoords\":[{2}],"
                           + "\n \"VertexIndices\":[{3}],"
                           + "\n \"Normals\":[{4}],"
                           + "\n \"NormalIndices\":[{5}],"
                           + "\n \"Center\":[{6}],"
                           + "\n \"Color\":[{7}],"
                           + "\n \"Id\":\"{8}\"",
                           FacetCount,
                           VertexCount,
                           string.Join(",", VertexCoords.Select <int, string>(i => (_export_factor * i).ToString("0.#")).ToArray()),
                           string.Join(",", VertexIndices.Select <int, string>(i => i.ToString()).ToArray()),
                           string.Join(",", Normals.Select <double, string>(a => a.ToString("0.####")).ToArray()),
                           string.Join(",", NormalIndices.Select <int, string>(i => i.ToString())),
                           string.Join(",", Center.Select <int, string>(i => (_export_factor * i).ToString("0.#"))),
                           Color,
                           Id);

            return("\n{" + s + "\n}");
        }
Пример #2
0
 public VertexIndices(VertexIndices previous, int finalIndex)
 {
     Vertex     = previous.Vertex;
     TexCoord   = previous.TexCoord;
     Normal     = previous.Normal;
     FinalIndex = finalIndex;
 }
Пример #3
0
        private static VertexIndices ParseVertexIndices(string element)
        {
            int           count  = element.Count(ch => ch == '/');
            VertexIndices result = new VertexIndices();

            if (element.Contains("//"))
            {
                // Vertex, normal
                string[] vertexNormal = element.Split(new [] { "//" }, StringSplitOptions.None);
                result.Vertex = int.Parse(vertexNormal[0]);
                result.Normal = int.Parse(vertexNormal[1]);
            }
            else if (count == 1)
            {
                // Vertex, texcoord
                string[] vertexTCoord = element.Split('/');
                result.Vertex   = int.Parse(vertexTCoord[0]);
                result.TexCoord = int.Parse(vertexTCoord[1]);
            }
            else if (count == 2)
            {
                // Vertex, texcoord, normal
                string[] vertexTCoordNormal = element.Split('/');
                result.Vertex   = int.Parse(vertexTCoordNormal[0]);
                result.TexCoord = int.Parse(vertexTCoordNormal[1]);
                result.Normal   = int.Parse(vertexTCoordNormal[2]);
            }
            else
            {
                throw new AssetLoadException("model", "texture face element declaration incorrect, count was " + count.ToString() + " @ line " + currentLine.ToString());
            }

            return(result);
        }
Пример #4
0
 public virtual void Dispose()
 {
     VertexOffsets.Dispose();
     VertexIndices.Dispose();
     EdgeFlags.Dispose();
     Triangles.Dispose();
 }
Пример #5
0
        protected override void PopulateSerializedValues(IList <string> serializedValues)
        {
            SerializeToFloat(serializedValues, VertexIndices.Count());

            foreach (var index in VertexIndices)
            {
                SerializeToFloat(serializedValues, index);
            }

            if (Normal != null)
            {
                SerializeToFloat(serializedValues, Normal.X);
                SerializeToFloat(serializedValues, Normal.Y);
                SerializeToFloat(serializedValues, Normal.Z);
            }

            if (Color.HasValue)
            {
                Serialize(serializedValues, Color.Value.R);
                Serialize(serializedValues, Color.Value.G);
                Serialize(serializedValues, Color.Value.B);
                Serialize(serializedValues, Color.Value.A);
            }

            if (BackColor.HasValue)
            {
                Serialize(serializedValues, Color.Value.R);
                Serialize(serializedValues, Color.Value.G);
                Serialize(serializedValues, Color.Value.B);
                Serialize(serializedValues, Color.Value.A);
            }
        }
Пример #6
0
 public VertexSet(PrimitiveType mode, IAttributedVertexBuffer buffer, VertexIndices indices, ISet <int> enabledAttribs = null, int depth = 0)
 {
     DrawMode          = mode;
     VBuffer           = buffer;
     EnabledAttributes = enabledAttribs;
     this.indices      = indices;
     DrawDepth         = depth;
 }
Пример #7
0
        protected void GenerateVertices()
        {
            var Count = VertexIndices.Count;

            VertexIndices.Clear();

            List <ObjMeshSection> SortedMeshSectionList = new List <ObjMeshSection>();

            foreach (var sectionlist in MeshSectionList.GroupBy(x => x.SectionName))
            {
                var sectionName  = sectionlist.First().SectionName;
                var sectionCount = sectionlist.Count();

                UInt32 StartIndex = (UInt32)VertexIndices.Count;

                foreach (var section in sectionlist)
                {
                    for (int i = (int)section.StartIndex; i < section.EndIndex; ++i)
                    {
                        var V1 = new PNTT_VertexAttribute();

                        V1.VertexPosition = TempVertexList[(int)VertexIndexList[i]];

                        if (HasTexCoordinate)
                        {
                            V1.TexCoord = TempTexCoordList[(int)TexCoordIndexList[i]];
                            V1.Tangent  = TempTangentList[(int)VertexIndexList[i]];
                        }

                        if (HasNormal)
                        {
                            V1.VertexNormal = TempNormalList[(int)NormalIndexList[i]];
                        }

                        uint index = 0;
                        if (GetSimilarVertexIndex(ref V1, out index))
                        {
                            VertexIndices.Add(index);
                        }
                        else
                        {
                            Vertices.Add(V1);
                            uint newIndex = (uint)Vertices.Count - 1;
                            VertexCacheMap.Add(V1, newIndex);
                            VertexIndices.Add(newIndex);
                        }
                    }
                }

                UInt32 EndIndex = (UInt32)VertexIndices.Count;

                SortedMeshSectionList.Add(new ObjMeshSection(sectionName, StartIndex, EndIndex));
            }

            MeshSectionList = SortedMeshSectionList;

            Debug.Assert(Count == VertexIndices.Count);
        }
Пример #8
0
 public Sprite(Texture tex, IBindableVertexBuffer buffer, int bufferInd, int depth = 0)
     : base(
         tex,
         PrimitiveType.Quads,
         new AttributedVertexBuffer(buffer, VertexAttributeSet.FromType <TexturedVertex2>()),
         VertexIndices.FromRange(bufferInd, 4),
         null,
         depth)
 {
     index = bufferInd;
 }
Пример #9
0
 private static int GetFirstFinalIndexOfDuplicate(List <VertexIndices> vIndices, int currentIndex, bool optimize)
 {
     if (optimize)
     {
         VertexIndices vertex = vIndices[currentIndex];
         for (int i = 0; i < currentIndex; ++i)
         {
             VertexIndices other = vIndices[i];
             if (vertex == other)
             {
                 return(other.FinalIndex);
             }
         }
     }
     return(-1);
 }
Пример #10
0
        private static void SortOutVIndices(
            List <Vector4> verticesIn,
            out List <Vector4> verticesOut,
            List <Vector3> normalsIn,
            out List <Vector3> normalsOut,
            List <Vector2> tCoordsIn,
            out List <Vector2> tCoordsOut,
            out List <int> indicesOut,
            List <VertexIndices> vIndices,
            bool optimize)
        {
            verticesOut = new List <Vector4>(verticesIn.Count);
            normalsOut  = new List <Vector3>(normalsIn.Count);
            tCoordsOut  = new List <Vector2>(tCoordsIn.Count);
            indicesOut  = new List <int>(verticesIn.Count);

            for (int i = 0; i < vIndices.Count; ++i)
            {
                int firstFinalIndex = GetFirstFinalIndexOfDuplicate(vIndices, i, optimize);

                if (firstFinalIndex == -1)
                {
                    VertexIndices vertex = vIndices[i];
                    vIndices[i] = new VertexIndices(vertex, verticesOut.Count);

                    indicesOut.Add(verticesOut.Count);
                    verticesOut.Add(verticesIn[vertex.Vertex - 1]);

                    if (vertex.TexCoord.HasValue)
                    {
                        tCoordsOut.Add(tCoordsIn[vertex.TexCoord.Value - 1]);
                    }
                    if (vertex.Normal.HasValue)
                    {
                        normalsOut.Add(normalsIn[vertex.Normal.Value - 1]);
                    }
                }
                else
                {
                    indicesOut.Add(firstFinalIndex);
                }
            }
        }
Пример #11
0
        private static StringBuilder CreateObjGeometry(List <Dictionary <string, List <WorldVertex[]> > > geometryByTexture, ref WavefrontExportSettings data)
        {
            StringBuilder obj = new StringBuilder();
            Vector2D      offset;
            const string  vertexFormatter = "{0} {2} {1}\n";

            Dictionary <Vector3D, int> uniqueVerts   = new Dictionary <Vector3D, int>();
            Dictionary <Vector3D, int> uniqueNormals = new Dictionary <Vector3D, int>();
            Dictionary <PointF, int>   uniqueUVs     = new Dictionary <PointF, int>();

            var vertexDataByTexture = new Dictionary <string, Dictionary <WorldVertex, VertexIndices> >(StringComparer.Ordinal);
            int pc  = 0;
            int nc  = 0;
            int uvc = 0;

            Vector3D tl = new Vector3D(double.MaxValue, double.MinValue, double.MinValue);
            Vector3D br = new Vector3D(double.MinValue, double.MaxValue, double.MaxValue);

            //optimize geometry
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    Dictionary <WorldVertex, VertexIndices> vertsData = new Dictionary <WorldVertex, VertexIndices>();
                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //vertex normals. biwa not sure why I need to invert the normal, but it seems to be necessary
                        Vector3D n = new Vector3D(verts[0].nx, verts[0].ny, verts[0].nz).GetNormal() * -1;
                        int      ni;
                        if (uniqueNormals.ContainsKey(n))
                        {
                            ni = uniqueNormals[n];
                        }
                        else
                        {
                            uniqueNormals.Add(n, ++nc);
                            ni = nc;
                        }

                        foreach (WorldVertex v in verts)
                        {
                            if (vertsData.ContainsKey(v))
                            {
                                continue;
                            }
                            VertexIndices indices = new VertexIndices();
                            indices.NormalIndex = ni;

                            //vertex coords
                            Vector3D vc = new Vector3D(v.x, v.y, v.z);
                            if (uniqueVerts.ContainsKey(vc))
                            {
                                indices.PositionIndex = uniqueVerts[vc];
                            }
                            else
                            {
                                uniqueVerts.Add(vc, ++pc);
                                indices.PositionIndex = pc;
                            }

                            //uv
                            PointF uv = new PointF(v.u, v.v);
                            if (uniqueUVs.ContainsKey(uv))
                            {
                                indices.UVIndex = uniqueUVs[uv];
                            }
                            else
                            {
                                uniqueUVs.Add(uv, ++uvc);
                                indices.UVIndex = uvc;
                            }

                            vertsData.Add(v, indices);
                        }
                    }

                    if (vertsData.Count > 0)
                    {
                        if (vertexDataByTexture.ContainsKey(group.Key))
                        {
                            foreach (KeyValuePair <WorldVertex, VertexIndices> g in vertsData)
                            {
                                vertexDataByTexture[group.Key].Add(g.Key, g.Value);
                            }
                        }
                        else
                        {
                            vertexDataByTexture.Add(group.Key, vertsData);
                        }
                    }
                }
            }

            // Get the dimensions of the model
            foreach (Dictionary <WorldVertex, VertexIndices> vdata in vertexDataByTexture.Values)
            {
                foreach (WorldVertex wv in vdata.Keys)
                {
                    if (wv.x < tl.x)
                    {
                        tl.x = wv.x;
                    }
                    if (wv.x > br.x)
                    {
                        br.x = wv.x;
                    }
                    if (wv.y > tl.y)
                    {
                        tl.y = wv.y;
                    }
                    if (wv.y < br.y)
                    {
                        br.y = wv.y;
                    }
                    if (wv.z > tl.z)
                    {
                        tl.z = wv.z;
                    }
                    if (wv.z < br.z)
                    {
                        br.z = wv.z;
                    }
                }
            }

            data.Radius = br.x - tl.x > tl.y - br.y ? (int)(tl.y - br.y) / 2 : (int)(br.x - tl.x) / 2;
            data.Height = (int)(tl.z - br.z);

            if (data.CenterModel)
            {
                offset = new Vector2D(tl.x + (br.x - tl.x) / 2.0, tl.y + (br.y - tl.y) / 2.0);
            }
            else
            {
                offset = new Vector2D(0.0, 0.0);
            }

            //write geometry
            //write vertices
            if (data.ExportForGZDoom)
            {
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    double z = (group.Key.z - (data.NormalizeLowestVertex ? br.z : 0)) * data.Scale * 1.2f;

                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, (group.Key.x - offset.x) * data.Scale, -(group.Key.y - offset.y) * data.Scale, z));
                }
            }
            else
            {
                // biwa. Not sure why the x-axis is flipped here, since it will result in wrong normals when using the model directly in GZDoom. For this reason
                // I disabled the flipping above
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    double z = (group.Key.z - (data.NormalizeLowestVertex ? br.z : 0)) * data.Scale;

                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, -(group.Key.x - offset.x) * data.Scale, (group.Key.y - offset.y) * data.Scale, z));
                }
            }

            //write normals
            foreach (KeyValuePair <Vector3D, int> group in uniqueNormals)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vn " + vertexFormatter, group.Key.x, group.Key.y, group.Key.z));
            }

            //write UV coords
            foreach (KeyValuePair <PointF, int> group in uniqueUVs)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vt {0} {1}\n", group.Key.X, -group.Key.Y));
            }

            // GZDoom ignores the material lib, so don't add it if the model is for GZDoom
            if (!data.ExportForGZDoom)
            {
                obj.Append("mtllib ").Append(data.ObjName + ".mtl").Append("\n");
            }

            //write materials and surface indices
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    //material
                    obj.Append("usemtl ").Append(group.Key).Append("\n");

                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //surface indices
                        obj.Append("f");
                        foreach (WorldVertex v in verts)
                        {
                            VertexIndices vi = vertexDataByTexture[group.Key][v];
                            obj.Append(" " + vi.PositionIndex + "/" + vi.UVIndex + "/" + vi.NormalIndex);
                        }
                        obj.Append("\n");
                    }
                }
            }

            return(obj);
        }
        private static StringBuilder CreateObjGeometry(List <Dictionary <string, List <WorldVertex[]> > > geometryByTexture, WavefrontExportSettings data)
        {
            StringBuilder obj             = new StringBuilder();
            const string  vertexFormatter = "{0} {2} {1}\n";

            Dictionary <Vector3D, int> uniqueVerts   = new Dictionary <Vector3D, int>();
            Dictionary <Vector3D, int> uniqueNormals = new Dictionary <Vector3D, int>();
            Dictionary <PointF, int>   uniqueUVs     = new Dictionary <PointF, int>();

            var vertexDataByTexture = new Dictionary <string, Dictionary <WorldVertex, VertexIndices> >(StringComparer.Ordinal);
            int pc  = 0;
            int nc  = 0;
            int uvc = 0;

            //optimize geometry
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    Dictionary <WorldVertex, VertexIndices> vertsData = new Dictionary <WorldVertex, VertexIndices>();
                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //vertex normals
                        Vector3D n = new Vector3D(verts[0].nx, verts[0].ny, verts[0].nz).GetNormal();
                        int      ni;
                        if (uniqueNormals.ContainsKey(n))
                        {
                            ni = uniqueNormals[n];
                        }
                        else
                        {
                            uniqueNormals.Add(n, ++nc);
                            ni = nc;
                        }

                        foreach (WorldVertex v in verts)
                        {
                            if (vertsData.ContainsKey(v))
                            {
                                continue;
                            }
                            VertexIndices indices = new VertexIndices();
                            indices.NormalIndex = ni;

                            //vertex coords
                            Vector3D vc = new Vector3D(v.x, v.y, v.z);
                            if (uniqueVerts.ContainsKey(vc))
                            {
                                indices.PositionIndex = uniqueVerts[vc];
                            }
                            else
                            {
                                uniqueVerts.Add(vc, ++pc);
                                indices.PositionIndex = pc;
                            }

                            //uv
                            PointF uv = new PointF(v.u, v.v);
                            if (uniqueUVs.ContainsKey(uv))
                            {
                                indices.UVIndex = uniqueUVs[uv];
                            }
                            else
                            {
                                uniqueUVs.Add(uv, ++uvc);
                                indices.UVIndex = uvc;
                            }

                            vertsData.Add(v, indices);
                        }
                    }

                    if (vertsData.Count > 0)
                    {
                        if (vertexDataByTexture.ContainsKey(group.Key))
                        {
                            foreach (KeyValuePair <WorldVertex, VertexIndices> g in vertsData)
                            {
                                vertexDataByTexture[group.Key].Add(g.Key, g.Value);
                            }
                        }
                        else
                        {
                            vertexDataByTexture.Add(group.Key, vertsData);
                        }
                    }
                }
            }

            //write geometry
            //write vertices
            if (data.FixScale)
            {
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, -group.Key.x * data.Scale, group.Key.y * data.Scale, group.Key.z * data.Scale * 1.2f));
                }
            }
            else
            {
                foreach (KeyValuePair <Vector3D, int> group in uniqueVerts)
                {
                    obj.Append(string.Format(CultureInfo.InvariantCulture, "v " + vertexFormatter, -group.Key.x * data.Scale, group.Key.y * data.Scale, group.Key.z * data.Scale));
                }
            }

            //write normals
            foreach (KeyValuePair <Vector3D, int> group in uniqueNormals)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vn " + vertexFormatter, group.Key.x, group.Key.y, group.Key.z));
            }

            //write UV coords
            foreach (KeyValuePair <PointF, int> group in uniqueUVs)
            {
                obj.Append(string.Format(CultureInfo.InvariantCulture, "vt {0} {1}\n", group.Key.X, -group.Key.Y));
            }

            //write material library
            obj.Append("mtllib ").Append(data.ObjName + ".mtl").Append("\n");

            //write materials and surface indices
            foreach (Dictionary <string, List <WorldVertex[]> > dictionary in geometryByTexture)
            {
                foreach (KeyValuePair <string, List <WorldVertex[]> > group in dictionary)
                {
                    //material
                    obj.Append("usemtl ").Append(group.Key).Append("\n");

                    foreach (WorldVertex[] verts in group.Value)
                    {
                        //surface indices
                        obj.Append("f");
                        foreach (WorldVertex v in verts)
                        {
                            VertexIndices vi = vertexDataByTexture[group.Key][v];
                            obj.Append(" " + vi.PositionIndex + "/" + vi.UVIndex + "/" + vi.NormalIndex);
                        }
                        obj.Append("\n");
                    }
                }
            }

            return(obj);
        }
 public TexturedVertexSet(Texture tex, PrimitiveType mode, IAttributedVertexBuffer buffer, VertexIndices indices, ISet <int> enabledAttribs = null, int depth = 0)
     : base(mode, buffer, indices, enabledAttribs, depth)
 {
     Texture = tex;
 }
Пример #14
0
 public void AddVertexSet(PrimitiveType mode, V[] vertices, ISet <int> enabledAttribs = null)
 {
     AddState(new VertexSet(mode, VBuffer, VertexIndices.FromRange(currentIndex, vertices.Length), enabledAttribs));
     AddVertices(vertices);
 }
Пример #15
0
        public void Import(string FilePath, string MtlPath)
        {
            if (File.Exists(MtlPath))
            {
                ParseMtlFile(MtlPath);
            }

            if (File.Exists(FilePath))
            {
                var Lines = File.ReadAllLines(FilePath);

                foreach (var line in Lines)
                {
                    var Trimmedline = line.TrimStart(new char[] { ' ', '\t' });

                    if (Trimmedline.StartsWith("vn"))
                    {
                        var tokens = Trimmedline.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

                        HasNormal = true;

                        if (tokens.Count() >= 4)
                        {
                            Vector3 VN = new Vector3();
                            VN.X = Convert.ToSingle(tokens[1]);
                            VN.Y = Convert.ToSingle(tokens[2]);
                            VN.Z = Convert.ToSingle(tokens[3]);

                            TempNormalList.Add(VN);
                        }
                    }
                    else if (Trimmedline.StartsWith("v "))
                    {
                        var tokens = Trimmedline.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

                        if (tokens.Count() == 4)
                        {
                            Vector3 V = new Vector3();
                            V.X = Convert.ToSingle(tokens[1]);
                            V.Y = Convert.ToSingle(tokens[2]);
                            V.Z = Convert.ToSingle(tokens[3]);

                            UpdateMinMaxVertex(ref V);

                            TempVertexList.Add(V);
                        }
                    }
                    else if (Trimmedline.StartsWith("vt"))
                    {
                        HasTexCoordinate = true;

                        var tokens = Trimmedline.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

                        if (tokens.Count() >= 3)
                        {
                            Vector2 V = new Vector2();
                            V.X = Convert.ToSingle(tokens[1]);
                            V.Y = Convert.ToSingle(tokens[2]);

                            TempTexCoordList.Add(V);
                        }
                    }
                    else if (Trimmedline.StartsWith("f "))
                    {
                        var tokens = Trimmedline.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

                        if (tokens.Count() == 4)
                        {
                            var Token1 = tokens[1].Split('/');
                            var Token2 = tokens[2].Split('/');
                            var Token3 = tokens[3].Split('/');

                            uint Index1 = Convert.ToUInt32(Token1[0]);
                            uint Index2 = Convert.ToUInt32(Token2[0]);
                            uint Index3 = Convert.ToUInt32(Token3[0]);

                            VertexIndexList.Add(Index1 - 1);
                            VertexIndexList.Add(Index2 - 1);
                            VertexIndexList.Add(Index3 - 1);

                            if (HasTexCoordinate)
                            {
                                uint TexIndex1 = Convert.ToUInt32(Token1[1]);
                                uint TexIndex2 = Convert.ToUInt32(Token2[1]);
                                uint TexIndex3 = Convert.ToUInt32(Token3[1]);

                                TexCoordIndexList.Add(TexIndex1 - 1);
                                TexCoordIndexList.Add(TexIndex2 - 1);
                                TexCoordIndexList.Add(TexIndex3 - 1);
                            }

                            if (HasNormal)
                            {
                                uint NormIndex1 = Convert.ToUInt32(Token1[2]);
                                uint NormIndex2 = Convert.ToUInt32(Token2[2]);
                                uint NormIndex3 = Convert.ToUInt32(Token3[2]);

                                NormalIndexList.Add(NormIndex1 - 1);
                                NormalIndexList.Add(NormIndex2 - 1);
                                NormalIndexList.Add(NormIndex3 - 1);
                            }

                            VertexIndices.Add((uint)VertexIndices.Count);
                            VertexIndices.Add((uint)VertexIndices.Count);
                            VertexIndices.Add((uint)VertexIndices.Count);
                        }
                    }
                    else if (Trimmedline.StartsWith("usemtl"))
                    {
                        var MtlLine = Trimmedline.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);

                        if (MtlLine.Count() == 2)
                        {
                            if (MeshSectionList.Count() == 0)
                            {
                                ObjMeshSection NewSection = new ObjMeshSection();
                                NewSection.StartIndex  = 0;
                                NewSection.SectionName = MtlLine[1];
                                MeshSectionList.Add(NewSection);
                            }
                            else
                            {
                                MeshSectionList.Last().EndIndex = (UInt32)VertexIndices.Count;

                                ObjMeshSection NewSection = new ObjMeshSection();
                                NewSection.SectionName = MtlLine[1];
                                NewSection.StartIndex  = (UInt32)VertexIndices.Count;
                                MeshSectionList.Add(NewSection);
                            }
                        }
                    }
                }

                if (MeshSectionList.Count > 0)
                {
                    MeshSectionList.Last().EndIndex = (UInt32)VertexIndices.Count;
                }
            }

            // update min,max,center
            MinVertex    = new Vector3(MinX, MinY, MinZ);
            MaxVertex    = new Vector3(MaxX, MaxY, MaxZ);
            CenterVertex = (MinVertex + MaxVertex) / 2;


            if (HasTexCoordinate)
            {
                GenerateTangents();
            }

            GenerateVertices();

            Clear();
        }