summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2022-03-08 19:14:03 +0100
committerLéo Lam <leo@leolam.fr>2022-03-08 20:30:12 +0100
commita9ee6f839e40fbef0c8bd6eb40999aacfbda906d (patch)
tree7e7a8c6f0a22c74862d019d4c81b0fd47dc955fc /src
parentc11a33c5abbbe7696c6a46ee591bc9e84e65d766 (diff)
ksys/phys: Start adding EntityContactListener
Diffstat (limited to 'src')
-rw-r--r--src/KingSystem/Physics/CMakeLists.txt2
-rw-r--r--src/KingSystem/Physics/System/physEntityContactListener.cpp73
-rw-r--r--src/KingSystem/Physics/System/physEntityContactListener.h39
-rw-r--r--src/KingSystem/Physics/System/physMaterialTable.h12
-rw-r--r--src/KingSystem/Physics/physConversions.h22
-rw-r--r--src/KingSystem/Physics/physMaterialMask.h12
6 files changed, 158 insertions, 2 deletions
diff --git a/src/KingSystem/Physics/CMakeLists.txt b/src/KingSystem/Physics/CMakeLists.txt
index d437e5ef..cecb70e5 100644
--- a/src/KingSystem/Physics/CMakeLists.txt
+++ b/src/KingSystem/Physics/CMakeLists.txt
@@ -121,6 +121,8 @@ target_sources(uking PRIVATE
System/physContactPointInfo.h
System/physLayerContactPointInfo.cpp
System/physLayerContactPointInfo.h
+ System/physEntityContactListener.cpp
+ System/physEntityContactListener.h
System/physEntityGroupFilter.cpp
System/physEntityGroupFilter.h
System/physGroupFilter.cpp
diff --git a/src/KingSystem/Physics/System/physEntityContactListener.cpp b/src/KingSystem/Physics/System/physEntityContactListener.cpp
new file mode 100644
index 00000000..c7ae31ee
--- /dev/null
+++ b/src/KingSystem/Physics/System/physEntityContactListener.cpp
@@ -0,0 +1,73 @@
+#include "KingSystem/Physics/System/physEntityContactListener.h"
+#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCdBody.h>
+#include <Havok/Physics2012/Dynamics/Collide/ContactListener/hkpContactPointEvent.h>
+#include <Havok/Physics2012/Dynamics/Constraint/Contact/hkpContactPointProperties.h>
+#include <math/seadMathCalcCommon.h>
+#include "KingSystem/Physics/RigidBody/physRigidBody.h"
+#include "KingSystem/Physics/System/physMaterialTable.h"
+#include "KingSystem/Physics/System/physSystem.h"
+#include "KingSystem/Physics/physConversions.h"
+#include "KingSystem/Physics/physMaterialMask.h"
+
+namespace ksys::phys {
+
+EntityContactListener* EntityContactListener::make(ContactMgr* mgr, sead::Heap* heap) {
+ auto* listener = new (heap) EntityContactListener(mgr, heap);
+ listener->init(heap);
+ return listener;
+}
+
+EntityContactListener::EntityContactListener(ContactMgr* mgr, sead::Heap* heap)
+ : ContactListener(mgr, ContactLayerType::Entity, MaxNumLayersPerType) {}
+
+EntityContactListener::~EntityContactListener() = default;
+
+bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const RigidBody& body) {
+ switch (body.getContactLayer().value()) {
+ case ContactLayer::EntityObject:
+ case ContactLayer::EntityGroundObject:
+ case ContactLayer::EntityNPC:
+ case ContactLayer::EntityTree:
+ if (body.hasFlag(RigidBody::Flag::_400000))
+ break;
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool EntityContactListener::isObjectOrGroundOrNPCOrTree(const hkpCdBody& cd_body) {
+ auto* body = getRigidBody(*cd_body.getRootCollidable());
+ if (!body)
+ return false;
+
+ return isObjectOrGroundOrNPCOrTree(*body);
+}
+
+void EntityContactListener::m11(const hkpContactPointEvent& event,
+ const RigidBodyCollisionMasks& masks_a,
+ const RigidBodyCollisionMasks& masks_b, RigidBody* body_a,
+ RigidBody* body_b) {
+ auto* hk_point_properties = event.m_contactPointProperties;
+
+ const MaterialMask mat_mask_a = MaterialMaskData(masks_a.material_mask);
+ const MaterialMask mat_mask_b = MaterialMaskData(masks_b.material_mask);
+ const auto* material_table = System::instance()->getMaterialTable();
+
+ const auto mat_a = mat_mask_a.getMaterial();
+ const auto mat_b = mat_mask_b.getMaterial();
+ const auto properties = material_table->getPairProperties(mat_a, mat_b);
+
+ const float friction = properties.friction *
+ sead::Mathf::min(body_a->getFrictionScale(), body_b->getFrictionScale());
+
+ const float restitution =
+ properties.restitution * sead::Mathf::min(body_a->getEffectiveRestitutionScale(),
+ body_b->getEffectiveRestitutionScale());
+
+ hk_point_properties->setFriction(friction);
+ hk_point_properties->setRestitution(restitution);
+}
+
+} // namespace ksys::phys
diff --git a/src/KingSystem/Physics/System/physEntityContactListener.h b/src/KingSystem/Physics/System/physEntityContactListener.h
new file mode 100644
index 00000000..11445013
--- /dev/null
+++ b/src/KingSystem/Physics/System/physEntityContactListener.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "KingSystem/Physics/System/physContactListener.h"
+
+class hkpCdBody;
+
+namespace ksys::phys {
+
+class EntityContactListener : public ContactListener {
+ SEAD_RTTI_OVERRIDE(EntityContactListener, ContactListener)
+public:
+ static EntityContactListener* make(ContactMgr* mgr, sead::Heap* heap);
+
+ ~EntityContactListener() override;
+ void collisionAddedCallback(const hkpCollisionEvent& event) override;
+ void collisionRemovedCallback(const hkpCollisionEvent& event) override;
+
+ static bool isObjectOrGroundOrNPCOrTree(const RigidBody& body);
+ static bool isObjectOrGroundOrNPCOrTree(const hkpCdBody& cd_body);
+
+protected:
+ EntityContactListener(ContactMgr* mgr, sead::Heap* heap);
+
+ bool contactPointCallbackImpl(u32 ignored_layers_a, u32 ignored_layers_b, RigidBody* body_a,
+ RigidBody* body_b, ContactLayer layer_a, ContactLayer layer_b,
+ const hkpContactPointEvent& event) override;
+
+ void m11(const hkpContactPointEvent& event, const RigidBodyCollisionMasks& masks_a,
+ const RigidBodyCollisionMasks& masks_b, RigidBody* body_a, RigidBody* body_b) override;
+
+ bool
+ regularContactPointCallback(const hkpContactPointEvent& event, RigidBody* body_a,
+ RigidBody* body_b,
+ sead::SafeArray<MaterialMaskData, 2>* out_material_masks) override;
+
+ u32 m15() override;
+};
+
+} // namespace ksys::phys
diff --git a/src/KingSystem/Physics/System/physMaterialTable.h b/src/KingSystem/Physics/System/physMaterialTable.h
index 9d94bd81..89dedf7d 100644
--- a/src/KingSystem/Physics/System/physMaterialTable.h
+++ b/src/KingSystem/Physics/System/physMaterialTable.h
@@ -13,6 +13,13 @@ namespace ksys::phys {
class MaterialTable {
public:
+ /// Properties for interactions between two materials.
+ struct MaterialPairProperties {
+ float friction;
+ float restitution;
+ };
+
+ /// Parameter object that stores an entire row of InteractionProperties.
struct Values : agl::utl::IParameterObj {
sead::SafeArray<agl::utl::Parameter<sead::Vector2f>, Material::size()> values;
};
@@ -30,6 +37,11 @@ public:
void loadMaterialTable(sead::Heap* heap, agl::utl::ResParameterArchive archive);
void loadSubMaterialTable(sead::Heap* heap, agl::utl::ResParameterArchive archive);
+ MaterialPairProperties getPairProperties(Material mat_a, Material mat_b) const {
+ auto& vec = mMaterialTable[mat_a].values[mat_b];
+ return {vec->x, vec->y};
+ }
+
const sead::SafeString& getSubMaterial(Material material, int submat_idx) const;
const sead::SafeString& getSoundMatchingSubMaterial(Material material, int submat_idx) const;
diff --git a/src/KingSystem/Physics/physConversions.h b/src/KingSystem/Physics/physConversions.h
index b6dcd984..1f9aeece 100644
--- a/src/KingSystem/Physics/physConversions.h
+++ b/src/KingSystem/Physics/physConversions.h
@@ -1,12 +1,18 @@
#pragma once
#include <Havok/Common/Base/hkBase.h>
+#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCdBody.h>
+#include <Havok/Physics2012/Collide/Agent/Collidable/hkpCollidable.h>
+#include <Havok/Physics2012/Dynamics/Entity/hkpEntity.h>
+#include <Havok/Physics2012/Dynamics/World/hkpWorldObject.h>
#include <math/seadMatrix.h>
#include <math/seadQuat.h>
#include <math/seadVector.h>
namespace ksys::phys {
+class RigidBody;
+
inline void toVec3(sead::Vector3f* out, const hkVector4f& vec) {
out->x = vec.getX();
out->y = vec.getY();
@@ -96,4 +102,20 @@ inline u32 getShapeKeyOrMinus1(const u32* shape_key) {
return shape_key ? *shape_key : u32(-1);
}
+inline RigidBody* getRigidBody(const hkpEntity* entity) {
+ // This needs to be kept in sync with the RigidBody constructor!
+ return reinterpret_cast<RigidBody*>(entity->getUserData());
+}
+
+inline RigidBody* getRigidBody(const hkpCollidable& collidable) {
+ if (collidable.getType() != hkpWorldObject::BroadPhaseType::BROAD_PHASE_ENTITY)
+ return nullptr;
+
+ auto* entity = static_cast<const hkpEntity*>(collidable.getOwner());
+ if (!entity)
+ return nullptr;
+
+ return getRigidBody(entity);
+}
+
} // namespace ksys::phys
diff --git a/src/KingSystem/Physics/physMaterialMask.h b/src/KingSystem/Physics/physMaterialMask.h
index 40e73a63..f4482325 100644
--- a/src/KingSystem/Physics/physMaterialMask.h
+++ b/src/KingSystem/Physics/physMaterialMask.h
@@ -23,6 +23,11 @@ union MaterialMaskData {
return u32(idx) < (1 << decltype(sub_material)::NumBits());
}
+ Material getMaterial() const { return int(material.Value()); }
+ int getSubMaterialIndex() const { return int(sub_material.Value()); }
+ FloorCode getFloorCode() const { return int(floor.Value()); }
+ WallCode getWallCode() const { return int(wall.Value()); }
+
void setFlag(bool b) {
if (!b)
clearFlag();
@@ -75,8 +80,11 @@ public:
MaterialMaskData& getData() { return mData; }
const MaterialMaskData& getData() const { return mData; }
u32 getRawData() const { return mData.raw; }
- Material getMaterial() const { return Material::ValueType(mData.material.Value()); }
- int getSubMaterialIdx() const { return mData.sub_material; }
+
+ Material getMaterial() const { return mData.getMaterial(); }
+ int getSubMaterialIdx() const { return mData.getSubMaterialIndex(); }
+ FloorCode getFloorCode() const { return mData.getFloorCode(); }
+ WallCode getWallCode() const { return mData.getWallCode(); }
const char* getMaterialName() const;
const char* getSubMaterialName() const;