#include #include #include "Components.h" #include "GameData.h" #include "LuaData.h" #include "EventModule.h" #include "EventTriggerModule.h" #include struct TriggerBody { void *data; }; #if 0 struct TriggerBody { btPairCachingGhostObject *mBody; btCylinderShape *shape; Ogre::SceneNode *mSceneNode; std::set 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(); ecs.component(); ecs.component(); ecs.component(); ecs.component(); ecs.import (); ecs.import (); ecs.observer("CreateTrigger") .event(flecs::OnSet) .each([](flecs::entity e, const EngineData &eng, const EventTrigger &trigger) { ZoneScoped; e.set({}); e.set({}); }); ecs.observer("CreateTriggerEvent") .event(flecs::OnSet) .each([](flecs::entity e, const EventTrigger &trigger, EventData &evt) { ZoneScoped; evt.add(e, "actuator_created", e, e); }); ecs.system("HandleEventSystem") .kind(flecs::OnUpdate) .each([](flecs::entity e, const EventTrigger &trigger, EventData &evt) { ZoneScoped; if (e.parent().is_valid() && e.parent().has()) { bool added = false; for (auto ev : evt.events) { e.parent().get_mut().add( ev.sender, ev.event, ev.e1, ev.e2); added = true; } evt.events.clear(); if (added) e.parent().modified(); } }); #if 0 ecs.component(); ecs.component().on_add([](flecs::entity e, TriggerBody &body) { bool kinematic = false; if (e.get().parent) { body.mSceneNode = e.get() .parent->createChildSceneNode( e.get().position, Ogre::Quaternion(0, 0, 0, 1)); kinematic = true; } else { body.mSceneNode = ECS::get() .mScnMgr->getRootSceneNode() ->createChildSceneNode( e.get().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().halfheight; float r = e.get().radius; Ogre::Vector3 position = e.get().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().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( body.mBody, ECS::get().mWorld->getBtWorld()); body.mSceneNode->getUserObjectBindings().setUserAny( "BtCollisionObject", objWrapper); }); ecs.component().on_set([](flecs::entity e, EventTrigger &ev) { e.add(); e.set({}); ECS::get().mLua->call_handler("actuator_created", e, e); }); ecs.system("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 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( obj_e); } } } } } } std::set::iterator it = body.contactBodies.begin(); while (it != body.contactBodies.end()) { if (currentContactBodies.find(*it) == currentContactBodies.end()) { flecs::entity obj_e = ECS::get() .entities .at(const_cast< btCollisionObject *>( *it)); ECS::get().mLua->call_handler( evt.event + "_exit", e, obj_e); obj_e.remove(e); e.remove(obj_e); std::cout << "body exited" << std::endl; it = body.contactBodies.erase(it); if (it == body.contactBodies.end()) break; } it++; } }); #endif }