Browse Source

Finally integrate Jolt

Panagiotis Christopoulos Charitos 10 months ago
parent
commit
162f5bf4af
100 changed files with 1858 additions and 1283 deletions
  1. 6 6
      AnKi/Core/App.cpp
  2. 3 1
      AnKi/Gr/Vulkan/VkGrManager.cpp
  3. 1 1
      AnKi/Importer/GltfImporter.cpp
  4. 5 6
      AnKi/Physics.h
  5. 1 1
      AnKi/Physics2/CMakeLists.txt
  6. 8 1
      AnKi/Physics2/Common.h
  7. 26 2
      AnKi/Physics2/PhysicsBody.cpp
  8. 8 5
      AnKi/Physics2/PhysicsBody.h
  9. 36 7
      AnKi/Physics2/PhysicsPlayerController.cpp
  10. 3 4
      AnKi/Physics2/PhysicsPlayerController.h
  11. 67 3
      AnKi/Physics2/PhysicsWorld.cpp
  12. 93 23
      AnKi/Renderer/Dbg.cpp
  13. 2 3
      AnKi/Renderer/Dbg.h
  14. 2 2
      AnKi/Renderer/FinalComposite.cpp
  15. 1 1
      AnKi/Renderer/ForwardShading.cpp
  16. 1 1
      AnKi/Renderer/GBuffer.cpp
  17. 20 4
      AnKi/Resource/CpuMeshResource.cpp
  18. 6 15
      AnKi/Resource/CpuMeshResource.h
  19. 40 0
      AnKi/Resource/MeshResource.cpp
  20. 8 0
      AnKi/Resource/MeshResource.h
  21. 2 2
      AnKi/Resource/ResourceFilesystem.cpp
  22. 4 3
      AnKi/Resource/ResourceFilesystem.h
  23. 1 1
      AnKi/Scene/CMakeLists.txt
  24. 38 88
      AnKi/Scene/Components/BodyComponent.cpp
  25. 81 24
      AnKi/Scene/Components/BodyComponent.h
  26. 27 225
      AnKi/Scene/Components/JointComponent.cpp
  27. 21 37
      AnKi/Scene/Components/JointComponent.h
  28. 13 14
      AnKi/Scene/Components/ParticleEmitterComponent.cpp
  29. 10 8
      AnKi/Scene/Components/PlayerControllerComponent.cpp
  30. 7 7
      AnKi/Scene/Components/PlayerControllerComponent.h
  31. 17 0
      AnKi/Scene/Components/SceneComponent.cpp
  32. 11 8
      AnKi/Scene/Components/SceneComponent.h
  33. 3 3
      AnKi/Scene/Components/SceneComponentClasses.def.h
  34. 64 53
      AnKi/Scene/Components/TriggerComponent.cpp
  35. 17 20
      AnKi/Scene/Components/TriggerComponent.h
  36. 2 9
      AnKi/Scene/SceneGraph.cpp
  37. 4 1
      AnKi/Scene/SceneNode.cpp
  38. 15 4
      AnKi/Scene/SceneNode.h
  39. 250 227
      AnKi/Script/Scene.cpp
  40. 31 24
      AnKi/Script/Scene.xml
  41. 277 0
      AnKi/Shaders/Dbg.ankiprog
  42. 0 144
      AnKi/Shaders/DbgBillboard.ankiprog
  43. 0 88
      AnKi/Shaders/DbgRenderables.ankiprog
  44. 2 0
      AnKi/Util/BlockArray.inl.h
  45. 3 3
      AnKi/Util/CVarSet.cpp
  46. 8 4
      AnKi/Util/CVarSet.h
  47. 21 2
      AnKi/Util/Hierarchy.h
  48. 13 1
      CMakeLists.txt
  49. 8 8
      Samples/Common/SampleApp.cpp
  50. 46 46
      Samples/PhysicsPlayground/Assets/Scene.lua
  51. 94 89
      Samples/PhysicsPlayground/Main.cpp
  52. 1 1
      Samples/SkeletalAnimation/Main.cpp
  53. 11 11
      Sandbox/Main.cpp
  54. 1 1
      Tests/Gr/Gr.cpp
  55. 5 5
      Tests/Gr/GrAsyncCompute.cpp
  56. 4 4
      Tests/Gr/GrCommon.h
  57. 4 4
      Tests/Gr/GrMeshShaders.cpp
  58. 1 1
      Tests/Gr/GrTextureBuffer.cpp
  59. 5 5
      Tests/Ui/Ui.cpp
  60. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/FontPixelShader.hlsl
  61. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/FontVertexShader.hlsl
  62. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/LinePixelShader.hlsl
  63. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/LineVertexShader.hlsl
  64. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/TriangleDepthPixelShader.hlsl
  65. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/TriangleDepthVertexShader.hlsl
  66. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/TrianglePixelShader.hlsl
  67. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/TriangleVertexShader.hlsl
  68. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/UIPixelShader.hlsl
  69. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/UIPixelShaderUntextured.hlsl
  70. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/UIVertexShader.hlsl
  71. 0 0
      ThirdParty/Jolt/Assets/Shaders/DX/VertexConstants.h
  72. 39 0
      ThirdParty/Jolt/Assets/Shaders/MTL/FontShader.metal
  73. 30 0
      ThirdParty/Jolt/Assets/Shaders/MTL/LineShader.metal
  74. 199 0
      ThirdParty/Jolt/Assets/Shaders/MTL/TriangleShader.metal
  75. 41 0
      ThirdParty/Jolt/Assets/Shaders/MTL/UIShader.metal
  76. 13 0
      ThirdParty/Jolt/Assets/Shaders/MTL/VertexConstants.h
  77. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/FontPixelShader.frag
  78. 1 1
      ThirdParty/Jolt/Assets/Shaders/VK/FontVertexShader.vert
  79. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/LinePixelShader.frag
  80. 1 1
      ThirdParty/Jolt/Assets/Shaders/VK/LineVertexShader.vert
  81. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/TriangleDepthPixelShader.frag
  82. 1 1
      ThirdParty/Jolt/Assets/Shaders/VK/TriangleDepthVertexShader.vert
  83. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/TrianglePixelShader.frag
  84. 1 1
      ThirdParty/Jolt/Assets/Shaders/VK/TriangleVertexShader.vert
  85. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/UIPixelShader.frag
  86. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/UIPixelShaderUntextured.frag
  87. 1 1
      ThirdParty/Jolt/Assets/Shaders/VK/UIVertexShader.vert
  88. 0 0
      ThirdParty/Jolt/Assets/Shaders/VK/VertexConstants.h
  89. 13 6
      ThirdParty/Jolt/Build/CMakeLists.txt
  90. 3 2
      ThirdParty/Jolt/Build/README.md
  91. 1 1
      ThirdParty/Jolt/Build/iOS/JoltViewerInfo.plist
  92. 1 1
      ThirdParty/Jolt/Build/iOS/SamplesInfo.plist
  93. BIN
      ThirdParty/Jolt/Build/macOS/icon.icns
  94. 1 1
      ThirdParty/Jolt/Build/macos_install_vulkan_sdk.sh
  95. 3 0
      ThirdParty/Jolt/Docs/APIChanges.md
  96. 24 1
      ThirdParty/Jolt/Docs/Architecture.md
  97. 2 0
      ThirdParty/Jolt/Docs/ProjectsUsingJolt.md
  98. 22 3
      ThirdParty/Jolt/Docs/ReleaseNotes.md
  99. 1 1
      ThirdParty/Jolt/Docs/Samples.md
  100. 1 1
      ThirdParty/Jolt/Jolt/Core/Color.h

+ 6 - 6
AnKi/Core/App.cpp

@@ -23,7 +23,7 @@
 #include <AnKi/Window/Input.h>
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Script/ScriptManager.h>
 #include <AnKi/Resource/ResourceFilesystem.h>
@@ -131,7 +131,7 @@ void App::cleanup()
 	UiManager::freeSingleton();
 	GpuSceneMicroPatcher::freeSingleton();
 	ResourceManager::freeSingleton();
-	PhysicsWorld::freeSingleton();
+	v2::PhysicsWorld::freeSingleton();
 	RebarTransientMemoryPool::freeSingleton();
 	GpuVisibleTransientMemoryPool::freeSingleton();
 	UnifiedGeometryBuffer::freeSingleton();
@@ -224,7 +224,7 @@ Error App::initInternal()
 	if(g_benchmarkModeCVar && g_vsyncCVar)
 	{
 		ANKI_CORE_LOGW("Vsync is enabled and benchmark mode as well. Will turn vsync off");
-		g_vsyncCVar.set(false);
+		g_vsyncCVar = false;
 	}
 
 	GlobalFrameIndex::allocateSingleton();
@@ -293,8 +293,8 @@ Error App::initInternal()
 	//
 	// Physics
 	//
-	PhysicsWorld::allocateSingleton();
-	ANKI_CHECK(PhysicsWorld::getSingleton().init(allocCb, allocCbUserData));
+	v2::PhysicsWorld::allocateSingleton();
+	ANKI_CHECK(v2::PhysicsWorld::getSingleton().init(allocCb, allocCbUserData));
 
 	//
 	// Resources
@@ -310,7 +310,7 @@ Error App::initInternal()
 	extraPaths += ":" ANKI_SOURCE_DIRECTORY "|EngineAssets,!AndroidProject"; // EngineAssets
 	extraPaths += ":";
 	extraPaths += g_dataPathsCVar;
-	g_dataPathsCVar.set(extraPaths);
+	g_dataPathsCVar = extraPaths;
 #endif
 
 	ANKI_CHECK(ResourceManager::allocateSingleton().init(allocCb, allocCbUserData));

+ 3 - 1
AnKi/Gr/Vulkan/VkGrManager.cpp

@@ -836,7 +836,9 @@ Error GrManagerImpl::initDevice()
 
 	Array<F32, U32(GpuQueueType::kCount)> priorities = {1.0f, 0.5f};
 	Array<VkDeviceQueueCreateInfo, U32(GpuQueueType::kCount)> q = {};
-	q.fill({VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO});
+	VkDeviceQueueCreateInfo queueCreateInfo = {};
+	queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+	q.fill(queueCreateInfo);
 
 	VkDeviceCreateInfo ci = {};
 	ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;

+ 1 - 1
AnKi/Importer/GltfImporter.cpp

@@ -876,7 +876,7 @@ Error GltfImporter::visitNode(const cgltf_node& node, const Transform& parentTrf
 
 					const ImporterString meshFname = computeMeshResourceFilename(*node.mesh);
 
-					ANKI_CHECK(m_sceneFile.writeText("comp:setMeshFromModelComponent()\n"));
+					ANKI_CHECK(m_sceneFile.writeText("comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)\n"));
 					ANKI_CHECK(m_sceneFile.writeText("comp:teleportTo(trf)\n"));
 				}
 			}

+ 5 - 6
AnKi/Physics.h

@@ -5,11 +5,10 @@
 
 #pragma once
 
-#include <AnKi/Physics/PhysicsWorld.h>
-#include <AnKi/Physics/PhysicsBody.h>
-#include <AnKi/Physics/PhysicsCollisionShape.h>
-#include <AnKi/Physics/PhysicsJoint.h>
-#include <AnKi/Physics/PhysicsPlayerController.h>
-#include <AnKi/Physics/PhysicsTrigger.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsBody.h>
+#include <AnKi/Physics2/PhysicsCollisionShape.h>
+#include <AnKi/Physics2/PhysicsJoint.h>
+#include <AnKi/Physics2/PhysicsPlayerController.h>
 
 /// @defgroup physics Physics subsystem

+ 1 - 1
AnKi/Physics2/CMakeLists.txt

@@ -2,4 +2,4 @@ file(GLOB_RECURSE sources *.cpp)
 file(GLOB_RECURSE headers *.h)
 add_library(AnKiPhysics2 ${sources} ${headers})
 target_compile_definitions(AnKiPhysics2 PRIVATE "-DANKI_SOURCE_FILE" "-DJPH_DEBUG_RENDERER")
-target_link_libraries(AnKiPhysics2 AnKiUtil)
+target_link_libraries(AnKiPhysics2 AnKiUtil Jolt)

+ 8 - 1
AnKi/Physics2/Common.h

@@ -10,7 +10,14 @@
 #include <AnKi/Util/Ptr.h>
 #include <AnKi/Util/MemoryPool.h>
 #include <AnKi/Math.h>
-#include <AnKi/Util/Enum.h>
+
+#if ANKI_ASSERTIONS_ENABLED && !defined(JPH_ENABLE_ASSERTS)
+#	error "See file"
+#endif
+
+#if !defined(JPH_DEBUG_RENDERER)
+#	error "See file"
+#endif
 
 #include <Jolt/Jolt.h>
 #include <Jolt/Physics/Body/Body.h>

+ 26 - 2
AnKi/Physics2/PhysicsBody.cpp

@@ -31,9 +31,18 @@ Bool PhysicsBody::MyGroupFilter::CanCollide(const JPH::CollisionGroup& inGroup1,
 	}
 }
 
