예제 #1
0
        protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder)
        {
            if (RebuildStrategy == Strategy.AutoBestResult)
            {
                DMesh3 result = BuildMesh_Auto(solid);
                builder.AppendNewMesh(result);
            }
            else if (RebuildStrategy == Strategy.IdenticalVertexWeld)
            {
                DMesh3 result = BuildMesh_IdenticalWeld(solid);
                builder.AppendNewMesh(result);
            }
            else if (RebuildStrategy == Strategy.TolerantVertexWeld)
            {
                DMesh3 result = BuildMesh_TolerantWeld(solid, WeldTolerance);
                builder.AppendNewMesh(result);
            }
            else
            {
                BuildMesh_NoMerge(solid, builder);
            }

            if (WantPerTriAttribs && solid.TriAttribs != null && builder.SupportsMetaData)
            {
                builder.AppendMetaData(PerTriAttribMetadataName, solid.TriAttribs);
            }
        }
예제 #2
0
        public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(Model));
            Model         model;

            try {
                model = (Model)serializer.Deserialize(reader);
            } catch (Exception e) {
                return(new IOReadResult(IOCode.FileParsingError, $"XML parsing error: {e}"));
            }

            foreach (var @object in model.resources.objects)
            {
                var mesh   = @object.mesh;
                int meshId = builder.AppendNewMesh(false, false, false, true);
                var mapV   = new int[mesh.vertices.vertices.Length];
                for (int k = 0; k < mesh.vertices.vertices.Length; ++k)
                {
                    var vertex = mesh.vertices.vertices[k];
                    mapV[k] = builder.AppendVertex(vertex.x, vertex.y, vertex.z);
                }
                for (int j = 0; j < mesh.triangles.triangles.Length; ++j)
                {
                    var triangle = mesh.triangles.triangles[j];
                    builder.AppendTriangle(mapV[triangle.v1], mapV[triangle.v2], mapV[triangle.v3]);
                }
            }

            return(IOReadResult.Ok);
        }
예제 #3
0
        public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder)
        {
            XmlSerializer serializer = new XmlSerializer(typeof(AMF));
            AMF           amf;

            try {
                amf = (AMF)serializer.Deserialize(reader);
            } catch (Exception e) {
                return(new IOReadResult(IOCode.FileParsingError, $"XML parsing error: {e}"));
            }

            foreach (var @object in amf.objects)
            {
                foreach (var mesh in @object.meshes)
                {
                    int meshId = builder.AppendNewMesh(false, false, false, true);
                    var mapV   = new int[mesh.vertices.vertices.Length];
                    for (int k = 0; k < mesh.vertices.vertices.Length; ++k)
                    {
                        var coordinates = mesh.vertices.vertices[k].coordinates;
                        mapV[k] = builder.AppendVertex(coordinates.x, coordinates.y, coordinates.z);
                    }
                    for (int i = 0; i < mesh.volumes.Length; ++i)
                    {
                        for (int j = 0; j < mesh.volumes[i].triangles.Length; ++j)
                        {
                            var triangle = mesh.volumes[i].triangles[j];
                            builder.AppendTriangle(mapV[triangle.v1], mapV[triangle.v2], mapV[triangle.v3], i);
                        }
                    }
                }
            }

            return(IOReadResult.Ok);
        }
        public IOReadResult Read(BinaryReader reader, ReadOptions options, IMeshBuilder builder)
        {
            int nMeshes = reader.ReadInt32();

            for (int k = 0; k < nMeshes; ++k)
            {
                var m = new DMesh3();
                gSerialization.Restore(m, reader);
                builder.AppendNewMesh(m);
            }

            return(new IOReadResult(IOCode.Ok, ""));
        }
예제 #5
0
 protected virtual void BuildMesh(STLSolid solid, IMeshBuilder builder)
 {
     if (RebuildStrategy == Strategy.AutoBestResult)
     {
         DMesh3 result = BuildMesh_Auto(solid);
         builder.AppendNewMesh(result);
     }
     else if (RebuildStrategy == Strategy.IdenticalVertexWeld)
     {
         DMesh3 result = BuildMesh_IdenticalWeld(solid);
         builder.AppendNewMesh(result);
     }
     else if (RebuildStrategy == Strategy.TolerantVertexWeld)
     {
         DMesh3 result = BuildMesh_TolerantWeld(solid, WeldTolerance);
         builder.AppendNewMesh(result);
     }
     else
     {
         BuildMesh_NoMerge(solid, builder);
     }
 }
