diff --git a/data/uking_functions.csv b/data/uking_functions.csv index f606e1aa..6a3e7f11 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -83569,7 +83569,7 @@ Address,Quality,Size,Name 0x0000007100fab688,U,000276, 0x0000007100fab79c,U,000008, 0x0000007100fab7a4,U,000184, -0x0000007100fab85c,m,000332,_ZN4ksys4phys12CapsuleShape4initEPN4sead4HeapE +0x0000007100fab85c,W,000332,_ZN4ksys4phys12CapsuleShape4initEPN4sead4HeapE 0x0000007100fab9a8,O,000184,_ZN4ksys4phys11CapsuleBody5cloneEPN4sead4HeapE 0x0000007100faba60,O,000008,_ZNK4ksys4phys11CapsuleBody9getRadiusEv 0x0000007100faba68,O,000060,_ZNK4ksys4phys11CapsuleBody11getVerticesEPN4sead7Vector3IfEES5_ @@ -83778,23 +83778,23 @@ Address,Quality,Size,Name 0x0000007100fb509c,O,000096,_ZThn40_N4ksys4phys17EntityGroupFilterD0Ev 0x0000007100fb50fc,O,000032,_ZN4ksys4phys17EntityGroupFilter7doInit_EPN4sead4HeapE 0x0000007100fb511c,U,001440, -0x0000007100fb56bc,U,000268, -0x0000007100fb57c8,U,000028, -0x0000007100fb57e4,U,000176, -0x0000007100fb5894,U,000176, -0x0000007100fb5944,U,000304, -0x0000007100fb5a74,U,000028, +0x0000007100fb56bc,O,000268,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK13hkpCollidableS4_ +0x0000007100fb57c8,O,000028,_ZThn16_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK13hkpCollidableS4_ +0x0000007100fb57e4,O,000176,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerSA_jj +0x0000007100fb5894,O,000176,_ZThn24_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerSA_jj +0x0000007100fb5944,O,000304,_ZNK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerj +0x0000007100fb5a74,O,000028,_ZThn24_NK4ksys4phys17EntityGroupFilter18isCollisionEnabledERK17hkpCollisionInputRK9hkpCdBodyS7_RK17hkpShapeContainerj 0x0000007100fb5a90,U,000284, 0x0000007100fb5bac,U,000284, 0x0000007100fb5cc8,U,000256, 0x0000007100fb5dc8,U,000028, 0x0000007100fb5de4,O,000192,_ZN4ksys4phys17EntityGroupFilter30doInitSystemGroupHandlerLists_EPN4sead4HeapE 0x0000007100fb5ea4,O,000016,_ZN4ksys4phys17EntityGroupFilter16getFreeListIndexEPKNS0_18SystemGroupHandlerE -0x0000007100fb5eb4,O,000036,_ZN4ksys4phys19orGroundHitTypeMaskEjNS0_9GroundHitE -0x0000007100fb5ed8,O,000060,_ZN4ksys4phys19orGroundHitTypeMaskEjRKN4sead14SafeStringBaseIcEE -0x0000007100fb5f14,U,000032, -0x0000007100fb5f34,U,000068, -0x0000007100fb5f78,U,000036, +0x0000007100fb5eb4,O,000036,_ZN4ksys4phys21orEntityGroundHitMaskEjNS0_9GroundHitE +0x0000007100fb5ed8,O,000060,_ZN4ksys4phys21orEntityGroundHitMaskEjRKN4sead14SafeStringBaseIcEE +0x0000007100fb5f14,O,000032,_ZN4ksys4phys23makeEntityGroundHitMaskENS0_12ContactLayerEj +0x0000007100fb5f34,O,000068,_ZN4ksys4phys23makeEntityCollisionMaskENS0_12ContactLayerEj +0x0000007100fb5f78,O,000036,_ZN4ksys4phys31setEntityCollisionMaskGroundHitENS0_9GroundHitEj 0x0000007100fb5f9c,U,000084, 0x0000007100fb5ff0,U,000048, 0x0000007100fb6020,U,000040, diff --git a/lib/hkStubs/CMakeLists.txt b/lib/hkStubs/CMakeLists.txt index bb011b9f..efa96f49 100644 --- a/lib/hkStubs/CMakeLists.txt +++ b/lib/hkStubs/CMakeLists.txt @@ -32,11 +32,14 @@ add_library(hkStubs OBJECT Havok/Geometry/Collide/Shapes/hkcdShape.h Havok/Physics2012/Collide/Agent/hkpCollisionInput.h + Havok/Physics2012/Collide/Agent/hkpCollisionQualityInfo.h Havok/Physics2012/Collide/Agent/Collidable/hkpCdBody.h Havok/Physics2012/Collide/Agent/Collidable/hkpCollidable.h Havok/Physics2012/Collide/Agent/Collidable/hkpCollidableQualityType.h + Havok/Physics2012/Collide/Agent3/BvTree3/hkpBvTreeAgent3.h Havok/Physics2012/Collide/BroadPhase/hkpBroadPhaseHandle.h Havok/Physics2012/Collide/BroadPhase/hkpTypedBroadPhaseHandle.h + Havok/Physics2012/Collide/Dispatch/hkpCollisionDispatcher.h Havok/Physics2012/Collide/Filter/hkpCollidableCollidableFilter.h Havok/Physics2012/Collide/Filter/hkpCollisionFilter.cpp Havok/Physics2012/Collide/Filter/hkpCollisionFilter.h @@ -48,12 +51,16 @@ add_library(hkStubs OBJECT Havok/Physics2012/Collide/Query/CastUtil/hkpWorldRayCastInput.h Havok/Physics2012/Collide/Shape/hkpShape.h Havok/Physics2012/Collide/Shape/hkpShapeBase.h + Havok/Physics2012/Collide/Shape/hkpShapeType.h Havok/Physics2012/Collide/Shape/hkpShapeContainer.h + Havok/Physics2012/Collide/Shape/Compound/Collection/hkpShapeCollection.h + Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h Havok/Physics2012/Collide/Shape/Convex/hkpConvexShape.h Havok/Physics2012/Collide/Shape/Convex/Capsule/hkpCapsuleShape.h Havok/Physics2012/Collide/Shape/HeightField/hkpSphereRepShape.h Havok/Physics2012/Collide/Shape/Query/hkpRayShapeCollectionFilter.h Havok/Physics2012/Collide/Shape/Query/hkpShapeRayCastInput.h + Havok/Physics2012/Collide/Util/Welding/hkpWeldingUtility.h Havok/Physics2012/Dynamics/Entity/hkpEntity.h Havok/Physics2012/Dynamics/Entity/hkpRigidBody.h @@ -62,6 +69,7 @@ add_library(hkStubs OBJECT Havok/Physics2012/Dynamics/World/hkpWorldCinfo.cpp Havok/Physics2012/Dynamics/World/hkpWorldCinfo.h Havok/Physics2012/Dynamics/World/hkpWorldEntity.h + Havok/Physics2012/Dynamics/World/hkpWorldObject.h Havok/Physics2012/Dynamics/World/Memory/hkpWorldMemoryAvailableWatchDog.h Havok/Physics2012/Dynamics/World/Memory/Default/hkpDefaultWorldMemoryWatchDog.h ) diff --git a/lib/hkStubs/Havok/Common/Base/Container/Array/hkArray.h b/lib/hkStubs/Havok/Common/Base/Container/Array/hkArray.h index ccfeee69..8e7e9001 100644 --- a/lib/hkStubs/Havok/Common/Base/Container/Array/hkArray.h +++ b/lib/hkStubs/Havok/Common/Base/Container/Array/hkArray.h @@ -11,7 +11,7 @@ class hkArrayBase { public: HK_DECLARE_CLASS_ALLOCATOR(hkArrayBase) - enum : int { + enum : unsigned int { CAPACITY_MASK = 0x3FFFFFFF, FLAG_MASK = 0xC0000000, DONT_DEALLOCATE_FLAG = 0x80000000, diff --git a/lib/hkStubs/Havok/Common/Base/hkBase.h b/lib/hkStubs/Havok/Common/Base/hkBase.h index 47c37691..982e862c 100644 --- a/lib/hkStubs/Havok/Common/Base/hkBase.h +++ b/lib/hkStubs/Havok/Common/Base/hkBase.h @@ -9,4 +9,5 @@ #include +#include #include diff --git a/lib/hkStubs/Havok/Geometry/Collide/Shapes/hkcdShape.h b/lib/hkStubs/Havok/Geometry/Collide/Shapes/hkcdShape.h index 4d07c5b8..95154c21 100644 --- a/lib/hkStubs/Havok/Geometry/Collide/Shapes/hkcdShape.h +++ b/lib/hkStubs/Havok/Geometry/Collide/Shapes/hkcdShape.h @@ -84,6 +84,7 @@ public: using DispatchType = hkcdShapeDispatchType::ShapeDispatchTypeEnum; using ShapeInfoCodecType = hkcdShapeInfoCodecType::ShapeInfoCodecTypeEnum; + HK_FORCE_INLINE hkcdShape() = default; HK_FORCE_INLINE explicit hkcdShape(ShapeType shapeType) : m_type(shapeType), m_dispatchType(hkcdShapeDispatchType::USER), m_bitsPerKey(0), m_shapeInfoCodecType(hkcdShapeInfoCodecType::NULL_CODEC) {} diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Agent/hkpCollisionQualityInfo.h b/lib/hkStubs/Havok/Physics2012/Collide/Agent/hkpCollisionQualityInfo.h new file mode 100644 index 00000000..5e465859 --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Agent/hkpCollisionQualityInfo.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +struct hkpCollisionQualityInfo { + HK_DECLARE_CLASS_ALLOCATOR(hkpCollisionQualityInfo) + + alignas(16) hkReal m_keepContact; + hkReal m_create4dContact; + hkReal m_createContact; + hkReal m_manifoldTimDistance; + hkBool32 m_useContinuousPhysics; + hkBool m_useSimpleToiHandling; + hkReal m_minSeparation; + hkReal m_minExtraSeparation; + hkReal m_minSafeDeltaTime; + hkReal m_minAbsoluteSafeDeltaTime; + hkReal m_toiSeparation; + hkReal m_toiExtraSeparation; + hkReal m_toiAccuracy; + hkReal m_maxContraintViolation; + hkReal m_minToiDeltaTime; + hkUint16 m_constraintPriority; + hkBool m_enableToiWeldRejection; + + hkReal calcMinSeparation(hkReal currentDistance) const { return m_minSeparation; } +}; diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Agent3/BvTree3/hkpBvTreeAgent3.h b/lib/hkStubs/Havok/Physics2012/Collide/Agent3/BvTree3/hkpBvTreeAgent3.h new file mode 100644 index 00000000..69d69bfc --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Agent3/BvTree3/hkpBvTreeAgent3.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +class hkpShapeContainer; + +namespace hkBvTreeAgent3 { + +HK_FORCE_INLINE const hkpShapeContainer* getShapeContainerFrom(const hkpCdBody* body); + +} // namespace hkBvTreeAgent3 + +inline const hkpShapeContainer* hkBvTreeAgent3::getShapeContainerFrom(const hkpCdBody* body) { + auto* shape = static_cast(body->getShape()); + return shape->getContainer(); +} diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Dispatch/hkpCollisionDispatcher.h b/lib/hkStubs/Havok/Physics2012/Collide/Dispatch/hkpCollisionDispatcher.h new file mode 100644 index 00000000..fa61a901 --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Dispatch/hkpCollisionDispatcher.h @@ -0,0 +1,146 @@ +#pragma once + +#include +#include +#include +#include +#include + +class hkpCdBody; +class hkpCdBodyPairCollector; +class hkpCdPointCollector; +class hkpCollisionAgent; +struct hkpCollisionInput; +class hkpContactMgr; +class hkpContactMgrFactory; +class hkpLinearCastCollisionInput; + +namespace hkAgent3 { +enum Symmetric : int; +} + +// FIXME: incomplete +class hkpCollisionDispatcher : public hkReferencedObject { +public: + HK_DECLARE_CLASS_ALLOCATOR(hkpCollisionDispatcher) + + enum { + HK_MAX_RESPONSE_TYPE = 8, + HK_MAX_SHAPE_TYPE = hkcdShapeType::MAX_PPU_SHAPE_TYPE, + HK_MAX_AGENT2_TYPES = 64, + HK_MAX_AGENT3_TYPES = 18, + HK_MAX_COLLISION_QUALITIES = 8 + }; + + using CreateFunc = hkpCollisionAgent* (*)(const hkpCdBody& collA, const hkpCdBody& collB, + const hkpCollisionInput& env, hkpContactMgr* mgr); + + using GetPenetrationsFunc = void (*)(const hkpCdBody& bodyA, const hkpCdBody& bodyB, + const hkpCollisionInput& input, + hkpCdBodyPairCollector& collector); + + using GetClosestPointsFunc = void (*)(const hkpCdBody& bodyA, const hkpCdBody& bodyB, + const hkpCollisionInput& input, + hkpCdPointCollector& output); + + using LinearCastFunc = void (*)(const hkpCdBody& bodyA, const hkpCdBody& bodyB, + const hkpLinearCastCollisionInput& input, + hkpCdPointCollector& castCollector, + hkpCdPointCollector* startCollector); + + struct ShapeInheritance { + HK_DECLARE_CLASS_ALLOCATOR(ShapeInheritance) + + hkpShapeType m_primaryType; + hkpShapeType m_alternateType; + }; + + struct AgentFuncs { + HK_DECLARE_CLASS_ALLOCATOR(AgentFuncs) + + CreateFunc m_createFunc; + GetPenetrationsFunc m_getPenetrationsFunc; + GetClosestPointsFunc m_getClosestPointFunc; + LinearCastFunc m_linearCastFunc; + hkBool m_isFlipped = false; + hkBool m_isPredictive = false; + }; + + // FIXME: types + struct Agent3Funcs { + HK_DECLARE_CLASS_ALLOCATOR(Agent3Funcs) + + Agent3Funcs() { + m_updateFilterFunc = nullptr; + m_invalidateTimFunc = nullptr; + m_warpTimeFunc = nullptr; + m_sepNormalFunc = nullptr; + } + + alignas(16) void* m_createFunc; + void* m_destroyFunc; + void* m_cleanupFunc; + + void* m_removePointFunc; + void* m_commitPotentialFunc; + void* m_createZombieFunc; + + void* m_updateFilterFunc; + void* m_invalidateTimFunc; + void* m_warpTimeFunc; + + void* m_sepNormalFunc; + void* m_processFunc; + + hkBool m_isPredictive = false; + hkBool m_ignoreSymmetricVersion = false; + hkBool m_reusePreviousEntry = false; + }; + + struct Agent3FuncsIntern : Agent3Funcs { + HK_DECLARE_CLASS_ALLOCATOR(Agent3FuncsIntern) + + hkAgent3::Symmetric m_symmetric; + }; + + hkpCollisionDispatcher(CreateFunc defaultCreationFunction, + hkpContactMgrFactory* defaultContactMgrFactory); + ~hkpCollisionDispatcher() override; + + inline hkBool32 hasAlternateType(hkpShapeType type, hkpShapeType alternateType) const { + return m_hasAlternateType[type] & (1 << alternateType); + } + + CreateFunc m_defaultCollisionAgent; + hkpContactMgrFactory* m_contactMgrFactory[HK_MAX_RESPONSE_TYPE][HK_MAX_RESPONSE_TYPE]; + alignas(16) hkUint32 m_hasAlternateType[HK_MAX_SHAPE_TYPE]; + + int m_numAgent2Types; + alignas(16) hkUchar m_agent2Types[HK_MAX_SHAPE_TYPE][HK_MAX_SHAPE_TYPE]; + hkUchar m_agent2TypesPred[HK_MAX_SHAPE_TYPE][HK_MAX_SHAPE_TYPE]; + AgentFuncs m_agent2Func[HK_MAX_AGENT2_TYPES]; + + int m_numAgent3Types; + alignas(16) hkUchar m_agent3Types[HK_MAX_SHAPE_TYPE][HK_MAX_SHAPE_TYPE]; + alignas(16) hkUchar m_agent3TypesPred[HK_MAX_SHAPE_TYPE][HK_MAX_SHAPE_TYPE]; + Agent3FuncsIntern m_agent3Func[HK_MAX_AGENT3_TYPES]; + + alignas(16) hkChar + m_collisionQualityTable[HK_COLLIDABLE_QUALITY_MAX][HK_COLLIDABLE_QUALITY_MAX]; + alignas(16) hkpCollisionQualityInfo m_collisionQualityInfo[HK_MAX_COLLISION_QUALITIES]; + + hkBool m_collisionAgentRegistered; + hkBool m_agent3Registered; + hkBool m_midphaseAgent3Registered; + hkBool m_checkEnabled; + hkArray m_shapeInheritance; + + struct DebugTable; + DebugTable* m_debugAgent2Table; + DebugTable* m_debugAgent2TablePred; + DebugTable* m_debugAgent3Table; + DebugTable* m_debugAgent3TablePred; + + hkReal m_expectedMaxLinearVelocity; + hkReal m_expectedMinPsiDeltaTime; +}; diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Filter/hkpShapeCollectionFilter.h b/lib/hkStubs/Havok/Physics2012/Collide/Filter/hkpShapeCollectionFilter.h index 6d8c8778..c04cbcfb 100644 --- a/lib/hkStubs/Havok/Physics2012/Collide/Filter/hkpShapeCollectionFilter.h +++ b/lib/hkStubs/Havok/Physics2012/Collide/Filter/hkpShapeCollectionFilter.h @@ -6,7 +6,7 @@ class hkAabb; class hkpBvTreeShape; class hkpCdBody; -class hkpCollisionInput; +struct hkpCollisionInput; class hkpShapeContainer; class hkpShapeCollectionFilter { diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Shape/Compound/Collection/hkpShapeCollection.h b/lib/hkStubs/Havok/Physics2012/Collide/Shape/Compound/Collection/hkpShapeCollection.h new file mode 100644 index 00000000..899a1c87 --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Shape/Compound/Collection/hkpShapeCollection.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +class hkpShapeCollection : public hkpShape, public hkpShapeContainer { +public: + HK_DECLARE_CLASS_ALLOCATOR(hkpShapeCollection) + HKCD_DECLARE_SHAPE_TYPE(hkcdShapeType::COLLECTION) + + enum CollectionType { + COLLECTION_LIST, + COLLECTION_EXTENDED_MESH, + COLLECTION_TRISAMPLED_HEIGHTFIELD, + COLLECTION_USER, + COLLECTION_SIMPLE_MESH, + COLLECTION_MESH_SHAPE, + COLLECTION_COMPRESSED_MESH, + COLLECTION_MAX + }; + + HK_FORCE_INLINE hkpShapeCollection() = default; + hkpShapeCollection(ShapeType type, CollectionType collectionType); + explicit hkpShapeCollection(hkFinishLoadedObjectFlag flag); + + void getAabb(const hkTransform& localToWorld, hkReal tolerance, hkAabb& out) const override; + + hkBool castRay(const hkpShapeRayCastInput& input, + hkpShapeRayCastOutput& results) const override; + + void castRayWithCollector(const hkpShapeRayCastInput& input, const hkpCdBody& cdBody, + hkpRayHitCollector& collector) const override; + + hkReal getMaximumProjection(const hkVector4& direction) const override; + + const hkpShapeContainer* getContainer() const override; + + virtual void initWeldingInfo(hkpWeldingUtility::WeldingType weldingType); + virtual void setWeldingInfo(hkpShapeKey key, hkInt16 weldingInfo); + + bool isWeldingEnabled() const override { return !m_disableWelding; } + + hkBool m_disableWelding; + hkEnum m_collectionType; +}; diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h b/lib/hkStubs/Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h new file mode 100644 index 00000000..da2c0209 --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +class hkpAabbCastCollector; + +class hkpBvTreeShape : public hkpShape { +public: + HK_DECLARE_CLASS_ALLOCATOR(hkpBvTreeShape) + HKCD_DECLARE_SHAPE_TYPE(hkcdShapeType::BV_TREE) + + enum BvTreeType { + BVTREE_MOPP, + BVTREE_TRISAMPLED_HEIGHTFIELD, + BVTREE_STATIC_COMPOUND, + BVTREE_COMPRESSED_MESH, + BVTREE_USER, + BVTREE_MAX + }; + + inline hkpBvTreeShape(ShapeType type, BvTreeType bvType) + : hkpShape(type), m_bvTreeType(bvType) {} + + explicit hkpBvTreeShape(hkFinishLoadedObjectFlag flag); + + virtual void queryAabb(const hkAabb& aabb, hkArray& hits) const = 0; + inline hkUint32 queryAabb(const hkAabb& aabb, hkpShapeKey* hits, int maxNumKeys) const; + inline void castAabb(const hkAabb& from, hkVector4Parameter to, + hkpAabbCastCollector& collector) const; + virtual void castAabbImpl(const hkAabb& from, hkVector4Parameter to, + hkpAabbCastCollector& collector) const; + const hkpShapeContainer* getContainer() const override = 0; + virtual hkUint32 queryAabbImpl(const hkAabb& aabb, hkpShapeKey* hits, int maxNumKeys) const = 0; + + hkEnum m_bvTreeType; +}; + +inline hkUint32 hkpBvTreeShape::queryAabb(const hkAabb& aabb, hkpShapeKey* hits, + int maxNumKeys) const { + return queryAabbImpl(aabb, hits, maxNumKeys); +} + +inline void hkpBvTreeShape::castAabb(const hkAabb& from, hkVector4Parameter to, + hkpAabbCastCollector& collector) const { + castAabbImpl(from, to, collector); +} diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShape.h b/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShape.h index 6e488417..80fc2a51 100644 --- a/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShape.h +++ b/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShape.h @@ -6,13 +6,29 @@ #define HK_INVALID_SHAPE_KEY 0xffffffff #define HK_INVALID_VERTEX_ID 0xffff -// FIXME: incomplete. +class hkpShapeContainer; + class hkpShape : public hkpShapeBase { public: - virtual ~hkpShape(); + HK_DECLARE_CLASS_ALLOCATOR(hkpShape) + HKCD_DECLARE_SHAPE_TYPE(hkcdShapeType::INVALID) + struct CalcSizeForSpuInput; + + HK_FORCE_INLINE hkpShape() = default; + HK_FORCE_INLINE explicit hkpShape(ShapeType type) : hkpShapeBase(type), m_userData(0) {} + explicit hkpShape(hkFinishLoadedObjectFlag flag); + ~hkpShape() override; + + virtual const hkpShapeContainer* getContainer() const { return nullptr; } virtual hkReal getMaximumProjection(const hkVector4& direction) const; + virtual int calcSizeForSpu(const CalcSizeForSpuInput& input, int spuBufferSizeLeft) const; + inline hkUlong getUserData() const { return m_userData; } + inline void setUserData(hkUlong data) { m_userData = data; } - hkUint64 m_type; - hkUchar filler2[0x30]; + hkVector4Comparison castRayBundle(const hkpShapeRayBundleCastInput& input, + hkpShapeRayBundleCastOutput& output, + hkVector4ComparisonParameter mask) const override; + + hkUlong m_userData; }; diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeBase.h b/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeBase.h index 493d490c..09c38774 100644 --- a/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeBase.h +++ b/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeBase.h @@ -23,6 +23,7 @@ public: HK_DECLARE_CLASS_ALLOCATOR(hkpShapeBase) HKCD_DECLARE_SHAPE_TYPE(hkcdShapeType::INVALID) + HK_FORCE_INLINE hkpShapeBase() = default; HK_FORCE_INLINE explicit hkpShapeBase(ShapeType type) : hkcdShape(type) {} explicit hkpShapeBase(hkFinishLoadedObjectFlag flag); diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeType.h b/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeType.h new file mode 100644 index 00000000..823d007e --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Shape/hkpShapeType.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +using hkpShapeType = hkcdShape::ShapeType; diff --git a/lib/hkStubs/Havok/Physics2012/Collide/Util/Welding/hkpWeldingUtility.h b/lib/hkStubs/Havok/Physics2012/Collide/Util/Welding/hkpWeldingUtility.h new file mode 100644 index 00000000..49e08c9e --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Collide/Util/Welding/hkpWeldingUtility.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +// FIXME: incomplete +class hkpWeldingUtility { +public: + HK_DECLARE_CLASS_ALLOCATOR(hkpWeldingUtility) + + enum WeldingType { + WELDING_TYPE_ANTICLOCKWISE = 0, + WELDING_TYPE_CLOCKWISE = 4, + WELDING_TYPE_TWO_SIDED = 5, + WELDING_TYPE_NONE = 6, + }; + + enum SectorType { + ACCEPT_0 = 1, + SNAP_0 = 0, + REJECT = 2, + SNAP_1 = 4, + ACCEPT_1 = 3, + }; +}; diff --git a/lib/hkStubs/Havok/Physics2012/Dynamics/World/hkpWorldObject.h b/lib/hkStubs/Havok/Physics2012/Dynamics/World/hkpWorldObject.h new file mode 100644 index 00000000..435c0586 --- /dev/null +++ b/lib/hkStubs/Havok/Physics2012/Dynamics/World/hkpWorldObject.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +// FIXME: incomplete +class hkpWorldObject : public hkReferencedObject { +public: + HK_DECLARE_CLASS_ALLOCATOR(hkpWorldObject) + + enum BroadPhaseType { + BROAD_PHASE_INVALID, + /// hkpEntity + BROAD_PHASE_ENTITY, + /// hkpPhantom + BROAD_PHASE_PHANTOM, + /// hkpBroadPhaseBorder's objects (AABB phantoms) + BROAD_PHASE_BORDER, + BROAD_PHASE_MAX_ID + }; +}; diff --git a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp index 05dc3bd9..523f2eee 100644 --- a/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp +++ b/src/KingSystem/Physics/RigidBody/Shape/physCapsuleShape.cpp @@ -18,7 +18,7 @@ CapsuleBody* CapsuleShape::init(sead::Heap* heap) { body->unk.shape_type = 1 << 23; } body->unk._10 = nullptr; - hk_shape->m_type = body->unk.shape_type; + hk_shape->setUserData(body->unk.shape_type); return body; } @@ -38,7 +38,7 @@ CapsuleBody* CapsuleBody::clone(sead::Heap* heap) { body->unk.shape_type = unk.shape_type; body->unk._10 = nullptr; if (body->shape != nullptr) - body->shape->m_type = unk.shape_type; + body->shape->setUserData(unk.shape_type); return body; } diff --git a/src/KingSystem/Physics/RigidBody/physRigidBodyParam.cpp b/src/KingSystem/Physics/RigidBody/physRigidBodyParam.cpp index b40c7149..327232f6 100644 --- a/src/KingSystem/Physics/RigidBody/physRigidBodyParam.cpp +++ b/src/KingSystem/Physics/RigidBody/physRigidBodyParam.cpp @@ -133,7 +133,7 @@ void RigidBodyParam::Info::postRead_() { } if (*use_ground_hit_type_mask && !ground_hit_type_mask->isEmpty()) { - ground_hit_type_mask_val = 0; + ground_hit_mask = 0; sead::FixedSafeString<64> type_str; auto it = ground_hit_type_mask->tokenBegin(","); @@ -141,10 +141,10 @@ void RigidBodyParam::Info::postRead_() { while (end != it) { it.getAndForward(&type_str); if (!type_str.isEmpty()) - ground_hit_type_mask_val = orGroundHitTypeMask(ground_hit_type_mask_val, type_str); + ground_hit_mask = orEntityGroundHitMask(ground_hit_mask, type_str); } } else { - ground_hit_type_mask_val = 0; + ground_hit_mask = 0; } } diff --git a/src/KingSystem/Physics/RigidBody/physRigidBodyParam.h b/src/KingSystem/Physics/RigidBody/physRigidBodyParam.h index 38c5731f..471bd459 100644 --- a/src/KingSystem/Physics/RigidBody/physRigidBodyParam.h +++ b/src/KingSystem/Physics/RigidBody/physRigidBodyParam.h @@ -137,7 +137,7 @@ struct RigidBodyParam : agl::utl::ParameterList { agl::utl::Parameter shape_num; NavMeshType navmesh_val = NavMeshType::NOT_USE; NavMeshSubMaterial navmesh_sub_material_val = NavMeshSubMaterial::None; - u32 ground_hit_type_mask_val = 0; + u32 ground_hit_mask = 0; protected: void postRead_() override; diff --git a/src/KingSystem/Physics/System/physEntityGroupFilter.cpp b/src/KingSystem/Physics/System/physEntityGroupFilter.cpp index 3fa7d06b..c67b0855 100644 --- a/src/KingSystem/Physics/System/physEntityGroupFilter.cpp +++ b/src/KingSystem/Physics/System/physEntityGroupFilter.cpp @@ -1,5 +1,13 @@ #include "KingSystem/Physics/System/physEntityGroupFilter.h" +#include +#include +#include +#include +#include +#include +#include #include +#include "KingSystem/Utils/BitField.h" #include "KingSystem/Utils/HeapUtil.h" namespace ksys::phys { @@ -7,6 +15,42 @@ namespace ksys::phys { constexpr int NumEntityHandlersInList0 = 0x10; constexpr int NumEntityHandlers = 0x400; +namespace { + +/// Internal representation of collision masks for entities. +/// This is exposed as a u32 externally. +union EntityCollisionFilterInfo { + union Data { + ContactLayer getLayer() const { return int(layer); } + GroundHit getGroundHit() const { return int(ground_hit); } + + util::BitField<0, 5, u32> layer; + util::BitField<24, 1, u32> unk24; + util::BitField<25, 1, u32> unk25; + util::BitField<26, 4, u32> ground_hit; + util::BitField<30, 1, u32> unk30; + }; + + union GroundHitMask { + ContactLayer getLayer() const { return int(layer); } + + util::BitField<0, 8, u32> unk; + util::BitField<8, 16, u32> ground_hit_types; + util::BitField<24, 1, u32> unk24; + util::BitField<25, 5, u32> layer; + }; + + explicit EntityCollisionFilterInfo(u32 raw_ = 0) : raw(raw_) {} + + u32 raw; + Data data; + GroundHitMask ground_hit; + util::BitField<31, 1, u32> is_ground_hit_mask; +}; +static_assert(sizeof(EntityCollisionFilterInfo) == sizeof(u32)); + +} // namespace + EntityGroupFilter* EntityGroupFilter::make(ContactLayer::ValueType first, ContactLayer::ValueType last, sead::Heap* heap) { auto* filter = util::alloc(heap, first, last); @@ -24,6 +68,110 @@ void EntityGroupFilter::doInit_(sead::Heap* heap) { mMasks.fill(0xffffffff); } +hkBool EntityGroupFilter::isCollisionEnabledPhantom(u32 infoPhantom, u32 infoB) const { + if (mInhibitCollisions) + return false; + + // TODO: figure out what kind of mask infoPhantom is. Receiver/sensor mask? + // RigidBodyParam::getParams and ContactInfoTable seem to manipulate similar looking masks. + const EntityCollisionFilterInfo info{infoB}; + if (info.is_ground_hit_mask) + return infoPhantom & (1 << info.ground_hit.getLayer()); + return (infoPhantom & (1 << info.data.layer)) & 0x1ffff; +} + +hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollidable& a, const hkpCollidable& b) const { + if (a.getType() == hkpWorldObject::BROAD_PHASE_PHANTOM && + b.getType() == hkpWorldObject::BROAD_PHASE_PHANTOM) { + return false; + } + + if (a.getType() == hkpWorldObject::BROAD_PHASE_PHANTOM) { + if (a.getShape() != nullptr) + return isCollisionEnabled(a.getCollisionFilterInfo(), b.getCollisionFilterInfo()); + + return isCollisionEnabledPhantom(a.getCollisionFilterInfo(), b.getCollisionFilterInfo()); + } + + if (b.getType() == hkpWorldObject::BROAD_PHASE_PHANTOM) { + if (b.getShape() != nullptr) + return isCollisionEnabled(a.getCollisionFilterInfo(), b.getCollisionFilterInfo()); + + return isCollisionEnabledPhantom(b.getCollisionFilterInfo(), a.getCollisionFilterInfo()); + } + + return isCollisionEnabled(a.getCollisionFilterInfo(), b.getCollisionFilterInfo()); +} + +hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollisionInput& input, + const hkpCdBody& collectionBodyA, + const hkpCdBody& collectionBodyB, + const hkpShapeContainer& containerShapeA, + const hkpShapeContainer& containerShapeB, + hkpShapeKey keyA, hkpShapeKey keyB) const { + auto infoA = containerShapeA.getCollisionFilterInfo(keyA); + if (infoA == 0xffffffff) + infoA = collectionBodyA.getRootCollidable()->getCollisionFilterInfo(); + + auto infoB = containerShapeB.getCollisionFilterInfo(keyB); + if (infoB == 0xffffffff) + infoB = collectionBodyB.getRootCollidable()->getCollisionFilterInfo(); + + return isCollisionEnabled(infoA, infoB); +} + +hkBool EntityGroupFilter::isCollisionEnabled(const hkpCollisionInput& input, const hkpCdBody& a, + const hkpCdBody& b, + const hkpShapeContainer& bContainer, + hkpShapeKey bKey) const { + u32 infoB = bContainer.getCollisionFilterInfo(bKey); + if (infoB == 0xffffffff) + infoB = b.getRootCollidable()->getCollisionFilterInfo(); + + u32 infoA = static_cast(a).getCollisionFilterInfo(); + + if (a.getParent() != nullptr) { + if (mInhibitCollisions) + return false; + + hkpCollisionDispatcher* dispatcher = input.m_dispatcher; + + auto* collidable = &a; + auto* parent = collidable->getParent(); + while (parent) { + auto* shape = parent->m_shape; + + if (dispatcher->hasAlternateType(shape->m_type, hkcdShapeType::COLLECTION)) { + auto* collection = static_cast(shape); + infoA = collection->getCollisionFilterInfo(collidable->getShapeKey()); + goto end; + } + + if (dispatcher->hasAlternateType(shape->m_type, hkcdShapeType::BV_TREE)) { + auto* container = shape->getContainer(); + infoA = container->getCollisionFilterInfo(collidable->getShapeKey()); + goto end; + } + + if (dispatcher->hasAlternateType(shape->m_type, hkcdShapeType::MULTI_SPHERE)) { + infoA = a.getRootCollidable()->getCollisionFilterInfo(); + goto end; + } + + if (dispatcher->hasAlternateType(shape->m_type, hkcdShapeType::CONVEX_LIST)) { + return true; + } + + collidable = parent; + parent = collidable->getParent(); + infoA = static_cast(collidable)->getCollisionFilterInfo(); + } + } + +end: + return isCollisionEnabled(infoA, infoB); +} + void EntityGroupFilter::doInitSystemGroupHandlerLists_(sead::Heap* heap) { for (auto& list : mFreeLists) list.initOffset(SystemGroupHandler::getFreeListNodeOffset()); @@ -40,13 +188,50 @@ int EntityGroupFilter::getFreeListIndex(const SystemGroupHandler* handler) { return handler->getIndex() < NumEntityHandlersInList0; } -u32 orGroundHitTypeMask(u32 mask, GroundHit type) { - mask |= (0x100 << type) & 0xffff00; - return mask; +u32 orEntityGroundHitMask(u32 mask, GroundHit type) { + EntityCollisionFilterInfo info{mask}; + info.ground_hit.ground_hit_types |= 1 << type; + return info.raw; } -u32 orGroundHitTypeMask(u32 mask, const sead::SafeString& type) { - return orGroundHitTypeMask(mask, groundHitFromText(type)); +u32 orEntityGroundHitMask(u32 mask, const sead::SafeString& type) { + return orEntityGroundHitMask(mask, groundHitFromText(type)); +} + +template +static EntityCollisionFilterInfo makeEntityGroundHitMaskImpl(ContactLayer layer, u32 mask) { + const EntityCollisionFilterInfo current{mask}; + EntityCollisionFilterInfo info{}; + info.ground_hit.layer.SetUnsafe(layer); + info.ground_hit.ground_hit_types = current.ground_hit.ground_hit_types; + info.is_ground_hit_mask = true; + if constexpr (WithUnk) + info.ground_hit.unk = current.ground_hit.unk & 1; + return info; +} + +u32 makeEntityGroundHitMask(ContactLayer layer, u32 mask) { + return makeEntityGroundHitMaskImpl(layer, mask).raw; +} + +u32 makeEntityCollisionMask(ContactLayer layer, u32 mask) { + EntityCollisionFilterInfo current{mask}; + if (current.is_ground_hit_mask) { + return makeEntityGroundHitMaskImpl(layer, mask).raw; + } else { + current.data.layer.SetUnsafe(layer); + return current.raw; + } +} + +u32 setEntityCollisionMaskGroundHit(GroundHit ground_hit, u32 mask) { + EntityCollisionFilterInfo current{mask}; + if (current.is_ground_hit_mask) { + // This shouldn't happen: this function is not supposed to be called on ground hit masks. + } else { + current.data.ground_hit.SetUnsafe(ground_hit); + } + return current.raw; } } // namespace ksys::phys diff --git a/src/KingSystem/Physics/System/physEntityGroupFilter.h b/src/KingSystem/Physics/System/physEntityGroupFilter.h index f0153429..9350a7fc 100644 --- a/src/KingSystem/Physics/System/physEntityGroupFilter.h +++ b/src/KingSystem/Physics/System/physEntityGroupFilter.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "KingSystem/Physics/System/physDefines.h" #include "KingSystem/Physics/System/physGroupFilter.h" @@ -51,6 +52,9 @@ public: void m10() override {} private: + hkBool isCollisionEnabled(u32 infoA, u32 infoB) const; + hkBool isCollisionEnabledPhantom(u32 infoPhantom, u32 infoB) const; + void doInitSystemGroupHandlerLists_(sead::Heap* heap) override; int getFreeListIndex(const SystemGroupHandler* handler) override; void doInit_(sead::Heap* heap) override; @@ -60,7 +64,18 @@ private: sead::SafeArray mMasks; }; -u32 orGroundHitTypeMask(u32 mask, GroundHit type); -u32 orGroundHitTypeMask(u32 mask, const sead::SafeString& type); +u32 orEntityGroundHitMask(u32 mask, GroundHit type); +u32 orEntityGroundHitMask(u32 mask, const sead::SafeString& type); + +/// Returns a new collision mask in ground hit mask mode. +/// @param mask A collision mask that has been built using orEntityGroundHitMask. +u32 makeEntityGroundHitMask(ContactLayer layer, u32 mask); + +/// Returns a new collision mask with the specified layer. +/// Preserves ground hit mask mode. +u32 makeEntityCollisionMask(ContactLayer layer, u32 mask); + +/// Updates the collision mask with the specified ground hit type (*not* mask). +u32 setEntityCollisionMaskGroundHit(GroundHit ground_hit, u32 mask); } // namespace ksys::phys diff --git a/src/KingSystem/Utils/BitField.h b/src/KingSystem/Utils/BitField.h new file mode 100644 index 00000000..6b00b7df --- /dev/null +++ b/src/KingSystem/Utils/BitField.h @@ -0,0 +1,195 @@ +// Copyright 2014 Tony Wasserka +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the owner nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#include +#include +#include + +namespace ksys::util { + +/* + * Abstract bitfield class + * + * Allows endianness-independent access to individual bitfields within some raw + * integer value. The assembly generated by this class is identical to the + * usage of raw bitfields, so it's a perfectly fine replacement. + * + * For BitField, X is the distance of the bitfield to the LSB of the + * raw value, Y is the length in bits of the bitfield. Z is an integer type + * which determines the sign of the bitfield. Z must have the same size as the + * raw integer. + * + * + * General usage: + * + * Create a new union with the raw integer value as a member. + * Then for each bitfield you want to expose, add a BitField member + * in the union. The template parameters are the bit offset and the number + * of desired bits. + * + * Changes in the bitfield members will then get reflected in the raw integer + * value and vice-versa. + * + * + * Sample usage: + * + * union SomeRegister + * { + * u32 hex; + * + * BitField<0,7,u32> first_seven_bits; // unsigned + * BitField<7,8,u32> next_eight_bits; // unsigned + * BitField<3,15,s32> some_signed_fields; // signed + * }; + * + * This is equivalent to the little-endian specific code: + * + * union SomeRegister + * { + * u32 hex; + * + * struct + * { + * u32 first_seven_bits : 7; + * u32 next_eight_bits : 8; + * }; + * struct + * { + * u32 : 3; // padding + * s32 some_signed_fields : 15; + * }; + * }; + * + * + * Caveats: + * + * 1) + * BitField provides automatic casting from and to the storage type where + * appropriate. However, when using non-typesafe functions like printf, an + * explicit cast must be performed on the BitField object to make sure it gets + * passed correctly, e.g.: + * printf("Value: %d", (s32)some_register.some_signed_fields); + * + * 2) + * Not really a caveat, but potentially irritating: This class is used in some + * packed structures that do not guarantee proper alignment. Therefore we have + * to use #pragma pack here not to pack the members of the class, but instead + * to break GCC's assumption that the members of the class are aligned on + * sizeof(StorageType). + */ +#pragma pack(1) +template ::type directly. + typename StorageType = typename std::conditional_t< + std::is_enum::value, std::underlying_type, std::enable_if>::type> +struct BitField { + // Force default constructor to be created + // so that we can use this within unions + constexpr BitField() = default; + + // This constructor might be considered ambiguous: + // Would it initialize the storage or just the bitfield? + // Hence, delete it. Use the assignment operator to set bitfield values! + BitField(T val) = delete; + + inline constexpr void Set(T val) { + storage = + (storage & ~GetMask()) | ((static_cast(val) << position) & GetMask()); + } + + /// @warning This does *not* check whether the value fits within the mask, + /// so this might overwrite unrelated fields! Using Set() is preferred. + inline constexpr void SetUnsafe(T val) { + storage = (storage & ~GetMask()) | (static_cast(val) << position); + } + + inline constexpr BitField& operator=(const BitField& other) { + Set(other.Value()); + return *this; + } + + inline constexpr BitField& operator=(T val) { + Set(val); + return *this; + } + +#define BITFIELD_DEFINE_OP_(OP, OP_EQUAL) \ + inline constexpr BitField& operator OP_EQUAL(T val) { \ + *this = Value() OP val; \ + return *this; \ + } + + BITFIELD_DEFINE_OP_(|, |=) + BITFIELD_DEFINE_OP_(^, ^=) + BITFIELD_DEFINE_OP_(&, &=) + BITFIELD_DEFINE_OP_(+, +=) + BITFIELD_DEFINE_OP_(-, -=) + BITFIELD_DEFINE_OP_(*, *=) + BITFIELD_DEFINE_OP_(/, /=) +#undef BITFIELD_DEFINE_OP_ + + constexpr T Value() const { + if constexpr (IsSigned()) { + const size_t shift_amount = 8 * sizeof(StorageType) - bits; + return static_cast((storage << (shift_amount - position)) >> shift_amount); + } else { + return static_cast((storage & GetMask()) >> position); + } + } + + constexpr operator T() const { return Value(); } // NOLINT(google-explicit-constructor) + static constexpr bool IsSigned() { return std::is_signed(); } + static constexpr std::size_t StartBit() { return position; } + static constexpr std::size_t NumBits() { return bits; } + +private: + // Unsigned version of StorageType + using StorageTypeU = std::make_unsigned_t; + + static constexpr StorageType GetMask() { + return (std::numeric_limits::max() >> (8 * sizeof(StorageType) - bits)) + << position; + } + + StorageType storage; + + static_assert(bits + position <= 8 * sizeof(StorageType), "Bitfield out of range"); + static_assert(sizeof(T) <= sizeof(StorageType), "T must fit in StorageType"); + + // And, you know, just in case people specify something stupid like bits=position=0x80000000 + static_assert(position < 8 * sizeof(StorageType), "Invalid position"); + static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); + static_assert(bits > 0, "Invalid number of bits"); +}; +#pragma pack() + +} // namespace ksys::util