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 | |
parent | 1f71cc5e127f6163e9163afd42453fe145defbeb (diff) |
Initial bullet physics support
-rw-r--r-- | configure.in | 82 | ||||
-rw-r--r-- | doc/installation.html | 29 | ||||
-rw-r--r-- | osirion.kdevelop | 2 | ||||
-rw-r--r-- | src/Makefile.am | 9 | ||||
-rw-r--r-- | src/game/base/Makefile.am | 9 | ||||
-rw-r--r-- | src/game/base/game.cc | 53 | ||||
-rw-r--r-- | src/game/base/physics.cc | 308 | ||||
-rw-r--r-- | src/game/base/physics.h | 166 | ||||
-rw-r--r-- | src/game/base/ship.cc | 147 | ||||
-rw-r--r-- | src/game/base/ship.h | 6 | ||||
-rw-r--r-- | src/game/base/station.cc | 4 | ||||
-rw-r--r-- | src/game/base/station.h | 3 |
12 files changed, 718 insertions, 100 deletions
diff --git a/configure.in b/configure.in index 74551a2..a66fb24 100644 --- a/configure.in +++ b/configure.in @@ -229,6 +229,52 @@ AC_SUBST(CURSES_CFLAGS) AC_SUBST(CURSES_LIBS) dnl ---------------------------------------------------------------- +dnl bullet +dnl + +HAVE_BULLET=no + +AC_ARG_WITH(bullet, + AC_HELP_STRING([--with-bullet=DIR], + [use the bullet physics library in DIR (read the documentation)] + ) +) + +if test "x${with_bullet}" != "xno"; then + save_CPPFLAGS="$CPPFLAGS" + save_LDFLAGS="$LDFLAGS" + + AC_MSG_CHECKING(for bullet directory) + + BULLET_DIR="/usr/local" + if test "x${with_bullet}" != "x"; then + BULLET_DIR="${with_bullet}" + fi + AC_MSG_RESULT([$BULLET_DIR]) + + BULLET_CFLAGS="-I${BULLET_DIR}/include/bullet" + BULLET_LIBS="-L${BULLET_DIR}/lib" + + CPPFLAGS="$save_CPPFLAGS $BULLET_CFLAGS" + LDFLAGS="$save_LDFLAGS $BULLET_LIBS" + + AC_CHECK_HEADER(btBulletDynamicsCommon.h, + AC_DEFINE(HAVE_BULLET, yes, [Define this if you have the bullet physics library]) + BULLET_LIBS="$BULLET_LIBS -lbulletmath -lbulletdynamics -lbulletcollision" + HAVE_BULLET="yes", + BULLET_LIBS="" + BULLET_CFLAGS="" + HAVE_BULLET="no" + ) + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" +fi + +AC_SUBST(BULLET_CFLAGS) +AC_SUBST(BULLET_LIBS) + +dnl ---------------------------------------------------------------- dnl zlib dnl @@ -392,6 +438,9 @@ fi CXXFLAGS="-pipe $DEBUG_CFLAGS $WARN_CFLAGS $CXXFLAGS" AC_SUBST(CXXFLAGS) +CPPFLAGS="$CPPFLAGS $BULLET_CFLAGS" +AC_SUBST(CPPFLAGS) + dnl --------------------------------------------------------------- dnl Installation paths @@ -442,20 +491,27 @@ AC_MSG_RESULT([ Project::OSiRiON $VERSION Configuration summary: - platform ........... $host - flags .............. $CXXFLAGS - libraries .......... $HOST_LIBS $LIBJPG_LIBS $LIBPNG_LIBS - curses ............. $HAVE_CURSES - build client ....... $BUILD_CLIENT - SDL .................$LIBSDL_LIBS - opengl ............. $GL_LIBS - openal ............. $AL_LIBS +platform ........... $host +flags .............. $CPPFLAGS $CXXFLAGS +libraries .......... $HOST_LIBS $LIBJPG_LIBS $LIBPNG_LIBS $CURSES_LIBS $BULLET_LIBS +curses ............. $HAVE_CURSES +bullet ............. $HAVE_BULLET +build client ....... $BUILD_CLIENT]) + +if test "x$BUILD_CLIENT" = xyes; then +AC_MSG_RESULT([SDL .................$LIBSDL_LIBS +opengl ............. $GL_LIBS +openal ............. $AL_LIBS]) +fi + +AC_MSG_RESULT([ Installation directories: - installation type .. $INSTALLTYPE - prefix ............. $prefix - binaries ........... $bindir - documentation ...... $docdir - game data .......... $PACKAGE_DATADIR + +installation type .. $INSTALLTYPE +prefix ............. $prefix +binaries ........... $bindir +documentation ...... $docdir +game data .......... $PACKAGE_DATADIR ]) diff --git a/doc/installation.html b/doc/installation.html index 8f66113..7640057 100644 --- a/doc/installation.html +++ b/doc/installation.html @@ -173,7 +173,34 @@ svn co svn://intranifty.no-ip.org/osirion osirion <a href="http://ingar.satgnu.net/osirion/files/osirion-src-latest.tar.bz2">osirion-src-latest.tar.bz2</a> </p> </div> - +<div class="subtitle"> + Bullet physics support +</div> +<div class="text"> +<p> + Experimental support for the <a href="http://www.bulletphysics.com/wordpress/">Bullet Physics Library</a> + is under development. You can download the source code here:<br> + <a href="http://code.google.com/p/bullet/downloads/list">http://code.google.com/p/bullet/downloads/list</a> +</p> +<p> + To download and install the library: +<div class="code"> +wget http://bullet.googlecode.com/files/bullet-2.75-rc3.tgz<br> +tar zxvf bullet-2.75-rc3.tgz<br> +cd bullet-2.75-rc3<br> +./autogen.sh<br> +./configure --prefix=/usr/local<br> +make<br> +sudo make install<br> +sudo install --mode=644 src/BulletDynamics/Dynamics/btActionInterface.h /usr/local/include/bullet/BulletDynamics/Dynamics +</div> +</p> +<p> + The osirion configure script will automaticly detect the bullet library in <i>/usr/local</i>. + If you use a different prefix, like <i>/opt/bullet</i>, you will have to call the osirion + configure script using the <i>--with-bullet=/opt/bullet</i> option. +</p> +</div> <div class="subtitle"> Compiling the source code </div> diff --git a/osirion.kdevelop b/osirion.kdevelop index 45c0f6b..4872ec6 100644 --- a/osirion.kdevelop +++ b/osirion.kdevelop @@ -21,7 +21,7 @@ </general> <kdevautoproject> <general> - <activetarget>src/core/libcore.la</activetarget> + <activetarget>src/game/base/libbase.la</activetarget> <useconfiguration>debug</useconfiguration> </general> <run> diff --git a/src/Makefile.am b/src/Makefile.am index 085f15f..ede200f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ SUFFIXES = .rc .rc.o: windres $< -o $@ -SUBDIRS = auxiliary sys filesystem math model core dedicated audio render ui \ +SUBDIRS = auxiliary math sys filesystem model core dedicated render ui audio \ client game noinst_HEADERS = config.h @@ -26,7 +26,8 @@ osiriond_LDADD = $(top_builddir)/src/auxiliary/libauxiliary.la \ $(top_builddir)/src/core/libcore.la $(top_builddir)/src/filesystem/libfilesystem.la \ $(top_builddir)/src/game/libgame.la \ $(top_builddir)/src/model/libmodel.la $(top_builddir)/src/dedicated/libdedicated.la \ - $(top_builddir)/src/math/libmath.la $(top_builddir)/src/sys/libsys.la $(HOST_LIBS) $(ICON_SERVER) $(CURSES_LIBS) + $(top_builddir)/src/math/libmath.la $(top_builddir)/src/sys/libsys.la \ + $(HOST_LIBS) $(BULLET_LIBS) $(CURSES_LIBS) $(ICON_SERVER) # client osirion_SOURCES = osirion.cc @@ -42,6 +43,6 @@ osirion_LDADD = $(top_builddir)/src/game/libgame.la $(top_builddir)/src/ui/libui $(top_builddir)/src/filesystem/libfilesystem.la $(top_builddir)/src/model/libmodel.la \ $(top_builddir)/src/math/libmath.la $(top_builddir)/src/auxiliary/libauxiliary.la \ $(top_builddir)/src/filesystem/libfilesystem.la $(top_builddir)/src/sys/libsys.la \ - $(top_builddir)/src/auxiliary/libauxiliary.la \ - $(AL_LIBS) $(GL_LIBS) $(HOST_LIBS) $(LIBPNG_LIBS) $(LIBJPG_LIBS) $(ICON_CLIENT) $(SDLMAIN) + $(top_builddir)/src/auxiliary/libauxiliary.la $(AL_LIBS) $(GL_LIBS) $(HOST_LIBS) \ + $(LIBPNG_LIBS) $(LIBJPG_LIBS) $(BULLET_LIBS) $(SDLMAIN) $(ICON_CLIENT) osirion_LDFLAGS = $(LIBSDL_LIBS) diff --git a/src/game/base/Makefile.am b/src/game/base/Makefile.am index 74b5d74..d2dfe64 100644 --- a/src/game/base/Makefile.am +++ b/src/game/base/Makefile.am @@ -2,7 +2,8 @@ INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/game METASOURCES = AUTO libbase_la_LDFLAGS = -avoid-version noinst_LTLIBRARIES = libbase.la -libbase_la_SOURCES = game.cc collision.cc jumppoint.cc navpoint.cc planet.cc racetrack.cc \ - ship.cc shipdealer.cc shipmodel.cc star.cc station.cc -noinst_HEADERS = game.h collision.h jumppoint.h navpoint.h planet.h racetrack.h ship.h \ - shipdealer.h shipmodel.h star.h station.h +libbase_la_SOURCES = collision.cc game.cc jumppoint.cc navpoint.cc physics.cc \ + planet.cc racetrack.cc ship.cc shipdealer.cc shipmodel.cc star.cc station.cc +noinst_HEADERS = game.h collision.h jumppoint.h navpoint.h physics.h planet.h \ + racetrack.h ship.h shipdealer.h shipmodel.h star.h station.h + diff --git a/src/game/base/game.cc b/src/game/base/game.cc index 4128af8..441e080 100644 --- a/src/game/base/game.cc +++ b/src/game/base/game.cc @@ -52,7 +52,6 @@ core::Cvar *Game::g_impulsespeed = 0; core::Cvar *Game::g_impulseacceleration = 0; core::Cvar *Game::g_jumppointrange = 0; core::Cvar *Game::g_devel = 0; -core::Cvar *Game::g_collision = 0; core::Module *factory() { @@ -235,10 +234,13 @@ void Game::func_launch(core::Player *player, std::string const &args) assert(player->view()->zone() == player->control()->zone()); + Ship *ship = static_cast<Ship *>(player->control()); + ship->shutdown_physics(); core::Entity *dock = player->view(); - player->control()->entity_location.assign(dock->location() + (dock->axis().forward() * (player->control()->radius()+ dock->radius())*2.0f)); - player->control()->entity_axis.assign(dock->axis()); - player->control()->set_state(core::Entity::Normal); + ship->entity_location.assign(dock->location() + (dock->axis().forward() * (player->control()->radius()+ dock->radius()))); + ship->entity_axis.assign(dock->axis()); + ship->set_state(core::Entity::Normal); + ship->init_physics(ship->radius()); player->set_view(0); player->send("^BLaunching from " + dock->name()); @@ -259,7 +261,7 @@ void Game::func_respawn(core::Player *player, std::string const &args) player->control()->set_zone(Default::zone); core::Entity *dock = player->control()->zone()->default_view(); if (dock) { - player->control()->entity_location.assign(dock->location() + (dock->axis().forward() * ((player->control()->radius()+ dock->radius())*2.0f))); + player->control()->entity_location.assign(dock->location() + (dock->axis().forward() * ((player->control()->radius()+ dock->radius())))); player->control()->entity_axis.assign(dock->axis()); player->control()->set_state(core::Entity::Docked); player->set_view(dock); @@ -289,11 +291,18 @@ void Game::func_goto(core::Player *player, const std::string &args) return; core::Entity *dock = player->control()->zone()->search_entity(args); + Ship *ship = static_cast<Ship *>(player->control()); + if (dock) { - player->control()->entity_location.assign(dock->location() + (dock->axis().forward() * (player->control()->radius()+dock->radius())*2.0f)); - player->control()->entity_axis.assign(dock->axis()); - player->control()->entity_axis.change_direction(180.0f); - player->control()->set_state(core::Entity::Normal); + ship->shutdown_physics(); + + ship->entity_location.assign(dock->location() + (dock->axis().forward() * (ship->radius()+dock->radius()))); + ship->entity_axis.assign(dock->axis()); + ship->entity_axis.change_direction(180.0f); + ship->set_state(core::Entity::Normal); + + ship->init_physics(ship->radius()); + player->set_view(0); player->send("Going to " + dock->name()); } else { @@ -307,6 +316,8 @@ Game::Game() : core::Module("Project::OSiRiON", true) { Default::clear(); ShipModel::clear(); + + Physics::init(); if (!load_ships()) { abort(); @@ -371,9 +382,6 @@ Game::Game() : core::Module("Project::OSiRiON", true) g_devel = core::Cvar::get("g_devel", "0", core::Cvar::Archive); g_devel->set_info("[bool] enable or disable developer mode"); - - g_collision = core::Cvar::get("g_collision", "0", core::Cvar::Archive); - g_collision->set_info("[bool] enable or disable collision detection"); } Game::~Game() @@ -384,7 +392,12 @@ Game::~Game() // remove engine core functions core::Func::remove("list_ship"); + // we explicity clear game data to prevent bullet from beeing confused + core::game()->clear(); + ShipModel::clear(); + + Physics::shutdown(); } bool Game::load_world() @@ -401,7 +414,7 @@ bool Game::load_world() con_print << "^BLoading world..." << std::endl; - core::Zone *zone = 0; + PhysicsZone *zone = 0; std::string label; while (worldini.getline()) { @@ -420,7 +433,7 @@ bool Game::load_world() if (worldini.got_key_string("zone", label)) { aux::to_label(label); - zone = new core::Zone(label); + zone = new PhysicsZone(label); core::Zone::add(zone); } else { worldini.unkown_key(); @@ -668,7 +681,13 @@ bool Game::validate_zone(core::Zone *zone) // validate jump gate JumpGate *jumpgate = static_cast<JumpGate *>(entity); jumpgate->validate(); + } else { + if (entity->entity_moduletypeid == station_enttype) { + Station *station = static_cast<Station *>(entity); + station->init_physics(0.0f); + } + if ((entity->flags() & core::Entity::Dockable) == core::Entity::Dockable) load_menus(entity, "zones/" + zone->label() + "/" + entity->label()); } @@ -929,11 +948,7 @@ void Game::frame(float seconds) if (!running()) return; - // TODO check Module::frame() is execute before are Entity::frame() - - // collision - if (g_collision->value()) - Collision::frame(seconds); + Physics::frame(seconds); } void Game::player_connect(core::Player *player) 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; +} + +} diff --git a/src/game/base/physics.h b/src/game/base/physics.h new file mode 100644 index 0000000..37ed1cf --- /dev/null +++ b/src/game/base/physics.h @@ -0,0 +1,166 @@ +/* + base/physics.h + This file is part of the Osirion project and is distributed under + the terms and conditions of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_BASE_PHYSICS_H__ +#define __INCLUDED_BASE_PHYSICS_H__ + +#include "sys/sys.h" +#include "core/zone.h" +#include <vector> + +#ifdef HAVE_BULLET +#include "btBulletDynamicsCommon.h" +#include "BulletCollision/CollisionShapes/btTriangleMesh.h" +#endif + +/* + + This file provides the interface between the osirion game library + and the bullet physics library + +*/ + +namespace game { + +#ifdef HAVE_BULLET +/// helper function to convert math:Vector3f to btVector3 +inline btVector3 to_btVector3(const math::Vector3f & v) +{ + return btVector3(v[0], v[1], v[2]); +} + +/// helper function to conver math::Axis to btMatrix3x3 +inline btMatrix3x3 to_btMatrix3x3(const math::Axis &a) +{ + return btMatrix3x3(a[0][0], a[0][1], a[0][2], + a[1][0], a[1][1], a[1][2], + a[2][0], a[2][1], a[2][2]); +}; +#endif + +/* ---- class CollisionShape --------------------------------------- */ + +/// a bullet collision shape +class CollisionShape { +public: + CollisionShape(model::Model *model, const bool moving); + + ~CollisionShape(); + + inline const std::string &label() const { return shape_label; } + + inline const bool moving() const { return shape_moving; } + +#ifdef HAVE_BULLET + inline btCollisionShape *bullet_shape() { return shape_bulletshape; } +#endif + +/* ----- static functions for the shape registry ------------------- */ + + /// tpye definition for the collision shape registry + typedef std::vector<CollisionShape *> Registry; + + static void clear(); + + static CollisionShape *add(model::Model *model, const bool moving); + + static CollisionShape *find(model::Model *model, const bool moving); + +private: + std::string shape_label; + bool shape_moving; + +#ifdef HAVE_BULLET + btCollisionShape *shape_bulletshape; + btTriangleMesh *shape_mesh; +#endif + + /// collision shape registry + static Registry shape_registry; +}; + +/* ---- class Physics ---------------------------------------------- */ + +/// main physics functions +class Physics { +public: + /// intialize world physics + static void init(); + + /// run a world physics frame + static void frame(const float elapsed); + + /// shutdown world physics + static void shutdown(); + +#ifdef HAVE_BULLET + static btDefaultCollisionConfiguration *configuration; + + static btCollisionDispatcher *dispatcher; + + static btSequentialImpulseConstraintSolver *solver; +#endif +}; + +/* ---- class PhysicsZone ------------------------------------------ */ + +/// a zone containing collision objects +class PhysicsZone : public core::Zone { +public: + PhysicsZone(const std::string &label); + virtual ~PhysicsZone(); + +#ifdef HAVE_BULLET + inline btDiscreteDynamicsWorld *dynamics_world() { return zone_dynamics_world; } + +private: + btAxisSweep3 *zone_cache; + btDiscreteDynamicsWorld *zone_dynamics_world; +#endif +}; + +/* ---- class PhysicsBody ------------------------------------------ */ + +/// an object that is capable of colliding with other objects +class PhysicsBody { +public: + /// initialize a collider attached to an entity + /** + * a PhysicsBody with zero mass is considered non-moving + */ + PhysicsBody(core::Entity *entity); + ~PhysicsBody(); + + /// initialize the collision body + void init_physics(const float mass); + + /// shutdown the collision body + void shutdown_physics(); + + /// collider mass + inline const float mass() const { return collider_mass; } + + /// the entity the collider is attached to + inline core::Entity *entity() { return collider_entity; } + +#ifdef HAVE_BULLET + /// the bullet rigid body associated with this collider + inline btRigidBody *body() { return collider_body; } +#endif + +private: + CollisionShape *collider_shape; + core::Entity *collider_entity; +#ifdef HAVE_BULLET + btRigidBody *collider_body; +#endif + float collider_mass; +}; + +} + +#endif // __INCLUDED_BASE_PHYSICS_H__ + diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc index ba5d7ba..739b29a 100644 --- a/src/game/base/ship.cc +++ b/src/game/base/ship.cc @@ -24,7 +24,8 @@ namespace game { const float MIN_DELTA = 0.000001f; Ship::Ship(core::Player *owner, ShipModel *shipmodel) : - core::EntityControlable(owner, ship_enttype) + core::EntityControlable(owner, ship_enttype), + PhysicsBody(this) { set_modelname(shipmodel->modelname()); set_name(shipmodel->name()); @@ -50,7 +51,7 @@ Ship::Ship(core::Player *owner, ShipModel *shipmodel) : Ship::~Ship() { - + shutdown_physics(); } void Ship::reset() @@ -145,8 +146,6 @@ void Ship::func_jump(std::string const &args) owner()->send("Jumping to the " + jumptargetzone->name()); set_zone(jumptargetzone); - if (owner()->control() == (EntityControlable*) this) - owner()->set_zone(jumptargetzone); ship_jumpdrive_timer = 0; entity_timer = 0; @@ -225,27 +224,40 @@ void Ship::explode() } }; -void Ship::frame(float seconds) +void Ship::set_zone(core::Zone *zone) { - const float direction_change_speed = 2; - float cosangle; // cosine of an angle - float angle; // angle in radians - math::Vector3f n; // normal of a plane + shutdown_physics(); + + core::EntityControlable::set_zone(zone); + + if (owner() && (owner()->control() == (EntityControlable*) this)) + owner()->set_zone(zone); + + init_physics(radius()); +} +void Ship::frame(float seconds) +{ float actual_maxspeed = ship_shipmodel->maxspeed(); float actual_turnspeed = ship_shipmodel->turnspeed(); float actual_acceleration = ship_shipmodel->acceleration(); + float actual_thrust = 0; +#ifndef HAVE_BULLET + const float direction_change_speed = 2; + float cosangle; // cosine of an angle + float angle; // angle in radians + math::Vector3f n; // normal of a plane + math::Axis target_axis(entity_axis); // target axis +#endif entity_movement = 0; - // speed might get set to 0 on this update + /* -- update state ----------------------------------------- */ + + // speed might be set to 0 on this update if (entity_speed != 0.0f) entity_dirty = true; - // jumpdrive - // target axis - math::Axis target_axis(entity_axis); - if (entity_state == core::Entity::Docked) { target_thrust = 0; @@ -257,7 +269,6 @@ void Ship::frame(float seconds) entity_speed = 0; entity_thrust = 0; - return; } else if (entity_state == core::Entity::JumpInitiate) { @@ -267,10 +278,6 @@ void Ship::frame(float seconds) if (entity_timer <= 0) { if (ship_jumpdepart && ship_jumpdepart->target()) { set_state(core::Entity::Jump); - set_zone(ship_jumpdepart->target()->zone()); - if (owner() && owner()->control() == (EntityControlable*) this) - owner()->set_zone(ship_jumpdepart->target()->zone()); - if (ship_jumpdepart->moduletype() == jumpgate_enttype) { entity_axis.assign(ship_jumpdepart->target()->axis()); entity_location.assign(ship_jumpdepart->target()->location()); @@ -278,6 +285,8 @@ void Ship::frame(float seconds) } else { entity_location.assign(ship_jumpdepart->target()->location() + location() - ship_jumpdepart->location()); } + + set_zone(ship_jumpdepart->target()->zone()); owner()->send("^BJumping to the " + ship_jumpdepart->target()->zone()->name()); } else { set_state(core::Entity::Normal); @@ -302,6 +311,7 @@ void Ship::frame(float seconds) target_thrust = 0.1; } else if (entity_state == core::Entity::Jump) { + // control is disabled while the jumpdrive is activated target_thrust = 0; target_pitch = 0; @@ -345,6 +355,7 @@ void Ship::frame(float seconds) math::clamp(target_roll, -1.0f, 1.0f); math::clamp(target_direction, -1.0f, 1.0f); math::clamp(target_afterburner, -1.0f, 1.0f); + actual_turnspeed *= 0.5; } else if (entity_state == core::Entity::Impulse) { @@ -355,6 +366,7 @@ void Ship::frame(float seconds) math::clamp(target_roll, -1.0f, 1.0f); math::clamp(target_direction, -1.0f, 1.0f); target_afterburner = 0.0f; + actual_maxspeed = Game::g_impulsespeed->value(); actual_acceleration = Game::g_impulseacceleration->value(); actual_turnspeed *= 0.5; @@ -385,6 +397,41 @@ void Ship::frame(float seconds) entity_thrust = 0; } + // update afterburner + if (current_target_afterburner < target_afterburner) { + current_target_afterburner += 2.0f * seconds; + if (current_target_afterburner > target_afterburner) + current_target_afterburner = target_afterburner; + } else if (current_target_afterburner > target_afterburner) { + current_target_afterburner -= 2.0f * seconds; + if (current_target_afterburner < target_afterburner) + current_target_afterburner = target_afterburner; + } + + // update thrust + if (current_target_afterburner < 0.0f) { + target_thrust = 0; + } + + if (entity_thrust < target_thrust) { + entity_thrust += seconds * 0.5f; + if (entity_thrust > target_thrust) + entity_thrust = target_thrust; + } else if (entity_thrust > target_thrust) { + entity_thrust -= seconds * 0.5f; + if (entity_thrust < target_thrust) + entity_thrust = target_thrust; + } + math::clamp(entity_thrust, 0.0f, 1.0f); + actual_thrust = entity_thrust + current_target_afterburner * 0.15f; + if ((entity_state == core::Entity::ImpulseInitiate) || (entity_state == core::Entity::Impulse)) { + actual_thrust = 1.0f; + } + +#ifndef HAVE_BULLET + + /* -- original frame --------------------------------------- */ + // update roll if (current_target_roll < target_roll) { current_target_roll += direction_change_speed * seconds; @@ -450,38 +497,6 @@ void Ship::frame(float seconds) entity_axis.rotate(n, -angle); } - // update afterburner - if (current_target_afterburner < target_afterburner) { - current_target_afterburner += 2.0f * seconds; - if (current_target_afterburner > target_afterburner) - current_target_afterburner = target_afterburner; - } else if (current_target_afterburner > target_afterburner) { - current_target_afterburner -= 2.0f * seconds; - if (current_target_afterburner < target_afterburner) - current_target_afterburner = target_afterburner; - } - - // update thrust - if (current_target_afterburner < 0.0f) { - target_thrust = 0; - } - - if (entity_thrust < target_thrust) { - entity_thrust += seconds * 0.5f; - if (entity_thrust > target_thrust) - entity_thrust = target_thrust; - } else if (entity_thrust > target_thrust) { - entity_thrust -= seconds * 0.5f; - if (entity_thrust < target_thrust) - entity_thrust = target_thrust; - } - math::clamp(entity_thrust, 0.0f, 1.0f); - float actual_thrust = entity_thrust + current_target_afterburner * 0.15f; - - if ((entity_state == core::Entity::ImpulseInitiate) || (entity_state == core::Entity::Impulse)) { - actual_thrust = 1.0f; - } - // update speed if (entity_speed < actual_thrust * actual_maxspeed) { entity_speed += actual_acceleration * seconds; @@ -510,6 +525,31 @@ void Ship::frame(float seconds) entity_location += entity_axis.left() * (current_target_strafe * 0.15f * actual_maxspeed) * seconds; } + if (entity_speed) { + entity_location += entity_axis.forward() * entity_speed * seconds; + } + +#else /* #ifndef HAVE_BULLET */ + + /* -- bullet frame ----------------------------------------- */ + + // get entity speed from physics body + btVector3 velocity(body()->getInterpolationLinearVelocity()); + entity_speed = velocity.length(); + + // get physics body world transformation + btTransform t; + body()->getMotionState()->getWorldTransform(t); + + // get entity location from physics body + btVector3 v(t.getOrigin()); + location().assign(v[0], v[1], v[2]); + + // apply engine trust to the body + body()->applyCentralImpulse(to_btVector3(axis().forward() * actual_thrust * actual_acceleration * seconds * 10.0f)); + +#endif /* else #ifndef HAVE_BULLET */ + entity_movement = target_thrust; entity_movement = math::max(entity_movement, fabs(current_target_pitch)); entity_movement = math::max(entity_movement, fabs(current_target_direction)); @@ -517,10 +557,7 @@ void Ship::frame(float seconds) entity_movement = math::max(entity_movement, fabs(current_target_afterburner)); entity_movement = math::max(entity_movement, fabs(current_target_strafe)); - if (entity_speed) { - entity_location += entity_axis.forward() * entity_speed * seconds; - entity_dirty = true; - } else if (entity_movement > 0.0f) { + if ((entity_movement > 0)|| (entity_speed > 0)) { entity_dirty = true; } } diff --git a/src/game/base/ship.h b/src/game/base/ship.h index 37f8b88..21987e7 100644 --- a/src/game/base/ship.h +++ b/src/game/base/ship.h @@ -9,6 +9,7 @@ #include "core/player.h" #include "core/entity.h" +#include "base/physics.h" #include "base/shipmodel.h" #include "base/jumppoint.h" #include "math/vector3f.h" @@ -16,7 +17,7 @@ namespace game { /// A ship in the game, controled by a player -class Ship : public core::EntityControlable +class Ship : public core::EntityControlable, public PhysicsBody { public: Ship(core::Player *owner, ShipModel *shipmodel); @@ -25,6 +26,9 @@ public: /// update the ship state virtual void frame(float seconds); + /// move the ship to a different zone + virtual void set_zone(core::Zone *zone); + /// true if the ship is equiped with a jumpdrive inline bool jumpdrive() const { return ship_jumpdrive; } diff --git a/src/game/base/station.cc b/src/game/base/station.cc index 69949fb..67c1595 100644 --- a/src/game/base/station.cc +++ b/src/game/base/station.cc @@ -10,7 +10,7 @@ namespace game { -Station::Station() : Entity() +Station::Station() : Entity(), PhysicsBody(this) { entity_moduletypeid = station_enttype; set_flag(core::Entity::Dockable); @@ -22,6 +22,8 @@ Station::~Station() { if (station_shipdealer) delete station_shipdealer; + + shutdown_physics(); } void Station::set_shipdealer(ShipDealer *shipdealer) diff --git a/src/game/base/station.h b/src/game/base/station.h index 3fc2158..ae4d0f4 100644 --- a/src/game/base/station.h +++ b/src/game/base/station.h @@ -8,10 +8,11 @@ #define __INCLUDED_BASE_STATION_H__ #include "base/shipdealer.h" +#include "base/physics.h" namespace game { -class Station : public core::Entity +class Station : public core::Entity, public PhysicsBody { public: Station(); |