Engine²
Open-source game engine written in C++.
Loading...
Searching...
No Matches
ConstraintHelpers.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Physics.pch.hpp"
4
5#include "Logger.hpp"
11
13#include <array>
14#include <fmt/format.h>
15#include <stdexcept>
16
17#include <Jolt/Physics/Body/BodyLockMulti.h>
18#include <Jolt/Physics/Constraints/DistanceConstraint.h>
19#include <Jolt/Physics/Constraints/FixedConstraint.h>
20#include <Jolt/Physics/Constraints/PointConstraint.h>
21#include <Jolt/Physics/PhysicsSystem.h>
22
23namespace Physics::System {
24
29 JPH::PhysicsSystem &physicsSystem;
30
31 static std::optional<ConstraintContext> Create(Engine::Core::Registry &registry, const char *constraintName);
32};
33
34template <typename ConstraintT>
35static bool ValidateConstraint(const ConstraintT &constraint, const char *constraintName)
36{
37 const char *safeName = constraintName ? constraintName : "<constraint>";
38 if (!constraint.bodyA.IsNull())
39 {
40 Log::Error(fmt::format("{}: bodyA is invalid", safeName));
41 return false;
42 }
43
44 if (constraint.bodyA == constraint.bodyB)
45 {
46 Log::Error(fmt::format("{}: Cannot constrain body to itself", safeName));
47 return false;
48 }
49
50 return true;
51}
52
53Component::RigidBodyInternal *GetBodyInternal(Engine::Entity entity, const char *constraintName, const char *bodyName);
54
55template <typename SettingsT, typename ConstraintT>
56static JPH::Constraint *CreateJoltConstraint(ConstraintContext &ctx, SettingsT &joltSettings,
57 const ConstraintT &constraint, Component::RigidBodyInternal *internalA,
58 const char *constraintName)
59{
60 if (constraint.IsWorldConstraint())
61 {
62 JPH::BodyLockWrite lockA(ctx.physicsSystem.GetBodyLockInterface(), internalA->bodyID);
63 if (!lockA.Succeeded())
64 {
65 Log::Error(fmt::format("{}: Failed to lock bodyA", constraintName));
66 return nullptr;
67 }
68
69 joltSettings.mSpace = JPH::EConstraintSpace::WorldSpace;
70 joltSettings.mPoint2 = Utils::ToJoltRVec3(constraint.localPointB);
71
72 return joltSettings.Create(lockA.GetBody(), JPH::Body::sFixedToWorld);
73 }
74
75 auto *internalB = GetBodyInternal(Engine::Entity{ctx.core, constraint.bodyB}, constraintName, "bodyB");
76 if (!internalB)
77 return nullptr;
78
79 std::array<JPH::BodyID, 2> bodyIDs = {internalA->bodyID, internalB->bodyID};
80 JPH::BodyLockMultiWrite lock(ctx.physicsSystem.GetBodyLockInterface(), bodyIDs.data(),
81 static_cast<int>(bodyIDs.size()));
82
83 JPH::Body *bodyA = lock.GetBody(0);
84 JPH::Body *bodyB = lock.GetBody(1);
85
86 if (!bodyA || !bodyB)
87 {
88 Log::Error(fmt::format("{}: Failed to lock bodies", constraintName));
89 return nullptr;
90 }
91
92 return joltSettings.Create(*bodyA, *bodyB);
93}
94
95void FinalizeConstraint(ConstraintContext &ctx, Engine::Entity entity, JPH::Constraint *joltConstraint,
97 const char *constraintName);
98
99void DestroyConstraint(Engine::Core::Registry &registry, Engine::EntityId entity, const char *constraintName);
100
101template <Component::ConstraintType TYPE, typename CompT, typename SettingsT, typename Configurator,
102 typename ExtraValidate>
104 const char *constraintName, Configurator &&configurator,
105 ExtraValidate &&extraValidate)
106{
107 const char *safeName = constraintName ? constraintName : "<constraint>";
108 try
109 {
110 auto ctxOpt = ConstraintContext::Create(registry, safeName);
111 if (!ctxOpt)
112 return;
113 auto &ctx = *ctxOpt;
114
115 auto &constraint = registry.get<CompT>(entity);
116
117 if (!ValidateConstraint(constraint, safeName))
118 return;
119
120 if (!extraValidate(constraint))
121 return;
122
123 auto *internalA = GetBodyInternal(Engine::Entity{ctx.core, constraint.bodyA}, safeName, "bodyA");
124 if (!internalA)
125 return;
126
127 SettingsT joltSettings;
128 joltSettings.mSpace = JPH::EConstraintSpace::LocalToBodyCOM;
129
130 configurator(constraint, joltSettings);
131
132 auto *joltConstraint = CreateJoltConstraint(ctx, joltSettings, constraint, internalA, safeName);
133 FinalizeConstraint(ctx, Engine::Entity{ctx.core, entity}, joltConstraint, TYPE, constraint.settings, safeName);
134 }
136 {
137 Log::Warning(fmt::format("{} constraint error: {}", safeName, e.what()));
138 }
139 catch (const std::bad_alloc &e)
140 {
141 Log::Critical(fmt::format("{} bad alloc: {}", safeName, e.what()));
142 }
143 catch (const std::exception &e)
144 {
145 Log::Error(fmt::format("{} unexpected error: {}", safeName, e.what()));
146 }
147}
148
149} // namespace Physics::System
The core is the place where all the data of the engine is stored. It contains the registry (entities)...
Definition Core.hpp:33
entt::basic_registry< Id > Registry
The type of the registry used by the core. It is an alias for entt::basic_registry with Id as entity ...
Definition Core.hpp:37
Wrapper class providing a convenient interface for entity manipulation with the Core....
Definition Entity.hpp:20
Exception thrown when a constraint operation fails.
Definition ConstraintError.hpp:37
Definition PhysicsManager.hpp:25
void Warning(const T &msg) noexcept
Definition Logger.hpp:49
void Error(const T &msg) noexcept
Definition Logger.hpp:51
void Critical(const T &msg) noexcept
Definition Logger.hpp:53
ConstraintType
Enumeration of supported constraint types.
Definition ConstraintInternal.hpp:38
Definition CharacterControllerSystem.cpp:15
static JPH::Constraint * CreateJoltConstraint(ConstraintContext &ctx, SettingsT &joltSettings, const ConstraintT &constraint, Component::RigidBodyInternal *internalA, const char *constraintName)
Definition ConstraintHelpers.hpp:56
void FinalizeConstraint(ConstraintContext &ctx, Engine::Entity entity, JPH::Constraint *joltConstraint, Component::ConstraintType type, const Component::ConstraintSettings &settings, const char *constraintName)
Definition ConstraintHelpers.cpp:54
void DestroyConstraint(Engine::Core::Registry &registry, Engine::EntityId entity, const char *constraintName)
Definition ConstraintHelpers.cpp:111
static bool ValidateConstraint(const ConstraintT &constraint, const char *constraintName)
Definition ConstraintHelpers.hpp:35
Component::RigidBodyInternal * GetBodyInternal(Engine::Entity entity, const char *constraintName, const char *bodyName)
Definition ConstraintHelpers.cpp:42
static void CreateConstraintGeneric(Engine::Core::Registry &registry, Engine::EntityId entity, const char *constraintName, Configurator &&configurator, ExtraValidate &&extraValidate)
Definition ConstraintHelpers.hpp:103
JPH::RVec3 ToJoltRVec3(const glm::vec3 &v)
Convert glm::vec3 to JPH::RVec3 (real vector, double precision).
Definition JoltConversions.hpp:46
Represents a unique identifier for an entity in the Engine's entity-component system....
Definition EntityId.hpp:14
Definition ConstraintSettings.hpp:52
Internal component storing Jolt Physics data.
Definition RigidBodyInternal.hpp:40
JPH::BodyID bodyID
Jolt Physics body identifier.
Definition RigidBodyInternal.hpp:42
Definition ConstraintHelpers.hpp:25
Engine::Core & core
Definition ConstraintHelpers.hpp:26
Resource::PhysicsManager & physicsManager
Definition ConstraintHelpers.hpp:28
static std::optional< ConstraintContext > Create(Engine::Core::Registry &registry, const char *constraintName)
Definition ConstraintHelpers.cpp:5
Engine::Core::Registry & registry
Definition ConstraintHelpers.hpp:27
JPH::PhysicsSystem & physicsSystem
Definition ConstraintHelpers.hpp:29