stk-code_catmod/src/physics/physics.hpp
hikerstk fe35613323 Fixed #560: if a rigid body has more than one collision (and one collision can be
reported p to 4 times by bullet), a crash would be caused when the rigid body is
removed (meaning that all further collisions with this body are invalid/removed,
while the loop in physics still tries to access them).
This patches removes bodies only when it is safe to do so, i.e. after the collision
loop. Removals done in the loop will be stored and executed later.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@11198 178a84e3-b1eb-0310-8ba1-8eac791a3b58
2012-05-07 21:59:21 +00:00

177 lines
7.5 KiB
C++

//
// 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
// as published by the Free Software Foundation; either version 3
// 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.
#ifndef HEADER_PHYSICS_HPP
#define HEADER_PHYSICS_HPP
/**
* \defgroup physics
* Contains various physics utilities.
*/
#include <set>
#include <vector>
#include "btBulletDynamicsCommon.h"
#include "physics/irr_debug_drawer.hpp"
#include "physics/stk_dynamics_world.hpp"
#include "physics/user_pointer.hpp"
class AbstractKart;
class STKDynamicsWorld;
class Vec3;
/**
* \ingroup physics
*/
class Physics : public btSequentialImpulseConstraintSolver
{
private:
/** Bullet can report the same collision more than once (up to 4
* contact points per collision. Additionally, more than one internal
* substep might be taken, resulting in potentially even more
* duplicates. To handle this, all collisions (i.e. pair of objects)
* are stored in a vector, but only one entry per collision pair
* of objects.
* While this is a natural application of std::set, the set has some
* overhead (since it will likely use a tree to sort the entries).
* Considering that the number of collisions is usually rather small
* a simple list and linear search is faster is is being used here. */
class CollisionPair {
private:
/** The user pointer of the objects involved in this collision. */
const UserPointer *m_up[2];
/** The contact point for each object (in local coordincates). */
Vec3 m_contact_point[2];
public:
/** The entries in Collision Pairs are sorted: if a projectile
* is included, it's always 'a'. If only two karts are reported
* the first kart pointer is the smaller one. */
CollisionPair(const UserPointer *a, const btVector3 &contact_point_a,
const UserPointer *b, const btVector3 &contact_point_b)
{
if(a->is(UserPointer::UP_KART) &&
b->is(UserPointer::UP_KART) && a>b) {
m_up[0]=b; m_contact_point[0] = contact_point_b;
m_up[1]=a; m_contact_point[1] = contact_point_a;
} else {
m_up[0]=a; m_contact_point[0] = contact_point_a;
m_up[1]=b; m_contact_point[1] = contact_point_b;
}
}; // CollisionPair
// --------------------------------------------------------------------
/** Tests if two collision pairs involve the same objects. This test
* is simplified (i.e. no test if p.b==a and p.a==b) since the
* elements are sorted. */
bool operator==(const CollisionPair p)
{
return (p.m_up[0]==m_up[0] && p.m_up[1]==m_up[1]);
} // operator==
// --------------------------------------------------------------------
const UserPointer *getUserPointer(unsigned int n) const
{
assert(n>=0 && n<=1);
return m_up[n];
} // getUserPointer
// --------------------------------------------------------------------
/** Returns the contact point of the collision in
* car (local) coordinates. */
const Vec3 &getContactPointCS(unsigned int n) const
{
assert(n>=0 && n<=1);
return m_contact_point[n];
} // getContactPointCS
}; // CollisionPair
// ========================================================================
// This class is the list of collision objects, where each collision
// pair is stored as most once.
class CollisionList : public std::vector<CollisionPair>
{
private:
void push_back(CollisionPair p) {
// only add a pair if it's not already in there
for(iterator i=begin(); i!=end(); i++) {
if((*i)==p) return;
}
std::vector<CollisionPair>::push_back(p);
}; // push_back
public:
/** Adds information about a collision to this vector. */
void push_back(const UserPointer *a, const btVector3 &contact_point_a,
const UserPointer *b, const btVector3 &contact_point_b)
{
push_back(CollisionPair(a, contact_point_a, b, contact_point_b));
}
}; // CollisionList
// ========================================================================
/** This flag is set while bullets time step processing is taking
* place. It is used to avoid altering data structures that might
* be used (e.g. removing a kart while a loop over all karts is
* taking place, as can happen in collision handling). */
bool m_physics_loop_active;
/** If kart need to be removed from the physics world while physics
* processing is taking place, store the pointers to the karts to
* be removed here, and remove them once the physics processing
* is finished. */
std::vector<const AbstractKart*> m_karts_to_delete;
/** Pointer to the physics dynamics world. */
STKDynamicsWorld *m_dynamics_world;
/** Used in physics debugging to draw the physics world. */
IrrDebugDrawer *m_debug_drawer;
btCollisionDispatcher *m_dispatcher;
btBroadphaseInterface *m_axis_sweep;
btDefaultCollisionConfiguration *m_collision_conf;
CollisionList m_all_collisions;
public:
Physics ();
~Physics ();
void init (const Vec3 &min_world, const Vec3 &max_world);
void addKart (const AbstractKart *k);
void addBody (btRigidBody* b) {m_dynamics_world->addRigidBody(b);}
void removeKart (const AbstractKart *k);
void removeBody (btRigidBody* b) {m_dynamics_world->removeRigidBody(b);}
void KartKartCollision(AbstractKart *ka, const Vec3 &contact_point_a,
AbstractKart *kb, const Vec3 &contact_point_b);
void update (float dt);
void draw ();
STKDynamicsWorld*
getPhysicsWorld () const {return m_dynamics_world;}
/** Activates the next debug mode (or switches it off again).
*/
void nextDebugMode () {m_debug_drawer->nextDebugMode(); }
/** Returns true if the debug drawer is enabled. */
bool isDebug() const {return m_debug_drawer->debugEnabled(); }
bool projectKartDownwards(const AbstractKart *k);
virtual btScalar solveGroup(btCollisionObject** bodies, int numBodies,
btPersistentManifold** manifold,int numManifolds,
btTypedConstraint** constraints,int numConstraints,
const btContactSolverInfo& info,
btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc,
btDispatcher* dispatcher);
};
#endif // HEADER_PHYSICS_HPP