From 1687737ca713cd0baeca3cf79950ef4877640c99 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Thu, 5 May 2011 18:08:45 +0000 Subject: Initial support for btCompoundShape and the infrastructure required to accomodate multiple meshes per collision model, added prototype files for signals --- src/core/Makefile.am | 2 + src/core/entity.cc | 236 +++++++++++++++++++++++++++++++++++--------- src/core/entity.h | 16 ++- src/core/physics.cc | 4 +- src/core/signals.cc | 16 +++ src/core/signals.h | 51 ++++++++++ src/model/Makefile.am | 2 + src/model/collisionmesh.cc | 27 +++-- src/model/collisionmesh.h | 31 +++--- src/model/collisionmodel.cc | 76 ++++++++++++++ src/model/collisionmodel.h | 111 +++++++++++++++++++++ src/model/mapfile.cc | 83 +++++++++------- src/model/mapfile.h | 1 + src/model/model.cc | 6 +- src/model/model.h | 12 +-- 15 files changed, 552 insertions(+), 122 deletions(-) create mode 100644 src/core/signals.cc create mode 100644 src/core/signals.h create mode 100644 src/model/collisionmodel.cc create mode 100644 src/model/collisionmodel.h (limited to 'src') diff --git a/src/core/Makefile.am b/src/core/Makefile.am index ce76303..e6b98e5 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -31,6 +31,7 @@ noinst_HEADERS = \ physics.h \ player.h \ range.h \ + signals.h \ stats.h \ timer.h \ zone.h @@ -60,6 +61,7 @@ libcore_la_SOURCES = \ parser.cc \ physics.cc \ player.cc \ + signals.cc \ stats.cc \ timer.cc \ zone.cc diff --git a/src/core/entity.cc b/src/core/entity.cc index ec25017..64812cc 100644 --- a/src/core/entity.cc +++ b/src/core/entity.cc @@ -150,7 +150,6 @@ Entity::Entity() : entity_body = 0; entity_body_info = 0; - entity_collision_shape = 0; entity_speed = 0.0f; @@ -189,7 +188,6 @@ Entity::Entity(std::istream & is) entity_body = 0; entity_body_info = 0; - entity_collision_shape = 0; entity_speed = 0.0f; @@ -214,8 +212,9 @@ Entity::~Entity() } // delete entity menus - for (Menus::iterator it = menus().begin(); it != menus().end(); it++) { - delete(*it); + for (Menus::iterator mit = menus().begin(); mit != menus().end(); mit++) { + delete (*mit); + (*mit) = 0; } menus().clear(); @@ -231,8 +230,11 @@ Entity::~Entity() } } - if (entity_collision_shape) - delete entity_collision_shape; + for (CollisionShapes::iterator sit = entity_collision_shapes.begin(); sit != entity_collision_shapes.end(); sit++) { + delete (*sit); + (*sit) = 0; + } + entity_collision_shapes.clear(); if (entity_body) delete entity_body; @@ -498,33 +500,82 @@ void Entity::reset() // construct physics body if necessary if (!entity_body) { + btCollisionShape * myshape = 0; + // create collision shape if (model() && model()->radius()) { const float modelscale = radius() / model()->radius(); - if (flag_is_set(Complex) && model()->collisionmesh()) { - // use collision mesh - // static entities use a btBvhTriangleMeshShape - btBvhTriangleMeshShape *meshshape = new btBvhTriangleMeshShape(model()->collisionmesh()->triangles(), true, true); - meshshape->buildOptimizedBvh(); - meshshape->recalcLocalAabb(); + if (flag_is_set(Complex) && model()->collisionmodel() && model()->collisionmodel()->size()) { + if (model()->collisionmodel()->size() == 1 ) { + // the collision model only has a single mesh, + // we can use a triangle mesh shape + + model::CollisionMesh *mesh = (*model()->collisionmodel()->meshes().begin()); + + // static entities use a btBvhTriangleMeshShape + btBvhTriangleMeshShape *meshshape = new btBvhTriangleMeshShape(mesh->triangles(), true, true); + meshshape->buildOptimizedBvh(); + meshshape->recalcLocalAabb(); + + btVector3 modelscalevec(modelscale, modelscale, modelscale); + meshshape->setLocalScaling(modelscalevec); + + shapes().push_back(meshshape); + myshape = meshshape; - btVector3 modelscalevec(modelscale, modelscale, modelscale); - meshshape->setLocalScaling(modelscalevec); + } else { + // the collision model has multiple meshes that need to be + // combined into a compound shape + btCompoundShape *compoundshape = new btCompoundShape(); + + for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin(); + it != model()->collisionmodel()->meshes().end(); it++) { + + model::CollisionMesh *mesh = (*it); + btTransform childtransform; + childtransform.setIdentity(); + + // static entities use a btBvhTriangleMeshShape + btBvhTriangleMeshShape *meshshape = new btBvhTriangleMeshShape(mesh->triangles(), true, true); + meshshape->buildOptimizedBvh(); + meshshape->recalcLocalAabb(); + + // FIXME apply vertexgroup transformations + compoundshape->addChildShape(childtransform, meshshape); + shapes().push_back(meshshape); + } + + btVector3 modelscalevec(modelscale, modelscale, modelscale); + compoundshape->setLocalScaling(modelscalevec); + + shapes().push_back(compoundshape); + myshape = compoundshape; + } - entity_collision_shape = meshshape; } else { // use bounding box - entity_collision_shape = new btBoxShape(to_btVector3(model()->box().max() * modelscale)); + btBoxShape *boxshape = new btBoxShape(to_btVector3(model()->box().max() * modelscale)); + shapes().push_back(boxshape); + myshape = boxshape; } + } else { - entity_collision_shape = new btSphereShape(radius()); + // use a sphere with a radius matching the entity + btSphereShape *sphereshape = new btSphereShape(radius()); + shapes().push_back(sphereshape); + myshape = sphereshape; + + } + + // set margin on each mesh + for (CollisionShapes::iterator it = shapes().begin(); it != shapes().end(); it++) { + (*it)->setMargin(Cvar::sv_collisionmargin->value()); } - entity_collision_shape->setMargin(Cvar::sv_collisionmargin->value()); - btVector3 inertia(0, 0, 0); // create physics body - entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(0, 0, entity_collision_shape, inertia); + btVector3 inertia(0, 0, 0); + entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(0, 0, myshape, inertia); entity_body = new btRigidBody(*entity_body_info); entity_body->setActivationState(ISLAND_SLEEPING); @@ -587,38 +638,81 @@ void EntityDynamic::reset() // construct physics body if necessary if (!entity_body) { + btCollisionShape * myshape = 0; + // create collision shape if (model() && model()->radius()) { const float modelscale = radius() / model()->radius(); - if (flag_is_set(Complex) && model()->collisionmesh()) { - // use collision mesh - // dynamic entities use a btGImpactMeshShape - btGImpactMeshShape *meshshape = new btGImpactMeshShape(model()->collisionmesh()->triangles()); + if (flag_is_set(Complex) && model()->collisionmodel() && model()->collisionmodel()->size()) { + if (model()->collisionmodel()->size() == 1 ) { + // the collision model only has a single mesh, + // we can use a triangle mesh shape + + model::CollisionMesh *mesh = (*model()->collisionmodel()->meshes().begin()); + + // static entities use a btBvhTriangleMeshShape + btGImpactMeshShape *meshshape = new btGImpactMeshShape(mesh->triangles()); + btVector3 modelscalevec(modelscale, modelscale, modelscale); + meshshape->setLocalScaling(modelscalevec); + + shapes().push_back(meshshape); + myshape = meshshape; - btVector3 modelscalevec(modelscale, modelscale, modelscale); - meshshape->setLocalScaling(modelscalevec); - meshshape->updateBound(); + } else { + // the collision model has multiple meshes that need to be + // combined into a compound shape + btCompoundShape *compoundshape = new btCompoundShape(); + + for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin(); + it != model()->collisionmodel()->meshes().end(); it++) { + + model::CollisionMesh *mesh = (*it); + btTransform childtransform; + + // dynamic entities use a btGImpactMeshShape + btGImpactMeshShape *meshshape = new btGImpactMeshShape(mesh->triangles()); + // FIXME apply vertexgroup transformations + compoundshape->addChildShape(childtransform, meshshape); + shapes().push_back(meshshape); + } + + btVector3 modelscalevec(modelscale, modelscale, modelscale); + compoundshape->setLocalScaling(modelscalevec); + + shapes().push_back(compoundshape); + myshape = compoundshape; + } - entity_collision_shape = meshshape; } else { // use bounding box - entity_collision_shape = new btBoxShape(to_btVector3(model()->box().max() * modelscale)); + btBoxShape *boxshape = new btBoxShape(to_btVector3(model()->box().max() * modelscale)); + shapes().push_back(boxshape); + myshape = boxshape; } + } else { - entity_collision_shape = new btSphereShape(radius()); + // use a sphere with a radius matching the entity + btSphereShape *sphereshape = new btSphereShape(radius()); + shapes().push_back(sphereshape); + myshape = sphereshape; + } - entity_collision_shape->setMargin(Cvar::sv_collisionmargin->value()); + // set margin on each mesh + for (CollisionShapes::iterator it = shapes().begin(); it != shapes().end(); it++) { + (*it)->setMargin(Cvar::sv_collisionmargin->value()); + } + btVector3 inertia(0, 0, 0); if (entity_mass) - entity_collision_shape->calculateLocalInertia(entity_mass, inertia); + myshape->calculateLocalInertia(entity_mass, inertia); // create motion state entity_motionstate = new btDefaultMotionState(t); // create physics body - entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(entity_mass, entity_motionstate, entity_collision_shape, inertia); + entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(entity_mass, entity_motionstate, myshape, inertia); entity_body = new btRigidBody(*entity_body_info); if (entity_mass) { @@ -1009,37 +1103,87 @@ void EntityControlable::reset() // construct physics body if necessary if (!entity_body) { + btCollisionShape * myshape = 0; + // create collision shape if (model() && model()->radius()) { const float modelscale = radius() / model()->radius(); - if (flag_is_set(Complex) && model()->collisionmesh()) { - // use collision mesh - // dynamic entities use a btGImpactMeshShape - btGImpactMeshShape *meshshape = new btGImpactMeshShape(model()->collisionmesh()->triangles()); + if (flag_is_set(Complex) && model()->collisionmodel() && (model()->collisionmodel()->size() > 0) ) { + if (model()->collisionmodel()->size() == 1 ) { + // the collision model only has a single mesh, + // we can use a triangle mesh shape + + model::CollisionMesh *mesh = (*model()->collisionmodel()->meshes().begin()); + + // dynamic entities use a btGImpactMeshShape + btGImpactMeshShape *meshshape = new btGImpactMeshShape(mesh->triangles()); + btVector3 modelscalevec(modelscale, modelscale, modelscale); + meshshape->setLocalScaling(modelscalevec); + + shapes().push_back(meshshape); + myshape = meshshape; + meshshape->updateBound(); - btVector3 modelscalevec(modelscale, modelscale, modelscale); - meshshape->setLocalScaling(modelscalevec); - meshshape->setMargin(Cvar::sv_collisionmargin->value()); - meshshape->updateBound(); + } else { + // the collision model has multiple meshes that need to be + // combined into a compound shape + btCompoundShape *compoundshape = new btCompoundShape(); + btVector3 modelscalevec(modelscale, modelscale, modelscale); + + for (model::CollisionModel::CollisionMeshes::iterator it = model()->collisionmodel()->meshes().begin(); + it != model()->collisionmodel()->meshes().end(); it++) { + + model::CollisionMesh *mesh = (*it); + btTransform childtransform; + childtransform.setIdentity(); + + // dynamic entities use a btGImpactMeshShape + btGImpactMeshShape *meshshape = new btGImpactMeshShape(mesh->triangles()); + meshshape->setLocalScaling(modelscalevec); + meshshape->updateBound(); + + // FIXME apply vertexgroup transformations + compoundshape->addChildShape(childtransform, meshshape); + shapes().push_back(meshshape); + } + + + + + shapes().push_back(compoundshape); + myshape = compoundshape; + } - entity_collision_shape = meshshape; } else { // use bounding box - entity_collision_shape = new btBoxShape(to_btVector3(model()->box().max() * modelscale)); + btBoxShape *boxshape = new btBoxShape(to_btVector3(model()->box().max() * modelscale)); + shapes().push_back(boxshape); + myshape = boxshape; } + } else { - entity_collision_shape = new btSphereShape(radius()); + // use a sphere with a radius matching the entity + btSphereShape *sphereshape = new btSphereShape(radius()); + shapes().push_back(sphereshape); + myshape = sphereshape; + } + + // set margin on each mesh + for (CollisionShapes::iterator it = shapes().begin(); it != shapes().end(); it++) { + (*it)->setMargin(Cvar::sv_collisionmargin->value()); + } + btVector3 inertia(0, 0, 0); if (entity_mass) - entity_collision_shape->calculateLocalInertia(entity_mass, inertia); + myshape->calculateLocalInertia(entity_mass, inertia); // create motion state entity_motionstate = new btDefaultMotionState(t); // create physics body - entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(entity_mass, entity_motionstate, entity_collision_shape, inertia); + entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(entity_mass, entity_motionstate, myshape, inertia); entity_body = new btRigidBody(*entity_body_info); entity_body->setActivationState(DISABLE_DEACTIVATION); diff --git a/src/core/entity.h b/src/core/entity.h index 54849b7..a356525 100644 --- a/src/core/entity.h +++ b/src/core/entity.h @@ -57,6 +57,9 @@ public: /// entity menus collection typedef typedef std::list Menus; + + /// type definition for entity bullet shapes collection + typedef std::list CollisionShapes; /// create a new entity and add it to the registry Entity(); @@ -164,8 +167,8 @@ public: } /// physics collision shape - inline btCollisionShape *collision_shape() { - return entity_collision_shape; + inline CollisionShapes collision_shapes() { + return entity_collision_shapes; } /// indicates a server-side entity @@ -192,6 +195,11 @@ public: inline Menus &menus() { return entity_menus; } + + /// entity collision shapes + inline CollisionShapes & shapes() { + return entity_collision_shapes; + } /// extensions inline Extension *extension(size_t type) const { @@ -445,9 +453,9 @@ public: protected: btRigidBody *entity_body; btRigidBody::btRigidBodyConstructionInfo *entity_body_info; - btCollisionShape *entity_collision_shape; + CollisionShapes entity_collision_shapes; - // the zone the entity belongs to + // the zone the entity belongs to Zone* entity_zone; // the previous zone the entity belonged too Zone* entity_oldzone; diff --git a/src/core/physics.cc b/src/core/physics.cc index 5504c50..90fb184 100644 --- a/src/core/physics.cc +++ b/src/core/physics.cc @@ -21,7 +21,7 @@ void Physics::init() { con_print << "^BInitializing physics engine..." << std::endl; - model::CollisionMesh::init(); + model::CollisionModel::init(); physics_configuration = new btDefaultCollisionConfiguration(); physics_dispatcher = new btCollisionDispatcher(physics_configuration); @@ -35,7 +35,7 @@ void Physics::done() { con_print << "^BShutting down physics engine..." << std::endl; - model::CollisionMesh::shutdown(); + model::CollisionModel::shutdown(); delete physics_solver; delete physics_dispatcher; diff --git a/src/core/signals.cc b/src/core/signals.cc new file mode 100644 index 0000000..f05b328 --- /dev/null +++ b/src/core/signals.cc @@ -0,0 +1,16 @@ +/* + core/signals.cc + This file is part of the Osirion project and is distributed under + the terms and conditions of the GNU General Public License version 2 +*/ + +#include "core/signals.h" + +namespace core { + +void Signal::send(Player *sender, Player *reciever, Signals signal) +{ + +} + +} // namespace core \ No newline at end of file diff --git a/src/core/signals.h b/src/core/signals.h new file mode 100644 index 0000000..88841ea --- /dev/null +++ b/src/core/signals.h @@ -0,0 +1,51 @@ +/* + core/signals.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_CORE_SIGNALS_H__ +#define __INCLUDED_CORE_SIGNALS_H__ + +#include + +#include "core/player.h" + +namespace core +{ + +/** + * @brief a signal is a confirmation request from one player to another. + */ +class Signal { +public: + /// signal types + enum Signals {Trade = 1, Dock = 2, Chat = 3}; + + /// current state of a signal + enum State {Rejected = 0, Accepted = 1, Pending = 2}; + + + /// type definition for the signal registry + typedef std::list Registry; + + static void send(Player *sender, Player *receiver, Signals signal); + + static void init(); + + static void done(); + + static void clear(); + +private: + Signals signal_type; + State signal_state; + unsigned long signal_timestamp; + + static Registry signal_registry; +}; + +} + +#endif // __INCLUDED_CORE_SIGNALS_H__ + diff --git a/src/model/Makefile.am b/src/model/Makefile.am index de6d902..3552392 100644 --- a/src/model/Makefile.am +++ b/src/model/Makefile.am @@ -6,6 +6,7 @@ noinst_LTLIBRARIES = libmodel.la noinst_HEADERS = \ asefile.h \ collisionmesh.h \ + collisionmodel.h \ face.h \ fragment.h \ mapfile.h \ @@ -21,6 +22,7 @@ noinst_HEADERS = \ libmodel_la_SOURCES = \ asefile.cc \ collisionmesh.cc \ + collisionmodel.cc \ face.cc \ fragment.cc \ mapfile.cc \ diff --git a/src/model/collisionmesh.cc b/src/model/collisionmesh.cc index 5d4505a..5d2328a 100644 --- a/src/model/collisionmesh.cc +++ b/src/model/collisionmesh.cc @@ -26,7 +26,7 @@ void CollisionMesh::shutdown() void CollisionMesh::add(CollisionMesh *collisionmesh) { - collisionmesh_registry[collisionmesh->name()] = collisionmesh; + collisionmesh_registry.push_back(collisionmesh); } void CollisionMesh::clear() @@ -34,26 +34,16 @@ void CollisionMesh::clear() con_debug << " clearing collision meshes" << std::endl; for (Registry::iterator i = collisionmesh_registry.begin(); i != collisionmesh_registry.end(); ++i) { - delete (*i).second; - (*i).second = 0; + delete (*i); + (*i) = 0; } collisionmesh_registry.clear(); } -CollisionMesh *CollisionMesh::find(const std::string &name) -{ - for (Registry::iterator i = collisionmesh_registry.begin(); i != collisionmesh_registry.end(); ++i) { - if ((*i).first.compare(name) == 0) - return (*i).second; - } - - return 0; -} - -CollisionMesh::CollisionMesh(const std::string &name) : - collisionmesh_name(name) +CollisionMesh::CollisionMesh() { + collisionmesh_type = FragmentGroup::None; collisionmesh_size = 0; // btTriangleMesh (bool use32bitIndices=true, bool use4componentVertices=true) collisionmesh_triangles = new btTriangleMesh(true, false); @@ -64,6 +54,11 @@ CollisionMesh::~CollisionMesh() delete collisionmesh_triangles; } +void CollisionMesh::set_type(const FragmentGroup::Type type) +{ + collisionmesh_type = type; +} + void CollisionMesh::add_triangle(const math::Vector3f & v0, const math::Vector3f & v1, const math::Vector3f & v2) { collisionmesh_triangles->addTriangle( @@ -72,7 +67,7 @@ void CollisionMesh::add_triangle(const math::Vector3f & v0, const math::Vector3f to_btVector3(v2), true ); - collisionmesh_size += 1; + collisionmesh_size++; } } // namespace model diff --git a/src/model/collisionmesh.h b/src/model/collisionmesh.h index 9efd21a..cbd063a 100644 --- a/src/model/collisionmesh.h +++ b/src/model/collisionmesh.h @@ -8,6 +8,7 @@ #define __INCLUDED_MODEL_COLLISIONMESH_H__ #include "math/mathlib.h" +#include "model/fragment.h" #include "BulletCollision/CollisionShapes/btTriangleMesh.h" @@ -17,23 +18,23 @@ namespace model { +/** + * @brief a collection of triangles, representing the collision geometry of a model + * A CollisionModel consists of a number of collisionmeshes. + * */ class CollisionMesh { public: - /// type definition for the material registry - typedef std::map Registry; + /// type definition for the collisionmesh registry + typedef std::list Registry; - CollisionMesh(const std::string &name); + CollisionMesh(); ~CollisionMesh(); /* ---- inspectors ----------------------------------------- */ - inline const std::string &name() const { - return collisionmesh_name; - } - /** * @brief the number of triangles in the collision mesh */ @@ -41,10 +42,6 @@ public: return collisionmesh_size; } - static bool initialized() { - return collisionmesh_initialized; - } - /** * @brief the bullet triangle mesh object */ @@ -53,6 +50,11 @@ public: } /* ---- mutators ------------------------------------------- */ + + /** + * @brief change the group type + * */ + void set_type(const FragmentGroup::Type type); /** * @brief add a triangle to the collision mesh @@ -86,15 +88,20 @@ public: */ static void add(CollisionMesh *collisionmesh); + + static bool initialized() { + return collisionmesh_initialized; + } + private: /// the materials registry static Registry collisionmesh_registry; static bool collisionmesh_initialized; - std::string collisionmesh_name; size_t collisionmesh_size; btTriangleMesh *collisionmesh_triangles; + FragmentGroup::Type collisionmesh_type; }; } // namespace model diff --git a/src/model/collisionmodel.cc b/src/model/collisionmodel.cc new file mode 100644 index 0000000..d52c9bc --- /dev/null +++ b/src/model/collisionmodel.cc @@ -0,0 +1,76 @@ +/* + model/collisionmodel.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "sys/sys.h" +#include "model/collisionmodel.h" + +namespace model { + +CollisionModel::CollisionModel(const std::string & label) : + collisionmodel_label(label) +{ + +} + +CollisionModel::~CollisionModel() +{ + // clear the list of meshes, do not delete the meshes + for (CollisionMeshes::iterator it = collisionmodel_meshes.begin(); it != collisionmodel_meshes.end(); it++) { + (*it) = 0; + } + collisionmodel_meshes.clear(); +} + +void CollisionModel::add_mesh(CollisionMesh *mesh) +{ + collisionmodel_meshes.push_back(mesh); +} + +/* ---- static methods --------------------------------------------- */ + +CollisionModel::Registry CollisionModel::collisionmodel_registry; + +void CollisionModel::init() +{ + CollisionMesh::init(); + clear(); +} + +void CollisionModel::shutdown() +{ + clear(); + CollisionMesh::shutdown(); +} + +CollisionModel *CollisionModel::find(const std::string & label) +{ + for (Registry::iterator it = collisionmodel_registry.begin(); it != collisionmodel_registry.end(); it++) { + CollisionModel *cmodel = (*it); + if (cmodel->label().compare(label) == 0) + return cmodel; + + } + return 0; +} + +void CollisionModel::clear() +{ + for (Registry::iterator it = collisionmodel_registry.begin(); it != collisionmodel_registry.end(); it++) { + CollisionModel *collisionmodel = (*it); + delete collisionmodel; + (*it) = 0; + } + collisionmodel_registry.clear(); + con_debug << " clearing collision models" << std::endl; + +} + +void CollisionModel::add(CollisionModel *collisionmodel) +{ + collisionmodel_registry.push_back(collisionmodel); +} + +} //namespace model \ No newline at end of file diff --git a/src/model/collisionmodel.h b/src/model/collisionmodel.h new file mode 100644 index 0000000..04268d2 --- /dev/null +++ b/src/model/collisionmodel.h @@ -0,0 +1,111 @@ +/* + model/collisionmodel.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_MODEL_COLLISIONMODEL_H__ +#define __INCLUDED_MODEL_COLLISIONMODEL_H__ + +#include +#include + +#include "math/mathlib.h" +#include "model/collisionmesh.h" + +namespace model +{ + +/** + * @brief a container class for collision geometry + * The CollisionModel class holds a list of references to one or more CollisionMeshes. + * It is referenced by a single Model, and the static registry takes ownership of the + * CollisionModel instances. This is because a Model can be reloaded while the game is running, + * but the CollisionMeshes are tied to bullet physics and can not be reloaded on the fly. + * Note that the CollisionModel doesn't own its meshes either, it merely reference them. + * CollisionMeshes are stored in the static CollisionMesh::registry() and can be referenced + * by multiple CollisionModels. + */ +class CollisionModel +{ +public: + /** + * @brief type definition for the CollisionModel registry + * */ + typedef std::list Registry; + + /** + * @brief type definition for a lost of collision meshes + * */ + typedef std::list CollisionMeshes; + + /** + * @brief create a new collisionmodel with a give label + * */ + CollisionModel(const std::string & label); + ~CollisionModel(); + + inline const std::string &label() const { + return collisionmodel_label; + } + + /** + * @brief returns the number of meshes this collision model consists of + * */ + inline const size_t size() const { + return collisionmodel_meshes.size(); + } + + /** + * @brief the collection of meshes this model consists of + * */ + inline CollisionMeshes & meshes() { + return collisionmodel_meshes; + } + + /** + * @brief add a mesh to the CollisionModel + * CollisionModel does not take ownership of the COllisionMesh, + * the mesh should be registered with the CollisionMesh::registry + * */ + void add_mesh(CollisionMesh *mesh); + + /** + * @brief initialize the CollisionModel registry + * init() calls clear() + * */ + static void init(); + + /** + * @brief shutdown the CollisionModel registry + * shutdown() calls clear() + * */ + static void shutdown(); + + /** + * @brief clear the CollisionModel registry and delete all CollisionModel instances it holds + * */ + static void clear(); + + /** + * @brief add a CollisionModel to the registry + * the models label should be unique and not yet exist in the registry. + * */ + static void add(CollisionModel *collisionmodel); + + /** + * @brief search the registry for a model with a particular label, returns 0 if not found. + * */ + static CollisionModel *find(const std::string & label); + +private: + std::string collisionmodel_label; + CollisionMeshes collisionmodel_meshes; + + static Registry collisionmodel_registry; + +}; // class CollisionModel + +} // namespace model + +#endif // __INCLUDED_MODEL_COLLISIONMODEL_H__ diff --git a/src/model/mapfile.cc b/src/model/mapfile.cc index 20d4c5c..92349c0 100644 --- a/src/model/mapfile.cc +++ b/src/model/mapfile.cc @@ -174,6 +174,8 @@ void MapFile::clear_materials() delete(*mit).second; } map_materials.clear(); + + map_collisiontriangles.clear(); } bool MapFile::open(std::string const & mapname) @@ -357,12 +359,12 @@ bool MapFile::read_patchdef() std::string word; if (!(linestream >> word)) { - //con_debug << "Error reading trialing line ')'" << std::endl; + //con_debug << "Error reading trailing line ')'" << std::endl; return false; } if (word.compare(")") != 0) { - //con_debug << "No trialing line ')'" << std::endl; + //con_debug << "No trailing line ')'" << std::endl; return false; } } @@ -1300,8 +1302,25 @@ void MapFile::load_fragmentgroup(Model *model, const FragmentGroup::Type class_t } - // add the group to the model + // add the vertexgroup to the model model->add_group(group); + + // add collision triangles + if (map_load_clip) { + if (map_collisiontriangles.size()) { + CollisionMesh *collisionmesh = new CollisionMesh(); + + // add clip triangles to collision mesh + for (TriangleList::iterator it = map_collisiontriangles.begin(); it != map_collisiontriangles.end(); it++) { + Triangle *triangle = (*it); + collisionmesh->add_triangle(triangle->v0() - translation, triangle->v1() - translation, triangle->v2() - translation); + } + + // add the collision mesh to the collision model + model->collisionmodel()->add_mesh(collisionmesh); + } + } + } void MapFile::unknown_value() const @@ -1365,17 +1384,18 @@ Model * MapFile::load(std::string const &name) float r, s; std::string str; - // load clip into collision mesh - // if the model has been loaded before (e.g. on r_restart), the collision mesh won't be reloaded - // submodel clip will not be imported - model->set_collisionmesh(CollisionMesh::find(name)); - - if (CollisionMesh::initialized() && !model->collisionmesh()) { - mapfile.map_load_clip = true; + // load clip into collision meshes + // if the model has been loaded before (e.g. on r_restart), the collision model won't be reloaded + mapfile.map_collisionmodel = CollisionModel::find(name); + if (!mapfile.map_collisionmodel) { + mapfile.map_load_clip = true; + mapfile.map_collisionmodel = new CollisionModel(name); + CollisionModel::add(mapfile.map_collisionmodel); } else { mapfile.map_load_clip = false; } - + model->set_collisionmodel(mapfile.map_collisionmodel); + while (mapfile.getline()) { if (mapfile.got_classname("worldspawn")) { mapfile.clear_bbox(); @@ -1840,6 +1860,12 @@ Model * MapFile::load(std::string const &name) delete groupdst; } } + + /* TODO + * + * import submodel collision meshes + */ + // copy light tags for (Model::Lights::const_iterator lit = submodel_model->lights().begin(); lit != submodel_model->lights().end(); lit++) { @@ -1921,31 +1947,22 @@ Model * MapFile::load(std::string const &name) con_warn << mapfile.name() << " quake2 style brushes detected" << std::endl; con_debug << " " << mapfile.name() << " " << mapfile.map_brushes << " brushes " << - model->model_tris_detail_count << "/" << model->model_tris_count << " detail/tris " << - model->model_quad_detail_count << "/" << model->model_quad_count << " detail/quads" << std::endl; + model->model_tris_count << " triangles " << + model->model_quad_count << " quads" << std::endl; - if (mapfile.map_load_clip) { - if (mapfile.map_collisiontriangles.size()) { - - CollisionMesh *collisionmesh = new CollisionMesh(name); - - // add clip triangles to collision mesh - for (TriangleList::iterator it = mapfile.map_collisiontriangles.begin(); it != mapfile.map_collisiontriangles.end(); it++) { - Triangle *triangle = (*it); - collisionmesh->add_triangle(triangle->v0() - map_center, triangle->v1() - map_center, triangle->v2() - map_center); - } - - // TODO merge submodel collision meshes - // seperate collision meshes for movers - - // register the mesh - CollisionMesh::add(collisionmesh); - model->set_collisionmesh(collisionmesh); - - con_debug << " " << mapfile.name() << " " << model->collisionmesh()->size() << " collision triangles" << std::endl; + if (mapfile.map_load_clip && model->collisionmodel() && model->collisionmodel()->meshes().size()) { + size_t collision_tris_count = 0; // total number of triangles in the collision model + size_t collision_mesh_count = 0; // number of meshes in the collision model + + for (CollisionModel::CollisionMeshes::const_iterator cmit = model->collisionmodel()->meshes().begin(); + cmit != model->collisionmodel()->meshes().end(); cmit++) { + collision_tris_count += (*cmit)->size(); + collision_mesh_count++; } + + con_debug << " " << mapfile.name() << " collision " << collision_tris_count << " triangles " << collision_mesh_count << " meshes" << std::endl; } - + return model; } diff --git a/src/model/mapfile.h b/src/model/mapfile.h index b576384..011c01d 100644 --- a/src/model/mapfile.h +++ b/src/model/mapfile.h @@ -184,6 +184,7 @@ private: bool last_read_was_classend; bool map_load_clip; + CollisionModel *map_collisionmodel; unsigned int map_brushes; unsigned int map_faces; diff --git a/src/model/model.cc b/src/model/model.cc index d1805df..ab89dae 100644 --- a/src/model/model.cc +++ b/src/model/model.cc @@ -30,7 +30,7 @@ Model::Model(const std::string & name) : model_quad_detail_count = 0; model_quad_count = 0; - model_collisionmesh = 0; + model_collisionmodel = 0; } Model::~Model() @@ -72,8 +72,8 @@ Model::~Model() model_sounds.clear(); } -void Model::set_collisionmesh(CollisionMesh *collisionmesh) -{ model_collisionmesh = collisionmesh; +void Model::set_collisionmodel(CollisionModel *collisionmodel) +{ model_collisionmodel = collisionmodel; } diff --git a/src/model/model.h b/src/model/model.h index 8e3d82d..c15213c 100644 --- a/src/model/model.h +++ b/src/model/model.h @@ -13,7 +13,7 @@ #include "math/mathlib.h" -#include "model/collisionmesh.h" +#include "model/collisionmodel.h" #include "model/tags.h" #include "model/fragment.h" @@ -76,8 +76,8 @@ public: return model_groups; } - inline CollisionMesh *collisionmesh() { - return model_collisionmesh; + inline CollisionModel *collisionmodel() { + return model_collisionmodel; } /// list of model light tags @@ -150,8 +150,8 @@ public: /// set model radius void set_radius(const float radius); - /// set model collision mesh - void set_collisionmesh(CollisionMesh *collisionmesh); + /// set collision model + void set_collisionmodel(CollisionModel *collisionmodel); /// set model origin void set_origin(const math::Vector3f &origin); @@ -206,7 +206,7 @@ private: Groups model_groups; float model_radius; static Registry model_registry; - CollisionMesh *model_collisionmesh; + CollisionModel *model_collisionmodel; }; } -- cgit v1.2.3