-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, k.Nrm, k.Tex, 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.Pos.x, j.Pos.y, j.Pos.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 Point3 Pos;\r
- public Point3 Nrm;\r
- public Point2 Tex;\r
- public int mtl;\r
- \r
- public UVertex()\r
- {\r
- }\r
-\r
- public UVertex(Point3 pos, Point3 nrm, Point2 tex, int mtl)\r
- {\r
- Pos = pos;\r
- Nrm = nrm;\r
- Tex = tex;\r
- this.mtl= mtl;\r
- }\r
-\r
- public int CompareTo(UVertex o)\r
- {\r
- if(Pos.x < o.Pos.x) return -1; if(Pos.x > o.Pos.x) return 1;\r
- if(Pos.y < o.Pos.y) return -1; if(Pos.y > o.Pos.y) return 1;\r
- if(Pos.z < o.Pos.z) return -1; if(Pos.z > o.Pos.z) return 1;\r
- if(Nrm.x < o.Nrm.x) return -1; if(Nrm.x > o.Nrm.x) return 1;\r
- if(Nrm.y < o.Nrm.y) return -1; if(Nrm.y > o.Nrm.y) return 1;\r
- if(Nrm.z < o.Nrm.z) return -1; if(Nrm.z > o.Nrm.z) return 1;\r
- if(Tex.x < o.Tex.x) return -1; if(Tex.x > o.Tex.x) return 1;\r
- if(Tex.y < o.Tex.y) return -1; if(Tex.y > o.Tex.y) return 1;\r
- return mtl - o.mtl;\r
- }\r
-\r
- public override int GetHashCode()\r
- {\r
- return Pos.x.GetHashCode() ^ Pos.y.GetHashCode() ^ Pos.z.GetHashCode()\r
- ^ Nrm.x.GetHashCode() ^ Nrm.y.GetHashCode() ^ Nrm.z.GetHashCode();\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 Pos.x==o.Pos.x && Pos.y==o.Pos.y && Pos.z==o.Pos.z\r
- && Nrm.x==o.Nrm.x && Nrm.y==o.Nrm.y && Nrm.z==o.Nrm.z;\r
- }\r
- }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Xml;
+
+namespace Tso2MqoGui
+{
+ 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 bool MqxEnabled;
+
+ 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;
+
+ //TODO: .bmpのはずが.psdになってるものがある
+
+ 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;
+
+ default:
+ 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 tso)
+ {
+ tw.WriteLine("Metasequoia Document");
+ tw.WriteLine("Format Text Ver 1.0");
+ tw.WriteLine("");
+ if (MqxEnabled)
+ {
+ tw.WriteLine("IncludeXml \"{0}\"", Path.GetFileName(Path.ChangeExtension(OutFile, ".mqx")));
+ 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("}");
+
+ foreach (TSOTex tex in tso.textures)
+ CreateTextureFile(tex);
+
+ tw.WriteLine("Material {0} {{", tso.materials.Length);
+
+ foreach (TSOMaterial mat in tso.materials)
+ {
+ TSOTex tex = null;
+ if (tso.texturemap.TryGetValue(mat.ColorTex, out tex))
+ {
+ 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("}");
+
+ MqoBone[] bones = null;
+
+ if (MqxEnabled)
+ bones = CreateBones(tso);
+
+ MqoObjectGen.uid_enabled = MqxEnabled;
+ MqoObjectGen obj = new MqoObjectGen();
+
+ ushort object_id = 0;
+ foreach (TSOMesh mesh in tso.meshes)
+ {
+ obj.id = ++object_id;
+ obj.name = mesh.Name;
+ obj.Update(mesh);
+ obj.Write(tw);
+
+ if (MqxEnabled)
+ obj.AddWeits(bones);
+ }
+
+ if (MqxEnabled)
+ {
+ MqxWriter writer = new MqxWriter();
+ writer.MqoFile = OutFile;
+ writer.Write(bones, object_id /* eq numobjects */);
+ }
+
+ tw.WriteLine("Eof");
+ }
+
+ MqoBone[] CreateBones(TSOFile tso)
+ {
+ MqoBone[] bones = new MqoBone[tso.nodes.Length];
+
+ tso.UpdateNodesWorld();
+
+ foreach (TSONode node in tso.nodes)
+ {
+ MqoBone bone = new MqoBone();
+ bone.id = node.id;
+ bone.name = node.ShortName;
+ bone.tail = node.children.Count == 0;
+
+ if (node.parent == null)
+ {
+ bone.pid = -1;
+ }
+ else
+ {
+ bone.pid = node.parent.id;
+ bones[bone.pid].cids.Add(bone.id);
+ }
+
+ //根本
+ bone.q = node.world.Translation;
+ //先端
+ if (! bone.tail)
+ bone.p = node.children[0].world.Translation;
+ else
+ bone.p = node.world.Translation;
+
+ bones[node.id] = bone;
+ }
+ return bones;
+ }
+ }
+
+ public class MqoObjectGen
+ {
+ public static bool uid_enabled;
+
+ public int id; //object_id
+ public string name;
+ VertexHeap<UVertex> vh = new VertexHeap<UVertex>();
+ public List<MqoFace> faces;
+
+ public int numvertices { get { return vh.Count; } }
+ public List<UVertex> vertices { get { return vh.verts; } }
+ public int numfaces { get { return faces.Count; } }
+
+ public MqoObjectGen()
+ {
+ faces = new List<MqoFace>(2048);
+ }
+
+ public void Update(TSOMesh mesh)
+ {
+ vh.Clear();
+ faces.Clear();
+
+ foreach (TSOSubMesh sub_mesh in mesh.sub_meshes)
+ {
+ int cnt = 0;
+ ushort a = 0, b = 0, c = 0;
+ Vertex va = new Vertex(), vb = new Vertex(), vc = new Vertex();
+
+ foreach (Vertex v in sub_mesh.vertices)
+ {
+ ++cnt;
+ va = vb; a = b;
+ vb = vc; b = c;
+ vc = v; c = vh.Add(new UVertex(v.Pos, v.Wgt, v.Idx, v.Nrm));
+
+ if (cnt < 3) continue;
+ if (a == b || b == c || c == a) continue;
+
+ if ((cnt & 1) == 0)
+ {
+ MqoFace f = new MqoFace(a, b, c, (ushort)sub_mesh.spec,
+ new Point2(va.Tex.x, 1 - va.Tex.y),
+ new Point2(vb.Tex.x, 1 - vb.Tex.y),
+ new Point2(vc.Tex.x, 1 - vc.Tex.y));
+ faces.Add(f);
+ }
+ else
+ {
+ MqoFace f = new MqoFace(a, c, b, (ushort)sub_mesh.spec,
+ new Point2(va.Tex.x, 1 - va.Tex.y),
+ new Point2(vc.Tex.x, 1 - vc.Tex.y),
+ new Point2(vb.Tex.x, 1 - vb.Tex.y));
+ faces.Add(f);
+ }
+ }
+ }
+ }
+
+ public void Write(TextWriter tw)
+ {
+ tw.WriteLine("Object \"{0}\" {{", name);
+ if (uid_enabled)
+ tw.WriteLine("\tuid {0}", id);
+ 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} {{", numvertices);
+
+ foreach (UVertex v in vertices)
+ v.Write(tw);
+
+ tw.WriteLine("\t}");
+
+ if (uid_enabled)
+ {
+ tw.WriteLine("\tvertexattr {");
+ tw.WriteLine("\t\tuid {");
+
+ ushort vertex_id = 0;
+ foreach (UVertex v in vertices)
+ tw.WriteLine("\t\t\t{0}", ++vertex_id);
+
+ tw.WriteLine("\t\t}");
+ tw.WriteLine("\t}");
+ }
+
+ //
+ tw.WriteLine("\tface {0} {{", numfaces);
+
+ for (int i = 0, n = numfaces; i < n; i++)
+ faces[i].Write(tw);
+ tw.WriteLine("\t}");
+ tw.WriteLine("}");
+ }
+
+ public unsafe void AddWeits(MqoBone[] bones)
+ {
+ ushort vertex_id = 0;
+ foreach (UVertex v in vertices)
+ {
+ ++vertex_id;
+
+ uint idx0 = v.Idx;
+ byte* idx = (byte*)(&idx0);
+ Point4 wgt0 = v.Wgt;
+ float* wgt = (float*)(&wgt0);
+
+ for (int k = 0; k < 4; ++k)
+ if (wgt[k] > float.Epsilon)
+ {
+ MqoWeit weit = new MqoWeit();
+ weit.object_id = id;
+ weit.vertex_id = vertex_id;
+ weit.weit = wgt[k];
+ bones[idx[k]].weits.Add(weit);
+ }
+ }
+ }
+ }
+}