예제 #6
0
        unsafe IOReadResult BuildMeshes_Simple(ReadOptions options, IMeshBuilder builder)
        {
            if (vPositions.Length == 0)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "No vertices in file"));
            }
            if (vTriangles.Length == 0)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "No triangles in file"));
            }

            // [TODO] support non-per-vertex normals/colors
            bool bHaveNormals = (vNormals.Length == vPositions.Length);
            bool bHaveColors  = (vColors.Length == vPositions.Length);
            bool bHaveUVs     = (vUVs.Length / 2 == vPositions.Length / 3);

            int nVertices = vPositions.Length / 3;

            int[] mapV = new int[nVertices];

            int meshID = builder.AppendNewMesh(bHaveNormals, bHaveColors, bHaveUVs, false);

            for (int k = 0; k < nVertices; ++k)
            {
                vtx_key vk = new vtx_key()
                {
                    vi = k, ci = k, ni = k, ui = k
                };
                mapV[k] = append_vertex(builder, vk, bHaveNormals, bHaveColors, bHaveUVs);
            }

            // [TODO] this doesn't handle missing vertices...
            for (int k = 0; k < vTriangles.Length; ++k)
            {
                append_triangle(builder, k, mapV);
            }

            if (UsedMaterials.Count == 1)           // [RMS] should not be in here otherwise
            {
                int         material_id = UsedMaterials.Keys.First();
                string      sMatName    = UsedMaterials[material_id];
                OBJMaterial useMat      = Materials[sMatName];
                int         matID       = builder.BuildMaterial(useMat);
                builder.AssignMaterial(matID, meshID);
            }

            return(new IOReadResult(IOCode.Ok, ""));
        }
예제 #7
0
        protected virtual void BuildMesh_NoMerge(STLSolid solid, IMeshBuilder builder)
        {
            /*int meshID = */ builder.AppendNewMesh(false, false, false, false);

            DVectorArray3f vertices = solid.Vertices;
            int            nTris    = vertices.Count / 3;

            for (int ti = 0; ti < nTris; ++ti)
            {
                Vector3f va = vertices[3 * ti];
                int      a  = builder.AppendVertex(va.x, va.y, va.z);
                Vector3f vb = vertices[3 * ti + 1];
                int      b  = builder.AppendVertex(vb.x, vb.y, vb.z);
                Vector3f vc = vertices[3 * ti + 2];
                int      c  = builder.AppendVertex(vc.x, vc.y, vc.z);

                builder.AppendTriangle(a, b, c);
            }
        }
예제 #8
0
        protected virtual void BuildMesh_IdenticalWeld(STLSolid solid, IMeshBuilder builder)
        {
            /*int meshID = */ builder.AppendNewMesh(false, false, false, false);

            DVectorArray3f vertices = solid.Vertices;
            int            N        = vertices.Count;

            int[] mapV = new int[N];

            Dictionary <Vector3f, int> uniqueV = new Dictionary <Vector3f, int>();

            for (int vi = 0; vi < N; ++vi)
            {
                Vector3f v = vertices[vi];
                int      existing_idx;
                if (uniqueV.TryGetValue(v, out existing_idx))
                {
                    mapV[vi] = existing_idx;
                }
                else
                {
                    int vid = builder.AppendVertex(v.x, v.y, v.z);
                    uniqueV[v] = vid;
                    mapV[vi]   = vid;
                }
            }


            int nTris = N / 3;

            for (int ti = 0; ti < nTris; ++ti)
            {
                int a = mapV[3 * ti];
                int b = mapV[3 * ti + 1];
                int c = mapV[3 * ti + 2];
                if (a == b || a == c || b == c)     // don't try to add degenerate triangles
                {
                    continue;
                }
                builder.AppendTriangle(a, b, c);
            }
        }
