From 38eb51c26ab0d9dbebc974c7a21f96a429ce3098 Mon Sep 17 00:00:00 2001
From: Stijn Buys <ingar@osirion.org>
Date: Tue, 8 Feb 2011 16:55:23 +0000
Subject: Corrected triangle loading of collision model, added 'complex' flag
 to ships.ini to enable collision models on player ships.

---
 src/core/entity.cc         | 95 ++++++++++++++++++++++++++++++++++++++--------
 src/core/entity.h          | 12 +++---
 src/game/base/ship.cc      |  4 +-
 src/game/base/shipmodel.cc |  7 ++++
 src/game/base/shipmodel.h  | 14 +++++++
 src/model/collisionmesh.cc |  3 +-
 6 files changed, 112 insertions(+), 23 deletions(-)

(limited to 'src')

diff --git a/src/core/entity.cc b/src/core/entity.cc
index 6aef6e5..7aa72fa 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_motionstate = 0;
 	entity_collision_shape = 0;
 	
 	entity_speed = 0.0f;
@@ -191,7 +190,6 @@ Entity::Entity(std::istream & is)
 
 	entity_body = 0;
 	entity_body_info = 0;
-	entity_motionstate = 0;
 	entity_collision_shape = 0;
 	
 	entity_speed = 0.0f;
@@ -235,9 +233,6 @@ Entity::~Entity()
 		}
 	}
 	
-	if (entity_motionstate)
-		delete entity_motionstate;
-	
 	if (entity_collision_shape)
 		delete entity_collision_shape;
 	
@@ -511,6 +506,7 @@ void Entity::reset()
 			
 			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(); 
@@ -519,7 +515,7 @@ void Entity::reset()
 				
 				btVector3 modelscalevec(modelscale, modelscale, modelscale);
 				meshshape->setLocalScaling(modelscalevec);
-				meshshape->setMargin(0.0f);
+				//meshshape->setMargin(0.0f);
 				//meshshape->updateBound();
 				
 				entity_collision_shape = meshshape;
@@ -536,14 +532,12 @@ void Entity::reset()
 		if (entity_mass)
 			entity_collision_shape->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, 0, entity_collision_shape, inertia);
 		
 		entity_body = new btRigidBody(*entity_body_info);
 		entity_body->setActivationState(ISLAND_SLEEPING);
+		entity_body->setCollisionFlags(entity_body->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT); 
 		
 		if (zone())
 			zone()->physics()->addRigidBody(entity_body);
@@ -553,7 +547,6 @@ void Entity::reset()
 	body()->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
 	body()->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
 	body()->setWorldTransform(t);
-	motionstate()->setWorldTransform(t);
 	
 	//if (zone())
 	//	zone()->physics()->synchronizeSingleMotionState(entity_body);
@@ -567,16 +560,20 @@ EntityDynamic::EntityDynamic() : Entity()
 {
 	entity_state = Normal;
 	entity_timer = 0;
+	entity_motionstate = 0;
 }
 
 EntityDynamic::EntityDynamic(std::istream & is) : Entity(is)
 {
 	entity_state = Normal;
 	entity_timer = 0;
+	entity_motionstate = 0;
 }
 
 EntityDynamic::~EntityDynamic()
 {
+	if (entity_motionstate)
+		delete entity_motionstate;
 }
 
 void EntityDynamic::set_state(int state)
@@ -593,7 +590,58 @@ void EntityDynamic::reset()
 		return;
 	}
 	
