123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804 |
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #include <Jolt.h>
- #include <Physics/PhysicsSettings.h>
- #include <Physics/Body/BodyManager.h>
- #include <Physics/Body/BodyCreationSettings.h>
- #include <Physics/Body/BodyLock.h>
- #include <Physics/Body/BodyActivationListener.h>
- #include <Physics/StateRecorder.h>
- #include <Core/StringTools.h>
- #include <Core/StatCollector.h>
- #ifdef JPH_DEBUG_RENDERER
- #include <Renderer/DebugRenderer.h>
- #endif // JPH_DEBUG_RENDERER
- namespace JPH {
- #ifdef JPH_ENABLE_ASSERTS
- thread_local bool BodyManager::sOverrideAllowActivation = false;
- thread_local bool BodyManager::sOverrideAllowDeactivation = false;
- #endif
- BodyManager::~BodyManager()
- {
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- // Destroy any bodies that are still alive
- for (Body *b : mBodies)
- if (sIsValidBodyPointer(b))
- delete b;
- delete [] mActiveBodies;
- }
- void BodyManager::Init(uint inMaxBodies)
- {
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- // Allocate space for bodies
- mBodies.reserve(inMaxBodies);
- // Allocate space for active bodies
- JPH_ASSERT(mActiveBodies == nullptr);
- mActiveBodies = new BodyID [inMaxBodies];
- // Allocate space for sequence numbers
- mBodySequenceNumbers.resize(inMaxBodies);
- }
- uint BodyManager::GetNumBodies() const
- {
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- return mNumBodies;
- }
- BodyManager::BodyStats BodyManager::GetBodyStats() const
- {
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- BodyStats stats;
- stats.mNumBodies = mNumBodies;
- stats.mMaxBodies = uint(mBodies.capacity());
- for (const Body *body : mBodies)
- if (sIsValidBodyPointer(body))
- {
- switch (body->GetMotionType())
- {
- case EMotionType::Static:
- stats.mNumBodiesStatic++;
- break;
- case EMotionType::Dynamic:
- stats.mNumBodiesDynamic++;
- if (body->IsActive())
- stats.mNumActiveBodiesDynamic++;
- break;
- case EMotionType::Kinematic:
- stats.mNumBodiesKinematic++;
- if (body->IsActive())
- stats.mNumActiveBodiesKinematic++;
- break;
- }
- }
- return stats;
- }
- Body *BodyManager::CreateBody(const BodyCreationSettings &inBodyCreationSettings)
- {
- // Determine next free index
- uint32 idx;
- {
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- if (mBodyIDFreeListStart != cBodyIDFreeListEnd)
- {
- // Pop an item from the freelist
- JPH_ASSERT(mBodyIDFreeListStart & cIsFreedBody);
- idx = uint32(mBodyIDFreeListStart >> cFreedBodyIndexShift);
- JPH_ASSERT(!sIsValidBodyPointer(mBodies[idx]));
- mBodyIDFreeListStart = uintptr_t(mBodies[idx]);
- }
- else
- {
- if (mBodies.size() < mBodies.capacity())
- {
- // Allocate a new entry, note that the array should not actually resize since we've reserved it at init time
- idx = uint32(mBodies.size());
- mBodies.push_back((Body *)cBodyIDFreeListEnd);
- }
- else
- {
- // Out of bodies
- return nullptr;
- }
- }
- // Update cached number of bodies
- mNumBodies++;
- }
- // Get next sequence number
- uint8 seq_no = GetNextSequenceNumber(idx);
- // Fill in basic properties
- Body *body = new Body();
- body->mID = BodyID(idx, seq_no);
- body->mShape = inBodyCreationSettings.GetShape();
- body->SetFriction(inBodyCreationSettings.mFriction);
- body->SetRestitution(inBodyCreationSettings.mRestitution);
- body->mMotionType = inBodyCreationSettings.mMotionType;
- if (inBodyCreationSettings.mIsSensor)
- body->mFlags |= uint8(Body::EFlags::IsSensor);
- body->mObjectLayer = inBodyCreationSettings.mObjectLayer;
- body->mCollisionGroup = inBodyCreationSettings.mCollisionGroup;
-
- if (inBodyCreationSettings.HasMassProperties())
- {
- MotionProperties *mp = new MotionProperties();
- mp->SetLinearDamping(inBodyCreationSettings.mLinearDamping);
- mp->SetAngularDamping(inBodyCreationSettings.mAngularDamping);
- mp->SetMaxLinearVelocity(inBodyCreationSettings.mMaxLinearVelocity);
- mp->SetMaxAngularVelocity(inBodyCreationSettings.mMaxAngularVelocity);
- mp->SetGravityFactor(inBodyCreationSettings.mGravityFactor);
- mp->SetMotionQuality(inBodyCreationSettings.mMotionQuality);
- mp->mAllowSleeping = inBodyCreationSettings.mAllowSleeping;
- mp->mIndexInActiveBodies = Body::cInactiveIndex;
- mp->mIslandIndex = Body::cInactiveIndex;
- JPH_IF_ENABLE_ASSERTS(mp->mCachedMotionType = body->mMotionType;)
- mp->SetMassProperties(inBodyCreationSettings.GetMassProperties());
- body->mMotionProperties = mp;
- }
- // Position body
- body->SetPositionAndRotationInternal(inBodyCreationSettings.mPosition, inBodyCreationSettings.mRotation);
- // Add body
- mBodies[idx] = body;
- return body;
- }
- void BodyManager::DestroyBodies(const BodyID *inBodyIDs, int inNumber)
- {
- // Don't take lock if no bodies are to be destroyed
- if (inNumber <= 0)
- return;
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- // Update cached number of bodies
- JPH_ASSERT(mNumBodies >= (uint)inNumber);
- mNumBodies -= inNumber;
- for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
- {
- // Get body
- BodyID body_id = *b;
- uint32 idx = body_id.GetIndex();
- Body *body = mBodies[idx];
- // Validate that it can be removed
- JPH_ASSERT(body->GetID() == body_id);
- JPH_ASSERT(!body->IsActive());
- JPH_ASSERT(!body->IsInBroadPhase());
-
- // Push the id onto the freelist
- mBodies[idx] = (Body *)mBodyIDFreeListStart;
- mBodyIDFreeListStart = (uintptr_t(idx) << cFreedBodyIndexShift) | cIsFreedBody;
- // Free the body
- delete body;
- }
- #if defined(_DEBUG) && defined(JPH_ENABLE_ASSERTS)
- // Check that the freelist is correct
- size_t num_freed = 0;
- for (uintptr_t start = mBodyIDFreeListStart; start != cBodyIDFreeListEnd; start = uintptr_t(mBodies[start >> cFreedBodyIndexShift]))
- {
- JPH_ASSERT(start & cIsFreedBody);
- num_freed++;
- }
- JPH_ASSERT(mNumBodies == mBodies.size() - num_freed);
- #endif // defined(_DEBUG) && _defined(JPH_ENABLE_ASSERTS)
- }
- void BodyManager::ActivateBodies(const BodyID *inBodyIDs, int inNumber)
- {
- // Don't take lock if no bodies are to be activated
- if (inNumber <= 0)
- return;
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- JPH_ASSERT(!mActiveBodiesLocked || sOverrideAllowActivation);
- for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
- {
- BodyID body_id = *b;
- Body &body = *mBodies[body_id.GetIndex()];
- JPH_ASSERT(GetMutexForBody(body_id).is_locked(), "Assuming that body has been locked!");
- JPH_ASSERT(body.GetID() == body_id);
- JPH_ASSERT(body.IsInBroadPhase());
- if (!body.IsStatic()
- && body.mMotionProperties->mIndexInActiveBodies == Body::cInactiveIndex)
- {
- body.mMotionProperties->mIndexInActiveBodies = mNumActiveBodies;
- body.ResetSleepTestSpheres();
- JPH_ASSERT(mNumActiveBodies < GetMaxBodies());
- mActiveBodies[mNumActiveBodies] = body_id;
- mNumActiveBodies++; // Increment atomic after setting the body ID so that PhysicsSystem::JobFindCollisions (which doesn't lock the mActiveBodiesMutex) will only read valid IDs
- // Count CCD bodies
- if (body.mMotionProperties->GetMotionQuality() == EMotionQuality::LinearCast)
- mNumActiveCCDBodies++;
- // Call activation listener
- if (mActivationListener != nullptr)
- mActivationListener->OnBodyActivated(body_id, body.GetUserData());
- }
- }
- }
- void BodyManager::DeactivateBodies(const BodyID *inBodyIDs, int inNumber)
- {
- // Don't take lock if no bodies are to be deactivated
- if (inNumber <= 0)
- return;
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- JPH_ASSERT(!mActiveBodiesLocked || sOverrideAllowDeactivation);
- for (const BodyID *b = inBodyIDs, *b_end = inBodyIDs + inNumber; b < b_end; b++)
- {
- BodyID body_id = *b;
- Body &body = *mBodies[body_id.GetIndex()];
- JPH_ASSERT(GetMutexForBody(body_id).is_locked(), "Assuming that body has been locked!");
- JPH_ASSERT(body.GetID() == body_id);
- JPH_ASSERT(body.IsInBroadPhase());
- if (body.mMotionProperties != nullptr
- && body.mMotionProperties->mIndexInActiveBodies != Body::cInactiveIndex)
- {
- uint32 last_body_index = mNumActiveBodies - 1;
- if (body.mMotionProperties->mIndexInActiveBodies != last_body_index)
- {
- // This is not the last body, use the last body to fill the hole
- BodyID last_body_id = mActiveBodies[last_body_index];
- mActiveBodies[body.mMotionProperties->mIndexInActiveBodies] = last_body_id;
- // Update that body's index in the active list
- Body &last_body = *mBodies[last_body_id.GetIndex()];
- JPH_ASSERT(last_body.mMotionProperties->mIndexInActiveBodies == last_body_index);
- last_body.mMotionProperties->mIndexInActiveBodies = body.mMotionProperties->mIndexInActiveBodies;
- }
- // Mark this body as no longer active
- body.mMotionProperties->mIndexInActiveBodies = Body::cInactiveIndex;
- body.mMotionProperties->mIslandIndex = Body::cInactiveIndex;
- // Reset velocity
- body.mMotionProperties->mLinearVelocity = Vec3::sZero();
- body.mMotionProperties->mAngularVelocity = Vec3::sZero();
- // Remove unused element from active bodies list
- --mNumActiveBodies;
- // Count CCD bodies
- if (body.mMotionProperties->GetMotionQuality() == EMotionQuality::LinearCast)
- mNumActiveCCDBodies--;
- // Call activation listener
- if (mActivationListener != nullptr)
- mActivationListener->OnBodyDeactivated(body_id, body.GetUserData());
- }
- }
- }
- void BodyManager::GetActiveBodies(BodyIDVector &outBodyIDs) const
- {
- JPH_PROFILE_FUNCTION();
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- outBodyIDs.assign(mActiveBodies, mActiveBodies + mNumActiveBodies);
- }
- void BodyManager::GetBodyIDs(BodyIDVector &outBodies) const
- {
- JPH_PROFILE_FUNCTION();
- UniqueLock lock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- // Reserve space for all bodies
- outBodies.clear();
- outBodies.reserve(mNumBodies);
- // Iterate the list and find the bodies that are not null
- for (const Body *b : mBodies)
- if (sIsValidBodyPointer(b))
- outBodies.push_back(b->GetID());
- // Validate that our reservation was correct
- JPH_ASSERT(outBodies.size() == mNumBodies);
- }
- void BodyManager::SetBodyActivationListener(BodyActivationListener *inListener)
- {
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- mActivationListener = inListener;
- }
- BodyManager::MutexMask BodyManager::GetMutexMask(const BodyID *inBodies, int inNumber) const
- {
- static_assert(sizeof(MutexMask) * 8 == BodyMutexes::NumMutexes, "MutexMask must have the same amount of bits");
- if (inNumber >= BodyMutexes::NumMutexes)
- {
- // Just lock everything if there are too many bodies
- return ~MutexMask(0);
- }
- else
- {
- MutexMask mask = 0;
- for (const BodyID *b = inBodies, *b_end = inBodies + inNumber; b < b_end; ++b)
- if (!b->IsInvalid())
- {
- uint32 index = mBodyMutexes.GetMutexIndex(b->GetIndex());
- mask |= (MutexMask(1) << index);
- }
- return mask;
- }
- }
- void BodyManager::LockRead(MutexMask inMutexMask) const
- {
- JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
- int index = 0;
- for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
- if (mask & 1)
- mBodyMutexes.GetMutexByIndex(index).lock_shared();
- }
- void BodyManager::UnlockRead(MutexMask inMutexMask) const
- {
- JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
- int index = 0;
- for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
- if (mask & 1)
- mBodyMutexes.GetMutexByIndex(index).unlock_shared();
- }
- void BodyManager::LockWrite(MutexMask inMutexMask) const
- {
- JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
- int index = 0;
- for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
- if (mask & 1)
- mBodyMutexes.GetMutexByIndex(index).lock();
- }
- void BodyManager::UnlockWrite(MutexMask inMutexMask) const
- {
- JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
- int index = 0;
- for (MutexMask mask = inMutexMask; mask != 0; mask >>= 1, index++)
- if (mask & 1)
- mBodyMutexes.GetMutexByIndex(index).unlock();
- }
- void BodyManager::LockAllBodies() const
- {
- JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckLock(EPhysicsLockTypes::PerBody));
- mBodyMutexes.LockAll();
- PhysicsLock::sLock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- }
- void BodyManager::UnlockAllBodies() const
- {
- PhysicsLock::sUnlock(mBodiesMutex, EPhysicsLockTypes::BodiesList);
- JPH_IF_ENABLE_ASSERTS(PhysicsLock::sCheckUnlock(EPhysicsLockTypes::PerBody));
- mBodyMutexes.UnlockAll();
- }
- void BodyManager::SaveState(StateRecorder &inStream) const
- {
- {
- LockAllBodies();
- // Count number of bodies
- size_t num_bodies = 0;
- for (const Body *b : mBodies)
- if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
- ++num_bodies;
- inStream.Write(num_bodies);
-
- // Write state of bodies
- for (const Body *b : mBodies)
- if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
- {
- inStream.Write(b->GetID());
- b->SaveState(inStream);
- }
- UnlockAllBodies();
- }
- {
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- // Write active bodies, sort because activation can come from multiple threads, so order is not deterministic
- inStream.Write(mNumActiveBodies);
- BodyIDVector sorted_active_bodies(mActiveBodies, mActiveBodies + mNumActiveBodies);
- sort(sorted_active_bodies.begin(), sorted_active_bodies.end());
- for (const BodyID &id : sorted_active_bodies)
- inStream.Write(id);
- inStream.Write(mNumActiveCCDBodies);
- }
- }
- bool BodyManager::RestoreState(StateRecorder &inStream)
- {
- {
- LockAllBodies();
- // Read state of bodies, note this reads it in a way to be consistent with validation
- size_t old_num_bodies = 0;
- for (const Body *b : mBodies)
- if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
- ++old_num_bodies;
- size_t num_bodies = old_num_bodies; // Initialize to current value for validation
- inStream.Read(num_bodies);
- if (num_bodies != old_num_bodies)
- {
- JPH_ASSERT(false, "Cannot handle adding/removing bodies");
- UnlockAllBodies();
- return false;
- }
- for (Body *b : mBodies)
- if (sIsValidBodyPointer(b) && b->IsInBroadPhase())
- {
- BodyID body_id = b->GetID(); // Initialize to current value for validation
- inStream.Read(body_id);
- if (body_id != b->GetID())
- {
- JPH_ASSERT(false, "Cannot handle adding/removing bodies");
- UnlockAllBodies();
- return false;
- }
- b->RestoreState(inStream);
- }
- UnlockAllBodies();
- }
- {
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- // Mark current active bodies as deactivated
- for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
- mBodies[id->GetIndex()]->mMotionProperties->mIndexInActiveBodies = Body::cInactiveIndex;
- sort(mActiveBodies, mActiveBodies + mNumActiveBodies); // Sort for validation
- // Read active bodies
- inStream.Read(mNumActiveBodies);
- for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
- {
- inStream.Read(*id);
- mBodies[id->GetIndex()]->mMotionProperties->mIndexInActiveBodies = uint32(id - mActiveBodies);
- }
- inStream.Read(mNumActiveCCDBodies);
- }
- return true;
- }
- #ifdef JPH_DEBUG_RENDERER
- void BodyManager::Draw(const DrawSettings &inDrawSettings, const PhysicsSettings &inPhysicsSettings, DebugRenderer *inRenderer)
- {
- JPH_PROFILE_FUNCTION();
- LockAllBodies();
- for (const Body *body : mBodies)
- if (sIsValidBodyPointer(body) && body->IsInBroadPhase())
- {
- JPH_ASSERT(mBodies[body->GetID().GetIndex()] == body);
- bool is_sensor = body->IsSensor();
- // Determine drawing mode
- Color color;
- if (is_sensor)
- color = Color::sYellow;
- else
- switch (inDrawSettings.mDrawShapeColor)
- {
- case EShapeColor::InstanceColor:
- // Each instance has own color
- color = Color::sGetDistinctColor(body->mID.GetIndex());
- break;
- case EShapeColor::ShapeTypeColor:
- // Each shape type has own color
- switch (body->GetShape()->GetType())
- {
- case EShapeType::Convex:
- color = Color::sGreen;
- break;
- case EShapeType::Scaled:
- color = Color::sYellow;
- break;
- case EShapeType::StaticCompound:
- color = Color::sOrange;
- break;
- case EShapeType::MutableCompound:
- color = Color::sDarkOrange;
- break;
- case EShapeType::Mesh:
- color = Color::sRed;
- break;
- case EShapeType::HeightField:
- color = Color::sPurple;
- break;
- case EShapeType::RotatedTranslated:
- color = Color::sBlue;
- break;
- case EShapeType::OffsetCenterOfMass:
- color = Color::sCyan;
- break;
- default:
- JPH_ASSERT(false);
- color = Color::sBlack;
- break;
- }
- break;
- case EShapeColor::MotionTypeColor:
- // Determine color based on motion type
- switch (body->mMotionType)
- {
- case EMotionType::Static:
- color = Color::sGrey;
- break;
- case EMotionType::Kinematic:
- color = Color::sGreen;
- break;
- case EMotionType::Dynamic:
- color = Color::sGetDistinctColor(body->mID.GetIndex());
- break;
- default:
- JPH_ASSERT(false);
- color = Color::sBlack;
- break;
- }
- break;
- case EShapeColor::SleepColor:
- // Determine color based on motion type
- switch (body->mMotionType)
- {
- case EMotionType::Static:
- color = Color::sGrey;
- break;
- case EMotionType::Kinematic:
- color = body->IsActive()? Color::sGreen : Color::sRed;
- break;
- case EMotionType::Dynamic:
- color = body->IsActive()? Color::sYellow : Color::sRed;
- break;
- default:
- JPH_ASSERT(false);
- color = Color::sBlack;
- break;
- }
- break;
- case EShapeColor::IslandColor:
- // Determine color based on motion type
- switch (body->mMotionType)
- {
- case EMotionType::Static:
- color = Color::sGrey;
- break;
- case EMotionType::Kinematic:
- case EMotionType::Dynamic:
- {
- uint32 idx = body->GetMotionProperties()->GetIslandIndexInternal();
- color = idx != Body::cInactiveIndex? Color::sGetDistinctColor(idx) : Color::sLightGrey;
- }
- break;
- default:
- JPH_ASSERT(false);
- color = Color::sBlack;
- break;
- }
- break;
- case EShapeColor::MaterialColor:
- color = Color::sWhite;
- break;
- default:
- JPH_ASSERT(false);
- color = Color::sBlack;
- break;
- }
-
- // Draw the results of GetSupportFunction
- if (inDrawSettings.mDrawGetSupportFunction)
- body->mShape->DrawGetSupportFunction(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), color, inDrawSettings.mDrawSupportDirection);
- // Draw the results of GetSupportingFace
- if (inDrawSettings.mDrawGetSupportingFace)
- body->mShape->DrawGetSupportingFace(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
- // Draw the shape
- if (inDrawSettings.mDrawShape)
- body->mShape->Draw(inRenderer, body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), color, inDrawSettings.mDrawShapeColor == EShapeColor::MaterialColor, inDrawSettings.mDrawShapeWireframe || is_sensor);
- // Draw bounding box
- if (inDrawSettings.mDrawBoundingBox)
- inRenderer->DrawWireBox(body->mBounds, color);
- // Draw center of mass transform
- if (inDrawSettings.mDrawCenterOfMassTransform)
- inRenderer->DrawCoordinateSystem(body->GetCenterOfMassTransform(), 0.2f);
- // Draw world transform
- if (inDrawSettings.mDrawWorldTransform)
- inRenderer->DrawCoordinateSystem(body->GetWorldTransform(), 0.2f);
- // Draw world space linear and angular velocity
- if (inDrawSettings.mDrawVelocity)
- {
- Vec3 pos = body->GetCenterOfMassPosition();
- inRenderer->DrawArrow(pos, pos + body->GetLinearVelocity(), Color::sGreen, 0.1f);
- inRenderer->DrawArrow(pos, pos + body->GetAngularVelocity(), Color::sRed, 0.1f);
- }
- if (inDrawSettings.mDrawMassAndInertia && body->IsDynamic())
- {
- const MotionProperties *mp = body->GetMotionProperties();
- // Invert mass again
- float mass = 1.0f / mp->GetInverseMass();
- // Invert diagonal again
- Vec3 diagonal = mp->GetInverseInertiaDiagonal().Reciprocal();
- // Determine how big of a box has the equivalent inertia
- Vec3 box_size = MassProperties::sGetEquivalentSolidBoxSize(mass, diagonal);
- // Draw box with equivalent inertia
- inRenderer->DrawWireBox(body->GetCenterOfMassTransform() * Mat44::sRotation(mp->GetInertiaRotation()), AABox(-0.5f * box_size, 0.5f * box_size), Color::sOrange);
- // Draw mass
- inRenderer->DrawText3D(body->GetCenterOfMassPosition(), StringFormat("%.2f", (double)mass), Color::sOrange, 0.2f);
- }
- if (inDrawSettings.mDrawSleepStats && body->IsDynamic() && body->IsActive())
- {
- // Draw stats to know which bodies could go to sleep
- string text = StringFormat("t: %.1f", (double)body->mMotionProperties->mSleepTestTimer);
- uint8 g = uint8(Clamp(255.0f * body->mMotionProperties->mSleepTestTimer / inPhysicsSettings.mTimeBeforeSleep, 0.0f, 255.0f));
- Color sleep_color = Color(0, 255 - g, g);
- inRenderer->DrawText3D(body->GetCenterOfMassPosition(), text, sleep_color, 0.2f);
- for (int i = 0; i < 3; ++i)
- inRenderer->DrawWireSphere(body->mMotionProperties->mSleepTestSpheres[i].GetCenter(), body->mMotionProperties->mSleepTestSpheres[i].GetRadius(), sleep_color);
- }
- if (inDrawSettings.mDrawNames)
- inRenderer->DrawText3D(body->GetCenterOfMassPosition(), body->GetDebugName(), Color::sCyan, 0.2f);
- }
- UnlockAllBodies();
- }
- #endif // JPH_DEBUG_RENDERER
- void BodyManager::InvalidateContactCacheForBody(Body &ioBody)
- {
- lock_guard lock(mBodiesCacheInvalidMutex);
-
- if (!ioBody.IsCollisionCacheInvalid())
- {
- mBodiesCacheInvalid.push_back(ioBody.GetID());
- ioBody.InvalidateCollisionCacheInternal(true);
- }
- }
- void BodyManager::ValidateContactCacheForAllBodies()
- {
- lock_guard lock(mBodiesCacheInvalidMutex);
-
- for (const BodyID &b : mBodiesCacheInvalid)
- {
- // The body may have been removed between the call to InvalidateContactCacheForBody and this call, so check if it still exists
- Body *body = TryGetBody(b);
- if (body != nullptr)
- body->InvalidateCollisionCacheInternal(false);
- }
- mBodiesCacheInvalid.clear();
- }
- #ifdef JPH_STAT_COLLECTOR
- void BodyManager::CollectStats() const
- {
- JPH_PROFILE_FUNCTION();
- BodyLockInterfaceLocking lock_interface(const_cast<BodyManager &>(*this));
- BodyIDVector active_body_ids;
- GetActiveBodies(active_body_ids);
- for (const BodyID &id : active_body_ids)
- {
- BodyLockRead body_lock(lock_interface, id);
- if (body_lock.SucceededAndIsInBroadPhase())
- {
- const Body &body = body_lock.GetBody();
- string prefix = "Body." + body.GetDebugName();
- JPH_STAT_COLLECTOR_ADD(prefix + ".Position", body.GetPosition());
- JPH_STAT_COLLECTOR_ADD(prefix + ".Rotation", body.GetRotation());
- JPH_STAT_COLLECTOR_ADD(prefix + ".LinearVelocity", body.GetLinearVelocity());
- JPH_STAT_COLLECTOR_ADD(prefix + ".LinearVelocity.Length", body.GetLinearVelocity().Length());
- JPH_STAT_COLLECTOR_ADD(prefix + ".AngularVelocity", body.GetAngularVelocity());
- JPH_STAT_COLLECTOR_ADD(prefix + ".AngularVelocity.Length", body.GetAngularVelocity().Length());
- }
- }
- }
- #endif // JPH_STAT_COLLECTOR
- #ifdef _DEBUG
- void BodyManager::ValidateActiveBodyBounds()
- {
- UniqueLock lock(mActiveBodiesMutex, EPhysicsLockTypes::ActiveBodiesList);
- for (BodyID *id = mActiveBodies, *id_end = mActiveBodies + mNumActiveBodies; id < id_end; ++id)
- {
- const Body *body = mBodies[id->GetIndex()];
- AABox cached = body->GetWorldSpaceBounds();
- AABox calculated = body->GetShape()->GetWorldSpaceBounds(body->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f));
- JPH_ASSERT(cached == calculated);
- }
- }
- #endif // _DEBUG
- } // JPH
|