Physics module now is an optional module.

Fixed Android build.
ecode: Added Help -> Check for Updates. Added "Rosé Pine" terminal color scheme.
This commit is contained in:
Martín Lucas Golini
2023-01-15 04:08:29 -03:00
parent 2090b3bf14
commit 16890cae6c
105 changed files with 573 additions and 240 deletions

View File

@@ -29,7 +29,7 @@ using namespace EE::System;
#define EE_MAPS_API __declspec( dllimport )
#endif
#else
#if ( __GNUC__ >= 4 )
#if ( __GNUC__ >= 4 ) && !defined( EE_MAPS_API )
#define EE_MAPS_API __attribute__( ( visibility( "default" ) ) )
#endif
#endif

View File

@@ -0,0 +1,62 @@
#ifndef EE_PHYSICS_CARBITER_HPP
#define EE_PHYSICS_CARBITER_HPP
#include <eepp/physics/base.hpp>
#include <eepp/physics/body.hpp>
#include <eepp/physics/shape.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API Arbiter {
public:
Arbiter( cpArbiter* arbiter );
cVect totalImpulse();
cVect totalImpulseWithFriction();
void ignore();
void getShapes( Shape** a, Shape** b );
void getBodies( Body** a, Body** b );
bool isFirstContact();
int getCount();
cVect getNormal( int i );
cVect getPoint( int i );
cpFloat getDepth( int i );
cpContactPointSet getContactPointSet();
void setContactPointSet( cpContactPointSet* contact );
cpArbiter* getArbiter() const;
cpFloat getElasticity();
void setElasticity( cpFloat value );
cpFloat getFriction();
void setFriction( cpFloat value );
cVect getSurfaceVelocity();
void setSurfaceVelocity( cVect value );
void setUserData( cpDataPointer value );
cpDataPointer getUserData() const;
protected:
cpArbiter* mArbiter;
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,19 @@
#ifndef EE_PHYSICS_AREA_HPP
#define EE_PHYSICS_AREA_HPP
#include <eepp/physics/base.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API Area {
public:
cpFloat forCircle( cpFloat r1, cpFloat r2 );
cpFloat forSegment( cVect a, cVect b, cpFloat r );
cpFloat forPoly( const int numVerts, const cVect* verts );
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,45 @@
#ifndef EE_PHYSICS_BASE
#define EE_PHYSICS_BASE
//! Chipmunk includes
#include <eepp/thirdparty/chipmunk/chipmunk_private.h>
//! EE includes needed for the wrapper, all templates, so it will be easy to port this.
#include <eepp/math/rect.hpp>
#include <eepp/math/vector2.hpp>
using namespace EE::Math;
#include <eepp/core.hpp>
#include <eepp/system/color.hpp>
#include <eepp/system/singleton.hpp>
using namespace EE::System;
//! Default settings are defined here
#include <eepp/physics/settings.hpp>
//! Some helpers for the wrapper ( most of them can be disabled in the settings )
#include <eepp/physics/physicshelper.hpp>
#ifndef EE_PHYSICS_STATIC
#if EE_PLATFORM == EE_PLATFORM_WIN
// Windows platforms
#ifdef EE_PHYSICS_EXPORTS
// From DLL side, we must export
#define EE_PHYSICS_API __declspec( dllexport )
#else
// From client application side, we must import
#define EE_PHYSICS_API __declspec( dllimport )
#endif
#else
#if ( __GNUC__ >= 4 ) && !defined( EE_PHYSICS_API )
#define EE_PHYSICS_API __attribute__( ( visibility( "default" ) ) )
#endif
#endif
#endif
#endif
#ifndef EE_PHYSICS_API
#define EE_PHYSICS_API
#endif

View File

