issue #503, chippmunk library is upgraded from 5.1 to 5.3.4, which is usd in cocos2d-iphone 0.99.5 & 1.0.0-rc

This commit is contained in:
Walzer 2011-05-21 14:58:22 +08:00
parent 57a14e90c9
commit 948c6d750e
43 changed files with 1074 additions and 1034 deletions

View File

@ -26,7 +26,10 @@ src/cpHashSet.c \
src/cpPolyShape.c \ src/cpPolyShape.c \
src/cpShape.c \ src/cpShape.c \
src/cpSpace.c \ src/cpSpace.c \
src/cpSpaceComponent.c \
src/cpSpaceHash.c \ src/cpSpaceHash.c \
src/cpSpaceQuery.c \
src/cpSpaceStep.c \
src/cpVect.c src/cpVect.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/chipmunk LOCAL_C_INCLUDES := $(LOCAL_PATH)/include/chipmunk

View File

@ -26,6 +26,16 @@
extern "C" { extern "C" {
#endif #endif
#ifndef CP_ALLOW_PRIVATE_ACCESS
#define CP_ALLOW_PRIVATE_ACCESS 1
#endif
#if CP_ALLOW_PRIVATE_ACCESS == 1
#define CP_PRIVATE(symbol) symbol
#else
#define CP_PRIVATE(symbol) symbol##_private
#endif
void cpMessage(const char *message, const char *condition, const char *file, int line, int isError); void cpMessage(const char *message, const char *condition, const char *file, int line, int isError);
#ifdef NDEBUG #ifdef NDEBUG
#define cpAssertWarn(condition, message) #define cpAssertWarn(condition, message)
@ -41,42 +51,6 @@ void cpMessage(const char *message, const char *condition, const char *file, int
#include "chipmunk_types.h" #include "chipmunk_types.h"
static inline cpFloat
cpfmax(cpFloat a, cpFloat b)
{
return (a > b) ? a : b;
}
static inline cpFloat
cpfmin(cpFloat a, cpFloat b)
{
return (a < b) ? a : b;
}
static inline cpFloat
cpfabs(cpFloat n)
{
return (n < 0) ? -n : n;
}
static inline cpFloat
cpfclamp(cpFloat f, cpFloat min, cpFloat max)
{
return cpfmin(cpfmax(f, min), max);
}
static inline cpFloat
cpflerp(cpFloat f1, cpFloat f2, cpFloat t)
{
return f1*(1.0f - t) + f2*t;
}
static inline cpFloat
cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
{
return f1 + cpfclamp(f2 - f1, -d, d);
}
#ifndef INFINITY #ifndef INFINITY
#ifdef _MSC_VER #ifdef _MSC_VER
union MSVC_EVIL_FLOAT_HACK union MSVC_EVIL_FLOAT_HACK
@ -97,7 +71,7 @@ cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
#endif #endif
#endif #endif
// Maximum allocated size for various Chipmunk buffer sizes // Maximum allocated size for various Chipmunk buffers
#define CP_BUFFER_BYTES (32*1024) #define CP_BUFFER_BYTES (32*1024)
#define cpmalloc malloc #define cpmalloc malloc
@ -107,11 +81,11 @@ cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
#include "cpVect.h" #include "cpVect.h"
#include "cpBB.h" #include "cpBB.h"
#include "cpBody.h"
#include "cpArray.h" #include "cpArray.h"
#include "cpHashSet.h" #include "cpHashSet.h"
#include "cpSpaceHash.h" #include "cpSpaceHash.h"
#include "cpBody.h"
#include "cpShape.h" #include "cpShape.h"
#include "cpPolyShape.h" #include "cpPolyShape.h"
@ -125,24 +99,65 @@ cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
#define CP_HASH_COEF (3344921057ul) #define CP_HASH_COEF (3344921057ul)
#define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF) #define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF)
extern char *cpVersionString; extern const char *cpVersionString;
void cpInitChipmunk(void); void cpInitChipmunk(void);
// Calculate the moment of inertia for a circle, r1 and r2 are the inner and outer diameters. /**
// (A solid circle has an inner diameter of 0) Calculate the moment of inertia for a circle.
r1 and 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); cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);
// Calculate the moment of inertia for a line segment. (beveling radius not supported) /**
Calculate area of a hollow circle.
*/
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); cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b);
// Calculate the moment of inertia for a solid polygon shape. /**
cpFloat cpMomentForPoly(cpFloat m, int numVerts, cpVect *verts, cpVect offset); 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 box. /**
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.
*/
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); cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height);
#ifdef __cplusplus #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
#endif #endif

View File

@ -15,6 +15,7 @@
#endif #endif
MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv() MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv()
MAKE_REF(cpveql);
MAKE_REF(cpvadd); MAKE_REF(cpvadd);
MAKE_REF(cpvneg); MAKE_REF(cpvneg);
MAKE_REF(cpvsub); MAKE_REF(cpvsub);
@ -33,8 +34,8 @@ MAKE_REF(cpvnormalize_safe);
MAKE_REF(cpvclamp); MAKE_REF(cpvclamp);
MAKE_REF(cpvlerpconst); MAKE_REF(cpvlerpconst);
MAKE_REF(cpvdist); MAKE_REF(cpvdist);
MAKE_REF(cpvnear);
MAKE_REF(cpvdistsq); MAKE_REF(cpvdistsq);
MAKE_REF(cpvnear);
MAKE_REF(cpBBNew); MAKE_REF(cpBBNew);
MAKE_REF(cpBBintersects); MAKE_REF(cpBBintersects);
@ -46,10 +47,18 @@ MAKE_REF(cpBBexpand);
MAKE_REF(cpBodyWorld2Local); MAKE_REF(cpBodyWorld2Local);
MAKE_REF(cpBodyLocal2World); MAKE_REF(cpBodyLocal2World);
MAKE_REF(cpBodyApplyImpulse); MAKE_REF(cpBodyApplyImpulse);
MAKE_REF(cpBodyIsSleeping);
MAKE_REF(cpBodyIsRogue);
MAKE_REF(cpBodyKineticEnergy);
MAKE_REF(cpArbiterIsFirstContact); MAKE_REF(cpArbiterIsFirstContact);
MAKE_REF(cpArbiterGetShapes); MAKE_REF(cpArbiterGetShapes);
MAKE_REF(cpArbiterGetNormal); MAKE_REF(cpArbiterGetNormal);
MAKE_REF(cpArbiterGetPoint); MAKE_REF(cpArbiterGetPoint);
MAKE_REF(cpConstraintGetImpulse);
MAKE_REF(cpSegmentQueryHitPoint);
MAKE_REF(cpSegmentQueryHitDist);
#endif // _CHIPMUNK_FFI_H_ #endif // _CHIPMUNK_FFI_H_

View File

@ -5,12 +5,27 @@
#ifndef AIRPLAYUSECHIPMUNK #ifndef AIRPLAYUSECHIPMUNK
#import "TargetConditionals.h" #import "TargetConditionals.h"
#endif #endif
// dont' use CGPoints in cocos2d-x to make your code multi-platform
// #if (defined TARGET_OS_IPHONE) && (!defined CP_USE_CGPOINTS)
// #define CP_USE_CGPOINTS
// #endif
#ifdef CP_USE_CGPOINTS
#if TARGET_OS_IPHONE
#import <CoreGraphics/CGGeometry.h>
#elif TARGET_OS_MAC
#import <ApplicationServices/ApplicationServices.h>
#endif
#if defined(__LP64__) && __LP64__
#define CP_USE_DOUBLES 1
#else
#define CP_USE_DOUBLES 0
#endif
#endif #endif
// Use single precision floats on the iPhone. #ifndef CP_USE_DOUBLES
#if TARGET_OS_IPHONE==1
#define CP_USE_DOUBLES 0
#else
// use doubles by default for higher precision // use doubles by default for higher precision
#define CP_USE_DOUBLES 1 #define CP_USE_DOUBLES 1
#endif #endif
@ -41,17 +56,67 @@
#define cpfceil ceilf #define cpfceil ceilf
#endif #endif
//#if TARGET_OS_IPHONE static inline cpFloat
// CCPoints are structurally the same, and allow cpfmax(cpFloat a, cpFloat b)
// easy interoperability with other iPhone libraries {
//#import <CoreGraphics/CCGeometry.h> return (a > b) ? a : b;
//typedef CCPoint cpVect; }
//#else
static inline cpFloat
cpfmin(cpFloat a, cpFloat b)
{
return (a < b) ? a : b;
}
static inline cpFloat
cpfabs(cpFloat n)
{
return (n < 0) ? -n : n;
}
static inline cpFloat
cpfclamp(cpFloat f, cpFloat min, cpFloat max)
{
return cpfmin(cpfmax(f, min), max);
}
static inline cpFloat
cpflerp(cpFloat f1, cpFloat f2, cpFloat t)
{
return f1*(1.0f - t) + f2*t;
}
static inline cpFloat
cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
{
return f1 + cpfclamp(f2 - f1, -d, d);
}
// CGPoints are structurally the same, and allow
// easy interoperability with other Cocoa libraries
#ifdef CP_USE_CGPOINTS
typedef CGPoint cpVect;
#else
typedef struct cpVect{cpFloat x,y;} cpVect; typedef struct cpVect{cpFloat x,y;} cpVect;
//#endif #endif
typedef unsigned int cpHashValue; typedef unsigned int cpHashValue;
// Oh C, how we love to define our own boolean types to get compiler compatibility
#ifdef CP_BOOL_TYPE
typedef CP_BOOL_TYPE cpBool;
#else
typedef int cpBool;
#endif
#ifndef cpTrue
#define cpTrue 1
#endif
#ifndef cpFalse
#define cpFalse 0
#endif
#ifdef CP_DATA_POINTER_TYPE #ifdef CP_DATA_POINTER_TYPE
typedef CP_DATA_POINTER_TYPE cpDataPointer; typedef CP_DATA_POINTER_TYPE cpDataPointer;
#else #else
@ -76,6 +141,12 @@ typedef unsigned int cpHashValue;
typedef unsigned int cpLayers; typedef unsigned int cpLayers;
#endif #endif
#ifdef CP_TIMESTAMP_TYPE
typedef CP_TIMESTAMP_TYPE cpTimestamp;
#else
typedef unsigned int cpTimestamp;
#endif
#ifndef CP_NO_GROUP #ifndef CP_NO_GROUP
#define CP_NO_GROUP ((cpGroup)0) #define CP_NO_GROUP ((cpGroup)0)
#endif #endif

View File

@ -39,7 +39,7 @@ typedef struct cpConstraintClass {
typedef struct cpConstraint { typedef struct cpConstraint {
const cpConstraintClass *klass; CP_PRIVATE(const cpConstraintClass *klass);
cpBody *a, *b; cpBody *a, *b;
cpFloat maxForce; cpFloat maxForce;
@ -56,14 +56,26 @@ typedef cpConstraint cpJoint;
void cpConstraintDestroy(cpConstraint *constraint); void cpConstraintDestroy(cpConstraint *constraint);
void cpConstraintFree(cpConstraint *constraint); void cpConstraintFree(cpConstraint *constraint);
static inline void
cpConstraintActivateBodies(cpConstraint *constraint)
{
cpBody *a = constraint->a; if(a) cpBodyActivate(a);
cpBody *b = constraint->b; if(b) cpBodyActivate(b);
}
static inline cpFloat
cpConstraintGetImpulse(cpConstraint *constraint)
{
return constraint->CP_PRIVATE(klass)->getImpulse(constraint);
}
#define cpConstraintCheckCast(constraint, struct) \ #define cpConstraintCheckCast(constraint, struct) \
cpAssert(constraint->klass == struct##GetClass(), "Constraint is not a "#struct); cpAssert(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct);
#define CP_DefineConstraintGetter(struct, type, member, name) \ #define CP_DefineConstraintGetter(struct, type, member, name) \
static inline type \ static inline type \
struct##Get##name(cpConstraint *constraint){ \ struct##Get##name(const cpConstraint *constraint){ \
cpConstraintCheckCast(constraint, struct); \ cpConstraintCheckCast(constraint, struct); \
return ((struct *)constraint)->member; \ return ((struct *)constraint)->member; \
} \ } \
@ -72,6 +84,7 @@ struct##Get##name(cpConstraint *constraint){ \
static inline void \ static inline void \
struct##Set##name(cpConstraint *constraint, type value){ \ struct##Set##name(cpConstraint *constraint, type value){ \
cpConstraintCheckCast(constraint, struct); \ cpConstraintCheckCast(constraint, struct); \
cpConstraintActivateBodies(constraint); \
((struct *)constraint)->member = value; \ ((struct *)constraint)->member = value; \
} \ } \

View File

@ -30,8 +30,8 @@ typedef struct cpDampedRotarySpring {
cpFloat damping; cpFloat damping;
cpDampedRotarySpringTorqueFunc springTorqueFunc; cpDampedRotarySpringTorqueFunc springTorqueFunc;
cpFloat dt;
cpFloat target_wrn; cpFloat target_wrn;
cpFloat w_coef;
cpFloat iSum; cpFloat iSum;
} cpDampedRotarySpring; } cpDampedRotarySpring;

View File

@ -33,8 +33,8 @@ typedef struct cpDampedSpring {
cpFloat damping; cpFloat damping;
cpDampedSpringForceFunc springForceFunc; cpDampedSpringForceFunc springForceFunc;
cpFloat dt;
cpFloat target_vrn; cpFloat target_vrn;
cpFloat v_coef;
cpVect r1, r2; cpVect r1, r2;
cpFloat nMass; cpFloat nMass;

View File

@ -40,5 +40,9 @@ cpGrooveJoint *cpGrooveJointAlloc(void);
cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2); cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
cpConstraint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2); cpConstraint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
// TODO setters for the groove.
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA);
void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB);
void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value);
CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2); CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2);

View File

@ -25,6 +25,17 @@ void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass,
#define J_MAX(constraint, dt) (((cpConstraint *)constraint)->maxForce*(dt)) #define J_MAX(constraint, dt) (((cpConstraint *)constraint)->maxForce*(dt))
// Get valid body pointers and exit early if the bodies are idle
#define CONSTRAINT_BEGIN(constraint, a_var, b_var) \
cpBody *a_var, *b_var; { \
a_var = ((cpConstraint *)constraint)->a; \
b_var = ((cpConstraint *)constraint)->b; \
if( \
(cpBodyIsSleeping(a_var) || cpBodyIsStatic(a_var)) && \
(cpBodyIsSleeping(b_var) || cpBodyIsStatic(b_var)) \
) return; \
}
static inline cpVect static inline cpVect
relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){ relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){
cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w)); cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
@ -45,11 +56,18 @@ apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
cpBodyApplyImpulse(b, j, r2); cpBodyApplyImpulse(b, j, r2);
} }
static inline void
apply_bias_impulse(cpBody *body, cpVect j, cpVect r)
{
body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));
body->w_bias += body->i_inv*cpvcross(r, j);
}
static inline void static inline void
apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j) apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
{ {
cpBodyApplyBiasImpulse(a, cpvneg(j), r1); apply_bias_impulse(a, cpvneg(j), r1);
cpBodyApplyBiasImpulse(b, j, r2); apply_bias_impulse(b, j, r2);
} }
static inline cpVect static inline cpVect

View File

