OSDN Git Service

rename TSONode#name to path.
[tdcgexplorer/tso2mqo.git] / TSOGenerator.cs
1 using System;\r
2 using System.Collections.Generic;\r
3 using System.Drawing.Design;\r
4 using System.IO;\r
5 using System.Text;\r
6 using System.Runtime.InteropServices;\r
7 using System.ComponentModel;\r
8 using System.Windows.Forms.Design;\r
9 \r
10 namespace Tso2MqoGui\r
11 {\r
12     public abstract class TSOGenerator\r
13     {\r
14         string dir;\r
15         TSOGeneratorConfig config;\r
16         protected MqoReader mqo;\r
17         protected MqxReader mqx;\r
18         protected TSOFile tsoref;\r
19         protected List<TSOMesh> meshes;\r
20         ImportInfo ii;\r
21         BinaryWriter bw;\r
22         Dictionary<string, MaterialInfo> materials;\r
23         protected int nummaterials { get { return materials.Count; } }\r
24         Dictionary<string, TextureInfo> textures;\r
25 \r
26         public TSOGenerator(TSOGeneratorConfig config)\r
27         {\r
28             this.config = config;\r
29         }\r
30 \r
31         public TSOFile LoadTSO(string file)\r
32         {\r
33             TSOFile tso = new TSOFile(file);\r
34             tso.ReadAll();\r
35             return tso;\r
36         }\r
37 \r
38         bool SetCurrentDirectory(string dir)\r
39         {\r
40             this.dir = dir;\r
41             Environment.CurrentDirectory = dir;\r
42             return true;\r
43         }\r
44 \r
45         bool DoLoadMQO(string mqo_file)\r
46         {\r
47             // MQO読み込み\r
48             mqo = new MqoReader();\r
49             mqo.Load(mqo_file);\r
50             return true;\r
51         }\r
52 \r
53         bool DoLoadMqx(string mqo_file)\r
54         {\r
55             // Mqx読み込み\r
56             mqx = new MqxReader();\r
57             if (mqx.Load(mqo_file))\r
58             {\r
59                 mqx.CreateWeits();\r
60                 mqx.CreateWeitMap();\r
61             }\r
62             return true;\r
63         }\r
64 \r
65         bool DoLoadXml(string importinfo_file)\r
66         {\r
67             // XML読み込み\r
68             ii = ImportInfo.Load(importinfo_file);\r
69 \r
70             // 使用マテリアル一覧取得\r
71             materials = new Dictionary<string, MaterialInfo>();\r
72             bool validmap = true;\r
73 \r
74             foreach (MqoMaterial i in mqo.Materials)\r
75             {\r
76                 MaterialInfo mi = new MaterialInfo(dir, i, ii.GetMaterial(i.name));\r
77                 validmap &= mi.Valid;\r
78                 materials.Add(i.name, mi);\r
79             }\r
80 \r
81             if (!validmap || config.ShowMaterials)\r
82             {\r
83                 if (config.cui)\r
84                     throw new Exception("マテリアルの設定が無効です");\r
85 \r
86                 FormMaterial dlg = new FormMaterial();\r
87                 dlg.materials = materials;\r
88 \r
89                 if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\r
90                     return false;\r
91             }\r
92 \r
93             // 使用テクスチャ一覧の取得\r
94             textures = new Dictionary<string, TextureInfo>();\r
95 \r
96             foreach (MaterialInfo i in materials.Values)\r
97             {\r
98                 string color_tex_name = Path.GetFileNameWithoutExtension(i.ColorTexture);\r
99 \r
100                 if (color_tex_name != null && !textures.ContainsKey(color_tex_name))\r
101                         textures.Add(color_tex_name, new TextureInfo(color_tex_name, i.ColorTexture));\r
102 \r
103                 string shade_tex_name = Path.GetFileNameWithoutExtension(i.ShadeTexture);\r
104 \r
105                 if (shade_tex_name != null && !textures.ContainsKey(shade_tex_name))\r
106                         textures.Add(shade_tex_name, new TextureInfo(shade_tex_name, i.ShadeTexture));\r
107             }\r
108 \r
109             return true;\r
110         }\r
111 \r
112         bool DoWriteHeader()\r
113         {\r
114             bw.Write(0x314F5354);\r
115             return true;\r
116         }\r
117 \r
118         bool DoWriteNodeNames()\r
119         {\r
120             if (tsoref != null)\r
121             {\r
122                 bw.Write(tsoref.nodes.Length);\r
123 \r
124                 foreach (TSONode i in tsoref.nodes)\r
125                     WriteString(bw, i.Path);\r
126             }\r
127             else if (mqx != null)\r
128             {\r
129                 bw.Write(mqx.bones.Length);\r
130 \r
131                 foreach (MqoBone i in mqx.bones)\r
132                     WriteString(bw, i.path);\r
133             }\r
134             else\r
135                 return false;\r
136 \r
137             return true;\r
138         }\r
139 \r
140         bool DoWriteNodeMatrices()\r
141         {\r
142             if (tsoref != null)\r
143             {\r
144                 bw.Write(tsoref.nodes.Length);\r
145 \r
146                 foreach (TSONode i in tsoref.nodes)\r
147                     WriteMatrix(bw, i.Matrix);\r
148             }\r
149             else if (mqx != null)\r
150             {\r
151                 bw.Write(mqx.bones.Length);\r
152 \r
153                 foreach (MqoBone i in mqx.bones)\r
154                     WriteMatrix(bw, i.matrix);\r
155             }\r
156             else\r
157                 return false;\r
158 \r
159             return true;\r
160         }\r
161 \r
162         bool DoWriteTextures()\r
163         {\r
164             bw.Write(textures.Count);\r
165 \r
166             foreach (TextureInfo tex_info in textures.Values)\r
167             {\r
168                 string file = tex_info.file;\r
169                 string name = tex_info.name;\r
170 \r
171                 string file_directory_name = Path.GetDirectoryName(file);\r
172                 string file_name = Path.GetFileName(file);\r
173 \r
174                 WriteString(bw, name);\r
175                 WriteString(bw, "\"" + file_name + "\"");\r
176 \r
177                 // テクスチャの読み込み\r
178                 TSOTex tex = LoadTex(file);\r
179                 tex.name = name;\r
180                 bw.Write(tex.Width);\r
181                 bw.Write(tex.Height);\r
182                 bw.Write(tex.Depth);\r
183                 bw.Write(tex.data, 0, tex.data.Length);\r
184 \r
185                 ImportTextureInfo import_tex_info = new ImportTextureInfo(tex);\r
186                 ii.textures.Add(import_tex_info);\r
187 \r
188                 // テクスチャが同じフォルダにない場合、コピーしておく\r
189                 if (file_directory_name != "" && file_directory_name.ToUpper() != dir.ToUpper())\r
190                 {\r
191                     import_tex_info.File = Path.Combine(dir, file_name);\r
192                     File.Copy(file, import_tex_info.File, true);\r
193                 }\r
194             }\r
195 \r
196             return true;\r
197         }\r
198 \r
199         bool DoWriteEffects()\r
200         {\r
201             bw.Write(ii.effects.Count);\r
202 \r
203             foreach (ImportEffectInfo import_effect_info in ii.effects)\r
204             {\r
205                 string file = Path.Combine(dir, import_effect_info.Name);\r
206                 string[] code = File.ReadAllLines(file, Encoding.Default);\r
207 \r
208                 WriteString(bw, import_effect_info.Name);\r
209                 bw.Write(code.Length);\r
210 \r
211                 foreach (string line in code)\r
212                     WriteString(bw, line.Trim('\r', '\n'));\r
213             }\r
214 \r
215             return true;\r
216         }\r
217 \r
218         bool DoWriteMaterials()\r
219         {\r
220             bw.Write(mqo.Materials.Count);\r
221 \r
222             foreach (MqoMaterial mat in mqo.Materials)\r
223             {\r
224                 MaterialInfo mat_info = materials[mat.name];\r
225                 string[] code = mat_info.GetCode();\r
226 \r
227                 WriteString(bw, mat.name);\r
228                 WriteString(bw, "cgfxShader");\r
229                 bw.Write(code.Length);\r
230 \r
231                 foreach (string line in code)\r
232                     WriteString(bw, line.Trim('\r', '\n'));\r
233 \r
234                 ImportMaterialInfo import_mat_info = new ImportMaterialInfo();\r
235                 import_mat_info.Name = mat.name;\r
236                 import_mat_info.File = "cgfxShader";\r
237                 ii.materials.Add(import_mat_info);\r
238 \r
239                 // コードを保存する\r
240                 File.WriteAllLines(Path.Combine(dir, mat.name), code);\r
241             }\r
242 \r
243             return true;\r
244         }\r
245 \r
246         bool DoWriteMeshes()\r
247         {\r
248             bw.Write(meshes.Count);\r
249 \r
250             foreach (TSOMesh mesh in meshes)\r
251             {\r
252                 WriteString(bw, mesh.Name);\r
253                 WriteMatrix(bw, mesh.Matrix);\r
254                 bw.Write(1);\r
255                 bw.Write(mesh.numsubs);\r
256 \r
257                 foreach (TSOSubMesh sub in mesh.sub_meshes)\r
258                 {\r
259                     bw.Write(sub.spec);\r
260                     bw.Write(sub.numbones);\r
261 \r
262                     foreach (int i in sub.bones)\r
263                         bw.Write(i);\r
264 \r
265                     bw.Write(sub.numvertices);\r
266 \r
267                     foreach (Vertex v in sub.vertices)\r
268                         WriteVertex(bw, v);\r
269                 }\r
270             }\r
271 \r
272             return true;\r
273         }\r
274 \r
275         bool DoOutput(string path)\r
276         {\r
277             //----- 出力処理 -----------------------------------------------\r
278             ii.materials.Clear();\r
279             ii.textures.Clear();\r
280 \r
281             using (FileStream fs = File.OpenWrite(path))\r
282             {\r
283                 fs.SetLength(0);\r
284                 bw = new BinaryWriter(fs);\r
285 \r
286                 DoWriteHeader();\r
287                 DoWriteNodeNames();\r
288                 DoWriteNodeMatrices();\r
289                 DoWriteTextures();\r
290                 DoWriteEffects();\r
291                 DoWriteMaterials();\r
292                 DoGenerateMeshes();\r
293                 DoWriteMeshes();\r
294             }\r
295 \r
296             return true;\r
297         }\r
298 \r
299         //メッシュリストを生成する。\r
300         //メッシュリストはthis.meshesに保持する。\r
301         protected abstract bool DoGenerateMeshes();\r
302 \r
303         bool DoSaveXml(string importinfo_file)\r
304         {\r
305             // 結果を保存しておく\r
306             ImportInfo.Save(importinfo_file, ii);\r
307             return true;\r
308         }\r
309 \r
310         protected virtual bool DoCleanup()\r
311         {\r
312             dir = null;\r
313             tsoref = null;\r
314             meshes = null;\r
315             mqo = null;\r
316             ii = null;\r
317             bw = null;\r
318             materials = null;\r
319             textures = null;\r
320 \r
321             System.GC.Collect();\r
322             return true;\r
323         }\r
324 \r
325         public void Generate(string mqo_file, string tsoref_file, string tsoout_file)\r
326         {\r
327             string dir = Path.GetDirectoryName(mqo_file);\r
328             string importinfo_file = Path.ChangeExtension(mqo_file, ".xml");\r
329 \r
330             try\r
331             {\r
332                 if (!SetCurrentDirectory(dir)) return;\r
333                 if (!DoLoadMQO(mqo_file)) return;\r
334                 if (!DoLoadMqx(mqo_file)) return;\r
335                 if (!DoLoadRefTSO(tsoref_file)) return;\r
336                 if (!DoLoadXml(importinfo_file)) return;\r
337                 if (!DoOutput(tsoout_file)) return;\r
338                 if (!DoSaveXml(importinfo_file)) return;\r
339             }\r
340             finally\r
341             {\r
342                 DoCleanup();\r
343             }\r
344         }\r
345 \r
346         // 参照tsoを読み込む。\r
347         // 参照tsoはthis.tsorefに保持する。\r
348         protected abstract bool DoLoadRefTSO(string path);\r
349 \r
350         #region ユーティリティ\r
351         public void WriteString(BinaryWriter bw, string s)\r
352         {\r
353             byte[] b = Encoding.Default.GetBytes(s);\r
354             bw.Write(b);\r
355             bw.Write((byte)0);\r
356         }\r
357 \r
358         public void WriteMatrix(BinaryWriter bw, Matrix44 m)\r
359         {\r
360             bw.Write(m.M11); bw.Write(m.M12); bw.Write(m.M13); bw.Write(m.M14);\r
361             bw.Write(m.M21); bw.Write(m.M22); bw.Write(m.M23); bw.Write(m.M24);\r
362             bw.Write(m.M31); bw.Write(m.M32); bw.Write(m.M33); bw.Write(m.M34);\r
363             bw.Write(m.M41); bw.Write(m.M42); bw.Write(m.M43); bw.Write(m.M44);\r
364         }\r
365 \r
366         public unsafe void WriteVertex(BinaryWriter bw, Vertex v)\r
367         {\r
368             uint idx0 = v.Idx;\r
369             byte* idx = (byte*)(&idx0);\r
370             List<int> idxs = new List<int>(4);\r
371             List<float> wgts = new List<float>(4);\r
372 \r
373             if (v.Wgt.x > 0) { idxs.Add(idx[0]); wgts.Add(v.Wgt.x); }\r
374             if (v.Wgt.y > 0) { idxs.Add(idx[1]); wgts.Add(v.Wgt.y); }\r
375             if (v.Wgt.z > 0) { idxs.Add(idx[2]); wgts.Add(v.Wgt.z); }\r
376             if (v.Wgt.w > 0) { idxs.Add(idx[3]); wgts.Add(v.Wgt.w); }\r
377 \r
378             bw.Write(v.Pos.X); bw.Write(v.Pos.Y); bw.Write(v.Pos.Z);\r
379             bw.Write(v.Nrm.X); bw.Write(v.Nrm.Y); bw.Write(v.Nrm.Z);\r
380             bw.Write(v.Tex.X); bw.Write(v.Tex.Y);\r
381 \r
382             bw.Write(wgts.Count);\r
383 \r
384             for (int i = 0, n = idxs.Count; i < n; ++i)\r
385             {\r
386                 bw.Write(idxs[i]);\r
387                 bw.Write(wgts[i]);\r
388             }\r
389         }\r
390         #endregion\r
391         #region テクスチャ処理\r
392         public TSOTex LoadTex(string file)\r
393         {\r
394             string ext = Path.GetExtension(file).ToUpper();\r
395             TSOTex tex;\r
396 \r
397             switch (ext)\r
398             {\r
399                 case ".TGA": tex = LoadTarga(file); break;\r
400                 case ".BMP": tex = LoadBitmap(file); break;\r
401                 default: throw new Exception("Unsupported texture file: " + file);\r
402             }\r
403 \r
404             for (int i = 0, n = tex.data.Length; i < n; i += tex.Depth)\r
405             {\r
406                 byte b = tex.data[i + 0];\r
407                 tex.data[i + 0] = tex.data[i + 2];\r
408                 tex.data[i + 2] = b;\r
409             }\r
410 \r
411             return tex;\r
412         }\r
413 \r
414         public unsafe TSOTex LoadTarga(string file)\r
415         {\r
416             using (FileStream fs = File.OpenRead(file))\r
417             {\r
418                 BinaryReader br = new BinaryReader(fs);\r
419                 TARGA_HEADER header;\r
420 \r
421                 Marshal.Copy(br.ReadBytes(sizeof(TARGA_HEADER)), 0, (IntPtr)(&header), sizeof(TARGA_HEADER));\r
422 \r
423                 if (header.imagetype != 0x02) throw new Exception("Invalid imagetype: " + file);\r
424                 if (header.depth != 24\r
425                 && header.depth != 32) throw new Exception("Invalid depth: " + file);\r
426 \r
427                 TSOTex tex = new TSOTex();\r
428                 tex.depth = header.depth / 8;\r
429                 tex.width = header.width;\r
430                 tex.height = header.height;\r
431                 tex.File = file;\r
432                 tex.data = br.ReadBytes(tex.width * tex.height * tex.depth);\r
433 \r
434                 return tex;\r
435             }\r
436         }\r
437 \r
438         public unsafe TSOTex LoadBitmap(string file)\r
439         {\r
440             using (FileStream fs = File.OpenRead(file))\r
441             {\r
442                 BinaryReader br = new BinaryReader(fs);\r
443                 BITMAPFILEHEADER bfh;\r
444                 BITMAPINFOHEADER bih;\r
445 \r
446                 Marshal.Copy(br.ReadBytes(sizeof(BITMAPFILEHEADER)), 0, (IntPtr)(&bfh), sizeof(BITMAPFILEHEADER));\r
447                 Marshal.Copy(br.ReadBytes(sizeof(BITMAPINFOHEADER)), 0, (IntPtr)(&bih), sizeof(BITMAPINFOHEADER));\r
448 \r
449                 if (bfh.bfType != 0x4D42) throw new Exception("Invalid imagetype: " + file);\r
450                 if (bih.biBitCount != 24\r
451                 && bih.biBitCount != 32) throw new Exception("Invalid depth: " + file);\r
452 \r
453                 TSOTex tex = new TSOTex();\r
454                 tex.depth = bih.biBitCount / 8;\r
455                 tex.width = bih.biWidth;\r
456                 tex.height = bih.biHeight;\r
457                 tex.File = file;\r
458                 tex.data = br.ReadBytes(tex.width * tex.height * tex.depth);\r
459 \r
460                 return tex;\r
461             }\r
462         }\r
463         #endregion\r
464     }\r
465 \r
466     public class TextureInfo\r
467     {\r
468         public string name;\r
469         public string file;\r
470 \r
471         public TextureInfo(string name, string file)\r
472         {\r
473             this.name = name;\r
474             this.file = file;\r
475         }\r
476     }\r
477 \r
478     public class MaterialInfo\r
479     {\r
480         string name;\r
481         string shader;\r
482         string color_tex;\r
483         string shade_tex;\r
484         //public Dictionary<string, string>   parameters;\r
485 \r
486         public MaterialInfo(string path, MqoMaterial mat, ImportMaterialInfo import_mat_info)\r
487         {\r
488             name = mat.name;\r
489             color_tex = mat.tex;\r
490 \r
491             if (import_mat_info != null)\r
492             {\r
493                 string file = Path.Combine(path, import_mat_info.Name);\r
494 \r
495                 if (File.Exists(file))\r
496                     shader = import_mat_info.Name;\r
497 \r
498                 if (import_mat_info.ShadeTex != null)\r
499                 {\r
500                     file = Path.Combine(path, import_mat_info.ShadeTex.File);\r
501 \r
502                     if (File.Exists(file))\r
503                         shade_tex = import_mat_info.ShadeTex.File;\r
504                 }\r
505             }\r
506         }\r
507 \r
508         public bool Valid\r
509         {\r
510             get\r
511             {\r
512                 return File.Exists(shader);\r
513             }\r
514         }\r
515 \r
516         public string[] GetCode()\r
517         {\r
518             TSOMaterialCode code = TSOMaterialCode.GenerateFromFile(shader);\r
519             if (color_tex != null)\r
520                 code.SetValue("ColorTex", Path.GetFileNameWithoutExtension(color_tex));\r
521             if (shade_tex != null)\r
522                 code.SetValue("ShadeTex", Path.GetFileNameWithoutExtension(shade_tex));\r
523 \r
524             List<string> line = new List<string>();\r
525             foreach (KeyValuePair<string, TSOParameter> i in code)\r
526                 line.Add(i.Value.ToString());\r
527 \r
528             return line.ToArray();\r
529         }\r
530 \r
531         public string Name { get { return name; } }\r
532 \r
533         [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\r
534         [DisplayNameAttribute("シェーダー設定ファイル")]\r
535         public string ShaderFile { get { return shader; } set { shader = value; } }\r
536 \r
537         [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\r
538         [DisplayNameAttribute("テクスチャ:カラー")]\r
539         public string ColorTexture { get { return color_tex; } set { color_tex = value; } }\r
540 \r
541         [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\r
542         [DisplayNameAttribute("テクスチャ:シェーティング")]\r
543         public string ShadeTexture { get { return shade_tex; } set { shade_tex = value; } }\r
544     }\r
545 }\r