@@ -0,0 +1,184 @@
#ifndef EE_PHYSICS_CBODY_HPP
#define EE_PHYSICS_CBODY_HPP
#include <eepp/physics/base.hpp>
namespace EE { namespace Physics {
class Shape;
class Constraint;
class Arbiter;
class EE_PHYSICS_API Body {
public:
typedef std::function<void( Body*, Shape*, void* )> ShapeIteratorFunc;
typedef std::function<void( Body*, Constraint*, void* )> ConstraintIteratorFunc;
typedef std::function<void( Body*, Arbiter*, void* )> ArbiterIteratorFunc;
typedef std::function<void( Body*, cVect, cpFloat, cpFloat )> BodyVelocityFunc;
typedef std::function<void( Body*, cpFloat )> BodyPositionFunc;
class ShapeIterator {
public:
ShapeIterator( Physics::Body* body, void* data, ShapeIteratorFunc func ) :
Body( body ), Data( data ), Func( func ) {}
Physics::Body* Body;
void* Data;
ShapeIteratorFunc Func;
};
class ConstraintIterator {
public:
ConstraintIterator( Physics::Body* body, void* data, ConstraintIteratorFunc func ) :
Body( body ), Data( data ), Func( func ) {}
Physics::Body* Body;
void* Data;
ConstraintIteratorFunc Func;
};
class ArbiterIterator {
public:
ArbiterIterator( Physics::Body* body, void* data, ArbiterIteratorFunc func ) :
Body( body ), Data( data ), Func( func ) {}
Physics::Body* Body;
void* Data;
ArbiterIteratorFunc Func;
};
static Body* New( cpFloat m, cpFloat i );
static Body* New( cpBody* body );
static Body* New();
static void Free( Body* body );
Body( cpBody* body );
Body( cpFloat m, cpFloat i );
Body();
virtual ~Body();
void activate();
void activateStatic( Body* body, Shape* filter );
void sleep();
void sleepWithGroup( Body* Group );
bool isSleeping();
bool isStatic();
bool isRogue();
cpBody* getBody() const;
cpFloat getMass() const;
void setMass( const cpFloat& mass );
cpFloat getMoment() const;
void setMoment( const cpFloat& i );
cVect getPos() const;
void setPos( const cVect& pos );
cVect getVel() const;
void setVel( const cVect& vel );
cVect getForce() const;
void setForce( const cVect& force );
cpFloat getAngle() const;
void setAngle( const cpFloat& rads );
cpFloat getAngleDeg();
void setAngleDeg( const cpFloat& angle );
cpFloat getAngVel() const;
void setAngVel( const cpFloat& angVel );
cpFloat getTorque() const;
void setTorque( const cpFloat& torque );
cVect getRot() const;
cpFloat getVelLimit() const;
void setVelLimit( const cpFloat& speed );
cpFloat getAngVelLimit() const;
void setAngVelLimit( const cpFloat& speed );
void updateVelocity( cVect gravity, cpFloat damping, cpFloat dt );
void updatePosition( cpFloat dt );
cVect local2World( const cVect v );
cVect world2Local( const cVect v );
void applyImpulse( const cVect j, const cVect r );
void resetForces();
void applyForce( const cVect f, const cVect r );
cpFloat kineticEnergy();
void* getData() const;
void setData( void* data );
void eachShape( ShapeIteratorFunc Func, void* data );
virtual void onEachShape( Shape* Shape, ShapeIterator* it );
void eachConstraint( ConstraintIteratorFunc Func, void* data );
virtual void onEachConstraint( Constraint* Constraint, ConstraintIterator* it );
void eachArbiter( ArbiterIteratorFunc Func, void* data );
virtual void onEachArbiter( Arbiter* Arbiter, ArbiterIterator* it );
void velocityFunc( BodyVelocityFunc func );
void positionFunc( BodyPositionFunc func );
protected:
friend class Space;
static void bodyVelocityFuncWrapper( cpBody* body, cpVect gravity, cpFloat damping,
cpFloat dt );
static void bodyPositionFuncWrapper( cpBody* body, cpFloat dt );
cpBody* mBody;
void* mData;
BodyVelocityFunc mVelocityFunc;
BodyPositionFunc mPositionFunc;
void setData();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,55 @@
#ifndef EE_PHYSICS_CCONSTRAINT_HPP
#define EE_PHYSICS_CCONSTRAINT_HPP
#include <eepp/physics/base.hpp>
#include <eepp/physics/body.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API Constraint {
public:
static void Free( Constraint* constraint );
Constraint( cpConstraint* Constraint );
virtual ~Constraint();
cpConstraint* getConstraint() const;
Body* getA();
Body* getB();
cpFloat getMaxForce();
void setMaxForce( const cpFloat& maxforce );
cpFloat getMaxBias();
void setMaxBias( const cpFloat& maxbias );
virtual void draw();
cpFloat getErrorBias();
void setErrorBias( cpFloat value );
void setData( void* data );
void* getData() const;
cpFloat getImpulse();
protected:
cpConstraint* mConstraint;
void* mData;
Constraint();
void setData();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,29 @@
#ifndef EE_PHYSICS_CDAMPEDROTARYSPRING_HPP
#define EE_PHYSICS_CDAMPEDROTARYSPRING_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API DampedRotarySpring : public Constraint {
public:
DampedRotarySpring( Body* a, Body* b, cpFloat restAngle, cpFloat stiffness, cpFloat damping );
cpFloat getRestAngle();
void setRestAngle( const cpFloat& restangle );
cpFloat getStiffness();
void setStiffness( const cpFloat& stiffness );
cpFloat getDamping();
void setDamping( const cpFloat& damping );
virtual void draw();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,47 @@
#ifndef EE_PHYSICS_CDAMPEDSPRING_HPP
#define EE_PHYSICS_CDAMPEDSPRING_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API DampedSpring : public Constraint {
public:
DampedSpring( Body* a, Body* b, cVect anchr1, cVect anchr2, cpFloat restLength,
cpFloat stiffness, cpFloat damping );
cVect getAnchr1();
void setAnchr1( const cVect& anchr1 );
cVect getAnchr2();
void setAnchr2( const cVect& anchr2 );
cpFloat getRestLength();
void setRestLength( const cpFloat& restlength );
cpFloat getStiffness();
void setStiffness( const cpFloat& stiffness );
cpFloat getDamping();
void setDamping( const cpFloat& damping );
virtual void draw();
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat getDrawPointSize();
virtual void setDrawPointSize( const cpFloat& size );
protected:
cpFloat mDrawPointSize;
#endif
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,25 @@
#ifndef EE_PHYSICS_CGEARJOINT_HPP
#define EE_PHYSICS_CGEARJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API GearJoint : public Constraint {
public:
GearJoint( Body* a, Body* b, cpFloat phase, cpFloat ratio );
cpFloat getPhase();
void setPhase( const cpFloat& phase );
cpFloat getRatio();
void setRatio( const cpFloat& ratio );
virtual void draw();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,38 @@
#ifndef EE_PHYSICS_CGROOVEJOINT_HPP
#define EE_PHYSICS_CGROOVEJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API GrooveJoint : public Constraint {
public:
GrooveJoint( Body* a, Body* b, cVect groove_a, cVect groove_b, cVect anchr2 );
cVect getAnchr2();
void setAnchr2( const cVect& anchr2 );
cVect getGrooveA();
void setGrooveA( const cVect& groove_a );
cVect getGrooveB();
void setGrooveB( const cVect& groove_b );
virtual void draw();
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat getDrawPointSize();
virtual void setDrawPointSize( const cpFloat& size );
protected:
cpFloat mDrawPointSize;
#endif
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,38 @@
#ifndef EE_PHYSICS_CPINJOINT_HPP
#define EE_PHYSICS_CPINJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API PinJoint : public Constraint {
public:
PinJoint( Body* a, Body* b, cVect anchr1, cVect anchr2 );
cVect getAnchr1();
void setAnchr1( const cVect& anchr1 );
cVect getAnchr2();
void setAnchr2( const cVect& anchr2 );
cpFloat getDist();
void setDist( const cpFloat& dist );
virtual void draw();
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat getDrawPointSize();
virtual void setDrawPointSize( const cpFloat& size );
protected:
cpFloat mDrawPointSize;
#endif
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,36 @@
#ifndef EE_PHYSICS_CPIVOTJOINT_HPP
#define EE_PHYSICS_CPIVOTJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API PivotJoint : public Constraint {
public:
PivotJoint( Body* a, Body* b, cVect pivot );
PivotJoint( Body* a, Body* b, cVect anchr1, cVect anchr2 );
cVect getAnchr1();
void setAnchr1( const cVect& anchr1 );
cVect getAnchr2();
void setAnchr2( const cVect& anchr2 );
virtual void draw();
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat getDrawPointSize();
virtual void setDrawPointSize( const cpFloat& size );
protected:
cpFloat mDrawPointSize;
#endif
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,29 @@
#ifndef EE_PHYSICS_CRATCHETJOINT_HPP
#define EE_PHYSICS_CRATCHETJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API RatchetJoint : public Constraint {
public:
RatchetJoint( Body* a, Body* b, cpFloat phase, cpFloat ratchet );
cpFloat getAngle();
void setAngle( const cpFloat& angle );
cpFloat getPhase();
void setPhase( const cpFloat& phase );
cpFloat getRatchet();
void setRatchet( const cpFloat& ratchet );
virtual void draw();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,25 @@
#ifndef EE_PHYSICS_CROTARYLIMITJOINT_HPP
#define EE_PHYSICS_CROTARYLIMITJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API RotaryLimitJoint : public Constraint {
public:
RotaryLimitJoint( Body* a, Body* b, cpFloat min, cpFloat max );
cpFloat getMin();
void setMin( const cpFloat& min );
cpFloat getMax();
void setMax( const cpFloat& max );
virtual void draw();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,21 @@
#ifndef EE_PHYSICS_CSIMPLEMOTOR_HPP
#define EE_PHYSICS_CSIMPLEMOTOR_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API SimpleMotor : public Constraint {
public:
SimpleMotor( Body* a, Body* b, cpFloat rate );
cpFloat getRate();
void setRate( const cpFloat& rate );
virtual void draw();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,42 @@
#ifndef EE_PHYSICS_CSLIDEJOINT_HPP
#define EE_PHYSICS_CSLIDEJOINT_HPP
#include <eepp/physics/constraints/constraint.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API SlideJoint : public Constraint {
public:
SlideJoint( Body* a, Body* b, cVect anchr1, cVect anchr2, cpFloat min, cpFloat max );
cVect getAnchr1();
void setAnchr1( const cVect& anchr1 );
cVect getAnchr2();
void setAnchr2( const cVect& anchr2 );
cpFloat getMin();
void setMin( const cpFloat& min );
cpFloat getMax();
void setMax( const cpFloat& max );
virtual void draw();
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat getDrawPointSize();
virtual void setDrawPointSize( const cpFloat& size );
protected:
cpFloat mDrawPointSize;
#endif
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,21 @@
#ifndef EE_PHYSICS_MOMENT_HPP
#define EE_PHYSICS_MOMENT_HPP
#include <eepp/physics/base.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API Moment {
public:
static cpFloat forCircle( cpFloat m, cpFloat r1, cpFloat r2, cVect offset );
static cpFloat forSegment( cpFloat m, cVect a, cVect b );
static cpFloat forPoly( cpFloat m, int numVerts, const cVect* verts, cVect offset );
static cpFloat forBox( cpFloat m, cpFloat width, cpFloat height );
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,29 @@
#ifndef EEPP_PHYSICS_HPP
#define EEPP_PHYSICS_HPP
#include <eepp/physics/area.hpp>
#include <eepp/physics/body.hpp>
#include <eepp/physics/constraints/constraint.hpp>
#include <eepp/physics/constraints/dampedrotaryspring.hpp>
#include <eepp/physics/constraints/dampedspring.hpp>
#include <eepp/physics/constraints/gearjoint.hpp>
#include <eepp/physics/constraints/groovejoint.hpp>
#include <eepp/physics/constraints/pinjoint.hpp>
#include <eepp/physics/constraints/pivotjoint.hpp>
#include <eepp/physics/constraints/ratchetjoint.hpp>
#include <eepp/physics/constraints/rotarylimitjoint.hpp>
#include <eepp/physics/constraints/simplemotor.hpp>
#include <eepp/physics/constraints/slidejoint.hpp>
#include <eepp/physics/moment.hpp>
#include <eepp/physics/physicsmanager.hpp>
#include <eepp/physics/shape.hpp>
#include <eepp/physics/shapecircle.hpp>
#include <eepp/physics/shapecirclesprite.hpp>
#include <eepp/physics/shapepoint.hpp>
#include <eepp/physics/shapepoly.hpp>
#include <eepp/physics/shapepolysprite.hpp>
#include <eepp/physics/shapesegment.hpp>
#include <eepp/physics/space.hpp>
using namespace EE::Physics;
#endif

View File

@@ -0,0 +1,130 @@
#ifndef EE_PHYSICS_HELPER
#define EE_PHYSICS_HELPER
#include <eepp/graphics/base.hpp>
#include <eepp/physics/base.hpp>
namespace EE { namespace Physics {
const cpFloat cpPI = 3.14159265358979323846;
const cpFloat cpPI_180 = cpPI / 180;
const cpFloat cp180_PI = 180 / cpPI;
inline static cpFloat cpRadians( const cpFloat& Ang ) {
return Ang * cpPI_180;
}
inline static cpFloat cpDegrees( const cpFloat& Radians ) {
return Radians * cp180_PI;
}
#ifdef USE_EE_VECTOR
typedef Vector2<cpFloat> cVect;
inline static cVect toVect( cpVect vect ) {
return cVect( vect.x, vect.y );
}
#define tocpv( vect ) cpv( vect.x, vect.y )
#define tovect( vect ) toVect( vect )
#define casttocpv( vect ) reinterpret_cast<cpVect*>( vect )
#define constcasttocpv( vect ) reinterpret_cast<const cpVect*>( vect )
#define cVectZero cVect( 0, 0 )
#define cVectNew( x, y ) cVect( x, y )
#else
typedef cpVect cVect;
#define tocpv( vect ) vect
#define tovect( vect ) vect
#define casttocpv( vect ) vect
#define constcasttocpv( vect ) vect
#define cVectZero cpvzero
#define cVectNew( x, y ) cpv( x, y )
#endif
#ifdef USE_EE_AABB
typedef tRECT<cpFloat> cBB;
inline static cBB toAABB( cpBB bb ) {
#ifdef BB_INVERT_Y_AXIS
return cBB( bb.l, bb.b, bb.r, bb.t );
#else
return cBB( bb.l, bb.t, bb.r, bb.b );
#endif
}
#define tocpbb( bb ) cpBBNew( bb.Left, bb.Top, bb.Right, bb.Bottom )
#define tocbb( bb ) toAABB( bb )
#define cBBNew( l, t, r, b ) cBB( l, t, r, b )
#else
typedef cpBB cBB;
#define tocpbb( bb ) bb
#define tocbb( bb ) bb
#ifdef BB_INVERT_Y_AXIS
#define cBBNew( l, t, r, b ) cpBBNew( l, t, r, b ) //! Inverted Top/Bottom here too
#else
#define cBBNew( l, t, r, b ) cpBBNew( l, b, r, t )
#endif
#endif
#ifdef PHYSICS_RENDERER_ENABLED
inline Color colorFromPointer( void* ptr ) {
UintPtr val = (UintPtr)ptr;
// hash the pointer up nicely
val = ( val + 0x7ed55d16 ) + ( val << 12 );
val = ( val ^ 0xc761c23c ) ^ ( val >> 19 );
val = ( val + 0x165667b1 ) + ( val << 5 );
val = ( val + 0xd3a2646c ) ^ ( val << 9 );
val = ( val + 0xfd7046c5 ) + ( val << 3 );
val = ( val ^ 0xb55a4f09 ) ^ ( val >> 16 );
unsigned char r = ( val >> 0 ) & 0xFF;
unsigned char g = ( val >> 8 ) & 0xFF;
unsigned char b = ( val >> 16 ) & 0xFF;
unsigned char max = r > g ? ( r > b ? r : b ) : ( g > b ? g : b );
const int mult = 127;
const int add = 63;
r = ( r * mult ) / max + add;
g = ( g * mult ) / max + add;
b = ( b * mult ) / max + add;
return Color( r, g, b, 255 );
}
inline Color colorForShape( cpShape* shape, cpSpace* space ) {
cpBody* body = shape->body;
int nc;
if ( body ) {
if ( cpBodyIsSleeping( body ) ) {
float v = 0.25f;
nc = (int)( v * 255 );
return Color( nc, nc, nc, 255 );
} else if ( body->CP_PRIVATE( node ).idleTime > space->sleepTimeThreshold ) {
float v = 0.9f;
nc = (int)( v * 255 );
return Color( nc, nc, nc, 255 );
}
}
return colorFromPointer( shape );
}
#endif
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,90 @@
#ifndef EE_PHYSICS_PHYSICSMANAGER_HPP
#define EE_PHYSICS_PHYSICSMANAGER_HPP
#include <eepp/physics/base.hpp>
#include <list>
namespace EE { namespace Physics {
class Body;
class Shape;
class Constraint;
class Space;
class EE_PHYSICS_API PhysicsManager {
SINGLETON_DECLARE_HEADERS( PhysicsManager )
public:
class DrawSpaceOptions {
public:
DrawSpaceOptions() :
DrawBBs( false ),
DrawShapes( true ),
#ifdef EE_GLES
DrawShapesBorders( false ),
#else
DrawShapesBorders( true ),
#endif
CollisionPointSize( 0.0f ),
BodyPointSize( 0.0f ),
LineThickness( 0.0f ) {
}
bool DrawBBs;
bool DrawShapes;
bool DrawShapesBorders;
cpFloat CollisionPointSize;
cpFloat BodyPointSize;
cpFloat LineThickness;
};
~PhysicsManager();
/** The Memory Manager will keep track of all the allocations from Space, Body, Shape and
*Constraint and will release any non-released pointer.
*** This is a lazy deallocation for the lazy programmers. It is disabled by default.
*** To work properly set as active before allocating anything, activate it just after the
*singleton instantiation.
*/
void setMemoryManager( bool memoryManager );
const bool& isMemoryManagerEnabled() const;
PhysicsManager::DrawSpaceOptions* getDrawOptions();
protected:
DrawSpaceOptions mOptions;
friend class Body;
friend class Shape;
friend class Constraint;
friend class Space;
bool mMemoryManager;
std::list<Body*> mBodysFree;
std::list<Shape*> mShapesFree;
std::list<Constraint*> mConstraintFree;
std::list<Space*> mSpaces;
PhysicsManager();
void addBodyFree( Body* body );
void removeBodyFree( Body* body );
void addShapeFree( Shape* shape );
void removeShapeFree( Shape* shape );
void addConstraintFree( Constraint* constraint );
void removeConstraintFree( Constraint* constraint );
void addSpace( Space* space );
void removeSpace( Space* space );
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,22 @@
#ifndef EE_PHYSICS_SETTINGS_HPP
#define EE_PHYSICS_SETTINGS_HPP
namespace EE { namespace Physics {
//! Comment this if you don't want to use all the rendering stuff from EE. Disabling this will
//! disable any kind of rendering, and the only dependencies with EE will be the templates.
#define PHYSICS_RENDERER_ENABLED
//! Define this to use the template vector from EE
#define USE_EE_VECTOR
//! Define this to use the template AABB from EE
#define USE_EE_AABB
//! Define this if you want to invert the BB Y Axis ( by default BB.Top is the bigger y-axis instead
//! of BB.Bottom )
#define BB_INVERT_Y_AXIS
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,103 @@
#ifndef EE_PHYSICS_CSHAPE_HPP
#define EE_PHYSICS_CSHAPE_HPP
#include <eepp/physics/base.hpp>
#include <eepp/physics/body.hpp>
namespace EE { namespace Physics {
class ShapeCircle;
class ShapeSegment;
class ShapePoly;
class Space;
class EE_PHYSICS_API Shape {
public:
static void resetShapeIdCounter();
static void Free( Shape* shape, bool DeleteBody = false );
cpShape* getShape() const;
virtual ~Shape();
Physics::Body* getBody() const;
void setBody( Physics::Body* body );
cBB getBB() const;
void setBB( const cBB& bb );
bool isSensor();
void setSensor( const bool& sensor );
cpFloat getE() const;
void setE( const cpFloat& e );
cpFloat getElasticity() const;
void setElasticity( const cpFloat& e );
cpFloat getU() const;
void setU( const cpFloat& u );
cpFloat getFriction() const;
void setFriction( const cpFloat& u );
cVect getSurfaceVel() const;
void getSurfaceVel( const cVect& vel );
cpCollisionType getCollisionType() const;
void setCollisionType( const cpCollisionType& type );
cpGroup getGroup() const;
void setGroup( const cpGroup& group );
cpLayers getLayers() const;
void setLayers( const cpLayers& layers );
cBB cacheBB();
cBB update( cVect pos, cVect rot );
bool pointQuery( cVect p );
cpShapeType getType() const;
ShapePoly* getAsPoly();
ShapeCircle* getAsCircle();
ShapeSegment* getAsSegment();
virtual void draw( Space* space );
virtual void drawBorder( Space* space );
virtual void drawBB();
void* getData() const;
void setData( void* data );
protected:
Shape();
cpShape* mShape;
void* mData;
void setData();
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,27 @@
#ifndef EE_PHYSICS_CSHAPECIRCLE_HPP
#define EE_PHYSICS_CSHAPECIRCLE_HPP
#include <eepp/physics/shape.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API ShapeCircle : public Shape {
public:
static ShapeCircle* New( Physics::Body* body, cpFloat radius, cVect offset );
ShapeCircle( Physics::Body* body, cpFloat radius, cVect offset );
cVect getOffset();
virtual void setOffset( const cVect& offset );
cpFloat getRadius();
virtual void setRadius( const cpFloat& radius );
virtual void draw( Space* space );
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,44 @@
#ifndef EE_PHYSICS_SHAPECIRCLESPRITE_HPP
#define EE_PHYSICS_SHAPECIRCLESPRITE_HPP
#include <eepp/physics/shapecircle.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
namespace EE { namespace Graphics {
class Sprite;
}} // namespace EE::Graphics
using namespace EE::Graphics;
namespace EE { namespace Physics {
class EE_PHYSICS_API ShapeCircleSprite : public ShapeCircle {
public:
static ShapeCircleSprite* New( Physics::Body* body, cpFloat radius, cVect offset,
Sprite* Sprite, bool AutoDeleteSprite = false );
ShapeCircleSprite( Physics::Body* body, cpFloat radius, cVect offset, Sprite* Sprite,
bool AutoDeleteSprite = false );
virtual ~ShapeCircleSprite();
virtual void draw( Space* space );
virtual void setRadius( const cpFloat& radius );
virtual void setOffset( const cVect& offset );
Sprite* getSprite() const;
protected:
Sprite* mSprite;
bool mSpriteAutoDelete;
void offsetSet();
};
}} // namespace EE::Physics
#endif
#endif

View File

@@ -0,0 +1,36 @@
#ifndef EE_PHYSICS_CSHAPEPOINT_HPP
#define EE_PHYSICS_CSHAPEPOINT_HPP
#include <eepp/physics/shape.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API ShapePoint : public Shape {
public:
static ShapePoint* New( Physics::Body* body, cpFloat radius, cVect offset );
ShapePoint( Physics::Body* body, cpFloat radius, cVect offset );
cVect getOffset();
virtual void setOffset( const cVect& offset );
cpFloat getRadius();
virtual void setRadius( const cpFloat& radius );
virtual void draw( Space* space );
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat getDrawRadius();
virtual void setDrawRadius( const cpFloat& radius );
protected:
cpFloat mDrawRadius;
#endif
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,37 @@
#ifndef EE_PHYSICS_CSHAPEPOLY_HPP
#define EE_PHYSICS_CSHAPEPOLY_HPP
#include <eepp/physics/shape.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API ShapePoly : public Shape {
public:
static ShapePoly* New( Physics::Body* body, int numVerts, cVect* verts, cVect offset );
static ShapePoly* New( Physics::Body* body, cpFloat width, cpFloat height );
ShapePoly( Physics::Body* body, int numVerts, cVect* verts, cVect offset );
ShapePoly( Physics::Body* body, cpFloat width, cpFloat height );
static bool validate( const cVect* verts, const int numVerts );
int getNumVerts();
cVect getVert( int idx );
void setVerts( int numVerts, cVect* verts, cVect offset );
virtual void draw( Space* space );
virtual void drawBorder( Space* space );
static void recenter( int numVerts, cVect* verts );
static cVect centroid( int numVerts, const cVect* verts );
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,47 @@
#ifndef EE_PHYSICS_CSHAPEPOLYSPRITE_HPP
#define EE_PHYSICS_CSHAPEPOLYSPRITE_HPP
#include <eepp/physics/shapepoly.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
namespace EE { namespace Graphics {
class Sprite;
}} // namespace EE::Graphics
using namespace EE::Graphics;
namespace EE { namespace Physics {
class EE_PHYSICS_API ShapePolySprite : public ShapePoly {
public:
static ShapePolySprite* New( Physics::Body* body, int numVerts, cVect* verts, cVect offset,
Sprite* Sprite, bool AutoDeleteSprite = false );
static ShapePolySprite* New( Physics::Body* body, cpFloat width, cpFloat height, Sprite* Sprite,
bool AutoDeleteSprite = false );
ShapePolySprite( Physics::Body* body, int numVerts, cVect* verts, cVect offset, Sprite* Sprite,
bool AutoDeleteSprite = false );
ShapePolySprite( Physics::Body* body, cpFloat width, cpFloat height, Sprite* Sprite,
bool AutoDeleteSprite = false );
virtual ~ShapePolySprite();
virtual void draw( Space* space );
Sprite* getSprite() const;
protected:
Sprite* mSprite;
bool mSpriteAutoDelete;
Vector2i mOffset;
void offsetSet( cVect center );
};
}} // namespace EE::Physics
#endif
#endif

View File

@@ -0,0 +1,38 @@
#ifndef EE_PHYSICS_CSHAPESEGMENT_HPP
#define EE_PHYSICS_CSHAPESEGMENT_HPP
#include <eepp/physics/shape.hpp>
namespace EE { namespace Physics {
class EE_PHYSICS_API ShapeSegment : public Shape {
public:
static ShapeSegment* New( Physics::Body* body, cVect a, cVect b, cpFloat radius );
ShapeSegment( Physics::Body* body, cVect a, cVect b, cpFloat radius );
cVect getA();
cVect getB();
cVect getNormal();
cpFloat getRadius();
void setRadius( const cpFloat& radius );
void setEndpoints( const cVect& a, const cVect& b );
bool query( cVect a, cVect b, cpSegmentQueryInfo* info );
static cVect queryHitPoint( const cVect start, const cVect end, const cpSegmentQueryInfo info );
static cpFloat queryHitDist( const cVect start, const cVect end,
const cpSegmentQueryInfo info );
virtual void draw( Space* space );
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,256 @@
#ifndef EE_PHYSICS_CSPACE_HPP
#define EE_PHYSICS_CSPACE_HPP
#include <eepp/physics/arbiter.hpp>
#include <eepp/physics/base.hpp>
#include <eepp/physics/body.hpp>
#include <eepp/physics/constraints/constraint.hpp>
#include <eepp/physics/shape.hpp>
#include <list>
namespace EE { namespace Physics {
class EE_PHYSICS_API Space {
public:
typedef std::function<int( Arbiter*, Space*, void* )> CollisionBeginFunc;
typedef std::function<int( Arbiter*, Space*, void* )> CollisionPreSolveFunc;
typedef std::function<void( Arbiter*, Space*, void* )> CollisionPostSolveFunc;
typedef std::function<void( Arbiter*, Space*, void* )> CollisionSeparateFunc;
typedef std::function<void( Space*, void*, void* )> PostStepCallback;
typedef std::function<void( Shape*, void* )> BBQueryFunc;
typedef std::function<void( Shape*, cpFloat, cVect, void* )> SegmentQueryFunc;
typedef std::function<void( Shape*, void* )> PointQueryFunc;
typedef std::function<void( Space*, Body*, void* )> BodyIteratorFunc;
typedef std::function<void( Space*, Shape*, void* )> ShapeIteratorFunc;
class CollisionHandler {
public:
CollisionHandler() : a( 0 ), b( 0 ), data( NULL ) {}
inline void reset() {
a = 0;
b = 0;
data = NULL;
begin = CollisionBeginFunc();
preSolve = CollisionPreSolveFunc();
postSolve = CollisionPostSolveFunc();
separate = CollisionSeparateFunc();
}
cpCollisionType a;
cpCollisionType b;
CollisionBeginFunc begin;
CollisionPreSolveFunc preSolve;
CollisionPostSolveFunc postSolve;
CollisionSeparateFunc separate;
void* data;
};
class PostStepCallbackCont {
public:
PostStepCallbackCont() : Data( NULL ) {}
PostStepCallback Callback;
void* Data;
};
class BBQuery {
public:
BBQuery() : Space( NULL ), Data( NULL ) {}
Physics::Space* Space;
BBQueryFunc Func;
void* Data;
};
class SegmentQuery {
public:
SegmentQuery() : Space( NULL ), Data( NULL ) {}
Physics::Space* Space;
SegmentQueryFunc Func;
void* Data;
};
class PointQuery {
public:
PointQuery() : Space( NULL ), Data( NULL ) {}
Physics::Space* Space;
PointQueryFunc Func;
void* Data;
};
class BodyIterator {
public:
BodyIterator( Physics::Space* space, void* data, BodyIteratorFunc func ) :
Space( space ), Data( data ), Func( func ) {}
Physics::Space* Space;
void* Data;
BodyIteratorFunc Func;
};
class ShapeIterator {
public:
ShapeIterator( Physics::Space* space, void* data, ShapeIteratorFunc func ) :
Space( space ), Data( data ), Func( func ) {}
Physics::Space* Space;
void* Data;
ShapeIteratorFunc Func;
};
static Space* New();
static void Free( Space* space );
Space();
virtual ~Space();
void step( const cpFloat& dt );
void update();
Body* getStaticBody() const;
const int& getIterations() const;
void setIterations( const int& iterations );
cVect getGravity() const;
void setGravity( const cVect& gravity );
const cpFloat& getDamping() const;
void setDamping( const cpFloat& damping );
const cpFloat& getIdleSpeedThreshold() const;
void setIdleSpeedThreshold( const cpFloat& idleSpeedThreshold );
const cpFloat& getSleepTimeThreshold() const;
void setSleepTimeThreshold( const cpFloat& sleepTimeThreshold );
void setCollisionSlop( cpFloat slop );
cpFloat getCollisionSlop() const;
void setCollisionBias( cpFloat bias );
cpFloat getCollisionBias() const;
cpTimestamp getCollisionPersistence();
void setCollisionPersistence( cpTimestamp value );
bool getEnableContactGraph();
void setEnableContactGraph( bool value );
bool contains( Shape* shape );
bool contains( Body* body );
bool contains( Constraint* constraint );
Shape* addShape( Shape* shape );
Shape* addStaticShape( Shape* shape );
Body* addBody( Body* body );
Constraint* addConstraint( Constraint* constraint );
void removeShape( Shape* shape );
void removeStatiShape( Shape* shape );
void removeBody( Body* body );
void removeConstraint( Constraint* constraint );
cpSpace* getSpace() const;
void activateShapesTouchingShape( Shape* shape );
virtual void draw();
Shape* pointQueryFirst( cVect point, cpLayers layers, cpGroup group );
Shape* segmentQueryFirst( cVect start, cVect end, cpLayers layers, cpGroup group,
cpSegmentQueryInfo* out );
void addCollisionHandler( const CollisionHandler& handler );
void removeCollisionHandler( cpCollisionType a, cpCollisionType b );
void setDefaultCollisionHandler( const CollisionHandler& handler );
void addPostStepCallback( PostStepCallback postStep, void* obj, void* data );
virtual cpBool onCollisionBegin( Arbiter* arb, void* data );
virtual cpBool onCollisionPreSolve( Arbiter* arb, void* data );
virtual void onCollisionPostSolve( Arbiter* arb, void* data );
virtual void onCollisionSeparate( Arbiter* arb, void* data );
virtual void onPostStepCallback( void* obj, void* data );
virtual void onBBQuery( Shape* shape, BBQuery* query );
virtual void onSegmentQuery( Shape* shape, cpFloat t, cVect n, SegmentQuery* query );
virtual void onPointQuery( Shape* shape, PointQuery* query );
void bbQuery( cBB bb, cpLayers layers, cpGroup group, BBQueryFunc func, void* data );
void segmentQuery( cVect start, cVect end, cpLayers layers, cpGroup group,
SegmentQueryFunc func, void* data );
void pointQuery( cVect point, cpLayers layers, cpGroup group, PointQueryFunc func, void* data );
void setData( void* data );
void* getData() const;
void reindexShape( Shape* shape );
void reindexShapesForBody( Body* body );
void reindexStatic();
void useSpatialHash( cpFloat dim, int count );
void eachShape( ShapeIteratorFunc Func, void* data );
virtual void onEachShape( Shape* Shape, ShapeIterator* it );
void eachBody( BodyIteratorFunc Func, void* data );
virtual void onEachBody( Body* Body, BodyIterator* it );
void convertBodyToDynamic( Body* body, cpFloat mass, cpFloat moment );
void convertBodyToStatic( Body* body );
protected:
cpSpace* mSpace;
Body* mStatiBody;
void* mData;
std::list<Body*> mBodys;
std::list<Shape*> mShapes;
std::list<Constraint*> mConstraints;
std::map<cpHashValue, CollisionHandler> mCollisions;
CollisionHandler mCollisionsDefault;
std::list<PostStepCallbackCont*> mPostStepCallbacks;
};
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,222 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef CHIPMUNK_HEADER
#define CHIPMUNK_HEADER
#ifdef _MSC_VER
#define _USE_MATH_DEFINES
#endif
#include <stdlib.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef CP_ALLOW_PRIVATE_ACCESS
#define CP_ALLOW_PRIVATE_ACCESS 0
#endif
#if CP_ALLOW_PRIVATE_ACCESS == 1
#define CP_PRIVATE(__symbol__) __symbol__
#else
#define CP_PRIVATE(__symbol__) __symbol__##_private
#endif
void cpMessage(const char *condition, const char *file, int line, int isError, int isHardError, const char *message, ...);
#ifdef NDEBUG
#define cpAssertWarn(__condition__, ...)
#else
#define cpAssertWarn(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 0, 0, __VA_ARGS__)
#endif
#ifdef NDEBUG
#define cpAssertSoft(__condition__, ...)
#else
#define cpAssertSoft(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 1, 0, __VA_ARGS__)
#endif
// Hard assertions are important and cheap to execute. They are not disabled by compiling as debug.
#define cpAssertHard(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 1, 1, __VA_ARGS__)
#include "chipmunk_types.h"
/// @defgroup misc Misc
/// @{
/// Allocated size for various Chipmunk buffers
#ifndef CP_BUFFER_BYTES
#define CP_BUFFER_BYTES (32*1024)
#endif
#ifndef cpcalloc
/// Chipmunk calloc() alias.
#define cpcalloc calloc
#endif
#ifndef cprealloc
/// Chipmunk realloc() alias.
#define cprealloc realloc
#endif
#ifndef cpfree
/// Chipmunk free() alias.
#define cpfree free
#endif
typedef struct cpArray cpArray;
typedef struct cpHashSet cpHashSet;
typedef struct cpBody cpBody;
typedef struct cpShape cpShape;
typedef struct cpConstraint cpConstraint;
typedef struct cpCollisionHandler cpCollisionHandler;
typedef struct cpArbiter cpArbiter;
typedef struct cpSpace cpSpace;
#include "cpVect.h"
#include "cpBB.h"
#include "cpSpatialIndex.h"
#include "cpBody.h"
#include "cpShape.h"
#include "cpPolyShape.h"
#include "cpArbiter.h"
#include "constraints/cpConstraint.h"
#include "cpSpace.h"
// Chipmunk 6.1.4
#define CP_VERSION_MAJOR 6
#define CP_VERSION_MINOR 1
#define CP_VERSION_RELEASE 4
/// Version string.
extern const char *cpVersionString;
/// @deprecated
void cpInitChipmunk(void);
/// Enables segment to segment shape collisions.
void cpEnableSegmentToSegmentCollisions(void);
/// Calculate the moment of inertia for a circle.
/// @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);
/// Calculate area of a hollow circle.
/// @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
cpFloat cpAreaForCircle(cpFloat r1, cpFloat r2);
/// Calculate the moment of inertia for a line segment.
/// Beveling radius is not supported.
cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b);
/// Calculate the area of a fattened (capsule shaped) line segment.
cpFloat cpAreaForSegment(cpVect a, cpVect b, cpFloat r);
/// Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex.
cpFloat cpMomentForPoly(cpFloat m, int numVerts, const cpVect *verts, cpVect offset);
/// Calculate the signed area of a polygon. A Clockwise winding gives positive area.
/// This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes.
cpFloat cpAreaForPoly(const int numVerts, const cpVect *verts);
/// Calculate the natural centroid of a polygon.
cpVect cpCentroidForPoly(const int numVerts, const cpVect *verts);
/// Center the polygon on the origin. (Subtracts the centroid of the polygon from each vertex)
void cpRecenterPoly(const int numVerts, cpVect *verts);
/// Calculate the moment of inertia for a solid box.
cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height);
/// Calculate the moment of inertia for a solid box.
cpFloat cpMomentForBox2(cpFloat m, cpBB box);
/// Calculate the convex hull of a given set of points. Returns the count of points in the hull.
/// @c result must be a pointer to a @c cpVect array with at least @c count elements. If @c result is @c NULL, then @c verts will be reduced instead.
/// @c first is an optional pointer to an integer to store where the first vertex in the hull came from (i.e. verts[first] == result[0])
/// @c tol is the allowed amount to shrink the hull when simplifying it. A tolerance of 0.0 creates an exact hull.
int cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol);
#ifdef _MSC_VER
#include "malloc.h"
#endif
/// Convenience macro to work with cpConvexHull.
/// @c count and @c verts is the input array passed to cpConvexHull().
/// @c count_var and @c verts_var are the names of the variables the macro creates to store the result.
/// The output vertex array is allocated on the stack using alloca() so it will be freed automatically, but cannot be returned from the current scope.
#define CP_CONVEX_HULL(__count__, __verts__, __count_var__, __verts_var__) \
cpVect *__verts_var__ = (cpVect *)alloca(__count__*sizeof(cpVect)); \
int __count_var__ = cpConvexHull(__count__, __verts__, __verts_var__, NULL, 0.0); \
#if defined(__has_extension)
#if __has_extension(blocks)
// Define alternate block based alternatives for a few of the callback heavy functions.
// Collision handlers are post-step callbacks are not included to avoid memory management issues.
// If you want to use blocks for those and are aware of how to correctly manage the memory, the implementation is trivial.
void cpSpaceEachBody_b(cpSpace *space, void (^block)(cpBody *body));
void cpSpaceEachShape_b(cpSpace *space, void (^block)(cpShape *shape));
void cpSpaceEachConstraint_b(cpSpace *space, void (^block)(cpConstraint *constraint));
void cpBodyEachShape_b(cpBody *body, void (^block)(cpShape *shape));
void cpBodyEachConstraint_b(cpBody *body, void (^block)(cpConstraint *constraint));
void cpBodyEachArbiter_b(cpBody *body, void (^block)(cpArbiter *arbiter));
typedef void (^cpSpaceNearestPointQueryBlock)(cpShape *shape, cpFloat distance, cpVect point);
void cpSpaceNearestPointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryBlock block);
typedef void (^cpSpaceSegmentQueryBlock)(cpShape *shape, cpFloat t, cpVect n);
void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryBlock block);
typedef void (^cpSpaceBBQueryBlock)(cpShape *shape);
void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryBlock block);
typedef void (^cpSpaceShapeQueryBlock)(cpShape *shape, cpContactPointSet *points);
cpBool cpSpaceShapeQuery_b(cpSpace *space, cpShape *shape, cpSpaceShapeQueryBlock block);
#endif
#endif
//@}
#ifdef __cplusplus
}
static inline cpVect operator *(const cpVect v, const cpFloat s){return cpvmult(v, s);}
static inline cpVect operator +(const cpVect v1, const cpVect v2){return cpvadd(v1, v2);}
static inline cpVect operator -(const cpVect v1, const cpVect v2){return cpvsub(v1, v2);}
static inline cpBool operator ==(const cpVect v1, const cpVect v2){return cpveql(v1, v2);}
static inline cpVect operator -(const cpVect v){return cpvneg(v);}
#endif
#endif

View File

@@ -0,0 +1,177 @@
#ifdef CHIPMUNK_FFI
// Create non static inlined copies of Chipmunk functions, useful for working with dynamic FFIs
// This file should only be included in chipmunk.c
#ifdef _MSC_VER
#if _MSC_VER >= 1600
#define MAKE_REF(name) decltype(name) *_##name = name
#else
#define MAKE_REF(name)
#endif
#else
#define MAKE_REF(name) __typeof__(name) *_##name = name
#endif
#define MAKE_PROPERTIES_REF(struct, property) \
MAKE_REF(struct##Get##property); MAKE_REF(struct##Set##property)
MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv()
MAKE_REF(cpveql);
MAKE_REF(cpvadd);
MAKE_REF(cpvneg);
MAKE_REF(cpvsub);
MAKE_REF(cpvmult);
MAKE_REF(cpvdot);
MAKE_REF(cpvcross);
MAKE_REF(cpvperp);
MAKE_REF(cpvrperp);
MAKE_REF(cpvproject);
MAKE_REF(cpvforangle);
MAKE_REF(cpvtoangle);
MAKE_REF(cpvrotate);
MAKE_REF(cpvunrotate);
MAKE_REF(cpvlengthsq);
MAKE_REF(cpvlength);
MAKE_REF(cpvlerp);
MAKE_REF(cpvnormalize);
MAKE_REF(cpvnormalize_safe);
MAKE_REF(cpvclamp);
MAKE_REF(cpvlerpconst);
MAKE_REF(cpvdist);
MAKE_REF(cpvdistsq);
MAKE_REF(cpvnear);
MAKE_REF(cpfmax);
MAKE_REF(cpfmin);
MAKE_REF(cpfabs);
MAKE_REF(cpfclamp);
MAKE_REF(cpflerp);
MAKE_REF(cpflerpconst);
MAKE_REF(cpBBNew);
MAKE_REF(cpBBNewForCircle);
MAKE_REF(cpBBIntersects);
MAKE_REF(cpBBContainsBB);
MAKE_REF(cpBBContainsVect);
MAKE_REF(cpBBMerge);
MAKE_REF(cpBBExpand);
MAKE_REF(cpBBArea);
MAKE_REF(cpBBMergedArea);
MAKE_REF(cpBBSegmentQuery);
MAKE_REF(cpBBIntersectsSegment);
MAKE_REF(cpBBClampVect);
MAKE_REF(cpBodyGetMass);
MAKE_REF(cpBodyGetMoment);
MAKE_REF(cpBodyGetPos);
MAKE_REF(cpBodyGetAngle);
MAKE_REF(cpBodyGetRot);
MAKE_PROPERTIES_REF(cpBody, Vel);
MAKE_PROPERTIES_REF(cpBody, Force);
MAKE_PROPERTIES_REF(cpBody, AngVel);
MAKE_PROPERTIES_REF(cpBody, Torque);
MAKE_PROPERTIES_REF(cpBody, VelLimit);
MAKE_PROPERTIES_REF(cpBody, AngVelLimit);
MAKE_PROPERTIES_REF(cpBody, UserData);
MAKE_REF(cpBodyIsSleeping);
MAKE_REF(cpBodyIsStatic);
MAKE_REF(cpBodyIsRogue);
MAKE_REF(cpBodyLocal2World);
MAKE_REF(cpBodyWorld2Local);
MAKE_REF(cpBodyKineticEnergy);
MAKE_REF(cpShapeGetBB);
MAKE_PROPERTIES_REF(cpShape, Body);
MAKE_PROPERTIES_REF(cpShape, Sensor);
MAKE_PROPERTIES_REF(cpShape, Elasticity);
MAKE_PROPERTIES_REF(cpShape, Friction);
MAKE_PROPERTIES_REF(cpShape, SurfaceVelocity);
MAKE_PROPERTIES_REF(cpShape, UserData);
MAKE_PROPERTIES_REF(cpShape, CollisionType);
MAKE_PROPERTIES_REF(cpShape, Group);
MAKE_PROPERTIES_REF(cpShape, Layers);
MAKE_REF(cpArbiterGetShapes);
MAKE_REF(cpArbiterGetBodies);
MAKE_REF(cpArbiterIsFirstContact);
MAKE_REF(cpArbiterGetCount);
MAKE_REF(cpConstraintGetA);
MAKE_REF(cpConstraintGetB);
MAKE_PROPERTIES_REF(cpConstraint, MaxForce);
MAKE_PROPERTIES_REF(cpConstraint, ErrorBias);
MAKE_PROPERTIES_REF(cpConstraint, MaxBias);
MAKE_PROPERTIES_REF(cpConstraint, UserData);
MAKE_REF(cpConstraintGetImpulse);
MAKE_PROPERTIES_REF(cpDampedRotarySpring, RestAngle);
MAKE_PROPERTIES_REF(cpDampedRotarySpring, Stiffness);
MAKE_PROPERTIES_REF(cpDampedRotarySpring, Damping);
//MAKE_PROPERTIES_REF(cpDampedRotarySpring, SpringTorqueFunc);
MAKE_PROPERTIES_REF(cpDampedSpring, Anchr1);
MAKE_PROPERTIES_REF(cpDampedSpring, Anchr2);
MAKE_PROPERTIES_REF(cpDampedSpring, RestLength);
MAKE_PROPERTIES_REF(cpDampedSpring, Stiffness);
MAKE_PROPERTIES_REF(cpDampedSpring, Damping);
//MAKE_PROPERTIES_REF(cpDampedSpring, SpringForceFunc);
MAKE_PROPERTIES_REF(cpGearJoint, Phase);
MAKE_REF(cpGearJointGetRatio);
MAKE_PROPERTIES_REF(cpGrooveJoint, Anchr2);
MAKE_REF(cpGrooveJointGetGrooveA);
MAKE_REF(cpGrooveJointGetGrooveB);
MAKE_PROPERTIES_REF(cpPinJoint, Anchr1);
MAKE_PROPERTIES_REF(cpPinJoint, Anchr2);
MAKE_PROPERTIES_REF(cpPinJoint, Dist);
MAKE_PROPERTIES_REF(cpPivotJoint, Anchr1);
MAKE_PROPERTIES_REF(cpPivotJoint, Anchr2);
MAKE_PROPERTIES_REF(cpRatchetJoint, Angle);
MAKE_PROPERTIES_REF(cpRatchetJoint, Phase);
MAKE_PROPERTIES_REF(cpRatchetJoint, Ratchet);
MAKE_PROPERTIES_REF(cpRotaryLimitJoint, Min);
MAKE_PROPERTIES_REF(cpRotaryLimitJoint, Max);
MAKE_PROPERTIES_REF(cpSimpleMotor, Rate);
MAKE_PROPERTIES_REF(cpSlideJoint, Anchr1);
MAKE_PROPERTIES_REF(cpSlideJoint, Anchr2);
MAKE_PROPERTIES_REF(cpSlideJoint, Min);
MAKE_PROPERTIES_REF(cpSlideJoint, Max);
MAKE_REF(cpSegmentQueryHitPoint);
MAKE_REF(cpSegmentQueryHitDist);
MAKE_REF(cpSpatialIndexDestroy);
MAKE_REF(cpSpatialIndexCount);
MAKE_REF(cpSpatialIndexEach);
MAKE_REF(cpSpatialIndexContains);
MAKE_REF(cpSpatialIndexInsert);
MAKE_REF(cpSpatialIndexRemove);
MAKE_REF(cpSpatialIndexReindex);
MAKE_REF(cpSpatialIndexReindexObject);
MAKE_REF(cpSpatialIndexSegmentQuery);
MAKE_REF(cpSpatialIndexQuery);
MAKE_REF(cpSpatialIndexReindexQuery);
MAKE_PROPERTIES_REF(cpSpace, Iterations);
MAKE_PROPERTIES_REF(cpSpace, Gravity);
MAKE_PROPERTIES_REF(cpSpace, Damping);
MAKE_PROPERTIES_REF(cpSpace, IdleSpeedThreshold);
MAKE_PROPERTIES_REF(cpSpace, SleepTimeThreshold);
MAKE_PROPERTIES_REF(cpSpace, CollisionSlop);
MAKE_PROPERTIES_REF(cpSpace, CollisionBias);
MAKE_PROPERTIES_REF(cpSpace, CollisionPersistence);
MAKE_PROPERTIES_REF(cpSpace, EnableContactGraph);
MAKE_PROPERTIES_REF(cpSpace, UserData);
MAKE_REF(cpSpaceGetStaticBody);
MAKE_REF(cpSpaceGetCurrentTimeStep);
MAKE_REF(cpSpaceIsLocked);
#endif

View File

@@ -0,0 +1,265 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#define CP_ALLOW_PRIVATE_ACCESS 1
#include "chipmunk.h"
#define CP_HASH_COEF (3344921057ul)
#define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF)
//MARK: cpArray
struct cpArray {
int num, max;
void **arr;
};
cpArray *cpArrayNew(int size);
void cpArrayFree(cpArray *arr);
void cpArrayPush(cpArray *arr, void *object);
void *cpArrayPop(cpArray *arr);
void cpArrayDeleteObj(cpArray *arr, void *obj);
cpBool cpArrayContains(cpArray *arr, void *ptr);
void cpArrayFreeEach(cpArray *arr, void (freeFunc)(void*));
//MARK: Foreach loops
static inline cpConstraint *
cpConstraintNext(cpConstraint *node, cpBody *body)
{
return (node->a == body ? node->next_a : node->next_b);
}
#define CP_BODY_FOREACH_CONSTRAINT(bdy, var)\
for(cpConstraint *var = bdy->constraintList; var; var = cpConstraintNext(var, bdy))
static inline cpArbiter *
cpArbiterNext(cpArbiter *node, cpBody *body)
{
return (node->body_a == body ? node->thread_a.next : node->thread_b.next);
}
#define CP_BODY_FOREACH_ARBITER(bdy, var)\
for(cpArbiter *var = bdy->arbiterList; var; var = cpArbiterNext(var, bdy))
#define CP_BODY_FOREACH_SHAPE(body, var)\
for(cpShape *var = body->shapeList; var; var = var->next)
#define CP_BODY_FOREACH_COMPONENT(root, var)\
for(cpBody *var = root; var; var = var->node.next)
//MARK: cpHashSet
typedef cpBool (*cpHashSetEqlFunc)(void *ptr, void *elt);
typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc);
void cpHashSetSetDefaultValue(cpHashSet *set, void *default_value);
void cpHashSetFree(cpHashSet *set);
int cpHashSetCount(cpHashSet *set);
void *cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data, cpHashSetTransFunc trans);
void *cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr);
void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr);
typedef void (*cpHashSetIteratorFunc)(void *elt, void *data);
void cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data);
typedef cpBool (*cpHashSetFilterFunc)(void *elt, void *data);
void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data);
//MARK: Body Functions
void cpBodyAddShape(cpBody *body, cpShape *shape);
void cpBodyRemoveShape(cpBody *body, cpShape *shape);
void cpBodyRemoveConstraint(cpBody *body, cpConstraint *constraint);
//MARK: Shape/Collision Functions
// TODO should move this to the cpVect API. It's pretty useful.
static inline cpVect
cpClosetPointOnSegment(const cpVect p, const cpVect a, const cpVect b)
{
cpVect delta = cpvsub(a, b);
cpFloat t = cpfclamp01(cpvdot(delta, cpvsub(p, b))/cpvlengthsq(delta));
return cpvadd(b, cpvmult(delta, t));
}
cpShape* cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body);
static inline cpBool
cpShapeActive(cpShape *shape)
{
return shape->prev || (shape->body && shape->body->shapeList == shape);
}
int cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr);
// TODO doesn't really need to be inline, but need a better place to put this function
static inline cpSplittingPlane
cpSplittingPlaneNew(cpVect a, cpVect b)
{
cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));
cpSplittingPlane plane = {n, cpvdot(n, a)};
return plane;
}
static inline cpFloat
cpSplittingPlaneCompare(cpSplittingPlane plane, cpVect v)
{
return cpvdot(plane.n, v) - plane.d;
}
void cpLoopIndexes(cpVect *verts, int count, int *start, int *end);
static inline cpFloat
cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
{
cpVect *verts = poly->tVerts;
cpFloat min = cpvdot(n, verts[0]);
for(int i=1; i<poly->numVerts; i++){
min = cpfmin(min, cpvdot(n, verts[i]));
}
return min - d;
}
static inline cpBool
cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
{
cpSplittingPlane *planes = poly->tPlanes;
for(int i=0; i<poly->numVerts; i++){
cpFloat dist = cpSplittingPlaneCompare(planes[i], v);
if(dist > 0.0f) return cpFalse;
}
return cpTrue;
}
static inline cpBool
cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n)
{
cpSplittingPlane *planes = poly->tPlanes;
for(int i=0; i<poly->numVerts; i++){
if(cpvdot(planes[i].n, n) < 0.0f) continue;
cpFloat dist = cpSplittingPlaneCompare(planes[i], v);
if(dist > 0.0f) return cpFalse;
}
return cpTrue;
}
//MARK: Spatial Index Functions
cpSpatialIndex *cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
//MARK: Space Functions
extern cpCollisionHandler cpDefaultCollisionHandler;
void cpSpaceProcessComponents(cpSpace *space, cpFloat dt);
void cpSpacePushFreshContactBuffer(cpSpace *space);
cpContact *cpContactBufferGetArray(cpSpace *space);
void cpSpacePushContacts(cpSpace *space, int count);
typedef struct cpPostStepCallback {
cpPostStepFunc func;
void *key;
void *data;
} cpPostStepCallback;
cpPostStepCallback *cpSpaceGetPostStepCallback(cpSpace *space, void *key);
cpBool cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space);
void cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter);
void cpSpaceActivateBody(cpSpace *space, cpBody *body);
void cpSpaceLock(cpSpace *space);
void cpSpaceUnlock(cpSpace *space, cpBool runPostStep);
static inline cpCollisionHandler *
cpSpaceLookupHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)
{
cpCollisionType types[] = {a, b};
return (cpCollisionHandler *)cpHashSetFind(space->collisionHandlers, CP_HASH_PAIR(a, b), types);
}
static inline void
cpSpaceUncacheArbiter(cpSpace *space, cpArbiter *arb)
{
cpShape *a = arb->a, *b = arb->b;
cpShape *shape_pair[] = {a, b};
cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);
cpHashSetRemove(space->cachedArbiters, arbHashID, shape_pair);
cpArrayDeleteObj(space->arbiters, arb);
}
void cpShapeUpdateFunc(cpShape *shape, void *unused);
void cpSpaceCollideShapes(cpShape *a, cpShape *b, cpSpace *space);
//MARK: Arbiters
struct cpContact {
cpVect p, n;
cpFloat dist;
cpVect r1, r2;
cpFloat nMass, tMass, bounce;
cpFloat jnAcc, jtAcc, jBias;
cpFloat bias;
cpHashValue hash;
};
cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash);
cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b);
static inline void
cpArbiterCallSeparate(cpArbiter *arb, cpSpace *space)
{
// The handler needs to be looked up again as the handler cached on the arbiter may have been deleted since the last step.
cpCollisionHandler *handler = cpSpaceLookupHandler(space, arb->a->collision_type, arb->b->collision_type);
handler->separate(arb, space, handler->data);
}
static inline struct cpArbiterThread *
cpArbiterThreadForBody(cpArbiter *arb, cpBody *body)
{
return (arb->body_a == body ? &arb->thread_a : &arb->thread_b);
}
void cpArbiterUnthread(cpArbiter *arb);
void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, struct cpCollisionHandler *handler, cpShape *a, cpShape *b);
void cpArbiterPreStep(cpArbiter *arb, cpFloat dt, cpFloat bias, cpFloat slop);
void cpArbiterApplyCachedImpulse(cpArbiter *arb, cpFloat dt_coef);
void cpArbiterApplyImpulse(cpArbiter *arb);

