OSDN Git Service

refactor.
[tdcgexplorer/tso2mqo.git] / TSOGeneratorRefBone.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Text;
5
6 namespace Tso2MqoGui
7 {
8     public unsafe class TSOGeneratorRefBone : TSOGenerator
9     {
10         public TSOGeneratorRefBone(TSOGeneratorConfig config)
11             : base(config)
12         {
13         }
14
15         // 参照tso上の全頂点を保持する
16         List<Vertex> refverts;
17         // 最近傍探索
18         PointCluster pc;
19
20         void CreateRefVerts(TSOFile tso)
21         {
22             refverts = new List<Vertex>();
23
24             foreach (TSOMesh i in tso.meshes)
25                 foreach (TSOSubMesh j in i.sub_meshes)
26                     refverts.AddRange(j.vertices);
27         }
28
29         void CreatePointCluster()
30         {
31             pc = new PointCluster(refverts.Count);
32
33             foreach (Vertex i in refverts)
34                 pc.Add(i.Pos);
35
36             pc.Clustering();
37         }
38
39         protected override bool DoLoadRefTSO(string path)
40         {
41             tsoref = LoadTSO(path);
42             tsoref.SwitchBoneIndicesOnMesh();
43             CreateRefVerts(tsoref);
44             CreatePointCluster();
45             return true;
46         }
47
48         protected override bool DoGenerateMeshes()
49         {
50             meshes = new List<TSOMesh>();
51
52             foreach (MqoObject obj in mqo.Objects)
53             {
54                 if (obj.name.ToLower() == "bone")
55                     continue;
56
57                 Console.WriteLine("object:" + obj.name);
58
59                 // 一番近い頂点への参照
60                 List<int> vref = new List<int>(obj.vertices.Count);
61
62                 foreach (UVertex j in obj.vertices)
63                     vref.Add(pc.NearestIndex(j.Pos.x, j.Pos.y, j.Pos.z));
64
65                 obj.CreateNormal();
66
67                 // フェイスの組成
68                 List<int> faces1 = new List<int>();
69                 List<int> faces2 = new List<int>();
70                 //int[]                   bonecnv = new int[tsor.nodes.Length];   // ボーン変換テーブル
71                 VertexHeap<Vertex> vh = new VertexHeap<Vertex>();
72                 Vertex[] v = new Vertex[3];
73                 List<int> bones = new List<int>(16);
74                 List<ushort> indices = new List<ushort>();
75                 Dictionary<int, int> selected = new Dictionary<int, int>();
76                 Dictionary<int, int> work = new Dictionary<int, int>();
77                 List<TSOSubMesh> subs = new List<TSOSubMesh>();
78
79                 for (int j = 0, n = obj.faces.Count; j < n; ++j)
80                     faces1.Add(j);
81
82                 #region ボーンパーティション
83                 Console.WriteLine("  vertices bone_indices");
84                 Console.WriteLine("  -------- ------------");
85
86                 while (faces1.Count > 0)
87                 {
88                     int mtl = obj.faces[faces1[0]].mtl;
89                     selected.Clear();
90                     indices.Clear();
91                     vh.Clear();
92                     bones.Clear();
93
94                     foreach (int j in faces1)
95                     {
96                         MqoFace f = obj.faces[j];
97
98                         if (f.mtl != mtl)
99                         {
100                             faces2.Add(j);
101                             continue;
102                         }
103
104                         v[0] = refverts[vref[f.a]];
105                         v[1] = refverts[vref[f.b]];
106                         v[2] = refverts[vref[f.c]];
107
108                         work.Clear();
109
110                         for (int k = 0; k < 3; ++k)
111                         {
112                             Vertex vv = v[k];
113                             UInt32 idx0 = vv.Idx;
114                             Point4 wgt0 = vv.Wgt;
115                             byte* idx = (byte*)(&idx0);
116                             float* wgt = (float*)(&wgt0);
117
118                             for (int l = 0; l < 4; ++l)
119                             {
120                                 if (wgt[l] <= float.Epsilon) continue;
121                                 if (selected.ContainsKey(idx[l])) continue;
122
123                                 if (!work.ContainsKey(idx[l]))
124                                     work.Add(idx[l], 0);
125                             }
126                         }
127
128                         if (selected.Count + work.Count > 16)
129                         {
130                             faces2.Add(j);
131                             continue;
132                         }
133
134                         // ボーンリストに足してvalid
135                         foreach (KeyValuePair<int, int> l in work)
136                         {
137                             selected.Add(l.Key, selected.Count);    // ボーンテーブルに追加
138                             bones.Add(l.Key);
139                         }
140
141                         // \todo 点の追加
142                         Vertex va = new Vertex(obj.vertices[f.a].Pos, v[0].Wgt, v[0].Idx, obj.vertices[f.a].Nrm, new Point2(f.ta.x, 1 - f.ta.y));
143                         Vertex vb = new Vertex(obj.vertices[f.b].Pos, v[1].Wgt, v[1].Idx, obj.vertices[f.b].Nrm, new Point2(f.tb.x, 1 - f.tb.y));
144                         Vertex vc = new Vertex(obj.vertices[f.c].Pos, v[2].Wgt, v[2].Idx, obj.vertices[f.c].Nrm, new Point2(f.tc.x, 1 - f.tc.y));
145
146                         indices.Add(vh.Add(va));
147                         indices.Add(vh.Add(vc));
148                         indices.Add(vh.Add(vb));
149                     }
150
151                     // フェイス最適化
152                     ushort[] nidx = NvTriStrip.Optimize(indices.ToArray());
153
154                     // 頂点のボーン参照ローカルに変換
155                     Vertex[] verts = vh.verts.ToArray();
156
157                     for (int j = 0; j < verts.Length; ++j)
158                     {
159                         uint idx0 = verts[j].Idx;
160                         byte* idx = (byte*)(&idx0);
161                         Point4 wgt0 = verts[j].Wgt;
162                         float* wgt = (float*)(&wgt0);
163
164                         for (int k = 0; k < 4; ++k)
165                             if (wgt[k] > float.Epsilon)
166                                 idx[k] = (byte)selected[idx[k]];
167
168                         verts[j].Idx = idx0;
169                     }
170
171                     // サブメッシュ生成
172                     TSOSubMesh sub = new TSOSubMesh();
173                     sub.spec = mtl;
174                     sub.numbones = bones.Count;
175                     sub.bones = bones.ToArray();
176                     sub.numvertices = nidx.Length;
177                     sub.vertices = new Vertex[nidx.Length];
178
179                     for (int j = 0; j < nidx.Length; ++j)
180                         sub.vertices[j] = verts[nidx[j]];
181
182                     Console.WriteLine("  {0,8} {1,12}", sub.vertices.Length, sub.bones.Length);
183
184                     subs.Add(sub);
185
186                     // 次の周回
187                     List<int> t = faces1;
188                     faces1 = faces2;
189                     faces2 = t;
190                     t.Clear();
191                 }
192                 #endregion
193                 // \todo TSOMesh生成
194                 TSOMesh mesh = new TSOMesh();
195                 mesh.name = obj.name;
196                 mesh.numsubs = subs.Count;
197                 mesh.sub_meshes = subs.ToArray();
198                 mesh.matrix = Matrix44.Identity;
199                 mesh.effect = 0;
200                 meshes.Add(mesh);
201             }
202
203             return true;
204         }
205
206         protected override bool DoCleanup()
207         {
208             pc = null;
209             refverts = null;
210             return base.DoCleanup();
211         }
212     }
213 }