OSDN Git Service

reformat
[tdcgexplorer/tso2mqo.git] / MqoWriter.cs
index 58ab3b5..e39a9cb 100644 (file)
-using System;\r
-using System.Collections.Generic;\r
-using System.IO;\r
-using System.Text;\r
-\r
-namespace Tso2MqoGui\r
-{\r
-    public enum MqoBoneMode\r
-    {\r
-        None,\r
-        RokDeBone,\r
-        Mikoto,\r
-    }\r
-\r
-    public class Pair<T, U>\r
-    {\r
-        public T    First;\r
-        public U    Second;\r
-\r
-        public Pair()\r
-        {\r
-        }\r
-\r
-        public Pair(T first, U second)\r
-        {\r
-            First   = first;\r
-            Second  = second;\r
-        }\r
-    }\r
-\r
-    public class MqoWriter : IDisposable\r
-    {\r
-        public TextWriter   tw;\r
-        public string       OutPath;\r
-        public string       OutFile;\r
-        public MqoBoneMode  BoneMode    = MqoBoneMode.None;\r
-\r
-        public MqoWriter(string file)\r
-        {\r
-            FileStream  fs  = File.OpenWrite(file);\r
-            fs.SetLength(0);\r
-            tw              = new StreamWriter(fs, Encoding.Default);\r
-            OutFile         = file;\r
-            OutPath         = Path.GetDirectoryName(file);\r
-        }\r
-\r
-        void IDisposable.Dispose()\r
-        {\r
-            Close();\r
-        }\r
-\r
-        public void Close()\r
-        {\r
-            if(tw != null)\r
-                tw.Close();\r
-            tw  = null;\r
-        }\r
-\r
-        public void CreateTextureFile(TSOTex tex)\r
-        {\r
-            string  file= Path.Combine(OutPath, Path.GetFileName(tex.file.Trim('"')));\r
-            byte[]  data= tex.data;\r
-\r
-            using(FileStream fs= File.OpenWrite(file))\r
-            {\r
-                BinaryWriter    bw  = new BinaryWriter(fs);\r
-\r
-                switch(Path.GetExtension(file).ToUpper())\r
-                {\r
-                case ".TGA":\r
-                    bw.Write((byte)0);              // id\r
-                    bw.Write((byte)0);              // colormap\r
-                    bw.Write((byte)2);              // imagetype\r
-                    bw.Write((byte)0);              // unknown0\r
-                    bw.Write((byte)0);              // unknown1\r
-                    bw.Write((byte)0);              // unknown2\r
-                    bw.Write((byte)0);              // unknown3\r
-                    bw.Write((byte)0);              // unknown4\r
-                    bw.Write((short)0);             // width\r
-                    bw.Write((short)0);             // height\r
-                    bw.Write((short)tex.Width);     // width\r
-                    bw.Write((short)tex.Height);    // height\r
-                    bw.Write((byte)(tex.depth * 8));// depth\r
-                    bw.Write((byte)0);              // depth\r
-                    break;\r
-\r
-                case ".BMP":\r
-                    bw.Write((byte)'B');\r
-                    bw.Write((byte)'M');\r
-                    bw.Write((int)(54 + data.Length));\r
-                    bw.Write((int)0);\r
-                    bw.Write((int)54);\r
-                    bw.Write((int)40);\r
-                    bw.Write((int)tex.Width);\r
-                    bw.Write((int)tex.Height);\r
-                    bw.Write((short)1);\r
-                    bw.Write((short)(tex.Depth*8));\r
-                    bw.Write((int)0);\r
-                    bw.Write((int)data.Length);\r
-                    bw.Write((int)0);\r
-                    bw.Write((int)0);\r
-                    bw.Write((int)0);\r
-                    bw.Write((int)0);\r
-                    break;\r
-                }\r
-\r
-                bw.Write(data, 0, data.Length);\r
-                bw.Flush();\r
-            }\r
-        }\r
-\r
-        public void Write(TSOFile file)\r
-        {\r
-            tw.WriteLine("Metasequoia Document");\r
-            tw.WriteLine("Format Text Ver 1.0");\r
-            tw.WriteLine("");\r
-            tw.WriteLine("Scene {");\r
-            tw.WriteLine("     pos -7.0446 4.1793 1541.1764");\r
-            tw.WriteLine("     lookat 11.8726 193.8590 0.4676");\r
-            tw.WriteLine("     head 0.8564");\r
-            tw.WriteLine("     pich 0.1708");\r
-            tw.WriteLine("     ortho 0");\r
-            tw.WriteLine("     zoom2 31.8925");\r
-            tw.WriteLine("     amb 0.250 0.250 0.250");\r
-            tw.WriteLine("}");\r
-\r
-          //VertexHeap<UVertex> vh  = new VertexHeap<UVertex>();\r
-            VertexHeap          vh  = new VertexHeap();\r
-            List<ushort>        face= new List<ushort>(2048*3);\r
-            List<float>         uv  = new List<float>(2048*3 * 2);\r
-            List<int>           mtl = new List<int>(2048);\r
-\r
-            foreach(TSOTex i in file.textures)\r
-                CreateTextureFile(i);\r
-\r
-            tw.WriteLine("Material {0} {{", file.materials.Length);\r
-\r
-            foreach(TSOMaterial i in file.materials)\r
-            {\r
-                if(i.ColorTex != null)\r
-                {\r
-                    TSOTex  tex = file.texturemap[i.ColorTex];\r
-                    tw.WriteLine(\r
-                        "      \"{0}\" col(1.000 1.000 1.000 1.000) dif(0.800) amb(0.600) emi(0.000) spc(0.000) power(5.00) tex(\"{1}\")",\r
-                        i.name, Path.Combine(OutPath, tex.File.Trim('"')));\r
-                } else\r
-                {\r
-                    tw.WriteLine(\r
-                        "      \"{0}\" col(1.000 1.000 1.000 1.000) dif(0.800) amb(0.600) emi(0.000) spc(0.000) power(5.00))",\r
-                        i.name);\r
-                }\r
-            }\r
-\r
-            tw.WriteLine("}");\r
-\r
-            foreach(TSOMesh i in file.meshes)\r
-            {\r
-                vh.Clear();\r
-                face.Clear();\r
-                uv.Clear();\r
-                mtl.Clear();\r
-\r
-                foreach(TSOSubMesh j in i.sub)\r
-                {\r
-                    int     cnt = 0;\r
-                    ushort  a= 0, b= 0, c= 0;\r
-                    Vertex  va= new Vertex(), vb= new Vertex(), vc= new Vertex();\r
-\r
-                    foreach(Vertex k in j.vertices)\r
-                    {\r
-                        ++cnt;\r
-                        va= vb; a= b;\r
-                        vb= vc; b= c;\r
-                        vc= k;  c= vh.Add(new UVertex(k.Pos.x, k.Pos.y, k.Pos.z, k.Nrm.x, k.Nrm.y, k.Nrm.z, k.Tex.x, k.Tex.y, j.spec));\r
-\r
-                        if(cnt < 3)                     continue;\r
-                        if(a == b || b == c || c == a)  continue;\r
-\r
-                        if((cnt & 1) == 0)\r
-                        {\r
-                            face.Add(a); uv.Add(va.Tex.x); uv.Add(1-va.Tex.y);\r
-                            face.Add(b); uv.Add(vb.Tex.x); uv.Add(1-vb.Tex.y);\r
-                            face.Add(c); uv.Add(vc.Tex.x); uv.Add(1-vc.Tex.y);\r
-                            mtl.Add(j.spec);\r
-                        } else\r
-                        {\r
-                            face.Add(a); uv.Add(va.Tex.x); uv.Add(1-va.Tex.y);\r
-                            face.Add(c); uv.Add(vc.Tex.x); uv.Add(1-vc.Tex.y);\r
-                            face.Add(b); uv.Add(vb.Tex.x); uv.Add(1-vb.Tex.y);\r
-                            mtl.Add(j.spec);\r
-                        }\r
-                    }\r
-                }\r
-\r
-                tw.WriteLine("Object \"{0}\" {{", i.Name);\r
-                tw.WriteLine(" visible {0}", 15);\r
-                tw.WriteLine(" locking {0}", 0);\r
-                tw.WriteLine(" shading {0}", 1);\r
-                tw.WriteLine(" facet {0}", 59.5);\r
-                tw.WriteLine(" color {0:F3} {1:F3} {2:F3}", 0.898f, 0.498f, 0.698f);\r
-                tw.WriteLine(" color_type {0}", 0);\r
-\r
-                //\r
-                tw.WriteLine(" vertex {0} {{", vh.Count);\r
-\r
-                foreach(UVertex j in vh.verts)\r
-                    WriteVertex(j.x, j.y, j.z);\r
-\r
-                tw.WriteLine(" }");\r
-\r
-                //\r
-                tw.WriteLine(" face {0} {{", face.Count);\r
-\r
-                System.Diagnostics.Debug.Assert(face.Count*2 == uv.Count);\r
-                System.Diagnostics.Debug.Assert(face.Count == mtl.Count * 3);\r
-\r
-                for(int j= 0, n= face.Count; j < n; j+=3)\r
-                    WriteFace(face[j+0], face[j+1], face[j+2],\r
-                              uv[j*2+0], uv[j*2+1],\r
-                              uv[j*2+2], uv[j*2+3],\r
-                              uv[j*2+4], uv[j*2+5],\r
-                              mtl[j/3]);\r
-                tw.WriteLine(" }");\r
-                tw.WriteLine("}");\r
-            }\r
-\r
-            // ボーンを出す\r
-            switch(BoneMode)\r
-            {\r
-            case MqoBoneMode.None:      break;\r
-            case MqoBoneMode.RokDeBone:\r
-                {\r
-                // マトリクス計算\r
-                foreach(TSONode i in file.nodes)\r
-                {\r
-                    if(i.parent == null)\r
-                            i.world = i.Matrix;\r
-                    else    i.world = Matrix44.Mul(i.Matrix, i.parent.World);\r
-                }\r
-                \r
-                List<Point3>                points  = new List<Point3>();\r
-                List<int>                   bones   = new List<int>();\r
-\r
-                tw.WriteLine("Object \"{0}\" {{", "Bone");\r
-                tw.WriteLine(" visible {0}", 15);\r
-                tw.WriteLine(" locking {0}", 0);\r
-                tw.WriteLine(" shading {0}", 1);\r
-                tw.WriteLine(" facet {0}", 59.5);\r
-                tw.WriteLine(" color {0} {1} {2}", 1, 0, 0);\r
-                tw.WriteLine(" color_type {0}", 0);\r
-\r
-                foreach(TSONode i in file.nodes)\r
-                {\r
-                    if(i.children.Count == 0)\r
-                        continue;\r
-\r
-                    Point3  q   = new Point3(i.world.M41, i.world.M42, i.world.M43);\r
-                    Point3  p   = new Point3();\r
-                    \r
-                    foreach(TSONode j in i.children)\r
-                    {\r
-                        p.x     +=j.world.M41;\r
-                        p.y     +=j.world.M42;\r
-                        p.z     +=j.world.M43;\r
-                    }\r
-\r
-                    p.x         /=i.children.Count;\r
-                    p.y         /=i.children.Count;\r
-                    p.z         /=i.children.Count;\r
-\r
-                    bones.Add(points.Count); points.Add(q);\r
-                    bones.Add(points.Count); points.Add(p);\r
-                }\r
-\r
-                tw.WriteLine(" vertex {0} {{", points.Count);\r
-\r
-                foreach(Point3 j in points)\r
-                    WriteVertex(j.x, j.y, j.z);\r
-\r
-                tw.WriteLine(" }");\r
-\r
-                //\r
-                tw.WriteLine(" face {0} {{", bones.Count / 2);\r
-\r
-                for(int j= 0, n= bones.Count; j < n; j+=2)\r
-                    tw.WriteLine(string.Format("               2 V({0} {1})", bones[j+0], bones[j+1]));\r
-\r
-                tw.WriteLine(" }");\r
-                tw.WriteLine("}");\r
-                }\r
-                break;\r
-\r
-            case MqoBoneMode.Mikoto:\r
-                {\r
-                }\r
-                break;\r
-            }\r
-\r
-            tw.WriteLine("Eof");\r
-        }\r
-\r
-        public void WriteFace(int a, int b, int c, float u1, float v1, float u2, float v2, float u3, float v3, int m)\r
-        {\r
-            tw.WriteLine("             {0} V({1} {2} {3}) M({10}) UV({4:F5} {5:F5} {6:F5} {7:F5} {8:F5} {9:F5})",\r
-                3, a, b, c, u1, v1, u2, v2, u3, v3, m);\r
-        }\r
-\r
-        public void WriteVertex(float x, float y, float z)\r
-        {\r
-            tw.WriteLine("             {0:F4} {1:F4} {2:F4}", x, y, z);\r
-        }\r
-    }\r
-\r
-    public class UVertex : IComparable<UVertex>\r
-    {\r
-        public float    x, y, z, nx, ny, nz, u, v;\r
-        public int      mtl;\r
-        \r
-        public UVertex()\r
-        {\r
-        }\r
-\r
-        public UVertex(float x, float y, float z, float nx, float ny, float nz, float u, float v, int mtl)\r
-        {\r
-            this.x  = x;\r
-            this.y  = y;\r
-            this.z  = z;\r
-            this.nx = nx;\r
-            this.ny = ny;\r
-            this.nz = nz;\r
-            this.u  = u;\r
-            this.v  = v;\r
-            this.mtl= mtl;\r
-        }\r
-\r
-        public int CompareTo(UVertex o)\r
-        {\r
-            if(x   < o.x)   return -1; if(x   > o.x)   return 1;\r
-            if(y   < o.y)   return -1; if(y   > o.y)   return 1;\r
-            if(z   < o.z)   return -1; if(z   > o.z)   return 1;\r
-            if(nx  < o.nx)  return -1; if(nx  > o.nx)  return 1;\r
-            if(ny  < o.ny)  return -1; if(ny  > o.ny)  return 1;\r
-            if(nz  < o.nz)  return -1; if(nz  > o.nz)  return 1;\r
-            if(u   < o.u)   return -1; if(u   > o.u)   return 1;\r
-            if(v   < o.v)   return -1; if(v   > o.v)   return 1;\r
-            return mtl - o.mtl;\r
-        }\r
-\r
-        public override int GetHashCode()\r
-        {\r
-            return x .GetHashCode() ^ y .GetHashCode() ^ z .GetHashCode()\r
-                 ^ nx.GetHashCode() ^ ny.GetHashCode() ^ nz.GetHashCode()\r
-               //^ u .GetHashCode() ^ v .GetHashCode()\r
-               //^ mtl.GetHashCode()\r
-                 ;\r
-        }\r
-\r
-        public override bool Equals(object obj)\r
-        {\r
-            UVertex o   = obj as UVertex;\r
-\r
-            if(o == null)\r
-                return false;\r
-\r
-            return x  == o.x  && y  == o.y  && y  == o.y\r
-                && nx == o.nx && ny == o.ny && ny == o.ny\r
-              //&& u  == o.u  && v  == o.y\r
-              //&& mtl == o.mtl\r
-                ;\r
-        }\r
-    }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Tso2MqoGui
+{
+    public enum MqoBoneMode
+    {
+        None,
+        RokDeBone,
+        Mikoto,
+    }
+
+    public class Pair<T, U>
+    {
+        public T First;
+        public U Second;
+
+        public Pair()
+        {
+        }
+
+        public Pair(T first, U second)
+        {
+            First = first;
+            Second = second;
+        }
+    }
+
+    public class MqoWriter : IDisposable
+    {
+        public TextWriter tw;
+        public string OutPath;
+        public string OutFile;
+        public MqoBoneMode BoneMode = MqoBoneMode.None;
+
+        public MqoWriter(string file)
+        {
+            FileStream fs = File.OpenWrite(file);
+            fs.SetLength(0);
+            tw = new StreamWriter(fs, Encoding.Default);
+            OutFile = file;
+            OutPath = Path.GetDirectoryName(file);
+        }
+
+        void IDisposable.Dispose()
+        {
+            Close();
+        }
+
+        public void Close()
+        {
+            if (tw != null)
+                tw.Close();
+            tw = null;
+        }
+
+        string GetTextureFileName(TSOTex tex)
+        {
+            string filename = Path.GetFileName(tex.File.Trim('"'));
+            if (filename == "")
+                filename = "none";
+            return filename;
+        }
+
+        string GetTexturePath(TSOTex tex)
+        {
+            return Path.Combine(OutPath, GetTextureFileName(tex));
+        }
+
+        public void CreateTextureFile(TSOTex tex)
+        {
+            string file = GetTexturePath(tex);
+            byte[] data = tex.data;
+
+
+            using (FileStream fs = File.OpenWrite(file))
+            {
+                BinaryWriter bw = new BinaryWriter(fs);
+
+                switch (Path.GetExtension(file).ToUpper())
+                {
+                    case ".TGA":
+                        bw.Write((byte)0);              // id
+                        bw.Write((byte)0);              // colormap
+                        bw.Write((byte)2);              // imagetype
+                        bw.Write((byte)0);              // unknown0
+                        bw.Write((byte)0);              // unknown1
+                        bw.Write((byte)0);              // unknown2
+                        bw.Write((byte)0);              // unknown3
+                        bw.Write((byte)0);              // unknown4
+                        bw.Write((short)0);             // width
+                        bw.Write((short)0);             // height
+                        bw.Write((short)tex.Width);     // width
+                        bw.Write((short)tex.Height);    // height
+                        bw.Write((byte)(tex.depth * 8));// depth
+                        bw.Write((byte)0);              // depth
+                        break;
+
+                    case ".BMP":
+                        bw.Write((byte)'B');
+                        bw.Write((byte)'M');
+                        bw.Write((int)(54 + data.Length));
+                        bw.Write((int)0);
+                        bw.Write((int)54);
+                        bw.Write((int)40);
+                        bw.Write((int)tex.Width);
+                        bw.Write((int)tex.Height);
+                        bw.Write((short)1);
+                        bw.Write((short)(tex.Depth * 8));
+                        bw.Write((int)0);
+                        bw.Write((int)data.Length);
+                        bw.Write((int)0);
+                        bw.Write((int)0);
+                        bw.Write((int)0);
+                        bw.Write((int)0);
+                        break;
+                }
+
+                bw.Write(data, 0, data.Length);
+                bw.Flush();
+            }
+        }
+
+        public void Write(TSOFile file)
+        {
+            tw.WriteLine("Metasequoia Document");
+            tw.WriteLine("Format Text Ver 1.0");
+            tw.WriteLine("");
+            tw.WriteLine("Scene {");
+            tw.WriteLine("\tpos -7.0446 4.1793 1541.1764");
+            tw.WriteLine("\tlookat 11.8726 193.8590 0.4676");
+            tw.WriteLine("\thead 0.8564");
+            tw.WriteLine("\tpich 0.1708");
+            tw.WriteLine("\tortho 0");
+            tw.WriteLine("\tzoom2 31.8925");
+            tw.WriteLine("\tamb 0.250 0.250 0.250");
+            tw.WriteLine("}");
+
+            VertexHeap<UVertex> vh = new VertexHeap<UVertex>();
+            List<ushort> face = new List<ushort>(2048 * 3);
+            List<float> uv = new List<float>(2048 * 3 * 2);
+            List<int> mtl = new List<int>(2048);
+
+            foreach (TSOTex tex in file.textures)
+                CreateTextureFile(tex);
+
+            tw.WriteLine("Material {0} {{", file.materials.Length);
+
+            foreach (TSOMaterial mat in file.materials)
+            {
+                if (mat.ColorTex != null)
+                {
+                    TSOTex tex = file.texturemap[mat.ColorTex];
+                    tw.WriteLine(
+                        "\t\"{0}\" col(1.000 1.000 1.000 1.000) dif(0.800) amb(0.600) emi(0.000) spc(0.000) power(5.00) tex(\"{1}\")",
+                        mat.name, GetTextureFileName(tex));
+                }
+                else
+                {
+                    tw.WriteLine(
+                        "\t\"{0}\" col(1.000 1.000 1.000 1.000) dif(0.800) amb(0.600) emi(0.000) spc(0.000) power(5.00))",
+                        mat.name);
+                }
+            }
+
+            tw.WriteLine("}");
+
+            foreach (TSOMesh i in file.meshes)
+            {
+                vh.Clear();
+                face.Clear();
+                uv.Clear();
+                mtl.Clear();
+
+                foreach (TSOSubMesh j in i.sub_meshes)
+                {
+                    int cnt = 0;
+                    ushort a = 0, b = 0, c = 0;
+                    Vertex va = new Vertex(), vb = new Vertex(), vc = new Vertex();
+
+                    foreach (Vertex k in j.vertices)
+                    {
+                        ++cnt;
+                        va = vb; a = b;
+                        vb = vc; b = c;
+                        vc = k; c = vh.Add(new UVertex(k.Pos, k.Nrm, k.Tex, j.spec));
+
+                        if (cnt < 3) continue;
+                        if (a == b || b == c || c == a) continue;
+
+                        if ((cnt & 1) == 0)
+                        {
+                            face.Add(a); uv.Add(va.Tex.x); uv.Add(1 - va.Tex.y);
+                            face.Add(b); uv.Add(vb.Tex.x); uv.Add(1 - vb.Tex.y);
+                            face.Add(c); uv.Add(vc.Tex.x); uv.Add(1 - vc.Tex.y);
+                            mtl.Add(j.spec);
+                        }
+                        else
+                        {
+                            face.Add(a); uv.Add(va.Tex.x); uv.Add(1 - va.Tex.y);
+                            face.Add(c); uv.Add(vc.Tex.x); uv.Add(1 - vc.Tex.y);
+                            face.Add(b); uv.Add(vb.Tex.x); uv.Add(1 - vb.Tex.y);
+                            mtl.Add(j.spec);
+                        }
+                    }
+                }
+
+                tw.WriteLine("Object \"{0}\" {{", i.Name);
+                tw.WriteLine("\tvisible {0}", 15);
+                tw.WriteLine("\tlocking {0}", 0);
+                tw.WriteLine("\tshading {0}", 1);
+                tw.WriteLine("\tfacet {0}", 59.5);
+                tw.WriteLine("\tcolor {0:F3} {1:F3} {2:F3}", 0.898f, 0.498f, 0.698f);
+                tw.WriteLine("\tcolor_type {0}", 0);
+
+                //
+                tw.WriteLine("\tvertex {0} {{", vh.Count);
+
+                foreach (UVertex j in vh.verts)
+                    WriteVertex(j.Pos.x, j.Pos.y, j.Pos.z);
+
+                tw.WriteLine("\t}");
+
+                //
+                tw.WriteLine("\tface {0} {{", face.Count / 3);
+
+                System.Diagnostics.Debug.Assert(face.Count * 2 == uv.Count);
+                System.Diagnostics.Debug.Assert(face.Count == mtl.Count * 3);
+
+                for (int j = 0, n = face.Count; j < n; j += 3)
+                    WriteFace(face[j + 0], face[j + 1], face[j + 2],
+                              uv[j * 2 + 0], uv[j * 2 + 1],
+                              uv[j * 2 + 2], uv[j * 2 + 3],
+                              uv[j * 2 + 4], uv[j * 2 + 5],
+                              mtl[j / 3]);
+                tw.WriteLine("\t}");
+                tw.WriteLine("}");
+            }
+
+            // ボーンを出す
+            switch (BoneMode)
+            {
+                case MqoBoneMode.None: break;
+                case MqoBoneMode.RokDeBone:
+                    {
+                        // マトリクス計算
+                        foreach (TSONode i in file.nodes)
+                        {
+                            if (i.parent == null)
+                                i.world = i.Matrix;
+                            else i.world = Matrix44.Mul(i.Matrix, i.parent.World);
+                        }
+
+                        List<Point3> points = new List<Point3>();
+                        List<int> bones = new List<int>();
+
+                        tw.WriteLine("Object \"{0}\" {{", "Bone");
+                        tw.WriteLine("\tvisible {0}", 15);
+                        tw.WriteLine("\tlocking {0}", 0);
+                        tw.WriteLine("\tshading {0}", 1);
+                        tw.WriteLine("\tfacet {0}", 59.5);
+                        tw.WriteLine("\tcolor {0} {1} {2}", 1, 0, 0);
+                        tw.WriteLine("\tcolor_type {0}", 0);
+
+                        foreach (TSONode i in file.nodes)
+                        {
+                            if (i.children.Count == 0)
+                                continue;
+
+                            Point3 q = new Point3(i.world.M41, i.world.M42, i.world.M43);
+                            Point3 p = new Point3();
+
+                            foreach (TSONode j in i.children)
+                            {
+                                p.x += j.world.M41;
+                                p.y += j.world.M42;
+                                p.z += j.world.M43;
+                            }
+
+                            p.x /= i.children.Count;
+                            p.y /= i.children.Count;
+                            p.z /= i.children.Count;
+
+                            bones.Add(points.Count); points.Add(q);
+                            bones.Add(points.Count); points.Add(p);
+                        }
+
+                        tw.WriteLine("\tvertex {0} {{", points.Count);
+
+                        foreach (Point3 j in points)
+                            WriteVertex(j.x, j.y, j.z);
+
+                        tw.WriteLine("\t}");
+
+                        //
+                        tw.WriteLine("\tface {0} {{", bones.Count / 2);
+
+                        for (int j = 0, n = bones.Count; j < n; j += 2)
+                            tw.WriteLine(string.Format("\t\t2 V({0} {1})", bones[j + 0], bones[j + 1]));
+
+                        tw.WriteLine("\t}");
+                        tw.WriteLine("}");
+                    }
+                    break;
+
+                case MqoBoneMode.Mikoto:
+                    {
+                    }
+                    break;
+            }
+
+            tw.WriteLine("Eof");
+        }
+
+        public void WriteFace(int a, int b, int c, float u1, float v1, float u2, float v2, float u3, float v3, int m)
+        {
+            tw.WriteLine("\t\t{0} V({1} {2} {3}) M({10}) UV({4:F5} {5:F5} {6:F5} {7:F5} {8:F5} {9:F5})",
+                3, a, b, c, u1, v1, u2, v2, u3, v3, m);
+        }
+
+        public void WriteVertex(float x, float y, float z)
+        {
+            tw.WriteLine("\t\t{0:F4} {1:F4} {2:F4}", x, y, z);
+        }
+    }
+
+    public class UVertex : IComparable<UVertex>
+    {
+        public Point3 Pos;
+        public Point3 Nrm;
+        public Point2 Tex;
+        public int mtl;
+
+        public UVertex()
+        {
+        }
+
+        public UVertex(Point3 pos, Point3 nrm, Point2 tex, int mtl)
+        {
+            Pos = pos;
+            Nrm = nrm;
+            Tex = tex;
+            this.mtl = mtl;
+        }
+
+        public int CompareTo(UVertex o)
+        {
+            int cmp;
+            cmp = Pos.CompareTo(o.Pos); if (cmp != 0) return cmp;
+            cmp = Nrm.CompareTo(o.Nrm);
+            return cmp;
+        }
+
+        public override int GetHashCode()
+        {
+            return Pos.GetHashCode() ^ Nrm.GetHashCode();
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (obj is UVertex)
+            {
+                UVertex v = (UVertex)obj;
+                return Pos.Equals(v.Pos) && Nrm.Equals(v.Nrm);
+            }
+            return false;
+        }
+
+        public bool Equals(UVertex v)
+        {
+            if ((object)v == null)
+            {
+                return false;
+            }
+
+            return Pos.Equals(v.Pos) && Nrm.Equals(v.Nrm);
+        }
+    }
+}
\ No newline at end of file