View File

@@ -0,0 +1,205 @@
#include <stdint.h>
#ifdef __APPLE__
#include "TargetConditionals.h"
#endif
#if ((TARGET_OS_IPHONE == 1) || (TARGET_OS_MAC == 1)) && (!defined CP_USE_CGPOINTS)
#if defined(__LP64__) && __LP64__
#define CP_USE_DOUBLES 1
#else
#define CP_USE_DOUBLES 0
#endif
#endif
#ifndef CP_USE_DOUBLES
// use doubles by default for higher precision
#define CP_USE_DOUBLES 1
#endif
/// @defgroup basicTypes Basic Types
/// Most of these types can be configured at compile time.
/// @{
#if CP_USE_DOUBLES
/// Chipmunk's floating point type.
/// Can be reconfigured at compile time.
typedef double cpFloat;
#define cpfsqrt sqrt
#define cpfsin sin
#define cpfcos cos
#define cpfacos acos
#define cpfatan2 atan2
#define cpfmod fmod
#define cpfexp exp
#define cpfpow pow
#define cpffloor floor
#define cpfceil ceil
#else
typedef float cpFloat;
#define cpfsqrt sqrtf
#define cpfsin sinf
#define cpfcos cosf
#define cpfacos acosf
#define cpfatan2 atan2f
#define cpfmod fmodf
#define cpfexp expf
#define cpfpow powf
#define cpffloor floorf
#define cpfceil ceilf
#endif
#ifndef INFINITY
#ifdef _MSC_VER
union MSVC_EVIL_FLOAT_HACK
{
unsigned __int8 Bytes[4];
float Value;
};
static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}};
#define INFINITY (INFINITY_HACK.Value)
#endif
#ifdef __GNUC__
#define INFINITY (__builtin_inf())
#endif
#ifndef INFINITY
#define INFINITY (1e1000)
#endif
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
#ifndef M_E
#define M_E 2.71828182845904523536028747135266250
#endif
/// Return the max of two cpFloats.
static inline cpFloat cpfmax(cpFloat a, cpFloat b)
{
return (a > b) ? a : b;
}
/// Return the min of two cpFloats.
static inline cpFloat cpfmin(cpFloat a, cpFloat b)
{
return (a < b) ? a : b;
}
/// Return the absolute value of a cpFloat.
static inline cpFloat cpfabs(cpFloat f)
{
return (f < 0) ? -f : f;
}
/// Clamp @c f to be between @c min and @c max.
static inline cpFloat cpfclamp(cpFloat f, cpFloat min, cpFloat max)
{
return cpfmin(cpfmax(f, min), max);
}
/// Clamp @c f to be between 0 and 1.
static inline cpFloat cpfclamp01(cpFloat f)
{
return cpfmax(0.0f, cpfmin(f, 1.0f));
}
/// Linearly interpolate (or extrapolate) between @c f1 and @c f2 by @c t percent.
static inline cpFloat cpflerp(cpFloat f1, cpFloat f2, cpFloat t)
{
return f1*(1.0f - t) + f2*t;
}
/// Linearly interpolate from @c f1 to @c f2 by no more than @c d.
static inline cpFloat cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
{
return f1 + cpfclamp(f2 - f1, -d, d);
}
/// Hash value type.
typedef uintptr_t cpHashValue;
// Oh C, how we love to define our own boolean types to get compiler compatibility
/// Chipmunk's boolean type.
#ifdef CP_BOOL_TYPE
typedef CP_BOOL_TYPE cpBool;
#else
typedef int cpBool;
#endif
#ifndef cpTrue
/// true value.
#define cpTrue 1
#endif
#ifndef cpFalse
/// false value.
#define cpFalse 0
#endif
#ifdef CP_DATA_POINTER_TYPE
typedef CP_DATA_POINTER_TYPE cpDataPointer;
#else
/// Type used for user data pointers.
typedef void * cpDataPointer;
#endif
#ifdef CP_COLLISION_TYPE_TYPE
typedef CP_COLLISION_TYPE_TYPE cpCollisionType;
#else
/// Type used for cpSpace.collision_type.
typedef uintptr_t cpCollisionType;
#endif
#ifdef CP_GROUP_TYPE
typedef CP_GROUP_TYPE cpGroup;
#else
/// Type used for cpShape.group.
typedef uintptr_t cpGroup;
#endif
#ifdef CP_LAYERS_TYPE
typedef CP_LAYERS_TYPE cpLayers;
#else
/// Type used for cpShape.layers.
typedef unsigned int cpLayers;
#endif
#ifdef CP_TIMESTAMP_TYPE
typedef CP_TIMESTAMP_TYPE cpTimestamp;
#else
/// Type used for various timestamps in Chipmunk.
typedef unsigned int cpTimestamp;
#endif
#ifndef CP_NO_GROUP
/// Value for cpShape.group signifying that a shape is in no group.
#define CP_NO_GROUP ((cpGroup)0)
#endif
#ifndef CP_ALL_LAYERS
/// Value for cpShape.layers signifying that a shape is in every layer.
#define CP_ALL_LAYERS (~(cpLayers)0)
#endif
/// @}
// CGPoints are structurally the same, and allow
// easy interoperability with other Cocoa libraries
#if CP_USE_CGPOINTS
typedef CGPoint cpVect;
#else
/// Chipmunk's 2D vector type.
/// @addtogroup cpVect
typedef struct cpVect{cpFloat x,y;} cpVect;
#endif
typedef struct cpMat2x2 {
// Row major [[a, b][c d]]
cpFloat a, b, c, d;
} cpMat2x2;

View File

@@ -0,0 +1,63 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* This header defines a number of "unsafe" operations on Chipmunk objects.
* In this case "unsafe" is referring to operations which may reduce the
* physical accuracy or numerical stability of the simulation, but will not
* cause crashes.
*
* The prime example is mutating collision shapes. Chipmunk does not support
* this directly. Mutating shapes using this API will caused objects in contact
* to be pushed apart using Chipmunk's overlap solver, but not using real
* persistent velocities. Probably not what you meant, but perhaps close enough.
*/
/// @defgroup unsafe Chipmunk Unsafe Shape Operations
/// These functions are used for mutating collision shapes.
/// Chipmunk does not have any way to get velocity information on changing shapes,
/// so the results will be unrealistic. You must explicity include the chipmunk_unsafe.h header to use them.
/// @{
#ifndef CHIPMUNK_UNSAFE_HEADER
#define CHIPMUNK_UNSAFE_HEADER
#ifdef __cplusplus
extern "C" {
#endif
/// Set the radius of a circle shape.
void cpCircleShapeSetRadius(cpShape *shape, cpFloat radius);
/// Set the offset of a circle shape.
void cpCircleShapeSetOffset(cpShape *shape, cpVect offset);
/// Set the endpoints of a segment shape.
void cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b);
/// Set the radius of a segment shape.
void cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius);
/// Set the vertexes of a poly shape.
void cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset);
#ifdef __cplusplus
}
#endif
#endif
/// @}

View File

@@ -0,0 +1,161 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpConstraint cpConstraint
/// @{
typedef struct cpConstraintClass cpConstraintClass;
typedef void (*cpConstraintPreStepImpl)(cpConstraint *constraint, cpFloat dt);
typedef void (*cpConstraintApplyCachedImpulseImpl)(cpConstraint *constraint, cpFloat dt_coef);
typedef void (*cpConstraintApplyImpulseImpl)(cpConstraint *constraint, cpFloat dt);
typedef cpFloat (*cpConstraintGetImpulseImpl)(cpConstraint *constraint);
/// @private
struct cpConstraintClass {
cpConstraintPreStepImpl preStep;
cpConstraintApplyCachedImpulseImpl applyCachedImpulse;
cpConstraintApplyImpulseImpl applyImpulse;
cpConstraintGetImpulseImpl getImpulse;
};
/// Callback function type that gets called before solving a joint.
typedef void (*cpConstraintPreSolveFunc)(cpConstraint *constraint, cpSpace *space);
/// Callback function type that gets called after solving a joint.
typedef void (*cpConstraintPostSolveFunc)(cpConstraint *constraint, cpSpace *space);
/// Opaque cpConstraint struct.
struct cpConstraint {
CP_PRIVATE(const cpConstraintClass *klass);
/// The first body connected to this constraint.
cpBody *a;
/// The second body connected to this constraint.
cpBody *b;
CP_PRIVATE(cpSpace *space);
CP_PRIVATE(cpConstraint *next_a);
CP_PRIVATE(cpConstraint *next_b);
/// The maximum force that this constraint is allowed to use.
/// Defaults to infinity.
cpFloat maxForce;
/// The rate at which joint error is corrected.
/// Defaults to pow(1.0 - 0.1, 60.0) meaning that it will
/// correct 10% of the error every 1/60th of a second.
cpFloat errorBias;
/// The maximum rate at which joint error is corrected.
/// Defaults to infinity.
cpFloat maxBias;
/// Function called before the solver runs.
/// Animate your joint anchors, update your motor torque, etc.
cpConstraintPreSolveFunc preSolve;
/// Function called after the solver runs.
/// Use the applied impulse to perform effects like breakable joints.
cpConstraintPostSolveFunc postSolve;
/// User definable data pointer.
/// Generally this points to your the game object class so you can access it
/// when given a cpConstraint reference in a callback.
cpDataPointer data;
};
/// Destroy a constraint.
void cpConstraintDestroy(cpConstraint *constraint);
/// Destroy and free a constraint.
void cpConstraintFree(cpConstraint *constraint);
/// @private
static inline void cpConstraintActivateBodies(cpConstraint *constraint)
{
cpBody *a = constraint->a; if(a) cpBodyActivate(a);
cpBody *b = constraint->b; if(b) cpBodyActivate(b);
}
/// @private
#define CP_DefineConstraintStructGetter(type, member, name) \
static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;}
/// @private
#define CP_DefineConstraintStructSetter(type, member, name) \
static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \
cpConstraintActivateBodies(constraint); \
constraint->member = value; \
}
/// @private
#define CP_DefineConstraintStructProperty(type, member, name) \
CP_DefineConstraintStructGetter(type, member, name) \
CP_DefineConstraintStructSetter(type, member, name)
CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
CP_DefineConstraintStructGetter(cpBody*, a, A)
CP_DefineConstraintStructGetter(cpBody*, b, B)
CP_DefineConstraintStructProperty(cpFloat, maxForce, MaxForce)
CP_DefineConstraintStructProperty(cpFloat, errorBias, ErrorBias)
CP_DefineConstraintStructProperty(cpFloat, maxBias, MaxBias)
CP_DefineConstraintStructProperty(cpConstraintPreSolveFunc, preSolve, PreSolveFunc)
CP_DefineConstraintStructProperty(cpConstraintPostSolveFunc, postSolve, PostSolveFunc)
CP_DefineConstraintStructProperty(cpDataPointer, data, UserData)
// Get the last impulse applied by this constraint.
static inline cpFloat cpConstraintGetImpulse(cpConstraint *constraint)
{
return constraint->CP_PRIVATE(klass)->getImpulse(constraint);
}
/// @}
#define cpConstraintCheckCast(constraint, struct) \
cpAssertHard(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct)
#define CP_DefineConstraintGetter(struct, type, member, name) \
static inline type struct##Get##name(const cpConstraint *constraint){ \
cpConstraintCheckCast(constraint, struct); \
return ((struct *)constraint)->member; \
}
#define CP_DefineConstraintSetter(struct, type, member, name) \
static inline void struct##Set##name(cpConstraint *constraint, type value){ \
cpConstraintCheckCast(constraint, struct); \
cpConstraintActivateBodies(constraint); \
((struct *)constraint)->member = value; \
}
#define CP_DefineConstraintProperty(struct, type, member, name) \
CP_DefineConstraintGetter(struct, type, member, name) \
CP_DefineConstraintSetter(struct, type, member, name)
#include "cpPinJoint.h"
#include "cpSlideJoint.h"
#include "cpPivotJoint.h"
#include "cpGrooveJoint.h"
#include "cpDampedSpring.h"
#include "cpDampedRotarySpring.h"
#include "cpRotaryLimitJoint.h"
#include "cpRatchetJoint.h"
#include "cpGearJoint.h"
#include "cpSimpleMotor.h"

View File

@@ -0,0 +1,56 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpDampedRotarySpring cpDampedRotarySpring
/// @{
typedef cpFloat (*cpDampedRotarySpringTorqueFunc)(struct cpConstraint *spring, cpFloat relativeAngle);
const cpConstraintClass *cpDampedRotarySpringGetClass(void);
/// @private
typedef struct cpDampedRotarySpring {
cpConstraint constraint;
cpFloat restAngle;
cpFloat stiffness;
cpFloat damping;
cpDampedRotarySpringTorqueFunc springTorqueFunc;
cpFloat target_wrn;
cpFloat w_coef;
cpFloat iSum;
cpFloat jAcc;
} cpDampedRotarySpring;
/// Allocate a damped rotary spring.
cpDampedRotarySpring* cpDampedRotarySpringAlloc(void);
/// Initialize a damped rotary spring.
cpDampedRotarySpring* cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
/// Allocate and initialize a damped rotary spring.
cpConstraint* cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle)
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness)
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping)
CP_DefineConstraintProperty(cpDampedRotarySpring, cpDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc)
/// @}

View File

@@ -0,0 +1,64 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpDampedSpring cpDampedSpring
/// @{
typedef struct cpDampedSpring cpDampedSpring;
typedef cpFloat (*cpDampedSpringForceFunc)(cpConstraint *spring, cpFloat dist);
const cpConstraintClass *cpDampedSpringGetClass(void);
/// @private
struct cpDampedSpring {
cpConstraint constraint;
cpVect anchr1, anchr2;
cpFloat restLength;
cpFloat stiffness;
cpFloat damping;
cpDampedSpringForceFunc springForceFunc;
cpFloat target_vrn;
cpFloat v_coef;
cpVect r1, r2;
cpFloat nMass;
cpVect n;
cpFloat jAcc;
};
/// Allocate a damped spring.
cpDampedSpring* cpDampedSpringAlloc(void);
/// Initialize a damped spring.
cpDampedSpring* cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
/// Allocate and initialize a damped spring.
cpConstraint* cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr2, Anchr2)
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, restLength, RestLength)
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, stiffness, Stiffness)
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, damping, Damping)
CP_DefineConstraintProperty(cpDampedSpring, cpDampedSpringForceFunc, springForceFunc, SpringForceFunc)
/// @}

View File

@@ -0,0 +1,51 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpGearJoint cpGearJoint
/// @{
const cpConstraintClass *cpGearJointGetClass(void);
/// @private
typedef struct cpGearJoint {
cpConstraint constraint;
cpFloat phase, ratio;
cpFloat ratio_inv;
cpFloat iSum;
cpFloat bias;
cpFloat jAcc;
} cpGearJoint;
/// Allocate a gear joint.
cpGearJoint* cpGearJointAlloc(void);
/// Initialize a gear joint.
cpGearJoint* cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
/// Allocate and initialize a gear joint.
cpConstraint* cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase)
CP_DefineConstraintGetter(cpGearJoint, cpFloat, ratio, Ratio)
/// Set the ratio of a gear joint.
void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value);
/// @}

View File

@@ -0,0 +1,57 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpGrooveJoint cpGrooveJoint
/// @{
const cpConstraintClass *cpGrooveJointGetClass(void);
/// @private
typedef struct cpGrooveJoint {
cpConstraint constraint;
cpVect grv_n, grv_a, grv_b;
cpVect anchr2;
cpVect grv_tn;
cpFloat clamp;
cpVect r1, r2;
cpMat2x2 k;
cpVect jAcc;
cpVect bias;
} cpGrooveJoint;
/// Allocate a groove joint.
cpGrooveJoint* cpGrooveJointAlloc(void);
/// Initialize a groove joint.
cpGrooveJoint* cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
/// Allocate and initialize a groove joint.
cpConstraint* cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA)
/// Set endpoint a of a groove joint's groove
void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB)
/// Set endpoint b of a groove joint's groove
void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value);
CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2)
/// @}

View File

@@ -0,0 +1,52 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpPinJoint cpPinJoint
/// @{
const cpConstraintClass *cpPinJointGetClass(void);
/// @private
typedef struct cpPinJoint {
cpConstraint constraint;
cpVect anchr1, anchr2;
cpFloat dist;
cpVect r1, r2;
cpVect n;
cpFloat nMass;
cpFloat jnAcc;
cpFloat bias;
} cpPinJoint;
/// Allocate a pin joint.
cpPinJoint* cpPinJointAlloc(void);
/// Initialize a pin joint.
cpPinJoint* cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
/// Allocate and initialize a pin joint.
cpConstraint* cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr2, Anchr2)
CP_DefineConstraintProperty(cpPinJoint, cpFloat, dist, Dist)
///@}

View File

@@ -0,0 +1,51 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpPivotJoint cpPivotJoint
/// @{
const cpConstraintClass *cpPivotJointGetClass(void);
/// @private
typedef struct cpPivotJoint {
cpConstraint constraint;
cpVect anchr1, anchr2;
cpVect r1, r2;
cpMat2x2 k;
cpVect jAcc;
cpVect bias;
} cpPivotJoint;
/// Allocate a pivot joint
cpPivotJoint* cpPivotJointAlloc(void);
/// Initialize a pivot joint.
cpPivotJoint* cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
/// Allocate and initialize a pivot joint.
cpConstraint* cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);
/// Allocate and initialize a pivot joint with specific anchors.
cpConstraint* cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2)
/// @}

View File

@@ -0,0 +1,49 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpRatchetJoint cpRatchetJoint
/// @{
const cpConstraintClass *cpRatchetJointGetClass(void);
/// @private
typedef struct cpRatchetJoint {
cpConstraint constraint;
cpFloat angle, phase, ratchet;
cpFloat iSum;
cpFloat bias;
cpFloat jAcc;
} cpRatchetJoint;
/// Allocate a ratchet joint.
cpRatchetJoint* cpRatchetJointAlloc(void);
/// Initialize a ratched joint.
cpRatchetJoint* cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
/// Allocate and initialize a ratchet joint.
cpConstraint* cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, angle, Angle)
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, phase, Phase)
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, ratchet, Ratchet)
/// @}

View File

@@ -0,0 +1,48 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpRotaryLimitJoint cpRotaryLimitJoint
/// @{
const cpConstraintClass *cpRotaryLimitJointGetClass(void);
/// @private
typedef struct cpRotaryLimitJoint {
cpConstraint constraint;
cpFloat min, max;
cpFloat iSum;
cpFloat bias;
cpFloat jAcc;
} cpRotaryLimitJoint;
/// Allocate a damped rotary limit joint.
cpRotaryLimitJoint* cpRotaryLimitJointAlloc(void);
/// Initialize a damped rotary limit joint.
cpRotaryLimitJoint* cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max);
/// Allocate and initialize a damped rotary limit joint.
cpConstraint* cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max);
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min)
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max)
/// @}

View File

@@ -0,0 +1,46 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpSimpleMotor cpSimpleMotor
/// @{
const cpConstraintClass *cpSimpleMotorGetClass(void);
/// @private
typedef struct cpSimpleMotor {
cpConstraint constraint;
cpFloat rate;
cpFloat iSum;
cpFloat jAcc;
} cpSimpleMotor;
/// Allocate a simple motor.
cpSimpleMotor* cpSimpleMotorAlloc(void);
/// initialize a simple motor.
cpSimpleMotor* cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);
/// Allocate and initialize a simple motor.
cpConstraint* cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);
CP_DefineConstraintProperty(cpSimpleMotor, cpFloat, rate, Rate)
/// @}

View File

@@ -0,0 +1,53 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpSlideJoint cpSlideJoint
/// @{
const cpConstraintClass *cpSlideJointGetClass(void);
/// @private
typedef struct cpSlideJoint {
cpConstraint constraint;
cpVect anchr1, anchr2;
cpFloat min, max;
cpVect r1, r2;
cpVect n;
cpFloat nMass;
cpFloat jnAcc;
cpFloat bias;
} cpSlideJoint;
/// Allocate a slide joint.
cpSlideJoint* cpSlideJointAlloc(void);
/// Initialize a slide joint.
cpSlideJoint* cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
/// Allocate and initialize a slide joint.
cpConstraint* cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2)
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min)
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max)
/// @}

View File