@ -31,73 +31,79 @@ extern cpFloat cp_collision_slop;
// Data structure for contact points. // Data structure for contact points.
typedef struct cpContact { typedef struct cpContact {
// Contact point and normal. // Contact point and normal.
cpVect p, n; cpVect CP_PRIVATE(p), CP_PRIVATE(n);
// Penetration distance. // Penetration distance.
cpFloat dist; CP_PRIVATE(cpFloat dist);
// Calculated by cpArbiterPreStep(). // Calculated by cpArbiterPreStep().
cpVect r1, r2; cpVect CP_PRIVATE(r1), CP_PRIVATE(r2);
cpFloat nMass, tMass, bounce; cpFloat CP_PRIVATE(nMass), CP_PRIVATE(tMass), CP_PRIVATE(bounce);
// Persistant contact information. // Persistant contact information.
cpFloat jnAcc, jtAcc, jBias; cpFloat CP_PRIVATE(jnAcc), CP_PRIVATE(jtAcc), CP_PRIVATE(jBias);
cpFloat bias; CP_PRIVATE(cpFloat bias);
// Hash value used to (mostly) uniquely identify a contact. // Hash value used to (mostly) uniquely identify a contact.
cpHashValue hash; CP_PRIVATE(cpHashValue hash);
} cpContact; } cpContact;
// Contacts are always allocated in groups. // Contacts are always allocated in groups.
cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash); cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash);
// Sum the contact impulses. (Can be used after cpSpaceStep() returns) // Sum the contact impulses. (Can be used after cpSpaceStep() returns)
cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts); cpVect CP_PRIVATE(cpContactsSumImpulses)(cpContact *contacts, int numContacts);
cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts); cpVect CP_PRIVATE(cpContactsSumImpulsesWithFriction)(cpContact *contacts, int numContacts);
#define CP_MAX_CONTACTS_PER_ARBITER 6
typedef enum cpArbiterState { typedef enum cpArbiterState {
cpArbiterStateNormal, cpArbiterStateNormal,
cpArbiterStateFirstColl, cpArbiterStateFirstColl,
cpArbiterStateIgnore, cpArbiterStateIgnore,
cpArbiterStateSleep,
cpArbiterStateCached,
} cpArbiterState; } cpArbiterState;
// Data structure for tracking collisions between shapes. // Data structure for tracking collisions between shapes.
typedef struct cpArbiter { typedef struct cpArbiter {
// Information on the contact points between the objects. // Information on the contact points between the objects.
int numContacts; CP_PRIVATE(int numContacts);
cpContact *contacts; CP_PRIVATE(cpContact *contacts);
// The two shapes involved in the collision. // The two shapes and bodies involved in the collision.
// These variables are NOT in the order defined by the collision handler. // These variables are NOT in the order defined by the collision handler.
cpShape *private_a, *private_b; // Using CP_ARBITER_GET_SHAPES and CP_ARBITER_GET_BODIES will save you from
// many headaches
cpShape CP_PRIVATE(*a), CP_PRIVATE(*b);
// Calculated before calling the pre-solve collision handler // Calculated before calling the pre-solve collision handler
// Override them with custom values if you want specialized behavior // Override them with custom values if you want specialized behavior
cpFloat e; CP_PRIVATE(cpFloat e);
cpFloat u; CP_PRIVATE(cpFloat u);
// Used for surface_v calculations, implementation may change // Used for surface_v calculations, implementation may change
cpVect surface_vr; CP_PRIVATE(cpVect surface_vr);
// Time stamp of the arbiter. (from cpSpace) // Time stamp of the arbiter. (from cpSpace)
int stamp; CP_PRIVATE(cpTimestamp stamp);
struct cpCollisionHandler *handler; CP_PRIVATE(struct cpCollisionHandler *handler);
// Are the shapes swapped in relation to the collision handler? // Are the shapes swapped in relation to the collision handler?
char swappedColl; CP_PRIVATE(cpBool swappedColl);
char state; CP_PRIVATE(cpArbiterState state);
} cpArbiter; } cpArbiter;
// Arbiters are allocated in large buffers by the space and don't require a destroy function // Arbiters are allocated in large buffers by the space and don't require a destroy function
cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b); cpArbiter* CP_PRIVATE(cpArbiterInit)(cpArbiter *arb, cpShape *a, cpShape *b);
// These functions are all intended to be used internally. // These functions are all intended to be used internally.
// Inject new contact points into the arbiter while preserving contact history. // Inject new contact points into the arbiter while preserving contact history.
void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, struct cpCollisionHandler *handler, cpShape *a, cpShape *b); void CP_PRIVATE(cpArbiterUpdate)(cpArbiter *arb, cpContact *contacts, int numContacts, struct cpCollisionHandler *handler, cpShape *a, cpShape *b);
// Precalculate values used by the solver. // Precalculate values used by the solver.
void cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv); void CP_PRIVATE(cpArbiterPreStep)(cpArbiter *arb, cpFloat dt_inv);
void cpArbiterApplyCachedImpulse(cpArbiter *arb); void CP_PRIVATE(cpArbiterApplyCachedImpulse)(cpArbiter *arb);
// Run an iteration of the solver on the arbiter. // Run an iteration of the solver on the arbiter.
void cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef); void CP_PRIVATE(cpArbiterApplyImpulse)(cpArbiter *arb, cpFloat eCoef);
// Arbiter Helper Functions // Arbiter Helper Functions
cpVect cpArbiterTotalImpulse(cpArbiter *arb); cpVect cpArbiterTotalImpulse(cpArbiter *arb);
@ -106,31 +112,77 @@ void cpArbiterIgnore(cpArbiter *arb);
static inline void static inline void
cpArbiterGetShapes(cpArbiter *arb, cpShape **a, cpShape **b) cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b)
{ {
if(arb->swappedColl){ if(arb->CP_PRIVATE(swappedColl)){
(*a) = arb->private_b, (*b) = arb->private_a; (*a) = arb->CP_PRIVATE(b), (*b) = arb->CP_PRIVATE(a);
} else { } else {
(*a) = arb->private_a, (*b) = arb->private_b; (*a) = arb->CP_PRIVATE(a), (*b) = arb->CP_PRIVATE(b);
} }
} }
#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b); #define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
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;
}
#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
static inline cpBool
cpArbiterIsFirstContact(const cpArbiter *arb)
{
return arb->CP_PRIVATE(state) == cpArbiterStateFirstColl;
}
static inline int static inline int
cpArbiterIsFirstContact(cpArbiter *arb) cpArbiterGetCount(const cpArbiter *arb)
{ {
return arb->state == cpArbiterStateFirstColl; return arb->CP_PRIVATE(numContacts);
} }
static inline cpVect static inline cpVect
cpArbiterGetNormal(cpArbiter *arb, int i) cpArbiterGetNormal(const cpArbiter *arb, int i)
{ {
cpVect n = arb->contacts[i].n; cpVect n = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(n);
return arb->swappedColl ? cpvneg(n) : n; return arb->CP_PRIVATE(swappedColl) ? cpvneg(n) : n;
} }
static inline cpVect static inline cpVect
cpArbiterGetPoint(cpArbiter *arb, int i) cpArbiterGetPoint(const cpArbiter *arb, int i)
{ {
return arb->contacts[i].p; return arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(p);
}
static inline cpFloat
cpArbiteGetDepth(const cpArbiter *arb, int i)
{
return arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist);
}
typedef struct cpContactPointSet {
int count;
struct {
cpVect point, normal;
cpFloat dist;
} points[CP_MAX_CONTACTS_PER_ARBITER];
} cpContactPointSet;
static inline cpContactPointSet
cpArbiterGetContactPointSet(const cpArbiter *arb)
{
cpContactPointSet set;
set.count = cpArbiterGetCount(arb);
int i;
for(i=0; i<set.count; i++){
set.points[i].point = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(p);
set.points[i].normal = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(n);
set.points[i].dist = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist);
}
return set;
} }

View File

@ -22,8 +22,9 @@
// NOTE: cpArray is rarely used and will probably go away. // NOTE: cpArray is rarely used and will probably go away.
typedef struct cpArray{ typedef struct cpArray{
int num, max; CP_PRIVATE(int num);
void **arr; CP_PRIVATE(int max);
CP_PRIVATE(void **arr);
} cpArray; } cpArray;
typedef void (*cpArrayIter)(void *ptr, void *data); typedef void (*cpArrayIter)(void *ptr, void *data);
@ -42,5 +43,7 @@ void *cpArrayPop(cpArray *arr);
void cpArrayDeleteIndex(cpArray *arr, int idx); void cpArrayDeleteIndex(cpArray *arr, int idx);
void cpArrayDeleteObj(cpArray *arr, void *obj); void cpArrayDeleteObj(cpArray *arr, void *obj);
void cpArrayAppend(cpArray *arr, cpArray *other);
void cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data); void cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data);
int cpArrayContains(cpArray *arr, void *ptr); cpBool cpArrayContains(cpArray *arr, void *ptr);

View File

@ -31,19 +31,19 @@ cpBBNew(const cpFloat l, const cpFloat b,
return bb; return bb;
} }
static inline int static inline cpBool
cpBBintersects(const cpBB a, const cpBB b) cpBBintersects(const cpBB a, const cpBB b)
{ {
return (a.l<=b.r && b.l<=a.r && a.b<=b.t && b.b<=a.t); return (a.l<=b.r && b.l<=a.r && a.b<=b.t && b.b<=a.t);
} }
static inline int static inline cpBool
cpBBcontainsBB(const cpBB bb, const cpBB other) cpBBcontainsBB(const cpBB bb, const cpBB other)
{ {
return (bb.l < other.l && bb.r > other.r && bb.b < other.b && bb.t > other.t); return (bb.l < other.l && bb.r > other.r && bb.b < other.b && bb.t > other.t);
} }
static inline int static inline cpBool
cpBBcontainsVect(const cpBB bb, const cpVect v) cpBBcontainsVect(const cpBB bb, const cpVect v)
{ {
return (bb.l < v.x && bb.r > v.x && bb.b < v.y && bb.t > v.y); return (bb.l < v.x && bb.r > v.x && bb.b < v.y && bb.t > v.y);

View File

@ -20,14 +20,27 @@
*/ */
struct cpBody; struct cpBody;
struct cpShape;
struct cpSpace;
typedef void (*cpBodyVelocityFunc)(struct cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt); typedef void (*cpBodyVelocityFunc)(struct cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
typedef void (*cpBodyPositionFunc)(struct cpBody *body, cpFloat dt); typedef void (*cpBodyPositionFunc)(struct cpBody *body, cpFloat dt);
extern cpBodyVelocityFunc cpBodyUpdateVelocityDefault; extern cpBodyVelocityFunc cpBodyUpdateVelocityDefault;
extern cpBodyPositionFunc cpBodyUpdatePositionDefault; extern cpBodyPositionFunc cpBodyUpdatePositionDefault;
// Structure to hold information about the contact graph components
// when putting groups of objects to sleep.
// No interesting user accessible fields.
typedef struct cpComponentNode {
struct cpBody *parent;
struct cpBody *next;
int rank;
cpFloat idleTime;
} cpComponentNode;
typedef struct cpBody{ typedef struct cpBody{
// *** Integration Functions.ntoehu // *** Integration Functions.
// Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity) // Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)
cpBodyVelocityFunc velocity_func; cpBodyVelocityFunc velocity_func;
@ -63,16 +76,26 @@ typedef struct cpBody{
// User defined data pointer. // User defined data pointer.
cpDataPointer data; cpDataPointer data;
// *** Other Fields
// Maximum velocities this body can move at after integrating velocity // Maximum velocities this body can move at after integrating velocity
cpFloat v_limit, w_limit; cpFloat v_limit, w_limit;
// *** Internally Used Fields // *** Internally Used Fields
// Velocity bias values used when solving penetrations and correcting constraints. // Velocity bias values used when solving penetrations and correcting constraints.
cpVect v_bias; CP_PRIVATE(cpVect v_bias);
cpFloat w_bias; CP_PRIVATE(cpFloat w_bias);
// int active; // Space this body has been added to
CP_PRIVATE(struct cpSpace *space);
// Pointer to the shape list.
// Shapes form a linked list using cpShape.next when added to a space.
CP_PRIVATE(struct cpShape *shapesList);
// Used by cpSpaceStep() to store contact graph information.
CP_PRIVATE(cpComponentNode node);
} cpBody; } cpBody;
// Basic allocation/destruction functions // Basic allocation/destruction functions
@ -80,11 +103,48 @@ cpBody *cpBodyAlloc(void);
cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i); cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
cpBody *cpBodyNew(cpFloat m, cpFloat i); cpBody *cpBodyNew(cpFloat m, cpFloat i);
cpBody *cpBodyInitStatic(cpBody *body);
cpBody *cpBodyNewStatic();
void cpBodyDestroy(cpBody *body); void cpBodyDestroy(cpBody *body);
void cpBodyFree(cpBody *body); void cpBodyFree(cpBody *body);
#define CP_DefineBodyGetter(type, member, name) static inline type cpBodyGet##name(cpBody *body){return body->member;} // Wake up a sleeping or idle body. (defined in cpSpace.c)
#define CP_DefineBodySetter(type, member, name) static inline void cpBodySet##name(cpBody *body, type value){body->member = value;} void cpBodyActivate(cpBody *body);
// Force a body to sleep;
// defined in cpSpaceComponent.c
void cpBodySleep(cpBody *body);
void cpBodySleepWithGroup(cpBody *body, cpBody *group);
static inline cpBool
cpBodyIsSleeping(const cpBody *body)
{
return (CP_PRIVATE(body->node).next != ((cpBody*)0));
}
static inline cpBool
cpBodyIsStatic(const cpBody *body)
{
return CP_PRIVATE(body->node).idleTime == INFINITY;
}
static inline cpBool
cpBodyIsRogue(const cpBody *body)
{
return (body->CP_PRIVATE(space) == ((struct cpSpace*)0));
}
#define CP_DefineBodyGetter(type, member, name) \
static inline type cpBodyGet##name(const cpBody *body){return body->member;}
#define CP_DefineBodySetter(type, member, name) \
static inline void \
cpBodySet##name(cpBody *body, const type value){ \
cpBodyActivate(body); \
body->member = value; \
} \
#define CP_DefineBodyProperty(type, member, name) \ #define CP_DefineBodyProperty(type, member, name) \
CP_DefineBodyGetter(type, member, name) \ CP_DefineBodyGetter(type, member, name) \
@ -120,41 +180,40 @@ void cpBodyUpdatePosition(cpBody *body, cpFloat dt);
// Convert body local to world coordinates // Convert body local to world coordinates
static inline cpVect static inline cpVect
cpBodyLocal2World(cpBody *body, cpVect v) cpBodyLocal2World(const cpBody *body, const cpVect v)
{ {
return cpvadd(body->p, cpvrotate(v, body->rot)); return cpvadd(body->p, cpvrotate(v, body->rot));
} }
// Convert world to body local coordinates // Convert world to body local coordinates
static inline cpVect static inline cpVect
cpBodyWorld2Local(cpBody *body, cpVect v) cpBodyWorld2Local(const cpBody *body, const cpVect v)
{ {
return cpvunrotate(cpvsub(v, body->p), body->rot); return cpvunrotate(cpvsub(v, body->p), body->rot);
} }
// Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates). // Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
static inline void static inline void
cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r) cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r)
{ {
body->v = cpvadd(body->v, cpvmult(j, body->m_inv)); body->v = cpvadd(body->v, cpvmult(j, body->m_inv));
body->w += body->i_inv*cpvcross(r, j); body->w += body->i_inv*cpvcross(r, j);
} }
// Not intended for external use. Used by cpArbiter.c and cpConstraint.c.
static inline void
cpBodyApplyBiasImpulse(cpBody *body, cpVect j, cpVect r)
{
body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));
body->w_bias += body->i_inv*cpvcross(r, j);
}
// Zero the forces on a body. // Zero the forces on a body.
void cpBodyResetForces(cpBody *body); void cpBodyResetForces(cpBody *body);
// Apply a force (in world coordinates) to a body at a point relative to the center of gravity (also in world coordinates). // Apply a force (in world coordinates) to a body at a point relative to the center of gravity (also in world coordinates).
void cpBodyApplyForce(cpBody *body, cpVect f, cpVect r); void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r);
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);
}
// Apply a damped spring force between two bodies. // Apply a damped spring force between two bodies.
// Warning: Large damping values can be unstable. Use a cpDampedSpring constraint for this instead. // Warning: Large damping values can be unstable. Use a cpDampedSpring constraint for this instead.
void cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt); void cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);
//int cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max);

View File

@ -19,5 +19,10 @@
* SOFTWARE. * SOFTWARE.
*/ */
// Collides two cpShape structures. (this function is lonely :( ) //TODO delete this header?
int cpCollideShapes(cpShape *a, cpShape *b, cpContact *arr);
// Collides two cpShape structures.
// Returns the number of contact points added to arr
// which should be at least CP_MAX_CONTACTS_PER_ARBITER in length.
// This function is very lonely in this header :(
int cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr);

View File

@ -25,39 +25,36 @@
// cpHashSetBin's form the linked lists in the chained hash table. // cpHashSetBin's form the linked lists in the chained hash table.
typedef struct cpHashSetBin { typedef struct cpHashSetBin {
// Pointer to the element. // Pointer to the element.
void *elt; CP_PRIVATE(void *elt);
// Hash value of the element. // Hash value of the element.
cpHashValue hash; CP_PRIVATE(cpHashValue hash);
// Next element in the chain. // Next element in the chain.
struct cpHashSetBin *next; CP_PRIVATE(struct cpHashSetBin *next);
} cpHashSetBin; } cpHashSetBin;
// Equality function. Returns true if ptr is equal to elt. // Equality function. Returns true if ptr is equal to elt.
typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt); typedef cpBool (*cpHashSetEqlFunc)(void *ptr, void *elt);
// Used by cpHashSetInsert(). Called to transform the ptr into an element. // Used by cpHashSetInsert(). Called to transform the ptr into an element.
typedef void *(*cpHashSetTransFunc)(void *ptr, void *data); typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
// Iterator function for a hashset.
typedef void (*cpHashSetIterFunc)(void *elt, void *data);
// Filter function. Returns false if elt should be dropped.
typedef int (*cpHashSetFilterFunc)(void *elt, void *data);
typedef struct cpHashSet { typedef struct cpHashSet {
// Number of elements stored in the table. // Number of elements stored in the table.
int entries; CP_PRIVATE(int entries);
// Number of cells in the table. // Number of cells in the table.
int size; CP_PRIVATE(int size);
cpHashSetEqlFunc eql; CP_PRIVATE(cpHashSetEqlFunc eql);
cpHashSetTransFunc trans; CP_PRIVATE(cpHashSetTransFunc trans);
// Default value returned by cpHashSetFind() when no element is found. // Default value returned by cpHashSetFind() when no element is found.
// Defaults to NULL. // Defaults to NULL.
void *default_value; CP_PRIVATE(void *default_value);
// The table and recycled bins // The table and recycled bins
cpHashSetBin **table, *pooledBins; CP_PRIVATE(cpHashSetBin **table);
CP_PRIVATE(cpHashSetBin *pooledBins);
cpArray *allocatedBuffers; CP_PRIVATE(cpArray *allocatedBuffers);
} cpHashSet; } cpHashSet;
// Basic allocation/destruction functions. // Basic allocation/destruction functions.
@ -77,6 +74,9 @@ void *cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr);
void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr); void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr);
// Iterate over a hashset. // Iterate over a hashset.
typedef void (*cpHashSetIterFunc)(void *elt, void *data);
void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data); void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data);
// Iterate over a hashset, retain .
// Iterate over a hashset, drop the element if the func returns false.
typedef cpBool (*cpHashSetFilterFunc)(void *elt, void *data);
void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data); void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data);

