mirror of https://github.com/zeldaret/botw.git
612 lines
20 KiB
C++
612 lines
20 KiB
C++
#include "KingSystem/Physics/Ragdoll/physRagdollController.h"
|
|
#include <Havok/Animation/Animation/Mapper/hkaSkeletonMapper.h>
|
|
#include <Havok/Animation/Animation/Rig/hkaPose.h>
|
|
#include <Havok/Animation/Physics2012Bridge/Instance/hkaRagdollInstance.h>
|
|
#include <Havok/Common/Serialize/Util/hkNativePackfileUtils.h>
|
|
#include <Havok/Common/Serialize/Util/hkRootLevelContainer.h>
|
|
#include <Havok/Physics2012/Dynamics/Constraint/hkpConstraintInstance.h>
|
|
#include <Havok/Physics2012/Dynamics/Entity/hkpRigidBody.h>
|
|
#include <Havok/Physics2012/Dynamics/World/hkpPhysicsSystem.h>
|
|
#include <Havok/Physics2012/Dynamics/World/hkpWorld.h>
|
|
#include <Havok/Physics2012/Utilities/Dynamics/ScaleSystem/hkpSystemScalingUtility.h>
|
|
#include <math/seadMathCalcCommon.h>
|
|
#include <resource/seadResource.h>
|
|
#include "KingSystem/Physics/Ragdoll/physRagdollControllerMgr.h"
|
|
#include "KingSystem/Physics/Ragdoll/physRagdollRigidBody.h"
|
|
#include "KingSystem/Physics/Rig/physModelBoneAccessor.h"
|
|
#include "KingSystem/Physics/Rig/physSkeletonMapper.h"
|
|
#include "KingSystem/Physics/RigidBody/physRigidBody.h"
|
|
#include "KingSystem/Physics/System/physEntityGroupFilter.h"
|
|
#include "KingSystem/Physics/System/physGroupFilter.h"
|
|
#include "KingSystem/Physics/System/physSystem.h"
|
|
#include "KingSystem/Physics/physConversions.h"
|
|
#include "KingSystem/Utils/Debug.h"
|
|
#include "KingSystem/Utils/IteratorUtil.h"
|
|
#include "KingSystem/Utils/SafeDelete.h"
|
|
|
|
namespace ksys::phys {
|
|
|
|
static u8 sRagdollCtrlUnk1 = 15;
|
|
static RagdollController::Config sRagdollCtrlConfig;
|
|
|
|
RagdollController::RagdollController(SystemGroupHandler* handler)
|
|
: mGroupHandler(handler), _e8(sRagdollCtrlUnk1), _e9(sRagdollCtrlUnk1) {}
|
|
|
|
RagdollController::~RagdollController() {
|
|
finalize();
|
|
}
|
|
|
|
bool RagdollController::init(const RagdollParam* param, sead::DirectResource* res,
|
|
gsys::Model* model, sead::Heap* heap) {
|
|
return doInit(param, res, model, heap);
|
|
}
|
|
|
|
bool RagdollController::doInit(const RagdollParam* param, sead::DirectResource* res,
|
|
gsys::Model* model, sead::Heap* heap) {
|
|
if (!res)
|
|
return false;
|
|
|
|
// Copy the ragdoll data from the resource and load it in place.
|
|
mRagdollDataSize = res->getRawSize();
|
|
mRagdollData = new (heap, 0x10) u8[mRagdollDataSize];
|
|
std::memcpy(mRagdollData, res->getRawData(), mRagdollDataSize);
|
|
{
|
|
const char* error = nullptr;
|
|
mRootLevelContainer = static_cast<hkRootLevelContainer*>(hkNativePackfileUtils::loadInPlace(
|
|
mRagdollData, static_cast<int>(mRagdollDataSize), nullptr, &error));
|
|
|
|
if (!mRootLevelContainer) {
|
|
util::safeDeleteArray(mRagdollData);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
mRagdollInstance = mRootLevelContainer->findObject<hkaRagdollInstance>();
|
|
if (!mRagdollInstance)
|
|
return false;
|
|
|
|
const hkaSkeleton* skeleton = mRagdollInstance->getSkeleton();
|
|
const int num_bones = skeleton->m_bones.size();
|
|
|
|
// Initialise the skeleton mapper or model bone accessor.
|
|
if (mRootLevelContainer->findObject<hkaSkeletonMapper>()) {
|
|
mSkeletonMapper = new (heap) SkeletonMapper;
|
|
auto* skeleton_mapper = mRootLevelContainer->findObject<hkaSkeletonMapper>(nullptr);
|
|
auto* model_skeleton_mapper =
|
|
mRootLevelContainer->findObject<hkaSkeletonMapper>(skeleton_mapper);
|
|
|
|
if (!mSkeletonMapper ||
|
|
!mSkeletonMapper->init(skeleton_mapper, model_skeleton_mapper, model, heap)) {
|
|
return false;
|
|
}
|
|
} else {
|
|
mModelBoneAccessor = new (heap) ModelBoneAccessor;
|
|
if (!mModelBoneAccessor->init(skeleton, model, heap)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
mBoneRigidBodies.allocBufferAssert(num_bones, heap);
|
|
|
|
{
|
|
static constexpr size_t Alignment = 0x20;
|
|
_b0 = sead::Mathu::roundUpPow2(sizeof(hkQsTransformf) * num_bones, Alignment);
|
|
auto* buffer = new (heap, Alignment) u8[_b0];
|
|
if (num_bones > 0 && buffer != nullptr) {
|
|
_a0 = num_bones;
|
|
_a8 = buffer;
|
|
}
|
|
}
|
|
|
|
mBoneVectors.allocBufferAssert(num_bones, heap);
|
|
mBoneStuff.allocBufferAssert(num_bones, heap);
|
|
|
|
// Create a RagdollRigidBody for each bone.
|
|
for (int i = 0; i < num_bones; ++i) {
|
|
const int parent_bone_idx = getParentOfBone(i) >= 0 ? getParentOfBone(i) : 0;
|
|
|
|
EntityCollisionMask mask;
|
|
if (mGroupHandler)
|
|
mask.regular.group_handler_index.SetUnsafe(mGroupHandler->getIndex());
|
|
mask.raw = makeEntityCollisionMask(mContactLayer, mask.raw);
|
|
mask.raw = setEntityCollisionMaskGroundHit(GroundHit::HitAll, mask.raw);
|
|
setBitFields(&mask.raw, //
|
|
std::make_pair(mask.regular.ragdoll_bone_index, i),
|
|
std::make_pair(mask.regular.ragdoll_parent_bone_index, parent_bone_idx),
|
|
std::make_pair(mask.is_ragdoll, true));
|
|
|
|
hkpRigidBody* const hkp_rigid_body = mRagdollInstance->getRigidBodyOfBone(i);
|
|
hkp_rigid_body->setCollisionFilterInfo(mask.raw);
|
|
|
|
sead::SafeString bone_name = skeleton->m_bones[i].m_name.cString();
|
|
int separator_index = bone_name.rfindIndex(":");
|
|
if (separator_index >= 0 && separator_index < bone_name.calcLength() - 1)
|
|
bone_name = bone_name.cstr() + separator_index + 1;
|
|
|
|
mBoneRigidBodies[i] = new (heap) RagdollRigidBody(bone_name, this, i, hkp_rigid_body, heap);
|
|
if (!mBoneRigidBodies[i]->initMotionAccessorForDynamicMotion(heap))
|
|
return false;
|
|
}
|
|
|
|
// Initialise each RagdollRigidBody. This must be done in a separate pass after all
|
|
// bodies have been created because each bone will store references to its neighbours.
|
|
for (int i = 0; i < num_bones; ++i) {
|
|
mBoneRigidBodies[i]->init(heap);
|
|
}
|
|
|
|
mTransform = new (heap, alignof(hkQsTransformf))
|
|
hkQsTransformf[1]{hkQsTransformf::IdentityInitializer{}};
|
|
mRagdollParam = param;
|
|
|
|
util::PrintDebugFmt("%s %s", sead::SafeString::cEmptyString.cstr(),
|
|
sead::SafeString::cEmptyString.cstr());
|
|
|
|
for (int i = 0, n = mRagdollInstance->m_constraints.size(); i < n; ++i) {
|
|
mRagdollInstance->m_constraints[i]->setPriority(hkpConstraintInstance::PRIORITY_TOI);
|
|
}
|
|
|
|
mBoneStuff2.allocBufferAssert(num_bones, heap);
|
|
for (int i = 0; i < num_bones; ++i) {
|
|
// XXX: this is probably an inlined function?
|
|
mBoneStuff2[i] = 0;
|
|
mFlags.set(Flag::_80);
|
|
}
|
|
|
|
mModel = model;
|
|
|
|
registerSelf();
|
|
return true;
|
|
}
|
|
|
|
void RagdollController::registerSelf() {
|
|
const bool registered = System::instance()->getRagdollControllerMgr()->addController(this);
|
|
mFlags.change(Flag::IsRegistered, registered);
|
|
}
|
|
|
|
void RagdollController::unregisterSelf() {
|
|
if (mFlags.isOn(Flag::IsRegistered)) {
|
|
System::instance()->getRagdollControllerMgr()->removeController(this);
|
|
mFlags.reset(Flag::IsRegistered);
|
|
}
|
|
}
|
|
|
|
void RagdollController::finalize() {
|
|
for (auto body : util::indexIter(mBoneRigidBodies)) {
|
|
body.get()->setCollisionInfo(nullptr);
|
|
body.get()->setContactPointInfo(nullptr);
|
|
}
|
|
|
|
if (isAddedToWorld())
|
|
removeFromWorldImmediately();
|
|
|
|
if (mRagdollInstance != nullptr)
|
|
removeConstraints();
|
|
|
|
for (auto body : util::indexIter(mBoneRigidBodies))
|
|
delete body.get();
|
|
|
|
mBoneRigidBodies.freeBuffer();
|
|
|
|
if (mSkeletonMapper)
|
|
util::safeDelete(mSkeletonMapper);
|
|
|
|
if (mModelBoneAccessor)
|
|
util::safeDelete(mModelBoneAccessor);
|
|
|
|
if (mRagdollData) {
|
|
hkNativePackfileUtils::unloadInPlace(mRagdollData, static_cast<int>(mRagdollDataSize));
|
|
delete[] mRagdollData;
|
|
mRagdollData = nullptr;
|
|
mRootLevelContainer = nullptr;
|
|
mRagdollInstance = nullptr;
|
|
}
|
|
|
|
if (mTransform)
|
|
util::safeDeleteArray(mTransform);
|
|
|
|
mBoneVectors.freeBuffer();
|
|
mBoneStuff.freeBuffer();
|
|
mBoneStuff2.freeBuffer();
|
|
|
|
if (_b0) {
|
|
delete[] _a8;
|
|
_b0 = 0;
|
|
}
|
|
}
|
|
|
|
void RagdollController::removeConstraints() {
|
|
for (int i = 0, n = mRagdollInstance->m_constraints.getSize(); i < n; ++i) {
|
|
auto* constraint = mRagdollInstance->m_constraints[i];
|
|
if (constraint->getOwner() != nullptr) {
|
|
auto* world = System::instance()->getHavokWorld(ContactLayerType::Entity);
|
|
world->removeConstraint(constraint);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool RagdollController::isAddedToWorld() const {
|
|
return mBoneRigidBodies.size() > 0 && mBoneRigidBodies.back()->isAddedToWorld();
|
|
}
|
|
|
|
void RagdollController::removeFromWorldImmediately() {
|
|
ScopedPhysicsLock lock{this};
|
|
|
|
removeConstraints();
|
|
for (auto body : util::indexIter(mBoneRigidBodies))
|
|
body.get()->removeFromWorldImmediately();
|
|
}
|
|
|
|
void RagdollController::removeFromWorld() {
|
|
for (auto body : util::indexIter(mBoneRigidBodies))
|
|
body.get()->removeFromWorld();
|
|
}
|
|
|
|
bool RagdollController::removeFromWorldAndResetLinks() {
|
|
bool removed = true;
|
|
for (auto body : util::indexIter(mBoneRigidBodies))
|
|
removed &= body.get()->removeFromWorldAndResetLinks();
|
|
|
|
unregisterSelf();
|
|
|
|
return removed;
|
|
}
|
|
|
|
bool RagdollController::isAddingToWorld() const {
|
|
return mBoneRigidBodies.size() > 0 && mBoneRigidBodies.back()->isAddingBodyToWorld();
|
|
}
|
|
|
|
void RagdollController::setTransform(const sead::Matrix34f& transform) {
|
|
hkQsTransformf hk_transform;
|
|
toHkQsTransform(&hk_transform, transform, sead::Vector3f::ones);
|
|
setTransform(hk_transform);
|
|
}
|
|
|
|
void RagdollController::setTransform(const hkQsTransformf& transform) {
|
|
ScopedPhysicsLock lock{this};
|
|
|
|
if (mSkeletonMapper)
|
|
mSkeletonMapper->mapPoseA();
|
|
|
|
mRagdollInstance->setPoseModelSpace(
|
|
getBoneAccessor()->getPose()->getSyncedPoseModelSpace().data(), transform);
|
|
|
|
if (mExtraRigidBody) {
|
|
sead::Matrix34f old_transform;
|
|
mBoneRigidBodies[mBoneIndexForExtraRigidBody]->getTransform(&old_transform);
|
|
mExtraRigidBody->setTransform(old_transform);
|
|
|
|
if (mGroupHandler) {
|
|
mExtraRigidBody->setCollisionFilterInfo(
|
|
mGroupHandler->makeRagdollCollisionFilterInfo(GroundHit::HitAll));
|
|
}
|
|
}
|
|
}
|
|
|
|
void RagdollController::setScale(float scale) {
|
|
if (sead::Mathf::equalsEpsilon(scale, 1.0))
|
|
return;
|
|
|
|
{
|
|
ScopedPhysicsLock lock{this};
|
|
|
|
const hkVector4 translation =
|
|
mRagdollInstance->getRigidBodyOfBone(0)->getTransform().getTranslation();
|
|
|
|
// Construct a system with all the rigid bodies and constraints, then scale it.
|
|
hkpPhysicsSystem system;
|
|
|
|
const int num_bodies = mRagdollInstance->getRigidBodyArray().size();
|
|
for (int i = 0; i < num_bodies; ++i) {
|
|
hkpRigidBody* body = mRagdollInstance->getRigidBodyArray()[i];
|
|
|
|
// Fix the positions to be in model space.
|
|
hkVector4f pos;
|
|
pos.setSub(body->getTransform().getTranslation(), translation);
|
|
body->setPosition(pos);
|
|
|
|
system.addRigidBody(body);
|
|
}
|
|
|
|
for (int i = 0, n = mRagdollInstance->getConstraintArray().size(); i < n; ++i) {
|
|
system.addConstraint(mRagdollInstance->getConstraintArray()[i]);
|
|
}
|
|
|
|
hkpSystemScalingUtility::scaleSystem(&system, scale);
|
|
|
|
for (int i = 0; i < num_bodies; ++i) {
|
|
hkpRigidBody* body = mRagdollInstance->getRigidBodyArray()[i];
|
|
|
|
// Fix the positions to be in world space.
|
|
hkVector4f pos;
|
|
pos.setAdd(body->getTransform().getTranslation(), translation);
|
|
body->setPosition(pos);
|
|
|
|
mBoneRigidBodies[i]->updateShape();
|
|
}
|
|
}
|
|
|
|
if (mSkeletonMapper)
|
|
mSkeletonMapper->getBoneAccessor().setScale(scale);
|
|
}
|
|
|
|
void RagdollController::setFixedAndPreserveImpulse(Fixed fixed,
|
|
MarkLinearVelAsDirty mark_linear_vel_as_dirty) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setFixedAndPreserveImpulse(fixed, mark_linear_vel_as_dirty);
|
|
}
|
|
|
|
void RagdollController::resetFrozenState() {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->resetFrozenState();
|
|
}
|
|
|
|
void RagdollController::setUseSystemTimeFactor(bool use) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setUseSystemTimeFactor(use);
|
|
}
|
|
|
|
void RagdollController::clearFlag400000(bool clear) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->clearFlag400000(clear);
|
|
}
|
|
|
|
void RagdollController::setEntityMotionFlag200(bool set) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setEntityMotionFlag200(set);
|
|
}
|
|
|
|
void RagdollController::setFixed(Fixed fixed, PreserveVelocities preserve_velocities) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setFixed(fixed, preserve_velocities);
|
|
}
|
|
|
|
ModelBoneAccessor* RagdollController::getModelBoneAccessor() const {
|
|
if (mSkeletonMapper)
|
|
return &mSkeletonMapper->getModelBoneAccessor();
|
|
|
|
return mModelBoneAccessor;
|
|
}
|
|
|
|
void RagdollController::m3() {}
|
|
|
|
void RagdollController::setUserTag(UserTag* tag) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setUserTag(tag);
|
|
}
|
|
|
|
void RagdollController::setSystemGroupHandler(SystemGroupHandler* handler) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setSystemGroupHandler(handler);
|
|
|
|
mGroupHandler = handler;
|
|
}
|
|
|
|
void RagdollController::setContactPointInfo(ContactPointInfo* info) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setContactPointInfo(info);
|
|
}
|
|
|
|
void RagdollController::enableContactLayer(ContactLayer layer) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->enableContactLayer(layer, false);
|
|
}
|
|
|
|
void RagdollController::disableContactLayer(ContactLayer layer) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->disableContactLayer(layer, false);
|
|
}
|
|
|
|
void RagdollController::setContactAll() {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setContactAll(false);
|
|
}
|
|
|
|
void RagdollController::setContactNone() {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setContactNone(false);
|
|
}
|
|
|
|
void RagdollController::setContactAll(int bone_index) {
|
|
mBoneRigidBodies[bone_index]->setContactAll(false);
|
|
}
|
|
|
|
void RagdollController::setContactNone(int bone_index) {
|
|
mBoneRigidBodies[bone_index]->setContactNone(false);
|
|
}
|
|
|
|
void RagdollController::setExtraRigidBody(RigidBody* body, int bone_index) {
|
|
mExtraRigidBody = body;
|
|
mBoneIndexForExtraRigidBody = bone_index;
|
|
}
|
|
|
|
void RagdollController::setGravityFactor(float factor) {
|
|
for (auto* body : mBoneRigidBodies)
|
|
body->setGravityFactor(factor);
|
|
}
|
|
|
|
RagdollRigidBody* RagdollController::getBoneRigidBodyByName(const sead::SafeString& name) const {
|
|
const int index = getBoneIndexByName(name);
|
|
if (index < 0)
|
|
return nullptr;
|
|
|
|
return mBoneRigidBodies[index];
|
|
}
|
|
|
|
int RagdollController::getBoneIndexByModelKey(const gsys::BoneAccessKey& key) const {
|
|
const int model_bone_index = getModelBoneAccessor()->findBoneIndex(key);
|
|
|
|
const char* bone_name = getModelBoneAccessor()->getBoneName(model_bone_index);
|
|
if (bone_name == nullptr)
|
|
return -1;
|
|
|
|
return getBoneIndexByName(sead::FormatFixedSafeString<256>("Ragdoll_%s", bone_name));
|
|
}
|
|
|
|
int RagdollController::getBoneIndexByName(const sead::SafeString& name) const {
|
|
int index = 0;
|
|
for (auto* body : mBoneRigidBodies) {
|
|
if (name == body->getHkBodyName())
|
|
return index;
|
|
++index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int RagdollController::getParentOfBone(int index) const {
|
|
return mRagdollInstance->getParentOfBone(index);
|
|
}
|
|
|
|
RagdollRigidBody* RagdollController::getParentBoneRigidBody(const RigidBody* body) const {
|
|
return sead::DynamicCast<const RagdollRigidBody>(body)->getParentBody_();
|
|
}
|
|
|
|
int RagdollController::getNumChildBones(const RigidBody* body) const {
|
|
return sead::DynamicCast<const RagdollRigidBody>(body)->getChildBodies_().size();
|
|
}
|
|
|
|
RagdollRigidBody* RagdollController::getChildBoneRigidBody(const RigidBody* body, int index) const {
|
|
return sead::DynamicCast<const RagdollRigidBody>(body)->getChildBodies_()[index];
|
|
}
|
|
|
|
int RagdollController::getConstraintIndexByName(const sead::SafeString& name) const {
|
|
for (int i = 0, n = getNumConstraints(); i < n; ++i) {
|
|
if (name == mRagdollInstance->m_constraints[i]->getName())
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int RagdollController::getNumConstraints() const {
|
|
return mRagdollInstance->m_constraints.size();
|
|
}
|
|
|
|
void RagdollController::enableConstraint(int index, bool enable) {
|
|
mDisabledConstraints.changeBit(index, !enable);
|
|
}
|
|
|
|
bool RagdollController::isConstraintEnabled(int index) const {
|
|
return mDisabledConstraints.isOffBit(index);
|
|
}
|
|
|
|
void RagdollController::setContactLayer(ContactLayer layer) {
|
|
if (mContactLayer.value() == layer)
|
|
return;
|
|
|
|
if (mFlags.isOn(Flag::_10)) {
|
|
for (int bone = 0, num_bones = mBoneRigidBodies.size(); bone < num_bones; ++bone) {
|
|
if (mKeyframedBones.isOffBit(bone))
|
|
mBoneRigidBodies[bone]->setContactLayer(layer);
|
|
}
|
|
}
|
|
|
|
mContactLayer = layer;
|
|
}
|
|
|
|
void RagdollController::setKeyframed(int bone_index, bool keyframed,
|
|
SyncToThisBone sync_to_this_bone) {
|
|
mKeyframedBones.changeBit(bone_index, keyframed);
|
|
|
|
if (keyframed) {
|
|
mBoneRigidBodies[bone_index]->setContactLayer(ContactLayer::EntityNoHit);
|
|
mBoneRigidBodies[bone_index]->changeMotionType(MotionType::Keyframed);
|
|
} else {
|
|
mBoneRigidBodies[bone_index]->setContactLayer(mContactLayer);
|
|
mBoneRigidBodies[bone_index]->changeMotionType(MotionType::Dynamic);
|
|
}
|
|
|
|
mKeyframedBonesToSyncTo.changeBit(bone_index, keyframed && bool(sync_to_this_bone));
|
|
}
|
|
|
|
// NON_MATCHING: swapped csel operands
|
|
void RagdollController::setUnk1(u8 value) {
|
|
value = sead::Mathi::min(value, sRagdollCtrlUnk1);
|
|
_e9 = value;
|
|
_e8 = value;
|
|
}
|
|
|
|
void RagdollController::setMaximumUnk1(u8 value) {
|
|
sRagdollCtrlUnk1 = value;
|
|
}
|
|
|
|
void RagdollController::stopForcingKeyframing() {
|
|
if (mFlags.isOn(Flag::_10)) {
|
|
for (int i = 0, n = mBoneRigidBodies.size(); i < n; ++i) {
|
|
setKeyframed(i, false, {});
|
|
}
|
|
} else {
|
|
mKeyframedBones.makeAllZero();
|
|
mKeyframedBonesToSyncTo.makeAllZero();
|
|
}
|
|
}
|
|
|
|
void RagdollController::update() {
|
|
if (!isAddedToWorld()) {
|
|
for (int i = 0, n = getNumConstraints(); i < n; ++i) {
|
|
auto* constraint = mRagdollInstance->m_constraints[i];
|
|
if (constraint->getOwner() != nullptr) {
|
|
System::instance()
|
|
->getHavokWorld(ContactLayerType::Entity)
|
|
->removeConstraint(constraint);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (int i = 0, n = getNumConstraints(); i < n; ++i) {
|
|
auto* constraint = mRagdollInstance->m_constraints[i];
|
|
if (constraint->getOwner() == nullptr) {
|
|
System::instance()->getHavokWorld(ContactLayerType::Entity)->addConstraint(constraint);
|
|
}
|
|
|
|
const bool should_enable = mDisabledConstraints.isOffBit(i);
|
|
if (should_enable != constraint->isEnabled()) {
|
|
if (should_enable) {
|
|
constraint->setPriority(getConfig().priority);
|
|
constraint->enable();
|
|
} else {
|
|
constraint->setPriority(hkpConstraintInstance::PRIORITY_PSI);
|
|
constraint->disable();
|
|
}
|
|
}
|
|
}
|
|
|
|
updateGravityFactorOverride();
|
|
}
|
|
|
|
RagdollController::Config& RagdollController::getConfig() {
|
|
return sRagdollCtrlConfig;
|
|
}
|
|
|
|
void RagdollController::updateGravityFactorOverride() {
|
|
if (mFlags.isOff(Flag::_200))
|
|
return;
|
|
|
|
if (System::instance() == nullptr)
|
|
return;
|
|
|
|
const float factor_divisor = System::instance()->get6c();
|
|
for (int i = 0, n = mBoneRigidBodies.size(); i < n; ++i) {
|
|
mBoneRigidBodies[i]->setGravityFactor(mGravityFactorOverride / factor_divisor);
|
|
}
|
|
}
|
|
|
|
RagdollController::ScopedPhysicsLock::ScopedPhysicsLock(const RagdollController* ctrl)
|
|
: mCtrl{ctrl}, mWorldLock{ctrl->isAddedToWorld(), ContactLayerType::Entity} {
|
|
for (auto body : util::indexIter(ctrl->mBoneRigidBodies))
|
|
body.get()->lock(RigidBody::AlsoLockWorld::No);
|
|
}
|
|
|
|
RagdollController::ScopedPhysicsLock::~ScopedPhysicsLock() {
|
|
for (auto body : util::indexIter(mCtrl->mBoneRigidBodies))
|
|
body.get()->unlock(RigidBody::AlsoLockWorld::No);
|
|
}
|
|
|
|
BoneAccessor* RagdollController::getBoneAccessor() const {
|
|
if (mSkeletonMapper)
|
|
return &mSkeletonMapper->getBoneAccessor();
|
|
|
|
return mModelBoneAccessor;
|
|
}
|
|
|
|
} // namespace ksys::phys
|