@@ -0,0 +1,126 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// These are utility routines to use when creating custom constraints.
// I'm not sure if this should be part of the private API or not.
// I should probably clean up the naming conventions if it is...
#define CP_DefineClassGetter(t) const cpConstraintClass * t##GetClass(void){return (cpConstraintClass *)&klass;}
void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b);
static inline cpVect
relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){
cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
cpVect v2_sum = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));
return cpvsub(v2_sum, v1_sum);
}
static inline cpFloat
normal_relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n){
return cpvdot(relative_velocity(a, b, r1, r2), n);
}
static inline void
apply_impulse(cpBody *body, cpVect j, cpVect r){
body->v = cpvadd(body->v, cpvmult(j, body->m_inv));
body->w += body->i_inv*cpvcross(r, j);
}
static inline void
apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
{
apply_impulse(a, cpvneg(j), r1);
apply_impulse(b, j, r2);
}
static inline void
apply_bias_impulse(cpBody *body, cpVect j, cpVect r)
{
body->CP_PRIVATE(v_bias) = cpvadd(body->CP_PRIVATE(v_bias), cpvmult(j, body->m_inv));
body->CP_PRIVATE(w_bias) += body->i_inv*cpvcross(r, j);
}
static inline void
apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
{
apply_bias_impulse(a, cpvneg(j), r1);
apply_bias_impulse(b, j, r2);
}
static inline cpFloat
k_scalar_body(cpBody *body, cpVect r, cpVect n)
{
cpFloat rcn = cpvcross(r, n);
return body->m_inv + body->i_inv*rcn*rcn;
}
static inline cpFloat
k_scalar(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)
{
cpFloat value = k_scalar_body(a, r1, n) + k_scalar_body(b, r2, n);
cpAssertSoft(value != 0.0, "Unsolvable collision or constraint.");
return value;
}
static inline cpMat2x2
k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2)
{
cpFloat m_sum = a->m_inv + b->m_inv;
// start with Identity*m_sum
cpFloat k11 = m_sum, k12 = 0.0f;
cpFloat k21 = 0.0f, k22 = m_sum;
// add the influence from r1
cpFloat a_i_inv = a->i_inv;
cpFloat r1xsq = r1.x * r1.x * a_i_inv;
cpFloat r1ysq = r1.y * r1.y * a_i_inv;
cpFloat r1nxy = -r1.x * r1.y * a_i_inv;
k11 += r1ysq; k12 += r1nxy;
k21 += r1nxy; k22 += r1xsq;
// add the influnce from r2
cpFloat b_i_inv = b->i_inv;
cpFloat r2xsq = r2.x * r2.x * b_i_inv;
cpFloat r2ysq = r2.y * r2.y * b_i_inv;
cpFloat r2nxy = -r2.x * r2.y * b_i_inv;
k11 += r2ysq; k12 += r2nxy;
k21 += r2nxy; k22 += r2xsq;
// invert
cpFloat det = k11*k22 - k12*k21;
cpAssertSoft(det != 0.0, "Unsolvable constraint.");
cpFloat det_inv = 1.0f/det;
return cpMat2x2New(
k22*det_inv, -k12*det_inv,
-k21*det_inv, k11*det_inv
);
}
static inline cpFloat
bias_coef(cpFloat errorBias, cpFloat dt)
{
return 1.0f - cpfpow(errorBias, dt);
}

View File

@@ -0,0 +1,207 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpArbiter cpArbiter
/// The cpArbiter struct controls pairs of colliding shapes.
/// They are also used in conjuction with collision handler callbacks
/// allowing you to retrieve information on the collision and control it.
/// @{
/// Collision begin event function callback type.
/// Returning false from a begin callback causes the collision to be ignored until
/// the the separate callback is called when the objects stop colliding.
typedef cpBool (*cpCollisionBeginFunc)(cpArbiter *arb, cpSpace *space, void *data);
/// Collision pre-solve event function callback type.
/// Returning false from a pre-step callback causes the collision to be ignored until the next step.
typedef cpBool (*cpCollisionPreSolveFunc)(cpArbiter *arb, cpSpace *space, void *data);
/// Collision post-solve event function callback type.
typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, cpSpace *space, void *data);
/// Collision separate event function callback type.
typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, cpSpace *space, void *data);
/// @private
struct cpCollisionHandler {
cpCollisionType a;
cpCollisionType b;
cpCollisionBeginFunc begin;
cpCollisionPreSolveFunc preSolve;
cpCollisionPostSolveFunc postSolve;
cpCollisionSeparateFunc separate;
void *data;
};
typedef struct cpContact cpContact;
#define CP_MAX_CONTACTS_PER_ARBITER 4
/// @private
typedef enum cpArbiterState {
// Arbiter is active and its the first collision.
cpArbiterStateFirstColl,
// Arbiter is active and its not the first collision.
cpArbiterStateNormal,
// Collision has been explicitly ignored.
// Either by returning false from a begin collision handler or calling cpArbiterIgnore().
cpArbiterStateIgnore,
// Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.
cpArbiterStateCached,
} cpArbiterState;
/// @private
struct cpArbiterThread {
// Links to next and previous arbiters in the contact graph.
struct cpArbiter *next, *prev;
};
/// A colliding pair of shapes.
struct cpArbiter {
/// Calculated value to use for the elasticity coefficient.
/// Override in a pre-solve collision handler for custom behavior.
cpFloat e;
/// Calculated value to use for the friction coefficient.
/// Override in a pre-solve collision handler for custom behavior.
cpFloat u;
/// Calculated value to use for applying surface velocities.
/// Override in a pre-solve collision handler for custom behavior.
cpVect surface_vr;
/// User definable data pointer.
/// The value will persist for the pair of shapes until the separate() callback is called.
/// NOTE: If you need to clean up this pointer, you should implement the separate() callback to do it.
cpDataPointer data;
CP_PRIVATE(cpShape *a);
CP_PRIVATE(cpShape *b);
CP_PRIVATE(cpBody *body_a);
CP_PRIVATE(cpBody *body_b);
CP_PRIVATE(struct cpArbiterThread thread_a);
CP_PRIVATE(struct cpArbiterThread thread_b);
CP_PRIVATE(int numContacts);
CP_PRIVATE(cpContact *contacts);
CP_PRIVATE(cpTimestamp stamp);
CP_PRIVATE(cpCollisionHandler *handler);
CP_PRIVATE(cpBool swappedColl);
CP_PRIVATE(cpArbiterState state);
};
#define CP_DefineArbiterStructGetter(type, member, name) \
static inline type cpArbiterGet##name(const cpArbiter *arb){return arb->member;}
#define CP_DefineArbiterStructSetter(type, member, name) \
static inline void cpArbiterSet##name(cpArbiter *arb, type value){arb->member = value;}
#define CP_DefineArbiterStructProperty(type, member, name) \
CP_DefineArbiterStructGetter(type, member, name) \
CP_DefineArbiterStructSetter(type, member, name)
CP_DefineArbiterStructProperty(cpFloat, e, Elasticity)
CP_DefineArbiterStructProperty(cpFloat, u, Friction)
// Get the relative surface velocity of the two shapes in contact.
cpVect cpArbiterGetSurfaceVelocity(cpArbiter *arb);
// Override the relative surface velocity of the two shapes in contact.
// By default this is calculated to be the difference of the two
// surface velocities clamped to the tangent plane.
void cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr);
CP_DefineArbiterStructProperty(cpDataPointer, data, UserData)
/// Calculate the total impulse that was applied by this arbiter.
/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
cpVect cpArbiterTotalImpulse(const cpArbiter *arb);
/// Calculate the total impulse including the friction that was applied by this arbiter.
/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
cpVect cpArbiterTotalImpulseWithFriction(const cpArbiter *arb);
/// Calculate the amount of energy lost in a collision including static, but not dynamic friction.
/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
cpFloat cpArbiterTotalKE(const cpArbiter *arb);
/// Causes a collision pair to be ignored as if you returned false from a begin callback.
/// If called from a pre-step callback, you will still need to return false
/// if you want it to be ignored in the current step.
void cpArbiterIgnore(cpArbiter *arb);
/// Return the colliding shapes involved for this arbiter.
/// The order of their cpSpace.collision_type values will match
/// the order set when the collision handler was registered.
static inline void cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b)
{
if(arb->CP_PRIVATE(swappedColl)){
(*a) = arb->CP_PRIVATE(b), (*b) = arb->CP_PRIVATE(a);
} else {
(*a) = arb->CP_PRIVATE(a), (*b) = arb->CP_PRIVATE(b);
}
}
/// A macro shortcut for defining and retrieving the shapes from an arbiter.
#define CP_ARBITER_GET_SHAPES(__arb__, __a__, __b__) cpShape *__a__, *__b__; cpArbiterGetShapes(__arb__, &__a__, &__b__);
/// Return the colliding bodies involved for this arbiter.
/// The order of the cpSpace.collision_type the bodies are associated with values will match
/// the order set when the collision handler was registered.
static inline void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b)
{
CP_ARBITER_GET_SHAPES(arb, shape_a, shape_b);
(*a) = shape_a->body;
(*b) = shape_b->body;
}
/// A macro shortcut for defining and retrieving the bodies from an arbiter.
#define CP_ARBITER_GET_BODIES(__arb__, __a__, __b__) cpBody *__a__, *__b__; cpArbiterGetBodies(__arb__, &__a__, &__b__);
/// A struct that wraps up the important collision data for an arbiter.
typedef struct cpContactPointSet {
/// The number of contact points in the set.
int count;
/// The array of contact points.
struct {
/// The position of the contact point.
cpVect point;
/// The normal of the contact point.
cpVect normal;
/// The depth of the contact point.
cpFloat dist;
} points[CP_MAX_CONTACTS_PER_ARBITER];
} cpContactPointSet;
/// Return a contact set from an arbiter.
cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb);
/// Replace the contact point set for an arbiter.
/// This can be a very powerful feature, but use it with caution!
void cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set);
/// Returns true if this is the first step a pair of objects started colliding.
cpBool cpArbiterIsFirstContact(const cpArbiter *arb);
/// Get the number of contact points for this arbiter.
int cpArbiterGetCount(const cpArbiter *arb);
/// Get the normal of the @c ith contact point.
cpVect cpArbiterGetNormal(const cpArbiter *arb, int i);
/// Get the position of the @c ith contact point.
cpVect cpArbiterGetPoint(const cpArbiter *arb, int i);
/// Get the depth of the @c ith contact point.
cpFloat cpArbiterGetDepth(const cpArbiter *arb, int i);
/// @}

View File

@@ -0,0 +1,136 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpBBB cpBB
/// Chipmunk's axis-aligned 2D bounding box type along with a few handy routines.
/// @{
/// Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top)
typedef struct cpBB{
cpFloat l, b, r ,t;
} cpBB;
/// Convenience constructor for cpBB structs.
static inline cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t)
{
cpBB bb = {l, b, r, t};
return bb;
}
/// Constructs a cpBB for a circle with the given position and radius.
static inline cpBB cpBBNewForCircle(const cpVect p, const cpFloat r)
{
return cpBBNew(p.x - r, p.y - r, p.x + r, p.y + r);
}
/// Returns true if @c a and @c b intersect.
static inline cpBool cpBBIntersects(const cpBB a, const cpBB b)
{
return (a.l <= b.r && b.l <= a.r && a.b <= b.t && b.b <= a.t);
}
/// Returns true if @c other lies completely within @c bb.
static inline cpBool cpBBContainsBB(const cpBB bb, const cpBB other)
{
return (bb.l <= other.l && bb.r >= other.r && bb.b <= other.b && bb.t >= other.t);
}
/// Returns true if @c bb contains @c v.
static inline cpBool cpBBContainsVect(const cpBB bb, const cpVect v)
{
return (bb.l <= v.x && bb.r >= v.x && bb.b <= v.y && bb.t >= v.y);
}
/// Returns a bounding box that holds both bounding boxes.
static inline cpBB cpBBMerge(const cpBB a, const cpBB b){
return cpBBNew(
cpfmin(a.l, b.l),
cpfmin(a.b, b.b),
cpfmax(a.r, b.r),
cpfmax(a.t, b.t)
);
}
/// Returns a bounding box that holds both @c bb and @c v.
static inline cpBB cpBBExpand(const cpBB bb, const cpVect v){
return cpBBNew(
cpfmin(bb.l, v.x),
cpfmin(bb.b, v.y),
cpfmax(bb.r, v.x),
cpfmax(bb.t, v.y)
);
}
/// Returns the area of the bounding box.
static inline cpFloat cpBBArea(cpBB bb)
{
return (bb.r - bb.l)*(bb.t - bb.b);
}
/// Merges @c a and @c b and returns the area of the merged bounding box.
static inline cpFloat cpBBMergedArea(cpBB a, cpBB b)
{
return (cpfmax(a.r, b.r) - cpfmin(a.l, b.l))*(cpfmax(a.t, b.t) - cpfmin(a.b, b.b));
}
/// Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn't hit.
static inline cpFloat cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b)
{
cpFloat idx = 1.0f/(b.x - a.x);
cpFloat tx1 = (bb.l == a.x ? -INFINITY : (bb.l - a.x)*idx);
cpFloat tx2 = (bb.r == a.x ? INFINITY : (bb.r - a.x)*idx);
cpFloat txmin = cpfmin(tx1, tx2);
cpFloat txmax = cpfmax(tx1, tx2);
cpFloat idy = 1.0f/(b.y - a.y);
cpFloat ty1 = (bb.b == a.y ? -INFINITY : (bb.b - a.y)*idy);
cpFloat ty2 = (bb.t == a.y ? INFINITY : (bb.t - a.y)*idy);
cpFloat tymin = cpfmin(ty1, ty2);
cpFloat tymax = cpfmax(ty1, ty2);
if(tymin <= txmax && txmin <= tymax){
cpFloat min = cpfmax(txmin, tymin);
cpFloat max = cpfmin(txmax, tymax);
if(0.0 <= max && min <= 1.0) return cpfmax(min, 0.0);
}
return INFINITY;
}
/// Return true if the bounding box intersects the line segment with ends @c a and @c b.
static inline cpBool cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b)
{
return (cpBBSegmentQuery(bb, a, b) != INFINITY);
}
/// Clamp a vector to a bounding box.
static inline cpVect
cpBBClampVect(const cpBB bb, const cpVect v)
{
return cpv(cpfclamp(v.x, bb.l, bb.r), cpfclamp(v.y, bb.b, bb.t));
}
// TODO edge case issue
/// Wrap a vector to a bounding box.
cpVect cpBBWrapVect(const cpBB bb, const cpVect v); // wrap a vector to a bbox
///@}

View File

@@ -0,0 +1,251 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpBody cpBody
/// Chipmunk's rigid body type. Rigid bodies hold the physical properties of an object like
/// it's mass, and position and velocity of it's center of gravity. They don't have an shape on their own.
/// They are given a shape by creating collision shapes (cpShape) that point to the body.
/// @{
/// Rigid body velocity update function type.
typedef void (*cpBodyVelocityFunc)(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
/// Rigid body position update function type.
typedef void (*cpBodyPositionFunc)(cpBody *body, cpFloat dt);
/// Used internally to track information on the collision graph.
/// @private
typedef struct cpComponentNode {
cpBody *root;
cpBody *next;
cpFloat idleTime;
} cpComponentNode;
/// Chipmunk's rigid body struct.
struct cpBody {
/// Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)
cpBodyVelocityFunc velocity_func;
/// Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)
cpBodyPositionFunc position_func;
/// Mass of the body.
/// Must agree with cpBody.m_inv! Use cpBodySetMass() when changing the mass for this reason.
cpFloat m;
/// Mass inverse.
cpFloat m_inv;
/// Moment of inertia of the body.
/// Must agree with cpBody.i_inv! Use cpBodySetMoment() when changing the moment for this reason.
cpFloat i;
/// Moment of inertia inverse.
cpFloat i_inv;
/// Position of the rigid body's center of gravity.
cpVect p;
/// Velocity of the rigid body's center of gravity.
cpVect v;
/// Force acting on the rigid body's center of gravity.
cpVect f;
/// Rotation of the body around it's center of gravity in radians.
/// Must agree with cpBody.rot! Use cpBodySetAngle() when changing the angle for this reason.
cpFloat a;
/// Angular velocity of the body around it's center of gravity in radians/second.
cpFloat w;
/// Torque applied to the body around it's center of gravity.
cpFloat t;
/// Cached unit length vector representing the angle of the body.
/// Used for fast rotations using cpvrotate().
cpVect rot;
/// User definable data pointer.
/// Generally this points to your the game object class so you can access it
/// when given a cpBody reference in a callback.
cpDataPointer data;
/// Maximum velocity allowed when updating the velocity.
cpFloat v_limit;
/// Maximum rotational rate (in radians/second) allowed when updating the angular velocity.
cpFloat w_limit;
CP_PRIVATE(cpVect v_bias);
CP_PRIVATE(cpFloat w_bias);
CP_PRIVATE(cpSpace *space);
CP_PRIVATE(cpShape *shapeList);
CP_PRIVATE(cpArbiter *arbiterList);
CP_PRIVATE(cpConstraint *constraintList);
CP_PRIVATE(cpComponentNode node);
};
/// Allocate a cpBody.
cpBody* cpBodyAlloc(void);
/// Initialize a cpBody.
cpBody* cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
/// Allocate and initialize a cpBody.
cpBody* cpBodyNew(cpFloat m, cpFloat i);
/// Initialize a static cpBody.
cpBody* cpBodyInitStatic(cpBody *body);
/// Allocate and initialize a static cpBody.
cpBody* cpBodyNewStatic(void);
/// Destroy a cpBody.
void cpBodyDestroy(cpBody *body);
/// Destroy and free a cpBody.
void cpBodyFree(cpBody *body);
/// Check that the properties of a body is sane. (Only in debug mode)
#ifdef NDEBUG
#define cpBodyAssertSane(body)
#else
void cpBodySanityCheck(cpBody *body);
#define cpBodyAssertSane(body) cpBodySanityCheck(body)
#endif
// Defined in cpSpace.c
/// Wake up a sleeping or idle body.
void cpBodyActivate(cpBody *body);
/// Wake up any sleeping or idle bodies touching a static body.
void cpBodyActivateStatic(cpBody *body, cpShape *filter);
/// Force a body to fall asleep immediately.
void cpBodySleep(cpBody *body);
/// Force a body to fall asleep immediately along with other bodies in a group.
void cpBodySleepWithGroup(cpBody *body, cpBody *group);
/// Returns true if the body is sleeping.
static inline cpBool cpBodyIsSleeping(const cpBody *body)
{
return (CP_PRIVATE(body->node).root != ((cpBody*)0));
}
/// Returns true if the body is static.
static inline cpBool cpBodyIsStatic(const cpBody *body)
{
return CP_PRIVATE(body->node).idleTime == INFINITY;
}
/// Returns true if the body has not been added to a space.
/// Note: Static bodies are a subtype of rogue bodies.
static inline cpBool cpBodyIsRogue(const cpBody *body)
{
return (body->CP_PRIVATE(space) == ((cpSpace*)0));
}
#define CP_DefineBodyStructGetter(type, member, name) \
static inline type cpBodyGet##name(const cpBody *body){return body->member;}
#define CP_DefineBodyStructSetter(type, member, name) \
static inline void cpBodySet##name(cpBody *body, const type value){ \
cpBodyActivate(body); \
body->member = value; \
cpBodyAssertSane(body); \
}
#define CP_DefineBodyStructProperty(type, member, name) \
CP_DefineBodyStructGetter(type, member, name) \
CP_DefineBodyStructSetter(type, member, name)
// TODO add to docs
CP_DefineBodyStructGetter(cpSpace*, CP_PRIVATE(space), Space)
CP_DefineBodyStructGetter(cpFloat, m, Mass)
/// Set the mass of a body.
void cpBodySetMass(cpBody *body, cpFloat m);
CP_DefineBodyStructGetter(cpFloat, i, Moment)
/// Set the moment of a body.
void cpBodySetMoment(cpBody *body, cpFloat i);
CP_DefineBodyStructGetter(cpVect, p, Pos)
/// Set the position of a body.
void cpBodySetPos(cpBody *body, cpVect pos);
CP_DefineBodyStructProperty(cpVect, v, Vel)
CP_DefineBodyStructProperty(cpVect, f, Force)
CP_DefineBodyStructGetter(cpFloat, a, Angle)
/// Set the angle of a body.
void cpBodySetAngle(cpBody *body, cpFloat a);
CP_DefineBodyStructProperty(cpFloat, w, AngVel)
CP_DefineBodyStructProperty(cpFloat, t, Torque)
CP_DefineBodyStructGetter(cpVect, rot, Rot)
CP_DefineBodyStructProperty(cpFloat, v_limit, VelLimit)
CP_DefineBodyStructProperty(cpFloat, w_limit, AngVelLimit)
CP_DefineBodyStructProperty(cpDataPointer, data, UserData)
/// Default Integration functions.
void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
void cpBodyUpdatePosition(cpBody *body, cpFloat dt);
/// Convert body relative/local coordinates to absolute/world coordinates.
static inline cpVect cpBodyLocal2World(const cpBody *body, const cpVect v)
{
return cpvadd(body->p, cpvrotate(v, body->rot));
}
/// Convert body absolute/world coordinates to relative/local coordinates.
static inline cpVect cpBodyWorld2Local(const cpBody *body, const cpVect v)
{
return cpvunrotate(cpvsub(v, body->p), body->rot);
}
/// Set the forces and torque or a body to zero.
void cpBodyResetForces(cpBody *body);
/// Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r);
/// Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
void cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r);
/// Get the velocity on a body (in world units) at a point on the body in world coordinates.
cpVect cpBodyGetVelAtWorldPoint(cpBody *body, cpVect point);
/// Get the velocity on a body (in world units) at a point on the body in local coordinates.
cpVect cpBodyGetVelAtLocalPoint(cpBody *body, cpVect point);
/// Get the kinetic energy of a body.
static inline cpFloat cpBodyKineticEnergy(const cpBody *body)
{
// Need to do some fudging to avoid NaNs
cpFloat vsq = cpvdot(body->v, body->v);
cpFloat wsq = body->w*body->w;
return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f);
}
/// Body/shape iterator callback function type.
typedef void (*cpBodyShapeIteratorFunc)(cpBody *body, cpShape *shape, void *data);
/// Call @c func once for each shape attached to @c body and added to the space.
void cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data);
/// Body/constraint iterator callback function type.
typedef void (*cpBodyConstraintIteratorFunc)(cpBody *body, cpConstraint *constraint, void *data);
/// Call @c func once for each constraint attached to @c body and added to the space.
void cpBodyEachConstraint(cpBody *body, cpBodyConstraintIteratorFunc func, void *data);
/// Body/arbiter iterator callback function type.
typedef void (*cpBodyArbiterIteratorFunc)(cpBody *body, cpArbiter *arbiter, void *data);
/// Call @c func once for each arbiter that is currently active on the body.
void cpBodyEachArbiter(cpBody *body, cpBodyArbiterIteratorFunc func, void *data);
///@}

View File

@@ -0,0 +1,67 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpPolyShape cpPolyShape
/// @{
/// @private
typedef struct cpSplittingPlane {
cpVect n;
cpFloat d;
} cpSplittingPlane;
/// @private
typedef struct cpPolyShape {
cpShape shape;
int numVerts;
cpVect *verts, *tVerts;
cpSplittingPlane *planes, *tPlanes;
} cpPolyShape;
/// Allocate a polygon shape.
cpPolyShape* cpPolyShapeAlloc(void);
/// Initialize a polygon shape.
/// A convex hull will be created from the vertexes.
cpPolyShape* cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset);
/// Allocate and initialize a polygon shape.
/// A convex hull will be created from the vertexes.
cpShape* cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
/// Initialize a box shaped polygon shape.
cpPolyShape* cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
/// Initialize an offset box shaped polygon shape.
cpPolyShape* cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box);
/// Allocate and initialize a box shaped polygon shape.
cpShape* cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
/// Allocate and initialize an offset box shaped polygon shape.
cpShape* cpBoxShapeNew2(cpBody *body, cpBB box);
/// Check that a set of vertexes is convex and has a clockwise winding.
/// NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
cpBool cpPolyValidate(const cpVect *verts, const int numVerts);
/// Get the number of verts in a polygon shape.
int cpPolyShapeGetNumVerts(cpShape *shape);
/// Get the @c ith vertex of a polygon shape.
cpVect cpPolyShapeGetVert(cpShape *shape, int idx);
/// @}

View File

