2011-01-20 20:54:38 -05:00
|
|
|
// $Id$
|
2007-05-27 12:01:53 -04:00
|
|
|
//
|
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
|
|
// Copyright (C) 2006 Joerg Henrichs
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
2008-06-12 20:53:52 -04:00
|
|
|
// as published by the Free Software Foundation; either version 3
|
2007-05-27 12:01:53 -04:00
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
2009-03-31 21:30:10 -04:00
|
|
|
#include "physics/physical_object.hpp"
|
2008-09-19 02:07:29 -04:00
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2009-12-29 19:08:20 -05:00
|
|
|
|
2009-03-11 01:10:56 -04:00
|
|
|
#include "irrlicht.h"
|
|
|
|
using namespace irr;
|
2008-09-19 02:07:29 -04:00
|
|
|
|
2009-03-11 01:10:56 -04:00
|
|
|
#include "graphics/irr_driver.hpp"
|
|
|
|
#include "graphics/mesh_tools.hpp"
|
2009-03-11 23:49:31 -04:00
|
|
|
#include "io/file_manager.hpp"
|
2009-03-11 01:10:56 -04:00
|
|
|
#include "io/xml_node.hpp"
|
2009-01-22 17:27:13 -05:00
|
|
|
#include "modes/world.hpp"
|
2009-03-11 01:10:56 -04:00
|
|
|
#include "tracks/track.hpp"
|
2009-11-23 00:20:05 -05:00
|
|
|
#include "utils/constants.hpp"
|
2009-01-22 17:27:13 -05:00
|
|
|
#include "utils/string_utils.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2009-12-29 19:08:20 -05:00
|
|
|
PhysicalObject::PhysicalObject(const XMLNode &xml_node)
|
|
|
|
: TrackObject(xml_node)
|
2009-03-11 01:10:56 -04:00
|
|
|
{
|
|
|
|
|
|
|
|
m_shape = NULL;
|
|
|
|
m_body = NULL;
|
|
|
|
m_motion_state = NULL;
|
|
|
|
m_mass = 1;
|
2009-08-07 02:21:39 -04:00
|
|
|
m_radius = -1;
|
2009-03-11 01:10:56 -04:00
|
|
|
|
|
|
|
std::string shape;
|
2009-12-29 19:08:20 -05:00
|
|
|
xml_node.get("mass", &m_mass );
|
|
|
|
xml_node.get("radius", &m_radius);
|
|
|
|
xml_node.get("shape", &shape );
|
2009-03-11 01:10:56 -04:00
|
|
|
|
|
|
|
m_body_type = MP_NONE;
|
2011-02-05 08:39:42 -05:00
|
|
|
if (shape=="cone" ||
|
|
|
|
shape=="coneY" ) m_body_type = MP_CONE_Y;
|
|
|
|
else if(shape=="coneX" ) m_body_type = MP_CONE_X;
|
|
|
|
else if(shape=="coneZ" ) m_body_type = MP_CONE_Z;
|
|
|
|
else if(shape=="cylinder"||
|
|
|
|
shape=="cylinderY") m_body_type = MP_CYLINDER_Y;
|
|
|
|
else if(shape=="cylinderX") m_body_type = MP_CYLINDER_X;
|
|
|
|
else if(shape=="cylinderZ") m_body_type = MP_CYLINDER_Z;
|
|
|
|
|
2009-03-11 01:10:56 -04:00
|
|
|
else if(shape=="box" ) m_body_type = MP_BOX;
|
|
|
|
else if(shape=="sphere" ) m_body_type = MP_SPHERE;
|
2010-06-05 20:03:41 -04:00
|
|
|
else fprintf(stderr, "Unknown shape type : %s\n", shape.c_str());
|
|
|
|
|
2009-12-29 19:08:20 -05:00
|
|
|
m_init_pos.setIdentity();
|
2011-02-05 08:22:00 -05:00
|
|
|
Vec3 hpr(m_init_hpr);
|
|
|
|
hpr.degreeToRad();
|
|
|
|
btQuaternion q;
|
|
|
|
q.setEuler(hpr.getX(), hpr.getY(), hpr.getZ());
|
|
|
|
m_init_pos.setRotation(q);
|
2010-11-04 17:35:55 -04:00
|
|
|
Vec3 init_xyz(m_init_xyz);
|
|
|
|
m_init_pos.setOrigin(init_xyz);
|
2009-12-29 19:08:20 -05:00
|
|
|
|
2009-03-31 21:30:10 -04:00
|
|
|
} // PhysicalObject
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2009-03-31 21:30:10 -04:00
|
|
|
PhysicalObject::~PhysicalObject()
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2010-02-11 02:11:52 -05:00
|
|
|
World::getWorld()->getPhysics()->removeBody(m_body);
|
2007-05-27 12:01:53 -04:00
|
|
|
delete m_body;
|
2008-01-09 07:09:55 -05:00
|
|
|
delete m_motion_state;
|
|
|
|
delete m_shape;
|
2009-03-31 21:30:10 -04:00
|
|
|
} // ~PhysicalObject
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
/** Additional initialisation after loading of the model is finished.
|
|
|
|
*/
|
2009-03-31 21:30:10 -04:00
|
|
|
void PhysicalObject::init()
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2009-03-15 21:23:23 -04:00
|
|
|
// 1. Determine size of the object
|
2007-05-27 12:01:53 -04:00
|
|
|
// -------------------------------
|
2008-09-19 02:07:29 -04:00
|
|
|
Vec3 min, max;
|
2010-12-05 15:55:09 -05:00
|
|
|
scene::IAnimatedMesh *mesh
|
|
|
|
= ((scene::IAnimatedMeshSceneNode*)m_node)->getMesh();
|
|
|
|
MeshTools::minMax3D(mesh, &min, &max);
|
2008-09-19 02:07:29 -04:00
|
|
|
Vec3 extend = max-min;
|
2009-08-07 02:21:39 -04:00
|
|
|
// Adjust the mesth of the graphical object so that its center is where it
|
|
|
|
// is in bullet (usually at (0,0,0)). It can be changed in the case clause
|
|
|
|
// if this is not correct for a particular shape.
|
|
|
|
Vec3 offset_from_center = -0.5f*(max+min);
|
2007-05-27 12:01:53 -04:00
|
|
|
switch (m_body_type)
|
|
|
|
{
|
2011-02-05 08:39:42 -05:00
|
|
|
case MP_CONE_Y: {
|
2009-08-07 02:21:39 -04:00
|
|
|
if(m_radius<0) m_radius = 0.5f*extend.length_2d();
|
2010-04-14 09:20:30 -04:00
|
|
|
m_shape = new btConeShape(m_radius, extend.getY());
|
2007-05-27 12:01:53 -04:00
|
|
|
break;
|
2008-09-19 02:07:29 -04:00
|
|
|
}
|
2010-06-07 18:08:15 -04:00
|
|
|
case MP_CONE_X: {
|
|
|
|
if(m_radius<0)
|
|
|
|
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
|
|
|
|
extend.getZ()*extend.getZ());
|
|
|
|
m_shape = new btConeShapeX(m_radius, extend.getY());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MP_CONE_Z: {
|
|
|
|
if(m_radius<0)
|
|
|
|
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
|
|
|
|
extend.getY()*extend.getY());
|
|
|
|
m_shape = new btConeShapeZ(m_radius, extend.getY());
|
|
|
|
break;
|
|
|
|
}
|
2011-02-05 08:39:42 -05:00
|
|
|
case MP_CYLINDER_Y: {
|
|
|
|
if(m_radius<0) m_radius = 0.5f*extend.length_2d();
|
|
|
|
m_shape = new btCylinderShape(0.5f*extend);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MP_CYLINDER_X: {
|
|
|
|
if(m_radius<0)
|
|
|
|
m_radius = 0.5f*sqrt(extend.getY()*extend.getY() +
|
|
|
|
extend.getZ()*extend.getZ());
|
|
|
|
m_shape = new btCylinderShapeX(0.5f*extend);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MP_CYLINDER_Z: {
|
|
|
|
if(m_radius<0)
|
|
|
|
m_radius = 0.5f*sqrt(extend.getX()*extend.getX() +
|
|
|
|
extend.getY()*extend.getY());
|
|
|
|
m_shape = new btCylinderShapeZ(0.5f*extend);
|
|
|
|
break;
|
|
|
|
}
|
2008-09-19 02:07:29 -04:00
|
|
|
case MP_BOX: m_shape = new btBoxShape(0.5*extend);
|
2007-05-27 12:01:53 -04:00
|
|
|
break;
|
2008-09-19 02:07:29 -04:00
|
|
|
case MP_SPHERE: {
|
2009-08-07 02:21:39 -04:00
|
|
|
if(m_radius<0)
|
|
|
|
{
|
2009-12-29 19:08:20 -05:00
|
|
|
m_radius = std::max(extend.getX(), extend.getY());
|
|
|
|
m_radius = 0.5f*std::max(m_radius, extend.getZ());
|
2009-08-07 02:21:39 -04:00
|
|
|
}
|
|
|
|
m_shape = new btSphereShape(m_radius);
|
2008-04-20 19:30:28 -04:00
|
|
|
break;
|
2008-09-19 02:07:29 -04:00
|
|
|
}
|
2008-04-20 19:30:28 -04:00
|
|
|
case MP_NONE: fprintf(stderr, "WARNING: Uninitialised moving shape\n");
|
2009-03-15 21:23:23 -04:00
|
|
|
break;
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
|
2009-08-07 02:21:39 -04:00
|
|
|
// 2. Adjust the mesh so that its center is where it is in bullet
|
|
|
|
// --------------------------------------------------------------
|
|
|
|
// This means that the graphical and physical position are identical
|
|
|
|
// which simplifies drawing later on.
|
|
|
|
scene::IMeshManipulator *mesh_manipulator =
|
|
|
|
irr_driver->getSceneManager()->getMeshManipulator();
|
|
|
|
core::matrix4 transform(core::matrix4::EM4CONST_IDENTITY); //
|
|
|
|
transform.setTranslation(offset_from_center.toIrrVector());
|
2010-12-05 15:55:09 -05:00
|
|
|
mesh_manipulator->transformMesh(mesh, transform);
|
2009-08-07 02:21:39 -04:00
|
|
|
|
2009-03-15 21:23:23 -04:00
|
|
|
// 2. Create the rigid object
|
2007-05-27 12:01:53 -04:00
|
|
|
// --------------------------
|
2009-08-09 01:54:33 -04:00
|
|
|
// m_init_pos is the point on the track - add the offset
|
2010-04-14 09:20:30 -04:00
|
|
|
m_init_pos.setOrigin(m_init_pos.getOrigin()+btVector3(0,extend.getY()*0.5f, 0));
|
2008-02-05 06:56:21 -05:00
|
|
|
m_motion_state = new btDefaultMotionState(m_init_pos);
|
2007-05-27 12:01:53 -04:00
|
|
|
btVector3 inertia;
|
2008-01-09 07:09:55 -05:00
|
|
|
m_shape->calculateLocalInertia(m_mass, inertia);
|
2008-01-31 07:40:22 -05:00
|
|
|
btRigidBody::btRigidBodyConstructionInfo info(m_mass, m_motion_state, m_shape, inertia);
|
2008-02-05 06:56:21 -05:00
|
|
|
|
|
|
|
// Make sure that the cones stop rolling by defining angular friction != 0.
|
|
|
|
info.m_angularDamping = 0.5f;
|
2008-01-31 07:40:22 -05:00
|
|
|
m_body = new btRigidBody(info);
|
2008-02-05 06:56:21 -05:00
|
|
|
m_user_pointer.set(this);
|
|
|
|
m_body->setUserPointer(&m_user_pointer);
|
2009-08-09 01:54:33 -04:00
|
|
|
|
2010-02-11 02:11:52 -05:00
|
|
|
World::getWorld()->getPhysics()->addBody(m_body);
|
2007-05-27 12:01:53 -04:00
|
|
|
} // init
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2009-03-31 21:30:10 -04:00
|
|
|
void PhysicalObject::update(float dt)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
btTransform t;
|
|
|
|
m_motion_state->getWorldTransform(t);
|
2009-08-09 01:54:33 -04:00
|
|
|
|
2010-04-14 09:20:30 -04:00
|
|
|
Vec3 xyz = t.getOrigin();
|
|
|
|
if(xyz.getY()<-100)
|
2008-04-20 19:30:28 -04:00
|
|
|
{
|
|
|
|
m_body->setCenterOfMassTransform(m_init_pos);
|
2010-04-14 09:20:30 -04:00
|
|
|
m_body->setLinearVelocity (btVector3(0,0,0));
|
|
|
|
m_body->setAngularVelocity(btVector3(0,0,0));
|
|
|
|
xyz = Vec3(m_init_pos.getOrigin());
|
2008-04-20 19:30:28 -04:00
|
|
|
}
|
2010-12-05 15:55:09 -05:00
|
|
|
m_node->setPosition(xyz.toIrrVector());
|
2010-04-14 09:20:30 -04:00
|
|
|
Vec3 hpr;
|
|
|
|
hpr.setHPR(t.getRotation());
|
2010-12-05 15:55:09 -05:00
|
|
|
m_node->setRotation(hpr.toIrrHPR());
|
2009-08-09 01:54:33 -04:00
|
|
|
return;
|
2007-05-27 12:01:53 -04:00
|
|
|
} // update
|
2009-03-15 21:23:23 -04:00
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
// -----------------------------------------------------------------------------
|
2009-03-31 21:30:10 -04:00
|
|
|
void PhysicalObject::reset()
|
2008-02-05 06:56:21 -05:00
|
|
|
{
|
|
|
|
m_body->setCenterOfMassTransform(m_init_pos);
|
2008-02-11 19:08:48 -05:00
|
|
|
m_body->setAngularVelocity(btVector3(0,0,0));
|
|
|
|
m_body->setLinearVelocity(btVector3(0,0,0));
|
2009-01-12 07:32:14 -05:00
|
|
|
m_body->activate();
|
2008-02-05 06:56:21 -05:00
|
|
|
} // reset
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
2009-03-31 21:30:10 -04:00
|
|
|
void PhysicalObject::handleExplosion(const Vec3& pos, bool direct_hit) {
|
2008-02-05 06:56:21 -05:00
|
|
|
if(direct_hit) {
|
|
|
|
btVector3 impulse(0.0f, 0.0f, stk_config->m_explosion_impulse_objects);
|
|
|
|
m_body->applyCentralImpulse(impulse);
|
|
|
|
}
|
|
|
|
else // only affected by a distant explosion
|
|
|
|
{
|
|
|
|
btTransform t;
|
|
|
|
m_motion_state->getWorldTransform(t);
|
|
|
|
btVector3 diff=t.getOrigin()-pos;
|
|
|
|
|
|
|
|
float len2=diff.length2();
|
|
|
|
|
|
|
|
// The correct formhale would be to first normalise diff,
|
|
|
|
// then apply the impulse (which decreases 1/r^2 depending
|
|
|
|
// on the distance r), so:
|
|
|
|
// diff/len(diff) * impulseSize/len(diff)^2
|
|
|
|
// = diff*impulseSize/len(diff)^3
|
|
|
|
// We use diff*impulseSize/len(diff)^2 here, this makes the impulse
|
|
|
|
// somewhat larger, which is actually more fun :)
|
|
|
|
btVector3 impulse=diff*stk_config->m_explosion_impulse_objects/len2;
|
|
|
|
m_body->applyCentralImpulse(impulse);
|
|
|
|
}
|
|
|
|
m_body->activate();
|
|
|
|
|
|
|
|
} // handleExplosion
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-02-05 06:56:21 -05:00
|
|
|
// -----------------------------------------------------------------------------
|
2007-05-27 12:01:53 -04:00
|
|
|
/* EOF */
|
|
|
|
|