Add JoltPhysics3D for a performance test

This commit is contained in:
SirLynix 2023-03-15 13:44:58 +01:00 committed by Jérôme Leclercq
parent bd4c2d6ee7
commit c5ac142888
40 changed files with 2555 additions and 95 deletions

View File

@ -0,0 +1,360 @@
// Sources pour https://github.com/NazaraEngine/NazaraEngine/wiki/(FR)-Tutoriel:-%5B01%5D-Hello-World
#define USE_JOLT 0
#include <Nazara/Core.hpp>
#include <Nazara/Graphics.hpp>
#include <Nazara/Platform/AppWindowingComponent.hpp>
#if USE_JOLT
#include <Nazara/JoltPhysics3D.hpp>
#else
#include <Nazara/BulletPhysics3D.hpp>
#endif
#include <Nazara/Renderer.hpp>
#include <Nazara/Utility.hpp>
#include <iostream>
#include <random>
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<Nz::Graphics, Nz::JoltPhysics3D> app(renderConfig);
#else
Nz::Application<Nz::Graphics, Nz::BulletPhysics3D> app(renderConfig);
#endif
auto& windowing = app.AddComponent<Nz::AppWindowingComponent>();
Nz::Window& mainWindow = windowing.CreateWindow(Nz::VideoMode(1920, 1080), "Physics playground");
auto& fs = app.AddComponent<Nz::AppFilesystemComponent>();
{
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<Nz::AppEntitySystemComponent>();
auto& world = ecs.AddWorld<Nz::EnttWorld>();
#if USE_JOLT
auto& physSystem = world.AddSystem<Nz::JoltPhysics3DSystem>();
#else
auto& physSystem = world.AddSystem<Nz::BulletPhysics3DSystem>();
#endif
physSystem.GetPhysWorld().SetMaxStepCount(1);
//physSystem.GetPhysWorld().SetGravity(Nz::Vector3f::Down() * 9.81f);
physSystem.GetPhysWorld().SetGravity(Nz::Vector3f::Zero());
auto& renderSystem = world.AddSystem<Nz::RenderSystem>();
Nz::WindowSwapchain& windowSwapchain = renderSystem.CreateSwapchain(mainWindow);
Nz::Vector3f target = Nz::Vector3f::Zero();
entt::handle boxEntity = world.CreateEntity();
{
std::shared_ptr<Nz::GraphicalMesh> 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<Nz::MaterialInstance> boxMat = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
boxMat->SetTextureProperty("BaseColorMap", fs.Load<Nz::Texture>("assets/dev_grey.png"), planeSampler);
boxMat->DisablePass("ShadowPass");
boxMat->UpdatePassesStates([&](Nz::RenderStates& states)
{
states.frontFace = Nz::FrontFace::Clockwise;
});
std::shared_ptr<Nz::Model> boxModel = std::make_shared<Nz::Model>(std::move(boxMesh));
boxModel->SetMaterial(0, std::move(boxMat));
auto& boxGfx = boxEntity.emplace<Nz::GraphicsComponent>();
boxGfx.AttachRenderable(std::move(boxModel));
boxEntity.emplace<Nz::NodeComponent>();
#if USE_JOLT
std::shared_ptr<Nz::JoltBoxCollider3D> wallCollider = std::make_shared<Nz::JoltBoxCollider3D>(Nz::Vector3f(BoxDims, BoxDims, 1.f));
#else
std::shared_ptr<Nz::BulletBoxCollider3D> wallCollider = std::make_shared<Nz::BulletBoxCollider3D>(Nz::Vector3f(BoxDims, BoxDims, 1.f));
#endif
#if USE_JOLT
std::vector<Nz::JoltCompoundCollider3D::ChildCollider> colliders;
#else
std::vector<Nz::BulletCompoundCollider3D::ChildCollider> 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<Nz::JoltCompoundCollider3D> boxCollider = std::make_shared<Nz::JoltCompoundCollider3D>(std::move(colliders));
#else
std::shared_ptr<Nz::BulletCompoundCollider3D> boxCollider = std::make_shared<Nz::BulletCompoundCollider3D>(std::move(colliders));
#endif
#if USE_JOLT
auto& ballPhysics = boxEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider));
#else
auto& ballPhysics = boxEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider));
#endif
ballPhysics.SetMass(0.f);
std::shared_ptr<Nz::Model> colliderModel;
{
std::shared_ptr<Nz::MaterialInstance> 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<Nz::Mesh> colliderMesh = Nz::Mesh::Build(boxCollider->GenerateDebugMesh());
std::shared_ptr<Nz::GraphicalMesh> colliderGraphicalMesh = Nz::GraphicalMesh::BuildFromMesh(*colliderMesh);
colliderModel = std::make_shared<Nz::Model>(colliderGraphicalMesh);
for (std::size_t i = 0; i < colliderModel->GetSubMeshCount(); ++i)
colliderModel->SetMaterial(i, colliderMat);
boxGfx.AttachRenderable(std::move(colliderModel));*/
}
}
std::shared_ptr<Nz::GraphicalMesh> sphereMesh = Nz::GraphicalMesh::Build(Nz::Primitive::IcoSphere(1.f));
//std::mt19937 rd(std::random_device{}());
std::mt19937 rd(42);
std::uniform_real_distribution<float> colorDis(0.f, 360.f);
std::uniform_real_distribution<float> 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<float> positionRandom(-BoxDims * 0.5f + radius, BoxDims * 0.5f - radius);
#if USE_JOLT
std::shared_ptr<Nz::JoltSphereCollider3D> sphereCollider = std::make_shared<Nz::JoltSphereCollider3D>(radius);
#else
std::shared_ptr<Nz::BulletSphereCollider3D> sphereCollider = std::make_shared<Nz::BulletSphereCollider3D>(radius);
#endif
entt::handle ballEntity = world.CreateEntity();
std::shared_ptr<Nz::MaterialInstance> ballMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
ballMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f));
std::shared_ptr<Nz::Model> sphereModel = std::make_shared<Nz::Model>(sphereMesh);
sphereModel->SetMaterial(0, std::move(ballMaterial));
auto& ballGfx = ballEntity.emplace<Nz::GraphicsComponent>();
ballGfx.AttachRenderable(std::move(sphereModel));
auto& ballNode = ballEntity.emplace<Nz::NodeComponent>();
ballNode.SetPosition(positionRandom(rd), positionRandom(rd), positionRandom(rd));
ballNode.SetScale(radius);
#if USE_JOLT
auto& ballPhysics = ballEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(sphereCollider));
#else
auto& ballPhysics = ballEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(sphereCollider));
#endif
//ballPhysics.SetMass(4.f / 3.f * Nz::Pi<float> * Nz::IntegralPow(radius, 3));
ballPhysics.DisableSleeping();
}
std::uniform_real_distribution<float> lengthDis(0.1f, 1.f);
std::shared_ptr<Nz::GraphicalMesh> 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<float> xRandom(-BoxDims * 0.5f + width, BoxDims * 0.5f - width);
std::uniform_real_distribution<float> yRandom(-BoxDims * 0.5f + height, BoxDims * 0.5f - height);
std::uniform_real_distribution<float> zRandom(-BoxDims * 0.5f + depth, BoxDims * 0.5f - depth);
entt::handle ballEntity = world.CreateEntity();
std::shared_ptr<Nz::MaterialInstance> boxMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
boxMaterial->SetValueProperty("BaseColor", Nz::Color::FromHSV(colorDis(rd), 1.f, 1.f));
std::shared_ptr<Nz::Model> sphereModel = std::make_shared<Nz::Model>(boxMesh);
sphereModel->SetMaterial(0, std::move(boxMaterial));
auto& ballGfx = ballEntity.emplace<Nz::GraphicsComponent>();
ballGfx.AttachRenderable(std::move(sphereModel));
auto& ballNode = ballEntity.emplace<Nz::NodeComponent>();
ballNode.SetPosition(xRandom(rd), yRandom(rd), zRandom(rd));
ballNode.SetScale(width, height, depth);
#if USE_JOLT
std::shared_ptr<Nz::JoltBoxCollider3D> boxCollider = std::make_shared<Nz::JoltBoxCollider3D>(Nz::Vector3f(width, height, depth));
#else
std::shared_ptr<Nz::BulletBoxCollider3D> boxCollider = std::make_shared<Nz::BulletBoxCollider3D>(Nz::Vector3f(width, height, depth));
#endif
#if USE_JOLT
auto& ballPhysics = ballEntity.emplace<Nz::JoltRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider));
#else
auto& ballPhysics = ballEntity.emplace<Nz::BulletRigidBody3DComponent>(physSystem.CreateRigidBody(boxCollider));
#endif
//ballPhysics.SetMass(width * height * depth);
ballPhysics.DisableSleeping();
}
// Lumière
entt::handle lightEntity = world.CreateEntity();
{
auto& lightNode = lightEntity.emplace<Nz::NodeComponent>();
//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<Nz::LightComponent>();
auto& spotLight = lightComp.AddLight<Nz::SpotLight>();
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<Nz::NodeComponent>();
auto& cameraComponent = cameraEntity.emplace<Nz::CameraComponent>(&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<Nz::NodeComponent>();
cameraNode.SetRotation(camAngles);
cameraNode.SetPosition(target - cameraNode.GetForward() * camDistance);
};
UpdateCamera();
NazaraSlot(Nz::WindowEventHandler, OnMouseMoved, cameraMove);
NazaraSlot(Nz::WindowEventHandler, OnMouseMoved, grabbedObjectMove);
//std::optional<Nz::JoltPivotConstraint3D> 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<Nz::NodeComponent>();
auto& cameraComponent = cameraEntity.get<Nz::CameraComponent>();
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<Nz::NodeComponent>();
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();
}

