362 lines
12 KiB
C++
362 lines
12 KiB
C++
|
/*
|
||
|
irrDynamics - Light-weight Bullet Physics wrapper for the irrlicht graphics engine
|
||
|
Copyright (C) 2014 Otto Naderer - otto.naderer@aec.at
|
||
|
|
||
|
This program is free software: you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation, either version 3 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include <btBulletCollisionCommon.h>
|
||
|
#include <btBulletDynamicsCommon.h>
|
||
|
#include "irrDynamics.h"
|
||
|
|
||
|
using namespace irr;
|
||
|
|
||
|
irrDynamics* irrDynamics::instance = NULL;
|
||
|
|
||
|
irrDynamics::irrDynamics() : lastStep(0)
|
||
|
{
|
||
|
// Initialize bullet
|
||
|
collisionConfiguration = new btDefaultCollisionConfiguration();
|
||
|
broadPhase = new btAxisSweep3(btVector3(-1000, -1000, -1000), btVector3(1000, 1000, 1000));
|
||
|
dispatcher = new btCollisionDispatcher(collisionConfiguration);
|
||
|
solver = new btSequentialImpulseConstraintSolver();
|
||
|
world = new btDiscreteDynamicsWorld(dispatcher, broadPhase, solver, collisionConfiguration);
|
||
|
}
|
||
|
|
||
|
irrDynamics* irrDynamics::getInstance()
|
||
|
{
|
||
|
if (!instance)
|
||
|
{
|
||
|
instance = new irrDynamics();
|
||
|
}
|
||
|
return instance;
|
||
|
}
|
||
|
|
||
|
void irrDynamics::simStep(const u32& curTimeStamp)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
if (inst->lastStep == 0)
|
||
|
inst->lastStep = curTimeStamp;
|
||
|
|
||
|
inst->world->stepSimulation((curTimeStamp - inst->lastStep) * 0.001f, 5);
|
||
|
inst->updateObjects();
|
||
|
inst->lastStep = curTimeStamp;
|
||
|
}
|
||
|
|
||
|
void irrDynamics::shutdown()
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
inst->clearObjects();
|
||
|
delete inst->world;
|
||
|
delete inst->solver;
|
||
|
delete inst->dispatcher;
|
||
|
delete inst->broadPhase;
|
||
|
delete inst->collisionConfiguration;
|
||
|
}
|
||
|
|
||
|
void irrDynamics::addTerrain(scene::ITerrainSceneNode* terrain, u32 lodLevel)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
terrain->updateAbsolutePosition();
|
||
|
core::vector3df irrPos = terrain->getPosition();
|
||
|
btVector3 btPos(irrPos.X, irrPos.Y, irrPos.Z);
|
||
|
btTransform Transform;
|
||
|
Transform.setIdentity();
|
||
|
Transform.setOrigin(btPos);
|
||
|
|
||
|
btDefaultMotionState *MotionState = new btDefaultMotionState(Transform);
|
||
|
|
||
|
btTriangleMesh * mTriMesh = new btTriangleMesh();
|
||
|
scene::CDynamicMeshBuffer* buffer = 0;
|
||
|
btVector3 vertices[3];
|
||
|
s32 j, k;
|
||
|
buffer = new scene::CDynamicMeshBuffer(irr::video::EVT_2TCOORDS, irr::video::EIT_32BIT);
|
||
|
(terrain)->getMeshBufferForLOD(*buffer, lodLevel);
|
||
|
|
||
|
core::vector3df terrScale = terrain->getScale();
|
||
|
//Build the triangleMesh
|
||
|
const u32 indexCount = buffer->getIndexCount();
|
||
|
printf("indeces: %u\n", indexCount);
|
||
|
video::S3DVertex2TCoords* mb_vertices = (irr::video::S3DVertex2TCoords*) buffer->getVertexBuffer().getData();
|
||
|
u32* mb_indices = (u32*) buffer->getIndices();
|
||
|
for (j = 0; (u32) j < indexCount; j += 3)
|
||
|
{
|
||
|
for (k = 0; k < 3; k++)
|
||
|
{
|
||
|
s32 index = mb_indices[j + k];
|
||
|
vertices[k] = btVector3(mb_vertices[index].Pos.X * terrScale.X, mb_vertices[index].Pos.Y * terrScale.Y, mb_vertices[index].Pos.Z * terrScale.Z);
|
||
|
}
|
||
|
mTriMesh->addTriangle(vertices[0], vertices[1], vertices[2]);
|
||
|
}
|
||
|
|
||
|
buffer->drop();
|
||
|
//Add the terrain collision shape to the world
|
||
|
btBvhTriangleMeshShape* mShape = new btBvhTriangleMeshShape(mTriMesh, true);
|
||
|
btRigidBody* rbody = new btRigidBody(0.f, MotionState, mShape);
|
||
|
inst->world->addRigidBody(rbody);
|
||
|
inst->objects.insert(std::pair<scene::ISceneNode*, btRigidBody*>(terrain, rbody));
|
||
|
|
||
|
terrain->grab();
|
||
|
}
|
||
|
|
||
|
void irrDynamics::debugDraw()
|
||
|
{
|
||
|
// getInstance()->bWorld->debugDrawWorld(true);
|
||
|
}
|
||
|
|
||
|
void irrDynamics::updateObjects()
|
||
|
{
|
||
|
for (std::map<scene::ISceneNode*, btRigidBody*>::iterator iter = objects.begin(); iter != objects.end(); iter++)
|
||
|
{
|
||
|
btVector3 Point = iter->second->getCenterOfMassPosition();
|
||
|
iter->first->setPosition(core::vector3df((f32)Point[0], (f32)Point[1], (f32)Point[2]));
|
||
|
|
||
|
// Set rotation
|
||
|
core::vector3df euler;
|
||
|
const btQuaternion& quat = iter->second->getOrientation();
|
||
|
core::quaternion q(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
|
||
|
q.toEuler(euler);
|
||
|
euler *= core::RADTODEG;
|
||
|
iter->first->setRotation(euler);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void irrDynamics::removeObject(scene::ISceneNode* node)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
std::map<scene::ISceneNode*, btRigidBody*>::iterator iter = inst->objects.find(node);
|
||
|
if (iter == inst->objects.end())
|
||
|
{
|
||
|
inst->world->removeRigidBody(iter->second);
|
||
|
|
||
|
// Free memory
|
||
|
delete iter->second->getMotionState();
|
||
|
delete iter->second->getCollisionShape();
|
||
|
delete iter->second;
|
||
|
iter->first->drop();
|
||
|
inst->objects.erase(iter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("irrdynamics: object not found in map!\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void irrDynamics::clearObjects()
|
||
|
{
|
||
|
for (std::map<scene::ISceneNode*, btRigidBody*>::iterator iter = objects.begin(); iter != objects.end(); iter++)
|
||
|
{
|
||
|
world->removeRigidBody(iter->second);
|
||
|
|
||
|
// Free memory
|
||
|
delete iter->second->getMotionState();
|
||
|
delete iter->second->getCollisionShape();
|
||
|
delete iter->second;
|
||
|
iter->first->drop();
|
||
|
}
|
||
|
objects.clear();
|
||
|
}
|
||
|
|
||
|
btRigidBody* irrDynamics::addSphericalObject(scene::ISceneNode* node, f32 radius, f32 mass)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
core::vector3df irrPos = node->getAbsolutePosition();
|
||
|
btVector3 tPosition(irrPos.X, irrPos.Y, irrPos.Z);
|
||
|
btTransform transform;
|
||
|
transform.setIdentity();
|
||
|
transform.setOrigin(tPosition);
|
||
|
|
||
|
btDefaultMotionState *motionState = new btDefaultMotionState(transform);
|
||
|
|
||
|
// Create the shape
|
||
|
btCollisionShape *shape = new btSphereShape(radius);
|
||
|
|
||
|
// Add mass
|
||
|
btVector3 localInertia;
|
||
|
shape->calculateLocalInertia(mass, localInertia);
|
||
|
|
||
|
// Create the rigid body object
|
||
|
btRigidBody *rigidBody = new btRigidBody(mass, motionState, shape, localInertia);
|
||
|
|
||
|
// Add it to the world
|
||
|
inst->world->addRigidBody(rigidBody);
|
||
|
inst->objects.insert(std::pair<scene::ISceneNode*, btRigidBody*>(node, rigidBody));
|
||
|
node->grab();
|
||
|
return rigidBody;
|
||
|
}
|
||
|
|
||
|
btRigidBody* irrDynamics::addBoxObject(scene::ISceneNode* node, f32 mass)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
node->updateAbsolutePosition();
|
||
|
core::vector3df irrPos = node->getAbsolutePosition();
|
||
|
btVector3 tPosition(irrPos.X, irrPos.Y, irrPos.Z);
|
||
|
|
||
|
|
||
|
|
||
|
const core::aabbox3df aabox = node->getTransformedBoundingBox();
|
||
|
core::vector3df fullExtent = aabox.getExtent();
|
||
|
btVector3 halfExtent(fullExtent.X * .5f, fullExtent.Y * .5f, fullExtent.Z * .5f);
|
||
|
|
||
|
//get rotation to quaternion
|
||
|
core::vector3df rotationRadians = node->getRotation();
|
||
|
rotationRadians *= core::DEGTORAD;
|
||
|
core::quaternion quat(rotationRadians);
|
||
|
|
||
|
btTransform transform;
|
||
|
transform.setIdentity();
|
||
|
transform.setOrigin(tPosition);
|
||
|
transform.setRotation(btQuaternion(quat.X, quat.Y, quat.Z, quat.W));
|
||
|
|
||
|
btDefaultMotionState *motionState = new btDefaultMotionState(transform);
|
||
|
|
||
|
// Create the shape
|
||
|
btCollisionShape *shape = new btBoxShape(halfExtent);
|
||
|
|
||
|
// Add mass
|
||
|
btVector3 localInertia;
|
||
|
shape->calculateLocalInertia(mass, localInertia);
|
||
|
|
||
|
// Create the rigid body object
|
||
|
btRigidBody *rigidBody = new btRigidBody(mass, motionState, shape, localInertia);
|
||
|
|
||
|
// Add it to the world
|
||
|
inst->world->addRigidBody(rigidBody);
|
||
|
inst->objects.insert(std::pair<scene::ISceneNode*, btRigidBody*>(node, rigidBody));
|
||
|
node->grab();
|
||
|
return rigidBody;
|
||
|
}
|
||
|
|
||
|
bool irrDynamics::createHingeConstraint(scene::ISceneNode* nodeA, scene::ISceneNode* nodeB, const core::vector3df& pivotInA, const core::vector3df& pivotInB, const core::vector3df& axisInA, const irr::core::vector3df& axisInB)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
//find the corresponding rigid bodies:
|
||
|
std::map<scene::ISceneNode*, btRigidBody*>::iterator iterA, iterB;
|
||
|
iterA = inst->objects.find(nodeA);
|
||
|
iterB = inst->objects.find(nodeB);
|
||
|
|
||
|
if (iterA == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find first node for constraint!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (iterB == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find second node for constraint!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
btHingeConstraint* constraint = new btHingeConstraint(*(iterA->second), *(iterB->second), btVector3(pivotInA.X, pivotInA.Y, pivotInA.Z), btVector3(pivotInB.X, pivotInB.Y, pivotInB.Z), btVector3(axisInA.X, axisInA.Y, axisInA.Z), btVector3(axisInB.X, axisInB.Y, axisInB.Z));
|
||
|
inst->world->addConstraint(constraint);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool irrDynamics::createPoint2PointConstraint(scene::ISceneNode* nodeA, scene::ISceneNode* nodeB, const core::vector3df& pivotInA, const core::vector3df& pivotInB)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
//find the corresponding rigid bodies:
|
||
|
std::map<scene::ISceneNode*, btRigidBody*>::iterator iterA, iterB;
|
||
|
iterA = inst->objects.find(nodeA);
|
||
|
iterB = inst->objects.find(nodeB);
|
||
|
|
||
|
if (iterA == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find first node for constraint!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (iterB == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find second node for constraint!\n");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
btPoint2PointConstraint* constraint = new btPoint2PointConstraint(*(iterA->second), *(iterB->second), btVector3(pivotInA.X, pivotInA.Y, pivotInA.Z), btVector3(pivotInB.X, pivotInB.Y, pivotInB.Z));
|
||
|
inst->world->addConstraint(constraint);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void irrDynamics::applyCentralForce(scene::ISceneNode* node, const core::vector3df& force)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
//find the corresponding rigid body:
|
||
|
std::map<scene::ISceneNode*, btRigidBody*>::iterator iter;
|
||
|
iter = inst->objects.find(node);
|
||
|
if (iter == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find node in list. Force application aborted.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
iter->second->applyCentralForce(btVector3(force.X, force.Y, force.Z));
|
||
|
}
|
||
|
|
||
|
btRigidBody* irrDynamics::addFloor(const core::vector3df& normal, const core::vector3df& offset)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
btVector3 tPosition(offset.X, offset.Y, offset.Z);
|
||
|
btTransform transform;
|
||
|
transform.setIdentity();
|
||
|
transform.setOrigin(tPosition);
|
||
|
|
||
|
btDefaultMotionState *motionState = new btDefaultMotionState(transform);
|
||
|
|
||
|
// Create the shape
|
||
|
btCollisionShape *shape = new btStaticPlaneShape(btVector3(normal.X, normal.Y, normal.Z), 0);
|
||
|
|
||
|
// Add mass
|
||
|
btVector3 localInertia;
|
||
|
shape->calculateLocalInertia(0.f, localInertia);
|
||
|
|
||
|
// Create the rigid body object
|
||
|
btRigidBody *rigidBody = new btRigidBody(0.f, motionState, shape, localInertia);
|
||
|
|
||
|
// Add it to the world
|
||
|
inst->world->addRigidBody(rigidBody);
|
||
|
return rigidBody;
|
||
|
}
|
||
|
|
||
|
void irrDynamics::setDamping(scene::ISceneNode* node, f32 linearDamping, f32 angularDamping)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
//find the corresponding rigid body:
|
||
|
std::map<scene::ISceneNode*, btRigidBody*>::iterator iter;
|
||
|
iter = inst->objects.find(node);
|
||
|
if (iter == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find node in list. Damping application aborted.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
iter->second->setDamping(linearDamping, angularDamping);
|
||
|
}
|
||
|
|
||
|
void irrDynamics::setPosition(scene::ISceneNode* node, const core::vector3df& newPos)
|
||
|
{
|
||
|
irrDynamics* inst = getInstance();
|
||
|
//find the corresponding rigid body:
|
||
|
std::map<scene::ISceneNode*, btRigidBody*>::iterator iter;
|
||
|
iter = inst->objects.find(node);
|
||
|
if (iter == inst->objects.end())
|
||
|
{
|
||
|
printf("irrdynamics: Unable to find node in list. Position update aborted.\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
btTransform transform = iter->second->getCenterOfMassTransform();
|
||
|
transform.setOrigin(btVector3(newPos.X, newPos.Y, newPos.Z));
|
||
|
iter->second->setCenterOfMassTransform(transform);
|
||
|
}
|