예제 #9
0
        public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder)
        {
            // format is:
            //
            // OFF
            // VCOUNT TCOUNT     (2 ints)
            // x y z
            // ...
            // 3 va vb vc
            // ...
            //

            string first_line = reader.ReadLine();

            if (first_line.StartsWith("OFF") == false)
            {
                return(new IOReadResult(IOCode.FileParsingError, "ascii OFF file must start with OFF header"));
            }

            int nVertexCount   = 0;
            int nTriangleCount = 0;

            int nLines = 0;

            while (reader.Peek() >= 0)
            {
                string line = reader.ReadLine();
                nLines++;
                string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                if (tokens.Length == 0)
                {
                    continue;
                }

                if (tokens[0].StartsWith("#"))
                {
                    continue;
                }

                if (tokens.Length != 3)
                {
                    return(new IOReadResult(IOCode.FileParsingError, "first non-comment line of OFF must be vertex/tri/edge counts, found: " + line));
                }
                nVertexCount   = int.Parse(tokens[0]);
                nTriangleCount = int.Parse(tokens[1]);
                //int nEdgeCount = int.Parse(tokens[2]);
                break;
            }


            builder.AppendNewMesh(false, false, false, false);

            int vi = 0;

            while (vi < nVertexCount && reader.Peek() > 0)
            {
                string line = reader.ReadLine();
                nLines++;
                string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                if (tokens.Length == 0)
                {
                    continue;
                }

                if (tokens[0].StartsWith("#"))
                {
                    continue;
                }

                if (tokens.Length != 3)
                {
                    emit_warning("found invalid OFF vertex line: " + line);
                }

                double x = Double.Parse(tokens[0]);
                double y = Double.Parse(tokens[1]);
                double z = Double.Parse(tokens[2]);
                builder.AppendVertex(x, y, z);
                vi++;
            }
            if (vi < nVertexCount)
            {
                return(new IOReadResult(IOCode.FileParsingError,
                                        string.Format("File specified {0} vertices but only found {1}", nVertexCount, vi)));
            }


            int ti = 0;

            while (ti < nTriangleCount && reader.Peek() > 0)
            {
                string line = reader.ReadLine();
                nLines++;
                string[] tokens = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
                if (tokens.Length == 0)
                {
                    continue;
                }

                if (tokens[0].StartsWith("#"))
                {
                    continue;
                }

                if (tokens.Length < 4)
                {
                    emit_warning("found invalid OFF triangle line: " + line);
                }

                int nV = int.Parse(tokens[0]);
                if (nV != 3)
                {
                    emit_warning("found non-triangle polygon in OFF, currently unsupported: " + line);
                }

                int a = int.Parse(tokens[1]);
                int b = int.Parse(tokens[2]);
                int c = int.Parse(tokens[3]);

                builder.AppendTriangle(a, b, c);
                ti++;
            }
            if (ti < nTriangleCount)
            {
                emit_warning(string.Format("File specified {0} triangles but only found {1}", nTriangleCount, ti));
            }

            return(new IOReadResult(IOCode.Ok, ""));
        }