View File

@ -0,0 +1,5 @@
target("PhysicsPlayground")
add_deps("NazaraGraphics", "NazaraBulletPhysics3D", "NazaraJoltPhysics3D")
add_packages("entt")
add_files("main.cpp")
add_defines("NAZARA_ENTT")

View File

@ -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 <Nazara/BulletPhysics3D/BulletCollider3D.hpp>
#include <Nazara/BulletPhysics3D/Config.hpp>
#include <Nazara/BulletPhysics3D/BulletConstraint3D.hpp>
#include <Nazara/BulletPhysics3D/Enums.hpp>
#include <Nazara/BulletPhysics3D/BulletPhysics3D.hpp>
#include <Nazara/BulletPhysics3D/BulletPhysWorld3D.hpp>
#include <Nazara/BulletPhysics3D/BulletRigidBody3D.hpp>
#include <Nazara/BulletPhysics3D/Config.hpp>
#include <Nazara/BulletPhysics3D/Enums.hpp>
#ifdef NAZARA_ENTT
@ -44,4 +44,4 @@
#endif
#endif // NAZARA_GLOBAL_PHYSICS3D_HPP
#endif // NAZARA_GLOBAL_BULLETPHYSICS3D_HPP

View File

@ -62,11 +62,11 @@ namespace Nz
static std::shared_ptr<BulletCollider3D> 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<Vector3f>& vertices, std::vector<UInt16>& 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<Vector3f>& vertices, std::vector<UInt16>& 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<ChildCollider> childs);
~CompoundCollider3D();
BulletCompoundCollider3D(std::vector<ChildCollider> childs);
~BulletCompoundCollider3D();
void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
@ -123,11 +123,11 @@ namespace Nz
std::vector<ChildCollider> 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<Vector3f>& vertices, std::vector<UInt16>& 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<const Vector3f> vertices, unsigned int vertexCount);
~ConvexCollider3D();
BulletConvexCollider3D(SparsePtr<const Vector3f> vertices, unsigned int vertexCount);
~BulletConvexCollider3D();
void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
@ -157,11 +157,11 @@ namespace Nz
std::unique_ptr<btConvexHullShape> 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<Vector3f>& vertices, std::vector<UInt16>& 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<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
@ -194,11 +194,11 @@ namespace Nz
std::unique_ptr<btEmptyShape> 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<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;

