From be93dbff065b203556de3f82f099c1ce2f497066 Mon Sep 17 00:00:00 2001 From: BreakfastBrainz2 <100167349+BreakfastBrainz2@users.noreply.github.com> Date: Wed, 21 Jun 2023 06:27:34 +0000 Subject: [PATCH] [MeshSetPlugin] WIP composite mesh importing support (#262) --- Plugins/MeshSetPlugin/Fbx.cs | 8 + Plugins/MeshSetPlugin/FrostyMeshSetEditor.cs | 318 +++++++++++++++++-- Plugins/MeshSetPlugin/MeshSetPlugin.csproj | 26 +- Plugins/MeshSetPlugin/Resources/MeshSet.cs | 176 +++++++--- 4 files changed, 443 insertions(+), 85 deletions(-) diff --git a/Plugins/MeshSetPlugin/Fbx.cs b/Plugins/MeshSetPlugin/Fbx.cs index 119146e0..d6d02367 100644 --- a/Plugins/MeshSetPlugin/Fbx.cs +++ b/Plugins/MeshSetPlugin/Fbx.cs @@ -1441,6 +1441,9 @@ internal class FbxMesh : FbxGeometry [DllImport("thirdparty/libfbxsdk", EntryPoint = "?GetPolygonVertex@FbxMesh@fbxsdk@@QEBAHHH@Z")] private static extern int GetPolygonIndexInternal(IntPtr handle, int pPolygonIndex, int pPositionInPolygon); + [DllImport("thirdparty/libfbxsdk", EntryPoint = "?GetPolygonVertexIndex@FbxMesh@fbxsdk@@QEBAHH@Z")] + private static extern int GetPolygonVertexIndexInternal(IntPtr handle, int pPolygonIndex); + [DllImport("thirdparty/libfbxsdk", EntryPoint = "?IsTriangleMesh@FbxMesh@fbxsdk@@QEBA_NXZ")] private static extern bool IsTriangleMeshInternal(IntPtr handle); @@ -1511,6 +1514,11 @@ public int GetPolygonIndex(int index, int position) return GetPolygonIndexInternal(pHandle, index, position); } + public int GetPolygonVertexIndex(int index) + { + return GetPolygonVertexIndexInternal(pHandle, index); + } + public bool IsTriangleMesh() { return IsTriangleMeshInternal(pHandle); diff --git a/Plugins/MeshSetPlugin/FrostyMeshSetEditor.cs b/Plugins/MeshSetPlugin/FrostyMeshSetEditor.cs index e371a8e5..01d30686 100644 --- a/Plugins/MeshSetPlugin/FrostyMeshSetEditor.cs +++ b/Plugins/MeshSetPlugin/FrostyMeshSetEditor.cs @@ -374,16 +374,19 @@ public void ExportFBX(dynamic meshAsset, string filename, string fbxVersion, str } currentProgress++; + int lodIdx = 0; foreach (MeshSet meshSet in meshSets) { foreach (MeshSetLod lod in meshSet.Lods) { task.Update("Writing " + lod.String03); - FBXCreateMesh(scene, lod, boneNodes); - if (exportSingleLod) - { - break; + FBXCreateMesh(scene, lod, boneNodes, lodIdx); + if (exportSingleLod) + { + break; } + + lodIdx++; } } @@ -680,7 +683,7 @@ private FbxNode FBXCreateSkeleton(FbxScene scene, dynamic meshAsset, string skel /// /// Creates the FBX mesh /// - private void FBXCreateMesh(FbxScene scene, MeshSetLod lod, List boneNodes) + private void FBXCreateMesh(FbxScene scene, MeshSetLod lod, List boneNodes, int lodIdx) { int indexSize = (lod.IndexUnitSize / 8); @@ -703,7 +706,7 @@ private void FBXCreateMesh(FbxScene scene, MeshSetLod lod, List boneNod { FbxNode actor = FBXExportSubObject(scene, section, lod.VertexBufferSize, indexSize, reader); if (flattenHierarchy) - actor.Name = $"{section.Name}:{lod.String03.Insert(lod.String03.Length - 1, ".00")}"; + actor.Name = $"{section.Name}.lod{lodIdx}"; meshNode.AddChild(actor); if ((lod.Type == MeshType.MeshType_Skinned || lod.Type == MeshType.MeshType_Composite) && boneNodes.Count > 0) @@ -1591,9 +1594,6 @@ public void ImportFBX(string filename, MeshSet inMeshSet, EbxAsset asset, EbxAss } } - if (meshSet.Type != MeshType.MeshType_Rigid && meshSet.Type != MeshType.MeshType_Skinned) - throw new FBXImportInvalidMeshTypeException(); - // @hack entry.LinkedAssets.Clear(); resEntry.LinkedAssets.Clear(); @@ -1613,7 +1613,19 @@ public void ImportFBX(string filename, MeshSet inMeshSet, EbxAsset asset, EbxAss foreach (FbxNode child in scene.RootNode.Children) { string nodeName = child.Name.ToLower(); - if (nodeName.Contains("lod")) + int lodIndex = 0; + string possibleLodIndex = nodeName.Substring(nodeName.LastIndexOf(".") + 4); + // If the node doesn't contain a .0xx, it must be lod 0 + if (int.TryParse(possibleLodIndex, out lodIndex)) + { + if (lodNodes[lodIndex] == null) + { + lodNodes[lodIndex] = new List(); + lodCount++; + } + lodNodes[lodIndex].Add(child); + } + /*if (nodeName.Contains("lod")) { if (nodeName.Contains(":")) { @@ -1647,7 +1659,7 @@ public void ImportFBX(string filename, MeshSet inMeshSet, EbxAsset asset, EbxAss lodNodes[lodIndex].AddRange(child.Children); } } - } + }*/ } if (lodCount < meshSet.Lods.Count) @@ -1758,12 +1770,7 @@ private void ProcessLod(List nodes, int lodIndex) foreach (var node in sectionNodes) { - string sectionName = node.Name; - if (sectionName.Contains(':')) - { - // remove the lod portion of the name - sectionName = sectionName.Remove(sectionName.IndexOf(':')); - } + string sectionName = node.Name.Substring(0, node.Name.LastIndexOf(".")); // remove .lodx from the name int idx = meshSections.FindIndex((a) => a.Name == sectionName); if (idx != -1 && sectionNodeMapping[idx] == null) @@ -1874,6 +1881,11 @@ private void ProcessLod(List nodes, int lodIndex) } } + if (meshSet.Type == MeshType.MeshType_Composite) + { + CalculateCompositePartDataForLod(sectionNodeMapping, meshLod); + } + if (ProfilesLibrary.DataVersion == (int)ProfileVersion.StarWarsBattlefrontII) { // update shader block depot mesh parameters @@ -1944,6 +1956,169 @@ private void ProcessLod(List nodes, int lodIndex) } } + private LinearTransform FbxTransformToLinearTransform(FbxNode inFbxNode) + { + LinearTransform trns = new LinearTransform(); + float pi = (float)(Math.PI / 180.0); + + // Setup the rotation matrix + Vector3 fbxRotation = new Vector3(inFbxNode.LclRotation.X * pi, inFbxNode.LclRotation.Y * pi, inFbxNode.LclRotation.Z * pi); + + Matrix rotMatrix = Matrix.Identity; + + rotMatrix *= Matrix.RotationX(fbxRotation.X); + rotMatrix *= Matrix.RotationY(fbxRotation.Y); + rotMatrix *= Matrix.RotationZ(fbxRotation.Z); + + // Now create the LinearTransform matrix + Vector3 nodeScale = inFbxNode.LclScaling; + Matrix fbMatrix = new Matrix(); + fbMatrix.M11 = rotMatrix.M11 * nodeScale.X; + fbMatrix.M12 = rotMatrix.M12 * nodeScale.Y; + fbMatrix.M13 = rotMatrix.M13 * nodeScale.Z; + + fbMatrix.M21 = rotMatrix.M21 * nodeScale.X; + fbMatrix.M22 = rotMatrix.M22 * nodeScale.Y; + fbMatrix.M23 = rotMatrix.M23 * nodeScale.Z; + + fbMatrix.M31 = rotMatrix.M31 * nodeScale.X; + fbMatrix.M32 = rotMatrix.M32 * nodeScale.Y; + fbMatrix.M33 = rotMatrix.M33 * nodeScale.Z; + + fbMatrix.M41 = inFbxNode.LclTranslation.X; + fbMatrix.M42 = inFbxNode.LclTranslation.Y; + fbMatrix.M43 = inFbxNode.LclTranslation.Z; + + fbMatrix.M14 = 0f; + fbMatrix.M24 = 0f; + fbMatrix.M34 = 0f; + fbMatrix.M44 = 1f; + + // Converting from the SharpDX Matrix + trns.trans.x = inFbxNode.LclTranslation.X; + trns.trans.y = inFbxNode.LclTranslation.Y; + trns.trans.z = inFbxNode.LclTranslation.Z; + + trns.right.x = fbMatrix.M11; + trns.right.y = fbMatrix.M12; + trns.right.z = fbMatrix.M13; + + trns.up.x = fbMatrix.M21; + trns.up.y = fbMatrix.M22; + trns.up.z = fbMatrix.M23; + + trns.forward.x = fbMatrix.M31; + trns.forward.y = fbMatrix.M32; + trns.forward.z = fbMatrix.M33; + + return trns; + } + + private List GetVerticesFromCluster(FbxMesh fmesh, FbxCluster cluster, Matrix sectionMatrix) + { + IntPtr verticesBuffer = fmesh.GetControlPoints(); + + int[] controlPointIndices = cluster.GetControlPointIndices(); + int controlPointIndiceCount = controlPointIndices.Count(); + List vertexIndices = new List(); + List vertexPositions = new List(); + + for (int i = 0; i < fmesh.PolygonCount; i++) + { + for (int j = 0; j < 3; j++) + { + int vertexIndex = fmesh.GetPolygonIndex(i, j); + + if (controlPointIndiceCount > vertexIndex && controlPointIndices[vertexIndex] >= 0) + { + vertexIndices.Add(vertexIndex); + } + } + } + + foreach (int vIdx in vertexIndices) + { + Vector3 position; + unsafe + { + double* pointsPtr = (double*)(verticesBuffer + (vIdx * 32)); + position = new Vector3((float)pointsPtr[XAxis] * Scale, (float)pointsPtr[YAxis] * Scale, (float)(pointsPtr[ZAxis] * FlipZ) * Scale); + } + + Vector4 tmp = Vector3.Transform(position, sectionMatrix); + position.X = tmp.X; + position.Y = tmp.Y; + position.Z = tmp.Z; + + vertexPositions.Add(position); + } + + return vertexPositions; + } + + private void CalculateCompositePartDataForLod(List nodes, MeshSetLod meshLod) + { + List boneList = new List(); + List partTransforms = new List(); + List partAABBs = new List(); + List partIndices = new List(); + Dictionary> boneToVerticesMapping = new Dictionary>(); + + foreach(FbxNode node in nodes) + { + FbxNodeAttribute attr = node.GetNodeAttribute(FbxNodeAttribute.EType.eMesh); + FbxMesh fmesh = new FbxMesh(attr); + FbxSkin fskin = (fmesh.GetDeformerCount(FbxDeformer.EDeformerType.eSkin) != 0) + ? new FbxSkin(fmesh.GetDeformer(0, FbxDeformer.EDeformerType.eSkin)) + : null; + + if (fskin == null) + return; + + foreach (FbxCluster cluster in fskin.Clusters) + { + if (cluster.ControlPointIndicesCount == 0) + continue; + + FbxNode bone = cluster.GetLink(); + ushort idx = ushort.Parse(bone.Name.Substring(bone.Name.LastIndexOf('_') + 1)); + + Matrix sectionMatrix = new FbxMatrix(node.EvaluateGlobalTransform()).ToSharpDX(); + + if (!boneList.Contains(idx)) + { + boneList.Add(idx); + partTransforms.Add(FbxTransformToLinearTransform(bone)); + + boneToVerticesMapping.Add(idx, GetVerticesFromCluster(fmesh, cluster, sectionMatrix)); + } + else + { + boneToVerticesMapping[idx].Concat(GetVerticesFromCluster(fmesh, cluster, sectionMatrix)); + } + } + } + + foreach(var boneAndVertices in boneToVerticesMapping) + { + partAABBs.Add(AABBFromPoints(boneAndVertices.Value)); + } + + // TEMP + // For now, just set the part indices to include everything + foreach(ushort boneIdx in boneList) + { + int partIndice = 0; + for (int i = 0; i < boneList.Count; i++) + { + partIndice |= 1 << i; + } + partIndices.Add(partIndice); + } + + meshLod.SetParts(partTransforms, partAABBs, partIndices); + } + private void ProcessSection(FbxNode[] sectionNodes, MeshSetLod meshLod, int sectionIndex, MemoryStream verticesBuffer, List indicesBuffer, uint vertexOffset, ref uint startIndex) { MeshSetSection meshSection = meshLod.Sections[sectionIndex]; @@ -1958,6 +2133,9 @@ private void ProcessSection(FbxNode[] sectionNodes, MeshSetLod meshLod, int sect List boneList = new List(); List boneNames = new List(); List procBones = new List(); + List partTransforms = new List(); + //List partBoundingBoxes = new List(); + List partIndices = new List(); // load in skeleton dynamic skeleton = null; @@ -2038,12 +2216,28 @@ private void ProcessSection(FbxNode[] sectionNodes, MeshSetLod meshLod, int sect continue; FbxNode bone = cluster.GetLink(); - ushort idx = (ushort)skeleton.BoneNames.IndexOf(bone.Name); + ushort idx; + if(meshSet.Type == MeshType.MeshType_Composite) + { + // get id from bone name, composite bone names should always be in the format PART_X + idx = ushort.Parse(bone.Name.Substring(bone.Name.LastIndexOf('_') + 1)); + } + else + { + idx = (ushort)skeleton.BoneNames.IndexOf(bone.Name); + } if (!boneList.Contains(idx)) { boneList.Add(idx); - boneNames.Add(skeleton.BoneNames[idx]); + if(meshSet.Type == MeshType.MeshType_Composite) + { + boneNames.Add(bone.Name); + } + else + { + boneNames.Add(skeleton.BoneNames[idx]); + } } } } @@ -2055,6 +2249,11 @@ private void ProcessSection(FbxNode[] sectionNodes, MeshSetLod meshLod, int sect Array.Sort(boneListArray, boneNamesArray); meshSection.SetBones(boneListArray); + if(meshSet.Type == MeshType.MeshType_Composite) + { + //meshLod.SetParts(partTransforms, partBoundingBoxes); + //meshLod.SetPartIndices(partIndices); + } meshLod.AddBones(boneListArray, boneNamesArray); boneList.Clear(); @@ -2106,8 +2305,15 @@ private void ProcessSection(FbxNode[] sectionNodes, MeshSetLod meshLod, int sect } else { - boneIdx = (ushort)skeleton.BoneNames.IndexOf(bone.Name); - boneIdx = (ushort)boneList.IndexOf(boneIdx); + if(meshSet.Type == MeshType.MeshType_Composite) + { + boneIdx = ushort.Parse(bone.Name.Substring(bone.Name.LastIndexOf('_') + 1)); + } + else + { + boneIdx = (ushort)skeleton.BoneNames.IndexOf(bone.Name); + boneIdx = (ushort)boneList.IndexOf(boneIdx); + } } for (int i = 0; i < tmpIndices.Length; i++) @@ -2896,13 +3102,57 @@ private void ProcessSection(FbxNode[] sectionNodes, MeshSetLod meshLod, int sect numIndices++; } + // generate part bounding box + /*if(meshSet.Type == MeshType.MeshType_Composite) + { + List verticePositions = new List(); + foreach (DbObject vertex in vertices) + { + Vector4 tmp = vertex.GetValue("Pos"); + Vector4 position = Vector3.Transform(new Vector3(tmp.X, tmp.Y, tmp.Z), sectionMatrix); + verticePositions.Add(new Vector3(position.X, position.Y, position.Z)); + } + + //partBoundingBoxes.Add(AABBFromPoints(verticePositions)); + + // TEMP + // For now, just set the part indice to include everything + int partIndice = 0; + for (int i = 0; i < boneList.Count; i++) + { + partIndice |= 1 << i; + } + partIndices.Add(partIndice); + }*/ meshSection.PrimitiveCount += (uint)(numIndices / 3); startIndex += (uint)numIndices; indexOffset += (uint)vertices.Count; } + + } + + private AxisAlignedBox AABBFromPoints(List points) + { + BoundingBox bbox = BoundingBox.FromPoints(points.ToArray()); + + Vec3 min = new Vec3(); + min.x = bbox.Minimum.X; + min.y = bbox.Minimum.Y; + min.z = bbox.Minimum.Z; + + Vec3 max = new Vec3(); + max.x = bbox.Maximum.X; + max.y = bbox.Maximum.Y; + max.z = bbox.Maximum.Z; + + AxisAlignedBox aabb = new AxisAlignedBox(); + aabb.min = min; + aabb.max = max; + return aabb; } } + #endregion class VariationToStringConverter : IValueConverter @@ -3481,6 +3731,23 @@ private void FrostyMeshSetEditor_Loaded(object sender, RoutedEventArgs e) ResAssetEntry rEntry = App.AssetManager.GetResEntry(resRid); meshSet = App.AssetManager.GetResAs(rEntry); + /*if (meshSet.Lods[0].SectionCount == 2) + { + ResAssetEntry meshset = App.AssetManager.GetResEntry( + "worlds/themepark/vegetation/themepark_rome_busha_indestructable_mesh"); + MeshSet donorMeshSet = App.AssetManager.GetResAs(meshset); + + for (int i = 0; i < meshSet.Lods.Count; i++) + { + MeshSetLod lod = meshSet.Lods[i]; + MeshSetLod donorLod = donorMeshSet.Lods[0]; + + lod.SectionCount++; + MeshSetSection donorSection = donorLod.Sections[1]; + lod.Sections.Add(donorSection); + } + App.AssetManager.ModifyRes(meshSet.ResourceId, meshSet.SaveBytes(), meshSet.ResourceMeta); + }*/ if (ProfilesLibrary.DataVersion == (int)ProfileVersion.Madden19 || ProfilesLibrary.DataVersion == (int)ProfileVersion.Madden20) meshSet.TangentSpaceCompressionType = (TangentSpaceCompressionType)((dynamic)RootObject).TangentSpaceCompressionType; @@ -3968,6 +4235,10 @@ private List LoadVariations() AssetClassGuid guid = material.GetInstanceGuid(); MeshVariationMaterial varMaterial = mv.GetMaterial(guid.ExportedGuid); + if (varMaterial == null) + { + continue; + } MeshSetMaterialDetails details = new MeshSetMaterialDetails(); variationDetails.MaterialCollection = new MeshMaterialCollection.Container(new MeshMaterialCollection(asset, new PointerRef(varMaterial.MaterialVariationAssetGuid))); } @@ -4144,7 +4415,10 @@ private void ImportButton_Click(object sender, RoutedEventArgs e) } catch (Exception exp) { - App.AssetManager.RevertAsset(AssetEntry); + if (!AssetEntry.IsAdded) + { + App.AssetManager.RevertAsset(AssetEntry); + } logger.LogError(exp.Message); } }); diff --git a/Plugins/MeshSetPlugin/MeshSetPlugin.csproj b/Plugins/MeshSetPlugin/MeshSetPlugin.csproj index d182953c..ab376ede 100644 --- a/Plugins/MeshSetPlugin/MeshSetPlugin.csproj +++ b/Plugins/MeshSetPlugin/MeshSetPlugin.csproj @@ -48,6 +48,14 @@ + + + + + + + + ..\..\FrostyEditor\ThirdParty\SharpDX.dll @@ -67,24 +75,6 @@ - - - false - - - false - - - false - - - false - - - false - - - diff --git a/Plugins/MeshSetPlugin/Resources/MeshSet.cs b/Plugins/MeshSetPlugin/Resources/MeshSet.cs index 9fcffeb3..3cff1cb3 100644 --- a/Plugins/MeshSetPlugin/Resources/MeshSet.cs +++ b/Plugins/MeshSetPlugin/Resources/MeshSet.cs @@ -7,6 +7,8 @@ using System.Runtime.InteropServices; using FrostySdk; using FrostySdk.Resources; +using Frosty.Core; +using MeshSetPlugin.Fbx; namespace MeshSetPlugin.Resources { @@ -740,6 +742,18 @@ struct IndexBufferFormatStruct public MeshType Type { get => meshType; set => meshType = value; } public List Sections => sections; + + public int SectionCount + { + get + { + return sectionCount; + } + set + { + sectionCount = value; + } + } public MeshLayoutFlags Flags => flags; public int IndexUnitSize { @@ -762,9 +776,10 @@ public int IndexUnitSize public int BoneCount => boneIndexArray.Count; public List BoneIndexArray => boneIndexArray; public List BoneShortNameArray => boneShortNameArray; - public int PartCount => partBoundingBoxes.Count; + public int PartCount => PartTransforms.Count; public List PartBoundingBoxes => partBoundingBoxes; public List PartTransforms => partTransforms; + public List PartIndices => partIndices; public byte[] InlineData => inlineData; public List> CategorySubsetIndices => subsetCategories; @@ -844,6 +859,7 @@ public bool HasAdjacencyInMesh private string shortName; private uint nameHash; private List sections = new List(); + private int sectionCount; private List> subsetCategories = new List>(); //private uint boneCount; @@ -852,6 +868,8 @@ public bool HasAdjacencyInMesh private List partBoundingBoxes = new List(); private List partTransforms = new List(); + private List partIndices = new List(); + public List rawPartIndices = new List(); private byte[] inlineData; private uint inlineDataOffset; @@ -866,13 +884,9 @@ public MeshSetLod(NativeReader reader, AssetManager am) if (ProfilesLibrary.DataVersion == (int)ProfileVersion.Anthem) reader.ReadUInt(); - uint sectionCount = reader.ReadUInt(); + sectionCount = (int)reader.ReadUInt(); long sectionOffset = reader.ReadLong(); - // sections - for (uint i = 0; i < sectionCount; i++) - sections.Add(null); - // section categories List subsetCategoryOffsets = new List(); for (int i = 0; i < MaxCategories; i++) @@ -991,8 +1005,9 @@ public MeshSetLod(NativeReader reader, AssetManager am) reader.Pad(16); - // bone data long curPos = reader.Position; + + // bone data if (meshType == MeshType.MeshType_Skinned) { reader.Position = bonePartOffset01; @@ -1025,18 +1040,30 @@ public MeshSetLod(NativeReader reader, AssetManager am) if (bonePartOffset03 != 0) { reader.Position = bonePartOffset03; - List partIndices = new List(); - for (int i = 0; i < 0x18; i++) + for (int s = 0; s < sectionCount; s++) { - int b = reader.ReadByte(); - for (int j = 0; j < 8; j++) + for (int i = 0; i < 0x18; i++) { - if ((b & 0x01) != 0) - partIndices.Add((i * 8) + j); - b >>= 1; + int b = reader.ReadByte(); + for (int j = 0; j < 8; j++) + { + if ((b & 0x01) != 0) + partIndices.Add((i * 8) + j); + b >>= 1; + } } } + + // TEMP + reader.Position = bonePartOffset03; + + for (int s2 = 0; s2 < sectionCount; s2++) + { + rawPartIndices.Add(reader.ReadLong()); + reader.ReadLong(); + reader.ReadLong(); + } } } @@ -1100,27 +1127,11 @@ public void SetSectionCategory(MeshSetSection inSection, MeshSubsetCategory cate subsetCategories[(int)category].Add(index); } - public void SetParts(List inPartTransforms, List inPartBBoxes) + public void SetParts(List inPartTransforms, List inPartBBoxes, List inPartIndices) { partTransforms = inPartTransforms; partBoundingBoxes = inPartBBoxes; - - if (partTransforms.Count != partBoundingBoxes.Count) - { - for (int i = 0; i < partBoundingBoxes.Count; i++) - { - if (i >= partTransforms.Count) - { - partTransforms.Add(new LinearTransform() - { - right = new Vec3() { x = 1.0f, y = 0.0f, z = 0.0f }, - up = new Vec3() { x = 0.0f, y = 1.0f, z = 0.0f }, - forward = new Vec3() { x = 0.0f, y = 0.0f, z = 1.0f }, - trans = new Vec3() { x = 0.0f, y = 0.0f, z = 0.0f } - }); - } - } - } + partIndices = inPartIndices; } public void ClearBones() @@ -1129,6 +1140,13 @@ public void ClearBones() boneShortNameArray.Clear(); } + public void ClearPartData() + { + partTransforms.Clear(); + partBoundingBoxes.Clear(); + partIndices.Clear(); + } + public void AddBones(IEnumerable bones, IEnumerable boneNames) { foreach (ushort boneId in bones) @@ -1195,7 +1213,7 @@ private int GetSectionIndex(MeshSetSection inSection) return index; } - internal void PreProcess(MeshContainer meshContainer, ref uint inInlineDataOffset) + internal void PreProcess(MeshContainer meshContainer, ref uint inInlineDataOffset, int lodIdx) { inlineDataOffset = 0xFFFFFFFF; if (inlineData != null) @@ -1248,9 +1266,16 @@ internal void PreProcess(MeshContainer meshContainer, ref uint inInlineDataOffse } } } + + if(meshType == MeshType.MeshType_Composite) + { + meshContainer.AddRelocPtr("PARTBBOXES" + lodIdx.ToString(), partBoundingBoxes); + meshContainer.AddRelocPtr("PARTTRANSFORMS" + lodIdx.ToString(), partTransforms); + meshContainer.AddRelocPtr("PARTINDICES" + lodIdx.ToString(), partIndices); + } } - internal void Process(NativeWriter writer, MeshContainer meshContainer) + internal void Process(NativeWriter writer, MeshContainer meshContainer, int lodIdx) { writer.Write((int)meshType); writer.Write(maxInstances); @@ -1320,11 +1345,15 @@ internal void Process(NativeWriter writer, MeshContainer meshContainer) writer.Write((ulong)0); } } - //else - //{ - // // All others - // writer.Write(boneIndexArray.Count); - //} + + if(meshType == MeshType.MeshType_Composite) + { + // Write composite part data + writer.Write(boneIndexArray.Count); // part count + meshContainer.WriteRelocPtr("PARTBBOXES" + lodIdx.ToString(), partBoundingBoxes, writer); + meshContainer.WriteRelocPtr("PARTTRANSFORMS" + lodIdx.ToString(), partTransforms, writer); + meshContainer.WriteRelocPtr("PARTINDICES" + lodIdx.ToString(), partIndices, writer); + } writer.WritePadding(16); } } @@ -1398,6 +1427,7 @@ public int MaxLodCount private List partBoundingBoxes = new List(); private List partTransforms = new List(); + private List partIndices = new List(); private byte[] unknownbfv; @@ -1606,16 +1636,16 @@ public override void Read(NativeReader reader, AssetManager am, ResAssetEntry en Debug.Assert(reader.Position == lodOffsets[i]); lods.Add(new MeshSetLod(reader, am)); - if (ProfilesLibrary.DataVersion == (int)ProfileVersion.MassEffectAndromeda || ProfilesLibrary.DataVersion == (int)ProfileVersion.StarWarsBattlefrontII || ProfilesLibrary.DataVersion == (int)ProfileVersion.StarWarsSquadrons) - lods[i].SetParts(partTransforms, partBoundingBoxes); + //if (ProfilesLibrary.DataVersion == (int)ProfileVersion.MassEffectAndromeda || ProfilesLibrary.DataVersion == (int)ProfileVersion.StarWarsBattlefrontII || ProfilesLibrary.DataVersion == (int)ProfileVersion.StarWarsSquadrons) + // lods[i].SetParts(partTransforms, partBoundingBoxes); } // sections int z = 0; foreach (MeshSetLod lod in lods) { - for (int i = 0; i < lod.Sections.Count; i++) - lod.Sections[i] = new MeshSetSection(reader, am, z++); + for (int i = 0; i < lod.SectionCount; i++) + lod.Sections.Add(new MeshSetSection(reader, am, z++)); } // strings @@ -1794,9 +1824,11 @@ public override byte[] SaveBytes() private void PreProcess(MeshContainer meshContainer) { uint inlineDataOffset = 0; + int lodIdx = 0; foreach (var lod in lods) { - lod.PreProcess(meshContainer, ref inlineDataOffset); + lod.PreProcess(meshContainer, ref inlineDataOffset, lodIdx); + lodIdx++; } foreach (var lod in lods) meshContainer.AddRelocPtr("LOD", lod); @@ -1865,10 +1897,12 @@ private void Process(NativeWriter writer, MeshContainer meshContainer) Debug.Assert(writer.Position == HeaderSize); // lods + int lodIdx = 0; foreach (var lod in lods) { meshContainer.AddOffset("LOD", lod, writer); - lod.Process(writer, meshContainer); + lod.Process(writer, meshContainer, lodIdx); + lodIdx++; } // sections @@ -1951,6 +1985,58 @@ private void Process(NativeWriter writer, MeshContainer meshContainer) writer.WritePadding(16); } } + if (meshType == MeshType.MeshType_Composite) + { + // each lod needs it's own part bboxes, transforms, and indices + int lIdx = 0; + + foreach(var lod in lods) + { + meshContainer.AddOffset("PARTBBOXES" + lIdx.ToString(), lod.PartBoundingBoxes, writer); + foreach (AxisAlignedBox box in lod.PartBoundingBoxes) + writer.Write(box); + + meshContainer.AddOffset("PARTTRANSFORMS" + lIdx.ToString(), lod.PartTransforms, writer); + foreach (LinearTransform lt in lod.PartTransforms) + writer.Write(lt); + + meshContainer.AddOffset("PARTINDICES" + lIdx.ToString(), lod.PartIndices, writer); + foreach(int partIndice in lod.PartIndices) + { + writer.Write((long)partIndice); + writer.Write((long)0); + writer.Write((long)0); + } + //for (int sectionIdx = 0; sectionIdx < lod.Sections.Count; sectionIdx++) + //{ + /*long indice = 0; + for (int indiceIdx = 0; indiceIdx < lod.PartCount; indiceIdx++) + { + int indiceListIdx = sectionIdx == 0 + ? indiceIdx + : (sectionIdx * lod.PartCount) + indiceIdx; + + indice |= 1 << lod.PartIndices[indiceListIdx]; + } + writer.Write(indice);*/ + //writer.Write(origMeshSet.Lods[lIdx].rawPartIndices[sectionIdx]); + //writer.Write((long)0); + //writer.Write((long)0); + //} + long writerPos = writer.Position; + // make sure data is aligned + long alignedPos = (writerPos + 0x10 - (writerPos % 0x10)); + bool needsPadding = alignedPos != (writerPos + 0x10); + if (needsPadding) + { + while(writer.Position < alignedPos) + { + writer.Write((byte)0); + } + } + lIdx++; + } + } } } #endregion