363 lines
9.7 KiB
C++
363 lines
9.7 KiB
C++
#include <iostream>
|
|
#include <OgreMeshManager.h>
|
|
#include "Components.h"
|
|
#include "GameData.h"
|
|
#include "LuaData.h"
|
|
#include "EventModule.h"
|
|
#include "EventTriggerModule.h"
|
|
#include <tracy/Tracy.hpp>
|
|
|
|
struct TriggerBody {
|
|
void *data;
|
|
};
|
|
#if 0
|
|
struct TriggerBody {
|
|
btPairCachingGhostObject *mBody;
|
|
btCylinderShape *shape;
|
|
Ogre::SceneNode *mSceneNode;
|
|
std::set<const btCollisionObject *> contactBodies;
|
|
};
|
|
struct DeepPenetrationContactResultCallback : public btManifoldResult {
|
|
DeepPenetrationContactResultCallback(
|
|
const btCollisionObjectWrapper *body0Wrap,
|
|
const btCollisionObjectWrapper *body1Wrap)
|
|
: btManifoldResult(body0Wrap, body1Wrap)
|
|
, mPenetrationDistance(0)
|
|
, mOtherIndex(0)
|
|
{
|
|
}
|
|
float mPenetrationDistance;
|
|
int mOtherIndex;
|
|
btVector3 mNormal, mPoint;
|
|
void reset()
|
|
{
|
|
mPenetrationDistance = 0.0f;
|
|
}
|
|
bool hasHit()
|
|
{
|
|
return mPenetrationDistance < 0.0f;
|
|
}
|
|
virtual void addContactPoint(const btVector3 &normalOnBInWorld,
|
|
const btVector3 &pointInWorldOnB,
|
|
btScalar depth)
|
|
{
|
|
#ifdef VDEBUG
|
|
std::cout
|
|
<< "contact: " << Ogre::Bullet::convert(pointInWorldOnB)
|
|
<< " " << Ogre::Bullet::convert(normalOnBInWorld)
|
|
<< "\n";
|
|
#endif
|
|
if (mPenetrationDistance > depth) { // Has penetration?
|
|
|
|
const bool isSwapped =
|
|
m_manifoldPtr->getBody0() !=
|
|
m_body0Wrap->getCollisionObject();
|
|
mPenetrationDistance = depth;
|
|
mOtherIndex = isSwapped ? m_index0 : m_index1;
|
|
mPoint = isSwapped ? (pointInWorldOnB +
|
|
(normalOnBInWorld * depth)) :
|
|
pointInWorldOnB;
|
|
|
|
mNormal = isSwapped ? normalOnBInWorld * -1 :
|
|
normalOnBInWorld;
|
|
}
|
|
}
|
|
};
|
|
#endif
|
|
|
|
ECS::EventTriggerModule::EventTriggerModule(flecs::world &ecs)
|
|
{
|
|
ecs.module<EventTriggerModule>();
|
|
ecs.component<EventTrigger>();
|
|
ecs.component<EventTriggerData>();
|
|
ecs.component<InTrigger>();
|
|
ecs.component<TriggeredBy>();
|
|
ecs.import <EventModule>();
|
|
ecs.import <LuaModule>();
|
|
ecs.observer<const EngineData, const EventTrigger>("CreateTrigger")
|
|
.event(flecs::OnSet)
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const EventTrigger &trigger) {
|
|
ZoneScoped;
|
|
e.set<EventTriggerData>({});
|
|
e.set<EventData>({});
|
|
});
|
|
ecs.observer<const EventTrigger, EventData>("CreateTriggerEvent")
|
|
.event(flecs::OnSet)
|
|
.each([](flecs::entity e, const EventTrigger &trigger,
|
|
EventData &evt) {
|
|
ZoneScoped;
|
|
evt.add(e, "actuator_created", e, e);
|
|
});
|
|
ecs.system<const EventTrigger, EventData>("HandleEventSystem")
|
|
.kind(flecs::OnUpdate)
|
|
.each([](flecs::entity e, const EventTrigger &trigger,
|
|
EventData &evt) {
|
|
ZoneScoped;
|
|
if (e.parent().is_valid() &&
|
|
e.parent().has<EventData>()) {
|
|
bool added = false;
|
|
for (auto ev : evt.events) {
|
|
e.parent().get_mut<EventData>().add(
|
|
ev.sender, ev.event, ev.e1,
|
|
ev.e2);
|
|
added = true;
|
|
}
|
|
evt.events.clear();
|
|
if (added)
|
|
e.parent().modified<EventData>();
|
|
}
|
|
});
|
|
#if 0
|
|
ecs.component<EventTriggerData>();
|
|
ecs.component<TriggerBody>().on_add([](flecs::entity e,
|
|
TriggerBody &body) {
|
|
bool kinematic = false;
|
|
if (e.get<EventTrigger>().parent) {
|
|
body.mSceneNode =
|
|
e.get<EventTrigger>()
|
|
.parent->createChildSceneNode(
|
|
e.get<EventTrigger>().position,
|
|
Ogre::Quaternion(0, 0, 0, 1));
|
|
kinematic = true;
|
|
} else {
|
|
body.mSceneNode =
|
|
ECS::get<EngineData>()
|
|
.mScnMgr->getRootSceneNode()
|
|
->createChildSceneNode(
|
|
e.get<EventTrigger>().position,
|
|
Ogre::Quaternion(0, 0, 0, 1));
|
|
}
|
|
body.mBody = new btPairCachingGhostObject();
|
|
body.mBody->getWorldTransform().setOrigin(Ogre::Bullet::convert(
|
|
body.mSceneNode->_getDerivedPosition()));
|
|
float h = e.get<EventTrigger>().halfheight;
|
|
float r = e.get<EventTrigger>().radius;
|
|
Ogre::Vector3 position = e.get<EventTrigger>().position;
|
|
body.shape = new btCylinderShape(btVector3(r, h, r));
|
|
body.mBody->setCollisionShape(body.shape);
|
|
int flags = body.mBody->getCollisionFlags();
|
|
flags |= btCollisionObject::CF_NO_CONTACT_RESPONSE;
|
|
if (kinematic)
|
|
flags |= btCollisionObject::CF_STATIC_OBJECT;
|
|
body.mBody->setCollisionFlags(flags);
|
|
ECS::get<EngineData>().mWorld->getBtWorld()->addCollisionObject(
|
|
body.mBody, 16, 0x1);
|
|
struct EntityCollisionListener {
|
|
const Ogre::MovableObject *entity;
|
|
Ogre::Bullet::CollisionListener *listener;
|
|
};
|
|
body.mBody->setUserPointer(
|
|
new EntityCollisionListener{ nullptr, nullptr });
|
|
class CollisionObject {
|
|
protected:
|
|
btCollisionObject *mBtBody;
|
|
btCollisionWorld *mBtWorld;
|
|
|
|
public:
|
|
CollisionObject(btCollisionObject *btBody,
|
|
btCollisionWorld *btWorld)
|
|
: mBtBody(btBody)
|
|
, mBtWorld(btWorld)
|
|
{
|
|
}
|
|
virtual ~CollisionObject()
|
|
{
|
|
mBtWorld->removeCollisionObject(mBtBody);
|
|
delete mBtBody->getCollisionShape();
|
|
delete mBtBody;
|
|
}
|
|
};
|
|
auto objWrapper = std::make_shared<CollisionObject>(
|
|
body.mBody,
|
|
ECS::get<EngineData>().mWorld->getBtWorld());
|
|
body.mSceneNode->getUserObjectBindings().setUserAny(
|
|
"BtCollisionObject", objWrapper);
|
|
});
|
|
ecs.component<EventTrigger>().on_set([](flecs::entity e,
|
|
EventTrigger &ev) {
|
|
e.add<TriggerBody>();
|
|
e.set<EventTriggerData>({});
|
|
ECS::get<LuaBase>().mLua->call_handler("actuator_created", e,
|
|
e);
|
|
});
|
|
ecs.system<const EngineData, const EventTrigger, TriggerBody,
|
|
EventTriggerData>("CheckCollisions")
|
|
.kind(flecs::OnUpdate)
|
|
.each([](flecs::entity e, const EngineData &eng,
|
|
const EventTrigger &evt, TriggerBody &body,
|
|
EventTriggerData &data) {
|
|
btDispatcher *dispatch =
|
|
eng.mWorld->getBtWorld()->getDispatcher();
|
|
btHashedOverlappingPairCache *cache =
|
|
body.mBody->getOverlappingPairCache();
|
|
int i;
|
|
int count = cache->getNumOverlappingPairs();
|
|
std::set<const btCollisionObject *> currentContactBodies;
|
|
if (count > 0) {
|
|
btManifoldArray contacts;
|
|
btBroadphasePairArray &collisionPairs =
|
|
cache->getOverlappingPairArray();
|
|
for (i = 0; i < count; i++) {
|
|
contacts.resize(0);
|
|
if (collisionPairs[i].m_algorithm) {
|
|
collisionPairs[i]
|
|
.m_algorithm
|
|
->getAllContactManifolds(
|
|
contacts);
|
|
OgreAssert(false,
|
|
"Not implemented");
|
|
} else {
|
|
const btBroadphasePair *collisionPairPtr =
|
|
eng.mWorld->getBtWorld()
|
|
->getBroadphase()
|
|
->getOverlappingPairCache()
|
|
->findPair(
|
|
collisionPairs[i]
|
|
.m_pProxy0,
|
|
collisionPairs[i]
|
|
.m_pProxy1);
|
|
if (collisionPairPtr) {
|
|
const btBroadphasePair
|
|
&collisionPair =
|
|
*collisionPairPtr;
|
|
const btCollisionObject *objA = static_cast<
|
|
btCollisionObject
|
|
*>(
|
|
collisionPair
|
|
.m_pProxy0
|
|
->m_clientObject);
|
|
const btCollisionObject *objB = static_cast<
|
|
btCollisionObject
|
|
*>(
|
|
collisionPair
|
|
.m_pProxy1
|
|
->m_clientObject);
|
|
const btCollisionObject
|
|
*me,
|
|
*other;
|
|
if (objA ==
|
|
static_cast<
|
|
btCollisionObject
|
|
*>(
|
|
body.mBody)) {
|
|
me = objA;
|
|
other = objB;
|
|
} else {
|
|
me = objB;
|
|
other = objA;
|
|
}
|
|
const btCollisionShape *my_shape =
|
|
me->getCollisionShape();
|
|
const btCollisionShape *other_shape =
|
|
other->getCollisionShape();
|
|
btCollisionObjectWrapper obA(
|
|
NULL, my_shape,
|
|
body.mBody,
|
|
body.mBody
|
|
->getWorldTransform(),
|
|
-1, i);
|
|
btCollisionObjectWrapper obB(
|
|
NULL,
|
|
other_shape,
|
|
other,
|
|
other->getWorldTransform(),
|
|
-1, 0);
|
|
btCollisionAlgorithm *algorithm =
|
|
dispatch->findAlgorithm(
|
|
&obA,
|
|
&obB,
|
|
NULL,
|
|
BT_CONTACT_POINT_ALGORITHMS);
|
|
DeepPenetrationContactResultCallback
|
|
contactPointResult(
|
|
&obA,
|
|
&obB);
|
|
|
|
algorithm->processCollision(
|
|
&obA, &obB,
|
|
eng.mWorld
|
|
->getBtWorld()
|
|
->getDispatchInfo(),
|
|
&contactPointResult);
|
|
algorithm
|
|
->~btCollisionAlgorithm();
|
|
dispatch->freeCollisionAlgorithm(
|
|
algorithm);
|
|
if (contactPointResult
|
|
.hasHit()) {
|
|
currentContactBodies
|
|
.insert(other);
|
|
if (body.contactBodies
|
|
.find(other) ==
|
|
body.contactBodies
|
|
.end()) {
|
|
body.contactBodies
|
|
.insert(other);
|
|
OgreAssert(
|
|
ECS::get<
|
|
Body2Entity>()
|
|
.entities
|
|
.find(const_cast<
|
|
btCollisionObject
|
|
*>(
|
|
other)) !=
|
|
ECS::get<
|
|
Body2Entity>()
|
|
.entities
|
|
.end(),
|
|
"No body to entity mapping");
|
|
flecs::entity obj_e =
|
|
ECS::get<
|
|
Body2Entity>()
|
|
.entities
|
|
.at(const_cast<
|
|
btCollisionObject
|
|
*>(
|
|
other));
|
|
ECS::get<
|
|
LuaBase>()
|
|
.mLua
|
|
->call_handler(
|
|
evt.event +
|
|
"_enter",
|
|
e,
|
|
obj_e);
|
|
obj_e.add<
|
|
InTrigger>(
|
|
e);
|
|
e.add<TriggeredBy>(
|
|
obj_e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
std::set<const btCollisionObject *>::iterator it =
|
|
body.contactBodies.begin();
|
|
while (it != body.contactBodies.end()) {
|
|
if (currentContactBodies.find(*it) ==
|
|
currentContactBodies.end()) {
|
|
flecs::entity obj_e =
|
|
ECS::get<Body2Entity>()
|
|
.entities
|
|
.at(const_cast<
|
|
btCollisionObject
|
|
*>(
|
|
*it));
|
|
ECS::get<LuaBase>().mLua->call_handler(
|
|
evt.event + "_exit", e, obj_e);
|
|
obj_e.remove<InTrigger>(e);
|
|
e.remove<TriggeredBy>(obj_e);
|
|
std::cout << "body exited" << std::endl;
|
|
it = body.contactBodies.erase(it);
|
|
if (it == body.contactBodies.end())
|
|
break;
|
|
}
|
|
it++;
|
|
}
|
|
});
|
|
#endif
|
|
}
|