View File

@ -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);

View File

@ -8,6 +8,7 @@
#define NAZARA_BULLETPHYSICS3D_SYSTEMS_BULLETPHYSICS3DSYSTEM_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Clock.hpp>
#include <Nazara/BulletPhysics3D/BulletPhysWorld3D.hpp>
#include <Nazara/BulletPhysics3D/Components/BulletRigidBody3DComponent.hpp>
#include <Nazara/Core/Time.hpp>
@ -32,6 +33,8 @@ namespace Nz
template<typename... Args> 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<entt::entity> 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;
};
}

View File

@ -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 <Nazara/JoltPhysics3D/Config.hpp>
#include <Nazara/JoltPhysics3D/Enums.hpp>
#include <Nazara/JoltPhysics3D/JoltCollider3D.hpp>
#include <Nazara/JoltPhysics3D/JoltConstraint3D.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysics3D.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp>
#include <Nazara/JoltPhysics3D/JoltRigidBody3D.hpp>
#ifdef NAZARA_ENTT
#include <Nazara/JoltPhysics3D/Components.hpp>
#include <Nazara/JoltPhysics3D/Systems.hpp>
#endif
#endif // NAZARA_GLOBAL_JOLTPHYSICS3D_HPP

View File

@ -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 <Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp>
#endif // NAZARA_JOLTPHYSICS3D_COMPONENTS_HPP

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/JoltPhysics3D/JoltRigidBody3D.hpp>
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 <Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.inl>
#endif // NAZARA_JOLTPHYSICS3D_COMPONENTS_JOLTRIGIDBODY3DCOMPONENT_HPP

View File

@ -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 <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
}
#include <Nazara/JoltPhysics3D/DebugOff.hpp>

View File

