Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Constraints/ConstraintManager.cpp
9912 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#include <Jolt/Jolt.h>56#include <Jolt/Physics/Constraints/ConstraintManager.h>7#include <Jolt/Physics/Constraints/CalculateSolverSteps.h>8#include <Jolt/Physics/IslandBuilder.h>9#include <Jolt/Physics/StateRecorder.h>10#include <Jolt/Physics/PhysicsLock.h>11#include <Jolt/Core/Profiler.h>12#include <Jolt/Core/QuickSort.h>1314JPH_NAMESPACE_BEGIN1516void ConstraintManager::Add(Constraint **inConstraints, int inNumber)17{18UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));1920mConstraints.reserve(mConstraints.size() + inNumber);2122for (Constraint **c = inConstraints, **c_end = inConstraints + inNumber; c < c_end; ++c)23{24Constraint *constraint = *c;2526// Assume this constraint has not been added yet27JPH_ASSERT(constraint->mConstraintIndex == Constraint::cInvalidConstraintIndex);2829// Add to the list30constraint->mConstraintIndex = uint32(mConstraints.size());31mConstraints.push_back(constraint);32}33}3435void ConstraintManager::Remove(Constraint **inConstraints, int inNumber)36{37UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));3839for (Constraint **c = inConstraints, **c_end = inConstraints + inNumber; c < c_end; ++c)40{41Constraint *constraint = *c;4243// Reset constraint index for this constraint44uint32 this_constraint_idx = constraint->mConstraintIndex;45constraint->mConstraintIndex = Constraint::cInvalidConstraintIndex;46JPH_ASSERT(this_constraint_idx != Constraint::cInvalidConstraintIndex);4748// Check if this constraint is somewhere in the middle of the constraints, in this case we need to move the last constraint to this position49uint32 last_constraint_idx = uint32(mConstraints.size() - 1);50if (this_constraint_idx < last_constraint_idx)51{52Constraint *last_constraint = mConstraints[last_constraint_idx];53last_constraint->mConstraintIndex = this_constraint_idx;54mConstraints[this_constraint_idx] = last_constraint;55}5657// Pop last constraint58mConstraints.pop_back();59}60}6162Constraints ConstraintManager::GetConstraints() const63{64UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));6566Constraints copy = mConstraints;67return copy;68}6970void ConstraintManager::GetActiveConstraints(uint32 inStartConstraintIdx, uint32 inEndConstraintIdx, Constraint **outActiveConstraints, uint32 &outNumActiveConstraints) const71{72JPH_PROFILE_FUNCTION();7374JPH_ASSERT(inEndConstraintIdx <= mConstraints.size());7576uint32 num_active_constraints = 0;77for (uint32 constraint_idx = inStartConstraintIdx; constraint_idx < inEndConstraintIdx; ++constraint_idx)78{79Constraint *c = mConstraints[constraint_idx];80JPH_ASSERT(c->mConstraintIndex == constraint_idx);81if (c->IsActive())82{83*(outActiveConstraints++) = c;84num_active_constraints++;85}86}8788outNumActiveConstraints = num_active_constraints;89}9091void ConstraintManager::sBuildIslands(Constraint **inActiveConstraints, uint32 inNumActiveConstraints, IslandBuilder &ioBuilder, BodyManager &inBodyManager)92{93JPH_PROFILE_FUNCTION();9495for (uint32 constraint_idx = 0; constraint_idx < inNumActiveConstraints; ++constraint_idx)96{97Constraint *c = inActiveConstraints[constraint_idx];98c->BuildIslands(constraint_idx, ioBuilder, inBodyManager);99}100}101102void ConstraintManager::sSortConstraints(Constraint **inActiveConstraints, uint32 *inConstraintIdxBegin, uint32 *inConstraintIdxEnd)103{104JPH_PROFILE_FUNCTION();105106QuickSort(inConstraintIdxBegin, inConstraintIdxEnd, [inActiveConstraints](uint32 inLHS, uint32 inRHS) {107const Constraint *lhs = inActiveConstraints[inLHS];108const Constraint *rhs = inActiveConstraints[inRHS];109110if (lhs->GetConstraintPriority() != rhs->GetConstraintPriority())111return lhs->GetConstraintPriority() < rhs->GetConstraintPriority();112113return lhs->mConstraintIndex < rhs->mConstraintIndex;114});115}116117void ConstraintManager::sSetupVelocityConstraints(Constraint **inActiveConstraints, uint32 inNumActiveConstraints, float inDeltaTime)118{119JPH_PROFILE_FUNCTION();120121for (Constraint **c = inActiveConstraints, **c_end = inActiveConstraints + inNumActiveConstraints; c < c_end; ++c)122(*c)->SetupVelocityConstraint(inDeltaTime);123}124125template <class ConstraintCallback>126void ConstraintManager::sWarmStartVelocityConstraints(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, ConstraintCallback &ioCallback)127{128JPH_PROFILE_FUNCTION();129130for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)131{132Constraint *c = inActiveConstraints[*constraint_idx];133ioCallback(c);134c->WarmStartVelocityConstraint(inWarmStartImpulseRatio);135}136}137138// Specialize for the two constraint callback types139template void ConstraintManager::sWarmStartVelocityConstraints<CalculateSolverSteps>(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, CalculateSolverSteps &ioCallback);140template void ConstraintManager::sWarmStartVelocityConstraints<DummyCalculateSolverSteps>(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inWarmStartImpulseRatio, DummyCalculateSolverSteps &ioCallback);141142bool ConstraintManager::sSolveVelocityConstraints(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime)143{144JPH_PROFILE_FUNCTION();145146bool any_impulse_applied = false;147148for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)149{150Constraint *c = inActiveConstraints[*constraint_idx];151any_impulse_applied |= c->SolveVelocityConstraint(inDeltaTime);152}153154return any_impulse_applied;155}156157bool ConstraintManager::sSolvePositionConstraints(Constraint **inActiveConstraints, const uint32 *inConstraintIdxBegin, const uint32 *inConstraintIdxEnd, float inDeltaTime, float inBaumgarte)158{159JPH_PROFILE_FUNCTION();160161bool any_impulse_applied = false;162163for (const uint32 *constraint_idx = inConstraintIdxBegin; constraint_idx < inConstraintIdxEnd; ++constraint_idx)164{165Constraint *c = inActiveConstraints[*constraint_idx];166any_impulse_applied |= c->SolvePositionConstraint(inDeltaTime, inBaumgarte);167}168169return any_impulse_applied;170}171172#ifdef JPH_DEBUG_RENDERER173void ConstraintManager::DrawConstraints(DebugRenderer *inRenderer) const174{175JPH_PROFILE_FUNCTION();176177UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));178179for (const Ref<Constraint> &c : mConstraints)180c->DrawConstraint(inRenderer);181}182183void ConstraintManager::DrawConstraintLimits(DebugRenderer *inRenderer) const184{185JPH_PROFILE_FUNCTION();186187UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));188189for (const Ref<Constraint> &c : mConstraints)190c->DrawConstraintLimits(inRenderer);191}192193void ConstraintManager::DrawConstraintReferenceFrame(DebugRenderer *inRenderer) const194{195JPH_PROFILE_FUNCTION();196197UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));198199for (const Ref<Constraint> &c : mConstraints)200c->DrawConstraintReferenceFrame(inRenderer);201}202#endif // JPH_DEBUG_RENDERER203204void ConstraintManager::SaveState(StateRecorder &inStream, const StateRecorderFilter *inFilter) const205{206UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));207208// Write state of constraints209if (inFilter != nullptr)210{211// Determine which constraints to save212Array<Constraint *> constraints;213constraints.reserve(mConstraints.size());214for (const Ref<Constraint> &c : mConstraints)215if (inFilter->ShouldSaveConstraint(*c))216constraints.push_back(c);217218// Save them219uint32 num_constraints = (uint32)constraints.size();220inStream.Write(num_constraints);221for (const Constraint *c : constraints)222{223inStream.Write(c->mConstraintIndex);224c->SaveState(inStream);225}226}227else228{229// Save all constraints230uint32 num_constraints = (uint32)mConstraints.size();231inStream.Write(num_constraints);232for (const Ref<Constraint> &c : mConstraints)233{234inStream.Write(c->mConstraintIndex);235c->SaveState(inStream);236}237}238}239240bool ConstraintManager::RestoreState(StateRecorder &inStream)241{242UniqueLock lock(mConstraintsMutex JPH_IF_ENABLE_ASSERTS(, mLockContext, EPhysicsLockTypes::ConstraintsList));243244if (inStream.IsValidating())245{246// Read state of constraints247uint32 num_constraints = (uint32)mConstraints.size(); // Initialize to current value for validation248inStream.Read(num_constraints);249if (num_constraints != mConstraints.size())250{251JPH_ASSERT(false, "Cannot handle adding/removing constraints");252return false;253}254for (const Ref<Constraint> &c : mConstraints)255{256uint32 constraint_index = c->mConstraintIndex;257inStream.Read(constraint_index);258if (constraint_index != c->mConstraintIndex)259{260JPH_ASSERT(false, "Unexpected constraint index");261return false;262}263c->RestoreState(inStream);264}265}266else267{268// Not validating, use more flexible reading, read number of constraints269uint32 num_constraints = 0;270inStream.Read(num_constraints);271272for (uint32 idx = 0; idx < num_constraints; ++idx)273{274uint32 constraint_index;275inStream.Read(constraint_index);276if (mConstraints.size() <= constraint_index)277{278JPH_ASSERT(false, "Restoring state for non-existing constraint");279return false;280}281mConstraints[constraint_index]->RestoreState(inStream);282}283}284285return true;286}287288JPH_NAMESPACE_END289290291