예제 #10
0
        IOReadResult BuildMeshes_ByMaterial(ReadOptions options, IMeshBuilder builder)
        {
            if (vPositions.Length == 0)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "No vertices in file"));
            }

            if (vTriangles.Length == 0)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "No triangles in file"));
            }

            bool bHaveNormals = (vNormals.Length > 0);
            bool bHaveColors  = (vColors.Length > 0);
            bool bHaveUVs     = (vUVs.Length > 0);

            var usedMaterialIDs = new List <int>(UsedMaterials.Keys);

            usedMaterialIDs.Add(Triangle.InvalidMaterialID);
            foreach (int material_id in usedMaterialIDs)
            {
                int matID = Triangle.InvalidMaterialID;
                if (material_id != Triangle.InvalidMaterialID)
                {
                    string      sMatName = UsedMaterials[material_id];
                    OBJMaterial useMat   = Materials[sMatName];
                    matID = builder.BuildMaterial(useMat);
                }
                bool bMatHaveUVs = (material_id == Triangle.InvalidMaterialID) ? false : bHaveUVs;

                // don't append mesh until we actually see triangles
                int meshID = -1;

                var mapV = new Dictionary <Index3i, int>();

                for (int k = 0; k < vTriangles.Length; ++k)
                {
                    Triangle t = vTriangles[k];
                    if (t.nMaterialID == material_id)
                    {
                        if (meshID == -1)
                        {
                            meshID = builder.AppendNewMesh(bHaveNormals, bHaveColors, bMatHaveUVs, false);
                        }

                        var t2 = new Triangle();
                        for (int j = 0; j < 3; ++j)
                        {
                            var vk = new Index3i(
                                t.vIndices[j] - 1, t.vNormals[j] - 1, t.vUVs[j] - 1);

                            int use_vtx = -1;
                            if (mapV.ContainsKey(vk) == false)
                            {
                                use_vtx  = append_vertex(builder, vk, bHaveNormals, bHaveColors, bMatHaveUVs);
                                mapV[vk] = use_vtx;
                            }
                            else
                            {
                                use_vtx = mapV[vk];
                            }

                            t2.vIndices[j] = use_vtx;
                        }
                        append_triangle(builder, t2);
                    }
                }

                if (matID != Triangle.InvalidMaterialID)
                {
                    builder.AssignMaterial(matID, meshID);
                }
            }

            return(new IOReadResult(IOCode.Ok, ""));
        }
