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