From 7f74a97a37385bff724ed2dd65758d24c75b150f Mon Sep 17 00:00:00 2001 From: Sezz Date: Sun, 14 Dec 2025 23:10:05 +1100 Subject: [PATCH 1/4] Write baked frames and real planes to TEN level --- TombLib/TombLib/IO/BinaryWriterEx.cs | 8 ++ .../Compilers/TombEngine/FloorData.cs | 40 ++++----- .../LevelData/Compilers/TombEngine/Rooms.cs | 4 +- .../LevelData/Compilers/TombEngine/Structs.cs | 81 +++++++++++++++---- 4 files changed, 93 insertions(+), 40 deletions(-) diff --git a/TombLib/TombLib/IO/BinaryWriterEx.cs b/TombLib/TombLib/IO/BinaryWriterEx.cs index bd331773c..5fe15f01e 100644 --- a/TombLib/TombLib/IO/BinaryWriterEx.cs +++ b/TombLib/TombLib/IO/BinaryWriterEx.cs @@ -37,6 +37,14 @@ public void Write(Vector4 value) Write(value.W); } + public void Write(Plane value) + { + Write(value.Normal.X); + Write(value.Normal.Y); + Write(value.Normal.Z); + Write(value.D); + } + public void Write(Quaternion value) { Write(value.X); diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs index edd86306c..222f9bdcc 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs @@ -100,10 +100,10 @@ private void BuildFloorData() compiledSector.WallPortal = _roomRemapping[sector.WallPortal.AdjoiningRoom]; } - compiledSector.FloorCollision.Planes[0].Z = -room.Position.Y; - compiledSector.FloorCollision.Planes[1].Z = -room.Position.Y; - compiledSector.CeilingCollision.Planes[0].Z = -room.Position.Y; - compiledSector.CeilingCollision.Planes[1].Z = -room.Position.Y; + compiledSector.FloorCollision.Planes[0].D = -room.Position.Y; + compiledSector.FloorCollision.Planes[1].D = -room.Position.Y; + compiledSector.CeilingCollision.Planes[0].D = -room.Position.Y; + compiledSector.CeilingCollision.Planes[1].D = -room.Position.Y; } else { @@ -511,14 +511,14 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0].Z = -float.MaxValue; + newCollision.Planes[0].D = -float.MaxValue; } else { if (shape.SplitPortalFirst) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0] = GetPlane( + newCollision.Planes[0] = Plane.CreateFromVertices( new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp, Level.HalfSectorSizeUnit), new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn, -Level.HalfSectorSizeUnit) @@ -530,14 +530,14 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1].Z = -float.MaxValue; + newCollision.Planes[1].D = -float.MaxValue; } else { if (shape.SplitPortalSecond) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1] = GetPlane( + newCollision.Planes[1] = Plane.CreateFromVertices( new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit), new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn - shape.DiagonalStep, -Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp - shape.DiagonalStep, Level.HalfSectorSizeUnit) @@ -553,14 +553,14 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0].Z = -float.MaxValue; + newCollision.Planes[0].D = -float.MaxValue; } else { if (shape.SplitPortalSecond) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0] = GetPlane( + newCollision.Planes[0] = Plane.CreateFromVertices( new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn - shape.DiagonalStep, -Level.HalfSectorSizeUnit), new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp - shape.DiagonalStep, Level.HalfSectorSizeUnit) @@ -571,18 +571,18 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1].Z = -float.MaxValue; + newCollision.Planes[1].D = -float.MaxValue; } else { if (shape.SplitPortalFirst) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1] = GetPlane( - new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn, -Level.HalfSectorSizeUnit), - new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), - new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit) - ); + newCollision.Planes[1] = Plane.CreateFromVertices( + new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn, -Level.HalfSectorSizeUnit), + new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), + new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit) + ); } } } @@ -594,7 +594,7 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT newCollision.Portals[1] = newCollision.Portals[0]; } - newCollision.Planes[0] = GetPlane( + newCollision.Planes[0] = Plane.CreateFromVertices( new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit) @@ -602,11 +602,5 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT newCollision.Planes[1] = newCollision.Planes[0]; } } - - private Vector3 GetPlane(Vector3 p1, Vector3 p2, Vector3 p3) - { - var plane = Plane.CreateFromVertices(p1, p2, p3); - return new Vector3(-plane.Normal.X, -plane.Normal.Z, Vector3.Dot(plane.Normal, p1)) / plane.Normal.Y; - } } } diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs index 1cc738914..e816e9096 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs @@ -1023,10 +1023,10 @@ private void ConvertSectors(Room room, TombEngineRoom newRoom) compiledSector.FloorCollision = new TombEngineCollisionInfo(); compiledSector.FloorCollision.Portals = new int[2] {-1, -1}; - compiledSector.FloorCollision.Planes = new Vector3[2]; + compiledSector.FloorCollision.Planes = new Plane[2]; compiledSector.CeilingCollision = new TombEngineCollisionInfo(); compiledSector.CeilingCollision.Portals = new int[2] {-1, -1}; - compiledSector.CeilingCollision.Planes = new Vector3[2]; + compiledSector.CeilingCollision.Planes = new Plane[2]; compiledSector.WallPortal = -1; compiledSector.StepSound = (int)GetTextureSound(room, x, z); compiledSector.BoxIndex = -1; diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs index a00161107..94a8b8eb9 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs @@ -52,7 +52,7 @@ public class TombEngineCollisionInfo { public float SplitAngle; public int[] Portals; - public Vector3[] Planes; + public Plane[] Planes; } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -665,6 +665,7 @@ public void Write(BinaryWriterEx writer) writer.Write(fixedMotionCurveZ.StartHandle); writer.Write(fixedMotionCurveZ.EndHandle); + // Write dummy frame if no key frames exist. if (animation.KeyFrames.Count == 0) { var defaultKeyFrame = new TombEngineKeyFrame(); @@ -673,12 +674,49 @@ public void Write(BinaryWriterEx writer) writer.Write(1); defaultKeyFrame.Write(writer); } + // Write baked frames. else { - writer.Write(animation.KeyFrames.Count); - foreach (var keyFrame in animation.KeyFrames) + // Write key frame. + writer.Write(animation.KeyFrames.Count * animation.Interpolation); + + float alphaStep = 1.0f / (float)animation.Interpolation; + for (int i = 0; i < animation.KeyFrames.Count; i++) { - keyFrame.Write(writer); + var currentKeyframe = animation.KeyFrames[i]; + currentKeyframe.Write(writer); + + if (i == (animation.KeyFrames.Count - 1)) + continue; + + var nextKeyframe = animation.KeyFrames[i + 1]; + + // Write interpolated frames. + for (int j = 1; j < animation.Interpolation; j++) + { + float alpha = alphaStep * j; + + var center = Vector3.Lerp(currentKeyframe.BoundingBox.Center, nextKeyframe.BoundingBox.Center, alpha); + var extents = Vector3.Lerp(currentKeyframe.BoundingBox.Extents, nextKeyframe.BoundingBox.Extents, alpha); + + var rootPos = Vector3.Lerp(currentKeyframe.RootOffset, nextKeyframe.RootOffset, alpha); + + var boneOrients = new List(currentKeyframe.BoneOrientations.Count); + for (int k = 0; k < boneOrients.Count; k++) + boneOrients[k] = Quaternion.Slerp(currentKeyframe.BoneOrientations[k], nextKeyframe.BoneOrientations[k], alpha); + + var frame = new TombEngineKeyFrame(); + frame.BoundingBox = new TombEngineBoundingBox(); + frame.BoundingBox.X1 = (short)(center.X - extents.X); + frame.BoundingBox.X2 = (short)(center.X + extents.X); + frame.BoundingBox.Y1 = (short)(center.Y - extents.Y); + frame.BoundingBox.Y2 = (short)(center.Y + extents.Y); + frame.BoundingBox.Z1 = (short)(center.Z + extents.Z); + frame.BoundingBox.Z2 = (short)(center.Z - extents.Z); + frame.RootOffset = rootPos; + frame.BoneOrientations = boneOrients; + frame.Write(writer); + } } } @@ -757,17 +795,8 @@ public class TombEngineKeyFrame public void Write(BinaryWriterEx writer) { - var center = new Vector3( - BoundingBox.X1 + BoundingBox.X2, - BoundingBox.Y1 + BoundingBox.Y2, - BoundingBox.Z1 + BoundingBox.Z2) / 2; - var extents = new Vector3( - BoundingBox.X2 - BoundingBox.X1, - BoundingBox.Y2 - BoundingBox.Y1, - BoundingBox.Z2 - BoundingBox.Z1) / 2; - - writer.Write(center); - writer.Write(extents); + writer.Write(BoundingBox.Center); + writer.Write(BoundingBox.Extents); writer.Write(RootOffset); writer.Write(BoneOrientations.Count); @@ -784,6 +813,28 @@ public struct TombEngineBoundingBox public short Y2; public short Z1; public short Z2; + + public Vector3 Center + { + get + { + return new Vector3( + X1 + X2, + Y1 + Y2, + Z1 + Z2) / 2; + } + } + + public Vector3 Extents + { + get + { + return new Vector3( + X1 - X2, + Y1 - Y2, + Z1 - Z2) / 2; + } + } } [StructLayout(LayoutKind.Sequential, Pack = 1)] From e03e66a41abde75bc7c26cb7a085e459a556f867 Mon Sep 17 00:00:00 2001 From: Sezz Date: Mon, 15 Dec 2025 18:33:31 +1100 Subject: [PATCH 2/4] Revert "Write baked frames and real planes to TEN level" This reverts commit 7f74a97a37385bff724ed2dd65758d24c75b150f. --- TombLib/TombLib/IO/BinaryWriterEx.cs | 8 -- .../Compilers/TombEngine/FloorData.cs | 40 +++++---- .../LevelData/Compilers/TombEngine/Rooms.cs | 4 +- .../LevelData/Compilers/TombEngine/Structs.cs | 81 ++++--------------- 4 files changed, 40 insertions(+), 93 deletions(-) diff --git a/TombLib/TombLib/IO/BinaryWriterEx.cs b/TombLib/TombLib/IO/BinaryWriterEx.cs index 5fe15f01e..bd331773c 100644 --- a/TombLib/TombLib/IO/BinaryWriterEx.cs +++ b/TombLib/TombLib/IO/BinaryWriterEx.cs @@ -37,14 +37,6 @@ public void Write(Vector4 value) Write(value.W); } - public void Write(Plane value) - { - Write(value.Normal.X); - Write(value.Normal.Y); - Write(value.Normal.Z); - Write(value.D); - } - public void Write(Quaternion value) { Write(value.X); diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs index 222f9bdcc..edd86306c 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/FloorData.cs @@ -100,10 +100,10 @@ private void BuildFloorData() compiledSector.WallPortal = _roomRemapping[sector.WallPortal.AdjoiningRoom]; } - compiledSector.FloorCollision.Planes[0].D = -room.Position.Y; - compiledSector.FloorCollision.Planes[1].D = -room.Position.Y; - compiledSector.CeilingCollision.Planes[0].D = -room.Position.Y; - compiledSector.CeilingCollision.Planes[1].D = -room.Position.Y; + compiledSector.FloorCollision.Planes[0].Z = -room.Position.Y; + compiledSector.FloorCollision.Planes[1].Z = -room.Position.Y; + compiledSector.CeilingCollision.Planes[0].Z = -room.Position.Y; + compiledSector.CeilingCollision.Planes[1].Z = -room.Position.Y; } else { @@ -511,14 +511,14 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0].D = -float.MaxValue; + newCollision.Planes[0].Z = -float.MaxValue; } else { if (shape.SplitPortalFirst) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0] = Plane.CreateFromVertices( + newCollision.Planes[0] = GetPlane( new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp, Level.HalfSectorSizeUnit), new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn, -Level.HalfSectorSizeUnit) @@ -530,14 +530,14 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1].D = -float.MaxValue; + newCollision.Planes[1].Z = -float.MaxValue; } else { if (shape.SplitPortalSecond) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1] = Plane.CreateFromVertices( + newCollision.Planes[1] = GetPlane( new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit), new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn - shape.DiagonalStep, -Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp - shape.DiagonalStep, Level.HalfSectorSizeUnit) @@ -553,14 +553,14 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0].D = -float.MaxValue; + newCollision.Planes[0].Z = -float.MaxValue; } else { if (shape.SplitPortalSecond) newCollision.Portals[0] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[0] = Plane.CreateFromVertices( + newCollision.Planes[0] = GetPlane( new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn - shape.DiagonalStep, -Level.HalfSectorSizeUnit), new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp - shape.DiagonalStep, Level.HalfSectorSizeUnit) @@ -571,18 +571,18 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT if (portal != null) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1].D = -float.MaxValue; + newCollision.Planes[1].Z = -float.MaxValue; } else { if (shape.SplitPortalFirst) newCollision.Portals[1] = _roomRemapping[portal.AdjoiningRoom]; - newCollision.Planes[1] = Plane.CreateFromVertices( - new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn, -Level.HalfSectorSizeUnit), - new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), - new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit) - ); + newCollision.Planes[1] = GetPlane( + new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZn, -Level.HalfSectorSizeUnit), + new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), + new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit) + ); } } } @@ -594,7 +594,7 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT newCollision.Portals[1] = newCollision.Portals[0]; } - newCollision.Planes[0] = Plane.CreateFromVertices( + newCollision.Planes[0] = GetPlane( new Vector3(-Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXnZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZp, Level.HalfSectorSizeUnit), new Vector3(Level.HalfSectorSizeUnit, -reportRoom.Position.Y - shape.HeightXpZn, -Level.HalfSectorSizeUnit) @@ -602,5 +602,11 @@ private void BuildFloorDataCollision(RoomSectorShape shape, Room.RoomConnectionT newCollision.Planes[1] = newCollision.Planes[0]; } } + + private Vector3 GetPlane(Vector3 p1, Vector3 p2, Vector3 p3) + { + var plane = Plane.CreateFromVertices(p1, p2, p3); + return new Vector3(-plane.Normal.X, -plane.Normal.Z, Vector3.Dot(plane.Normal, p1)) / plane.Normal.Y; + } } } diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs index 9cdeabea6..c71ba5555 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Rooms.cs @@ -1025,10 +1025,10 @@ private void ConvertSectors(Room room, TombEngineRoom newRoom) compiledSector.FloorCollision = new TombEngineCollisionInfo(); compiledSector.FloorCollision.Portals = new int[2] {-1, -1}; - compiledSector.FloorCollision.Planes = new Plane[2]; + compiledSector.FloorCollision.Planes = new Vector3[2]; compiledSector.CeilingCollision = new TombEngineCollisionInfo(); compiledSector.CeilingCollision.Portals = new int[2] {-1, -1}; - compiledSector.CeilingCollision.Planes = new Plane[2]; + compiledSector.CeilingCollision.Planes = new Vector3[2]; compiledSector.WallPortal = -1; compiledSector.StepSound = (int)GetTextureSound(room, x, z); compiledSector.BoxIndex = -1; diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs index 94a8b8eb9..a00161107 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs @@ -52,7 +52,7 @@ public class TombEngineCollisionInfo { public float SplitAngle; public int[] Portals; - public Plane[] Planes; + public Vector3[] Planes; } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -665,7 +665,6 @@ public void Write(BinaryWriterEx writer) writer.Write(fixedMotionCurveZ.StartHandle); writer.Write(fixedMotionCurveZ.EndHandle); - // Write dummy frame if no key frames exist. if (animation.KeyFrames.Count == 0) { var defaultKeyFrame = new TombEngineKeyFrame(); @@ -674,49 +673,12 @@ public void Write(BinaryWriterEx writer) writer.Write(1); defaultKeyFrame.Write(writer); } - // Write baked frames. else { - // Write key frame. - writer.Write(animation.KeyFrames.Count * animation.Interpolation); - - float alphaStep = 1.0f / (float)animation.Interpolation; - for (int i = 0; i < animation.KeyFrames.Count; i++) + writer.Write(animation.KeyFrames.Count); + foreach (var keyFrame in animation.KeyFrames) { - var currentKeyframe = animation.KeyFrames[i]; - currentKeyframe.Write(writer); - - if (i == (animation.KeyFrames.Count - 1)) - continue; - - var nextKeyframe = animation.KeyFrames[i + 1]; - - // Write interpolated frames. - for (int j = 1; j < animation.Interpolation; j++) - { - float alpha = alphaStep * j; - - var center = Vector3.Lerp(currentKeyframe.BoundingBox.Center, nextKeyframe.BoundingBox.Center, alpha); - var extents = Vector3.Lerp(currentKeyframe.BoundingBox.Extents, nextKeyframe.BoundingBox.Extents, alpha); - - var rootPos = Vector3.Lerp(currentKeyframe.RootOffset, nextKeyframe.RootOffset, alpha); - - var boneOrients = new List(currentKeyframe.BoneOrientations.Count); - for (int k = 0; k < boneOrients.Count; k++) - boneOrients[k] = Quaternion.Slerp(currentKeyframe.BoneOrientations[k], nextKeyframe.BoneOrientations[k], alpha); - - var frame = new TombEngineKeyFrame(); - frame.BoundingBox = new TombEngineBoundingBox(); - frame.BoundingBox.X1 = (short)(center.X - extents.X); - frame.BoundingBox.X2 = (short)(center.X + extents.X); - frame.BoundingBox.Y1 = (short)(center.Y - extents.Y); - frame.BoundingBox.Y2 = (short)(center.Y + extents.Y); - frame.BoundingBox.Z1 = (short)(center.Z + extents.Z); - frame.BoundingBox.Z2 = (short)(center.Z - extents.Z); - frame.RootOffset = rootPos; - frame.BoneOrientations = boneOrients; - frame.Write(writer); - } + keyFrame.Write(writer); } } @@ -795,8 +757,17 @@ public class TombEngineKeyFrame public void Write(BinaryWriterEx writer) { - writer.Write(BoundingBox.Center); - writer.Write(BoundingBox.Extents); + var center = new Vector3( + BoundingBox.X1 + BoundingBox.X2, + BoundingBox.Y1 + BoundingBox.Y2, + BoundingBox.Z1 + BoundingBox.Z2) / 2; + var extents = new Vector3( + BoundingBox.X2 - BoundingBox.X1, + BoundingBox.Y2 - BoundingBox.Y1, + BoundingBox.Z2 - BoundingBox.Z1) / 2; + + writer.Write(center); + writer.Write(extents); writer.Write(RootOffset); writer.Write(BoneOrientations.Count); @@ -813,28 +784,6 @@ public struct TombEngineBoundingBox public short Y2; public short Z1; public short Z2; - - public Vector3 Center - { - get - { - return new Vector3( - X1 + X2, - Y1 + Y2, - Z1 + Z2) / 2; - } - } - - public Vector3 Extents - { - get - { - return new Vector3( - X1 - X2, - Y1 - Y2, - Z1 - Z2) / 2; - } - } } [StructLayout(LayoutKind.Sequential, Pack = 1)] From fd80fb5f051c53f77fe04e208b31199b22dfcbf0 Mon Sep 17 00:00:00 2001 From: Sezz Date: Mon, 15 Dec 2025 18:49:25 +1100 Subject: [PATCH 3/4] Only write baked frames --- .../LevelData/Compilers/TombEngine/Structs.cs | 79 +++++++++++++++---- 1 file changed, 65 insertions(+), 14 deletions(-) diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs index a00161107..4ecf54b29 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs @@ -665,6 +665,7 @@ public void Write(BinaryWriterEx writer) writer.Write(fixedMotionCurveZ.StartHandle); writer.Write(fixedMotionCurveZ.EndHandle); + // Write dummy frame if no key frames exist. if (animation.KeyFrames.Count == 0) { var defaultKeyFrame = new TombEngineKeyFrame(); @@ -673,12 +674,49 @@ public void Write(BinaryWriterEx writer) writer.Write(1); defaultKeyFrame.Write(writer); } + // Write baked frames. else { - writer.Write(animation.KeyFrames.Count); - foreach (var keyFrame in animation.KeyFrames) + // Write key frame. + writer.Write(animation.KeyFrames.Count * animation.Interpolation); + + float alphaStep = 1.0f / (float)animation.Interpolation; + for (int i = 0; i < animation.KeyFrames.Count; i++) { - keyFrame.Write(writer); + var currentKeyframe = animation.KeyFrames[i]; + currentKeyframe.Write(writer); + + if (i == (animation.KeyFrames.Count - 1)) + break; + + var nextKeyframe = animation.KeyFrames[i + 1]; + + // Write interpolated frames. + for (int j = 0; j < animation.Interpolation; j++) + { + float alpha = alphaStep * j; + + var center = Vector3.Lerp(currentKeyframe.BoundingBox.Center, nextKeyframe.BoundingBox.Center, alpha); + var extents = Vector3.Lerp(currentKeyframe.BoundingBox.Extents, nextKeyframe.BoundingBox.Extents, alpha); + + var rootPos = Vector3.Lerp(currentKeyframe.RootOffset, nextKeyframe.RootOffset, alpha); + + var boneOrients = new List(currentKeyframe.BoneOrientations.Count); + for (int k = 0; k < boneOrients.Count; k++) + boneOrients[k] = Quaternion.Slerp(currentKeyframe.BoneOrientations[k], nextKeyframe.BoneOrientations[k], alpha); + + var frame = new TombEngineKeyFrame(); + frame.BoundingBox = new TombEngineBoundingBox(); + frame.BoundingBox.X1 = (short)(center.X - extents.X); + frame.BoundingBox.X2 = (short)(center.X + extents.X); + frame.BoundingBox.Y1 = (short)(center.Y - extents.Y); + frame.BoundingBox.Y2 = (short)(center.Y + extents.Y); + frame.BoundingBox.Z1 = (short)(center.Z + extents.Z); + frame.BoundingBox.Z2 = (short)(center.Z - extents.Z); + frame.RootOffset = rootPos; + frame.BoneOrientations = boneOrients; + frame.Write(writer); + } } } @@ -757,17 +795,8 @@ public class TombEngineKeyFrame public void Write(BinaryWriterEx writer) { - var center = new Vector3( - BoundingBox.X1 + BoundingBox.X2, - BoundingBox.Y1 + BoundingBox.Y2, - BoundingBox.Z1 + BoundingBox.Z2) / 2; - var extents = new Vector3( - BoundingBox.X2 - BoundingBox.X1, - BoundingBox.Y2 - BoundingBox.Y1, - BoundingBox.Z2 - BoundingBox.Z1) / 2; - - writer.Write(center); - writer.Write(extents); + writer.Write(BoundingBox.Center); + writer.Write(BoundingBox.Extents); writer.Write(RootOffset); writer.Write(BoneOrientations.Count); @@ -784,6 +813,28 @@ public struct TombEngineBoundingBox public short Y2; public short Z1; public short Z2; + + public Vector3 Center + { + get + { + return new Vector3( + X1 + X2, + Y1 + Y2, + Z1 + Z2) / 2; + } + } + + public Vector3 Extents + { + get + { + return new Vector3( + X1 - X2, + Y1 - Y2, + Z1 - Z2) / 2; + } + } } [StructLayout(LayoutKind.Sequential, Pack = 1)] From 6dabf84df9c6f1a3455a83f57d20133f7a92ba81 Mon Sep 17 00:00:00 2001 From: Sezz Date: Mon, 15 Dec 2025 19:30:57 +1100 Subject: [PATCH 4/4] Update Structs.cs --- TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs index 4ecf54b29..916f4ec1b 100644 --- a/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs +++ b/TombLib/TombLib/LevelData/Compilers/TombEngine/Structs.cs @@ -631,7 +631,6 @@ public void Write(BinaryWriterEx writer) foreach (var animation in Animations) { writer.Write(animation.StateID); - writer.Write(animation.Interpolation); writer.Write(animation.FrameEnd); writer.Write(animation.NextAnimation); writer.Write(animation.NextFrame); @@ -692,7 +691,7 @@ public void Write(BinaryWriterEx writer) var nextKeyframe = animation.KeyFrames[i + 1]; // Write interpolated frames. - for (int j = 0; j < animation.Interpolation; j++) + for (int j = 1; j < animation.Interpolation; j++) { float alpha = alphaStep * j;