Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.in82
-rw-r--r--doc/installation.html29
-rw-r--r--osirion.kdevelop2
-rw-r--r--src/Makefile.am9
-rw-r--r--src/game/base/Makefile.am9
-rw-r--r--src/game/base/game.cc53
-rw-r--r--src/game/base/physics.cc308
-rw-r--r--src/game/base/physics.h166
-rw-r--r--src/game/base/ship.cc147
-rw-r--r--src/game/base/ship.h6
-rw-r--r--src/game/base/station.cc4
-rw-r--r--src/game/base/station.h3
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();