@@ -0,0 +1,228 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpShape cpShape
/// The cpShape struct defines the shape of a rigid body.
/// @{
typedef struct cpShapeClass cpShapeClass;
/// Nearest point query info struct.
typedef struct cpNearestPointQueryInfo {
/// The nearest shape, NULL if no shape was within range.
cpShape *shape;
/// The closest point on the shape's surface. (in world space coordinates)
cpVect p;
/// The distance to the point. The distance is negative if the point is inside the shape.
cpFloat d;
} cpNearestPointQueryInfo;
/// Segment query info struct.
typedef struct cpSegmentQueryInfo {
/// The shape that was hit, NULL if no collision occured.
cpShape *shape;
/// The normalized distance along the query segment in the range [0, 1].
cpFloat t;
/// The normal of the surface hit.
cpVect n;
} cpSegmentQueryInfo;
/// @private
typedef enum cpShapeType{
CP_CIRCLE_SHAPE,
CP_SEGMENT_SHAPE,
CP_POLY_SHAPE,
CP_NUM_SHAPES
} cpShapeType;
typedef cpBB (*cpShapeCacheDataImpl)(cpShape *shape, cpVect p, cpVect rot);
typedef void (*cpShapeDestroyImpl)(cpShape *shape);
typedef void (*cpShapeNearestPointQueryImpl)(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info);
typedef void (*cpShapeSegmentQueryImpl)(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
/// @private
struct cpShapeClass {
cpShapeType type;
cpShapeCacheDataImpl cacheData;
cpShapeDestroyImpl destroy;
cpShapeNearestPointQueryImpl nearestPointQuery;
cpShapeSegmentQueryImpl segmentQuery;
};
/// Opaque collision shape struct.
struct cpShape {
CP_PRIVATE(const cpShapeClass *klass);
/// The rigid body this collision shape is attached to.
cpBody *body;
/// The current bounding box of the shape.
cpBB bb;
/// Sensor flag.
/// Sensor shapes call collision callbacks but don't produce collisions.
cpBool sensor;
/// Coefficient of restitution. (elasticity)
cpFloat e;
/// Coefficient of friction.
cpFloat u;
/// Surface velocity used when solving for friction.
cpVect surface_v;
/// User definable data pointer.
/// Generally this points to your the game object class so you can access it
/// when given a cpShape reference in a callback.
cpDataPointer data;
/// Collision type of this shape used when picking collision handlers.
cpCollisionType collision_type;
/// Group of this shape. Shapes in the same group don't collide.
cpGroup group;
// Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero.
cpLayers layers;
CP_PRIVATE(cpSpace *space);
CP_PRIVATE(cpShape *next);
CP_PRIVATE(cpShape *prev);
CP_PRIVATE(cpHashValue hashid);
};
/// Destroy a shape.
void cpShapeDestroy(cpShape *shape);
/// Destroy and Free a shape.
void cpShapeFree(cpShape *shape);
/// Update, cache and return the bounding box of a shape based on the body it's attached to.
cpBB cpShapeCacheBB(cpShape *shape);
/// Update, cache and return the bounding box of a shape with an explicit transformation.
cpBB cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot);
/// Test if a point lies within a shape.
cpBool cpShapePointQuery(cpShape *shape, cpVect p);
/// Perform a nearest point query. It finds the closest point on the surface of shape to a specific point.
/// The value returned is the distance between the points. A negative distance means the point is inside the shape.
cpFloat cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *out);
/// Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure.
cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
/// Get the hit point for a segment query.
static inline cpVect cpSegmentQueryHitPoint(const cpVect start, const cpVect end, const cpSegmentQueryInfo info)
{
return cpvlerp(start, end, info.t);
}
/// Get the hit distance for a segment query.
static inline cpFloat cpSegmentQueryHitDist(const cpVect start, const cpVect end, const cpSegmentQueryInfo info)
{
return cpvdist(start, end)*info.t;
}
#define CP_DefineShapeStructGetter(type, member, name) \
static inline type cpShapeGet##name(const cpShape *shape){return shape->member;}
#define CP_DefineShapeStructSetter(type, member, name, activates) \
static inline void cpShapeSet##name(cpShape *shape, type value){ \
if(activates && shape->body) cpBodyActivate(shape->body); \
shape->member = value; \
}
#define CP_DefineShapeStructProperty(type, member, name, activates) \
CP_DefineShapeStructGetter(type, member, name) \
CP_DefineShapeStructSetter(type, member, name, activates)
CP_DefineShapeStructGetter(cpSpace*, CP_PRIVATE(space), Space)
CP_DefineShapeStructGetter(cpBody*, body, Body)
void cpShapeSetBody(cpShape *shape, cpBody *body);
CP_DefineShapeStructGetter(cpBB, bb, BB)
CP_DefineShapeStructProperty(cpBool, sensor, Sensor, cpTrue)
CP_DefineShapeStructProperty(cpFloat, e, Elasticity, cpFalse)
CP_DefineShapeStructProperty(cpFloat, u, Friction, cpTrue)
CP_DefineShapeStructProperty(cpVect, surface_v, SurfaceVelocity, cpTrue)
CP_DefineShapeStructProperty(cpDataPointer, data, UserData, cpFalse)
CP_DefineShapeStructProperty(cpCollisionType, collision_type, CollisionType, cpTrue)
CP_DefineShapeStructProperty(cpGroup, group, Group, cpTrue)
CP_DefineShapeStructProperty(cpLayers, layers, Layers, cpTrue)
/// When initializing a shape, it's hash value comes from a counter.
/// Because the hash value may affect iteration order, you can reset the shape ID counter
/// when recreating a space. This will make the simulation be deterministic.
void cpResetShapeIdCounter(void);
#define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(const cpShape *shape)
/// @}
/// @defgroup cpCircleShape cpCircleShape
/// @private
typedef struct cpCircleShape {
cpShape shape;
cpVect c, tc;
cpFloat r;
} cpCircleShape;
/// Allocate a circle shape.
cpCircleShape* cpCircleShapeAlloc(void);
/// Initialize a circle shape.
cpCircleShape* cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);
/// Allocate and initialize a circle shape.
cpShape* cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);
CP_DeclareShapeGetter(cpCircleShape, cpVect, Offset);
CP_DeclareShapeGetter(cpCircleShape, cpFloat, Radius);
/// @}
/// @defgroup cpSegmentShape cpSegmentShape
/// @private
typedef struct cpSegmentShape {
cpShape shape;
cpVect a, b, n;
cpVect ta, tb, tn;
cpFloat r;
cpVect a_tangent, b_tangent;
} cpSegmentShape;
/// Allocate a segment shape.
cpSegmentShape* cpSegmentShapeAlloc(void);
/// Initialize a segment shape.
cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius);
/// Allocate and initialize a segment shape.
cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius);
void cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next);
CP_DeclareShapeGetter(cpSegmentShape, cpVect, A);
CP_DeclareShapeGetter(cpSegmentShape, cpVect, B);
CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal);
CP_DeclareShapeGetter(cpSegmentShape, cpFloat, Radius);
/// @}

View File

@@ -0,0 +1,285 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpSpace cpSpace
/// @{
typedef struct cpContactBufferHeader cpContactBufferHeader;
typedef void (*cpSpaceArbiterApplyImpulseFunc)(cpArbiter *arb);
/// Basic Unit of Simulation in Chipmunk
struct cpSpace {
/// Number of iterations to use in the impulse solver to solve contacts.
int iterations;
/// Gravity to pass to rigid bodies when integrating velocity.
cpVect gravity;
/// Damping rate expressed as the fraction of velocity bodies retain each second.
/// A value of 0.9 would mean that each body's velocity will drop 10% per second.
/// The default value is 1.0, meaning no damping is applied.
/// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring.
cpFloat damping;
/// Speed threshold for a body to be considered idle.
/// The default value of 0 means to let the space guess a good threshold based on gravity.
cpFloat idleSpeedThreshold;
/// Time a group of bodies must remain idle in order to fall asleep.
/// Enabling sleeping also implicitly enables the the contact graph.
/// The default value of INFINITY disables the sleeping algorithm.
cpFloat sleepTimeThreshold;
/// Amount of encouraged penetration between colliding shapes.
/// Used to reduce oscillating contacts and keep the collision cache warm.
/// Defaults to 0.1. If you have poor simulation quality,
/// increase this number as much as possible without allowing visible amounts of overlap.
cpFloat collisionSlop;
/// Determines how fast overlapping shapes are pushed apart.
/// Expressed as a fraction of the error remaining after each second.
/// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz.
cpFloat collisionBias;
/// Number of frames that contact information should persist.
/// Defaults to 3. There is probably never a reason to change this value.
cpTimestamp collisionPersistence;
/// Rebuild the contact graph during each step. Must be enabled to use the cpBodyEachArbiter() function.
/// Disabled by default for a small performance boost. Enabled implicitly when the sleeping feature is enabled.
cpBool enableContactGraph;
/// User definable data pointer.
/// Generally this points to your game's controller or game state
/// class so you can access it when given a cpSpace reference in a callback.
cpDataPointer data;
/// The designated static body for this space.
/// You can modify this body, or replace it with your own static body.
/// By default it points to a statically allocated cpBody in the cpSpace struct.
cpBody *staticBody;
CP_PRIVATE(cpTimestamp stamp);
CP_PRIVATE(cpFloat curr_dt);
CP_PRIVATE(cpArray *bodies);
CP_PRIVATE(cpArray *rousedBodies);
CP_PRIVATE(cpArray *sleepingComponents);
CP_PRIVATE(cpSpatialIndex *staticShapes);
CP_PRIVATE(cpSpatialIndex *activeShapes);
CP_PRIVATE(cpArray *arbiters);
CP_PRIVATE(cpContactBufferHeader *contactBuffersHead);
CP_PRIVATE(cpHashSet *cachedArbiters);
CP_PRIVATE(cpArray *pooledArbiters);
CP_PRIVATE(cpArray *constraints);
CP_PRIVATE(cpArray *allocatedBuffers);
CP_PRIVATE(int locked);
CP_PRIVATE(cpHashSet *collisionHandlers);
CP_PRIVATE(cpCollisionHandler defaultHandler);
CP_PRIVATE(cpBool skipPostStep);
CP_PRIVATE(cpArray *postStepCallbacks);
CP_PRIVATE(cpBody _staticBody);
};
/// Allocate a cpSpace.
cpSpace* cpSpaceAlloc(void);
/// Initialize a cpSpace.
cpSpace* cpSpaceInit(cpSpace *space);
/// Allocate and initialize a cpSpace.
cpSpace* cpSpaceNew(void);
/// Destroy a cpSpace.
void cpSpaceDestroy(cpSpace *space);
/// Destroy and free a cpSpace.
void cpSpaceFree(cpSpace *space);
#define CP_DefineSpaceStructGetter(type, member, name) \
static inline type cpSpaceGet##name(const cpSpace *space){return space->member;}
#define CP_DefineSpaceStructSetter(type, member, name) \
static inline void cpSpaceSet##name(cpSpace *space, type value){space->member = value;}
#define CP_DefineSpaceStructProperty(type, member, name) \
CP_DefineSpaceStructGetter(type, member, name) \
CP_DefineSpaceStructSetter(type, member, name)
CP_DefineSpaceStructProperty(int, iterations, Iterations)
CP_DefineSpaceStructProperty(cpVect, gravity, Gravity)
CP_DefineSpaceStructProperty(cpFloat, damping, Damping)
CP_DefineSpaceStructProperty(cpFloat, idleSpeedThreshold, IdleSpeedThreshold)
CP_DefineSpaceStructProperty(cpFloat, sleepTimeThreshold, SleepTimeThreshold)
CP_DefineSpaceStructProperty(cpFloat, collisionSlop, CollisionSlop)
CP_DefineSpaceStructProperty(cpFloat, collisionBias, CollisionBias)
CP_DefineSpaceStructProperty(cpTimestamp, collisionPersistence, CollisionPersistence)
CP_DefineSpaceStructProperty(cpBool, enableContactGraph, EnableContactGraph)
CP_DefineSpaceStructProperty(cpDataPointer, data, UserData)
CP_DefineSpaceStructGetter(cpBody*, staticBody, StaticBody)
CP_DefineSpaceStructGetter(cpFloat, CP_PRIVATE(curr_dt), CurrentTimeStep)
/// returns true from inside a callback and objects cannot be added/removed.
static inline cpBool
cpSpaceIsLocked(cpSpace *space)
{
return space->CP_PRIVATE(locked);
}
/// Set a default collision handler for this space.
/// The default collision handler is invoked for each colliding pair of shapes
/// that isn't explicitly handled by a specific collision handler.
/// You can pass NULL for any function you don't want to implement.
void cpSpaceSetDefaultCollisionHandler(
cpSpace *space,
cpCollisionBeginFunc begin,
cpCollisionPreSolveFunc preSolve,
cpCollisionPostSolveFunc postSolve,
cpCollisionSeparateFunc separate,
void *data
);
/// Set a collision handler to be used whenever the two shapes with the given collision types collide.
/// You can pass NULL for any function you don't want to implement.
void cpSpaceAddCollisionHandler(
cpSpace *space,
cpCollisionType a, cpCollisionType b,
cpCollisionBeginFunc begin,
cpCollisionPreSolveFunc preSolve,
cpCollisionPostSolveFunc postSolve,
cpCollisionSeparateFunc separate,
void *data
);
/// Unset a collision handler.
void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b);
/// Add a collision shape to the simulation.
/// If the shape is attached to a static body, it will be added as a static shape.
cpShape* cpSpaceAddShape(cpSpace *space, cpShape *shape);
/// Explicity add a shape as a static shape to the simulation.
cpShape* cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
/// Add a rigid body to the simulation.
cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body);
/// Add a constraint to the simulation.
cpConstraint* cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
/// Remove a collision shape from the simulation.
void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);
/// Remove a collision shape added using cpSpaceAddStaticShape() from the simulation.
void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);
/// Remove a rigid body from the simulation.
void cpSpaceRemoveBody(cpSpace *space, cpBody *body);
/// Remove a constraint from the simulation.
void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint);
/// Test if a collision shape has been added to the space.
cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape);
/// Test if a rigid body has been added to the space.
cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body);
/// Test if a constraint has been added to the space.
cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint);
/// Convert a dynamic rogue body to a static one.
/// This will convert any shapes attached to the body into static shapes, but does not handle constraints.
/// If the body is active, you must remove it from the space first.
void cpSpaceConvertBodyToStatic(cpSpace *space, cpBody *body);
/// Convert a body to a dynamic rogue body.
/// This will convert any static shapes attached to the body into regular ones.
/// If you want the body to be active after the transition, you must add it to the space also.
void cpSpaceConvertBodyToDynamic(cpSpace *space, cpBody *body, cpFloat mass, cpFloat moment);
/// Post Step callback function type.
typedef void (*cpPostStepFunc)(cpSpace *space, void *key, void *data);
/// Schedule a post-step callback to be called when cpSpaceStep() finishes.
/// You can only register one callback per unique value for @c key.
/// Returns true only if @c key has never been scheduled before.
/// It's possible to pass @c NULL for @c func if you only want to mark @c key as being used.
cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data);
/// Point query callback function type.
typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);
/// Query the space at a point and call @c func for each shape found.
void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data);
/// Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group);
/// Nearest point query callback function type.
typedef void (*cpSpaceNearestPointQueryFunc)(cpShape *shape, cpFloat distance, cpVect point, void *data);
/// Query the space at a point and call @c func for each shape found.
void cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data);
/// Query the space at a point and return the nearest shape found. Returns NULL if no shapes were found.
cpShape *cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out);
/// Segment query callback function type.
typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data);
/// Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.
void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data);
/// Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.
cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out);
/// Rectangle Query callback function type.
typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data);
/// Perform a fast rectangle query on the space calling @c func for each shape found.
/// Only the shape's bounding boxes are checked for overlap, not their full shape.
void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data);
/// Shape query callback function type.
typedef void (*cpSpaceShapeQueryFunc)(cpShape *shape, cpContactPointSet *points, void *data);
/// Query a space for any shapes overlapping the given shape and call @c func for each shape found.
cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data);
/// Call cpBodyActivate() for any shape that is overlaps the given shape.
void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape);
/// Space/body iterator callback function type.
typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data);
/// Call @c func for each body in the space.
void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data);
/// Space/body iterator callback function type.
typedef void (*cpSpaceShapeIteratorFunc)(cpShape *shape, void *data);
/// Call @c func for each shape in the space.
void cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data);
/// Space/constraint iterator callback function type.
typedef void (*cpSpaceConstraintIteratorFunc)(cpConstraint *constraint, void *data);
/// Call @c func for each shape in the space.
void cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data);
/// Update the collision detection info for the static shapes in the space.
void cpSpaceReindexStatic(cpSpace *space);
/// Update the collision detection data for a specific shape in the space.
void cpSpaceReindexShape(cpSpace *space, cpShape *shape);
/// Update the collision detection data for all shapes attached to a body.
void cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body);
/// Switch the space to use a spatial has as it's spatial index.
void cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count);
/// Step the space forward in time by @c dt.
void cpSpaceStep(cpSpace *space, cpFloat dt);
/// @}

View File

@@ -0,0 +1,227 @@
/* Copyright (c) 2010 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
@defgroup cpSpatialIndex cpSpatialIndex
Spatial indexes are data structures that are used to accelerate collision detection
and spatial queries. Chipmunk provides a number of spatial index algorithms to pick from
and they are programmed in a generic way so that you can use them for holding more than
just cpShape structs.
It works by using @c void pointers to the objects you add and using a callback to ask your code
for bounding boxes when it needs them. Several types of queries can be performed an index as well
as reindexing and full collision information. All communication to the spatial indexes is performed
through callback functions.
Spatial indexes should be treated as opaque structs.
This meanns you shouldn't be reading any of the struct fields.
@{
*/
//MARK: Spatial Index
/// Spatial index bounding box callback function type.
/// The spatial index calls this function and passes you a pointer to an object you added
/// when it needs to get the bounding box associated with that object.
typedef cpBB (*cpSpatialIndexBBFunc)(void *obj);
/// Spatial index/object iterator callback function type.
typedef void (*cpSpatialIndexIteratorFunc)(void *obj, void *data);
/// Spatial query callback function type.
typedef void (*cpSpatialIndexQueryFunc)(void *obj1, void *obj2, void *data);
/// Spatial segment query callback function type.
typedef cpFloat (*cpSpatialIndexSegmentQueryFunc)(void *obj1, void *obj2, void *data);
typedef struct cpSpatialIndexClass cpSpatialIndexClass;
typedef struct cpSpatialIndex cpSpatialIndex;
/// @private
struct cpSpatialIndex {
cpSpatialIndexClass *klass;
cpSpatialIndexBBFunc bbfunc;
cpSpatialIndex *staticIndex, *dynamicIndex;
};
//MARK: Spatial Hash
typedef struct cpSpaceHash cpSpaceHash;
/// Allocate a spatial hash.
cpSpaceHash* cpSpaceHashAlloc(void);
/// Initialize a spatial hash.
cpSpatialIndex* cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Allocate and initialize a spatial hash.
cpSpatialIndex* cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Change the cell dimensions and table size of the spatial hash to tune it.
/// The cell dimensions should roughly match the average size of your objects
/// and the table size should be ~10 larger than the number of objects inserted.
/// Some trial and error is required to find the optimum numbers for efficiency.
void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);
//MARK: AABB Tree
typedef struct cpBBTree cpBBTree;
/// Allocate a bounding box tree.
cpBBTree* cpBBTreeAlloc(void);
/// Initialize a bounding box tree.
cpSpatialIndex* cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Allocate and initialize a bounding box tree.
cpSpatialIndex* cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Perform a static top down optimization of the tree.
void cpBBTreeOptimize(cpSpatialIndex *index);
/// Bounding box tree velocity callback function.
/// This function should return an estimate for the object's velocity.
typedef cpVect (*cpBBTreeVelocityFunc)(void *obj);
/// Set the velocity function for the bounding box tree to enable temporal coherence.
void cpBBTreeSetVelocityFunc(cpSpatialIndex *index, cpBBTreeVelocityFunc func);
//MARK: Single Axis Sweep
typedef struct cpSweep1D cpSweep1D;
/// Allocate a 1D sort and sweep broadphase.
cpSweep1D* cpSweep1DAlloc(void);
/// Initialize a 1D sort and sweep broadphase.
cpSpatialIndex* cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Allocate and initialize a 1D sort and sweep broadphase.
cpSpatialIndex* cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
//MARK: Spatial Index Implementation
typedef void (*cpSpatialIndexDestroyImpl)(cpSpatialIndex *index);
typedef int (*cpSpatialIndexCountImpl)(cpSpatialIndex *index);
typedef void (*cpSpatialIndexEachImpl)(cpSpatialIndex *index, cpSpatialIndexIteratorFunc func, void *data);
typedef cpBool (*cpSpatialIndexContainsImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);
typedef void (*cpSpatialIndexInsertImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);
typedef void (*cpSpatialIndexRemoveImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);
typedef void (*cpSpatialIndexReindexImpl)(cpSpatialIndex *index);
typedef void (*cpSpatialIndexReindexObjectImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);
typedef void (*cpSpatialIndexReindexQueryImpl)(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data);
typedef void (*cpSpatialIndexQueryImpl)(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data);
typedef void (*cpSpatialIndexSegmentQueryImpl)(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data);
struct cpSpatialIndexClass {
cpSpatialIndexDestroyImpl destroy;
cpSpatialIndexCountImpl count;
cpSpatialIndexEachImpl each;
cpSpatialIndexContainsImpl contains;
cpSpatialIndexInsertImpl insert;
cpSpatialIndexRemoveImpl remove;
cpSpatialIndexReindexImpl reindex;
cpSpatialIndexReindexObjectImpl reindexObject;
cpSpatialIndexReindexQueryImpl reindexQuery;
cpSpatialIndexQueryImpl query;
cpSpatialIndexSegmentQueryImpl segmentQuery;
};
/// Destroy and free a spatial index.
void cpSpatialIndexFree(cpSpatialIndex *index);
/// Collide the objects in @c dynamicIndex against the objects in @c staticIndex using the query callback function.
void cpSpatialIndexCollideStatic(cpSpatialIndex *dynamicIndex, cpSpatialIndex *staticIndex, cpSpatialIndexQueryFunc func, void *data);
/// Destroy a spatial index.
static inline void cpSpatialIndexDestroy(cpSpatialIndex *index)
{
if(index->klass) index->klass->destroy(index);
}
/// Get the number of objects in the spatial index.
static inline int cpSpatialIndexCount(cpSpatialIndex *index)
{
return index->klass->count(index);
}
/// Iterate the objects in the spatial index. @c func will be called once for each object.
static inline void cpSpatialIndexEach(cpSpatialIndex *index, cpSpatialIndexIteratorFunc func, void *data)
{
index->klass->each(index, func, data);
}
/// Returns true if the spatial index contains the given object.
/// Most spatial indexes use hashed storage, so you must provide a hash value too.
static inline cpBool cpSpatialIndexContains(cpSpatialIndex *index, void *obj, cpHashValue hashid)
{
return index->klass->contains(index, obj, hashid);
}
/// Add an object to a spatial index.
/// Most spatial indexes use hashed storage, so you must provide a hash value too.
static inline void cpSpatialIndexInsert(cpSpatialIndex *index, void *obj, cpHashValue hashid)
{
index->klass->insert(index, obj, hashid);
}
/// Remove an object from a spatial index.
/// Most spatial indexes use hashed storage, so you must provide a hash value too.
static inline void cpSpatialIndexRemove(cpSpatialIndex *index, void *obj, cpHashValue hashid)
{
index->klass->remove(index, obj, hashid);
}
/// Perform a full reindex of a spatial index.
static inline void cpSpatialIndexReindex(cpSpatialIndex *index)
{
index->klass->reindex(index);
}
/// Reindex a single object in the spatial index.
static inline void cpSpatialIndexReindexObject(cpSpatialIndex *index, void *obj, cpHashValue hashid)
{
index->klass->reindexObject(index, obj, hashid);
}
/// Perform a rectangle query against the spatial index, calling @c func for each potential match.
static inline void cpSpatialIndexQuery(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)
{
index->klass->query(index, obj, bb, func, data);
}
/// Perform a segment query against the spatial index, calling @c func for each potential match.
static inline void cpSpatialIndexSegmentQuery(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)
{
index->klass->segmentQuery(index, obj, a, b, t_exit, func, data);
}
/// Simultaneously reindex and find all colliding objects.
/// @c func will be called once for each potentially overlapping pair of objects found.
/// If the spatial index was initialized with a static index, it will collide it's objects against that as well.
static inline void cpSpatialIndexReindexQuery(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data)
{
index->klass->reindexQuery(index, func, data);
}
///@}

View File

