diff options
author | Stijn Buys <ingar@osirion.org> | 2009-07-07 13:43:05 +0000 |
---|---|---|
committer | Stijn Buys <ingar@osirion.org> | 2009-07-07 13:43:05 +0000 |
commit | 7e15b99c01616999496155fe5d2ce89d7608932b (patch) | |
tree | 226d5c23b0a931ccbbf490aaf2da647ed6ebe5d4 /src/game/base/physics.cc | |
parent | 1f71cc5e127f6163e9163afd42453fe145defbeb (diff) |
Initial bullet physics support
Diffstat (limited to 'src/game/base/physics.cc')
-rw-r--r-- | src/game/base/physics.cc | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/src/game/base/physics.cc b/src/game/base/physics.cc new file mode 100644 index 0000000..e0b6a70 --- /dev/null +++ b/src/game/base/physics.cc @@ -0,0 +1,308 @@ +/* + base/physics.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2. +*/ + +#include "base/physics.h" +#include "base/collision.h" +#include "base/game.h" +#include "core/zone.h" +#include "math/functions.h" +#include "math/vector3f.h" +#include "model/vertexarray.h" +#include "sys/sys.h" + +#ifdef HAVE_BULLET +#include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" +#include "BulletCollision/Gimpact/btGImpactShape.h" +#endif + +namespace game +{ + +/* ---- class ColliderShape ---------------------------------------- */ + +CollisionShape::Registry CollisionShape::shape_registry; + +CollisionShape::CollisionShape(model::Model *model, const bool moving) +{ + shape_label.assign(model->name()); + shape_moving = moving; + +#ifdef HAVE_BULLET + btGImpactMeshShape *moving_shape = 0; + btBvhTriangleMeshShape *static_shape = 0; + + shape_mesh = new btTriangleMesh(); + + size_t count = 0; + + model::VertexArray *vertexarray = model::VertexArray::instance(); + + // iterate model FragmentGroups + for (model::Model::Groups::iterator git = model->groups().begin(); git != model->groups().end(); git++) { + + model::FragmentGroup *group = (*git); + + // FIXME ignore moving parts + if (group->type() == model::FragmentGroup::None) { + + // for each fragment + for (model::FragmentGroup::iterator fit = group->begin(); fit != group->end(); fit++) { + model::Fragment *fragment = (*fit); + + const size_t index = fragment->index(); + const size_t triangle_count = (fragment->structural_size() + fragment->detail_size()) / 3; + + // load vertices from the global VertexArray into the bullet shape + for (size_t i = 0; i < triangle_count; i++) { + float *f = vertexarray->vertex() + index + (i * 9); + + btVector3 v0(f[0], f[1], f[2]); + btVector3 v1(f[3], f[4], f[5]); + btVector3 v2(f[6], f[7], f[8]); + + shape_mesh->addTriangle(v0, v1, v2); + } + + count += triangle_count; + } + } + } + + if (moving) { + moving_shape = new btGImpactMeshShape(shape_mesh); + moving_shape->updateBound(); + moving_shape->postUpdate(); + shape_bulletshape = moving_shape; + + } else { + static_shape = new btBvhTriangleMeshShape(shape_mesh, true, false); + shape_bulletshape = static_shape; + } + + + con_debug << " collision data for " << model->name() << ": " << count << " tris " << std::endl; +#endif +} + +CollisionShape::~CollisionShape() +{ + shape_label.clear(); +#ifdef HAVE_BULLET + delete shape_bulletshape; +#endif +} + +void CollisionShape::clear() +{ + for (Registry::iterator it = shape_registry.begin(); it != shape_registry.end(); it++) { + CollisionShape *shape = (*it); + delete shape; + } + shape_registry.clear(); +} + +CollisionShape *CollisionShape::add(model::Model *model, const bool moving) +{ + CollisionShape *shape = new CollisionShape(model, moving); + + shape_registry.push_back(shape); + return shape; +} + +CollisionShape *CollisionShape::find(model::Model *model, const bool moving) +{ + for (Registry::iterator it = shape_registry.begin(); it != shape_registry.end(); it++) { + CollisionShape *shape = (*it); + + if ((shape->moving() == moving) && (shape->label().compare(model->name()) == 0)) { + return shape; + } + } + return 0; +} + +/* ---- class Physics ---------------------------------------------- */ + +#ifdef HAVE_BULLET + +btDefaultCollisionConfiguration *Physics::configuration; +btCollisionDispatcher *Physics::dispatcher; +btSequentialImpulseConstraintSolver *Physics::solver; + +void Physics::init() +{ + con_print << "^BInitializing bullet physics..." << std::endl; + + configuration = new btDefaultCollisionConfiguration(); + dispatcher = new btCollisionDispatcher(configuration); + solver = new btSequentialImpulseConstraintSolver; + +} + +void Physics::frame(const float seconds) +{ + for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) { + PhysicsZone *bz = static_cast<PhysicsZone *>((*it).second); + bz->dynamics_world()->stepSimulation(seconds); + } +} + +void Physics::shutdown() +{ + con_print << "^BShutting down bullet physics..." << std::endl; + + CollisionShape::clear(); + + delete solver; + delete dispatcher; + delete configuration; +} + +#else + +void Physics::init() +{ +} + +void Physics::frame(const float seconds) +{ + Collision::frame(seconds); +} + +void Physics::shutdown() +{ +} + +#endif + +/* ---- class PhysicsZone ------------------------------------------ */ + +PhysicsZone::PhysicsZone(const std::string &label) : core::Zone(label) +{ +#ifdef HAVE_BULLET + btVector3 worldAabbMin(-10000,-10000,-10000); + btVector3 worldAabbMax(10000,10000,10000); + const int maxProxies = 1024; + + zone_cache = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies); + zone_dynamics_world = new btDiscreteDynamicsWorld(Physics::dispatcher, zone_cache, Physics::solver,Physics::configuration); + + // disable gravity + zone_dynamics_world->setGravity(btVector3(0.0f, 0.0f, 0.0f)); +#endif +} + +PhysicsZone::~PhysicsZone() +{ +#ifdef HAVE_BULLET + if (zone_cache) { + delete zone_cache; + zone_cache = 0; + } + + if (zone_dynamics_world) { + delete zone_dynamics_world; + zone_dynamics_world = 0; + } +#endif +} + +/* ---- class PhysicsBody ------------------------------------------ */ + +PhysicsBody::PhysicsBody(core::Entity *entity) +{ + collider_entity = entity; + collider_shape = 0; + collider_mass = 0; +#ifdef HAVE_BULLET + collider_body = 0; +#endif +} + +PhysicsBody::~PhysicsBody() +{ +#ifdef HAVE_BULLET + if (collider_body) { + delete collider_body; + collider_body = 0; + } +#endif +} + +void PhysicsBody::init_physics(const float mass) +{ + collider_mass = mass; + +#ifdef HAVE_BULLET + bool moving = (mass > 0.0f); + + if (!entity()->model()) + return; + + if (!collider_shape) { + collider_shape = CollisionShape::find(entity()->model(), moving); + if (!collider_shape) { + collider_shape = CollisionShape::add(entity()->model(), moving); + + } + } + + if (!collider_body) { + btVector3 inertia(0,0,0); + + btTransform t; + t.setIdentity(); + t.setOrigin(to_btVector3(entity()->location())); + t.setBasis(to_btMatrix3x3(entity()->axis())); + + + if (moving) { + collider_shape->bullet_shape()->calculateLocalInertia(mass,inertia); + + btMotionState *motionstate = new btDefaultMotionState(t); + btRigidBody::btRigidBodyConstructionInfo body_info(mass, motionstate, collider_shape->bullet_shape(), inertia); + collider_body = new btRigidBody(body_info); + collider_body->setUserPointer((void *)entity()); + collider_body->setLinearFactor(btVector3(1,1,1)); + //collider_body->setCcdMotionThreshold(0.0001f); + } else { + collider_body = new btRigidBody(mass, 0, collider_shape->bullet_shape(), inertia); + collider_body->setWorldTransform(t); + } + } + + if (entity()->zone()) { + PhysicsZone *zone = static_cast<PhysicsZone *>(entity()->zone()); + zone->dynamics_world()->addRigidBody(collider_body); + if (moving) { + //collider_body->setActivationState(ISLAND_SLEEPING); + //collider_body->setActivationState(ACTIVE_TAG); + //collider_body->activate(true); + } + } +#endif +} + +void PhysicsBody::shutdown_physics() +{ +#ifdef HAVE_BULLET + if (collider_body && entity()->zone()) { + PhysicsZone *zone = static_cast<PhysicsZone *>(entity()->zone()); + + if(collider_body->getMotionState()) + { + delete collider_body->getMotionState(); + } + zone->dynamics_world()->removeCollisionObject(collider_body); + + delete collider_body; + collider_body = 0; + } +#endif + collider_mass = 0; +} + +} |