예제 #11
0
        private bool hasMesh; // used to show that at least one mesh has been found

        public IOReadResult Read(TextReader reader, ReadOptions options, IMeshBuilder builder)
        {
            string[]       chunks;
            List <element> elements = new List <element>(); // we will decant the element specifications into here
            string         proj     = "";
            string         line;
            bool           binary = false;

            // check for the magic number which in  a PLY file is "ply"
            if (!reader.ReadLine().Contains("ply"))
            {
                return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - Magic number failure"));
            }

            // Read header

            line = reader.ReadLine();
            if (line == null)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt"));
            }

            /*
             * The header is a format defintion and a series of element definitions and/or comment lines
             * cycle through these until end-header
             */
            do
            {
                /*
                 * iterate through all of the element blocks in the header and enumerate the number of members and the properties
                 */
                if (line.StartsWith("element"))
                {
                    chunks = line.Split(' ');
                    if ((chunks.Length != 3))
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt"));
                    }
                    element element = new element();
                    element.properties = new List <string>();
                    element.types      = new List <string>();
                    element.list       = new List <bool>();
                    element.name       = chunks[1];
                    element.size       = ParseInt(chunks[2]);
                    do
                    {
                        line = reader.ReadLine();
                        if (line == null)
                        {
                            return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt"));
                        }
                        if (line.StartsWith("property"))
                        {
                            chunks = line.Split(' ');
                            switch (chunks.Length)
                            {
                            case 3:
                                element.properties.Add(chunks[2].ToLower());
                                element.types.Add(chunks[1].ToLower());
                                element.list.Add(false);
                                break;

                            case 5:
                                element.properties.Add(chunks[4].ToLower());
                                element.types.Add(chunks[3].ToLower());
                                element.list.Add(true);
                                break;

                            default:
                                return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - invalid element line" + line));
                            }
                        }
                        else
                        {
                            break;
                        }
                    }while (true);
                    elements.Add(element);
                }

                // if end - stop looping
                else if (line.StartsWith("end_header"))
                {
                    break;
                }

                //if binary - give up

                else if (line.StartsWith("binary"))
                {
                    binary = true;
                }

                // if "comment crs" assume that the rest is the crs data
                else if (line.StartsWith("comment crs "))
                {
                    line.Remove(12);
                    proj = line;
                    line = reader.ReadLine();
                    if (line == null)
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt"));
                    }
                }

                // probably a comment line
                else
                {
                    line = reader.ReadLine();
                    if (line == null)
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt"));
                    }
                }
            }while (true);

            //
            // create new DMesh
            //

            bool bHasColors  = false;
            bool bHasNormals = false;
            bool bHasUVs     = false;

            for (int elid = 0; elid < elements.Count; ++elid)
            {
                element el = elements[elid];
                if (el.name == "vertex")
                {
                    if (
                        (!el.properties.Contains("x")) ||
                        (!el.properties.Contains("y")) ||
                        (!el.properties.Contains("z"))
                        )
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Verteces do not have XYZ"));
                    }
                    if (
                        el.properties.Contains("red") &&
                        el.properties.Contains("blue") &&
                        el.properties.Contains("green")
                        )
                    {
                        bHasColors = true;
                    }
                    if (
                        el.properties.Contains("nx") &&
                        el.properties.Contains("ny") &&
                        el.properties.Contains("nz")
                        )
                    {
                        bHasNormals = true;
                    }
                    if (
                        el.properties.Contains("u") &&
                        el.properties.Contains("v")
                        )
                    {
                        bHasUVs = true;
                    }
                }
                if (el.name == "faces")
                {
                    if (!el.properties.Contains("vertex_indices"))
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Faces do not have vertex indices"));
                    }
                }
                if (el.name == "edges")
                {
                    if (
                        (!el.properties.Contains("vertex1")) ||
                        (!el.properties.Contains("vertex2"))
                        )
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Edges do not have vertex indices"));
                    }
                }
            }

            int mesh_idx = builder.AppendNewMesh(bHasNormals, bHasColors, bHasUVs, false);

            /*
             * load the elements in order
             */
            line = reader.ReadLine();
            if (line == null)
            {
                return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - header is corrupt"));
            }
            chunks = line.Split(' ');

            for (int elid = 0; elid < elements.Count; ++elid)
            {
                element el = elements[elid];

                // load the data
                for (int i = 0; i < el.size; ++i)
                {
                    /*
                     * set the line size - we will only deal with one list at the begining of the line
                     */
                    int nChunks = el.properties.Count;
                    if (el.list[0])
                    {
                        nChunks += ParseInt(chunks[0]);
                    }
                    if (chunks.Length != nChunks)
                    {
                        return(new IOReadResult(IOCode.GarbageDataError, "Not a valid PLY file - contains invalid line : " + line));
                    }

                    /*
                     * Load the vertexes
                     */
                    if (el.name == "vertex")
                    {
                        Vector3d vertex = new Vector3d();
                        Vector3f normal = new Vector3f();
                        Vector3f color  = new Vector3f();
                        Vector2f uvs    = new Vector2f();
                        vertex.x = ParseValue(chunks[el.properties.FindIndex(item => item == "x")]);
                        vertex.y = ParseValue(chunks[el.properties.FindIndex(item => item == "y")]);
                        vertex.z = ParseValue(chunks[el.properties.FindIndex(item => item == "z")]);

                        if (bHasNormals)
                        {
                            normal.x = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "nx")]);
                            normal.y = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "ny")]);
                            normal.z = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "nz")]);
                        }

                        if (bHasColors)
                        {
                            color.x = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "red")]);
                            color.y = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "blue")]);
                            color.z = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "green")]);
                        }

                        if (bHasUVs)
                        {
                            uvs.x = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "u")]);
                            uvs.y = (float)ParseValue(chunks[el.properties.FindIndex(item => item == "v")]);
                        }

                        append_vertex(builder, vertex, normal, color, uvs, bHasNormals, bHasColors, bHasUVs);
                    }

                    /*
                     * load the faces
                     */
                    else if (el.name == "face")
                    {
                        int faceSize = ParseInt(chunks[0]);
                        if (faceSize != 3)
                        {
                            emit_warning("[PLYReader] cann only read triangles");
                            return(new IOReadResult(IOCode.FormatNotSupportedError, "Can only read tri faces"));
                        }
                        Index3i tri = new Index3i();
                        tri.a = ParseInt(chunks[1]);
                        tri.b = ParseInt(chunks[2]);
                        tri.c = ParseInt(chunks[3]);

                        append_triangle(builder, tri);
                    }

                    // any other element ignore and move to the next line

                    line = reader.ReadLine();
                    if (line == null)
                    {
                        // if it is supposed to be the last line - don't look further
                        if (elid != (elements.Count - 1) && i != (el.size - 1))
                        {
                            return(new IOReadResult(IOCode.GarbageDataError, " does not contain enough definitions of type " + el.name));
                        }
                    }
                    chunks = line?.Split(' ');
                }
            }

            return(new IOReadResult(IOCode.Ok, ""));
        }
