Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Constraints/ConstraintManager.cpp
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/Physics/Constraints/ConstraintManager.h>
8
#include <Jolt/Physics/Constraints/CalculateSolverSteps.h>
9
#include <Jolt/Physics/IslandBuilder.h>
10
#include <Jolt/Physics/StateRecorder.h>
11
#include <Jolt/Physics/PhysicsLock.h>
12
#include <Jolt/Core/Profiler.h>
13
#include <Jolt/Core/QuickSort.h>
14
15
JPH_NAMESPACE_BEGIN
16
17
void ConstraintManager::Add(Constraint **inConstraints, int inNumber)
18
{
19
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
20
21
mConstraints.reserve(mConstraints.size() + inNumber);
22
23
for (Constraint **c = inConstraints, **c_end = inConstraints + inNumber; c < c_end; ++c)
24
{
25
Constraint *constraint = *c;
26
27
// Assume this constraint has not been added yet
28
JPH_ASSERT(constraint->mConstraintIndex == Constraint::cInvalidConstraintIndex);
29
30
// Add to the list
31
constraint->mConstraintIndex = uint32(mConstraints.size());
32
mConstraints.push_back(constraint);
33
}
34
}
35
36
void ConstraintManager::Remove(Constraint **inConstraints, int inNumber)
37
{
38
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
39
40
for (Constraint **c = inConstraints, **c_end = inConstraints + inNumber; c < c_end; ++c)
41
{
42
Constraint *constraint = *c;
43
44
// Reset constraint index for this constraint
45
uint32 this_constraint_idx = constraint->mConstraintIndex;
46
constraint->mConstraintIndex = Constraint::cInvalidConstraintIndex;
47
JPH_ASSERT(this_constraint_idx != Constraint::cInvalidConstraintIndex);
48
49
// Check if this constraint is somewhere in the middle of the constraints, in this case we need to move the last constraint to this position
50
uint32 last_constraint_idx = uint32(mConstraints.size() - 1);
51
if (this_constraint_idx < last_constraint_idx)
52
{
53
Constraint *last_constraint = mConstraints[last_constraint_idx];
54
last_constraint->mConstraintIndex = this_constraint_idx;
55
mConstraints[this_constraint_idx] = last_constraint;
56
}
57
58
// Pop last constraint
59
mConstraints.pop_back();
60
}
61
}
62
63
Constraints ConstraintManager::GetConstraints() const
64
{
65
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
66
67
Constraints copy = mConstraints;
68
return copy;
69
}
70
71
void ConstraintManager::GetActiveConstraints(uint32 inStartConstraintIdx, uint32 inEndConstraintIdx, Constraint **outActiveConstraints, uint32 &outNumActiveConstraints) const
72
{
73
JPH_PROFILE_FUNCTION();
74
75
JPH_ASSERT(inEndConstraintIdx <= mConstraints.size());
76
77
uint32 num_active_constraints = 0;
78
for (uint32 constraint_idx = inStartConstraintIdx; constraint_idx < inEndConstraintIdx; ++constraint_idx)
79
{
80
Constraint *c = mConstraints[constraint_idx];
81
JPH_ASSERT(c->mConstraintIndex == constraint_idx);
82
if (c->IsActive())
83
{
84
*(outActiveConstraints++) = c;
85
num_active_constraints++;
86
}
87
}
88
89
outNumActiveConstraints = num_active_constraints;
90
}
91
92
void ConstraintManager::sBuildIslands(Constraint **inActiveConstraints, uint32 inNumActiveConstraints, IslandBuilder &ioBuilder, BodyManager &inBodyManager)
93
{
94
JPH_PROFILE_FUNCTION();
95
96
for (uint32 constraint_idx = 0; constraint_idx < inNumActiveConstraints; ++constraint_idx)
97
{
98
Constraint *c = inActiveConstraints[constraint_idx];
99
c->BuildIslands(constraint_idx, ioBuilder, inBodyManager);
100
}
101
}
102
103
void ConstraintManager::sSortConstraints(Constraint **inActiveConstraints, uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd)
104
{
105
JPH_PROFILE_FUNCTION();
106
107
QuickSort(inConstraintIdxBegin, inConstraintIdxEnd, [inActiveConstraints](uint32 inLHS, uint32 inRHS) {
108
const Constraint *lhs = inActiveConstraints[inLHS];
109
const Constraint *rhs = inActiveConstraints[inRHS];
110
111
if (lhs->GetConstraintPriority() != rhs->GetConstraintPriority())
112
return lhs->GetConstraintPriority() < rhs->GetConstraintPriority();
113
114
return lhs->mConstraintIndex < rhs->mConstraintIndex;
115
});
116
}
117
118
void ConstraintManager::sSetupVelocityConstraints(Constraint **inActiveConstraints, uint32 inNumActiveConstraints, float inDeltaTime)
119
{
120
JPH_PROFILE_FUNCTION();
121
122
for (Constraint **c = inActiveConstraints, **c_end = inActiveConstraints + inNumActiveConstraints; c < c_end; ++c)
123
(*c)->SetupVelocityConstraint(inDeltaTime);
124
}
125
126
template <class ConstraintCallback>
127
void ConstraintManager::sWarmStartVelocityConstraints(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, ConstraintCallback &ioCallback)
128
{
129
JPH_PROFILE_FUNCTION();
130
131
for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
132
{
133
Constraint *c = inActiveConstraints[*constraint_idx];
134
ioCallback(c);
135
c->WarmStartVelocityConstraint(inWarmStartImpulseRatio);
136
}
137
}
138
139
// Specialize for the two constraint callback types
140
template void ConstraintManager::sWarmStartVelocityConstraints<CalculateSolverSteps>(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, CalculateSolverSteps &ioCallback);
141
template void ConstraintManager::sWarmStartVelocityConstraints<DummyCalculateSolverSteps>(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, DummyCalculateSolverSteps &ioCallback);
142
143
bool ConstraintManager::sSolveVelocityConstraints(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime)
144
{
145
JPH_PROFILE_FUNCTION();
146
147
bool any_impulse_applied = false;
148
149
for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
150
{
151
Constraint *c = inActiveConstraints[*constraint_idx];
152
any_impulse_applied |= c->SolveVelocityConstraint(inDeltaTime);
153
}
154
155
return any_impulse_applied;
156
}
157
158
bool ConstraintManager::sSolvePositionConstraints(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime, float inBaumgarte)
159
{
160
JPH_PROFILE_FUNCTION();
161
162
bool any_impulse_applied = false;
163
164
for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)
165
{
166
Constraint *c = inActiveConstraints[*constraint_idx];
167
any_impulse_applied |= c->SolvePositionConstraint(inDeltaTime, inBaumgarte);
168
}
169
170
return any_impulse_applied;
171
}
172
173
#ifdef JPH_DEBUG_RENDERER
174
void ConstraintManager::DrawConstraints(DebugRenderer *inRenderer) const
175
{
176
JPH_PROFILE_FUNCTION();
177
178
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
179
180
for (const Ref<Constraint> &c : mConstraints)
181
c->DrawConstraint(inRenderer);
182
}
183
184
void ConstraintManager::DrawConstraintLimits(DebugRenderer *inRenderer) const
185
{
186
JPH_PROFILE_FUNCTION();
187
188
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
189
190
for (const Ref<Constraint> &c : mConstraints)
191
c->DrawConstraintLimits(inRenderer);
192
}
193
194
void ConstraintManager::DrawConstraintReferenceFrame(DebugRenderer *inRenderer) const
195
{
196
JPH_PROFILE_FUNCTION();
197
198
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
199
200
for (const Ref<Constraint> &c : mConstraints)
201
c->DrawConstraintReferenceFrame(inRenderer);
202
}
203
#endif // JPH_DEBUG_RENDERER
204
205
void ConstraintManager::SaveState(StateRecorder &inStream, const StateRecorderFilter *inFilter) const
206
{
207
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
208
209
// Write state of constraints
210
if (inFilter != nullptr)
211
{
212
// Determine which constraints to save
213
Array<Constraint *> constraints;
214
constraints.reserve(mConstraints.size());
215
for (const Ref<Constraint> &c : mConstraints)
216
if (inFilter->ShouldSaveConstraint(*c))
217
constraints.push_back(c);
218
219
// Save them
220
uint32 num_constraints = (uint32)constraints.size();
221
inStream.Write(num_constraints);
222
for (const Constraint *c : constraints)
223
{
224
inStream.Write(c->mConstraintIndex);
225
c->SaveState(inStream);
226
}
227
}
228
else
229
{
230
// Save all constraints
231
uint32 num_constraints = (uint32)mConstraints.size();
232
inStream.Write(num_constraints);
233
for (const Ref<Constraint> &c : mConstraints)
234
{
235
inStream.Write(c->mConstraintIndex);
236
c->SaveState(inStream);
237
}
238
}
239
}
240
241
bool ConstraintManager::RestoreState(StateRecorder &inStream)
242
{
243
UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));
244
245
if (inStream.IsValidating())
246
{
247
// Read state of constraints
248
uint32 num_constraints = (uint32)mConstraints.size(); // Initialize to current value for validation
249
inStream.Read(num_constraints);
250
if (num_constraints != mConstraints.size())
251
{
252
JPH_ASSERT(false, "Cannot handle adding/removing constraints");
253
return false;
254
}
255
for (const Ref<Constraint> &c : mConstraints)
256
{
257
uint32 constraint_index = c->mConstraintIndex;
258
inStream.Read(constraint_index);
259
if (constraint_index != c->mConstraintIndex)
260
{
261
JPH_ASSERT(false, "Unexpected constraint index");
262
return false;
263
}
264
c->RestoreState(inStream);
265
}
266
}
267
else
268
{
269
// Not validating, use more flexible reading, read number of constraints
270
uint32 num_constraints = 0;
271
inStream.Read(num_constraints);
272
273
for (uint32 idx = 0; idx < num_constraints; ++idx)
274
{
275
uint32 constraint_index;
276
inStream.Read(constraint_index);
277
if (mConstraints.size() <= constraint_index)
278
{
279
JPH_ASSERT(false, "Restoring state for non-existing constraint");
280
return false;
281
}
282
mConstraints[constraint_index]->RestoreState(inStream);
283
}
284
}
285
286
return true;
287
}
288
289
JPH_NAMESPACE_END
290
291