OSDN Git Service

560782e78b02d85fa81cde8dab9d1241adb0145f
[tdcgexplorer/tso2mqo.git] / MqoWriter.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.IO;\r
4 using System.Text;\r
5 \r
6 namespace Tso2MqoGui\r
7 {\r
8     public enum MqoBoneMode\r
9     {\r
10         None,\r
11         RokDeBone,\r
12         Mikoto,\r
13     }\r
14 \r
15     public class Pair<T, U>\r
16     {\r
17         public T    First;\r
18         public U    Second;\r
19 \r
20         public Pair()\r
21         {\r
22         }\r
23 \r
24         public Pair(T first, U second)\r
25         {\r
26             First   = first;\r
27             Second  = second;\r
28         }\r
29     }\r
30 \r
31     public class MqoWriter : IDisposable\r
32     {\r
33         public TextWriter   tw;\r
34         public string       OutPath;\r
35         public string       OutFile;\r
36         public MqoBoneMode  BoneMode    = MqoBoneMode.None;\r
37 \r
38         public MqoWriter(string file)\r
39         {\r
40             FileStream  fs  = File.OpenWrite(file);\r
41             fs.SetLength(0);\r
42             tw              = new StreamWriter(fs, Encoding.Default);\r
43             OutFile         = file;\r
44             OutPath         = Path.GetDirectoryName(file);\r
45         }\r
46 \r
47         void IDisposable.Dispose()\r
48         {\r
49             Close();\r
50         }\r
51 \r
52         public void Close()\r
53         {\r
54             if(tw != null)\r
55                 tw.Close();\r
56             tw  = null;\r
57         }\r
58 \r
59         public void CreateTextureFile(TSOTex tex)\r
60         {\r
61             string  file= Path.Combine(OutPath, Path.GetFileName(tex.file.Trim('"')));\r
62             byte[]  data= tex.data;\r
63 \r
64             using(FileStream fs= File.OpenWrite(file))\r
65             {\r
66                 BinaryWriter    bw  = new BinaryWriter(fs);\r
67 \r
68                 switch(Path.GetExtension(file).ToUpper())\r
69                 {\r
70                 case ".TGA":\r
71                     bw.Write((byte)0);              // id\r
72                     bw.Write((byte)0);              // colormap\r
73                     bw.Write((byte)2);              // imagetype\r
74                     bw.Write((byte)0);              // unknown0\r
75                     bw.Write((byte)0);              // unknown1\r
76                     bw.Write((byte)0);              // unknown2\r
77                     bw.Write((byte)0);              // unknown3\r
78                     bw.Write((byte)0);              // unknown4\r
79                     bw.Write((short)0);             // width\r
80                     bw.Write((short)0);             // height\r
81                     bw.Write((short)tex.Width);     // width\r
82                     bw.Write((short)tex.Height);    // height\r
83                     bw.Write((byte)(tex.depth * 8));// depth\r
84                     bw.Write((byte)0);              // depth\r
85                     break;\r
86 \r
87                 case ".BMP":\r
88                     bw.Write((byte)'B');\r
89                     bw.Write((byte)'M');\r
90                     bw.Write((int)(54 + data.Length));\r
91                     bw.Write((int)0);\r
92                     bw.Write((int)54);\r
93                     bw.Write((int)40);\r
94                     bw.Write((int)tex.Width);\r
95                     bw.Write((int)tex.Height);\r
96                     bw.Write((short)1);\r
97                     bw.Write((short)(tex.Depth*8));\r
98                     bw.Write((int)0);\r
99                     bw.Write((int)data.Length);\r
100                     bw.Write((int)0);\r
101                     bw.Write((int)0);\r
102                     bw.Write((int)0);\r
103                     bw.Write((int)0);\r
104                     break;\r
105                 }\r
106 \r
107                 bw.Write(data, 0, data.Length);\r
108                 bw.Flush();\r
109             }\r
110         }\r
111 \r
112         public void Write(TSOFile file)\r
113         {\r
114             tw.WriteLine("Metasequoia Document");\r
115             tw.WriteLine("Format Text Ver 1.0");\r
116             tw.WriteLine("");\r
117             tw.WriteLine("Scene {");\r
118             tw.WriteLine("      pos -7.0446 4.1793 1541.1764");\r
119             tw.WriteLine("      lookat 11.8726 193.8590 0.4676");\r
120             tw.WriteLine("      head 0.8564");\r
121             tw.WriteLine("      pich 0.1708");\r
122             tw.WriteLine("      ortho 0");\r
123             tw.WriteLine("      zoom2 31.8925");\r
124             tw.WriteLine("      amb 0.250 0.250 0.250");\r
125             tw.WriteLine("}");\r
126 \r
127           //VertexHeap<UVertex> vh  = new VertexHeap<UVertex>();\r
128             VertexHeap          vh  = new VertexHeap();\r
129             List<ushort>        face= new List<ushort>(2048*3);\r
130             List<float>         uv  = new List<float>(2048*3 * 2);\r
131             List<int>           mtl = new List<int>(2048);\r
132 \r
133             foreach(TSOTex i in file.textures)\r
134                 CreateTextureFile(i);\r
135 \r
136             tw.WriteLine("Material {0} {{", file.materials.Length);\r
137 \r
138             foreach(TSOMaterial i in file.materials)\r
139             {\r
140                 if(i.ColorTex != null)\r
141                 {\r
142                     TSOTex  tex = file.texturemap[i.ColorTex];\r
143                     tw.WriteLine(\r
144                         "       \"{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
145                         i.name, Path.Combine(OutPath, tex.File.Trim('"')));\r
146                 } else\r
147                 {\r
148                     tw.WriteLine(\r
149                         "       \"{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
150                         i.name);\r
151                 }\r
152             }\r
153 \r
154             tw.WriteLine("}");\r
155 \r
156             foreach(TSOMesh i in file.meshes)\r
157             {\r
158                 vh.Clear();\r
159                 face.Clear();\r
160                 uv.Clear();\r
161                 mtl.Clear();\r
162 \r
163                 foreach(TSOSubMesh j in i.sub)\r
164                 {\r
165                     int     cnt = 0;\r
166                     ushort  a= 0, b= 0, c= 0;\r
167                     Vertex  va= new Vertex(), vb= new Vertex(), vc= new Vertex();\r
168 \r
169                     foreach(Vertex k in j.vertices)\r
170                     {\r
171                         ++cnt;\r
172                         va= vb; a= b;\r
173                         vb= vc; b= c;\r
174                         vc= k;  c= vh.Add(new UVertex(k.Pos, k.Nrm, k.Tex, j.spec));\r
175 \r
176                         if(cnt < 3)                     continue;\r
177                         if(a == b || b == c || c == a)  continue;\r
178 \r
179                         if((cnt & 1) == 0)\r
180                         {\r
181                             face.Add(a); uv.Add(va.Tex.x); uv.Add(1-va.Tex.y);\r
182                             face.Add(b); uv.Add(vb.Tex.x); uv.Add(1-vb.Tex.y);\r
183                             face.Add(c); uv.Add(vc.Tex.x); uv.Add(1-vc.Tex.y);\r
184                             mtl.Add(j.spec);\r
185                         } else\r
186                         {\r
187                             face.Add(a); uv.Add(va.Tex.x); uv.Add(1-va.Tex.y);\r
188                             face.Add(c); uv.Add(vc.Tex.x); uv.Add(1-vc.Tex.y);\r
189                             face.Add(b); uv.Add(vb.Tex.x); uv.Add(1-vb.Tex.y);\r
190                             mtl.Add(j.spec);\r
191                         }\r
192                     }\r
193                 }\r
194 \r
195                 tw.WriteLine("Object \"{0}\" {{", i.Name);\r
196                 tw.WriteLine("  visible {0}", 15);\r
197                 tw.WriteLine("  locking {0}", 0);\r
198                 tw.WriteLine("  shading {0}", 1);\r
199                 tw.WriteLine("  facet {0}", 59.5);\r
200                 tw.WriteLine("  color {0:F3} {1:F3} {2:F3}", 0.898f, 0.498f, 0.698f);\r
201                 tw.WriteLine("  color_type {0}", 0);\r
202 \r
203                 //\r
204                 tw.WriteLine("  vertex {0} {{", vh.Count);\r
205 \r
206                 foreach(UVertex j in vh.verts)\r
207                     WriteVertex(j.Pos.x, j.Pos.y, j.Pos.z);\r
208 \r
209                 tw.WriteLine("  }");\r
210 \r
211                 //\r
212                 tw.WriteLine("  face {0} {{", face.Count);\r
213 \r
214                 System.Diagnostics.Debug.Assert(face.Count*2 == uv.Count);\r
215                 System.Diagnostics.Debug.Assert(face.Count == mtl.Count * 3);\r
216 \r
217                 for(int j= 0, n= face.Count; j < n; j+=3)\r
218                     WriteFace(face[j+0], face[j+1], face[j+2],\r
219                               uv[j*2+0], uv[j*2+1],\r
220                               uv[j*2+2], uv[j*2+3],\r
221                               uv[j*2+4], uv[j*2+5],\r
222                               mtl[j/3]);\r
223                 tw.WriteLine("  }");\r
224                 tw.WriteLine("}");\r
225             }\r
226 \r
227             // ボーンを出す\r
228             switch(BoneMode)\r
229             {\r
230             case MqoBoneMode.None:      break;\r
231             case MqoBoneMode.RokDeBone:\r
232                 {\r
233                 // マトリクス計算\r
234                 foreach(TSONode i in file.nodes)\r
235                 {\r
236                     if(i.parent == null)\r
237                             i.world = i.Matrix;\r
238                     else    i.world = Matrix44.Mul(i.Matrix, i.parent.World);\r
239                 }\r
240                 \r
241                 List<Point3>                points  = new List<Point3>();\r
242                 List<int>                   bones   = new List<int>();\r
243 \r
244                 tw.WriteLine("Object \"{0}\" {{", "Bone");\r
245                 tw.WriteLine("  visible {0}", 15);\r
246                 tw.WriteLine("  locking {0}", 0);\r
247                 tw.WriteLine("  shading {0}", 1);\r
248                 tw.WriteLine("  facet {0}", 59.5);\r
249                 tw.WriteLine("  color {0} {1} {2}", 1, 0, 0);\r
250                 tw.WriteLine("  color_type {0}", 0);\r
251 \r
252                 foreach(TSONode i in file.nodes)\r
253                 {\r
254                     if(i.children.Count == 0)\r
255                         continue;\r
256 \r
257                     Point3  q   = new Point3(i.world.M41, i.world.M42, i.world.M43);\r
258                     Point3  p   = new Point3();\r
259                     \r
260                     foreach(TSONode j in i.children)\r
261                     {\r
262                         p.x     +=j.world.M41;\r
263                         p.y     +=j.world.M42;\r
264                         p.z     +=j.world.M43;\r
265                     }\r
266 \r
267                     p.x         /=i.children.Count;\r
268                     p.y         /=i.children.Count;\r
269                     p.z         /=i.children.Count;\r
270 \r
271                     bones.Add(points.Count); points.Add(q);\r
272                     bones.Add(points.Count); points.Add(p);\r
273                 }\r
274 \r
275                 tw.WriteLine("  vertex {0} {{", points.Count);\r
276 \r
277                 foreach(Point3 j in points)\r
278                     WriteVertex(j.x, j.y, j.z);\r
279 \r
280                 tw.WriteLine("  }");\r
281 \r
282                 //\r
283                 tw.WriteLine("  face {0} {{", bones.Count / 2);\r
284 \r
285                 for(int j= 0, n= bones.Count; j < n; j+=2)\r
286                     tw.WriteLine(string.Format("                2 V({0} {1})", bones[j+0], bones[j+1]));\r
287 \r
288                 tw.WriteLine("  }");\r
289                 tw.WriteLine("}");\r
290                 }\r
291                 break;\r
292 \r
293             case MqoBoneMode.Mikoto:\r
294                 {\r
295                 }\r
296                 break;\r
297             }\r
298 \r
299             tw.WriteLine("Eof");\r
300         }\r
301 \r
302         public void WriteFace(int a, int b, int c, float u1, float v1, float u2, float v2, float u3, float v3, int m)\r
303         {\r
304             tw.WriteLine("              {0} V({1} {2} {3}) M({10}) UV({4:F5} {5:F5} {6:F5} {7:F5} {8:F5} {9:F5})",\r
305                 3, a, b, c, u1, v1, u2, v2, u3, v3, m);\r
306         }\r
307 \r
308         public void WriteVertex(float x, float y, float z)\r
309         {\r
310             tw.WriteLine("              {0:F4} {1:F4} {2:F4}", x, y, z);\r
311         }\r
312     }\r
313 \r
314     public class UVertex : IComparable<UVertex>\r
315     {\r
316         public Point3 Pos;\r
317         public Point3 Nrm;\r
318         public Point2 Tex;\r
319         public int      mtl;\r
320         \r
321         public UVertex()\r
322         {\r
323         }\r
324 \r
325         public UVertex(Point3 pos, Point3 nrm, Point2 tex, int mtl)\r
326         {\r
327             Pos = pos;\r
328             Nrm = nrm;\r
329             Tex = tex;\r
330             this.mtl= mtl;\r
331         }\r
332 \r
333         public int CompareTo(UVertex o)\r
334         {\r
335             if(Pos.x < o.Pos.x) return -1; if(Pos.x > o.Pos.x) return 1;\r
336             if(Pos.y < o.Pos.y) return -1; if(Pos.y > o.Pos.y) return 1;\r
337             if(Pos.z < o.Pos.z) return -1; if(Pos.z > o.Pos.z) return 1;\r
338             if(Nrm.x < o.Nrm.x) return -1; if(Nrm.x > o.Nrm.x) return 1;\r
339             if(Nrm.y < o.Nrm.y) return -1; if(Nrm.y > o.Nrm.y) return 1;\r
340             if(Nrm.z < o.Nrm.z) return -1; if(Nrm.z > o.Nrm.z) return 1;\r
341             if(Tex.x < o.Tex.x) return -1; if(Tex.x > o.Tex.x) return 1;\r
342             if(Tex.y < o.Tex.y) return -1; if(Tex.y > o.Tex.y) return 1;\r
343             return mtl - o.mtl;\r
344         }\r
345 \r
346         public override int GetHashCode()\r
347         {\r
348             return Pos.x.GetHashCode() ^ Pos.y.GetHashCode() ^ Pos.z.GetHashCode()\r
349                  ^ Nrm.x.GetHashCode() ^ Nrm.y.GetHashCode() ^ Nrm.z.GetHashCode();\r
350         }\r
351 \r
352         public override bool Equals(object obj)\r
353         {\r
354             UVertex o   = obj as UVertex;\r
355 \r
356             if(o == null)\r
357                 return false;\r
358 \r
359             return Pos.x==o.Pos.x && Pos.y==o.Pos.y && Pos.z==o.Pos.z\r
360                 && Nrm.x==o.Nrm.x && Nrm.y==o.Nrm.y && Nrm.z==o.Nrm.z;\r
361         }\r
362     }\r
363 }\r