OSDN Git Service

refactored
[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;\r
9 using System.Windows.Forms.Design;\r
10 \r
11 namespace Tso2MqoGui\r
12 {\r
13     public unsafe class TSOGenerator\r
14     {\r
15         private string                      dir;\r
16         private TSOGenerateConfig           config;\r
17         private PointCluster                pc;\r
18         private MqoFile                     mqo;\r
19         private TSOFile                     tsor;\r
20         private List<Vertex>                vlst;\r
21         private Dictionary<string, TSONode> nodes;\r
22         private List<TSOMesh>               meshes;\r
23         private string                      mqoin;\r
24         private string                      tsoref;\r
25         private string                      tsoex;\r
26         private ImportInfo                  ii;\r
27         private BinaryWriter                bw;\r
28         private Dictionary<string, MaterialInfo>    materials;\r
29         private Dictionary<string, TextureInfo>     textures;\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         private void CreatePointCluster(TSOFile tso)\r
39         {\r
40             vlst= new List<Vertex>();\r
41 \r
42             foreach(TSOMesh i in tso.meshes)\r
43             foreach(TSOSubMesh j in i.sub)\r
44                 vlst.AddRange(j.vertices);\r
45 \r
46             pc  = new PointCluster(vlst.Count);\r
47 \r
48             foreach(Vertex i in vlst)\r
49                 pc.Add(i.Pos.x, i.Pos.y, i.Pos.z);\r
50 \r
51             pc.Clustering();\r
52         }\r
53 \r
54         private bool Common_DoSetupDir()\r
55         {\r
56             Environment.CurrentDirectory= dir= Path.GetDirectoryName(mqoin);\r
57             return true;\r
58         }\r
59 \r
60         private bool Common_DoLoadMQO()\r
61         {\r
62             // MQO読み込み\r
63             mqo = new MqoFile();\r
64             mqo.Load(mqoin);\r
65             mqo.Dump();\r
66             return true;\r
67         }\r
68 \r
69         private bool AutoBone_DoLoadRefTSO()\r
70         {\r
71             // 参照TSOロード\r
72             tsor    = LoadTSO(tsoref);\r
73 \r
74             foreach(TSOMesh i in tsor.meshes)\r
75             foreach(TSOSubMesh j in i.sub)\r
76             {\r
77                 int[]   bones   = j.bones;\r
78 \r
79                 for(int k= 0, n= j.numvertices; k < n; ++k)\r
80                 {\r
81                     // ボーンをグローバルな番号に変換\r
82                     uint    idx0= j.vertices[k].Idx;\r
83                     byte*   idx = (byte*)(&idx0);\r
84                     idx[0]      = (byte)bones[idx[0]];\r
85                     idx[1]      = (byte)bones[idx[1]];\r
86                     idx[2]      = (byte)bones[idx[2]];\r
87                     idx[3]      = (byte)bones[idx[3]];\r
88                     j.vertices[k].Idx   = idx0;\r
89                 }\r
90             }\r
91 \r
92             CreatePointCluster(tsor);\r
93             return true;\r
94         }\r
95 \r
96         private bool OneBone_DoLoadRefTSO()\r
97         {\r
98             // 参照TSOロード\r
99             tsor    = LoadTSO(tsoref);\r
100             return true;\r
101         }\r
102 \r
103         private bool Common_DoLoadXml()\r
104         {\r
105             // XML読み込み\r
106             ii  = ImportInfo.Load(Path.ChangeExtension(mqoin, ".xml"));\r
107 \r
108             // 使用マテリアル一覧取得\r
109             materials       = new Dictionary<string, MaterialInfo>();\r
110             bool    validmap= true;\r
111 \r
112             foreach(MqoMaterial i in mqo.Materials)\r
113             {\r
114                 MaterialInfo    mi  = new MaterialInfo(dir, i, ii.GetMaterial(i.name));\r
115                 validmap            &=mi.Valid;\r
116                 materials.Add(i.name, mi);\r
117             }\r
118 \r
119             if(!validmap || config.materialconfig)\r
120             {\r
121                 if(config.cui)\r
122                     throw new Exception("マテリアルの設定が無効です");\r
123 \r
124                 FormMaterial    dlg = new FormMaterial();\r
125                 dlg.materials       = materials;\r
126 \r
127                 if(dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)\r
128                     return false;\r
129             }\r
130 \r
131             // 使用テクスチャ一覧の取得\r
132             textures        = new Dictionary<string, TextureInfo>();\r
133 \r
134             foreach(MaterialInfo i in materials.Values)\r
135             {\r
136                 string  name= Path.GetFileNameWithoutExtension(i.diffuse);\r
137 \r
138                 if(!textures.ContainsKey(name))\r
139                     textures.Add(name, new TextureInfo(name, i.diffuse));\r
140 \r
141                 name        = Path.GetFileNameWithoutExtension(i.shadow);\r
142 \r
143                 if(!textures.ContainsKey(name))\r
144                     textures.Add(name, new TextureInfo(name, i.shadow));\r
145             }\r
146 \r
147             return true;\r
148         }\r
149 \r
150         private bool Common_DoWriteHeader()\r
151         {\r
152             bw.Write(0x314F5354);\r
153             return true;\r
154         }\r
155 \r
156         private bool Common_DoWriteNodeNames()\r
157         {\r
158             bw.Write(tsor.nodes.Length);\r
159 \r
160             nodes   = new Dictionary<string,TSONode>();\r
161 \r
162             foreach(TSONode i in tsor.nodes)\r
163             {\r
164                 WriteString(bw, i.Name);\r
165                 nodes.Add(i.ShortName, i);\r
166             }\r
167 \r
168             return true;\r
169         }\r
170 \r
171         private bool Common_DoWriteNodeMatrices()\r
172         {\r
173             bw.Write(tsor.nodes.Length);\r
174 \r
175             foreach(TSONode i in tsor.nodes)\r
176                 WriteMatrix(bw, i.Matrix);\r
177 \r
178             return true;\r
179         }\r
180 \r
181         private bool Common_DoWriteTextures()\r
182         {\r
183             bw.Write(textures.Count);\r
184 \r
185             foreach(TextureInfo i in textures.Values)\r
186             {\r
187                 string  file= i.file;\r
188                 string  name= i.name;\r
189 \r
190                 WriteString(bw, name);\r
191                 WriteString(bw, "\"" + Path.GetFileName(file) + "\"");\r
192 \r
193                 // テクスチャの読み込み\r
194                 TSOTex  tex = LoadTex(file);\r
195                 tex.name    = name;\r
196                 bw.Write(tex.Width);\r
197                 bw.Write(tex.Height);\r
198                 bw.Write(tex.Depth);\r
199                 bw.Write(tex.data, 0, tex.data.Length);\r
200 \r
201                 ImportTextureInfo   iti = new ImportTextureInfo(tex);\r
202                 ii.textures.Add(iti);\r
203 \r
204                 // テクスチャが同じフォルダにない場合、コピーしておく\r
205                 if(Path.GetDirectoryName(file).ToUpper() != dir.ToUpper())\r
206                 {\r
207                     iti.File    = Path.Combine(dir, Path.GetFileName(file));\r
208                     File.Copy(file, iti.File, true);\r
209                 }\r
210             }\r
211 \r
212             return true;\r
213         }\r
214 \r
215         private bool Common_DoWriteEffects()\r
216         {\r
217             bw.Write(ii.effects.Count);\r
218 \r
219             foreach(ImportEffectInfo i in ii.effects)\r
220             {\r
221                 string      file= Path.Combine(dir, i.Name);\r
222                 string[]    code= File.ReadAllLines(file, Encoding.Default);\r
223 \r
224                 WriteString(bw, i.Name);\r
225                 bw.Write(code.Length);\r
226 \r
227                 foreach(string j in code)\r
228                     WriteString(bw, j.Trim('\r', '\n'));\r
229             }\r
230 \r
231             return true;\r
232         }\r
233 \r
234         private bool Common_DoWriteMaterials()\r
235         {\r
236             bw.Write(mqo.Materials.Count);\r
237 \r
238             foreach(MqoMaterial i in mqo.Materials)\r
239             {\r
240                 MaterialInfo    mi  = materials[i.name];\r
241                 string[]        code= mi.GetCode();\r
242 \r
243                 WriteString(bw, i.name);\r
244                 WriteString(bw, "cgfxShader");\r
245                 bw.Write(code.Length);\r
246 \r
247                 foreach(string j in code)\r
248                     WriteString(bw, j.Trim('\r', '\n'));\r
249 \r
250                 ImportMaterialInfo  imi = new ImportMaterialInfo();\r
251                 imi.Name                = i.name;\r
252                 imi.File                = "cgfxShader";\r
253                 ii.materials.Add(imi);\r
254 \r
255                 // コードを保存する\r
256                 File.WriteAllLines(Path.Combine(dir, i.name), code);\r
257             }\r
258 \r
259             return true;\r
260         }\r
261 \r
262         private bool AutoBone_DoGenerateMeshes()\r
263         {\r
264             meshes  = new List<TSOMesh>();\r
265 \r
266             foreach(MqoObject i in mqo.Objects)\r
267             {\r
268                 if(i.name.ToLower() == "bone")\r
269                     continue;\r
270 \r
271                 Console.WriteLine("object:" + i.name);\r
272 \r
273                 // 一番近い頂点への参照\r
274                 List<int>       vref= new List<int>(i.vertices.Count);\r
275 \r
276                 foreach(Point3 j in i.vertices)\r
277                     vref.Add(pc.NearestIndex(j.x, j.y, j.z));\r
278 \r
279                 // 法線生成\r
280                 Point3[]        nrm = new Point3[i.vertices.Count];\r
281                 \r
282                 foreach(MqoFace j in i.faces)\r
283                 {\r
284                     Point3  v1  = Point3.Normalize(i.vertices[j.b] - i.vertices[j.a]);\r
285                     Point3  v2  = Point3.Normalize(i.vertices[j.c] - i.vertices[j.b]);\r
286                     Point3  n   = Point3.Normalize(Point3.Cross(v1, v2));\r
287 \r
288                     nrm[j.a]    -=n;\r
289                     nrm[j.b]    -=n;\r
290                     nrm[j.c]    -=n;\r
291                 }\r
292 \r
293                 for(int j= 0; j < nrm.Length; ++j)\r
294                     nrm[j]      = Point3.Normalize(nrm[j]);\r
295 \r
296                 // フェイスの組成\r
297                 List<int>               faces1  = new List<int>();\r
298                 List<int>               faces2  = new List<int>();\r
299               //int[]                   bonecnv = new int[tsor.nodes.Length];   // ボーン変換テーブル\r
300                 VertexHeap<Vertex>      vh      = new VertexHeap<Vertex>();\r
301                 Vertex[]                v       = new Vertex[3];\r
302                 List<int>               bones   = new List<int>(16);\r
303                 List<ushort>            indices = new List<ushort>();\r
304                 Dictionary<int, int>    selected= new Dictionary<int,int>();\r
305                 Dictionary<int, int>    work    = new Dictionary<int,int>();\r
306                 List<TSOSubMesh>        subs    = new List<TSOSubMesh>();\r
307 \r
308                 for(int j= 0, n= i.faces.Count; j < n; ++j)\r
309                     faces1.Add(j);\r
310 \r
311 #region ボーンパーティション\r
312                 Console.WriteLine("  vertices bone_indices");\r
313                 Console.WriteLine("  -------- ------------");\r
314 \r
315                 while (faces1.Count > 0)\r
316                 {\r
317                     int                 mtl     = i.faces[faces1[0]].mtl;\r
318                     selected.Clear();\r
319                     indices .Clear();\r
320                     vh      .Clear();\r
321                     bones   .Clear();\r
322 \r
323                     foreach(int j in faces1)\r
324                     {\r
325                         MqoFace         f       = i.faces[j];\r
326 \r
327                         if(f.mtl != mtl)\r
328                         {\r
329                             faces2.Add(j);\r
330                             continue;\r
331                         }\r
332 \r
333                         v[0]                    = vlst[vref[f.a]];\r
334                         v[1]                    = vlst[vref[f.b]];\r
335                         v[2]                    = vlst[vref[f.c]];\r
336 \r
337                         work.Clear();\r
338 \r
339                         for(int k= 0; k < 3; ++k)\r
340                         {\r
341                             Vertex      vv      = v[k];\r
342                             UInt32      idx0    = vv.Idx;\r
343                             Point4      wgt0    = vv.Wgt;\r
344                             byte*       idx     = (byte*)(&idx0);\r
345                             float*      wgt     = (float*)(&wgt0);\r
346 \r
347                             for(int l= 0; l < 4; ++l)\r
348                             {\r
349                                 if(wgt[l] <= float.Epsilon)         continue;\r
350                                 if(selected.ContainsKey(idx[l]))    continue;\r
351                                 \r
352                                 if(!work.ContainsKey(idx[l]))\r
353                                     work.Add(idx[l], 0);\r
354                             }\r
355                         }\r
356 \r
357                         if (selected.Count + work.Count > 16)\r
358                         {\r
359                             faces2.Add(j);\r
360                             continue;\r
361                         }\r
362 \r
363                         // ボーンリストに足してvalid\r
364                         foreach(KeyValuePair<int, int> l in work)\r
365                         {\r
366                             selected.Add(l.Key, selected.Count);    // ボーンテーブルに追加\r
367                             bones.Add(l.Key);\r
368                         }\r
369 \r
370                         // \todo 点の追加\r
371                         Vertex  va  = new Vertex(i.vertices[f.a], v[0].Wgt, v[0].Idx, nrm[f.a], new Point2(f.ta.x, 1-f.ta.y));\r
372                         Vertex  vb  = new Vertex(i.vertices[f.b], v[1].Wgt, v[1].Idx, nrm[f.b], new Point2(f.tb.x, 1-f.tb.y));\r
373                         Vertex  vc  = new Vertex(i.vertices[f.c], v[2].Wgt, v[2].Idx, nrm[f.c], new Point2(f.tc.x, 1-f.tc.y));\r
374 \r
375                         indices.Add(vh.Add(va));\r
376                         indices.Add(vh.Add(vc));\r
377                         indices.Add(vh.Add(vb));\r
378                     }\r
379 \r
380                     // フェイス最適化\r
381                     ushort[]    nidx    = NvTriStrip.Optimize(indices.ToArray());\r
382 \r
383                     // 頂点のボーン参照ローカルに変換\r
384                     Vertex[]    verts   = vh.verts.ToArray();\r
385 \r
386                     for(int j= 0; j < verts.Length; ++j)\r
387                     {\r
388                         uint        idx0= verts[j].Idx;\r
389                         byte*       idx = (byte*)(&idx0);\r
390                         Point4      wgt0= verts[j].Wgt;\r
391                         float*      wgt = (float*)(&wgt0);\r
392 \r
393                         for(int k= 0; k < 4; ++k)\r
394                             if(wgt[k] > float.Epsilon)\r
395                                 idx[k]  = (byte)selected[idx[k]];\r
396 \r
397                         verts[j].Idx    = idx0;\r
398                     }\r
399 \r
400                     // サブメッシュ生成\r
401                     TSOSubMesh  sub = new TSOSubMesh();\r
402                     sub.spec        = mtl;\r
403                     sub.numbones    = bones.Count;\r
404                     sub.bones       = bones.ToArray();\r
405                     sub.numvertices = nidx.Length;\r
406                     sub.vertices    = new Vertex[nidx.Length];\r
407                    \r
408                     for(int j= 0; j < nidx.Length; ++j)\r
409                         sub.vertices[j] = verts[nidx[j]];\r
410 \r
411                     Console.WriteLine("  {0,8} {1,12}", sub.vertices.Length, sub.bones.Length);\r
412 \r
413                     subs.Add(sub);\r
414 \r
415                     // 次の周回\r
416                     List<int>   t   = faces1;\r
417                     faces1          = faces2;\r
418                     faces2          = t;\r
419                     t.Clear();\r
420                 }\r
421 #endregion\r
422                 // \todo TSOMesh生成\r
423                 TSOMesh mesh    = new TSOMesh();\r
424                 mesh.name       = i.name;\r
425                 mesh.numsubs    = subs.Count;\r
426                 mesh.sub        = subs.ToArray();\r
427                 mesh.matrix     = Matrix44.Identity;\r
428                 mesh.effect     = 0;\r
429                 meshes.Add(mesh);\r
430             }\r
431 \r
432             return true;\r
433         }\r
434 \r
435         private bool OneBone_DoGenerateMeshes()\r
436         {\r
437             meshes  = new List<TSOMesh>();\r
438 \r
439             foreach(MqoObject i in mqo.Objects)\r
440             {\r
441                 if(i.name.ToLower() == "bone")\r
442                     continue;\r
443 \r
444                 Console.WriteLine("object:" + i.name);\r
445 \r
446                 // 法線生成\r
447                 Point3[]        nrm = new Point3[i.vertices.Count];\r
448                 \r
449                 foreach(MqoFace j in i.faces)\r
450                 {\r
451                     Point3  v1  = Point3.Normalize(i.vertices[j.b] - i.vertices[j.a]);\r
452                     Point3  v2  = Point3.Normalize(i.vertices[j.c] - i.vertices[j.b]);\r
453                     Point3  n   = Point3.Normalize(Point3.Cross(v1, v2));\r
454                     nrm[j.a]    -=n;\r
455                     nrm[j.b]    -=n;\r
456                     nrm[j.c]    -=n;\r
457                 }\r
458 \r
459                 for(int j= 0; j < nrm.Length; ++j)\r
460                     nrm[j]      = Point3.Normalize(nrm[j]);\r
461 \r
462                 // ボーン情報作成\r
463                 uint                idx     = 0x00000000;\r
464                 Point4              wgt     = new Point4(1, 0, 0, 0);\r
465                 int[]               bones   = new int[1];\r
466                 string              bone    = config.boneref[i.name];\r
467                 bones[0]                    = nodes[bone].ID;\r
468 \r
469                 // マテリアル別に処理を実行\r
470                 List<ushort>        indices = new List<ushort>();\r
471                 VertexHeap<Vertex>  vh      = new VertexHeap<Vertex>();\r
472                 List<TSOSubMesh>    subs    = new List<TSOSubMesh>();\r
473 \r
474                 for(int j= 0, n= materials.Count; j < n; ++j)\r
475                 {\r
476                     int mtl = j;\r
477                     indices.Clear();\r
478 \r
479                     foreach(MqoFace f in i.faces)\r
480                     {\r
481                         if(f.mtl != mtl)\r
482                             continue;\r
483 \r
484                         Vertex  va  = new Vertex(i.vertices[f.a], wgt, idx, nrm[f.a], new Point2(f.ta.x, 1-f.ta.y));\r
485                         Vertex  vb  = new Vertex(i.vertices[f.b], wgt, idx, nrm[f.b], new Point2(f.tb.x, 1-f.tb.y));\r
486                         Vertex  vc  = new Vertex(i.vertices[f.c], wgt, idx, nrm[f.c], new Point2(f.tc.x, 1-f.tc.y));\r
487 \r
488                         indices.Add(vh.Add(va));\r
489                         indices.Add(vh.Add(vc));\r
490                         indices.Add(vh.Add(vb));\r
491                     }\r
492 \r
493                     if(indices.Count == 0)\r
494                         continue;\r
495 \r
496                     // フェイス最適化\r
497                     ushort[]    nidx    = NvTriStrip.Optimize(indices.ToArray());\r
498 \r
499                     // サブメッシュ生成\r
500                     Vertex[]    verts= vh.verts.ToArray();\r
501                     TSOSubMesh  sub = new TSOSubMesh();\r
502                     sub.spec        = mtl;\r
503                     sub.numbones    = bones.Length;\r
504                     sub.bones       = bones;\r
505                     sub.numvertices = nidx.Length;\r
506                     sub.vertices    = new Vertex[nidx.Length];\r
507                    \r
508                     for(int k= 0; k < nidx.Length; ++k)\r
509                         sub.vertices[k] = verts[nidx[k]];\r
510 \r
511                     subs.Add(sub);\r
512                 }\r
513 \r
514                 // メッシュ生成\r
515                 TSOMesh mesh    = new TSOMesh();\r
516                 mesh.name       = i.name;\r
517                 mesh.numsubs    = subs.Count;\r
518                 mesh.sub        = subs.ToArray();\r
519                 mesh.matrix     = Matrix44.Identity;\r
520                 mesh.effect     = 0;\r
521                 meshes.Add(mesh);\r
522             }\r
523 \r
524             return true;\r
525         }\r
526 \r
527         private bool Common_DoWriteMeshes()\r
528         {\r
529             bw.Write(meshes.Count);\r
530 \r
531             foreach(TSOMesh i in meshes)\r
532             {\r
533                 WriteString(bw, i.Name);\r
534                 WriteMatrix(bw, i.Matrix);\r
535                 bw.Write(1);\r
536                 bw.Write(i.numsubs);\r
537 \r
538                 foreach(TSOSubMesh j in i.sub)\r
539                 {\r
540                     bw.Write(j.spec);\r
541                     bw.Write(j.numbones);\r
542 \r
543                     foreach(int k in j.bones)\r
544                         bw.Write(k);\r
545 \r
546                     bw.Write(j.numvertices);\r
547 \r
548                     foreach(Vertex k in j.vertices)\r
549                         WriteVertex(bw, k);\r
550                 }\r
551             }\r
552 \r
553             return true;\r
554         }\r
555 \r
556         private bool AutoBone_DoOutput()\r
557         {\r
558             //----- 出力処理 -----------------------------------------------\r
559             ii.materials.Clear();\r
560             ii.textures.Clear();\r
561 \r
562             using(FileStream fs= File.OpenWrite(tsoex))\r
563             {\r
564                 fs.SetLength(0);\r
565                 bw      = new BinaryWriter(fs);\r
566 \r
567                 Common_DoWriteHeader();\r
568                 Common_DoWriteNodeNames();\r
569                 Common_DoWriteNodeMatrices();\r
570                 Common_DoWriteTextures();\r
571                 Common_DoWriteEffects();\r
572                 Common_DoWriteMaterials();\r
573                 AutoBone_DoGenerateMeshes();\r
574                 Common_DoWriteMeshes();\r
575             }\r
576 \r
577             return true;\r
578         }\r
579 \r
580         private bool OneBone_DoOutput()\r
581         {\r
582             //----- 出力処理 -----------------------------------------------\r
583             ii.materials.Clear();\r
584             ii.textures.Clear();\r
585 \r
586             using(FileStream fs= File.OpenWrite(tsoex))\r
587             {\r
588                 fs.SetLength(0);\r
589                 bw      = new BinaryWriter(fs);\r
590 \r
591                 Common_DoWriteHeader();\r
592                 Common_DoWriteNodeNames();\r
593                 Common_DoWriteNodeMatrices();\r
594                 Common_DoWriteTextures();\r
595                 Common_DoWriteEffects();\r
596                 Common_DoWriteMaterials();\r
597                 OneBone_DoGenerateMeshes();\r
598                 Common_DoWriteMeshes();\r
599             }\r
600 \r
601             return true;\r
602         }\r
603 \r
604         private bool Common_DoSaveXml()\r
605         {\r
606             // 結果を保存しておく\r
607             ImportInfo.Save(Path.ChangeExtension(mqoin, ".xml"), ii);\r
608             return true;\r
609         }\r
610 \r
611         private bool Common_DoCleanup()\r
612         {\r
613             dir         = null;\r
614             pc          = null;\r
615             tsor        = null;\r
616             vlst        = null;\r
617             nodes       = null;\r
618             meshes      = null;\r
619             mqoin       = null;\r
620             tsoref      = null;\r
621             tsoex       = null;\r
622             config      = null;\r
623             mqo         = null;\r
624             ii          = null;\r
625             bw          = null;\r
626             materials   = null;\r
627             textures    = null;\r
628 \r
629             System.GC.Collect();\r
630             return true;\r
631         }\r
632 \r
633         public unsafe void GenerateOneBone(string mqoin, string tsoref, string tsoex, TSOGenerateConfig config)\r
634         {\r
635             this.mqoin  = mqoin;\r
636             this.tsoref = tsoref;\r
637             this.tsoex  = tsoex;\r
638             this.config = config;\r
639 \r
640             try\r
641             {\r
642                 if(!Common_DoSetupDir())        return;\r
643                 if(!Common_DoLoadMQO())         return;\r
644                 if(!OneBone_DoLoadRefTSO())     return;\r
645                 if(!Common_DoLoadXml())         return;\r
646                 if(!OneBone_DoOutput())         return;\r
647                 if(!Common_DoSaveXml())         return;\r
648             } finally\r
649             {\r
650                 Common_DoCleanup();\r
651             }\r
652         }\r
653         \r
654         public unsafe void GenerateAutoBone(string mqoin, string tsoref, string tsoex, TSOGenerateConfig config)\r
655         {\r
656             this.mqoin  = mqoin;\r
657             this.tsoref = tsoref;\r
658             this.tsoex  = tsoex;\r
659             this.config = config;\r
660 \r
661             try\r
662             {\r
663                 if(!Common_DoSetupDir())        return;\r
664                 if(!Common_DoLoadMQO())         return;\r
665                 if(!AutoBone_DoLoadRefTSO())    return;\r
666                 if(!Common_DoLoadXml())         return;\r
667                 if(!AutoBone_DoOutput())        return;\r
668                 if(!Common_DoSaveXml())         return;\r
669             } finally\r
670             {\r
671                 Common_DoCleanup();\r
672             }\r
673         }\r
674 #region ユーティリティ\r
675         public void WriteString(BinaryWriter bw, string s)\r
676         {\r
677             byte[]  b   = Encoding.Default.GetBytes(s);\r
678             bw.Write(b);\r
679             bw.Write((byte)0);\r
680         }\r
681 \r
682         public void WriteMatrix(BinaryWriter bw, Matrix44 m)\r
683         {\r
684             bw.Write(m.M11); bw.Write(m.M12); bw.Write(m.M13); bw.Write(m.M14);\r
685             bw.Write(m.M21); bw.Write(m.M22); bw.Write(m.M23); bw.Write(m.M24);\r
686             bw.Write(m.M31); bw.Write(m.M32); bw.Write(m.M33); bw.Write(m.M34);\r
687             bw.Write(m.M41); bw.Write(m.M42); bw.Write(m.M43); bw.Write(m.M44);\r
688         }\r
689 \r
690         public unsafe void WriteVertex(BinaryWriter bw, Vertex v)\r
691         {\r
692             uint        idx0    = v.Idx;\r
693             byte*       idx     = (byte*)(&idx0);\r
694             List<int>   idxs    = new List<int>(4);\r
695             List<float> wgts    = new List<float>(4);\r
696 \r
697             if(v.Wgt.x > 0) { idxs.Add(idx[0]); wgts.Add(v.Wgt.x); }\r
698             if(v.Wgt.y > 0) { idxs.Add(idx[1]); wgts.Add(v.Wgt.y); }\r
699             if(v.Wgt.z > 0) { idxs.Add(idx[2]); wgts.Add(v.Wgt.z); }\r
700             if(v.Wgt.w > 0) { idxs.Add(idx[3]); wgts.Add(v.Wgt.w); }\r
701 \r
702             bw.Write(v.Pos.X); bw.Write(v.Pos.Y); bw.Write(v.Pos.Z);\r
703             bw.Write(v.Nrm.X); bw.Write(v.Nrm.Y); bw.Write(v.Nrm.Z);\r
704             bw.Write(v.Tex.X); bw.Write(v.Tex.Y);\r
705 \r
706             bw.Write(wgts.Count);\r
707 \r
708             for(int i= 0, n= idxs.Count; i < n; ++i)\r
709             {\r
710                 bw.Write(idxs[i]);\r
711                 bw.Write(wgts[i]);\r
712             }\r
713         }\r
714 #endregion\r
715 #region テクスチャ処理\r
716         public TSOTex   LoadTex(string file)\r
717         {\r
718             string  ext = Path.GetExtension(file).ToUpper();\r
719             TSOTex  tex;\r
720 \r
721             switch(ext)\r
722             {\r
723             case ".TGA":    tex= LoadTarga(file);   break;\r
724             case ".BMP":    tex= LoadBitmap(file);  break;\r
725             default:        throw new Exception("Unsupported texture file: " + file);\r
726             }\r
727 \r
728             for(int i= 0, n= tex.data.Length; i < n; i+=tex.Depth)\r
729             {\r
730                 byte    b       = tex.data[i+0];\r
731                 tex.data[i+0]   = tex.data[i+2];\r
732                 tex.data[i+2]   = b;\r
733             }\r
734 \r
735             return tex;\r
736         }\r
737 \r
738         public unsafe TSOTex   LoadTarga(string file)\r
739         {\r
740             using(FileStream fs= File.OpenRead(file))\r
741             {\r
742                 BinaryReader        br      = new BinaryReader(fs);\r
743                 TARGA_HEADER        header;\r
744 \r
745                 Marshal.Copy(br.ReadBytes(sizeof(TARGA_HEADER)), 0, (IntPtr)(&header), sizeof(TARGA_HEADER));\r
746 \r
747                 if(header.imagetype != 0x02)    throw new Exception("Invalid imagetype: " + file);\r
748                 if(header.depth     != 24\r
749                 && header.depth     != 32)      throw new Exception("Invalid depth: " + file);\r
750                 \r
751                 TSOTex      tex = new TSOTex();\r
752                 tex.depth       = header.depth  / 8;\r
753                 tex.width       = header.width;\r
754                 tex.height      = header.height;\r
755                 tex.file        = file;\r
756                 tex.data        = br.ReadBytes(tex.width * tex.height * tex.depth);\r
757 \r
758                 return tex;\r
759             }\r
760         }\r
761 \r
762         public unsafe TSOTex   LoadBitmap(string file)\r
763         {\r
764             using(FileStream fs= File.OpenRead(file))\r
765             {\r
766                 BinaryReader        br      = new BinaryReader(fs);\r
767                 BITMAPFILEHEADER    bfh;\r
768                 BITMAPINFOHEADER    bih;\r
769 \r
770                 Marshal.Copy(br.ReadBytes(sizeof(BITMAPFILEHEADER)), 0, (IntPtr)(&bfh), sizeof(BITMAPFILEHEADER));\r
771                 Marshal.Copy(br.ReadBytes(sizeof(BITMAPINFOHEADER)), 0, (IntPtr)(&bih), sizeof(BITMAPINFOHEADER));\r
772 \r
773                 if(bfh.bfType != 0x4D42)        throw new Exception("Invalid imagetype: " + file);\r
774                 if(bih.biBitCount != 24\r
775                 && bih.biBitCount != 32)        throw new Exception("Invalid depth: " + file);\r
776                 \r
777                 TSOTex      tex = new TSOTex();\r
778                 tex.depth       = bih.biBitCount  / 8;\r
779                 tex.width       = bih.biWidth;\r
780                 tex.height      = bih.biHeight;\r
781                 tex.file        = file;\r
782                 tex.data        = br.ReadBytes(tex.width * tex.height * tex.depth);\r
783 \r
784                 return tex;\r
785             }\r
786         }\r
787 #endregion\r
788     }\r
789 \r
790     public class TextureInfo\r
791     {\r
792         public string name;\r
793         public string file;\r
794 \r
795         public TextureInfo(string name, string file)\r
796         {\r
797             this.name   = name;\r
798             this.file   = file;\r
799         }\r
800     }\r
801 \r
802     public class MaterialInfo\r
803     {\r
804         public string           name;\r
805         public string           shader;\r
806         public string           diffuse;\r
807         public string           shadow;\r
808       //public Dictionary<string, string>   parameters;\r
809 \r
810         public MaterialInfo(string path, MqoMaterial mqom, ImportMaterialInfo impm)\r
811         {\r
812             name    = mqom.name;\r
813             diffuse = mqom.tex;\r
814 \r
815             if(impm != null)\r
816             {\r
817                 string  file= Path.Combine(path, impm.Name);\r
818 \r
819                 if(File.Exists(file))\r
820                     shader          = file;\r
821 \r
822                 if(impm.shadow != null)\r
823                 {\r
824                     file        = Path.Combine(path, impm.shadow.File);\r
825 \r
826                     if(File.Exists(file))\r
827                         shadow  = file;\r
828                 }\r
829             }\r
830         }\r
831 \r
832         public bool   Valid\r
833         {\r
834             get\r
835             {\r
836                 return File.Exists(shader)\r
837                     && File.Exists(diffuse)\r
838                     && File.Exists(shadow);\r
839             }\r
840         }\r
841 \r
842         public string[] GetCode()\r
843         {\r
844             TSOMaterialCode code= TSOMaterialCode.GenerateFromFile(shader);\r
845             List<string>    line= new List<string>();\r
846 \r
847             code.SetValue("ColorTex", Path.GetFileNameWithoutExtension(diffuse));\r
848             code.SetValue("ShadeTex", Path.GetFileNameWithoutExtension(shadow));\r
849 \r
850             foreach(KeyValuePair<string, TSOParameter> i in code)\r
851                 line.Add(i.Value.ToString());\r
852 \r
853             return line.ToArray();\r
854         }\r
855 \r
856         public string Name           { get { return name;    } }\r
857         \r
858         [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\r
859         [DisplayNameAttribute("シェーダー設定ファイル")]\r
860         public string ShaderFile     { get { return shader;  } set { shader  = value; } }\r
861         \r
862         [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\r
863         [DisplayNameAttribute("テクスチャ:カラー")]\r
864         public string DiffuseTexture { get { return diffuse; } set { diffuse = value; } }\r
865 \r
866         [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]\r
867         [DisplayNameAttribute("テクスチャ:シェーティング")]\r
868         public string ShadowTexture  { get { return shadow;  } set { shadow  = value; } }\r
869     }\r
870 }\r