Here's the code of the implementation of my GameObject class.
It automagically creates an ODE trimesh from an Irrlicht IMesh*.
Have a look at the makeTriMeshData() method.
Code: Select all
#include "GameObject.h"
#include "physics/Physics.h"
#include <SMesh.h>
irr::core::matrix4 GameObject::currentTransformation = irr::core::matrix4();
GameObject::GameObject(
irr::scene::ISceneNode* node,
irr::scene::IMesh* mesh,
const dReal density, const dReal weight,
const bool createBody = true, const bool gravity = true
) :
OdeObject(density, weight),
node(node), mesh(mesh)
{
init(createBody, gravity);
}
GameObject::~GameObject()
{
if (this->geom)
dGeomDestroy(this->geom);
if (this->body)
dBodyDestroy(this->body);
dGeomTriMeshDataDestroy(this->data);
delete[] this->vertices;
delete[] this->indices;
}
void GameObject::update(const dBodyID body)
{
irr::scene::ISceneNode* const node = ((GameObject*)dBodyGetData(body))->node;
const irr::core::matrix4& mat = getTransformationMatrix(body);
node->setRotation(mat.getRotationDegrees());
node->setPosition(mat.getTranslation());
}
const irr::core::matrix4& GameObject::getTransformationMatrix(dBodyID const body)
{
const dReal* const p = dBodyGetPosition(body);
const dReal* const r = dBodyGetRotation(body);
irr::f32 m[16];
m[ 0] = r[ 0]; m[ 1] = r[ 4]; m[ 2] = r[ 8]; m[ 3] = 0;
m[ 4] = r[ 1]; m[ 5] = r[ 5]; m[ 6] = r[ 9]; m[ 7] = 0;
m[ 8] = r[ 2]; m[ 9] = r[ 6]; m[10] = r[10]; m[11] = 0;
m[12] = p[ 0]; m[13] = p[ 1]; m[14] = p[ 2]; m[15] = 1;
currentTransformation.setM(m);
return currentTransformation;
}
const void GameObject::init(const bool createBody, const bool gravityMode)
{
const irr::core::vector3df& pos = this->node->getPosition();
const irr::core::vector3df& rotationRAD = (this->node->getRotation()*irr::core::DEGTORAD);
const irr::core::quaternion irrQuat(rotationRAD);
dQuaternion odeQuat;
odeQuat[0] = irrQuat.W;
odeQuat[1] = irrQuat.X;
odeQuat[2] = irrQuat.Y;
odeQuat[3] = irrQuat.Z;
//create geom
this->internalCreateGeom();
dGeomSetData(this->geom, this);
dGeomSetPosition(this->geom, pos.X, pos.Y, pos.Z);
dGeomSetQuaternion(this->geom, odeQuat);
if (createBody)
{
//create body
this->body = dBodyCreate(Physics::getWorld());
dBodySetData(this->body, this);
//setup mass
this->internalSetUpMass();
dBodySetPosition(this->body, pos.X, pos.Y, pos.Z);
dBodySetQuaternion(this->body, odeQuat);
dBodySetGravityMode(this->body, gravityMode);
dBodySetMovedCallback(this->body, &this->update);
}
dGeomSetBody(this->geom, this->body);
}
const void GameObject::internalSetUpMass()
{
dMassSetTrimesh(&this->mass, this->density, this->geom);
dMassTranslate(&this->mass, -this->mass.c[0], -this->mass.c[1], -this->mass.c[2]);
dMassAdjust(&this->mass, this->weight);
dBodySetMass(this->body, &this->mass);
}
const void GameObject::internalCreateGeom()
{
makeTriMeshData();
this->geom = dCreateTriMesh(Physics::getSpace(), this->data, 0, 0, 0);
}
void GameObject::makeTriMeshData()
{
irr::u32 indexcount = 0;
irr::u32 vertexcount = 0;
// count vertices and indices
irr::u32 i;
for (i = 0; i < mesh->getMeshBufferCount(); i++)
{
const irr::scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);
indexcount += mb->getIndexCount();
vertexcount += mb->getVertexCount();
}
// build structure for ode trimesh geom
this->vertices = new dVector4[vertexcount];
this->indices = new dTriIndex[indexcount];
irr::u32 i_off = 0, i_cnt = 0, v_off = 0;
const irr::core::vector3df& scale = node->getScale();
for (irr::u32 i = 0; i < mesh->getMeshBufferCount(); ++i)
{
const irr::scene::IMeshBuffer* mb = mesh->getMeshBuffer(i);
const irr::u16* mb_indices = mb->getIndices();
for (irr::u32 j = 0; j < mb->getIndexCount(); ++j)
indices[i_off++] = i_cnt + mb_indices[j];
i_cnt += mb->getIndexCount();
if (mb->getVertexType() == irr::video::EVT_STANDARD)
{
const irr::video::S3DVertex* mb_vertices = (irr::video::S3DVertex*)mb->getVertices();
irr::u32 j;
for(j = 0; j < mb->getVertexCount(); ++j)
{
vertices[v_off][0] = mb_vertices[j].Pos.X*scale.X;
vertices[v_off][1] = mb_vertices[j].Pos.Y*scale.Y;
vertices[v_off][2] = mb_vertices[j].Pos.Z*scale.Z;
v_off++;
}
}
else if (mb->getVertexType() == irr::video::EVT_2TCOORDS)
{
const irr::video::S3DVertex2TCoords* mb_vertices = (irr::video::S3DVertex2TCoords*)mb->getVertices();
irr::u32 j;
for (j = 0; j < mb->getVertexCount(); ++j)
{
vertices[v_off][0] = mb_vertices[j].Pos.X*scale.X;
vertices[v_off][1] = mb_vertices[j].Pos.Y*scale.Y;
vertices[v_off][2] = mb_vertices[j].Pos.Z*scale.Z;
v_off++;
}
}
}
this->data = dGeomTriMeshDataCreate();
dGeomTriMeshDataBuildSimple(this->data, (const dReal*)this->vertices, vertexcount, (const dTriIndex*)this->indices, indexcount);
}