View File

@ -29,16 +29,16 @@ typedef struct cpPolyShapeAxis{
// Convex polygon shape structure. // Convex polygon shape structure.
typedef struct cpPolyShape{ typedef struct cpPolyShape{
cpShape shape; CP_PRIVATE(cpShape shape);
// Vertex and axis lists. // Vertex and axis lists.
int numVerts; CP_PRIVATE(int numVerts);
cpVect *verts; CP_PRIVATE(cpVect *verts);
cpPolyShapeAxis *axes; CP_PRIVATE(cpPolyShapeAxis *axes);
// Transformed vertex and axis lists. // Transformed vertex and axis lists.
cpVect *tVerts; CP_PRIVATE(cpVect *tVerts);
cpPolyShapeAxis *tAxes; CP_PRIVATE(cpPolyShapeAxis *tAxes);
} cpPolyShape; } cpPolyShape;
// Basic allocation functions. // Basic allocation functions.
@ -50,7 +50,7 @@ cpPolyShape *cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFl
cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height); cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
// Check that a set of vertexes has a correct winding and that they are convex // Check that a set of vertexes has a correct winding and that they are convex
int cpPolyValidate(cpVect *verts, int numVerts); cpBool cpPolyValidate(const cpVect *verts, const int numVerts);
int cpPolyShapeGetNumVerts(cpShape *shape); int cpPolyShapeGetNumVerts(cpShape *shape);
cpVect cpPolyShapeGetVert(cpShape *shape, int idx); cpVect cpPolyShapeGetVert(cpShape *shape, int idx);
@ -61,43 +61,43 @@ cpVect cpPolyShapeGetVert(cpShape *shape, int idx);
static inline cpFloat static inline cpFloat
cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d) cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
{ {
cpVect *verts = poly->tVerts; cpVect *verts = poly->CP_PRIVATE(tVerts);
cpFloat min = cpvdot(n, verts[0]); cpFloat min = cpvdot(n, verts[0]);
int i; int i;
for(i=1; i<poly->numVerts; i++) for(i=1; i<poly->CP_PRIVATE(numVerts); i++)
min = cpfmin(min, cpvdot(n, verts[i])); min = cpfmin(min, cpvdot(n, verts[i]));
return min - d; return min - d;
} }
// Returns true if the polygon contains the vertex. // Returns true if the polygon contains the vertex.
static inline int static inline cpBool
cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v) cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
{ {
cpPolyShapeAxis *axes = poly->tAxes; cpPolyShapeAxis *axes = poly->CP_PRIVATE(tAxes);
int i; int i;
for(i=0; i<poly->numVerts; i++){ for(i=0; i<poly->CP_PRIVATE(numVerts); i++){
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d; cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
if(dist > 0.0f) return 0; if(dist > 0.0f) return cpFalse;
} }
return 1; return cpTrue;
} }
// Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal. // Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.
static inline int static inline cpBool
cpPolyShapeContainsVertPartial(cpPolyShape *poly, cpVect v, cpVect n) cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n)
{ {
cpPolyShapeAxis *axes = poly->tAxes; cpPolyShapeAxis *axes = poly->CP_PRIVATE(tAxes);
int i; int i;
for(i=0; i<poly->numVerts; i++){ for(i=0; i<poly->CP_PRIVATE(numVerts); i++){
if(cpvdot(axes[i].n, n) < 0.0f) continue; if(cpvdot(axes[i].n, n) < 0.0f) continue;
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d; cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
if(dist > 0.0f) return 0; if(dist > 0.0f) return cpFalse;
} }
return 1; return cpTrue;
} }

View File

@ -47,7 +47,7 @@ typedef struct cpShapeClass {
void (*destroy)(struct cpShape *shape); void (*destroy)(struct cpShape *shape);
// called by cpShapePointQuery(). // called by cpShapePointQuery().
int (*pointQuery)(struct cpShape *shape, cpVect p); cpBool (*pointQuery)(struct cpShape *shape, cpVect p);
// called by cpShapeSegmentQuery() // called by cpShapeSegmentQuery()
void (*segmentQuery)(struct cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info); void (*segmentQuery)(struct cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
@ -56,7 +56,7 @@ typedef struct cpShapeClass {
// Basic shape struct that the others inherit from. // Basic shape struct that the others inherit from.
typedef struct cpShape{ typedef struct cpShape{
// The "class" of a shape as defined above // The "class" of a shape as defined above
const cpShapeClass *klass; CP_PRIVATE(const cpShapeClass *klass);
// cpBody that the shape is attached to. // cpBody that the shape is attached to.
cpBody *body; cpBody *body;
@ -65,7 +65,7 @@ typedef struct cpShape{
cpBB bb; cpBB bb;
// Sensors invoke callbacks, but do not generate collisions // Sensors invoke callbacks, but do not generate collisions
int sensor; cpBool sensor;
// *** Surface properties. // *** Surface properties.
@ -90,8 +90,11 @@ typedef struct cpShape{
// *** Internally Used Fields // *** Internally Used Fields
// Shapes form a linked list when added to space on a non-NULL body
CP_PRIVATE(struct cpShape *next);
// Unique id used as the hash value. // Unique id used as the hash value.
cpHashValue hashid; CP_PRIVATE(cpHashValue hashid);
} cpShape; } cpShape;
// Low level shape initialization func. // Low level shape initialization func.
@ -105,21 +108,21 @@ void cpShapeFree(cpShape *shape);
cpBB cpShapeCacheBB(cpShape *shape); cpBB cpShapeCacheBB(cpShape *shape);
// Test if a point lies within a shape. // Test if a point lies within a shape.
int cpShapePointQuery(cpShape *shape, cpVect p); cpBool cpShapePointQuery(cpShape *shape, cpVect p);
#define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(cpShape *shape) #define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(cpShape *shape)
// Circle shape structure. // Circle shape structure.
typedef struct cpCircleShape{ typedef struct cpCircleShape{
cpShape shape; CP_PRIVATE(cpShape shape);
// Center in body space coordinates // Center in body space coordinates
cpVect c; CP_PRIVATE(cpVect c);
// Radius. // Radius.
cpFloat r; CP_PRIVATE(cpFloat r);
// Transformed center. (world space coordinates) // Transformed center. (world space coordinates)
cpVect tc; CP_PRIVATE(cpVect tc);
} cpCircleShape; } cpCircleShape;
// Basic allocation functions for cpCircleShape. // Basic allocation functions for cpCircleShape.
@ -132,15 +135,15 @@ CP_DeclareShapeGetter(cpCircleShape, cpFloat, Radius);
// Segment shape structure. // Segment shape structure.
typedef struct cpSegmentShape{ typedef struct cpSegmentShape{
cpShape shape; CP_PRIVATE(cpShape shape);
// Endpoints and normal of the segment. (body space coordinates) // Endpoints and normal of the segment. (body space coordinates)
cpVect a, b, n; cpVect CP_PRIVATE(a), CP_PRIVATE(b), CP_PRIVATE(n);
// Radius of the segment. (Thickness) // Radius of the segment. (Thickness)
cpFloat r; cpFloat CP_PRIVATE(r);
// Transformed endpoints and normal. (world space coordinates) // Transformed endpoints and normal. (world space coordinates)
cpVect ta, tb, tn; cpVect CP_PRIVATE(ta), CP_PRIVATE(tb), CP_PRIVATE(tn);
} cpSegmentShape; } cpSegmentShape;
// Basic allocation functions for cpSegmentShape. // Basic allocation functions for cpSegmentShape.
@ -159,16 +162,16 @@ void cpResetShapeIdCounter(void);
// Directed segment queries against individual shapes. // Directed segment queries against individual shapes.
void cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info); void cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info);
int cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info); cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
static inline cpVect static inline cpVect
cpSegmentQueryHitPoint(cpVect start, cpVect end, cpSegmentQueryInfo info) cpSegmentQueryHitPoint(const cpVect start, const cpVect end, const cpSegmentQueryInfo info)
{ {
return cpvlerp(start, end, info.t); return cpvlerp(start, end, info.t);
} }
static inline cpFloat static inline cpFloat
cpSegmentQueryHitDist(cpVect start, cpVect end, cpSegmentQueryInfo info) cpSegmentQueryHitDist(const cpVect start, const cpVect end, const cpSegmentQueryInfo info)
{ {
return cpvdist(start, end)*info.t; return cpvdist(start, end)*info.t;
} }

View File

@ -22,11 +22,11 @@
struct cpSpace; struct cpSpace;
// Number of frames that contact information should persist. // Number of frames that contact information should persist.
extern int cp_contact_persistence; extern cpTimestamp cp_contact_persistence;
// User collision handler function types. // User collision handler function types.
typedef int (*cpCollisionBeginFunc)(cpArbiter *arb, struct cpSpace *space, void *data); typedef cpBool (*cpCollisionBeginFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
typedef int (*cpCollisionPreSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data); typedef cpBool (*cpCollisionPreSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data); typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, struct cpSpace *space, void *data); typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
@ -42,9 +42,8 @@ typedef struct cpCollisionHandler {
void *data; void *data;
} cpCollisionHandler; } cpCollisionHandler;
#define CP_MAX_CONTACTS_PER_ARBITER 6
typedef struct cpContactBufferHeader { typedef struct cpContactBufferHeader {
int stamp; cpTimestamp stamp;
struct cpContactBufferHeader *next; struct cpContactBufferHeader *next;
unsigned int numContacts; unsigned int numContacts;
} cpContactBufferHeader; } cpContactBufferHeader;
@ -64,44 +63,62 @@ typedef struct cpSpace{
// Default damping to supply when integrating rigid body motions. // Default damping to supply when integrating rigid body motions.
cpFloat damping; 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
// The default value of INFINITY disables the sleeping algorithm.
cpFloat sleepTimeThreshold;
// *** Internally Used Fields // *** Internally Used Fields
// When the space is locked, you should not add or remove objects; // When the space lock count is non zero you cannot add or remove objects
int locked; CP_PRIVATE(int locked);
// Time stamp. Is incremented on every call to cpSpaceStep(). // Time stamp. Is incremented on every call to cpSpaceStep().
int stamp; CP_PRIVATE(cpTimestamp stamp);
// The static and active shape spatial hashes. // The static and active shape spatial hashes.
cpSpaceHash *staticShapes; CP_PRIVATE(cpSpaceHash *staticShapes);
cpSpaceHash *activeShapes; CP_PRIVATE(cpSpaceHash *activeShapes);
// List of bodies in the system. // List of bodies in the system.
cpArray *bodies; CP_PRIVATE(cpArray *bodies);
// List of groups of sleeping bodies.
CP_PRIVATE(cpArray *sleepingComponents);
// List of bodies that have been flagged to be awoken.
CP_PRIVATE(cpArray *rousedBodies);
// List of active arbiters for the impulse solver. // List of active arbiters for the impulse solver.
cpArray *arbiters, *pooledArbiters; CP_PRIVATE(cpArray *arbiters);
CP_PRIVATE(cpArray *pooledArbiters);
// Linked list ring of contact buffers. // Linked list ring of contact buffers.
// Head is the current buffer. Tail is the oldest buffer. // Head is the newest buffer, and each buffer points to a newer buffer.
// The list points in the direction of tail->head. // Head wraps around and points to the oldest (tail) buffer.
cpContactBufferHeader *contactBuffersHead, *contactBuffersTail; CP_PRIVATE(cpContactBufferHeader *contactBuffersHead);
CP_PRIVATE(cpContactBufferHeader *_contactBuffersTail_Deprecated);
// List of buffers to be free()ed when destroying the space. // List of buffers to be free()ed when destroying the space.
cpArray *allocatedBuffers; CP_PRIVATE(cpArray *allocatedBuffers);
// Persistant contact set. // Persistant contact set.
cpHashSet *contactSet; CP_PRIVATE(cpHashSet *contactSet);
// List of constraints in the system. // List of constraints in the system.
cpArray *constraints; CP_PRIVATE(cpArray *constraints);
// Set of collisionpair functions. // Set of collisionpair functions.
cpHashSet *collFuncSet; CP_PRIVATE(cpHashSet *collFuncSet);
// Default collision handler. // Default collision handler.
cpCollisionHandler defaultHandler; CP_PRIVATE(cpCollisionHandler defaultHandler);
cpHashSet *postStepCallbacks; CP_PRIVATE(cpHashSet *postStepCallbacks);
cpBody staticBody;
} cpSpace; } cpSpace;
// Basic allocation/destruction functions. // Basic allocation/destruction functions.
@ -159,13 +176,20 @@ cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, c
// Segment query callback function // Segment query callback function
typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data); typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data);
int cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data); void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data);
cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out); cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out);
// BB query callback function // BB query callback function
typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data); typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data);
void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data); void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data);
// Shape query callback function
typedef void (*cpSpaceShapeQueryFunc)(cpShape *shape, cpContactPointSet *points, void *data);
cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data);
void cpSpaceActivateShapesTouchingShape(cpSpace *space, cpShape *shape);
// Iterator function for iterating the bodies in a space. // Iterator function for iterating the bodies in a space.
typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data); typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
@ -176,5 +200,7 @@ void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);
void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count); void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);
void cpSpaceRehashStatic(cpSpace *space); void cpSpaceRehashStatic(cpSpace *space);
void cpSpaceRehashShape(cpSpace *space, cpShape *shape);
// Update the space. // Update the space.
void cpSpaceStep(cpSpace *space, cpFloat dt); void cpSpaceStep(cpSpace *space, cpFloat dt);

View File

@ -30,7 +30,7 @@ typedef struct cpHandle{
int retain; int retain;
// Query stamp. Used to make sure two objects // Query stamp. Used to make sure two objects
// aren't identified twice in the same query. // aren't identified twice in the same query.
int stamp; cpTimestamp stamp;
} cpHandle; } cpHandle;
// Linked list element for in the chains. // Linked list element for in the chains.
@ -44,25 +44,26 @@ typedef cpBB (*cpSpaceHashBBFunc)(void *obj);
typedef struct cpSpaceHash{ typedef struct cpSpaceHash{
// Number of cells in the table. // Number of cells in the table.
int numcells; CP_PRIVATE(int numcells);
// Dimentions of the cells. // Dimentions of the cells.
cpFloat celldim; CP_PRIVATE(cpFloat celldim);
// BBox callback. // BBox callback.
cpSpaceHashBBFunc bbfunc; CP_PRIVATE(cpSpaceHashBBFunc bbfunc);
// Hashset of the handles and the recycled ones. // Hashset of the handles and the recycled ones.
cpHashSet *handleSet; CP_PRIVATE(cpHashSet *handleSet);
cpArray *pooledHandles; CP_PRIVATE(cpArray *pooledHandles);
// The table and the recycled bins. // The table and the recycled bins.
cpSpaceHashBin **table, *pooledBins; CP_PRIVATE(cpSpaceHashBin **table);
CP_PRIVATE(cpSpaceHashBin *pooledBins);
// list of buffers to free on destruction. // list of buffers to free on destruction.
cpArray *allocatedBuffers; CP_PRIVATE(cpArray *allocatedBuffers);
// Incremented on each query. See cpHandle.stamp. // Incremented on each query. See cpHandle.stamp.
int stamp; CP_PRIVATE(cpTimestamp stamp);
} cpSpaceHash; } cpSpaceHash;
//Basic allocation/destruction functions. //Basic allocation/destruction functions.
@ -77,7 +78,7 @@ void cpSpaceHashFree(cpSpaceHash *hash);
void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells); void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);
// Add an object to the hash. // Add an object to the hash.
void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB bb); void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB _deprecated_ignored);
// Remove an object from the hash. // Remove an object from the hash.
void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue id); void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue id);

View File