@ -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 <Nazara/JoltPhysics3D/ConfigCheck.hpp>
#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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/Core/ObjectLibrary.hpp>
#include <Nazara/JoltPhysics3D/Config.hpp>
#include <Nazara/JoltPhysics3D/Enums.hpp>
#include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Utils/Signal.hpp>
#include <Nazara/Utils/SparsePtr.hpp>
#include <memory>
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<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix = Matrix4f::Identity()) const = 0;
virtual std::shared_ptr<StaticMesh> 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<JoltCollider3D> Build(const PrimitiveList& list);
private:
static std::shared_ptr<JoltCollider3D> 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<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
Vector3f GetLengths() const;
JPH::ShapeSettings* GetShapeSettings() const override;
JoltColliderType3D GetType() const override;
private:
std::unique_ptr<JPH::BoxShapeSettings> m_shapeSettings;
Vector3f m_lengths;
};
class NAZARA_JOLTPHYSICS3D_API JoltCompoundCollider3D final : public JoltCollider3D
{
public:
struct ChildCollider;
JoltCompoundCollider3D(std::vector<ChildCollider> childs);
~JoltCompoundCollider3D();
void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
const std::vector<ChildCollider>& GetGeoms() const;
JPH::ShapeSettings* GetShapeSettings() const override;
JoltColliderType3D GetType() const override;
struct ChildCollider
{
std::shared_ptr<JoltCollider3D> collider;
Quaternionf rotation = Quaternionf::Identity();
Vector3f offset = Vector3f::Zero();
};
private:
std::unique_ptr<JPH::CompoundShapeSettings> m_shapeSettings;
std::vector<ChildCollider> m_childs;
};
class NAZARA_JOLTPHYSICS3D_API JoltSphereCollider3D final : public JoltCollider3D
{
public:
JoltSphereCollider3D(float radius);
~JoltSphereCollider3D();
void BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const override;
float GetRadius() const;
JPH::ShapeSettings* GetShapeSettings() const override;
JoltColliderType3D GetType() const override;
private:
std::unique_ptr<JPH::SphereShapeSettings> m_shapeSettings;
Vector3f m_position;
float m_radius;
};
}
#include <Nazara/JoltPhysics3D/JoltCollider3D.inl>
#endif // NAZARA_JOLTPHYSICS3D_JOLTCOLLIDER3D_HPP

View File

@ -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 <memory>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
}
#include <Nazara/JoltPhysics3D/DebugOff.hpp>

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/BulletPhysics3D/BulletPhysWorld3D.hpp>
#include <Nazara/BulletPhysics3D/BulletRigidBody3D.hpp>
#include <Nazara/BulletPhysics3D/Config.hpp>
#include <Nazara/Core/HandledObject.hpp>
#include <Nazara/Core/ObjectHandle.hpp>
class btTypedConstraint;
namespace Nz
{
class BulletConstraint3D;
using BulletConstraint3DHandle = ObjectHandle<BulletConstraint3D>;
class NAZARA_BULLETPHYSICS3D_API BulletConstraint3D : public HandledObject<BulletConstraint3D>
{
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<btTypedConstraint> constraint, bool disableCollisions = false);
template<typename T> T* GetConstraint();
template<typename T> const T* GetConstraint() const;
private:
std::unique_ptr<btTypedConstraint> 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 <Nazara/BulletPhysics3D/BulletConstraint3D.inl>
#endif // NAZARA_BULLETPHYSICS3D_BULLETCONSTRAINT3D_HPP
#endif // NAZARA_JOLTPHYSICS3D_JOLTCONSTRAINT3D_HPP

View File

@ -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 <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
inline bool BulletConstraint3D::IsBodyCollisionEnabled() const
{
return m_bodyCollisionEnabled;
}
template<typename T>
T* BulletConstraint3D::GetConstraint()
{
return SafeCast<T*>(m_constraint.get());
}
template<typename T>
const T* BulletConstraint3D::GetConstraint() const
{
return SafeCast<const T*>(m_constraint.get());
}
}
#include <Nazara/JoltPhysics3D/DebugOff.hpp>

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/JoltPhysics3D/Config.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Utils/FunctionRef.hpp>
#include <Nazara/Utils/MovablePtr.hpp>
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<JoltWorld> m_world;
Vector3f m_gravity;
Time m_stepSize;
Time m_timestepAccumulator;
};
}
#endif // NAZARA_JOLTPHYSICS3D_JOLTPHYSWORLD3D_HPP

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/JoltPhysics3D/Config.hpp>
#include <Nazara/Core/Core.hpp>
#include <memory>
namespace JPH
{
class JobSystem;
class JobSystemThreadPool;
}
namespace Nz
{
class NAZARA_JOLTPHYSICS3D_API JoltPhysics3D : public ModuleBase<JoltPhysics3D>
{
friend ModuleBase;
public:
using Dependencies = TypeList<Core>;
struct Config {};
JoltPhysics3D(Config /*config*/);
~JoltPhysics3D();
JPH::JobSystem& GetThreadPool();
private:
std::unique_ptr<JPH::JobSystemThreadPool> m_threadPool;
static JoltPhysics3D* s_instance;
};
}
#endif // NAZARA_JOLTPHYSICS3D_HPP

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/JoltPhysics3D/JoltCollider3D.hpp>
#include <Nazara/JoltPhysics3D/Config.hpp>
#include <Nazara/Core/Enums.hpp>
#include <Nazara/Math/Matrix4.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Utils/MovablePtr.hpp>
namespace Nz
{
class JoltPhysWorld3D;
class NAZARA_JOLTPHYSICS3D_API JoltRigidBody3D
{
public:
JoltRigidBody3D(JoltPhysWorld3D* world, const Matrix4f& mat = Matrix4f::Identity());
JoltRigidBody3D(JoltPhysWorld3D* world, std::shared_ptr<JoltCollider3D> 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<JoltCollider3D>& 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<JoltCollider3D> 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<JoltCollider3D> m_geom;
JoltPhysWorld3D* m_world;
UInt32 m_bodyIndex;
};
}
#include <Nazara/JoltPhysics3D/JoltRigidBody3D.inl>
#endif // NAZARA_JOLTPHYSICS3D_JOLTRIGIDBODY3D_HPP

View File

@ -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 <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
inline void JoltRigidBody3D::DisableSleeping()
{
return EnableSleeping(false);
}
inline const std::shared_ptr<JoltCollider3D>& JoltRigidBody3D::GetGeom() const
{
return m_geom;
}
inline JoltPhysWorld3D* JoltRigidBody3D::GetWorld() const
{
return m_world;
}
}
#include <Nazara/JoltPhysics3D/DebugOff.hpp>

