using System; using System.Collections.Generic; using System.IO; using System.Text; namespace Tso2MqoGui { public unsafe class TSOGeneratorRefBone : TSOGenerator { public TSOGeneratorRefBone(TSOGeneratorConfig config) : base(config) { } // 参照tso上の全頂点を保持する List refverts; // 最近傍探索 PointCluster pc; void CreateRefVerts(TSOFile tso) { refverts = new List(); foreach (TSOMesh i in tso.meshes) foreach (TSOSubMesh j in i.sub_meshes) refverts.AddRange(j.vertices); } void CreatePointCluster() { pc = new PointCluster(refverts.Count); foreach (Vertex i in refverts) pc.Add(i.Pos); pc.Clustering(); } protected override bool DoLoadRefTSO(string path) { tsoref = LoadTSO(path); tsoref.SwitchBoneIndicesOnMesh(); CreateRefVerts(tsoref); CreatePointCluster(); return true; } protected override bool DoGenerateMeshes() { meshes = new List(); foreach (MqoObject obj in mqo.Objects) { if (obj.name.ToLower() == "bone") continue; Console.WriteLine("object:" + obj.name); // 一番近い頂点への参照 List vref = new List(obj.vertices.Count); foreach (UVertex i in obj.vertices) vref.Add(pc.NearestIndex(i.Pos.x, i.Pos.y, i.Pos.z)); obj.CreateNormal(); List faces_1 = new List(); List faces_2 = new List(); Heap bh = new Heap(); Heap vh = new Heap(); Vertex[] refvs = new Vertex[3]; List vert_indices = new List(); Dictionary adding_bone_indices = new Dictionary(); List subs = new List(); for (int i = 0, n = obj.faces.Count; i < n; ++i) faces_1.Add(i); #region ボーンパーティション Console.WriteLine(" vertices bone_indices"); Console.WriteLine(" -------- ------------"); while (faces_1.Count != 0) { int spec = obj.faces[faces_1[0]].spec; bh.Clear(); vh.Clear(); vert_indices.Clear(); foreach (int f in faces_1) { MqoFace face = obj.faces[f]; if (face.spec != spec) { faces_2.Add(f); continue; } for (int k = 0; k < 3; ++k) { refvs[k] = refverts[vref[face.vert_indices[k]]]; } adding_bone_indices.Clear(); for (int k = 0; k < 3; ++k) { UInt32 idx0 = refvs[k].Idx; Point4 wgt0 = refvs[k].Wgt; byte* idx = (byte*)(&idx0); float* wgt = (float*)(&wgt0); for (int l = 0; l < 4; ++l) { if (wgt[l] <= float.Epsilon) continue; if (bh.map.ContainsKey(idx[l])) continue; adding_bone_indices[idx[l]] = true; } } if (bh.Count + adding_bone_indices.Count > 16) { faces_2.Add(f); continue; } foreach (int i in adding_bone_indices.Keys) { bh.Add(i); } for (int k = 0; k < 3; ++k) { UInt32 idx0 = refvs[k].Idx; Point4 wgt0 = refvs[k].Wgt; byte* idx = (byte*)(&idx0); float* wgt = (float*)(&wgt0); for (int l = 0; l < 4; ++l) { if (wgt[l] <= float.Epsilon) continue; idx[l] = (byte)bh[idx[l]]; } refvs[k].Idx = idx0; } Vertex va = new Vertex(obj.vertices[face.a].Pos, refvs[0].Wgt, refvs[0].Idx, obj.vertices[face.a].Nrm, new Point2(face.ta.x, 1 - face.ta.y)); Vertex vb = new Vertex(obj.vertices[face.b].Pos, refvs[1].Wgt, refvs[1].Idx, obj.vertices[face.b].Nrm, new Point2(face.tb.x, 1 - face.tb.y)); Vertex vc = new Vertex(obj.vertices[face.c].Pos, refvs[2].Wgt, refvs[2].Idx, obj.vertices[face.c].Nrm, new Point2(face.tc.x, 1 - face.tc.y)); vert_indices.Add(vh.Add(va)); vert_indices.Add(vh.Add(vc)); vert_indices.Add(vh.Add(vb)); } ushort[] optimized_indices = NvTriStrip.Optimize(vert_indices.ToArray()); TSOSubMesh sub = new TSOSubMesh(); sub.spec = spec; sub.numbones = bh.Count; sub.bones = bh.ary.ToArray(); sub.numvertices = optimized_indices.Length; Vertex[] vertices = new Vertex[optimized_indices.Length]; for (int i = 0; i < optimized_indices.Length; ++i) { vertices[i] = vh.ary[optimized_indices[i]]; } sub.vertices = vertices; Console.WriteLine(" {0,8} {1,12}", sub.vertices.Length, sub.bones.Length); subs.Add(sub); List faces_tmp = faces_1; faces_1 = faces_2; faces_2 = faces_tmp; faces_tmp.Clear(); } #endregion TSOMesh mesh = new TSOMesh(); mesh.name = obj.name; mesh.numsubs = subs.Count; mesh.sub_meshes = subs.ToArray(); mesh.matrix = Matrix44.Identity; mesh.effect = 0; meshes.Add(mesh); } return true; } protected override bool DoCleanup() { pc = null; refverts = null; return base.DoCleanup(); } } }