@@ -0,0 +1,212 @@
/* Copyright (c) 2007 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/// @defgroup cpVect cpVect
/// Chipmunk's 2D vector type along with a handy 2D vector math lib.
/// @{
/// Constant for the zero vector.
static const cpVect cpvzero = {0.0f,0.0f};
/// Convenience constructor for cpVect structs.
static inline cpVect cpv(const cpFloat x, const cpFloat y)
{
cpVect v = {x, y};
return v;
}
/// Spherical linearly interpolate between v1 and v2.
cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t);
/// Spherical linearly interpolate between v1 towards v2 by no more than angle a radians
cpVect cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a);
/// Returns a string representation of v. Intended mostly for debugging purposes and not production use.
/// @attention The string points to a static local and is reset every time the function is called.
/// If you want to print more than one vector you will have to split up your printing onto separate lines.
char* cpvstr(const cpVect v);
/// Check if two vectors are equal. (Be careful when comparing floating point numbers!)
static inline cpBool cpveql(const cpVect v1, const cpVect v2)
{
return (v1.x == v2.x && v1.y == v2.y);
}
/// Add two vectors
static inline cpVect cpvadd(const cpVect v1, const cpVect v2)
{
return cpv(v1.x + v2.x, v1.y + v2.y);
}
/// Subtract two vectors.
static inline cpVect cpvsub(const cpVect v1, const cpVect v2)
{
return cpv(v1.x - v2.x, v1.y - v2.y);
}
/// Negate a vector.
static inline cpVect cpvneg(const cpVect v)
{
return cpv(-v.x, -v.y);
}
/// Scalar multiplication.
static inline cpVect cpvmult(const cpVect v, const cpFloat s)
{
return cpv(v.x*s, v.y*s);
}
/// Vector dot product.
static inline cpFloat cpvdot(const cpVect v1, const cpVect v2)
{
return v1.x*v2.x + v1.y*v2.y;
}
/// 2D vector cross product analog.
/// The cross product of 2D vectors results in a 3D vector with only a z component.
/// This function returns the magnitude of the z value.
static inline cpFloat cpvcross(const cpVect v1, const cpVect v2)
{
return v1.x*v2.y - v1.y*v2.x;
}
/// Returns a perpendicular vector. (90 degree rotation)
static inline cpVect cpvperp(const cpVect v)
{
return cpv(-v.y, v.x);
}
/// Returns a perpendicular vector. (-90 degree rotation)
static inline cpVect cpvrperp(const cpVect v)
{
return cpv(v.y, -v.x);
}
/// Returns the vector projection of v1 onto v2.
static inline cpVect cpvproject(const cpVect v1, const cpVect v2)
{
return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
}
/// Returns the unit length vector for the given angle (in radians).
static inline cpVect cpvforangle(const cpFloat a)
{
return cpv(cpfcos(a), cpfsin(a));
}
/// Returns the angular direction v is pointing in (in radians).
static inline cpFloat cpvtoangle(const cpVect v)
{
return cpfatan2(v.y, v.x);
}
/// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
static inline cpVect cpvrotate(const cpVect v1, const cpVect v2)
{
return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);
}
/// Inverse of cpvrotate().
static inline cpVect cpvunrotate(const cpVect v1, const cpVect v2)
{
return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);
}
/// Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
static inline cpFloat cpvlengthsq(const cpVect v)
{
return cpvdot(v, v);
}
/// Returns the length of v.
static inline cpFloat cpvlength(const cpVect v)
{
return cpfsqrt(cpvdot(v, v));
}
/// Linearly interpolate between v1 and v2.
static inline cpVect cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)
{
return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));
}
/// Returns a normalized copy of v.
static inline cpVect cpvnormalize(const cpVect v)
{
return cpvmult(v, 1.0f/cpvlength(v));
}
/// Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
static inline cpVect cpvnormalize_safe(const cpVect v)
{
return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v));
}
/// Clamp v to length len.
static inline cpVect cpvclamp(const cpVect v, const cpFloat len)
{
return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
}
/// Linearly interpolate between v1 towards v2 by distance d.
static inline cpVect cpvlerpconst(cpVect v1, cpVect v2, cpFloat d)
{
return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d));
}
/// Returns the distance between v1 and v2.
static inline cpFloat cpvdist(const cpVect v1, const cpVect v2)
{
return cpvlength(cpvsub(v1, v2));
}
/// Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
static inline cpFloat cpvdistsq(const cpVect v1, const cpVect v2)
{
return cpvlengthsq(cpvsub(v1, v2));
}
/// Returns true if the distance between v1 and v2 is less than dist.
static inline cpBool cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)
{
return cpvdistsq(v1, v2) < dist*dist;
}
/// @}
/// @defgroup cpMat2x2 cpMat2x2
/// 2x2 matrix type used for tensors and such.
/// @{
static inline cpMat2x2
cpMat2x2New(cpFloat a, cpFloat b, cpFloat c, cpFloat d)
{
cpMat2x2 m = {a, b, c, d};
return m;
}
static inline cpVect
cpMat2x2Transform(cpMat2x2 m, cpVect v)
{
return cpv(v.x*m.a + v.y*m.b, v.x*m.c + v.y*m.d);
}
///@}

View File

@@ -0,0 +1,119 @@
#include <eepp/physics/arbiter.hpp>
namespace EE { namespace Physics {
Arbiter::Arbiter( cpArbiter* arbiter ) {
mArbiter = arbiter;
}
cVect Arbiter::totalImpulse() {
return tovect( cpArbiterTotalImpulse( mArbiter ) );
}
cVect Arbiter::totalImpulseWithFriction() {
return tovect( cpArbiterTotalImpulseWithFriction( mArbiter ) );
}
void Arbiter::ignore() {
return cpArbiterIgnore( mArbiter );
}
void Arbiter::getShapes( Shape** a, Shape** b ) {
cpShape* tA;
cpShape* tB;
cpArbiterGetShapes( mArbiter, &tA, &tB );
if ( NULL != tA )
*a = reinterpret_cast<Shape*>( tA->data );
else
*a = NULL;
if ( NULL != tB )
*b = reinterpret_cast<Shape*>( tB->data );
else
*b = NULL;
}
void Arbiter::getBodies( Body** a, Body** b ) {
cpBody* tA;
cpBody* tB;
cpArbiterGetBodies( mArbiter, &tA, &tB );
if ( NULL != tA )
*a = reinterpret_cast<Body*>( tA->data );
else
*a = NULL;
if ( NULL != tB )
*b = reinterpret_cast<Body*>( tB->data );
else
*b = NULL;
}
bool Arbiter::isFirstContact() {
return 0 != cpArbiterIsFirstContact( mArbiter );
}
int Arbiter::getCount() {
return cpArbiterGetCount( mArbiter );
}
cVect Arbiter::getNormal( int i ) {
return tovect( cpArbiterGetNormal( mArbiter, i ) );
}
cVect Arbiter::getPoint( int i ) {
return tovect( cpArbiterGetPoint( mArbiter, i ) );
}
cpFloat Arbiter::getDepth( int i ) {
return cpArbiterGetDepth( mArbiter, i );
}
cpContactPointSet Arbiter::getContactPointSet() {
return cpArbiterGetContactPointSet( mArbiter );
}
void Arbiter::setContactPointSet( cpContactPointSet* contact ) {
cpArbiterSetContactPointSet( mArbiter, contact );
}
cpArbiter* Arbiter::getArbiter() const {
return mArbiter;
}
cpFloat Arbiter::getElasticity() {
return cpArbiterGetElasticity( mArbiter );
}
void Arbiter::setElasticity( cpFloat value ) {
cpArbiterSetElasticity( mArbiter, value );
}
cpFloat Arbiter::getFriction() {
return cpArbiterGetFriction( mArbiter );
}
void Arbiter::setFriction( cpFloat value ) {
cpArbiterSetFriction( mArbiter, value );
}
cVect Arbiter::getSurfaceVelocity() {
return tovect( cpArbiterGetSurfaceVelocity( mArbiter ) );
}
void Arbiter::setSurfaceVelocity( cVect value ) {
cpArbiterSetSurfaceVelocity( mArbiter, tocpv( value ) );
}
void Arbiter::setUserData( cpDataPointer value ) {
cpArbiterSetUserData( mArbiter, value );
}
cpDataPointer Arbiter::getUserData() const {
return cpArbiterGetUserData( mArbiter );
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,17 @@
#include <eepp/physics/area.hpp>
namespace EE { namespace Physics {
cpFloat Area::forCircle( cpFloat r1, cpFloat r2 ) {
return cpAreaForCircle( r1, r2 );
}
cpFloat Area::forSegment( cVect a, cVect b, cpFloat r ) {
return cpAreaForSegment( tocpv( a ), tocpv( b ), r );
}
cpFloat Area::forPoly( const int numVerts, const cVect* verts ) {
return cpAreaForPoly( numVerts, constcasttocpv( verts ) );
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,292 @@
#include <eepp/physics/arbiter.hpp>
#include <eepp/physics/body.hpp>
#include <eepp/physics/constraints/constraint.hpp>
#include <eepp/physics/physicsmanager.hpp>
#include <eepp/physics/shape.hpp>
namespace EE { namespace Physics {
Body* Body::New( cpFloat m, cpFloat i ) {
return eeNew( Body, ( m, i ) );
}
Body* Body::New( cpBody* body ) {
return eeNew( Body, ( body ) );
}
Body* Body::New() {
return eeNew( Body, () );
}
void Body::Free( Body* body ) {
eeSAFE_DELETE( body );
}
Body::Body( cpBody* body ) : mBody( body ), mData( NULL ) {
setData();
}
Body::Body( cpFloat m, cpFloat i ) : mBody( cpBodyNew( m, i ) ), mData( NULL ) {
setData();
}
Body::Body() : mBody( cpBodyNewStatic() ), mData( NULL ) {
setData();
}
Body::~Body() {
if ( NULL != mBody )
cpBodyFree( mBody );
PhysicsManager::instance()->removeBodyFree( this );
}
void Body::setData() {
mBody->data = (void*)this;
PhysicsManager::instance()->addBodyFree( this );
}
void Body::activate() {
cpBodyActivate( mBody );
}
void Body::activateStatic( Body* body, Shape* filter ) {
cpBodyActivateStatic( mBody, filter->getShape() );
}
void Body::sleep() {
cpBodySleep( mBody );
}
void Body::sleepWithGroup( Body* Group ) {
cpBodySleepWithGroup( mBody, Group->getBody() );
}
bool Body::isSleeping() {
return cpFalse != cpBodyIsSleeping( mBody );
}
bool Body::isStatic() {
return cpFalse != cpBodyIsStatic( mBody );
}
bool Body::isRogue() {
return cpFalse != cpBodyIsRogue( mBody );
}
cpBody* Body::getBody() const {
return mBody;
}
cpFloat Body::getMass() const {
return cpBodyGetMass( mBody );
}
void Body::setMass( const cpFloat& mass ) {
cpBodySetMass( mBody, mass );
}
cpFloat Body::getMoment() const {
return cpBodyGetMoment( mBody );
}
void Body::setMoment( const cpFloat& i ) {
cpBodySetMoment( mBody, i );
}
cVect Body::getPos() const {
return tovect( cpBodyGetPos( mBody ) );
}
void Body::setPos( const cVect& pos ) {
cpBodySetPos( mBody, tocpv( pos ) );
}
cVect Body::getVel() const {
return tovect( cpBodyGetVel( mBody ) );
}
void Body::setVel( const cVect& vel ) {
cpBodySetVel( mBody, tocpv( vel ) );
}
cVect Body::getForce() const {
return tovect( cpBodyGetForce( mBody ) );
}
void Body::setForce( const cVect& force ) {
cpBodySetForce( mBody, tocpv( force ) );
}
cpFloat Body::getAngle() const {
return cpBodyGetAngle( mBody );
}
void Body::setAngle( const cpFloat& rads ) {
cpBodySetAngle( mBody, rads );
}
cpFloat Body::getAngleDeg() {
return cpDegrees( mBody->a );
}
void Body::setAngleDeg( const cpFloat& angle ) {
this->setAngle( cpRadians( angle ) );
}
cpFloat Body::getAngVel() const {
return cpBodyGetAngVel( mBody );
}
void Body::setAngVel( const cpFloat& rotVel ) {
cpBodySetAngVel( mBody, rotVel );
}
cpFloat Body::getTorque() const {
return cpBodyGetTorque( mBody );
}
void Body::setTorque( const cpFloat& torque ) {
cpBodySetTorque( mBody, torque );
}
cVect Body::getRot() const {
return tovect( cpBodyGetRot( mBody ) );
}
cpFloat Body::getVelLimit() const {
return cpBodyGetVelLimit( mBody );
}
void Body::setVelLimit( const cpFloat& speed ) {
cpBodySetVelLimit( mBody, speed );
}
cpFloat Body::getAngVelLimit() const {
return cpBodyGetAngVelLimit( mBody );
}
void Body::setAngVelLimit( const cpFloat& speed ) {
cpBodySetAngVelLimit( mBody, speed );
}
void Body::updateVelocity( cVect gravity, cpFloat damping, cpFloat dt ) {
cpBodyUpdateVelocity( mBody, tocpv( gravity ), damping, dt );
}
void Body::updatePosition( cpFloat dt ) {
cpBodyUpdatePosition( mBody, dt );
}
void Body::bodyVelocityFuncWrapper( cpBody* body, cpVect gravity, cpFloat damping, cpFloat dt ) {
Body* tBody = reinterpret_cast<Body*>( body->data );
if ( tBody->mVelocityFunc ) {
tBody->mVelocityFunc( reinterpret_cast<Body*>( body->data ), tovect( gravity ), damping,
dt );
}
}
void Body::velocityFunc( BodyVelocityFunc func ) {
mBody->velocity_func = &Body::bodyVelocityFuncWrapper;
mVelocityFunc = func;
}
void Body::bodyPositionFuncWrapper( cpBody* body, cpFloat dt ) {
Body* tBody = reinterpret_cast<Body*>( body->data );
if ( tBody->mPositionFunc ) {
tBody->mPositionFunc( reinterpret_cast<Body*>( body->data ), dt );
}
}
void Body::positionFunc( BodyPositionFunc func ) {
mBody->position_func = &Body::bodyPositionFuncWrapper;
mPositionFunc = func;
}
cVect Body::local2World( const cVect v ) {
return tovect( cpBodyLocal2World( mBody, tocpv( v ) ) );
}
cVect Body::world2Local( const cVect v ) {
return tovect( cpBodyWorld2Local( mBody, tocpv( v ) ) );
}
void Body::applyImpulse( const cVect j, const cVect r ) {
cpBodyApplyImpulse( mBody, tocpv( j ), tocpv( r ) );
}
void Body::resetForces() {
cpBodyResetForces( mBody );
}
void Body::applyForce( const cVect f, const cVect r ) {
cpBodyApplyForce( mBody, tocpv( f ), tocpv( r ) );
}
cpFloat Body::kineticEnergy() {
return cpBodyKineticEnergy( mBody );
}
void* Body::getData() const {
return mData;
}
void Body::setData( void* data ) {
mData = data;
}
static void BodyShapeIteratorFunc( cpBody* body, cpShape* shape, void* data ) {
Body::ShapeIterator* it = reinterpret_cast<Body::ShapeIterator*>( data );
it->Body->onEachShape( reinterpret_cast<Shape*>( shape->data ), it );
}
void Body::eachShape( ShapeIteratorFunc Func, void* data ) {
ShapeIterator it( this, data, Func );
cpBodyEachShape( mBody, &BodyShapeIteratorFunc, (void*)&it );
}
void Body::onEachShape( Shape* Shape, ShapeIterator* it ) {
if ( it->Func ) {
it->Func( it->Body, Shape, it->Data );
}
}
static void BodyConstraintIteratorFunc( cpBody* body, cpConstraint* constraint, void* data ) {
Body::ConstraintIterator* it = reinterpret_cast<Body::ConstraintIterator*>( data );
it->Body->onEachConstraint( reinterpret_cast<Constraint*>( constraint->data ), it );
}
void Body::eachConstraint( ConstraintIteratorFunc Func, void* data ) {
ConstraintIterator it( this, data, Func );
cpBodyEachConstraint( mBody, &BodyConstraintIteratorFunc, (void*)&it );
}
void Body::onEachConstraint( Constraint* Constraint, ConstraintIterator* it ) {
if ( it->Func ) {
it->Func( this, Constraint, it->Data );
}
}
static void BodyArbiterIteratorFunc( cpBody* body, cpArbiter* arbiter, void* data ) {
Body::ArbiterIterator* it = reinterpret_cast<Body::ArbiterIterator*>( data );
Arbiter tarb( arbiter );
it->Body->onEachArbiter( &tarb, it );
}
void Body::eachArbiter( ArbiterIteratorFunc Func, void* data ) {
ArbiterIterator it( this, data, Func );
cpBodyEachArbiter( mBody, &BodyArbiterIteratorFunc, (void*)&it );
}
void Body::onEachArbiter( Arbiter* Arbiter, ArbiterIterator* it ) {
if ( it->Func ) {
it->Func( this, Arbiter, it->Data );
}
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,78 @@
#include <eepp/physics/constraints/constraint.hpp>
#include <eepp/physics/physicsmanager.hpp>
namespace EE { namespace Physics {
void Constraint::Free( Constraint* constraint ) {
eeSAFE_DELETE( constraint );
}
Constraint::Constraint( cpConstraint* Constraint ) : mData( NULL ) {
mConstraint = Constraint;
setData();
}
Constraint::Constraint() : mConstraint( NULL ), mData( NULL ) {}
Constraint::~Constraint() {
cpConstraintFree( mConstraint );
PhysicsManager::instance()->removeConstraintFree( this );
}
void Constraint::setData() {
mConstraint->data = (void*)this;
PhysicsManager::instance()->addConstraintFree( this );
}
cpConstraint* Constraint::getConstraint() const {
return mConstraint;
}
Body* Constraint::getA() {
return reinterpret_cast<Body*>( mConstraint->a->data );
}
Body* Constraint::getB() {
return reinterpret_cast<Body*>( mConstraint->b->data );
}
cpFloat Constraint::getMaxForce() {
return mConstraint->maxForce;
}
void Constraint::setMaxForce( const cpFloat& maxforce ) {
mConstraint->maxForce = maxforce;
}
cpFloat Constraint::getMaxBias() {
return mConstraint->maxBias;
}
void Constraint::setMaxBias( const cpFloat& maxbias ) {
mConstraint->maxBias = maxbias;
}
cpFloat Constraint::getErrorBias() {
return cpConstraintGetErrorBias( mConstraint );
}
void Constraint::setErrorBias( cpFloat value ) {
cpConstraintSetErrorBias( mConstraint, value );
}
void Constraint::setData( void* data ) {
mData = data;
}
void* Constraint::getData() const {
return mData;
}
cpFloat Constraint::getImpulse() {
return cpConstraintGetImpulse( mConstraint );
}
void Constraint::draw() {}
}} // namespace EE::Physics

View File

@@ -0,0 +1,40 @@
#include <eepp/physics/constraints/dampedrotaryspring.hpp>
namespace EE { namespace Physics {
DampedRotarySpring::DampedRotarySpring( Body* a, Body* b, cpFloat restAngle, cpFloat stiffness,
cpFloat damping ) {
mConstraint =
cpDampedRotarySpringNew( a->getBody(), b->getBody(), restAngle, stiffness, damping );
setData();
}
cpFloat DampedRotarySpring::getRestAngle() {
return cpDampedRotarySpringGetRestAngle( mConstraint );
}
void DampedRotarySpring::setRestAngle( const cpFloat& restangle ) {
cpDampedRotarySpringSetRestAngle( mConstraint, restangle );
}
cpFloat DampedRotarySpring::getStiffness() {
return cpDampedRotarySpringGetStiffness( mConstraint );
}
void DampedRotarySpring::setStiffness( const cpFloat& stiffness ) {
cpDampedRotarySpringSetStiffness( mConstraint, stiffness );
}
cpFloat DampedRotarySpring::getDamping() {
return cpDampedRotarySpringGetDamping( mConstraint );
}
void DampedRotarySpring::setDamping( const cpFloat& damping ) {
cpDampedRotarySpringSetDamping( mConstraint, damping );
}
void DampedRotarySpring::draw() {
// Not implemented
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,135 @@
#include <eepp/physics/constraints/dampedspring.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
#include <eepp/graphics/renderer/opengl.hpp>
#include <eepp/graphics/renderer/renderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
DampedSpring::DampedSpring( Body* a, Body* b, cVect anchr1, cVect anchr2, cpFloat restLength,
cpFloat stiffness, cpFloat damping )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawPointSize( 5.f )
#endif
{
mConstraint = cpDampedSpringNew( a->getBody(), b->getBody(), tocpv( anchr1 ), tocpv( anchr2 ),
restLength, stiffness, damping );
setData();
}
cVect DampedSpring::getAnchr1() {
return tovect( cpDampedSpringGetAnchr1( mConstraint ) );
}
void DampedSpring::setAnchr1( const cVect& anchr1 ) {
cpDampedSpringSetAnchr1( mConstraint, tocpv( anchr1 ) );
}
cVect DampedSpring::getAnchr2() {
return tovect( cpDampedSpringGetAnchr2( mConstraint ) );
}
void DampedSpring::setAnchr2( const cVect& anchr2 ) {
cpDampedSpringSetAnchr2( mConstraint, tocpv( anchr2 ) );
}
cpFloat DampedSpring::getRestLength() {
return cpDampedSpringGetRestLength( mConstraint );
}
void DampedSpring::setRestLength( const cpFloat& restlength ) {
cpDampedSpringSetRestLength( mConstraint, restlength );
}
cpFloat DampedSpring::getStiffness() {
return cpDampedSpringGetStiffness( mConstraint );
}
void DampedSpring::setStiffness( const cpFloat& stiffness ) {
cpDampedSpringSetStiffness( mConstraint, stiffness );
}
cpFloat DampedSpring::getDamping() {
return cpDampedSpringGetDamping( mConstraint );
}
void DampedSpring::setDamping( const cpFloat& damping ) {
cpDampedSpringSetDamping( mConstraint, damping );
}
void DampedSpring::draw() {
#ifdef PHYSICS_RENDERER_ENABLED
static const float springVAR[] = {
0.00f, 0.0f, 0.20f, 0.0f, 0.25f, 3.0f, 0.30f, -6.0f, 0.35f, 6.0f,
0.40f, -6.0f, 0.45f, 6.0f, 0.50f, -6.0f, 0.55f, 6.0f, 0.60f, -6.0f,
0.65f, 6.0f, 0.70f, -3.0f, 0.75f, 6.0f, 0.80f, 0.0f, 1.00f, 0.0f,
};
static const int springVAR_count = sizeof( springVAR ) / sizeof( float ) / 2;
if ( mDrawPointSize <= 0 )
return;
cpDampedSpring* spring = (cpDampedSpring*)mConstraint;
cpBody* body_a = mConstraint->a;
cpBody* body_b = mConstraint->b;
cVect a = tovect( cpvadd( body_a->p, cpvrotate( spring->anchr1, body_a->rot ) ) );
cVect b = tovect( cpvadd( body_b->p, cpvrotate( spring->anchr2, body_b->rot ) ) );
GLi->pointSize( mDrawPointSize );
BatchRenderer* BR = GlobalBatchRenderer::instance();
BR->setTexture( NULL );
BR->pointsBegin();
BR->batchPoint( a.x, a.y );
BR->batchPoint( b.x, b.y );
BR->draw();
cVect delta = b - a;
GLi->disable( GL_TEXTURE_2D );
GLi->disableClientState( GL_TEXTURE_COORD_ARRAY );
std::vector<Color> tcolors( springVAR_count * 4, Color( 0, 255, 0, 255 ) );
GLi->colorPointer( 4, GL_UNSIGNED_BYTE, 0, reinterpret_cast<const void*>( &tcolors[0] ),
springVAR_count * 4 );
GLi->vertexPointer( 2, GL_FLOAT, 0, springVAR, springVAR_count * sizeof( float ) * 2 );
GLi->pushMatrix();
float x = a.x;
float y = a.y;
float cos = delta.x;
float sin = delta.y;
float s = 1.0f / cpvlength( tocpv( delta ) );
const float matrix[] = {
cos, sin, 0.0f, 0.0f, -sin * s, cos * s, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f, x, y, 0.0f, 1.0f,
};
GLi->multMatrixf( matrix );
GLi->drawArrays( GL_LINE_STRIP, 0, springVAR_count );
GLi->popMatrix();
GLi->enable( GL_TEXTURE_2D );
GLi->enableClientState( GL_TEXTURE_COORD_ARRAY );
#endif
}
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat DampedSpring::getDrawPointSize() {
return mDrawPointSize;
}
void DampedSpring::setDrawPointSize( const cpFloat& size ) {
mDrawPointSize = size;
}
#endif
}} // namespace EE::Physics

View File

@@ -0,0 +1,30 @@
#include <eepp/physics/constraints/gearjoint.hpp>
namespace EE { namespace Physics {
GearJoint::GearJoint( Body* a, Body* b, cpFloat phase, cpFloat ratio ) {
mConstraint = cpGearJointNew( a->getBody(), b->getBody(), phase, ratio );
setData();
}
cpFloat GearJoint::getPhase() {
return cpGearJointGetPhase( mConstraint );
}
void GearJoint::setPhase( const cpFloat& phase ) {
cpGearJointSetPhase( mConstraint, phase );
}
cpFloat GearJoint::getRatio() {
return cpGearJointGetRatio( mConstraint );
}
void GearJoint::setRatio( const cpFloat& ratio ) {
cpGearJointSetRatio( mConstraint, ratio );
}
void GearJoint::draw() {
// Not implemented
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,83 @@
#include <eepp/physics/constraints/groovejoint.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
GrooveJoint::GrooveJoint( Body* a, Body* b, cVect groove_a, cVect groove_b, cVect anchr2 )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawPointSize( 5.f )
#endif
{
mConstraint = cpGrooveJointNew( a->getBody(), b->getBody(), tocpv( groove_a ),
tocpv( groove_b ), tocpv( anchr2 ) );
setData();
}
cVect GrooveJoint::getAnchr2() {
return tovect( cpGrooveJointGetAnchr2( mConstraint ) );
}
void GrooveJoint::setAnchr2( const cVect& anchr2 ) {
cpGrooveJointSetAnchr2( mConstraint, tocpv( anchr2 ) );
}
cVect GrooveJoint::getGrooveA() {
return tovect( cpGrooveJointGetGrooveA( mConstraint ) );
}
void GrooveJoint::setGrooveA( const cVect& groove_a ) {
cpGrooveJointSetGrooveA( mConstraint, tocpv( groove_a ) );
}
cVect GrooveJoint::getGrooveB() {
return tovect( cpGrooveJointGetGrooveB( mConstraint ) );
}
void GrooveJoint::setGrooveB( const cVect& groove_b ) {
cpGrooveJointSetGrooveB( mConstraint, tocpv( groove_b ) );
}
void GrooveJoint::draw() {
#ifdef PHYSICS_RENDERER_ENABLED
if ( mDrawPointSize <= 0 )
return;
cpGrooveJoint* joint = (cpGrooveJoint*)mConstraint;
cpBody* body_a = mConstraint->a;
cpBody* body_b = mConstraint->b;
cVect a = tovect( cpvadd( body_a->p, cpvrotate( joint->grv_a, body_a->rot ) ) );
cVect b = tovect( cpvadd( body_a->p, cpvrotate( joint->grv_b, body_a->rot ) ) );
cVect c = tovect( cpvadd( body_b->p, cpvrotate( joint->anchr2, body_b->rot ) ) );
BatchRenderer* BR = GlobalBatchRenderer::instance();
cpFloat ps = BR->getPointSize();
BR->setTexture( NULL );
BR->setPointSize( mDrawPointSize );
BR->pointsBegin();
BR->pointSetColor( Color( 128, 255, 128, 255 ) );
BR->batchPoint( c.x, c.y );
BR->draw();
BR->linesBegin();
BR->linesSetColor( Color( 128, 255, 128, 255 ) );
BR->batchLine( a.x, a.y, b.x, b.y );
BR->draw();
BR->setPointSize( ps );
#endif
}
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat GrooveJoint::getDrawPointSize() {
return mDrawPointSize;
}
void GrooveJoint::setDrawPointSize( const cpFloat& size ) {
mDrawPointSize = size;
}
#endif
}} // namespace EE::Physics

View File

@@ -0,0 +1,84 @@
#include <eepp/physics/constraints/pinjoint.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
PinJoint::PinJoint( Body* a, Body* b, cVect anchr1, cVect anchr2 )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawPointSize( 5.f )
#endif
{
mConstraint = cpPinJointNew( a->getBody(), b->getBody(), tocpv( anchr1 ), tocpv( anchr2 ) );
setData();
}
cVect PinJoint::getAnchr1() {
return tovect( cpPinJointGetAnchr1( mConstraint ) );
}
void PinJoint::setAnchr1( const cVect& anchr1 ) {
cpPinJointSetAnchr1( mConstraint, tocpv( anchr1 ) );
}
cVect PinJoint::getAnchr2() {
return tovect( cpPinJointGetAnchr2( mConstraint ) );
}
void PinJoint::setAnchr2( const cVect& anchr2 ) {
cpPinJointSetAnchr2( mConstraint, tocpv( anchr2 ) );
}
cpFloat PinJoint::getDist() {
return cpPinJointGetDist( mConstraint );
}
void PinJoint::setDist( const cpFloat& dist ) {
cpPinJointSetDist( mConstraint, dist );
}
void PinJoint::draw() {
#ifdef PHYSICS_RENDERER_ENABLED
if ( mDrawPointSize <= 0 )
return;
cpPinJoint* joint = (cpPinJoint*)mConstraint;
cpBody* body_a = mConstraint->a;
cpBody* body_b = mConstraint->b;
cVect a = tovect( cpvadd( body_a->p, cpvrotate( joint->anchr1, body_a->rot ) ) );
cVect b = tovect( cpvadd( body_b->p, cpvrotate( joint->anchr2, body_b->rot ) ) );
BatchRenderer* BR = GlobalBatchRenderer::instance();
cpFloat ps = BR->getPointSize();
BR->setTexture( NULL );
BR->setPointSize( mDrawPointSize );
BR->pointsBegin();
BR->pointSetColor( Color( 128, 255, 128, 255 ) );
BR->batchPoint( a.x, a.y );
BR->batchPoint( b.x, b.y );
BR->draw();
BR->linesBegin();
BR->linesSetColor( Color( 128, 255, 128, 255 ) );
BR->batchLine( a.x, a.y, b.x, b.y );
BR->draw();
BR->setPointSize( ps );
#endif
}
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat PinJoint::getDrawPointSize() {
return mDrawPointSize;
}
void PinJoint::setDrawPointSize( const cpFloat& size ) {
mDrawPointSize = size;
}
#endif
}} // namespace EE::Physics

View File

@@ -0,0 +1,80 @@
#include <eepp/physics/constraints/pivotjoint.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
PivotJoint::PivotJoint( Body* a, Body* b, cVect pivot )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawPointSize( 10.f )
#endif
{
mConstraint = cpPivotJointNew( a->getBody(), b->getBody(), tocpv( pivot ) );
setData();
}
PivotJoint::PivotJoint( Body* a, Body* b, cVect anchr1, cVect anchr2 )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawPointSize( 10.f )
#endif
{
mConstraint = cpPivotJointNew2( a->getBody(), b->getBody(), tocpv( anchr1 ), tocpv( anchr2 ) );
setData();
}
cVect PivotJoint::getAnchr1() {
return tovect( cpPivotJointGetAnchr1( mConstraint ) );
}
void PivotJoint::setAnchr1( const cVect& anchr1 ) {
cpPivotJointSetAnchr1( mConstraint, tocpv( anchr1 ) );
}
cVect PivotJoint::getAnchr2() {
return tovect( cpPivotJointGetAnchr2( mConstraint ) );
}
void PivotJoint::setAnchr2( const cVect& anchr2 ) {
cpPivotJointSetAnchr2( mConstraint, tocpv( anchr2 ) );
}
void PivotJoint::draw() {
#ifdef PHYSICS_RENDERER_ENABLED
if ( mDrawPointSize <= 0 )
return;
cpBody* body_a = mConstraint->a;
cpBody* body_b = mConstraint->b;
cpPivotJoint* joint = (cpPivotJoint*)mConstraint;
cVect a = tovect( cpvadd( body_a->p, cpvrotate( joint->anchr1, body_a->rot ) ) );
cVect b = tovect( cpvadd( body_b->p, cpvrotate( joint->anchr2, body_b->rot ) ) );
BatchRenderer* BR = GlobalBatchRenderer::instance();
cpFloat ps = BR->getPointSize();
BR->setTexture( NULL );
BR->setPointSize( mDrawPointSize );
BR->pointsBegin();
BR->pointSetColor( Color( 128, 255, 128, 255 ) );
BR->batchPoint( a.x, a.y );
BR->batchPoint( b.x, b.y );
BR->draw();
BR->setPointSize( ps );
#endif
}
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat PivotJoint::getDrawPointSize() {
return mDrawPointSize;
}
void PivotJoint::setDrawPointSize( const cpFloat& size ) {
mDrawPointSize = size;
}
#endif
}} // namespace EE::Physics

View File

@@ -0,0 +1,38 @@
#include <eepp/physics/constraints/ratchetjoint.hpp>
namespace EE { namespace Physics {
RatchetJoint::RatchetJoint( Body* a, Body* b, cpFloat phase, cpFloat ratchet ) {
mConstraint = cpRatchetJointNew( a->getBody(), b->getBody(), phase, ratchet );
setData();
}
cpFloat RatchetJoint::getAngle() {
return cpRatchetJointGetAngle( mConstraint );
}
void RatchetJoint::setAngle( const cpFloat& angle ) {
cpRatchetJointSetAngle( mConstraint, angle );
}
cpFloat RatchetJoint::getPhase() {
return cpRatchetJointGetPhase( mConstraint );
}
void RatchetJoint::setPhase( const cpFloat& phase ) {
cpRatchetJointSetPhase( mConstraint, phase );
}
cpFloat RatchetJoint::getRatchet() {
return cpRatchetJointGetRatchet( mConstraint );
}
void RatchetJoint::setRatchet( const cpFloat& ratchet ) {
cpRatchetJointSetRatchet( mConstraint, ratchet );
}
void RatchetJoint::draw() {
// Not implemented
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,30 @@
#include <eepp/physics/constraints/rotarylimitjoint.hpp>
namespace EE { namespace Physics {
RotaryLimitJoint::RotaryLimitJoint( Body* a, Body* b, cpFloat min, cpFloat max ) {
mConstraint = cpRotaryLimitJointNew( a->getBody(), b->getBody(), min, max );
setData();
}
cpFloat RotaryLimitJoint::getMin() {
return cpRotaryLimitJointGetMin( mConstraint );
}
void RotaryLimitJoint::setMin( const cpFloat& min ) {
cpRotaryLimitJointSetMin( mConstraint, min );
}
cpFloat RotaryLimitJoint::getMax() {
return cpRotaryLimitJointGetMax( mConstraint );
}
void RotaryLimitJoint::setMax( const cpFloat& max ) {
cpRotaryLimitJointSetMax( mConstraint, max );
}
void RotaryLimitJoint::draw() {
// Not implemented
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,22 @@
#include <eepp/physics/constraints/simplemotor.hpp>
namespace EE { namespace Physics {
SimpleMotor::SimpleMotor( Body* a, Body* b, cpFloat rate ) {
mConstraint = cpSimpleMotorNew( a->getBody(), b->getBody(), rate );
setData();
}
cpFloat SimpleMotor::getRate() {
return cpSimpleMotorGetRate( mConstraint );
}
void SimpleMotor::setRate( const cpFloat& rate ) {
cpSimpleMotorSetRate( mConstraint, rate );
}
void SimpleMotor::draw() {
// Not implemented
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,91 @@
#include <eepp/physics/constraints/slidejoint.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
SlideJoint::SlideJoint( Body* a, Body* b, cVect anchr1, cVect anchr2, cpFloat min, cpFloat max )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawPointSize( 5.f )
#endif
{
mConstraint =
cpSlideJointNew( a->getBody(), b->getBody(), tocpv( anchr1 ), tocpv( anchr2 ), min, max );
setData();
}
cVect SlideJoint::getAnchr1() {
return tovect( cpSlideJointGetAnchr1( mConstraint ) );
}
void SlideJoint::setAnchr1( const cVect& anchr1 ) {
cpSlideJointSetAnchr1( mConstraint, tocpv( anchr1 ) );
}
cVect SlideJoint::getAnchr2() {
return tovect( cpSlideJointGetAnchr2( mConstraint ) );
}
void SlideJoint::setAnchr2( const cVect& anchr2 ) {
cpSlideJointSetAnchr2( mConstraint, tocpv( anchr2 ) );
}
cpFloat SlideJoint::getMin() {
return cpSlideJointGetMin( mConstraint );
}
void SlideJoint::setMin( const cpFloat& min ) {
cpSlideJointSetMin( mConstraint, min );
}
cpFloat SlideJoint::getMax() {
return cpSlideJointGetMax( mConstraint );
}
void SlideJoint::setMax( const cpFloat& max ) {
cpSlideJointSetMax( mConstraint, max );
}
void SlideJoint::draw() {
#ifdef PHYSICS_RENDERER_ENABLED
if ( mDrawPointSize <= 0 )
return;
cpBody* body_a = mConstraint->a;
cpBody* body_b = mConstraint->b;
cpSlideJoint* joint = (cpSlideJoint*)mConstraint;
cVect a = tovect( cpvadd( body_a->p, cpvrotate( joint->anchr1, body_a->rot ) ) );
cVect b = tovect( cpvadd( body_b->p, cpvrotate( joint->anchr2, body_b->rot ) ) );
BatchRenderer* BR = GlobalBatchRenderer::instance();
cpFloat ps = BR->getPointSize();
BR->setTexture( NULL );
BR->setPointSize( mDrawPointSize );
BR->pointsBegin();
BR->pointSetColor( Color( 128, 255, 128, 255 ) );
BR->batchPoint( a.x, a.y );
BR->batchPoint( b.x, b.y );
BR->draw();
BR->linesBegin();
BR->batchLine( a.x, a.y, b.x, b.y );
BR->draw();
BR->setPointSize( ps );
#endif
}
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat SlideJoint::getDrawPointSize() {
return mDrawPointSize;
}
void SlideJoint::setDrawPointSize( const cpFloat& size ) {
mDrawPointSize = size;
}
#endif
}} // namespace EE::Physics

View File

@@ -0,0 +1,21 @@
#include <eepp/physics/moment.hpp>
namespace EE { namespace Physics {
cpFloat Moment::forCircle( cpFloat m, cpFloat r1, cpFloat r2, cVect offset ) {
return cpMomentForCircle( m, r1, r2, tocpv( offset ) );
}
cpFloat Moment::forSegment( cpFloat m, cVect a, cVect b ) {
return cpMomentForSegment( m, tocpv( a ), tocpv( b ) );
}
cpFloat Moment::forPoly( cpFloat m, int numVerts, const cVect* verts, cVect offset ) {
return cpMomentForPoly( m, numVerts, constcasttocpv( verts ), tocpv( offset ) );
}
cpFloat Moment::forBox( cpFloat m, cpFloat width, cpFloat height ) {
return cpMomentForBox( m, width, height );
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,101 @@
#include <algorithm>
#include <eepp/physics/body.hpp>
#include <eepp/physics/constraints/constraint.hpp>
#include <eepp/physics/physicsmanager.hpp>
#include <eepp/physics/shape.hpp>
#include <eepp/physics/space.hpp>
namespace EE { namespace Physics {
SINGLETON_DECLARE_IMPLEMENTATION( PhysicsManager )
PhysicsManager::PhysicsManager() : mMemoryManager( false ) {}
PhysicsManager::~PhysicsManager() {
if ( mMemoryManager ) {
mMemoryManager = false;
std::list<Space*>::iterator its = mSpaces.begin();
for ( ; its != mSpaces.end(); ++its )
eeSAFE_DELETE( *its );
std::list<Body*>::iterator itb = mBodysFree.begin();
for ( ; itb != mBodysFree.end(); ++itb )
eeSAFE_DELETE( *itb );
std::list<Shape*>::iterator itp = mShapesFree.begin();
for ( ; itp != mShapesFree.end(); ++itp )
eeSAFE_DELETE( *itp );
std::list<Constraint*>::iterator itc = mConstraintFree.begin();
for ( ; itc != mConstraintFree.end(); ++itc )
eeSAFE_DELETE( *itc );
}
}
PhysicsManager::DrawSpaceOptions* PhysicsManager::getDrawOptions() {
return &mOptions;
}
void PhysicsManager::setMemoryManager( bool MemoryManager ) {
mMemoryManager = MemoryManager;
}
const bool& PhysicsManager::isMemoryManagerEnabled() const {
return mMemoryManager;
}
void PhysicsManager::addBodyFree( Body* body ) {
if ( mMemoryManager ) {
if ( std::find( mBodysFree.begin(), mBodysFree.end(), body ) == mBodysFree.end() )
mBodysFree.push_back( body );
}
}
void PhysicsManager::removeBodyFree( Body* body ) {
if ( mMemoryManager ) {
mBodysFree.remove( body );
}
}
void PhysicsManager::addShapeFree( Shape* shape ) {
if ( mMemoryManager ) {
if ( std::find( mShapesFree.begin(), mShapesFree.end(), shape ) == mShapesFree.end() )
mShapesFree.push_back( shape );
}
}
void PhysicsManager::removeShapeFree( Shape* shape ) {
if ( mMemoryManager ) {
mShapesFree.remove( shape );
}
}
void PhysicsManager::addConstraintFree( Constraint* constraint ) {
if ( mMemoryManager ) {
if ( std::find( mConstraintFree.begin(), mConstraintFree.end(), constraint ) ==
mConstraintFree.end() )
mConstraintFree.push_back( constraint );
}
}
void PhysicsManager::removeConstraintFree( Constraint* constraint ) {
if ( mMemoryManager ) {
mConstraintFree.remove( constraint );
}
}
void PhysicsManager::addSpace( Space* space ) {
if ( mMemoryManager ) {
if ( std::find( mSpaces.begin(), mSpaces.end(), space ) == mSpaces.end() )
mSpaces.push_back( space );
}
}
void PhysicsManager::removeSpace( Space* space ) {
if ( mMemoryManager ) {
mSpaces.remove( space );
}
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,194 @@
#include <eepp/physics/physicsmanager.hpp>
#include <eepp/physics/shape.hpp>
#include <eepp/physics/shapecircle.hpp>
#include <eepp/physics/shapepoly.hpp>
#include <eepp/physics/shapesegment.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/primitives.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
void Shape::resetShapeIdCounter() {
cpResetShapeIdCounter();
}
void Shape::Free( Shape* shape, bool DeleteBody ) {
if ( DeleteBody ) {
Physics::Body* b = shape->getBody();
eeSAFE_DELETE( b );
}
eeSAFE_DELETE( shape );
}
Shape::Shape() : mData( NULL ) {}
Shape::~Shape() {
cpShapeFree( mShape );
PhysicsManager::instance()->removeShapeFree( this );
}
void Shape::setData() {
mShape->data = (void*)this;
PhysicsManager::instance()->addShapeFree( this );
}
cpShape* Shape::getShape() const {
return mShape;
}
cBB Shape::cacheBB() {
return tocbb( cpShapeCacheBB( mShape ) );
}
cBB Shape::update( cVect pos, cVect rot ) {
return tocbb( cpShapeUpdate( mShape, tocpv( pos ), tocpv( rot ) ) );
}
bool Shape::pointQuery( cVect p ) {
return 0 != cpShapePointQuery( mShape, tocpv( p ) );
}
Physics::Body* Shape::getBody() const {
return reinterpret_cast<Physics::Body*>( mShape->body->data );
}
void Shape::setBody( Physics::Body* body ) {
mShape->body = body->getBody();
}
cBB Shape::getBB() const {
return tocbb( mShape->bb );
}
void Shape::setBB( const cBB& bb ) {
mShape->bb = tocpbb( bb );
}
bool Shape::isSensor() {
return 0 != mShape->sensor;
}
void Shape::setSensor( const bool& sensor ) {
mShape->sensor = sensor ? 1 : 0;
}
cpFloat Shape::getE() const {
return mShape->e;
}
void Shape::setE( const cpFloat& e ) {
mShape->e = e;
}
cpFloat Shape::getElasticity() const {
return getE();
}
void Shape::setElasticity( const cpFloat& e ) {
this->setE( e );
}
cpFloat Shape::getU() const {
return mShape->u;
}
void Shape::setU( const cpFloat& u ) {
mShape->u = u;
}
cpFloat Shape::getFriction() const {
return getU();
}
void Shape::setFriction( const cpFloat& u ) {
this->setU( u );
}
cVect Shape::getSurfaceVel() const {
return tovect( mShape->surface_v );
}
void Shape::getSurfaceVel( const cVect& vel ) {
mShape->surface_v = tocpv( vel );
}
cpCollisionType Shape::getCollisionType() const {
return mShape->collision_type;
}
void Shape::setCollisionType( const cpCollisionType& type ) {
mShape->collision_type = type;
}
cpGroup Shape::getGroup() const {
return mShape->group;
}
void Shape::setGroup( const cpGroup& group ) {
mShape->group = group;
}
cpLayers Shape::getLayers() const {
return mShape->layers;
}
void Shape::setLayers( const cpLayers& layers ) {
mShape->layers = layers;
}
cpShapeType Shape::getType() const {
return mShape->CP_PRIVATE( klass )->type;
}
ShapePoly* Shape::getAsPoly() {
eeASSERT( getType() == CP_POLY_SHAPE );
return reinterpret_cast<ShapePoly*>( this );
}
ShapeCircle* Shape::getAsCircle() {
eeASSERT( getType() == CP_CIRCLE_SHAPE );
return reinterpret_cast<ShapeCircle*>( this );
}
ShapeSegment* Shape::getAsSegment() {
eeASSERT( getType() == CP_SEGMENT_SHAPE );
return reinterpret_cast<ShapeSegment*>( this );
}
void Shape::drawBB() {
#ifdef PHYSICS_RENDERER_ENABLED
Primitives P;
P.setColor( Color( 76, 128, 76, 255 ) );
P.setForceDraw( false );
P.drawLine(
Line2f( Vector2f( mShape->bb.l, mShape->bb.t ), Vector2f( mShape->bb.r, mShape->bb.t ) ) );
P.drawLine(
Line2f( Vector2f( mShape->bb.l, mShape->bb.t ), Vector2f( mShape->bb.l, mShape->bb.b ) ) );
P.drawLine(
Line2f( Vector2f( mShape->bb.l, mShape->bb.b ), Vector2f( mShape->bb.r, mShape->bb.b ) ) );
P.drawLine(
Line2f( Vector2f( mShape->bb.r, mShape->bb.t ), Vector2f( mShape->bb.r, mShape->bb.b ) ) );
#endif
}
void* Shape::getData() const {
return mData;
}
void Shape::setData( void* data ) {
mData = data;
}
void Shape::draw( Space* space ) {}
void Shape::drawBorder( Space* space ) {}
}} // namespace EE::Physics

View File

@@ -0,0 +1,49 @@
#include <eepp/physics/shapecircle.hpp>
#include <eepp/physics/space.hpp>
#include <eepp/thirdparty/chipmunk/chipmunk_unsafe.h>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/primitives.hpp>
#include <eepp/graphics/renderer/renderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
ShapeCircle* ShapeCircle::New( Physics::Body* body, cpFloat radius, cVect offset ) {
return eeNew( ShapeCircle, ( body, radius, offset ) );
}
ShapeCircle::ShapeCircle( Physics::Body* body, cpFloat radius, cVect offset ) {
mShape = cpCircleShapeNew( body->getBody(), radius, tocpv( offset ) );
setData();
}
cVect ShapeCircle::getOffset() {
return tovect( cpCircleShapeGetOffset( mShape ) );
}
void ShapeCircle::setOffset( const cVect& offset ) {
cpCircleShapeSetOffset( mShape, tocpv( offset ) );
}
cpFloat ShapeCircle::getRadius() {
return cpCircleShapeGetRadius( mShape );
}
void ShapeCircle::setRadius( const cpFloat& radius ) {
cpCircleShapeSetRadius( mShape, radius );
}
void ShapeCircle::draw( Space* space ) {
#ifdef PHYSICS_RENDERER_ENABLED
Primitives p;
cpCircleShape* cs = (cpCircleShape*)mShape;
p.setColor( colorForShape( mShape, space->getSpace() ) );
p.drawCircle( Vector2f( cs->CP_PRIVATE( tc ).x, cs->CP_PRIVATE( tc ).y ), cs->CP_PRIVATE( r ) );
#endif
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,55 @@
#include <eepp/physics/shapecirclesprite.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/sprite.hpp>
namespace EE { namespace Physics {
ShapeCircleSprite* ShapeCircleSprite::New( Physics::Body* body, cpFloat radius, cVect offset,
Sprite* Sprite, bool AutoDeleteSprite ) {
return eeNew( ShapeCircleSprite, ( body, radius, offset, Sprite, AutoDeleteSprite ) );
}
ShapeCircleSprite::ShapeCircleSprite( Physics::Body* body, cpFloat radius, cVect offset,
Sprite* Sprite, bool AutoDeleteSprite ) :
ShapeCircle( body, radius, offset ), mSprite( Sprite ), mSpriteAutoDelete( AutoDeleteSprite ) {
offsetSet();
}
ShapeCircleSprite::~ShapeCircleSprite() {
if ( mSpriteAutoDelete )
eeSAFE_DELETE( mSprite );
}
void ShapeCircleSprite::draw( Space* space ) {
cVect Pos = getBody()->getPos();
mSprite->setPosition( Vector2f( Pos.x, Pos.y ) );
mSprite->setRotation( getBody()->getAngleDeg() );
mSprite->draw();
}
void ShapeCircleSprite::offsetSet() {
mSprite->setSize( Sizef( ShapeCircle::getRadius() * 2, ShapeCircle::getRadius() * 2 ) );
mSprite->setOffset( Vector2i( -ShapeCircle::getRadius() + ShapeCircle::getOffset().x,
-ShapeCircle::getRadius() + ShapeCircle::getOffset().y ) );
}
Sprite* ShapeCircleSprite::getSprite() const {
return mSprite;
}
void ShapeCircleSprite::setRadius( const cpFloat& radius ) {
ShapeCircle::setRadius( radius );
offsetSet();
}
void ShapeCircleSprite::setOffset( const cVect& offset ) {
ShapeCircle::setOffset( offset );
offsetSet();
}
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,70 @@
#include <eepp/physics/shapepoint.hpp>
#include <eepp/physics/space.hpp>
#include <eepp/thirdparty/chipmunk/chipmunk_unsafe.h>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
#include <eepp/graphics/primitives.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
ShapePoint* ShapePoint::New( Physics::Body* body, cpFloat radius, cVect offset ) {
return eeNew( ShapePoint, ( body, radius, offset ) );
}
ShapePoint::ShapePoint( Physics::Body* body, cpFloat radius, cVect offset )
#ifdef PHYSICS_RENDERER_ENABLED
:
mDrawRadius( radius )
#endif
{
mShape = cpCircleShapeNew( body->getBody(), radius, tocpv( offset ) );
setData();
}
cVect ShapePoint::getOffset() {
return tovect( cpCircleShapeGetOffset( mShape ) );
}
void ShapePoint::setOffset( const cVect& offset ) {
cpCircleShapeSetOffset( mShape, tocpv( offset ) );
}
cpFloat ShapePoint::getRadius() {
return cpCircleShapeGetRadius( mShape );
}
void ShapePoint::setRadius( const cpFloat& radius ) {
cpCircleShapeSetRadius( mShape, radius );
}
void ShapePoint::draw( Space* space ) {
#ifdef PHYSICS_RENDERER_ENABLED
BatchRenderer* BR = GlobalBatchRenderer::instance();
BR->setTexture( NULL );
BR->pointsBegin();
BR->pointSetColor( colorForShape( mShape, space->getSpace() ) );
cpCircleShape* cs = (cpCircleShape*)mShape;
BR->batchPoint( cs->CP_PRIVATE( tc ).x, cs->CP_PRIVATE( tc ).y );
BR->setPointSize( mDrawRadius );
BR->drawOpt();
#endif
}
#ifdef PHYSICS_RENDERER_ENABLED
cpFloat ShapePoint::getDrawRadius() {
return mDrawRadius;
}
void ShapePoint::setDrawRadius( const cpFloat& radius ) {
mDrawRadius = radius;
}
#endif
}} // namespace EE::Physics

View File

@@ -0,0 +1,108 @@
#include <eepp/physics/shapepoly.hpp>
#include <eepp/physics/space.hpp>
#include <eepp/thirdparty/chipmunk/chipmunk_unsafe.h>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
ShapePoly* ShapePoly::New( Physics::Body* body, int numVerts, cVect* verts, cVect offset ) {
return eeNew( ShapePoly, ( body, numVerts, verts, offset ) );
}
ShapePoly* ShapePoly::New( Physics::Body* body, cpFloat width, cpFloat height ) {
return eeNew( ShapePoly, ( body, width, height ) );
}
ShapePoly::ShapePoly( Physics::Body* body, int numVerts, cVect* verts, cVect offset ) {
mShape = cpPolyShapeNew( body->getBody(), numVerts, casttocpv( verts ), tocpv( offset ) );
setData();
}
ShapePoly::ShapePoly( Physics::Body* body, cpFloat width, cpFloat height ) : Shape() {
mShape = cpBoxShapeNew( body->getBody(), width, height );
setData();
}
bool ShapePoly::validate( const cVect* verts, const int numVerts ) {
return 0 != cpPolyValidate( constcasttocpv( verts ), numVerts );
}
int ShapePoly::getNumVerts() {
return cpPolyShapeGetNumVerts( mShape );
}
cVect ShapePoly::getVert( int idx ) {
return tovect( cpPolyShapeGetVert( mShape, idx ) );
}
void ShapePoly::setVerts( int numVerts, cVect* verts, cVect offset ) {
cpPolyShapeSetVerts( mShape, numVerts, casttocpv( verts ), tocpv( offset ) );
}
void ShapePoly::recenter( int numVerts, cVect* verts ) {
cpRecenterPoly( numVerts, casttocpv( verts ) );
}
cVect ShapePoly::centroid( int numVerts, const cVect* verts ) {
return tovect( cpCentroidForPoly( numVerts, constcasttocpv( verts ) ) );
}
void ShapePoly::draw( Space* space ) {
#ifdef PHYSICS_RENDERER_ENABLED
cpPolyShape* poly = (cpPolyShape*)mShape;
BatchRenderer* BR = GlobalBatchRenderer::instance();
BR->setTexture( NULL );
Color Col = colorForShape( (cpShape*)poly, space->getSpace() );
if ( !poly->CP_PRIVATE( shape ).sensor ) {
if ( 4 != poly->CP_PRIVATE( numVerts ) ) {
BR->pointsBegin();
BR->polygonSetColor( Col );
for ( int i = 0; i < poly->CP_PRIVATE( numVerts ); i++ ) {
BR->batchPolygonByPoint( poly->CP_PRIVATE( tVerts )[i].x,
poly->CP_PRIVATE( tVerts )[i].y );
}
} else {
BR->quadsBegin();
BR->quadsSetColor( Col );
BR->batchQuadFreeEx( poly->CP_PRIVATE( tVerts )[0].x, poly->CP_PRIVATE( tVerts )[0].y,
poly->CP_PRIVATE( tVerts )[1].x, poly->CP_PRIVATE( tVerts )[1].y,
poly->CP_PRIVATE( tVerts )[2].x, poly->CP_PRIVATE( tVerts )[2].y,
poly->CP_PRIVATE( tVerts )[3].x, poly->CP_PRIVATE( tVerts )[3].y );
}
BR->drawOpt();
}
#endif
}
void ShapePoly::drawBorder( Space* space ) {
#ifdef PHYSICS_RENDERER_ENABLED
cpPolyShape* poly = (cpPolyShape*)mShape;
BatchRenderer* BR = GlobalBatchRenderer::instance();
Color Col = colorForShape( (cpShape*)poly, space->getSpace() );
BR->lineLoopBegin();
BR->lineLoopSetColor( Col );
for ( int i = 0; i < poly->CP_PRIVATE( numVerts ); i++ ) {
BR->batchLineLoop( poly->CP_PRIVATE( tVerts )[i].x, poly->CP_PRIVATE( tVerts )[i].y );
}
BR->draw();
#endif
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,61 @@
#include <eepp/physics/shapepolysprite.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/sprite.hpp>
namespace EE { namespace Physics {
ShapePolySprite* ShapePolySprite::New( Physics::Body* body, int numVerts, cVect* verts,
cVect offset, Sprite* Sprite, bool AutoDeleteSprite ) {
return eeNew( ShapePolySprite, ( body, numVerts, verts, offset, Sprite, AutoDeleteSprite ) );
}
ShapePolySprite* ShapePolySprite::New( Physics::Body* body, cpFloat width, cpFloat height,
Sprite* Sprite, bool AutoDeleteSprite ) {
return eeNew( ShapePolySprite, ( body, width, height, Sprite, AutoDeleteSprite ) );
}
ShapePolySprite::ShapePolySprite( Physics::Body* body, int numVerts, cVect* verts, cVect offset,
Sprite* Sprite, bool AutoDeleteSprite ) :
ShapePoly( body, numVerts, verts, offset ),
mSprite( Sprite ),
mSpriteAutoDelete( AutoDeleteSprite ) {
offsetSet( centroid( numVerts, verts ) );
}
ShapePolySprite::ShapePolySprite( Physics::Body* body, cpFloat width, cpFloat height,
Sprite* Sprite, bool AutoDeleteSprite ) :
ShapePoly( body, width, height ), mSprite( Sprite ), mSpriteAutoDelete( AutoDeleteSprite ) {
mSprite->setSize( Sizef( width, height ) );
offsetSet( cVectNew( width / 2, height / 2 ) );
}
ShapePolySprite::~ShapePolySprite() {
if ( mSpriteAutoDelete )
eeSAFE_DELETE( mSprite );
}
void ShapePolySprite::draw( Space* space ) {
cVect Pos = getBody()->getPos();
mSprite->setOffset( mOffset );
mSprite->setPosition( Vector2f( Pos.x, Pos.y ) );
mSprite->setRotation( getBody()->getAngleDeg() );
mSprite->draw();
}
void ShapePolySprite::offsetSet( cVect center ) {
cVect myCenter = cVectNew( ( mSprite->getSize().x / 2 ), ( mSprite->getSize().y / 2 ) );
mOffset = Vector2i( ( Int32 )( -myCenter.x + ( center.x - myCenter.x ) ),
( Int32 )( -myCenter.y + ( center.y - myCenter.y ) ) );
}
Sprite* ShapePolySprite::getSprite() const {
return mSprite;
}
}} // namespace EE::Physics
#endif

View File

@@ -0,0 +1,131 @@
#include <eepp/physics/shapesegment.hpp>
#include <eepp/physics/space.hpp>
#include <eepp/thirdparty/chipmunk/chipmunk_unsafe.h>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/primitives.hpp>
#include <eepp/graphics/renderer/opengl.hpp>
#include <eepp/graphics/renderer/renderer.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
ShapeSegment* ShapeSegment::New( Physics::Body* body, cVect a, cVect b, cpFloat radius ) {
return eeNew( ShapeSegment, ( body, a, b, radius ) );
}
ShapeSegment::ShapeSegment( Physics::Body* body, cVect a, cVect b, cpFloat radius ) {
mShape = cpSegmentShapeNew( body->getBody(), tocpv( a ), tocpv( b ), radius );
setData();
}
cVect ShapeSegment::getA() {
return tovect( cpSegmentShapeGetA( mShape ) );
}
cVect ShapeSegment::getB() {
return tovect( cpSegmentShapeGetB( mShape ) );
}
cVect ShapeSegment::getNormal() {
return tovect( cpSegmentShapeGetNormal( mShape ) );
}
cpFloat ShapeSegment::getRadius() {
return cpSegmentShapeGetRadius( mShape );
}
void ShapeSegment::setRadius( const cpFloat& radius ) {
cpSegmentShapeSetRadius( mShape, radius );
}
void ShapeSegment::setEndpoints( const cVect& a, const cVect& b ) {
cpSegmentShapeSetEndpoints( mShape, tocpv( a ), tocpv( b ) );
}
bool ShapeSegment::query( cVect a, cVect b, cpSegmentQueryInfo* info ) {
return 0 != cpShapeSegmentQuery( mShape, tocpv( a ), tocpv( b ), info );
}
cVect ShapeSegment::queryHitPoint( const cVect start, const cVect end,
const cpSegmentQueryInfo info ) {
return tovect( cpSegmentQueryHitPoint( tocpv( start ), tocpv( end ), info ) );
}
cpFloat ShapeSegment::queryHitDist( const cVect start, const cVect end,
const cpSegmentQueryInfo info ) {
return cpSegmentQueryHitDist( tocpv( start ), tocpv( end ), info );
}
void ShapeSegment::draw( Space* space ) {
#ifdef PHYSICS_RENDERER_ENABLED
static const float pillVAR[] = {
0.0000f, 1.0000f, 1.0f, 0.2588f, 0.9659f, 1.0f, 0.5000f, 0.8660f,
1.0f, 0.7071f, 0.7071f, 1.0f, 0.8660f, 0.5000f, 1.0f, 0.9659f,
0.2588f, 1.0f, 1.0000f, 0.0000f, 1.0f, 0.9659f, -0.2588f, 1.0f,
0.8660f, -0.5000f, 1.0f, 0.7071f, -0.7071f, 1.0f, 0.5000f, -0.8660f,
1.0f, 0.2588f, -0.9659f, 1.0f, 0.0000f, -1.0000f, 1.0f,
0.0000f, -1.0000f, 0.0f, -0.2588f, -0.9659f, 0.0f, -0.5000f, -0.8660f,
0.0f, -0.7071f, -0.7071f, 0.0f, -0.8660f, -0.5000f, 0.0f, -0.9659f,
-0.2588f, 0.0f, -1.0000f, -0.0000f, 0.0f, -0.9659f, 0.2588f, 0.0f,
-0.8660f, 0.5000f, 0.0f, -0.7071f, 0.7071f, 0.0f, -0.5000f, 0.8660f,
0.0f, -0.2588f, 0.9659f, 0.0f, 0.0000f, 1.0000f, 0.0f,
};
static const int pillVAR_count = sizeof( pillVAR ) / sizeof( float ) / 3;
cpSegmentShape* seg = (cpSegmentShape*)mShape;
cVect a = tovect( seg->CP_PRIVATE( ta ) );
cVect b = tovect( seg->CP_PRIVATE( tb ) );
if ( seg->CP_PRIVATE( r ) ) {
GLi->disable( GL_TEXTURE_2D );
GLi->disableClientState( GL_TEXTURE_COORD_ARRAY );
std::vector<Color> tcolors( pillVAR_count * 4 );
GLi->pushMatrix();
cVect d = b - a;
cVect r = d * ( seg->CP_PRIVATE( r ) / cpvlength( tocpv( d ) ) );
const float matrix[] = {
(float)r.x, (float)r.y, 0.0f, 0.0f, (float)-r.y, (float)r.x, 0.0f, 0.0f,
(float)d.x, (float)d.y, 0.0f, 0.0f, (float)a.x, (float)a.y, 0.0f, 1.0f,
};
GLi->multMatrixf( matrix );
GLi->vertexPointer( 3, GL_FLOAT, 0, pillVAR, pillVAR_count * sizeof( float ) * 3 );
if ( !seg->CP_PRIVATE( shape ).sensor ) {
Color C = colorForShape( mShape, space->getSpace() );
tcolors.assign( tcolors.size(), C );
GLi->colorPointer( 4, GL_UNSIGNED_BYTE, 0, reinterpret_cast<const void*>( &tcolors[0] ),
pillVAR_count * 4 );
GLi->drawArrays( GL_TRIANGLE_FAN, 0, pillVAR_count );
}
tcolors.assign( tcolors.size(), Color( 102, 102, 102, 255 ) );
GLi->colorPointer( 4, GL_UNSIGNED_BYTE, 0, reinterpret_cast<const void*>( &tcolors[0] ),
pillVAR_count * 4 );
GLi->drawArrays( GL_LINE_LOOP, 0, pillVAR_count );
GLi->popMatrix();
GLi->enable( GL_TEXTURE_2D );
GLi->enableClientState( GL_TEXTURE_COORD_ARRAY );
} else {
Primitives p;
p.drawLine( Line2f( Vector2f( a.x, a.y ), Vector2f( b.x, b.y ) ) );
}
#endif
}
}} // namespace EE::Physics

View File

@@ -0,0 +1,656 @@
#include <eepp/physics/physicsmanager.hpp>
#include <eepp/physics/space.hpp>
#ifdef PHYSICS_RENDERER_ENABLED
#include <eepp/graphics/globalbatchrenderer.hpp>
#include <eepp/window/engine.hpp>
using namespace EE::Graphics;
#endif
namespace EE { namespace Physics {
Space* Space::New() {
return eeNew( Space, () );
}
void Space::Free( Space* space ) {
eeSAFE_DELETE( space );
}
Space::Space() : mData( NULL ) {
mSpace = cpSpaceNew();
mSpace->data = (void*)this;
mStatiBody = eeNew( Body, ( mSpace->staticBody ) );
PhysicsManager::instance()->removeBodyFree( mStatiBody );
PhysicsManager::instance()->addSpace( this );
}
Space::~Space() {
cpSpaceFree( mSpace );
std::list<Constraint*>::iterator itc = mConstraints.begin();
for ( ; itc != mConstraints.end(); ++itc )
eeSAFE_DELETE( *itc );
std::list<Shape*>::iterator its = mShapes.begin();
for ( ; its != mShapes.end(); ++its )
eeSAFE_DELETE( *its );
std::list<Body*>::iterator itb = mBodys.begin();
for ( ; itb != mBodys.end(); ++itb )
eeSAFE_DELETE( *itb );
mStatiBody->mBody = NULL; // The body has been released by cpSpaceFree( mSpace )
eeSAFE_DELETE( mStatiBody );
PhysicsManager::instance()->removeSpace( this );
}
void Space::setData( void* data ) {
mData = data;
}
void* Space::getData() const {
return mData;
}
void Space::step( const cpFloat& dt ) {
cpSpaceStep( mSpace, dt );
}
void Space::update() {
#ifdef PHYSICS_RENDERER_ENABLED
step( Window::Engine::instance()->getCurrentWindow()->getElapsed().asSeconds() );
#else
Step( 1 / 60 );
#endif
}
const int& Space::getIterations() const {
return mSpace->iterations;
}
void Space::setIterations( const int& iterations ) {
mSpace->iterations = iterations;
}
cVect Space::getGravity() const {
return tovect( mSpace->gravity );
}
void Space::setGravity( const cVect& gravity ) {
mSpace->gravity = tocpv( gravity );
}
const cpFloat& Space::getDamping() const {
return mSpace->damping;
}
void Space::setDamping( const cpFloat& damping ) {
mSpace->damping = damping;
}
const cpFloat& Space::getIdleSpeedThreshold() const {
return mSpace->idleSpeedThreshold;
}
void Space::setIdleSpeedThreshold( const cpFloat& idleSpeedThreshold ) {
mSpace->idleSpeedThreshold = idleSpeedThreshold;
}
const cpFloat& Space::getSleepTimeThreshold() const {
return mSpace->sleepTimeThreshold;
}
void Space::setSleepTimeThreshold( const cpFloat& sleepTimeThreshold ) {
mSpace->sleepTimeThreshold = sleepTimeThreshold;
}
void Space::setCollisionSlop( cpFloat slop ) {
mSpace->collisionSlop = slop;
}
cpFloat Space::getCollisionSlop() const {
return mSpace->collisionSlop;
}
void Space::setCollisionBias( cpFloat bias ) {
mSpace->collisionBias = bias;
}
cpFloat Space::getCollisionBias() const {
return mSpace->collisionBias;
}
cpTimestamp Space::getCollisionPersistence() {
return cpSpaceGetCollisionPersistence( mSpace );
}
void Space::setCollisionPersistence( cpTimestamp value ) {
cpSpaceSetCollisionPersistence( mSpace, value );
}
bool Space::getEnableContactGraph() {
return cpTrue == cpSpaceGetEnableContactGraph( mSpace );
}
void Space::setEnableContactGraph( bool value ) {
cpSpaceSetEnableContactGraph( mSpace, value );
}
Body* Space::getStaticBody() const {
return mStatiBody;
}
bool Space::contains( Shape* shape ) {
return cpTrue == cpSpaceContainsShape( mSpace, shape->getShape() );
}
bool Space::contains( Body* body ) {
return cpTrue == cpSpaceContainsBody( mSpace, body->getBody() );
}
bool Space::contains( Constraint* constraint ) {
return cpTrue == cpSpaceContainsConstraint( mSpace, constraint->getConstraint() );
}
Shape* Space::addShape( Shape* shape ) {
cpSpaceAddShape( mSpace, shape->getShape() );
mShapes.push_back( shape );
PhysicsManager::instance()->removeShapeFree( shape );
return shape;
}
Shape* Space::addStaticShape( Shape* shape ) {
cpSpaceAddStaticShape( mSpace, shape->getShape() );
mShapes.push_back( shape );
PhysicsManager::instance()->removeShapeFree( shape );
return shape;
}
Body* Space::addBody( Body* body ) {
cpSpaceAddBody( mSpace, body->getBody() );
mBodys.push_back( body );
PhysicsManager::instance()->removeBodyFree( body );
return body;
}
Constraint* Space::addConstraint( Constraint* constraint ) {
cpSpaceAddConstraint( mSpace, constraint->getConstraint() );
mConstraints.push_back( constraint );
PhysicsManager::instance()->removeConstraintFree( constraint );
return constraint;
}
void Space::removeShape( Shape* shape ) {
if ( NULL != shape ) {
cpSpaceRemoveShape( mSpace, shape->getShape() );
mShapes.remove( shape );
PhysicsManager::instance()->addShapeFree( shape );
}
}
void Space::removeStatiShape( Shape* shape ) {
if ( NULL != shape ) {
cpSpaceRemoveStaticShape( mSpace, shape->getShape() );
mShapes.remove( shape );
PhysicsManager::instance()->addShapeFree( shape );
}
}
void Space::removeBody( Body* body ) {
if ( NULL != body ) {
cpSpaceRemoveBody( mSpace, body->getBody() );
mBodys.remove( body );
PhysicsManager::instance()->removeBodyFree( body );
}
}
void Space::removeConstraint( Constraint* constraint ) {
if ( NULL != constraint ) {
cpSpaceRemoveConstraint( mSpace, constraint->getConstraint() );
mConstraints.remove( constraint );
PhysicsManager::instance()->addConstraintFree( constraint );
}
}
Shape* Space::pointQueryFirst( cVect point, cpLayers layers, cpGroup group ) {
cpShape* shape = cpSpacePointQueryFirst( mSpace, tocpv( point ), layers, group );
if ( NULL != shape ) {
return reinterpret_cast<Shape*>( shape->data );
}
return NULL;
}
Shape* Space::segmentQueryFirst( cVect start, cVect end, cpLayers layers, cpGroup group,
cpSegmentQueryInfo* out ) {
cpShape* shape =
cpSpaceSegmentQueryFirst( mSpace, tocpv( start ), tocpv( end ), layers, group, out );
if ( NULL != shape ) {
return reinterpret_cast<Shape*>( shape->data );
}
return NULL;
}
cpSpace* Space::getSpace() const {
return mSpace;
}
void Space::activateShapesTouchingShape( Shape* shape ) {
cpSpaceActivateShapesTouchingShape( mSpace, shape->getShape() );
}
#ifdef PHYSICS_RENDERER_ENABLED
static void drawObject( cpShape* shape, cpSpace* space ) {
reinterpret_cast<Shape*>( shape->data )->draw( reinterpret_cast<Space*>( space->data ) );
}
static void drawObjectBorder( cpShape* shape, cpSpace* space ) {
reinterpret_cast<Shape*>( shape->data )->drawBorder( reinterpret_cast<Space*>( space->data ) );
}
static void drawBB( cpShape* shape, void* unused ) {
reinterpret_cast<Shape*>( shape->data )->drawBB();
}
static void drawConstraint( cpConstraint* constraint ) {
reinterpret_cast<Constraint*>( constraint->data )->draw();
}
#endif
void Space::draw() {
#ifdef PHYSICS_RENDERER_ENABLED
BatchRenderer* BR = GlobalBatchRenderer::instance();
BR->setBlendMode( BlendMode::Alpha() );
PhysicsManager::DrawSpaceOptions* options = PhysicsManager::instance()->getDrawOptions();
cpFloat lw = BR->getLineWidth();
cpFloat ps = BR->getPointSize();
BR->setLineWidth( options->LineThickness );
if ( options->DrawShapes ) {
cpSpatialIndexEach( mSpace->CP_PRIVATE( activeShapes ),
(cpSpatialIndexIteratorFunc)drawObject, mSpace );
cpSpatialIndexEach( mSpace->CP_PRIVATE( staticShapes ),
(cpSpatialIndexIteratorFunc)drawObject, mSpace );
}
if ( options->DrawShapesBorders ) {
cpSpatialIndexEach( mSpace->CP_PRIVATE( activeShapes ),
(cpSpatialIndexIteratorFunc)drawObjectBorder, mSpace );
cpSpatialIndexEach( mSpace->CP_PRIVATE( staticShapes ),
(cpSpatialIndexIteratorFunc)drawObjectBorder, mSpace );
}
BR->setLineWidth( lw );
if ( options->DrawBBs ) {
cpSpatialIndexEach( mSpace->CP_PRIVATE( activeShapes ), (cpSpatialIndexIteratorFunc)drawBB,
NULL );
cpSpatialIndexEach( mSpace->CP_PRIVATE( staticShapes ), (cpSpatialIndexIteratorFunc)drawBB,
NULL );
BR->draw();
}
cpArray* constraints = mSpace->CP_PRIVATE( constraints );
for ( int i = 0, count = constraints->num; i < count; i++ ) {
drawConstraint( (cpConstraint*)constraints->arr[i] );
}
if ( options->BodyPointSize ) {
BR->setPointSize( options->BodyPointSize );
BR->pointsBegin();
BR->pointSetColor( Color( 255, 255, 255, 255 ) );
cpArray* bodies = mSpace->CP_PRIVATE( bodies );
for ( int i = 0, count = bodies->num; i < count; i++ ) {
cpBody* body = (cpBody*)bodies->arr[i];
BR->batchPoint( body->p.x, body->p.y );
}
BR->draw();
}
if ( options->CollisionPointSize ) {
BR->setPointSize( options->CollisionPointSize );
BR->pointsBegin();
BR->pointSetColor( Color( 255, 0, 0, 255 ) );
cpArray* arbiters = mSpace->CP_PRIVATE( arbiters );
for ( int i = 0; i < arbiters->num; i++ ) {
cpArbiter* arb = (cpArbiter*)arbiters->arr[i];
for ( int i = 0; i < arb->CP_PRIVATE( numContacts ); i++ ) {
cVect v = tovect( arb->CP_PRIVATE( contacts )[i].CP_PRIVATE( p ) );
BR->batchPoint( v.x, v.y );
}
}
BR->draw();
}
BR->setLineWidth( lw );
BR->setPointSize( ps );
#endif
}
/** Collision Handling */
static cpBool RecieverCollisionBeginFunc( cpArbiter* arb, cpSpace* space, void* data ) {
Space* tspace = reinterpret_cast<Space*>( space->data );
Arbiter tarb( arb );
return tspace->onCollisionBegin( &tarb, data );
}
static cpBool RecieverCollisionPreSolveFunc( cpArbiter* arb, cpSpace* space, void* data ) {
Space* tspace = reinterpret_cast<Space*>( space->data );
Arbiter tarb( arb );
return tspace->onCollisionPreSolve( &tarb, data );
}
static void RecieverCollisionPostSolve( cpArbiter* arb, cpSpace* space, void* data ) {
Space* tspace = reinterpret_cast<Space*>( space->data );
Arbiter tarb( arb );
tspace->onCollisionPostSolve( &tarb, data );
}
static void RecieverCollisionSeparateFunc( cpArbiter* arb, cpSpace* space, void* data ) {
Space* tspace = reinterpret_cast<Space*>( space->data );
Arbiter tarb( arb );
tspace->onCollisionSeparate( &tarb, data );
}
static void RecieverPostStepCallback( cpSpace* space, void* obj, void* data ) {
Space* tspace = reinterpret_cast<Space*>( space->data );
tspace->onPostStepCallback( obj, data );
}
static void RecieverBBQueryFunc( cpShape* shape, void* data ) {
Space::BBQuery* query = reinterpret_cast<Space::BBQuery*>( data );
query->Space->onBBQuery( reinterpret_cast<Shape*>( shape->data ), query );
}
static void RecieverSegmentQueryFunc( cpShape* shape, cpFloat t, cpVect n, void* data ) {
Space::SegmentQuery* query = reinterpret_cast<Space::SegmentQuery*>( data );
query->Space->onSegmentQuery( reinterpret_cast<Shape*>( shape->data ), t, tovect( n ), query );
}
static void RecieverPointQueryFunc( cpShape* shape, void* data ) {
Space::PointQuery* query = reinterpret_cast<Space::PointQuery*>( data );
query->Space->onPointQuery( reinterpret_cast<Shape*>( shape->data ), query );
}
cpBool Space::onCollisionBegin( Arbiter* arb, void* data ) {
cpHashValue hash = (cpHashValue)data;
// if ( NULL != data ) {
std::map<cpHashValue, CollisionHandler>::iterator it = mCollisions.find( hash );
CollisionHandler handler = static_cast<CollisionHandler>( it->second );
if ( it != mCollisions.end() && handler.begin ) {
return handler.begin( arb, this, handler.data );
}
//}
if ( mCollisionsDefault.begin ) {
return mCollisionsDefault.begin( arb, this, mCollisionsDefault.data );
}
return 1;
}
cpBool Space::onCollisionPreSolve( Arbiter* arb, void* data ) {
cpHashValue hash = (cpHashValue)data;
// if ( NULL != data ) {
std::map<cpHashValue, CollisionHandler>::iterator it = mCollisions.find( hash );
CollisionHandler handler = static_cast<CollisionHandler>( it->second );
if ( it != mCollisions.end() && handler.preSolve ) {
return handler.preSolve( arb, this, handler.data );
}
//}
if ( mCollisionsDefault.preSolve ) {
return mCollisionsDefault.preSolve( arb, this, mCollisionsDefault.data );
}
return 1;
}
void Space::onCollisionPostSolve( Arbiter* arb, void* data ) {
cpHashValue hash = (cpHashValue)data;
// if ( NULL != data ) {
std::map<cpHashValue, CollisionHandler>::iterator it = mCollisions.find( hash );
CollisionHandler handler = static_cast<CollisionHandler>( it->second );
if ( it != mCollisions.end() && handler.postSolve ) {
handler.postSolve( arb, this, handler.data );
return;
}
//}
if ( mCollisionsDefault.begin ) {
mCollisionsDefault.postSolve( arb, this, mCollisionsDefault.data );
}
}
void Space::onCollisionSeparate( Arbiter* arb, void* data ) {
cpHashValue hash = (cpHashValue)data;
// if ( NULL != data ) {
std::map<cpHashValue, CollisionHandler>::iterator it = mCollisions.find( hash );
CollisionHandler handler = static_cast<CollisionHandler>( it->second );
if ( it != mCollisions.end() && handler.separate ) {
handler.separate( arb, this, handler.data );
return;
}
//}
if ( mCollisionsDefault.begin ) {
mCollisionsDefault.separate( arb, this, mCollisionsDefault.data );
}
}
void Space::onPostStepCallback( void* obj, void* data ) {
PostStepCallbackCont* Cb = reinterpret_cast<PostStepCallbackCont*>( data );
if ( Cb->Callback ) {
Cb->Callback( this, obj, Cb->Data );
}
mPostStepCallbacks.remove( Cb );
eeSAFE_DELETE( Cb );
}
void Space::onBBQuery( Shape* shape, BBQuery* query ) {
if ( query->Func ) {
query->Func( shape, query->Data );
}
}
void Space::onSegmentQuery( Shape* shape, cpFloat t, cVect n, SegmentQuery* query ) {
if ( query->Func ) {
query->Func( shape, t, n, query->Data );
}
}
void Space::onPointQuery( Shape* shape, PointQuery* query ) {
if ( query->Func ) {
query->Func( shape, query->Data );
}
}
void Space::addCollisionHandler( const CollisionHandler& handler ) {
cpHashValue hash = CP_HASH_PAIR( handler.a, handler.b );
cpCollisionBeginFunc f1 = ( handler.begin ) ? &RecieverCollisionBeginFunc : NULL;
cpCollisionPreSolveFunc f2 = ( handler.preSolve ) ? &RecieverCollisionPreSolveFunc : NULL;
cpCollisionPostSolveFunc f3 = ( handler.postSolve ) ? &RecieverCollisionPostSolve : NULL;
cpCollisionSeparateFunc f4 = ( handler.separate ) ? &RecieverCollisionSeparateFunc : NULL;
cpSpaceAddCollisionHandler( mSpace, handler.a, handler.b, f1, f2, f3, f4, (void*)hash );
mCollisions.erase( hash );
mCollisions[hash] = handler;
}
void Space::removeCollisionHandler( cpCollisionType a, cpCollisionType b ) {
cpSpaceRemoveCollisionHandler( mSpace, a, b );
mCollisions.erase( CP_HASH_PAIR( a, b ) );
}
void Space::setDefaultCollisionHandler( const CollisionHandler& handler ) {
cpCollisionBeginFunc f1 = ( handler.begin ) ? &RecieverCollisionBeginFunc : NULL;
cpCollisionPreSolveFunc f2 = ( handler.preSolve ) ? &RecieverCollisionPreSolveFunc : NULL;
cpCollisionPostSolveFunc f3 = ( handler.postSolve ) ? &RecieverCollisionPostSolve : NULL;
cpCollisionSeparateFunc f4 = ( handler.separate ) ? &RecieverCollisionSeparateFunc : NULL;
cpSpaceSetDefaultCollisionHandler( mSpace, f1, f2, f3, f4, NULL );
mCollisionsDefault = handler;
}
void Space::addPostStepCallback( PostStepCallback postStep, void* obj, void* data ) {
PostStepCallbackCont* PostStepCb = eeNew( PostStepCallbackCont, () );
PostStepCb->Callback = postStep, PostStepCb->Data = data;
cpSpaceAddPostStepCallback( mSpace, &RecieverPostStepCallback, obj, PostStepCb );
mPostStepCallbacks.push_back( PostStepCb );
}
void Space::bbQuery( cBB bb, cpLayers layers, cpGroup group, BBQueryFunc func, void* data ) {
BBQuery tBBQuery;
tBBQuery.Space = this;
tBBQuery.Data = data;
tBBQuery.Func = func;
cpSpaceBBQuery( mSpace, tocpbb( bb ), layers, group, &RecieverBBQueryFunc,
reinterpret_cast<void*>( &tBBQuery ) );
}
void Space::segmentQuery( cVect start, cVect end, cpLayers layers, cpGroup group,
SegmentQueryFunc func, void* data ) {
SegmentQuery tSegmentQuery;
tSegmentQuery.Space = this;
tSegmentQuery.Data = data;
tSegmentQuery.Func = func;
cpSpaceSegmentQuery( mSpace, tocpv( start ), tocpv( end ), layers, group,
&RecieverSegmentQueryFunc, reinterpret_cast<void*>( &tSegmentQuery ) );
}
void Space::pointQuery( cVect point, cpLayers layers, cpGroup group, PointQueryFunc func,
void* data ) {
PointQuery tPointQuery;
tPointQuery.Space = this;
tPointQuery.Data = data;
tPointQuery.Func = func;
cpSpacePointQuery( mSpace, tocpv( point ), layers, group, &RecieverPointQueryFunc,
reinterpret_cast<void*>( &tPointQuery ) );
}
void Space::reindexShape( Shape* shape ) {
cpSpaceReindexShape( mSpace, shape->getShape() );
}
void Space::reindexShapesForBody( Body* body ) {
cpSpaceReindexShapesForBody( mSpace, body->getBody() );
}
void Space::reindexStatic() {
cpSpaceReindexStatic( mSpace );
}
void Space::useSpatialHash( cpFloat dim, int count ) {
cpSpaceUseSpatialHash( mSpace, dim, count );
}
static void SpaceBodyIteratorFunc( cpBody* body, void* data ) {
Space::BodyIterator* it = reinterpret_cast<Space::BodyIterator*>( data );
it->Space->onEachBody( reinterpret_cast<Body*>( body->data ), it );
}
void Space::eachBody( BodyIteratorFunc Func, void* data ) {
BodyIterator it( this, data, Func );
cpSpaceEachBody( mSpace, &SpaceBodyIteratorFunc, (void*)&it );
}
void Space::onEachBody( Body* Body, BodyIterator* it ) {
if ( it->Func ) {
it->Func( it->Space, Body, it->Data );
}
}
static void SpaceShapeIteratorFunc( cpShape* shape, void* data ) {
Space::ShapeIterator* it = reinterpret_cast<Space::ShapeIterator*>( data );
it->Space->onEachShape( reinterpret_cast<Shape*>( shape->data ), it );
}
void Space::eachShape( ShapeIteratorFunc Func, void* data ) {
ShapeIterator it( this, data, Func );
cpSpaceEachShape( mSpace, &SpaceShapeIteratorFunc, (void*)&it );
}
void Space::onEachShape( Shape* Shape, ShapeIterator* it ) {
if ( it->Func ) {
it->Func( it->Space, Shape, it->Data );
}
}
void Space::convertBodyToDynamic( Body* body, cpFloat mass, cpFloat moment ) {
cpSpaceConvertBodyToDynamic( mSpace, body->getBody(), mass, moment );
}
void Space::convertBodyToStatic( Body* body ) {
cpSpaceConvertBodyToStatic( mSpace, body->getBody() );
}
}} // namespace EE::Physics