View File

@ -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 <Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp>
#endif // NAZARA_JOLTPHYSICS3D_SYSTEMS_HPP

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Clock.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp>
#include <Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Utils/TypeList.hpp>
#include <entt/entt.hpp>
#include <vector>
namespace Nz
{
class NAZARA_JOLTPHYSICS3D_API JoltPhysics3DSystem
{
public:
static constexpr Int64 ExecutionOrder = 0;
using Components = TypeList<JoltRigidBody3DComponent, class NodeComponent>;
struct RaycastHit;
JoltPhysics3DSystem(entt::registry& registry);
JoltPhysics3DSystem(const JoltPhysics3DSystem&) = delete;
JoltPhysics3DSystem(JoltPhysics3DSystem&&) = delete;
~JoltPhysics3DSystem();
template<typename... Args> 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<entt::entity> 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 <Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.inl>
#endif // NAZARA_JOLTPHYSICS3D_SYSTEMS_JOLTPHYSICS3DSYSTEM_HPP

View File

@ -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 <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
template<typename... Args>
JoltRigidBody3DComponent JoltPhysics3DSystem::CreateRigidBody(Args&&... args)
{
return JoltRigidBody3DComponent(&m_physWorld, std::forward<Args>(args)...);
}
inline JoltPhysWorld3D& JoltPhysics3DSystem::GetPhysWorld()
{
return m_physWorld;
}
inline const JoltPhysWorld3D& JoltPhysics3DSystem::GetPhysWorld() const
{
return m_physWorld;
}
}
#include <Nazara/JoltPhysics3D/DebugOff.hpp>

View File

@ -72,7 +72,7 @@ namespace Nz
std::size_t primitiveCount = list.GetSize();
if (primitiveCount > 1)
{
std::vector<CompoundCollider3D::ChildCollider> childColliders(primitiveCount);
std::vector<BulletCompoundCollider3D::ChildCollider> 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<CompoundCollider3D>(std::move(childColliders));
return std::make_shared<BulletCompoundCollider3D>(std::move(childColliders));
}
else if (primitiveCount > 0)
return CreateGeomFromPrimitive(list.GetPrimitive(0));
else
return std::make_shared<NullCollider3D>();
return std::make_shared<BulletNullCollider3D>();
}
std::shared_ptr<BulletCollider3D> BulletCollider3D::CreateGeomFromPrimitive(const Primitive& primitive)
@ -94,17 +94,17 @@ namespace Nz
switch (primitive.type)
{
case PrimitiveType::Box:
return std::make_shared<BoxCollider3D>(primitive.box.lengths);
return std::make_shared<BulletBoxCollider3D>(primitive.box.lengths);
case PrimitiveType::Cone:
return std::make_shared<ConeCollider3D>(primitive.cone.length, primitive.cone.radius);
return std::make_shared<BulletConeCollider3D>(primitive.cone.length, primitive.cone.radius);
case PrimitiveType::Plane:
return std::make_shared<BoxCollider3D>(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y));
return std::make_shared<BulletBoxCollider3D>(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y));
///TODO: PlaneGeom?
case PrimitiveType::Sphere:
return std::make_shared<SphereCollider3D>(primitive.sphere.size);
return std::make_shared<BulletSphereCollider3D>(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<btBoxShape>(ToBullet(m_lengths * 0.5f));
}
BoxCollider3D::~BoxCollider3D() = default;
BulletBoxCollider3D::~BulletBoxCollider3D() = default;
void BoxCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletBoxCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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<btCapsuleShape>(radius, length);
}
CapsuleCollider3D::~CapsuleCollider3D() = default;
BulletCapsuleCollider3D::~BulletCapsuleCollider3D() = default;
void CapsuleCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletCapsuleCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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<ChildCollider> childs) :
BulletCompoundCollider3D::BulletCompoundCollider3D(std::vector<ChildCollider> childs) :
m_childs(std::move(childs))
{
m_shape = std::make_unique<btCompoundShape>();
@ -226,67 +226,67 @@ namespace Nz
}
}
CompoundCollider3D::~CompoundCollider3D() = default;
BulletCompoundCollider3D::~BulletCompoundCollider3D() = default;
void CompoundCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletCompoundCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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<ChildCollider>&
auto BulletCompoundCollider3D::GetGeoms() const -> const std::vector<ChildCollider>&
{
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<btConeShape>(radius, length);
}
ConeCollider3D::~ConeCollider3D() = default;
BulletConeCollider3D::~BulletConeCollider3D() = default;
void ConeCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletConeCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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<const Vector3f> vertices, unsigned int vertexCount)
BulletConvexCollider3D::BulletConvexCollider3D(SparsePtr<const Vector3f> vertices, unsigned int vertexCount)
{
static_assert(std::is_same_v<btScalar, float>);
@ -294,9 +294,9 @@ namespace Nz
m_shape->optimizeConvexHull();
}
ConvexCollider3D::~ConvexCollider3D() = default;
BulletConvexCollider3D::~BulletConvexCollider3D() = default;
void ConvexCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletConvexCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
{
tsl::ordered_map<Vector3f, UInt16> 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<btCylinderShape>(btVector3{ radius, length, radius });
}
CylinderCollider3D::~CylinderCollider3D() = default;
BulletCylinderCollider3D::~BulletCylinderCollider3D() = default;
void CylinderCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletCylinderCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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<btEmptyShape>();
}
NullCollider3D::~NullCollider3D() = default;
BulletNullCollider3D::~BulletNullCollider3D() = default;
void NullCollider3D::BuildDebugMesh(std::vector<Vector3f>& /*vertices*/, std::vector<UInt16>& /*indices*/, const Matrix4f& /*offsetMatrix*/) const
void BulletNullCollider3D::BuildDebugMesh(std::vector<Vector3f>& /*vertices*/, std::vector<UInt16>& /*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<btSphereShape>(radius);
}
SphereCollider3D::~SphereCollider3D() = default;
BulletSphereCollider3D::~BulletSphereCollider3D() = default;
void SphereCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
void BulletSphereCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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;
}

View File

@ -121,11 +121,19 @@ namespace Nz
}
}
#define HACK 0
btRigidBody* BulletPhysWorld3D::AddRigidBody(std::size_t& rigidBodyIndex, FunctionRef<void(btRigidBody* body)> 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
}
}

View File

@ -27,7 +27,7 @@ namespace Nz
NazaraAssert(m_world, "Invalid world");
if (!m_geom)
m_geom = std::make_shared<NullCollider3D>();
m_geom = std::make_shared<BulletNullCollider3D>();
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<NullCollider3D>();
m_geom = std::make_shared<BulletNullCollider3D>();
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();

View File

@ -4,6 +4,7 @@
#include <Nazara/BulletPhysics3D/Systems/BulletPhysics3DSystem.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>
#include <iostream>
#include <Nazara/BulletPhysics3D/Debug.hpp>
namespace Nz
@ -14,6 +15,10 @@ namespace Nz
{
m_constructConnection = registry.on_construct<BulletRigidBody3DComponent>().connect<&BulletPhysics3DSystem::OnConstruct>(this);
m_destructConnection = registry.on_destroy<BulletRigidBody3DComponent>().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<BulletRigidBody3DComponent>(entity);
NodeComponent& entityNode = m_registry.get<NodeComponent>(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)

View File

@ -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 <Nazara/JoltPhysics3D/Components/JoltRigidBody3DComponent.hpp>
#include <Nazara/BulletPhysics3D/Components/BulletRigidBody3DComponent.hpp>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
}

View File

@ -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 <Nazara/JoltPhysics3D/JoltCollider3D.hpp>
#include <Nazara/Core/PrimitiveList.hpp>
#include <Nazara/JoltPhysics3D/JoltHelper.hpp>
#include <Nazara/Utility/Algorithm.hpp>
#include <Nazara/Utility/IndexBuffer.hpp>
#include <Nazara/Utility/SoftwareBuffer.hpp>
#include <Nazara/Utility/StaticMesh.hpp>
#include <Nazara/Utility/VertexBuffer.hpp>
#include <Nazara/Utils/MemoryHelper.hpp>
#include <Jolt/Core/Core.h>
#include <Jolt/Physics/Collision/Shape/BoxShape.h>
#include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
#include <Jolt/Physics/Collision/Shape/SphereShape.h>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
JoltCollider3D::~JoltCollider3D() = default;
std::shared_ptr<StaticMesh> JoltCollider3D::GenerateDebugMesh() const
{
std::vector<Vector3f> colliderVertices;
std::vector<UInt16> colliderIndices;
BuildDebugMesh(colliderVertices, colliderIndices);
std::shared_ptr<VertexBuffer> colliderVB = std::make_shared<VertexBuffer>(VertexDeclaration::Get(VertexLayout::XYZ), SafeCast<UInt32>(colliderVertices.size()), BufferUsage::Write, SoftwareBufferFactory, colliderVertices.data());
std::shared_ptr<IndexBuffer> colliderIB = std::make_shared<IndexBuffer>(IndexType::U16, colliderIndices.size(), BufferUsage::Write, SoftwareBufferFactory, colliderIndices.data());
std::shared_ptr<StaticMesh> colliderSubMesh = std::make_shared<StaticMesh>(std::move(colliderVB), std::move(colliderIB));
colliderSubMesh->GenerateAABB();
colliderSubMesh->SetPrimitiveMode(PrimitiveMode::LineList);
return colliderSubMesh;
}
std::shared_ptr<JoltCollider3D> JoltCollider3D::Build(const PrimitiveList& list)
{
std::size_t primitiveCount = list.GetSize();
if (primitiveCount > 1)
{
std::vector<JoltCompoundCollider3D::ChildCollider> 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<JoltCompoundCollider3D>(std::move(childColliders));
}
else if (primitiveCount > 0)
return CreateGeomFromPrimitive(list.GetPrimitive(0));
else
return nullptr;// std::make_shared<NullCollider3D>(); //< TODO
}
std::shared_ptr<JoltCollider3D> JoltCollider3D::CreateGeomFromPrimitive(const Primitive& primitive)
{
switch (primitive.type)
{
case PrimitiveType::Box:
return std::make_shared<JoltBoxCollider3D>(primitive.box.lengths);
case PrimitiveType::Cone:
return nullptr; //< TODO
//return std::make_shared<ConeCollider3D>(primitive.cone.length, primitive.cone.radius);
case PrimitiveType::Plane:
return std::make_shared<JoltBoxCollider3D>(Vector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y));
///TODO: PlaneGeom?
case PrimitiveType::Sphere:
return std::make_shared<JoltSphereCollider3D>(primitive.sphere.size);
}
NazaraError("Primitive type not handled (0x" + NumberToString(UnderlyingCast(primitive.type), 16) + ')');
return std::shared_ptr<JoltCollider3D>();
}
/********************************** BoxCollider3D **********************************/
JoltBoxCollider3D::JoltBoxCollider3D(const Vector3f& lengths, float convexRadius) :
m_lengths(lengths)
{
m_shapeSettings = std::make_unique<JPH::BoxShapeSettings>(ToJolt(m_lengths * 0.5f), convexRadius);
}
JoltBoxCollider3D::~JoltBoxCollider3D() = default;
void JoltBoxCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& indices, const Matrix4f& offsetMatrix) const
{
auto InsertVertex = [&](float x, float y, float z) -> UInt16
{
UInt16 index = SafeCast<UInt16>(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<ChildCollider> childs) :
m_childs(std::move(childs))
{
m_shapeSettings = std::make_unique<JPH::StaticCompoundShapeSettings>();
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<Vector3f>& vertices, std::vector<UInt16>& 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<ChildCollider>&
{
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<JPH::SphereShapeSettings>(radius);
}
JoltSphereCollider3D::~JoltSphereCollider3D() = default;
void JoltSphereCollider3D::BuildDebugMesh(std::vector<Vector3f>& vertices, std::vector<UInt16>& 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;
}
}

View File

@ -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 <Nazara/JoltPhysics3D/JoltConstraint3D.hpp>
#include <Nazara/BulletPhysics3D/BulletConstraint3D.hpp>
#include <Nazara/BulletPhysics3D/BulletHelper.hpp>
#include <BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h>
#include <BulletDynamics/Dynamics/btDynamicsWorld.h>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
BulletConstraint3D::BulletConstraint3D(std::unique_ptr<btTypedConstraint> 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<BulletRigidBody3D*>(m_constraint->getRigidBodyA().getUserPointer());
}
const BulletRigidBody3D& BulletConstraint3D::GetBodyA() const
{
return *static_cast<BulletRigidBody3D*>(m_constraint->getRigidBodyA().getUserPointer());
}
BulletRigidBody3D& BulletConstraint3D::GetBodyB()
{
NazaraAssert(!IsSingleBody(), "constraint is not attached to a second body");
return *static_cast<BulletRigidBody3D*>(m_constraint->getRigidBodyB().getUserPointer());
}
const BulletRigidBody3D& BulletConstraint3D::GetBodyB() const
{
NazaraAssert(!IsSingleBody(), "constraint is not attached to a second body");
return *static_cast<BulletRigidBody3D*>(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<btPoint2PointConstraint>(*first.GetRigidBody(), ToBullet(first.ToLocal(pivot))))
{
}
BulletPivotConstraint3D::BulletPivotConstraint3D(BulletRigidBody3D& first, BulletRigidBody3D& second, const Vector3f& pivot, bool disableCollisions) :
BulletConstraint3D(std::make_unique<btPoint2PointConstraint>(*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<btPoint2PointConstraint>(*first.GetRigidBody(), *second.GetRigidBody(), ToBullet(firstAnchor), ToBullet(secondAnchor)), disableCollisions)
{
}
Vector3f BulletPivotConstraint3D::GetFirstAnchor() const
{
return FromBullet(GetConstraint<btPoint2PointConstraint>()->getPivotInA());
}
Vector3f BulletPivotConstraint3D::GetSecondAnchor() const
{
return FromBullet(GetConstraint<btPoint2PointConstraint>()->getPivotInB());
}
void BulletPivotConstraint3D::SetFirstAnchor(const Vector3f& firstAnchor)
{
GetConstraint<btPoint2PointConstraint>()->setPivotA(ToBullet(firstAnchor));
}
void BulletPivotConstraint3D::SetSecondAnchor(const Vector3f& secondAnchor)
{
GetConstraint<btPoint2PointConstraint>()->setPivotB(ToBullet(secondAnchor));
}
}
#endif

View File

@ -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 <Nazara/Prerequisites.hpp>
#include <Nazara/BulletPhysics3D/Config.hpp>
#include <Nazara/Math/Matrix4.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Jolt/Jolt.h>
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 <Nazara/JoltPhysics3D/JoltHelper.inl>
#endif // NAZARA_JOLTPHYSICS3D_JOLTHELPER_HPP

View File

@ -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 <Nazara/JoltPhysics3D/Debug.hpp>
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 <Nazara/JoltPhysics3D/DebugOff.hpp>

View File

@ -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 <Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp>
#include <Nazara/JoltPhysics3D/JoltHelper.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysics3D.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp>
#include <Nazara/Utils/MemoryPool.hpp>
#include <Nazara/Utils/StackVector.hpp>
#include <Jolt/Jolt.h>
#include <Jolt/Core/TempAllocator.h>
#include <Jolt/Physics/Collision/ObjectLayer.h>
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
#include <Jolt/Physics/PhysicsSettings.h>
#include <Jolt/Physics/PhysicsSystem.h>
#include <Jolt/Physics/Body/BodyActivationListener.h>
#include <cassert>
#include <iostream>
#include <Nazara/JoltPhysics3D/Debug.hpp>
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<JoltWorld>();
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<BulletRigidBody3D*>(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<float>();
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++;
}
}
}

View File

@ -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 <Nazara/JoltPhysics3D/JoltPhysics3D.hpp>
#include <Nazara/JoltPhysics3D/Config.hpp>
#include <Nazara/Core/Core.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Log.hpp>
#include <Jolt/Jolt.h>
#include <Jolt/RegisterTypes.h>
#include <Jolt/Core/Factory.h>
#include <Jolt/Core/JobSystemThreadPool.h>
#include <Jolt/Physics/PhysicsSettings.h>
#include <cstdarg>
#include <iostream>
#include <Nazara/JoltPhysics3D/Debug.hpp>
// 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::JobSystemThreadPool>(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;
}

