ksys/phys: Add ListShape

This commit is contained in:
Léo Lam 2022-02-12 12:06:43 +01:00
parent 4a1bb88bd5
commit bc66305e3d
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
15 changed files with 463 additions and 31 deletions

View File

@ -83603,27 +83603,27 @@ Address,Quality,Size,Name
0x0000007100fabf40,O,000204,_ZNK4ksys4phys12CapsuleShape27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fac00c,O,000092,_ZNK4ksys4phys12CapsuleShape18getRuntimeTypeInfoEv
0x0000007100fac068,O,000008,_ZNK4ksys4phys12CapsuleShape7getTypeEv
0x0000007100fac070,U,000420,
0x0000007100fac214,U,000192,
0x0000007100fac2d4,U,000884,
0x0000007100fac648,U,000316,
0x0000007100fac784,U,000036,
0x0000007100fac7a8,U,000156,
0x0000007100fac844,U,000156,
0x0000007100fac8e0,U,000156,
0x0000007100fac97c,U,000156,
0x0000007100faca18,U,000156,
0x0000007100facab4,U,000156,
0x0000007100facb50,U,001052,
0x0000007100facf6c,U,001044,
0x0000007100fad380,U,000152,
0x0000007100fad418,U,000008,
0x0000007100fad420,U,000008,
0x0000007100fad428,U,000796,
0x0000007100fad744,U,000160,
0x0000007100fad7e4,U,000204,
0x0000007100fad8b0,U,000092,
0x0000007100fad90c,U,000008,
0x0000007100fac070,O,000420,_ZN4ksys4phys9ListShape4makeERKNS0_14ListShapeParamEPN4sead4HeapE
0x0000007100fac214,O,000192,_ZNK4ksys4phys9ListShape5cloneEPN4sead4HeapE
0x0000007100fac2d4,O,000884,_ZN4ksys4phys9ListShape16replaceWithCloneEiPKNS0_5ShapeEPN4sead4HeapE
0x0000007100fac648,O,000316,_ZN4ksys4phys9ListShapeD1Ev
0x0000007100fac784,O,000036,_ZN4ksys4phys9ListShapeD0Ev
0x0000007100fac7a8,O,000156,_ZN4ksys4phys9ListShape20replaceWithNewSphereEiRKNS0_16SphereShapeParamEPN4sead4HeapE
0x0000007100fac844,O,000156,_ZN4ksys4phys9ListShape21replaceWithNewCapsuleEiRKNS0_17CapsuleShapeParamEPN4sead4HeapE
0x0000007100fac8e0,O,000156,_ZN4ksys4phys9ListShape22replaceWithNewCylinderEiRKNS0_18CylinderShapeParamEPN4sead4HeapE
0x0000007100fac97c,O,000156,_ZN4ksys4phys9ListShape17replaceWithNewBoxEiRKNS0_13BoxShapeParamEPN4sead4HeapE
0x0000007100faca18,O,000156,_ZN4ksys4phys9ListShape22replaceWithNewPolytopeEiRKNS0_18PolytopeShapeParamEPN4sead4HeapE
0x0000007100facab4,O,000156,_ZN4ksys4phys9ListShape28replaceWithNewCharacterPrismEiRKNS0_24CharacterPrismShapeParamEPN4sead4HeapE
0x0000007100facb50,O,001052,_ZN4ksys4phys9ListShape15setMaterialMaskERKNS0_12MaterialMaskEi
0x0000007100facf6c,O,001044,_ZNK4ksys4phys9ListShape15getMaterialMaskEi
0x0000007100fad380,O,000152,_ZNK4ksys4phys9ListShape9getVolumeEv
0x0000007100fad418,O,000008,_ZN4ksys4phys9ListShape13getHavokShapeEv
0x0000007100fad420,O,000008,_ZNK4ksys4phys9ListShape13getHavokShapeEv
0x0000007100fad428,O,000796,_ZN4ksys4phys9ListShape16updateHavokShapeEv
0x0000007100fad744,O,000160,_ZN4ksys4phys9ListShape8setScaleEf
0x0000007100fad7e4,O,000204,_ZNK4ksys4phys9ListShape27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE
0x0000007100fad8b0,O,000092,_ZNK4ksys4phys9ListShape18getRuntimeTypeInfoEv
0x0000007100fad90c,O,000008,_ZNK4ksys4phys9ListShape7getTypeEv
0x0000007100fad914,O,000344,_ZN4ksys4phys13CylinderShape4makeERKNS0_18CylinderShapeParamEPN4sead4HeapE
0x0000007100fada6c,O,000032,_ZN4ksys4phys13CylinderShape15setMaterialMaskERKNS0_12MaterialMaskE
0x0000007100fada8c,O,000064,_ZN4ksys4phys13CylinderShapeD1Ev