@ -19,8 +19,10 @@
* SOFTWARE. * SOFTWARE.
*/ */
static const cpVect cpvzero={0.0f,0.0f}; /// Constant for the zero vector.
static const cpVect cpvzero = {0.0f,0.0f};
/// Convenience constructor for cpVect structs.
static inline cpVect static inline cpVect
cpv(const cpFloat x, const cpFloat y) cpv(const cpFloat x, const cpFloat y)
{ {
@ -29,128 +31,176 @@ cpv(const cpFloat x, const cpFloat y)
} }
// non-inlined functions // non-inlined functions
cpFloat cpvlength(const cpVect v);
cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t);
cpVect cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a);
cpVect cpvforangle(const cpFloat a); // convert radians to a normalized vector
cpFloat cpvtoangle(const cpVect v); // convert a vector to radians
char *cpvstr(const cpVect v); // get a string representation of a vector
/// Returns the length of v.
cpFloat cpvlength(const cpVect 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 the unit length vector for the given angle (in radians).
cpVect cpvforangle(const cpFloat a);
/// Returns the angular direction v is pointing in (in radians).
cpFloat cpvtoangle(const cpVect v);
/**
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 static inline cpVect
cpvadd(const cpVect v1, const cpVect v2) cpvadd(const cpVect v1, const cpVect v2)
{ {
return cpv(v1.x + v2.x, v1.y + v2.y); return cpv(v1.x + v2.x, v1.y + v2.y);
} }
/// Negate a vector.
static inline cpVect static inline cpVect
cpvneg(const cpVect v) cpvneg(const cpVect v)
{ {
return cpv(-v.x, -v.y); return cpv(-v.x, -v.y);
} }
/// Subtract two vectors.
static inline cpVect static inline cpVect
cpvsub(const cpVect v1, const cpVect v2) cpvsub(const cpVect v1, const cpVect v2)
{ {
return cpv(v1.x - v2.x, v1.y - v2.y); return cpv(v1.x - v2.x, v1.y - v2.y);
} }
/// Scalar multiplication.
static inline cpVect static inline cpVect
cpvmult(const cpVect v, const cpFloat s) cpvmult(const cpVect v, const cpFloat s)
{ {
return cpv(v.x*s, v.y*s); return cpv(v.x*s, v.y*s);
} }
/// Vector dot product.
static inline cpFloat static inline cpFloat
cpvdot(const cpVect v1, const cpVect v2) cpvdot(const cpVect v1, const cpVect v2)
{ {
return v1.x*v2.x + v1.y*v2.y; 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 static inline cpFloat
cpvcross(const cpVect v1, const cpVect v2) cpvcross(const cpVect v1, const cpVect v2)
{ {
return v1.x*v2.y - v1.y*v2.x; return v1.x*v2.y - v1.y*v2.x;
} }
/// Returns a perpendicular vector. (90 degree rotation)
static inline cpVect static inline cpVect
cpvperp(const cpVect v) cpvperp(const cpVect v)
{ {
return cpv(-v.y, v.x); return cpv(-v.y, v.x);
} }
/// Returns a perpendicular vector. (-90 degree rotation)
static inline cpVect static inline cpVect
cpvrperp(const cpVect v) cpvrperp(const cpVect v)
{ {
return cpv(v.y, -v.x); return cpv(v.y, -v.x);
} }
/// Returns the vector projection of v1 onto v2.
static inline cpVect static inline cpVect
cpvproject(const cpVect v1, const cpVect v2) cpvproject(const cpVect v1, const cpVect v2)
{ {
return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2)); return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
} }
/// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
static inline cpVect static inline cpVect
cpvrotate(const cpVect v1, const cpVect v2) 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); return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);
} }
/// Inverse of cpvrotate().
static inline cpVect static inline cpVect
cpvunrotate(const cpVect v1, const cpVect v2) 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); 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 static inline cpFloat
cpvlengthsq(const cpVect v) cpvlengthsq(const cpVect v)
{ {
return cpvdot(v, v); return cpvdot(v, v);
} }
/// Linearly interpolate between v1 and v2.
static inline cpVect static inline cpVect
cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t) cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)
{ {
return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t)); return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));
} }
/// Returns a normalized copy of v.
static inline cpVect static inline cpVect
cpvnormalize(const cpVect v) cpvnormalize(const cpVect v)
{ {
return cpvmult(v, 1.0f/cpvlength(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 static inline cpVect
cpvnormalize_safe(const cpVect v) cpvnormalize_safe(const cpVect v)
{ {
return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v)); return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v));
} }
/// Clamp v to length len.
static inline cpVect static inline cpVect
cpvclamp(const cpVect v, const cpFloat len) cpvclamp(const cpVect v, const cpFloat len)
{ {
return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v; return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
} }
/// Linearly interpolate between v1 towards v2 by distance d.
static inline cpVect static inline cpVect
cpvlerpconst(cpVect v1, cpVect v2, cpFloat d) cpvlerpconst(cpVect v1, cpVect v2, cpFloat d)
{ {
return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d)); return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d));
} }
/// Returns the distance between v1 and v2.
static inline cpFloat static inline cpFloat
cpvdist(const cpVect v1, const cpVect v2) cpvdist(const cpVect v1, const cpVect v2)
{ {
return cpvlength(cpvsub(v1, 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 static inline cpFloat
cpvdistsq(const cpVect v1, const cpVect v2) cpvdistsq(const cpVect v1, const cpVect v2)
{ {
return cpvlengthsq(cpvsub(v1, v2)); return cpvlengthsq(cpvsub(v1, v2));
} }
static inline int /// 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) cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)
{ {
return cpvdistsq(v1, v2) < dist*dist; return cpvdistsq(v1, v2) < dist*dist;

View File

@ -39,7 +39,10 @@ OBJECTS = \
$(OBJECTS_DIR)/cpPolyShape.o \ $(OBJECTS_DIR)/cpPolyShape.o \
$(OBJECTS_DIR)/cpShape.o \ $(OBJECTS_DIR)/cpShape.o \
$(OBJECTS_DIR)/cpSpace.o \ $(OBJECTS_DIR)/cpSpace.o \
$(OBJECTS_DIR)/cpSpaceComponent.o \
$(OBJECTS_DIR)/cpSpaceHash.o \ $(OBJECTS_DIR)/cpSpaceHash.o \
$(OBJECTS_DIR)/cpSpaceQuery.o \
$(OBJECTS_DIR)/cpSpaceStep.o \
$(OBJECTS_DIR)/cpVect.o \ $(OBJECTS_DIR)/cpVect.o \
$(OBJECTS_DIR)/cpConstraint.o \ $(OBJECTS_DIR)/cpConstraint.o \
$(OBJECTS_DIR)/cpDampedRotarySpring.o \ $(OBJECTS_DIR)/cpDampedRotarySpring.o \
@ -100,9 +103,18 @@ $(OBJECTS_DIR)/cpShape.o : ../src/cpShape.c
$(OBJECTS_DIR)/cpSpace.o : ../src/cpSpace.c $(OBJECTS_DIR)/cpSpace.o : ../src/cpSpace.c
$(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpace.o ../src/cpSpace.c $(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpace.o ../src/cpSpace.c
$(OBJECTS_DIR)/cpSpace.o : ../src/cpSpaceComponent.c
$(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpace.o ../src/cpSpaceComponent.c
$(OBJECTS_DIR)/cpSpaceHash.o : ../src/cpSpaceHash.c $(OBJECTS_DIR)/cpSpaceHash.o : ../src/cpSpaceHash.c
$(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpaceHash.o ../src/cpSpaceHash.c $(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpaceHash.o ../src/cpSpaceHash.c
$(OBJECTS_DIR)/cpSpace.o : ../src/cpSpaceQuery.c
$(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpace.o ../src/cpSpaceQuery.c
$(OBJECTS_DIR)/cpSpace.o : ../src/cpSpaceStep.c
$(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpSpace.o ../src/cpSpaceStep.c
$(OBJECTS_DIR)/cpVect.o : ../src/cpVect.c $(OBJECTS_DIR)/cpVect.o : ../src/cpVect.c
$(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpVect.o ../src/cpVect.c $(CC) -c $(CC_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/cpVect.o ../src/cpVect.c

View File

@ -9,7 +9,7 @@ if(BUILD_SHARED)
${chipmunk_source_files} ${chipmunk_source_files}
) )
# set the lib's version number # set the lib's version number
set_target_properties(chipmunk PROPERTIES VERSION 5.1) set_target_properties(chipmunk PROPERTIES VERSION 5.3.4)
install(TARGETS chipmunk RUNTIME DESTINATION lib LIBRARY DESTINATION lib) install(TARGETS chipmunk RUNTIME DESTINATION lib LIBRARY DESTINATION lib)
endif(BUILD_SHARED) endif(BUILD_SHARED)

View File

@ -21,6 +21,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include "chipmunk.h" #include "chipmunk.h"
@ -43,7 +45,7 @@ cpMessage(const char *message, const char *condition, const char *file, int line
} }
char *cpVersionString = "5.x.x"; const char *cpVersionString = "5.3.4";
void void
cpInitChipmunk(void) cpInitChipmunk(void)
@ -59,7 +61,13 @@ cpInitChipmunk(void)
cpFloat cpFloat
cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset) cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)
{ {
return (1.0f/2.0f)*m*(r1*r1 + r2*r2) + m*cpvdot(offset, offset); return m*(0.5f*(r1*r1 + r2*r2) + cpvlengthsq(offset));
}
cpFloat
cpAreaForCircle(cpFloat r1, cpFloat r2)
{
return 2.0f*(cpFloat)M_PI*cpfabs(r1*r1 - r2*r2);
} }
cpFloat cpFloat
@ -68,21 +76,23 @@ cpMomentForSegment(cpFloat m, cpVect a, cpVect b)
cpFloat length = cpvlength(cpvsub(b, a)); cpFloat length = cpvlength(cpvsub(b, a));
cpVect offset = cpvmult(cpvadd(a, b), 1.0f/2.0f); cpVect offset = cpvmult(cpvadd(a, b), 1.0f/2.0f);
return m*length*length/12.0f + m*cpvdot(offset, offset); return m*(length*length/12.0f + cpvlengthsq(offset));
} }
cpFloat cpFloat
cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset) cpAreaForSegment(cpVect a, cpVect b, cpFloat r)
{ {
cpVect *tVerts = (cpVect *)cpcalloc(numVerts, sizeof(cpVect)); return 2.0f*r*((cpFloat)M_PI*r + cpvdist(a, b));
for(int i=0; i<numVerts; i++) }
tVerts[i] = cpvadd(verts[i], offset);
cpFloat
cpMomentForPoly(cpFloat m, const int numVerts, const cpVect *verts, cpVect offset)
{
cpFloat sum1 = 0.0f; cpFloat sum1 = 0.0f;
cpFloat sum2 = 0.0f; cpFloat sum2 = 0.0f;
for(int i=0; i<numVerts; i++){ for(int i=0; i<numVerts; i++){
cpVect v1 = tVerts[i]; cpVect v1 = cpvadd(verts[i], offset);
cpVect v2 = tVerts[(i+1)%numVerts]; cpVect v2 = cpvadd(verts[(i+1)%numVerts], offset);
cpFloat a = cpvcross(v2, v1); cpFloat a = cpvcross(v2, v1);
cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2); cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2);
@ -91,15 +101,51 @@ cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset)
sum2 += a; sum2 += a;
} }
cpfree(tVerts);
return (m*sum1)/(6.0f*sum2); return (m*sum1)/(6.0f*sum2);
} }
cpFloat
cpAreaForPoly(const int numVerts, const cpVect *verts)
{
cpFloat area = 0.0f;
for(int i=0; i<numVerts; i++){
area += cpvcross(verts[i], verts[(i+1)%numVerts]);
}
return area/2.0f;
}
cpVect
cpCentroidForPoly(const int numVerts, const cpVect *verts)
{
cpFloat sum = 0.0f;
cpVect vsum = cpvzero;
for(int i=0; i<numVerts; i++){
cpVect v1 = verts[i];
cpVect v2 = verts[(i+1)%numVerts];
cpFloat cross = cpvcross(v1, v2);
sum += cross;
vsum = cpvadd(vsum, cpvmult(cpvadd(v1, v2), cross));
}
return cpvmult(vsum, 1.0f/(3.0f*sum));
}
void
cpRecenterPoly(const int numVerts, cpVect *verts){
cpVect centroid = cpCentroidForPoly(numVerts, verts);
for(int i=0; i<numVerts; i++){
verts[i] = cpvsub(verts[i], centroid);
}
}
cpFloat cpFloat
cpMomentForBox(cpFloat m, cpFloat width, cpFloat height) cpMomentForBox(cpFloat m, cpFloat width, cpFloat height)
{ {
return m*(width*width + height*height)/12; return m*(width*width + height*height)/12.0f;
} }
#include "chipmunk_ffi.h" #include "chipmunk_ffi.h"

View File

@ -21,7 +21,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
// TODO: Comment me! // TODO: Comment me!

View File

@ -22,7 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static cpFloat static cpFloat
@ -33,12 +33,12 @@ defaultSpringTorque(cpDampedRotarySpring *spring, cpFloat relativeAngle){
static void static void
preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv) preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = spring->constraint.a; CONSTRAINT_BEGIN(spring, a, b);
cpBody *b = spring->constraint.b;
spring->iSum = 1.0f/(a->i_inv + b->i_inv); cpFloat moment = a->i_inv + b->i_inv;
spring->iSum = 1.0f/moment;
spring->dt = dt; spring->w_coef = 1.0f - cpfexp(-spring->damping*dt*moment);
spring->target_wrn = 0.0f; spring->target_wrn = 0.0f;
// apply spring torque // apply spring torque
@ -50,15 +50,14 @@ preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv)
static void static void
applyImpulse(cpDampedRotarySpring *spring) applyImpulse(cpDampedRotarySpring *spring)
{ {
cpBody *a = spring->constraint.a; CONSTRAINT_BEGIN(spring, a, b);
cpBody *b = spring->constraint.b;
// compute relative velocity // compute relative velocity
cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn; cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;
// compute velocity loss from drag // compute velocity loss from drag
// not 100% certain this is derived correctly, though it makes sense // not 100% certain this is derived correctly, though it makes sense
cpFloat w_damp = wrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->iSum)); cpFloat w_damp = wrn*spring->w_coef;
spring->target_wrn = wrn - w_damp; spring->target_wrn = wrn - w_damp;
//apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass)); //apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));

View File

@ -22,7 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static cpFloat static cpFloat
@ -33,8 +33,7 @@ defaultSpringForce(cpDampedSpring *spring, cpFloat dist){
static void static void
preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv) preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = spring->constraint.a; CONSTRAINT_BEGIN(spring, a, b);
cpBody *b = spring->constraint.b;
spring->r1 = cpvrotate(spring->anchr1, a->rot); spring->r1 = cpvrotate(spring->anchr1, a->rot);
spring->r2 = cpvrotate(spring->anchr2, b->rot); spring->r2 = cpvrotate(spring->anchr2, b->rot);
@ -43,11 +42,11 @@ preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv)
cpFloat dist = cpvlength(delta); cpFloat dist = cpvlength(delta);
spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY)); spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
// calculate mass normal cpFloat k = k_scalar(a, b, spring->r1, spring->r2, spring->n);
spring->nMass = 1.0f/k_scalar(a, b, spring->r1, spring->r2, spring->n); spring->nMass = 1.0f/k;
spring->dt = dt;
spring->target_vrn = 0.0f; spring->target_vrn = 0.0f;
spring->v_coef = 1.0f - cpfexp(-spring->damping*dt*k);
// apply spring force // apply spring force
cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist); cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist);
@ -57,8 +56,7 @@ preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv)
static void static void
applyImpulse(cpDampedSpring *spring) applyImpulse(cpDampedSpring *spring)
{ {
cpBody *a = spring->constraint.a; CONSTRAINT_BEGIN(spring, a, b);
cpBody *b = spring->constraint.b;
cpVect n = spring->n; cpVect n = spring->n;
cpVect r1 = spring->r1; cpVect r1 = spring->r1;
@ -69,7 +67,7 @@ applyImpulse(cpDampedSpring *spring)
// compute velocity loss from drag // compute velocity loss from drag
// not 100% certain this is derived correctly, though it makes sense // not 100% certain this is derived correctly, though it makes sense
cpFloat v_damp = -vrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->nMass)); cpFloat v_damp = -vrn*spring->v_coef;
spring->target_vrn = vrn + v_damp; spring->target_vrn = vrn + v_damp;
apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass)); apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));

View File

@ -21,14 +21,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpGearJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpGearJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// calculate moment of inertia coefficient. // calculate moment of inertia coefficient.
joint->iSum = 1.0f/(a->i_inv*joint->ratio_inv + joint->ratio*b->i_inv); joint->iSum = 1.0f/(a->i_inv*joint->ratio_inv + joint->ratio*b->i_inv);
@ -49,8 +48,7 @@ preStep(cpGearJoint *joint, cpFloat dt, cpFloat dt_inv)
static void static void
applyImpulse(cpGearJoint *joint) applyImpulse(cpGearJoint *joint)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// compute relative rotational velocity // compute relative rotational velocity
cpFloat wr = b->w*joint->ratio - a->w; cpFloat wr = b->w*joint->ratio - a->w;
@ -111,4 +109,5 @@ cpGearJointSetRatio(cpConstraint *constraint, cpFloat value)
cpConstraintCheckCast(constraint, cpGearJoint); cpConstraintCheckCast(constraint, cpGearJoint);
((cpGearJoint *)constraint)->ratio = value; ((cpGearJoint *)constraint)->ratio = value;
((cpGearJoint *)constraint)->ratio_inv = 1.0f/value; ((cpGearJoint *)constraint)->ratio_inv = 1.0f/value;
cpConstraintActivateBodies(constraint);
} }

View File

@ -21,14 +21,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpGrooveJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpGrooveJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// calculate endpoints in worldspace // calculate endpoints in worldspace
cpVect ta = cpBodyLocal2World(a, joint->grv_a); cpVect ta = cpBodyLocal2World(a, joint->grv_a);
@ -79,8 +78,7 @@ grooveConstrain(cpGrooveJoint *joint, cpVect j){
static void static void
applyImpulse(cpGrooveJoint *joint) applyImpulse(cpGrooveJoint *joint)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
cpVect r1 = joint->r1; cpVect r1 = joint->r1;
cpVect r2 = joint->r2; cpVect r2 = joint->r2;
@ -136,3 +134,28 @@ cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect
{ {
return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2); return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);
} }
void
cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value)
{
cpGrooveJoint *g = (cpGrooveJoint *)constraint;
cpConstraintCheckCast(constraint, cpGrooveJoint);
g->grv_a = value;
g->grv_n = cpvperp(cpvnormalize(cpvsub(g->grv_b, value)));
cpConstraintActivateBodies(constraint);
}
void
cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value)
{
cpGrooveJoint *g = (cpGrooveJoint *)constraint;
cpConstraintCheckCast(constraint, cpGrooveJoint);
g->grv_b = value;
g->grv_n = cpvperp(cpvnormalize(cpvsub(value, g->grv_a)));
cpConstraintActivateBodies(constraint);
}

View File

@ -22,14 +22,13 @@
#include <stdlib.h> #include <stdlib.h>
//#include <math.h> //#include <math.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpPinJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpPinJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
joint->r1 = cpvrotate(joint->anchr1, a->rot); joint->r1 = cpvrotate(joint->anchr1, a->rot);
joint->r2 = cpvrotate(joint->anchr2, b->rot); joint->r2 = cpvrotate(joint->anchr2, b->rot);
@ -56,8 +55,7 @@ preStep(cpPinJoint *joint, cpFloat dt, cpFloat dt_inv)
static void static void
applyImpulse(cpPinJoint *joint) applyImpulse(cpPinJoint *joint)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
cpVect n = joint->n; cpVect n = joint->n;
// compute relative velocity // compute relative velocity
@ -101,8 +99,9 @@ cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect an
joint->anchr1 = anchr1; joint->anchr1 = anchr1;
joint->anchr2 = anchr2; joint->anchr2 = anchr2;
cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot)); // STATIC_BODY_CHECK
cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot)); cpVect p1 = (a ? cpvadd(a->p, cpvrotate(anchr1, a->rot)) : anchr1);
cpVect p2 = (b ? cpvadd(b->p, cpvrotate(anchr2, b->rot)) : anchr2);
joint->dist = cpvlength(cpvsub(p2, p1)); joint->dist = cpvlength(cpvsub(p2, p1));
joint->jnAcc = 0.0f; joint->jnAcc = 0.0f;

View File

@ -21,14 +21,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
joint->r1 = cpvrotate(joint->anchr1, a->rot); joint->r1 = cpvrotate(joint->anchr1, a->rot);
joint->r2 = cpvrotate(joint->anchr2, b->rot); joint->r2 = cpvrotate(joint->anchr2, b->rot);
@ -50,8 +49,7 @@ preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv)
static void static void
applyImpulse(cpPivotJoint *joint) applyImpulse(cpPivotJoint *joint)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
cpVect r1 = joint->r1; cpVect r1 = joint->r1;
cpVect r2 = joint->r2; cpVect r2 = joint->r2;
@ -110,5 +108,7 @@ cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
cpConstraint * cpConstraint *
cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot) cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
{ {
return cpPivotJointNew2(a, b, cpBodyWorld2Local(a, pivot), cpBodyWorld2Local(b, pivot)); cpVect anchr1 = (a ? cpBodyWorld2Local(a, pivot) : pivot);
cpVect anchr2 = (b ? cpBodyWorld2Local(b, pivot) : pivot);
return cpPivotJointNew2(a, b, anchr1, anchr2);
} }

View File

@ -19,18 +19,16 @@
* SOFTWARE. * SOFTWARE.
*/ */
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
cpFloat angle = joint->angle; cpFloat angle = joint->angle;
cpFloat phase = joint->phase; cpFloat phase = joint->phase;
@ -70,8 +68,7 @@ applyImpulse(cpRatchetJoint *joint)
{ {
if(!joint->bias) return; // early exit if(!joint->bias) return; // early exit
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// compute relative rotational velocity // compute relative rotational velocity
cpFloat wr = b->w - a->w; cpFloat wr = b->w - a->w;
@ -116,7 +113,8 @@ cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, c
joint->phase = phase; joint->phase = phase;
joint->ratchet = ratchet; joint->ratchet = ratchet;
joint->angle = b->a - a->a; // STATIC_BODY_CHECK
joint->angle = (b ? b->a : 0.0f) - (a ? a->a : 0.0f);
return joint; return joint;
} }

View File

@ -21,14 +21,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
cpFloat dist = b->a - a->a; cpFloat dist = b->a - a->a;
cpFloat pdist = 0.0f; cpFloat pdist = 0.0f;
@ -62,8 +61,7 @@ applyImpulse(cpRotaryLimitJoint *joint)
{ {
if(!joint->bias) return; // early exit if(!joint->bias) return; // early exit
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// compute relative rotational velocity // compute relative rotational velocity
cpFloat wr = b->w - a->w; cpFloat wr = b->w - a->w;

View File

@ -21,14 +21,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpSimpleMotor *joint, cpFloat dt, cpFloat dt_inv) preStep(cpSimpleMotor *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// calculate moment of inertia coefficient. // calculate moment of inertia coefficient.
joint->iSum = 1.0f/(a->i_inv + b->i_inv); joint->iSum = 1.0f/(a->i_inv + b->i_inv);
@ -44,8 +43,7 @@ preStep(cpSimpleMotor *joint, cpFloat dt, cpFloat dt_inv)
static void static void
applyImpulse(cpSimpleMotor *joint) applyImpulse(cpSimpleMotor *joint)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
// compute relative rotational velocity // compute relative rotational velocity
cpFloat wr = b->w - a->w + joint->rate; cpFloat wr = b->w - a->w + joint->rate;

View File

@ -21,14 +21,13 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
static void static void
preStep(cpSlideJoint *joint, cpFloat dt, cpFloat dt_inv) preStep(cpSlideJoint *joint, cpFloat dt, cpFloat dt_inv)
{ {
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
joint->r1 = cpvrotate(joint->anchr1, a->rot); joint->r1 = cpvrotate(joint->anchr1, a->rot);
joint->r2 = cpvrotate(joint->anchr2, b->rot); joint->r2 = cpvrotate(joint->anchr2, b->rot);
@ -69,8 +68,7 @@ applyImpulse(cpSlideJoint *joint)
{ {
if(!joint->bias) return; // early exit if(!joint->bias) return; // early exit
cpBody *a = joint->constraint.a; CONSTRAINT_BEGIN(joint, a, b);
cpBody *b = joint->constraint.b;
cpVect n = joint->n; cpVect n = joint->n;
cpVect r1 = joint->r1; cpVect r1 = joint->r1;

View File

@ -21,7 +21,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "constraints/util.h" #include "constraints/util.h"
cpFloat cp_bias_coef = 0.1f; cpFloat cp_bias_coef = 0.1f;
@ -104,13 +104,20 @@ cpArbiterAlloc(void)
cpArbiter* cpArbiter*
cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b) cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b)
{ {
arb->handler = NULL;
arb->swappedColl = cpFalse;
arb->e = 0.0f;
arb->u = 0.0f;
arb->surface_vr = cpvzero;
arb->numContacts = 0; arb->numContacts = 0;
arb->contacts = NULL; arb->contacts = NULL;
arb->private_a = a; arb->a = a;
arb->private_b = b; arb->b = b;
arb->stamp = -1; arb->stamp = 0;
arb->state = cpArbiterStateFirstColl; arb->state = cpArbiterStateFirstColl;
return arb; return arb;
@ -157,8 +164,6 @@ cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, cpCollisio
} }
} }
} }
// cpfree(arb->contacts);
} }
arb->contacts = contacts; arb->contacts = contacts;
@ -172,17 +177,18 @@ cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, cpCollisio
arb->surface_vr = cpvsub(a->surface_v, b->surface_v); arb->surface_vr = cpvsub(a->surface_v, b->surface_v);
// For collisions between two similar primitive types, the order could have been swapped. // For collisions between two similar primitive types, the order could have been swapped.
arb->private_a = a; arb->private_b = b; arb->a = a;
arb->b = b;
// mark it as new if it's been cached
if(arb->state == cpArbiterStateCached) arb->state = cpArbiterStateFirstColl;
} }
void void
cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv) cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv)
{ {
cpShape *shapea = arb->private_a; cpBody *a = arb->a->body;
cpShape *shapeb = arb->private_b; cpBody *b = arb->b->body;
cpBody *a = shapea->body;
cpBody *b = shapeb->body;
for(int i=0; i<arb->numContacts; i++){ for(int i=0; i<arb->numContacts; i++){
cpContact *con = &arb->contacts[i]; cpContact *con = &arb->contacts[i];
@ -207,8 +213,8 @@ cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv)
void void
cpArbiterApplyCachedImpulse(cpArbiter *arb) cpArbiterApplyCachedImpulse(cpArbiter *arb)
{ {
cpShape *shapea = arb->private_a; cpShape *shapea = arb->a;
cpShape *shapeb = arb->private_b; cpShape *shapeb = arb->b;
arb->u = shapea->u * shapeb->u; arb->u = shapea->u * shapeb->u;
arb->surface_vr = cpvsub(shapeb->surface_v, shapea->surface_v); arb->surface_vr = cpvsub(shapeb->surface_v, shapea->surface_v);
@ -225,8 +231,8 @@ cpArbiterApplyCachedImpulse(cpArbiter *arb)
void void
cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef) cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef)
{ {
cpBody *a = arb->private_a->body; cpBody *a = arb->a->body;
cpBody *b = arb->private_b->body; cpBody *b = arb->b->body;
for(int i=0; i<arb->numContacts; i++){ for(int i=0; i<arb->numContacts; i++){
cpContact *con = &arb->contacts[i]; cpContact *con = &arb->contacts[i];

View File

@ -22,7 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "chipmunk.h" #include "chipmunk_private.h"
//#define CP_ARRAY_INCREMENT 10 //#define CP_ARRAY_INCREMENT 10
@ -57,6 +57,7 @@ void
cpArrayDestroy(cpArray *arr) cpArrayDestroy(cpArray *arr)
{ {
cpfree(arr->arr); cpfree(arr->arr);
arr->arr = NULL;
} }
void void
@ -111,6 +112,20 @@ cpArrayDeleteObj(cpArray *arr, void *obj)
} }
} }
void
cpArrayAppend(cpArray *arr, cpArray *other)
{
void *tail = &arr->arr[arr->num];
arr->num += other->num;
if(arr->num >= arr->max){
arr->max = arr->num;
arr->arr = (void **)cprealloc(arr->arr, arr->max*sizeof(void**));
}
memcpy(tail, other->arr, other->num*sizeof(void**));
}
void void
cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data) cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data)
{ {
@ -118,11 +133,11 @@ cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data)
iterFunc(arr->arr[i], data); iterFunc(arr->arr[i], data);
} }
int cpBool
cpArrayContains(cpArray *arr, void *ptr) cpArrayContains(cpArray *arr, void *ptr)
{ {
for(int i=0; i<arr->num; i++) for(int i=0; i<arr->num; i++)
if(arr->arr[i] == ptr) return 1; if(arr->arr[i] == ptr) return cpTrue;
return 0; return cpFalse;
} }

