ksys/phys: Add RigidBodyFromResource

This commit is contained in:
Léo Lam
2022-02-07 14:58:48 +01:00
parent a3e72dd6f8
commit 635be7c1e4
21 changed files with 271 additions and 29 deletions
+2
View File
@@ -23,6 +23,8 @@ target_sources(uking PRIVATE
RigidBody/physRigidBodyAccessor.h
RigidBody/physRigidBodyFactory.cpp
RigidBody/physRigidBodyFactory.h
RigidBody/physRigidBodyFromResource.cpp
RigidBody/physRigidBodyFromResource.h
RigidBody/physRigidBodyFromShape.cpp
RigidBody/physRigidBodyFromShape.h
RigidBody/physRigidBodyMotionEntity.cpp
@@ -65,7 +65,7 @@ const Shape* BoxRigidBody::getShape_() const {
return mShape;
}
u32 BoxRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks) {
u32 BoxRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) {
masks->ignored_layers = ~mContactMask.getDirect();
masks->collision_filter_info = getCollisionFilterInfo();
masks->material_mask = getMaterialMask().getRawData();
@@ -33,7 +33,7 @@ public:
protected:
Shape* getShape_() override;
const Shape* getShape_() const override;
u32 getCollisionMasks(CollisionMasks* masks) override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
BoxShape* mShape;
};
@@ -55,7 +55,7 @@ const Shape* BoxWaterRigidBody::getShape_() const {
return mShape;
}
u32 BoxWaterRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks) {
u32 BoxWaterRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) {
masks->ignored_layers = ~mContactMask.getDirect();
masks->collision_filter_info = getCollisionFilterInfo();
masks->material_mask = getMaterialMask().getRawData();
@@ -31,7 +31,7 @@ public:
protected:
Shape* getShape_() override;
const Shape* getShape_() const override;
u32 getCollisionMasks(CollisionMasks* masks) override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
BoxWaterShape* mShape;
u32 _d8{};
@@ -66,7 +66,7 @@ const Shape* CapsuleRigidBody::getShape_() const {
return mShape;
}
u32 CapsuleRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks) {
u32 CapsuleRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) {
masks->ignored_layers = ~mContactMask.getDirect();
masks->collision_filter_info = getCollisionFilterInfo();
masks->material_mask = getMaterialMask().getRawData();
@@ -31,7 +31,7 @@ public:
protected:
Shape* getShape_() override;
const Shape* getShape_() const override;
u32 getCollisionMasks(CollisionMasks* masks) override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
CapsuleShape* mShape{};
};
@@ -65,7 +65,7 @@ const Shape* CylinderRigidBody::getShape_() const {
return mShape;
}
u32 CylinderRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks) {
u32 CylinderRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) {
masks->ignored_layers = ~mContactMask.getDirect();
masks->collision_filter_info = getCollisionFilterInfo();
masks->material_mask = getMaterialMask().getRawData();
@@ -30,7 +30,7 @@ public:
protected:
Shape* getShape_() override;
const Shape* getShape_() const override;
u32 getCollisionMasks(CollisionMasks* masks) override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
private:
CylinderShape* mShape;
@@ -59,7 +59,7 @@ const Shape* CylinderWaterRigidBody::getShape_() const {
return mShape;
}
u32 CylinderWaterRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks) {
u32 CylinderWaterRigidBody::getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) {
masks->ignored_layers = ~mContactMask.getDirect();
masks->collision_filter_info = getCollisionFilterInfo();
masks->material_mask = getMaterialMask().getRawData();
@@ -30,7 +30,7 @@ public:
protected:
Shape* getShape_() override;
const Shape* getShape_() const override;
u32 getCollisionMasks(CollisionMasks* masks) override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
private:
CylinderWaterShape* mShape{};
@@ -9,7 +9,7 @@ class TeraMeshRigidBody : public RigidBody {
public:
TeraMeshRigidBody(hkpRigidBody* hk_body, sead::Heap* heap);
u32 getCollisionMasks(CollisionMasks* masks) override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
};
} // namespace ksys::phys
@@ -520,7 +520,7 @@ public:
protected:
// FIXME: return type
virtual u32 getCollisionMasks(CollisionMasks* masks) = 0;
virtual u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) = 0;
/// Called whenever a shape update is requested.
/// @return the new shape to use for the Havok rigid body or null to keep the current hkpShape
@@ -0,0 +1,149 @@
#include "KingSystem/Physics/RigidBody/physRigidBodyFromResource.h"
#include <Havok/Physics2012/Collide/Shape/hkpShapeContainer.h>
#include <Havok/Physics2012/Dynamics/Entity/hkpRigidBody.h>
#include <Havok/Physics2012/Dynamics/World/hkpPhysicsSystem.h>
#include <Havok/Physics2012/Utilities/Dynamics/ScaleSystem/hkpSystemScalingUtility.h>
#include <math/seadMathCalcCommon.h>
#include "KingSystem/Physics/RigidBody/physRigidBodyParam.h"
#include "KingSystem/Physics/System/physMaterialMask.h"
#include "KingSystem/Physics/physConversions.h"
namespace ksys::phys {
static const char* getRigidBodyResourceName(const hkpRigidBody* hk_body) {
if (const char* name = hk_body->getName())
return name;
return "RigidBodyFromResource";
}
RigidBodyFromResource::RigidBodyFromResource(float volume, hkpRigidBody* hk_body,
ContactLayerType layer_type, sead::Heap* heap,
RigidBody::Type type)
: RigidBody(type, layer_type, hk_body, getRigidBodyResourceName(hk_body), heap, true),
mShape(hk_body->getCollidable()->getShape()), mVolume(volume) {}
RigidBodyFromResource::~RigidBodyFromResource() = default;
bool RigidBodyFromResource::init(const RigidBodyInstanceParam& param, sead::Heap* heap) {
if (!initMotionAccessor(param, heap, true))
return false;
updateCollidableQualityType(param.toi);
getHkBody()->getCollidableRw()->setMotionState(getHkBody()->getMotion()->getMotionState());
if (auto* shape = getHkBody()->getCollidable()->getShape()) {
hkVector4 extent_out;
getHkBody()->updateCachedShapeInfo(shape, extent_out);
}
return true;
}
bool RigidBodyFromResource::isBvTreeOrStaticCompound() const {
switch (mShape->getType()) {
case hkcdShapeType::TRI_SAMPLED_HEIGHT_FIELD_BV_TREE:
case hkcdShapeType::MOPP:
case hkcdShapeType::STATIC_COMPOUND:
case hkcdShapeType::BV_COMPRESSED_MESH:
case hkcdShapeType::BV_TREE:
return true;
default:
return false;
}
}
bool RigidBodyFromResource::isMaterial(Material material) const {
if (isBvTreeOrStaticCompound())
return false;
bool found_child_shape_with_material = false;
if (auto* container = mShape->getContainer()) {
for (auto key = container->getFirstKey(); key != HK_INVALID_SHAPE_KEY;
key = container->getNextKey(key)) {
hkpShapeBuffer buffer;
auto* shape = container->getChildShape(key, buffer);
if (!shape)
return false;
MaterialMask shape_material{MaterialMaskData(shape->getUserData())};
if (int(shape_material.getMaterial()) == material) {
found_child_shape_with_material = true;
break;
}
}
} else {
MaterialMask shape_material{MaterialMaskData(mShape->getUserData())};
if (int(shape_material.getMaterial()) == material)
return true;
}
return found_child_shape_with_material;
}
// FIXME: move this to the appropriate header
// 0x0000007100fd0a1c
u32 getCollisionFilterInfoFromCollidable(u32* material_mask, u32* collision_filter_info,
const hkpCollidable* collidable, const u32* unk);
u32 RigidBodyFromResource::getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) {
masks->ignored_layers = ~mContactMask;
auto* collidable = getHkBody()->getCollidable();
if (unk != nullptr) {
return getCollisionFilterInfoFromCollidable(&masks->material_mask,
&masks->collision_filter_info, collidable, unk);
}
masks->material_mask = collidable->getShape()->getUserData();
masks->collision_filter_info = collidable->getCollisionFilterInfo();
return 0;
}
float RigidBodyFromResource::updateScale_(float scale, float old_scale) {
if (getHkBody()->getCollidable()->getShape()->getType() == hkcdShapeType::BV_COMPRESSED_MESH) {
static_cast<void>(getPosition());
return old_scale;
}
mNewScale = scale;
updateShape();
return scale;
}
const hkpShape* RigidBodyFromResource::getNewHavokShape_() {
if (sead::Mathf::equalsEpsilon(mCurrentScale, mNewScale))
return nullptr;
const float ratio = mNewScale / mCurrentScale;
mVolume = ratio * ratio * ratio * mVolume;
const hkTransformf saved_transform = getHkBody()->getTransform();
hkTransformf identity;
identity.setIdentity();
getHkBody()->setTransform(identity);
// Actually scale it now.
// XXX: hkpSystemScalingUtility is not supposed to be used at runtime.
hkpPhysicsSystem system;
system.addRigidBody(getHkBody());
hkpSystemScalingUtility::scaleSystem(&system, ratio);
getHkBody()->setTransform(saved_transform);
if (getHkBody()->getMass() > 0) {
setMass(getHkBody()->getMass());
setCenterOfMassInLocal(toVec3(getHkBody()->getCenterOfMassLocal()));
hkMatrix3 inertia;
getHkBody()->getInertiaLocal(inertia);
setInertiaLocal({inertia.get<0, 0>(), inertia.get<1, 1>(), inertia.get<2, 2>()});
}
mCurrentScale = mNewScale;
return nullptr;
}
float RigidBodyFromResource::getVolume() {
return mVolume;
}
} // namespace ksys::phys
@@ -0,0 +1,33 @@
#pragma once
#include "KingSystem/Physics/RigidBody/physRigidBody.h"
namespace ksys::phys {
class RigidBodyFromResource : public RigidBody {
SEAD_RTTI_OVERRIDE(RigidBodyFromResource, RigidBody)
public:
RigidBodyFromResource(float volume, hkpRigidBody* hk_body, ContactLayerType layer_type,
sead::Heap* heap, Type type);
~RigidBodyFromResource() override;
bool init(const RigidBodyInstanceParam& param, sead::Heap* heap);
bool isBvTreeOrStaticCompound() const;
bool isMaterial(Material material) const;
float getVolume() override;
u32 getCollisionMasks(RigidBody::CollisionMasks* masks, const u32* unk) override;
protected:
float updateScale_(float scale, float old_scale) override;
const hkpShape* getNewHavokShape_() override;
private:
const hkpShape* mShape = nullptr;
float mVolume = 1.0;
float mCurrentScale = 1.0;
float mNewScale = 1.0;
};
} // namespace ksys::phys