-	Entity::reset();
+	// location and orientation
+	btTransform t;
+	t.setIdentity();
+	t.setOrigin(to_btVector3(location()));
+	t.setBasis(to_btMatrix3x3(axis()));
+	
+	// construct physics body if necessary
+	if (!entity_body) {
+		// 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());
+				
+				btVector3 modelscalevec(modelscale, modelscale, modelscale);
+				meshshape->setLocalScaling(modelscalevec);
+				//meshshape->setMargin(0.0f);
+				meshshape->updateBound();
+				
+				entity_collision_shape = meshshape;			
+			} else {
+				// use bounding box
+				entity_collision_shape  = new btBoxShape(to_btVector3(model()->box().max() * modelscale));
+			}
+		} else {
+			entity_collision_shape  = new btSphereShape(radius());
+		}
+		btVector3 inertia(0, 0, 0);
+		if (entity_mass)
+			entity_collision_shape->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 = new btRigidBody(*entity_body_info);
+		entity_body->setActivationState(ISLAND_SLEEPING);
+		entity_body->setCollisionFlags(entity_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); 
+		
+		if (zone())
+			zone()->physics()->addRigidBody(entity_body);
+	}
+
+	// transfer entity location to motion state
+	body()->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
+	body()->setLinearVelocity(btVector3(0.0f, 0.0f, 0.0f));
+	body()->setWorldTransform(t);
 
 	if (entity_state == Docked) {
 		body()->setLinearFactor(btVector3(0.0f, 0.0f, 0.0f));
@@ -602,6 +650,8 @@ void EntityDynamic::reset()
 		body()->setLinearFactor(btVector3(1.0f, 1.0f, 1.0f));
 		body()->setAngularFactor(btVector3(1.0f, 1.0f, 1.0f));
 	}
+	
+	set_dirty();
 }
 
 void EntityDynamic::frame(float seconds)
@@ -966,18 +1016,32 @@ void EntityControlable::reset()
 	
 	// construct physics body if necessary
 	if (!entity_body) {
-		// create collision shape
 		// create collision shape
 		if (model() && model()->radius()) {
 			const float modelscale = radius() / model()->radius();
-			entity_collision_shape  = new btBoxShape(to_btVector3(model()->box().max() * modelscale));
+			
+			if (flag_is_set(Complex) && model()->collisionmesh()) {
+				// use collision mesh 
+				// dynamic entities use a btGImpactMeshShape
+				btGImpactMeshShape *meshshape = new btGImpactMeshShape(model()->collisionmesh()->triangles());
+				
+				btVector3 modelscalevec(modelscale, modelscale, modelscale);
+				meshshape->setLocalScaling(modelscalevec);
+				//meshshape->setMargin(0.0f);
+				meshshape->updateBound();
+				
+				entity_collision_shape = meshshape;			
+			} else {
+				// use bounding box
+				entity_collision_shape  = new btBoxShape(to_btVector3(model()->box().max() * modelscale));
+			}
 		} else {
 			entity_collision_shape  = new btSphereShape(radius());
 		}
 		btVector3 inertia(0, 0, 0);
 		if (entity_mass)
 			entity_collision_shape->calculateLocalInertia(entity_mass, inertia);
-		
+				
 		// create motion state
 		entity_motionstate = new btDefaultMotionState(t);
 		
@@ -985,6 +1049,7 @@ void EntityControlable::reset()
 		entity_body_info = new btRigidBody::btRigidBodyConstructionInfo(entity_mass, entity_motionstate, entity_collision_shape, inertia);		
 		entity_body = new btRigidBody(*entity_body_info);
 		entity_body->setActivationState(DISABLE_DEACTIVATION);
+		//entity_body->setCollisionFlags(entity_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); 
 		
 		entity_actioninterface = new ActionInterface(this);
 		
diff --git a/src/core/entity.h b/src/core/entity.h
index 378a71a..e12123e 100644
--- a/src/core/entity.h
+++ b/src/core/entity.h
@@ -173,11 +173,6 @@ public:
 		return entity_collision_shape;
 	}
 	
-	/// physics motion info
-	inline btMotionState *motionstate() {
-		return entity_motionstate;
-	}
-		
 	/// indicates a server-side entity
 	inline const bool serverside() const {
 		return entity_serverside;
@@ -456,7 +451,6 @@ protected:
 	btRigidBody					*entity_body;
 	btRigidBody::btRigidBodyConstructionInfo	*entity_body_info;
 	btCollisionShape				*entity_collision_shape;
-	btMotionState					*entity_motionstate;
 
 		// the zone the entity belongs to
 	Zone*			entity_zone;
@@ -536,6 +530,11 @@ public:
 		return entity_timer;
 	}
 
+	/// physics motion info
+	inline btMotionState *motionstate() {
+		return entity_motionstate;
+	}
+		
 	/*----- mutators -------------------------------------------------- */
 
 	/// mass of the entity
