// sequential write of input mesh triangles. preserves triangle IDs up to constant shift.
        void write_triangles_flat(TextWriter writer, WriteMesh write_mesh, int[] mapV, DenseUVMesh uvSet, IIndexMap mapUV, bool bNormals, bool bMaterials)
        {
            bool bUVs = (mapUV != null);

            int cur_material = -1;

            IMesh mesh = write_mesh.Mesh;

            foreach (int ti in mesh.TriangleIndices())
            {
                if (bMaterials)
                {
                    set_current_material(writer, ti, write_mesh, ref cur_material);
                }

                Index3i t = mesh.GetTriangle(ti);
                t[0] = mapV[t[0]];
                t[1] = mapV[t[1]];
                t[2] = mapV[t[2]];

                if (bUVs)
                {
                    Index3i tuv = (uvSet != null) ? uvSet.TriangleUVs[ti] : t;
                    tuv[0] = mapUV[tuv[0]];
                    tuv[1] = mapUV[tuv[1]];
                    tuv[2] = mapUV[tuv[2]];
                    write_tri(writer, ref t, bNormals, true, ref tuv);
                }
                else
                {
                    write_tri(writer, ref t, bNormals, false, ref t);
                }
            }
        }
        // update material state if necessary
        public void set_current_material(TextWriter writer, int ti, WriteMesh mesh, ref int cur_material)
        {
            int mi = mesh.TriToMaterialMap[ti];

            if (mi != cur_material && mi >= 0 && mi < mesh.Materials.Count)
            {
                writer.WriteLine("usemtl " + mesh.Materials[mi].name);
                cur_material = mi;
            }
        }