View File

@ -21,8 +21,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <float.h> #include <float.h>
#include <stdarg.h>
#include "chipmunk.h" #include "chipmunk_private.h"
// initialized in cpInitChipmunk()
cpBody cpStaticBodySingleton;
cpBody* cpBody*
cpBodyAlloc(void) cpBodyAlloc(void)
@ -56,7 +60,12 @@ cpBodyInit(cpBody *body, cpFloat m, cpFloat i)
body->data = NULL; body->data = NULL;
body->v_limit = (cpFloat)INFINITY; body->v_limit = (cpFloat)INFINITY;
body->w_limit = (cpFloat)INFINITY; body->w_limit = (cpFloat)INFINITY;
// body->active = 1;
body->space = NULL;
body->shapesList = NULL;
cpComponentNode node = {NULL, NULL, 0, 0.0f};
body->node = node;
return body; return body;
} }
@ -67,6 +76,21 @@ cpBodyNew(cpFloat m, cpFloat i)
return cpBodyInit(cpBodyAlloc(), m, i); return cpBodyInit(cpBodyAlloc(), m, i);
} }
cpBody *
cpBodyInitStatic(cpBody *body)
{
cpBodyInit(body, (cpFloat)INFINITY, (cpFloat)INFINITY);
body->node.idleTime = (cpFloat)INFINITY;
return body;
}
cpBody *
cpBodyNewStatic()
{
return cpBodyInitStatic(cpBodyAlloc());
}
void cpBodyDestroy(cpBody *body){} void cpBodyDestroy(cpBody *body){}
void void
@ -166,23 +190,3 @@ cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat
cpBodyApplyForce(a, f, r1); cpBodyApplyForce(a, f, r1);
cpBodyApplyForce(b, cpvneg(f), r2); cpBodyApplyForce(b, cpvneg(f), r2);
} }
//int
//cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max)
//{
// cpFloat ke = body->m*cpvdot(body->v, body->v);
// cpFloat re = body->i*body->w*body->w;
//
// if(ke + re > body->m*dvsq)
// body->active = 1;
// else if(body->active)
// body->active = (body->active + 1)%(max + 1);
// else {
// body->v = cpvzero;
// body->v_bias = cpvzero;
// body->w = 0.0f;
// body->w_bias = 0.0f;
// }
//
// return body->active;
//}

View File

