OSDN Git Service

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