2 using System.Collections.Generic;
\r
3 using System.Drawing.Design;
\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
11 namespace Tso2MqoGui
\r
13 public abstract class TSOGenerator
\r
16 private TSOGenerateConfig config;
\r
17 protected MqoFile mqo;
\r
18 protected TSOFile tsor;
\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
26 public TSOFile LoadTSO(string file)
\r
28 TSOFile tso = new TSOFile(file);
\r
33 private bool DoSetupDir(string mqoin)
\r
35 dir = Path.GetDirectoryName(mqoin);
\r
36 Environment.CurrentDirectory = dir;
\r
40 private bool DoLoadMQO(string mqoin)
\r
43 mqo = new MqoFile();
\r
49 private bool DoLoadXml(string importinfo_file)
\r
52 ii = ImportInfo.Load(importinfo_file);
\r
55 materials = new Dictionary<string, MaterialInfo>();
\r
56 bool validmap = true;
\r
58 foreach (MqoMaterial i in mqo.Materials)
\r
60 MaterialInfo mi = new MaterialInfo(dir, i, ii.GetMaterial(i.name));
\r
61 validmap &= mi.Valid;
\r
62 materials.Add(i.name, mi);
\r
65 if (!validmap || config.ShowMaterials)
\r
68 throw new Exception("マテリアルの設定が無効です");
\r
70 FormMaterial dlg = new FormMaterial();
\r
71 dlg.materials = materials;
\r
73 if (dlg.ShowDialog() != System.Windows.Forms.DialogResult.OK)
\r
78 textures = new Dictionary<string, TextureInfo>();
\r
80 foreach (MaterialInfo i in materials.Values)
\r
82 string name = Path.GetFileNameWithoutExtension(i.diffuse);
\r
84 if (!textures.ContainsKey(name))
\r
85 textures.Add(name, new TextureInfo(name, i.diffuse));
\r
87 name = Path.GetFileNameWithoutExtension(i.shadow);
\r
89 if (!textures.ContainsKey(name))
\r
90 textures.Add(name, new TextureInfo(name, i.shadow));
\r
96 private bool DoWriteHeader()
\r
98 bw.Write(0x314F5354);
\r
102 private bool DoWriteNodeNames()
\r
104 bw.Write(tsor.nodes.Length);
\r
106 nodes = new Dictionary<string,TSONode>();
\r
108 foreach(TSONode i in tsor.nodes)
\r
110 WriteString(bw, i.Name);
\r
111 nodes.Add(i.ShortName, i);
\r
117 private bool DoWriteNodeMatrices()
\r
119 bw.Write(tsor.nodes.Length);
\r
121 foreach(TSONode i in tsor.nodes)
\r
122 WriteMatrix(bw, i.Matrix);
\r
127 private bool DoWriteTextures()
\r
129 bw.Write(textures.Count);
\r
131 foreach(TextureInfo i in textures.Values)
\r
133 string file= i.file;
\r
134 string name= i.name;
\r
136 WriteString(bw, name);
\r
137 WriteString(bw, "\"" + Path.GetFileName(file) + "\"");
\r
140 TSOTex tex = LoadTex(file);
\r
142 bw.Write(tex.Width);
\r
143 bw.Write(tex.Height);
\r
144 bw.Write(tex.Depth);
\r
145 bw.Write(tex.data, 0, tex.data.Length);
\r
147 ImportTextureInfo iti = new ImportTextureInfo(tex);
\r
148 ii.textures.Add(iti);
\r
150 // テクスチャが同じフォルダにない場合、コピーしておく
\r
151 if(Path.GetDirectoryName(file).ToUpper() != dir.ToUpper())
\r
153 iti.File = Path.Combine(dir, Path.GetFileName(file));
\r
154 File.Copy(file, iti.File, true);
\r
161 private bool DoWriteEffects()
\r
163 bw.Write(ii.effects.Count);
\r
165 foreach(ImportEffectInfo i in ii.effects)
\r
167 string file= Path.Combine(dir, i.Name);
\r
168 string[] code= File.ReadAllLines(file, Encoding.Default);
\r
170 WriteString(bw, i.Name);
\r
171 bw.Write(code.Length);
\r
173 foreach(string j in code)
\r
174 WriteString(bw, j.Trim('\r', '\n'));
\r
180 private bool DoWriteMaterials()
\r
182 bw.Write(mqo.Materials.Count);
\r
184 foreach(MqoMaterial i in mqo.Materials)
\r
186 MaterialInfo mi = materials[i.name];
\r
187 string[] code= mi.GetCode();
\r
189 WriteString(bw, i.name);
\r
190 WriteString(bw, "cgfxShader");
\r
191 bw.Write(code.Length);
\r
193 foreach(string j in code)
\r
194 WriteString(bw, j.Trim('\r', '\n'));
\r
196 ImportMaterialInfo imi = new ImportMaterialInfo();
\r
198 imi.File = "cgfxShader";
\r
199 ii.materials.Add(imi);
\r
202 File.WriteAllLines(Path.Combine(dir, i.name), code);
\r
208 private bool DoWriteMeshes()
\r
210 bw.Write(meshes.Count);
\r
212 foreach(TSOMesh i in meshes)
\r
214 WriteString(bw, i.Name);
\r
215 WriteMatrix(bw, i.Matrix);
\r
217 bw.Write(i.numsubs);
\r
219 foreach(TSOSubMesh j in i.sub)
\r
222 bw.Write(j.numbones);
\r
224 foreach(int k in j.bones)
\r
227 bw.Write(j.numvertices);
\r
229 foreach(Vertex k in j.vertices)
\r
230 WriteVertex(bw, k);
\r
237 private bool DoOutput(string tsoex)
\r
239 //----- 出力処理 -----------------------------------------------
\r
240 ii.materials.Clear();
\r
241 ii.textures.Clear();
\r
243 using (FileStream fs = File.OpenWrite(tsoex))
\r
246 bw = new BinaryWriter(fs);
\r
249 DoWriteNodeNames();
\r
250 DoWriteNodeMatrices();
\r
253 DoWriteMaterials();
\r
254 DoGenerateMeshes();
\r
260 protected abstract bool DoGenerateMeshes();
\r
262 private bool DoSaveXml(string importinfo_file)
\r
265 ImportInfo.Save(importinfo_file, ii);
\r
269 private bool DoCleanup()
\r
282 System.GC.Collect();
\r
286 public void Generate(string mqoin, string tsoref, string tsoex, TSOGenerateConfig config)
\r
288 this.config = config;
\r
289 string importinfo_file = Path.ChangeExtension(mqoin, ".xml");
\r
293 if (!DoSetupDir(mqoin)) return;
\r
294 if (!DoLoadMQO(mqoin)) return;
\r
295 if (!DoLoadRefTSO(tsoref)) return;
\r
296 if (!DoLoadXml(importinfo_file)) return;
\r
297 if (!DoOutput(tsoex)) return;
\r
298 if (!DoSaveXml(importinfo_file)) return;
\r
306 protected abstract bool DoLoadRefTSO(string tsoref);
\r
309 public void WriteString(BinaryWriter bw, string s)
\r
311 byte[] b = Encoding.Default.GetBytes(s);
\r
316 public void WriteMatrix(BinaryWriter bw, Matrix44 m)
\r
318 bw.Write(m.M11); bw.Write(m.M12); bw.Write(m.M13); bw.Write(m.M14);
\r
319 bw.Write(m.M21); bw.Write(m.M22); bw.Write(m.M23); bw.Write(m.M24);
\r
320 bw.Write(m.M31); bw.Write(m.M32); bw.Write(m.M33); bw.Write(m.M34);
\r
321 bw.Write(m.M41); bw.Write(m.M42); bw.Write(m.M43); bw.Write(m.M44);
\r
324 public unsafe void WriteVertex(BinaryWriter bw, Vertex v)
\r
327 byte* idx = (byte*)(&idx0);
\r
328 List<int> idxs = new List<int>(4);
\r
329 List<float> wgts = new List<float>(4);
\r
331 if(v.Wgt.x > 0) { idxs.Add(idx[0]); wgts.Add(v.Wgt.x); }
\r
332 if(v.Wgt.y > 0) { idxs.Add(idx[1]); wgts.Add(v.Wgt.y); }
\r
333 if(v.Wgt.z > 0) { idxs.Add(idx[2]); wgts.Add(v.Wgt.z); }
\r
334 if(v.Wgt.w > 0) { idxs.Add(idx[3]); wgts.Add(v.Wgt.w); }
\r
336 bw.Write(v.Pos.X); bw.Write(v.Pos.Y); bw.Write(v.Pos.Z);
\r
337 bw.Write(v.Nrm.X); bw.Write(v.Nrm.Y); bw.Write(v.Nrm.Z);
\r
338 bw.Write(v.Tex.X); bw.Write(v.Tex.Y);
\r
340 bw.Write(wgts.Count);
\r
342 for(int i= 0, n= idxs.Count; i < n; ++i)
\r
350 public TSOTex LoadTex(string file)
\r
352 string ext = Path.GetExtension(file).ToUpper();
\r
357 case ".TGA": tex= LoadTarga(file); break;
\r
358 case ".BMP": tex= LoadBitmap(file); break;
\r
359 default: throw new Exception("Unsupported texture file: " + file);
\r
362 for(int i= 0, n= tex.data.Length; i < n; i+=tex.Depth)
\r
364 byte b = tex.data[i+0];
\r
365 tex.data[i+0] = tex.data[i+2];
\r
372 public unsafe TSOTex LoadTarga(string file)
\r
374 using(FileStream fs= File.OpenRead(file))
\r
376 BinaryReader br = new BinaryReader(fs);
\r
377 TARGA_HEADER header;
\r
379 Marshal.Copy(br.ReadBytes(sizeof(TARGA_HEADER)), 0, (IntPtr)(&header), sizeof(TARGA_HEADER));
\r
381 if(header.imagetype != 0x02) throw new Exception("Invalid imagetype: " + file);
\r
382 if(header.depth != 24
\r
383 && header.depth != 32) throw new Exception("Invalid depth: " + file);
\r
385 TSOTex tex = new TSOTex();
\r
386 tex.depth = header.depth / 8;
\r
387 tex.width = header.width;
\r
388 tex.height = header.height;
\r
390 tex.data = br.ReadBytes(tex.width * tex.height * tex.depth);
\r
396 public unsafe TSOTex LoadBitmap(string file)
\r
398 using(FileStream fs= File.OpenRead(file))
\r
400 BinaryReader br = new BinaryReader(fs);
\r
401 BITMAPFILEHEADER bfh;
\r
402 BITMAPINFOHEADER bih;
\r
404 Marshal.Copy(br.ReadBytes(sizeof(BITMAPFILEHEADER)), 0, (IntPtr)(&bfh), sizeof(BITMAPFILEHEADER));
\r
405 Marshal.Copy(br.ReadBytes(sizeof(BITMAPINFOHEADER)), 0, (IntPtr)(&bih), sizeof(BITMAPINFOHEADER));
\r
407 if(bfh.bfType != 0x4D42) throw new Exception("Invalid imagetype: " + file);
\r
408 if(bih.biBitCount != 24
\r
409 && bih.biBitCount != 32) throw new Exception("Invalid depth: " + file);
\r
411 TSOTex tex = new TSOTex();
\r
412 tex.depth = bih.biBitCount / 8;
\r
413 tex.width = bih.biWidth;
\r
414 tex.height = bih.biHeight;
\r
416 tex.data = br.ReadBytes(tex.width * tex.height * tex.depth);
\r
424 public class TSOGeneratorOneBone : TSOGenerator
\r
426 public Dictionary<string, string> ObjectBoneNames = new Dictionary<string, string>();
\r
428 protected override bool DoLoadRefTSO(string tsoref)
\r
431 tsor = LoadTSO(tsoref);
\r
435 protected override bool DoGenerateMeshes()
\r
437 meshes = new List<TSOMesh>();
\r
439 foreach(MqoObject i in mqo.Objects)
\r
441 if(i.name.ToLower() == "bone")
\r
444 Console.WriteLine("object:" + i.name);
\r
447 Point3[] nrm = new Point3[i.vertices.Count];
\r
449 foreach(MqoFace j in i.faces)
\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
459 for(int j= 0; j < nrm.Length; ++j)
\r
460 nrm[j] = Point3.Normalize(nrm[j]);
\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 = ObjectBoneNames[i.name];
\r
467 bones[0] = nodes[bone].ID;
\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
474 Console.WriteLine(" vertices bone_indices");
\r
475 Console.WriteLine(" -------- ------------");
\r
477 for(int j= 0, n= materials.Count; j < n; ++j)
\r
482 foreach(MqoFace f in i.faces)
\r
487 Vertex va = new Vertex(i.vertices[f.a], wgt, idx, nrm[f.a], new Point2(f.ta.x, 1-f.ta.y));
\r
488 Vertex vb = new Vertex(i.vertices[f.b], wgt, idx, nrm[f.b], new Point2(f.tb.x, 1-f.tb.y));
\r
489 Vertex vc = new Vertex(i.vertices[f.c], wgt, idx, nrm[f.c], new Point2(f.tc.x, 1-f.tc.y));
\r
491 indices.Add(vh.Add(va));
\r
492 indices.Add(vh.Add(vc));
\r
493 indices.Add(vh.Add(vb));
\r
496 if(indices.Count == 0)
\r
500 ushort[] nidx = NvTriStrip.Optimize(indices.ToArray());
\r
503 Vertex[] verts= vh.verts.ToArray();
\r
504 TSOSubMesh sub = new TSOSubMesh();
\r
506 sub.numbones = bones.Length;
\r
508 sub.numvertices = nidx.Length;
\r
509 sub.vertices = new Vertex[nidx.Length];
\r
511 for(int k= 0; k < nidx.Length; ++k)
\r
512 sub.vertices[k] = verts[nidx[k]];
\r
514 Console.WriteLine(" {0,8} {1,12}", sub.vertices.Length, sub.bones.Length);
\r
520 TSOMesh mesh = new TSOMesh();
\r
521 mesh.name = i.name;
\r
522 mesh.numsubs = subs.Count;
\r
523 mesh.sub = subs.ToArray();
\r
524 mesh.matrix = Matrix44.Identity;
\r
534 public unsafe class TSOGeneratorRefBone : TSOGenerator
\r
536 private List<Vertex> vlst;
\r
537 private PointCluster pc;
\r
539 private void CreatePointCluster(TSOFile tso)
\r
541 vlst= new List<Vertex>();
\r
543 foreach(TSOMesh i in tso.meshes)
\r
544 foreach(TSOSubMesh j in i.sub)
\r
545 vlst.AddRange(j.vertices);
\r
547 pc = new PointCluster(vlst.Count);
\r
549 foreach(Vertex i in vlst)
\r
550 pc.Add(i.Pos.x, i.Pos.y, i.Pos.z);
\r
555 protected override bool DoLoadRefTSO(string tsoref)
\r
558 tsor = LoadTSO(tsoref);
\r
560 foreach(TSOMesh i in tsor.meshes)
\r
561 foreach(TSOSubMesh j in i.sub)
\r
563 int[] bones = j.bones;
\r
565 for(int k= 0, n= j.numvertices; k < n; ++k)
\r
568 uint idx0= j.vertices[k].Idx;
\r
569 byte* idx = (byte*)(&idx0);
\r
570 idx[0] = (byte)bones[idx[0]];
\r
571 idx[1] = (byte)bones[idx[1]];
\r
572 idx[2] = (byte)bones[idx[2]];
\r
573 idx[3] = (byte)bones[idx[3]];
\r
574 j.vertices[k].Idx = idx0;
\r
578 CreatePointCluster(tsor);
\r
582 protected override bool DoGenerateMeshes()
\r
584 meshes = new List<TSOMesh>();
\r
586 foreach(MqoObject i in mqo.Objects)
\r
588 if(i.name.ToLower() == "bone")
\r
591 Console.WriteLine("object:" + i.name);
\r
594 List<int> vref= new List<int>(i.vertices.Count);
\r
596 foreach(Point3 j in i.vertices)
\r
597 vref.Add(pc.NearestIndex(j.x, j.y, j.z));
\r
600 Point3[] nrm = new Point3[i.vertices.Count];
\r
602 foreach(MqoFace j in i.faces)
\r
604 Point3 v1 = Point3.Normalize(i.vertices[j.b] - i.vertices[j.a]);
\r
605 Point3 v2 = Point3.Normalize(i.vertices[j.c] - i.vertices[j.b]);
\r
606 Point3 n = Point3.Normalize(Point3.Cross(v1, v2));
\r
613 for(int j= 0; j < nrm.Length; ++j)
\r
614 nrm[j] = Point3.Normalize(nrm[j]);
\r
617 List<int> faces1 = new List<int>();
\r
618 List<int> faces2 = new List<int>();
\r
619 //int[] bonecnv = new int[tsor.nodes.Length]; // ボーン変換テーブル
\r
620 VertexHeap<Vertex> vh = new VertexHeap<Vertex>();
\r
621 Vertex[] v = new Vertex[3];
\r
622 List<int> bones = new List<int>(16);
\r
623 List<ushort> indices = new List<ushort>();
\r
624 Dictionary<int, int> selected= new Dictionary<int,int>();
\r
625 Dictionary<int, int> work = new Dictionary<int,int>();
\r
626 List<TSOSubMesh> subs = new List<TSOSubMesh>();
\r
628 for(int j= 0, n= i.faces.Count; j < n; ++j)
\r
632 Console.WriteLine(" vertices bone_indices");
\r
633 Console.WriteLine(" -------- ------------");
\r
635 while (faces1.Count > 0)
\r
637 int mtl = i.faces[faces1[0]].mtl;
\r
643 foreach(int j in faces1)
\r
645 MqoFace f = i.faces[j];
\r
653 v[0] = vlst[vref[f.a]];
\r
654 v[1] = vlst[vref[f.b]];
\r
655 v[2] = vlst[vref[f.c]];
\r
659 for(int k= 0; k < 3; ++k)
\r
662 UInt32 idx0 = vv.Idx;
\r
663 Point4 wgt0 = vv.Wgt;
\r
664 byte* idx = (byte*)(&idx0);
\r
665 float* wgt = (float*)(&wgt0);
\r
667 for(int l= 0; l < 4; ++l)
\r
669 if(wgt[l] <= float.Epsilon) continue;
\r
670 if(selected.ContainsKey(idx[l])) continue;
\r
672 if(!work.ContainsKey(idx[l]))
\r
673 work.Add(idx[l], 0);
\r
677 if (selected.Count + work.Count > 16)
\r
684 foreach(KeyValuePair<int, int> l in work)
\r
686 selected.Add(l.Key, selected.Count); // ボーンテーブルに追加
\r
691 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
692 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
693 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
695 indices.Add(vh.Add(va));
\r
696 indices.Add(vh.Add(vc));
\r
697 indices.Add(vh.Add(vb));
\r
701 ushort[] nidx = NvTriStrip.Optimize(indices.ToArray());
\r
704 Vertex[] verts = vh.verts.ToArray();
\r
706 for(int j= 0; j < verts.Length; ++j)
\r
708 uint idx0= verts[j].Idx;
\r
709 byte* idx = (byte*)(&idx0);
\r
710 Point4 wgt0= verts[j].Wgt;
\r
711 float* wgt = (float*)(&wgt0);
\r
713 for(int k= 0; k < 4; ++k)
\r
714 if(wgt[k] > float.Epsilon)
\r
715 idx[k] = (byte)selected[idx[k]];
\r
717 verts[j].Idx = idx0;
\r
721 TSOSubMesh sub = new TSOSubMesh();
\r
723 sub.numbones = bones.Count;
\r
724 sub.bones = bones.ToArray();
\r
725 sub.numvertices = nidx.Length;
\r
726 sub.vertices = new Vertex[nidx.Length];
\r
728 for(int j= 0; j < nidx.Length; ++j)
\r
729 sub.vertices[j] = verts[nidx[j]];
\r
731 Console.WriteLine(" {0,8} {1,12}", sub.vertices.Length, sub.bones.Length);
\r
736 List<int> t = faces1;
\r
743 TSOMesh mesh = new TSOMesh();
\r
744 mesh.name = i.name;
\r
745 mesh.numsubs = subs.Count;
\r
746 mesh.sub = subs.ToArray();
\r
747 mesh.matrix = Matrix44.Identity;
\r
757 public class TextureInfo
\r
759 public string name;
\r
760 public string file;
\r
762 public TextureInfo(string name, string file)
\r
769 public class MaterialInfo
\r
771 public string name;
\r
772 public string shader;
\r
773 public string diffuse;
\r
774 public string shadow;
\r
775 //public Dictionary<string, string> parameters;
\r
777 public MaterialInfo(string path, MqoMaterial mqom, ImportMaterialInfo impm)
\r
780 diffuse = mqom.tex;
\r
784 string file= Path.Combine(path, impm.Name);
\r
786 if(File.Exists(file))
\r
789 if(impm.shadow != null)
\r
791 file = Path.Combine(path, impm.shadow.File);
\r
793 if(File.Exists(file))
\r
803 return File.Exists(shader)
\r
804 && File.Exists(diffuse)
\r
805 && File.Exists(shadow);
\r
809 public string[] GetCode()
\r
811 TSOMaterialCode code= TSOMaterialCode.GenerateFromFile(shader);
\r
812 List<string> line= new List<string>();
\r
814 code.SetValue("ColorTex", Path.GetFileNameWithoutExtension(diffuse));
\r
815 code.SetValue("ShadeTex", Path.GetFileNameWithoutExtension(shadow));
\r
817 foreach(KeyValuePair<string, TSOParameter> i in code)
\r
818 line.Add(i.Value.ToString());
\r
820 return line.ToArray();
\r
823 public string Name { get { return name; } }
\r
825 [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]
\r
826 [DisplayNameAttribute("シェーダー設定ファイル")]
\r
827 public string ShaderFile { get { return shader; } set { shader = value; } }
\r
829 [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]
\r
830 [DisplayNameAttribute("テクスチャ:カラー")]
\r
831 public string DiffuseTexture { get { return diffuse; } set { diffuse = value; } }
\r
833 [Editor(typeof(FileNameEditor), typeof(UITypeEditor))]
\r
834 [DisplayNameAttribute("テクスチャ:シェーティング")]
\r
835 public string ShadowTexture { get { return shadow; } set { shadow = value; } }
\r