@ -21,16 +21,16 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <stdio.h> //#include <stdio.h>
#include "chipmunk.h" #include "chipmunk_private.h"
typedef int (*collisionFunc)(cpShape *, cpShape *, cpContact *); typedef int (*collisionFunc)(const cpShape *, const cpShape *, cpContact *);
// Add contact points for circle to circle collisions. // Add contact points for circle to circle collisions.
// Used by several collision tests. // Used by several collision tests.
static int static int
circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con) circle2circleQuery(const cpVect p1, const cpVect p2, const cpFloat r1, const cpFloat r2, cpContact *con)
{ {
cpFloat mindist = r1 + r2; cpFloat mindist = r1 + r2;
cpVect delta = cpvsub(p2, p1); cpVect delta = cpvsub(p2, p1);
@ -38,14 +38,12 @@ circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con)
if(distsq >= mindist*mindist) return 0; if(distsq >= mindist*mindist) return 0;
cpFloat dist = cpfsqrt(distsq); cpFloat dist = cpfsqrt(distsq);
// To avoid singularities, do nothing in the case of dist = 0.
cpFloat non_zero_dist = (dist ? dist : INFINITY);
// Allocate and initialize the contact. // Allocate and initialize the contact.
cpContactInit( cpContactInit(
con, con,
cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/non_zero_dist)), cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/(dist ? dist : INFINITY))),
cpvmult(delta, 1.0f/non_zero_dist), (dist ? cpvmult(delta, 1.0f/dist) : cpv(1.0f, 0.0f)),
dist - mindist, dist - mindist,
0 0
); );
@ -55,7 +53,7 @@ circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con)
// Collide circle shapes. // Collide circle shapes.
static int static int
circle2circle(cpShape *shape1, cpShape *shape2, cpContact *arr) circle2circle(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{ {
cpCircleShape *circ1 = (cpCircleShape *)shape1; cpCircleShape *circ1 = (cpCircleShape *)shape1;
cpCircleShape *circ2 = (cpCircleShape *)shape2; cpCircleShape *circ2 = (cpCircleShape *)shape2;
@ -65,7 +63,7 @@ circle2circle(cpShape *shape1, cpShape *shape2, cpContact *arr)
// Collide circles to segment shapes. // Collide circles to segment shapes.
static int static int
circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact *con) circle2segment(const cpShape *circleShape, const cpShape *segmentShape, cpContact *con)
{ {
cpCircleShape *circ = (cpCircleShape *)circleShape; cpCircleShape *circ = (cpCircleShape *)circleShape;
cpSegmentShape *seg = (cpSegmentShape *)segmentShape; cpSegmentShape *seg = (cpSegmentShape *)segmentShape;
@ -118,17 +116,19 @@ circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact *con)
static cpContact * static cpContact *
nextContactPoint(cpContact *arr, int *numPtr) nextContactPoint(cpContact *arr, int *numPtr)
{ {
int num = *numPtr; int index = *numPtr;
if(num <= CP_MAX_CONTACTS_PER_ARBITER) if(index < CP_MAX_CONTACTS_PER_ARBITER){
(*numPtr) = num + 1; (*numPtr) = index + 1;
return &arr[index];
return &arr[num]; } else {
return &arr[CP_MAX_CONTACTS_PER_ARBITER - 1];
}
} }
// Find the minimum separating axis for the give poly and axis list. // Find the minimum separating axis for the give poly and axis list.
static inline int static inline int
findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out) findMSA(const cpPolyShape *poly, const cpPolyShapeAxis *axes, const int num, cpFloat *min_out)
{ {
int min_index = 0; int min_index = 0;
cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d); cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);
@ -148,9 +148,11 @@ findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out)
return min_index; return min_index;
} }
// Add contacts for penetrating vertexes. // Add contacts for probably penetrating vertexes.
// This handles the degenerate case where an overlap was detected, but no vertexes fall inside
// the opposing polygon. (like a star of david)
static inline int static inline int
findVerts(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist) findVertsFallback(cpContact *arr, const cpPolyShape *poly1, const cpPolyShape *poly2, const cpVect n, const cpFloat dist)
{ {
int num = 0; int num = 0;
@ -166,15 +168,33 @@ findVerts(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFl
cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly2->shape.hashid, i)); cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly2->shape.hashid, i));
} }
// if(!num)
// addContactPoint(arr, &size, &num, cpContactNew(shape1->body->p, n, dist, 0));
return num; return num;
} }
// Add contacts for penetrating vertexes.
static inline int
findVerts(cpContact *arr, const cpPolyShape *poly1, const cpPolyShape *poly2, const cpVect n, const cpFloat dist)
{
int num = 0;
for(int i=0; i<poly1->numVerts; i++){
cpVect v = poly1->tVerts[i];
if(cpPolyShapeContainsVert(poly2, v))
cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly1->shape.hashid, i));
}
for(int i=0; i<poly2->numVerts; i++){
cpVect v = poly2->tVerts[i];
if(cpPolyShapeContainsVert(poly1, v))
cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly2->shape.hashid, i));
}
return (num ? num : findVertsFallback(arr, poly1, poly2, n, dist));
}
// Collide poly shapes together. // Collide poly shapes together.
static int static int
poly2poly(cpShape *shape1, cpShape *shape2, cpContact *arr) poly2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{ {
cpPolyShape *poly1 = (cpPolyShape *)shape1; cpPolyShape *poly1 = (cpPolyShape *)shape1;
cpPolyShape *poly2 = (cpPolyShape *)shape2; cpPolyShape *poly2 = (cpPolyShape *)shape2;
@ -196,7 +216,7 @@ poly2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
// Like cpPolyValueOnAxis(), but for segments. // Like cpPolyValueOnAxis(), but for segments.
static inline cpFloat static inline cpFloat
segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d) segValueOnAxis(const cpSegmentShape *seg, const cpVect n, const cpFloat d)
{ {
cpFloat a = cpvdot(n, seg->ta) - seg->r; cpFloat a = cpvdot(n, seg->ta) - seg->r;
cpFloat b = cpvdot(n, seg->tb) - seg->r; cpFloat b = cpvdot(n, seg->tb) - seg->r;
@ -205,7 +225,7 @@ segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)
// Identify vertexes that have penetrated the segment. // Identify vertexes that have penetrated the segment.
static inline void static inline void
findPointsBehindSeg(cpContact *arr, int *num, cpSegmentShape *seg, cpPolyShape *poly, cpFloat pDist, cpFloat coef) findPointsBehindSeg(cpContact *arr, int *num, const cpSegmentShape *seg, const cpPolyShape *poly, const cpFloat pDist, const cpFloat coef)
{ {
cpFloat dta = cpvcross(seg->tn, seg->ta); cpFloat dta = cpvcross(seg->tn, seg->ta);
cpFloat dtb = cpvcross(seg->tn, seg->tb); cpFloat dtb = cpvcross(seg->tn, seg->tb);
@ -225,7 +245,7 @@ findPointsBehindSeg(cpContact *arr, int *num, cpSegmentShape *seg, cpPolyShape *
// This one is complicated and gross. Just don't go there... // This one is complicated and gross. Just don't go there...
// TODO: Comment me! // TODO: Comment me!
static int static int
seg2poly(cpShape *shape1, cpShape *shape2, cpContact *arr) seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{ {
cpSegmentShape *seg = (cpSegmentShape *)shape1; cpSegmentShape *seg = (cpSegmentShape *)shape1;
cpPolyShape *poly = (cpPolyShape *)shape2; cpPolyShape *poly = (cpPolyShape *)shape2;
@ -294,7 +314,7 @@ seg2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
// This one is less gross, but still gross. // This one is less gross, but still gross.
// TODO: Comment me! // TODO: Comment me!
static int static int
circle2poly(cpShape *shape1, cpShape *shape2, cpContact *con) circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
{ {
cpCircleShape *circ = (cpCircleShape *)shape1; cpCircleShape *circ = (cpCircleShape *)shape1;
cpPolyShape *poly = (cpPolyShape *)shape2; cpPolyShape *poly = (cpPolyShape *)shape2;
@ -352,7 +372,7 @@ circle2poly(cpShape *shape1, cpShape *shape2, cpContact *con)
static collisionFunc *colfuncs = NULL; static collisionFunc *colfuncs = NULL;
static void static void
addColFunc(cpShapeType a, cpShapeType b, collisionFunc func) addColFunc(const cpShapeType a, const cpShapeType b, const collisionFunc func)
{ {
colfuncs[a + b*CP_NUM_SHAPES] = func; colfuncs[a + b*CP_NUM_SHAPES] = func;
} }
@ -381,7 +401,7 @@ extern "C" {
#endif #endif
int int
cpCollideShapes(cpShape *a, cpShape *b, cpContact *arr) cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr)
{ {
// Their shape types must be in order. // Their shape types must be in order.
cpAssert(a->klass->type <= b->klass->type, "Collision shapes passed to cpCollideShapes() are not sorted."); cpAssert(a->klass->type <= b->klass->type, "Collision shapes passed to cpCollideShapes() are not sorted.");

View File

@ -22,7 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "prime.h" #include "prime.h"
static void freeWrap(void *ptr, void *unused){cpfree(ptr);} static void freeWrap(void *ptr, void *unused){cpfree(ptr);}

View File

@ -20,9 +20,8 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "chipmunk_unsafe.h" #include "chipmunk_unsafe.h"
cpPolyShape * cpPolyShape *
@ -94,7 +93,7 @@ cpPolyShapeDestroy(cpShape *shape)
cpfree(poly->tAxes); cpfree(poly->tAxes);
} }
static int static cpBool
cpPolyShapePointQuery(cpShape *shape, cpVect p){ cpPolyShapePointQuery(cpShape *shape, cpVect p){
return cpBBcontainsVect(shape->bb, p) && cpPolyShapeContainsVert((cpPolyShape *)shape, p); return cpBBcontainsVect(shape->bb, p) && cpPolyShapeContainsVert((cpPolyShape *)shape, p);
} }
@ -137,8 +136,8 @@ static const cpShapeClass polyClass = {
cpPolyShapeSegmentQuery, cpPolyShapeSegmentQuery,
}; };
int cpBool
cpPolyValidate(cpVect *verts, int numVerts) cpPolyValidate(const cpVect *verts, const int numVerts)
{ {
for(int i=0; i<numVerts; i++){ for(int i=0; i<numVerts; i++){
cpVect a = verts[i]; cpVect a = verts[i];
@ -146,10 +145,10 @@ cpPolyValidate(cpVect *verts, int numVerts)
cpVect c = verts[(i+2)%numVerts]; cpVect c = verts[(i+2)%numVerts];
if(cpvcross(cpvsub(b, a), cpvsub(c, b)) > 0.0f) if(cpvcross(cpvsub(b, a), cpvsub(c, b)) > 0.0f)
return 0; return cpFalse;
} }
return 1; return cpTrue;
} }
int int
@ -211,8 +210,8 @@ cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)
cpPolyShape * cpPolyShape *
cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height) cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height)
{ {
cpFloat hw = width/2; cpFloat hw = width/2.0f;
cpFloat hh = height/2; cpFloat hh = height/2.0f;
cpVect verts[] = { cpVect verts[] = {
cpv(-hw,-hh), cpv(-hw,-hh),

View File

@ -23,7 +23,7 @@
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "chipmunk_unsafe.h" #include "chipmunk_unsafe.h"
#define CP_DefineShapeGetter(struct, type, member, name) \ #define CP_DefineShapeGetter(struct, type, member, name) \
@ -60,8 +60,9 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
shape->layers = CP_ALL_LAYERS; shape->layers = CP_ALL_LAYERS;
shape->data = NULL; shape->data = NULL;
shape->next = NULL;
cpShapeCacheBB(shape); // cpShapeCacheBB(shape);
return shape; return shape;
} }
@ -81,6 +82,7 @@ cpShapeFree(cpShape *shape)
} }
} }
// TODO this function should really take a position and rotation explicitly and be renamed
cpBB cpBB
cpShapeCacheBB(cpShape *shape) cpShapeCacheBB(cpShape *shape)
{ {
@ -90,12 +92,12 @@ cpShapeCacheBB(cpShape *shape)
return shape->bb; return shape->bb;
} }
int cpBool
cpShapePointQuery(cpShape *shape, cpVect p){ cpShapePointQuery(cpShape *shape, cpVect p){
return shape->klass->pointQuery(shape, p); return shape->klass->pointQuery(shape, p);
} }
int cpBool
cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){ cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){
cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero}; cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero};
(*info) = blank; (*info) = blank;
@ -138,7 +140,7 @@ cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
return bbFromCircle(circle->tc, circle->r); return bbFromCircle(circle->tc, circle->r);
} }
static int static cpBool
cpCircleShapePointQuery(cpShape *shape, cpVect p){ cpCircleShapePointQuery(cpShape *shape, cpVect p){
cpCircleShape *circle = (cpCircleShape *)shape; cpCircleShape *circle = (cpCircleShape *)shape;
return cpvnear(circle->tc, p, circle->r); return cpvnear(circle->tc, p, circle->r);
@ -147,7 +149,7 @@ cpCircleShapePointQuery(cpShape *shape, cpVect p){
static void static void
circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info) circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info)
{ {
// umm... gross I normally frown upon such things // offset the line to be relative to the circle
a = cpvsub(a, center); a = cpvsub(a, center);
b = cpvsub(b, center); b = cpvsub(b, center);
@ -239,16 +241,16 @@ cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
return cpBBNew(l - rad, s - rad, r + rad, t + rad); return cpBBNew(l - rad, s - rad, r + rad, t + rad);
} }
static int static cpBool
cpSegmentShapePointQuery(cpShape *shape, cpVect p){ cpSegmentShapePointQuery(cpShape *shape, cpVect p){
if(!cpBBcontainsVect(shape->bb, p)) return 0; if(!cpBBcontainsVect(shape->bb, p)) return cpFalse;
cpSegmentShape *seg = (cpSegmentShape *)shape; cpSegmentShape *seg = (cpSegmentShape *)shape;
// Calculate normal distance from segment. // Calculate normal distance from segment.
cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn); cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
cpFloat dist = cpfabs(dn) - seg->r; cpFloat dist = cpfabs(dn) - seg->r;
if(dist > 0.0f) return 0; if(dist > 0.0f) return cpFalse;
// Calculate tangential distance along segment. // Calculate tangential distance along segment.
cpFloat dt = -cpvcross(seg->tn, p); cpFloat dt = -cpvcross(seg->tn, p);
@ -258,28 +260,32 @@ cpSegmentShapePointQuery(cpShape *shape, cpVect p){
// Decision tree to decide which feature of the segment to collide with. // Decision tree to decide which feature of the segment to collide with.
if(dt <= dtMin){ if(dt <= dtMin){
if(dt < (dtMin - seg->r)){ if(dt < (dtMin - seg->r)){
return 0; return cpFalse;
} else { } else {
return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r); return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
} }
} else { } else {
if(dt < dtMax){ if(dt < dtMax){
return 1; return cpTrue;
} else { } else {
if(dt < (dtMax + seg->r)) { if(dt < (dtMax + seg->r)) {
return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r); return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
} else { } else {
return 0; return cpFalse;
} }
} }
} }
return 1; return cpTrue;
} }
static inline cpBool inUnitRange(cpFloat t){return (0.0f < t && t < 1.0f);}
static void static void
cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info) cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
{ {
// TODO this function could be optimized better.
cpSegmentShape *seg = (cpSegmentShape *)shape; cpSegmentShape *seg = (cpSegmentShape *)shape;
cpVect n = seg->tn; cpVect n = seg->tn;
// flip n if a is behind the axis // flip n if a is behind the axis
@ -288,9 +294,11 @@ cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInf
cpFloat an = cpvdot(a, n); cpFloat an = cpvdot(a, n);
cpFloat bn = cpvdot(b, n); cpFloat bn = cpvdot(b, n);
cpFloat d = cpvdot(seg->ta, n) + seg->r;
if(an != bn){
cpFloat d = cpvdot(seg->ta, n) + seg->r;
cpFloat t = (d - an)/(bn - an); cpFloat t = (d - an)/(bn - an);
if(0.0f < t && t < 1.0f){ if(0.0f < t && t < 1.0f){
cpVect point = cpvlerp(a, b, t); cpVect point = cpvlerp(a, b, t);
cpFloat dt = -cpvcross(seg->tn, point); cpFloat dt = -cpvcross(seg->tn, point);
@ -305,25 +313,20 @@ cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInf
return; // don't continue on and check endcaps return; // don't continue on and check endcaps
} }
} }
}
if(seg->r) { if(seg->r) {
cpSegmentQueryInfo info1; info1.shape = NULL; cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero};
cpSegmentQueryInfo info2; info2.shape = NULL; cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero};
circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1); circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1);
circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2); circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2);
if(info1.shape && !info2.shape){
(*info) = info1;
} else if(info2.shape && !info1.shape){
(*info) = info2;
} else if(info1.shape && info2.shape){
if(info1.t < info2.t){ if(info1.t < info2.t){
(*info) = info1; (*info) = info1;
} else { } else {
(*info) = info2; (*info) = info2;
} }
} }
}
} }
static const cpShapeClass cpSegmentShapeClass = { static const cpShapeClass cpSegmentShapeClass = {

View File

@ -20,24 +20,24 @@
*/ */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> //#include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include "chipmunk.h" #include "chipmunk_private.h"
int cp_contact_persistence = 1; cpTimestamp cp_contact_persistence = 3;
#pragma mark Contact Set Helpers #pragma mark Contact Set Helpers
// Equal function for contactSet. // Equal function for contactSet.
static int static cpBool
contactSetEql(cpShape **shapes, cpArbiter *arb) contactSetEql(cpShape **shapes, cpArbiter *arb)
{ {
cpShape *a = shapes[0]; cpShape *a = shapes[0];
cpShape *b = shapes[1]; cpShape *b = shapes[1];
return ((a == arb->private_a && b == arb->private_b) || (b == arb->private_a && a == arb->private_b)); return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));
} }
// Transformation function for contactSet. // Transformation function for contactSet.
@ -55,13 +55,13 @@ contactSetTrans(cpShape **shapes, cpSpace *space)
for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i); for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);
} }
return cpArbiterInit( (cpArbiter *)cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]); return cpArbiterInit((cpArbiter *) cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);
} }
#pragma mark Collision Pair Function Helpers #pragma mark Collision Pair Function Helpers
// Equals function for collFuncSet. // Equals function for collFuncSet.
static int static cpBool
collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair) collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
{ {
return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b)); return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b));
@ -77,32 +77,10 @@ collFuncSetTrans(cpCollisionHandler *handler, void *unused)
return copy; return copy;
} }
#pragma mark Post Step Function Helpers
typedef struct postStepCallback {
cpPostStepFunc func;
void *obj;
void *data;
} postStepCallback;
static int
postStepFuncSetEql(postStepCallback *a, postStepCallback *b){
return a->obj == b->obj;
}
static void *
postStepFuncSetTrans(postStepCallback *callback, void *ignored)
{
postStepCallback *value = (postStepCallback *)cpmalloc(sizeof(postStepCallback));
(*value) = (*callback);
return value;
}
#pragma mark Misc Helper Funcs #pragma mark Misc Helper Funcs
// Default collision functions. // Default collision functions.
static int alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;} static cpBool alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
static void nothing(cpArbiter *arb, cpSpace *space, void *data){} static void nothing(cpArbiter *arb, cpSpace *space, void *data){}
// BBfunc callback for the spatial hash. // BBfunc callback for the spatial hash.
@ -116,30 +94,6 @@ static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFr
#pragma mark Memory Management Functions #pragma mark Memory Management Functions
#define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(cpContact))
typedef struct cpContactBuffer {
cpContactBufferHeader header;
cpContact contacts[CP_CONTACTS_BUFFER_SIZE];
} cpContactBuffer;
static cpContactBufferHeader *
cpSpaceAllocContactBuffer(cpSpace *space)
{
cpContactBuffer *buffer = (cpContactBuffer *)malloc(sizeof(cpContactBuffer));
cpArrayPush(space->allocatedBuffers, buffer);
return (cpContactBufferHeader *)buffer;
}
static cpContactBufferHeader *
cpContactBufferHeaderInit(cpContactBufferHeader *header, cpSpace *space)
{
header->stamp = space->stamp;
header->next = space->contactBuffersTail;
header->numContacts = 0;
return header;
}
cpSpace * cpSpace *
cpSpaceAlloc(void) cpSpaceAlloc(void)
{ {
@ -151,8 +105,6 @@ cpSpaceAlloc(void)
#define DEFAULT_ITERATIONS 10 #define DEFAULT_ITERATIONS 10
#define DEFAULT_ELASTIC_ITERATIONS 0 #define DEFAULT_ELASTIC_ITERATIONS 0
#define MAX_CONTACTS 10000
cpCollisionHandler defaultHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL}; cpCollisionHandler defaultHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL};
cpSpace* cpSpace*
@ -174,14 +126,16 @@ cpSpaceInit(cpSpace *space)
space->allocatedBuffers = cpArrayNew(0); space->allocatedBuffers = cpArrayNew(0);
space->bodies = cpArrayNew(0); space->bodies = cpArrayNew(0);
space->sleepingComponents = cpArrayNew(0);
space->rousedBodies = cpArrayNew(0);
space->sleepTimeThreshold = INFINITY;
space->idleSpeedThreshold = 0.0f;
space->arbiters = cpArrayNew(0); space->arbiters = cpArrayNew(0);
space->pooledArbiters = cpArrayNew(0); space->pooledArbiters = cpArrayNew(0);
cpContactBufferHeader *header = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), space); space->contactBuffersHead = NULL;
space->contactBuffersHead = header;
space->contactBuffersTail = header;
header->next = header; // Buffers will form a ring, start the ring explicitly
space->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans); space->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);
space->constraints = cpArrayNew(0); space->constraints = cpArrayNew(0);
@ -190,7 +144,9 @@ cpSpaceInit(cpSpace *space)
space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans); space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);
space->collFuncSet->default_value = &space->defaultHandler; space->collFuncSet->default_value = &space->defaultHandler;
space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql, (cpHashSetTransFunc)postStepFuncSetTrans); space->postStepCallbacks = NULL;
cpBodyInitStatic(&space->staticBody);
return space; return space;
} }
@ -208,6 +164,8 @@ cpSpaceDestroy(cpSpace *space)
cpSpaceHashFree(space->activeShapes); cpSpaceHashFree(space->activeShapes);
cpArrayFree(space->bodies); cpArrayFree(space->bodies);
cpArrayFree(space->sleepingComponents);
cpArrayFree(space->rousedBodies);
cpArrayFree(space->constraints); cpArrayFree(space->constraints);
@ -244,6 +202,9 @@ cpSpaceFree(cpSpace *space)
void void
cpSpaceFreeChildren(cpSpace *space) cpSpaceFreeChildren(cpSpace *space)
{ {
cpArray *components = space->sleepingComponents;
while(components->num) cpBodyActivate((cpBody *)components->arr[0]);
cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL); cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL); cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL); cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL);
@ -310,31 +271,62 @@ cpSpaceSetDefaultCollisionHandler(
#define cpAssertSpaceUnlocked(space) \ #define cpAssertSpaceUnlocked(space) \
cpAssert(!space->locked, \ cpAssert(!space->locked, \
"This addition/removal cannot be done safely during a call to cpSpaceStep(). " \ "This addition/removal cannot be done safely during a call to cpSpaceStep() or during a query. " \
"Put these calls into a Post Step Callback." \ "Put these calls into a post-step callback." \
); );
static void
cpBodyAddShape(cpBody *body, cpShape *shape)
{
shape->next = shape->body->shapesList;
shape->body->shapesList = shape;
}
static void
cpBodyRemoveShape(cpBody *body, cpShape *shape)
{
cpShape **prev_ptr = &body->shapesList;
cpShape *node = body->shapesList;
while(node && node != shape){
prev_ptr = &node->next;
node = node->next;
}
cpAssert(node, "Attempted to remove a shape from a body it was never attached to.");
(*prev_ptr) = node->next;
}
cpShape * cpShape *
cpSpaceAddShape(cpSpace *space, cpShape *shape) cpSpaceAddShape(cpSpace *space, cpShape *shape)
{ {
cpAssert(shape->body, "Cannot add a shape with a NULL body."); cpBody *body = shape->body;
if(!body || cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape);
cpAssert(!cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape), cpAssert(!cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
"Cannot add the same shape more than once."); "Cannot add the same shape more than once.");
cpAssertSpaceUnlocked(space); cpAssertSpaceUnlocked(space);
cpBodyActivate(body);
cpBodyAddShape(body, shape);
cpShapeCacheBB(shape);
cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb); cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
return shape; return shape;
} }
cpShape * cpShape *
cpSpaceAddStaticShape(cpSpace *space, cpShape *shape) cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
{ {
cpAssert(shape->body, "Cannot add a static shape with a NULL body.");
cpAssert(!cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape), cpAssert(!cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
"Cannot add the same static shape more than once."); "Cannot add the same static shape more than once.");
cpAssertSpaceUnlocked(space); cpAssertSpaceUnlocked(space);
if(!shape->body) shape->body = &space->staticBody;
cpShapeCacheBB(shape); cpShapeCacheBB(shape);
cpSpaceActivateShapesTouchingShape(space, shape);
cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb); cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
return shape; return shape;
@ -343,10 +335,12 @@ cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
cpBody * cpBody *
cpSpaceAddBody(cpSpace *space, cpBody *body) cpSpaceAddBody(cpSpace *space, cpBody *body)
{ {
cpAssert(!cpArrayContains(space->bodies, body), "Cannot add the same body more than once."); cpAssertWarn(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated.");
cpAssert(!body->space, "Cannot add a body to a more than one space or to the same space twice.");
// cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback // cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback
cpArrayPush(space->bodies, body); cpArrayPush(space->bodies, body);
body->space = space;
return body; return body;
} }
@ -357,6 +351,11 @@ cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
cpAssert(!cpArrayContains(space->constraints, constraint), "Cannot add the same constraint more than once."); cpAssert(!cpArrayContains(space->constraints, constraint), "Cannot add the same constraint more than once.");
// cpAssertSpaceUnlocked(space); This should be safe as long as its not from a constraint callback. // cpAssertSpaceUnlocked(space); This should be safe as long as its not from a constraint callback.
if(!constraint->a) constraint->a = &space->staticBody;
if(!constraint->b) constraint->b = &space->staticBody;
cpBodyActivate(constraint->a);
cpBodyActivate(constraint->b);
cpArrayPush(space->constraints, constraint); cpArrayPush(space->constraints, constraint);
return constraint; return constraint;
@ -368,24 +367,37 @@ typedef struct removalContext {
} removalContext; } removalContext;
// Hashset filter func to throw away old arbiters. // Hashset filter func to throw away old arbiters.
static int static cpBool
contactSetFilterRemovedShape(cpArbiter *arb, removalContext *context) contactSetFilterRemovedShape(cpArbiter *arb, removalContext *context)
{ {
if(context->shape == arb->private_a || context->shape == arb->private_b){ if(context->shape == arb->a || context->shape == arb->b){
if(arb->state != cpArbiterStateCached){
arb->handler->separate(arb, context->space, arb->handler->data); arb->handler->separate(arb, context->space, arb->handler->data);
cpArrayPush(context->space->pooledArbiters, arb);
return 0;
} }
return 1; cpArrayPush(context->space->pooledArbiters, arb);
return cpFalse;
}
return cpTrue;
} }
void void
cpSpaceRemoveShape(cpSpace *space, cpShape *shape) cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
{ {
cpAssertWarn(cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape), cpBody *body = shape->body;
"Cannot remove a shape that was never added to the space. (Removed twice maybe?)"); if(cpBodyIsStatic(body)){
cpSpaceRemoveStaticShape(space, shape);
return;
}
cpBodyActivate(body);
cpAssertSpaceUnlocked(space); cpAssertSpaceUnlocked(space);
cpAssertWarn(cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
"Cannot remove a shape that was not added to the space. (Removed twice maybe?)");
cpBodyRemoveShape(body, shape);
removalContext context = {space, shape}; removalContext context = {space, shape};
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context); cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
@ -396,238 +408,43 @@ void
cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape) cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
{ {
cpAssertWarn(cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape), cpAssertWarn(cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
"Cannot remove a static shape that was never added to the space. (Removed twice maybe?)"); "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)");
cpAssertSpaceUnlocked(space); cpAssertSpaceUnlocked(space);
removalContext context = {space, shape}; removalContext context = {space, shape};
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context); cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
cpSpaceHashRemove(space->staticShapes, shape, shape->hashid); cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
cpSpaceActivateShapesTouchingShape(space, shape);
} }
void void
cpSpaceRemoveBody(cpSpace *space, cpBody *body) cpSpaceRemoveBody(cpSpace *space, cpBody *body)
{ {
cpAssertWarn(cpArrayContains(space->bodies, body), cpAssertWarn(body->space == space,
"Cannot remove a body that was never added to the space. (Removed twice maybe?)"); "Cannot remove a body that was not added to the space. (Removed twice maybe?)");
cpAssertSpaceUnlocked(space); cpAssertSpaceUnlocked(space);
cpBodyActivate(body);
cpArrayDeleteObj(space->bodies, body); cpArrayDeleteObj(space->bodies, body);
body->space = NULL;
} }
void void
cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint) cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
{ {
cpAssertWarn(cpArrayContains(space->constraints, constraint), cpAssertWarn(cpArrayContains(space->constraints, constraint),
"Cannot remove a constraint that was never added to the space. (Removed twice maybe?)"); "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");
// cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback. // cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback.
cpBodyActivate(constraint->a);
cpBodyActivate(constraint->b);
cpArrayDeleteObj(space->constraints, constraint); cpArrayDeleteObj(space->constraints, constraint);
} }
#pragma mark Post Step Functions
void
cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data)
{
postStepCallback callback = {func, obj, data};
cpHashSetInsert(space->postStepCallbacks, (cpHashValue)(size_t)obj, &callback, NULL);
}
static void
removeAndFreeShapeAndBody(cpShape *shape, cpSpace *space)
{
cpSpaceRemoveShape(space, shape);
cpShapeFree(shape);
}
void
cpSpacePostStepRemoveAndFreeShapeAndBody(cpSpace *space, cpShape *shape)
{
cpSpaceAddPostStepCallback(space, (cpPostStepFunc)removeAndFreeShapeAndBody, shape, space);
}
#pragma mark Point Query Functions
typedef struct pointQueryContext {
cpLayers layers;
cpGroup group;
cpSpacePointQueryFunc func;
void *data;
} pointQueryContext;
static void
pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
{
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
cpShapePointQuery(shape, *point)
){
context->func(shape, context->data);
}
}
void
cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)
{
pointQueryContext context = {layers, group, func, data};
cpSpaceHashPointQuery(space->activeShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
cpSpaceHashPointQuery(space->staticShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
}
static void
rememberLastPointQuery(cpShape *shape, cpShape **outShape)
{
(*outShape) = shape;
}
cpShape *
cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)
{
cpShape *shape = NULL;
cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)rememberLastPointQuery, &shape);
return shape;
}
void
cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
{
cpArray *bodies = space->bodies;
for(int i=0; i<bodies->num; i++)
func((cpBody *)bodies->arr[i], data);
}
#pragma mark Segment Query Functions
typedef struct segQueryContext {
cpVect start, end;
cpLayers layers;
cpGroup group;
cpSpaceSegmentQueryFunc func;
int anyCollision;
} segQueryContext;
static cpFloat
segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
{
cpSegmentQueryInfo info;
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
cpShapeSegmentQuery(shape, context->start, context->end, &info)
){
if(context->func){
context->func(shape, info.t, info.n, data);
}
context->anyCollision = 1;
}
return 1.0f;
}
int
cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
{
segQueryContext context = {
start, end,
layers, group,
func,
0,
};
cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFunc, data);
cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFunc, data);
return context.anyCollision;
}
typedef struct segQueryFirstContext {
cpVect start, end;
cpLayers layers;
cpGroup group;
} segQueryFirstContext;
static cpFloat
segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo *out)
{
cpSegmentQueryInfo info;// = {NULL, 1.0f, cpvzero};
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
cpShapeSegmentQuery(shape, context->start, context->end, &info)
){
if(info.t < out->t){
out->shape = info.shape;
out->t = info.t;
out->n = info.n;
}
return info.t;
}
return 1.0f;
}
cpShape *
cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out)
{
cpSegmentQueryInfo info = {NULL, 1.0f, cpvzero};
if(out){
(*out) = info;
} else {
out = &info;
}
out->t = 1.0f;
segQueryFirstContext context = {
start, end,
layers, group
};
cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
return out->shape;
}
#pragma mark BB Query functions
typedef struct bbQueryContext {
cpLayers layers;
cpGroup group;
cpSpaceBBQueryFunc func;
void *data;
} bbQueryContext;
static void
bbQueryHelper(cpBB *bb, cpShape *shape, bbQueryContext *context)
{
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
cpBBintersects(*bb, shape->bb)
){
context->func(shape, context->data);
}
}
void
cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data)
{
bbQueryContext context = {layers, group, func, data};
cpSpaceHashQuery(space->activeShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
cpSpaceHashQuery(space->staticShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
}
#pragma mark Spatial Hash Management #pragma mark Spatial Hash Management
// Iterator function used for updating shape BBoxes. static void updateBBCache(cpShape *shape, void *unused){cpShapeCacheBB(shape);}
static void
updateBBCache(cpShape *shape, void *unused)
{
cpShapeCacheBB(shape);
}
void void
cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count) cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
@ -649,251 +466,34 @@ cpSpaceRehashStatic(cpSpace *space)
cpSpaceHashRehash(space->staticShapes); cpSpaceHashRehash(space->staticShapes);
} }
#pragma mark Collision Detection Functions void
cpSpaceRehashShape(cpSpace *space, cpShape *shape)
static cpContactBufferHeader *
cpSpaceGetFreeContactBuffer(cpSpace *space)
{ {
if(space->stamp - space->contactBuffersTail->stamp > cp_contact_persistence){ cpShapeCacheBB(shape);
cpContactBufferHeader *header = space->contactBuffersTail;
space->contactBuffersTail = header->next;
return cpContactBufferHeaderInit(header, space); // attempt to rehash the shape in both hashes
} else { cpSpaceHashRehashObject(space->activeShapes, shape, shape->hashid);
cpContactBufferHeader *header = cpSpaceAllocContactBuffer(space); cpSpaceHashRehashObject(space->staticShapes, shape, shape->hashid);
return cpContactBufferHeaderInit(header, space);
}
} }
static void
cpSpacePushNewContactBuffer(cpSpace *space)
{
// for(cpContactBuffer *buffer = space->contactBuffersTail; buffer != space->contactBuffersHead; buffer = buffer->next){
// printf("%p -> ", buffer);
// }
// printf("%p (head)\n", space->contactBuffersHead);
cpContactBufferHeader *buffer = cpSpaceGetFreeContactBuffer(space);
space->contactBuffersHead->next = buffer;
space->contactBuffersHead = buffer;
}
static inline int
queryReject(cpShape *a, cpShape *b)
{
return
// BBoxes must overlap
!cpBBintersects(a->bb, b->bb)
// Don't collide shapes attached to the same body.
|| a->body == b->body
// Don't collide objects in the same non-zero group
|| (a->group && b->group && a->group == b->group)
// Don't collide objects that don't share at least on layer.
|| !(a->layers & b->layers);
}
// Callback from the spatial hash.
static void
queryFunc(cpShape *a, cpShape *b, cpSpace *space)
{
// Reject any of the simple cases
if(queryReject(a,b)) return;
// Find the collision pair function for the shapes.
struct{cpCollisionType a, b;} ids = {a->collision_type, b->collision_type};
cpHashValue collHashID = CP_HASH_PAIR(a->collision_type, b->collision_type);
cpCollisionHandler *handler = (cpCollisionHandler *)cpHashSetFind(space->collFuncSet, collHashID, &ids);
int sensor = a->sensor || b->sensor;
if(sensor && handler == &space->defaultHandler) return;
// Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
if(a->klass->type > b->klass->type){
cpShape *temp = a;
a = b;
b = temp;
}
if(space->contactBuffersHead->numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){
// contact buffer could overflow on the next collision, push a fresh one.
cpSpacePushNewContactBuffer(space);
}
// Narrow-phase collision detection.
cpContact *contacts = ((cpContactBuffer *)(space->contactBuffersHead))->contacts + space->contactBuffersHead->numContacts;
int numContacts = cpCollideShapes(a, b, contacts);
if(!numContacts) return; // Shapes are not colliding.
space->contactBuffersHead->numContacts += numContacts;
// Get an arbiter from space->contactSet for the two shapes.
// This is where the persistant contact magic comes from.
cpShape *shape_pair[] = {a, b};
cpHashValue arbHashID = CP_HASH_PAIR((size_t)a, (size_t)b);
cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->contactSet, arbHashID, shape_pair, space);
cpArbiterUpdate(arb, contacts, numContacts, handler, a, b); // retains the contacts array
// Call the begin function first if it's the first step
if(arb->stamp == -1 && !handler->begin(arb, space, handler->data)){
cpArbiterIgnore(arb); // permanently ignore the collision until separation
}
if(
// Ignore the arbiter if it has been flagged
(arb->state != cpArbiterStateIgnore) &&
// Call preSolve
handler->preSolve(arb, space, handler->data) &&
// Process, but don't add collisions for sensors.
!sensor
){
cpArrayPush(space->arbiters, arb);
} else {
// cpfree(arb->contacts);
space->contactBuffersHead->numContacts -= numContacts;
arb->contacts = NULL;
arb->numContacts = 0;
}
// Time stamp the arbiter so we know it was used recently.
arb->stamp = space->stamp;
}
// Iterator for active/static hash collisions.
static void
active2staticIter(cpShape *shape, cpSpace *space)
{
cpSpaceHashQuery(space->staticShapes, shape, shape->bb, (cpSpaceHashQueryFunc)queryFunc, space);
}
// Hashset filter func to throw away old arbiters.
static int
contactSetFilter(cpArbiter *arb, cpSpace *space)
{
int ticks = space->stamp - arb->stamp;
// was used last frame, but not this one
if(ticks == 1){
arb->handler->separate(arb, space, arb->handler->data);
arb->stamp = -1; // mark it as a new pair again.
}
if(ticks >= cp_contact_persistence){
cpArrayPush(space->pooledArbiters, arb);
return 0;
}
return 1;
}
// Hashset filter func to call and throw away post step callbacks.
static int
postStepCallbackSetFilter(postStepCallback *callback, cpSpace *space)
{
callback->func(space, callback->obj, callback->data);
cpfree(callback);
return 0;
}
#pragma mark All Important cpSpaceStep() Function
void void
cpSpaceStep(cpSpace *space, cpFloat dt) cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
{ {
if(!dt) return; // don't step if the timestep is 0!
cpFloat dt_inv = 1.0f/dt;
cpArray *bodies = space->bodies; cpArray *bodies = space->bodies;
cpArray *constraints = space->constraints;
space->locked = 1;
// Empty the arbiter list.
space->arbiters->num = 0;
// Integrate positions.
for(int i=0; i<bodies->num; i++){ for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody *)bodies->arr[i]; func((cpBody *)bodies->arr[i], data);
body->position_func(body, dt);
} }
// Pre-cache BBoxes and shape data. cpArray *components = space->sleepingComponents;
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)updateBBCache, NULL); for(int i=0; i<components->num; i++){
cpBody *root = (cpBody *)components->arr[i];
// Collide! cpBody *body = root, *next;
cpSpacePushNewContactBuffer(space); do {
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)active2staticIter, space); next = body->node.next;
cpSpaceHashQueryRehash(space->activeShapes, (cpSpaceHashQueryFunc)queryFunc, space); func(body, data);
} while((body = next) != root);
// Clear out old cached arbiters and dispatch untouch functions
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilter, space);
// Prestep the arbiters.
cpArray *arbiters = space->arbiters;
for(int i=0; i<arbiters->num; i++)
cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt_inv);
// Prestep the constraints.
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
constraint->klass->preStep(constraint, dt, dt_inv);
} }
for(int i=0; i<space->elasticIterations; i++){
for(int j=0; j<arbiters->num; j++)
cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 1.0f);
for(int j=0; j<constraints->num; j++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
constraint->klass->applyImpulse(constraint);
}
}
// Integrate velocities.
cpFloat damping = cpfpow(1.0f/space->damping, -dt);
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody *)bodies->arr[i];
body->velocity_func(body, space->gravity, damping, dt);
}
for(int i=0; i<arbiters->num; i++)
cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i]);
// run the old-style elastic solver if elastic iterations are disabled
cpFloat elasticCoef = (space->elasticIterations ? 0.0f : 1.0f);
// Run the impulse solver.
for(int i=0; i<space->iterations; i++){
for(int j=0; j<arbiters->num; j++)
cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], elasticCoef);
for(int j=0; j<constraints->num; j++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
constraint->klass->applyImpulse(constraint);
}
}
space->locked = 0;
// run the post solve callbacks
for(int i=0; i<arbiters->num; i++){
cpArbiter *arb = (cpArbiter *) arbiters->arr[i];
cpCollisionHandler *handler = arb->handler;
handler->postSolve(arb, space, handler->data);
arb->state = cpArbiterStateNormal;
}
// Run the post step callbacks
// Use filter as an easy way to clear out the queue as it runs
cpHashSetFilter(space->postStepCallbacks, (cpHashSetFilterFunc)postStepCallbackSetFilter, space);
// cpFloat dvsq = cpvdot(space->gravity, space->gravity);
// dvsq *= dt*dt * space->damping*space->damping;
// for(int i=0; i<bodies->num; i++)
// cpBodyMarkLowEnergy(bodies->arr[i], dvsq, space->sleepTicks);
// Increment the stamp.
space->stamp++;
} }