@@ -588,6 +587,7 @@ public:
 protected:
 	float			entity_timer;
 	int			entity_state;
+	btMotionState		*entity_motionstate;
 };
 
 /// an entity that can be controlled by a player
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
index ef60e97..84b4e0a 100644
--- a/src/game/base/ship.cc
+++ b/src/game/base/ship.cc
@@ -374,8 +374,9 @@ void Ship::frame(float seconds)
 	/* -- update state ----------------------------------------- */
 
 	// speed might be set to 0 on this update
-	if (entity_speed != 0.0f)
+	if (entity_speed != 0.0f) {
 		set_dirty();
+	}
 
 	if (entity_state == core::Entity::Docked) {
 
@@ -642,6 +643,7 @@ void Ship::frame(float seconds)
 	*/
 	
 	EntityControlable::frame(seconds);
+
 }
 
 } // namespace game
diff --git a/src/game/base/shipmodel.cc b/src/game/base/shipmodel.cc
index 126557c..ec712ac 100644
--- a/src/game/base/shipmodel.cc
+++ b/src/game/base/shipmodel.cc
@@ -92,6 +92,9 @@ bool ShipModel::init()
 				} else if (inifile.got_key_bool("dock", b)) {
 					shipmodel->set_dockable(b);
 					continue;
+				} else if (inifile.got_key_bool("complex", b)) {
+					shipmodel->set_complex_collision(b);
+					continue;
 				} else if (inifile.got_key_float("maxspeed", f)) {
 					shipmodel->set_maxspeed(f * 0.01f);
 					continue;
@@ -212,6 +215,7 @@ ShipModel::ShipModel() : core::Info(shipmodel_infotype)
 	shipmodel_jumpdrive = false;	// no jumpdrive capability
 	shipmodel_dockable = false;		// not dockable
 	shipmodel_template = 0;
+	shipmodel_complex_collision = false;
 	
 }
 
@@ -374,6 +378,9 @@ void ShipModel::apply(core::Entity *entity) const
 	
 	if (radius())
 		entity->set_radius(radius());
+	
+	if (complex_collision())
+		entity->set_flag(core::Entity::Complex);
 }
 
 void ShipModel::apply(Ship *ship) const
diff --git a/src/game/base/shipmodel.h b/src/game/base/shipmodel.h
index f790bcd..a576c1d 100644
--- a/src/game/base/shipmodel.h
+++ b/src/game/base/shipmodel.h
@@ -80,6 +80,11 @@ public:
 		return shipmodel_angular_damping;
 	}
 	
+	/// complex collision
+	inline const bool complex_collision() const {
+		return shipmodel_complex_collision;
+	}
+	
 	/// maximum thrust speed
 	inline const float maxspeed() const {
 		return shipmodel_maxspeed;
@@ -191,6 +196,13 @@ protected:
 		shipmodel_angular_damping = angular_damping;
 	}
 	
+	/**
+	 * @brief enable collision mesh
+	 */
+	inline void set_complex_collision(const float complex_collision) {
+		shipmodel_complex_collision = complex_collision;
+	}
+	
 public:
 	void generate_info();
 	
@@ -232,6 +244,8 @@ private:
 	bool			shipmodel_jumpdrive;
 	bool			shipmodel_dockable;	
 	
+	bool			shipmodel_complex_collision;
+	
 	const Template		*shipmodel_template;
 	
 	/* --- static ----------------------------------------------------- */
diff --git a/src/model/collisionmesh.cc b/src/model/collisionmesh.cc
index 90aafc3..5d4505a 100644
--- a/src/model/collisionmesh.cc
+++ b/src/model/collisionmesh.cc
@@ -69,7 +69,8 @@ void CollisionMesh::add_triangle(const math::Vector3f & v0, const math::Vector3f
 	collisionmesh_triangles->addTriangle(
 		to_btVector3(v0),
 		to_btVector3(v1),
-		to_btVector3(v1)
+		to_btVector3(v2),
+		true
 	);
 	collisionmesh_size += 1;
 }
-- 
cgit v1.2.3