View File

@ -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 <Nazara/JoltPhysics3D/JoltRigidBody3D.hpp>
#include <Nazara/JoltPhysics3D/JoltHelper.hpp>
#include <Nazara/JoltPhysics3D/JoltPhysWorld3D.hpp>
#include <Nazara/JoltPhysics3D/JoltRigidBody3D.hpp>
#include <Nazara/Utils/MemoryHelper.hpp>
#include <Jolt/Jolt.h>
#include <Jolt/Physics/PhysicsSystem.h>
#include <Jolt/Physics/Body/BodyCreationSettings.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D* world, const Matrix4f& mat) :
JoltRigidBody3D(world, nullptr, mat)
{
}
JoltRigidBody3D::JoltRigidBody3D(JoltPhysWorld3D* world, std::shared_ptr<JoltCollider3D> 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<JoltSphereCollider3D>(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<UInt64>(reinterpret_cast<std::uintptr_t>(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<JoltCollider3D> geom, bool recomputeInertia)
{
if (m_geom != geom)
{
if (geom)
m_geom = std::move(geom);
else
m_geom = std::make_shared<NullCollider3D>();
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();
}
}

View File

@ -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 <Nazara/JoltPhysics3D/Systems/JoltPhysics3DSystem.hpp>
#include <Nazara/Utility/Components/NodeComponent.hpp>
#include <iostream>
#include <Nazara/JoltPhysics3D/Debug.hpp>
namespace Nz
{
JoltPhysics3DSystem::JoltPhysics3DSystem(entt::registry& registry) :
m_registry(registry),
m_physicsConstructObserver(m_registry, entt::collector.group<JoltRigidBody3DComponent, NodeComponent>())
{
m_constructConnection = registry.on_construct<JoltRigidBody3DComponent>().connect<&JoltPhysics3DSystem::OnConstruct>(this);
m_destructConnection = registry.on_destroy<JoltRigidBody3DComponent>().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<JoltRigidBody3DComponent>();
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<JoltRigidBody3DComponent>(entity);
NodeComponent& entityNode = m_registry.get<NodeComponent>(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<NodeComponent, const JoltRigidBody3DComponent>();
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)
{
}
}

View File

@ -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 } })