View File

@ -21,9 +21,8 @@
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include "chipmunk.h" #include "chipmunk_private.h"
#include "prime.h" #include "prime.h"
static cpHandle* static cpHandle*
@ -36,11 +35,7 @@ cpHandleInit(cpHandle *hand, void *obj)
return hand; return hand;
} }
static inline void static inline void cpHandleRetain(cpHandle *hand){hand->retain++;}
cpHandleRetain(cpHandle *hand)
{
hand->retain++;
}
static inline void static inline void
cpHandleRelease(cpHandle *hand, cpArray *pooledHandles) cpHandleRelease(cpHandle *hand, cpArray *pooledHandles)
@ -55,7 +50,7 @@ cpSpaceHashAlloc(void)
return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash)); return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash));
} }
// Frees the old table, and allocates a new one. // Frees the old table, and allocate a new one.
static void static void
cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells) cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
{ {
@ -66,12 +61,7 @@ cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
} }
// Equality function for the handleset. // Equality function for the handleset.
static int static int handleSetEql(void *obj, cpHandle *hand){return (obj == hand->obj);}
handleSetEql(void *obj, void *elt)
{
cpHandle *hand = (cpHandle *)elt;
return (obj == hand->obj);
}
// Transformation function for the handleset. // Transformation function for the handleset.
static void * static void *
@ -101,7 +91,7 @@ cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBF
hash->celldim = celldim; hash->celldim = celldim;
hash->bbfunc = bbfunc; hash->bbfunc = bbfunc;
hash->handleSet = cpHashSetNew(0, handleSetEql, (cpHashSetTransFunc)handleSetTrans); hash->handleSet = cpHashSetNew(0, (cpHashSetEqlFunc)handleSetEql, (cpHashSetTransFunc)handleSetTrans);
hash->pooledHandles = cpArrayNew(0); hash->pooledHandles = cpArrayNew(0);
hash->pooledBins = NULL; hash->pooledBins = NULL;
@ -132,7 +122,6 @@ clearHashCell(cpSpaceHash *hash, int idx)
while(bin){ while(bin){
cpSpaceHashBin *next = bin->next; cpSpaceHashBin *next = bin->next;
// Release the lock on the handle.
cpHandleRelease(bin->handle, hash->pooledHandles); cpHandleRelease(bin->handle, hash->pooledHandles);
recycleBin(hash, bin); recycleBin(hash, bin);
@ -186,15 +175,15 @@ cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)
} }
// Return true if the chain contains the handle. // Return true if the chain contains the handle.
static inline int static inline cpBool
containsHandle(cpSpaceHashBin *bin, cpHandle *hand) containsHandle(cpSpaceHashBin *bin, cpHandle *hand)
{ {
while(bin){ while(bin){
if(bin->handle == hand) return 1; if(bin->handle == hand) return cpTrue;
bin = bin->next; bin = bin->next;
} }
return 0; return cpFalse;
} }
// Get a recycled or new bin. // Get a recycled or new bin.
@ -266,36 +255,32 @@ hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
} }
void void
cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB bb) cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB _deprecated_unused)
{ {
cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash); cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash);
hashHandle(hash, hand, bb); hashHandle(hash, hand, hash->bbfunc(obj));
} }
void void
cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid) cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid)
{ {
cpHandle *hand = (cpHandle *)cpHashSetFind(hash->handleSet, hashid, obj); cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
hashHandle(hash, hand, hash->bbfunc(obj));
if(hand){
hand->obj = NULL;
cpHandleRelease(hand, hash->pooledHandles);
cpSpaceHashInsert(hash, obj, hashid, cpBBNew(0.0f, 0.0f, 0.0f, 0.0f));
}
} }
// Hashset iterator function for rehashing the spatial hash. (hash hash hash hash?) static void handleRehashHelper(cpHandle *hand, cpSpaceHash *hash){hashHandle(hash, hand, hash->bbfunc(hand->obj));}
static void
handleRehashHelper(void *elt, void *data)
{
cpHandle *hand = (cpHandle *)elt;
cpSpaceHash *hash = (cpSpaceHash *)data;
hashHandle(hash, hand, hash->bbfunc(hand->obj));
}
void void
cpSpaceHashRehash(cpSpaceHash *hash) cpSpaceHashRehash(cpSpaceHash *hash)
{ {
clearHash(hash); clearHash(hash);
cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)handleRehashHelper, hash);
// Rehash all of the handles.
cpHashSetEach(hash->handleSet, &handleRehashHelper, hash);
} }
void void
@ -309,54 +294,63 @@ cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid)
} }
} }
// Used by the cpSpaceHashEach() iterator.
typedef struct eachPair { typedef struct eachPair {
cpSpaceHashIterator func; cpSpaceHashIterator func;
void *data; void *data;
} eachPair; } eachPair;
// Calls the user iterator function. (Gross I know.) static void eachHelper(cpHandle *hand, eachPair *pair){pair->func(hand->obj, pair->data);}
static void
eachHelper(void *elt, void *data)
{
cpHandle *hand = (cpHandle *)elt;
eachPair *pair = (eachPair *)data;
pair->func(hand->obj, pair->data);
}
// Iterate over the objects in the spatial hash. // Iterate over the objects in the spatial hash.
void void
cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data) cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)
{ {
// Bundle the callback up to send to the hashset iterator.
eachPair pair = {func, data}; eachPair pair = {func, data};
cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)eachHelper, &pair);
}
cpHashSetEach(hash->handleSet, &eachHelper, &pair); static inline void
removeOrphanedHandles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr)
{
cpSpaceHashBin *bin = *bin_ptr;
while(bin){
cpHandle *hand = bin->handle;
cpSpaceHashBin *next = bin->next;
if(!hand->obj){
// orphaned handle, unlink and recycle the bin
(*bin_ptr) = bin->next;
recycleBin(hash, bin);
cpHandleRelease(hand, hash->pooledHandles);
} else {
bin_ptr = &bin->next;
}
bin = next;
}
} }
// Calls the callback function for the objects in a given chain. // Calls the callback function for the objects in a given chain.
static inline void static inline void
query(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashQueryFunc func, void *data) query(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashQueryFunc func, void *data)
{ {
for(; bin; bin = bin->next){ restart:
for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
cpHandle *hand = bin->handle; cpHandle *hand = bin->handle;
void *other = hand->obj; void *other = hand->obj;
// Skip over certain conditions if(hand->stamp == hash->stamp || obj == other){
if( continue;
// Have we already tried this pair in this query? } else if(other){
hand->stamp == hash->stamp
// Is obj the same as other?
|| obj == other
// Has other been removed since the last rehash?
|| !other
) continue;
func(obj, other, data); func(obj, other, data);
// Stamp that the handle was checked already against this object.
hand->stamp = hash->stamp; hand->stamp = hash->stamp;
} else {
// The object for this handle has been removed
// cleanup this cell and restart the query
removeOrphanedHandles(hash, bin_ptr);
goto restart; // GCC not smart enough/able to tail call an inlined function.
}
} }
} }
@ -366,10 +360,7 @@ cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func
cpFloat dim = hash->celldim; cpFloat dim = hash->celldim;
int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells); // Fix by ShiftZ int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells); // Fix by ShiftZ
query(hash, hash->table[idx], &point, func, data); query(hash, &hash->table[idx], &point, func, data);
// Increment the stamp.
// Only one cell is checked, but query() requires it anyway.
hash->stamp++; hash->stamp++;
} }
@ -384,16 +375,15 @@ cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc fun
int t = floor_int(bb.t/dim); int t = floor_int(bb.t/dim);
int n = hash->numcells; int n = hash->numcells;
cpSpaceHashBin **table = hash->table;
// Iterate over the cells and query them. // Iterate over the cells and query them.
for(int i=l; i<=r; i++){ for(int i=l; i<=r; i++){
for(int j=b; j<=t; j++){ for(int j=b; j<=t; j++){
int idx = hash_func(i,j,n); query(hash, &table[hash_func(i,j,n)], obj, func, data);
query(hash, hash->table[idx], obj, func, data);
} }
} }
// Increment the stamp.
hash->stamp++; hash->stamp++;
} }
@ -426,28 +416,26 @@ handleQueryRehashHelper(void *elt, void *data)
int b = floor_int(bb.b/dim); int b = floor_int(bb.b/dim);
int t = floor_int(bb.t/dim); int t = floor_int(bb.t/dim);
cpSpaceHashBin **table = hash->table;
for(int i=l; i<=r; i++){ for(int i=l; i<=r; i++){
for(int j=b; j<=t; j++){ for(int j=b; j<=t; j++){
// // exit the loops if the object has been deleted in func().
// if(!hand->obj) goto break_out;
int idx = hash_func(i,j,n); int idx = hash_func(i,j,n);
cpSpaceHashBin *bin = hash->table[idx]; cpSpaceHashBin *bin = table[idx];
if(containsHandle(bin, hand)) continue; if(containsHandle(bin, hand)) continue;
cpHandleRetain(hand); // this MUST be done first in case the object is removed in func() cpHandleRetain(hand); // this MUST be done first in case the object is removed in func()
query(hash, bin, obj, func, pair->data); query(hash, &bin, obj, func, pair->data);
cpSpaceHashBin *newBin = getEmptyBin(hash); cpSpaceHashBin *newBin = getEmptyBin(hash);
newBin->handle = hand; newBin->handle = hand;
newBin->next = bin; newBin->next = bin;
hash->table[idx] = newBin; table[idx] = newBin;
} }
} }
// break_out: // Increment the stamp for each object hashed.
// Increment the stamp for each object we hash.
hash->stamp++; hash->stamp++;
} }
@ -461,26 +449,27 @@ cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)
} }
static inline cpFloat static inline cpFloat
segmentQuery(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashSegmentQueryFunc func, void *data) segmentQuery(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashSegmentQueryFunc func, void *data)
{ {
cpFloat t = 1.0f; cpFloat t = 1.0f;
for(; bin; bin = bin->next){ restart:
for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
cpHandle *hand = bin->handle; cpHandle *hand = bin->handle;
void *other = hand->obj; void *other = hand->obj;
// Skip over certain conditions // Skip over certain conditions
if( if(hand->stamp == hash->stamp){
// Have we already tried this pair in this query? continue;
hand->stamp == hash->stamp } else if(other){
// Has other been removed since the last rehash?
|| !other
) continue;
// Stamp that the handle was checked already against this object.
hand->stamp = hash->stamp;
t = cpfmin(t, func(obj, other, data)); t = cpfmin(t, func(obj, other, data));
hand->stamp = hash->stamp;
} else {
// The object for this handle has been removed
// cleanup this cell and restart the query
removeOrphanedHandles(hash, bin_ptr);
goto restart; // GCC not smart enough/able to tail call an inlined function.
}
} }
return t; return t;
@ -492,8 +481,6 @@ void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, c
a = cpvmult(a, 1.0f/hash->celldim); a = cpvmult(a, 1.0f/hash->celldim);
b = cpvmult(b, 1.0f/hash->celldim); b = cpvmult(b, 1.0f/hash->celldim);
cpFloat dt_dx = 1.0f/cpfabs(b.x - a.x), dt_dy = 1.0f/cpfabs(b.y - a.y);
int cell_x = floor_int(a.x), cell_y = floor_int(a.y); int cell_x = floor_int(a.x), cell_y = floor_int(a.y);
cpFloat t = 0; cpFloat t = 0;
@ -517,14 +504,20 @@ void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, c
temp_v = (a.y - cpffloor(a.y)); temp_v = (a.y - cpffloor(a.y));
} }
// Division by zero is *very* slow on ARM
cpFloat dx = cpfabs(b.x - a.x), dy = cpfabs(b.y - a.y);
cpFloat dt_dx = (dx ? 1.0f/dx : INFINITY), dt_dy = (dy ? 1.0f/dy : INFINITY);
// fix NANs in horizontal directions // fix NANs in horizontal directions
cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx); cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx);
cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy); cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy);
cpSpaceHashBin **table = hash->table;
int n = hash->numcells; int n = hash->numcells;
while(t < t_exit){ while(t < t_exit){
int idx = hash_func(cell_x, cell_y, n); int idx = hash_func(cell_x, cell_y, n);
t_exit = cpfmin(t_exit, segmentQuery(hash, hash->table[idx], obj, func, data)); t_exit = cpfmin(t_exit, segmentQuery(hash, &table[idx], obj, func, data));
if (next_v < next_h){ if (next_v < next_h){
cell_y += y_inc; cell_y += y_inc;