ksys/phys: Implement the easier parts of EntityGroupFilter

This commit is contained in:
Léo Lam 2021-12-25 00:56:06 +01:00
parent e9024ed406
commit 90f83901ad
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
22 changed files with 787 additions and 31 deletions

View File

@ -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,

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

View File

@ -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
)

View File

@ -11,7 +11,7 @@ class hkArrayBase {
public:
HK_DECLARE_CLASS_ALLOCATOR(hkArrayBase<T>)
enum : int {
enum : unsigned int {
CAPACITY_MASK = 0x3FFFFFFF,
FLAG_MASK = 0xC0000000,
DONT_DEALLOCATE_FLAG = 0x80000000,

View File

@ -9,4 +9,5 @@
#include <Havok/Common/Base/Memory/Router/hkMemoryRouter.h>
#include <Havok/Common/Base/Container/Array/hkArray.h>
#include <Havok/Common/Base/Container/String/hkStringPtr.h>

View File

@ -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) {}

View File

@ -0,0 +1,27 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
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; }
};

View File

@ -0,0 +1,18 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCdBody.h>
#include <Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h>
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<const hkpBvTreeShape*>(body->getShape());
return shape->getContainer();
}

View File

@ -0,0 +1,146 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
#include <Havok/Geometry/Collide/Shapes/hkcdShape.h>
#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCollidableQualityType.h>
#include <Havok/Physics2012/Collide/Agent/hkpCollisionQualityInfo.h>
#include <Havok/Physics2012/Collide/Shape/hkpShapeType.h>
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<ShapeInheritance> m_shapeInheritance;
struct DebugTable;
DebugTable* m_debugAgent2Table;
DebugTable* m_debugAgent2TablePred;
DebugTable* m_debugAgent3Table;
DebugTable* m_debugAgent3TablePred;
hkReal m_expectedMaxLinearVelocity;
hkReal m_expectedMinPsiDeltaTime;
};

View File

@ -6,7 +6,7 @@
class hkAabb;
class hkpBvTreeShape;
class hkpCdBody;
class hkpCollisionInput;
struct hkpCollisionInput;
class hkpShapeContainer;
class hkpShapeCollectionFilter {

View File

@ -0,0 +1,47 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
#include <Havok/Physics2012/Collide/Shape/hkpShape.h>
#include <Havok/Physics2012/Collide/Shape/hkpShapeContainer.h>
#include <Havok/Physics2012/Collide/Util/Welding/hkpWeldingUtility.h>
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<CollectionType, hkUint8> m_collectionType;
};

View File

@ -0,0 +1,47 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
#include <Havok/Physics2012/Collide/Shape/hkpShape.h>
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<hkpShapeKey>& 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<BvTreeType, hkUint8> 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);
}

View File

@ -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;
};

View File

@ -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);

View File

@ -0,0 +1,5 @@
#pragma once
#include <Havok/Geometry/Collide/Shapes/hkcdShape.h>
using hkpShapeType = hkcdShape::ShapeType;

View File

@ -0,0 +1,24 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
// 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,
};
};

View File

@ -0,0 +1,20 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
// 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
};
};

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -137,7 +137,7 @@ struct RigidBodyParam : agl::utl::ParameterList {
agl::utl::Parameter<int> 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;

View File

@ -1,5 +1,13 @@
#include "KingSystem/Physics/System/physEntityGroupFilter.h"
#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCollidable.h>
#include <Havok/Physics2012/Collide/Agent/hkpCollisionInput.h>
#include <Havok/Physics2012/Collide/Dispatch/hkpCollisionDispatcher.h>
#include <Havok/Physics2012/Collide/Shape/Compound/Collection/hkpShapeCollection.h>
#include <Havok/Physics2012/Collide/Shape/Compound/Tree/hkpBvTreeShape.h>
#include <Havok/Physics2012/Collide/Shape/hkpShapeContainer.h>
#include <Havok/Physics2012/Dynamics/World/hkpWorldObject.h>
#include <heap/seadHeap.h>
#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<EntityGroupFilter>(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<const hkpCollidable&>(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<const hkpShapeCollection*>(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<const hkpCollidable*>(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 <bool WithUnk>
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<false>(layer, mask).raw;
}
u32 makeEntityCollisionMask(ContactLayer layer, u32 mask) {
EntityCollisionFilterInfo current{mask};
if (current.is_ground_hit_mask) {
return makeEntityGroundHitMaskImpl<true>(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

View File

@ -1,6 +1,7 @@
#pragma once
#include <container/seadSafeArray.h>
#include <prim/seadBitUtil.h>
#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<u32, ContactLayer::size()> 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

View File

@ -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 <cstddef>
#include <limits>
#include <type_traits>
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,Y,Z>, 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 <std::size_t position, std::size_t bits, typename T,
// StorageType is T for non-enum types and the underlying type of T if
// T is an enumeration. Note that T is wrapped within an enable_if in the
// former case to workaround compile errors which arise when using
// std::underlying_type<T>::type directly.
typename StorageType = typename std::conditional_t<
std::is_enum<T>::value, std::underlying_type<T>, std::enable_if<true, T>>::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<StorageType>(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<StorageType>(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<T>((storage << (shift_amount - position)) >> shift_amount);
} else {
return static_cast<T>((storage & GetMask()) >> position);
}
}
constexpr operator T() const { return Value(); } // NOLINT(google-explicit-constructor)
static constexpr bool IsSigned() { return std::is_signed<T>(); }
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<StorageType>;
static constexpr StorageType GetMask() {
return (std::numeric_limits<StorageTypeU>::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