From c777fe187d62f8e8f8329f34b076e20d87f69da3 Mon Sep 17 00:00:00 2001 From: Jaremie Romer Date: Sun, 30 Nov 2025 13:01:39 -0600 Subject: [PATCH 1/3] No ccache for assimp --- cmake/FetchDependencies.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/FetchDependencies.cmake b/cmake/FetchDependencies.cmake index 5d4d8438b..b6ee7a02a 100644 --- a/cmake/FetchDependencies.cmake +++ b/cmake/FetchDependencies.cmake @@ -93,7 +93,7 @@ set(PROFILER_IN_DEBUG_AND_RELEASE OFF CACHE BOOL "" FORCE) set(ENABLE_INSTALL OFF CACHE BOOL "" FORCE) FetchContent_Declare(JoltPhysics GIT_REPOSITORY https://github.com/jrouwe/JoltPhysics - GIT_TAG v5.3.0 + GIT_TAG 0ec24eb93ad8ebe01f7f095b544af8e122713123 # No release available yet with VS 2026 fixes yet GIT_SHALLOW TRUE SOURCE_SUBDIR "Build" ) @@ -192,6 +192,7 @@ if(NC_BUILD_NCCONVERT) set(ASSIMP_BUILD_FBX_IMPORTER ON CACHE BOOL "" FORCE) set(ASSIMP_BUILD_OBJ_IMPORTER ON CACHE BOOL "" FORCE) set(ASSIMP_INSTALL_PDB OFF CACHE BOOL "" FORCE) + set(ASSIMP_BUILD_USE_CCACHE OFF CACHE BOOL "" FORCE) FetchContent_Declare(assimp GIT_REPOSITORY https://github.com/assimp/assimp From 863c214cb5d600de7ce9b215f6da3480199fba63 Mon Sep 17 00:00:00 2001 From: Jaremie Romer Date: Sat, 6 Dec 2025 10:42:03 -0600 Subject: [PATCH 2/3] Fix for jolt and for hierarchy UB --- cmake/FetchDependencies.cmake | 4 +- sample/source/scenes/GraphicsTest.cpp | 19 ++++++ source/ncengine/ecs/NcEcsImpl.cpp | 15 +++-- test/ncengine/ecs/Transform_unit_tests.cpp | 69 ++++++++++++++++++++-- 4 files changed, 95 insertions(+), 12 deletions(-) diff --git a/cmake/FetchDependencies.cmake b/cmake/FetchDependencies.cmake index b6ee7a02a..4505beb39 100644 --- a/cmake/FetchDependencies.cmake +++ b/cmake/FetchDependencies.cmake @@ -93,8 +93,8 @@ set(PROFILER_IN_DEBUG_AND_RELEASE OFF CACHE BOOL "" FORCE) set(ENABLE_INSTALL OFF CACHE BOOL "" FORCE) FetchContent_Declare(JoltPhysics GIT_REPOSITORY https://github.com/jrouwe/JoltPhysics - GIT_TAG 0ec24eb93ad8ebe01f7f095b544af8e122713123 # No release available yet with VS 2026 fixes yet - GIT_SHALLOW TRUE + GIT_TAG db654de2a6098fd1ad78cb9a3e70f6a8a61c00b5 # No release available yet with VS 2026 fixes yet + GIT_SHALLOW FALSE SOURCE_SUBDIR "Build" ) diff --git a/sample/source/scenes/GraphicsTest.cpp b/sample/source/scenes/GraphicsTest.cpp index 624886771..92c258117 100644 --- a/sample/source/scenes/GraphicsTest.cpp +++ b/sample/source/scenes/GraphicsTest.cpp @@ -165,6 +165,25 @@ void GraphicsTest::Load(ecs::Ecs world, ModuleProvider modules) .tag = "Main Camera" }); + // Grandchildren test + auto emptyChild = world.Emplace( + { + .position = Vector3::Zero(), + .rotation = Quaternion::Identity(), + .scale = Vector3::One(), + .parent = cameraHandle, + .tag = "Camera child" + }); + + auto emptyGrandChild = world.Emplace( + { + .position = Vector3::Zero(), + .rotation = Quaternion::Identity(), + .scale = Vector3::One(), + .parent = emptyChild, + .tag = "Camera grand child" + }); + auto& camera = world.Emplace(cameraHandle); world.Emplace(cameraHandle, InvokeFreeComponent{}); ncGraphics->SetCamera(&camera); diff --git a/source/ncengine/ecs/NcEcsImpl.cpp b/source/ncengine/ecs/NcEcsImpl.cpp index 6882524f1..4292885b6 100644 --- a/source/ncengine/ecs/NcEcsImpl.cpp +++ b/source/ncengine/ecs/NcEcsImpl.cpp @@ -99,26 +99,29 @@ void EcsModule::UpdateWorldSpaceMatrices() stack.emplace_back(&transform, hierarchy.children); while (!stack.empty()) { - auto& children = stack.back().children; - if (children.empty()) + if (stack.back().children.empty()) { stack.pop_back(); continue; } - if (!children.front().IsStatic()) + if (!stack.back().children.front().IsStatic()) { - auto& child = world.Get(children.front()); + auto& child = world.Get(stack.back().children.front()); dirty = dirty || child.IsDirty(); if (dirty) child.UpdateWorldMatrix(stack.back().transform->TransformationMatrix()); - auto& childHierarchy = world.Get(children.front()); + auto& childHierarchy = world.Get(stack.back().children.front()); if (!childHierarchy.children.empty()) + { + auto currentIndex = stack.size() - 1; // Save index before push stack.emplace_back(&child, childHierarchy.children); + stack[currentIndex].children = stack[currentIndex].children.subspan(1); // Advance using index + } } - children = children.subspan(1); + stack.back().children = stack.back().children.subspan(1); } } #else // debug update diff --git a/test/ncengine/ecs/Transform_unit_tests.cpp b/test/ncengine/ecs/Transform_unit_tests.cpp index 9368f4af1..e481f3b29 100644 --- a/test/ncengine/ecs/Transform_unit_tests.cpp +++ b/test/ncengine/ecs/Transform_unit_tests.cpp @@ -27,16 +27,58 @@ void EcsModule::RunFrameLogic() void EcsModule::UpdateWorldSpaceMatrices() { auto world = Ecs{*m_registry}; + + struct ParentInfo + { + Transform* transform; + std::span children; + }; + + auto stack = std::vector{}; for (auto entity : world.GetAll()) { + if (entity.IsStatic()) + continue; + auto& hierarchy = world.Get(entity); + if (hierarchy.parent.Valid()) // process root nodes first + continue; + auto& transform = world.Get(entity); - if (!hierarchy.parent.Valid()) + auto dirty = transform.IsDirty(); + if (dirty) transform.UpdateWorldMatrix(); - else + + if (hierarchy.children.empty()) + continue; + + stack.emplace_back(&transform, hierarchy.children); + while (!stack.empty()) { - auto& parentTransform = world.Get(hierarchy.parent); - transform.UpdateWorldMatrix(parentTransform.TransformationMatrix()); + if (stack.back().children.empty()) + { + stack.pop_back(); + continue; + } + + if (!stack.back().children.front().IsStatic()) + { + auto& child = world.Get(stack.back().children.front()); + dirty = dirty || child.IsDirty(); + if (dirty) + child.UpdateWorldMatrix(stack.back().transform->TransformationMatrix()); + + auto& childHierarchy = world.Get(stack.back().children.front()); + if (!childHierarchy.children.empty()) + { + auto currentIndex = stack.size() - 1; // Save index before push + stack.emplace_back(&child, childHierarchy.children); + stack[currentIndex].children = stack[currentIndex].children.subspan(1); // Advance using index + continue; + } + } + + stack.back().children = stack.back().children.subspan(1); } } } @@ -597,6 +639,25 @@ TEST_F(Transform_unit_tests, RotateAxisAngleOverload_CalledOnParent_OnlyWorldRot EXPECT_EQ(tChild.LocalScale(), Vector3::One()); } +TEST_F(Transform_unit_tests, RunFrameLogic_HasGrandchild_ChildrenAndGrandChildrenHaveDefaultLocals) +{ + auto parent = world.Emplace(EntityInfo{.position = testPos1, .scale = testScale1}); + auto child = world.Emplace(EntityInfo{.parent = parent}); + auto grandChild = world.Emplace(EntityInfo{.parent = child}); + auto& tChild = world.Get(child); + auto& tGrandChild = world.Get(grandChild); + + ecsModule.RunFrameLogic(); + + EXPECT_EQ(tChild.LocalPosition(), Vector3::Zero()); + EXPECT_EQ(tChild.LocalRotation(), Quaternion::Identity()); + EXPECT_EQ(tChild.LocalScale(), Vector3::One()); + + EXPECT_EQ(tGrandChild.LocalPosition(), Vector3::Zero()); + EXPECT_EQ(tGrandChild.LocalRotation(), Quaternion::Identity()); + EXPECT_EQ(tGrandChild.LocalScale(), Vector3::One()); +} + int main(int argc, char ** argv) { ::testing::InitGoogleTest(&argc, argv); From 4d6f55a24fcf94df53ec6527244de02954f1caec Mon Sep 17 00:00:00 2001 From: Jaremie Romer Date: Sat, 6 Dec 2025 11:01:42 -0600 Subject: [PATCH 3/3] Fix --- sample/source/scenes/GraphicsTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample/source/scenes/GraphicsTest.cpp b/sample/source/scenes/GraphicsTest.cpp index 92c258117..43ab5be22 100644 --- a/sample/source/scenes/GraphicsTest.cpp +++ b/sample/source/scenes/GraphicsTest.cpp @@ -175,7 +175,7 @@ void GraphicsTest::Load(ecs::Ecs world, ModuleProvider modules) .tag = "Camera child" }); - auto emptyGrandChild = world.Emplace( + world.Emplace( { .position = Vector3::Zero(), .rotation = Quaternion::Identity(),