| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545 |
- #include "Base.h"
- #include "PhysicsController.h"
- #include "PhysicsRigidBody.h"
- #include "PhysicsCharacter.h"
- #include "Game.h"
- #include "MeshPart.h"
- #include "Bundle.h"
- #include "ScriptListener.h"
- #include "BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h"
- // The initial capacity of the Bullet debug drawer's vertex batch.
- #define INITIAL_CAPACITY 280
- namespace gameplay
- {
- const int PhysicsController::DIRTY = 0x01;
- const int PhysicsController::COLLISION = 0x02;
- const int PhysicsController::REGISTERED = 0x04;
- const int PhysicsController::REMOVE = 0x08;
- PhysicsController::PhysicsController()
- : _collisionConfiguration(NULL), _dispatcher(NULL),
- _overlappingPairCache(NULL), _solver(NULL), _world(NULL), _ghostPairCallback(NULL),
- _debugDrawer(NULL), _status(PhysicsController::Listener::DEACTIVATED), _listeners(NULL),
- _gravity(btScalar(0.0), btScalar(-9.8), btScalar(0.0)), _collisionCallback(NULL), _scriptListeners(NULL)
- {
- // Default gravity is 9.8 along the negative Y axis.
- _collisionCallback = new CollisionCallback(this);
- }
- PhysicsController::~PhysicsController()
- {
- SAFE_DELETE(_collisionCallback);
- SAFE_DELETE(_ghostPairCallback);
- SAFE_DELETE(_debugDrawer);
- SAFE_DELETE(_listeners);
- if (_scriptListeners)
- {
- for (unsigned int i = 0; i < _scriptListeners->size(); i++)
- {
- SAFE_DELETE((*_scriptListeners)[i]);
- }
- SAFE_DELETE(_scriptListeners);
- }
- }
- void PhysicsController::addStatusListener(Listener* listener)
- {
- GP_ASSERT(listener);
- if (!_listeners)
- _listeners = new std::vector<Listener*>();
- _listeners->push_back(listener);
- }
- void PhysicsController::removeStatusListener(Listener* listener)
- {
- GP_ASSERT(listener);
- if (!_listeners)
- return;
- for (std::vector<Listener*>::iterator iter = _listeners->begin(); iter != _listeners->end(); iter++)
- {
- if (*iter == listener)
- {
- _listeners->erase(iter);
- return;
- }
- }
- }
- void PhysicsController::addStatusListener(const char* function)
- {
- if (!_scriptListeners)
- _scriptListeners = new std::vector<ScriptListener*>();
- ScriptListener* listener = new ScriptListener(function);
- _scriptListeners->push_back(listener);
- addStatusListener(listener);
- }
- void PhysicsController::removeStatusListener(const char* function)
- {
- if (!_scriptListeners)
- return;
- std::string functionStr = function;
- for (unsigned int i = 0; i < _scriptListeners->size(); i++)
- {
- if ((*_scriptListeners)[i]->_function == functionStr)
- {
- removeStatusListener((*_scriptListeners)[i]);
- SAFE_DELETE((*_scriptListeners)[i]);
- _scriptListeners->erase(_scriptListeners->begin() + i);
- return;
- }
- }
- }
- PhysicsFixedConstraint* PhysicsController::createFixedConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsFixedConstraint* constraint = new PhysicsFixedConstraint(a, b);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsGenericConstraint* PhysicsController::createGenericConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsGenericConstraint* constraint = new PhysicsGenericConstraint(a, b);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsGenericConstraint* PhysicsController::createGenericConstraint(PhysicsRigidBody* a,
- const Quaternion& rotationOffsetA, const Vector3& translationOffsetA, PhysicsRigidBody* b,
- const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsGenericConstraint* constraint = new PhysicsGenericConstraint(a, rotationOffsetA, translationOffsetA, b, rotationOffsetB, translationOffsetB);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsHingeConstraint* PhysicsController::createHingeConstraint(PhysicsRigidBody* a,
- const Quaternion& rotationOffsetA, const Vector3& translationOffsetA, PhysicsRigidBody* b,
- const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsHingeConstraint* constraint = new PhysicsHingeConstraint(a, rotationOffsetA, translationOffsetA, b, rotationOffsetB, translationOffsetB);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsSocketConstraint* PhysicsController::createSocketConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsSocketConstraint* constraint = new PhysicsSocketConstraint(a, b);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsSocketConstraint* PhysicsController::createSocketConstraint(PhysicsRigidBody* a,
- const Vector3& translationOffsetA, PhysicsRigidBody* b, const Vector3& translationOffsetB)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsSocketConstraint* constraint = new PhysicsSocketConstraint(a,translationOffsetA, b, translationOffsetB);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsSpringConstraint* PhysicsController::createSpringConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsSpringConstraint* constraint = new PhysicsSpringConstraint(a, b);
- addConstraint(a, b, constraint);
- return constraint;
- }
- PhysicsSpringConstraint* PhysicsController::createSpringConstraint(PhysicsRigidBody* a, const Quaternion& rotationOffsetA, const Vector3& translationOffsetA,
- PhysicsRigidBody* b, const Quaternion& rotationOffsetB, const Vector3& translationOffsetB)
- {
- checkConstraintRigidBodies(a, b);
- PhysicsSpringConstraint* constraint = new PhysicsSpringConstraint(a, rotationOffsetA, translationOffsetA, b, rotationOffsetB, translationOffsetB);
- addConstraint(a, b, constraint);
- return constraint;
- }
- const Vector3& PhysicsController::getGravity() const
- {
- return _gravity;
- }
- void PhysicsController::setGravity(const Vector3& gravity)
- {
- _gravity = gravity;
- if (_world)
- _world->setGravity(BV(_gravity));
- }
- void PhysicsController::drawDebug(const Matrix& viewProjection)
- {
- GP_ASSERT(_debugDrawer);
- GP_ASSERT(_world);
- _debugDrawer->begin(viewProjection);
- _world->debugDrawWorld();
- _debugDrawer->end();
- }
- bool PhysicsController::rayTest(const Ray& ray, float distance, PhysicsController::HitResult* result, PhysicsController::HitFilter* filter)
- {
- class RayTestCallback : public btCollisionWorld::ClosestRayResultCallback
- {
- private:
- HitFilter* filter;
- HitResult hitResult;
- public:
- RayTestCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, PhysicsController::HitFilter* filter)
- : btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld), filter(filter)
- {
- }
- virtual bool needsCollision(btBroadphaseProxy* proxy0) const
- {
- if (!btCollisionWorld::ClosestRayResultCallback::needsCollision(proxy0))
- return false;
- btCollisionObject* co = reinterpret_cast<btCollisionObject*>(proxy0->m_clientObject);
- PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(co->getUserPointer());
- if (object == NULL)
- return false;
- return filter ? !filter->filter(object) : true;
- }
- btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
- {
- GP_ASSERT(rayResult.m_collisionObject);
- PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(rayResult.m_collisionObject->getUserPointer());
- if (object == NULL)
- return 1.0f; // ignore
- float result = btCollisionWorld::ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
- hitResult.object = object;
- hitResult.point.set(m_hitPointWorld.x(), m_hitPointWorld.y(), m_hitPointWorld.z());
- hitResult.fraction = m_closestHitFraction;
- hitResult.normal.set(m_hitNormalWorld.x(), m_hitNormalWorld.y(), m_hitNormalWorld.z());
- if (filter && !filter->hit(hitResult))
- return 1.0f; // process next collision
- return result; // continue normally
- }
- };
- GP_ASSERT(_world);
- btVector3 rayFromWorld(BV(ray.getOrigin()));
- btVector3 rayToWorld(rayFromWorld + BV(ray.getDirection() * distance));
- RayTestCallback callback(rayFromWorld, rayToWorld, filter);
- _world->rayTest(rayFromWorld, rayToWorld, callback);
- if (callback.hasHit())
- {
- if (result)
- {
- result->object = getCollisionObject(callback.m_collisionObject);
- result->point.set(callback.m_hitPointWorld.x(), callback.m_hitPointWorld.y(), callback.m_hitPointWorld.z());
- result->fraction = callback.m_closestHitFraction;
- result->normal.set(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
- }
- return true;
- }
- return false;
- }
- bool PhysicsController::sweepTest(PhysicsCollisionObject* object, const Vector3& endPosition, PhysicsController::HitResult* result, PhysicsController::HitFilter* filter)
- {
- class SweepTestCallback : public btCollisionWorld::ClosestConvexResultCallback
- {
- private:
- PhysicsCollisionObject* me;
- PhysicsController::HitFilter* filter;
- PhysicsController::HitResult hitResult;
- public:
- SweepTestCallback(PhysicsCollisionObject* me, PhysicsController::HitFilter* filter)
- : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), me(me), filter(filter)
- {
- }
- virtual bool needsCollision(btBroadphaseProxy* proxy0) const
- {
- if (!btCollisionWorld::ClosestConvexResultCallback::needsCollision(proxy0))
- return false;
- btCollisionObject* co = reinterpret_cast<btCollisionObject*>(proxy0->m_clientObject);
- PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(co->getUserPointer());
- if (object == NULL || object == me)
- return false;
- return filter ? !filter->filter(object) : true;
- }
- btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
- {
- GP_ASSERT(convexResult.m_hitCollisionObject);
- PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(convexResult.m_hitCollisionObject->getUserPointer());
- if (object == NULL)
- return 1.0f;
- float result = ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
- hitResult.object = object;
- hitResult.point.set(m_hitPointWorld.x(), m_hitPointWorld.y(), m_hitPointWorld.z());
- hitResult.fraction = m_closestHitFraction;
- hitResult.normal.set(m_hitNormalWorld.x(), m_hitNormalWorld.y(), m_hitNormalWorld.z());
- if (filter && !filter->hit(hitResult))
- return 1.0f;
- return result;
- }
- };
- GP_ASSERT(object && object->getCollisionShape());
- PhysicsCollisionShape* shape = object->getCollisionShape();
- PhysicsCollisionShape::Type type = shape->getType();
- if (type != PhysicsCollisionShape::SHAPE_BOX && type != PhysicsCollisionShape::SHAPE_SPHERE && type != PhysicsCollisionShape::SHAPE_CAPSULE)
- return false; // unsupported type
- // Define the start transform.
- btTransform start;
- start.setIdentity();
- if (object->getNode())
- {
- Vector3 translation;
- Quaternion rotation;
- const Matrix& m = object->getNode()->getWorldMatrix();
- m.getTranslation(&translation);
- m.getRotation(&rotation);
- start.setIdentity();
- start.setOrigin(BV(translation));
- start.setRotation(BQ(rotation));
- }
- // Define the end transform.
- btTransform end(start);
- end.setOrigin(BV(endPosition));
- // Perform bullet convex sweep test.
- SweepTestCallback callback(object, filter);
- // If the object is represented by a ghost object, use the ghost object's convex sweep test
- // since it is much faster than the world's version.
- // NOTE: Unfortunately the ghost object sweep test does not seem reliable here currently, so using world's version instead.
- /*switch (object->getType())
- {
- case PhysicsCollisionObject::GHOST_OBJECT:
- case PhysicsCollisionObject::CHARACTER:
- static_cast<PhysicsGhostObject*>(object)->_ghostObject->convexSweepTest(static_cast<btConvexShape*>(shape->getShape()), start, end, callback, _world->getDispatchInfo().m_allowedCcdPenetration);
- break;
- default:
- _world->convexSweepTest(static_cast<btConvexShape*>(shape->getShape()), start, end, callback, _world->getDispatchInfo().m_allowedCcdPenetration);
- break;
- }*/
- GP_ASSERT(_world);
- _world->convexSweepTest(static_cast<btConvexShape*>(shape->getShape()), start, end, callback, _world->getDispatchInfo().m_allowedCcdPenetration);
- // Check for hits and store results.
- if (callback.hasHit())
- {
- if (result)
- {
- result->object = getCollisionObject(callback.m_hitCollisionObject);
- result->point.set(callback.m_hitPointWorld.x(), callback.m_hitPointWorld.y(), callback.m_hitPointWorld.z());
- result->fraction = callback.m_closestHitFraction;
- result->normal.set(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
- }
- return true;
- }
- return false;
- }
- btScalar PhysicsController::CollisionCallback::addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA,
- const btCollisionObject* b, int partIdB, int indexB)
- {
- GP_ASSERT(_pc);
- // Get pointers to the PhysicsCollisionObject objects.
- PhysicsCollisionObject* objectA = _pc->getCollisionObject(a);
- PhysicsCollisionObject* objectB = _pc->getCollisionObject(b);
- // If the given collision object pair has collided in the past, then
- // we notify the listeners only if the pair was not colliding
- // during the previous frame. Otherwise, it's a new pair, so add a
- // new entry to the cache with the appropriate listeners and notify them.
- PhysicsCollisionObject::CollisionPair pair(objectA, objectB);
- CollisionInfo* collisionInfo;
- if (_pc->_collisionStatus.count(pair) > 0)
- {
- collisionInfo = &_pc->_collisionStatus[pair];
- }
- else
- {
- // Add a new collision pair for these objects.
- collisionInfo = &_pc->_collisionStatus[pair];
- // Add the appropriate listeners.
- PhysicsCollisionObject::CollisionPair p1(pair.objectA, NULL);
- if (_pc->_collisionStatus.count(p1) > 0)
- {
- const CollisionInfo& ci = _pc->_collisionStatus[p1];
- std::vector<PhysicsCollisionObject::CollisionListener*>::const_iterator iter = ci._listeners.begin();
- for (; iter != ci._listeners.end(); iter++)
- {
- GP_ASSERT(*iter);
- collisionInfo->_listeners.push_back(*iter);
- }
- }
- PhysicsCollisionObject::CollisionPair p2(pair.objectB, NULL);
- if (_pc->_collisionStatus.count(p2) > 0)
- {
- const CollisionInfo& ci = _pc->_collisionStatus[p2];
- std::vector<PhysicsCollisionObject::CollisionListener*>::const_iterator iter = ci._listeners.begin();
- for (; iter != ci._listeners.end(); iter++)
- {
- GP_ASSERT(*iter);
- collisionInfo->_listeners.push_back(*iter);
- }
- }
- }
- // Fire collision event.
- if ((collisionInfo->_status & COLLISION) == 0)
- {
- std::vector<PhysicsCollisionObject::CollisionListener*>::const_iterator iter = collisionInfo->_listeners.begin();
- for (; iter != collisionInfo->_listeners.end(); iter++)
- {
- GP_ASSERT(*iter);
- if ((collisionInfo->_status & REMOVE) == 0)
- {
- (*iter)->collisionEvent(PhysicsCollisionObject::CollisionListener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
- Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
- }
- }
- }
- // Update the collision status cache (we remove the dirty bit
- // set in the controller's update so that this particular collision pair's
- // status is not reset to 'no collision' when the controller's update completes).
- collisionInfo->_status &= ~DIRTY;
- collisionInfo->_status |= COLLISION;
- return 0.0f;
- }
- void PhysicsController::initialize()
- {
- _collisionConfiguration = new btDefaultCollisionConfiguration();
- _dispatcher = new btCollisionDispatcher(_collisionConfiguration);
- _overlappingPairCache = new btDbvtBroadphase();
- _solver = new btSequentialImpulseConstraintSolver();
- // Create the world.
- _world = new btDiscreteDynamicsWorld(_dispatcher, _overlappingPairCache, _solver, _collisionConfiguration);
- _world->setGravity(BV(_gravity));
- // Register ghost pair callback so bullet detects collisions with ghost objects (used for character collisions).
- GP_ASSERT(_world->getPairCache());
- _ghostPairCallback = bullet_new<btGhostPairCallback>();
- _world->getPairCache()->setInternalGhostPairCallback(_ghostPairCallback);
- _world->getDispatchInfo().m_allowedCcdPenetration = 0.0001f;
- // Set up debug drawing.
- _debugDrawer = new DebugDrawer();
- _world->setDebugDrawer(_debugDrawer);
- }
- void PhysicsController::finalize()
- {
- // Clean up the world and its various components.
- SAFE_DELETE(_world);
- SAFE_DELETE(_ghostPairCallback);
- SAFE_DELETE(_solver);
- SAFE_DELETE(_overlappingPairCache);
- SAFE_DELETE(_dispatcher);
- SAFE_DELETE(_collisionConfiguration);
- }
- void PhysicsController::pause()
- {
- // Unused
- }
- void PhysicsController::resume()
- {
- // Unused
- }
- void PhysicsController::update(float elapsedTime)
- {
- GP_ASSERT(_world);
- // Update the physics simulation, with a maximum
- // of 10 simulation steps being performed in a given frame.
- //
- // Note that stepSimulation takes elapsed time in seconds
- // so we divide by 1000 to convert from milliseconds.
- _world->stepSimulation(elapsedTime * 0.001f, 10);
- // If we have status listeners, then check if our status has changed.
- if (_listeners)
- {
- Listener::EventType oldStatus = _status;
- if (_status == Listener::DEACTIVATED)
- {
- for (int i = 0; i < _world->getNumCollisionObjects(); i++)
- {
- GP_ASSERT(_world->getCollisionObjectArray()[i]);
- if (_world->getCollisionObjectArray()[i]->isActive())
- {
- _status = Listener::ACTIVATED;
- break;
- }
- }
- }
- else
- {
- bool allInactive = true;
- for (int i = 0; i < _world->getNumCollisionObjects(); i++)
- {
- GP_ASSERT(_world->getCollisionObjectArray()[i]);
- if (_world->getCollisionObjectArray()[i]->isActive())
- {
- allInactive = false;
- break;
- }
- }
- if (allInactive)
- _status = Listener::DEACTIVATED;
- }
- // If the status has changed, notify our listeners.
- if (oldStatus != _status)
- {
- for (unsigned int k = 0; k < _listeners->size(); k++)
- {
- GP_ASSERT((*_listeners)[k]);
- (*_listeners)[k]->statusEvent(_status);
- }
- }
- }
- // All statuses are set with the DIRTY bit before collision processing occurs.
- // During collision processing, if a collision occurs, the status is
- // set to COLLISION and the DIRTY bit is cleared. Then, after collision processing
- // is finished, if a given status is still dirty, the COLLISION bit is cleared.
- //
- // If an entry was marked for removal in the last frame, remove it now.
- // Dirty the collision status cache entries.
- std::map<PhysicsCollisionObject::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
- for (; iter != _collisionStatus.end();)
- {
- if ((iter->second._status & REMOVE) != 0)
- {
- std::map<PhysicsCollisionObject::CollisionPair, CollisionInfo>::iterator eraseIter = iter;
- iter++;
- _collisionStatus.erase(eraseIter);
- }
- else
- {
- iter->second._status |= DIRTY;
- iter++;
- }
- }
- // Go through the collision status cache and perform all registered collision tests.
- iter = _collisionStatus.begin();
- for (; iter != _collisionStatus.end(); iter++)
- {
- // If this collision pair was one that was registered for listening, then perform the collision test.
- // (In the case where we register for all collisions with a rigid body, there will be a lot
- // of collision pairs in the status cache that we did not explicitly register for.)
- if ((iter->second._status & REGISTERED) != 0 && (iter->second._status & REMOVE) == 0)
- {
- if (iter->first.objectB)
- _world->contactPairTest(iter->first.objectA->getCollisionObject(), iter->first.objectB->getCollisionObject(), *_collisionCallback);
- else
- _world->contactTest(iter->first.objectA->getCollisionObject(), *_collisionCallback);
- }
- }
- // Update all the collision status cache entries.
- iter = _collisionStatus.begin();
- for (; iter != _collisionStatus.end(); iter++)
- {
- if ((iter->second._status & DIRTY) != 0)
- {
- if ((iter->second._status & COLLISION) != 0 && iter->first.objectB)
- {
- unsigned int size = iter->second._listeners.size();
- for (unsigned int i = 0; i < size; i++)
- {
- iter->second._listeners[i]->collisionEvent(PhysicsCollisionObject::CollisionListener::NOT_COLLIDING, iter->first);
- }
- }
- iter->second._status &= ~COLLISION;
- }
- }
- }
- void PhysicsController::addCollisionListener(PhysicsCollisionObject::CollisionListener* listener, PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
- {
- GP_ASSERT(listener);
-
- // One of the collision objects in the pair must be non-null.
- GP_ASSERT(objectA || objectB);
- PhysicsCollisionObject::CollisionPair pair(objectA, objectB);
- // Add the listener and ensure the status includes that this collision pair is registered.
- CollisionInfo& info = _collisionStatus[pair];
- info._listeners.push_back(listener);
- info._status |= PhysicsController::REGISTERED;
- }
- void PhysicsController::removeCollisionListener(PhysicsCollisionObject::CollisionListener* listener, PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
- {
- // One of the collision objects in the pair must be non-null.
- GP_ASSERT(objectA || objectB);
- PhysicsCollisionObject::CollisionPair pair(objectA, objectB);
- // Mark the collision pair for these objects for removal.
- if (_collisionStatus.count(pair) > 0)
- {
- _collisionStatus[pair]._status |= REMOVE;
- }
- }
- void PhysicsController::addCollisionObject(PhysicsCollisionObject* object)
- {
- GP_ASSERT(object && object->getCollisionObject());
- GP_ASSERT(_world);
- // Assign user pointer for the bullet collision object to allow efficient
- // lookups of bullet objects -> gameplay objects.
- object->getCollisionObject()->setUserPointer(object);
- // Add the object to the physics world.
- switch (object->getType())
- {
- case PhysicsCollisionObject::RIGID_BODY:
- _world->addRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
- break;
- case PhysicsCollisionObject::CHARACTER:
- _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
- break;
- case PhysicsCollisionObject::GHOST_OBJECT:
- _world->addCollisionObject(object->getCollisionObject(), btBroadphaseProxy::DefaultFilter, btBroadphaseProxy::DefaultFilter | btBroadphaseProxy::StaticFilter | btBroadphaseProxy::CharacterFilter | btBroadphaseProxy::AllFilter);
- break;
- default:
- GP_ERROR("Unsupported collision object type (%d).", object->getType());
- break;
- }
- }
- void PhysicsController::removeCollisionObject(PhysicsCollisionObject* object)
- {
- GP_ASSERT(object);
- GP_ASSERT(_world);
- // Remove the collision object from the world.
- if (object->getCollisionObject())
- {
- switch (object->getType())
- {
- case PhysicsCollisionObject::RIGID_BODY:
- _world->removeRigidBody(static_cast<btRigidBody*>(object->getCollisionObject()));
- break;
- case PhysicsCollisionObject::CHARACTER:
- case PhysicsCollisionObject::GHOST_OBJECT:
- _world->removeCollisionObject(object->getCollisionObject());
- break;
- default:
- GP_ERROR("Unsupported collision object type (%d).", object->getType());
- break;
- }
- }
- // Find all references to the object in the collision status cache and mark them for removal.
- std::map<PhysicsCollisionObject::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
- for (; iter != _collisionStatus.end(); iter++)
- {
- if (iter->first.objectA == object || iter->first.objectB == object)
- iter->second._status |= REMOVE;
- }
- }
- PhysicsCollisionObject* PhysicsController::getCollisionObject(const btCollisionObject* collisionObject) const
- {
- // Gameplay collision objects are stored in the userPointer data of Bullet collision objects.
- GP_ASSERT(collisionObject);
- return reinterpret_cast<PhysicsCollisionObject*>(collisionObject->getUserPointer());
- }
- static void getBoundingBox(Node* node, BoundingBox* out, bool merge = false)
- {
- GP_ASSERT(node);
- GP_ASSERT(out);
- if (node->getModel())
- {
- GP_ASSERT(node->getModel()->getMesh());
- if (merge)
- out->merge(node->getModel()->getMesh()->getBoundingBox());
- else
- {
- out->set(node->getModel()->getMesh()->getBoundingBox());
- merge = true;
- }
- }
- Node* child = node->getFirstChild();
- while (child)
- {
- getBoundingBox(child, out, merge);
- child = child->getNextSibling();
- }
- }
- static void getBoundingSphere(Node* node, BoundingSphere* out, bool merge = false)
- {
- GP_ASSERT(node);
- GP_ASSERT(out);
- if (node->getModel())
- {
- GP_ASSERT(node->getModel()->getMesh());
- if (merge)
- out->merge(node->getModel()->getMesh()->getBoundingSphere());
- else
- {
- out->set(node->getModel()->getMesh()->getBoundingSphere());
- merge = true;
- }
- }
- Node* child = node->getFirstChild();
- while (child)
- {
- getBoundingSphere(child, out, merge);
- child = child->getNextSibling();
- }
- }
- static void computeCenterOfMass(const Vector3& center, const Vector3& scale, Vector3* centerOfMassOffset)
- {
- GP_ASSERT(centerOfMassOffset);
- // Update center of mass offset.
- *centerOfMassOffset = center;
- centerOfMassOffset->x *= scale.x;
- centerOfMassOffset->y *= scale.y;
- centerOfMassOffset->z *= scale.z;
- centerOfMassOffset->negate();
- }
- PhysicsCollisionShape* PhysicsController::createShape(Node* node, const PhysicsCollisionShape::Definition& shape, Vector3* centerOfMassOffset)
- {
- GP_ASSERT(node);
- PhysicsCollisionShape* collisionShape = NULL;
- // Get the node's world scale (we need to apply this during creation since rigid bodies don't scale dynamically).
- Vector3 scale;
- node->getWorldMatrix().getScale(&scale);
- switch (shape.type)
- {
- case PhysicsCollisionShape::SHAPE_BOX:
- {
- if (shape.isExplicit)
- {
- // Use the passed in box information.
- collisionShape = createBox(Vector3(shape.data.box.extents), Vector3::one());
- if (shape.centerAbsolute)
- {
- computeCenterOfMass(Vector3(shape.data.box.center), Vector3::one(), centerOfMassOffset);
- }
- else
- {
- BoundingBox box;
- getBoundingBox(node, &box);
- computeCenterOfMass(box.getCenter() + Vector3(shape.data.box.center), scale, centerOfMassOffset);
- }
- }
- else
- {
- // Automatically compute bounding box from mesh's bounding box.
- BoundingBox box;
- getBoundingBox(node, &box);
- collisionShape = createBox(Vector3(std::fabs(box.max.x - box.min.x), std::fabs(box.max.y - box.min.y), std::fabs(box.max.z - box.min.z)), scale);
- computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
- }
- }
- break;
- case PhysicsCollisionShape::SHAPE_SPHERE:
- {
- if (shape.isExplicit)
- {
- // Use the passed in sphere information.
- collisionShape = createSphere(shape.data.sphere.radius, Vector3::one());
- if (shape.centerAbsolute)
- {
- computeCenterOfMass(Vector3(shape.data.sphere.center), Vector3::one(), centerOfMassOffset);
- }
- else
- {
- BoundingSphere sphere;
- getBoundingSphere(node, &sphere);
- computeCenterOfMass(sphere.center + Vector3(shape.data.sphere.center), scale, centerOfMassOffset);
- }
- }
- else
- {
- // Automatically compute bounding sphere from mesh's bounding sphere.
- BoundingSphere sphere;
- getBoundingSphere(node, &sphere);
- collisionShape = createSphere(sphere.radius, scale);
- computeCenterOfMass(sphere.center, scale, centerOfMassOffset);
- }
- }
- break;
- case PhysicsCollisionShape::SHAPE_CAPSULE:
- {
- if (shape.isExplicit)
- {
- // Use the passed in capsule information.
- collisionShape = createCapsule(shape.data.capsule.radius, shape.data.capsule.height, Vector3::one());
- if (shape.centerAbsolute)
- {
- computeCenterOfMass(Vector3(shape.data.capsule.center), Vector3::one(), centerOfMassOffset);
- }
- else
- {
- BoundingBox box;
- getBoundingBox(node, &box);
- computeCenterOfMass(box.getCenter() + Vector3(shape.data.capsule.center), scale, centerOfMassOffset);
- }
- }
- else
- {
- // Compute a capsule shape that roughly matches the bounding box of the mesh.
- BoundingBox box;
- getBoundingBox(node, &box);
- float radius = std::max((box.max.x - box.min.x) * 0.5f, (box.max.z - box.min.z) * 0.5f);
- float height = box.max.y - box.min.y;
- collisionShape = createCapsule(radius, height, scale);
- computeCenterOfMass(box.getCenter(), scale, centerOfMassOffset);
- }
- }
- break;
- case PhysicsCollisionShape::SHAPE_HEIGHTFIELD:
- {
- // Build heightfield rigid body from the passed in shape.
- collisionShape = createHeightfield(node, shape.data.heightfield, centerOfMassOffset);
- }
- break;
- case PhysicsCollisionShape::SHAPE_MESH:
- {
- // Build mesh from passed in shape.
- collisionShape = createMesh(shape.data.mesh, scale);
- }
- break;
- default:
- GP_ERROR("Unsupported collision shape type (%d).", shape.type);
- break;
- }
- return collisionShape;
- }
- PhysicsCollisionShape* PhysicsController::createBox(const Vector3& extents, const Vector3& scale)
- {
- btVector3 halfExtents(scale.x * 0.5 * extents.x, scale.y * 0.5 * extents.y, scale.z * 0.5 * extents.z);
- PhysicsCollisionShape* shape;
- // Return the box shape from the cache if it already exists.
- for (unsigned int i = 0; i < _shapes.size(); ++i)
- {
- shape = _shapes[i];
- GP_ASSERT(shape);
- if (shape->getType() == PhysicsCollisionShape::SHAPE_BOX)
- {
- btBoxShape* box = static_cast<btBoxShape*>(shape->_shape);
- if (box && box->getHalfExtentsWithMargin() == halfExtents)
- {
- shape->addRef();
- return shape;
- }
- }
- }
- // Create the box shape and add it to the cache.
- shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_BOX, bullet_new<btBoxShape>(halfExtents));
- _shapes.push_back(shape);
- return shape;
- }
- PhysicsCollisionShape* PhysicsController::createSphere(float radius, const Vector3& scale)
- {
- // Since sphere shapes depend only on the radius, the best we can do is take
- // the largest dimension and apply that as the uniform scale to the rigid body.
- float uniformScale = scale.x;
- if (uniformScale < scale.y)
- uniformScale = scale.y;
- if (uniformScale < scale.z)
- uniformScale = scale.z;
- float scaledRadius = radius * uniformScale;
- PhysicsCollisionShape* shape;
- // Return the sphere shape from the cache if it already exists.
- for (unsigned int i = 0; i < _shapes.size(); ++i)
- {
- shape = _shapes[i];
- GP_ASSERT(shape);
- if (shape->getType() == PhysicsCollisionShape::SHAPE_SPHERE)
- {
- btSphereShape* sphere = static_cast<btSphereShape*>(shape->_shape);
- if (sphere && sphere->getRadius() == scaledRadius)
- {
- shape->addRef();
- return shape;
- }
- }
- }
- // Create the sphere shape and add it to the cache.
- shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_SPHERE, bullet_new<btSphereShape>(scaledRadius));
- _shapes.push_back(shape);
- return shape;
- }
- PhysicsCollisionShape* PhysicsController::createCapsule(float radius, float height, const Vector3& scale)
- {
- float girthScale = scale.x;
- if (girthScale < scale.z)
- girthScale = scale.z;
- float scaledRadius = radius * girthScale;
- float scaledHeight = height * scale.y - radius * 2;
- PhysicsCollisionShape* shape;
- // Return the capsule shape from the cache if it already exists.
- for (unsigned int i = 0; i < _shapes.size(); i++)
- {
- shape = _shapes[i];
- GP_ASSERT(shape);
- if (shape->getType() == PhysicsCollisionShape::SHAPE_CAPSULE)
- {
- btCapsuleShape* capsule = static_cast<btCapsuleShape*>(shape->_shape);
- if (capsule && capsule->getRadius() == scaledRadius && capsule->getHalfHeight() == 0.5f * scaledHeight)
- {
- shape->addRef();
- return shape;
- }
- }
- }
- // Create the capsule shape and add it to the cache.
- shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_CAPSULE, bullet_new<btCapsuleShape>(scaledRadius, scaledHeight));
- _shapes.push_back(shape);
- return shape;
- }
- PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* image, Vector3* centerOfMassOffset)
- {
- GP_ASSERT(node);
- GP_ASSERT(image);
- GP_ASSERT(centerOfMassOffset);
- // Get the dimensions of the heightfield.
- // If the node has a mesh defined, use the dimensions of the bounding box for the mesh.
- // Otherwise simply use the image dimensions (with a max height of 255).
- float width, length, minHeight, maxHeight;
- if (node->getModel() && node->getModel()->getMesh())
- {
- const BoundingBox& box = node->getModel()->getMesh()->getBoundingBox();
- width = box.max.x - box.min.x;
- length = box.max.z - box.min.z;
- minHeight = box.min.y;
- maxHeight = box.max.y;
- }
- else
- {
- width = image->getWidth();
- length = image->getHeight();
- minHeight = 0.0f;
- maxHeight = 255.0f;
- }
- // Get the size in bytes of a pixel (we ensure that the image's
- // pixel format is actually supported before calling this constructor).
- unsigned int pixelSize = 0;
- switch (image->getFormat())
- {
- case Image::RGB:
- pixelSize = 3;
- break;
- case Image::RGBA:
- pixelSize = 4;
- break;
- default:
- GP_ERROR("Unsupported pixel format for heightmap image (%d).", image->getFormat());
- return NULL;
- }
- // Calculate the heights for each pixel.
- float* heights = new float[image->getWidth() * image->getHeight()];
- unsigned char* data = image->getData();
- for (unsigned int x = 0, w = image->getWidth(); x < w; ++x)
- {
- for (unsigned int y = 0, h = image->getHeight(); y < h; ++y)
- {
- heights[x + y * w] = ((((float)data[(x + y * h) * pixelSize + 0]) +
- ((float)data[(x + y * h) * pixelSize + 1]) +
- ((float)data[(x + y * h) * pixelSize + 2])) / 768.0f) * (maxHeight - minHeight) + minHeight;
- }
- }
- PhysicsCollisionShape::HeightfieldData* heightfieldData = new PhysicsCollisionShape::HeightfieldData();
- heightfieldData->heightData = NULL;
- heightfieldData->normalData = NULL;
- heightfieldData->inverseIsDirty = true;
- unsigned int sizeWidth = width;
- unsigned int sizeHeight = length;
- GP_ASSERT(sizeWidth);
- GP_ASSERT(sizeHeight);
-
- // Generate the heightmap data needed for physics (one height per world unit).
- heightfieldData->width = sizeWidth + 1;
- heightfieldData->height = sizeHeight + 1;
- heightfieldData->heightData = new float[heightfieldData->width * heightfieldData->height];
- heightfieldData->normalData = new Vector3[heightfieldData->width * heightfieldData->height];
- unsigned int heightIndex = 0, prevRowIndex = 0, prevColIndex = 0;
- float widthImageFactor = (float)(image->getWidth() - 1) / sizeWidth;
- float heightImageFactor = (float)(image->getHeight() - 1) / sizeHeight;
- float x = 0.0f;
- float z = 0.0f;
- const float horizStepsize = 1.0f;
- for (unsigned int row = 0, z = 0.0f; row <= sizeHeight; row++, z += horizStepsize)
- {
- for (unsigned int col = 0, x = 0.0f; col <= sizeWidth; col++, x += horizStepsize)
- {
- heightIndex = row * heightfieldData->width + col;
- prevRowIndex = heightIndex - heightfieldData->width; // ignored if row<1
- prevColIndex = heightIndex - 1; // ignored if col<1
- heightfieldData->heightData[heightIndex] = calculateHeight(heights, image->getWidth(), image->getHeight(), x * widthImageFactor, (sizeHeight - z) * heightImageFactor);
- //
- // Normal calculation based on height data using a backward difference.
- //
- if (row == 0 || col == 0)
- {
- // This is just a safe default value.
- heightfieldData->normalData[heightIndex].set(Vector3::unitY());
- }
- else
- {
- heightfieldData->normalData[heightIndex].set(
- heightfieldData->heightData[prevColIndex] - heightfieldData->heightData[heightIndex],
- horizStepsize,
- heightfieldData->heightData[prevRowIndex] - heightfieldData->heightData[heightIndex]);
- heightfieldData->normalData[heightIndex].normalize();
- }
- // For the starting row, just copy from the second row (i.e., a forward difference).
- if (row == 1)
- {
- heightfieldData->normalData[prevRowIndex].set(heightfieldData->normalData[heightIndex]);
- }
- // For the starting column, just copy from the second column (i.e., a forward difference).
- // (We don't care which of the 2 valid sources heightfieldData->normalData[0] ultimately comes from).
- if (col == 1)
- {
- heightfieldData->normalData[prevColIndex].set(heightfieldData->normalData[heightIndex]);
- }
- }
- }
- SAFE_DELETE_ARRAY(heights);
- // Offset the heightmap's center of mass according to the way that Bullet calculates the origin
- // of its heightfield collision shape; see documentation for the btHeightfieldTerrainShape for more info.
- Vector3 s;
- node->getWorldMatrix().getScale(&s);
- GP_ASSERT(s.y);
- centerOfMassOffset->set(0.0f, -(maxHeight - (0.5f * (maxHeight - minHeight))) / s.y, 0.0f);
- // Create the bullet terrain shape.
- btHeightfieldTerrainShape* terrainShape = bullet_new<btHeightfieldTerrainShape>(
- heightfieldData->width, heightfieldData->height, heightfieldData->heightData, 1.0f, minHeight, maxHeight, 1, PHY_FLOAT, false);
- // Create our collision shape object and store heightfieldData in it.
- PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_HEIGHTFIELD, terrainShape);
- shape->_shapeData.heightfieldData = heightfieldData;
- _shapes.push_back(shape);
- return shape;
- }
- PhysicsCollisionShape* PhysicsController::createMesh(Mesh* mesh, const Vector3& scale)
- {
- GP_ASSERT(mesh);
- // Only support meshes with triangle list primitive types.
- bool triMesh = true;
- if (mesh->getPartCount() > 0)
- {
- for (unsigned int i = 0; i < mesh->getPartCount(); ++i)
- {
- if (mesh->getPart(i)->getPrimitiveType() != Mesh::TRIANGLES)
- {
- triMesh = false;
- break;
- }
- }
- }
- else
- {
- triMesh = mesh->getPrimitiveType() == Mesh::TRIANGLES;
- }
- if (!triMesh)
- {
- GP_ERROR("Mesh rigid bodies are currently only supported on meshes with TRIANGLES primitive type.");
- return NULL;
- }
- // The mesh must have a valid URL (i.e. it must have been loaded from a Bundle)
- // in order to fetch mesh data for computing mesh rigid body.
- if (strlen(mesh->getUrl()) == 0)
- {
- GP_ERROR("Cannot create mesh rigid body for mesh without valid URL.");
- return NULL;
- }
- Bundle::MeshData* data = Bundle::readMeshData(mesh->getUrl());
- if (data == NULL)
- {
- GP_ERROR("Failed to load mesh data from url '%s'.", mesh->getUrl());
- return NULL;
- }
- // Create mesh data to be populated and store in returned collision shape.
- PhysicsCollisionShape::MeshData* shapeMeshData = new PhysicsCollisionShape::MeshData();
- shapeMeshData->vertexData = NULL;
- // Copy the scaled vertex position data to the rigid body's local buffer.
- Matrix m;
- Matrix::createScale(scale, &m);
- unsigned int vertexCount = data->vertexCount;
- shapeMeshData->vertexData = new float[vertexCount * 3];
- Vector3 v;
- int vertexStride = data->vertexFormat.getVertexSize();
- for (unsigned int i = 0; i < data->vertexCount; i++)
- {
- v.set(*((float*)&data->vertexData[i * vertexStride + 0 * sizeof(float)]),
- *((float*)&data->vertexData[i * vertexStride + 1 * sizeof(float)]),
- *((float*)&data->vertexData[i * vertexStride + 2 * sizeof(float)]));
- v *= m;
- memcpy(&(shapeMeshData->vertexData[i * 3]), &v, sizeof(float) * 3);
- }
- btTriangleIndexVertexArray* meshInterface = bullet_new<btTriangleIndexVertexArray>();
- unsigned int partCount = data->parts.size();
- if (partCount > 0)
- {
- PHY_ScalarType indexType = PHY_UCHAR;
- int indexStride = 0;
- Bundle::MeshPartData* meshPart = NULL;
- for (unsigned int i = 0; i < partCount; i++)
- {
- meshPart = data->parts[i];
- GP_ASSERT(meshPart);
- switch (meshPart->indexFormat)
- {
- case Mesh::INDEX8:
- indexType = PHY_UCHAR;
- indexStride = 1;
- break;
- case Mesh::INDEX16:
- indexType = PHY_SHORT;
- indexStride = 2;
- break;
- case Mesh::INDEX32:
- indexType = PHY_INTEGER;
- indexStride = 4;
- break;
- default:
- GP_ERROR("Unsupported index format (%d).", meshPart->indexFormat);
- SAFE_DELETE(meshInterface);
- SAFE_DELETE_ARRAY(shapeMeshData->vertexData);
- SAFE_DELETE(shapeMeshData);
- SAFE_DELETE(data);
- return NULL;
- }
- // Move the index data into the rigid body's local buffer.
- // Set it to NULL in the MeshPartData so it is not released when the data is freed.
- shapeMeshData->indexData.push_back(meshPart->indexData);
- meshPart->indexData = NULL;
- // Create a btIndexedMesh object for the current mesh part.
- btIndexedMesh indexedMesh;
- indexedMesh.m_indexType = indexType;
- indexedMesh.m_numTriangles = meshPart->indexCount / 3; // assume TRIANGLES primitive type
- indexedMesh.m_numVertices = meshPart->indexCount;
- indexedMesh.m_triangleIndexBase = (const unsigned char*)shapeMeshData->indexData[i];
- indexedMesh.m_triangleIndexStride = indexStride*3;
- indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
- indexedMesh.m_vertexStride = sizeof(float)*3;
- indexedMesh.m_vertexType = PHY_FLOAT;
- // Add the indexed mesh data to the mesh interface.
- meshInterface->addIndexedMesh(indexedMesh, indexType);
- }
- }
- else
- {
- // Generate index data for the mesh locally in the rigid body.
- unsigned int* indexData = new unsigned int[data->vertexCount];
- for (unsigned int i = 0; i < data->vertexCount; i++)
- {
- indexData[i] = i;
- }
- shapeMeshData->indexData.push_back((unsigned char*)indexData);
- // Create a single btIndexedMesh object for the mesh interface.
- btIndexedMesh indexedMesh;
- indexedMesh.m_indexType = PHY_INTEGER;
- indexedMesh.m_numTriangles = data->vertexCount / 3; // assume TRIANGLES primitive type
- indexedMesh.m_numVertices = data->vertexCount;
- indexedMesh.m_triangleIndexBase = shapeMeshData->indexData[0];
- indexedMesh.m_triangleIndexStride = sizeof(unsigned int);
- indexedMesh.m_vertexBase = (const unsigned char*)shapeMeshData->vertexData;
- indexedMesh.m_vertexStride = sizeof(float)*3;
- indexedMesh.m_vertexType = PHY_FLOAT;
- // Set the data in the mesh interface.
- meshInterface->addIndexedMesh(indexedMesh, indexedMesh.m_indexType);
- }
- // Create our collision shape object and store shapeMeshData in it.
- PhysicsCollisionShape* shape = new PhysicsCollisionShape(PhysicsCollisionShape::SHAPE_MESH, bullet_new<btBvhTriangleMeshShape>(meshInterface, true));
- shape->_shapeData.meshData = shapeMeshData;
- _shapes.push_back(shape);
- // Free the temporary mesh data now that it's stored in physics system.
- SAFE_DELETE(data);
- return shape;
- }
- void PhysicsController::destroyShape(PhysicsCollisionShape* shape)
- {
- if (shape)
- {
- if (shape->getRefCount() == 1)
- {
- // Remove shape from shape cache.
- std::vector<PhysicsCollisionShape*>::iterator shapeItr = std::find(_shapes.begin(), _shapes.end(), shape);
- if (shapeItr != _shapes.end())
- _shapes.erase(shapeItr);
- }
- // Release the shape.
- shape->release();
- }
- }
- float PhysicsController::calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y,
- const Matrix* worldMatrix, Vector3* normalData, Vector3* normalResult)
- {
- GP_ASSERT(data);
- unsigned int x1 = x;
- unsigned int y1 = y;
- unsigned int x2 = x1 + 1;
- unsigned int y2 = y1 + 1;
- float tmp;
- float xFactor = x2 >= width ? 0.0f : modf(x, &tmp);
- float yFactor = y2 >= height ? 0.0f : modf(y, &tmp);
- float xFactorI = 1.0f - xFactor;
- float yFactorI = 1.0f - yFactor;
- float a = xFactorI * yFactorI;
- float b = xFactorI * yFactor;
- float c = xFactor * yFactor;
- float d = xFactor * yFactorI;
- if (normalResult)
- {
- normalResult->set(normalData[x1 + y1 * width] * a + normalData[x1 + y2 * width] * b +
- normalData[x2 + y2 * width] * c + normalData[x2 + y1 * width] * d);
- normalResult->normalize();
- worldMatrix->transformVector(normalResult);
- }
- return data[x1 + y1 * width] * a + data[x1 + y2 * width] * b +
- data[x2 + y2 * width] * c + data[x2 + y1 * width] * d;
- }
- void PhysicsController::addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
- {
- GP_ASSERT(a);
- GP_ASSERT(constraint);
- GP_ASSERT(_world);
- a->addConstraint(constraint);
- if (b)
- {
- b->addConstraint(constraint);
- }
-
- _world->addConstraint(constraint->_constraint);
- }
- bool PhysicsController::checkConstraintRigidBodies(PhysicsRigidBody* a, PhysicsRigidBody* b)
- {
- GP_ASSERT(a);
- if (!a->supportsConstraints())
- {
- GP_ASSERT(a->_node);
- GP_ERROR("Rigid body '%s' does not support constraints; unexpected behavior may occur.", a->_node->getId());
- return false;
- }
-
- if (b && !b->supportsConstraints())
- {
- GP_ASSERT(b->_node);
- GP_ERROR("Rigid body '%s' does not support constraints; unexpected behavior may occur.", b->_node->getId());
- return false;
- }
- return true;
- }
- void PhysicsController::removeConstraint(PhysicsConstraint* constraint)
- {
- GP_ASSERT(constraint);
- GP_ASSERT(_world);
- // Find the constraint and remove it from the physics world.
- for (int i = _world->getNumConstraints() - 1; i >= 0; i--)
- {
- btTypedConstraint* currentConstraint = _world->getConstraint(i);
- if (constraint->_constraint == currentConstraint)
- {
- _world->removeConstraint(currentConstraint);
- break;
- }
- }
- }
- PhysicsController::DebugDrawer::DebugDrawer()
- : _mode(btIDebugDraw::DBG_DrawAabb | btIDebugDraw::DBG_DrawConstraintLimits | btIDebugDraw::DBG_DrawConstraints |
- btIDebugDraw::DBG_DrawContactPoints | btIDebugDraw::DBG_DrawWireframe), _viewProjection(NULL), _meshBatch(NULL)
- {
- // Vertex shader for drawing colored lines.
- const char* vs_str =
- {
- "uniform mat4 u_viewProjectionMatrix;\n"
- "attribute vec4 a_position;\n"
- "attribute vec4 a_color;\n"
- "varying vec4 v_color;\n"
- "void main(void) {\n"
- " v_color = a_color;\n"
- " gl_Position = u_viewProjectionMatrix * a_position;\n"
- "}"
- };
- // Fragment shader for drawing colored lines.
- const char* fs_str =
- {
- #ifdef OPENGL_ES
- "precision highp float;\n"
- #endif
- "varying vec4 v_color;\n"
- "void main(void) {\n"
- " gl_FragColor = v_color;\n"
- "}"
- };
- Effect* effect = Effect::createFromSource(vs_str, fs_str);
- Material* material = Material::create(effect);
- GP_ASSERT(material && material->getStateBlock());
- material->getStateBlock()->setDepthTest(true);
- VertexFormat::Element elements[] =
- {
- VertexFormat::Element(VertexFormat::POSITION, 3),
- VertexFormat::Element(VertexFormat::COLOR, 4),
- };
- _meshBatch = MeshBatch::create(VertexFormat(elements, 2), Mesh::LINES, material, false);
- SAFE_RELEASE(material);
- SAFE_RELEASE(effect);
- }
- PhysicsController::DebugDrawer::~DebugDrawer()
- {
- SAFE_DELETE(_meshBatch);
- }
- void PhysicsController::DebugDrawer::begin(const Matrix& viewProjection)
- {
- GP_ASSERT(_meshBatch);
- _viewProjection = &viewProjection;
- _meshBatch->begin();
- }
- void PhysicsController::DebugDrawer::end()
- {
- GP_ASSERT(_meshBatch && _meshBatch->getMaterial() && _meshBatch->getMaterial()->getParameter("u_viewProjectionMatrix"));
- _meshBatch->finish();
- _meshBatch->getMaterial()->getParameter("u_viewProjectionMatrix")->setValue(_viewProjection);
- _meshBatch->draw();
- }
- void PhysicsController::DebugDrawer::drawLine(const btVector3& from, const btVector3& to, const btVector3& fromColor, const btVector3& toColor)
- {
- GP_ASSERT(_meshBatch);
- static DebugDrawer::DebugVertex fromVertex, toVertex;
- fromVertex.x = from.getX();
- fromVertex.y = from.getY();
- fromVertex.z = from.getZ();
- fromVertex.r = fromColor.getX();
- fromVertex.g = fromColor.getY();
- fromVertex.b = fromColor.getZ();
- fromVertex.a = 1.0f;
- toVertex.x = to.getX();
- toVertex.y = to.getY();
- toVertex.z = to.getZ();
- toVertex.r = toColor.getX();
- toVertex.g = toColor.getY();
- toVertex.b = toColor.getZ();
- toVertex.a = 1.0f;
- _meshBatch->add(&fromVertex, 1);
- _meshBatch->add(&toVertex, 1);
- }
- void PhysicsController::DebugDrawer::drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
- {
- drawLine(from, to, color, color);
- }
- void PhysicsController::DebugDrawer::drawContactPoint(const btVector3& pointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color)
- {
- drawLine(pointOnB, pointOnB + normalOnB, color);
- }
- void PhysicsController::DebugDrawer::reportErrorWarning(const char* warningString)
- {
- GP_WARN(warningString);
- }
- void PhysicsController::DebugDrawer::draw3dText(const btVector3& location, const char* textString)
- {
- GP_WARN("Physics debug drawing: 3D text is not supported.");
- }
- void PhysicsController::DebugDrawer::setDebugMode(int mode)
- {
- _mode = mode;
- }
- int PhysicsController::DebugDrawer::getDebugMode() const
- {
- return _mode;
- }
- PhysicsController::Listener::~Listener()
- {
- GP_ASSERT(Game::getInstance()->getPhysicsController());
- Game::getInstance()->getPhysicsController()->removeStatusListener(this);
- }
- PhysicsController::HitFilter::HitFilter()
- {
- }
- PhysicsController::HitFilter::~HitFilter()
- {
- }
- bool PhysicsController::HitFilter::filter(PhysicsCollisionObject* object)
- {
- return false;
- }
- bool PhysicsController::HitFilter::hit(const PhysicsController::HitResult& result)
- {
- return true;
- }
- }
|