예제 #12
0
        private bool is3ds;      // usd to shwo that the 4D4D magic number has been found


        public IOReadResult Read(BinaryReader reader, ReadOptions options, IMeshBuilder builder)
        {
            ushort ChunkID;
            String ChnkID = "";
            UInt32 Clength;

            MeshName = "";
            hasMesh  = false;
            is3ds    = false;

            // Process the file - fails very politely when there is no more data
            while (true)
            {
                //Get the Id of the next Chunk
                try {
                    ChunkID = reader.ReadUInt16();
                } catch {
                    break;
                }
                ChnkID = ChunkID.ToString("X");

                //Get the size of the next chunk in chars
                Clength = reader.ReadUInt32();

                //Process based on Chunk ID
                switch (ChnkID)
                {
                case "4D4D":
                    //This is a new file header
                    is3ds = true;
                    reader.ReadChars(10);
                    break;

                case "3D3D":
                    //This is a new Object Header
                    reader.ReadChars(10);
                    break;

                case "4000":
                    //This is an object Block. Store the name temporarily in case it is a mesh
                    List <char> name = new List <char>();
                    while (true)
                    {
                        char next = reader.ReadChar();
                        if (next == 0)
                        {
                            break;
                        }
                        name.Add(next);
                    }
                    MeshName = new String(name.ToArray <char>());
                    break;

                case "4100":
                    // This is a new Mesh. Retrieve the name and add if the builder supports Metadata
                    builder.AppendNewMesh(false, false, false, false);
                    if (builder.SupportsMetaData)
                    {
                        builder.AppendMetaData("name", MeshName);
                    }
                    break;

                case "4110":
                    // List of Vertexes
                    ushort VertexCount = reader.ReadUInt16();
                    for (int x = 0; x < VertexCount; x++)
                    {
                        double X = reader.ReadSingle();
                        double Y = reader.ReadSingle();
                        double Z = reader.ReadSingle();
                        builder.AppendVertex(X, Y, Z);
                    }
                    break;

                case "4120":
                    // List of Triangles
                    ushort PolygonCount = reader.ReadUInt16();
                    for (int j = 0; j < PolygonCount; j++)
                    {
                        int a     = reader.ReadInt16();
                        int b     = reader.ReadInt16();
                        int c     = reader.ReadInt16();
                        int flags = reader.ReadUInt16();
                        builder.AppendTriangle(a, b, c);
                    }
                    break;

                case "4130":
                    // Mapping from Vertex to Material - retrieved but not currently used
                    List <char> mname = new List <char>();
                    while (true)
                    {
                        char next = reader.ReadChar();
                        if (next == 0)
                        {
                            break;
                        }
                        mname.Add(next);
                    }
                    string MatName = new String(mname.ToArray <char>());
                    ushort entries = reader.ReadUInt16();
                    for (int i = 0; i < entries; i++)
                    {
                        ushort face = reader.ReadUInt16();
                    }
                    break;

                case "4140":
                    // List of UVs per vertex
                    ushort uvCount = reader.ReadUInt16();
                    for (ushort y = 0; y < uvCount; y++)
                    {
                        Vector2f UV = new Vector2f(reader.ReadSingle(), reader.ReadSingle());
                        builder.SetVertexUV(y, UV);
                    }
                    break;

                default:
                    // Any other chunk - retrieved and not used - held in dump temporarily for debug
                    char[] dump = reader.ReadChars((int)Clength - 6);
                    break;
                }
            }
            if (!is3ds)
            {
                return(new IOReadResult(IOCode.FileAccessError, "File is not in .3DS format"));
            }
            else if (!hasMesh)
            {
                return(new IOReadResult(IOCode.FileParsingError, "no mesh found in file"));
            }
            else
            {
                return(new IOReadResult(IOCode.Ok, ""));
            }
        }