/// <summary> /// Initialize a new <see cref="RwMeshListNode"/> using a <see cref="RwGeometryNode"/> and the primitive id for the split data. /// </summary> /// <param name="geometryNode"></param> /// <param name="primitiveType"></param> public RwMeshListNode(RwGeometryNode geometryNode, RwPrimitiveType primitiveType = RwPrimitiveType.TriangleStrip, RwNode parent = null) : base(RwNodeId.RwMeshListNode, parent) { // set id and prim count mPrimitiveType = primitiveType; //mPrimitiveCount = geometryNode.TriangleCount; // pass 1: order the triangles by ascending material id var sortedTriangles = geometryNode.Triangles.OrderBy(tri => tri.MatId); // pass 2: split the indices List <ushort>[] matSplitsIndices = new List <ushort> [geometryNode.MaterialCount]; List <ushort> curMatSplitIndices = null; int curMatIdx = -1; foreach (var tri in sortedTriangles) { 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 mMeshes = new RwMesh[geometryNode.MaterialCount]; for (int i = 0; i < mMeshes.Length; i++) { ushort[] matSplitIndices = matSplitsIndices[i].ToArray(); int triangleCount; if (primitiveType == RwPrimitiveType.TriangleStrip) { if (NvTriStripUtility.GenerateStrips(matSplitIndices, out PrimitiveGroup[] primitives) && primitives[0].Type == ManagedNvTriStrip.PrimitiveType.TriangleStrip)
// 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 RwSkinNode(RwNodeFactory.RwNodeHeader header, BinaryReader reader, RwGeometryNode rwGeometryNode) : base(header) { int numVertices = rwGeometryNode.VertexCount; BoneCount = reader.ReadByte(); UsedBoneCount = reader.ReadByte(); MaxWeightCountPerVertex = reader.ReadByte(); reader.Seek(1, SeekOrigin.Current); UsedBoneIndices = reader.ReadBytes(UsedBoneCount); VertexBoneIndices = new byte[numVertices][]; for (int i = 0; i < numVertices; i++) { VertexBoneIndices[i] = reader.ReadBytes(4); } VertexBoneWeights = new float[numVertices][]; for (int i = 0; i < numVertices; i++) { VertexBoneWeights[i] = reader.ReadFloatArray(4); } SkinToBoneMatrices = new Matrix4x4[BoneCount]; 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; SkinToBoneMatrices[i] = mtx; } BoneLimit = reader.ReadInt32(); MeshCount = reader.ReadInt32(); RleCount = reader.ReadInt32(); if (MeshCount < 1) { return; } MeshBoneRemapIndices = reader.ReadBytes(BoneCount); MeshBoneRleCount = new SkinSplitMeshRleCount[MeshCount]; for (int i = 0; i < MeshCount; i++) { MeshBoneRleCount[i] = new SkinSplitMeshRleCount { StartIndex = reader.ReadByte(), Count = reader.ReadByte() } } ; MeshBoneRle = new SkinSplitMeshBoneRle[RleCount]; for (int i = 0; i < RleCount; i++) { MeshBoneRle[i] = new SkinSplitMeshBoneRle { BoneIndex = reader.ReadByte(), SkinBoneIndexCount = reader.ReadByte() } } ; //PrintInfo(); }
/// <summary> /// Initialize a new <see cref="RwMeshListNode"/> using a <see cref="RwGeometryNode"/> and the primitive id for the split data. /// </summary> /// <param name="geometryNode"></param> /// <param name="primitiveType"></param> public RwMeshListNode(RwGeometryNode geometryNode, RwPrimitiveType primitiveType = RwPrimitiveType.TriangleStrip, RwNode parent = null) : base(RwNodeId.RwMeshListNode, parent) { // set id and prim count mPrimitiveType = primitiveType; //mPrimitiveCount = geometryNode.TriangleCount; // pass 1: order the triangles by ascending material id var sortedTriangles = geometryNode.Triangles.OrderBy(tri => tri.MatId); // pass 2: split the indices List <ushort>[] matSplitsIndices = new List <ushort> [geometryNode.MaterialCount]; List <ushort> curMatSplitIndices = null; int curMatIdx = -1; foreach (var tri in sortedTriangles) { 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 mMeshes = new RwMesh[geometryNode.MaterialCount]; for (int i = 0; i < mMeshes.Length; i++) { ushort[] matSplitIndices = matSplitsIndices[i].ToArray(); int triangleCount; if (primitiveType == RwPrimitiveType.TriangleStrip) { if (sStripifier.GenerateStrips(matSplitIndices, out var primitives) && primitives[0].Type == NvTriStripDotNet.PrimitiveType.TriangleStrip) { matSplitIndices = primitives[0].Indices; geometryNode.Flags |= RwGeometryFlags.CanTriStrip; triangleCount = matSplitIndices.Length - 2; } else { mPrimitiveType = RwPrimitiveType.TriangleList; triangleCount = matSplitIndices.Length / 3; //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(); * } */ } else { triangleCount = matSplitIndices.Length / 3; } mPrimitiveCount += triangleCount; mMeshes[i] = new RwMesh(i, matSplitIndices); } }