OSDN Git Service

assign node.path and node.local_position.
[tdcgexplorer/tso2mqo.git] / MqoWriter.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text;
5 using System.Xml;
6
7 namespace Tso2MqoGui
8 {
9     public class Pair<T, U>
10     {
11         public T First;
12         public U Second;
13
14         public Pair()
15         {
16         }
17
18         public Pair(T first, U second)
19         {
20             First = first;
21             Second = second;
22         }
23     }
24
25     public class MqoWriter : IDisposable
26     {
27         public TextWriter tw;
28         public string OutPath;
29         public string OutFile;
30         public bool MqxEnabled;
31
32         public MqoWriter(string file)
33         {
34             FileStream fs = File.OpenWrite(file);
35             fs.SetLength(0);
36             tw = new StreamWriter(fs, Encoding.Default);
37             OutFile = file;
38             OutPath = Path.GetDirectoryName(file);
39         }
40
41         void IDisposable.Dispose()
42         {
43             Close();
44         }
45
46         public void Close()
47         {
48             if (tw != null)
49                 tw.Close();
50             tw = null;
51         }
52
53         string GetTextureFileName(TSOTex tex)
54         {
55             string filename = Path.GetFileName(tex.File.Trim('"'));
56             if (filename == "")
57                 filename = "none";
58             return filename;
59         }
60
61         string GetTexturePath(TSOTex tex)
62         {
63             return Path.Combine(OutPath, GetTextureFileName(tex));
64         }
65
66         public void CreateTextureFile(TSOTex tex)
67         {
68             string file = GetTexturePath(tex);
69             byte[] data = tex.data;
70
71             //TODO: .bmpのはずが.psdになってるものがある
72
73             using (FileStream fs = File.OpenWrite(file))
74             {
75                 BinaryWriter bw = new BinaryWriter(fs);
76
77                 switch (Path.GetExtension(file).ToUpper())
78                 {
79                     case ".TGA":
80                         bw.Write((byte)0);              // id
81                         bw.Write((byte)0);              // colormap
82                         bw.Write((byte)2);              // imagetype
83                         bw.Write((byte)0);              // unknown0
84                         bw.Write((byte)0);              // unknown1
85                         bw.Write((byte)0);              // unknown2
86                         bw.Write((byte)0);              // unknown3
87                         bw.Write((byte)0);              // unknown4
88                         bw.Write((short)0);             // width
89                         bw.Write((short)0);             // height
90                         bw.Write((short)tex.Width);     // width
91                         bw.Write((short)tex.Height);    // height
92                         bw.Write((byte)(tex.depth * 8));// depth
93                         bw.Write((byte)0);              // depth
94                         break;
95
96                     default:
97                         bw.Write((byte)'B');
98                         bw.Write((byte)'M');
99                         bw.Write((int)(54 + data.Length));
100                         bw.Write((int)0);
101                         bw.Write((int)54);
102                         bw.Write((int)40);
103                         bw.Write((int)tex.Width);
104                         bw.Write((int)tex.Height);
105                         bw.Write((short)1);
106                         bw.Write((short)(tex.Depth * 8));
107                         bw.Write((int)0);
108                         bw.Write((int)data.Length);
109                         bw.Write((int)0);
110                         bw.Write((int)0);
111                         bw.Write((int)0);
112                         bw.Write((int)0);
113                         break;
114                 }
115
116                 bw.Write(data, 0, data.Length);
117                 bw.Flush();
118             }
119         }
120
121         public void Write(TSOFile tso)
122         {
123             tw.WriteLine("Metasequoia Document");
124             tw.WriteLine("Format Text Ver 1.0");
125             tw.WriteLine("");
126             if (MqxEnabled)
127             {
128                 tw.WriteLine("IncludeXml \"{0}\"", Path.GetFileName(Path.ChangeExtension(OutFile, ".mqx")));
129                 tw.WriteLine("");
130             }
131             tw.WriteLine("Scene {");
132             tw.WriteLine("\tpos -7.0446 4.1793 1541.1764");
133             tw.WriteLine("\tlookat 11.8726 193.8590 0.4676");
134             tw.WriteLine("\thead 0.8564");
135             tw.WriteLine("\tpich 0.1708");
136             tw.WriteLine("\tortho 0");
137             tw.WriteLine("\tzoom2 31.8925");
138             tw.WriteLine("\tamb 0.250 0.250 0.250");
139             tw.WriteLine("}");
140
141             foreach (TSOTex tex in tso.textures)
142                 CreateTextureFile(tex);
143
144             tw.WriteLine("Material {0} {{", tso.materials.Length);
145
146             foreach (TSOMaterial mat in tso.materials)
147             {
148                 TSOTex tex = null;
149                 if (tso.texturemap.TryGetValue(mat.ColorTex, out tex))
150                 {
151                     tw.WriteLine(
152                         "\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}\")",
153                         mat.name, GetTextureFileName(tex));
154                 }
155                 else
156                 {
157                     tw.WriteLine(
158                         "\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))",
159                         mat.name);
160                 }
161             }
162
163             tw.WriteLine("}");
164
165             MqoBone[] bones = null;
166
167             if (MqxEnabled)
168                 bones = CreateBones(tso);
169
170             MqoObjectGen.uid_enabled = MqxEnabled;
171             MqoObjectGen obj = new MqoObjectGen();
172
173             ushort object_id = 0;
174             foreach (TSOMesh mesh in tso.meshes)
175             {
176                 obj.id = ++object_id;
177                 obj.name = mesh.Name;
178                 obj.Update(mesh);
179                 obj.Write(tw);
180
181                 if (MqxEnabled)
182                     obj.AddWeits(bones);
183             }
184
185             if (MqxEnabled)
186             {
187                 MqxWriter writer = new MqxWriter();
188                 writer.MqoFile = OutFile;
189                 writer.Write(bones, object_id /* eq numobjects */);
190             }
191
192             tw.WriteLine("Eof");
193         }
194
195         MqoBone[] CreateBones(TSOFile tso)
196         {
197             MqoBone[] bones = new MqoBone[tso.nodes.Length];
198
199             tso.UpdateNodesWorld();
200
201             foreach (TSONode node in tso.nodes)
202             {
203                 MqoBone bone = new MqoBone();
204                 bone.id = node.id+1;
205                 bone.name = node.ShortName;
206                 bone.tail = node.children.Count == 0;
207
208                 if (node.parent == null)
209                 {
210                     bone.pid = 0;
211                 }
212                 else
213                 {
214                     bone.pid = node.parent.id+1;
215                     bones[node.parent.id].cids.Add(bone.id);
216                 }
217
218                 //根本
219                 bone.q = node.world.Translation;
220                 //先端
221                 if (! bone.tail)
222                     bone.p = node.children[0].world.Translation;
223                 else
224                     bone.p = node.world.Translation;
225
226                 bones[node.id] = bone;
227             }
228             return bones;
229         }
230     }
231
232     public class MqoObjectGen
233     {
234         public static bool uid_enabled;
235
236         public int id; //object_id
237         public string name;
238         Heap<UVertex> vh = new Heap<UVertex>();
239         public List<MqoFace> faces;
240
241         public int numvertices { get { return vh.Count; } }
242         public List<UVertex> vertices { get { return vh.ary; } }
243         public int numfaces { get { return faces.Count; } }
244
245         public MqoObjectGen()
246         {
247             faces = new List<MqoFace>(2048);
248         }
249
250         public void Update(TSOMesh mesh)
251         {
252             vh.Clear();
253             faces.Clear();
254
255             foreach (TSOSubMesh sub_mesh in mesh.sub_meshes)
256             {
257                 int cnt = 0;
258                 ushort a = 0, b = 0, c = 0;
259                 Vertex va = new Vertex(), vb = new Vertex(), vc = new Vertex();
260
261                 foreach (Vertex v in sub_mesh.vertices)
262                 {
263                     ++cnt;
264                     va = vb; a = b;
265                     vb = vc; b = c;
266                     vc = v; c = vh.Add(new UVertex(v.Pos, v.Wgt, v.Idx, v.Nrm));
267
268                     if (cnt < 3) continue;
269                     if (a == b || b == c || c == a) continue;
270
271                     if ((cnt & 1) == 0)
272                     {
273                         MqoFace f = new MqoFace(a, b, c, (ushort)sub_mesh.spec,
274                                 new Point2(va.Tex.x, 1 - va.Tex.y),
275                                 new Point2(vb.Tex.x, 1 - vb.Tex.y),
276                                 new Point2(vc.Tex.x, 1 - vc.Tex.y));
277                         faces.Add(f);
278                     }
279                     else
280                     {
281                         MqoFace f = new MqoFace(a, c, b, (ushort)sub_mesh.spec,
282                                 new Point2(va.Tex.x, 1 - va.Tex.y),
283                                 new Point2(vc.Tex.x, 1 - vc.Tex.y),
284                                 new Point2(vb.Tex.x, 1 - vb.Tex.y));
285                         faces.Add(f);
286                     }
287                 }
288             }
289         }
290
291         public void Write(TextWriter tw)
292         {
293             tw.WriteLine("Object \"{0}\" {{", name);
294             if (uid_enabled)
295                 tw.WriteLine("\tuid {0}", id);
296             tw.WriteLine("\tvisible {0}", 15);
297             tw.WriteLine("\tlocking {0}", 0);
298             tw.WriteLine("\tshading {0}", 1);
299             tw.WriteLine("\tfacet {0}", 59.5);
300             tw.WriteLine("\tcolor {0:F3} {1:F3} {2:F3}", 0.898f, 0.498f, 0.698f);
301             tw.WriteLine("\tcolor_type {0}", 0);
302
303             //
304             tw.WriteLine("\tvertex {0} {{", numvertices);
305
306             foreach (UVertex v in vertices)
307                 v.Write(tw);
308
309             tw.WriteLine("\t}");
310
311             if (uid_enabled)
312             {
313                 tw.WriteLine("\tvertexattr {");
314                 tw.WriteLine("\t\tuid {");
315
316                 ushort vertex_id = 0;
317                 foreach (UVertex v in vertices)
318                     tw.WriteLine("\t\t\t{0}", ++vertex_id);
319
320                 tw.WriteLine("\t\t}");
321                 tw.WriteLine("\t}");
322             }
323
324             //
325             tw.WriteLine("\tface {0} {{", numfaces);
326
327             for (int i = 0, n = numfaces; i < n; i++)
328                 faces[i].Write(tw);
329             tw.WriteLine("\t}");
330             tw.WriteLine("}");
331         }
332
333         public unsafe void AddWeits(MqoBone[] bones)
334         {
335             ushort vertex_id = 0;
336             foreach (UVertex v in vertices)
337             {
338                 ++vertex_id;
339
340                 uint idx0 = v.Idx;
341                 byte* idx = (byte*)(&idx0);
342                 Point4 wgt0 = v.Wgt;
343                 float* wgt = (float*)(&wgt0);
344
345                 for (int k = 0; k < 4; ++k)
346                     if (wgt[k] > float.Epsilon)
347                     {
348                         MqoWeit weit = new MqoWeit();
349                         weit.object_id = id;
350                         weit.vertex_id = vertex_id;
351                         weit.weit = wgt[k];
352                         bones[idx[k]].weits.Add(weit);
353                     }
354             }
355         }
356     }
357 }