
In its original state, it required pointers to some other classes that are specific to my project, so I did a bit of editing to remove that requirement. I have however not tested the edited version, but I believe it should work fine. If there are any issues, I'll be happy to fix them

Now, to give credit where it is due -> I borrowed code from several sources to create this, although I have forgotten who most of them are

Its meant for those that want to quickly implement Bullet into their projects, but don't want a full wrapper.
So, first off, some screenies ->
A standard box stack


The same stack after an explosion ->

And, the resulting rubble after an "attraction"


So, here is CPhysics.h --
Code: Select all
#ifndef _CPHYSICS_H
#define _CPHYSICS_H
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include <BulletCollision\CollisionDispatch\btGhostObject.h>
class CPhysics
{
public:
CPhysics(ISceneManager* smgr, IVideoDriver* driver, ITimer* Timer, btVector3 Gravity, IAnimatedMeshSceneNode* Map);
void Update();
bool UpdateRender(btRigidBody* TObject);
btTriangleMesh* ConvertIrrMeshToBulletTriangleMesh(IMesh* pMesh,const vector3df& scaling);
void QuaternionToEuler(const btQuaternion &TQuat, btVector3 &TEuler);
void getConvexHull(IMesh *collMesh, btConvexHullShape *hullShape, IAnimatedMeshSceneNode* node);
list<btRigidBody *> getObjectList();
btRigidBody* CreateBox(const btVector3 &TPosition, const vector3df &TScale, btScalar TMass);
btRigidBody* loadConvex(std::string filename, const btVector3 &TPosition, const vector3df &TScale, btScalar TMass);
btDiscreteDynamicsWorld* getWorld();
private:
ISceneManager* smgr;
IVideoDriver* driver;
ITimer* Timer;
btDiscreteDynamicsWorld* World;
list<btRigidBody *> Objects;
btVector3 Gravity;
u32 TimeStamp;
u32 DeltaTime;
};
#endif
Code: Select all
#include "CPhysics.h"
CPhysics::CPhysics(ISceneManager* smgr, IVideoDriver* driver, ITimer* Timer, btVector3 Gravity, IAnimatedMeshSceneNode* Map)
{
btDefaultCollisionConfiguration* CollisionConfiguration = new btDefaultCollisionConfiguration();
btBroadphaseInterface* BroadPhase = new btAxisSweep3(btVector3(-100000, -100000, -100000), btVector3(100000, 100000, 100000));
BroadPhase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback());
btCollisionDispatcher* Dispatcher = new btCollisionDispatcher(CollisionConfiguration);
btSequentialImpulseConstraintSolver* Solver = new btSequentialImpulseConstraintSolver();
CPhysics::World = new btDiscreteDynamicsWorld(Dispatcher, BroadPhase, Solver, CollisionConfiguration);
CPhysics::World->setGravity(Gravity);
CPhysics::Gravity = Gravity;
CPhysics::smgr = smgr;
CPhysics::driver = driver;
CPhysics::Timer = Timer;
CPhysics::TimeStamp = Timer->getTime();
CPhysics::DeltaTime = 0;
btTriangleMesh* indexVertexArrays = CPhysics::ConvertIrrMeshToBulletTriangleMesh(Map->getMesh(),Map->getMesh()->getScale());
btBvhTriangleMeshShape* trimeshShape = new btBvhTriangleMeshShape(indexVertexArrays, true);
btQuaternion quat;
quat.setEulerZYX(0,0,0);
btTransform Transform2;
Transform2.setIdentity();
Transform2.setOrigin(btVector3(0,0,0));
Transform2.setRotation(quat);
btDefaultMotionState *MotionState2 = new btDefaultMotionState(Transform2);
btRigidBody *RigidBody = new btRigidBody(0, MotionState2, trimeshShape);
RigidBody->setUserPointer((void *)(Map->getNode()));
CPhysics::World->addRigidBody(RigidBody);
CPhysics::Objects.push_back(RigidBody);
RigidBody->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
}
void CPhysics::Update()
{
CPhysics::DeltaTime = CPhysics::Timer->getTime() - CPhysics::TimeStamp;
CPhysics::TimeStamp = CPhysics::Timer->getTime();
CPhysics::World->stepSimulation(CPhysics::DeltaTime * 0.001f, 2);
for(list<btRigidBody *>::Iterator Iterator = CPhysics::Objects.begin(); Iterator != CPhysics::Objects.end();)
if(!CPhysics::UpdateRender(*Iterator))
{
Iterator = CPhysics::Objects.erase(Iterator);
}
else
{
Iterator++;
}
}
bool CPhysics::UpdateRender(btRigidBody* TObject)
{
ISceneNode* Node = static_cast<ISceneNode *>(TObject->getUserPointer());
if(Node == NULL)
{
return false;
}
const btVector3& Point = TObject->getCenterOfMassPosition();
Node->setPosition(vector3df((f32)Point[0], (f32)Point[1], (f32)Point[2]));
btVector3 EulerRotation;
CPhysics::QuaternionToEuler(TObject->getOrientation(), EulerRotation);
Node->setRotation(vector3df(EulerRotation[0], EulerRotation[1], EulerRotation[2]));
return true;
}
btRigidBody* CPhysics::CreateBox(const btVector3 &TPosition, const vector3df &TScale, btScalar TMass)
{
ISceneNode* Node = CPhysics::smgr->addCubeSceneNode(1.0f);
Node->setScale(TScale);
Node->setMaterialFlag(EMF_LIGHTING, true);
Node->setMaterialFlag(EMF_NORMALIZE_NORMALS, true);
//Node->setMaterialTexture(0, driver->getTexture("rust0.jpg"));
btTransform Transform;
Transform.setIdentity();
Transform.setOrigin(TPosition);
btDefaultMotionState *MotionState = new btDefaultMotionState(Transform);
btVector3 HalfExtents(TScale.X * 0.5f, TScale.Y * 0.5f, TScale.Z * 0.5f);
btCollisionShape *Shape = new btBoxShape(HalfExtents);
btVector3 LocalInertia;
Shape->calculateLocalInertia(TMass, LocalInertia);
btRigidBody *RigidBody = new btRigidBody(TMass, MotionState, Shape, LocalInertia);
RigidBody->setUserPointer((void *)(Node));
RigidBody->setActivationState(DISABLE_DEACTIVATION);
CPhysics::World->addRigidBody(RigidBody);
CPhysics::Objects.push_back(RigidBody);
return RigidBody;
}
btTriangleMesh* CPhysics::ConvertIrrMeshToBulletTriangleMesh(IMesh* pMesh,const vector3df& scaling)
{
btVector3 vertices[3];
u32 i,j,k,index,numVertices,numIndices;
u16* mb_indices;
btTriangleMesh *pTriMesh = new btTriangleMesh();
for (i=0; i<pMesh->getMeshBufferCount(); i++)
{
IMeshBuffer* mb=pMesh->getMeshBuffer(i);
if(mb->getVertexType()==EVT_STANDARD)
{
S3DVertex* mb_vertices=(S3DVertex*)mb->getVertices();
mb_indices = mb->getIndices();
numVertices = mb->getVertexCount();
numIndices = mb->getIndexCount();
for(j=0;j<numIndices;j+=3)
{
for (k=0;k<3;k++)
{
index = mb_indices[j+k];
vertices[k] = btVector3(mb_vertices[index].Pos.X*scaling.X, mb_vertices[index].Pos.Y*scaling.Y, mb_vertices[index].Pos.Z*scaling.Z);
}
pTriMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
}
}
else if(mb->getVertexType()==EVT_2TCOORDS)
{
S3DVertex2TCoords* mb_vertices=(S3DVertex2TCoords*)mb->getVertices();
mb_indices = mb->getIndices();
numVertices = mb->getVertexCount();
numIndices = mb->getIndexCount();
for(j=0;j<numIndices;j+=3)
{
for (k=0;k<3;k++)
{
index = mb_indices[j+k];
vertices[k] = btVector3(mb_vertices[index].Pos.X*scaling.X, mb_vertices[index].Pos.Y*scaling.Y, mb_vertices[index].Pos.Z*scaling.Z);
}
pTriMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
}
}
}
return pTriMesh;
};
void CPhysics::QuaternionToEuler(const btQuaternion &TQuat, btVector3 &TEuler)
{
btScalar W = TQuat.getW();
btScalar X = TQuat.getX();
btScalar Y = TQuat.getY();
btScalar Z = TQuat.getZ();
float WSquared = W * W;
float XSquared = X * X;
float YSquared = Y * Y;
float ZSquared = Z * Z;
TEuler.setX(atan2f(2.0f * (Y * Z + X * W), -XSquared - YSquared + ZSquared + WSquared));
TEuler.setY(asinf(-2.0f * (X * Z - Y * W)));
TEuler.setZ(atan2f(2.0f * (X * Y + Z * W), XSquared - YSquared - ZSquared + WSquared));
TEuler *= RADTODEG;
};
btRigidBody* CPhysics::loadConvex(std::string filename, const btVector3 &TPosition, const vector3df &TScale, btScalar TMass)
{
IAnimatedMeshSceneNode* Node = CPhysics::smgr->addAnimatedMeshSceneNode((IAnimatedMesh*)CPhysics::smgr->getMesh(filename.c_str()));
btTriangleMesh* trimesh = CPhysics::ConvertIrrMeshToBulletTriangleMesh(Node->getMesh(), Node->getScale());
btConvexShape* hull = new btConvexTriangleMeshShape(trimesh);
hull->setUserPointer(hull);
btVector3 localInertia(0,0,0);
hull->calculateLocalInertia(TMass, localInertia);
btQuaternion quat;
quat.setEulerZYX(Node->getRotation().X,Node->getRotation().Y,Node->getRotation().Z);
btTransform Transform2;
Transform2.setIdentity();
Transform2.setOrigin(TPosition);
Transform2.setRotation(quat);
btDefaultMotionState *MotionState2 = new btDefaultMotionState(Transform2);
btRigidBody* RigidBody = new btRigidBody(TMass, MotionState2, hull, localInertia);
RigidBody->setUserPointer((void *)(Node));
RigidBody->setActivationState(DISABLE_DEACTIVATION);
CPhysics::World->addRigidBody(RigidBody);
CPhysics::Objects.push_back(RigidBody);
return RigidBody;
}
list<btRigidBody *> CPhysics::getObjectList()
{
return CPhysics::Objects;
}
btDiscreteDynamicsWorld* CPhysics::getWorld()
{
return CPhysics::World;
}
Code: Select all
CPhysics* Physics = new CPhysics(smgr, driver, Timer, btVector3(0, -500, 0), MapNode);
After that, simply call
Code: Select all
Physics->Update();
If you also want the debug drawer, then include DebugDraw.h -
Code: Select all
#ifndef _DEBUGDRAW_H
#define _DEBUGDRAW_H
enum DebugDrawModes
{
DBG_NoDebug=0,
DBG_DrawWireframe = 1,
DBG_DrawAabb=2,
DBG_DrawFeaturesText=4,
DBG_DrawContactPoints=8,
DBG_NoDeactivation=16,
DBG_NoHelpText = 32,
DBG_DrawText=64,
DBG_ProfileTimings = 128,
DBG_EnableSatComparison = 256,
DBG_DisableBulletLCP = 512,
DBG_EnableCCD = 1024,
DBG_MAX_DEBUG_DRAW_MODE
};
//Courtesy of randomMESH
class DebugDraw : public btIDebugDraw
{
public:
DebugDraw(IrrlichtDevice* const device) :
mode(DBG_NoDebug), driver(device->getVideoDriver()), logger(device->getLogger())
{
}
void drawLine(const btVector3& from, const btVector3& to, const btVector3& color)
{
SColor newColor(255, (u32)color[0], (u32)color[1], (u32)color[2]);
if (color[0] <= 1.0 && color[0] > 0.0)
newColor.setRed((u32)(color[0]*255.0));
if (color[1] <= 1.0 && color[1] > 0.0)
newColor.setGreen((u32)(color[1]*255.0));
if (color[2] <= 1.0 && color[2] > 0.0)
newColor.setBlue((u32)(color[2]*255.0));
this->driver->draw3DLine(vector3df(from[0], from[1], from[2]), vector3df(to[0], to[1], to[2]), newColor);
}
void drawContactPoint(const btVector3& PointOnB, const btVector3& normalOnB, btScalar distance, int lifeTime, const btVector3& color)
{
static const SColor CONTACTPOINT_COLOR(255, 255, 255, 0);
const btVector3 to(PointOnB + normalOnB*distance);
this->driver->draw3DLine(vector3df(PointOnB[0], PointOnB[1], PointOnB[2]),vector3df(to[0], to[1], to[2]),CONTACTPOINT_COLOR);
}
void reportErrorWarning(const char* text)
{
this->logger->log(text, irr::ELL_ERROR);
}
void draw3dText(const btVector3& location, const char* text) { }
void setDebugMode(int mode) { this->mode = mode; }
int getDebugMode() const { return this->mode; }
private:
int mode;
IVideoDriver* const driver;
ILogger* logger;
};
#endif
Code: Select all
DebugDraw* Debug = new DebugDraw(device);
Physics->getWorld()->setDebugDrawer(Debug);
Debug->setDebugMode(DBG_DrawAabb | DBG_DrawWireframe);
Code: Select all
SMaterial debugMat;
debugMat.Lighting = false;
Code: Select all
driver->setMaterial(debugMat);
driver->setTransform(ETS_WORLD, IdentityMatrix);
Physics->getWorld()->debugDrawWorld();
Code: Select all
int xshift = 0;
int yshift = 0;
for(yshift=0;yshift<=7;yshift++)
for(xshift=0;xshift<=7;xshift++)
{
btRigidBody* DummyRigidBody = Physics->CreateBox(btVector3((100+(50*xshift)),10+(50*yshift),1500),vector3df(50,50,50),40);
};

Enjoy!