// TODO: // // 1. Figure out how the bone remap indices work // They seem to be tied to the used bone indices somehow // Maybe building up an hierarchy as the same indices appear multiple times // Indices that aren't in the used bone indices are set to 0xFF // // 2. Figure out the BoneRLE // First byte is the hierarchy index of the affected bone // Second byte seems to be something like how many bones it shares weights with on the same material split? // // 3. Figure out the inverse matrices // I can currently just copy and paste the one from the original file // But knowing how to calculate it would be a lot easier internal RWSkinPlugin(RWNodeFactory.RWNodeInfo header, BinaryReader reader, RWMesh rwGeometry) : base(header) { int numVertices = rwGeometry.VertexCount; m_numBones = reader.ReadByte(); m_numUsedBones = reader.ReadByte(); m_numWeightPerVertex = reader.ReadByte(); m_unused = reader.ReadByte(); m_usedBoneIndices = reader.ReadBytes(m_numUsedBones); m_skinBoneIndices = new byte[numVertices][]; for (int i = 0; i < numVertices; i++) { m_skinBoneIndices[i] = reader.ReadBytes(4); } m_skinBoneWeights = new float[numVertices][]; for (int i = 0; i < numVertices; i++) { m_skinBoneWeights[i] = reader.ReadFloatArray(4); } m_inverseBoneMatrices = new Matrix4x4[m_numBones]; for (int i = 0; i < BoneCount; i++) { Matrix4x4 mtx = Matrix4x4.Identity; mtx.M11 = reader.ReadSingle(); mtx.M12 = reader.ReadSingle(); mtx.M13 = reader.ReadSingle(); reader.BaseStream.Position += 4; mtx.M21 = reader.ReadSingle(); mtx.M22 = reader.ReadSingle(); mtx.M23 = reader.ReadSingle(); reader.BaseStream.Position += 4; mtx.M31 = reader.ReadSingle(); mtx.M32 = reader.ReadSingle(); mtx.M33 = reader.ReadSingle(); reader.BaseStream.Position += 4; mtx.M41 = reader.ReadSingle(); mtx.M42 = reader.ReadSingle(); mtx.M43 = reader.ReadSingle(); reader.BaseStream.Position += 4; m_inverseBoneMatrices[i] = mtx; } m_boneLimit = reader.ReadInt32(); m_numMaterialSplit = reader.ReadInt32(); m_materialSplitNumUsedBones = reader.ReadInt32(); if (m_numMaterialSplit < 1) return; m_boneRemapIndices = reader.ReadBytes(m_numBones); m_materialSplitSkinInfo = new MaterialSplitSkinInfo[m_numMaterialSplit]; for (int i = 0; i < m_numMaterialSplit; i++) m_materialSplitSkinInfo[i] = new MaterialSplitSkinInfo { UsedBonesStartIndex = reader.ReadByte(), NumUsedBones = reader.ReadByte() }; m_materialSplitUsedBoneInfo = new MaterialSplitUsedBoneInfo[m_materialSplitNumUsedBones]; for (int i = 0; i < m_materialSplitNumUsedBones; i++) m_materialSplitUsedBoneInfo[i] = new MaterialSplitUsedBoneInfo { UsedBoneHierarchyIndex = reader.ReadByte(), Unknown = reader.ReadByte() }; PrintInfo(); }
/// <summary> /// Initialize a new <see cref="RWMeshMaterialSplitData"/> using a <see cref="RWMesh"/> and the primitive type for the split data. /// </summary> /// <param name="mesh"></param> /// <param name="primType"></param> public RWMeshMaterialSplitData(RWMesh mesh, RWPrimitiveType primType = RWPrimitiveType.TriangleStrip, RWNode parent = null) : base(RWNodeType.MeshMaterialSplitList, parent) { // set type and prim count _primType = primType; _numPrimitives = mesh.TriangleCount; // pass 1: order the triangles by ascending material id var sortedTriangles = mesh.Triangles.OrderBy(tri => tri.MatID).ToArray(); // pass 2: split the indices List<ushort>[] matSplitsIndices = new List<ushort>[mesh.MaterialCount]; List<ushort> curMatSplitIndices = null; int curMatIdx = -1; for (int i = 0; i < sortedTriangles.Length; i++) { var tri = sortedTriangles[i]; if (tri.MatID > curMatIdx) { if (curMatIdx != -1) matSplitsIndices[curMatIdx] = curMatSplitIndices; curMatIdx = tri.MatID; curMatSplitIndices = new List<ushort>(); } curMatSplitIndices.Add(tri.A); curMatSplitIndices.Add(tri.B); curMatSplitIndices.Add(tri.C); } matSplitsIndices[curMatIdx] = curMatSplitIndices; // pass 3: create the split data _splits = new RWMeshMaterialSplit[mesh.MaterialCount]; for (int i = 0; i < _splits.Length; i++) { ushort[] matSplitIndices = matSplitsIndices[i].ToArray(); if (primType == RWPrimitiveType.TriangleStrip) { ManagedNvTriStrip.PrimitiveGroup[] primitives = null; if (ManagedNvTriStrip.NvTriStripUtility.Stripify(matSplitIndices, ref primitives)) { matSplitIndices = primitives[0].Indices; } else { throw new System.Exception("Failed to generate strips."); } /* NvTriStripDotNet.PrimitiveGroup[] primitives; var tristripper = new NvTriStripDotNet.NvTriStrip(); if (tristripper.GenerateStrips(matSplitIndices, out primitives)) { matSplitIndices = primitives[0].indices.Cast<ushort>().ToArray(); } */ } _splits[i] = new RWMeshMaterialSplit(i, matSplitIndices); } }