mirror of https://github.com/zeldaret/botw.git
ksys/phys: Implement the easier parts of EntityGroupFilter
This commit is contained in:
parent
e9024ed406
commit
90f83901ad
|
@ -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.
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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; }
|
||||
};
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
class hkAabb;
|
||||
class hkpBvTreeShape;
|
||||
class hkpCdBody;
|
||||
class hkpCollisionInput;
|
||||
struct hkpCollisionInput;
|
||||
class hkpShapeContainer;
|
||||
|
||||
class hkpShapeCollectionFilter {
|
||||
|
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <Havok/Geometry/Collide/Shapes/hkcdShape.h>
|
||||
|
||||
using hkpShapeType = hkcdShape::ShapeType;
|
|
@ -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,
|
||||
};
|
||||
};
|
|
@ -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
|
||||
};
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue