From c5ac1428885c44688d6ce359e573225e7f036032 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Wed, 15 Mar 2023 13:44:58 +0100 Subject: [PATCH] Add JoltPhysics3D for a performance test --- examples/PhysicsPlayground/main.cpp | 360 ++++++++++++++++++ examples/PhysicsPlayground/xmake.lua | 5 + include/Nazara/BulletPhysics3D.hpp | 10 +- .../BulletPhysics3D/BulletCollider3D.hpp | 48 +-- .../BulletPhysics3D/BulletRigidBody3D.hpp | 1 + .../Systems/BulletPhysics3DSystem.hpp | 6 + include/Nazara/JoltPhysics3D.hpp | 47 +++ include/Nazara/JoltPhysics3D/Components.hpp | 34 ++ .../Components/JoltRigidBody3DComponent.hpp | 32 ++ .../Components/JoltRigidBody3DComponent.inl | 11 + include/Nazara/JoltPhysics3D/Config.hpp | 48 +++ include/Nazara/JoltPhysics3D/ConfigCheck.hpp | 10 + include/Nazara/JoltPhysics3D/Debug.hpp | 5 + include/Nazara/JoltPhysics3D/DebugOff.hpp | 5 + include/Nazara/JoltPhysics3D/Enums.hpp | 22 ++ .../Nazara/JoltPhysics3D/JoltCollider3D.hpp | 123 ++++++ .../Nazara/JoltPhysics3D/JoltCollider3D.inl | 12 + .../Nazara/JoltPhysics3D/JoltConstraint3D.hpp | 75 ++++ .../Nazara/JoltPhysics3D/JoltConstraint3D.inl | 27 ++ .../Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp | 72 ++++ .../Nazara/JoltPhysics3D/JoltPhysics3D.hpp | 44 +++ .../Nazara/JoltPhysics3D/JoltRigidBody3D.hpp | 90 +++++ .../Nazara/JoltPhysics3D/JoltRigidBody3D.inl | 25 ++ include/Nazara/JoltPhysics3D/Systems.hpp | 34 ++ .../Systems/JoltPhysics3DSystem.hpp | 71 ++++ .../Systems/JoltPhysics3DSystem.inl | 26 ++ .../BulletPhysics3D/BulletCollider3D.cpp | 114 +++--- .../BulletPhysics3D/BulletPhysWorld3D.cpp | 15 +- .../BulletPhysics3D/BulletRigidBody3D.cpp | 13 +- .../Systems/BulletPhysics3DSystem.cpp | 32 +- .../Components/JoltRigidBody3DComponent.cpp | 11 + src/Nazara/JoltPhysics3D/JoltCollider3D.cpp | 214 +++++++++++ src/Nazara/JoltPhysics3D/JoltConstraint3D.cpp | 125 ++++++ src/Nazara/JoltPhysics3D/JoltHelper.hpp | 31 ++ src/Nazara/JoltPhysics3D/JoltHelper.inl | 60 +++ src/Nazara/JoltPhysics3D/JoltPhysWorld3D.cpp | 284 ++++++++++++++ src/Nazara/JoltPhysics3D/JoltPhysics3D.cpp | 62 +++ src/Nazara/JoltPhysics3D/JoltRigidBody3D.cpp | 325 ++++++++++++++++ .../Systems/JoltPhysics3DSystem.cpp | 108 ++++++ xmake.lua | 13 +- 40 files changed, 2555 insertions(+), 95 deletions(-) create mode 100644 examples/PhysicsPlayground/main.cpp create mode 100644 examples/PhysicsPlayground/xmake.lua create mode 100644 include/Nazara/JoltPhysics3D.hpp create mode 100644 include/Nazara/JoltPhysics3D/Components.hpp create mode 100644 include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp create mode 100644 include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.inl create mode 100644 include/Nazara/JoltPhysics3D/Config.hpp create mode 100644 include/Nazara/JoltPhysics3D/ConfigCheck.hpp create mode 100644 include/Nazara/JoltPhysics3D/Debug.hpp create mode 100644 include/Nazara/JoltPhysics3D/DebugOff.hpp create mode 100644 include/Nazara/JoltPhysics3D/Enums.hpp create mode 100644 include/Nazara/JoltPhysics3D/JoltCollider3D.hpp create mode 100644 include/Nazara/JoltPhysics3D/JoltCollider3D.inl create mode 100644 include/Nazara/JoltPhysics3D/JoltConstraint3D.hpp create mode 100644 include/Nazara/JoltPhysics3D/JoltConstraint3D.inl create mode 100644 include/Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp create mode 100644 include/Nazara/JoltPhysics3D/JoltPhysics3D.hpp create mode 100644 include/Nazara/JoltPhysics3D/JoltRigidBody3D.hpp create mode 100644 include/Nazara/JoltPhysics3D/JoltRigidBody3D.inl create mode 100644 include/Nazara/JoltPhysics3D/Systems.hpp create mode 100644 include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp create mode 100644 include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.inl create mode 100644 src/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.cpp create mode 100644 src/Nazara/JoltPhysics3D/JoltCollider3D.cpp create mode 100644 src/Nazara/JoltPhysics3D/JoltConstraint3D.cpp create mode 100644 src/Nazara/JoltPhysics3D/JoltHelper.hpp create mode 100644 src/Nazara/JoltPhysics3D/JoltHelper.inl create mode 100644 src/Nazara/JoltPhysics3D/JoltPhysWorld3D.cpp create mode 100644 src/Nazara/JoltPhysics3D/JoltPhysics3D.cpp create mode 100644 src/Nazara/JoltPhysics3D/JoltRigidBody3D.cpp create mode 100644 src/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.cpp diff --git a/examples/PhysicsPlayground/main.cpp b/examples/PhysicsPlayground/main.cpp new file mode 100644 index 000000000..a947cc2f7 --- /dev/null +++ b/examples/PhysicsPlayground/main.cpp @@ -0,0 +1,360 @@ +// Sources pour https://github.com/NazaraEngine/NazaraEngine/wiki/(FR)-Tutoriel:-%5B01%5D-Hello-World + +#define USE_JOLT 0 + +#include +#include +#include +#if USE_JOLT +#include +#else +#include +#endif +#include +#include +#include +#include + +constexpr float BoxDims = 16.f; + +int main() +{ + // Mise en place de l'application, de la fenêtre et du monde + Nz::Renderer::Config renderConfig; + //renderConfig.preferredAPI = Nz::RenderAPI::OpenGL; + +#if USE_JOLT + Nz::Application app(renderConfig); +#else + Nz::Application app(renderConfig); +#endif + + auto& windowing = app.AddComponent(); + Nz::Window& mainWindow = windowing.CreateWindow(Nz::VideoMode(1920, 1080), "Physics playground"); + + auto& fs = app.AddComponent(); + { + std::filesystem::path resourceDir = "assets/examples"; + if (!std::filesystem::is_directory(resourceDir) && std::filesystem::is_directory("../.." / resourceDir)) + resourceDir = "../.." / resourceDir; + + fs.Mount("assets", resourceDir); + } + + auto& ecs = app.AddComponent(); + auto& world = ecs.AddWorld(); + +#if USE_JOLT + auto& physSystem = world.AddSystem(); +#else + auto& physSystem = world.AddSystem(); +#endif + physSystem.GetPhysWorld().SetMaxStepCount(1); + //physSystem.GetPhysWorld().SetGravity(Nz::Vector3f::Down() * 9.81f); + physSystem.GetPhysWorld().SetGravity(Nz::Vector3f::Zero()); + + auto& renderSystem = world.AddSystem(); + Nz::WindowSwapchain& windowSwapchain = renderSystem.CreateSwapchain(mainWindow); + + Nz::Vector3f target = Nz::Vector3f::Zero(); + + entt::handle boxEntity = world.CreateEntity(); + { + std::shared_ptr boxMesh = Nz::GraphicalMesh::Build(Nz::Primitive::Box(Nz::Vector3f(BoxDims), Nz::Vector3ui::Zero(), Nz::Matrix4f::Scale(Nz::Vector3f(-1.f)), Nz::Rectf(0.f, 0.f, 2.f, 2.f))); + + Nz::TextureSamplerInfo planeSampler; + planeSampler.anisotropyLevel = 16; + planeSampler.wrapModeU = Nz::SamplerWrap::Repeat; + planeSampler.wrapModeV = Nz::SamplerWrap::Repeat; + + std::shared_ptr boxMat = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate(); + boxMat->SetTextureProperty("BaseColorMap", fs.Load("assets/dev_grey.png"), planeSampler); + boxMat->DisablePass("ShadowPass"); + boxMat->UpdatePassesStates([&](Nz::RenderStates& states) + { + states.frontFace = Nz::FrontFace::Clockwise; + }); + + std::shared_ptr boxModel = std::make_shared(std::move(boxMesh)); + boxModel->SetMaterial(0, std::move(boxMat)); + + auto& boxGfx = boxEntity.emplace(); + boxGfx.AttachRenderable(std::move(boxModel)); + + boxEntity.emplace(); + +#if USE_JOLT + std::shared_ptr wallCollider = std::make_shared(Nz::Vector3f(BoxDims, BoxDims, 1.f)); +#else + std::shared_ptr wallCollider = std::make_shared(Nz::Vector3f(BoxDims, BoxDims, 1.f)); +#endif + +#if USE_JOLT + std::vector colliders; +#else + std::vector colliders; +#endif + + for (Nz::Vector3f normal : { Nz::Vector3f::Forward(), Nz::Vector3f::Backward(), Nz::Vector3f::Left(), Nz::Vector3f::Right(), Nz::Vector3f::Up(), Nz::Vector3f::Down() }) + { + auto& colliderEntry = colliders.emplace_back(); + colliderEntry.collider = wallCollider; +#if USE_JOLT + colliderEntry.rotation = Nz::Quaternionf::RotationBetween(Nz::Vector3f::Forward(), normal); + colliderEntry.offset = normal * BoxDims * 0.5f + normal * 0.5f; +#else + colliderEntry.offsetMatrix = Nz::Matrix4f::Transform(normal * BoxDims * 0.5f + normal * 0.5f, Nz::Quaternionf::RotationBetween(Nz::Vector3f::Forward(), normal)); +#endif + } + +#if USE_JOLT + std::shared_ptr boxCollider = std::make_shared(std::move(colliders)); +#else + std::shared_ptr boxCollider = std::make_shared(std::move(colliders)); +#endif + +#if USE_JOLT + auto& ballPhysics = boxEntity.emplace(physSystem.CreateRigidBody(boxCollider)); +#else + auto& ballPhysics = boxEntity.emplace(physSystem.CreateRigidBody(boxCollider)); +#endif + ballPhysics.SetMass(0.f); + + std::shared_ptr colliderModel; + { + std::shared_ptr colliderMat = Nz::Graphics::Instance()->GetDefaultMaterials().basicMaterial->Instantiate(); + colliderMat->SetValueProperty("BaseColor", Nz::Color::Green()); + colliderMat->UpdatePassesStates([](Nz::RenderStates& states) + { + states.primitiveMode = Nz::PrimitiveMode::LineList; + return true; + }); + + /*std::shared_ptr colliderMesh = Nz::Mesh::Build(boxCollider->GenerateDebugMesh()); + std::shared_ptr colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh); + + colliderModel = std::make_shared(colliderGraphicalMesh); + for (std::size_t i = 0; i < colliderModel->GetSubMeshCount(); ++i) + colliderModel->SetMaterial(i, colliderMat); + + boxGfx.AttachRenderable(std::move(colliderModel));*/ + } + } + + std::shared_ptr sphereMesh = Nz::GraphicalMesh::Build(Nz::Primitive::IcoSphere(1.f)); + + //std::mt19937 rd(std::random_device{}()); + std::mt19937 rd(42); + std::uniform_real_distribution colorDis(0.f, 360.f); + std::uniform_real_distribution radiusDis(0.05f, 0.5f); + + constexpr std::size_t SphereCount = 3000; + for (std::size_t i = 0; i < SphereCount; ++i) + { + float radius = radiusDis(rd); + std::uniform_real_distribution positionRandom(-BoxDims * 0.5f + radius, BoxDims * 0.5f - radius); + +#if USE_JOLT + std::shared_ptr sphereCollider = std::make_shared(radius); +#else + std::shared_ptr sphereCollider = std::make_shared(radius); +#endif + + entt::handle ballEntity = world.CreateEntity(); + + std::shared_ptr ballMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate(); + ballMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f)); + + std::shared_ptr sphereModel = std::make_shared(sphereMesh); + sphereModel->SetMaterial(0, std::move(ballMaterial)); + + auto& ballGfx = ballEntity.emplace(); + ballGfx.AttachRenderable(std::move(sphereModel)); + + auto& ballNode = ballEntity.emplace(); + ballNode.SetPosition(positionRandom(rd), positionRandom(rd), positionRandom(rd)); + ballNode.SetScale(radius); + +#if USE_JOLT + auto& ballPhysics = ballEntity.emplace(physSystem.CreateRigidBody(sphereCollider)); +#else + auto& ballPhysics = ballEntity.emplace(physSystem.CreateRigidBody(sphereCollider)); +#endif + //ballPhysics.SetMass(4.f / 3.f * Nz::Pi * Nz::IntegralPow(radius, 3)); + ballPhysics.DisableSleeping(); + } + + std::uniform_real_distribution lengthDis(0.1f, 1.f); + std::shared_ptr boxMesh = Nz::GraphicalMesh::Build(Nz::Primitive::Box(Nz::Vector3f(1.f))); + + constexpr std::size_t BoxCount = 100; + for (std::size_t i = 0; i < BoxCount; ++i) + { + float width = lengthDis(rd); + float height = lengthDis(rd); + float depth = lengthDis(rd); + + std::uniform_real_distribution xRandom(-BoxDims * 0.5f + width, BoxDims * 0.5f - width); + std::uniform_real_distribution yRandom(-BoxDims * 0.5f + height, BoxDims * 0.5f - height); + std::uniform_real_distribution zRandom(-BoxDims * 0.5f + depth, BoxDims * 0.5f - depth); + + entt::handle ballEntity = world.CreateEntity(); + + std::shared_ptr boxMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate(); + boxMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f)); + + std::shared_ptr sphereModel = std::make_shared(boxMesh); + sphereModel->SetMaterial(0, std::move(boxMaterial)); + + auto& ballGfx = ballEntity.emplace(); + ballGfx.AttachRenderable(std::move(sphereModel)); + + auto& ballNode = ballEntity.emplace(); + ballNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd)); + ballNode.SetScale(width, height, depth); + +#if USE_JOLT + std::shared_ptr boxCollider = std::make_shared(Nz::Vector3f(width, height, depth)); +#else + std::shared_ptr boxCollider = std::make_shared(Nz::Vector3f(width, height, depth)); +#endif + +#if USE_JOLT + auto& ballPhysics = ballEntity.emplace(physSystem.CreateRigidBody(boxCollider)); +#else + auto& ballPhysics = ballEntity.emplace(physSystem.CreateRigidBody(boxCollider)); +#endif + //ballPhysics.SetMass(width * height * depth); + ballPhysics.DisableSleeping(); + } + + // Lumière + entt::handle lightEntity = world.CreateEntity(); + { + auto& lightNode = lightEntity.emplace(); + //lightNode.SetPosition(Nz::Vector3f(-20.f, 20.f, -20.f)); + //lightNode.SetRotation(Nz::EulerAnglesf(-45.f, -135.f, 0.f)); + lightNode.SetPosition(Nz::Vector3f::Up() * 15.f); + lightNode.SetRotation(Nz::Quaternionf::RotationBetween(Nz::Vector3f::Forward(), Nz::Vector3f::Down())); + + auto& lightComp = lightEntity.emplace(); + auto& spotLight = lightComp.AddLight(); + spotLight.EnableShadowCasting(true); + spotLight.UpdateInnerAngle(Nz::DegreeAnglef(30.f)); + spotLight.UpdateOuterAngle(Nz::DegreeAnglef(40.f)); + spotLight.UpdateRadius(30.f); + spotLight.UpdateShadowMapSize(2048); + spotLight.UpdateAmbientFactor(0.5f); + } + + Nz::EulerAnglesf camAngles(-45.f, -135.f, 0.f); + float camDistance = 12.f; + + // Création de la caméra + entt::handle cameraEntity = world.CreateEntity(); + { + cameraEntity.emplace(); + + auto& cameraComponent = cameraEntity.emplace(&windowSwapchain, Nz::ProjectionType::Perspective); + cameraComponent.UpdateFOV(70.f); + cameraComponent.UpdateClearColor(Nz::Color(0.46f, 0.48f, 0.84f, 1.f)); + } + + auto UpdateCamera = [&] + { + auto& cameraNode = cameraEntity.get(); + cameraNode.SetRotation(camAngles); + cameraNode.SetPosition(target - cameraNode.GetForward() * camDistance); + }; + UpdateCamera(); + + NazaraSlot(Nz::WindowEventHandler, OnMouseMoved, cameraMove); + NazaraSlot(Nz::WindowEventHandler, OnMouseMoved, grabbedObjectMove); + //std::optional grabConstraint; + + Nz::WindowEventHandler& eventHandler = mainWindow.GetEventHandler(); + eventHandler.OnMouseButtonPressed.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseButtonEvent& event) + { + if (event.button == Nz::Mouse::Middle) + { + cameraMove.Connect(eventHandler.OnMouseMoved, [&](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseMoveEvent& event) + { + constexpr float sensitivity = 0.3f; + + camAngles.yaw -= event.deltaX * sensitivity; + camAngles.yaw.Normalize(); + + camAngles.pitch = Nz::Clamp(camAngles.pitch - event.deltaY * sensitivity, -89.f, 89.f); + UpdateCamera(); + }); + } + else if (event.button == Nz::Mouse::Left) + { + auto& cameraNode = cameraEntity.get(); + auto& cameraComponent = cameraEntity.get(); + + Nz::Vector3f from = cameraComponent.Unproject({ float(event.x), float(event.y), 0.f }); + Nz::Vector3f to = cameraComponent.Unproject({ float(event.x), float(event.y), 1.f }); + + /*Nz::JoltPhysics3DSystem::RaycastHit hitInfo; + if (physSystem.RaycastQueryFirst(from, to, &hitInfo)) + { + if (hitInfo.hitBody) + { + grabConstraint.emplace(*hitInfo.hitBody, hitInfo.hitPosition); + + grabbedObjectMove.Connect(eventHandler.OnMouseMoved, [&, body = hitInfo.hitBody, distance = Nz::Vector3f::Distance(from, hitInfo.hitPosition)](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseMoveEvent& event) + { + Nz::Vector3f from = cameraComponent.Unproject({ float(event.x), float(event.y), 0.f }); + Nz::Vector3f to = cameraComponent.Unproject({ float(event.x), float(event.y), 1.f }); + + Nz::Vector3f newPosition = from + (to - from).Normalize() * distance; + grabConstraint->SetSecondAnchor(newPosition); + }); + } + }*/ + } + }); + + eventHandler.OnMouseButtonReleased.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseButtonEvent& event) + { + if (event.button == Nz::Mouse::Left) + { + //grabConstraint.reset(); + grabbedObjectMove.Disconnect(); + } + else if (event.button == Nz::Mouse::Middle) + cameraMove.Disconnect(); + }); + + eventHandler.OnMouseWheelMoved.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::MouseWheelEvent& event) + { + camDistance = Nz::Clamp(camDistance - event.delta, 5.f, 20.f); + UpdateCamera(); + }); + + eventHandler.OnKeyReleased.Connect([&](const Nz::WindowEventHandler*, const Nz::WindowEvent::KeyEvent& event) + { + if (event.virtualKey == Nz::Keyboard::VKey::G) + { + auto& cameraNode = cameraEntity.get(); + + physSystem.GetPhysWorld().SetGravity(cameraNode.GetBackward() * 9.81f); + } + }); + + Nz::MillisecondClock fpsClock; + unsigned int fps = 0; + app.AddUpdater([&](Nz::Time /*elapsedTime*/) + { + fps++; + if (fpsClock.RestartIfOver(Nz::Time::Second())) + { + mainWindow.SetTitle("Physics playground - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(world.GetRegistry().alive()) + " entities"); + physSystem.Dump(); + fps = 0; + } + }); + + return app.Run(); +} diff --git a/examples/PhysicsPlayground/xmake.lua b/examples/PhysicsPlayground/xmake.lua new file mode 100644 index 000000000..310d1f998 --- /dev/null +++ b/examples/PhysicsPlayground/xmake.lua @@ -0,0 +1,5 @@ +target("PhysicsPlayground") + add_deps("NazaraGraphics", "NazaraBulletPhysics3D", "NazaraJoltPhysics3D") + add_packages("entt") + add_files("main.cpp") + add_defines("NAZARA_ENTT") diff --git a/include/Nazara/BulletPhysics3D.hpp b/include/Nazara/BulletPhysics3D.hpp index 1096362c2..0af8f73e5 100644 --- a/include/Nazara/BulletPhysics3D.hpp +++ b/include/Nazara/BulletPhysics3D.hpp @@ -26,16 +26,16 @@ #pragma once -#ifndef NAZARA_GLOBAL_PHYSICS3D_HPP -#define NAZARA_GLOBAL_PHYSICS3D_HPP +#ifndef NAZARA_GLOBAL_BULLETPHYSICS3D_HPP +#define NAZARA_GLOBAL_BULLETPHYSICS3D_HPP #include -#include #include -#include #include #include #include +#include +#include #ifdef NAZARA_ENTT @@ -44,4 +44,4 @@ #endif -#endif // NAZARA_GLOBAL_PHYSICS3D_HPP +#endif // NAZARA_GLOBAL_BULLETPHYSICS3D_HPP diff --git a/include/Nazara/BulletPhysics3D/BulletCollider3D.hpp b/include/Nazara/BulletPhysics3D/BulletCollider3D.hpp index c918c045f..2fe58cae5 100644 --- a/include/Nazara/BulletPhysics3D/BulletCollider3D.hpp +++ b/include/Nazara/BulletPhysics3D/BulletCollider3D.hpp @@ -62,11 +62,11 @@ namespace Nz static std::shared_ptr CreateGeomFromPrimitive(const Primitive& primitive); }; - class NAZARA_BULLETPHYSICS3D_API BoxCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletBoxCollider3D final : public BulletCollider3D { public: - BoxCollider3D(const Vector3f& lengths); - ~BoxCollider3D(); + BulletBoxCollider3D(const Vector3f& lengths); + ~BulletBoxCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -79,11 +79,11 @@ namespace Nz Vector3f m_lengths; }; - class NAZARA_BULLETPHYSICS3D_API CapsuleCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletCapsuleCollider3D final : public BulletCollider3D { public: - CapsuleCollider3D(float length, float radius); - ~CapsuleCollider3D(); + BulletCapsuleCollider3D(float length, float radius); + ~BulletCapsuleCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -98,13 +98,13 @@ namespace Nz float m_radius; }; - class NAZARA_BULLETPHYSICS3D_API CompoundCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletCompoundCollider3D final : public BulletCollider3D { public: struct ChildCollider; - CompoundCollider3D(std::vector childs); - ~CompoundCollider3D(); + BulletCompoundCollider3D(std::vector childs); + ~BulletCompoundCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -123,11 +123,11 @@ namespace Nz std::vector m_childs; }; - class NAZARA_BULLETPHYSICS3D_API ConeCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletConeCollider3D final : public BulletCollider3D { public: - ConeCollider3D(float length, float radius); - ~ConeCollider3D(); + BulletConeCollider3D(float length, float radius); + ~BulletConeCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -142,11 +142,11 @@ namespace Nz float m_radius; }; - class NAZARA_BULLETPHYSICS3D_API ConvexCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletConvexCollider3D final : public BulletCollider3D { public: - ConvexCollider3D(SparsePtr vertices, unsigned int vertexCount); - ~ConvexCollider3D(); + BulletConvexCollider3D(SparsePtr vertices, unsigned int vertexCount); + ~BulletConvexCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -157,11 +157,11 @@ namespace Nz std::unique_ptr m_shape; }; - class NAZARA_BULLETPHYSICS3D_API CylinderCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletCylinderCollider3D final : public BulletCollider3D { public: - CylinderCollider3D(float length, float radius); - ~CylinderCollider3D(); + BulletCylinderCollider3D(float length, float radius); + ~BulletCylinderCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -177,11 +177,11 @@ namespace Nz float m_radius; }; - class NAZARA_BULLETPHYSICS3D_API NullCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletNullCollider3D final : public BulletCollider3D { public: - NullCollider3D(); - ~NullCollider3D(); + BulletNullCollider3D(); + ~BulletNullCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; @@ -194,11 +194,11 @@ namespace Nz std::unique_ptr m_shape; }; - class NAZARA_BULLETPHYSICS3D_API SphereCollider3D final : public BulletCollider3D + class NAZARA_BULLETPHYSICS3D_API BulletSphereCollider3D final : public BulletCollider3D { public: - SphereCollider3D(float radius); - ~SphereCollider3D(); + BulletSphereCollider3D(float radius); + ~BulletSphereCollider3D(); void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; diff --git a/include/Nazara/BulletPhysics3D/BulletRigidBody3D.hpp b/include/Nazara/BulletPhysics3D/BulletRigidBody3D.hpp index 9f053673e..7533b3170 100644 --- a/include/Nazara/BulletPhysics3D/BulletRigidBody3D.hpp +++ b/include/Nazara/BulletPhysics3D/BulletRigidBody3D.hpp @@ -67,6 +67,7 @@ namespace Nz void SetMass(float mass); void SetMassCenter(const Vector3f& center); void SetPosition(const Vector3f& position); + void SetPositionAndRotation(const Vector3f& position, const Quaternionf& rotation); void SetRotation(const Quaternionf& rotation); Quaternionf ToLocal(const Quaternionf& worldRotation); diff --git a/include/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.hpp b/include/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.hpp index 3b3c8aa8f..93b1dd113 100644 --- a/include/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.hpp +++ b/include/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.hpp @@ -8,6 +8,7 @@ #define NAZARA_BULLETPHYSICS3D_SYSTEMS_BULLETPHYSICS3DSYSTEM_HPP #include +#include #include #include #include @@ -32,6 +33,8 @@ namespace Nz template BulletRigidBody3DComponent CreateRigidBody(Args&&... args); + void Dump(); + inline BulletPhysWorld3D& GetPhysWorld(); inline const BulletPhysWorld3D& GetPhysWorld() const; @@ -51,12 +54,15 @@ namespace Nz void OnConstruct(entt::registry& registry, entt::entity entity); void OnDestruct(entt::registry& registry, entt::entity entity); + std::size_t m_stepCount; std::vector m_physicsEntities; entt::registry& m_registry; entt::observer m_physicsConstructObserver; entt::scoped_connection m_constructConnection; entt::scoped_connection m_destructConnection; BulletPhysWorld3D m_physWorld; + Time m_physicsTime; + Time m_updateTime; }; } diff --git a/include/Nazara/JoltPhysics3D.hpp b/include/Nazara/JoltPhysics3D.hpp new file mode 100644 index 000000000..95a9585c5 --- /dev/null +++ b/include/Nazara/JoltPhysics3D.hpp @@ -0,0 +1,47 @@ +// this file was automatically generated and should not be edited + +/* + Nazara Engine - BulletPhysics3D module + + Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_GLOBAL_JOLTPHYSICS3D_HPP +#define NAZARA_GLOBAL_JOLTPHYSICS3D_HPP + +#include +#include +#include +#include +#include +#include +#include + +#ifdef NAZARA_ENTT + +#include +#include + +#endif + +#endif // NAZARA_GLOBAL_JOLTPHYSICS3D_HPP diff --git a/include/Nazara/JoltPhysics3D/Components.hpp b/include/Nazara/JoltPhysics3D/Components.hpp new file mode 100644 index 000000000..535114e54 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Components.hpp @@ -0,0 +1,34 @@ +// this file was automatically generated and should not be edited + +/* + Nazara Engine - BulletPhysics3D module + + Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_COMPONENTS_HPP +#define NAZARA_JOLTPHYSICS3D_COMPONENTS_HPP + +#include + +#endif // NAZARA_JOLTPHYSICS3D_COMPONENTS_HPP diff --git a/include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp b/include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp new file mode 100644 index 000000000..a1014952f --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp @@ -0,0 +1,32 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_COMPONENTS_JOLTRIGIDBODY3DCOMPONENT_HPP +#define NAZARA_JOLTPHYSICS3D_COMPONENTS_JOLTRIGIDBODY3DCOMPONENT_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_JOLTPHYSICS3D_API JoltRigidBody3DComponent : public JoltRigidBody3D + { + friend class JoltPhysics3DSystem; + + public: + using JoltRigidBody3D::JoltRigidBody3D; + JoltRigidBody3DComponent(const JoltRigidBody3DComponent&) = default; + JoltRigidBody3DComponent(JoltRigidBody3DComponent&&) noexcept = default; + ~JoltRigidBody3DComponent() = default; + + JoltRigidBody3DComponent& operator=(const JoltRigidBody3DComponent&) = default; + JoltRigidBody3DComponent& operator=(JoltRigidBody3DComponent&&) noexcept = default; + }; +} + +#include + +#endif // NAZARA_JOLTPHYSICS3D_COMPONENTS_JOLTRIGIDBODY3DCOMPONENT_HPP diff --git a/include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.inl b/include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.inl new file mode 100644 index 000000000..30a08e779 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.inl @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/JoltPhysics3D/Config.hpp b/include/Nazara/JoltPhysics3D/Config.hpp new file mode 100644 index 000000000..d019c9076 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Config.hpp @@ -0,0 +1,48 @@ +/* + Nazara Engine - BulletPhysics3D module + + Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_CONFIG_HPP +#define NAZARA_JOLTPHYSICS3D_CONFIG_HPP + +/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci + +// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +#define NAZARA_JOLTPHYSICS3D_SAFE 1 + +/// Vérification des valeurs et types de certaines constantes +#include + +#if defined(NAZARA_STATIC) + #define NAZARA_JOLTPHYSICS3D_API +#else + #ifdef NAZARA_JOLTPHYSICS3D_BUILD + #define NAZARA_JOLTPHYSICS3D_API NAZARA_EXPORT + #else + #define NAZARA_JOLTPHYSICS3D_API NAZARA_IMPORT + #endif +#endif + +#endif // NAZARA_JOLTPHYSICS3D_CONFIG_HPP diff --git a/include/Nazara/JoltPhysics3D/ConfigCheck.hpp b/include/Nazara/JoltPhysics3D/ConfigCheck.hpp new file mode 100644 index 000000000..540c3c619 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/ConfigCheck.hpp @@ -0,0 +1,10 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_CONFIGCHECK_HPP +#define NAZARA_JOLTPHYSICS3D_CONFIGCHECK_HPP + +#endif // NAZARA_JOLTPHYSICS3D_CONFIGCHECK_HPP diff --git a/include/Nazara/JoltPhysics3D/Debug.hpp b/include/Nazara/JoltPhysics3D/Debug.hpp new file mode 100644 index 000000000..cce706a53 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Debug.hpp @@ -0,0 +1,5 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// no header guards diff --git a/include/Nazara/JoltPhysics3D/DebugOff.hpp b/include/Nazara/JoltPhysics3D/DebugOff.hpp new file mode 100644 index 000000000..cce706a53 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/DebugOff.hpp @@ -0,0 +1,5 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// no header guards diff --git a/include/Nazara/JoltPhysics3D/Enums.hpp b/include/Nazara/JoltPhysics3D/Enums.hpp new file mode 100644 index 000000000..3fb74b4fe --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Enums.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_ENUMS_HPP +#define NAZARA_JOLTPHYSICS3D_ENUMS_HPP + +namespace Nz +{ + enum class JoltColliderType3D + { + Box, + Compound, + Sphere, + + Max = Sphere + }; +} + +#endif // NAZARA_JOLTPHYSICS3D_ENUMS_HPP diff --git a/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp b/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp new file mode 100644 index 000000000..c596e4635 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltCollider3D.hpp @@ -0,0 +1,123 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_JOLTCOLLIDER3D_HPP +#define NAZARA_JOLTPHYSICS3D_JOLTCOLLIDER3D_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace JPH +{ + class ShapeSettings; + class BoxShapeSettings; + class CompoundShapeSettings; + class SphereShapeSettings; +} + +namespace Nz +{ + class PrimitiveList; + class StaticMesh; + struct Primitive; + + class NAZARA_JOLTPHYSICS3D_API JoltCollider3D + { + public: + JoltCollider3D() = default; + JoltCollider3D(const JoltCollider3D&) = delete; + JoltCollider3D(JoltCollider3D&&) = delete; + virtual ~JoltCollider3D(); + + virtual void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix = Matrix4f::Identity()) const = 0; + + virtual std::shared_ptr GenerateDebugMesh() const; + + virtual JPH::ShapeSettings* GetShapeSettings() const = 0; + virtual JoltColliderType3D GetType() const = 0; + + JoltCollider3D& operator=(const JoltCollider3D&) = delete; + JoltCollider3D& operator=(JoltCollider3D&&) = delete; + + static std::shared_ptr Build(const PrimitiveList& list); + + private: + static std::shared_ptr CreateGeomFromPrimitive(const Primitive& primitive); + }; + + class NAZARA_JOLTPHYSICS3D_API JoltBoxCollider3D final : public JoltCollider3D + { + public: + JoltBoxCollider3D(const Vector3f& lengths, float convexRadius = 0.f); + ~JoltBoxCollider3D(); + + void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; + + Vector3f GetLengths() const; + JPH::ShapeSettings* GetShapeSettings() const override; + JoltColliderType3D GetType() const override; + + private: + std::unique_ptr m_shapeSettings; + Vector3f m_lengths; + }; + + class NAZARA_JOLTPHYSICS3D_API JoltCompoundCollider3D final : public JoltCollider3D + { + public: + struct ChildCollider; + + JoltCompoundCollider3D(std::vector childs); + ~JoltCompoundCollider3D(); + + void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; + + const std::vector& GetGeoms() const; + JPH::ShapeSettings* GetShapeSettings() const override; + JoltColliderType3D GetType() const override; + + struct ChildCollider + { + std::shared_ptr collider; + Quaternionf rotation = Quaternionf::Identity(); + Vector3f offset = Vector3f::Zero(); + }; + + private: + std::unique_ptr m_shapeSettings; + std::vector m_childs; + }; + + class NAZARA_JOLTPHYSICS3D_API JoltSphereCollider3D final : public JoltCollider3D + { + public: + JoltSphereCollider3D(float radius); + ~JoltSphereCollider3D(); + + void BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const override; + + float GetRadius() const; + JPH::ShapeSettings* GetShapeSettings() const override; + JoltColliderType3D GetType() const override; + + private: + std::unique_ptr m_shapeSettings; + Vector3f m_position; + float m_radius; + }; +} + +#include + +#endif // NAZARA_JOLTPHYSICS3D_JOLTCOLLIDER3D_HPP diff --git a/include/Nazara/JoltPhysics3D/JoltCollider3D.inl b/include/Nazara/JoltPhysics3D/JoltCollider3D.inl new file mode 100644 index 000000000..ea5c23f45 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltCollider3D.inl @@ -0,0 +1,12 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ +} + +#include diff --git a/include/Nazara/JoltPhysics3D/JoltConstraint3D.hpp b/include/Nazara/JoltPhysics3D/JoltConstraint3D.hpp new file mode 100644 index 000000000..d4ac31982 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltConstraint3D.hpp @@ -0,0 +1,75 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once +#if 0 +#ifndef NAZARA_JOLTPHYSICS3D_JOLTCONSTRAINT3D_HPP +#define NAZARA_JOLTPHYSICS3D_JOLTCONSTRAINT3D_HPP + +#include +#include +#include +#include +#include +#include + +class btTypedConstraint; + +namespace Nz +{ + class BulletConstraint3D; + + using BulletConstraint3DHandle = ObjectHandle; + + class NAZARA_BULLETPHYSICS3D_API BulletConstraint3D : public HandledObject + { + public: + BulletConstraint3D(const BulletConstraint3D&) = delete; + BulletConstraint3D(BulletConstraint3D&& constraint) noexcept; + virtual ~BulletConstraint3D(); + + BulletRigidBody3D& GetBodyA(); + const BulletRigidBody3D& GetBodyA() const; + BulletRigidBody3D& GetBodyB(); + const BulletRigidBody3D& GetBodyB() const; + BulletPhysWorld3D& GetWorld(); + const BulletPhysWorld3D& GetWorld() const; + + inline bool IsBodyCollisionEnabled() const; + bool IsSingleBody() const; + + BulletConstraint3D& operator=(const BulletConstraint3D&) = delete; + BulletConstraint3D& operator=(BulletConstraint3D&& constraint) noexcept; + + protected: + BulletConstraint3D(std::unique_ptr constraint, bool disableCollisions = false); + + template T* GetConstraint(); + template const T* GetConstraint() const; + + private: + std::unique_ptr m_constraint; + bool m_bodyCollisionEnabled; + }; + + class NAZARA_BULLETPHYSICS3D_API BulletPivotConstraint3D : public BulletConstraint3D + { + public: + BulletPivotConstraint3D(BulletRigidBody3D& first, const Vector3f& pivot); + BulletPivotConstraint3D(BulletRigidBody3D& first, BulletRigidBody3D& second, const Vector3f& pivot, bool disableCollisions = false); + BulletPivotConstraint3D(BulletRigidBody3D& first, BulletRigidBody3D& second, const Vector3f& firstAnchor, const Vector3f& secondAnchor, bool disableCollisions = false); + ~BulletPivotConstraint3D() = default; + + Vector3f GetFirstAnchor() const; + Vector3f GetSecondAnchor() const; + + void SetFirstAnchor(const Vector3f& firstAnchor); + void SetSecondAnchor(const Vector3f& secondAnchor); + }; +} + +#include + +#endif // NAZARA_BULLETPHYSICS3D_BULLETCONSTRAINT3D_HPP +#endif // NAZARA_JOLTPHYSICS3D_JOLTCONSTRAINT3D_HPP diff --git a/include/Nazara/JoltPhysics3D/JoltConstraint3D.inl b/include/Nazara/JoltPhysics3D/JoltConstraint3D.inl new file mode 100644 index 000000000..ed65f234f --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltConstraint3D.inl @@ -0,0 +1,27 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline bool BulletConstraint3D::IsBodyCollisionEnabled() const + { + return m_bodyCollisionEnabled; + } + + template + T* BulletConstraint3D::GetConstraint() + { + return SafeCast(m_constraint.get()); + } + + template + const T* BulletConstraint3D::GetConstraint() const + { + return SafeCast(m_constraint.get()); + } +} + +#include diff --git a/include/Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp b/include/Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp new file mode 100644 index 000000000..e87b81e17 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp @@ -0,0 +1,72 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_JOLTPHYSWORLD3D_HPP +#define NAZARA_JOLTPHYSICS3D_JOLTPHYSWORLD3D_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace JPH +{ + class PhysicsSystem; +} + +namespace Nz +{ + class JoltRigidBody3D; + + class NAZARA_JOLTPHYSICS3D_API JoltPhysWorld3D + { + public: + struct RaycastHit; + + JoltPhysWorld3D(); + JoltPhysWorld3D(const JoltPhysWorld3D&) = delete; + JoltPhysWorld3D(JoltPhysWorld3D&& ph) = delete; + ~JoltPhysWorld3D(); + + Vector3f GetGravity() const; + std::size_t GetMaxStepCount() const; + JPH::PhysicsSystem* GetPhysicsSystem(); + Time GetStepSize() const; + + bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr); + + void SetGravity(const Vector3f& gravity); + void SetMaxStepCount(std::size_t maxStepCount); + void SetStepSize(Time stepSize); + + void Step(Time timestep); + + JoltPhysWorld3D& operator=(const JoltPhysWorld3D&) = delete; + JoltPhysWorld3D& operator=(JoltPhysWorld3D&&) = delete; + + struct RaycastHit + { + float fraction; + JoltRigidBody3D* hitBody = nullptr; + Vector3f hitPosition; + Vector3f hitNormal; + }; + + private: + struct JoltWorld; + + std::size_t m_maxStepCount; + std::unique_ptr m_world; + Vector3f m_gravity; + Time m_stepSize; + Time m_timestepAccumulator; + }; +} + +#endif // NAZARA_JOLTPHYSICS3D_JOLTPHYSWORLD3D_HPP diff --git a/include/Nazara/JoltPhysics3D/JoltPhysics3D.hpp b/include/Nazara/JoltPhysics3D/JoltPhysics3D.hpp new file mode 100644 index 000000000..2802ac60d --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltPhysics3D.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_HPP +#define NAZARA_JOLTPHYSICS3D_HPP + +#include +#include +#include +#include + +namespace JPH +{ + class JobSystem; + class JobSystemThreadPool; +} + +namespace Nz +{ + class NAZARA_JOLTPHYSICS3D_API JoltPhysics3D : public ModuleBase + { + friend ModuleBase; + + public: + using Dependencies = TypeList; + + struct Config {}; + + JoltPhysics3D(Config /*config*/); + ~JoltPhysics3D(); + + JPH::JobSystem& GetThreadPool(); + + private: + std::unique_ptr m_threadPool; + + static JoltPhysics3D* s_instance; + }; +} + +#endif // NAZARA_JOLTPHYSICS3D_HPP diff --git a/include/Nazara/JoltPhysics3D/JoltRigidBody3D.hpp b/include/Nazara/JoltPhysics3D/JoltRigidBody3D.hpp new file mode 100644 index 000000000..04f430b6d --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltRigidBody3D.hpp @@ -0,0 +1,90 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_JOLTRIGIDBODY3D_HPP +#define NAZARA_JOLTPHYSICS3D_JOLTRIGIDBODY3D_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class JoltPhysWorld3D; + + class NAZARA_JOLTPHYSICS3D_API JoltRigidBody3D + { + public: + JoltRigidBody3D(JoltPhysWorld3D* world, const Matrix4f& mat = Matrix4f::Identity()); + JoltRigidBody3D(JoltPhysWorld3D* world, std::shared_ptr geom, const Matrix4f& mat = Matrix4f::Identity()); + JoltRigidBody3D(const JoltRigidBody3D& object) = delete; + JoltRigidBody3D(JoltRigidBody3D&& object) noexcept; + ~JoltRigidBody3D(); + + void AddForce(const Vector3f& force, CoordSys coordSys = CoordSys::Global); + void AddForce(const Vector3f& force, const Vector3f& point, CoordSys coordSys = CoordSys::Global); + void AddTorque(const Vector3f& torque, CoordSys coordSys = CoordSys::Global); + + inline void DisableSleeping(); + void EnableSleeping(bool enable); + + void FallAsleep(); + + Boxf GetAABB() const; + float GetAngularDamping() const; + Vector3f GetAngularVelocity() const; + inline const std::shared_ptr& GetGeom() const; + float GetLinearDamping() const; + Vector3f GetLinearVelocity() const; + float GetMass() const; + Vector3f GetMassCenter(CoordSys coordSys = CoordSys::Local) const; + Matrix4f GetMatrix() const; + Vector3f GetPosition() const; + Quaternionf GetRotation() const; + inline JoltPhysWorld3D* GetWorld() const; + + bool IsSimulationEnabled() const; + bool IsSleeping() const; + bool IsSleepingEnabled() const; + + void SetAngularDamping(float angularDamping); + void SetAngularVelocity(const Vector3f& angularVelocity); + void SetGeom(std::shared_ptr geom, bool recomputeInertia = true); + void SetLinearDamping(float damping); + void SetLinearVelocity(const Vector3f& velocity); + void SetMass(float mass); + void SetMassCenter(const Vector3f& center); + void SetPosition(const Vector3f& position); + void SetRotation(const Quaternionf& rotation); + + Quaternionf ToLocal(const Quaternionf& worldRotation); + Vector3f ToLocal(const Vector3f& worldPosition); + Quaternionf ToWorld(const Quaternionf& localRotation); + Vector3f ToWorld(const Vector3f& localPosition); + + void WakeUp(); + + JoltRigidBody3D& operator=(const JoltRigidBody3D& object) = delete; + JoltRigidBody3D& operator=(JoltRigidBody3D&& object) noexcept; + + protected: + void Destroy(); + + private: + std::shared_ptr m_geom; + JoltPhysWorld3D* m_world; + UInt32 m_bodyIndex; + }; +} + +#include + +#endif // NAZARA_JOLTPHYSICS3D_JOLTRIGIDBODY3D_HPP diff --git a/include/Nazara/JoltPhysics3D/JoltRigidBody3D.inl b/include/Nazara/JoltPhysics3D/JoltRigidBody3D.inl new file mode 100644 index 000000000..58b788b93 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/JoltRigidBody3D.inl @@ -0,0 +1,25 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline void JoltRigidBody3D::DisableSleeping() + { + return EnableSleeping(false); + } + + inline const std::shared_ptr& JoltRigidBody3D::GetGeom() const + { + return m_geom; + } + + inline JoltPhysWorld3D* JoltRigidBody3D::GetWorld() const + { + return m_world; + } +} + +#include diff --git a/include/Nazara/JoltPhysics3D/Systems.hpp b/include/Nazara/JoltPhysics3D/Systems.hpp new file mode 100644 index 000000000..516a8c017 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Systems.hpp @@ -0,0 +1,34 @@ +// this file was automatically generated and should not be edited + +/* + Nazara Engine - BulletPhysics3D module + + Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_SYSTEMS_HPP +#define NAZARA_JOLTPHYSICS3D_SYSTEMS_HPP + +#include + +#endif // NAZARA_JOLTPHYSICS3D_SYSTEMS_HPP diff --git a/include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp b/include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp new file mode 100644 index 000000000..6018b7355 --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp @@ -0,0 +1,71 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_SYSTEMS_JOLTPHYSICS3DSYSTEM_HPP +#define NAZARA_JOLTPHYSICS3D_SYSTEMS_JOLTPHYSICS3DSYSTEM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_JOLTPHYSICS3D_API JoltPhysics3DSystem + { + public: + static constexpr Int64 ExecutionOrder = 0; + using Components = TypeList; + + struct RaycastHit; + + JoltPhysics3DSystem(entt::registry& registry); + JoltPhysics3DSystem(const JoltPhysics3DSystem&) = delete; + JoltPhysics3DSystem(JoltPhysics3DSystem&&) = delete; + ~JoltPhysics3DSystem(); + + template JoltRigidBody3DComponent CreateRigidBody(Args&&... args); + + void Dump(); + + inline JoltPhysWorld3D& GetPhysWorld(); + inline const JoltPhysWorld3D& GetPhysWorld() const; + + bool RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo = nullptr); + + void Update(Time elapsedTime); + + JoltPhysics3DSystem& operator=(const JoltPhysics3DSystem&) = delete; + JoltPhysics3DSystem& operator=(JoltPhysics3DSystem&&) = delete; + + struct RaycastHit : JoltPhysWorld3D::RaycastHit + { + entt::handle hitEntity; + }; + + private: + void OnConstruct(entt::registry& registry, entt::entity entity); + void OnDestruct(entt::registry& registry, entt::entity entity); + + std::size_t m_stepCount; + std::vector m_physicsEntities; + entt::registry& m_registry; + entt::observer m_physicsConstructObserver; + entt::scoped_connection m_constructConnection; + entt::scoped_connection m_destructConnection; + JoltPhysWorld3D m_physWorld; + Time m_physicsTime; + Time m_updateTime; + }; +} + +#include + +#endif // NAZARA_JOLTPHYSICS3D_SYSTEMS_JOLTPHYSICS3DSYSTEM_HPP diff --git a/include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.inl b/include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.inl new file mode 100644 index 000000000..9990c308e --- /dev/null +++ b/include/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.inl @@ -0,0 +1,26 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + template + JoltRigidBody3DComponent JoltPhysics3DSystem::CreateRigidBody(Args&&... args) + { + return JoltRigidBody3DComponent(&m_physWorld, std::forward(args)...); + } + + inline JoltPhysWorld3D& JoltPhysics3DSystem::GetPhysWorld() + { + return m_physWorld; + } + + inline const JoltPhysWorld3D& JoltPhysics3DSystem::GetPhysWorld() const + { + return m_physWorld; + } +} + +#include diff --git a/src/Nazara/BulletPhysics3D/BulletCollider3D.cpp b/src/Nazara/BulletPhysics3D/BulletCollider3D.cpp index 937e378d2..eeb017865 100644 --- a/src/Nazara/BulletPhysics3D/BulletCollider3D.cpp +++ b/src/Nazara/BulletPhysics3D/BulletCollider3D.cpp @@ -72,7 +72,7 @@ namespace Nz std::size_t primitiveCount = list.GetSize(); if (primitiveCount > 1) { - std::vector childColliders(primitiveCount); + std::vector childColliders(primitiveCount); for (unsigned int i = 0; i < primitiveCount; ++i) { @@ -81,12 +81,12 @@ namespace Nz childColliders[i].offsetMatrix = primitive.matrix; } - return std::make_shared(std::move(childColliders)); + return std::make_shared(std::move(childColliders)); } else if (primitiveCount > 0) return CreateGeomFromPrimitive(list.GetPrimitive(0)); else - return std::make_shared(); + return std::make_shared(); } std::shared_ptr BulletCollider3D::CreateGeomFromPrimitive(const Primitive& primitive) @@ -94,17 +94,17 @@ namespace Nz switch (primitive.type) { case PrimitiveType::Box: - return std::make_shared(primitive.box.lengths); + return std::make_shared(primitive.box.lengths); case PrimitiveType::Cone: - return std::make_shared(primitive.cone.length, primitive.cone.radius); + return std::make_shared(primitive.cone.length, primitive.cone.radius); case PrimitiveType::Plane: - return std::make_shared(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y)); + return std::make_shared(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y)); ///TODO: PlaneGeom? case PrimitiveType::Sphere: - return std::make_shared(primitive.sphere.size); + return std::make_shared(primitive.sphere.size); } NazaraError("Primitive type not handled (0x" + NumberToString(UnderlyingCast(primitive.type), 16) + ')'); @@ -113,15 +113,15 @@ namespace Nz /********************************** BoxCollider3D **********************************/ - BoxCollider3D::BoxCollider3D(const Vector3f& lengths) : + BulletBoxCollider3D::BulletBoxCollider3D(const Vector3f& lengths) : m_lengths(lengths) { m_shape = std::make_unique(ToBullet(m_lengths * 0.5f)); } - BoxCollider3D::~BoxCollider3D() = default; + BulletBoxCollider3D::~BulletBoxCollider3D() = default; - void BoxCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletBoxCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { auto InsertVertex = [&](float x, float y, float z) -> UInt16 { @@ -163,59 +163,59 @@ namespace Nz InsertEdge(v3, v7); } - btCollisionShape* BoxCollider3D::GetShape() const + btCollisionShape* BulletBoxCollider3D::GetShape() const { return m_shape.get(); } - Vector3f BoxCollider3D::GetLengths() const + Vector3f BulletBoxCollider3D::GetLengths() const { return m_lengths; } - ColliderType3D BoxCollider3D::GetType() const + ColliderType3D BulletBoxCollider3D::GetType() const { return ColliderType3D::Box; } /******************************** CapsuleCollider3D ********************************/ - CapsuleCollider3D::CapsuleCollider3D(float length, float radius) : + BulletCapsuleCollider3D::BulletCapsuleCollider3D(float length, float radius) : m_length(length), m_radius(radius) { m_shape = std::make_unique(radius, length); } - CapsuleCollider3D::~CapsuleCollider3D() = default; + BulletCapsuleCollider3D::~BulletCapsuleCollider3D() = default; - void CapsuleCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletCapsuleCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { } - float CapsuleCollider3D::GetLength() const + float BulletCapsuleCollider3D::GetLength() const { return m_length; } - float CapsuleCollider3D::GetRadius() const + float BulletCapsuleCollider3D::GetRadius() const { return m_radius; } - btCollisionShape* CapsuleCollider3D::GetShape() const + btCollisionShape* BulletCapsuleCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D CapsuleCollider3D::GetType() const + ColliderType3D BulletCapsuleCollider3D::GetType() const { return ColliderType3D::Capsule; } /******************************* CompoundCollider3D ********************************/ - CompoundCollider3D::CompoundCollider3D(std::vector childs) : + BulletCompoundCollider3D::BulletCompoundCollider3D(std::vector childs) : m_childs(std::move(childs)) { m_shape = std::make_unique(); @@ -226,67 +226,67 @@ namespace Nz } } - CompoundCollider3D::~CompoundCollider3D() = default; + BulletCompoundCollider3D::~BulletCompoundCollider3D() = default; - void CompoundCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletCompoundCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { for (const auto& child : m_childs) child.collider->BuildDebugMesh(vertices, indices, offsetMatrix * child.offsetMatrix); } - auto CompoundCollider3D::GetGeoms() const -> const std::vector& + auto BulletCompoundCollider3D::GetGeoms() const -> const std::vector& { return m_childs; } - btCollisionShape* CompoundCollider3D::GetShape() const + btCollisionShape* BulletCompoundCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D CompoundCollider3D::GetType() const + ColliderType3D BulletCompoundCollider3D::GetType() const { return ColliderType3D::Compound; } /********************************* ConeCollider3D **********************************/ - ConeCollider3D::ConeCollider3D(float length, float radius) : + BulletConeCollider3D::BulletConeCollider3D(float length, float radius) : m_length(length), m_radius(radius) { m_shape = std::make_unique(radius, length); } - ConeCollider3D::~ConeCollider3D() = default; + BulletConeCollider3D::~BulletConeCollider3D() = default; - void ConeCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletConeCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { } - float ConeCollider3D::GetLength() const + float BulletConeCollider3D::GetLength() const { return m_length; } - float ConeCollider3D::GetRadius() const + float BulletConeCollider3D::GetRadius() const { return m_radius; } - btCollisionShape* ConeCollider3D::GetShape() const + btCollisionShape* BulletConeCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D ConeCollider3D::GetType() const + ColliderType3D BulletConeCollider3D::GetType() const { return ColliderType3D::Cone; } /****************************** ConvexCollider3D *******************************/ - ConvexCollider3D::ConvexCollider3D(SparsePtr vertices, unsigned int vertexCount) + BulletConvexCollider3D::BulletConvexCollider3D(SparsePtr vertices, unsigned int vertexCount) { static_assert(std::is_same_v); @@ -294,9 +294,9 @@ namespace Nz m_shape->optimizeConvexHull(); } - ConvexCollider3D::~ConvexCollider3D() = default; + BulletConvexCollider3D::~BulletConvexCollider3D() = default; - void ConvexCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletConvexCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { tsl::ordered_map vertexCache; auto InsertVertex = [&](const Vector3f& position) -> UInt16 @@ -324,19 +324,19 @@ namespace Nz } } - btCollisionShape* ConvexCollider3D::GetShape() const + btCollisionShape* BulletConvexCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D ConvexCollider3D::GetType() const + ColliderType3D BulletConvexCollider3D::GetType() const { return ColliderType3D::ConvexHull; } /******************************* CylinderCollider3D ********************************/ - CylinderCollider3D::CylinderCollider3D(float length, float radius) : + BulletCylinderCollider3D::BulletCylinderCollider3D(float length, float radius) : m_length(length), m_radius(radius) { @@ -344,85 +344,85 @@ namespace Nz m_shape = std::make_unique(btVector3{ radius, length, radius }); } - CylinderCollider3D::~CylinderCollider3D() = default; + BulletCylinderCollider3D::~BulletCylinderCollider3D() = default; - void CylinderCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletCylinderCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { } - float CylinderCollider3D::GetLength() const + float BulletCylinderCollider3D::GetLength() const { return m_length; } - float CylinderCollider3D::GetRadius() const + float BulletCylinderCollider3D::GetRadius() const { return m_radius; } - btCollisionShape* CylinderCollider3D::GetShape() const + btCollisionShape* BulletCylinderCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D CylinderCollider3D::GetType() const + ColliderType3D BulletCylinderCollider3D::GetType() const { return ColliderType3D::Cylinder; } /********************************* NullCollider3D **********************************/ - NullCollider3D::NullCollider3D() + BulletNullCollider3D::BulletNullCollider3D() { m_shape = std::make_unique(); } - NullCollider3D::~NullCollider3D() = default; + BulletNullCollider3D::~BulletNullCollider3D() = default; - void NullCollider3D::BuildDebugMesh(std::vector& /*vertices*/, std::vector& /*indices*/, const Matrix4f& /*offsetMatrix*/) const + void BulletNullCollider3D::BuildDebugMesh(std::vector& /*vertices*/, std::vector& /*indices*/, const Matrix4f& /*offsetMatrix*/) const { } - void NullCollider3D::ComputeInertia(float /*mass*/, Vector3f* inertia) const + void BulletNullCollider3D::ComputeInertia(float /*mass*/, Vector3f* inertia) const { inertia->Set(1.f, 1.f, 1.f); } - btCollisionShape* NullCollider3D::GetShape() const + btCollisionShape* BulletNullCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D NullCollider3D::GetType() const + ColliderType3D BulletNullCollider3D::GetType() const { return ColliderType3D::Null; } /******************************** SphereCollider3D *********************************/ - SphereCollider3D::SphereCollider3D(float radius) : + BulletSphereCollider3D::BulletSphereCollider3D(float radius) : m_radius(radius) { m_shape = std::make_unique(radius); } - SphereCollider3D::~SphereCollider3D() = default; + BulletSphereCollider3D::~BulletSphereCollider3D() = default; - void SphereCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + void BulletSphereCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const { } - float SphereCollider3D::GetRadius() const + float BulletSphereCollider3D::GetRadius() const { return m_radius; } - btCollisionShape* SphereCollider3D::GetShape() const + btCollisionShape* BulletSphereCollider3D::GetShape() const { return m_shape.get(); } - ColliderType3D SphereCollider3D::GetType() const + ColliderType3D BulletSphereCollider3D::GetType() const { return ColliderType3D::Sphere; } diff --git a/src/Nazara/BulletPhysics3D/BulletPhysWorld3D.cpp b/src/Nazara/BulletPhysics3D/BulletPhysWorld3D.cpp index b16c38046..ec4cb7ce2 100644 --- a/src/Nazara/BulletPhysics3D/BulletPhysWorld3D.cpp +++ b/src/Nazara/BulletPhysics3D/BulletPhysWorld3D.cpp @@ -121,11 +121,19 @@ namespace Nz } } +#define HACK 0 + btRigidBody* BulletPhysWorld3D::AddRigidBody(std::size_t& rigidBodyIndex, FunctionRef constructor) { +#if HACK + static std::size_t index = 0; + rigidBodyIndex = index++; + btRigidBody* rigidBody = (btRigidBody*) ::operator new(sizeof(btRigidBody)); + constructor(rigidBody); + m_world->dynamicWorld.addRigidBody(rigidBody); +#else btRigidBody* rigidBody = m_world->rigidBodyPool.Allocate(m_world->rigidBodyPool.DeferConstruct, rigidBodyIndex); constructor(rigidBody); - m_world->dynamicWorld.addRigidBody(rigidBody); // Small hack to order rigid bodies to make it cache friendly @@ -144,6 +152,7 @@ namespace Nz *it = rigidBody; } } +#endif return rigidBody; } @@ -152,6 +161,10 @@ namespace Nz { // TODO: Improve deletion (since rigid bodies are sorted) m_world->dynamicWorld.removeRigidBody(rigidBody); //< this does a linear search +#if HACK + ::operator delete(rigidBody); +#else m_world->rigidBodyPool.Free(rigidBodyIndex); +#endif } } diff --git a/src/Nazara/BulletPhysics3D/BulletRigidBody3D.cpp b/src/Nazara/BulletPhysics3D/BulletRigidBody3D.cpp index 91e469155..0b75b4c3b 100644 --- a/src/Nazara/BulletPhysics3D/BulletRigidBody3D.cpp +++ b/src/Nazara/BulletPhysics3D/BulletRigidBody3D.cpp @@ -27,7 +27,7 @@ namespace Nz NazaraAssert(m_world, "Invalid world"); if (!m_geom) - m_geom = std::make_shared(); + m_geom = std::make_shared(); Vector3f inertia; m_geom->ComputeInertia(1.f, &inertia); @@ -214,7 +214,7 @@ namespace Nz if (geom) m_geom = std::move(geom); else - m_geom = std::make_shared(); + m_geom = std::make_shared(); m_body->setCollisionShape(m_geom->GetShape()); if (recomputeInertia) @@ -267,6 +267,15 @@ namespace Nz m_body->setWorldTransform(worldTransform); } + void BulletRigidBody3D::SetPositionAndRotation(const Vector3f& position, const Quaternionf& rotation) + { + btTransform worldTransform; + worldTransform.setOrigin(ToBullet(position)); + worldTransform.setRotation(ToBullet(rotation)); + + m_body->setWorldTransform(worldTransform); + } + void BulletRigidBody3D::SetRotation(const Quaternionf& rotation) { btTransform worldTransform = m_body->getWorldTransform(); diff --git a/src/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.cpp b/src/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.cpp index d406745d8..d491587a9 100644 --- a/src/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.cpp +++ b/src/Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace Nz @@ -14,6 +15,10 @@ namespace Nz { m_constructConnection = registry.on_construct().connect<&BulletPhysics3DSystem::OnConstruct>(this); m_destructConnection = registry.on_destroy().connect<&BulletPhysics3DSystem::OnDestruct>(this); + + m_stepCount = 0; + m_physicsTime = Time::Zero(); + m_updateTime = Time::Zero(); } BulletPhysics3DSystem::~BulletPhysics3DSystem() @@ -26,6 +31,20 @@ namespace Nz rigidBodyComponent.Destroy(); } + void BulletPhysics3DSystem::Dump() + { + if (m_stepCount == 0) + m_stepCount = 1; + + std::cout << "Physics time: " << (m_physicsTime / Time::Nanoseconds(m_stepCount)) << std::endl; + std::cout << "Update time: " << (m_updateTime / Time::Nanoseconds(m_stepCount)) << std::endl; + std::cout << "--" << std::endl; + + m_stepCount = 0; + m_physicsTime = Time::Zero(); + m_updateTime = Time::Zero(); + } + bool BulletPhysics3DSystem::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo) { if (!m_physWorld.RaycastQueryFirst(from, to, hitInfo)) @@ -49,12 +68,16 @@ namespace Nz BulletRigidBody3DComponent& entityPhysics = m_registry.get(entity); NodeComponent& entityNode = m_registry.get(entity); - entityPhysics.SetPosition(entityNode.GetPosition(CoordSys::Global)); - entityPhysics.SetRotation(entityNode.GetRotation(CoordSys::Global)); + entityPhysics.SetPositionAndRotation(entityNode.GetPosition(CoordSys::Global), entityNode.GetRotation(CoordSys::Global)); }); + Time t1 = GetElapsedNanoseconds(); + // Update the physics world m_physWorld.Step(elapsedTime); + m_stepCount++; + + Time t2 = GetElapsedNanoseconds(); // Replicate rigid body position to their node components // TODO: Only replicate active entities @@ -67,6 +90,11 @@ namespace Nz nodeComponent.SetPosition(rigidBodyComponent.GetPosition(), CoordSys::Global); nodeComponent.SetRotation(rigidBodyComponent.GetRotation(), CoordSys::Global); } + + Time t3 = GetElapsedNanoseconds(); + + m_physicsTime += (t2 - t1); + m_updateTime += (t3 - t2); } void BulletPhysics3DSystem::OnConstruct(entt::registry& registry, entt::entity entity) diff --git a/src/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.cpp b/src/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.cpp new file mode 100644 index 000000000..314147032 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.cpp @@ -0,0 +1,11 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ +} diff --git a/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp b/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp new file mode 100644 index 000000000..16a5e1ccf --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltCollider3D.cpp @@ -0,0 +1,214 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + JoltCollider3D::~JoltCollider3D() = default; + + std::shared_ptr JoltCollider3D::GenerateDebugMesh() const + { + std::vector colliderVertices; + std::vector colliderIndices; + BuildDebugMesh(colliderVertices, colliderIndices); + + std::shared_ptr colliderVB = std::make_shared(VertexDeclaration::Get(VertexLayout::XYZ), SafeCast(colliderVertices.size()), BufferUsage::Write, SoftwareBufferFactory, colliderVertices.data()); + std::shared_ptr colliderIB = std::make_shared(IndexType::U16, colliderIndices.size(), BufferUsage::Write, SoftwareBufferFactory, colliderIndices.data()); + + std::shared_ptr colliderSubMesh = std::make_shared(std::move(colliderVB), std::move(colliderIB)); + colliderSubMesh->GenerateAABB(); + colliderSubMesh->SetPrimitiveMode(PrimitiveMode::LineList); + + return colliderSubMesh; + } + + std::shared_ptr JoltCollider3D::Build(const PrimitiveList& list) + { + std::size_t primitiveCount = list.GetSize(); + if (primitiveCount > 1) + { + std::vector childColliders(primitiveCount); + + for (unsigned int i = 0; i < primitiveCount; ++i) + { + const Primitive& primitive = list.GetPrimitive(i); + childColliders[i].collider = CreateGeomFromPrimitive(primitive); + childColliders[i].offset = primitive.matrix.GetTranslation(); + childColliders[i].rotation = primitive.matrix.GetRotation(); + } + + return std::make_shared(std::move(childColliders)); + } + else if (primitiveCount > 0) + return CreateGeomFromPrimitive(list.GetPrimitive(0)); + else + return nullptr;// std::make_shared(); //< TODO + } + + std::shared_ptr JoltCollider3D::CreateGeomFromPrimitive(const Primitive& primitive) + { + switch (primitive.type) + { + case PrimitiveType::Box: + return std::make_shared(primitive.box.lengths); + + case PrimitiveType::Cone: + return nullptr; //< TODO + //return std::make_shared(primitive.cone.length, primitive.cone.radius); + + case PrimitiveType::Plane: + return std::make_shared(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y)); + ///TODO: PlaneGeom? + + case PrimitiveType::Sphere: + return std::make_shared(primitive.sphere.size); + } + + NazaraError("Primitive type not handled (0x" + NumberToString(UnderlyingCast(primitive.type), 16) + ')'); + return std::shared_ptr(); + } + + /********************************** BoxCollider3D **********************************/ + + JoltBoxCollider3D::JoltBoxCollider3D(const Vector3f& lengths, float convexRadius) : + m_lengths(lengths) + { + m_shapeSettings = std::make_unique(ToJolt(m_lengths * 0.5f), convexRadius); + } + + JoltBoxCollider3D::~JoltBoxCollider3D() = default; + + void JoltBoxCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + { + auto InsertVertex = [&](float x, float y, float z) -> UInt16 + { + UInt16 index = SafeCast(vertices.size()); + vertices.push_back(offsetMatrix * Vector3f(x, y, z)); + return index; + }; + + Vector3f halfLengths = m_lengths * 0.5f; + + UInt16 v0 = InsertVertex(-halfLengths.x, -halfLengths.y, -halfLengths.z); + UInt16 v1 = InsertVertex(halfLengths.x, -halfLengths.y, -halfLengths.z); + UInt16 v2 = InsertVertex(halfLengths.x, -halfLengths.y, halfLengths.z); + UInt16 v3 = InsertVertex(-halfLengths.x, -halfLengths.y, halfLengths.z); + + UInt16 v4 = InsertVertex(-halfLengths.x, halfLengths.y, -halfLengths.z); + UInt16 v5 = InsertVertex(halfLengths.x, halfLengths.y, -halfLengths.z); + UInt16 v6 = InsertVertex(halfLengths.x, halfLengths.y, halfLengths.z); + UInt16 v7 = InsertVertex(-halfLengths.x, halfLengths.y, halfLengths.z); + + auto InsertEdge = [&](UInt16 from, UInt16 to) + { + indices.push_back(from); + indices.push_back(to); + }; + InsertEdge(v0, v1); + InsertEdge(v1, v2); + InsertEdge(v2, v3); + InsertEdge(v3, v0); + + InsertEdge(v4, v5); + InsertEdge(v5, v6); + InsertEdge(v6, v7); + InsertEdge(v7, v4); + + InsertEdge(v0, v4); + InsertEdge(v1, v5); + InsertEdge(v2, v6); + InsertEdge(v3, v7); + } + + JPH::ShapeSettings* JoltBoxCollider3D::GetShapeSettings() const + { + return m_shapeSettings.get(); + } + + Vector3f JoltBoxCollider3D::GetLengths() const + { + return m_lengths; + } + + JoltColliderType3D JoltBoxCollider3D::GetType() const + { + return JoltColliderType3D::Box; + } + + /******************************* JoltCompoundCollider3D ********************************/ + + JoltCompoundCollider3D::JoltCompoundCollider3D(std::vector childs) : + m_childs(std::move(childs)) + { + m_shapeSettings = std::make_unique(); + for (const auto& child : m_childs) + m_shapeSettings->AddShape(ToJolt(child.offset), ToJolt(child.rotation), child.collider->GetShapeSettings()); + } + + JoltCompoundCollider3D::~JoltCompoundCollider3D() = default; + + void JoltCompoundCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + { + for (const auto& child : m_childs) + child.collider->BuildDebugMesh(vertices, indices, offsetMatrix * Matrix4f::Transform(child.offset, child.rotation)); + } + + auto JoltCompoundCollider3D::GetGeoms() const -> const std::vector& + { + return m_childs; + } + + JPH::ShapeSettings* JoltCompoundCollider3D::GetShapeSettings() const + { + return m_shapeSettings.get(); + } + + JoltColliderType3D JoltCompoundCollider3D::GetType() const + { + return JoltColliderType3D::Compound; + } + + /******************************** JoltSphereCollider3D *********************************/ + + JoltSphereCollider3D::JoltSphereCollider3D(float radius) : + m_radius(radius) + { + m_shapeSettings = std::make_unique(radius); + } + + JoltSphereCollider3D::~JoltSphereCollider3D() = default; + + void JoltSphereCollider3D::BuildDebugMesh(std::vector& vertices, std::vector& indices, const Matrix4f& offsetMatrix) const + { + } + + float JoltSphereCollider3D::GetRadius() const + { + return m_radius; + } + + JPH::ShapeSettings* JoltSphereCollider3D::GetShapeSettings() const + { + return m_shapeSettings.get(); + } + + JoltColliderType3D JoltSphereCollider3D::GetType() const + { + return JoltColliderType3D::Sphere; + } +} diff --git a/src/Nazara/JoltPhysics3D/JoltConstraint3D.cpp b/src/Nazara/JoltPhysics3D/JoltConstraint3D.cpp new file mode 100644 index 000000000..280db9682 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltConstraint3D.cpp @@ -0,0 +1,125 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp +#if 0 +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + BulletConstraint3D::BulletConstraint3D(std::unique_ptr constraint, bool disableCollisions) : + m_constraint(std::move(constraint)), + m_bodyCollisionEnabled(!disableCollisions) + { + btDynamicsWorld* world = GetWorld().GetDynamicsWorld(); + world->addConstraint(m_constraint.get(), disableCollisions); + } + + BulletConstraint3D::BulletConstraint3D(BulletConstraint3D&& constraint) noexcept : + m_constraint(std::move(constraint.m_constraint)), + m_bodyCollisionEnabled(constraint.m_bodyCollisionEnabled) + { + if (m_constraint) + m_constraint->setUserConstraintPtr(this); + } + + BulletConstraint3D::~BulletConstraint3D() + { + if (m_constraint) + { + btDynamicsWorld* world = GetWorld().GetDynamicsWorld(); + world->removeConstraint(m_constraint.get()); + } + } + + BulletRigidBody3D& BulletConstraint3D::GetBodyA() + { + return *static_cast(m_constraint->getRigidBodyA().getUserPointer()); + } + + const BulletRigidBody3D& BulletConstraint3D::GetBodyA() const + { + return *static_cast(m_constraint->getRigidBodyA().getUserPointer()); + } + + BulletRigidBody3D& BulletConstraint3D::GetBodyB() + { + NazaraAssert(!IsSingleBody(), "constraint is not attached to a second body"); + return *static_cast(m_constraint->getRigidBodyB().getUserPointer()); + } + + const BulletRigidBody3D& BulletConstraint3D::GetBodyB() const + { + NazaraAssert(!IsSingleBody(), "constraint is not attached to a second body"); + return *static_cast(m_constraint->getRigidBodyB().getUserPointer()); + } + + BulletPhysWorld3D& BulletConstraint3D::GetWorld() + { + return *GetBodyA().GetWorld(); + } + + const BulletPhysWorld3D& BulletConstraint3D::GetWorld() const + { + return *GetBodyA().GetWorld(); + } + + bool BulletConstraint3D::IsSingleBody() const + { + return &m_constraint->getRigidBodyB() == &btTypedConstraint::getFixedBody(); + } + + BulletConstraint3D& BulletConstraint3D::operator=(BulletConstraint3D&& constraint) noexcept + { + m_constraint.reset(); + + m_constraint = std::move(constraint.m_constraint); + m_bodyCollisionEnabled = constraint.m_bodyCollisionEnabled; + + if (m_constraint) + m_constraint->setUserConstraintPtr(this); + + return *this; + } + + + BulletPivotConstraint3D::BulletPivotConstraint3D(BulletRigidBody3D& first, const Vector3f& pivot) : + BulletConstraint3D(std::make_unique(*first.GetRigidBody(), ToBullet(first.ToLocal(pivot)))) + { + } + + BulletPivotConstraint3D::BulletPivotConstraint3D(BulletRigidBody3D& first, BulletRigidBody3D& second, const Vector3f& pivot, bool disableCollisions) : + BulletConstraint3D(std::make_unique(*first.GetRigidBody(), *second.GetRigidBody(), ToBullet(first.ToLocal(pivot)), ToBullet(second.ToLocal(pivot))), disableCollisions) + { + } + + BulletPivotConstraint3D::BulletPivotConstraint3D(BulletRigidBody3D& first, BulletRigidBody3D& second, const Vector3f& firstAnchor, const Vector3f& secondAnchor, bool disableCollisions) : + BulletConstraint3D(std::make_unique(*first.GetRigidBody(), *second.GetRigidBody(), ToBullet(firstAnchor), ToBullet(secondAnchor)), disableCollisions) + { + } + + Vector3f BulletPivotConstraint3D::GetFirstAnchor() const + { + return FromBullet(GetConstraint()->getPivotInA()); + } + + Vector3f BulletPivotConstraint3D::GetSecondAnchor() const + { + return FromBullet(GetConstraint()->getPivotInB()); + } + + void BulletPivotConstraint3D::SetFirstAnchor(const Vector3f& firstAnchor) + { + GetConstraint()->setPivotA(ToBullet(firstAnchor)); + } + + void BulletPivotConstraint3D::SetSecondAnchor(const Vector3f& secondAnchor) + { + GetConstraint()->setPivotB(ToBullet(secondAnchor)); + } +} +#endif diff --git a/src/Nazara/JoltPhysics3D/JoltHelper.hpp b/src/Nazara/JoltPhysics3D/JoltHelper.hpp new file mode 100644 index 000000000..9725c77ed --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltHelper.hpp @@ -0,0 +1,31 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_JOLTPHYSICS3D_JOLTHELPER_HPP +#define NAZARA_JOLTPHYSICS3D_JOLTHELPER_HPP + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + inline Quaternionf FromJolt(const JPH::Quat& quat); + inline Matrix4f FromJolt(const JPH::Mat44& matrix); + inline Vector3f FromJolt(const JPH::Vec3& vec); + + inline JPH::Mat44 ToJolt(const Matrix4f& transformMatrix); + inline JPH::Quat ToJolt(const Quaternionf& quaternion); + inline JPH::Vec3 ToJolt(const Vector3f& vec); + inline JPH::Vec4 ToJolt(const Vector4f& vec); +} + +#include + +#endif // NAZARA_JOLTPHYSICS3D_JOLTHELPER_HPP diff --git a/src/Nazara/JoltPhysics3D/JoltHelper.inl b/src/Nazara/JoltPhysics3D/JoltHelper.inl new file mode 100644 index 000000000..259cd5d62 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltHelper.inl @@ -0,0 +1,60 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + Quaternionf FromJolt(const JPH::Quat& quat) + { + return Quaternionf(quat.GetW(), quat.GetX(), quat.GetY(), quat.GetZ()); + } + + Matrix4f FromJolt(const JPH::Mat44& transform) + { + const JPH::Vec4& row1 = transform.GetColumn4(0); + const JPH::Vec4& row2 = transform.GetColumn4(1); + const JPH::Vec4& row3 = transform.GetColumn4(2); + const JPH::Vec4& row4 = transform.GetColumn4(3); + + return Matrix4f( + row1.GetX(), row1.GetY(), row1.GetZ(), row1.GetW(), + row2.GetX(), row2.GetY(), row2.GetZ(), row2.GetW(), + row3.GetX(), row3.GetY(), row3.GetZ(), row3.GetW(), + row4.GetX(), row4.GetY(), row4.GetZ(), row4.GetW()); + } + + inline Vector3f FromJolt(const JPH::Vec3& vec) + { + return Vector3f(vec.GetX(), vec.GetY(), vec.GetZ()); + } + + inline JPH::Mat44 ToJolt(const Matrix4f& transformMatrix) + { + JPH::Mat44 transform; + transform.SetColumn4(0, JPH::Vec4{ transformMatrix.m11, transformMatrix.m12, transformMatrix.m13, transformMatrix.m14 }); + transform.SetColumn4(1, JPH::Vec4{ transformMatrix.m21, transformMatrix.m22, transformMatrix.m23, transformMatrix.m24 }); + transform.SetColumn4(2, JPH::Vec4{ transformMatrix.m31, transformMatrix.m32, transformMatrix.m33, transformMatrix.m34 }); + transform.SetColumn4(3, JPH::Vec4{ transformMatrix.m41, transformMatrix.m42, transformMatrix.m43, transformMatrix.m44 }); + + return transform; + } + + inline JPH::Quat ToJolt(const Quaternionf& quaternion) + { + return JPH::Quat(quaternion.x, quaternion.y, quaternion.z, quaternion.w); + } + + inline JPH::Vec3 ToJolt(const Vector3f& vec) + { + return JPH::Vec3(vec.x, vec.y, vec.z); + } + + inline JPH::Vec4 ToJolt(const Vector4f& vec) + { + return JPH::Vec4(vec.x, vec.y, vec.z, vec.w); + } +} + +#include diff --git a/src/Nazara/JoltPhysics3D/JoltPhysWorld3D.cpp b/src/Nazara/JoltPhysics3D/JoltPhysWorld3D.cpp new file mode 100644 index 000000000..929804f35 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltPhysWorld3D.cpp @@ -0,0 +1,284 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace DitchMeAsap +{ + using namespace JPH; + using std::cout; + using std::endl; + + // Layer that objects can be in, determines which other objects it can collide with + // Typically you at least want to have 1 layer for moving bodies and 1 layer for static bodies, but you can have more + // layers if you want. E.g. you could have a layer for high detail collision (which is not used by the physics simulation + // but only if you do collision testing). + namespace Layers + { + static constexpr uint8 NON_MOVING = 0; + static constexpr uint8 MOVING = 1; + static constexpr uint8 NUM_LAYERS = 2; + }; + + /// Class that determines if two object layers can collide + class ObjectLayerPairFilterImpl : public ObjectLayerPairFilter + { + public: + virtual bool ShouldCollide(ObjectLayer inObject1, ObjectLayer inObject2) const override + { + switch (inObject1) + { + case Layers::NON_MOVING: + return inObject2 == Layers::MOVING; // Non moving only collides with moving + case Layers::MOVING: + return true; // Moving collides with everything + default: + JPH_ASSERT(false); + return false; + } + } + }; + + // Each broadphase layer results in a separate bounding volume tree in the broad phase. You at least want to have + // a layer for non-moving and moving objects to avoid having to update a tree full of static objects every frame. + // You can have a 1-on-1 mapping between object layers and broadphase layers (like in this case) but if you have + // many object layers you'll be creating many broad phase trees, which is not efficient. If you want to fine tune + // your broadphase layers define JPH_TRACK_BROADPHASE_STATS and look at the stats reported on the TTY. + namespace BroadPhaseLayers + { + static constexpr BroadPhaseLayer NON_MOVING(0); + static constexpr BroadPhaseLayer MOVING(1); + static constexpr uint NUM_LAYERS(2); + }; + + // BroadPhaseLayerInterface implementation + // This defines a mapping between object and broadphase layers. + class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface + { + public: + BPLayerInterfaceImpl() + { + // Create a mapping table from object to broad phase layer + mObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING; + mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING; + } + + virtual uint GetNumBroadPhaseLayers() const override + { + return BroadPhaseLayers::NUM_LAYERS; + } + + virtual BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer inLayer) const override + { + JPH_ASSERT(inLayer < Layers::NUM_LAYERS); + return mObjectToBroadPhase[inLayer]; + } + +#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED) + virtual const char* GetBroadPhaseLayerName(BroadPhaseLayer inLayer) const override + { + switch ((BroadPhaseLayer::Type)inLayer) + { + case (BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING: return "NON_MOVING"; + case (BroadPhaseLayer::Type)BroadPhaseLayers::MOVING: return "MOVING"; + default: JPH_ASSERT(false); return "INVALID"; + } + } +#endif // JPH_EXTERNAL_PROFILE || JPH_PROFILE_ENABLED + + private: + BroadPhaseLayer mObjectToBroadPhase[Layers::NUM_LAYERS]; + }; + /// Class that determines if an object layer can collide with a broadphase layer + class ObjectVsBroadPhaseLayerFilterImpl : public ObjectVsBroadPhaseLayerFilter + { + public: + virtual bool ShouldCollide(ObjectLayer inLayer1, BroadPhaseLayer inLayer2) const override + { + switch (inLayer1) + { + case Layers::NON_MOVING: + return inLayer2 == BroadPhaseLayers::MOVING; + case Layers::MOVING: + return true; + default: + JPH_ASSERT(false); + return false; + } + } + }; + + // An example contact listener + class MyContactListener : public ContactListener + { + public: + // See: ContactListener + virtual ValidateResult OnContactValidate(const Body& inBody1, const Body& inBody2, RVec3Arg inBaseOffset, const CollideShapeResult& inCollisionResult) override + { + cout << "Contact validate callback" << endl; + + // Allows you to ignore a contact before it is created (using layers to not make objects collide is cheaper!) + return ValidateResult::AcceptAllContactsForThisBodyPair; + } + + virtual void OnContactAdded(const Body& inBody1, const Body& inBody2, const ContactManifold& inManifold, ContactSettings& ioSettings) override + { + cout << "A contact was added" << endl; + } + + virtual void OnContactPersisted(const Body& inBody1, const Body& inBody2, const ContactManifold& inManifold, ContactSettings& ioSettings) override + { + cout << "A contact was persisted" << endl; + } + + virtual void OnContactRemoved(const SubShapeIDPair& inSubShapePair) override + { + cout << "A contact was removed" << endl; + } + }; + + // An example activation listener + class MyBodyActivationListener : public BodyActivationListener + { + public: + virtual void OnBodyActivated(const BodyID& inBodyID, uint64 inBodyUserData) override + { + cout << "A body got activated" << endl; + } + + virtual void OnBodyDeactivated(const BodyID& inBodyID, uint64 inBodyUserData) override + { + cout << "A body went to sleep" << endl; + } + }; +} + +namespace Nz +{ + struct JoltPhysWorld3D::JoltWorld + { + JPH::TempAllocatorMalloc tempAllocation; + JPH::PhysicsSystem physicsSystem; + + DitchMeAsap::BPLayerInterfaceImpl layerInterface; + DitchMeAsap::ObjectLayerPairFilterImpl objectLayerFilter; + DitchMeAsap::ObjectVsBroadPhaseLayerFilterImpl objectBroadphaseLayerFilter; + + JoltWorld() = default; + JoltWorld(const JoltWorld&) = delete; + JoltWorld(JoltWorld&&) = delete; + + JoltWorld& operator=(const JoltWorld&) = delete; + JoltWorld& operator=(JoltWorld&&) = delete; + }; + + JoltPhysWorld3D::JoltPhysWorld3D() : + m_maxStepCount(50), + m_gravity(Vector3f::Zero()), + m_stepSize(Time::TickDuration(120)), + m_timestepAccumulator(Time::Zero()) + { + m_world = std::make_unique(); + m_world->physicsSystem.Init(0xFFFF, 0, 0xFFFF, 0xFFFF, m_world->layerInterface, m_world->objectBroadphaseLayerFilter, m_world->objectLayerFilter); + } + + JoltPhysWorld3D::~JoltPhysWorld3D() = default; + + Vector3f JoltPhysWorld3D::GetGravity() const + { + return FromJolt(m_world->physicsSystem.GetGravity()); + } + + std::size_t JoltPhysWorld3D::GetMaxStepCount() const + { + return m_maxStepCount; + } + + JPH::PhysicsSystem* JoltPhysWorld3D::GetPhysicsSystem() + { + return &m_world->physicsSystem; + } + + Time JoltPhysWorld3D::GetStepSize() const + { + return m_stepSize; + } + + bool JoltPhysWorld3D::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo) + { + return false; + /* + btCollisionWorld::ClosestRayResultCallback callback(ToBullet(from), ToBullet(to)); + m_world->dynamicWorld.rayTest(ToBullet(from), ToBullet(to), callback); + + if (!callback.hasHit()) + return false; + + if (hitInfo) + { + hitInfo->fraction = callback.m_closestHitFraction; + hitInfo->hitNormal = FromBullet(callback.m_hitNormalWorld); + hitInfo->hitPosition = FromBullet(callback.m_hitPointWorld); + + if (const btRigidBody* body = btRigidBody::upcast(callback.m_collisionObject)) + hitInfo->hitBody = static_cast(body->getUserPointer()); + } + + return true;*/ + } + + void JoltPhysWorld3D::SetGravity(const Vector3f& gravity) + { + m_world->physicsSystem.SetGravity(ToJolt(gravity)); + } + + void JoltPhysWorld3D::SetMaxStepCount(std::size_t maxStepCount) + { + m_maxStepCount = maxStepCount; + } + + void JoltPhysWorld3D::SetStepSize(Time stepSize) + { + m_stepSize = stepSize; + } + + void JoltPhysWorld3D::Step(Time timestep) + { + JPH::JobSystem& jobSystem = JoltPhysics3D::Instance()->GetThreadPool(); + + m_timestepAccumulator += timestep; + + float stepSize = m_stepSize.AsSeconds(); + + static bool firstStep = true; + if (firstStep) + { + m_world->physicsSystem.OptimizeBroadPhase(); + firstStep = false; + } + + std::size_t stepCount = 0; + while (m_timestepAccumulator >= m_stepSize && stepCount < m_maxStepCount) + { + m_world->physicsSystem.Update(stepSize, 1, 1, &m_world->tempAllocation, &jobSystem); + m_timestepAccumulator -= m_stepSize; + stepCount++; + } + } +} diff --git a/src/Nazara/JoltPhysics3D/JoltPhysics3D.cpp b/src/Nazara/JoltPhysics3D/JoltPhysics3D.cpp new file mode 100644 index 000000000..75fffedd7 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltPhysics3D.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Callback for traces, connect this to your own trace function if you have one +static void TraceImpl(const char* inFMT, ...) +{ + // Format the message + va_list list; + va_start(list, inFMT); + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), inFMT, list); + va_end(list); + + // Print to the TTY + std::cout << buffer << std::endl; +} + +namespace Nz +{ + JoltPhysics3D::JoltPhysics3D(Config /*config*/) : + ModuleBase("JoltPhysics3D", this) + { + JPH::RegisterDefaultAllocator(); + JPH::Trace = TraceImpl; + JPH::Factory::sInstance = new JPH::Factory; + JPH::RegisterTypes(); + + m_threadPool = std::make_unique(JPH::cMaxPhysicsJobs, JPH::cMaxPhysicsBarriers, Core::Instance()->GetHardwareInfo().GetCpuThreadCount()); + } + + JoltPhysics3D::~JoltPhysics3D() + { + m_threadPool.reset(); + // FIXME: Uncomment when next version of Jolt gets released + //JPH::UnregisterTypes(); + + delete JPH::Factory::sInstance; + JPH::Factory::sInstance = nullptr; + } + + JPH::JobSystem& JoltPhysics3D::GetThreadPool() + { + return *m_threadPool; + } + + JoltPhysics3D* JoltPhysics3D::s_instance; +} diff --git a/src/Nazara/JoltPhysics3D/JoltRigidBody3D.cpp b/src/Nazara/JoltPhysics3D/JoltRigidBody3D.cpp new file mode 100644 index 000000000..43d5d0096 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/JoltRigidBody3D.cpp @@ -0,0 +1,325 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D* world, const Matrix4f& mat) : + JoltRigidBody3D(world, nullptr, mat) + { + } + + JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D* world, std::shared_ptr geom, const Matrix4f& mat) : + m_geom(std::move(geom)), + m_world(world) + { + NazaraAssert(m_world, "Invalid world"); + + if (!m_geom) + m_geom = std::make_shared(1.f); + + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + + JPH::Vec3 position = ToJolt(mat.GetTranslation()); + JPH::Quat rotation = ToJolt(mat.GetRotation().Normalize()); + + JPH::BodyCreationSettings settings(m_geom->GetShapeSettings(), position, rotation, JPH::EMotionType::Dynamic, 1); + settings.mAllowSleeping = false; + + JPH::Body* body = body_interface.CreateBody(settings); + body->SetUserData(SafeCast(reinterpret_cast(this))); + + body_interface.AddBody(body->GetID(), JPH::EActivation::Activate); + m_bodyIndex = body->GetID().GetIndexAndSequenceNumber(); + } + + JoltRigidBody3D::JoltRigidBody3D(JoltRigidBody3D&& object) noexcept : + m_geom(std::move(object.m_geom)), + m_bodyIndex(object.m_bodyIndex), + m_world(object.m_world) + { + object.m_bodyIndex = JPH::BodyID::cInvalidBodyID; + } + + JoltRigidBody3D::~JoltRigidBody3D() + { + Destroy(); + } + +#if 0 + void JoltRigidBody3D::AddForce(const Vector3f& force, CoordSys coordSys) + { + switch (coordSys) + { + case CoordSys::Global: + WakeUp(); + m_body->applyCentralForce(ToJolt(force)); + break; + + case CoordSys::Local: + WakeUp(); + m_body->applyCentralForce(ToJolt(GetRotation() * force)); + break; + } + } + + void JoltRigidBody3D::AddForce(const Vector3f& force, const Vector3f& point, CoordSys coordSys) + { + switch (coordSys) + { + case CoordSys::Global: + WakeUp(); + m_body->applyForce(ToJolt(force), ToJolt(point)); + break; + + case CoordSys::Local: + { + Matrix4f transformMatrix = GetMatrix(); + return AddForce(transformMatrix.Transform(force, 0.f), point, CoordSys::Global); + } + } + } + + void JoltRigidBody3D::AddTorque(const Vector3f& torque, CoordSys coordSys) + { + switch (coordSys) + { + case CoordSys::Global: + WakeUp(); + m_body->applyTorque(ToJolt(torque)); + break; + + case CoordSys::Local: + Matrix4f transformMatrix = GetMatrix(); + WakeUp(); + m_body->applyTorque(ToJolt(transformMatrix.Transform(torque, 0.f))); + break; + } + } +#endif + void JoltRigidBody3D::EnableSleeping(bool enable) + { + } + +#if 0 + void JoltRigidBody3D::FallAsleep() + { + if (m_body->getActivationState() != DISABLE_DEACTIVATION) + m_body->setActivationState(ISLAND_SLEEPING); + } + + Boxf JoltRigidBody3D::GetAABB() const + { + btVector3 min, max; + m_body->getAabb(min, max); + + return Boxf(FromJolt(min), FromJolt(max)); + } + + float JoltRigidBody3D::GetAngularDamping() const + { + return m_body->getAngularDamping(); + } + + Vector3f JoltRigidBody3D::GetAngularVelocity() const + { + return FromJolt(m_body->getAngularVelocity()); + } + + float JoltRigidBody3D::GetLinearDamping() const + { + return m_body->getLinearDamping(); + } + + Vector3f JoltRigidBody3D::GetLinearVelocity() const + { + return FromJolt(m_body->getLinearVelocity()); + } + + float JoltRigidBody3D::GetMass() const + { + return m_body->getMass(); + } + + Vector3f JoltRigidBody3D::GetMassCenter(CoordSys coordSys) const + { + return FromJolt(m_body->getCenterOfMassPosition()); + } + + Matrix4f JoltRigidBody3D::GetMatrix() const + { + return FromJolt(m_body->getWorldTransform()); + } +#endif + + Vector3f JoltRigidBody3D::GetPosition() const + { + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + return FromJolt(body_interface.GetPosition(JPH::BodyID(m_bodyIndex))); + } + + Quaternionf JoltRigidBody3D::GetRotation() const + { + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + return FromJolt(body_interface.GetRotation(JPH::BodyID(m_bodyIndex))); + } + +#if 0 + bool JoltRigidBody3D::IsSimulationEnabled() const + { + return m_body->isActive(); + } +#endif + + bool JoltRigidBody3D::IsSleeping() const + { + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + return !body_interface.IsActive(JPH::BodyID(m_bodyIndex)); + } + +#if 0 + bool JoltRigidBody3D::IsSleepingEnabled() const + { + return m_body->getActivationState() != DISABLE_DEACTIVATION; + } + + void JoltRigidBody3D::SetAngularDamping(float angularDamping) + { + m_body->setDamping(m_body->getLinearDamping(), angularDamping); + } + + void JoltRigidBody3D::SetAngularVelocity(const Vector3f& angularVelocity) + { + m_body->setAngularVelocity(ToJolt(angularVelocity)); + } + + void JoltRigidBody3D::SetGeom(std::shared_ptr geom, bool recomputeInertia) + { + if (m_geom != geom) + { + if (geom) + m_geom = std::move(geom); + else + m_geom = std::make_shared(); + + m_body->setCollisionShape(m_geom->GetShape()); + if (recomputeInertia) + { + float mass = GetMass(); + + Vector3f inertia; + m_geom->ComputeInertia(mass, &inertia); + + m_body->setMassProps(mass, ToJolt(inertia)); + } + } + } + + void JoltRigidBody3D::SetLinearDamping(float damping) + { + m_body->setDamping(damping, m_body->getAngularDamping()); + } + + void JoltRigidBody3D::SetLinearVelocity(const Vector3f& velocity) + { + m_body->setLinearVelocity(ToJolt(velocity)); + } +#endif 0 + void JoltRigidBody3D::SetMass(float mass) + { + NazaraAssert(mass >= 0.f, "Mass must be positive and finite"); + NazaraAssert(std::isfinite(mass), "Mass must be positive and finite"); + + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + body_interface.SetMotionType(JPH::BodyID(m_bodyIndex), (mass > 0.f) ? JPH::EMotionType::Dynamic : JPH::EMotionType::Static, JPH::EActivation::Activate); + } + +#if 0 + void JoltRigidBody3D::SetMassCenter(const Vector3f& center) + { + btTransform centerTransform; + centerTransform.setIdentity(); + centerTransform.setOrigin(ToJolt(center)); + + m_body->setCenterOfMassTransform(centerTransform); + } +#endif 0 + void JoltRigidBody3D::SetPosition(const Vector3f& position) + { + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + body_interface.SetPosition(JPH::BodyID(m_bodyIndex), ToJolt(position), JPH::EActivation::Activate); + } + + void JoltRigidBody3D::SetRotation(const Quaternionf& rotation) + { + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + body_interface.SetRotation(JPH::BodyID(m_bodyIndex), ToJolt(rotation), JPH::EActivation::Activate); + } + +#if 0 + Quaternionf JoltRigidBody3D::ToLocal(const Quaternionf& worldRotation) + { + return GetRotation().Conjugate() * worldRotation; + } + + Vector3f JoltRigidBody3D::ToLocal(const Vector3f& worldPosition) + { + btTransform worldTransform = m_body->getWorldTransform(); + return GetMatrix().InverseTransform() * worldPosition; + } + + Quaternionf JoltRigidBody3D::ToWorld(const Quaternionf& localRotation) + { + return GetRotation() * localRotation; + } + + Vector3f JoltRigidBody3D::ToWorld(const Vector3f& localPosition) + { + return GetMatrix() * localPosition; + } + + void JoltRigidBody3D::WakeUp() + { + m_body->activate(); + } +#endif + + JoltRigidBody3D& JoltRigidBody3D::operator=(JoltRigidBody3D&& object) noexcept + { + Destroy(); + + m_bodyIndex = object.m_bodyIndex; + m_geom = std::move(object.m_geom); + m_world = object.m_world; + + object.m_bodyIndex = JPH::BodyID::cInvalidBodyID; + + return *this; + } + + void JoltRigidBody3D::Destroy() + { + if (m_bodyIndex != JPH::BodyID::cInvalidBodyID) + { + JPH::BodyInterface& body_interface = m_world->GetPhysicsSystem()->GetBodyInterface(); + body_interface.RemoveBody(JPH::BodyID(m_bodyIndex)); + body_interface.DestroyBody(JPH::BodyID(m_bodyIndex)); + m_bodyIndex = JPH::BodyID::cInvalidBodyID; + } + + m_geom.reset(); + } +} diff --git a/src/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.cpp b/src/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.cpp new file mode 100644 index 000000000..8d2184aa2 --- /dev/null +++ b/src/Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - JoltPhysics3D module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + JoltPhysics3DSystem::JoltPhysics3DSystem(entt::registry& registry) : + m_registry(registry), + m_physicsConstructObserver(m_registry, entt::collector.group()) + { + m_constructConnection = registry.on_construct().connect<&JoltPhysics3DSystem::OnConstruct>(this); + m_destructConnection = registry.on_destroy().connect<&JoltPhysics3DSystem::OnDestruct>(this); + + m_stepCount = 0; + m_physicsTime = Time::Zero(); + m_updateTime = Time::Zero(); + } + + JoltPhysics3DSystem::~JoltPhysics3DSystem() + { + m_physicsConstructObserver.disconnect(); + + // Ensure every RigidBody3D is destroyed before world is + auto rigidBodyView = m_registry.view(); + for (auto [entity, rigidBodyComponent] : rigidBodyView.each()) + rigidBodyComponent.Destroy(); + } + + void JoltPhysics3DSystem::Dump() + { + if (m_stepCount == 0) + m_stepCount = 1; + + std::cout << "Physics time: " << (m_physicsTime / Time::Nanoseconds(m_stepCount)) << std::endl; + std::cout << "Update time: " << (m_updateTime / Time::Nanoseconds(m_stepCount)) << std::endl; + std::cout << "--" << std::endl; + + m_stepCount = 0; + m_physicsTime = Time::Zero(); + m_updateTime = Time::Zero(); + } + + bool JoltPhysics3DSystem::RaycastQueryFirst(const Vector3f& from, const Vector3f& to, RaycastHit* hitInfo) + { + if (!m_physWorld.RaycastQueryFirst(from, to, hitInfo)) + return false; + + /*if (hitInfo->hitBody) + { + std::size_t uniqueIndex = hitInfo->hitBody->GetUniqueIndex(); + if (uniqueIndex < m_physicsEntities.size()) + hitInfo->hitEntity = entt::handle(m_registry, m_physicsEntities[uniqueIndex]); + }*/ + + return true; + } + + void JoltPhysics3DSystem::Update(Time elapsedTime) + { + // Move newly-created physics entities to their node position/rotation + m_physicsConstructObserver.each([&](entt::entity entity) + { + JoltRigidBody3DComponent& entityPhysics = m_registry.get(entity); + NodeComponent& entityNode = m_registry.get(entity); + + entityPhysics.SetPosition(entityNode.GetPosition(CoordSys::Global)); + entityPhysics.SetRotation(entityNode.GetRotation(CoordSys::Global)); + }); + + Time t1 = GetElapsedNanoseconds(); + + // Update the physics world + m_physWorld.Step(elapsedTime); + m_stepCount++; + + Time t2 = GetElapsedNanoseconds(); + + // Replicate rigid body position to their node components + // TODO: Only replicate active entities + auto view = m_registry.view(); + for (auto [entity, nodeComponent, rigidBodyComponent] : view.each()) + { + if (rigidBodyComponent.IsSleeping()) + continue; + + nodeComponent.SetPosition(rigidBodyComponent.GetPosition(), CoordSys::Global); + nodeComponent.SetRotation(rigidBodyComponent.GetRotation(), CoordSys::Global); + } + + Time t3 = GetElapsedNanoseconds(); + + m_physicsTime += (t2 - t1); + m_updateTime += (t3 - t2); + } + + void JoltPhysics3DSystem::OnConstruct(entt::registry& registry, entt::entity entity) + { + } + + void JoltPhysics3DSystem::OnDestruct(entt::registry& registry, entt::entity entity) + { + } +} diff --git a/xmake.lua b/xmake.lua index 40c7562ef..c6feab35d 100644 --- a/xmake.lua +++ b/xmake.lua @@ -66,6 +66,10 @@ local modules = { end end }, + BulletPhysics3D = { + Deps = {"NazaraUtility"}, + Packages = { "bullet3", "entt", "ordered_map" } + }, Core = { Custom = function () add_headerfiles("include/(Nazara/*.hpp)") @@ -105,6 +109,10 @@ local modules = { Deps = {"NazaraRenderer"}, Packages = {"entt"} }, + JoltPhysics3D = { + Deps = {"NazaraUtility"}, + Packages = { "joltphysics", "entt" } + }, Network = { Deps = {"NazaraCore"}, Custom = function() @@ -122,10 +130,6 @@ local modules = { Deps = {"NazaraUtility"}, Packages = { "chipmunk2d", "entt" } }, - BulletPhysics3D = { - Deps = {"NazaraUtility"}, - Packages = { "bullet3", "entt", "ordered_map" } - }, Platform = { Deps = {"NazaraUtility"}, Custom = function() @@ -234,6 +238,7 @@ add_requires( "minimp3", "ordered_map", "stb") +add_requires("joltphysics master", { configs = { debug = is_mode("debug") } }) add_requires("freetype", { configs = { bzip2 = true, png = true, woff2 = true, zlib = true, debug = is_mode("debug") } }) add_requires("libvorbis", { configs = { with_vorbisenc = false } })