ege/ege/physics/Engine.cpp

136 lines
5.2 KiB
C++

/** @file
* @author Edouard DUPIN
* @copyright 2011, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include <ege/physics/Engine.h>
#include <ege/debug.h>
#include <gale/renderer/openGL/openGL.h>
#include <etk/math/Matrix4.h>
#include <BulletDynamics/Dynamics/btRigidBody.h>
#include <LinearMath/btDefaultMotionState.h>
#include <BulletDynamics/Dynamics/btDynamicsWorld.h>
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
#include <LinearMath/btIDebugDraw.h>
#include <btBulletCollisionCommon.h>
#include <BulletCollision/CollisionShapes/btConvexPolyhedron.h>
#include <BulletCollision/CollisionShapes/btShapeHull.h>
#include <LinearMath/btTransformUtil.h>
#include <LinearMath/btIDebugDraw.h>
#include <btBulletDynamicsCommon.h>
#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
#include <ege/elements/ElementPhysic.h>
// unique callback function :
extern ContactProcessedCallback gContactProcessedCallback;
// TODO : remove double collision call ...
static bool handleContactsProcess(btManifoldPoint& _point, btCollisionObject* _body0, btCollisionObject* _body1) {
ege::ElementPhysic* elem0 = static_cast<ege::ElementPhysic*>(_body0->getUserPointer());
ege::ElementPhysic* elem1 = static_cast<ege::ElementPhysic*>(_body1->getUserPointer());
if ( elem0 == nullptr
|| elem1 == nullptr) {
EGE_WARNING("callback of collision error");
return false;
}
EGE_VERBOSE("collision process between " << elem0->getUID() << " && " << elem1->getUID() << " pos=" << _point.getPositionWorldOnA() << " norm=" << _point.m_normalWorldOnB);
if (elem0->getCollisionDetectionStatus() == true) {
elem0->onCollisionDetected(elem1->sharedFromThis(), _point.getPositionWorldOnA(), -_point.m_normalWorldOnB);
}
if (elem1->getCollisionDetectionStatus() == true) {
elem1->onCollisionDetected(elem0->sharedFromThis(), _point.getPositionWorldOnA(), _point.m_normalWorldOnB);
}
return true;
}
ege::physics::Engine::Engine() {
setBulletConfig();
// set callback for collisions ...
gContactProcessedCallback = (ContactProcessedCallback)handleContactsProcess;
}
ege::physics::Engine::~Engine() {
/*
m_dynamicsWorld.release();
m_solver.release();
m_broadphase.release();
m_dispatcher.release();
m_collisionConfiguration.release();
*/
}
void ege::physics::Engine::setBulletConfig(ememory::SharedPtr<btDefaultCollisionConfiguration> _collisionConfiguration,
ememory::SharedPtr<btCollisionDispatcher> _dispatcher,
ememory::SharedPtr<btBroadphaseInterface> _broadphase,
ememory::SharedPtr<btConstraintSolver> _solver,
ememory::SharedPtr<btDynamicsWorld> _dynamicsWorld) {
if (_collisionConfiguration != nullptr) {
m_collisionConfiguration = _collisionConfiguration;
} else {
m_collisionConfiguration = ememory::makeShared<btDefaultCollisionConfiguration>();
}
///use the default collision dispatcher.
if (_dispatcher != nullptr) {
m_dispatcher = _dispatcher;
} else {
m_dispatcher = ememory::makeShared<btCollisionDispatcher>(m_collisionConfiguration.get());
}
if (_broadphase != nullptr) {
m_broadphase = _broadphase;
} else {
m_broadphase = ememory::makeShared<btDbvtBroadphase>();
}
///the default constraint solver.
if (_solver != nullptr) {
m_solver = _solver;
} else {
m_solver = ememory::makeShared<btSequentialImpulseConstraintSolver>();
}
if (_dynamicsWorld != nullptr) {
m_dynamicsWorld = _dynamicsWorld;
} else {
m_dynamicsWorld = ememory::makeShared<btDiscreteDynamicsWorld>(m_dispatcher.get(),m_broadphase.get(),m_solver.get(),m_collisionConfiguration.get());
// By default we set no gravity
m_dynamicsWorld->setGravity(btVector3(0,0,0));
}
//m_env.setDynamicWorld(m_dynamicsWorld);
}
// some doccumantation : http://www.bulletphysics.org/mediawiki-1.5.8/index.php?title=Collision_Callbacks_and_Triggers
std::vector<ege::physics::Engine::collisionPoints> ege::physics::Engine::getListOfCollision() {
std::vector<collisionPoints> out;
if (m_dynamicsWorld != nullptr) {
int32_t numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds();
for (int i=0;i<numManifolds;i++) {
btPersistentManifold* contactManifold = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
const btCollisionObject* obA = static_cast<const btCollisionObject*>(contactManifold->getBody0());
const btCollisionObject* obB = static_cast<const btCollisionObject*>(contactManifold->getBody1());
if ( obA == nullptr
|| obB == nullptr) {
continue;
}
ege::ElementPhysic* elem0 = static_cast<ege::ElementPhysic*>(obA->getUserPointer());
ege::ElementPhysic* elem1 = static_cast<ege::ElementPhysic*>(obB->getUserPointer());
if ( elem0 == nullptr
|| elem1 == nullptr) {
continue;
}
int numContacts = contactManifold->getNumContacts();
for (int j=0;j<numContacts;j++) {
btManifoldPoint& pt = contactManifold->getContactPoint(j);
if (pt.getDistance()<0.f) {
out.push_back(collisionPoints(elem0->sharedFromThis(), elem1->sharedFromThis(), pt.getPositionWorldOnA(), pt.getPositionWorldOnB(), pt.m_normalWorldOnB));
}
}
}
}
return out;
}