Can't render this file because it is too large.

View File

@ -34,6 +34,9 @@ public:
HK_FORCE_INLINE int getCapacityAndFlags() const;
HK_FORCE_INLINE hkBool isEmpty() const;
HK_FORCE_INLINE T* data() { return m_data; }
HK_FORCE_INLINE const T* data() const { return m_data; }
HK_FORCE_INLINE T& operator[](int i);
HK_FORCE_INLINE const T& operator[](int i) const;

View File

@ -64,6 +64,10 @@ target_sources(uking PRIVATE
RigidBody/Shape/CylinderWater/physCylinderWaterRigidBody.h
RigidBody/Shape/CylinderWater/physCylinderWaterShape.cpp
RigidBody/Shape/CylinderWater/physCylinderWaterShape.h
RigidBody/Shape/List/physListShape.cpp
RigidBody/Shape/List/physListShape.h
RigidBody/Shape/List/physListShapeRigidBody.cpp
RigidBody/Shape/List/physListShapeRigidBody.h
RigidBody/Shape/Polytope/physPolytopeRigidBody.cpp
RigidBody/Shape/Polytope/physPolytopeRigidBody.h
RigidBody/Shape/Polytope/physPolytopeShape.cpp
@ -133,4 +137,5 @@ target_sources(uking PRIVATE
System/physUserTag.h
physConversions.h
physHeapUtil.h
)

View File

@ -145,7 +145,7 @@ const hkpShape* BoxShape::updateHavokShape() {
if (mFlags.isOn(Flag::DirtyTransform)) {
mFlags.reset(Flag::DirtyTransform);
return std::as_const(*this).getHavokShape();
return getHavokShapeConst();
}
return nullptr;

View File

@ -42,6 +42,7 @@ public:
bool setExtents(const sead::Vector3f& extents);
bool setTranslate(const sead::Vector3f& translate);
void setMaterialMask(const MaterialMask& mask);
const MaterialMask& getMaterialMask() const { return mMaterialMask; }
ShapeType getType() const override { return ShapeType::Box; }
float getVolume() const override;

View File

@ -50,6 +50,7 @@ public:
bool setVertices(const sead::Vector3f& va, const sead::Vector3f& vb);
void transformVertices(sead::Vector3f* veca, sead::Vector3f* vecb, const hkTransformf& rb_vec);
void setMaterialMask(const MaterialMask& mask);
const MaterialMask& getMaterialMask() const { return material_mask; }
sead::Vector3f vertex_a;
sead::TypedBitFlag<Flag, sead::Atomic<u32>> flags{};

View File

@ -12,4 +12,14 @@ struct CharacterPrismShapeParam {
CommonShapeParam common;
};
class CharacterPrismShape : public Shape {
SEAD_RTTI_OVERRIDE(CharacterPrismShape, Shape)
public:
static CharacterPrismShape* make(const CharacterPrismShapeParam& param, sead::Heap* heap);
CharacterPrismShape* clone(sead::Heap* heap) const;
void setMaterialMask(const MaterialMask& mask);
const MaterialMask& getMaterialMask() const;
};
} // namespace ksys::phys

View File

@ -0,0 +1,260 @@
#include "KingSystem/Physics/RigidBody/Shape/List/physListShape.h"
#include <Havok/Physics2012/Collide/Shape/Compound/Collection/List/hkpListShape.h>
#include <Havok/Physics2012/Collide/Shape/Convex/Sphere/hkpSphereShape.h>
#include <basis/seadRawPrint.h>
#include <container/seadSafeArray.h>
#include "KingSystem/Physics/RigidBody/Shape/Box/physBoxShape.h"
#include "KingSystem/Physics/RigidBody/Shape/Capsule/physCapsuleShape.h"
#include "KingSystem/Physics/RigidBody/Shape/CharacterPrism/physCharacterPrismShape.h"
#include "KingSystem/Physics/RigidBody/Shape/Cylinder/physCylinderShape.h"
#include "KingSystem/Physics/RigidBody/Shape/Polytope/physPolytopeShape.h"
#include "KingSystem/Physics/RigidBody/Shape/Sphere/physSphereShape.h"
#include "KingSystem/Physics/physHeapUtil.h"
namespace ksys::phys {
ListShape* ListShape::make(const ListShapeParam& param, sead::Heap* heap) {
auto* sphere = new hkpSphereShape(1.0);
if (!sphere)
return nullptr;
auto shapes = sead::toArray<const hkpShape*>({sphere});
auto* list_shape = new hkpListShape(shapes.getBufferPtr(), shapes.size());
sphere->removeReference();
if (!list_shape)
return nullptr;
return new (heap) ListShape(param, list_shape, heap);
}
ListShape* ListShape::clone(sead::Heap* heap) const {
ListShapeParam param;
param.num_shapes = static_cast<decltype(param.num_shapes)>(mShapes.size());
auto* cloned = make(param, heap);
if (!cloned)
return nullptr;
for (int i = 0, n = mShapes.size(); i < n; ++i)
cloned->replaceWithClone(i, mShapes[i], heap);
return cloned;
}
ListShape::ListShape(const ListShapeParam& param, hkpListShape* shape, sead::Heap* heap)
: mHavokShape(shape) {
mShapes.allocBufferAssert(param.num_shapes, heap);
for (int i = 0; i < int(param.num_shapes); ++i)
mShapes[i] = nullptr;
}
ListShape::~ListShape() {
deleteRefCountedHavokObject(mHavokShape);
for (int i = 0, n = mShapes.size(); i < n; ++i) {
if (mShapes[i]) {
delete mShapes[i];
mShapes[i] = nullptr;
}
}
mShapes.freeBuffer();
}
Shape* ListShape::replaceWithClone(int index, const Shape* shape_to_clone, sead::Heap* heap) {
delete mShapes[index];
switch (shape_to_clone->getType()) {
case ShapeType::Sphere:
mShapes[index] = sead::DynamicCast<const SphereShape>(shape_to_clone)->clone(heap);
break;
case ShapeType::Capsule:
mShapes[index] = sead::DynamicCast<const CapsuleShape>(shape_to_clone)->clone(heap);
break;
case ShapeType::Box:
mShapes[index] = sead::DynamicCast<const BoxShape>(shape_to_clone)->clone(heap);
break;
case ShapeType::Cylinder:
mShapes[index] = sead::DynamicCast<const CylinderShape>(shape_to_clone)->clone(heap);
break;
case ShapeType::Polytope:
mShapes[index] = sead::DynamicCast<const PolytopeShape>(shape_to_clone)->clone(heap);
break;
case ShapeType::CharacterPrism:
mShapes[index] = sead::DynamicCast<const CharacterPrismShape>(shape_to_clone)->clone(heap);
break;
case ShapeType::List:
case ShapeType::BoxWater:
case ShapeType::CylinderWater:
case ShapeType::Unknown:
SEAD_ASSERT_MSG(false, "unexpected shape type");
break;
}
mFlags.set(Flag::NeedsHavokShapeUpdate);
return mShapes[index];
}
Shape* ListShape::replaceWithNewSphere(int index, const SphereShapeParam& param, sead::Heap* heap) {
return replaceWithNewShape<SphereShape, SphereShapeParam>(index, param, heap);
}
Shape* ListShape::replaceWithNewCapsule(int index, const CapsuleShapeParam& param,
sead::Heap* heap) {
return replaceWithNewShape<CapsuleShape, CapsuleShapeParam>(index, param, heap);
}
Shape* ListShape::replaceWithNewCylinder(int index, const CylinderShapeParam& param,
sead::Heap* heap) {
return replaceWithNewShape<CylinderShape, CylinderShapeParam>(index, param, heap);
}
Shape* ListShape::replaceWithNewBox(int index, const BoxShapeParam& param, sead::Heap* heap) {
return replaceWithNewShape<BoxShape, BoxShapeParam>(index, param, heap);
}
Shape* ListShape::replaceWithNewPolytope(int index, const PolytopeShapeParam& param,
sead::Heap* heap) {
return replaceWithNewShape<PolytopeShape, PolytopeShapeParam>(index, param, heap);
}
Shape* ListShape::replaceWithNewCharacterPrism(int index, const CharacterPrismShapeParam& param,
sead::Heap* heap) {
return replaceWithNewShape<CharacterPrismShape, CharacterPrismShapeParam>(index, param, heap);
}
void ListShape::setMaterialMask(const MaterialMask& mask, int index) {
switch (mShapes[index]->getType()) {
case ShapeType::Sphere:
sead::DynamicCast<SphereShape>(mShapes[index])->setMaterialMask(mask);
break;
case ShapeType::Capsule:
sead::DynamicCast<CapsuleShape>(mShapes[index])->setMaterialMask(mask);
break;
case ShapeType::Box:
sead::DynamicCast<BoxShape>(mShapes[index])->setMaterialMask(mask);
break;
case ShapeType::Cylinder:
sead::DynamicCast<CylinderShape>(mShapes[index])->setMaterialMask(mask);
break;
case ShapeType::Polytope:
sead::DynamicCast<PolytopeShape>(mShapes[index])->setMaterialMask(mask);
break;
case ShapeType::CharacterPrism:
sead::DynamicCast<CharacterPrismShape>(mShapes[index])->setMaterialMask(mask);
break;
case ShapeType::List:
case ShapeType::BoxWater:
case ShapeType::CylinderWater:
case ShapeType::Unknown:
SEAD_ASSERT_MSG(false, "unexpected shape type");
break;
}
}
const MaterialMask& ListShape::getMaterialMask(int index) const {
if (index >= mShapes.size())
index = 0;
switch (mShapes[index]->getType()) {
case ShapeType::Sphere:
return sead::DynamicCast<SphereShape>(mShapes[index])->getMaterialMask();
case ShapeType::Capsule:
return sead::DynamicCast<CapsuleShape>(mShapes[index])->getMaterialMask();
case ShapeType::Box:
return sead::DynamicCast<BoxShape>(mShapes[index])->getMaterialMask();
case ShapeType::Cylinder:
return sead::DynamicCast<CylinderShape>(mShapes[index])->getMaterialMask();
case ShapeType::Polytope:
return sead::DynamicCast<PolytopeShape>(mShapes[index])->getMaterialMask();
case ShapeType::CharacterPrism:
return sead::DynamicCast<CharacterPrismShape>(mShapes[index])->getMaterialMask();
case ShapeType::List:
case ShapeType::BoxWater:
case ShapeType::CylinderWater:
case ShapeType::Unknown:
SEAD_ASSERT_MSG(false, "unexpected shape type");
break;
}
return sead::DynamicCast<SphereShape>(mShapes[index])->getMaterialMask();
}
float ListShape::getVolume() const {
float volume = 0.0;
for (int i = 0, n = mShapes.size(); i < n; ++i) {
if (mShapes[i])
volume += mShapes[i]->getVolume();
}
return volume;
}
hkpShape* ListShape::getHavokShape() {
return mHavokShape;
}
const hkpShape* ListShape::getHavokShape() const {
return mHavokShape;
}
const hkpShape* ListShape::updateHavokShape() {
bool updated = false;
if (mFlags.isOn(Flag::NeedsHavokShapeUpdate)) {
hkArray<const hkpShape*> havok_shapes;
int num_shapes = 0;
for (int i = 0, n = mShapes.size(); i < n; ++i) {
if (!mShapes[i])
continue;
const hkpShape* havok_shape = mShapes[i]->updateHavokShape();
if (havok_shape) {
// If one of the shapes was recreated, then we need to recreate the list shape.
havok_shapes.pushBack(havok_shape);
updated = true;
} else {
havok_shape = mShapes[i]->getHavokShapeConst();
havok_shapes.pushBack(havok_shape);
// Otherwise, we only need to recreate the list shape if the list has changed.
if (!updated && mHavokShape->m_childInfo.getSize() > num_shapes &&
mHavokShape->getChildShapeInl(num_shapes) != havok_shapes[num_shapes]) {
updated = true;
}
}
++num_shapes;
}
if (updated) {
const auto collision_filter_info =
mHavokShape->getCollisionFilterInfo(mHavokShape->getFirstKey());
mHavokShape->removeReference();
mHavokShape = new hkpListShape(havok_shapes.data(), num_shapes);
for (auto key = mHavokShape->getFirstKey(); key != HK_INVALID_SHAPE_KEY;
key = mHavokShape->getNextKey(key)) {
mHavokShape->setCollisionFilterInfo(key, collision_filter_info);
}
} else {
mHavokShape->recalcAabbExtents();
}
mFlags.reset(Flag::NeedsHavokShapeUpdate);
}
return updated ? mHavokShape : nullptr;
}
void ListShape::setScale(float scale) {
for (int i = 0, n = mShapes.size(); i < n; ++i) {
if (mShapes[i])
mShapes[i]->setScale(scale);
}
mFlags.set(Flag::NeedsHavokShapeUpdate);
}
} // namespace ksys::phys

View File

@ -0,0 +1,107 @@
#pragma once
#include <container/seadBuffer.h>
#include <prim/seadTypedBitFlag.h>
#include <thread/seadAtomic.h>
#include "KingSystem/Physics/RigidBody/Shape/physShape.h"
#include "KingSystem/Physics/RigidBody/physRigidBodyParam.h"
class hkpListShape;
namespace ksys::phys {
struct BoxShapeParam;
struct CapsuleShapeParam;
struct CharacterPrismShapeParam;
struct CylinderShapeParam;
struct PolytopeShapeParam;
struct SphereShapeParam;
class MaterialMask;
struct ListShapeParam {
u8 num_shapes = 1;
};
class ListShape : public Shape {
SEAD_RTTI_OVERRIDE(ListShape, Shape)
public:
static ListShape* make(const ListShapeParam& param, sead::Heap* heap);
ListShape* clone(sead::Heap* heap) const;
ListShape(const ListShapeParam& param, hkpListShape* shape, sead::Heap* heap);
~ListShape() override;
/// Replace the shape at the specified index with a clone of `shape_to_clone`.
/// The shape that is being replaced will be deleted.
/// @return the cloned heap
Shape* replaceWithClone(int index, const Shape* shape_to_clone, sead::Heap* heap);
/// Replace the shape at the specified index with a new sphere shape.
/// The shape that is being replaced will be deleted.
Shape* replaceWithNewSphere(int index, const SphereShapeParam& param, sead::Heap* heap);
/// Replace the shape at the specified index with a new capsule shape.
/// The shape that is being replaced will be deleted.
Shape* replaceWithNewCapsule(int index, const CapsuleShapeParam& param, sead::Heap* heap);
/// Replace the shape at the specified index with a new cylinder shape.
/// The shape that is being replaced will be deleted.
Shape* replaceWithNewCylinder(int index, const CylinderShapeParam& param, sead::Heap* heap);
/// Replace the shape at the specified index with a new box shape.
/// The shape that is being replaced will be deleted.
Shape* replaceWithNewBox(int index, const BoxShapeParam& param, sead::Heap* heap);
/// Replace the shape at the specified index with a new polytope shape.
/// The shape that is being replaced will be deleted.
Shape* replaceWithNewPolytope(int index, const PolytopeShapeParam& param, sead::Heap* heap);
/// Replace the shape at the specified index with a new character prism.
/// The shape that is being replaced will be deleted.
Shape* replaceWithNewCharacterPrism(int index, const CharacterPrismShapeParam& param,
sead::Heap* heap);
/// Set the material mask for the shape at the specified index.
void setMaterialMask(const MaterialMask& mask, int index);
/// Get the material mask for the shape at the specified index.
const MaterialMask& getMaterialMask(int index) const;
ShapeType getType() const override { return ShapeType::List; }
float getVolume() const override;
hkpShape* getHavokShape() override;
const hkpShape* getHavokShape() const override;
const hkpShape* updateHavokShape() override;
void setScale(float scale) override;
private:
enum class Flag {
/// Whether the Havok list shape needs to be recreated.
NeedsHavokShapeUpdate = 1 << 0,
};
template <typename T, typename ParamType>
Shape* replaceWithNewShape(int index, const ParamType& param, sead::Heap* heap) {
delete mShapes[index];
auto* shape = T::make(param, heap);
mShapes[index] = shape;
mFlags.set(Flag::NeedsHavokShapeUpdate);
return shape;
}
/// Child shapes. These are owned by this class.
sead::Buffer<Shape*> mShapes;
/// The Havok list shape. This is owned by this class.
hkpListShape* mHavokShape{};
sead::TypedBitFlag<Flag, sead::Atomic<u32>> mFlags{Flag::NeedsHavokShapeUpdate};
};
class ListShapeRigidBodyParam : public RigidBodyInstanceParam {
SEAD_RTTI_OVERRIDE(ListShapeRigidBodyParam, RigidBodyInstanceParam)
public:
u8 _90;
ListShapeParam shape;
};
} // namespace ksys::phys

View File

@ -0,0 +1 @@
#include "KingSystem/Physics/RigidBody/Shape/List/physListShapeRigidBody.h"

View File

@ -0,0 +1,13 @@
#pragma once
#include "KingSystem/Physics/RigidBody/physRigidBodyFromShape.h"
namespace ksys::phys {
class ListShapeRigidBody : public RigidBodyFromShape {
SEAD_RTTI_OVERRIDE(ListShapeRigidBody, RigidBodyFromShape)
public:
static ListShapeRigidBody* make(RigidBodyInstanceParam* param, sead::Heap* heap);
};
} // namespace ksys::phys

View File

@ -4,6 +4,7 @@
#include <Havok/Physics2012/Collide/Shape/Convex/ConvexVertices/hkpConvexVerticesShape.h>
#include <math/seadMathCalcCommon.h>
#include <prim/seadScopedLock.h>
#include "KingSystem/Physics/physHeapUtil.h"
#include "KingSystem/Utils/HeapUtil.h"
#include "KingSystem/Utils/SafeDelete.h"
@ -71,14 +72,7 @@ PolytopeShape::PolytopeShape(const PolytopeShapeParam& param)
}
PolytopeShape::~PolytopeShape() {
if (mHavokShape) {
/// @bug This is not how reference counting is supposed to work.
for (int i = 0, n = mHavokShape->getReferenceCount(); i < n; ++i)
mHavokShape->removeReference();
mHavokShape = nullptr;
}
deleteRefCountedHavokObject(mHavokShape);
util::deallocateObjectUnsafe(mTransformShape);
mVertices.freeBuffer();
}
@ -147,7 +141,7 @@ const hkpShape* PolytopeShape::updateHavokShape() {
return nullptr;
}
return std::as_const(*this).getHavokShape();
return getHavokShapeConst();
}
void PolytopeShape::setScale(float scale) {

View File

@ -19,6 +19,14 @@ class SphereShape : public Shape {
SEAD_RTTI_OVERRIDE(SphereShape, Shape)
public:
static SphereShape* make(const SphereShapeParam& param, sead::Heap* heap);
SphereShape* clone(sead::Heap* heap) const;
void setMaterialMask(const MaterialMask& mask);
const MaterialMask& getMaterialMask() const { return mMaterialMask; }
private:
char _8[0x28 - 0x8];
MaterialMask mMaterialMask;
};
class SphereParam : public RigidBodyInstanceParam {

View File

@ -15,6 +15,7 @@ enum class ShapeType {
Box = 2,
Cylinder = 3,
Polytope = 4,
List = 5,
CharacterPrism = 6,
BoxWater = 7,
CylinderWater = 8,
@ -29,11 +30,18 @@ public:
virtual ShapeType getType() const = 0;
virtual float getVolume() const = 0;
virtual ~Shape() = default;
virtual hkpShape* getHavokShape() = 0;
virtual const hkpShape* getHavokShape() const = 0;
/// Update the underlying Havok shape if necessary. This may recreate the Havok shape.
/// @return a pointer to the new underlying Havok shape if it was recreated, null otherwise
virtual const hkpShape* updateHavokShape() = 0;
/// @param scale New scale (relative to the current scale)
virtual void setScale(float scale) = 0;
const hkpShape* getHavokShapeConst() const { return getHavokShape(); }
};
struct CommonShapeParam {

View File

@ -0,0 +1,21 @@
#pragma once
#include <Havok/Common/Base/Object/hkReferencedObject.h>
namespace ksys::phys {
template <typename T>
inline std::enable_if_t<std::is_base_of_v<hkReferencedObject, T>, void>
deleteRefCountedHavokObject(T*& object) {
if (!object)
return;
/// @bug This should just be a delete expression. Decrementing the reference count
/// n times (with n = the reference count) is not how reference counting is supposed to work.
for (int i = 0, n = object->getReferenceCount(); i < n; ++i)
object->removeReference();
object = nullptr;
}
} // namespace ksys::phys