diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 5a760b2e..23d4c7d4 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -83547,23 +83547,23 @@ Address,Quality,Size,Name 0x0000007100fa9fac,O,000120,_ZNK4ksys4phys17RigidBodyAccessor16getPointVelocityEPN4sead7Vector3IfEERKS4_ 0x0000007100faa024,O,000020,_ZNK4ksys4phys17RigidBodyAccessor13getTimeFactorEv 0x0000007100faa038,O,000064,_ZNK4ksys4phys17RigidBodyAccessor20getDeltaCenterOfMassEPN4sead7Vector3IfEES5_ -0x0000007100faa078,U,000564, +0x0000007100faa078,O,000564,_ZN4ksys4phys13BoxShapeParam11createShapeEPN4sead4HeapE 0x0000007100faa2ac,U,000224, 0x0000007100faa38c,U,000048, -0x0000007100faa3bc,U,000364, -0x0000007100faa528,U,000080, -0x0000007100faa578,U,000088, -0x0000007100faa5d0,U,000120, -0x0000007100faa648,U,000292, -0x0000007100faa76c,U,000020, -0x0000007100faa780,U,000028, -0x0000007100faa79c,U,000028, -0x0000007100faa7b8,U,000644, -0x0000007100faaa3c,U,000128, -0x0000007100faaabc,U,000120, -0x0000007100faab34,U,000204, -0x0000007100faac00,U,000092, -0x0000007100faac5c,U,000008, +0x0000007100faa3bc,O,000364,_ZN4ksys4phys8BoxShapeC1ERKNS0_13BoxShapeParamEP11hkpBoxShapeP23hkpConvexTransformShape +0x0000007100faa528,O,000080,_ZN4ksys4phys8BoxShapeD1Ev +0x0000007100faa578,O,000088,_ZN4ksys4phys8BoxShapeD0Ev +0x0000007100faa5d0,O,000120,_ZN4ksys4phys8BoxShape10setExtentsERKN4sead7Vector3IfEE +0x0000007100faa648,O,000292,_ZN4ksys4phys8BoxShape12setTranslateERKN4sead7Vector3IfEE +0x0000007100faa76c,O,000020,_ZNK4ksys4phys8BoxShape9getVolumeEv +0x0000007100faa780,O,000028,_ZN4ksys4phys8BoxShape13getHavokShapeEv +0x0000007100faa79c,O,000028,_ZNK4ksys4phys8BoxShape13getHavokShapeEv +0x0000007100faa7b8,O,000644,_ZN4ksys4phys8BoxShape16updateHavokShapeEv +0x0000007100faaa3c,O,000128,_ZN4ksys4phys8BoxShape8setScaleEf +0x0000007100faaabc,O,000120,_ZNK4ksys4phys8BoxShape12getTranslateEPN4sead7Vector3IfEERK12hkTransformf +0x0000007100faab34,O,000204,_ZNK4ksys4phys8BoxShape27checkDerivedRuntimeTypeInfoEPKN4sead15RuntimeTypeInfo9InterfaceE +0x0000007100faac00,O,000092,_ZNK4ksys4phys8BoxShape18getRuntimeTypeInfoEv +0x0000007100faac5c,O,000008,_ZNK4ksys4phys8BoxShape7getTypeEv 0x0000007100faac64,U,000260, 0x0000007100faad68,U,000432, 0x0000007100faaf18,U,000032, diff --git a/src/KingSystem/Physics/RigidBody/Shape/physBoxRigidBody.h b/src/KingSystem/Physics/RigidBody/Shape/physBoxRigidBody.h index bf023334..a4f0a0a4 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physBoxRigidBody.h +++ b/src/KingSystem/Physics/RigidBody/Shape/physBoxRigidBody.h @@ -4,7 +4,7 @@ namespace ksys::phys { -struct BoxShape; +class BoxShape; struct RigidBodyInstanceParam; class BoxRigidBody : public RigidBodyFromShape { diff --git a/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.cpp b/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.cpp index e69de29b..8c5bb94b 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.cpp +++ b/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.cpp @@ -0,0 +1,165 @@ +#include "KingSystem/Physics/RigidBody/Shape/physBoxShape.h" +#include +#include +#include "KingSystem/Physics/physConversions.h" +#include "KingSystem/Utils/HeapUtil.h" +#include "KingSystem/Utils/SafeDelete.h" + +namespace ksys::phys { + +BoxShape* BoxShapeParam::createShape(sead::Heap* heap) { + hkpBoxShape* box = nullptr; + if (auto* storage = util::allocStorage(heap)) { + const auto radius = convex_radius; + const hkVector4f half_extents{sead::Mathf::max(extents.x / 2 - radius, 0.001), + sead::Mathf::max(extents.y / 2 - radius, 0.001), + sead::Mathf::max(extents.z / 2 - radius, 0.001)}; + box = new (storage) hkpBoxShape(half_extents, radius); + } + + hkpConvexTransformShape* transform_shape = nullptr; + if (auto* storage = util::allocStorage(heap)) { + sead::Quatf rotation; + rotation.setRPY(rotate.x, rotate.y, rotate.z); + hkQsTransformf transform{toHkVec4(translate), toHkQuat(rotation)}; + transform_shape = new (storage) hkpConvexTransformShape(box, transform); + } + + if (!box || !transform_shape) { + if (box) + delete reinterpret_cast(box); + if (transform_shape) + delete reinterpret_cast(transform_shape); + return nullptr; + } + + return new (heap) BoxShape(*this, box, transform_shape); +} + +BoxShape::BoxShape(const BoxShapeParam& param, hkpBoxShape* shape, + hkpConvexTransformShape* transform_shape) + : mExtents(param.extents), mTranslate(param.translate), mRotate(param.rotate), + mHavokShape(shape), mMaterialMask(param.common.getMaterialMask()), + mTransformShape(transform_shape) { + const bool no_transform = + mTranslate == sead::Vector3f(0, 0, 0) && mRotate == sead::Vector3f(0, 0, 0); + mFlags.change(Flag::HasTransform, !no_transform); + + if (param.common.item_code_disable_stick) + mMaterialMask.getData().setCustomFlag(MaterialMaskData::CustomFlag::_0); + + setMaterialMask(mMaterialMask); +} + +BoxShape::~BoxShape() { + util::deallocateObjectUnsafe(mHavokShape); + util::deallocateObjectUnsafe(mTransformShape); +} + +bool BoxShape::setExtents(const sead::Vector3f& extents) { + if (mExtents == extents) + return false; + + mExtents = extents; + mFlags.set(Flag::Dirty); + return true; +} + +bool BoxShape::setTranslate(const sead::Vector3f& translate) { + if (mTranslate == translate) + return false; + + mTranslate = translate; + + const bool had_transform = mFlags.isOn(Flag::HasTransform); + const bool no_transform = + mTranslate == sead::Vector3f(0, 0, 0) && mRotate == sead::Vector3f(0, 0, 0); + + mFlags.change(Flag::HasTransform, !no_transform); + mFlags.change(Flag::DirtyTransform, had_transform != !no_transform); + mFlags.set(Flag::Dirty); + + return true; +} + +void BoxShape::setMaterialMask(const MaterialMask& mask) { + mMaterialMask = mask; + + if (mHavokShape) + mHavokShape->setUserData(mask.getRawData()); + + if (mTransformShape) + mTransformShape->setUserData(mask.getRawData()); +} + +float BoxShape::getVolume() const { + return mExtents.x * mExtents.y * mExtents.z; +} + +hkpShape* BoxShape::getHavokShape() { + if (mFlags.isOn(Flag::HasTransform)) + return mTransformShape; + return mHavokShape; +} + +const hkpShape* BoxShape::getHavokShape() const { + if (mFlags.isOn(Flag::HasTransform)) + return mTransformShape; + return mHavokShape; +} + +const hkpShape* BoxShape::updateHavokShape() { + if (mFlags.isOn(Flag::Dirty)) { + { + const auto radius = mHavokShape->getRadius(); + const sead::Vector3f half_extents{sead::Mathf::max(mExtents.x / 2 - radius, 0.001), + sead::Mathf::max(mExtents.y / 2 - radius, 0.001), + sead::Mathf::max(mExtents.z / 2 - radius, 0.001)}; + const auto ref_count = mHavokShape->getReferenceCount(); + mHavokShape = new (mHavokShape) hkpBoxShape(toHkVec4(half_extents), radius); + mHavokShape->setReferenceCount(ref_count); + } + { + sead::Quatf rotation; + rotation.setRPY(mRotate.x, mRotate.y, mRotate.z); + hkQsTransformf transform{toHkVec4(mTranslate), toHkQuat(rotation)}; + const auto ref_count = mTransformShape->getReferenceCount(); + mTransformShape = new (mTransformShape) hkpConvexTransformShape(mHavokShape, transform); + mTransformShape->setReferenceCount(ref_count); + } + + setMaterialMask(mMaterialMask); + + mFlags.reset(Flag::Dirty); + } + + if (mFlags.isOn(Flag::DirtyTransform)) { + mFlags.reset(Flag::DirtyTransform); + return std::as_const(*this).getHavokShape(); + } + + return nullptr; +} + +void BoxShape::setScale(float scale) { + const auto scaled_extents = mExtents * scale; + if (mExtents != scaled_extents) { + mExtents = scaled_extents; + mFlags.set(Flag::Dirty); + } + setTranslate(mTranslate * scale); +} + +void BoxShape::getTranslate(sead::Vector3f* out, const hkTransformf& transform) const { + hkVector4f translate; + if (mFlags.isOn(Flag::HasTransform)) { + hkVector4f transformed; + transformed.setTransformedPos(transform, toHkVec4(mTranslate)); + translate = transformed; + } else { + translate = transform.getTranslation(); + } + storeToVec3(out, translate); +} + +} // namespace ksys::phys diff --git a/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.h b/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.h index 9da4a2e6..37cddcbf 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.h +++ b/src/KingSystem/Physics/RigidBody/Shape/physBoxShape.h @@ -1,26 +1,70 @@ #pragma once #include +#include +#include #include "KingSystem/Physics/RigidBody/Shape/physShape.h" #include "KingSystem/Physics/RigidBody/physRigidBody.h" #include "KingSystem/Physics/RigidBody/physRigidBodyParam.h" +#include "KingSystem/Physics/System/physMaterialMask.h" + +class hkTransformf; +class hkpBoxShape; +class hkpConvexTransformShape; namespace ksys::phys { class BoxParam; class BoxRigidBody; +struct BoxShapeParam; -struct BoxShape : Shape { +class BoxShape : public Shape { + SEAD_RTTI_OVERRIDE(BoxShape, Shape) +public: + enum class Flag { + /// Whether there is a pending change. + Dirty = 1 << 0, + /// Whether we have a transform (translation and/or rotation). + HasTransform = 1 << 1, + /// Whether there is a pending transform change. + DirtyTransform = 1 << 2, + }; + + BoxShape(const BoxShapeParam& param, hkpBoxShape* shape, + hkpConvexTransformShape* transform_shape); ~BoxShape() override; BoxRigidBody* createBody(bool flag, const RigidBodyInstanceParam& params, sead::Heap* heap); + + bool setExtents(const sead::Vector3f& extents); + bool setTranslate(const sead::Vector3f& translate); + void setMaterialMask(const MaterialMask& mask); + + ShapeType getType() const override { return ShapeType::Box; } + float getVolume() const override; + hkpShape* getHavokShape() override; + const hkpShape* getHavokShape() const override; + const hkpShape* updateHavokShape() override; + void setScale(float scale) override; + + /// Get the transform's translation or mTranslate transformed by the matrix + /// (if we have a non-zero translation vector). + void getTranslate(sead::Vector3f* out, const hkTransformf& transform) const; + + sead::Vector3f mExtents; + sead::TypedBitFlag> mFlags; + sead::Vector3f mTranslate; + sead::Vector3f mRotate; + hkpBoxShape* mHavokShape{}; + MaterialMask mMaterialMask{}; + hkpConvexTransformShape* mTransformShape{}; }; struct BoxShapeParam { BoxShape* createShape(sead::Heap* heap); - sead::Vector3f translate_1; - sead::Vector3f translate_0; + sead::Vector3f extents; + sead::Vector3f translate; sead::Vector3f rotate; float convex_radius; CommonShapeParam common; diff --git a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp index 383f9beb..99c71ddc 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp +++ b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp @@ -8,9 +8,7 @@ namespace ksys::phys { CapsuleShape::CapsuleShape(const CapsuleShapeParam& shape_, hkpShape* hkp_shape_) : vertex_a(shape_.vertex_a), vertex_b(shape_.vertex_b), radius(shape_.radius), - material_mask(shape_.common.material, shape_.common.sub_material, shape_.common.floor_code, - shape_.common.wall_code), - shape(hkp_shape_) { + material_mask(shape_.common.getMaterialMask()), shape(hkp_shape_) { if (shape_.common.item_code_disable_stick) material_mask.getData().setCustomFlag(MaterialMaskData::CustomFlag::_0); setMaterialMask(material_mask); diff --git a/src/KingSystem/Physics/RigidBody/Shape/physShape.h b/src/KingSystem/Physics/RigidBody/Shape/physShape.h index 4cab1053..f1c47a66 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physShape.h +++ b/src/KingSystem/Physics/RigidBody/Shape/physShape.h @@ -3,6 +3,7 @@ #include #include #include "KingSystem/Physics/System/physDefines.h" +#include "KingSystem/Physics/System/physMaterialMask.h" class hkpShape; @@ -28,12 +29,16 @@ public: virtual ~Shape() = default; virtual hkpShape* getHavokShape() = 0; virtual const hkpShape* getHavokShape() const = 0; - virtual hkpShape* updateHavokShape() = 0; + virtual const hkpShape* updateHavokShape() = 0; /// @param scale New scale (relative to the current scale) virtual void setScale(float scale) = 0; }; struct CommonShapeParam { + MaterialMask getMaterialMask(bool flag = false) const { + return {material, sub_material, floor_code, wall_code, flag}; + } + Material material; const char* sub_material = sead::SafeString::cEmptyString.cstr(); FloorCode floor_code; diff --git a/src/KingSystem/Physics/RigidBody/Shape/physShapeParamObj.cpp b/src/KingSystem/Physics/RigidBody/Shape/physShapeParamObj.cpp index 0667af93..8174d1e9 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physShapeParamObj.cpp +++ b/src/KingSystem/Physics/RigidBody/Shape/physShapeParamObj.cpp @@ -90,8 +90,8 @@ void ShapeParamObj::getCylinder(CylinderShapeParam* param) const { } void ShapeParamObj::getBox(BoxShapeParam* param) const { - param->translate_0 = *translate_0; - param->translate_1 = *translate_1; + param->translate = *translate_0; + param->extents = *translate_1; param->rotate = *rotate; param->convex_radius = *convex_radius; getCommon(¶m->common); diff --git a/src/KingSystem/Utils/HeapUtil.h b/src/KingSystem/Utils/HeapUtil.h index 238bfe63..3d6f8ac8 100644 --- a/src/KingSystem/Utils/HeapUtil.h +++ b/src/KingSystem/Utils/HeapUtil.h @@ -124,9 +124,15 @@ KSYS_ALWAYS_INLINE inline sead::Heap* tryCreateDualHeap(sead::Heap* parent) { sead::Heap::cHeapDirection_Forward, false); } +/// Allocate uninitialised, suitably aligned storage for an object of type T. +template +inline void* allocStorage(sead::Heap* heap) { + return heap->alloc(sizeof(T), alignof(T)); +} + template inline T* alloc(sead::Heap* heap, Args&&... args) { - void* storage = heap->alloc(sizeof(T), alignof(T)); + void* storage = allocStorage(heap); return new (storage) T(std::forward(args)...); } diff --git a/src/KingSystem/Utils/SafeDelete.h b/src/KingSystem/Utils/SafeDelete.h index bcbf5e74..ddaf3fb7 100644 --- a/src/KingSystem/Utils/SafeDelete.h +++ b/src/KingSystem/Utils/SafeDelete.h @@ -1,5 +1,7 @@ #pragma once +#include + namespace ksys::util { template @@ -33,4 +35,24 @@ inline void safeDeleteHeap(T*& heap) { } } +/// @warning This does not call T's destructor. +/// This should only be used if T is trivially destructible (or if you know T's destructor +/// can be skipped). +template +inline void deallocateObjectUnsafe(T*& pointer) { + if (pointer) { + operator delete(pointer); + pointer = nullptr; + } +} + +/// @warning This does not call T's destructor. +template +inline void deallocateObject(T*& pointer) { + static_assert(std::is_trivially_destructible_v, + "T must be trivially destructible: use safeDelete " + "(or use deallocateObjectUnsafe if you know T's destructor can be skipped)"); + deallocateObjectUnsafe(pointer); +} + } // namespace ksys::util