+PhysicsBody::PhysicsBody()
+	: PhysicsObjectBase(PhysicsObjectType::kBody)
+{
+}
+
+PhysicsBody::~PhysicsBody()
+{
+}
+
 void PhysicsBody::init(const PhysicsBodyInitInfo& init)
 {
-	if(init.m_layer == PhysicsLayer::kStatic)
+	if(init.m_layer == PhysicsLayer::kStatic || init.m_layer == PhysicsLayer::kTrigger)
 	{
 		ANKI_ASSERT(init.m_mass == 0.0f);
 	}
@@ -73,7 +82,7 @@ void PhysicsBody::init(const PhysicsBodyInitInfo& init)
 	JPH::BodyCreationSettings settings((scaledShape) ? &scaledShape->m_scaled : &init.m_shape->m_shapeBase, toJPH(pos), toJPH(rot), motionType,
 									   JPH::ObjectLayer(init.m_layer));
 
-	if(init.m_mass)
+	if(init.m_mass > 0.0f)
 	{
 		ANKI_ASSERT(!init.m_isTrigger && "Triggers can't have mass");
 		settings.mOverrideMassProperties = JPH::EOverrideMassProperties::CalculateInertia;
@@ -142,6 +151,21 @@ void PhysicsBody::setGravityFactor(F32 factor)
 	PhysicsWorld::getSingleton().m_jphPhysicsSystem->GetBodyInterfaceNoLock().SetGravityFactor(m_jphBody->GetID(), factor);
 }
 
+void PhysicsBody::setLinearVelocity(Vec3 v)
+{
+	PhysicsWorld::getSingleton().m_jphPhysicsSystem->GetBodyInterfaceNoLock().SetLinearVelocity(m_jphBody->GetID(), toJPH(v));
+}
+
+void PhysicsBody::setAngularVelocity(Vec3 v)
+{
+	PhysicsWorld::getSingleton().m_jphPhysicsSystem->GetBodyInterfaceNoLock().SetAngularVelocity(m_jphBody->GetID(), toJPH(v));
+}
+
+void PhysicsBody::clearForcesAndTorque()
+{
+	m_jphBody->ResetMotion();
+}
+
 void PhysicsBody::postPhysicsUpdate()
 {
 	if(m_activated)

+ 8 - 5
AnKi/Physics2/PhysicsBody.h

@@ -87,6 +87,12 @@ public:
 	/// Zero means no gravity, 1 means normal gravity.
 	void setGravityFactor(F32 factor);
 
+	void setLinearVelocity(Vec3 v);
+
+	void setAngularVelocity(Vec3 v);
+
+	void clearForcesAndTorque();
+
 	void setPhysicsTriggerCallbacks(PhysicsTriggerCallbacks* callbacks)
 	{
 		ANKI_ASSERT(m_isTrigger);
@@ -124,12 +130,9 @@ private:
 
 	F32 m_mass = 0.0f;
 
-	PhysicsBody()
-		: PhysicsObjectBase(PhysicsObjectType::kBody)
-	{
-	}
+	PhysicsBody();
 
-	~PhysicsBody() = default;
+	~PhysicsBody();
 
 	void init(const PhysicsBodyInitInfo& init);
 

+ 36 - 7
AnKi/Physics2/PhysicsPlayerController.cpp

@@ -12,6 +12,11 @@ namespace v2 {
 
 thread_local static StaticTempAllocator<1_MB> g_tempAllocator;
 
+PhysicsPlayerController::PhysicsPlayerController()
+	: PhysicsObjectBase(PhysicsObjectType::kPlayerController)
+{
+}
+
 PhysicsPlayerController::~PhysicsPlayerController()
 {
 	m_jphCharacter.destroy();
@@ -50,13 +55,6 @@ void PhysicsPlayerController::init(const PhysicsPlayerControllerInitInfo& init)
 
 void PhysicsPlayerController::prePhysicsUpdate(Second dt)
 {
-	if(!m_input.m_updated)
-	{
-		return;
-	}
-
-	m_input.m_updated = false;
-
 	const Bool bJump = m_input.m_jumpSpeed > 0.0f;
 	const JPH::Vec3 inMovementDirection = toJPH(m_input.m_forwardDir);
 
@@ -143,6 +141,37 @@ void PhysicsPlayerController::prePhysicsUpdate(Second dt)
 			m_jphCharacter->SetInnerBodyShape(innerShape);
 		}
 	}
+
+	if(m_input.m_updated)
+	{
+		m_input.m_updated = false;
+		m_input = {};
+	}
+
+	// Settings for our update function
+	JPH::CharacterVirtual::ExtendedUpdateSettings updateSettings;
+	if(!kEnableStickToFloor)
+	{
+		updateSettings.mStickToFloorStepDown = JPH::Vec3::sZero();
+	}
+	else
+	{
+		updateSettings.mStickToFloorStepDown = -m_jphCharacter->GetUp() * updateSettings.mStickToFloorStepDown.Length();
+	}
+	if(!kEnableWalkStairs)
+	{
+		updateSettings.mWalkStairsStepUp = JPH::Vec3::sZero();
+	}
+	else
+	{
+		updateSettings.mWalkStairsStepUp = m_jphCharacter->GetUp() * updateSettings.mWalkStairsStepUp.Length();
+	}
+
+	// Update the character position
+	JPH::PhysicsSystem& system = *PhysicsWorld::getSingleton().m_jphPhysicsSystem;
+	m_jphCharacter->ExtendedUpdate(F32(dt), -m_jphCharacter->GetUp() * system.GetGravity().Length(), updateSettings,
+								   system.GetDefaultBroadPhaseLayerFilter(JPH::ObjectLayer(PhysicsLayer::kPlayerController)),
+								   system.GetDefaultLayerFilter(JPH::ObjectLayer(PhysicsLayer::kPlayerController)), {}, {}, g_tempAllocator);
 }
 
 void PhysicsPlayerController::postPhysicsUpdate()

+ 3 - 4
AnKi/Physics2/PhysicsPlayerController.h

@@ -73,6 +73,8 @@ private:
 	static constexpr Bool kEnhancedInternalEdgeRemoval = false;
 	static constexpr Bool kEnableCharacterInertia = true;
 	static constexpr F32 kInnerShapeFraction = 0.9f;
+	static constexpr Bool kEnableStickToFloor = true;
+	static constexpr Bool kEnableWalkStairs = true;
 
 	ClassWrapper<JPH::CharacterVirtual> m_jphCharacter;
 	PhysicsCollisionShapePtr m_standingShape;
@@ -99,10 +101,7 @@ private:
 	U32 m_allowSliding : 1 = false;
 	U32 m_crouching : 1 = false;
 
-	PhysicsPlayerController()
-		: PhysicsObjectBase(PhysicsObjectType::kPlayerController)
-	{
-	}
+	PhysicsPlayerController();
 
 	~PhysicsPlayerController();
 

+ 67 - 3
AnKi/Physics2/PhysicsWorld.cpp

@@ -5,6 +5,9 @@
 
 #include <AnKi/Physics2/PhysicsWorld.h>
 #include <AnKi/Util/System.h>
+#include <AnKi/Core/StatsSet.h>
+#include <AnKi/Util/HighRezTimer.h>
+#include <AnKi/Util/Tracer.h>
 
 #include <Jolt/Renderer/DebugRendererSimple.h>
 #include <Jolt/ConfigurationString.h>
@@ -12,6 +15,11 @@
 namespace anki {
 namespace v2 {
 
+static StatCounter g_physicsBodiesCreatedStatVar(StatCategory::kMisc, "Phys bodies created", StatFlag::kZeroEveryFrame);
+static StatCounter g_physicsJointsCreatedStatVar(StatCategory::kMisc, "Phys joints created", StatFlag::kZeroEveryFrame);
+static StatCounter g_physicsUpdateTimeStatVar(StatCategory::kTime, "Phys update",
+											  StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
+
 class BroadphaseLayer
 {
 public:
@@ -47,6 +55,25 @@ public:
 	{
 		return objectLayerToBroadphaseLayer(PhysicsLayer(objLayer));
 	}
+
+#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
+	const char* GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer) const override
+	{
+		if(inLayer == BroadphaseLayer::kStatic)
+		{
+			return "Static";
+		}
+		else if(inLayer == BroadphaseLayer::kDynamic)
+		{
+			return "Dynamic";
+		}
+		else
+		{
+			ANKI_ASSERT(inLayer == BroadphaseLayer::kDebris);
+			return "Debris";
+		}
+	}
+#endif
 };
 
 // Class that determines if an object layer can collide with a broadphase layer
@@ -151,9 +178,18 @@ class PhysicsWorld::MyContactListener final : public JPH::ContactListener
 public:
 	void gatherObjects(U64 body1UserData, U64 body2UserData, PhysicsBody*& trigger, PhysicsObjectBase*& receiver)
 	{
+		trigger = nullptr;
+		receiver = nullptr;
+
 		PhysicsObjectBase* obj1 = numberToPtr<PhysicsObjectBase*>(body1UserData);
 		PhysicsObjectBase* obj2 = numberToPtr<PhysicsObjectBase*>(body2UserData);
 
+		if(!obj1 || !obj2)
+		{
+			// Possibly a body was removed and Jolt tried to remove the contact, that body doesn't have user data
+			return;
+		}
+
 		if(obj1->getType() == PhysicsObjectType::kBody && static_cast<PhysicsBody*>(obj1)->m_triggerCallbacks)
 		{
 			ANKI_ASSERT(obj2->getType() == PhysicsObjectType::kBody || obj2->getType() == PhysicsObjectType::kPlayerController);
@@ -168,8 +204,7 @@ public:
 		}
 		else
 		{
-			trigger = nullptr;
-			receiver = nullptr;
+			// Do nothing
 		}
 	}
 
@@ -253,6 +288,8 @@ void PhysicsJointPtrDeleter::operator()(PhysicsJoint* ptr)
 	ANKI_ASSERT(ptr);
 	PhysicsWorld& world = PhysicsWorld::getSingleton();
 
+	world.m_jphPhysicsSystem->RemoveConstraint(&(*ptr->m_base));
+
 	LockGuard lock(world.m_joints.m_mtx);
 	world.m_joints.m_array.erase(ptr->m_blockArrayIndex);
 }
@@ -291,6 +328,10 @@ public:
 	}
 };
 
+PhysicsWorld::PhysicsWorld()
+{
+}
+
 PhysicsWorld::~PhysicsWorld()
 {
 	ANKI_ASSERT(m_collisionShapes.m_array.getSize() == 0);
@@ -300,6 +341,7 @@ PhysicsWorld::~PhysicsWorld()
 
 	m_jobSystem.destroy();
 	m_jphPhysicsSystem.destroy();
+	m_tempAllocator.destroy();
 
 	JPH::UnregisterTypes();
 
@@ -354,6 +396,13 @@ Error PhysicsWorld::init(AllocAlignedCallback allocCb, void* allocCbData)
 		PhysicsMemoryPool::getSingleton().free(ptr);
 	};
 
+#if ANKI_ASSERTIONS_ENABLED
+	JPH::AssertFailed = [](const Char* inExpression, [[maybe_unused]] const Char* inMessage, const Char* inFile, U32 inLine) -> Bool {
+		Logger::getSingleton().write(inFile, inLine, "?", "JOLT", LoggerMessageType::kFatal, "?", inExpression);
+		return true;
+	};
+#endif
+
 	JPH::Factory::sInstance = new JPH::Factory();
 
 	JPH::RegisterTypes();
@@ -381,6 +430,12 @@ Error PhysicsWorld::init(AllocAlignedCallback allocCb, void* allocCbData)
 
 void PhysicsWorld::update(Second dt)
 {
+	ANKI_TRACE_SCOPED_EVENT(Physics);
+
+#if ANKI_STATS_ENABLED
+	const Second startTime = HighRezTimer::getCurrentTime();
+#endif
+
 	// Pre-update work
 	{
 		for(PhysicsPlayerController& charController : m_characters.m_array)
@@ -424,6 +479,10 @@ void PhysicsWorld::update(Second dt)
 
 		m_deletedContacts.destroy();
 	}
+
+#if ANKI_STATS_ENABLED
+	g_physicsUpdateTimeStatVar.set((HighRezTimer::getCurrentTime() - startTime) * 1000.0);
+#endif
 }
 
 template<typename TJPHCollisionShape, typename... TArgs>
@@ -494,7 +553,7 @@ PhysicsCollisionShapePtr PhysicsWorld::newStaticMeshShape(ConstWeakArray<Vec3> p
 	for(U32 i = 0; i < indices.getSize(); i += 3)
 	{
 		const U32 material = 0;
-		idx[i] = JPH::IndexedTriangle(indices[i], indices[i + 1], indices[i + 2], material);
+		idx[i / 3] = JPH::IndexedTriangle(indices[i], indices[i + 1], indices[i + 2], material);
 	}
 
 	JPH::MeshShapeSettings settings(std::move(verts), std::move(idx));
@@ -513,6 +572,8 @@ PhysicsCollisionShapePtr PhysicsWorld::newScaleCollisionObject(const Vec3& scale
 
 PhysicsBodyPtr PhysicsWorld::newPhysicsBody(const PhysicsBodyInitInfo& init)
 {
+	g_physicsBodiesCreatedStatVar.increment(1);
+
 	PhysicsBody* newBody;
 	{
 		LockGuard lock(m_bodies.m_mtx);
@@ -533,6 +594,8 @@ PhysicsJointPtr PhysicsWorld::newJoint(PhysicsBody* body1, PhysicsBody* body2, T
 {
 	ANKI_ASSERT(body1 && body2);
 
+	g_physicsJointsCreatedStatVar.increment(1);
+
 	decltype(m_joints.m_array)::Iterator it;
 	{
 		LockGuard lock(m_joints.m_mtx);
@@ -681,6 +744,7 @@ void PhysicsWorld::debugDraw(PhysicsDebugDrawerInterface& interface)
 	renderer.m_interface = &interface;
 
 	JPH::BodyManager::DrawSettings settings;
+	settings.mDrawShapeWireframe = true;
 	m_jphPhysicsSystem->DrawBodies(settings, &renderer);
 
 	m_jphPhysicsSystem->DrawConstraints(&renderer);

+ 93 - 23
AnKi/Renderer/Dbg.cpp

@@ -17,7 +17,7 @@
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/CVarSet.h>
 #include <AnKi/Collision/ConvexHullShape.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 
 namespace anki {
 
@@ -43,8 +43,7 @@ Error Dbg::init()
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/GreenDecal.ankitex", m_decalImage));
 	ANKI_CHECK(rsrcManager.loadResource("EngineAssets/Mirror.ankitex", m_reflectionImage));
 
-	ANKI_CHECK(rsrcManager.loadResource("ShaderBinaries/DbgRenderables.ankiprogbin", m_renderablesProg));
-	ANKI_CHECK(rsrcManager.loadResource("ShaderBinaries/DbgBillboard.ankiprogbin", m_nonRenderablesProg));
+	ANKI_CHECK(rsrcManager.loadResource("ShaderBinaries/Dbg.ankiprogbin", m_dbgProg));
 
 	{
 		BufferInitInfo buffInit("Dbg cube verts");
@@ -113,11 +112,12 @@ Error Dbg::init()
 void Dbg::drawNonRenderable(GpuSceneNonRenderableObjectType type, U32 objCount, const RenderingContext& ctx, const ImageResource& image,
 							CommandBuffer& cmdb)
 {
-	ShaderProgramResourceVariantInitInfo variantInitInfo(m_nonRenderablesProg);
+	ShaderProgramResourceVariantInitInfo variantInitInfo(m_dbgProg);
 	variantInitInfo.addMutation("DEPTH_FAIL_VISUALIZATION", U32(m_ditheredDepthTestOn != 0));
 	variantInitInfo.addMutation("OBJECT_TYPE", U32(type));
+	variantInitInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "Bilboards");
 	const ShaderProgramResourceVariant* variant;
-	m_nonRenderablesProg->getOrCreateVariant(variantInitInfo, variant);
+	m_dbgProg->getOrCreateVariant(variantInitInfo, variant);
 	cmdb.bindShaderProgram(&variant->getProgram());
 
 	class Constants
@@ -143,7 +143,7 @@ void Dbg::drawNonRenderable(GpuSceneNonRenderableObjectType type, U32 objCount,
 void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(Dbg);
-	ANKI_ASSERT(g_dbgCVar);
+	ANKI_ASSERT(g_dbgSceneCVar || g_dbgPhysicsCVar);
 
 	CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
@@ -159,13 +159,16 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	rgraphCtx.bindSrv(0, 0, getRenderer().getGBuffer().getDepthRt());
 
 	// GBuffer renderables
+	if(g_dbgSceneCVar)
 	{
 		const U32 allAabbCount = GpuSceneArrays::RenderableBoundingVolumeGBuffer::getSingleton().getElementCount();
 
-		ShaderProgramResourceVariantInitInfo variantInitInfo(m_renderablesProg);
+		ShaderProgramResourceVariantInitInfo variantInitInfo(m_dbgProg);
 		variantInitInfo.addMutation("DEPTH_FAIL_VISUALIZATION", U32(m_ditheredDepthTestOn != 0));
+		variantInitInfo.addMutation("OBJECT_TYPE", 0);
+		variantInitInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "Renderables");
 		const ShaderProgramResourceVariant* variant;
-		m_renderablesProg->getOrCreateVariant(variantInitInfo, variant);
+		m_dbgProg->getOrCreateVariant(variantInitInfo, variant);
 		cmdb.bindShaderProgram(&variant->getProgram());
 
 		class Constants
@@ -193,6 +196,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	}
 
 	// Forward shading renderables
+	if(g_dbgSceneCVar)
 	{
 		const U32 allAabbCount = GpuSceneArrays::RenderableBoundingVolumeForward::getSingleton().getElementCount();
 
@@ -210,13 +214,76 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	}
 
 	// Draw non-renderables
-	drawNonRenderable(GpuSceneNonRenderableObjectType::kLight, GpuSceneArrays::Light::getSingleton().getElementCount(), ctx, *m_pointLightImage,
-					  cmdb);
-	drawNonRenderable(GpuSceneNonRenderableObjectType::kDecal, GpuSceneArrays::Decal::getSingleton().getElementCount(), ctx, *m_decalImage, cmdb);
-	drawNonRenderable(GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe,
-					  GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount(), ctx, *m_giProbeImage, cmdb);
-	drawNonRenderable(GpuSceneNonRenderableObjectType::kReflectionProbe, GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount(), ctx,
-					  *m_reflectionImage, cmdb);
+	if(g_dbgSceneCVar)
+	{
+		drawNonRenderable(GpuSceneNonRenderableObjectType::kLight, GpuSceneArrays::Light::getSingleton().getElementCount(), ctx, *m_pointLightImage,
+						  cmdb);
+		drawNonRenderable(GpuSceneNonRenderableObjectType::kDecal, GpuSceneArrays::Decal::getSingleton().getElementCount(), ctx, *m_decalImage, cmdb);
+		drawNonRenderable(GpuSceneNonRenderableObjectType::kGlobalIlluminationProbe,
+						  GpuSceneArrays::GlobalIlluminationProbe::getSingleton().getElementCount(), ctx, *m_giProbeImage, cmdb);
+		drawNonRenderable(GpuSceneNonRenderableObjectType::kReflectionProbe, GpuSceneArrays::ReflectionProbe::getSingleton().getElementCount(), ctx,
+						  *m_reflectionImage, cmdb);
+	}
+
+	// Physics
+	if(g_dbgPhysicsCVar)
+	{
+		class MyPhysicsDebugDrawerInterface final : public v2::PhysicsDebugDrawerInterface
+		{
+		public:
+			RendererDynamicArray<HVec4> m_positions;
+			RendererDynamicArray<Array<U8, 4>> m_colors;
+
+			void drawLines(ConstWeakArray<Vec3> lines, Array<U8, 4> color) override
+			{
+				static constexpr U32 kMaxVerts = 1024 * 100;
+
+				for(const Vec3& pos : lines)
+				{
+					if(m_positions.getSize() >= kMaxVerts)
+					{
+						break;
+					}
+
+					m_positions.emplaceBack(HVec4(pos.xyz0()));
+					m_colors.emplaceBack(color);
+				}
+			}
+		} drawerInterface;
+
+		v2::PhysicsWorld::getSingleton().debugDraw(drawerInterface);
+
+		const U32 vertCount = drawerInterface.m_positions.getSize();
+		if(vertCount)
+		{
+			HVec4* positions;
+			const BufferView positionBuff =
+				RebarTransientMemoryPool::getSingleton().allocate(drawerInterface.m_positions.getSizeInBytes(), sizeof(HVec4), positions);
+			memcpy(positions, drawerInterface.m_positions.getBegin(), drawerInterface.m_positions.getSizeInBytes());
+
+			U8* colors;
+			const BufferView colorBuff =
+				RebarTransientMemoryPool::getSingleton().allocate(drawerInterface.m_colors.getSizeInBytes(), sizeof(U8) * 4, colors);
+			memcpy(colors, drawerInterface.m_colors.getBegin(), drawerInterface.m_colors.getSizeInBytes());
+
+			ShaderProgramResourceVariantInitInfo variantInitInfo(m_dbgProg);
+			variantInitInfo.addMutation("DEPTH_FAIL_VISUALIZATION", U32(m_ditheredDepthTestOn != 0));
+			variantInitInfo.addMutation("OBJECT_TYPE", 0);
+			variantInitInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "Lines");
+			const ShaderProgramResourceVariant* variant;
+			m_dbgProg->getOrCreateVariant(variantInitInfo, variant);
+			cmdb.bindShaderProgram(&variant->getProgram());
+
+			cmdb.setVertexAttribute(VertexAttributeSemantic::kPosition, 0, Format::kR16G16B16A16_Sfloat, 0);
+			cmdb.setVertexAttribute(VertexAttributeSemantic::kColor, 1, Format::kR8G8B8A8_Unorm, 0);
+			cmdb.bindVertexBuffer(0, positionBuff, sizeof(HVec4));
+			cmdb.bindVertexBuffer(1, colorBuff, sizeof(U8) * 4);
+
+			cmdb.setFastConstants(&ctx.m_matrices.m_viewProjection, sizeof(ctx.m_matrices.m_viewProjection));
+
+			cmdb.draw(PrimitiveTopology::kLines, vertCount);
+		}
+	}
 
 	// Restore state
 	cmdb.setDepthCompareOperation(CompareOperation::kLess);
@@ -227,7 +294,7 @@ void Dbg::populateRenderGraph(RenderingContext& ctx)
 {
 	ANKI_TRACE_SCOPED_EVENT(Dbg);
 
-	if(!g_dbgCVar)
+	if(!g_dbgSceneCVar && !g_dbgPhysicsCVar)
 	{
 		return;
 	}
@@ -254,15 +321,18 @@ void Dbg::populateRenderGraph(RenderingContext& ctx)
 	pass.newTextureDependency(m_runCtx.m_rt, TextureUsageBit::kRtvDsvWrite);
 	pass.newTextureDependency(getRenderer().getGBuffer().getDepthRt(), TextureUsageBit::kSrvPixel | TextureUsageBit::kRtvDsvRead);
 
-	BufferView indicesBuff;
-	BufferHandle dep;
-	getRenderer().getGBuffer().getVisibleAabbsBuffer(indicesBuff, dep);
-	pass.newBufferDependency(dep, BufferUsageBit::kSrvGeometry);
-
-	if(GpuSceneArrays::RenderableBoundingVolumeForward::getSingleton().getElementCount())
+	if(g_dbgSceneCVar)
 	{
-		getRenderer().getForwardShading().getVisibleAabbsBuffer(indicesBuff, dep);
+		BufferView indicesBuff;
+		BufferHandle dep;
+		getRenderer().getGBuffer().getVisibleAabbsBuffer(indicesBuff, dep);
 		pass.newBufferDependency(dep, BufferUsageBit::kSrvGeometry);
+
+		if(GpuSceneArrays::RenderableBoundingVolumeForward::getSingleton().getElementCount())
+		{
+			getRenderer().getForwardShading().getVisibleAabbsBuffer(indicesBuff, dep);
+			pass.newBufferDependency(dep, BufferUsageBit::kSrvGeometry);
+		}
 	}
 }
 

+ 2 - 3
AnKi/Renderer/Dbg.h

@@ -14,7 +14,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-inline BoolCVar g_dbgCVar("R", "Dbg", false, "Enable or not debug visualization");
+inline BoolCVar g_dbgSceneCVar("R", "DbgScene", false, "Enable or not debug visualization of scene");
 inline BoolCVar g_dbgPhysicsCVar("R", "DbgPhysics", false, "Enable or not physics debug visualization");
 
 /// Debugging stage
@@ -77,8 +77,7 @@ private:
 	BufferPtr m_cubeVertsBuffer;
 	BufferPtr m_cubeIndicesBuffer;
 
-	ShaderProgramResourcePtr m_renderablesProg;
-	ShaderProgramResourcePtr m_nonRenderablesProg;
+	ShaderProgramResourcePtr m_dbgProg;
 
 	Bool m_depthTestOn : 1 = false;
 	Bool m_ditheredDepthTestOn : 1 = false;

+ 2 - 2
AnKi/Renderer/FinalComposite.cpp

@@ -93,7 +93,7 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 
 	pass.newTextureDependency(outRt, TextureUsageBit::kRtvDsvWrite);
 
-	if(g_dbgCVar)
+	if(g_dbgSceneCVar || g_dbgPhysicsCVar)
 	{
 		pass.newTextureDependency(getRenderer().getDbg().getRt(), TextureUsageBit::kSrvPixel);
 	}
@@ -120,7 +120,7 @@ void FinalComposite::populateRenderGraph(RenderingContext& ctx)
 		ANKI_TRACE_SCOPED_EVENT(FinalComposite);
 
 		CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
-		const Bool dbgEnabled = g_dbgCVar;
+		const Bool dbgEnabled = g_dbgSceneCVar || g_dbgPhysicsCVar;
 
 		Array<RenderTargetHandle, kMaxDebugRenderTargets> dbgRts;
 		ShaderProgramPtr optionalDebugProgram;

+ 1 - 1
AnKi/Renderer/ForwardShading.cpp

@@ -36,7 +36,7 @@ void ForwardShading::populateRenderGraph(RenderingContext& ctx)
 	visIn.m_lodReferencePoint = ctx.m_matrices.m_cameraTransform.getTranslationPart().xyz();
 	visIn.m_lodDistances = lodDistances;
 	visIn.m_rgraph = &rgraph;
-	visIn.m_gatherAabbIndices = g_dbgCVar;
+	visIn.m_gatherAabbIndices = g_dbgSceneCVar;
 	RenderTargetHandle hzb = getRenderer().getGBuffer().getHzbRt();
 	visIn.m_hzbRt = &hzb;
 	visIn.m_viewportSize = getRenderer().getInternalResolution();

+ 1 - 1
AnKi/Renderer/GBuffer.cpp

@@ -107,7 +107,7 @@ void GBuffer::populateRenderGraph(RenderingContext& ctx)
 		visIn.m_lodDistances = lodDistances;
 		visIn.m_rgraph = &rgraph;
 		visIn.m_hzbRt = &m_runCtx.m_hzbRt;
-		visIn.m_gatherAabbIndices = g_dbgCVar;
+		visIn.m_gatherAabbIndices = g_dbgSceneCVar;
 		visIn.m_viewportSize = getRenderer().getInternalResolution();
 		visIn.m_twoPhaseOcclusionCulling = getRenderer().getMeshletRenderingType() != MeshletRenderingType::kNone;
 

+ 20 - 4
AnKi/Resource/CpuMeshResource.cpp

@@ -6,7 +6,7 @@
 #include <AnKi/Resource/CpuMeshResource.h>
 #include <AnKi/Resource/MeshBinaryLoader.h>
 #include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 
 namespace anki {
 
@@ -15,20 +15,36 @@ Error CpuMeshResource::load(const ResourceFilename& filename, [[maybe_unused]] B
 	MeshBinaryLoader loader(&ResourceMemoryPool::getSingleton());
 
 	ANKI_CHECK(loader.load(filename));
-	ANKI_CHECK(loader.storeIndicesAndPosition(0, m_indices, m_positions));
+	ANKI_CHECK(loader.storeIndicesAndPosition(loader.getHeader().m_lodCount - 1, m_indicesMaxLod, m_positionsMaxLod));
 
 	m_isConvex = !!(loader.getHeader().m_flags & MeshBinaryFlag::kConvex);
+	m_maxLod = U8(loader.getHeader().m_lodCount - 1);
 
 	return Error::kNone;
 }
 
-const PhysicsCollisionShapePtr& CpuMeshResource::getOrCreateCollisionShape([[maybe_unused]] Bool isStatic) const
+const v2::PhysicsCollisionShapePtr& CpuMeshResource::getOrCreateCollisionShape(Bool isStatic, U32 lod) const
 {
+	lod = min<U32>(lod, m_maxLod);
+	ANKI_ASSERT(lod == m_maxLod && "Not supported ATM");
+
 	LockGuard lock(m_shapeMtx);
 
 	if(!m_collisionShape)
 	{
-		m_collisionShape = PhysicsWorld::getSingleton().newInstance<PhysicsTriangleSoup>(m_positions, m_indices, m_isConvex);
+		if(m_isConvex || !isStatic)
+		{
+			if(!m_isConvex && !isStatic)
+			{
+				ANKI_RESOURCE_LOGE("Requesting a non-static non-convex collision shape is not supported. Will create a convex hull instead");
+			}
+
+			m_collisionShape = v2::PhysicsWorld::getSingleton().newConvexHullShape(m_positionsMaxLod);
+		}
+		else
+		{
+			m_collisionShape = v2::PhysicsWorld::getSingleton().newStaticMeshShape(m_positionsMaxLod, m_indicesMaxLod);
+		}
 	}
 
 	return m_collisionShape;

+ 6 - 15
AnKi/Resource/CpuMeshResource.h

@@ -8,7 +8,7 @@
 #include <AnKi/Resource/ResourceObject.h>
 #include <AnKi/Math.h>
 #include <AnKi/Util/WeakArray.h>
-#include <AnKi/Physics/PhysicsCollisionShape.h>
+#include <AnKi/Physics2/PhysicsCollisionShape.h>
 
 namespace anki {
 
@@ -27,26 +27,17 @@ public:
 	/// Load from a mesh file
 	Error load(const ResourceFilename& filename, Bool async);
 
-	ConstWeakArray<Vec3> getPositions() const
-	{
-		return m_positions;
-	}
-
-	ConstWeakArray<U32> getIndices() const
-	{
-		return m_indices;
-	}
-
-	const PhysicsCollisionShapePtr& getOrCreateCollisionShape(Bool isStatic) const;
+	const v2::PhysicsCollisionShapePtr& getOrCreateCollisionShape(Bool isStatic, U32 lod = kMaxLodCount - 1) const;
 
 private:
-	ResourceDynamicArray<Vec3> m_positions;
-	ResourceDynamicArray<U32> m_indices;
+	ResourceDynamicArray<Vec3> m_positionsMaxLod;
+	ResourceDynamicArray<U32> m_indicesMaxLod;
 
-	mutable PhysicsCollisionShapePtr m_collisionShape;
+	mutable v2::PhysicsCollisionShapePtr m_collisionShape;
 	mutable SpinLock m_shapeMtx;
 
 	Bool m_isConvex = false;
+	U8 m_maxLod = 0;
 };
 /// @}
 

+ 40 - 0
AnKi/Resource/MeshResource.cpp

@@ -10,6 +10,7 @@
 #include <AnKi/Util/Functions.h>
 #include <AnKi/Util/Filesystem.h>
 #include <AnKi/Core/App.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 
 namespace anki {
 
@@ -98,6 +99,7 @@ Error MeshResource::load(const ResourceFilename& filename, Bool async)
 	m_aabb.setMax(header.m_boundingVolume.m_aabbMax);
 	m_positionsScale = header.m_vertexAttributes[VertexStreamId::kPosition].m_scale[0];
 	m_positionsTranslation = Vec3(&header.m_vertexAttributes[VertexStreamId::kPosition].m_translation[0]);
+	m_isConvex = !!(loader.getHeader().m_flags & MeshBinaryFlag::kConvex);
 
 	// Submeshes
 	m_subMeshes.resize(header.m_subMeshCount);
@@ -436,4 +438,42 @@ Error MeshResource::loadAsync(MeshBinaryLoader& loader) const
 	return Error::kNone;
 }
 
+Error MeshResource::getOrCreateCollisionShape(Bool wantStatic, U32 lod, v2::PhysicsCollisionShapePtr& out) const
+{
+	lod = min<U32>(lod, getLodCount() - 1);
+
+	Bool isConvex = m_isConvex;
+	if(!isConvex && !wantStatic)
+	{
+		ANKI_RESOURCE_LOGW("Requesting a non-static non-convex collision shape is not supported. Will create a convex hull instead");
+		isConvex = true;
+	}
+
+	const Lod& l = m_lods[lod];
+
+	LockGuard lock(l.m_collisionShapeMtx);
+
+	if(!l.m_collisionShapes[isConvex])
+	{
+		MeshBinaryLoader loader(&ResourceMemoryPool::getSingleton());
+		ANKI_CHECK(loader.load(getFilename()));
+
+		ResourceDynamicArray<Vec3> positions;
+		ResourceDynamicArray<U32> indices;
+		ANKI_CHECK(loader.storeIndicesAndPosition(lod, indices, positions));
+
+		if(isConvex)
+		{
+			l.m_collisionShapes[isConvex] = v2::PhysicsWorld::getSingleton().newConvexHullShape(positions);
+		}
+		else
+		{
+			l.m_collisionShapes[isConvex] = v2::PhysicsWorld::getSingleton().newStaticMeshShape(positions, indices);
+		}
+	}
+
+	out = l.m_collisionShapes[isConvex];
+	return Error::kNone;
+}
+
 } // end namespace anki

+ 8 - 0
AnKi/Resource/MeshResource.h

@@ -11,6 +11,7 @@
 #include <AnKi/Collision/Aabb.h>
 #include <AnKi/Shaders/Include/MeshTypes.h>
 #include <AnKi/Core/GpuMemory/UnifiedGeometryBuffer.h>
+#include <AnKi/Physics2/PhysicsCollisionShape.h>
 
 namespace anki {
 
@@ -105,6 +106,8 @@ public:
 		return m_positionsTranslation;
 	}
 
+	Error getOrCreateCollisionShape(Bool wantStatic, U32 lod, v2::PhysicsCollisionShapePtr& out) const;
+
 private:
 	class LoadTask;
 	class LoadContext;
@@ -119,6 +122,9 @@ private:
 		UnifiedGeometryBufferAllocation m_meshletBoundingVolumes;
 		UnifiedGeometryBufferAllocation m_meshletGeometryDescriptors;
 
+		mutable Array<v2::PhysicsCollisionShapePtr, 2> m_collisionShapes;
+		mutable SpinLock m_collisionShapeMtx;
+
 		U32 m_indexCount = 0;
 		U32 m_vertexCount = 0;
 		U32 m_meshletCount = 0;
@@ -146,6 +152,8 @@ private:
 	F32 m_positionsScale = 0.0f;
 	Vec3 m_positionsTranslation = Vec3(0.0f);
 
+	Bool m_isConvex = false;
+
 	Error loadAsync(MeshBinaryLoader& loader) const;
 };
 /// @}

+ 2 - 2
AnKi/Resource/ResourceFilesystem.cpp

@@ -406,7 +406,7 @@ Error ResourceFilesystem::addNewPath(CString filepath, const ResourceStringList&
 	return Error::kNone;
 }
 
-Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFilePtr& filePtr)
+Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFilePtr& filePtr) const
 {
 	ResourceFile* rfile;
 	Error err = openFileInternal(filename, rfile);
@@ -425,7 +425,7 @@ Error ResourceFilesystem::openFile(const ResourceFilename& filename, ResourceFil
 	return err;
 }
 
-Error ResourceFilesystem::openFileInternal(const ResourceFilename& filename, ResourceFile*& rfile)
+Error ResourceFilesystem::openFileInternal(const ResourceFilename& filename, ResourceFile*& rfile) const
 {
 	rfile = nullptr;
 

+ 4 - 3
AnKi/Resource/ResourceFilesystem.h

@@ -94,8 +94,9 @@ public:
 
 	Error init();
 
-	/// Search the path list to find the file. Then open the file for reading. It's thread-safe.
-	Error openFile(const ResourceFilename& filename, ResourceFilePtr& file);
+	/// Search the path list to find the file. Then open the file for reading.
+	/// @note Thread-safe.
+	Error openFile(const ResourceFilename& filename, ResourceFilePtr& file) const;
 
 	/// Iterate all the filenames from all paths provided.
 	template<typename TFunc>
@@ -147,7 +148,7 @@ private:
 	/// Add a filesystem path or an archive. The path is read-only.
 	Error addNewPath(CString path, const ResourceStringList& includeStrings, const ResourceStringList& excludedStrings);
 
-	Error openFileInternal(const ResourceFilename& filename, ResourceFile*& rfile);
+	Error openFileInternal(const ResourceFilename& filename, ResourceFile*& rfile) const;
 };
 /// @}
 

+ 1 - 1
AnKi/Scene/CMakeLists.txt

@@ -2,4 +2,4 @@ file(GLOB_RECURSE sources *.cpp)
 file(GLOB_RECURSE headers *.h)
 add_library(AnKiScene ${sources} ${headers})
 target_compile_definitions(AnKiScene PRIVATE -DANKI_SOURCE_FILE)
-target_link_libraries(AnKiScene AnKiResource AnKiScript AnKiCollision)
+target_link_libraries(AnKiScene AnKiResource AnKiScript AnKiCollision AnKiPhysics2)

+ 38 - 88
AnKi/Scene/Components/BodyComponent.cpp

@@ -9,7 +9,7 @@
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Resource/CpuMeshResource.h>
 #include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 #include <AnKi/Resource/ModelResource.h>
 
 namespace anki {
@@ -25,75 +25,6 @@ BodyComponent::~BodyComponent()
 {
 }
 
-void BodyComponent::removeBody()
-{
-	m_shapeType = ShapeType::kCount;
-	m_body.reset(nullptr);
-	m_teleported = false;
-	m_force = Vec3(0.0f);
-	m_mesh.reset(nullptr);
-	m_collisionShape.reset(nullptr);
-}
-
-void BodyComponent::loadMeshResource(CString meshFilename)
-{
-	CpuMeshResourcePtr rsrc;
-	if(ResourceManager::getSingleton().loadResource(meshFilename, rsrc))
-	{
-		ANKI_SCENE_LOGE("Failed to load mesh");
-		return;
-	}
-
-	removeBody();
-	m_shapeType = ShapeType::kMesh;
-	m_mesh = std::move(rsrc);
-}
-
-void BodyComponent::setMeshFromModelComponent(U32 patchIndex)
-{
-	if(!ANKI_SCENE_ASSERT(m_modelc))
-	{
-		return;
-	}
-
-	if(!ANKI_SCENE_ASSERT(patchIndex < m_modelc->getModelResource()->getModelPatches().getSize()))
-	{
-		return;
-	}
-
-	loadMeshResource(m_modelc->getModelResource()->getModelPatches()[patchIndex].getMesh()->getFilename());
-}
-
-CString BodyComponent::getMeshResourceFilename() const
-{
-	return (m_mesh.isCreated()) ? m_mesh->getFilename() : CString();
-}
-
-void BodyComponent::setBoxCollisionShape(const Vec3& extend)
-{
-	if(ANKI_SCENE_ASSERT(extend > 0.0f))
-	{
-		removeBody();
-		m_shapeType = ShapeType::kAabb;
-		m_boxExtend = extend;
-		m_collisionShape = PhysicsWorld::getSingleton().newInstance<PhysicsBox>(extend);
-	}
-}
-
-void BodyComponent::setMass(F32 mass)
-{
-	if(!ANKI_SCENE_ASSERT(mass >= 0.0f))
-	{
-		return;
-	}
-
-	if(m_mass != mass)
-	{
-		m_mass = mass;
-		m_body.reset(nullptr);
-	}
-}
-
 void BodyComponent::teleportTo(const Transform& trf)
 {
 	m_teleportTrf = trf;
@@ -104,43 +35,66 @@ void BodyComponent::teleportTo(const Transform& trf)
 
 Error BodyComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 {
-	if(m_shapeType == ShapeType::kCount)
+	if(m_shapeType == BodyComponentCollisionShapeType::kCount
+	   || (m_shapeType == BodyComponentCollisionShapeType::kFromModelComponent && !m_mesh.m_modelc))
 	{
+		ANKI_ASSERT(!m_body);
 		return Error::kNone;
 	}
 
-	const Bool shapeDirty = !m_body.isCreated();
+	const Bool shapeDirty =
+		!m_body.isCreated()
+		|| (m_shapeType == BodyComponentCollisionShapeType::kFromModelComponent && m_mesh.m_modelc->getUuid() != m_mesh.m_modelcUuid);
 	if(shapeDirty)
 	{
 		updated = true;
 
-		PhysicsBodyInitInfo init;
+		v2::PhysicsBodyInitInfo init;
 		init.m_mass = m_mass;
 		init.m_transform = (m_teleported) ? m_teleportTrf : m_node->getWorldTransform();
 
-		if(m_shapeType == ShapeType::kMesh)
+		if(m_mass == 0.0f)
 		{
-			init.m_shape = m_mesh->getOrCreateCollisionShape(m_mass == 0.0f);
+			init.m_layer = v2::PhysicsLayer::kStatic;
 		}
 		else
 		{
-			init.m_shape = m_collisionShape;
+			init.m_layer = v2::PhysicsLayer::kMoving;
 		}
 
-		m_body = PhysicsWorld::getSingleton().newInstance<PhysicsBody>(init);
+		if(m_shapeType == BodyComponentCollisionShapeType::kFromModelComponent)
+		{
+			m_mesh.m_modelcUuid = m_mesh.m_modelc->getUuid();
+
+			ANKI_CHECK(m_mesh.m_modelc->getModelResource()->getModelPatches()[0].getMesh()->getOrCreateCollisionShape(
+				m_mass == 0.0f, kMaxLodCount - 1, m_collisionShape));
+		}
+		else if(m_shapeType == BodyComponentCollisionShapeType::kAabb)
+		{
+			m_collisionShape = v2::PhysicsWorld::getSingleton().newBoxCollisionShape(m_box.m_extend);
+		}
+		else
+		{
+			ANKI_ASSERT(m_shapeType == BodyComponentCollisionShapeType::kSphere);
+			m_collisionShape = v2::PhysicsWorld::getSingleton().newSphereCollisionShape(m_sphere.m_radius);
+		}
+
+		init.m_shape = m_collisionShape.get();
+
+		m_body = v2::PhysicsWorld::getSingleton().newPhysicsBody(init);
 		m_body->setUserData(this);
 
 		m_teleported = false; // Cancel teleportation since the body was re-created
 	}
 
-	if(m_body && m_teleported)
+	if(m_teleported)
 	{
 		updated = true;
 		m_teleported = false;
 		m_body->setTransform(m_teleportTrf);
 	}
 
-	if(m_body && m_body->getTransform() != info.m_node->getWorldTransform())
+	if(m_body->getTransform() != info.m_node->getWorldTransform())
 	{
 		updated = true;
 		info.m_node->setLocalTransform(m_body->getTransform());
@@ -148,11 +102,7 @@ Error BodyComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 
 	if(m_force.getLengthSquared() > 0.0f)
 	{
-		if(m_body)
-		{
-			m_body->applyForce(m_force, m_forcePosition);
-		}
-
+		m_body->applyForce(m_force, m_forcePosition);
 		m_force = Vec3(0.0f);
 	}
 
@@ -166,13 +116,13 @@ void BodyComponent::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool a
 		return;
 	}
 
-	if(added && m_modelc == nullptr)
+	if(added && m_mesh.m_modelc == nullptr)
 	{
-		m_modelc = static_cast<ModelComponent*>(other);
+		m_mesh.m_modelc = static_cast<ModelComponent*>(other);
 	}
-	else if(!added && m_modelc == other)
+	else if(!added && m_mesh.m_modelc == other)
 	{
-		m_modelc = nullptr;
+		m_mesh.m_modelc = nullptr;
 	}
 }
 

+ 81 - 24
AnKi/Scene/Components/BodyComponent.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <AnKi/Scene/Components/SceneComponent.h>
-#include <AnKi/Physics/PhysicsBody.h>
+#include <AnKi/Physics2/PhysicsBody.h>
 #include <AnKi/Resource/Forward.h>
 
 namespace anki {
@@ -14,6 +14,16 @@ namespace anki {
 /// @addtogroup scene
 /// @{
 
+/// @memberof BodyComponent
+enum class BodyComponentCollisionShapeType : U8
+{
+	kFromModelComponent, ///< Set the collision shape by looking at the ModelComponent's meshes.
+	kAabb,
+	kSphere,
+
+	kCount
+};
+
 /// Rigid body component.
 class BodyComponent : public SceneComponent
 {
@@ -24,24 +34,64 @@ public:
 
 	~BodyComponent();
 
-	void loadMeshResource(CString meshFilename);
+	void setBoxExtend(Vec3 extend)
+	{
+		if(ANKI_SCENE_ASSERT(extend > 0.01f) && extend != m_box.m_extend)
+		{
+			m_box.m_extend = extend;
+			if(m_shapeType == BodyComponentCollisionShapeType::kAabb)
+			{
+				m_body.reset(nullptr); // Force recreate
+			}
+		}
+	}
 
-	void setMeshFromModelComponent(U32 patchIndex = 0);
+	const Vec3& getBoxExtend() const
+	{
+		return m_box.m_extend;
+	}
 
-	CString getMeshResourceFilename() const;
+	void setSphereRadius(F32 radius)
+	{
+		if(ANKI_SCENE_ASSERT(radius > 0.01f) && radius != m_sphere.m_radius)
+		{
+			m_sphere.m_radius = radius;
+			if(m_shapeType == BodyComponentCollisionShapeType::kSphere)
+			{
+				m_body.reset(nullptr); // Force recreate
+			}
+		}
+	}
 
-	void setBoxCollisionShape(const Vec3& extend);
+	F32 getSphereRadius() const
+	{
+		return m_sphere.m_radius;
+	}
 
-	void removeBody();
+	void setCollisionShapeType(BodyComponentCollisionShapeType type)
+	{
+		if(ANKI_SCENE_ASSERT(type <= BodyComponentCollisionShapeType::kCount) && m_shapeType != type)
+		{
+			m_shapeType = type;
+			m_body.reset(nullptr); // Force recreate
+		}
+	}
 
-	void setMass(F32 mass);
+	void setMass(F32 mass)
+	{
+		if(ANKI_SCENE_ASSERT(mass >= 0.0f) && m_mass != mass)
+		{
+			m_mass = mass;
+			m_body.reset(nullptr); // Force recreate
+		}
+	}
 
 	F32 getMass() const
 	{
 		return m_mass;
 	}
 
-	const PhysicsBodyPtr& getPhysicsBody() const
+	const v2::PhysicsBodyPtr& getPhysicsBody() const
 	{
 		return m_body;
 	}
@@ -54,28 +104,35 @@ public:
 
 	void teleportTo(const Transform& trf);
 
-private:
-	enum class ShapeType : U8
+	SceneNode& getSceneNode()
 	{
-		kMesh,
-		kAabb,
-		kSphere,
-		kCount
-	};
+		return *m_node;
+	}
 
+private:
 	SceneNode* m_node = nullptr;
-	PhysicsBodyPtr m_body;
+	v2::PhysicsBodyPtr m_body;
 
-	ModelComponent* m_modelc = nullptr;
-	CpuMeshResourcePtr m_mesh;
+	v2::PhysicsCollisionShapePtr m_collisionShape;
 
-	PhysicsCollisionShapePtr m_collisionShape;
+	class
+	{
+	public:
+		ModelComponent* m_modelc = nullptr;
+		U32 m_modelcUuid = 0;
+	} m_mesh;
+
+	class
+	{
+	public:
+		Vec3 m_extend = Vec3(1.0f);
+	} m_box;
 
-	union
+	class
 	{
-		Vec3 m_boxExtend = Vec3(0.0f);
-		F32 m_sphereRadius;
-	};
+	public:
+		F32 m_radius = 1.0f;
+	} m_sphere;
 
 	F32 m_mass = 0.0f;
 
@@ -86,7 +143,7 @@ private:
 
 	Bool m_teleported = false;
 
-	ShapeType m_shapeType = ShapeType::kCount;
+	BodyComponentCollisionShapeType m_shapeType = BodyComponentCollisionShapeType::kCount;
 
 	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
 

+ 27 - 225
AnKi/Scene/Components/JointComponent.cpp

@@ -1,4 +1,3 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
 // All rights reserved.
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
@@ -6,266 +5,69 @@
 #include <AnKi/Scene/Components/JointComponent.h>
 #include <AnKi/Scene/Components/BodyComponent.h>
 #include <AnKi/Scene/SceneGraph.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 
 namespace anki {
 
-class JointComponent::JointNode : public IntrusiveListEnabled<JointNode>
+JointComponent::JointComponent(SceneNode* node)
+	: SceneComponent(node, kClassType)
 {
-public:
-	PhysicsJointPtr m_joint;
-	F32 m_breakingImpulse = 0.0f;
-
-	class P2P
-	{
-	public:
-		Vec3 m_relPosBody1 = Vec3(kMaxF32);
-		Vec3 m_relPosBody2 = Vec3(kMaxF32);
-	};
-
-	class Hinge
-	{
-	public:
-		Vec3 m_relPosBody1 = Vec3(kMaxF32);
-		Vec3 m_relPosBody2 = Vec3(kMaxF32);
-		Vec3 m_axis = Vec3(0.0f);
-	};
-
-	union
-	{
-		Hinge m_hinge = {};
-		P2P m_p2p;
-	};
-
-	JointType m_type = JointType::kCount;
-
-	JointNode() = default;
-};
-
-JointComponent::~JointComponent()
-{
-	while(!m_jointList.isEmpty())
-	{
-		JointNode* jnode = &m_jointList.getFront();
-		m_jointList.popFront();
-
-		deleteInstance(SceneMemoryPool::getSingleton(), jnode);
-	}
+	node->setIgnoreParentTransform(true);
 }
 
-Vec3 JointComponent::computeLocalPivotFromFactors(const PhysicsBodyPtr& body, const Vec3& factors)
-{
-	btTransform identityTrf;
-	identityTrf.setIdentity();
-	btVector3 aabbmin, aabbmax, center;
-	body->getBtBody()->getCollisionShape()->getAabb(identityTrf, aabbmin, aabbmax);
-
-	center = (aabbmin + aabbmax) * 0.5f;
-
-	Vec3 out;
-	for(U i = 0; i < 3; ++i)
-	{
-		const F32 factor = factors[i];
-		ANKI_ASSERT(factor >= -1.0f || factor <= 1.0f);
-		const F32 dist = aabbmax[i] - center[i];
-		out[i] = dist * factor + center[i];
-	}
-
-	return out;
-}
-
-void JointComponent::newPoint2PointJoint(const Vec3& relPosFactor, F32 breakingImpulse)
-{
-	JointNode* newNode = newInstance<JointNode>(SceneMemoryPool::getSingleton());
-
-	newNode->m_type = JointType::kPoint;
-	newNode->m_p2p.m_relPosBody1 = relPosFactor;
-	newNode->m_breakingImpulse = breakingImpulse;
-
-	m_jointList.pushBack(newNode);
-}
-
-void JointComponent::newPoint2PointJoint2(const Vec3& relPosFactorA, const Vec3& relPosFactorB, F32 breakingImpulse)
-{
-	JointNode* newNode = newInstance<JointNode>(SceneMemoryPool::getSingleton());
-
-	newNode->m_type = JointType::kPoint;
-	newNode->m_p2p.m_relPosBody1 = relPosFactorA;
-	newNode->m_p2p.m_relPosBody2 = relPosFactorB;
-	newNode->m_breakingImpulse = breakingImpulse;
-
-	m_jointList.pushBack(newNode);
-}
-
-void JointComponent::newHingeJoint(const Vec3& relPosFactor, const Vec3& axis, F32 breakingImpulse)
-{
-	JointNode* newNode = newInstance<JointNode>(SceneMemoryPool::getSingleton());
-
-	newNode->m_type = JointType::kHinge;
-	newNode->m_hinge.m_relPosBody1 = relPosFactor;
-	newNode->m_hinge.m_axis = axis;
-	newNode->m_breakingImpulse = breakingImpulse;
-
-	m_jointList.pushBack(newNode);
-}
-
-void JointComponent::newHingeJoint(const Vec3& relPosFactorA, const Vec3& relPosFactorB, const Vec3& axis, F32 breakingImpulse)
+JointComponent::~JointComponent()
 {
-	JointNode* newNode = newInstance<JointNode>(SceneMemoryPool::getSingleton());
-
-	newNode->m_type = JointType::kHinge;
-	newNode->m_hinge.m_relPosBody1 = relPosFactorA;
-	newNode->m_hinge.m_relPosBody2 = relPosFactorB;
-	newNode->m_hinge.m_axis = axis;
-	newNode->m_breakingImpulse = breakingImpulse;
-
-	m_jointList.pushBack(newNode);
 }
 
 Error JointComponent::update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated)
 {
-	SceneNode* parent = m_node->getParent();
-	BodyComponent* bodyc1 = (m_bodyc && m_bodyc->getPhysicsBody()) ? m_bodyc : nullptr;
-	BodyComponent* bodyc2 = nullptr;
-	if(parent)
-	{
-		bodyc2 = parent->tryGetFirstComponentOfType<BodyComponent>();
-		bodyc2 = (bodyc2 && bodyc2->getPhysicsBody()) ? bodyc2 : nullptr;
-	}
+	SceneNode& node = *info.m_node;
 
-	auto resetJoints = [this]() -> Bool {
-		U32 resetCount = 0;
-		for(JointNode& node : m_jointList)
-		{
-			resetCount += !!(node.m_joint);
-			node.m_joint.reset(nullptr);
-		}
+	SceneNode* parent = node.getParent();
+	SceneNode* child = node.hasChildren() ? &node.getChild(0) : nullptr;
 
-		return resetCount > 0;
-	};
+	BodyComponent* bodyc1 = (parent) ? parent->tryGetFirstComponentOfType<BodyComponent>() : nullptr;
+	BodyComponent* bodyc2 = (child) ? child->tryGetFirstComponentOfType<BodyComponent>() : nullptr;
 
-	if(!bodyc1)
+	v2::PhysicsBody* body1 = (bodyc1) ? bodyc1->getPhysicsBody().tryGet() : nullptr;
+	v2::PhysicsBody* body2 = (bodyc2) ? bodyc2->getPhysicsBody().tryGet() : nullptr;
+
+	if(!body1 || !body2 || m_type == JointType::kCount)
 	{
-		// No body no joints
-		if(resetJoints())
-		{
-			updated = true;
-		}
+		m_joint.reset(nullptr);
 		return Error::kNone;
 	}
 
-	const Bool parentChanged = parent && m_parentUuid != parent->getUuid();
-	if(parentChanged)
+	const Bool parentChanged = parent && m_parentNodeUuid != parent->getUuid();
+	const Bool childChanged = child && m_childNodeUuid != child->getUuid();
+	if(parentChanged || childChanged || node.movedThisFrame())
 	{
-		// New parent, reset joints
+		// Need to re-create the joint
 		updated = true;
-		m_parentUuid = parent->getUuid();
-		resetJoints();
+		m_parentNodeUuid = parent->getUuid();
+		m_childNodeUuid = child->getUuid();
+		m_joint.reset(nullptr);
 	}
 
-	// Remove broken joints
-	while(true)
+	// Create new joint
+	if(!m_joint)
 	{
-		Bool erasedOne = false;
-		for(JointNode& node : m_jointList)
-		{
-			if(node.m_joint && node.m_joint->isBroken())
-			{
-				m_jointList.erase(&node);
-				deleteInstance(SceneMemoryPool::getSingleton(), &node);
-				erasedOne = true;
-				updated = true;
-				break;
-			}
-		}
-
-		if(!erasedOne)
-		{
-			break;
-		}
-	}
-
-	// Create new joints
-	for(JointNode& node : m_jointList)
-	{
-		if(node.m_joint)
-		{
-			continue;
-		}
-
 		updated = true;
 
-		switch(node.m_type)
+		switch(m_type)
 		{
 		case JointType::kPoint:
-		{
-			const Vec3 relPos1 = computeLocalPivotFromFactors(bodyc1->getPhysicsBody(), node.m_p2p.m_relPosBody1);
-
-			if(node.m_p2p.m_relPosBody2 != Vec3(kMaxF32) && bodyc2)
-			{
-				const Vec3 relPos2 = computeLocalPivotFromFactors(bodyc2->getPhysicsBody(), node.m_p2p.m_relPosBody2);
-
-				node.m_joint = PhysicsWorld::getSingleton().newInstance<PhysicsPoint2PointJoint>(bodyc1->getPhysicsBody(), relPos1,
-																								 bodyc2->getPhysicsBody(), relPos2);
-			}
-			else
-			{
-				node.m_joint = PhysicsWorld::getSingleton().newInstance<PhysicsPoint2PointJoint>(bodyc1->getPhysicsBody(), relPos1);
-			}
+			m_joint = v2::PhysicsWorld::getSingleton().newPointJoint(body1, body2, node.getWorldTransform().getOrigin().xyz());
 			break;
-		}
 		case JointType::kHinge:
-		{
-			const Vec3 relPos1 = computeLocalPivotFromFactors(bodyc1->getPhysicsBody(), node.m_hinge.m_relPosBody1);
-
-			if(node.m_hinge.m_relPosBody2 != Vec3(kMaxF32) && bodyc2)
-			{
-				const Vec3 relPos2 = computeLocalPivotFromFactors(bodyc2->getPhysicsBody(), node.m_hinge.m_relPosBody2);
-
-				node.m_joint = PhysicsWorld::getSingleton().newInstance<PhysicsHingeJoint>(bodyc1->getPhysicsBody(), relPos1, node.m_hinge.m_axis,
-																						   bodyc2->getPhysicsBody(), relPos2, node.m_hinge.m_axis);
-			}
-			else
-			{
-				node.m_joint = PhysicsWorld::getSingleton().newInstance<PhysicsHingeJoint>(bodyc1->getPhysicsBody(), relPos1, node.m_hinge.m_axis);
-			}
+			m_joint = v2::PhysicsWorld::getSingleton().newHingeJoint(body1, body2, node.getWorldTransform());
 			break;
-		}
 		default:
 			ANKI_ASSERT(0);
 		}
-
-		node.m_joint->setBreakingImpulseThreshold(node.m_breakingImpulse);
 	}
 
 	return Error::kNone;
 }
 
-void JointComponent::onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added)
-{
-	if(other->getType() != SceneComponentType::kBody)
-	{
-		return;
-	}
-
-	BodyComponent* bodyc = static_cast<BodyComponent*>(other);
-
-	Bool jointListInvalid = false;
-	if(added && m_bodyc == nullptr)
-	{
-		m_bodyc = bodyc;
-		jointListInvalid = true;
-	}
-	else if(bodyc == m_bodyc)
-	{
-		m_bodyc = nullptr;
-		jointListInvalid = true;
-	}
-
-	if(jointListInvalid)
-	{
-		onDestroy(*m_node);
-	}
-}
-
 } // end namespace anki

+ 21 - 37
AnKi/Scene/Components/JointComponent.h

@@ -6,63 +6,47 @@
 #pragma once
 
 #include <AnKi/Scene/Components/SceneComponent.h>
-#include <AnKi/Physics/PhysicsJoint.h>
+#include <AnKi/Physics2/PhysicsJoint.h>
 
 namespace anki {
 
 /// @addtogroup scene
 /// @{
 
-/// Contains a list of joints.
+/// @memberof JointComponent
+enum class JointType : U8
+{
+	kPoint,
+	kHinge,
+
+	kCount,
+	kFirst
+};
+
+/// Contains a single joint that connects the parent node with the 1st child node of the node that has this component.
 class JointComponent : public SceneComponent
 {
 	ANKI_SCENE_COMPONENT(JointComponent)
 
 public:
-	JointComponent(SceneNode* node)
-		: SceneComponent(node, kClassType)
-		, m_node(node)
-	{
-	}
+	JointComponent(SceneNode* node);
 
 	~JointComponent();
 
-	/// Create a point 2 point joint on the BodyComponent of the SceneNode.
-	void newPoint2PointJoint(const Vec3& relPosFactor, F32 brakingImpulse = kMaxF32);
-
-	/// Create a point 2 point joint on the BodyComponents of the SceneNode and its child node.
-	void newPoint2PointJoint2(const Vec3& relPosFactorA, const Vec3& relPosFactorB, F32 brakingImpulse = kMaxF32);
-
-	/// Create a hinge joint on the BodyComponent of the SceneNode.
-	void newHingeJoint(const Vec3& relPosFactor, const Vec3& axis, F32 brakingImpulse = kMaxF32);
-
-	/// Create a hinge joint on the BodyComponent of the SceneNode.
-	void newHingeJoint(const Vec3& relPosFactorA, const Vec3& relPosFactorB, const Vec3& axis, F32 brakingImpulse = kMaxF32);
-
-private:
-	class JointNode;
-
-	enum class JointType : U8
+	void setType(JointType type)
 	{
-		kPoint,
-		kHinge,
-		kCount
-	};
-
-	SceneNode* m_node = nullptr;
-	BodyComponent* m_bodyc = nullptr;
+		m_type = type;
+	}
 
-	U32 m_parentUuid = 0;
+private:
+	v2::PhysicsJointPtr m_joint;
 
-	IntrusiveList<JointNode> m_jointList;
+	U32 m_parentNodeUuid = 0;
+	U32 m_childNodeUuid = 0;
 
-	/// Given a 3 coodrinates that lie in [-1.0, +1.0] compute a pivot point that lies into the AABB of the collision
-	/// shape of the body.
-	static Vec3 computeLocalPivotFromFactors(const PhysicsBodyPtr& body, const Vec3& factors);
+	JointType m_type = JointType::kCount;
 
 	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
-
-	void onOtherComponentRemovedOrAdded(SceneComponent* other, Bool added) override;
 };
 /// @}
 

+ 13 - 14
AnKi/Scene/Components/ParticleEmitterComponent.cpp

@@ -9,9 +9,9 @@
 #include <AnKi/Scene/Components/MoveComponent.h>
 #include <AnKi/Resource/ParticleEmitterResource.h>
 #include <AnKi/Resource/ResourceManager.h>
-#include <AnKi/Physics/PhysicsBody.h>
-#include <AnKi/Physics/PhysicsCollisionShape.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsBody.h>
+#include <AnKi/Physics2/PhysicsCollisionShape.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 #include <AnKi/Math.h>
 #include <AnKi/Shaders/Include/GpuSceneFunctions.h>
 #include <AnKi/Core/GpuMemory/RebarTransientMemoryPool.h>
@@ -127,16 +127,13 @@ public:
 class ParticleEmitterComponent::PhysicsParticle : public ParticleEmitterComponent::ParticleBase
 {
 public:
-	PhysicsBodyPtr m_body;
+	v2::PhysicsBodyPtr m_body;
 
-	PhysicsParticle(const PhysicsBodyInitInfo& init, ParticleEmitterComponent* component)
+	PhysicsParticle(const v2::PhysicsBodyInitInfo& init, ParticleEmitterComponent* component)
 	{
-		m_body = PhysicsWorld::getSingleton().newInstance<PhysicsBody>(init);
+		m_body = v2::PhysicsWorld::getSingleton().newPhysicsBody(init);
 		m_body->setUserData(component);
 		m_body->activate(false);
-		m_body->setMaterialGroup(PhysicsMaterialBit::kParticle);
-		m_body->setMaterialMask(PhysicsMaterialBit::kStaticGeometry);
-		m_body->setAngularFactor(Vec3(0.0f));
 	}
 
 	void kill()
@@ -157,7 +154,7 @@ public:
 		m_body->activate(true);
 		m_body->setLinearVelocity(Vec3(0.0f));
 		m_body->setAngularVelocity(Vec3(0.0f));
-		m_body->clearForces();
+		m_body->clearForcesAndTorque();
 
 		// force
 		if(forceFlag)
@@ -175,7 +172,7 @@ public:
 		// gravity
 		if(!worldGravFlag)
 		{
-			m_body->setGravity(getRandom(props.m_particle.m_minGravity, props.m_particle.m_maxGravity));
+			// TODO m_body->setGravity(getRandom(props.m_particle.m_minGravity, props.m_particle.m_maxGravity));
 		}
 
 		// Starting pos. In local space
@@ -283,10 +280,12 @@ void ParticleEmitterComponent::loadParticleEmitterResource(CString filename)
 	m_simulationType = (m_props.m_usePhysicsEngine) ? SimulationType::kPhysicsEngine : SimulationType::kSimple;
 	if(m_simulationType == SimulationType::kPhysicsEngine)
 	{
-		PhysicsCollisionShapePtr collisionShape = PhysicsWorld::getSingleton().newInstance<PhysicsSphere>(m_props.m_particle.m_minInitialSize / 2.0f);
+		v2::PhysicsCollisionShapePtr collisionShape =
+			v2::PhysicsWorld::getSingleton().newSphereCollisionShape(m_props.m_particle.m_minInitialSize / 2.0f);
 
-		PhysicsBodyInitInfo binit;
-		binit.m_shape = std::move(collisionShape);
+		v2::PhysicsBodyInitInfo binit;
+		binit.m_layer = v2::PhysicsLayer::kDebris;
+		binit.m_shape = collisionShape.get();
 
 		m_physicsParticles.resizeStorage(m_props.m_maxNumOfParticles);
 		for(U32 i = 0; i < m_props.m_maxNumOfParticles; i++)

+ 10 - 8
AnKi/Scene/Components/PlayerControllerComponent.cpp

@@ -6,16 +6,16 @@
 #include <AnKi/Scene/Components/PlayerControllerComponent.h>
 #include <AnKi/Scene/SceneNode.h>
 #include <AnKi/Scene/SceneGraph.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 
 namespace anki {
 
 PlayerControllerComponent::PlayerControllerComponent(SceneNode* node)
 	: SceneComponent(node, kClassType)
 {
-	PhysicsPlayerControllerInitInfo init;
-	init.m_position = node->getWorldTransform().getOrigin().xyz();
-	m_player = PhysicsWorld::getSingleton().newInstance<PhysicsPlayerController>(init);
+	v2::PhysicsPlayerControllerInitInfo init;
+	init.m_initialPosition = node->getWorldTransform().getOrigin().xyz();
+	m_player = v2::PhysicsWorld::getSingleton().newPlayerController(init);
 	m_player->setUserData(this);
 
 	node->setIgnoreParentTransform(true);
@@ -23,12 +23,14 @@ PlayerControllerComponent::PlayerControllerComponent(SceneNode* node)
 
 Error PlayerControllerComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 {
-	const Vec3 newPos = m_player->getTransform().getOrigin().xyz();
-	updated = newPos != m_worldPos;
+	U32 posVersion;
+	const Vec3 newPos = m_player->getPosition(&posVersion);
 
-	if(updated)
+	if(posVersion != m_positionVersion)
 	{
-		m_worldPos = newPos;
+		updated = true;
+		m_positionVersion = posVersion;
+
 		info.m_node->setLocalOrigin(newPos.xyz0());
 	}
 

+ 7 - 7
AnKi/Scene/Components/PlayerControllerComponent.h

@@ -6,7 +6,7 @@
 #pragma once
 
 #include <AnKi/Scene/Components/SceneComponent.h>
-#include <AnKi/Physics/PhysicsPlayerController.h>
+#include <AnKi/Physics2/PhysicsPlayerController.h>
 
 namespace anki {
 
@@ -21,9 +21,9 @@ class PlayerControllerComponent : public SceneComponent
 public:
 	PlayerControllerComponent(SceneNode* node);
 
-	void setVelocity(F32 forwardSpeed, F32 strafeSpeed, F32 jumpSpeed, const Vec4& forwardDir)
+	void setVelocity(F32 forwardSpeed, F32 jumpSpeed, Vec3 forwardDir, Bool crouch)
 	{
-		m_player->setVelocity(forwardSpeed, strafeSpeed, jumpSpeed, forwardDir);
+		m_player->updateState(forwardSpeed, forwardDir, jumpSpeed, crouch);
 	}
 
 	void moveToPosition(const Vec3& pos)
@@ -31,16 +31,16 @@ public:
 		m_player->moveToPosition(pos);
 	}
 
-	PhysicsPlayerController& getPhysicsPlayerController()
+	v2::PhysicsPlayerController& getPhysicsPlayerController()
 	{
 		return *m_player;
 	}
 
 private:
-	PhysicsPlayerControllerPtr m_player;
-	Vec3 m_worldPos = Vec3(0.0f);
+	v2::PhysicsPlayerControllerPtr m_player;
+	U32 m_positionVersion = kMaxU32;
 
-	Error update([[maybe_unused]] SceneComponentUpdateInfo& info, Bool& updated) override;
+	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
 };
 /// @}
 

+ 17 - 0
AnKi/Scene/Components/SceneComponent.cpp

@@ -0,0 +1,17 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <AnKi/Scene/Components/SceneComponent.h>
+#include <AnKi/Scene/SceneGraph.h>
+
+namespace anki {
+
+SceneComponent::SceneComponent([[maybe_unused]] SceneNode* node, SceneComponentType type)
+	: m_uuid(SceneGraph::getSingleton().getNewUuid())
+	, m_type(U8(type))
+{
+}
+
+} // namespace anki

+ 11 - 8
AnKi/Scene/Components/SceneComponent.h

@@ -69,21 +69,17 @@ public:
 };
 
 /// Scene node component.
-/// @note Doesn't have C++ virtuals to keep it compact.
 class SceneComponent
 {
 public:
 	/// Construct the scene component.
-	SceneComponent([[maybe_unused]] SceneNode* node, SceneComponentType type)
-		: m_type(type)
-	{
-	}
+	SceneComponent(SceneNode* node, SceneComponentType type);
 
 	virtual ~SceneComponent() = default;
 
 	SceneComponentType getType() const
 	{
-		return m_type;
+		return SceneComponentType(m_type);
 	}
 
 	Timestamp getTimestamp() const
@@ -91,6 +87,11 @@ public:
 		return m_timestamp;
 	}
 
+	U32 getUuid() const
+	{
+		return m_uuid;
+	}
+
 	ANKI_INTERNAL U32 getArrayIndex() const
 	{
 		ANKI_ASSERT(m_arrayIdx != kMaxU32);
@@ -127,8 +128,10 @@ public:
 
 private:
 	Timestamp m_timestamp = 1; ///< Indicates when an update happened
-	U32 m_arrayIdx = kMaxU32;
-	SceneComponentType m_type; ///< Cache the type ID.
+	U32 m_uuid = 0;
+
+	U32 m_arrayIdx : 24 = kMaxU32 >> 24u;
+	U32 m_type : 8 = 0; ///< Cache the type ID.
 
 	static constexpr Array<F32, U32(SceneComponentType::kCount)> m_updateOrderWeights = {
 #define ANKI_DEFINE_SCENE_COMPONENT(name, weight) weight

+ 3 - 3
AnKi/Scene/Components/SceneComponentClasses.def.h

@@ -15,14 +15,14 @@ ANKI_SCENE_COMPONENT_SEPARATOR
 ANKI_DEFINE_SCENE_COMPONENT(PlayerController, 10.0f)
 ANKI_SCENE_COMPONENT_SEPARATOR
 
-ANKI_DEFINE_SCENE_COMPONENT(Joint, 15.0f)
-ANKI_SCENE_COMPONENT_SEPARATOR
-
 ANKI_DEFINE_SCENE_COMPONENT(Move, 30.0f)
 ANKI_SCENE_COMPONENT_SEPARATOR
 ANKI_DEFINE_SCENE_COMPONENT(Skin, 30.0f)
 ANKI_SCENE_COMPONENT_SEPARATOR
 
+ANKI_DEFINE_SCENE_COMPONENT(Joint, 35.0f)
+ANKI_SCENE_COMPONENT_SEPARATOR
+
 ANKI_DEFINE_SCENE_COMPONENT(Trigger, 40.0f)
 ANKI_SCENE_COMPONENT_SEPARATOR
 

+ 64 - 53
AnKi/Scene/Components/TriggerComponent.cpp

@@ -4,103 +4,114 @@
 // http://www.anki3d.org/LICENSE
 
 #include <AnKi/Scene/Components/TriggerComponent.h>
+#include <AnKi/Scene/Components/BodyComponent.h>
 #include <AnKi/Scene/SceneNode.h>
 #include <AnKi/Scene/SceneGraph.h>
-#include <AnKi/Physics/PhysicsCollisionShape.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsCollisionShape.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 
 namespace anki {
 
 /// The callbacks execute before the TriggerComponent::update
-class TriggerComponent::MyPhysicsTriggerProcessContactCallback final : public PhysicsTriggerProcessContactCallback
+class TriggerComponent::MyPhysicsTriggerCallbacks final : public v2::PhysicsTriggerCallbacks
 {
 public:
-	TriggerComponent* m_comp = nullptr;
-	Bool m_updated = false;
-	Bool m_enterUpdated = false;
-	Bool m_insideUpdated = false;
-	Bool m_exitUpdated = false;
-
-	void onTriggerEnter([[maybe_unused]] PhysicsTrigger& trigger, PhysicsFilteredObject& obj)
+	void onTriggerEnter(const v2::PhysicsBody& trigger, const v2::PhysicsObjectBase& obj) override
 	{
-		// Clean previous results
-		if(!m_enterUpdated)
+		TriggerComponent& triggerc = *reinterpret_cast<TriggerComponent*>(trigger.getUserData());
+		ANKI_ASSERT(triggerc.getType() == TriggerComponent::kClassType);
+
+		if(triggerc.m_resetEnter)
 		{
-			m_enterUpdated = true;
-			m_comp->m_bodiesEnter.destroy();
+			triggerc.m_bodiesEnter.destroy();
+			triggerc.m_resetEnter = false;
 		}
 
-		m_updated = true;
-
-		m_comp->m_bodiesEnter.emplaceBack(static_cast<BodyComponent*>(obj.getUserData()));
-	}
-
-	void onTriggerInside([[maybe_unused]] PhysicsTrigger& trigger, PhysicsFilteredObject& obj)
-	{
-		// Clean previous results
-		if(!m_insideUpdated)
+		if(obj.getType() == v2::PhysicsObjectType::kBody)
 		{
-			m_insideUpdated = true;
-			m_comp->m_bodiesInside.destroy();
+			const v2::PhysicsBody& body = static_cast<const v2::PhysicsBody&>(obj);
+			BodyComponent& bodyc = *reinterpret_cast<BodyComponent*>(body.getUserData());
+			ANKI_ASSERT(bodyc.getType() == BodyComponent::kClassType);
+			triggerc.m_bodiesEnter.emplaceBack(&bodyc.getSceneNode());
 		}
-
-		m_updated = true;
-
-		m_comp->m_bodiesInside.emplaceBack(static_cast<BodyComponent*>(obj.getUserData()));
 	}
 
-	void onTriggerExit([[maybe_unused]] PhysicsTrigger& trigger, PhysicsFilteredObject& obj)
+	void onTriggerExit(const v2::PhysicsBody& trigger, const v2::PhysicsObjectBase& obj) override
 	{
-		// Clean previous results
-		if(!m_exitUpdated)
+		TriggerComponent& triggerc = *reinterpret_cast<TriggerComponent*>(trigger.getUserData());
+		ANKI_ASSERT(triggerc.getType() == TriggerComponent::kClassType);
+
+		if(triggerc.m_resetExit)
 		{
-			m_exitUpdated = true;
-			m_comp->m_bodiesExit.destroy();
+			triggerc.m_bodiesExit.destroy();
+			triggerc.m_resetExit = false;
 		}
 
-		m_updated = true;
-
-		m_comp->m_bodiesExit.emplaceBack(static_cast<BodyComponent*>(obj.getUserData()));
+		if(obj.getType() == v2::PhysicsObjectType::kBody)
+		{
+			const v2::PhysicsBody& body = static_cast<const v2::PhysicsBody&>(obj);
+			BodyComponent& bodyc = *reinterpret_cast<BodyComponent*>(body.getUserData());
+			ANKI_ASSERT(bodyc.getType() == BodyComponent::kClassType);
+			triggerc.m_bodiesExit.emplaceBack(&bodyc.getSceneNode());
+		}
 	}
 };
 
+TriggerComponent::MyPhysicsTriggerCallbacks TriggerComponent::m_callbacks;
+
 TriggerComponent::TriggerComponent(SceneNode* node)
 	: SceneComponent(node, kClassType)
 	, m_node(node)
 {
-	ANKI_ASSERT(node);
-	m_callbacks = newInstance<MyPhysicsTriggerProcessContactCallback>(SceneMemoryPool::getSingleton());
-	m_callbacks->m_comp = this;
 }
 
 TriggerComponent::~TriggerComponent()
 {
-	deleteInstance(SceneMemoryPool::getSingleton(), m_callbacks);
 }
 
 void TriggerComponent::setSphereVolumeRadius(F32 radius)
 {
 	// Need to re-create it
-	m_shape = PhysicsWorld::getSingleton().newInstance<PhysicsSphere>(radius);
-	m_trigger = PhysicsWorld::getSingleton().newInstance<PhysicsTrigger>(m_shape);
+	m_shape = v2::PhysicsWorld::getSingleton().newSphereCollisionShape(radius);
+
+	v2::PhysicsBodyInitInfo init;
+	init.m_isTrigger = true;
+	init.m_shape = m_shape.get();
+	init.m_transform = m_node->getWorldTransform();
+	init.m_layer = v2::PhysicsLayer::kTrigger;
+
+	m_trigger = v2::PhysicsWorld::getSingleton().newPhysicsBody(init);
 	m_trigger->setUserData(this);
-	m_trigger->setContactProcessCallback(m_callbacks);
+	m_trigger->setPhysicsTriggerCallbacks(&m_callbacks);
 	m_trigger->setTransform(m_node->getWorldTransform());
 }
 
 Error TriggerComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 {
-	updated = false;
-
-	if(m_trigger.isCreated()) [[likely]]
+	if(m_trigger) [[likely]]
 	{
-		updated = m_callbacks->m_updated;
-		m_callbacks->m_updated = false;
-		m_callbacks->m_enterUpdated = false;
-		m_callbacks->m_insideUpdated = false;
-		m_callbacks->m_exitUpdated = false;
+		if(!m_resetEnter || !m_resetExit)
+		{
+			updated = true;
+		}
+
+		if(m_resetEnter)
+		{
+			// None entered, cleanup
+			m_bodiesEnter.destroy();
+		}
+
+		if(m_resetExit)
+		{
+			// None exited, cleanup
+			m_bodiesExit.destroy();
+		}
+
+		// Prepare them for the next frame
+		m_resetEnter = true;
+		m_resetExit = true;
 
-		if(info.m_node->movedThisFrame() && m_trigger.isCreated())
+		if(info.m_node->movedThisFrame())
 		{
 			updated = true;
 			m_trigger->setTransform(info.m_node->getWorldTransform());

+ 17 - 20
AnKi/Scene/Components/TriggerComponent.h

@@ -6,13 +6,10 @@
 #pragma once
 
 #include <AnKi/Scene/Components/SceneComponent.h>
-#include <AnKi/Physics/PhysicsTrigger.h>
+#include <AnKi/Physics2/PhysicsBody.h>
 
 namespace anki {
 
-// Forward
-class BodyComponent;
-
 /// @addtogroup scene
 /// @{
 
@@ -28,31 +25,31 @@ public:
 
 	void setSphereVolumeRadius(F32 radius);
 
-	WeakArray<BodyComponent*> getBodyComponentsEnter()
-	{
-		return WeakArray<BodyComponent*>(m_bodiesEnter);
-	}
-
-	WeakArray<BodyComponent*> getBodyComponentsInside()
+	WeakArray<SceneNode*> getSceneNodesEnter()
 	{
-		return WeakArray<BodyComponent*>(m_bodiesInside);
+		return WeakArray<SceneNode*>(m_bodiesEnter);
 	}
 
-	WeakArray<BodyComponent*> getBodyComponentsExit()
+	WeakArray<SceneNode*> getSceneNodesExit()
 	{
-		return WeakArray<BodyComponent*>(m_bodiesExit);
+		return WeakArray<SceneNode*>(m_bodiesExit);
 	}
 
 private:
-	class MyPhysicsTriggerProcessContactCallback;
+	class MyPhysicsTriggerCallbacks;
 
 	SceneNode* m_node;
-	PhysicsCollisionShapePtr m_shape;
-	PhysicsTriggerPtr m_trigger;
-	SceneDynamicArray<BodyComponent*> m_bodiesEnter;
-	SceneDynamicArray<BodyComponent*> m_bodiesInside;
-	SceneDynamicArray<BodyComponent*> m_bodiesExit;
-	MyPhysicsTriggerProcessContactCallback* m_callbacks = nullptr;
+
+	v2::PhysicsCollisionShapePtr m_shape;
+	v2::PhysicsBodyPtr m_trigger;
+
+	SceneDynamicArray<SceneNode*> m_bodiesEnter;
+	SceneDynamicArray<SceneNode*> m_bodiesExit;
+
+	Bool m_resetEnter = true;
+	Bool m_resetExit = true;
+
+	static MyPhysicsTriggerCallbacks m_callbacks;
 
 	Error update(SceneComponentUpdateInfo& info, Bool& updated) override;
 };

+ 2 - 9
AnKi/Scene/SceneGraph.cpp

@@ -5,7 +5,7 @@
 
 #include <AnKi/Scene/SceneGraph.h>
 #include <AnKi/Scene/RenderStateBucket.h>
-#include <AnKi/Physics/PhysicsWorld.h>
+#include <AnKi/Physics2/PhysicsWorld.h>
 #include <AnKi/Resource/ResourceManager.h>
 #include <AnKi/Util/CVarSet.h>
 #include <AnKi/Core/StatsSet.h>
@@ -38,8 +38,6 @@ namespace anki {
 
 static StatCounter g_sceneUpdateTimeStatVar(StatCategory::kTime, "All scene update",
 											StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
-static StatCounter g_scenePhysicsTimeStatVar(StatCategory::kTime, "Physics",
-											 StatFlag::kMilisecond | StatFlag::kShowAverage | StatFlag::kMainThreadUpdates);
 
 constexpr U32 kUpdateNodeBatchSize = 10;
 
@@ -207,12 +205,7 @@ Error SceneGraph::update(Second prevUpdateTime, Second crntTime)
 
 	// Update
 	{
-		ANKI_TRACE_SCOPED_EVENT(ScenePhysics);
-		const Second physicsUpdate = HighRezTimer::getCurrentTime();
-
-		PhysicsWorld::getSingleton().update(crntTime - prevUpdateTime);
-
-		g_scenePhysicsTimeStatVar.set((HighRezTimer::getCurrentTime() - physicsUpdate) * 1000.0);
+		v2::PhysicsWorld::getSingleton().update(crntTime - prevUpdateTime);
 	}
 
 	{

+ 4 - 1
AnKi/Scene/SceneNode.cpp

@@ -148,7 +148,10 @@ Bool SceneNode::updateTransform()
 
 		// Make children dirty as well. Don't walk the whole tree because you will re-walk it later
 		[[maybe_unused]] const Error err = visitChildrenMaxDepth(1, [](SceneNode& childNode) -> Error {
-			childNode.m_localTransformDirty = true;
+			if(!childNode.m_ignoreParentNodeTransform)
+			{
+				childNode.m_localTransformDirty = true;
+			}
 			return Error::kNone;
 		});
 	}

+ 15 - 4
AnKi/Scene/SceneNode.h

@@ -73,6 +73,11 @@ public:
 		Base::addChild(obj);
 	}
 
+	void setParent(SceneNode* obj)
+	{
+		Base::setParent(obj);
+	}
+
 	/// This is called by the scenegraph every frame after all component updates. By default it does nothing.
 	/// @param prevUpdateTime Timestamp of the previous update
 	/// @param crntTime Timestamp of this update
@@ -105,7 +110,7 @@ public:
 	template<typename TComponent, typename TFunct>
 	void iterateComponentsOfType(TFunct func) const
 	{
-		if(!!(m_componentTypeMask & (1 << SceneComponentTypeMask(TComponent::kClassType))))
+		if(hasComponent<TComponent>())
 		{
 			for(U32 i = 0; i < m_components.getSize(); ++i)
 			{
@@ -121,7 +126,7 @@ public:
 	template<typename TComponent, typename TFunct>
 	void iterateComponentsOfType(TFunct func)
 	{
-		if(!!(m_componentTypeMask & (1 << SceneComponentTypeMask(TComponent::kClassType))))
+		if(hasComponent<TComponent>())
 		{
 			for(U32 i = 0; i < m_components.getSize(); ++i)
 			{
@@ -137,7 +142,7 @@ public:
 	template<typename TComponent>
 	const TComponent* tryGetFirstComponentOfType() const
 	{
-		if(!!(m_componentTypeMask & (1 << SceneComponentTypeMask(TComponent::kClassType))))
+		if(hasComponent<TComponent>())
 		{
 			for(U32 i = 0; i < m_components.getSize(); ++i)
 			{
@@ -179,7 +184,7 @@ public:
 	template<typename TComponent>
 	const TComponent* tryGetNthComponentOfType(U32 nth) const
 	{
-		if(!!(m_componentTypeMask & (1 << SceneComponentTypeMask(TComponent::kClassType))))
+		if(hasComponent<TComponent>())
 		{
 			I32 inth = I32(nth);
 			for(U32 i = 0; i < m_components.getSize(); ++i)
@@ -381,6 +386,12 @@ public:
 	template<typename TComponent>
 	TComponent* newComponent();
 
+	template<typename TComponent>
+	Bool hasComponent() const
+	{
+		return !!((1u << SceneComponentTypeMask(TComponent::kClassType)) & m_componentTypeMask);
+	}
+
 private:
 	SceneString m_name; ///< A unique name.
 	U32 m_uuid;

+ 250 - 227
AnKi/Script/Scene.cpp

@@ -59,9 +59,8 @@ static EventManager* getEventManager(lua_State* l)
 }
 
 using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
-using WeakArrayBodyComponentPtr = WeakArray<BodyComponent*>;
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLightComponentType = {4219517956328838712, "LightComponentType", 0, nullptr, nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoLightComponentType = {9069794947595355041, "LightComponentType", 0, nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LightComponentType>()
@@ -96,8 +95,52 @@ static inline void wrapLightComponentType(lua_State* l)
 	lua_settop(l, 0);
 }
 
+LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponentCollisionShapeType = {4012303373488841237, "BodyComponentCollisionShapeType", 0, nullptr,
+																		  nullptr};
+
+template<>
+const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<BodyComponentCollisionShapeType>()
+{
+	return luaUserDataTypeInfoBodyComponentCollisionShapeType;
+}
+
+/// Wrap enum BodyComponentCollisionShapeType.
+static inline void wrapBodyComponentCollisionShapeType(lua_State* l)
+{
+	lua_newtable(l);
+	lua_setglobal(l, luaUserDataTypeInfoBodyComponentCollisionShapeType.m_typeName);
+	lua_getglobal(l, luaUserDataTypeInfoBodyComponentCollisionShapeType.m_typeName);
+
+	lua_pushstring(l, "kFromModelComponent");
+	ANKI_ASSERT(BodyComponentCollisionShapeType(lua_Number(BodyComponentCollisionShapeType::kFromModelComponent))
+					== BodyComponentCollisionShapeType::kFromModelComponent
+				&& "Can't map the enumerant to a lua_Number");
+	lua_pushnumber(l, lua_Number(BodyComponentCollisionShapeType::kFromModelComponent));
+	lua_settable(l, -3);
+
+	lua_pushstring(l, "kAabb");
+	ANKI_ASSERT(BodyComponentCollisionShapeType(lua_Number(BodyComponentCollisionShapeType::kAabb)) == BodyComponentCollisionShapeType::kAabb
+				&& "Can't map the enumerant to a lua_Number");
+	lua_pushnumber(l, lua_Number(BodyComponentCollisionShapeType::kAabb));
+	lua_settable(l, -3);
+
+	lua_pushstring(l, "kSphere");
+	ANKI_ASSERT(BodyComponentCollisionShapeType(lua_Number(BodyComponentCollisionShapeType::kSphere)) == BodyComponentCollisionShapeType::kSphere
+				&& "Can't map the enumerant to a lua_Number");
+	lua_pushnumber(l, lua_Number(BodyComponentCollisionShapeType::kSphere));
+	lua_settable(l, -3);
+
+	lua_pushstring(l, "kCount");
+	ANKI_ASSERT(BodyComponentCollisionShapeType(lua_Number(BodyComponentCollisionShapeType::kCount)) == BodyComponentCollisionShapeType::kCount
+				&& "Can't map the enumerant to a lua_Number");
+	lua_pushnumber(l, lua_Number(BodyComponentCollisionShapeType::kCount));
+	lua_settable(l, -3);
+
+	lua_settop(l, 0);
+}
+
 LuaUserDataTypeInfo luaUserDataTypeInfoWeakArraySceneNodePtr = {
-	-89195344190135263, "WeakArraySceneNodePtr", LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>(), nullptr, nullptr};
+	-4465466740417030284, "WeakArraySceneNodePtr", LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<WeakArraySceneNodePtr>()
@@ -215,126 +258,7 @@ static inline void wrapWeakArraySceneNodePtr(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoWeakArrayBodyComponentPtr = {
-	8690829719095736348, "WeakArrayBodyComponentPtr", LuaUserData::computeSizeForGarbageCollected<WeakArrayBodyComponentPtr>(), nullptr, nullptr};
-
-template<>
-const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<WeakArrayBodyComponentPtr>()
-{
-	return luaUserDataTypeInfoWeakArrayBodyComponentPtr;
-}
-
-/// Pre-wrap method WeakArrayBodyComponentPtr::getSize.
-static inline int pwrapWeakArrayBodyComponentPtrgetSize(lua_State* l)
-{
-	[[maybe_unused]] LuaUserData* ud;
-	[[maybe_unused]] void* voidp;
-	[[maybe_unused]] PtrSize size;
-
-	if(LuaBinder::checkArgsCount(l, 1)) [[unlikely]]
-	{
-		return -1;
-	}
-
-	// Get "this" as "self"
-	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoWeakArrayBodyComponentPtr, ud))
-	{
-		return -1;
-	}
-
-	WeakArrayBodyComponentPtr* self = ud->getData<WeakArrayBodyComponentPtr>();
-
-	// Call the method
-	U32 ret = self->getSize();
-
-	// Push return value
-	lua_pushnumber(l, lua_Number(ret));
-
-	return 1;
-}
-
-/// Wrap method WeakArrayBodyComponentPtr::getSize.
-static int wrapWeakArrayBodyComponentPtrgetSize(lua_State* l)
-{
-	int res = pwrapWeakArrayBodyComponentPtrgetSize(l);
-	if(res >= 0)
-	{
-		return res;
-	}
-
-	lua_error(l);
-	return 0;
-}
-
-/// Pre-wrap method WeakArrayBodyComponentPtr::getAt.
-static inline int pwrapWeakArrayBodyComponentPtrgetAt(lua_State* l)
-{
-	[[maybe_unused]] LuaUserData* ud;
-	[[maybe_unused]] void* voidp;
-	[[maybe_unused]] PtrSize size;
-
-	if(LuaBinder::checkArgsCount(l, 2)) [[unlikely]]
-	{
-		return -1;
-	}
-
-	// Get "this" as "self"
-	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoWeakArrayBodyComponentPtr, ud))
-	{
-		return -1;
-	}
-
-	WeakArrayBodyComponentPtr* self = ud->getData<WeakArrayBodyComponentPtr>();
-
-	// Pop arguments
-	U32 arg0;
-	if(LuaBinder::checkNumber(l, 2, arg0)) [[unlikely]]
-	{
-		return -1;
-	}
-
-	// Call the method
-	BodyComponent* ret = (*self)[arg0];
-
-	// Push return value
-	if(ret == nullptr) [[unlikely]]
-	{
-		lua_pushstring(l, "Glue code returned nullptr");
-		return -1;
-	}
-
-	voidp = lua_newuserdata(l, sizeof(LuaUserData));
-	ud = static_cast<LuaUserData*>(voidp);
-	luaL_setmetatable(l, "BodyComponent");
-	extern LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponent;
-	ud->initPointed(&luaUserDataTypeInfoBodyComponent, ret);
-
-	return 1;
-}
-
-/// Wrap method WeakArrayBodyComponentPtr::getAt.
-static int wrapWeakArrayBodyComponentPtrgetAt(lua_State* l)
-{
-	int res = pwrapWeakArrayBodyComponentPtrgetAt(l);
-	if(res >= 0)
-	{
-		return res;
-	}
-
-	lua_error(l);
-	return 0;
-}
-
-/// Wrap class WeakArrayBodyComponentPtr.
-static inline void wrapWeakArrayBodyComponentPtr(lua_State* l)
-{
-	LuaBinder::createClass(l, &luaUserDataTypeInfoWeakArrayBodyComponentPtr);
-	LuaBinder::pushLuaCFuncMethod(l, "getSize", wrapWeakArrayBodyComponentPtrgetSize);
-	LuaBinder::pushLuaCFuncMethod(l, "getAt", wrapWeakArrayBodyComponentPtrgetAt);
-	lua_settop(l, 0);
-}
-
-LuaUserDataTypeInfo luaUserDataTypeInfoLightComponent = {-5271648520904895104, "LightComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoLightComponent = {1627842491458315331, "LightComponent",
 														 LuaUserData::computeSizeForGarbageCollected<LightComponent>(), nullptr, nullptr};
 
 template<>
@@ -945,7 +869,7 @@ static inline void wrapLightComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoDecalComponent = {5995036315092354567, "DecalComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoDecalComponent = {1156947010128629167, "DecalComponent",
 														 LuaUserData::computeSizeForGarbageCollected<DecalComponent>(), nullptr, nullptr};
 
 template<>
@@ -1117,7 +1041,7 @@ static inline void wrapDecalComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLensFlareComponent = {3035215901600321039, "LensFlareComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoLensFlareComponent = {-6804037317475103760, "LensFlareComponent",
 															 LuaUserData::computeSizeForGarbageCollected<LensFlareComponent>(), nullptr, nullptr};
 
 template<>
@@ -1280,7 +1204,7 @@ static inline void wrapLensFlareComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponent = {-9159963251664499177, "BodyComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponent = {-6173350858840068269, "BodyComponent",
 														LuaUserData::computeSizeForGarbageCollected<BodyComponent>(), nullptr, nullptr};
 
 template<>
@@ -1289,8 +1213,8 @@ const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<BodyComponent>()
 	return luaUserDataTypeInfoBodyComponent;
 }
 
-/// Pre-wrap method BodyComponent::loadMeshResource.
-static inline int pwrapBodyComponentloadMeshResource(lua_State* l)
+/// Pre-wrap method BodyComponent::setCollisionShapeType.
+static inline int pwrapBodyComponentsetCollisionShapeType(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
@@ -1310,22 +1234,23 @@ static inline int pwrapBodyComponentloadMeshResource(lua_State* l)
 	BodyComponent* self = ud->getData<BodyComponent>();
 
 	// Pop arguments
-	const char* arg0;
-	if(LuaBinder::checkString(l, 2, arg0)) [[unlikely]]
+	lua_Number arg0Tmp;
+	if(LuaBinder::checkNumber(l, 2, arg0Tmp)) [[unlikely]]
 	{
 		return -1;
 	}
+	const BodyComponentCollisionShapeType arg0 = BodyComponentCollisionShapeType(arg0Tmp);
 
 	// Call the method
-	self->loadMeshResource(arg0);
+	self->setCollisionShapeType(arg0);
 
 	return 0;
 }
 
-/// Wrap method BodyComponent::loadMeshResource.
-static int wrapBodyComponentloadMeshResource(lua_State* l)
+/// Wrap method BodyComponent::setCollisionShapeType.
+static int wrapBodyComponentsetCollisionShapeType(lua_State* l)
 {
-	int res = pwrapBodyComponentloadMeshResource(l);
+	int res = pwrapBodyComponentsetCollisionShapeType(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1335,14 +1260,14 @@ static int wrapBodyComponentloadMeshResource(lua_State* l)
 	return 0;
 }
 
-/// Pre-wrap method BodyComponent::setMeshFromModelComponent.
-static inline int pwrapBodyComponentsetMeshFromModelComponent(lua_State* l)
+/// Pre-wrap method BodyComponent::setBoxExtend.
+static inline int pwrapBodyComponentsetBoxExtend(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
 	[[maybe_unused]] PtrSize size;
 
-	if(LuaBinder::checkArgsCount(l, 1)) [[unlikely]]
+	if(LuaBinder::checkArgsCount(l, 2)) [[unlikely]]
 	{
 		return -1;
 	}
@@ -1355,16 +1280,26 @@ static inline int pwrapBodyComponentsetMeshFromModelComponent(lua_State* l)
 
 	BodyComponent* self = ud->getData<BodyComponent>();
 
+	// Pop arguments
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoVec3;
+	if(LuaBinder::checkUserData(l, 2, luaUserDataTypeInfoVec3, ud)) [[unlikely]]
+	{
+		return -1;
+	}
+
+	Vec3* iarg0 = ud->getData<Vec3>();
+	Vec3 arg0(*iarg0);
+
 	// Call the method
-	self->setMeshFromModelComponent();
+	self->setBoxExtend(arg0);
 
 	return 0;
 }
 
-/// Wrap method BodyComponent::setMeshFromModelComponent.
-static int wrapBodyComponentsetMeshFromModelComponent(lua_State* l)
+/// Wrap method BodyComponent::setBoxExtend.
+static int wrapBodyComponentsetBoxExtend(lua_State* l)
 {
-	int res = pwrapBodyComponentsetMeshFromModelComponent(l);
+	int res = pwrapBodyComponentsetBoxExtend(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1374,8 +1309,54 @@ static int wrapBodyComponentsetMeshFromModelComponent(lua_State* l)
 	return 0;
 }
 
-/// Pre-wrap method BodyComponent::teleportTo.
-static inline int pwrapBodyComponentteleportTo(lua_State* l)
+/// Pre-wrap method BodyComponent::getBoxExtend.
+static inline int pwrapBodyComponentgetBoxExtend(lua_State* l)
+{
+	[[maybe_unused]] LuaUserData* ud;
+	[[maybe_unused]] void* voidp;
+	[[maybe_unused]] PtrSize size;
+
+	if(LuaBinder::checkArgsCount(l, 1)) [[unlikely]]
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoBodyComponent, ud))
+	{
+		return -1;
+	}
+
+	BodyComponent* self = ud->getData<BodyComponent>();
+
+	// Call the method
+	const Vec3& ret = self->getBoxExtend();
+
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(LuaUserData));
+	ud = static_cast<LuaUserData*>(voidp);
+	luaL_setmetatable(l, "Vec3");
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoVec3;
+	ud->initPointed(&luaUserDataTypeInfoVec3, &ret);
+
+	return 1;
+}
+
+/// Wrap method BodyComponent::getBoxExtend.
+static int wrapBodyComponentgetBoxExtend(lua_State* l)
+{
+	int res = pwrapBodyComponentgetBoxExtend(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Pre-wrap method BodyComponent::setSphereRadius.
+static inline int pwrapBodyComponentsetSphereRadius(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
@@ -1395,25 +1376,22 @@ static inline int pwrapBodyComponentteleportTo(lua_State* l)
 	BodyComponent* self = ud->getData<BodyComponent>();
 
 	// Pop arguments
-	extern LuaUserDataTypeInfo luaUserDataTypeInfoTransform;
-	if(LuaBinder::checkUserData(l, 2, luaUserDataTypeInfoTransform, ud)) [[unlikely]]
+	F32 arg0;
+	if(LuaBinder::checkNumber(l, 2, arg0)) [[unlikely]]
 	{
 		return -1;
 	}
 
-	Transform* iarg0 = ud->getData<Transform>();
-	const Transform& arg0(*iarg0);
-
 	// Call the method
-	self->teleportTo(arg0);
+	self->setSphereRadius(arg0);
 
 	return 0;
 }
 
-/// Wrap method BodyComponent::teleportTo.
-static int wrapBodyComponentteleportTo(lua_State* l)
+/// Wrap method BodyComponent::setSphereRadius.
+static int wrapBodyComponentsetSphereRadius(lua_State* l)
 {
-	int res = pwrapBodyComponentteleportTo(l);
+	int res = pwrapBodyComponentsetSphereRadius(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1423,64 +1401,88 @@ static int wrapBodyComponentteleportTo(lua_State* l)
 	return 0;
 }
 
-/// Wrap class BodyComponent.
-static inline void wrapBodyComponent(lua_State* l)
+/// Pre-wrap method BodyComponent::getSphereRadius.
+static inline int pwrapBodyComponentgetSphereRadius(lua_State* l)
 {
-	LuaBinder::createClass(l, &luaUserDataTypeInfoBodyComponent);
-	LuaBinder::pushLuaCFuncMethod(l, "loadMeshResource", wrapBodyComponentloadMeshResource);
-	LuaBinder::pushLuaCFuncMethod(l, "setMeshFromModelComponent", wrapBodyComponentsetMeshFromModelComponent);
-	LuaBinder::pushLuaCFuncMethod(l, "teleportTo", wrapBodyComponentteleportTo);
-	lua_settop(l, 0);
-}
+	[[maybe_unused]] LuaUserData* ud;
+	[[maybe_unused]] void* voidp;
+	[[maybe_unused]] PtrSize size;
 
-LuaUserDataTypeInfo luaUserDataTypeInfoTriggerComponent = {-7425360375740373469, "TriggerComponent",
-														   LuaUserData::computeSizeForGarbageCollected<TriggerComponent>(), nullptr, nullptr};
+	if(LuaBinder::checkArgsCount(l, 1)) [[unlikely]]
+	{
+		return -1;
+	}
 
-template<>
-const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<TriggerComponent>()
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoBodyComponent, ud))
+	{
+		return -1;
+	}
+
+	BodyComponent* self = ud->getData<BodyComponent>();
+
+	// Call the method
+	F32 ret = self->getSphereRadius();
+
+	// Push return value
+	lua_pushnumber(l, lua_Number(ret));
+
+	return 1;
+}
+
+/// Wrap method BodyComponent::getSphereRadius.
+static int wrapBodyComponentgetSphereRadius(lua_State* l)
 {
-	return luaUserDataTypeInfoTriggerComponent;
+	int res = pwrapBodyComponentgetSphereRadius(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
 }
 
-/// Pre-wrap method TriggerComponent::getBodyComponentsEnter.
-static inline int pwrapTriggerComponentgetBodyComponentsEnter(lua_State* l)
+/// Pre-wrap method BodyComponent::teleportTo.
+static inline int pwrapBodyComponentteleportTo(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
 	[[maybe_unused]] PtrSize size;
 
-	if(LuaBinder::checkArgsCount(l, 1)) [[unlikely]]
+	if(LuaBinder::checkArgsCount(l, 2)) [[unlikely]]
 	{
 		return -1;
 	}
 
 	// Get "this" as "self"
-	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoTriggerComponent, ud))
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoBodyComponent, ud))
 	{
 		return -1;
 	}
 
-	TriggerComponent* self = ud->getData<TriggerComponent>();
+	BodyComponent* self = ud->getData<BodyComponent>();
 
-	// Call the method
-	WeakArrayBodyComponentPtr ret = self->getBodyComponentsEnter();
+	// Pop arguments
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoTransform;
+	if(LuaBinder::checkUserData(l, 2, luaUserDataTypeInfoTransform, ud)) [[unlikely]]
+	{
+		return -1;
+	}
 
-	// Push return value
-	size = LuaUserData::computeSizeForGarbageCollected<WeakArrayBodyComponentPtr>();
-	voidp = lua_newuserdata(l, size);
-	luaL_setmetatable(l, "WeakArrayBodyComponentPtr");
-	ud = static_cast<LuaUserData*>(voidp);
-	extern LuaUserDataTypeInfo luaUserDataTypeInfoWeakArrayBodyComponentPtr;
-	ud->initGarbageCollected(&luaUserDataTypeInfoWeakArrayBodyComponentPtr);
-	::new(ud->getData<WeakArrayBodyComponentPtr>()) WeakArrayBodyComponentPtr(std::move(ret));
+	Transform* iarg0 = ud->getData<Transform>();
+	const Transform& arg0(*iarg0);
 
-	return 1;
+	// Call the method
+	self->teleportTo(arg0);
+
+	return 0;
 }
 
-/// Wrap method TriggerComponent::getBodyComponentsEnter.
-static int wrapTriggerComponentgetBodyComponentsEnter(lua_State* l)
+/// Wrap method BodyComponent::teleportTo.
+static int wrapBodyComponentteleportTo(lua_State* l)
 {
-	int res = pwrapTriggerComponentgetBodyComponentsEnter(l);
+	int res = pwrapBodyComponentteleportTo(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1490,8 +1492,30 @@ static int wrapTriggerComponentgetBodyComponentsEnter(lua_State* l)
 	return 0;
 }
 
-/// Pre-wrap method TriggerComponent::getBodyComponentsInside.
-static inline int pwrapTriggerComponentgetBodyComponentsInside(lua_State* l)
+/// Wrap class BodyComponent.
+static inline void wrapBodyComponent(lua_State* l)
+{
+	LuaBinder::createClass(l, &luaUserDataTypeInfoBodyComponent);
+	LuaBinder::pushLuaCFuncMethod(l, "setCollisionShapeType", wrapBodyComponentsetCollisionShapeType);
+	LuaBinder::pushLuaCFuncMethod(l, "setBoxExtend", wrapBodyComponentsetBoxExtend);
+	LuaBinder::pushLuaCFuncMethod(l, "getBoxExtend", wrapBodyComponentgetBoxExtend);
+	LuaBinder::pushLuaCFuncMethod(l, "setSphereRadius", wrapBodyComponentsetSphereRadius);
+	LuaBinder::pushLuaCFuncMethod(l, "getSphereRadius", wrapBodyComponentgetSphereRadius);
+	LuaBinder::pushLuaCFuncMethod(l, "teleportTo", wrapBodyComponentteleportTo);
+	lua_settop(l, 0);
+}
+
+LuaUserDataTypeInfo luaUserDataTypeInfoTriggerComponent = {5790819453583864773, "TriggerComponent",
+														   LuaUserData::computeSizeForGarbageCollected<TriggerComponent>(), nullptr, nullptr};
+
+template<>
+const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<TriggerComponent>()
+{
+	return luaUserDataTypeInfoTriggerComponent;
+}
+
+/// Pre-wrap method TriggerComponent::getSceneNodesEnter.
+static inline int pwrapTriggerComponentgetSceneNodesEnter(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
@@ -1511,24 +1535,24 @@ static inline int pwrapTriggerComponentgetBodyComponentsInside(lua_State* l)
 	TriggerComponent* self = ud->getData<TriggerComponent>();
 
 	// Call the method
-	WeakArrayBodyComponentPtr ret = self->getBodyComponentsInside();
+	WeakArraySceneNodePtr ret = self->getSceneNodesEnter();
 
 	// Push return value
-	size = LuaUserData::computeSizeForGarbageCollected<WeakArrayBodyComponentPtr>();
+	size = LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>();
 	voidp = lua_newuserdata(l, size);
-	luaL_setmetatable(l, "WeakArrayBodyComponentPtr");
+	luaL_setmetatable(l, "WeakArraySceneNodePtr");
 	ud = static_cast<LuaUserData*>(voidp);
-	extern LuaUserDataTypeInfo luaUserDataTypeInfoWeakArrayBodyComponentPtr;
-	ud->initGarbageCollected(&luaUserDataTypeInfoWeakArrayBodyComponentPtr);
-	::new(ud->getData<WeakArrayBodyComponentPtr>()) WeakArrayBodyComponentPtr(std::move(ret));
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoWeakArraySceneNodePtr;
+	ud->initGarbageCollected(&luaUserDataTypeInfoWeakArraySceneNodePtr);
+	::new(ud->getData<WeakArraySceneNodePtr>()) WeakArraySceneNodePtr(std::move(ret));
 
 	return 1;
 }
 
-/// Wrap method TriggerComponent::getBodyComponentsInside.
-static int wrapTriggerComponentgetBodyComponentsInside(lua_State* l)
+/// Wrap method TriggerComponent::getSceneNodesEnter.
+static int wrapTriggerComponentgetSceneNodesEnter(lua_State* l)
 {
-	int res = pwrapTriggerComponentgetBodyComponentsInside(l);
+	int res = pwrapTriggerComponentgetSceneNodesEnter(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1538,8 +1562,8 @@ static int wrapTriggerComponentgetBodyComponentsInside(lua_State* l)
 	return 0;
 }
 
-/// Pre-wrap method TriggerComponent::getBodyComponentsExit.
-static inline int pwrapTriggerComponentgetBodyComponentsExit(lua_State* l)
+/// Pre-wrap method TriggerComponent::getSceneNodesExit.
+static inline int pwrapTriggerComponentgetSceneNodesExit(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
@@ -1559,24 +1583,24 @@ static inline int pwrapTriggerComponentgetBodyComponentsExit(lua_State* l)
 	TriggerComponent* self = ud->getData<TriggerComponent>();
 
 	// Call the method
-	WeakArrayBodyComponentPtr ret = self->getBodyComponentsExit();
+	WeakArraySceneNodePtr ret = self->getSceneNodesExit();
 
 	// Push return value
-	size = LuaUserData::computeSizeForGarbageCollected<WeakArrayBodyComponentPtr>();
+	size = LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>();
 	voidp = lua_newuserdata(l, size);
-	luaL_setmetatable(l, "WeakArrayBodyComponentPtr");
+	luaL_setmetatable(l, "WeakArraySceneNodePtr");
 	ud = static_cast<LuaUserData*>(voidp);
-	extern LuaUserDataTypeInfo luaUserDataTypeInfoWeakArrayBodyComponentPtr;
-	ud->initGarbageCollected(&luaUserDataTypeInfoWeakArrayBodyComponentPtr);
-	::new(ud->getData<WeakArrayBodyComponentPtr>()) WeakArrayBodyComponentPtr(std::move(ret));
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoWeakArraySceneNodePtr;
+	ud->initGarbageCollected(&luaUserDataTypeInfoWeakArraySceneNodePtr);
+	::new(ud->getData<WeakArraySceneNodePtr>()) WeakArraySceneNodePtr(std::move(ret));
 
 	return 1;
 }
 
-/// Wrap method TriggerComponent::getBodyComponentsExit.
-static int wrapTriggerComponentgetBodyComponentsExit(lua_State* l)
+/// Wrap method TriggerComponent::getSceneNodesExit.
+static int wrapTriggerComponentgetSceneNodesExit(lua_State* l)
 {
-	int res = pwrapTriggerComponentgetBodyComponentsExit(l);
+	int res = pwrapTriggerComponentgetSceneNodesExit(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1590,13 +1614,12 @@ static int wrapTriggerComponentgetBodyComponentsExit(lua_State* l)
 static inline void wrapTriggerComponent(lua_State* l)
 {
 	LuaBinder::createClass(l, &luaUserDataTypeInfoTriggerComponent);
-	LuaBinder::pushLuaCFuncMethod(l, "getBodyComponentsEnter", wrapTriggerComponentgetBodyComponentsEnter);
-	LuaBinder::pushLuaCFuncMethod(l, "getBodyComponentsInside", wrapTriggerComponentgetBodyComponentsInside);
-	LuaBinder::pushLuaCFuncMethod(l, "getBodyComponentsExit", wrapTriggerComponentgetBodyComponentsExit);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodesEnter", wrapTriggerComponentgetSceneNodesEnter);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodesExit", wrapTriggerComponentgetSceneNodesExit);
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityComponent = {-449397768782810738, "FogDensityComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityComponent = {-99769539089360673, "FogDensityComponent",
 															  LuaUserData::computeSizeForGarbageCollected<FogDensityComponent>(), nullptr, nullptr};
 
 template<>
@@ -1799,7 +1822,7 @@ static inline void wrapFogDensityComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoCameraComponent = {8960080176973402871, "CameraComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoCameraComponent = {-68521109795181851, "CameraComponent",
 														  LuaUserData::computeSizeForGarbageCollected<CameraComponent>(), nullptr, nullptr};
 
 template<>
@@ -1881,8 +1904,8 @@ static inline void wrapCameraComponent(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoGlobalIlluminationProbeComponent = {
-	3424589126774403182, "GlobalIlluminationProbeComponent", LuaUserData::computeSizeForGarbageCollected<GlobalIlluminationProbeComponent>(), nullptr,
-	nullptr};
+	-8940003758257335788, "GlobalIlluminationProbeComponent", LuaUserData::computeSizeForGarbageCollected<GlobalIlluminationProbeComponent>(),
+	nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<GlobalIlluminationProbeComponent>()
@@ -2128,7 +2151,7 @@ static inline void wrapGlobalIlluminationProbeComponent(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoReflectionProbeComponent = {
-	-6758135295013264798, "ReflectionProbeComponent", LuaUserData::computeSizeForGarbageCollected<ReflectionProbeComponent>(), nullptr, nullptr};
+	-111826572912818668, "ReflectionProbeComponent", LuaUserData::computeSizeForGarbageCollected<ReflectionProbeComponent>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ReflectionProbeComponent>()
@@ -2243,7 +2266,7 @@ static inline void wrapReflectionProbeComponent(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoParticleEmitterComponent = {
-	5706885704346443564, "ParticleEmitterComponent", LuaUserData::computeSizeForGarbageCollected<ParticleEmitterComponent>(), nullptr, nullptr};
+	3350524044897346812, "ParticleEmitterComponent", LuaUserData::computeSizeForGarbageCollected<ParticleEmitterComponent>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ParticleEmitterComponent>()
@@ -2305,7 +2328,7 @@ static inline void wrapParticleEmitterComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoModelComponent = {97249979289646973, "ModelComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoModelComponent = {-9059782793959299070, "ModelComponent",
 														 LuaUserData::computeSizeForGarbageCollected<ModelComponent>(), nullptr, nullptr};
 
 template<>
@@ -2368,7 +2391,7 @@ static inline void wrapModelComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSkinComponent = {-7585993549028037320, "SkinComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoSkinComponent = {5797775506072060908, "SkinComponent",
 														LuaUserData::computeSizeForGarbageCollected<SkinComponent>(), nullptr, nullptr};
 
 template<>
@@ -2431,7 +2454,7 @@ static inline void wrapSkinComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSkyboxComponent = {-6878543670401624158, "SkyboxComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoSkyboxComponent = {-3942881413516893543, "SkyboxComponent",
 														  LuaUserData::computeSizeForGarbageCollected<SkyboxComponent>(), nullptr, nullptr};
 
 template<>
@@ -2922,7 +2945,7 @@ static inline void wrapSkyboxComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {-1295485195147561206, "SceneNode", LuaUserData::computeSizeForGarbageCollected<SceneNode>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {-3261474765783124766, "SceneNode", LuaUserData::computeSizeForGarbageCollected<SceneNode>(),
 													nullptr, nullptr};
 
 template<>
@@ -4759,7 +4782,7 @@ static inline void wrapSceneNode(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {-7805560184770748431, "SceneGraph", LuaUserData::computeSizeForGarbageCollected<SceneGraph>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {2311127321533935429, "SceneGraph", LuaUserData::computeSizeForGarbageCollected<SceneGraph>(),
 													 nullptr, nullptr};
 
 template<>
@@ -4945,7 +4968,7 @@ static inline void wrapSceneGraph(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoEvent = {-6825970229082400759, "Event", LuaUserData::computeSizeForGarbageCollected<Event>(), nullptr,
+LuaUserDataTypeInfo luaUserDataTypeInfoEvent = {-4718494666009094294, "Event", LuaUserData::computeSizeForGarbageCollected<Event>(), nullptr,
 												nullptr};
 
 template<>
@@ -5010,7 +5033,7 @@ static inline void wrapEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLightEvent = {-2438111026101797635, "LightEvent", LuaUserData::computeSizeForGarbageCollected<LightEvent>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoLightEvent = {8360443534716675988, "LightEvent", LuaUserData::computeSizeForGarbageCollected<LightEvent>(),
 													 nullptr, nullptr};
 
 template<>
@@ -5129,7 +5152,7 @@ static inline void wrapLightEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoScriptEvent = {5136611228223914887, "ScriptEvent", LuaUserData::computeSizeForGarbageCollected<ScriptEvent>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoScriptEvent = {-5828444576659958894, "ScriptEvent", LuaUserData::computeSizeForGarbageCollected<ScriptEvent>(),
 													  nullptr, nullptr};
 
 template<>
@@ -5145,7 +5168,7 @@ static inline void wrapScriptEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoJitterMoveEvent = {-4365713583592201088, "JitterMoveEvent",
+LuaUserDataTypeInfo luaUserDataTypeInfoJitterMoveEvent = {-1382509976775521529, "JitterMoveEvent",
 														  LuaUserData::computeSizeForGarbageCollected<JitterMoveEvent>(), nullptr, nullptr};
 
 template<>
@@ -5220,7 +5243,7 @@ static inline void wrapJitterMoveEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoAnimationEvent = {4765740095150022724, "AnimationEvent",
+LuaUserDataTypeInfo luaUserDataTypeInfoAnimationEvent = {-7656461176932586107, "AnimationEvent",
 														 LuaUserData::computeSizeForGarbageCollected<AnimationEvent>(), nullptr, nullptr};
 
 template<>
@@ -5236,7 +5259,7 @@ static inline void wrapAnimationEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoEventManager = {8040133071572423967, "EventManager",
+LuaUserDataTypeInfo luaUserDataTypeInfoEventManager = {-1263917656658635236, "EventManager",
 													   LuaUserData::computeSizeForGarbageCollected<EventManager>(), nullptr, nullptr};
 
 template<>
@@ -5641,7 +5664,6 @@ static int wrapgetEventManager(lua_State* l)
 void wrapModuleScene(lua_State* l)
 {
 	wrapWeakArraySceneNodePtr(l);
-	wrapWeakArrayBodyComponentPtr(l);
 	wrapLightComponent(l);
 	wrapDecalComponent(l);
 	wrapLensFlareComponent(l);
@@ -5666,6 +5688,7 @@ void wrapModuleScene(lua_State* l)
 	LuaBinder::pushLuaCFunc(l, "getSceneGraph", wrapgetSceneGraph);
 	LuaBinder::pushLuaCFunc(l, "getEventManager", wrapgetEventManager);
 	wrapLightComponentType(l);
+	wrapBodyComponentCollisionShapeType(l);
 }
 
 } // end namespace anki

+ 31 - 24
AnKi/Script/Scene.xml

@@ -60,7 +60,6 @@ static EventManager* getEventManager(lua_State* l)
 }
 
 using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
-using WeakArrayBodyComponentPtr = WeakArray<BodyComponent*>;
 ]]></head>
 
 	<enums>
@@ -71,6 +70,15 @@ using WeakArrayBodyComponentPtr = WeakArray<BodyComponent*>;
 		</enum>
 	</enums>
 
+	<enums>
+		<enum name="BodyComponentCollisionShapeType">
+			<enumerant name="kFromModelComponent"/>
+			<enumerant name="kAabb"/>
+			<enumerant name="kSphere"/>
+			<enumerant name="kCount"/>
+		</enum>
+	</enums>
+
 	<classes>
 		<!-- Other -->
 		<class name="WeakArraySceneNodePtr">
@@ -86,19 +94,6 @@ using WeakArrayBodyComponentPtr = WeakArray<BodyComponent*>;
 			</methods>
 		</class>
 
-		<class name="WeakArrayBodyComponentPtr">
-			<methods>
-				<method name="getSize">
-					<return>U32</return>
-				</method>
-				<method name="getAt">
-					<overrideCall><![CDATA[BodyComponent* ret = (*self)[arg0];]]></overrideCall>
-					<args><arg>U32</arg></args>
-					<return>BodyComponent*</return>
-				</method>
-			</methods>
-		</class>
-
 		<!-- Components -->
 		<class name="LightComponent">
 			<methods>
@@ -202,12 +197,27 @@ using WeakArrayBodyComponentPtr = WeakArray<BodyComponent*>;
 
 		<class name="BodyComponent">
 			<methods>
-				<method name="loadMeshResource">
+				<method name="setCollisionShapeType">
 					<args>
-						<arg>CString</arg>
+						<arg>BodyComponentCollisionShapeType</arg>
+					</args>
+				</method>
+				<method name="setBoxExtend">
+					<args>
+						<arg>Vec3</arg>
 					</args>
 				</method>
-				<method name="setMeshFromModelComponent"></method>
+				<method name="getBoxExtend">
+					<return>const Vec3&amp;</return>
+				</method>
+				<method name="setSphereRadius">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="getSphereRadius">
+					<return>F32</return>
+				</method>
 				<method name="teleportTo">
 					<args>
 						<arg>const Transform&amp;</arg>
@@ -218,14 +228,11 @@ using WeakArrayBodyComponentPtr = WeakArray<BodyComponent*>;
 
 		<class name="TriggerComponent">
 			<methods>
-				<method name="getBodyComponentsEnter">
-					<return>WeakArrayBodyComponentPtr</return>
-				</method>
-				<method name="getBodyComponentsInside">
-					<return>WeakArrayBodyComponentPtr</return>
+				<method name="getSceneNodesEnter">
+					<return>WeakArraySceneNodePtr</return>
 				</method>
-				<method name="getBodyComponentsExit">
-					<return>WeakArrayBodyComponentPtr</return>
+				<method name="getSceneNodesExit">
+					<return>WeakArraySceneNodePtr</return>
 				</method>
 			</methods>
 		</class>

+ 277 - 0
AnKi/Shaders/Dbg.ankiprog

@@ -0,0 +1,277 @@
+// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma anki mutator DEPTH_FAIL_VISUALIZATION 0 1
+#pragma anki mutator OBJECT_TYPE 0 1 2 3 4 // Same as GpuSceneNonRenderableObjectType
+
+#pragma anki technique Renderables vert pixel mutators DEPTH_FAIL_VISUALIZATION
+#pragma anki technique Bilboards vert pixel
+#pragma anki technique Lines vert pixel mutators DEPTH_FAIL_VISUALIZATION
+
+#include <AnKi/Shaders/Common.hlsl>
+
+// ===========================================================================
+// Renderables                                                               =
+// ===========================================================================
+#if NOT_ZERO(ANKI_TECHNIQUE_Renderables)
+#	include <AnKi/Shaders/Include/GpuSceneTypes.h>
+
+struct Constants
+{
+	Vec4 m_color;
+	Mat4 m_viewProjMat;
+};
+
+ANKI_FAST_CONSTANTS(Constants, g_consts)
+
+StructuredBuffer<GpuSceneRenderableBoundingVolume> g_renderableBoundingVolumes : register(t1);
+StructuredBuffer<U32> g_visibleRenderableBoundingVolumeIndices : register(t2);
+
+struct VertOut
+{
+	Vec4 m_svPosition : SV_POSITION;
+};
+
+struct VertIn
+{
+	Vec3 m_position : POSITION;
+	U32 m_svInstanceId : SV_INSTANCEID;
+};
+
+#	if ANKI_VERTEX_SHADER
+VertOut main(VertIn input)
+{
+	VertOut output;
+
+	const U32 bvolumeCount = g_visibleRenderableBoundingVolumeIndices[0];
+
+	if(input.m_svInstanceId < bvolumeCount)
+	{
+		const GpuSceneRenderableBoundingVolume bvol = g_renderableBoundingVolumes[g_visibleRenderableBoundingVolumeIndices[input.m_svInstanceId + 1]];
+		const Vec3 boxCenter = (bvol.m_aabbMin + bvol.m_aabbMax) * 0.5f;
+		Vec3 localPos = input.m_position * (bvol.m_aabbMax - boxCenter) + boxCenter;
+		output.m_svPosition = mul(g_consts.m_viewProjMat, Vec4(localPos, 1.0));
+	}
+	else
+	{
+		// Skip this instance by making the vertex degenerate
+		output.m_svPosition = 0.0f;
+	}
+
+	return output;
+}
+#	endif // ANKI_VERTEX_SHADER
+
+#	if ANKI_PIXEL_SHADER
+#		include <AnKi/Shaders/ImportanceSampling.hlsl>
+
+// NOTE: Don't eliminate the binding because it confuses the descriptor set creation
+#		if DEPTH_FAIL_VISUALIZATION == 1
+SamplerState g_nearestAnyClampSampler : register(s0);
+Texture2D g_depthRt : register(t0);
+#		endif
+
+Vec4 main(VertOut input) : SV_TARGET0
+{
+	ANKI_MAYBE_UNUSED(input);
+
+	// Check if we should skip the frag
+#		if DEPTH_FAIL_VISUALIZATION == 1
+	Vec2 texSize;
+	g_depthRt.GetDimensions(texSize.x, texSize.y);
+	const Vec2 uv = input.m_svPosition.xy / texSize;
+	const F32 depthRef = g_depthRt.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
+	const Bool depthTestFailed = input.m_svPosition.z >= depthRef;
+	if(depthTestFailed)
+	{
+		return g_consts.m_color * 0.5;
+	}
+#		endif
+
+	// Write the color
+	return g_consts.m_color;
+}
+#	endif // ANKI_PIXEL_SHADER
+#endif // ANKI_TECHNIQUE_Renderables
+
+// ===========================================================================
+// Bilboards                                                                 =
+// ===========================================================================
+#if NOT_ZERO(ANKI_TECHNIQUE_Bilboards)
+#	include <AnKi/Shaders/ClusteredShadingFunctions.hlsl>
+#	include <AnKi/Shaders/TonemappingFunctions.hlsl>
+
+constexpr F32 kAlpha = 1.0f;
+constexpr F32 kBillboardScale = 0.25f;
+
+struct Constants
+{
+	Mat4 m_viewProjMat;
+	Mat3x4 m_camTrf;
+};
+
+ANKI_FAST_CONSTANTS(Constants, g_consts)
+
+#	if OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_LIGHT
+typedef LightUnion ClusteredType;
+#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_DECAL
+typedef Decal ClusteredType;
+#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_FOG_DENSITY_VOLUME
+typedef FogDensityVolume ClusteredType;
+#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_REFLECTION_PROBE
+typedef ReflectionProbe ClusteredType;
+#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_GLOBAL_ILLUMINATION_PROBE
+typedef GlobalIlluminationProbe ClusteredType;
+#	else
+#		error See file
+#	endif
+
+StructuredBuffer<ClusteredType> g_visibleObjects : register(t1);
+StructuredBuffer<U32> g_visibleObjectCount : register(t2);
+
+struct VertOut
+{
+	Vec4 m_svPosition : SV_POSITION;
+	Vec2 m_uv : TEXCOORD;
+	Vec4 m_colorScale : COLOR;
+	nointerpolation U32 m_textureIndex : TEX_INDEX;
+};
+
+struct VertIn
+{
+	U32 m_svInstanceId : SV_INSTANCEID;
+	U32 m_svVertexId : SV_VERTEXID;
+};
+
+#	if ANKI_VERTEX_SHADER
+VertOut main(VertIn input)
+{
+	VertOut output;
+
+	output.m_colorScale = Vec4(1.0f, 1.0f, 1.0f, kAlpha);
+	output.m_textureIndex = 0;
+
+	output.m_uv = Vec2(input.m_svVertexId & 1u, ((input.m_svVertexId + 1u) / 3u) & 1u);
+
+	const U32 objCount = g_visibleObjectCount[0];
+
+	if(input.m_svInstanceId < objCount)
+	{
+#		if OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_LIGHT
+		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_position;
+		output.m_colorScale.xyz = reinhardTonemap(g_visibleObjects[input.m_svInstanceId].m_diffuseColor);
+		output.m_textureIndex = g_visibleObjects[input.m_svInstanceId].m_lightType;
+#		elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_DECAL
+		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_sphereCenter;
+#		elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_FOG_DENSITY_VOLUME
+		const ClusteredType obj = g_visibleObjects[input.m_svInstanceId];
+		const Vec3 localPos = (obj.m_isBox) ? (obj.m_aabbMinOrSphereCenter + obj.m_aabbMaxOrSphereRadius) / 2.0f : obj.m_aabbMinOrSphereCenter;
+#		elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_REFLECTION_PROBE
+		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_position;
+#		elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_GLOBAL_ILLUMINATION_PROBE
+		const Vec3 localPos = (g_visibleObjects[input.m_svInstanceId].m_aabbMin + g_visibleObjects[input.m_svInstanceId].m_aabbMax) / 2.0f;
+#		else
+#			error See file
+#		endif
+
+		// Rotate towards the camera and apply translation
+		const Vec3 worldPos = mul(g_consts.m_camTrf, Vec4((output.m_uv * 2.0 - 1.0) * kBillboardScale, 0.0, 0.0)) + localPos;
+
+		output.m_svPosition = mul(g_consts.m_viewProjMat, Vec4(worldPos, 1.0));
+	}
+	else
+	{
+		// Skip this instance by making the vertex degenerate
+		output.m_svPosition = 0.0f;
+	}
+
+	return output;
+}
+#	endif // ANKI_VERTEX_SHADER
+
+#	if ANKI_PIXEL_SHADER
+#		include <AnKi/Shaders/ImportanceSampling.hlsl>
+
+SamplerState g_trilinearRepeatSampler : register(s1);
+Texture2D<Vec4> g_tex : register(t3);
+Texture2D<Vec4> g_tex2 : register(t4);
+
+// NOTE: Don't eliminate the binding because it confuses the descriptor set creation
+#		if DEPTH_FAIL_VISUALIZATION == 1
+SamplerState g_nearestAnyClampSampler : register(s0);
+Texture2D g_depthRt : register(t0);
+#		endif
+
+Vec4 main(VertOut input) : SV_TARGET0
+{
+	ANKI_MAYBE_UNUSED(input);
+
+	// Check if we should skip the frag
+	F32 colorFactor = 1.0f;
+#		if DEPTH_FAIL_VISUALIZATION == 1
+	Vec2 texSize;
+	g_depthRt.GetDimensions(texSize.x, texSize.y);
+	const Vec2 uv = input.m_svPosition.xy / texSize;
+	const F32 depthRef = g_depthRt.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
+	const Bool depthTestFailed = input.m_svPosition.z >= depthRef;
+	if(depthTestFailed)
+	{
+		colorFactor = 0.6;
+	}
+#		endif
+
+	// Write the color
+	if(input.m_textureIndex == 0)
+	{
+		return g_tex.Sample(g_trilinearRepeatSampler, input.m_uv) * input.m_colorScale * colorFactor;
+	}
+	else
+	{
+		return g_tex2.Sample(g_trilinearRepeatSampler, input.m_uv) * input.m_colorScale * colorFactor;
+	}
+}
+#	endif // ANKI_PIXEL_SHADER
+#endif // ANKI_TECHNIQUE_Bilboards
+
+// ===========================================================================
+// Lines                                                                     =
+// ===========================================================================
+#if NOT_ZERO(ANKI_TECHNIQUE_Lines)
+
+struct VertIn
+{
+	Vec3 m_position : POSITION;
+	Vec4 m_color : COLOR;
+};
+
+struct VertOut
+{
+	Vec4 m_svPosition : SV_Position;
+	Vec4 m_color : COLOR;
+};
+
+struct Constants
+{
+	Mat4 m_viewProjMatrix;
+};
+ANKI_FAST_CONSTANTS(Constants, g_consts);
+
+#	if ANKI_VERTEX_SHADER
+VertOut main(VertIn input)
+{
+	VertOut output;
+	output.m_svPosition = mul(g_consts.m_viewProjMatrix, Vec4(input.m_position, 1.0));
+	output.m_color = input.m_color;
+	return output;
+}
+#	endif // ANKI_VERTEX_SHADER
+
+#	if ANKI_PIXEL_SHADER
+Vec4 main(VertOut input) : SV_Target0
+{
+	return input.m_color;
+}
+#	endif // ANKI_PIXEL_SHADER
+#endif // ANKI_TECHNIQUE_Lines

+ 0 - 144
AnKi/Shaders/DbgBillboard.ankiprog

@@ -1,144 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki mutator DEPTH_FAIL_VISUALIZATION 0 1
-#pragma anki mutator OBJECT_TYPE 0 1 2 3 4 // Same as GpuSceneNonRenderableObjectType
-
-#pragma anki technique vert pixel
-
-#include <AnKi/Shaders/Common.hlsl>
-#include <AnKi/Shaders/ClusteredShadingFunctions.hlsl>
-#include <AnKi/Shaders/TonemappingFunctions.hlsl>
-
-constexpr F32 kAlpha = 1.0f;
-constexpr F32 kBillboardScale = 0.25f;
-
-struct Constants
-{
-	Mat4 m_viewProjMat;
-	Mat3x4 m_camTrf;
-};
-
-ANKI_FAST_CONSTANTS(Constants, g_consts)
-
-#if OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_LIGHT
-typedef LightUnion ClusteredType;
-#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_DECAL
-typedef Decal ClusteredType;
-#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_FOG_DENSITY_VOLUME
-typedef FogDensityVolume ClusteredType;
-#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_REFLECTION_PROBE
-typedef ReflectionProbe ClusteredType;
-#elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_GLOBAL_ILLUMINATION_PROBE
-typedef GlobalIlluminationProbe ClusteredType;
-#else
-#	error See file
-#endif
-
-StructuredBuffer<ClusteredType> g_visibleObjects : register(t1);
-StructuredBuffer<U32> g_visibleObjectCount : register(t2);
-
-struct VertOut
-{
-	Vec4 m_svPosition : SV_POSITION;
-	Vec2 m_uv : TEXCOORD;
-	Vec4 m_colorScale : COLOR;
-	nointerpolation U32 m_textureIndex : TEX_INDEX;
-};
-
-struct VertIn
-{
-	U32 m_svInstanceId : SV_INSTANCEID;
-	U32 m_svVertexId : SV_VERTEXID;
-};
-
-#if ANKI_VERTEX_SHADER
-VertOut main(VertIn input)
-{
-	VertOut output;
-
-	output.m_colorScale = Vec4(1.0f, 1.0f, 1.0f, kAlpha);
-	output.m_textureIndex = 0;
-
-	output.m_uv = Vec2(input.m_svVertexId & 1u, ((input.m_svVertexId + 1u) / 3u) & 1u);
-
-	const U32 objCount = g_visibleObjectCount[0];
-
-	if(input.m_svInstanceId < objCount)
-	{
-#	if OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_LIGHT
-		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_position;
-		output.m_colorScale.xyz = reinhardTonemap(g_visibleObjects[input.m_svInstanceId].m_diffuseColor);
-		output.m_textureIndex = g_visibleObjects[input.m_svInstanceId].m_lightType;
-#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_DECAL
-		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_sphereCenter;
-#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_FOG_DENSITY_VOLUME
-		const ClusteredType obj = g_visibleObjects[input.m_svInstanceId];
-		const Vec3 localPos = (obj.m_isBox) ? (obj.m_aabbMinOrSphereCenter + obj.m_aabbMaxOrSphereRadius) / 2.0f : obj.m_aabbMinOrSphereCenter;
-#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_REFLECTION_PROBE
-		const Vec3 localPos = g_visibleObjects[input.m_svInstanceId].m_position;
-#	elif OBJECT_TYPE == ANKI_GPU_SCENE_NON_RENDERABLE_OBJECT_TYPE_GLOBAL_ILLUMINATION_PROBE
-		const Vec3 localPos = (g_visibleObjects[input.m_svInstanceId].m_aabbMin + g_visibleObjects[input.m_svInstanceId].m_aabbMax) / 2.0f;
-#	else
-#		error See file
-#	endif
-
-		// Rotate towards the camera and apply translation
-		const Vec3 worldPos = mul(g_consts.m_camTrf, Vec4((output.m_uv * 2.0 - 1.0) * kBillboardScale, 0.0, 0.0)) + localPos;
-
-		output.m_svPosition = mul(g_consts.m_viewProjMat, Vec4(worldPos, 1.0));
-	}
-	else
-	{
-		// Skip this instance by making the vertex degenerate
-		output.m_svPosition = 0.0f;
-	}
-
-	return output;
-}
-#endif // ANKI_VERTEX_SHADER
-
-#if ANKI_PIXEL_SHADER
-#	include <AnKi/Shaders/ImportanceSampling.hlsl>
-
-SamplerState g_trilinearRepeatSampler : register(s1);
-Texture2D<Vec4> g_tex : register(t3);
-Texture2D<Vec4> g_tex2 : register(t4);
-
-// NOTE: Don't eliminate the binding because it confuses the descriptor set creation
-#	if DEPTH_FAIL_VISUALIZATION == 1
-SamplerState g_nearestAnyClampSampler : register(s0);
-Texture2D g_depthRt : register(t0);
-#	endif
-
-Vec4 main(VertOut input) : SV_TARGET0
-{
-	ANKI_MAYBE_UNUSED(input);
-
-	// Check if we should skip the frag
-	F32 colorFactor = 1.0f;
-#	if DEPTH_FAIL_VISUALIZATION == 1
-	Vec2 texSize;
-	g_depthRt.GetDimensions(texSize.x, texSize.y);
-	const Vec2 uv = input.m_svPosition.xy / texSize;
-	const F32 depthRef = g_depthRt.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
-	const Bool depthTestFailed = input.m_svPosition.z >= depthRef;
-	if(depthTestFailed)
-	{
-		colorFactor = 0.6;
-	}
-#	endif
-
-	// Write the color
-	if(input.m_textureIndex == 0)
-	{
-		return g_tex.Sample(g_trilinearRepeatSampler, input.m_uv) * input.m_colorScale * colorFactor;
-	}
-	else
-	{
-		return g_tex2.Sample(g_trilinearRepeatSampler, input.m_uv) * input.m_colorScale * colorFactor;
-	}
-}
-#endif // ANKI_PIXEL_SHADER

+ 0 - 88
AnKi/Shaders/DbgRenderables.ankiprog

@@ -1,88 +0,0 @@
-// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma anki mutator DEPTH_FAIL_VISUALIZATION 0 1
-
-#pragma anki technique vert pixel
-
-#include <AnKi/Shaders/Common.hlsl>
-#include <AnKi/Shaders/Include/GpuSceneTypes.h>
-
-struct Constants
-{
-	Vec4 m_color;
-	Mat4 m_viewProjMat;
-};
-
-ANKI_FAST_CONSTANTS(Constants, g_consts)
-
-StructuredBuffer<GpuSceneRenderableBoundingVolume> g_renderableBoundingVolumes : register(t1);
-StructuredBuffer<U32> g_visibleRenderableBoundingVolumeIndices : register(t2);
-
-struct VertOut
-{
-	Vec4 m_svPosition : SV_POSITION;
-};
-
-struct VertIn
-{
-	Vec3 m_position : POSITION;
-	U32 m_svInstanceId : SV_INSTANCEID;
-};
-
-#if ANKI_VERTEX_SHADER
-VertOut main(VertIn input)
-{
-	VertOut output;
-
-	const U32 bvolumeCount = g_visibleRenderableBoundingVolumeIndices[0];
-
-	if(input.m_svInstanceId < bvolumeCount)
-	{
-		const GpuSceneRenderableBoundingVolume bvol = g_renderableBoundingVolumes[g_visibleRenderableBoundingVolumeIndices[input.m_svInstanceId + 1]];
-		const Vec3 boxCenter = (bvol.m_aabbMin + bvol.m_aabbMax) * 0.5f;
-		Vec3 localPos = input.m_position * (bvol.m_aabbMax - boxCenter) + boxCenter;
-		output.m_svPosition = mul(g_consts.m_viewProjMat, Vec4(localPos, 1.0));
-	}
-	else
-	{
-		// Skip this instance by making the vertex degenerate
-		output.m_svPosition = 0.0f;
-	}
-
-	return output;
-}
-#endif // ANKI_VERTEX_SHADER
-
-#if ANKI_PIXEL_SHADER
-#	include <AnKi/Shaders/ImportanceSampling.hlsl>
-
-// NOTE: Don't eliminate the binding because it confuses the descriptor set creation
-#	if DEPTH_FAIL_VISUALIZATION == 1
-SamplerState g_nearestAnyClampSampler : register(s0);
-Texture2D g_depthRt : register(t0);
-#	endif
-
-Vec4 main(VertOut input) : SV_TARGET0
-{
-	ANKI_MAYBE_UNUSED(input);
-
-	// Check if we should skip the frag
-#	if DEPTH_FAIL_VISUALIZATION == 1
-	Vec2 texSize;
-	g_depthRt.GetDimensions(texSize.x, texSize.y);
-	const Vec2 uv = input.m_svPosition.xy / texSize;
-	const F32 depthRef = g_depthRt.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
-	const Bool depthTestFailed = input.m_svPosition.z >= depthRef;
-	if(depthTestFailed)
-	{
-		return g_consts.m_color * 0.5;
-	}
-#	endif
-
-	// Write the color
-	return g_consts.m_color;
-}
-#endif // ANKI_PIXEL_SHADER

+ 2 - 0
AnKi/Util/BlockArray.inl.h

@@ -115,6 +115,8 @@ void BlockArray<T, TMemoryPool, TConfig>::erase(Iterator it)
 	{
 		m_firstIndex = 0;
 		m_endIndex = 0;
+		m_blockStorages.destroy();
+		m_blockMetadatas.destroy();
 	}
 	else
 	{

+ 3 - 3
AnKi/Util/CVarSet.cpp

@@ -77,7 +77,7 @@ Error CVarSet::setMultiple(ConstWeakArray<const Char*> arr)
 		err = value.toNumber(v); \
 		if(!err) \
 		{ \
-			static_cast<NumericCVar<type>&>(*foundCVar).set(v); \
+			static_cast<NumericCVar<type>&>(*foundCVar) = v; \
 		} \
 		break; \
 	}
@@ -86,7 +86,7 @@ Error CVarSet::setMultiple(ConstWeakArray<const Char*> arr)
 			switch(foundCVar->m_type)
 			{
 			case CVar::Type::kString:
-				static_cast<StringCVar&>(*foundCVar).set(value);
+				static_cast<StringCVar&>(*foundCVar) = value;
 				break;
 			case CVar::Type::kBool:
 			{
@@ -94,7 +94,7 @@ Error CVarSet::setMultiple(ConstWeakArray<const Char*> arr)
 				err = value.toNumber(v);
 				if(!err)
 				{
-					static_cast<BoolCVar&>(*foundCVar).set(v != 0);
+					static_cast<BoolCVar&>(*foundCVar) = (v != 0);
 				}
 				break;
 			}

+ 8 - 4
AnKi/Util/CVarSet.h

@@ -77,7 +77,7 @@ public:
 		ANKI_ASSERT(defaultVal >= min && defaultVal <= max);
 	}
 
-	void set(TNumber val)
+	NumericCVar& operator=(TNumber val)
 	{
 		const TNumber newVal = clamp(val, m_min, m_max);
 		if(newVal != val)
@@ -85,6 +85,7 @@ public:
 			ANKI_UTIL_LOGW("Out of range value set for config var: %s", m_name.cstr());
 		}
 		m_value = newVal;
+		return *this;
 	}
 
 	operator TNumber() const
@@ -122,7 +123,7 @@ public:
 	StringCVar(CString subsystem, CString name, CString value, CString descr = CString())
 		: CVar(Type::kString, subsystem, name, descr)
 	{
-		set(value);
+		*this = value;
 	}
 
 	~StringCVar()
@@ -133,7 +134,7 @@ public:
 		}
 	}
 
-	void set(CString name)
+	StringCVar& operator=(CString name)
 	{
 		if(m_str)
 		{
@@ -150,6 +151,8 @@ public:
 		{
 			memcpy(m_str, name.cstr(), len + 1);
 		}
+
+		return *this;
 	}
 
 	operator CString() const
@@ -171,9 +174,10 @@ public:
 	{
 	}
 
-	void set(Bool val)
+	BoolCVar& operator=(Bool val)
 	{
 		m_val = val;
+		return *this;
 	}
 
 	operator Bool() const

+ 21 - 2
AnKi/Util/Hierarchy.h

@@ -49,22 +49,41 @@ public:
 		return m_parent;
 	}
 
-	Value& getChild(PtrSize i)
+	Value& getChild(U32 i)
 	{
 		return *(*(m_children.getBegin() + i));
 	}
 
-	const Value& getChild(PtrSize i) const
+	const Value& getChild(U32 i) const
 	{
 		return *(*(m_children.getBegin() + i));
 	}
 
+	Bool hasChildren() const
+	{
+		return !m_children.isEmpty();
+	}
+
 	/// Add a new child.
 	void addChild(Value* child);
 
 	/// Remove a child.
 	void removeChild(Value* child);
 
+	void setParent(Value* parent)
+	{
+		ANKI_ASSERT(parent);
+		parent->addChild(static_cast<Value*>(this));
+	}
+
+	void removeParent()
+	{
+		if(m_parent)
+		{
+			m_parent->removeChild(this);
+		}
+	}
+
 	/// Visit the children and the children's children. Use it with lambda
 	template<typename TVisitorFunc>
 	Error visitChildren(TVisitorFunc vis);

+ 13 - 1
CMakeLists.txt

@@ -1,4 +1,4 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
+CMAKE_MINIMUM_REQUIRED(VERSION 3.15)
 
 message("++ CMake version ${CMAKE_VERSION}")
 
@@ -224,6 +224,8 @@ if(NOT MSVC)
 		add_compile_options(-msse4)
 	endif()
 
+	add_compile_options(-fno-rtti)
+
 	if(ANKI_LTO)
 		add_compile_options(-flto)
 		set(LINKER_FLAGS "${LINKER_FLAGS} -flto ")
@@ -305,6 +307,16 @@ option(BUILD_OPENGL3_DEMOS OFF)
 option(BUILD_EXTRAS OFF)
 option(BUILD_UNIT_TESTS OFF)
 
+# Jolt config
+option(USE_STATIC_MSVC_RUNTIME_LIBRARY "Use the static MSVC runtime library" OFF)
+set(USE_STATIC_MSVC_RUNTIME_LIBRARY OFF)
+option(DEBUG_RENDERER_IN_DISTRIBUTION "Enable debug renderer in all builds" ON)
+set(DEBUG_RENDERER_IN_DISTRIBUTION ON)
+if(ANKI_EXTRA_CHECKS)
+	option(USE_ASSERTS "Enable asserts" ON)
+	set(USE_ASSERTS ON)
+endif()
+
 if((LINUX OR MACOS OR WINDOWS) AND GL)
 	set(ANKI_EXTERN_SUB_DIRS ${ANKI_EXTERN_SUB_DIRS} GLEW)
 endif()

+ 8 - 8
Samples/Common/SampleApp.cpp

@@ -10,7 +10,7 @@ using namespace anki;
 Error SampleApp::init(int argc, char** argv, CString sampleName)
 {
 	// Init the super class
-	g_windowFullscreenCVar.set(1);
+	g_windowFullscreenCVar = 1;
 
 #if !ANKI_OS_ANDROID
 	HeapMemoryPool tmpPool(allocAligned, nullptr);
@@ -23,7 +23,7 @@ Error SampleApp::init(int argc, char** argv, CString sampleName)
 	}
 	else
 	{
-		g_dataPathsCVar.set(BaseString<MemoryPoolPtrWrapper<HeapMemoryPool>>(&tmpPool).sprintf("%s|.anki,lua", assetsDataPath.cstr()));
+		g_dataPathsCVar = BaseString<MemoryPoolPtrWrapper<HeapMemoryPool>>(&tmpPool).sprintf("%s|.anki,lua", assetsDataPath.cstr());
 	}
 #endif
 
@@ -64,7 +64,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 	if(in.getKey(KeyCode::kY) == 1)
 	{
 		// renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "GBufferAlbedo") ? "" : "GBufferAlbedo");
-		g_shadowMappingPcssCVar.set(!g_shadowMappingPcssCVar);
+		g_shadowMappingPcssCVar = !g_shadowMappingPcssCVar;
 	}
 
 	if(in.getKey(KeyCode::kU) == 1)
@@ -135,7 +135,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kJ) == 1)
 	{
-		g_vrsCVar.set(!g_vrsCVar);
+		g_vrsCVar = !g_vrsCVar;
 	}
 
 	static Vec2 mousePosOn1stClick = in.getMousePosition();
@@ -151,17 +151,17 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 		mode = (mode + 1) % 3;
 		if(mode == 0)
 		{
-			g_dbgCVar.set(false);
+			g_dbgSceneCVar = false;
 		}
 		else if(mode == 1)
 		{
-			g_dbgCVar.set(true);
+			g_dbgSceneCVar = true;
 			renderer.getDbg().setDepthTestEnabled(true);
 			renderer.getDbg().setDitheredDepthTestEnabled(false);
 		}
 		else
 		{
-			g_dbgCVar.set(true);
+			g_dbgSceneCVar = true;
 			renderer.getDbg().setDepthTestEnabled(false);
 			renderer.getDbg().setDitheredDepthTestEnabled(true);
 		}
@@ -169,7 +169,7 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kF11) == 1 && ANKI_TRACING_ENABLED)
 	{
-		g_tracingEnabledCVar.set(!g_tracingEnabledCVar);
+		g_tracingEnabledCVar = !g_tracingEnabledCVar;
 	}
 
 	if(in.getMouseButton(MouseButton::kRight) || in.hasTouchDevice())

+ 46 - 46
Samples/PhysicsPlayground/Assets/Scene.lua

@@ -12,7 +12,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.912920, 1.912920, 1.912920, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Icosphere")
@@ -25,7 +25,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.264235, 1.264235, 1.264235, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.019")
@@ -38,7 +38,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.018")
@@ -51,7 +51,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.017")
@@ -64,7 +64,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.016")
@@ -77,7 +77,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.015")
@@ -90,7 +90,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.014")
@@ -103,7 +103,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.013")
@@ -116,7 +116,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.012")
@@ -129,7 +129,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.011")
@@ -142,7 +142,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.010")
@@ -155,7 +155,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.009")
@@ -168,7 +168,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.008")
@@ -181,7 +181,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.007")
@@ -194,7 +194,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.006")
@@ -207,7 +207,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.005")
@@ -220,7 +220,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.004")
@@ -233,7 +233,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.003")
@@ -246,7 +246,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.002")
@@ -259,7 +259,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Suzanne")
@@ -272,7 +272,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube")
@@ -285,7 +285,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Lamp_Orientation")
@@ -323,7 +323,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.022")
@@ -336,7 +336,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.023")
@@ -349,7 +349,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.024")
@@ -362,7 +362,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.025")
@@ -375,7 +375,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.026")
@@ -388,7 +388,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.027")
@@ -401,7 +401,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.028")
@@ -414,7 +414,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.029")
@@ -427,7 +427,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.030")
@@ -440,7 +440,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.031")
@@ -453,7 +453,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.032")
@@ -466,7 +466,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.033")
@@ -479,7 +479,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.034")
@@ -492,7 +492,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.035")
@@ -505,7 +505,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(0.995130, 0.995130, 0.995130, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.036")
@@ -518,7 +518,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.038")
@@ -531,7 +531,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.039")
@@ -544,7 +544,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.037")
@@ -557,7 +557,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.040")
@@ -570,7 +570,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.041")
@@ -583,7 +583,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.042")
@@ -596,7 +596,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.043")
@@ -609,7 +609,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("Cube.044")
@@ -622,7 +622,7 @@ trf:setRotation(rot)
 trf:setScale(Vec4.new(1.000000, 1.000000, 1.000000, 0))
 node:setLocalTransform(trf)
 comp = node:newBodyComponent()
-comp:setMeshFromModelComponent()
+comp:setCollisionShapeType(BodyComponentCollisionShapeType.kFromModelComponent)
 comp:teleportTo(trf)
 
 node = scene:newSceneNode("refl_probe.002")

+ 94 - 89
Samples/PhysicsPlayground/Main.cpp

@@ -69,36 +69,6 @@ end
 	return Error::kNone;
 }
 
-class RayCast : public PhysicsWorldRayCastCallback
-{
-public:
-	Vec3 m_hitPosition = Vec3(kMaxF32);
-	Vec3 m_hitNormal;
-	Bool m_hit = false;
-
-	RayCast(Vec3 from, Vec3 to, PhysicsMaterialBit mtl)
-		: PhysicsWorldRayCastCallback(from, to, mtl)
-	{
-	}
-
-	void processResult([[maybe_unused]] PhysicsFilteredObject& obj, const Vec3& worldNormal, const Vec3& worldPosition)
-	{
-		if((m_from - m_to).dot(worldNormal) < 0.0f)
-		{
-			return;
-		}
-
-		if((worldPosition - m_from).getLengthSquared() > (m_hitPosition - m_from).getLengthSquared())
-		{
-			return;
-		}
-
-		m_hitPosition = worldPosition;
-		m_hitNormal = worldNormal;
-		m_hit = true;
-	}
-};
-
 class MyApp : public SampleApp
 {
 public:
@@ -121,87 +91,99 @@ Error MyApp::sampleExtraInit()
 		SceneNode* player;
 		ANKI_CHECK(SceneGraph::getSingleton().newSceneNode("player", player));
 		PlayerControllerComponent* playerc = player->newComponent<PlayerControllerComponent>();
-		playerc->moveToPosition(Vec3(0.0f, 2.5f, 0.0f));
-		playerc->getPhysicsPlayerController().setMaterialMask(PhysicsMaterialBit::kStaticGeometry);
+		playerc->moveToPosition(Vec3(0.0f, 10.5f, 0.0f));
 
 		player->addChild(&cam);
 	}
 
-	// Create a body component with joint
+	// Create a body component with hinge joint
+	if(1)
 	{
 		SceneNode* base;
 		ANKI_CHECK(SceneGraph::getSingleton().newSceneNode("hingeBase", base));
 		BodyComponent* bodyc = base->newComponent<BodyComponent>();
-		bodyc->setBoxCollisionShape(Vec3(0.1f));
+		bodyc->setBoxExtend(Vec3(0.1f));
+		bodyc->setCollisionShapeType(BodyComponentCollisionShapeType::kAabb);
 		bodyc->teleportTo(Transform(Vec4(-0.0f, 5.0f, -3.0f, 0.0f), Mat3x4::getIdentity(), Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
 
+		SceneNode* joint;
+		ANKI_CHECK(SceneGraph::getSingleton().newSceneNode("hinge", joint));
+		JointComponent* jointc = joint->newComponent<JointComponent>();
+		jointc->setType(JointType::kHinge);
+		joint->setLocalOrigin(Vec4(-0.0f, 4.8f, -3.0f, 0.0f));
+		base->addChild(joint);
+
 		SceneNode* monkey;
 		ANKI_CHECK(SceneGraph::getSingleton().newSceneNode("monkey_p2p", monkey));
-		base->addChild(monkey);
 		ModelComponent* modelc = monkey->newComponent<ModelComponent>();
 		modelc->loadModelResource("Assets/Suzanne_dynamic_36043dae41fe12d5.ankimdl");
+		const Aabb aabb = modelc->getModelResource()->getBoundingVolume();
+		const F32 height = aabb.getMax().y() - aabb.getMin().y();
 
 		bodyc = monkey->newComponent<BodyComponent>();
-		bodyc->loadMeshResource("Assets/Suzanne_e3526e1428c0763c.ankimesh");
-		bodyc->teleportTo(Transform(Vec4(-0.0f, 4.0f, -3.0f, 0.0f), Mat3x4::getIdentity(), Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
+		bodyc->setCollisionShapeType(BodyComponentCollisionShapeType::kFromModelComponent);
+		bodyc->teleportTo(Transform(Vec4(-0.0f, 4.8f - height / 2.0f, -3.0f, 0.0f), Mat3x4::getIdentity(), Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
 		bodyc->setMass(2.0f);
 
-		JointComponent* jointc = monkey->newComponent<JointComponent>();
-		jointc->newHingeJoint(Vec3(0.2f, 1.0f, 0.0f), Vec3(0.0f, -1.3f, 0.0f), Vec3(1, 0, 0));
+		joint->addChild(monkey);
 	}
 
 	// Create a chain
+	if(1)
 	{
-		const U LINKS = 5;
+		const U linkCount = 5;
 
 		Transform trf(Vec4(-4.3f, 12.0f, -3.0f, 0.0f), Mat3x4::getIdentity(), Vec4(1.0, 1.0, 1.0, 0.0));
 
 		SceneNode* base;
 		ANKI_CHECK(SceneGraph::getSingleton().newSceneNode("p2pBase", base));
 		BodyComponent* bodyc = base->newComponent<BodyComponent>();
-		bodyc->setBoxCollisionShape(Vec3(0.1f));
+		bodyc->setBoxExtend(Vec3(0.1f));
+		bodyc->setCollisionShapeType(BodyComponentCollisionShapeType::kAabb);
 		bodyc->teleportTo(trf);
 
-		SceneNode* prevBody = nullptr;
-		for(U32 i = 0; i < LINKS; ++i)
+		trf.setOrigin(trf.getOrigin() - Vec4(0.0f, 0.5f, 0.0f, 0.0f));
+
+		SceneNode* prevNode = base;
+
+		for(U32 i = 0; i < linkCount; ++i)
 		{
+			SceneNode* joint;
+			ANKI_CHECK(SceneGraph::getSingleton().newSceneNode(String().sprintf("joint_chain%u", i), joint));
+			JointComponent* jointc = joint->newComponent<JointComponent>();
+			jointc->setType(JointType::kPoint);
+			joint->setLocalOrigin(trf.getOrigin());
+			joint->setParent(prevNode);
+
 			SceneNode* monkey;
 			ANKI_CHECK(SceneGraph::getSingleton().newSceneNode(String().sprintf("monkey_chain%u", i).toCString(), monkey));
-			monkey->newComponent<ModelComponent>()->loadModelResource("Assets/Suzanne_dynamic_36043dae41fe12d5.ankimdl");
-
-			trf.setOrigin(trf.getOrigin() - Vec4(0.0f, F32(i * 1) * 1.25f, 0.0f, 0.0f));
-			// trf.getOrigin().x() -= i * 0.25f;
+			ModelComponent* modelc = monkey->newComponent<ModelComponent>();
+			modelc->loadModelResource("Assets/Suzanne_dynamic_36043dae41fe12d5.ankimdl");
+			const Aabb aabb = modelc->getModelResource()->getBoundingVolume();
+			const F32 height = aabb.getMax().y() - aabb.getMin().y();
 
-			// monkey->getFirstComponentOfType<MoveComponent>().setLocalTransform(trf);
+			trf.setOrigin(trf.getOrigin() - Vec4(0.0f, height / 2.0f + 0.1f, 0.0f, 0.0f));
 
 			BodyComponent* bodyc = monkey->newComponent<BodyComponent>();
-			bodyc->setMeshFromModelComponent();
+			bodyc->setCollisionShapeType(BodyComponentCollisionShapeType::kFromModelComponent);
 			bodyc->teleportTo(trf);
 			bodyc->setMass(1.0f);
+			joint->addChild(monkey);
 
-			// Create joint
-			JointComponent* jointc = monkey->newComponent<JointComponent>();
-			if(prevBody == nullptr)
-			{
-				base->addChild(monkey);
-			}
-			else
-			{
-				prevBody->addChild(monkey);
-			}
-			jointc->newPoint2PointJoint2(Vec3(0, 1.0, 0), Vec3(0, -1.0, 0));
+			trf.setOrigin(trf.getOrigin() - Vec4(0.0f, height / 2.0f + 0.1f, 0.0f, 0.0f));
 
-			prevBody = monkey;
+			prevNode = monkey;
 		}
 	}
 
 	// Trigger
+	if(1)
 	{
 		SceneNode* node;
 		ANKI_CHECK(SceneGraph::getSingleton().newSceneNode("trigger", node));
 		TriggerComponent* triggerc = node->newComponent<TriggerComponent>();
 		triggerc->setSphereVolumeRadius(1.8f);
-		node->setLocalTransform(Transform(Vec4(1.0f, 0.5f, 0.0f, 0.0f), Mat3x4::getIdentity(), Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
+		node->setLocalTransform(Transform(Vec4(4.0f, 0.5f, 0.0f, 0.0f), Mat3x4::getIdentity(), Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
 	}
 
 	Input::getSingleton().lockCursor(true);
@@ -256,7 +238,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 
 	if(Input::getSingleton().getKey(KeyCode::kJ) == 1)
 	{
-		g_vrsCVar.set(!g_vrsCVar);
+		g_vrsCVar = !g_vrsCVar;
 	}
 
 	if(Input::getSingleton().getKey(KeyCode::kF1) == 1)
@@ -265,22 +247,29 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		mode = (mode + 1) % 3;
 		if(mode == 0)
 		{
-			g_dbgCVar.set(false);
+			g_dbgSceneCVar = false;
 		}
 		else if(mode == 1)
 		{
-			g_dbgCVar.set(true);
+			g_dbgSceneCVar = true;
 			renderer.getDbg().setDepthTestEnabled(true);
 			renderer.getDbg().setDitheredDepthTestEnabled(false);
 		}
 		else
 		{
-			g_dbgCVar.set(true);
+			g_dbgSceneCVar = true;
 			renderer.getDbg().setDepthTestEnabled(false);
 			renderer.getDbg().setDitheredDepthTestEnabled(true);
 		}
 	}
 
+	if(Input::getSingleton().getKey(KeyCode::kF2) == 1)
+	{
+		g_dbgPhysicsCVar = !g_dbgPhysicsCVar;
+		renderer.getDbg().setDepthTestEnabled(true);
+		renderer.getDbg().setDitheredDepthTestEnabled(false);
+	}
+
 	// Move player
 	{
 		SceneNode& player = SceneGraph::getSingleton().findSceneNode("player");
@@ -297,10 +286,6 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		F32 x = Input::getSingleton().getMousePosition().x();
 		if(y != 0.0 || x != 0.0)
 		{
-			// Set origin
-			Vec4 origin = player.getWorldTransform().getOrigin();
-			// origin.y() += 1.9f;
-
 			// Set rotation
 			Mat3x4 rot(Vec3(0.0f), Euler(ang * y * 11.25f, ang * x * -20.0f, 0.0f));
 
@@ -313,11 +298,11 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 			rot.reorthogonalize();
 
 			// Update move
-			player.setLocalTransform(Transform(origin, rot, Vec4(1.0f, 1.0f, 1.0f, 0.0f)));
+			player.setLocalRotation(rot);
 		}
 
-		const F32 speed = 0.5;
-		Vec4 moveVec(0.0);
+		const F32 speed = 8.5;
+		Vec3 moveVec(0.0);
 		if(Input::getSingleton().getKey(KeyCode::kW))
 		{
 			moveVec.z() += 1.0f;
@@ -325,7 +310,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 
 		if(Input::getSingleton().getKey(KeyCode::kA))
 		{
-			moveVec.x() -= 1.0f;
+			moveVec.x() += 1.0f;
 		}
 
 		if(Input::getSingleton().getKey(KeyCode::kS))
@@ -335,14 +320,35 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 
 		if(Input::getSingleton().getKey(KeyCode::kD))
 		{
-			moveVec.x() += 1.0f;
+			moveVec.x() -= 1.0f;
 		}
 
-		Vec4 dir = -player.getLocalRotation().getZAxis().xyz0();
-		dir.y() = 0.0f;
-		dir.normalize();
+		F32 jumpSpeed = 0.0f;
+		if(Input::getSingleton().getKey(KeyCode::kSpace))
+		{
+			jumpSpeed += 8.0f;
+		}
+
+		static Bool crouch = false;
+		Bool crouchChanged = false;
+		if(Input::getSingleton().getKey(KeyCode::kC))
+		{
+			crouch = !crouch;
+			crouchChanged = true;
+		}
+
+		if(moveVec != 0.0f || jumpSpeed != 0.0f || crouchChanged)
+		{
+			Vec3 dir;
+			if(moveVec != 0.0f)
+			{
+				dir = -(player.getLocalRotation() * moveVec.xyz0());
+				dir.y() = 0.0f;
+				dir.normalize();
+			}
 
-		playerc.setVelocity(moveVec.z() * speed, moveVec.x() * speed, 0.0, dir);
+			playerc.setVelocity(speed, jumpSpeed, dir, crouch);
+		}
 	}
 
 	if(Input::getSingleton().getMouseButton(MouseButton::kLeft) == 1)
@@ -360,7 +366,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		// monkey->getFirstComponentOfType<MoveComponent>().setLocalTransform(camTrf);
 
 		BodyComponent* bodyc = monkey->newComponent<BodyComponent>();
-		bodyc->setMeshFromModelComponent();
+		bodyc->setCollisionShapeType(BodyComponentCollisionShapeType::kFromModelComponent);
 		bodyc->teleportTo(camTrf);
 		bodyc->setMass(1.0f);
 
@@ -376,15 +382,13 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		Vec3 from = camTrf.getOrigin().xyz();
 		Vec3 to = from + -camTrf.getRotation().getZAxis() * 100.0f;
 
-		RayCast ray(from, to, PhysicsMaterialBit::kAll & (~PhysicsMaterialBit::kParticle));
-		ray.m_firstHit = true;
-
-		PhysicsWorld::getSingleton().rayCast(ray);
+		v2::RayHitResult result;
+		const Bool hit = v2::PhysicsWorld::getSingleton().castRayClosestHit(from, to, v2::PhysicsLayerBit::kStatic, result);
 
-		if(ray.m_hit)
+		if(hit)
 		{
 			// Create rotation
-			const Vec3& zAxis = ray.m_hitNormal;
+			const Vec3& zAxis = result.m_normal;
 			Vec3 yAxis = Vec3(0, 1, 0.5);
 			Vec3 xAxis = yAxis.cross(zAxis).getNormalized();
 			yAxis = zAxis.cross(xAxis);
@@ -394,7 +398,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 			rot.setYAxis(yAxis);
 			rot.setZAxis(zAxis);
 
-			Transform trf(ray.m_hitPosition.xyz0(), rot, Vec4(1.0f, 1.0f, 1.0f, 0.0f));
+			Transform trf(result.m_hitPosition.xyz0(), rot, Vec4(1.0f, 1.0f, 1.0f, 0.0f));
 
 			// Create an obj
 			static U32 id = 0;
@@ -438,7 +442,7 @@ Error MyApp::userMainLoop(Bool& quit, [[maybe_unused]] Second elapsedTime)
 		SceneNode& node = SceneGraph::getSingleton().findSceneNode("trigger");
 		TriggerComponent& comp = node.getFirstComponentOfType<TriggerComponent>();
 
-		for(U32 i = 0; i < comp.getBodyComponentsEnter().getSize(); ++i)
+		for(U32 i = 0; i < comp.getSceneNodesEnter().getSize(); ++i)
 		{
 			// ANKI_LOGI("Touching %s", comp.getContactSceneNodes()[i]->getName().cstr());
 		}
@@ -465,9 +469,10 @@ int myMain(int argc, char* argv[])
 	}
 	else
 	{
-		delete app;
 		ANKI_LOGI("Bye!!");
 	}
 
+	delete app;
+
 	return 0;
 }

+ 1 - 1
Samples/SkeletalAnimation/Main.cpp

@@ -30,7 +30,7 @@ public:
 		animInfo.m_repeatTimes = -1.0;
 		SceneGraph::getSingleton().findSceneNode("droid.001").getFirstComponentOfType<SkinComponent>().playAnimation(0, m_floatAnim, animInfo);
 
-		g_bloomThresholdCVar.set(5.0f);
+		g_bloomThresholdCVar = 5.0f;
 		return Error::kNone;
 	}
 

+ 11 - 11
Sandbox/Main.cpp

@@ -50,8 +50,8 @@ Error MyApp::init(int argc, char* argv[])
 	if(getenv("PROFILE"))
 	{
 		m_profile = true;
-		g_targetFpsCVar.set(240);
-		g_tracingEnabledCVar.set(true);
+		g_targetFpsCVar = 240;
+		g_tracingEnabledCVar = true;
 	}
 
 	// Load scene
@@ -120,17 +120,17 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 		mode = (mode + 1) % 3;
 		if(mode == 0)
 		{
-			g_dbgCVar.set(false);
+			g_dbgSceneCVar = false;
 		}
 		else if(mode == 1)
 		{
-			g_dbgCVar.set(true);
+			g_dbgSceneCVar = true;
 			renderer.getDbg().setDepthTestEnabled(true);
 			renderer.getDbg().setDitheredDepthTestEnabled(false);
 		}
 		else
 		{
-			g_dbgCVar.set(true);
+			g_dbgSceneCVar = true;
 			renderer.getDbg().setDepthTestEnabled(false);
 			renderer.getDbg().setDitheredDepthTestEnabled(true);
 		}
@@ -154,7 +154,7 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kF11) == 1)
 	{
-		g_tracingEnabledCVar.set(!g_tracingEnabledCVar);
+		g_tracingEnabledCVar = !g_tracingEnabledCVar;
 	}
 
 #if !PLAYER
@@ -183,17 +183,17 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 			mode = (mode + 1) % 3;
 			if(mode == 0)
 			{
-				g_dbgCVar.set(false);
+				g_dbgSceneCVar = false;
 			}
 			else if(mode == 1)
 			{
-				g_dbgCVar.set(true);
+				g_dbgSceneCVar = true;
 				renderer.getDbg().setDepthTestEnabled(true);
 				renderer.getDbg().setDitheredDepthTestEnabled(false);
 			}
 			else
 			{
-				g_dbgCVar.set(true);
+				g_dbgSceneCVar = true;
 				renderer.getDbg().setDepthTestEnabled(false);
 				renderer.getDbg().setDitheredDepthTestEnabled(true);
 			}
@@ -338,7 +338,7 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kY) == 1)
 	{
-		g_shadowMappingPcssCVar.set(!g_shadowMappingPcssCVar);
+		g_shadowMappingPcssCVar = !g_shadowMappingPcssCVar;
 	}
 
 	if(in.getKey(KeyCode::kU) == 1)
@@ -394,7 +394,7 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kJ) == 1)
 	{
-		g_vrsCVar.set(!g_vrsCVar);
+		g_vrsCVar = !g_vrsCVar;
 	}
 
 	if(in.getEvent(InputEvent::kWindowClosed))

+ 1 - 1
Tests/Gr/Gr.cpp

@@ -22,7 +22,7 @@ using namespace anki;
 
 ANKI_TEST(Gr, GrManager)
 {
-	g_validationCVar.set(true);
+	g_validationCVar = true;
 
 	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
 	initWindow();

+ 5 - 5
Tests/Gr/GrAsyncCompute.cpp

@@ -70,11 +70,11 @@ ANKI_TEST(Gr, AsyncComputeBench)
 	const U32 spheresToDrawPerDimension = 100;
 	const U32 windowSize = 512;
 
-	g_validationCVar.set(false); // TODO
-	g_debugMarkersCVar.set(false);
-	g_windowWidthCVar.set(windowSize);
-	g_windowHeightCVar.set(windowSize);
-	g_asyncComputeCVar.set(0);
+	g_validationCVar = false; // TODO
+	g_debugMarkersCVar = false;
+	g_windowWidthCVar = windowSize;
+	g_windowHeightCVar = windowSize;
+	g_asyncComputeCVar = 0;
 
 	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
 	ShaderCompilerMemoryPool::allocateSingleton(allocAligned, nullptr);

+ 4 - 4
Tests/Gr/GrCommon.h

@@ -90,10 +90,10 @@ inline void commonInit(Bool validation = true)
 {
 	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
 	ShaderCompilerMemoryPool::allocateSingleton(allocAligned, nullptr);
-	g_windowWidthCVar.set(kWidth);
-	g_windowHeightCVar.set(kHeight);
-	g_vsyncCVar.set(false);
-	g_debugMarkersCVar.set(true);
+	g_windowWidthCVar = kWidth;
+	g_windowHeightCVar = kHeight;
+	g_vsyncCVar = false;
+	g_debugMarkersCVar = true;
 	if(validation)
 	{
 		[[maybe_unused]] Error err = CVarSet::getSingleton().setMultiple(Array<const Char*, 4>{"Validation", "1", "DebugMarkers", "1"});

+ 4 - 4
Tests/Gr/GrMeshShaders.cpp

@@ -14,10 +14,10 @@ ANKI_TEST(Gr, MeshShaders)
 	constexpr U32 kTileCount = 4;
 	constexpr U32 kVertCount = 4;
 
-	g_validationCVar.set(true);
-	g_windowWidthCVar.set(64 * kTileCount);
-	g_windowHeightCVar.set(64);
-	g_meshShadersCVar.set(true);
+	g_validationCVar = true;
+	g_windowWidthCVar = 64 * kTileCount;
+	g_windowHeightCVar = 64;
+	g_meshShadersCVar = true;
 
 	DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
 	ShaderCompilerMemoryPool::allocateSingleton(allocAligned, nullptr);

+ 1 - 1
Tests/Gr/GrTextureBuffer.cpp

@@ -9,7 +9,7 @@
 
 ANKI_TEST(Gr, TextureBuffer)
 {
-	g_validationCVar.set(true);
+	g_validationCVar = true;
 
 	initWindow();
 	initGrManager();

+ 5 - 5
Tests/Ui/Ui.cpp

@@ -56,11 +56,11 @@ public:
 
 ANKI_TEST(Ui, Ui)
 {
-	g_vsyncCVar.set(true);
-	g_validationCVar.set(true);
-	g_windowWidthCVar.set(1024);
-	g_windowHeightCVar.set(760);
-	g_dataPathsCVar.set("EngineAssets");
+	g_vsyncCVar = true;
+	g_validationCVar = true;
+	g_windowWidthCVar = 1024;
+	g_windowHeightCVar = 760;
+	g_dataPathsCVar = "EngineAssets";
 
 	initWindow();
 	ANKI_TEST_EXPECT_NO_ERR(Input::allocateSingleton().init());

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/FontPixelShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/FontPixelShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/FontVertexShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/FontVertexShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/LinePixelShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/LinePixelShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/LineVertexShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/LineVertexShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/TriangleDepthPixelShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/TriangleDepthPixelShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/TriangleDepthVertexShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/TriangleDepthVertexShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/TrianglePixelShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/TrianglePixelShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/TriangleVertexShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/TriangleVertexShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/UIPixelShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/UIPixelShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/UIPixelShaderUntextured.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/UIPixelShaderUntextured.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/UIVertexShader.hlsl → ThirdParty/Jolt/Assets/Shaders/DX/UIVertexShader.hlsl


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/VertexConstants.h → ThirdParty/Jolt/Assets/Shaders/DX/VertexConstants.h


+ 39 - 0
ThirdParty/Jolt/Assets/Shaders/MTL/FontShader.metal

@@ -0,0 +1,39 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+#include "VertexConstants.h"
+
+constexpr sampler alphaTextureSampler(mag_filter::linear, min_filter::linear);
+
+struct FontVertex
+{
+	float3		vPos [[attribute(0)]];
+	float2		vTex [[attribute(1)]];
+	uchar4		vCol [[attribute(2)]];
+};
+
+struct FontOut
+{
+    float4 		oPosition [[position]];
+    float2 		oTex;
+    float4 		oColor;
+};
+
+vertex FontOut FontVertexShader(FontVertex vert [[stage_in]], constant VertexShaderConstantBuffer *constants [[buffer(2)]])
+{
+    FontOut out;
+    out.oPosition = constants->Projection * constants->View * float4(vert.vPos, 1.0);
+    out.oTex = vert.vTex;
+    out.oColor = float4(vert.vCol) / 255.0;
+    return out;
+}
+
+fragment float4 FontPixelShader(FontOut in [[stage_in]], texture2d<float> alphaTexture [[texture(0)]])
+{
+	const float4 sample = alphaTexture.sample(alphaTextureSampler, in.oTex);
+	if (sample.x < 0.5)
+		discard_fragment();
+
+    return float4(in.oColor.xyz, sample.x);
+}

+ 30 - 0
ThirdParty/Jolt/Assets/Shaders/MTL/LineShader.metal

@@ -0,0 +1,30 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+#include "VertexConstants.h"
+
+struct LineVertex
+{
+	float3	iPosition [[attribute(0)]];
+	uchar4	iColor [[attribute(1)]];
+};
+
+struct LineOut
+{
+    float4 	oPosition [[position]];
+    float4 	oColor;
+};
+
+vertex LineOut LineVertexShader(LineVertex vert [[stage_in]], constant VertexShaderConstantBuffer *constants [[buffer(2)]])
+{
+    LineOut out;
+	out.oPosition = constants->Projection * constants->View * float4(vert.iPosition, 1.0);
+    out.oColor = float4(vert.iColor) / 255.0;
+    return out;
+}
+
+fragment float4 LinePixelShader(LineOut in [[stage_in]])
+{
+    return in.oColor;
+}

+ 199 - 0
ThirdParty/Jolt/Assets/Shaders/MTL/TriangleShader.metal

@@ -0,0 +1,199 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+#include "VertexConstants.h"
+
+constexpr sampler depthSampler(mag_filter::nearest, min_filter::nearest);
+
+struct Vertex
+{
+	float3		vPos [[attribute(0)]];
+	float3		vNorm [[attribute(1)]];
+	float2		vTex [[attribute(2)]];
+	uchar4		vCol [[attribute(3)]];
+	float4		iModel0 [[attribute(4)]];
+	float4		iModel1 [[attribute(5)]];
+	float4		iModel2 [[attribute(6)]];
+	float4		iModel3 [[attribute(7)]];
+	float4		iModelInvTrans0 [[attribute(8)]];
+	float4		iModelInvTrans1 [[attribute(9)]];
+	float4		iModelInvTrans2 [[attribute(10)]];
+	float4		iModelInvTrans3 [[attribute(11)]];
+	uchar4		iCol [[attribute(12)]];
+};
+
+struct TriangleOut
+{
+	float4		oPosition [[position]];
+	float3		oNormal;
+	float3		oWorldPos;
+	float2		oTex;
+	float4		oPositionL;
+	float4		oColor;
+};
+
+vertex TriangleOut TriangleVertexShader(Vertex vert [[stage_in]], constant VertexShaderConstantBuffer *constants [[buffer(2)]])
+{
+	TriangleOut out;
+
+	// Convert input matrices
+	float4x4 iModel(vert.iModel0, vert.iModel1, vert.iModel2, vert.iModel3);
+	float4x4 iModelInvTrans(vert.iModelInvTrans0, vert.iModelInvTrans1, vert.iModelInvTrans2, vert.iModelInvTrans3);
+
+	// Get world position
+	float4 pos = float4(vert.vPos, 1.0f);
+	float4 world_pos = iModel * pos;
+
+	// Transform the position from world space to homogeneous projection space
+	float4 proj_pos = constants->View * world_pos;
+	proj_pos = constants->Projection * proj_pos;
+	out.oPosition = proj_pos;
+
+	// Transform the position from world space to projection space of the light
+	float4 proj_lpos = constants->LightView * world_pos;
+	proj_lpos = constants->LightProjection * proj_lpos;
+	out.oPositionL = proj_lpos;
+
+	// output normal
+	float4 norm = float4(vert.vNorm, 0.0f);
+	out.oNormal = normalize(iModelInvTrans * norm).xyz;
+
+	// output world position of the vertex
+	out.oWorldPos = world_pos.xyz;
+
+	// output texture coordinates
+	out.oTex = vert.vTex;
+
+	// output color
+	out.oColor = float4(vert.vCol) * float4(vert.iCol) / (255.0 * 255.0);
+
+	return out;
+}
+
+fragment float4 TrianglePixelShader(TriangleOut vert [[stage_in]], constant PixelShaderConstantBuffer *constants, texture2d<float> depthTexture [[texture(0)]])
+{
+	// Constants
+	float AmbientFactor = 0.3;
+	float3 DiffuseColor = float3(vert.oColor.r, vert.oColor.g, vert.oColor.b);
+	float3 SpecularColor = float3(1, 1, 1);
+	float SpecularPower = 100.0;
+	float bias = 1.0e-7;
+
+	// Homogenize position in light space
+	float3 position_l = vert.oPositionL.xyz / vert.oPositionL.w;
+
+	// Calculate dot product between direction to light and surface normal and clamp between [0, 1]
+	float3 view_dir = normalize(constants->CameraPos - vert.oWorldPos);
+	float3 world_to_light = constants->LightPos - vert.oWorldPos;
+	float3 light_dir = normalize(world_to_light);
+	float3 normal = normalize(vert.oNormal);
+	if (dot(view_dir, normal) < 0) // If we're viewing the triangle from the back side, flip the normal to get the correct lighting
+		normal = -normal;
+	float normal_dot_light_dir = clamp(dot(normal, light_dir), 0.0, 1.0);
+
+	// Calculate texture coordinates in light depth texture
+	float2 tex_coord;
+	tex_coord.x = position_l.x / 2.0 + 0.5;
+	tex_coord.y = -position_l.y / 2.0 + 0.5;
+
+	// Check that the texture coordinate is inside the depth texture, if not we don't know if it is lit or not so we assume lit
+	float shadow_factor = 1.0;
+	if (vert.oColor.a > 0 // Alpha = 0 means don't receive shadows
+		&& tex_coord.x == clamp(tex_coord.x, 0.0, 1.0) && tex_coord.y == clamp(tex_coord.y, 0.0, 1.0))
+	{
+		// Modify shadow bias according to the angle between the normal and the light dir
+		float modified_bias = bias * tan(acos(normal_dot_light_dir));
+		modified_bias = min(modified_bias, 10.0 * bias);
+		
+		// Get texture size
+		float width = 1.0 / 4096;
+		float height = 1.0 / 4096;
+
+		// Samples to take
+		uint num_samples = 16;
+		float2 offsets[] = { 
+			float2(-1.5 * width, -1.5 * height),
+			float2(-0.5 * width, -1.5 * height),
+			float2(0.5 * width, -1.5 * height),
+			float2(1.5 * width, -1.5 * height),
+
+			float2(-1.5 * width, -0.5 * height),
+			float2(-0.5 * width, -0.5 * height),
+			float2(0.5 * width, -0.5 * height),
+			float2(1.5 * width, -0.5 * height),
+
+			float2(-1.5 * width, 0.5 * height),
+			float2(-0.5 * width, 0.5 * height),
+			float2(0.5 * width, 0.5 * height),
+			float2(1.5 * width, 0.5 * height),
+
+			float2(-1.5 * width, 1.5 * height),
+			float2(-0.5 * width, 1.5 * height),
+			float2(0.5 * width, 1.5 * height),
+			float2(1.5 * width, 1.5 * height),
+		};
+
+		// Calculate depth of this pixel relative to the light
+		float light_depth = position_l.z + modified_bias;
+
+		// Sample shadow factor
+		shadow_factor = 0.0;
+		for (uint i = 0; i < num_samples; ++i)
+			shadow_factor += depthTexture.sample(depthSampler, tex_coord + offsets[i]).x <= light_depth? 1.0 : 0.0;
+		shadow_factor /= num_samples;
+	}
+
+	// Calculate diffuse and specular
+	float diffuse = normal_dot_light_dir;
+	float specular = diffuse > 0.0? pow(clamp(-dot(reflect(light_dir, normal), view_dir), 0.0, 1.0), SpecularPower) : 0.0;
+
+	// Apply procedural pattern based on the uv coordinates
+	bool2 less_half = (vert.oTex - floor(vert.oTex)) < float2(0.5, 0.5);
+	float darken_factor = less_half.r ^ less_half.g? 0.5 : 1.0;
+
+	// Fade out checkerboard pattern when it tiles too often
+	float2 dx = dfdx(vert.oTex), dy = dfdy(vert.oTex);
+	float texel_distance = sqrt(dot(dx, dx) + dot(dy, dy));
+	darken_factor = mix(darken_factor, 0.75, clamp(5.0 * texel_distance - 1.5, 0.0, 1.0));
+
+	// Calculate color
+	return float4(clamp((AmbientFactor + diffuse * shadow_factor) * darken_factor * DiffuseColor + SpecularColor * specular * shadow_factor, 0, 1), 1);
+}
+
+struct DepthOut
+{
+	float4		oPosition [[position]];
+};
+
+vertex DepthOut TriangleDepthVertexShader(Vertex vert [[stage_in]], constant VertexShaderConstantBuffer *constants [[buffer(2)]])
+{
+	DepthOut out;
+
+	// Check if the alpha = 0
+	if (vert.vCol.a * vert.iCol.a == 0.0)
+	{
+		// Don't draw the triangle by moving it to an invalid location
+		out.oPosition = float4(0, 0, 0, 0);
+	}
+	else
+	{
+		// Convert input matrix
+		float4x4 iModel(vert.iModel0, vert.iModel1, vert.iModel2, vert.iModel3);
+
+		// Transform the position from world space to homogeneous projection space for the light
+		float4 pos = float4(vert.vPos, 1.0f);
+		pos = iModel * pos;
+		pos = constants->LightView * pos;
+		pos = constants->LightProjection * pos;
+		out.oPosition = pos;
+	}
+
+	return out;
+}
+
+fragment float4 TriangleDepthPixelShader(DepthOut in [[stage_in]])
+{
+	// We only write depth, so this shader does nothing
+	return float4(0.0, 0.0, 0.0, 1.0);
+}

+ 41 - 0
ThirdParty/Jolt/Assets/Shaders/MTL/UIShader.metal

@@ -0,0 +1,41 @@
+#include <metal_stdlib>
+
+using namespace metal;
+
+#include "VertexConstants.h"
+
+constexpr sampler uiTextureSampler(mag_filter::linear, min_filter::linear);
+
+struct UIVertex
+{
+	float3		vPos [[attribute(0)]];
+	float2		vTex [[attribute(1)]];
+	uchar4		vCol [[attribute(2)]];
+};
+
+struct UIOut
+{
+    float4 		oPosition [[position]];
+    float2 		oTex;
+    float4 		oColor;
+};
+
+vertex UIOut UIVertexShader(UIVertex vert [[stage_in]], constant VertexShaderConstantBuffer *constants [[buffer(2)]])
+{
+    UIOut out;
+    out.oPosition = constants->Projection * constants->View * float4(vert.vPos, 1.0);
+    out.oTex = vert.vTex;
+    out.oColor = float4(vert.vCol) / 255.0;
+    return out;
+}
+
+fragment float4 UIPixelShader(UIOut in [[stage_in]], texture2d<float> uiTexture [[texture(0)]])
+{
+	const float4 sample = uiTexture.sample(uiTextureSampler, in.oTex);
+    return sample * in.oColor;
+}
+
+fragment float4 UIPixelShaderUntextured(UIOut in [[stage_in]])
+{
+    return in.oColor;
+}

+ 13 - 0
ThirdParty/Jolt/Assets/Shaders/MTL/VertexConstants.h

@@ -0,0 +1,13 @@
+struct VertexShaderConstantBuffer
+{
+	float4x4 	View;				// view matrix
+	float4x4 	Projection;		// projection matrix
+	float4x4 	LightView;			// view matrix of the light
+	float4x4 	LightProjection;	// projection matrix of the light
+};
+
+struct PixelShaderConstantBuffer
+{
+	float3		CameraPos;
+	float3		LightPos;
+};

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/FontPixelShader.frag → ThirdParty/Jolt/Assets/Shaders/VK/FontPixelShader.frag


+ 1 - 1
ThirdParty/Jolt/Assets/Shaders/FontVertexShader.vert → ThirdParty/Jolt/Assets/Shaders/VK/FontVertexShader.vert

@@ -1,6 +1,6 @@
 #version 450
 
-#include "VertexConstantsVK.h"
+#include "VertexConstants.h"
 
 layout(location = 0) in vec3 vPos;
 layout(location = 1) in vec2 vTex;

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/LinePixelShader.frag → ThirdParty/Jolt/Assets/Shaders/VK/LinePixelShader.frag


+ 1 - 1
ThirdParty/Jolt/Assets/Shaders/LineVertexShader.vert → ThirdParty/Jolt/Assets/Shaders/VK/LineVertexShader.vert

@@ -1,6 +1,6 @@
 #version 450
 
-#include "VertexConstantsVK.h"
+#include "VertexConstants.h"
 
 layout(location = 0) in vec3 iPosition;
 layout(location = 1) in vec4 iColor;

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/TriangleDepthPixelShader.frag → ThirdParty/Jolt/Assets/Shaders/VK/TriangleDepthPixelShader.frag


+ 1 - 1
ThirdParty/Jolt/Assets/Shaders/TriangleDepthVertexShader.vert → ThirdParty/Jolt/Assets/Shaders/VK/TriangleDepthVertexShader.vert

@@ -1,6 +1,6 @@
 #version 450
 
-#include "VertexConstantsVK.h"
+#include "VertexConstants.h"
 
 layout(location = 0) in vec3 vPos;
 layout(location = 1) in vec3 vNorm;

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/TrianglePixelShader.frag → ThirdParty/Jolt/Assets/Shaders/VK/TrianglePixelShader.frag


+ 1 - 1
ThirdParty/Jolt/Assets/Shaders/TriangleVertexShader.vert → ThirdParty/Jolt/Assets/Shaders/VK/TriangleVertexShader.vert

@@ -1,6 +1,6 @@
 #version 450
 
-#include "VertexConstantsVK.h"
+#include "VertexConstants.h"
 
 layout(location = 0) in vec3 vPos;
 layout(location = 1) in vec3 vNorm;

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/UIPixelShader.frag → ThirdParty/Jolt/Assets/Shaders/VK/UIPixelShader.frag


+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/UIPixelShaderUntextured.frag → ThirdParty/Jolt/Assets/Shaders/VK/UIPixelShaderUntextured.frag


+ 1 - 1
ThirdParty/Jolt/Assets/Shaders/UIVertexShader.vert → ThirdParty/Jolt/Assets/Shaders/VK/UIVertexShader.vert

@@ -1,6 +1,6 @@
 #version 450
 
-#include "VertexConstantsVK.h"
+#include "VertexConstants.h"
 
 layout(location = 0) in vec3 vPos;
 layout(location = 1) in vec2 vTex;

+ 0 - 0
ThirdParty/Jolt/Assets/Shaders/VertexConstantsVK.h → ThirdParty/Jolt/Assets/Shaders/VK/VertexConstants.h


+ 13 - 6
ThirdParty/Jolt/Build/CMakeLists.txt

@@ -65,6 +65,10 @@ option(USE_FMADD "Enable FMADD" ON)
 # See: https://caniuse.com/?search=WebAssembly%20SIMD (Safari got support in March 2023 and was the last major browser to get support).
 option(USE_WASM_SIMD "Enable SIMD for WASM" OFF)
 
+# Enable 64 bit WASM instead of the default 32 bit WASM. Note that this currently requires special commandline flags in browsers and nodejs to enable.
+# E.g. use 'node --experimental-wasm-memory64 UnitTests.js' to run the unit tests in nodejs in 64 bit.
+option(JPH_USE_WASM64 "Enable 64 bit WASM" OFF)
+
 # Enable all warnings
 option(ENABLE_ALL_WARNINGS "Enable all warnings and warnings as errors" ON)
 
@@ -107,7 +111,7 @@ include(CMakeDependentOption)
 cmake_dependent_option(USE_STATIC_MSVC_RUNTIME_LIBRARY "Use the static MSVC runtime library" ON "MSVC;NOT WINDOWS_STORE" OFF)
 
 # Enable Vulkan instead of DirectX
-cmake_dependent_option(JPH_ENABLE_VULKAN "Enable Vulkan" OFF "WIN32" ON)
+cmake_dependent_option(JPH_ENABLE_VULKAN "Enable Vulkan" ON "LINUX" OFF)
 
 # Determine which configurations exist
 if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) # Only do this when we're at the top level, see: https://gitlab.kitware.com/cmake/cmake/-/issues/24181
@@ -345,6 +349,10 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
 		target_include_directories(UnitTests PUBLIC ${UNIT_TESTS_ROOT})
 		target_link_libraries(UnitTests LINK_PUBLIC Jolt)
 
+		if (EMSCRIPTEN)
+			target_link_options(UnitTests PUBLIC -sSTACK_SIZE=1048576 -sINITIAL_MEMORY=134217728)
+		endif()
+
 		# Code coverage doesn't work when using precompiled headers
 		if (CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND MSVC)
 			# The Ninja Multi-Config generator errors out when selectively disabling precompiled headers for certain configurations.
@@ -385,6 +393,9 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
 			if (MSVC)
 				target_link_options(HelloWorld PUBLIC "/SUBSYSTEM:CONSOLE")
 			endif()
+			if (EMSCRIPTEN)
+				target_link_options(HelloWorld PUBLIC -sSTACK_SIZE=1048576 -sINITIAL_MEMORY=134217728)
+			endif()
 		endif()
 
 		if (TARGET_PERFORMANCE_TEST)
@@ -401,6 +412,7 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
 				target_link_options(PerformanceTest PUBLIC "SHELL:--preload-file ${PHYSICS_REPO_ROOT}/Assets/Human.tof@/Assets/Human.tof")
 				target_link_options(PerformanceTest PUBLIC "SHELL:--preload-file ${PHYSICS_REPO_ROOT}/Assets/Human/dead_pose1.tof@/Assets/Human/dead_pose1.tof")
 				target_link_options(PerformanceTest PUBLIC "SHELL:--preload-file ${PHYSICS_REPO_ROOT}/Assets/terrain2.bof@/Assets/terrain2.bof")
+				target_link_options(PerformanceTest PUBLIC -sSTACK_SIZE=1048576 -sINITIAL_MEMORY=134217728)
 			endif()
 			set_property(TARGET PerformanceTest PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${PHYSICS_REPO_ROOT}")
 		endif()
@@ -426,9 +438,4 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
 			endif()
 		endif()
 	endif()
-
-	# Copy the assets folder
-	if (TARGET_PERFORMANCE_TEST OR TEST_FRAMEWORK_AVAILABLE)
-		add_custom_command(TARGET Jolt PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${PHYSICS_REPO_ROOT}/Assets/ $<TARGET_FILE_DIR:Jolt>/Assets/)
-	endif()
 endif()

+ 3 - 2
ThirdParty/Jolt/Build/README.md

@@ -8,6 +8,7 @@ Each platform supports multiple build targets
 - Release - Release version of the library, no asserts but includes profiling support and can draw the world and simulation properties
 - ReleaseASAN - As Release but turns on Address Sanitizer (clang only) to find bugs
 - ReleaseUBSAN - As Release but turns on Undefined Behavior Sanitizer (clang only) to find bugs
+- ReleaseTSAN - As Release but turns on the Thread Sanitizer (clang only) to find bugs
 - ReleaseCoverage - As Release but turns on Coverage reporting (clang only) to find which areas of the code are not executed
 - Distribution - Shippable version of the library, turns off all debugging support
 
@@ -125,7 +126,7 @@ To implement your custom memory allocator override Allocate, Free, Reallocate, A
 </details>
 
 <details>
-	<summary>Linux</summary>
+	<summary>Linux (Ubuntu)</summary>
 	<ul>
 		<li>Install clang (apt-get install clang)</li>
 		<li>Install cmake (apt-get install cmake)</li>
@@ -152,7 +153,6 @@ To implement your custom memory allocator override Allocate, Free, Reallocate, A
 	<ul>
 		<li>Install XCode</li>
 		<li>Download CMake 3.23+ (https://cmake.org/download/)</li>
-		<li>If you want to build the Samples or JoltViewer, install the <a href="https://vulkan.lunarg.com/sdk/home#mac">Vulkan SDK</a></li>
 		<li>Run: ./cmake_xcode_macos.sh</li>
 		<li>This will open XCode with a newly generated project</li>
 		<li>Build and run the project</li>
@@ -187,6 +187,7 @@ To implement your custom memory allocator override Allocate, Free, Reallocate, A
 
 * A vcpkg package is available [here](https://github.com/microsoft/vcpkg/tree/master/ports/joltphysics).
 * A xmake package is available [here](https://github.com/xmake-io/xmake-repo/tree/dev/packages/j/joltphysics).
+* A conan package is available [here](https://conan.io/center/recipes/joltphysics)
 * Jolt has been verified to build with [ninja](https://ninja-build.org/) through CMake.
 
 ## Errors

+ 1 - 1
ThirdParty/Jolt/Build/iOS/JoltViewerInfo.plist

@@ -9,7 +9,7 @@
 	<key>CFBundleGetInfoString</key>
 	<string></string>
 	<key>CFBundleIconFile</key>
-	<string></string>
+	<string>icon.icns</string>
 	<key>CFBundleIdentifier</key>
 	<string>com.joltphysics.joltviewer</string>
 	<key>CFBundleInfoDictionaryVersion</key>

+ 1 - 1
ThirdParty/Jolt/Build/iOS/SamplesInfo.plist

@@ -9,7 +9,7 @@
 	<key>CFBundleGetInfoString</key>
 	<string></string>
 	<key>CFBundleIconFile</key>
-	<string></string>
+	<string>icon.icns</string>
 	<key>CFBundleIdentifier</key>
 	<string>com.joltphysics.samples</string>
 	<key>CFBundleInfoDictionaryVersion</key>

BIN
ThirdParty/Jolt/Build/macOS/icon.icns


+ 1 - 1
ThirdParty/Jolt/Build/macos_install_vulkan_sdk.sh

@@ -9,5 +9,5 @@ VULKAN_TEMP=/tmp/vulkan_sdk_install
 mkdir ${VULKAN_TEMP}
 curl -L -o ${VULKAN_TEMP}/vulkan_sdk.dmg https://sdk.lunarg.com/sdk/download/latest/mac/vulkan_sdk.dmg?Human=true
 unzip ${VULKAN_TEMP}/vulkan_sdk.dmg -d ${VULKAN_TEMP}
-${VULKAN_TEMP}/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $1 --accept-licenses --default-answer --confirm-command install
+${VULKAN_TEMP}/InstallVulkan*.app/Contents/MacOS/InstallVulkan* --root $1 --accept-licenses --default-answer --confirm-command install
 rm -rf ${VULKAN_TEMP}

+ 3 - 0
ThirdParty/Jolt/Docs/APIChanges.md

@@ -6,6 +6,9 @@ Changes that make some state saved through SaveBinaryState from a prior version
 
 ## Changes between v5.2.0 and latest
 
+* 20250131 - PhysicsSettings::mManifoldToleranceSq is no longer squared and now called mManifoldTolerance. ManifoldBetweenTwoFaces now takes inMaxContactDistance instead of inMaxContactDistanceSq. (7611a4cb33b15fcb9108794ecb6fc5090470a438)
+* 20250108 - CharacterVirtual::Contact::mHadCollision is now true for sensor contacts (mIsSensorB). Make sure you ignore all discarded contacts (mWasDiscarded) when using CharacterVirtual::GetActiveContacts. (0ce60932501cdadcb8b209b3e03c143fac4cbcd6)
+* 20250108 - CharacterContactListener now has OnContactPersisted, OnContactRemoved, OnCharacterContactPersisted and OnCharacterContactRemoved functions. If you relied on OnContactAdded/OnCharacterContactAdded callbacks, you may want to call those functions from OnContactPersisted/OnCharacterContactPersisted to keep the behavior the same. (0ce60932501cdadcb8b209b3e03c143fac4cbcd6)
 * 20241221 - BodyInterface::AddForce applied a force per soft body vertex rather than to the whole body, this resulted in a soft body accelerating much more compared to a rigid body of the same mass. If you are applying forces to soft bodies, you need to multiply the force by the number of vertices of the soft body to get the same effect as before. (7850b05a97d2079fc52e538507c843026a555ef3)
 * 20241125 - *SBS* - Changed the binary serialization format of MeshShape to allow for bigger meshes of up to 110M triangles. (c738b3490c72cf868bdd704db7d0191b41541751)
 * 20241119 - Removed the use of std::unordered_map and std::unordered_set and replaced them with our own implementation: UnorderedMap and UnorderedSet. The public facing interface includes some instances of these, e.g. Shape::ShapeToIDMap. Since these are typedeffed and the interface remained the same, applications should not notice the change. (f1420822d39c440492602b670eac8ae2f5821401)

+ 24 - 1
ThirdParty/Jolt/Docs/Architecture.md

@@ -182,6 +182,23 @@ An example of saving a shape in binary format:
 
 As the library does not offer an exporter from content creation packages and since most games will have their own content pipeline, we encourage you to store data in your own format, cook data while cooking the game data and store the result using the SaveBinaryState interface (and provide a way to force a re-cook when the library is updated).
 
+A possible pattern for serializing binary data in your own engine could be:
+
+* EngineBody at runtime creates a Body. Note that the prefix 'Engine' means that it's a class in your own engine.
+* It links to an EngineShape, which wraps a Shape.
+* EngineShape comes in different flavors, e.g. EngineMeshShape, EngineSphereShape etc.
+* EngineMeshShape contains the uncompressed mesh data (in a format that's editable in your tools).
+* When 'cooking' the game data:
+  * Create a MeshShape.
+  * Save it using Shape::SaveWithChildren in a binary blob that's associated with the EngineMeshShape (could be in an attribute that's an array of bytes).
+  * Throw away the uncompressed mesh data.
+* When loading the EngineMeshShape using your own serialization system, also restore the MeshShape from the binary blob using Shape::sRestoreWithChildren.
+* Your serialization system should take care that the pointer between EngineBody and EngineShape is restored.
+* There are some tricks for sharing Shapes, e.g. an EngineCompoundShape links to multiple child EngineShapes:
+  * At cooking time create a StaticCompoundShape.
+  * Before writing the shape to the binary blob with Shape::SaveWithChildren it inserts all leaf shapes (the Shape associated with the child EngineShape) in the Shape::ShapeToIDMap so they won't be included in the binary blob.
+  * Before loading the binary blob with Shape::sRestoreWithChildren prepopulate the Shape::IDToShapeMap with the pointers to the restored Shape's from the child EngineShapes (this again assumes that your own serialization system is capable of restoring the pointers between EngineCompoundShape and the child EntityShapes).
+
 ### Convex Radius {#convex-radius}
 
 In order to speed up the collision detection system, all convex shapes use a convex radius. The provided shape will first be shrunken by the convex radius and then inflated again by the same amount, resulting in a rounded off shape:
@@ -283,6 +300,11 @@ To create a sensor, either set [BodyCreationSettings::mIsSensor](@ref BodyCreati
 
 To make sensors detect collisions with static objects, set the [BodyCreationSettings::mCollideKinematicVsNonDynamic](@ref BodyCreationSettings::mCollideKinematicVsNonDynamic) to true or call [Body::SetCollideKinematicVsNonDynamic](@ref Body::SetCollideKinematicVsNonDynamic). Note that it can place a large burden on the collision detection system if you have a large sensor intersect with e.g. a large mesh terrain or a height field as you will get many contact callbacks and these contacts will take up a lot of space in the contact cache. Ensure that your sensor is in an object layer that collides with as few static bodies as possible.
 
+To temporarily disable a sensor, choose between:
+
+* Remove the sensor by calling BodyInterface::RemoveBody and re-add it later again with BodyInterface::AddBody.
+* Change the collision layer using BodyInterface::SetObjectLayer to a layer that doesn't collide with anything (possibly also in a BroadPhaseLayer that doesn't collide with anything)
+
 ## Sleeping {#sleeping-bodies}
 
 During the simulation step, bodies are divided in 'islands'. Each island consists of a set of dynamic bodies that are either in contact with each other, or that are connected through a constraint:
@@ -635,7 +657,8 @@ It is quite difficult to verify cross platform determinism, so this feature is l
 * Linux gcc RISC-V 64-bit
 * Linux gcc PowerPC (Little Endian) 64-bit
 * Linux gcc LoongArch 64-bit
-* WASM emscripten running in nodejs
+* WASM32 emscripten running in nodejs
+* WASM64 emscripten running in nodejs
 
 The most important things to look out for in your own application:
 

+ 2 - 0
ThirdParty/Jolt/Docs/ProjectsUsingJolt.md

@@ -2,6 +2,7 @@
 
 * [Dagor Engine](https://github.com/GaijinEntertainment/DagorEngine) - An open source engine used by [War Thunder](https://warthunder.com/). See [here](https://github.com/GaijinEntertainment/DagorEngine/tree/main/prog/engine/phys/physJolt).
 * [ezEngine](https://github.com/ezEngine/ezEngine) - An open source C++ game engine.
+* [GDevelop](https://gdevelop.io/) - An open-source, no-code game engine. See [this](https://blog.blips.fm/articles/gdevelop-55-released-with-enhanced-3d-support) announcement.
 * [Godot Jolt](https://github.com/godot-jolt/godot-jolt) - Godot extension that integrates the Jolt physics engine
 * [Horizon Forbidden West](https://www.playstation.com/en-us/games/horizon-forbidden-west/) - An open world action RPG adventure.
 * [HypeHype](https://www.hypehype.com/) - A mobile app to create, remix and play games. See [this](https://twitter.com/SebAaltonen/status/1726871354228482237) X post.
@@ -11,6 +12,7 @@
 * [Sceneri](https://www.sceneri.com/) - A mobile app for creating and sharing 3D games and experiences. See [this](https://www.sceneri.com/blog/2023-07-27-jolt-physics-bringing-sceneris-worlds-to-life) blog post.
 * [Substrata](https://substrata.info/) - A metaverse platform.
 * [Supernova Engine](https://www.supernovaengine.org/) - Game engine for 2D and 3D projects with entity component system (ECS) and data-oriented design.
+* [Traktor Engine](https://github.com/apistol78/traktor/) - An open-source 3d game engine written in C++.
 * [VPhysics Jolt](https://github.com/Joshua-Ashton/VPhysics-Jolt), a replacement for Ipion Virtual Physics in the Source Engine. Can be used in e.g. [Garry's Mod](https://store.steampowered.com/app/4000/Garrys_Mod/).
 * [Wicked Engine](https://wickedengine.net/) - 3D engine with modern graphics. See [X post](https://x.com/turanszkij/status/1805979390557528217) and [github](https://github.com/turanszkij/WickedEngine/blob/master/WickedEngine/wiPhysics_Jolt.cpp).
 * [X4 Foundations](https://store.steampowered.com/app/392160/X4_Foundations/) - A space simulation game. See [this](https://forum.egosoft.com/viewtopic.php?t=451046) announcement.

+ 22 - 3
ThirdParty/Jolt/Docs/ReleaseNotes.md

@@ -15,8 +15,17 @@ For breaking API changes see [this document](https://github.com/jrouwe/JoltPhysi
 * Added an example of a body that's both a sensor and a rigid body in `ContactListenerTest`.
 * Added binary serialization to `SkeletalAnimation`.
 * Added support for RISC-V, LoongArch and PowerPC (Little Endian) CPUs.
-* Added the ability to add a sub shape at a specified index in a MutableCompoundShape rather than at the end.
-* The Samples and JoltViewer can run on Linux/macOS using Vulkan now. Make sure to install the Vulkan SDK before compiling (see: Build/ubuntu24_install_vulkan_sdk.sh or [download](https://vulkan.lunarg.com/sdk/home) the SDK).
+* Added support for WASM64.
+* Added the ability to add a sub shape at a specified index in a `MutableCompoundShape` rather than at the end.
+* The Samples and JoltViewer can run on Linux using Vulkan. Make sure to install the Vulkan SDK before compiling (see: `Build/ubuntu24_install_vulkan_sdk.sh`).
+* The Samples and JoltViewer can run on macOS using Metal.
+* Added `STLLocalAllocator` which is an allocator that can be used in e.g. the Array class. It keeps a fixed size buffer for N elements and only when it runs out of space falls back to the heap.
+* Added support for `CharacterVirtual` to override the inner rigid body ID. This can be used to make the simulation deterministic in e.g. client/server setups.
+* Added `OnContactPersisted`, `OnContactRemoved`, `OnCharacterContactPersisted` and `OnCharacterContactRemoved` functions on `CharacterContactListener` to better match the interface of `ContactListener`.
+* Every `CharacterVirtual` now has a `CharacterID`. This ID can be used to identify the character after removal and is used to make the simulation deterministic in case a character collides with multiple other virtual characters.
+* Added overridable `CollisionCollector::OnBodyEnd` that is called after all hits for a body have been processed when collecting hits through `NarrowPhaseQuery`.
+* Added `ClosestHitPerBodyCollisionCollector` which will report the closest / deepest hit per body that the collision query collides with.
+* Added `PhysicsSystem::SetSimCollideBodyVsBody`. This allows overriding the collision detection between two bodies. It can be used to only store the 1st hit for sensor collisions. This makes sensors cheaper if you only need to know if there is an overlap or not. An example can be found in `SimCollideBodyVsBodyTest`.
 
 ### Bug fixes
 
@@ -25,7 +34,17 @@ For breaking API changes see [this document](https://github.com/jrouwe/JoltPhysi
 * Added overloads for placement new in the `JPH_OVERRIDE_NEW_DELETE` macro, this means it is no longer needed to do `:: new (address) JPH::class_name(constructor_arguments)` but you can do `new (address) JPH::class_name(constructor_arguments)`.
 * Fixed a GCC warning `-Wshadow=global`.
 * BodyInterface::AddForce applied a force per soft body vertex rather than to the whole body, this resulted in a soft body accelerating much more compared to a rigid body of the same mass.
-* Removing a sub shape from a MutableCompoundShape would not update the bounding box if the last shape was removed, which can result in a small performance loss.
+* Removing a sub shape from a `MutableCompoundShape` would not update the bounding box if the last shape was removed, which can result in a small performance loss.
+* VehicleConstraint would override `Body::SetAllowSleeping` every frame, making it impossible for client code to configure a vehicle that cannot go to sleep.
+* Fixed `CharacterVirtual::Contact::mIsSensorB` not being persisted in SaveState.
+* Fixed `CharacterVirtual::Contact::mHadContact` not being true for collisions with sensors. They will still be marked as mWasDiscarded to prevent any further interaction.
+* Fixed Character::SetShape failing to switch when standing inside a sensor / Character::PostSimulation finding a sensor as ground collision.
+* Fixed numerical inaccuracy in penetration depth calculation when `CollideShapeSettings::mMaxSeparationDistance` was set to a really high value (e.g. 1000).
+* Bugfix in `Semaphore::Acquire` for non-windows platform. The count was updated before waiting, meaning that the counter would become -(number of waiting threads) and the semaphore would not wake up until at least the same amount of releases was done. In practice this meant that the main thread had to do the last (number of threads) jobs, slowing down the simulation a bit.
+* An empty `MutableCompoundShape` now returns the same local bounding box as `EmptyShape` (a point at (0, 0, 0)). This prevents floating point overflow exceptions.
+* Fixed a bug in ManifoldBetweenTwoFaces that led to incorrect `ContactManifold::mRelativeContactPointsOn2` when the contact normal and the face normal were not roughly parallel. Also it led to possibly jitter in the simulation in that case.
+* Fixed InternalEdgeRemovingCollector not working when colliding with a very dense triangle grid because it ran out of internal space. Now falling back to memory allocations when this happens to avoid ghost collisions.
+* Fixed running out of stack space when simulating a really high number of active rigid bodies.
 
 ## v5.2.0
 

+ 1 - 1
ThirdParty/Jolt/Docs/Samples.md

@@ -1,6 +1,6 @@
 # Jolt Physics Samples
 
-This document describes the demos in the Samples application (currently compiles only under Windows). When you run the samples application the application will initially start paused, press P to unpause it. The menu is accessible through pressing ESC, it has the following options:
+This document describes the demos in the Samples application. When you run the samples application the application will initially start paused, press P to unpause it. The menu is accessible through pressing ESC, it has the following options:
 
 * Select Test - This allows you to select between the different types of physics tests
 * Test Settings - Some tests will allow extra configuration, if not this setting will be greyed out

+ 1 - 1
ThirdParty/Jolt/Jolt/Core/Color.h

@@ -12,7 +12,7 @@ class Color;
 using ColorArg = Color;
 
 /// Class that holds an RGBA color with 8-bits per component
-class [[nodiscard]] JPH_EXPORT_GCC_BUG_WORKAROUND Color
+class JPH_EXPORT_GCC_BUG_WORKAROUND [[nodiscard]] Color
 {
 public:
 	/// Constructors

Some files were not shown because too many files changed in this diff