Updated Chipmunk to 6.1.2

This commit is contained in:
spartanj@gmail.com
2012-11-23 22:55:47 -03:00
parent 5f60e288db
commit c031cd80f9
54 changed files with 1696 additions and 1193 deletions

View File

@@ -19,12 +19,12 @@
* SOFTWARE.
*/
/// @defgroup misc Misc
/// @{
#ifndef CHIPMUNK_HEADER
#define CHIPMUNK_HEADER
#include <stdlib.h>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -39,40 +39,45 @@ extern "C" {
#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 *condition, const char *file, int line, int isError, int isHardError, const char *message, ...);
#ifdef NDEBUG
#define cpAssertWarn(condition, message)
#define cpAssertWarn(condition, ...)
#else
#define cpAssertWarn(condition, message) if(!(condition)) cpMessage(message, #condition, __FILE__, __LINE__, 0)
#define cpAssertWarn(condition, ...) if(!(condition)) cpMessage(#condition, __FILE__, __LINE__, 0, 0, __VA_ARGS__)
#endif
#ifdef NDEBUG
#define cpAssertSoft(condition, ...)
#else
#define cpAssertSoft(condition, ...) if(!(condition)) cpMessage(#condition, __FILE__, __LINE__, 1, 0, __VA_ARGS__)
#endif
// Hard assertions are important and cheap to execute. They are not disabled by compiling as debug.
#define cpAssertHard(condition, message) if(!(condition)) cpMessage(message, #condition, __FILE__, __LINE__, 1)
#ifdef NDEBUG
#define cpAssertSoft(condition, message)
#else
#define cpAssertSoft(condition, message) cpAssertHard(condition, message)
#endif
#define cpAssertHard(condition, ...) if(!(condition)) cpMessage(#condition, __FILE__, __LINE__, 1, 1, __VA_ARGS__)
#include "chipmunk_types.h"
// Allocated size for various Chipmunk buffers
/// @defgroup misc Misc
/// @{
/// Allocated size for various Chipmunk buffers
#ifndef CP_BUFFER_BYTES
#define CP_BUFFER_BYTES (32*1024)
#endif
// Chipmunk memory function aliases.
#ifndef cpcalloc
/// Chipmunk calloc() alias.
#define cpcalloc calloc
#endif
#ifndef cprealloc
/// Chipmunk realloc() alias.
#define cprealloc realloc
#endif
#ifndef cpfree
/// Chipmunk free() alias.
#define cpfree free
#endif
@@ -101,9 +106,10 @@ typedef struct cpSpace cpSpace;
#include "cpSpace.h"
// Chipmunk 6.1.2
#define CP_VERSION_MAJOR 6
#define CP_VERSION_MINOR 0
#define CP_VERSION_RELEASE 0
#define CP_VERSION_MINOR 1
#define CP_VERSION_RELEASE 2
/// Version string.
extern const char *cpVersionString;
@@ -111,6 +117,10 @@ extern const char *cpVersionString;
/// @deprecated
void cpInitChipmunk(void);
/// Enables segment to segment shape collisions.
void cpEnableSegmentToSegmentCollisions(void);
/// Calculate the moment of inertia for a circle.
/// @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);
@@ -145,6 +155,56 @@ cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height);
/// Calculate the moment of inertia for a solid box.
cpFloat cpMomentForBox2(cpFloat m, cpBB box);
/// Calculate the convex hull of a given set of points. Returns the count of points in the hull.
/// @c result must be a pointer to a @c cpVect array with at least @c count elements. If @c result is @c NULL, then @c verts will be reduced instead.
/// @c first is an optional pointer to an integer to store where the first vertex in the hull came from (i.e. verts[first] == result[0])
/// @c tol is the allowed amount to shrink the hull when simplifying it. A tolerance of 0.0 creates an exact hull.
int cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol);
#ifdef _MSC_VER
#include "malloc.h"
#endif
/// Convenience macro to work with cpConvexHull.
/// @c count and @c verts is the input array passed to cpConvexHull().
/// @c count_var and @c verts_var are the names of the variables the macro creates to store the result.
/// The output vertex array is allocated on the stack using alloca() so it will be freed automatically, but cannot be returned from the current scope.
#define CP_CONVEX_HULL(__count__, __verts__, __count_var__, __verts_var__) \
cpVect *__verts_var__ = (cpVect *)alloca(__count__*sizeof(cpVect)); \
int __count_var__ = cpConvexHull(__count__, __verts__, __verts_var__, NULL, 0.0); \
#if defined(__has_extension)
#if __has_extension(blocks)
// Define alternate block based alternatives for a few of the callback heavy functions.
// Collision handlers are post-step callbacks are not included to avoid memory management issues.
// If you want to use blocks for those and are aware of how to correctly manage the memory, the implementation is trivial.
void cpSpaceEachBody_b(cpSpace *space, void (^block)(cpBody *body));
void cpSpaceEachShape_b(cpSpace *space, void (^block)(cpShape *shape));
void cpSpaceEachConstraint_b(cpSpace *space, void (^block)(cpConstraint *constraint));
void cpBodyEachShape_b(cpBody *body, void (^block)(cpShape *shape));
void cpBodyEachConstraint_b(cpBody *body, void (^block)(cpConstraint *constraint));
void cpBodyEachArbiter_b(cpBody *body, void (^block)(cpArbiter *arbiter));
typedef void (^cpSpaceNearestPointQueryBlock)(cpShape *shape, cpFloat distance, cpVect point);
void cpSpaceNearestPointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryBlock block);
typedef void (^cpSpaceSegmentQueryBlock)(cpShape *shape, cpFloat t, cpVect n);
void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryBlock block);
typedef void (^cpSpaceBBQueryBlock)(cpShape *shape);
void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryBlock block);
typedef void (^cpSpaceShapeQueryBlock)(cpShape *shape, cpContactPointSet *points);
cpBool cpSpaceShapeQuery_b(cpSpace *space, cpShape *shape, cpSpaceShapeQueryBlock block);
#endif
#endif
//@}
#ifdef __cplusplus
}
@@ -156,4 +216,3 @@ static inline cpVect operator -(const cpVect v){return cpvneg(v);}
#endif
#endif
//@}

View File

@@ -14,7 +14,7 @@
#endif
#define MAKE_PROPERTIES_REF(struct, property) \
MAKE_REF(struct##Get##property); MAKE_REF(struct##Set##property);
MAKE_REF(struct##Get##property); MAKE_REF(struct##Set##property)
MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv()
MAKE_REF(cpveql);
@@ -47,6 +47,7 @@ MAKE_REF(cpflerp);
MAKE_REF(cpflerpconst);
MAKE_REF(cpBBNew);
MAKE_REF(cpBBNewForCircle);
MAKE_REF(cpBBIntersects);
MAKE_REF(cpBBContainsBB);
MAKE_REF(cpBBContainsVect);
@@ -54,6 +55,7 @@ MAKE_REF(cpBBMerge);
MAKE_REF(cpBBExpand);
MAKE_REF(cpBBArea);
MAKE_REF(cpBBMergedArea);
MAKE_REF(cpBBSegmentQuery);
MAKE_REF(cpBBIntersectsSegment);
MAKE_REF(cpBodyGetMass);
@@ -77,7 +79,7 @@ MAKE_REF(cpBodyKineticEnergy);
MAKE_REF(cpShapeGetBB);
MAKE_PROPERTIES_REF(cpShape, Body);
MAKE_PROPERTIES_REF(cpShape, IsSensor);
MAKE_PROPERTIES_REF(cpShape, Sensor);
MAKE_PROPERTIES_REF(cpShape, Elasticity);
MAKE_PROPERTIES_REF(cpShape, Friction);
MAKE_PROPERTIES_REF(cpShape, SurfaceVelocity);
@@ -150,9 +152,22 @@ MAKE_REF(cpSpatialIndexInsert);
MAKE_REF(cpSpatialIndexRemove);
MAKE_REF(cpSpatialIndexReindex);
MAKE_REF(cpSpatialIndexReindexObject);
MAKE_REF(cpSpatialIndexPointQuery);
MAKE_REF(cpSpatialIndexSegmentQuery);
MAKE_REF(cpSpatialIndexQuery);
MAKE_REF(cpSpatialIndexReindexQuery);
MAKE_PROPERTIES_REF(cpSpace, Iterations);
MAKE_PROPERTIES_REF(cpSpace, Gravity);
MAKE_PROPERTIES_REF(cpSpace, Damping);
MAKE_PROPERTIES_REF(cpSpace, IdleSpeedThreshold);
MAKE_PROPERTIES_REF(cpSpace, SleepTimeThreshold);
MAKE_PROPERTIES_REF(cpSpace, CollisionSlop);
MAKE_PROPERTIES_REF(cpSpace, CollisionBias);
MAKE_PROPERTIES_REF(cpSpace, CollisionPersistence);
MAKE_PROPERTIES_REF(cpSpace, EnableContactGraph);
MAKE_PROPERTIES_REF(cpSpace, UserData);
MAKE_REF(cpSpaceGetStaticBody);
MAKE_REF(cpSpaceGetCurrentTimeStep);
MAKE_REF(cpSpaceIsLocked);
#endif

View File

@@ -25,7 +25,7 @@
#define CP_HASH_COEF (3344921057ul)
#define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF)
#pragma mark cpArray
//MARK: cpArray
struct cpArray {
int num, max;
@@ -43,7 +43,7 @@ cpBool cpArrayContains(cpArray *arr, void *ptr);
void cpArrayFreeEach(cpArray *arr, void (freeFunc)(void*));
#pragma mark Foreach loops
//MARK: Foreach loops
static inline cpConstraint *
cpConstraintNext(cpConstraint *node, cpBody *body)
@@ -69,7 +69,7 @@ cpArbiterNext(cpArbiter *node, cpBody *body)
#define CP_BODY_FOREACH_COMPONENT(root, var)\
for(cpBody *var = root; var; var = var->node.next)
#pragma mark cpHashSet
//MARK: cpHashSet
typedef cpBool (*cpHashSetEqlFunc)(void *ptr, void *elt);
typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
@@ -90,25 +90,51 @@ void cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data);
typedef cpBool (*cpHashSetFilterFunc)(void *elt, void *data);
void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data);
#pragma mark Body Functions
//MARK: Body Functions
void cpBodyAddShape(cpBody *body, cpShape *shape);
void cpBodyRemoveShape(cpBody *body, cpShape *shape);
void cpBodyRemoveConstraint(cpBody *body, cpConstraint *constraint);
#pragma mark Shape/Collision Functions
//MARK: Shape/Collision Functions
// TODO should move this to the cpVect API. It's pretty useful.
static inline cpVect
cpClosetPointOnSegment(const cpVect p, const cpVect a, const cpVect b)
{
cpVect delta = cpvsub(a, b);
cpFloat t = cpfclamp01(cpvdot(delta, cpvsub(p, b))/cpvlengthsq(delta));
return cpvadd(b, cpvmult(delta, t));
}
cpShape* cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body);
static inline cpBool
cpShapeActive(cpShape *shape)
{
return shape->prev || shape->body->shapeList == shape;
return shape->prev || (shape->body && shape->body->shapeList == shape);
}
int cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr);
// TODO doesn't really need to be inline, but need a better place to put this function
static inline cpSplittingPlane
cpSplittingPlaneNew(cpVect a, cpVect b)
{
cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));
cpSplittingPlane plane = {n, cpvdot(n, a)};
return plane;
}
static inline cpFloat
cpSplittingPlaneCompare(cpSplittingPlane plane, cpVect v)
{
return cpvdot(plane.n, v) - plane.d;
}
void cpLoopIndexes(cpVect *verts, int count, int *start, int *end);
static inline cpFloat
cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
{
@@ -125,10 +151,10 @@ cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
static inline cpBool
cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
{
cpPolyShapeAxis *axes = poly->tAxes;
cpSplittingPlane *planes = poly->tPlanes;
for(int i=0; i<poly->numVerts; i++){
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
cpFloat dist = cpSplittingPlaneCompare(planes[i], v);
if(dist > 0.0f) return cpFalse;
}
@@ -138,31 +164,39 @@ cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
static inline cpBool
cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n)
{
cpPolyShapeAxis *axes = poly->tAxes;
cpSplittingPlane *planes = poly->tPlanes;
for(int i=0; i<poly->numVerts; i++){
if(cpvdot(axes[i].n, n) < 0.0f) continue;
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
if(cpvdot(planes[i].n, n) < 0.0f) continue;
cpFloat dist = cpSplittingPlaneCompare(planes[i], v);
if(dist > 0.0f) return cpFalse;
}
return cpTrue;
}
#pragma mark Spatial Index Functions
//MARK: Spatial Index Functions
cpSpatialIndex *cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
#pragma mark Space Functions
//MARK: Space Functions
extern cpCollisionHandler cpDefaultCollisionHandler;
void cpSpaceProcessComponents(cpSpace *space, cpFloat dt);
void cpSpacePushFreshContactBuffer(cpSpace *space);
cpContact *cpContactBufferGetArray(cpSpace *space);
void cpSpacePushContacts(cpSpace *space, int count);
void *cpSpaceGetPostStepData(cpSpace *space, void *obj);
typedef struct cpPostStepCallback {
cpPostStepFunc func;
void *key;
void *data;
} cpPostStepCallback;
cpPostStepCallback *cpSpaceGetPostStepCallback(cpSpace *space, void *key);
cpBool cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space);
void cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter);
void cpSpaceActivateBody(cpSpace *space, cpBody *body);
@@ -186,7 +220,12 @@ cpSpaceUncacheArbiter(cpSpace *space, cpArbiter *arb)
cpArrayDeleteObj(space->arbiters, arb);
}
#pragma mark Arbiters
void cpShapeUpdateFunc(cpShape *shape, void *unused);
void cpSpaceCollideShapes(cpShape *a, cpShape *b, cpSpace *space);
//MARK: Arbiters
struct cpContact {
cpVect p, n;

View File

@@ -1,16 +1,18 @@
#include <stdint.h>
#ifdef __APPLE__
#import "TargetConditionals.h"
#include "TargetConditionals.h"
#endif
#if (defined TARGET_OS_IPHONE) && (!defined CP_USE_CGPOINTS)
#define CP_USE_CGPOINTS
#if (TARGET_OS_IPHONE == 1) || (TARGET_OS_MAC == 1) && (!defined CP_USE_CGPOINTS)
#define CP_USE_CGPOINTS 1
#endif
#ifdef CP_USE_CGPOINTS
#if CP_USE_CGPOINTS == 1
#if TARGET_OS_IPHONE
#import <CoreGraphics/CGGeometry.h>
#elif TARGET_OS_MAC
#import <ApplicationServices/ApplicationServices.h>
#include <ApplicationServices/ApplicationServices.h>
#endif
#if defined(__LP64__) && __LP64__
@@ -58,7 +60,6 @@
#endif
#ifndef INFINITY
//TODO use C++ infinity
#ifdef _MSC_VER
union MSVC_EVIL_FLOAT_HACK
{
@@ -132,15 +133,10 @@ static inline cpFloat cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
}
/// Hash value type.
#include "../sophist/sophist.h"
#if 1 == SOPHIST_pointer64
typedef SOPHIST_uint64 cpHashValue;
#else
typedef SOPHIST_uint32 cpHashValue;
#endif
typedef uintptr_t cpHashValue;
// Oh C, how we love to define our own boolean types to get compiler compatibility
/// Chipmunk's boolean type.
/// 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
@@ -168,18 +164,18 @@ typedef SOPHIST_uint32 cpHashValue;
typedef CP_COLLISION_TYPE_TYPE cpCollisionType;
#else
/// Type used for cpSpace.collision_type.
typedef unsigned int cpCollisionType;
typedef uintptr_t cpCollisionType;
#endif
#ifdef CP_GROUP_TYPE
typedef CP_GROUP_TYPE cpGroup;
#else
/// Type used for cpShape.group.
typedef unsigned int cpGroup;
typedef uintptr_t cpGroup;
#endif
#ifdef CP_LAYERS_TYPE
typedef CP_GROUP_TYPE cpLayers;
typedef CP_LAYERS_TYPE cpLayers;
#else
/// Type used for cpShape.layers.
typedef unsigned int cpLayers;
@@ -205,7 +201,7 @@ typedef SOPHIST_uint32 cpHashValue;
// CGPoints are structurally the same, and allow
// easy interoperability with other Cocoa libraries
#ifdef CP_USE_CGPOINTS
#if CP_USE_CGPOINTS
typedef CGPoint cpVect;
#else
/// Chipmunk's 2D vector type.
@@ -213,4 +209,7 @@ typedef SOPHIST_uint32 cpHashValue;
typedef struct cpVect{cpFloat x,y;} cpVect;
#endif
typedef struct cpMat2x2 {
// Row major [[a, b][c d]]
cpFloat a, b, c, d;
} cpMat2x2;

View File

@@ -26,7 +26,7 @@ typedef struct cpConstraintClass cpConstraintClass;
typedef void (*cpConstraintPreStepImpl)(cpConstraint *constraint, cpFloat dt);
typedef void (*cpConstraintApplyCachedImpulseImpl)(cpConstraint *constraint, cpFloat dt_coef);
typedef void (*cpConstraintApplyImpulseImpl)(cpConstraint *constraint);
typedef void (*cpConstraintApplyImpulseImpl)(cpConstraint *constraint, cpFloat dt);
typedef cpFloat (*cpConstraintGetImpulseImpl)(cpConstraint *constraint);
/// @private
@@ -37,6 +37,11 @@ struct cpConstraintClass {
cpConstraintGetImpulseImpl getImpulse;
};
/// Callback function type that gets called before solving a joint.
typedef void (*cpConstraintPreSolveFunc)(cpConstraint *constraint, cpSpace *space);
/// Callback function type that gets called after solving a joint.
typedef void (*cpConstraintPostSolveFunc)(cpConstraint *constraint, cpSpace *space);
/// Opaque cpConstraint struct.
struct cpConstraint {
@@ -63,6 +68,14 @@ struct cpConstraint {
/// Defaults to infinity.
cpFloat maxBias;
/// Function called before the solver runs.
/// Animate your joint anchors, update your motor torque, etc.
cpConstraintPreSolveFunc preSolve;
/// Function called after the solver runs.
/// Use the applied impulse to perform effects like breakable joints.
cpConstraintPostSolveFunc postSolve;
/// User definable data pointer.
/// Generally this points to your the game object class so you can access it
/// when given a cpConstraint reference in a callback.
@@ -81,27 +94,34 @@ static inline void cpConstraintActivateBodies(cpConstraint *constraint)
cpBody *b = constraint->b; if(b) cpBodyActivate(b);
}
/// @private
#define CP_DefineConstraintStructGetter(type, member, name) \
static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;}
/// @private
#define CP_DefineConstraintStructSetter(type, member, name) \
static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \
cpConstraintActivateBodies(constraint); \
constraint->member = value; \
}
/// @private
#define CP_DefineConstraintStructProperty(type, member, name) \
CP_DefineConstraintStructGetter(type, member, name) \
CP_DefineConstraintStructSetter(type, member, name)
CP_DefineConstraintStructGetter(cpBody *, a, A);
CP_DefineConstraintStructGetter(cpBody *, b, B);
CP_DefineConstraintStructProperty(cpFloat, maxForce, MaxForce);
CP_DefineConstraintStructProperty(cpFloat, errorBias, ErrorBias);
CP_DefineConstraintStructProperty(cpFloat, maxBias, MaxBias);
CP_DefineConstraintStructProperty(cpDataPointer, data, UserData);
CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
/// Get the last impulse applied by this constraint.
CP_DefineConstraintStructGetter(cpBody*, a, A)
CP_DefineConstraintStructGetter(cpBody*, b, B)
CP_DefineConstraintStructProperty(cpFloat, maxForce, MaxForce)
CP_DefineConstraintStructProperty(cpFloat, errorBias, ErrorBias)
CP_DefineConstraintStructProperty(cpFloat, maxBias, MaxBias)
CP_DefineConstraintStructProperty(cpConstraintPreSolveFunc, preSolve, PreSolveFunc)
CP_DefineConstraintStructProperty(cpConstraintPostSolveFunc, postSolve, PostSolveFunc)
CP_DefineConstraintStructProperty(cpDataPointer, data, UserData)
// Get the last impulse applied by this constraint.
static inline cpFloat cpConstraintGetImpulse(cpConstraint *constraint)
{
return constraint->CP_PRIVATE(klass)->getImpulse(constraint);

View File

@@ -24,8 +24,9 @@
typedef cpFloat (*cpDampedRotarySpringTorqueFunc)(struct cpConstraint *spring, cpFloat relativeAngle);
const cpConstraintClass *cpDampedRotarySpringGetClass();
const cpConstraintClass *cpDampedRotarySpringGetClass(void);
/// @private
typedef struct cpDampedRotarySpring {
cpConstraint constraint;
cpFloat restAngle;
@@ -40,15 +41,15 @@ typedef struct cpDampedRotarySpring {
} cpDampedRotarySpring;
/// Allocate a damped rotary spring.
cpDampedRotarySpring *cpDampedRotarySpringAlloc(void);
cpDampedRotarySpring* cpDampedRotarySpringAlloc(void);
/// Initialize a damped rotary spring.
cpDampedRotarySpring *cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
cpDampedRotarySpring* cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
/// Allocate and initialize a damped rotary spring.
cpConstraint *cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
cpConstraint* cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle);
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness);
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping);
CP_DefineConstraintProperty(cpDampedRotarySpring, cpDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc);
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle)
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness)
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping)
CP_DefineConstraintProperty(cpDampedRotarySpring, cpDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc)
/// @}

View File

@@ -26,7 +26,7 @@ typedef struct cpDampedSpring cpDampedSpring;
typedef cpFloat (*cpDampedSpringForceFunc)(cpConstraint *spring, cpFloat dist);
const cpConstraintClass *cpDampedSpringGetClass();
const cpConstraintClass *cpDampedSpringGetClass(void);
/// @private
struct cpDampedSpring {
@@ -46,17 +46,17 @@ struct cpDampedSpring {
};
/// Allocate a damped spring.
cpDampedSpring *cpDampedSpringAlloc(void);
cpDampedSpring* cpDampedSpringAlloc(void);
/// Initialize a damped spring.
cpDampedSpring *cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
cpDampedSpring* cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
/// Allocate and initialize a damped spring.
cpConstraint *cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
cpConstraint* cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1);
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr2, Anchr2);
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, restLength, RestLength);
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, stiffness, Stiffness);
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, damping, Damping);
CP_DefineConstraintProperty(cpDampedSpring, cpDampedSpringForceFunc, springForceFunc, SpringForceFunc);
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr2, Anchr2)
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, restLength, RestLength)
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, stiffness, Stiffness)
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, damping, Damping)
CP_DefineConstraintProperty(cpDampedSpring, cpDampedSpringForceFunc, springForceFunc, SpringForceFunc)
/// @}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpGearJoint cpGearJoint
/// @{
const cpConstraintClass *cpGearJointGetClass();
const cpConstraintClass *cpGearJointGetClass(void);
/// @private
typedef struct cpGearJoint {
@@ -33,18 +33,18 @@ typedef struct cpGearJoint {
cpFloat iSum;
cpFloat bias;
cpFloat jAcc, jMax;
cpFloat jAcc;
} cpGearJoint;
/// Allocate a gear joint.
cpGearJoint *cpGearJointAlloc(void);
cpGearJoint* cpGearJointAlloc(void);
/// Initialize a gear joint.
cpGearJoint *cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
cpGearJoint* cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
/// Allocate and initialize a gear joint.
cpConstraint *cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
cpConstraint* cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase);
CP_DefineConstraintGetter(cpGearJoint, cpFloat, ratio, Ratio);
CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase)
CP_DefineConstraintGetter(cpGearJoint, cpFloat, ratio, Ratio)
/// Set the ratio of a gear joint.
void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value);

View File

@@ -22,7 +22,7 @@
/// @defgroup cpGrooveJoint cpGrooveJoint
/// @{
const cpConstraintClass *cpGrooveJointGetClass();
const cpConstraintClass *cpGrooveJointGetClass(void);
/// @private
typedef struct cpGrooveJoint {
@@ -33,26 +33,25 @@ typedef struct cpGrooveJoint {
cpVect grv_tn;
cpFloat clamp;
cpVect r1, r2;
cpVect k1, k2;
cpMat2x2 k;
cpVect jAcc;
cpFloat jMaxLen;
cpVect bias;
} cpGrooveJoint;
/// Allocate a groove joint.
cpGrooveJoint *cpGrooveJointAlloc(void);
cpGrooveJoint* cpGrooveJointAlloc(void);
/// Initialize a groove joint.
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);
/// Allocate and initialize a groove joint.
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);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA)
/// Set endpoint a of a groove joint's groove
void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB);
CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB)
/// Set endpoint b of a groove joint's groove
void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value);
CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2);
CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2)
/// @}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpPinJoint cpPinJoint
/// @{
const cpConstraintClass *cpPinJointGetClass();
const cpConstraintClass *cpPinJointGetClass(void);
/// @private
typedef struct cpPinJoint {
@@ -34,19 +34,19 @@ typedef struct cpPinJoint {
cpVect n;
cpFloat nMass;
cpFloat jnAcc, jnMax;
cpFloat jnAcc;
cpFloat bias;
} cpPinJoint;
/// Allocate a pin joint.
cpPinJoint *cpPinJointAlloc(void);
cpPinJoint* cpPinJointAlloc(void);
/// Initialize a pin joint.
cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
cpPinJoint* cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
/// Allocate and initialize a pin joint.
cpConstraint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
cpConstraint* cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1);
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr2, Anchr2);
CP_DefineConstraintProperty(cpPinJoint, cpFloat, dist, Dist);
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr2, Anchr2)
CP_DefineConstraintProperty(cpPinJoint, cpFloat, dist, Dist)
///@}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpPivotJoint cpPivotJoint
/// @{
const cpConstraintClass *cpPivotJointGetClass();
const cpConstraintClass *cpPivotJointGetClass(void);
/// @private
typedef struct cpPivotJoint {
@@ -30,23 +30,22 @@ typedef struct cpPivotJoint {
cpVect anchr1, anchr2;
cpVect r1, r2;
cpVect k1, k2;
cpMat2x2 k;
cpVect jAcc;
cpFloat jMaxLen;
cpVect bias;
} cpPivotJoint;
/// Allocate a pivot joint
cpPivotJoint *cpPivotJointAlloc(void);
cpPivotJoint* cpPivotJointAlloc(void);
/// Initialize a pivot joint.
cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
cpPivotJoint* cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
/// Allocate and initialize a pivot joint.
cpConstraint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);
cpConstraint* cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);
/// Allocate and initialize a pivot joint with specific anchors.
cpConstraint *cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
cpConstraint* cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1);
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2);
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2)
/// @}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpRatchetJoint cpRatchetJoint
/// @{
const cpConstraintClass *cpRatchetJointGetClass();
const cpConstraintClass *cpRatchetJointGetClass(void);
/// @private
typedef struct cpRatchetJoint {
@@ -32,18 +32,18 @@ typedef struct cpRatchetJoint {
cpFloat iSum;
cpFloat bias;
cpFloat jAcc, jMax;
cpFloat jAcc;
} cpRatchetJoint;
/// Allocate a ratchet joint.
cpRatchetJoint *cpRatchetJointAlloc(void);
cpRatchetJoint* cpRatchetJointAlloc(void);
/// Initialize a ratched joint.
cpRatchetJoint *cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
cpRatchetJoint* cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
/// Allocate and initialize a ratchet joint.
cpConstraint *cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
cpConstraint* cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, angle, Angle);
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, phase, Phase);
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, ratchet, Ratchet);
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, angle, Angle)
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, phase, Phase)
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, ratchet, Ratchet)
/// @}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpRotaryLimitJoint cpRotaryLimitJoint
/// @{
const cpConstraintClass *cpRotaryLimitJointGetClass();
const cpConstraintClass *cpRotaryLimitJointGetClass(void);
/// @private
typedef struct cpRotaryLimitJoint {
@@ -32,17 +32,17 @@ typedef struct cpRotaryLimitJoint {
cpFloat iSum;
cpFloat bias;
cpFloat jAcc, jMax;
cpFloat jAcc;
} cpRotaryLimitJoint;
/// Allocate a damped rotary limit joint.
cpRotaryLimitJoint *cpRotaryLimitJointAlloc(void);
cpRotaryLimitJoint* cpRotaryLimitJointAlloc(void);
/// Initialize a damped rotary limit joint.
cpRotaryLimitJoint *cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max);
cpRotaryLimitJoint* cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max);
/// Allocate and initialize a damped rotary limit joint.
cpConstraint *cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max);
cpConstraint* cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max);
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min);
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max);
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min)
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max)
/// @}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpSimpleMotor cpSimpleMotor
/// @{
const cpConstraintClass *cpSimpleMotorGetClass();
const cpConstraintClass *cpSimpleMotorGetClass(void);
/// @private
typedef struct cpSimpleMotor {
@@ -31,16 +31,16 @@ typedef struct cpSimpleMotor {
cpFloat iSum;
cpFloat jAcc, jMax;
cpFloat jAcc;
} cpSimpleMotor;
/// Allocate a simple motor.
cpSimpleMotor *cpSimpleMotorAlloc(void);
cpSimpleMotor* cpSimpleMotorAlloc(void);
/// initialize a simple motor.
cpSimpleMotor *cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);
cpSimpleMotor* cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);
/// Allocate and initialize a simple motor.
cpConstraint *cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);
cpConstraint* cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);
CP_DefineConstraintProperty(cpSimpleMotor, cpFloat, rate, Rate);
CP_DefineConstraintProperty(cpSimpleMotor, cpFloat, rate, Rate)
/// @}

View File

@@ -22,7 +22,7 @@
/// @defgroup cpSlideJoint cpSlideJoint
/// @{
const cpConstraintClass *cpSlideJointGetClass();
const cpConstraintClass *cpSlideJointGetClass(void);
/// @private
typedef struct cpSlideJoint {
@@ -34,20 +34,20 @@ typedef struct cpSlideJoint {
cpVect n;
cpFloat nMass;
cpFloat jnAcc, jnMax;
cpFloat jnAcc;
cpFloat bias;
} cpSlideJoint;
/// Allocate a slide joint.
cpSlideJoint *cpSlideJointAlloc(void);
cpSlideJoint* cpSlideJointAlloc(void);
/// Initialize a slide joint.
cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
cpSlideJoint* cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
/// Allocate and initialize a slide joint.
cpConstraint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
cpConstraint* cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1);
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2);
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min);
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max);
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1)
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2)
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min)
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max)
/// @}

View File

@@ -19,12 +19,14 @@
* SOFTWARE.
*/
#define CP_DefineClassGetter(t) const cpConstraintClass * t##GetClass(){return (cpConstraintClass *)&klass;}
// These are utility routines to use when creating custom constraints.
// I'm not sure if this should be part of the private API or not.
// I should probably clean up the naming conventions if it is...
#define CP_DefineClassGetter(t) const cpConstraintClass * t##GetClass(void){return (cpConstraintClass *)&klass;}
void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b);
#define J_MAX(constraint, dt) (((cpConstraint *)constraint)->maxForce*(dt))
static inline cpVect
relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){
cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
@@ -54,8 +56,8 @@ apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
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);
body->CP_PRIVATE(v_bias) = cpvadd(body->CP_PRIVATE(v_bias), cpvmult(j, body->m_inv));
body->CP_PRIVATE(w_bias) += body->i_inv*cpvcross(r, j);
}
static inline void
@@ -65,30 +67,30 @@ apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
apply_bias_impulse(b, j, r2);
}
static inline cpFloat
k_scalar_body(cpBody *body, cpVect r, cpVect n)
{
cpFloat rcn = cpvcross(r, n);
return body->m_inv + body->i_inv*rcn*rcn;
}
static inline cpFloat
k_scalar(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)
{
cpFloat mass_sum = a->m_inv + b->m_inv;
cpFloat r1cn = cpvcross(r1, n);
cpFloat r2cn = cpvcross(r2, n);
cpFloat value = mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;
cpFloat value = k_scalar_body(a, r1, n) + k_scalar_body(b, r2, n);
cpAssertSoft(value != 0.0, "Unsolvable collision or constraint.");
return value;
}
static inline void
k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect *k1, cpVect *k2)
static inline cpMat2x2
k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2)
{
// calculate mass matrix
// If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...
cpFloat k11, k12, k21, k22;
cpFloat m_sum = a->m_inv + b->m_inv;
// start with I*m_sum
k11 = m_sum; k12 = 0.0f;
k21 = 0.0f; k22 = m_sum;
// start with Identity*m_sum
cpFloat k11 = m_sum, k12 = 0.0f;
cpFloat k21 = 0.0f, k22 = m_sum;
// add the influence from r1
cpFloat a_i_inv = a->i_inv;
@@ -107,18 +109,14 @@ k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect *k1, cpVect *k2)
k21 += r2nxy; k22 += r2xsq;
// invert
cpFloat determinant = k11*k22 - k12*k21;
cpAssertSoft(determinant != 0.0, "Unsolvable constraint.");
cpFloat det = k11*k22 - k12*k21;
cpAssertSoft(det != 0.0, "Unsolvable constraint.");
cpFloat det_inv = 1.0f/determinant;
*k1 = cpv( k22*det_inv, -k12*det_inv);
*k2 = cpv(-k21*det_inv, k11*det_inv);
}
static inline cpVect
mult_k(cpVect vr, cpVect k1, cpVect k2)
{
return cpv(cpvdot(vr, k1), cpvdot(vr, k2));
cpFloat det_inv = 1.0f/det;
return cpMat2x2New(
k22*det_inv, -k12*det_inv,
-k21*det_inv, k11*det_inv
);
}
static inline cpFloat

View File

@@ -83,6 +83,11 @@ struct cpArbiter {
/// Override in a pre-solve collision handler for custom behavior.
cpVect surface_vr;
/// User definable data pointer.
/// The value will persist for the pair of shapes until the separate() callback is called.
/// NOTE: If you need to clean up this pointer, you should implement the separate() callback to do it.
cpDataPointer data;
CP_PRIVATE(cpShape *a);
CP_PRIVATE(cpShape *b);
CP_PRIVATE(cpBody *body_a);
@@ -110,16 +115,21 @@ static inline void cpArbiterSet##name(cpArbiter *arb, type value){arb->member =
CP_DefineArbiterStructGetter(type, member, name) \
CP_DefineArbiterStructSetter(type, member, name)
CP_DefineArbiterStructProperty(cpFloat, e, Elasticity);
CP_DefineArbiterStructProperty(cpFloat, u, Friction);
CP_DefineArbiterStructProperty(cpVect, surface_vr, SurfaceVelocity);
CP_DefineArbiterStructProperty(cpFloat, e, Elasticity)
CP_DefineArbiterStructProperty(cpFloat, u, Friction)
CP_DefineArbiterStructProperty(cpVect, surface_vr, SurfaceVelocity)
CP_DefineArbiterStructProperty(cpDataPointer, data, UserData)
/// Calculate the total impulse that was applied by this arbiter.
/// Calling this function from a begin or pre-solve callback is undefined.
/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
cpVect cpArbiterTotalImpulse(const cpArbiter *arb);
/// Calculate the total impulse including the friction that was applied by this arbiter.
/// Calling this function from a begin or pre-solve callback is undefined.
/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
cpVect cpArbiterTotalImpulseWithFriction(const cpArbiter *arb);
/// Calculate the amount of energy lost in a collision including static, but not dynamic friction.
/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
cpFloat cpArbiterTotalKE(const cpArbiter *arb);
/// Causes a collision pair to be ignored as if you returned false from a begin callback.
/// If called from a pre-step callback, you will still need to return false
@@ -152,18 +162,6 @@ static inline void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody *
/// A macro shortcut for defining and retrieving the bodies from an arbiter.
#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
/// Returns true if this is the first step a pair of objects started colliding.
static inline cpBool cpArbiterIsFirstContact(const cpArbiter *arb)
{
return arb->CP_PRIVATE(state) == cpArbiterStateFirstColl;
}
/// Get the number of contact points for this arbiter.
static inline int cpArbiterGetCount(const cpArbiter *arb)
{
return arb->CP_PRIVATE(numContacts);
}
/// A struct that wraps up the important collision data for an arbiter.
typedef struct cpContactPointSet {
/// The number of contact points in the set.
@@ -182,6 +180,10 @@ typedef struct cpContactPointSet {
/// Return a contact set from an arbiter.
cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb);
/// Returns true if this is the first step a pair of objects started colliding.
cpBool cpArbiterIsFirstContact(const cpArbiter *arb);
/// Get the number of contact points for this arbiter.
int cpArbiterGetCount(const cpArbiter *arb);
/// Get the normal of the @c ith contact point.
cpVect cpArbiterGetNormal(const cpArbiter *arb, int i);
/// Get the position of the @c ith contact point.

View File

@@ -29,13 +29,18 @@ typedef struct cpBB{
} cpBB;
/// Convenience constructor for cpBB structs.
static inline cpBB cpBBNew(const cpFloat l, const cpFloat b,
const cpFloat r, const cpFloat t)
static inline cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t)
{
cpBB bb = {l, b, r, t};
return bb;
}
/// Constructs a cpBB for a circle with the given position and radius.
static inline cpBB cpBBNewForCircle(const cpVect p, const cpFloat r)
{
return cpBBNew(p.x - r, p.y - r, p.x + r, p.y + r);
}
/// Returns true if @c a and @c b intersect.
static inline cpBool cpBBIntersects(const cpBB a, const cpBB b)
{
@@ -86,23 +91,43 @@ static inline cpFloat cpBBMergedArea(cpBB a, cpBB b)
return (cpfmax(a.r, b.r) - cpfmin(a.l, b.l))*(cpfmax(a.t, b.t) - cpfmin(a.b, b.b));
}
/// Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn't hit.
static inline cpFloat cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b)
{
cpFloat idx = 1.0f/(b.x - a.x);
cpFloat tx1 = (bb.l == a.x ? -INFINITY : (bb.l - a.x)*idx);
cpFloat tx2 = (bb.r == a.x ? INFINITY : (bb.r - a.x)*idx);
cpFloat txmin = cpfmin(tx1, tx2);
cpFloat txmax = cpfmax(tx1, tx2);
cpFloat idy = 1.0f/(b.y - a.y);
cpFloat ty1 = (bb.b == a.y ? -INFINITY : (bb.b - a.y)*idy);
cpFloat ty2 = (bb.t == a.y ? INFINITY : (bb.t - a.y)*idy);
cpFloat tymin = cpfmin(ty1, ty2);
cpFloat tymax = cpfmax(ty1, ty2);
if(tymin <= txmax && txmin <= tymax){
cpFloat min = cpfmax(txmin, tymin);
cpFloat max = cpfmin(txmax, tymax);
if(0.0 <= max && min <= 1.0) return cpfmax(min, 0.0);
}
return INFINITY;
}
/// Return true if the bounding box intersects the line segment with ends @c a and @c b.
static inline cpBool cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b)
{
cpBB seg_bb = cpBBNew(cpfmin(a.x, b.x), cpfmin(a.y, b.y), cpfmax(a.x, b.x), cpfmax(a.y, b.y));
if(cpBBIntersects(bb, seg_bb)){
cpVect axis = cpv(b.y - a.y, a.x - b.x);
cpVect offset = cpv((a.x + b.x - bb.r - bb.l), (a.y + b.y - bb.t - bb.b));
cpVect extents = cpv(bb.r - bb.l, bb.t - bb.b);
return (cpfabs(cpvdot(axis, offset)) < cpfabs(axis.x*extents.x) + cpfabs(axis.y*extents.y));
}
return cpFalse;
return (cpBBSegmentQuery(bb, a, b) != INFINITY);
}
/// Clamp a vector to a bounding box.
cpVect cpBBClampVect(const cpBB bb, const cpVect v); // clamps the vector to lie within the bbox
static inline cpVect
cpBBClampVect(const cpBB bb, const cpVect v)
{
return cpv(cpfclamp(v.x, bb.l, bb.r), cpfclamp(v.y, bb.b, bb.t));
}
// TODO edge case issue
/// Wrap a vector to a bounding box.

View File

@@ -100,16 +100,16 @@ struct cpBody {
};
/// Allocate a cpBody.
cpBody *cpBodyAlloc(void);
cpBody* cpBodyAlloc(void);
/// Initialize a cpBody.
cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
cpBody* cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
/// Allocate and initialize a cpBody.
cpBody *cpBodyNew(cpFloat m, cpFloat i);
cpBody* cpBodyNew(cpFloat m, cpFloat i);
/// Initialize a static cpBody.
cpBody *cpBodyInitStatic(cpBody *body);
cpBody* cpBodyInitStatic(cpBody *body);
/// Allocate and initialize a static cpBody.
cpBody *cpBodyNewStatic();
cpBody* cpBodyNewStatic(void);
/// Destroy a cpBody.
void cpBodyDestroy(cpBody *body);
@@ -160,36 +160,39 @@ static inline type cpBodyGet##name(const cpBody *body){return body->member;}
#define CP_DefineBodyStructSetter(type, member, name) \
static inline void cpBodySet##name(cpBody *body, const type value){ \
cpBodyActivate(body); \
cpBodyAssertSane(body); \
body->member = value; \
cpBodyAssertSane(body); \
}
#define CP_DefineBodyStructProperty(type, member, name) \
CP_DefineBodyStructGetter(type, member, name) \
CP_DefineBodyStructSetter(type, member, name)
CP_DefineBodyStructGetter(cpFloat, m, Mass);
// TODO add to docs
CP_DefineBodyStructGetter(cpSpace*, CP_PRIVATE(space), Space)
CP_DefineBodyStructGetter(cpFloat, m, Mass)
/// Set the mass of a body.
void cpBodySetMass(cpBody *body, cpFloat m);
CP_DefineBodyStructGetter(cpFloat, i, Moment);
CP_DefineBodyStructGetter(cpFloat, i, Moment)
/// Set the moment of a body.
void cpBodySetMoment(cpBody *body, cpFloat i);
CP_DefineBodyStructGetter(cpVect, p, Pos);
CP_DefineBodyStructGetter(cpVect, p, Pos)
/// Set the position of a body.
void cpBodySetPos(cpBody *body, cpVect pos);
CP_DefineBodyStructProperty(cpVect, v, Vel);
CP_DefineBodyStructProperty(cpVect, f, Force);
CP_DefineBodyStructGetter(cpFloat, a, Angle);
CP_DefineBodyStructProperty(cpVect, v, Vel)
CP_DefineBodyStructProperty(cpVect, f, Force)
CP_DefineBodyStructGetter(cpFloat, a, Angle)
/// Set the angle of a body.
void cpBodySetAngle(cpBody *body, cpFloat a);
CP_DefineBodyStructProperty(cpFloat, w, AngVel);
CP_DefineBodyStructProperty(cpFloat, t, Torque);
CP_DefineBodyStructGetter(cpVect, rot, Rot);
CP_DefineBodyStructProperty(cpFloat, v_limit, VelLimit);
CP_DefineBodyStructProperty(cpFloat, w_limit, AngVelLimit);
CP_DefineBodyStructProperty(cpDataPointer, data, UserData);
CP_DefineBodyStructProperty(cpFloat, w, AngVel)
CP_DefineBodyStructProperty(cpFloat, t, Torque)
CP_DefineBodyStructGetter(cpVect, rot, Rot)
CP_DefineBodyStructProperty(cpFloat, v_limit, VelLimit)
CP_DefineBodyStructProperty(cpFloat, w_limit, AngVelLimit)
CP_DefineBodyStructProperty(cpDataPointer, data, UserData)
/// Default Integration functions.
void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
@@ -214,6 +217,12 @@ void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r);
/// Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
void cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r);
/// Get the velocity on a body (in world units) at a point on the body in world coordinates.
cpVect cpBodyGetVelAtWorldPoint(cpBody *body, cpVect point);
/// Get the velocity on a body (in world units) at a point on the body in local coordinates.
cpVect cpBodyGetVelAtLocalPoint(cpBody *body, cpVect point);
/// Get the kinetic energy of a body.
static inline cpFloat cpBodyKineticEnergy(const cpBody *body)
{

View File

@@ -23,10 +23,10 @@
/// @{
/// @private
typedef struct cpPolyShapeAxis {
typedef struct cpSplittingPlane {
cpVect n;
cpFloat d;
} cpPolyShapeAxis;
} cpSplittingPlane;
/// @private
typedef struct cpPolyShape {
@@ -34,28 +34,29 @@ typedef struct cpPolyShape {
int numVerts;
cpVect *verts, *tVerts;
cpPolyShapeAxis *axes, *tAxes;
cpSplittingPlane *planes, *tPlanes;
} cpPolyShape;
/// Allocate a polygon shape.
cpPolyShape *cpPolyShapeAlloc(void);
cpPolyShape* cpPolyShapeAlloc(void);
/// Initialize a polygon shape.
/// The vertexes must be convex and have a clockwise winding.
cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset);
/// A convex hull will be created from the vertexes.
cpPolyShape* cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset);
/// Allocate and initialize a polygon shape.
/// The vertexes must be convex and have a clockwise winding.
cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
/// A convex hull will be created from the vertexes.
cpShape* cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
/// Initialize a box shaped polygon shape.
cpPolyShape *cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
cpPolyShape* cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
/// Initialize an offset box shaped polygon shape.
cpPolyShape *cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box);
cpPolyShape* cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box);
/// Allocate and initialize a box shaped polygon shape.
cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
cpShape* cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
/// Allocate and initialize an offset box shaped polygon shape.
cpShape *cpBoxShapeNew2(cpBody *body, cpBB box);
cpShape* cpBoxShapeNew2(cpBody *body, cpBB box);
/// Check that a set of vertexes is convex and has a clockwise winding.
/// NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
cpBool cpPolyValidate(const cpVect *verts, const int numVerts);
/// Get the number of verts in a polygon shape.

View File

@@ -25,6 +25,16 @@
typedef struct cpShapeClass cpShapeClass;
/// Nearest point query info struct.
typedef struct cpNearestPointQueryInfo {
/// The nearest shape, NULL if no shape was within range.
cpShape *shape;
/// The closest point on the shape's surface. (in world space coordinates)
cpVect p;
/// The distance to the point. The distance is negative if the point is inside the shape.
cpFloat d;
} cpNearestPointQueryInfo;
/// Segment query info struct.
typedef struct cpSegmentQueryInfo {
/// The shape that was hit, NULL if no collision occured.
@@ -45,7 +55,7 @@ typedef enum cpShapeType{
typedef cpBB (*cpShapeCacheDataImpl)(cpShape *shape, cpVect p, cpVect rot);
typedef void (*cpShapeDestroyImpl)(cpShape *shape);
typedef cpBool (*cpShapePointQueryImpl)(cpShape *shape, cpVect p);
typedef void (*cpShapeNearestPointQueryImpl)(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info);
typedef void (*cpShapeSegmentQueryImpl)(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
/// @private
@@ -54,7 +64,7 @@ struct cpShapeClass {
cpShapeCacheDataImpl cacheData;
cpShapeDestroyImpl destroy;
cpShapePointQueryImpl pointQuery;
cpShapeNearestPointQueryImpl nearestPointQuery;
cpShapeSegmentQueryImpl segmentQuery;
};
@@ -112,36 +122,9 @@ cpBB cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot);
/// Test if a point lies within a shape.
cpBool cpShapePointQuery(cpShape *shape, cpVect p);
#define CP_DefineShapeStructGetter(type, member, name) \
static inline type cpShapeGet##name(const cpShape *shape){return shape->member;}
#define CP_DefineShapeStructSetter(type, member, name, activates) \
static inline void cpShapeSet##name(cpShape *shape, type value){ \
if(activates) cpBodyActivate(shape->body); \
shape->member = value; \
}
#define CP_DefineShapeStructProperty(type, member, name, activates) \
CP_DefineShapeStructGetter(type, member, name) \
CP_DefineShapeStructSetter(type, member, name, activates)
CP_DefineShapeStructGetter(cpBody *, body, Body);
void cpShapeSetBody(cpShape *shape, cpBody *body);
CP_DefineShapeStructGetter(cpBB, bb, BB);
CP_DefineShapeStructProperty(cpBool, sensor, Sensor, cpTrue);
CP_DefineShapeStructProperty(cpFloat, e, Elasticity, cpFalse);
CP_DefineShapeStructProperty(cpFloat, u, Friction, cpTrue);
CP_DefineShapeStructProperty(cpVect, surface_v, SurfaceVelocity, cpTrue);
CP_DefineShapeStructProperty(cpDataPointer, data, UserData, cpFalse);
CP_DefineShapeStructProperty(cpCollisionType, collision_type, CollisionType, cpTrue);
CP_DefineShapeStructProperty(cpGroup, group, Group, cpTrue);
CP_DefineShapeStructProperty(cpLayers, layers, Layers, cpTrue);
/// When initializing a shape, it's hash value comes from a counter.
/// Because the hash value may affect iteration order, you can reset the shape ID counter
/// when recreating a space. This will make the simulation be deterministic.
void cpResetShapeIdCounter(void);
/// Perform a nearest point query. It finds the closest point on the surface of shape to a specific point.
/// The value returned is the distance between the points. A negative distance means the point is inside the shape.
cpFloat cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *out);
/// Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure.
cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
@@ -158,6 +141,39 @@ static inline cpFloat cpSegmentQueryHitDist(const cpVect start, const cpVect end
return cpvdist(start, end)*info.t;
}
#define CP_DefineShapeStructGetter(type, member, name) \
static inline type cpShapeGet##name(const cpShape *shape){return shape->member;}
#define CP_DefineShapeStructSetter(type, member, name, activates) \
static inline void cpShapeSet##name(cpShape *shape, type value){ \
if(activates && shape->body) cpBodyActivate(shape->body); \
shape->member = value; \
}
#define CP_DefineShapeStructProperty(type, member, name, activates) \
CP_DefineShapeStructGetter(type, member, name) \
CP_DefineShapeStructSetter(type, member, name, activates)
CP_DefineShapeStructGetter(cpSpace*, CP_PRIVATE(space), Space)
CP_DefineShapeStructGetter(cpBody*, body, Body)
void cpShapeSetBody(cpShape *shape, cpBody *body);
CP_DefineShapeStructGetter(cpBB, bb, BB)
CP_DefineShapeStructProperty(cpBool, sensor, Sensor, cpTrue)
CP_DefineShapeStructProperty(cpFloat, e, Elasticity, cpFalse)
CP_DefineShapeStructProperty(cpFloat, u, Friction, cpTrue)
CP_DefineShapeStructProperty(cpVect, surface_v, SurfaceVelocity, cpTrue)
CP_DefineShapeStructProperty(cpDataPointer, data, UserData, cpFalse)
CP_DefineShapeStructProperty(cpCollisionType, collision_type, CollisionType, cpTrue)
CP_DefineShapeStructProperty(cpGroup, group, Group, cpTrue)
CP_DefineShapeStructProperty(cpLayers, layers, Layers, cpTrue)
/// When initializing a shape, it's hash value comes from a counter.
/// Because the hash value may affect iteration order, you can reset the shape ID counter
/// when recreating a space. This will make the simulation be deterministic.
void cpResetShapeIdCounter(void);
#define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(const cpShape *shape)
/// @}
@@ -172,11 +188,11 @@ typedef struct cpCircleShape {
} cpCircleShape;
/// Allocate a circle shape.
cpCircleShape *cpCircleShapeAlloc(void);
cpCircleShape* cpCircleShapeAlloc(void);
/// Initialize a circle shape.
cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);
cpCircleShape* cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);
/// Allocate and initialize a circle shape.
cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);
cpShape* cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);
CP_DeclareShapeGetter(cpCircleShape, cpVect, Offset);
CP_DeclareShapeGetter(cpCircleShape, cpFloat, Radius);
@@ -191,6 +207,8 @@ typedef struct cpSegmentShape {
cpVect a, b, n;
cpVect ta, tb, tn;
cpFloat r;
cpVect a_tangent, b_tangent;
} cpSegmentShape;
/// Allocate a segment shape.
@@ -200,6 +218,8 @@ cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a,
/// Allocate and initialize a segment shape.
cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius);
void cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next);
CP_DeclareShapeGetter(cpSegmentShape, cpVect, A);
CP_DeclareShapeGetter(cpSegmentShape, cpVect, B);
CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal);

View File

@@ -23,6 +23,7 @@
/// @{
typedef struct cpContactBufferHeader cpContactBufferHeader;
typedef void (*cpSpaceArbiterApplyImpulseFunc)(cpArbiter *arb);
/// Basic Unit of Simulation in Chipmunk
struct cpSpace {
@@ -47,7 +48,7 @@ struct cpSpace {
/// The default value of INFINITY disables the sleeping algorithm.
cpFloat sleepTimeThreshold;
/// Amount of encouraged penetration between colliding shapes..
/// Amount of encouraged penetration between colliding shapes.
/// Used to reduce oscillating contacts and keep the collision cache warm.
/// Defaults to 0.1. If you have poor simulation quality,
/// increase this number as much as possible without allowing visible amounts of overlap.
@@ -97,7 +98,9 @@ struct cpSpace {
CP_PRIVATE(cpHashSet *collisionHandlers);
CP_PRIVATE(cpCollisionHandler defaultHandler);
CP_PRIVATE(cpHashSet *postStepCallbacks);
CP_PRIVATE(cpBool skipPostStep);
CP_PRIVATE(cpArray *postStepCallbacks);
CP_PRIVATE(cpBody _staticBody);
};
@@ -124,18 +127,25 @@ static inline void cpSpaceSet##name(cpSpace *space, type value){space->member =
CP_DefineSpaceStructGetter(type, member, name) \
CP_DefineSpaceStructSetter(type, member, name)
CP_DefineSpaceStructProperty(int, iterations, Iterations);
CP_DefineSpaceStructProperty(cpVect, gravity, Gravity);
CP_DefineSpaceStructProperty(cpFloat, damping, Damping);
CP_DefineSpaceStructProperty(cpFloat, idleSpeedThreshold, IdleSpeedThreshold);
CP_DefineSpaceStructProperty(cpFloat, sleepTimeThreshold, SleepTimeThreshold);
CP_DefineSpaceStructProperty(cpFloat, collisionSlop, CollisionSlop);
CP_DefineSpaceStructProperty(cpFloat, collisionBias, CollisionBias);
CP_DefineSpaceStructProperty(cpTimestamp, collisionPersistence, CollisionPersistence);
CP_DefineSpaceStructProperty(cpBool, enableContactGraph, EnableContactGraph);
CP_DefineSpaceStructProperty(cpDataPointer, data, UserData);
CP_DefineSpaceStructGetter(cpBody *, staticBody, StaticBody);
CP_DefineSpaceStructGetter(cpFloat, CP_PRIVATE(curr_dt), CurrentTimeStep);
CP_DefineSpaceStructProperty(int, iterations, Iterations)
CP_DefineSpaceStructProperty(cpVect, gravity, Gravity)
CP_DefineSpaceStructProperty(cpFloat, damping, Damping)
CP_DefineSpaceStructProperty(cpFloat, idleSpeedThreshold, IdleSpeedThreshold)
CP_DefineSpaceStructProperty(cpFloat, sleepTimeThreshold, SleepTimeThreshold)
CP_DefineSpaceStructProperty(cpFloat, collisionSlop, CollisionSlop)
CP_DefineSpaceStructProperty(cpFloat, collisionBias, CollisionBias)
CP_DefineSpaceStructProperty(cpTimestamp, collisionPersistence, CollisionPersistence)
CP_DefineSpaceStructProperty(cpBool, enableContactGraph, EnableContactGraph)
CP_DefineSpaceStructProperty(cpDataPointer, data, UserData)
CP_DefineSpaceStructGetter(cpBody*, staticBody, StaticBody)
CP_DefineSpaceStructGetter(cpFloat, CP_PRIVATE(curr_dt), CurrentTimeStep)
/// returns true from inside a callback and objects cannot be added/removed.
static inline cpBool
cpSpaceIsLocked(cpSpace *space)
{
return space->CP_PRIVATE(locked);
}
/// Set a default collision handler for this space.
/// The default collision handler is invoked for each colliding pair of shapes
@@ -167,13 +177,13 @@ void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisio
/// Add a collision shape to the simulation.
/// If the shape is attached to a static body, it will be added as a static shape.
cpShape *cpSpaceAddShape(cpSpace *space, cpShape *shape);
cpShape* cpSpaceAddShape(cpSpace *space, cpShape *shape);
/// Explicity add a shape as a static shape to the simulation.
cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
cpShape* cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
/// Add a rigid body to the simulation.
cpBody *cpSpaceAddBody(cpSpace *space, cpBody *body);
cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body);
/// Add a constraint to the simulation.
cpConstraint *cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
cpConstraint* cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
/// Remove a collision shape from the simulation.
void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);
@@ -192,10 +202,12 @@ cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body);
cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint);
/// Post Step callback function type.
typedef void (*cpPostStepFunc)(cpSpace *space, void *obj, void *data);
typedef void (*cpPostStepFunc)(cpSpace *space, void *key, void *data);
/// Schedule a post-step callback to be called when cpSpaceStep() finishes.
/// @c obj is used a key, you can only register one callback per unique value for @c obj
void cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data);
/// You can only register one callback per unique value for @c key.
/// Returns true only if @c key has never been scheduled before.
/// It's possible to pass @c NULL for @c func if you only want to mark @c key as being used.
cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data);
/// Point query callback function type.
typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);
@@ -204,6 +216,13 @@ void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup gr
/// Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group);
/// Nearest point query callback function type.
typedef void (*cpSpaceNearestPointQueryFunc)(cpShape *shape, cpFloat distance, cpVect point, void *data);
/// Query the space at a point and call @c func for each shape found.
void cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data);
/// Query the space at a point and return the nearest shape found. Returns NULL if no shapes were found.
cpShape *cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out);
/// Segment query callback function type.
typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data);
/// Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.

View File

@@ -37,7 +37,7 @@
@{
*/
#pragma mark Spatial Index
//MARK: Spatial Index
/// Spatial index bounding box callback function type.
/// The spatial index calls this function and passes you a pointer to an object you added
@@ -64,16 +64,16 @@ struct cpSpatialIndex {
};
#pragma mark Spatial Hash
//MARK: Spatial Hash
typedef struct cpSpaceHash cpSpaceHash;
/// Allocate a spatial hash.
cpSpaceHash *cpSpaceHashAlloc(void);
cpSpaceHash* cpSpaceHashAlloc(void);
/// Initialize a spatial hash.
cpSpatialIndex *cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
cpSpatialIndex* cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Allocate and initialize a spatial hash.
cpSpatialIndex *cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
cpSpatialIndex* cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Change the cell dimensions and table size of the spatial hash to tune it.
/// The cell dimensions should roughly match the average size of your objects
@@ -81,16 +81,16 @@ cpSpatialIndex *cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc
/// Some trial and error is required to find the optimum numbers for efficiency.
void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);
#pragma mark AABB Tree
//MARK: AABB Tree
typedef struct cpBBTree cpBBTree;
/// Allocate a bounding box tree.
cpBBTree *cpBBTreeAlloc(void);
cpBBTree* cpBBTreeAlloc(void);
/// Initialize a bounding box tree.
cpSpatialIndex *cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
cpSpatialIndex* cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Allocate and initialize a bounding box tree.
cpSpatialIndex *cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
cpSpatialIndex* cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Perform a static top down optimization of the tree.
void cpBBTreeOptimize(cpSpatialIndex *index);
@@ -101,18 +101,18 @@ typedef cpVect (*cpBBTreeVelocityFunc)(void *obj);
/// Set the velocity function for the bounding box tree to enable temporal coherence.
void cpBBTreeSetVelocityFunc(cpSpatialIndex *index, cpBBTreeVelocityFunc func);
#pragma mark Single Axis Sweep
//MARK: Single Axis Sweep
typedef struct cpSweep1D cpSweep1D;
/// Allocate a 1D sort and sweep broadphase.
cpSweep1D *cpSweep1DAlloc(void);
cpSweep1D* cpSweep1DAlloc(void);
/// Initialize a 1D sort and sweep broadphase.
cpSpatialIndex *cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
cpSpatialIndex* cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
/// Allocate and initialize a 1D sort and sweep broadphase.
cpSpatialIndex *cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
cpSpatialIndex* cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);
#pragma mark Spatial Index Implementation
//MARK: Spatial Index Implementation
typedef void (*cpSpatialIndexDestroyImpl)(cpSpatialIndex *index);
@@ -127,9 +127,8 @@ typedef void (*cpSpatialIndexReindexImpl)(cpSpatialIndex *index);
typedef void (*cpSpatialIndexReindexObjectImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);
typedef void (*cpSpatialIndexReindexQueryImpl)(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data);
typedef void (*cpSpatialIndexPointQueryImpl)(cpSpatialIndex *index, cpVect point, cpSpatialIndexQueryFunc func, void *data);
typedef void (*cpSpatialIndexSegmentQueryImpl)(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data);
typedef void (*cpSpatialIndexQueryImpl)(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data);
typedef void (*cpSpatialIndexSegmentQueryImpl)(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data);
struct cpSpatialIndexClass {
cpSpatialIndexDestroyImpl destroy;
@@ -145,9 +144,8 @@ struct cpSpatialIndexClass {
cpSpatialIndexReindexObjectImpl reindexObject;
cpSpatialIndexReindexQueryImpl reindexQuery;
cpSpatialIndexPointQueryImpl pointQuery;
cpSpatialIndexSegmentQueryImpl segmentQuery;
cpSpatialIndexQueryImpl query;
cpSpatialIndexSegmentQueryImpl segmentQuery;
};
/// Destroy and free a spatial index.
@@ -206,11 +204,10 @@ static inline void cpSpatialIndexReindexObject(cpSpatialIndex *index, void *obj,
index->klass->reindexObject(index, obj, hashid);
}
/// Perform a point query against the spatial index, calling @c func for each potential match.
/// A pointer to the point will be passed as @c obj1 of @c func.
static inline void cpSpatialIndexPointQuery(cpSpatialIndex *index, cpVect point, cpSpatialIndexQueryFunc func, void *data)
/// Perform a rectangle query against the spatial index, calling @c func for each potential match.
static inline void cpSpatialIndexQuery(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)
{
index->klass->pointQuery(index, point, func, data);
index->klass->query(index, obj, bb, func, data);
}
/// Perform a segment query against the spatial index, calling @c func for each potential match.
@@ -219,12 +216,6 @@ static inline void cpSpatialIndexSegmentQuery(cpSpatialIndex *index, void *obj,
index->klass->segmentQuery(index, obj, a, b, t_exit, func, data);
}
/// Perform a rectangle query against the spatial index, calling @c func for each potential match.
static inline void cpSpatialIndexQuery(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)
{
index->klass->query(index, obj, bb, func, data);
}
/// Simultaneously reindex and find all colliding objects.
/// @c func will be called once for each potentially overlapping pair of objects found.
/// If the spatial index was initialized with a static index, it will collide it's objects against that as well.

View File

@@ -33,25 +33,16 @@ static inline cpVect cpv(const cpFloat x, const cpFloat y)
return v;
}
/// 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);
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)
@@ -115,6 +106,18 @@ static inline cpVect cpvproject(const cpVect v1, const cpVect v2)
return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
}
/// Returns the unit length vector for the given angle (in radians).
static inline cpVect cpvforangle(const cpFloat a)
{
return cpv(cpfcos(a), cpfsin(a));
}
/// Returns the angular direction v is pointing in (in radians).
static inline cpFloat cpvtoangle(const cpVect v)
{
return cpfatan2(v.y, v.x);
}
/// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
static inline cpVect cpvrotate(const cpVect v1, const cpVect v2)
{
@@ -133,6 +136,12 @@ static inline cpFloat cpvlengthsq(const cpVect v)
return cpvdot(v, v);
}
/// Returns the length of v.
static inline cpFloat cpvlength(const cpVect v)
{
return cpfsqrt(cpvdot(v, v));
}
/// Linearly interpolate between v1 and v2.
static inline cpVect cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)
{
@@ -180,4 +189,24 @@ static inline cpBool cpvnear(const cpVect v1, const cpVect v2, const cpFloat dis
{
return cpvdistsq(v1, v2) < dist*dist;
}
/// @}
/// @defgroup cpMat2x2 cpMat2x2
/// 2x2 matrix type used for tensors and such.
/// @{
static inline cpMat2x2
cpMat2x2New(cpFloat a, cpFloat b, cpFloat c, cpFloat d)
{
cpMat2x2 m = {a, b, c, d};
return m;
}
static inline cpVect
cpMat2x2Transform(cpMat2x2 m, cpVect v)
{
return cpv(v.x*m.a + v.y*m.b, v.x*m.c + v.y*m.d);
}
///@}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by Qt Creator 2.6.0, 2012-11-23T02:05:56. -->
<!-- Written by Qt Creator 2.6.0, 2012-11-23T22:51:42. -->
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>

View File

@@ -19,24 +19,23 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdarg.h>
#include "chipmunk_private.h"
//#ifdef __cplusplus
//extern "C" {
//#endif
// void cpInitCollisionFuncs(void);
//#ifdef __cplusplus
//}
//#endif
void
cpMessage(const char *message, const char *condition, const char *file, int line, int isError)
cpMessage(const char *condition, const char *file, int line, cpBool isError, cpBool isHardError, const char *message, ...)
{
fprintf(stderr, (isError ? "Aborting due to Chipmunk error: %s\n" : "Chipmunk warning: %s\n"), message);
fprintf(stderr, (isError ? "Aborting due to Chipmunk error: " : "Chipmunk warning: "));
va_list vargs;
va_start(vargs, message); {
vfprintf(stderr, message, vargs);
fprintf(stderr, "\n");
} va_end(vargs);
fprintf(stderr, "\tFailed condition: %s\n", condition);
fprintf(stderr, "\tSource:%s:%d\n", file, line);
@@ -51,14 +50,11 @@ const char *cpVersionString = XSTR(CP_VERSION_MAJOR)"."XSTR(CP_VERSION_MINOR)"."
void
cpInitChipmunk(void)
{
//#ifndef NDEBUG
// printf("Initializing Chipmunk v%s (Debug Enabled)\n", cpVersionString);
// printf("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n");
//#endif
//
// cpInitCollisionFuncs();
cpAssertWarn(cpFalse, "cpInitChipmunk is deprecated and no longer required. It will be removed in the future.");
}
//MARK: Misc Functions
cpFloat
cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)
{
@@ -74,10 +70,8 @@ cpAreaForCircle(cpFloat r1, cpFloat r2)
cpFloat
cpMomentForSegment(cpFloat m, cpVect a, cpVect b)
{
cpFloat length = cpvlength(cpvsub(b, a));
cpVect offset = cpvmult(cpvadd(a, b), 1.0f/2.0f);
return m*(length*length/12.0f + cpvlengthsq(offset));
cpVect offset = cpvmult(cpvadd(a, b), 0.5f);
return m*(cpvdistsq(b, a)/12.0f + cpvlengthsq(offset));
}
cpFloat
@@ -156,7 +150,173 @@ cpMomentForBox2(cpFloat m, cpBB box)
cpFloat height = box.t - box.b;
cpVect offset = cpvmult(cpv(box.l + box.r, box.b + box.t), 0.5f);
// TODO NaN when offset is 0 and m is INFINITY
return cpMomentForBox(m, width, height) + m*cpvlengthsq(offset);
}
//MARK: Quick Hull
void
cpLoopIndexes(cpVect *verts, int count, int *start, int *end)
{
(*start) = (*end) = 0;
cpVect min = verts[0];
cpVect max = min;
for(int i=1; i<count; i++){
cpVect v = verts[i];
if(v.x < min.x || (v.x == min.x && v.y < min.y)){
min = v;
(*start) = i;
} else if(v.x > max.x || (v.x == max.x && v.y > max.y)){
max = v;
(*end) = i;
}
}
}
#define SWAP(__A__, __B__) {cpVect __TMP__ = __A__; __A__ = __B__; __B__ = __TMP__;}
static int
QHullPartition(cpVect *verts, int count, cpVect a, cpVect b, cpFloat tol)
{
if(count == 0) return 0;
cpFloat max = 0;
int pivot = 0;
cpVect delta = cpvsub(b, a);
cpFloat valueTol = tol*cpvlength(delta);
int head = 0;
for(int tail = count-1; head <= tail;){
cpFloat value = cpvcross(delta, cpvsub(verts[head], a));
if(value > valueTol){
if(value > max){
max = value;
pivot = head;
}
head++;
} else {
SWAP(verts[head], verts[tail]);
tail--;
}
}
// move the new pivot to the front if it's not already there.
if(pivot != 0) SWAP(verts[0], verts[pivot]);
return head;
}
static int
QHullReduce(cpFloat tol, cpVect *verts, int count, cpVect a, cpVect pivot, cpVect b, cpVect *result)
{
if(count < 0){
return 0;
} else if(count == 0) {
result[0] = pivot;
return 1;
} else {
int left_count = QHullPartition(verts, count, a, pivot, tol);
int index = QHullReduce(tol, verts + 1, left_count - 1, a, verts[0], pivot, result);
result[index++] = pivot;
int right_count = QHullPartition(verts + left_count, count - left_count, pivot, b, tol);
return index + QHullReduce(tol, verts + left_count + 1, right_count - 1, pivot, verts[left_count], b, result + index);
}
}
// QuickHull seemed like a neat algorithm, and efficient-ish for large input sets.
// My implementation performs an in place reduction using the result array as scratch space.
int
cpConvexHull(int count, cpVect *verts, cpVect *result, int *first, cpFloat tol)
{
if(result){
// Copy the line vertexes into the empty part of the result polyline to use as a scratch buffer.
memcpy(result, verts, count*sizeof(cpVect));
} else {
// If a result array was not specified, reduce the input instead.
result = verts;
}
// Degenerate case, all poins are the same.
int start, end;
cpLoopIndexes(verts, count, &start, &end);
if(start == end){
if(first) (*first) = 0;
return 1;
}
SWAP(result[0], result[start]);
SWAP(result[1], result[end == 0 ? start : end]);
cpVect a = result[0];
cpVect b = result[1];
if(first) (*first) = start;
int resultCount = QHullReduce(tol, result + 2, count - 2, a, b, a, result + 1) + 1;
cpAssertSoft(cpPolyValidate(result, resultCount),
"Internal error: cpConvexHull() and cpPolyValidate() did not agree."
"Please report this error with as much info as you can.");
return resultCount;
}
//MARK: Alternate Block Iterators
#if defined(__has_extension)
#if __has_extension(blocks)
static void IteratorFunc(void *ptr, void (^block)(void *ptr)){block(ptr);}
void cpSpaceEachBody_b(cpSpace *space, void (^block)(cpBody *body)){
cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)IteratorFunc, block);
}
void cpSpaceEachShape_b(cpSpace *space, void (^block)(cpShape *shape)){
cpSpaceEachShape(space, (cpSpaceShapeIteratorFunc)IteratorFunc, block);
}
void cpSpaceEachConstraint_b(cpSpace *space, void (^block)(cpConstraint *constraint)){
cpSpaceEachConstraint(space, (cpSpaceConstraintIteratorFunc)IteratorFunc, block);
}
static void BodyIteratorFunc(cpBody *body, void *ptr, void (^block)(void *ptr)){block(ptr);}
void cpBodyEachShape_b(cpBody *body, void (^block)(cpShape *shape)){
cpBodyEachShape(body, (cpBodyShapeIteratorFunc)BodyIteratorFunc, block);
}
void cpBodyEachConstraint_b(cpBody *body, void (^block)(cpConstraint *constraint)){
cpBodyEachConstraint(body, (cpBodyConstraintIteratorFunc)BodyIteratorFunc, block);
}
void cpBodyEachArbiter_b(cpBody *body, void (^block)(cpArbiter *arbiter)){
cpBodyEachArbiter(body, (cpBodyArbiterIteratorFunc)BodyIteratorFunc, block);
}
static void NearestPointQueryIteratorFunc(cpShape *shape, cpFloat distance, cpVect point, cpSpaceNearestPointQueryBlock block){block(shape, distance, point);}
void cpSpaceNearestPointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryBlock block){
cpSpaceNearestPointQuery(space, point, maxDistance, layers, group, (cpSpaceNearestPointQueryFunc)NearestPointQueryIteratorFunc, block);
}
static void SegmentQueryIteratorFunc(cpShape *shape, cpFloat t, cpVect n, cpSpaceSegmentQueryBlock block){block(shape, t, n);}
void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryBlock block){
cpSpaceSegmentQuery(space, start, end, layers, group, (cpSpaceSegmentQueryFunc)SegmentQueryIteratorFunc, block);
}
void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryBlock block){
cpSpaceBBQuery(space, bb, layers, group, (cpSpaceBBQueryFunc)IteratorFunc, block);
}
static void ShapeQueryIteratorFunc(cpShape *shape, cpContactPointSet *points, cpSpaceShapeQueryBlock block){block(shape, points);}
cpBool cpSpaceShapeQuery_b(cpSpace *space, cpShape *shape, cpSpaceShapeQueryBlock block){
return cpSpaceShapeQuery(space, shape, (cpSpaceShapeQueryFunc)ShapeQueryIteratorFunc, block);
}
#endif
#endif
#include "chipmunk_ffi.h"

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -38,7 +35,7 @@ cpConstraintFree(cpConstraint *constraint)
}
}
// *** defined in util.h
// *** declared in util.h TODO move declaration to chipmunk_private.h
void
cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b)
@@ -47,6 +44,7 @@ cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBod
constraint->a = a;
constraint->b = b;
constraint->space = NULL;
constraint->next_a = NULL;
constraint->next_b = NULL;
@@ -54,4 +52,7 @@ cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBod
constraint->maxForce = (cpFloat)INFINITY;
constraint->errorBias = cpfpow(1.0f - 0.1f, 60.0f);
constraint->maxBias = (cpFloat)INFINITY;
constraint->preSolve = NULL;
constraint->postSolve = NULL;
}

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -52,7 +49,7 @@ preStep(cpDampedRotarySpring *spring, cpFloat dt)
static void applyCachedImpulse(cpDampedRotarySpring *spring, cpFloat dt_coef){}
static void
applyImpulse(cpDampedRotarySpring *spring)
applyImpulse(cpDampedRotarySpring *spring, cpFloat dt)
{
cpBody *a = spring->constraint.a;
cpBody *b = spring->constraint.b;

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -58,7 +55,7 @@ preStep(cpDampedSpring *spring, cpFloat dt)
static void applyCachedImpulse(cpDampedSpring *spring, cpFloat dt_coef){}
static void
applyImpulse(cpDampedSpring *spring)
applyImpulse(cpDampedSpring *spring, cpFloat dt)
{
cpBody *a = spring->constraint.a;
cpBody *b = spring->constraint.b;

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -37,9 +34,6 @@ preStep(cpGearJoint *joint, cpFloat dt)
// calculate bias velocity
cpFloat maxBias = joint->constraint.maxBias;
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*(b->a*joint->ratio - a->a - joint->phase)/dt, -maxBias, maxBias);
// compute max impulse
joint->jMax = J_MAX(joint, dt);
}
static void
@@ -54,7 +48,7 @@ applyCachedImpulse(cpGearJoint *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpGearJoint *joint)
applyImpulse(cpGearJoint *joint, cpFloat dt)
{
cpBody *a = joint->constraint.a;
cpBody *b = joint->constraint.b;
@@ -62,10 +56,12 @@ applyImpulse(cpGearJoint *joint)
// compute relative rotational velocity
cpFloat wr = b->w*joint->ratio - a->w;
cpFloat jMax = joint->constraint.maxForce*dt;
// compute normal impulse
cpFloat j = (joint->bias - wr)*joint->iSum;
cpFloat jOld = joint->jAcc;
joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);
joint->jAcc = cpfclamp(jOld + j, -jMax, jMax);
j = joint->jAcc - jOld;
// apply impulse

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -57,10 +54,7 @@ preStep(cpGrooveJoint *joint, cpFloat dt)
}
// Calculate mass tensor
k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);
// compute max impulse
joint->jMaxLen = J_MAX(joint, dt);
joint->k = k_tensor(a, b, joint->r1, joint->r2);
// calculate bias velocity
cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
@@ -77,14 +71,14 @@ applyCachedImpulse(cpGrooveJoint *joint, cpFloat dt_coef)
}
static inline cpVect
grooveConstrain(cpGrooveJoint *joint, cpVect j){
grooveConstrain(cpGrooveJoint *joint, cpVect j, cpFloat dt){
cpVect n = joint->grv_tn;
cpVect jClamp = (joint->clamp*cpvcross(j, n) > 0.0f) ? j : cpvproject(j, n);
return cpvclamp(jClamp, joint->jMaxLen);
return cpvclamp(jClamp, joint->constraint.maxForce*dt);
}
static void
applyImpulse(cpGrooveJoint *joint)
applyImpulse(cpGrooveJoint *joint, cpFloat dt)
{
cpBody *a = joint->constraint.a;
cpBody *b = joint->constraint.b;
@@ -95,9 +89,9 @@ applyImpulse(cpGrooveJoint *joint)
// compute impulse
cpVect vr = relative_velocity(a, b, r1, r2);
cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);
cpVect j = cpMat2x2Transform(joint->k, cpvsub(joint->bias, vr));
cpVect jOld = joint->jAcc;
joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j));
joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j), dt);
j = cpvsub(joint->jAcc, jOld);
// apply impulse

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -44,9 +41,6 @@ preStep(cpPinJoint *joint, cpFloat dt)
// calculate bias velocity
cpFloat maxBias = joint->constraint.maxBias;
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*(dist - joint->dist)/dt, -maxBias, maxBias);
// compute max impulse
joint->jnMax = J_MAX(joint, dt);
}
static void
@@ -60,7 +54,7 @@ applyCachedImpulse(cpPinJoint *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpPinJoint *joint)
applyImpulse(cpPinJoint *joint, cpFloat dt)
{
cpBody *a = joint->constraint.a;
cpBody *b = joint->constraint.b;
@@ -69,10 +63,12 @@ applyImpulse(cpPinJoint *joint)
// compute relative velocity
cpFloat vrn = normal_relative_velocity(a, b, joint->r1, joint->r2, n);
cpFloat jnMax = joint->constraint.maxForce*dt;
// compute normal impulse
cpFloat jn = (joint->bias - vrn)*joint->nMass;
cpFloat jnOld = joint->jnAcc;
joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, joint->jnMax);
joint->jnAcc = cpfclamp(jnOld + jn, -jnMax, jnMax);
jn = joint->jnAcc - jnOld;
// apply impulse
@@ -91,7 +87,7 @@ static const cpConstraintClass klass = {
(cpConstraintApplyImpulseImpl)applyImpulse,
(cpConstraintGetImpulseImpl)getImpulse,
};
CP_DefineClassGetter(cpPinJoint);
CP_DefineClassGetter(cpPinJoint)
cpPinJoint *
@@ -112,6 +108,8 @@ cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect an
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));
cpAssertWarn(joint->dist > 0.0, "You created a 0 length pin joint. A pivot joint will be much more stable.");
joint->jnAcc = 0.0f;

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -35,10 +32,7 @@ preStep(cpPivotJoint *joint, cpFloat dt)
joint->r2 = cpvrotate(joint->anchr2, b->rot);
// Calculate mass tensor
k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);
// compute max impulse
joint->jMaxLen = J_MAX(joint, dt);
joint-> k = k_tensor(a, b, joint->r1, joint->r2);
// calculate bias velocity
cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
@@ -55,7 +49,7 @@ applyCachedImpulse(cpPivotJoint *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpPivotJoint *joint)
applyImpulse(cpPivotJoint *joint, cpFloat dt)
{
cpBody *a = joint->constraint.a;
cpBody *b = joint->constraint.b;
@@ -67,9 +61,9 @@ applyImpulse(cpPivotJoint *joint)
cpVect vr = relative_velocity(a, b, r1, r2);
// compute normal impulse
cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);
cpVect j = cpMat2x2Transform(joint->k, cpvsub(joint->bias, vr));
cpVect jOld = joint->jAcc;
joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->jMaxLen);
joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->constraint.maxForce*dt);
j = cpvsub(joint->jAcc, jOld);
// apply impulse

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -51,9 +48,6 @@ preStep(cpRatchetJoint *joint, cpFloat dt)
// calculate bias velocity
cpFloat maxBias = joint->constraint.maxBias;
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
// compute max impulse
joint->jMax = J_MAX(joint, dt);
// If the bias is 0, the joint is not at a limit. Reset the impulse.
if(!joint->bias) joint->jAcc = 0.0f;
@@ -71,7 +65,7 @@ applyCachedImpulse(cpRatchetJoint *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpRatchetJoint *joint)
applyImpulse(cpRatchetJoint *joint, cpFloat dt)
{
if(!joint->bias) return; // early exit
@@ -82,10 +76,12 @@ applyImpulse(cpRatchetJoint *joint)
cpFloat wr = b->w - a->w;
cpFloat ratchet = joint->ratchet;
cpFloat jMax = joint->constraint.maxForce*dt;
// compute normal impulse
cpFloat j = -(joint->bias + wr)*joint->iSum;
cpFloat jOld = joint->jAcc;
joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, joint->jMax*cpfabs(ratchet))/ratchet;
joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, jMax*cpfabs(ratchet))/ratchet;
j = joint->jAcc - jOld;
// apply impulse

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -45,9 +42,6 @@ preStep(cpRotaryLimitJoint *joint, cpFloat dt)
// calculate bias velocity
cpFloat maxBias = joint->constraint.maxBias;
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
// compute max impulse
joint->jMax = J_MAX(joint, dt);
// If the bias is 0, the joint is not at a limit. Reset the impulse.
if(!joint->bias) joint->jAcc = 0.0f;
@@ -65,7 +59,7 @@ applyCachedImpulse(cpRotaryLimitJoint *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpRotaryLimitJoint *joint)
applyImpulse(cpRotaryLimitJoint *joint, cpFloat dt)
{
if(!joint->bias) return; // early exit
@@ -75,13 +69,15 @@ applyImpulse(cpRotaryLimitJoint *joint)
// compute relative rotational velocity
cpFloat wr = b->w - a->w;
cpFloat jMax = joint->constraint.maxForce*dt;
// compute normal impulse
cpFloat j = -(joint->bias + wr)*joint->iSum;
cpFloat jOld = joint->jAcc;
if(joint->bias < 0.0f){
joint->jAcc = cpfclamp(jOld + j, 0.0f, joint->jMax);
joint->jAcc = cpfclamp(jOld + j, 0.0f, jMax);
} else {
joint->jAcc = cpfclamp(jOld + j, -joint->jMax, 0.0f);
joint->jAcc = cpfclamp(jOld + j, -jMax, 0.0f);
}
j = joint->jAcc - jOld;

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -33,9 +30,6 @@ preStep(cpSimpleMotor *joint, cpFloat dt)
// calculate moment of inertia coefficient.
joint->iSum = 1.0f/(a->i_inv + b->i_inv);
// compute max impulse
joint->jMax = J_MAX(joint, dt);
}
static void
@@ -50,7 +44,7 @@ applyCachedImpulse(cpSimpleMotor *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpSimpleMotor *joint)
applyImpulse(cpSimpleMotor *joint, cpFloat dt)
{
cpBody *a = joint->constraint.a;
cpBody *b = joint->constraint.b;
@@ -58,10 +52,12 @@ applyImpulse(cpSimpleMotor *joint)
// compute relative rotational velocity
cpFloat wr = b->w - a->w + joint->rate;
cpFloat jMax = joint->constraint.maxForce*dt;
// compute normal impulse
cpFloat j = -wr*joint->iSum;
cpFloat jOld = joint->jAcc;
joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);
joint->jAcc = cpfclamp(jOld + j, -jMax, jMax);
j = joint->jAcc - jOld;
// apply impulse

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -39,11 +36,14 @@ preStep(cpSlideJoint *joint, cpFloat dt)
cpFloat pdist = 0.0f;
if(dist > joint->max) {
pdist = dist - joint->max;
joint->n = cpvnormalize_safe(delta);
} else if(dist < joint->min) {
pdist = joint->min - dist;
dist = -dist;
joint->n = cpvneg(cpvnormalize_safe(delta));
} else {
joint->n = cpvzero;
joint->jnAcc = 0.0f;
}
joint->n = cpvmult(delta, 1.0f/(dist ? dist : (cpFloat)INFINITY));
// calculate mass normal
joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);
@@ -51,12 +51,6 @@ preStep(cpSlideJoint *joint, cpFloat dt)
// calculate bias velocity
cpFloat maxBias = joint->constraint.maxBias;
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
// compute max impulse
joint->jnMax = J_MAX(joint, dt);
// if bias is 0, then the joint is not at a limit. Reset cached impulse.
if(!joint->bias) joint->jnAcc = 0.0f;
}
static void
@@ -70,9 +64,9 @@ applyCachedImpulse(cpSlideJoint *joint, cpFloat dt_coef)
}
static void
applyImpulse(cpSlideJoint *joint)
applyImpulse(cpSlideJoint *joint, cpFloat dt)
{
if(!joint->bias) return; // early exit
if(cpveql(joint->n, cpvzero)) return; // early exit
cpBody *a = joint->constraint.a;
cpBody *b = joint->constraint.b;
@@ -88,7 +82,7 @@ applyImpulse(cpSlideJoint *joint)
// compute normal impulse
cpFloat jn = (joint->bias - vrn)*joint->nMass;
cpFloat jnOld = joint->jnAcc;
joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, 0.0f);
joint->jnAcc = cpfclamp(jnOld + jn, -joint->constraint.maxForce*dt, 0.0f);
jn = joint->jnAcc - jnOld;
// apply impulse

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -68,10 +65,21 @@ cpArbiterUnthread(cpArbiter *arb)
unthreadHelper(arb, arb->body_b);
}
cpBool cpArbiterIsFirstContact(const cpArbiter *arb)
{
return arb->CP_PRIVATE(state) == cpArbiterStateFirstColl;
}
int cpArbiterGetCount(const cpArbiter *arb)
{
// Return 0 contacts if we are in a separate callback.
return (arb->CP_PRIVATE(state) != cpArbiterStateCached ? arb->CP_PRIVATE(numContacts) : 0);
}
cpVect
cpArbiterGetNormal(const cpArbiter *arb, int i)
{
cpAssertHard(0 <= i && i < arb->numContacts, "Index error: The specified contact index is invalid for this arbiter");
cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter");
cpVect n = arb->contacts[i].n;
return arb->swappedColl ? cpvneg(n) : n;
@@ -80,7 +88,7 @@ cpArbiterGetNormal(const cpArbiter *arb, int i)
cpVect
cpArbiterGetPoint(const cpArbiter *arb, int i)
{
cpAssertHard(0 <= i && i < arb->numContacts, "Index error: The specified contact index is invalid for this arbiter");
cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter");
return arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(p);
}
@@ -88,7 +96,7 @@ cpArbiterGetPoint(const cpArbiter *arb, int i)
cpFloat
cpArbiterGetDepth(const cpArbiter *arb, int i)
{
cpAssertHard(0 <= i && i < arb->numContacts, "Index error: The specified contact index is invalid for this arbiter");
cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter");
return arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist);
}
@@ -116,12 +124,12 @@ cpArbiterTotalImpulse(const cpArbiter *arb)
cpContact *contacts = arb->contacts;
cpVect sum = cpvzero;
for(int i=0, count=arb->numContacts; i<count; i++){
for(int i=0, count=cpArbiterGetCount(arb); i<count; i++){
cpContact *con = &contacts[i];
sum = cpvadd(sum, cpvmult(con->n, con->jnAcc));
}
return sum;
return (arb->swappedColl ? sum : cpvneg(sum));
}
cpVect
@@ -130,11 +138,29 @@ cpArbiterTotalImpulseWithFriction(const cpArbiter *arb)
cpContact *contacts = arb->contacts;
cpVect sum = cpvzero;
for(int i=0, count=arb->numContacts; i<count; i++){
for(int i=0, count=cpArbiterGetCount(arb); i<count; i++){
cpContact *con = &contacts[i];
sum = cpvadd(sum, cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc)));
}
return (arb->swappedColl ? sum : cpvneg(sum));
}
cpFloat
cpArbiterTotalKE(const cpArbiter *arb)
{
cpFloat eCoef = (1 - arb->e)/(1 + arb->e);
cpFloat sum = 0.0;
cpContact *contacts = arb->contacts;
for(int i=0, count=cpArbiterGetCount(arb); i<count; i++){
cpContact *con = &contacts[i];
cpFloat jnAcc = con->jnAcc;
cpFloat jtAcc = con->jtAcc;
sum += eCoef*jnAcc*jnAcc/con->nMass + jtAcc*jtAcc/con->tMass;
}
return sum;
}
@@ -186,6 +212,8 @@ cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b)
arb->stamp = 0;
arb->state = cpArbiterStateFirstColl;
arb->data = NULL;
return arb;
}
@@ -277,48 +305,38 @@ cpArbiterApplyImpulse(cpArbiter *arb)
{
cpBody *a = arb->body_a;
cpBody *b = arb->body_b;
cpVect surface_vr = arb->surface_vr;
cpFloat friction = arb->u;
for(int i=0; i<arb->numContacts; i++){
cpContact *con = &arb->contacts[i];
cpFloat nMass = con->nMass;
cpVect n = con->n;
cpVect r1 = con->r1;
cpVect r2 = con->r2;
// Calculate the relative bias velocities.
cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias));
cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias));
cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);
cpVect vr = relative_velocity(a, b, r1, r2);
// Calculate and clamp the bias impulse.
cpFloat jbn = (con->bias - vbn)*con->nMass;
cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);
cpFloat vrn = cpvdot(vr, n);
cpFloat vrt = cpvdot(cpvadd(vr, surface_vr), cpvperp(n));
cpFloat jbn = (con->bias - vbn)*nMass;
cpFloat jbnOld = con->jBias;
con->jBias = cpfmax(jbnOld + jbn, 0.0f);
jbn = con->jBias - jbnOld;
// Apply the bias impulse.
apply_bias_impulses(a, b, r1, r2, cpvmult(n, jbn));
// Calculate the relative velocity.
cpVect vr = relative_velocity(a, b, r1, r2);
cpFloat vrn = cpvdot(vr, n);
// Calculate and clamp the normal impulse.
cpFloat jn = -(con->bounce + vrn)*con->nMass;
cpFloat jn = -(con->bounce + vrn)*nMass;
cpFloat jnOld = con->jnAcc;
con->jnAcc = cpfmax(jnOld + jn, 0.0f);
jn = con->jnAcc - jnOld;
// Calculate the relative tangent velocity.
cpFloat vrt = cpvdot(cpvadd(vr, arb->surface_vr), cpvperp(n));
// Calculate and clamp the friction impulse.
cpFloat jtMax = arb->u*con->jnAcc;
cpFloat jtMax = friction*con->jnAcc;
cpFloat jt = -vrt*con->tMass;
cpFloat jtOld = con->jtAcc;
con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax);
jt = con->jtAcc - jtOld;
// Apply the final impulse.
apply_impulses(a, b, r1, r2, cpvrotate(n, cpv(jn, jt)));
apply_bias_impulses(a, b, r1, r2, cpvmult(n, con->jBias - jbnOld));
apply_impulses(a, b, r1, r2, cpvrotate(n, cpv(con->jnAcc - jnOld, con->jtAcc - jtOld)));
}
}

View File

@@ -19,7 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
#include "chipmunk_private.h"

View File

@@ -19,19 +19,8 @@
* SOFTWARE.
*/
#include <math.h>
#include <stdlib.h>
#include "chipmunk_private.h"
cpVect
cpBBClampVect(const cpBB bb, const cpVect v)
{
cpFloat x = cpfmin(cpfmax(bb.l, v.x), bb.r);
cpFloat y = cpfmin(cpfmax(bb.b, v.y), bb.t);
return cpv(x, y);
}
cpVect
cpBBWrapVect(const cpBB bb, const cpVect v)
{

View File

@@ -50,16 +50,22 @@ struct Node {
union {
// Internal nodes
struct { Node *a, *b; };
struct { Node *a, *b; } children;
// Leaves
struct {
cpTimestamp stamp;
Pair *pairs;
};
};
} leaf;
} node;
};
// Can't use anonymous unions and still get good x-compiler compatability
#define A node.children.a
#define B node.children.b
#define STAMP node.leaf.stamp
#define PAIRS node.leaf.pairs
typedef struct Thread {
Pair *prev;
Node *leaf;
@@ -68,13 +74,7 @@ typedef struct Thread {
struct Pair { Thread a, b; };
#pragma mark Misc Functions
//static inline cpFloat
//cpBBProximity(cpBB a, cpBB b)
//{
// return cpfabs(a.l + a.r - b.l - b.r) + cpfabs(a.b + b.t - b.b - b.t);
//}
//MARK: Misc Functions
static inline cpBB
GetBB(cpBBTree *tree, void *obj)
@@ -105,11 +105,11 @@ GetRootIfTree(cpSpatialIndex *index){
return (index && index->klass == Klass() ? ((cpBBTree *)index)->root : NULL);
}
static inline cpTimestamp
GetStamp(cpBBTree *tree)
static inline cpBBTree *
GetMasterTree(cpBBTree *tree)
{
cpBBTree *dynamicTree = GetTree(tree->spatialIndex.dynamicIndex);
return (dynamicTree ? dynamicTree->stamp : tree->stamp);
return (dynamicTree ? dynamicTree : tree);
}
static inline void
@@ -123,11 +123,15 @@ IncrementStamp(cpBBTree *tree)
}
}
#pragma mark Pair/Thread Functions
//MARK: Pair/Thread Functions
static void
PairRecycle(cpBBTree *tree, Pair *pair)
{
// Share the pool of the master tree.
// TODO would be lovely to move the pairs stuff into an external data structure.
tree = GetMasterTree(tree);
pair->a.next = tree->pooledPairs;
tree->pooledPairs = pair;
}
@@ -135,6 +139,10 @@ PairRecycle(cpBBTree *tree, Pair *pair)
static Pair *
PairFromPool(cpBBTree *tree)
{
// Share the pool of the master tree.
// TODO would be lovely to move the pairs stuff into an external data structure.
tree = GetMasterTree(tree);
Pair *pair = tree->pooledPairs;
if(pair){
@@ -143,7 +151,7 @@ PairFromPool(cpBBTree *tree)
} else {
// Pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(Pair);
cpAssertSoft(count, "Buffer size is too small.");
cpAssertHard(count, "Internal Error: Buffer size is too small.");
Pair *buffer = (Pair *)cpcalloc(1, CP_BUFFER_BYTES);
cpArrayPush(tree->allocatedBuffers, buffer);
@@ -167,15 +175,15 @@ ThreadUnlink(Thread thread)
if(prev){
if(prev->a.leaf == thread.leaf) prev->a.next = next; else prev->b.next = next;
} else {
thread.leaf->pairs = next;
thread.leaf->PAIRS = next;
}
}
static void
PairsClear(Node *leaf, cpBBTree *tree)
{
Pair *pair = leaf->pairs;
leaf->pairs = NULL;
Pair *pair = leaf->PAIRS;
leaf->PAIRS = NULL;
while(pair){
if(pair->a.leaf == leaf){
@@ -195,11 +203,11 @@ PairsClear(Node *leaf, cpBBTree *tree)
static void
PairInsert(Node *a, Node *b, cpBBTree *tree)
{
Pair *nextA = a->pairs, *nextB = b->pairs;
Pair *nextA = a->PAIRS, *nextB = b->PAIRS;
Pair *pair = PairFromPool(tree);
Pair temp = {{NULL, a, nextA},{NULL, b, nextB}};
a->pairs = b->pairs = pair;
a->PAIRS = b->PAIRS = pair;
*pair = temp;
if(nextA){
@@ -212,7 +220,7 @@ PairInsert(Node *a, Node *b, cpBBTree *tree)
}
#pragma mark Node Functions
//MARK: Node Functions
static void
NodeRecycle(cpBBTree *tree, Node *node)
@@ -232,7 +240,7 @@ NodeFromPool(cpBBTree *tree)
} else {
// Pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(Node);
cpAssertSoft(count, "Buffer size is too small.");
cpAssertHard(count, "Internal Error: Buffer size is too small.");
Node *buffer = (Node *)cpcalloc(1, CP_BUFFER_BYTES);
cpArrayPush(tree->allocatedBuffers, buffer);
@@ -246,14 +254,14 @@ NodeFromPool(cpBBTree *tree)
static inline void
NodeSetA(Node *node, Node *value)
{
node->a = value;
node->A = value;
value->parent = node;
}
static inline void
NodeSetB(Node *node, Node *value)
{
node->b = value;
node->B = value;
value->parent = node;
}
@@ -281,29 +289,35 @@ NodeIsLeaf(Node *node)
static inline Node *
NodeOther(Node *node, Node *child)
{
return (node->a == child ? node->b : node->a);
return (node->A == child ? node->B : node->A);
}
static inline void
NodeReplaceChild(Node *parent, Node *child, Node *value, cpBBTree *tree)
{
cpAssertSoft(!NodeIsLeaf(parent), "Cannot replace child of a leaf.");
cpAssertSoft(child == parent->a || child == parent->b, "Node is not a child of parent.");
cpAssertSoft(!NodeIsLeaf(parent), "Internal Error: Cannot replace child of a leaf.");
cpAssertSoft(child == parent->A || child == parent->B, "Internal Error: Node is not a child of parent.");
if(parent->a == child){
NodeRecycle(tree, parent->a);
if(parent->A == child){
NodeRecycle(tree, parent->A);
NodeSetA(parent, value);
} else {
NodeRecycle(tree, parent->b);
NodeRecycle(tree, parent->B);
NodeSetB(parent, value);
}
for(Node *node=parent; node; node = node->parent){
node->bb = cpBBMerge(node->a->bb, node->b->bb);
node->bb = cpBBMerge(node->A->bb, node->B->bb);
}
}
#pragma mark Subtree Functions
//MARK: Subtree Functions
static inline cpFloat
cpBBProximity(cpBB a, cpBB b)
{
return cpfabs(a.l + a.r - b.l - b.r) + cpfabs(a.b + a.t - b.b - b.t);
}
static Node *
SubtreeInsert(Node *subtree, Node *leaf, cpBBTree *tree)
@@ -313,16 +327,18 @@ SubtreeInsert(Node *subtree, Node *leaf, cpBBTree *tree)
} else if(NodeIsLeaf(subtree)){
return NodeNew(tree, leaf, subtree);
} else {
cpFloat cost_a = cpBBArea(subtree->b->bb) + cpBBMergedArea(subtree->a->bb, leaf->bb);
cpFloat cost_b = cpBBArea(subtree->a->bb) + cpBBMergedArea(subtree->b->bb, leaf->bb);
cpFloat cost_a = cpBBArea(subtree->B->bb) + cpBBMergedArea(subtree->A->bb, leaf->bb);
cpFloat cost_b = cpBBArea(subtree->A->bb) + cpBBMergedArea(subtree->B->bb, leaf->bb);
// cpFloat cost_a = cpBBProximity(subtree->a->bb, leaf->bb);
// cpFloat cost_b = cpBBProximity(subtree->b->bb, leaf->bb);
if(cost_a == cost_b){
cost_a = cpBBProximity(subtree->A->bb, leaf->bb);
cost_b = cpBBProximity(subtree->B->bb, leaf->bb);
}
if(cost_b < cost_a){
NodeSetB(subtree, SubtreeInsert(subtree->b, leaf, tree));
NodeSetB(subtree, SubtreeInsert(subtree->B, leaf, tree));
} else {
NodeSetA(subtree, SubtreeInsert(subtree->a, leaf, tree));
NodeSetA(subtree, SubtreeInsert(subtree->A, leaf, tree));
}
subtree->bb = cpBBMerge(subtree->bb, leaf->bb);
@@ -337,24 +353,31 @@ SubtreeQuery(Node *subtree, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, vo
if(NodeIsLeaf(subtree)){
func(obj, subtree->obj, data);
} else {
SubtreeQuery(subtree->a, obj, bb, func, data);
SubtreeQuery(subtree->b, obj, bb, func, data);
SubtreeQuery(subtree->A, obj, bb, func, data);
SubtreeQuery(subtree->B, obj, bb, func, data);
}
}
}
// TODO Needs early exit optimization for ray queries
static void
SubtreeSegmentQuery(Node *subtree, void *obj, cpVect a, cpVect b, cpSpatialIndexSegmentQueryFunc func, void *data)
static cpFloat
SubtreeSegmentQuery(Node *subtree, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)
{
if(cpBBIntersectsSegment(subtree->bb, a, b)){
if(NodeIsLeaf(subtree)){
func(obj, subtree->obj, data);
if(NodeIsLeaf(subtree)){
return func(obj, subtree->obj, data);
} else {
cpFloat t_a = cpBBSegmentQuery(subtree->A->bb, a, b);
cpFloat t_b = cpBBSegmentQuery(subtree->B->bb, a, b);
if(t_a < t_b){
if(t_a < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->A, obj, a, b, t_exit, func, data));
if(t_b < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->B, obj, a, b, t_exit, func, data));
} else {
SubtreeSegmentQuery(subtree->a, obj, a, b, func, data);
SubtreeSegmentQuery(subtree->b, obj, a, b, func, data);
if(t_b < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->B, obj, a, b, t_exit, func, data));
if(t_a < t_exit) t_exit = cpfmin(t_exit, SubtreeSegmentQuery(subtree->A, obj, a, b, t_exit, func, data));
}
return t_exit;
}
}
@@ -362,8 +385,8 @@ static void
SubtreeRecycle(cpBBTree *tree, Node *node)
{
if(!NodeIsLeaf(node)){
SubtreeRecycle(tree, node->a);
SubtreeRecycle(tree, node->b);
SubtreeRecycle(tree, node->A);
SubtreeRecycle(tree, node->B);
NodeRecycle(tree, node);
}
}
@@ -387,7 +410,7 @@ SubtreeRemove(Node *subtree, Node *leaf, cpBBTree *tree)
}
}
#pragma mark Marking Functions
//MARK: Marking Functions
typedef struct MarkContext {
cpBBTree *tree;
@@ -404,12 +427,12 @@ MarkLeafQuery(Node *subtree, Node *leaf, cpBool left, MarkContext *context)
if(left){
PairInsert(leaf, subtree, context->tree);
} else {
if(subtree->stamp < leaf->stamp) PairInsert(subtree, leaf, context->tree);
if(subtree->STAMP < leaf->STAMP) PairInsert(subtree, leaf, context->tree);
context->func(leaf->obj, subtree->obj, context->data);
}
} else {
MarkLeafQuery(subtree->a, leaf, left, context);
MarkLeafQuery(subtree->b, leaf, left, context);
MarkLeafQuery(subtree->A, leaf, left, context);
MarkLeafQuery(subtree->B, leaf, left, context);
}
}
}
@@ -418,19 +441,19 @@ static void
MarkLeaf(Node *leaf, MarkContext *context)
{
cpBBTree *tree = context->tree;
if(leaf->stamp == GetStamp(tree)){
if(leaf->STAMP == GetMasterTree(tree)->stamp){
Node *staticRoot = context->staticRoot;
if(staticRoot) MarkLeafQuery(staticRoot, leaf, cpFalse, context);
for(Node *node = leaf; node->parent; node = node->parent){
if(node == node->parent->a){
MarkLeafQuery(node->parent->b, leaf, cpTrue, context);
if(node == node->parent->A){
MarkLeafQuery(node->parent->B, leaf, cpTrue, context);
} else {
MarkLeafQuery(node->parent->a, leaf, cpFalse, context);
MarkLeafQuery(node->parent->A, leaf, cpFalse, context);
}
}
} else {
Pair *pair = leaf->pairs;
Pair *pair = leaf->PAIRS;
while(pair){
if(leaf == pair->b.leaf){
context->func(pair->a.leaf->obj, leaf->obj, context->data);
@@ -448,12 +471,12 @@ MarkSubtree(Node *subtree, MarkContext *context)
if(NodeIsLeaf(subtree)){
MarkLeaf(subtree, context);
} else {
MarkSubtree(subtree->a, context);
MarkSubtree(subtree->b, context);
MarkSubtree(subtree->A, context);
MarkSubtree(subtree->B, context);
}
}
#pragma mark Leaf Functions
//MARK: Leaf Functions
static Node *
LeafNew(cpBBTree *tree, void *obj, cpBB bb)
@@ -463,8 +486,8 @@ LeafNew(cpBBTree *tree, void *obj, cpBB bb)
node->bb = GetBB(tree, obj);
node->parent = NULL;
node->stamp = 0;
node->pairs = NULL;
node->STAMP = 0;
node->PAIRS = NULL;
return node;
}
@@ -482,7 +505,7 @@ LeafUpdate(Node *leaf, cpBBTree *tree)
tree->root = SubtreeInsert(root, leaf, tree);
PairsClear(leaf, tree);
leaf->stamp = GetStamp(tree);
leaf->STAMP = GetMasterTree(tree)->stamp;
return cpTrue;
}
@@ -510,7 +533,7 @@ LeafAddPairs(Node *leaf, cpBBTree *tree)
}
}
#pragma mark Memory Management Functions
//MARK: Memory Management Functions
cpBBTree *
cpBBTreeAlloc(void)
@@ -574,7 +597,7 @@ cpBBTreeDestroy(cpBBTree *tree)
cpArrayFree(tree->allocatedBuffers);
}
#pragma mark Insert/Remove
//MARK: Insert/Remove
static void
cpBBTreeInsert(cpBBTree *tree, void *obj, cpHashValue hashid)
@@ -584,7 +607,7 @@ cpBBTreeInsert(cpBBTree *tree, void *obj, cpHashValue hashid)
Node *root = tree->root;
tree->root = SubtreeInsert(root, leaf, tree);
leaf->stamp = GetStamp(tree);
leaf->STAMP = GetMasterTree(tree)->stamp;
LeafAddPairs(leaf, tree);
IncrementStamp(tree);
}
@@ -605,7 +628,7 @@ cpBBTreeContains(cpBBTree *tree, void *obj, cpHashValue hashid)
return (cpHashSetFind(tree->leaves, hashid, obj) != NULL);
}
#pragma mark Reindex
//MARK: Reindex
static void
cpBBTreeReindexQuery(cpBBTree *tree, cpSpatialIndexQueryFunc func, void *data)
@@ -641,20 +664,13 @@ cpBBTreeReindexObject(cpBBTree *tree, void *obj, cpHashValue hashid)
}
}
#pragma mark Query
static void
cpBBTreePointQuery(cpBBTree *tree, cpVect point, cpSpatialIndexQueryFunc func, void *data)
{
Node *root = tree->root;
if(root) SubtreeQuery(root, &point, cpBBNew(point.x, point.y, point.x, point.y), func, data);
}
//MARK: Query
static void
cpBBTreeSegmentQuery(cpBBTree *tree, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)
{
Node *root = tree->root;
if(root) SubtreeSegmentQuery(root, obj, a, b, func, data);
if(root) SubtreeSegmentQuery(root, obj, a, b, t_exit, func, data);
}
static void
@@ -663,7 +679,7 @@ cpBBTreeQuery(cpBBTree *tree, void *obj, cpBB bb, cpSpatialIndexQueryFunc func,
if(tree->root) SubtreeQuery(tree->root, obj, bb, func, data);
}
#pragma mark Misc
//MARK: Misc
static int
cpBBTreeCount(cpBBTree *tree)
@@ -699,15 +715,14 @@ static cpSpatialIndexClass klass = {
(cpSpatialIndexReindexObjectImpl)cpBBTreeReindexObject,
(cpSpatialIndexReindexQueryImpl)cpBBTreeReindexQuery,
(cpSpatialIndexPointQueryImpl)cpBBTreePointQuery,
(cpSpatialIndexSegmentQueryImpl)cpBBTreeSegmentQuery,
(cpSpatialIndexQueryImpl)cpBBTreeQuery,
(cpSpatialIndexSegmentQueryImpl)cpBBTreeSegmentQuery,
};
static inline cpSpatialIndexClass *Klass(){return &klass;}
#pragma mark Tree Optimization
//MARK: Tree Optimization
static int
cpfcompare(const cpFloat *a, const cpFloat *b){
@@ -827,7 +842,7 @@ cpBBTreeOptimize(cpSpatialIndex *index)
cpfree(nodes);
}
#pragma mark Debug Draw
//MARK: Debug Draw
//#define CP_BBTREE_DEBUG_DRAW
#ifdef CP_BBTREE_DEBUG_DRAW

View File

@@ -19,9 +19,7 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include "chipmunk_private.h"
#include "constraints/util.h"
@@ -88,7 +86,7 @@ cpBodyInitStatic(cpBody *body)
}
cpBody *
cpBodyNewStatic()
cpBodyNewStatic(void)
{
return cpBodyInitStatic(cpBodyAlloc());
}
@@ -108,6 +106,10 @@ static void cpv_assert_nan(cpVect v, char *message){cpAssertSoft(v.x == v.x && v
static void cpv_assert_infinite(cpVect v, char *message){cpAssertSoft(cpfabs(v.x) != INFINITY && cpfabs(v.y) != INFINITY, message);}
static void cpv_assert_sane(cpVect v, char *message){cpv_assert_nan(v, message); cpv_assert_infinite(v, message);}
#ifdef __cplusplus
extern "C" {
#endif
void
cpBodySanityCheck(cpBody *body)
{
@@ -122,26 +124,36 @@ cpBodySanityCheck(cpBody *body)
cpAssertSoft(body->w == body->w && cpfabs(body->w) != INFINITY, "Body's angular velocity is invalid.");
cpAssertSoft(body->t == body->t && cpfabs(body->t) != INFINITY, "Body's torque is invalid.");
cpv_assert_sane(body->rot, "Internal error: Body's rotation vector is invalid.");
cpv_assert_sane(body->rot, "Body's rotation vector is invalid.");
cpAssertSoft(body->v_limit == body->v_limit, "Body's velocity limit is invalid.");
cpAssertSoft(body->w_limit == body->w_limit, "Body's angular velocity limit is invalid.");
}
#ifdef __cplusplus
}
#endif
void
cpBodySetMass(cpBody *body, cpFloat mass)
{
cpAssertHard(mass > 0.0f, "Mass must be positive and non-zero.");
cpBodyActivate(body);
body->m = mass;
body->m_inv = 1.0f/mass;
cpBodyAssertSane(body);
}
void
cpBodySetMoment(cpBody *body, cpFloat moment)
{
cpAssertHard(moment > 0.0f, "Moment of Inertia must be positive and non-zero.");
cpBodyActivate(body);
body->i = moment;
body->i_inv = 1.0f/moment;
cpBodyAssertSane(body);
}
void
@@ -198,8 +210,8 @@ void
cpBodySetPos(cpBody *body, cpVect pos)
{
cpBodyActivate(body);
cpBodyAssertSane(body);
body->p = pos;
cpBodyAssertSane(body);
}
static inline void
@@ -207,13 +219,13 @@ setAngle(cpBody *body, cpFloat angle)
{
body->a = angle;//fmod(a, (cpFloat)M_PI*2.0f);
body->rot = cpvforangle(angle);
cpBodyAssertSane(body);
}
void
cpBodySetAngle(cpBody *body, cpFloat angle)
{
cpBodyActivate(body);
cpBodyAssertSane(body);
setAngle(body, angle);
}
@@ -243,6 +255,7 @@ cpBodyUpdatePosition(cpBody *body, cpFloat dt)
void
cpBodyResetForces(cpBody *body)
{
cpBodyActivate(body);
body->f = cpvzero;
body->t = 0.0f;
}
@@ -250,6 +263,7 @@ cpBodyResetForces(cpBody *body)
void
cpBodyApplyForce(cpBody *body, cpVect force, cpVect r)
{
cpBodyActivate(body);
body->f = cpvadd(body->f, force);
body->t += cpvcross(r, force);
}
@@ -261,6 +275,24 @@ cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r)
apply_impulse(body, j, r);
}
static inline cpVect
cpBodyGetVelAtPoint(cpBody *body, cpVect r)
{
return cpvadd(body->v, cpvmult(cpvperp(r), body->w));
}
cpVect
cpBodyGetVelAtWorldPoint(cpBody *body, cpVect point)
{
return cpBodyGetVelAtPoint(body, cpvsub(point, body->p));
}
cpVect
cpBodyGetVelAtLocalPoint(cpBody *body, cpVect point)
{
return cpBodyGetVelAtPoint(body, cpvrotate(point, body->rot));
}
void
cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data)
{

View File

@@ -19,10 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <math.h>
//#include <stdio.h>
#include "chipmunk_private.h"
typedef int (*collisionFunc)(const cpShape *, const cpShape *, cpContact *);
@@ -61,54 +57,30 @@ circle2circle(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr);
}
// Collide circles to segment shapes.
static int
circle2segment(const cpShape *circleShape, const cpShape *segmentShape, cpContact *con)
circle2segment(const cpCircleShape *circleShape, const cpSegmentShape *segmentShape, cpContact *con)
{
cpCircleShape *circ = (cpCircleShape *)circleShape;
cpSegmentShape *seg = (cpSegmentShape *)segmentShape;
cpVect seg_a = segmentShape->ta;
cpVect seg_b = segmentShape->tb;
cpVect center = circleShape->tc;
// Radius sum
cpFloat rsum = circ->r + seg->r;
cpVect seg_delta = cpvsub(seg_b, seg_a);
cpFloat closest_t = cpfclamp01(cpvdot(seg_delta, cpvsub(center, seg_a))/cpvlengthsq(seg_delta));
cpVect closest = cpvadd(seg_a, cpvmult(seg_delta, closest_t));
// Calculate normal distance from segment.
cpFloat dn = cpvdot(seg->tn, circ->tc) - cpvdot(seg->ta, seg->tn);
cpFloat dist = cpfabs(dn) - rsum;
if(dist > 0.0f) return 0;
// Calculate tangential distance along segment.
cpFloat dt = -cpvcross(seg->tn, circ->tc);
cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
// Decision tree to decide which feature of the segment to collide with.
if(dt < dtMin){
if(dt < (dtMin - rsum)){
return 0;
} else {
return circle2circleQuery(circ->tc, seg->ta, circ->r, seg->r, con);
}
if(circle2circleQuery(center, closest, circleShape->r, segmentShape->r, con)){
cpVect n = con[0].n;
// Reject endcap collisions if tangents are provided.
if(
(closest_t == 0.0f && cpvdot(n, segmentShape->a_tangent) < 0.0) ||
(closest_t == 1.0f && cpvdot(n, segmentShape->b_tangent) < 0.0)
) return 0;
return 1;
} else {
if(dt < dtMax){
cpVect n = (dn < 0.0f) ? seg->tn : cpvneg(seg->tn);
cpContactInit(
con,
cpvadd(circ->tc, cpvmult(n, circ->r + dist*0.5f)),
n,
dist,
0
);
return 1;
} else {
if(dt < (dtMax + rsum)) {
return circle2circleQuery(circ->tc, seg->tb, circ->r, seg->r, con);
} else {
return 0;
}
}
return 0;
}
return 1;
}
// Helper function for working with contact buffers
@@ -128,14 +100,14 @@ nextContactPoint(cpContact *arr, int *numPtr)
// Find the minimum separating axis for the give poly and axis list.
static inline int
findMSA(const cpPolyShape *poly, const cpPolyShapeAxis *axes, const int num, cpFloat *min_out)
findMSA(const cpPolyShape *poly, const cpSplittingPlane *planes, const int num, cpFloat *min_out)
{
int min_index = 0;
cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);
cpFloat min = cpPolyShapeValueOnAxis(poly, planes->n, planes->d);
if(min > 0.0f) return -1;
for(int i=1; i<num; i++){
cpFloat dist = cpPolyShapeValueOnAxis(poly, axes[i].n, axes[i].d);
cpFloat dist = cpPolyShapeValueOnAxis(poly, planes[i].n, planes[i].d);
if(dist > 0.0f) {
return -1;
} else if(dist > min){
@@ -200,18 +172,18 @@ poly2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
cpPolyShape *poly2 = (cpPolyShape *)shape2;
cpFloat min1;
int mini1 = findMSA(poly2, poly1->tAxes, poly1->numVerts, &min1);
int mini1 = findMSA(poly2, poly1->tPlanes, poly1->numVerts, &min1);
if(mini1 == -1) return 0;
cpFloat min2;
int mini2 = findMSA(poly1, poly2->tAxes, poly2->numVerts, &min2);
int mini2 = findMSA(poly1, poly2->tPlanes, poly2->numVerts, &min2);
if(mini2 == -1) return 0;
// There is overlap, find the penetrating verts
if(min1 > min2)
return findVerts(arr, poly1, poly2, poly1->tAxes[mini1].n, min1);
return findVerts(arr, poly1, poly2, poly1->tPlanes[mini1].n, min1);
else
return findVerts(arr, poly1, poly2, cpvneg(poly2->tAxes[mini2].n), min2);
return findVerts(arr, poly1, poly2, cpvneg(poly2->tPlanes[mini2].n), min2);
}
// Like cpPolyValueOnAxis(), but for segments.
@@ -249,7 +221,7 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{
cpSegmentShape *seg = (cpSegmentShape *)shape1;
cpPolyShape *poly = (cpPolyShape *)shape2;
cpPolyShapeAxis *axes = poly->tAxes;
cpSplittingPlane *planes = poly->tPlanes;
cpFloat segD = cpvdot(seg->tn, seg->ta);
cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r;
@@ -257,10 +229,10 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
if(minNeg > 0.0f || minNorm > 0.0f) return 0;
int mini = 0;
cpFloat poly_min = segValueOnAxis(seg, axes->n, axes->d);
cpFloat poly_min = segValueOnAxis(seg, planes->n, planes->d);
if(poly_min > 0.0f) return 0;
for(int i=0; i<poly->numVerts; i++){
cpFloat dist = segValueOnAxis(seg, axes[i].n, axes[i].d);
cpFloat dist = segValueOnAxis(seg, planes[i].n, planes[i].d);
if(dist > 0.0f){
return 0;
} else if(dist > poly_min){
@@ -271,7 +243,7 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
int num = 0;
cpVect poly_n = cpvneg(axes[mini].n);
cpVect poly_n = cpvneg(planes[mini].n);
cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r));
cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r));
@@ -296,17 +268,10 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
cpVect poly_a = poly->tVerts[mini];
cpVect poly_b = poly->tVerts[(mini + 1)%poly->numVerts];
if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr))
return 1;
if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr))
return 1;
if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr))
return 1;
if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr))
return 1;
if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr)) return 1;
if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr)) return 1;
if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr)) return 1;
if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr)) return 1;
}
return num;
@@ -319,12 +284,12 @@ circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
{
cpCircleShape *circ = (cpCircleShape *)shape1;
cpPolyShape *poly = (cpPolyShape *)shape2;
cpPolyShapeAxis *axes = poly->tAxes;
cpSplittingPlane *planes = poly->tPlanes;
int mini = 0;
cpFloat min = cpvdot(axes->n, circ->tc) - axes->d - circ->r;
cpFloat min = cpSplittingPlaneCompare(planes[0], circ->tc) - circ->r;
for(int i=0; i<poly->numVerts; i++){
cpFloat dist = cpvdot(axes[i].n, circ->tc) - axes[i].d - circ->r;
cpFloat dist = cpSplittingPlaneCompare(planes[i], circ->tc) - circ->r;
if(dist > 0.0f){
return 0;
} else if(dist > min) {
@@ -333,7 +298,7 @@ circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
}
}
cpVect n = axes[mini].n;
cpVect n = planes[mini].n;
cpVect a = poly->tVerts[mini];
cpVect b = poly->tVerts[(mini + 1)%poly->numVerts];
cpFloat dta = cpvcross(n, a);
@@ -357,11 +322,69 @@ circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
}
}
// Submitted by LegoCyclon
static int
seg2seg(const cpShape* shape1, const cpShape* shape2, cpContact* con)
{
cpSegmentShape* seg1 = (cpSegmentShape *)shape1;
cpSegmentShape* seg2 = (cpSegmentShape *)shape2;
cpVect v1 = cpvsub(seg1->tb, seg1->ta);
cpVect v2 = cpvsub(seg2->tb, seg2->ta);
cpFloat v1lsq = cpvlengthsq(v1);
cpFloat v2lsq = cpvlengthsq(v2);
// project seg2 onto seg1
cpVect p1a = cpvproject(cpvsub(seg2->ta, seg1->ta), v1);
cpVect p1b = cpvproject(cpvsub(seg2->tb, seg1->ta), v1);
// project seg1 onto seg2
cpVect p2a = cpvproject(cpvsub(seg1->ta, seg2->ta), v2);
cpVect p2b = cpvproject(cpvsub(seg1->tb, seg2->ta), v2);
// clamp projections to segment endcaps
if (cpvdot(p1a, v1) < 0.0f)
p1a = cpvzero;
else if (cpvdot(p1a, v1) > 0.0f && cpvlengthsq(p1a) > v1lsq)
p1a = v1;
if (cpvdot(p1b, v1) < 0.0f)
p1b = cpvzero;
else if (cpvdot(p1b, v1) > 0.0f && cpvlengthsq(p1b) > v1lsq)
p1b = v1;
if (cpvdot(p2a, v2) < 0.0f)
p2a = cpvzero;
else if (cpvdot(p2a, v2) > 0.0f && cpvlengthsq(p2a) > v2lsq)
p2a = v2;
if (cpvdot(p2b, v2) < 0.0f)
p2b = cpvzero;
else if (cpvdot(p2b, v2) > 0.0f && cpvlengthsq(p2b) > v2lsq)
p2b = v2;
p1a = cpvadd(p1a, seg1->ta);
p1b = cpvadd(p1b, seg1->ta);
p2a = cpvadd(p2a, seg2->ta);
p2b = cpvadd(p2b, seg2->ta);
int num = 0;
if (!circle2circleQuery(p1a, p2a, seg1->r, seg2->r, nextContactPoint(con, &num)))
--num;
if (!circle2circleQuery(p1b, p2b, seg1->r, seg2->r, nextContactPoint(con, &num)))
--num;
if (!circle2circleQuery(p1a, p2b, seg1->r, seg2->r, nextContactPoint(con, &num)))
--num;
if (!circle2circleQuery(p1b, p2a, seg1->r, seg2->r, nextContactPoint(con, &num)))
--num;
return num;
}
static const collisionFunc builtinCollisionFuncs[9] = {
circle2circle,
NULL,
NULL,
circle2segment,
(collisionFunc)circle2segment,
NULL,
NULL,
circle2poly,
@@ -370,36 +393,23 @@ static const collisionFunc builtinCollisionFuncs[9] = {
};
static const collisionFunc *colfuncs = builtinCollisionFuncs;
//static collisionFunc *colfuncs = NULL;
//
//static void
//addColFunc(const cpShapeType a, const cpShapeType b, const collisionFunc func)
//{
// colfuncs[a + b*CP_NUM_SHAPES] = func;
//}
//
//#ifdef __cplusplus
//extern "C" {
//#endif
// void cpInitCollisionFuncs(void);
//
// // Initializes the array of collision functions.
// // Called by cpInitChipmunk().
// void
// cpInitCollisionFuncs(void)
// {
// if(!colfuncs)
// colfuncs = (collisionFunc *)cpcalloc(CP_NUM_SHAPES*CP_NUM_SHAPES, sizeof(collisionFunc));
//
// addColFunc(CP_CIRCLE_SHAPE, CP_CIRCLE_SHAPE, circle2circle);
// addColFunc(CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, circle2segment);
// addColFunc(CP_SEGMENT_SHAPE, CP_POLY_SHAPE, seg2poly);
// addColFunc(CP_CIRCLE_SHAPE, CP_POLY_SHAPE, circle2poly);
// addColFunc(CP_POLY_SHAPE, CP_POLY_SHAPE, poly2poly);
// }
//#ifdef __cplusplus
//}
//#endif
static const collisionFunc segmentCollisions[9] = {
circle2circle,
NULL,
NULL,
(collisionFunc)circle2segment,
seg2seg,
NULL,
circle2poly,
seg2poly,
poly2poly,
};
void
cpEnableSegmentToSegmentCollisions(void)
{
colfuncs = segmentCollisions;
}
int
cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr)

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <assert.h>
#include "chipmunk_private.h"
#include "prime.h"
@@ -32,7 +29,7 @@ typedef struct cpHashSetBin {
} cpHashSetBin;
struct cpHashSet {
int entries, size;
unsigned int entries, size;
cpHashSetEqlFunc eql;
void *default_value;
@@ -91,18 +88,18 @@ static void
cpHashSetResize(cpHashSet *set)
{
// Get the next approximate doubled prime.
int newSize = next_prime(set->size + 1);
unsigned int newSize = next_prime(set->size + 1);
// Allocate a new table.
cpHashSetBin **newTable = (cpHashSetBin **)cpcalloc(newSize, sizeof(cpHashSetBin *));
// Iterate over the chains.
for(int i=0; i<set->size; i++){
for(unsigned int i=0; i<set->size; i++){
// Rehash the bins into the new table.
cpHashSetBin *bin = set->table[i];
while(bin){
cpHashSetBin *next = bin->next;
int idx = bin->hash%newSize;
cpHashValue idx = bin->hash%newSize;
bin->next = newTable[idx];
newTable[idx] = bin;
@@ -135,7 +132,7 @@ getUnusedBin(cpHashSet *set)
} else {
// Pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(cpHashSetBin);
cpAssertSoft(count, "Buffer size is too small.");
cpAssertHard(count, "Internal Error: Buffer size is too small.");
cpHashSetBin *buffer = (cpHashSetBin *)cpcalloc(1, CP_BUFFER_BYTES);
cpArrayPush(set->allocatedBuffers, buffer);
@@ -155,7 +152,7 @@ cpHashSetCount(cpHashSet *set)
void *
cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data, cpHashSetTransFunc trans)
{
int idx = hash%set->size;
cpHashValue idx = hash%set->size;
// Find the bin with the matching element.
cpHashSetBin *bin = set->table[idx];
@@ -181,7 +178,7 @@ cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data, cpHashS
void *
cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr)
{
int idx = hash%set->size;
cpHashValue idx = hash%set->size;
cpHashSetBin **prev_ptr = &set->table[idx];
cpHashSetBin *bin = set->table[idx];
@@ -210,7 +207,7 @@ cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr)
void *
cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr)
{
int idx = hash%set->size;
cpHashValue idx = hash%set->size;
cpHashSetBin *bin = set->table[idx];
while(bin && !set->eql(ptr, bin->elt))
bin = bin->next;
@@ -221,7 +218,7 @@ cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr)
void
cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data)
{
for(int i=0; i<set->size; i++){
for(unsigned int i=0; i<set->size; i++){
cpHashSetBin *bin = set->table[i];
while(bin){
cpHashSetBin *next = bin->next;
@@ -234,7 +231,7 @@ cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data)
void
cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data)
{
for(int i=0; i<set->size; i++){
for(unsigned int i=0; i<set->size; i++){
// The rest works similarly to cpHashSetRemove() above.
cpHashSetBin **prev_ptr = &set->table[i];
cpHashSetBin *bin = set->table[i];

View File

@@ -19,8 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include "chipmunk_private.h"
#include "chipmunk_unsafe.h"
@@ -55,8 +53,8 @@ cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot)
static void
cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot)
{
cpPolyShapeAxis *src = poly->axes;
cpPolyShapeAxis *dst = poly->tAxes;
cpSplittingPlane *src = poly->planes;
cpSplittingPlane *dst = poly->tPlanes;
for(int i=0; i<poly->numVerts; i++){
cpVect n = cpvrotate(src[i].n, rot);
@@ -78,21 +76,44 @@ static void
cpPolyShapeDestroy(cpPolyShape *poly)
{
cpfree(poly->verts);
cpfree(poly->tVerts);
cpfree(poly->axes);
cpfree(poly->tAxes);
cpfree(poly->planes);
}
static cpBool
cpPolyShapePointQuery(cpPolyShape *poly, cpVect p){
return cpBBContainsVect(poly->shape.bb, p) && cpPolyShapeContainsVert(poly, p);
static void
cpPolyShapeNearestPointQuery(cpPolyShape *poly, cpVect p, cpNearestPointQueryInfo *info){
int count = poly->numVerts;
cpSplittingPlane *planes = poly->tPlanes;
cpVect *verts = poly->tVerts;
cpVect v0 = verts[count - 1];
cpFloat minDist = INFINITY;
cpVect closestPoint = cpvzero;
cpBool outside = cpFalse;
for(int i=0; i<count; i++){
if(cpSplittingPlaneCompare(planes[i], p) > 0.0f) outside = cpTrue;
cpVect v1 = verts[i];
cpVect closest = cpClosetPointOnSegment(p, v0, v1);
cpFloat dist = cpvdist(p, closest);
if(dist < minDist){
minDist = dist;
closestPoint = closest;
}
v0 = v1;
}
info->shape = (cpShape *)poly;
info->p = closestPoint; // TODO div/0
info->d = (outside ? minDist : -minDist);
}
static void
cpPolyShapeSegmentQuery(cpPolyShape *poly, cpVect a, cpVect b, cpSegmentQueryInfo *info)
{
cpPolyShapeAxis *axes = poly->tAxes;
cpSplittingPlane *axes = poly->tPlanes;
cpVect *verts = poly->tVerts;
int numVerts = poly->numVerts;
@@ -122,7 +143,7 @@ static const cpShapeClass polyClass = {
CP_POLY_SHAPE,
(cpShapeCacheDataImpl)cpPolyShapeCacheData,
(cpShapeDestroyImpl)cpPolyShapeDestroy,
(cpShapePointQueryImpl)cpPolyShapePointQuery,
(cpShapeNearestPointQueryImpl)cpPolyShapeNearestPointQuery,
(cpShapeSegmentQueryImpl)cpPolyShapeSegmentQuery,
};
@@ -134,8 +155,9 @@ cpPolyValidate(const cpVect *verts, const int numVerts)
cpVect b = verts[(i+1)%numVerts];
cpVect c = verts[(i+2)%numVerts];
if(cpvcross(cpvsub(b, a), cpvsub(c, b)) > 0.0f)
if(cpvcross(cpvsub(b, a), cpvsub(c, a)) > 0.0f){
return cpFalse;
}
}
return cpTrue;
@@ -159,14 +181,16 @@ cpPolyShapeGetVert(cpShape *shape, int idx)
static void
setUpVerts(cpPolyShape *poly, int numVerts, cpVect *verts, cpVect offset)
setUpVerts(cpPolyShape *poly, int numVerts, const cpVect *verts, cpVect offset)
{
// Fail if the user attempts to pass a concave poly, or a bad winding.
cpAssertHard(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding. Consider using cpConvexHull() or CP_CONVEX_HULL().");
poly->numVerts = numVerts;
poly->verts = (cpVect *)cpcalloc(numVerts, sizeof(cpVect));
poly->tVerts = (cpVect *)cpcalloc(numVerts, sizeof(cpVect));
poly->axes = (cpPolyShapeAxis *)cpcalloc(numVerts, sizeof(cpPolyShapeAxis));
poly->tAxes = (cpPolyShapeAxis *)cpcalloc(numVerts, sizeof(cpPolyShapeAxis));
poly->verts = (cpVect *)cpcalloc(2*numVerts, sizeof(cpVect));
poly->planes = (cpSplittingPlane *)cpcalloc(2*numVerts, sizeof(cpSplittingPlane));
poly->tVerts = poly->verts + numVerts;
poly->tPlanes = poly->planes + numVerts;
for(int i=0; i<numVerts; i++){
cpVect a = cpvadd(offset, verts[i]);
@@ -174,17 +198,15 @@ setUpVerts(cpPolyShape *poly, int numVerts, cpVect *verts, cpVect offset)
cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));
poly->verts[i] = a;
poly->axes[i].n = n;
poly->axes[i].d = cpvdot(n, a);
poly->planes[i].n = n;
poly->planes[i].d = cpvdot(n, a);
}
}
cpPolyShape *
cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)
cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset)
{
// Fail if the user attempts to pass a concave poly, or a bad winding.
cpAssertHard(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding.");
setUpVerts(poly, numVerts, verts, offset);
cpShapeInit((cpShape *)poly, &polyClass, body);

View File

@@ -19,10 +19,6 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "chipmunk_private.h"
#include "chipmunk_unsafe.h"
@@ -61,6 +57,9 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
shape->layers = CP_ALL_LAYERS;
shape->data = NULL;
shape->space = NULL;
shape->next = NULL;
shape->prev = NULL;
@@ -85,7 +84,7 @@ cpShapeFree(cpShape *shape)
void
cpShapeSetBody(cpShape *shape, cpBody *body)
{
cpAssertHard(!cpShapeActive(shape), "You cannot change the body on an active shape. You must remove the shape, then ");
cpAssertHard(!cpShapeActive(shape), "You cannot change the body on an active shape. You must remove the shape from the space before changing the body.");
shape->body = body;
}
@@ -104,13 +103,35 @@ cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot)
cpBool
cpShapePointQuery(cpShape *shape, cpVect p){
return shape->klass->pointQuery(shape, p);
cpNearestPointQueryInfo info = {NULL, cpvzero, INFINITY};
cpShapeNearestPointQuery(shape, p, &info);
return (info.d < 0.0f);
}
cpFloat
cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info)
{
cpNearestPointQueryInfo blank = {NULL, cpvzero, INFINITY};
if(info){
(*info) = blank;
} else {
info = &blank;
}
shape->klass->nearestPointQuery(shape, p, info);
return info->d;
}
cpBool
cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){
cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero};
(*info) = blank;
if(info){
(*info) = blank;
} else {
info = &blank;
}
shape->klass->segmentQuery(shape, a, b, info);
return (info->shape != NULL);
@@ -126,13 +147,19 @@ static cpBB
cpCircleShapeCacheData(cpCircleShape *circle, cpVect p, cpVect rot)
{
cpVect c = circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
cpFloat r = circle->r;
return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);
return cpBBNewForCircle(c, circle->r);
}
static cpBool
cpCircleShapePointQuery(cpCircleShape *circle, cpVect p){
return cpvnear(circle->tc, p, circle->r);
static void
cpCicleShapeNearestPointQuery(cpCircleShape *circle, cpVect p, cpNearestPointQueryInfo *info)
{
cpVect delta = cpvsub(p, circle->tc);
cpFloat d = cpvlength(delta);
cpFloat r = circle->r;
info->shape = (cpShape *)circle;
info->p = cpvadd(circle->tc, cpvmult(delta, r/d)); // TODO div/0
info->d = d - r;
}
static void
@@ -168,7 +195,7 @@ static const cpShapeClass cpCircleShapeClass = {
CP_CIRCLE_SHAPE,
(cpShapeCacheDataImpl)cpCircleShapeCacheData,
NULL,
(cpShapePointQueryImpl)cpCircleShapePointQuery,
(cpShapeNearestPointQueryImpl)cpCicleShapeNearestPointQuery,
(cpShapeSegmentQueryImpl)cpCircleShapeSegmentQuery,
};
@@ -227,76 +254,46 @@ cpSegmentShapeCacheData(cpSegmentShape *seg, cpVect p, cpVect rot)
return cpBBNew(l - rad, b - rad, r + rad, t + rad);
}
static cpBool
cpSegmentShapePointQuery(cpSegmentShape *seg, cpVect p){
if(!cpBBContainsVect(seg->shape.bb, p)) return cpFalse;
static void
cpSegmentShapeNearestPointQuery(cpSegmentShape *seg, cpVect p, cpNearestPointQueryInfo *info)
{
cpVect closest = cpClosetPointOnSegment(p, seg->ta, seg->tb);
// Calculate normal distance from segment.
cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
cpFloat dist = cpfabs(dn) - seg->r;
if(dist > 0.0f) return cpFalse;
cpVect delta = cpvsub(p, closest);
cpFloat d = cpvlength(delta);
cpFloat r = seg->r;
// Calculate tangential distance along segment.
cpFloat dt = -cpvcross(seg->tn, p);
cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
// Decision tree to decide which feature of the segment to collide with.
if(dt <= dtMin){
if(dt < (dtMin - seg->r)){
return cpFalse;
} else {
return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
}
} else {
if(dt < dtMax){
return cpTrue;
} else {
if(dt < (dtMax + seg->r)) {
return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
} else {
return cpFalse;
}
}
}
return cpTrue;
info->shape = (cpShape *)seg;
info->p = (d ? cpvadd(closest, cpvmult(delta, r/d)) : closest);
info->d = d - r;
}
static inline cpBool inUnitRange(cpFloat t){return (0.0f < t && t < 1.0f);}
static void
cpSegmentShapeSegmentQuery(cpSegmentShape *seg, cpVect a, cpVect b, cpSegmentQueryInfo *info)
{
cpVect n = seg->tn;
// flip n if a is behind the axis
if(cpvdot(a, n) < cpvdot(seg->ta, n))
n = cpvneg(n);
cpFloat d = cpvdot(cpvsub(seg->ta, a), n);
cpFloat r = seg->r;
cpFloat an = cpvdot(a, n);
cpFloat bn = cpvdot(b, n);
cpVect flipped_n = (d > 0.0f ? cpvneg(n) : n);
cpVect seg_offset = cpvsub(cpvmult(flipped_n, r), a);
if(an != bn){
cpFloat d = cpvdot(seg->ta, n) + seg->r;
cpFloat t = (d - an)/(bn - an);
// Make the endpoints relative to 'a' and move them by the thickness of the segment.
cpVect seg_a = cpvadd(seg->ta, seg_offset);
cpVect seg_b = cpvadd(seg->tb, seg_offset);
cpVect delta = cpvsub(b, a);
if(cpvcross(delta, seg_a)*cpvcross(delta, seg_b) <= 0.0f){
cpFloat d_offset = d + (d > 0.0f ? -r : r);
cpFloat ad = -d_offset;
cpFloat bd = cpvdot(delta, n) - d_offset;
if(0.0f < t && t < 1.0f){
cpVect point = cpvlerp(a, b, t);
cpFloat dt = -cpvcross(seg->tn, point);
cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
if(dtMin < dt && dt < dtMax){
info->shape = (cpShape *)seg;
info->t = t;
info->n = n;
return; // don't continue on and check endcaps
}
if(ad*bd < 0.0f){
info->shape = (cpShape *)seg;
info->t = ad/(ad - bd);
info->n = flipped_n;
}
}
if(seg->r) {
} else if(r != 0.0f){
cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero};
cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero};
circleSegmentQuery((cpShape *)seg, seg->ta, seg->r, a, b, &info1);
@@ -314,7 +311,7 @@ static const cpShapeClass cpSegmentShapeClass = {
CP_SEGMENT_SHAPE,
(cpShapeCacheDataImpl)cpSegmentShapeCacheData,
NULL,
(cpShapePointQueryImpl)cpSegmentShapePointQuery,
(cpShapeNearestPointQueryImpl)cpSegmentShapeNearestPointQuery,
(cpShapeSegmentQueryImpl)cpSegmentShapeSegmentQuery,
};
@@ -327,6 +324,9 @@ cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloa
seg->r = r;
seg->a_tangent = cpvzero;
seg->b_tangent = cpvzero;
cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body);
return seg;
@@ -343,6 +343,16 @@ CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B)
CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal)
CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius)
void
cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next)
{
cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
cpSegmentShape *seg = (cpSegmentShape *)shape;
seg->a_tangent = cpvsub(prev, seg->a);
seg->b_tangent = cpvsub(next, seg->b);
}
// Unsafe API (chipmunk_unsafe.h)
void

View File

@@ -19,14 +19,12 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "chipmunk_private.h"
#pragma mark Contact Set Helpers
//MARK: Contact Set Helpers
// Equal function for arbiterSet.
static cpBool
@@ -38,7 +36,7 @@ arbiterSetEql(cpShape **shapes, cpArbiter *arb)
return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));
}
#pragma mark Collision Handler Set HelperFunctions
//MARK: Collision Handler Set HelperFunctions
// Equals function for collisionHandlers.
static cpBool
@@ -57,7 +55,7 @@ handlerSetTrans(cpCollisionHandler *handler, void *unused)
return copy;
}
#pragma mark Misc Helper Funcs
//MARK: Misc Helper Funcs
// Default collision functions.
static cpBool alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
@@ -68,7 +66,7 @@ static cpVect shapeVelocityFunc(cpShape *shape){return shape->body->v;}
static void freeWrap(void *ptr, void *unused){cpfree(ptr);}
#pragma mark Memory Management Functions
//MARK: Memory Management Functions
cpSpace *
cpSpaceAlloc(void)
@@ -82,8 +80,12 @@ cpSpace*
cpSpaceInit(cpSpace *space)
{
#ifndef NDEBUG
printf("Initializing cpSpace - Chipmunk v%s (Debug Enabled)\n", cpVersionString);
//printf("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n");
static cpBool done = cpFalse;
if(!done){
printf("Initializing cpSpace - Chipmunk v%s (Debug Enabled)\n", cpVersionString);
printf("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n");
done = cpTrue;
}
#endif
space->iterations = 10;
@@ -124,7 +126,8 @@ cpSpaceInit(cpSpace *space)
space->collisionHandlers = cpHashSetNew(0, (cpHashSetEqlFunc)handlerSetEql);
cpHashSetSetDefaultValue(space->collisionHandlers, &cpDefaultCollisionHandler);
space->postStepCallbacks = NULL;
space->postStepCallbacks = cpArrayNew(0);
space->skipPostStep = cpFalse;
cpBodyInitStatic(&space->_staticBody);
space->staticBody = &space->_staticBody;
@@ -141,6 +144,8 @@ cpSpaceNew(void)
void
cpSpaceDestroy(cpSpace *space)
{
cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)cpBodyActivate, NULL);
cpSpatialIndexFree(space->staticShapes);
cpSpatialIndexFree(space->activeShapes);
@@ -160,8 +165,10 @@ cpSpaceDestroy(cpSpace *space)
cpArrayFree(space->allocatedBuffers);
}
if(space->postStepCallbacks) cpHashSetEach(space->postStepCallbacks, freeWrap, NULL);
cpHashSetFree(space->postStepCallbacks);
if(space->postStepCallbacks){
cpArrayFreeEach(space->postStepCallbacks, cpfree);
cpArrayFree(space->postStepCallbacks);
}
if(space->collisionHandlers) cpHashSetEach(space->collisionHandlers, freeWrap, NULL);
cpHashSetFree(space->collisionHandlers);
@@ -182,7 +189,7 @@ cpSpaceFree(cpSpace *space)
"Put these calls into a post-step callback." \
);
#pragma mark Collision Handler Function Management
//MARK: Collision Handler Function Management
void
cpSpaceAddCollisionHandler(
@@ -245,15 +252,14 @@ cpSpaceSetDefaultCollisionHandler(
cpHashSetSetDefaultValue(space->collisionHandlers, &space->defaultHandler);
}
#pragma mark Body, Shape, and Joint Management
//MARK: Body, Shape, and Joint Management
cpShape *
cpSpaceAddShape(cpSpace *space, cpShape *shape)
{
cpBody *body = shape->body;
if(cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape);
// TODO change these to check if it was added to a space at all.
cpAssertSoft(!shape->space, "This shape is already added to a space and cannot be added to another.");
cpAssertHard(!shape->space, "This shape is already added to a space and cannot be added to another.");
cpAssertSpaceUnlocked(space);
cpBodyActivate(body);
@@ -269,7 +275,7 @@ cpSpaceAddShape(cpSpace *space, cpShape *shape)
cpShape *
cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
{
cpAssertSoft(!shape->space, "This shape is already added to a space and cannot be added to another.");
cpAssertHard(!shape->space, "This shape is already added to a space and cannot be added to another.");
cpAssertSpaceUnlocked(space);
cpBody *body = shape->body;
@@ -284,8 +290,8 @@ cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
cpBody *
cpSpaceAddBody(cpSpace *space, cpBody *body)
{
cpAssertWarn(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated.");
cpAssertSoft(!body->space, "This body is already added to a space and cannot be added to another.");
cpAssertHard(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated.");
cpAssertHard(!body->space, "This body is already added to a space and cannot be added to another.");
cpAssertSpaceUnlocked(space);
cpArrayPush(space->bodies, body);
@@ -297,7 +303,7 @@ cpSpaceAddBody(cpSpace *space, cpBody *body)
cpConstraint *
cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
{
cpAssertSoft(!constraint->space, "This shape is already added to a space and cannot be added to another.");
cpAssertHard(!constraint->space, "This shape is already added to a space and cannot be added to another.");
cpAssertSpaceUnlocked(space);
cpBodyActivate(constraint->a);
@@ -316,15 +322,28 @@ cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
struct arbiterFilterContext {
cpSpace *space;
cpBody *body;
cpShape *shape;
};
static cpBool
contactSetFilterRemovedBody(cpArbiter *arb, struct arbiterFilterContext *context)
cachedArbitersFilter(cpArbiter *arb, struct arbiterFilterContext *context)
{
cpShape *shape = context->shape;
cpBody *body = context->body;
if(body == arb->body_a || body == arb->body_b){
// Match on the filter shape, or if it's NULL the filter body
if(
(body == arb->body_a && (shape == arb->a || shape == NULL)) ||
(body == arb->body_b && (shape == arb->b || shape == NULL))
){
// Call separate when removing shapes.
if(shape && arb->state != cpArbiterStateCached) cpArbiterCallSeparate(arb, context->space);
cpArbiterUnthread(arb);
cpArrayDeleteObj(context->space->arbiters, arb);
cpArrayPush(context->space->pooledArbiters, arb);
return cpFalse;
}
@@ -334,25 +353,10 @@ contactSetFilterRemovedBody(cpArbiter *arb, struct arbiterFilterContext *context
void
cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter)
{
cpArbiter *arb = body->arbiterList;
while(arb){
cpArbiter *next = cpArbiterNext(arb, body);
if(filter == NULL || filter == arb->a || filter == arb->b){
if(arb->state != cpArbiterStateCached) cpArbiterCallSeparate(arb, space);
cpArbiterUnthread(arb);
cpSpaceUncacheArbiter(space, arb);
cpArrayPush(space->pooledArbiters, arb);
}
arb = next;
}
// TODO see note at cpSpaceArbiterSetFilter()
// When just removing the body, so we need to filter all cached arbiters to avoid dangling pointers.
if(filter == NULL){
struct arbiterFilterContext context = {space, body};
cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)contactSetFilterRemovedBody, &context);
}
cpSpaceLock(space); {
struct arbiterFilterContext context = {space, body, filter};
cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cachedArbitersFilter, &context);
} cpSpaceUnlock(space, cpTrue);
}
void
@@ -362,8 +366,7 @@ cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
if(cpBodyIsStatic(body)){
cpSpaceRemoveStaticShape(space, shape);
} else {
cpAssertSoft(cpSpaceContainsShape(space, shape),
"Cannot remove a shape that was not added to the space. (Removed twice maybe?)");
cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a shape that was not added to the space. (Removed twice maybe?)");
cpAssertSpaceUnlocked(space);
cpBodyActivate(body);
@@ -377,12 +380,11 @@ cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
void
cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
{
cpAssertSoft(cpSpaceContainsShape(space, shape),
"Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)");
cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a static or sleeping shape that was not added to the space. (Removed twice maybe?)");
cpAssertSpaceUnlocked(space);
cpBody *body = shape->body;
cpBodyActivateStatic(body, shape);
if(cpBodyIsStatic(body)) cpBodyActivateStatic(body, shape);
cpBodyRemoveShape(body, shape);
cpSpaceFilterArbiters(space, body, shape);
cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid);
@@ -392,12 +394,11 @@ cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
void
cpSpaceRemoveBody(cpSpace *space, cpBody *body)
{
cpAssertWarn(cpSpaceContainsBody(space, body),
"Cannot remove a body that was not added to the space. (Removed twice maybe?)");
cpAssertHard(cpSpaceContainsBody(space, body), "Cannot remove a body that was not added to the space. (Removed twice maybe?)");
cpAssertSpaceUnlocked(space);
cpBodyActivate(body);
cpSpaceFilterArbiters(space, body, NULL);
// cpSpaceFilterArbiters(space, body, NULL);
cpArrayDeleteObj(space->bodies, body);
body->space = NULL;
}
@@ -405,8 +406,7 @@ cpSpaceRemoveBody(cpSpace *space, cpBody *body)
void
cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
{
cpAssertWarn(cpSpaceContainsConstraint(space, constraint),
"Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");
cpAssertHard(cpSpaceContainsConstraint(space, constraint), "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");
cpAssertSpaceUnlocked(space);
cpBodyActivate(constraint->a);
@@ -434,7 +434,7 @@ cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint)
}
#pragma mark Iteration
//MARK: Iteration
void
cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data)
@@ -449,7 +449,13 @@ cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data)
cpArray *components = space->sleepingComponents;
for(int i=0; i<components->num; i++){
cpBody *root = (cpBody *)components->arr[i];
CP_BODY_FOREACH_COMPONENT(root, body) func(body, data);
cpBody *body = root;
while(body){
cpBody *next = body->node.next;
func(body, data);
body = next;
}
}
} cpSpaceUnlock(space, cpTrue);
}
@@ -487,7 +493,7 @@ cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *
} cpSpaceUnlock(space, cpTrue);
}
#pragma mark Spatial Index Management
//MARK: Spatial Index Management
static void
updateBBCache(cpShape *shape, void *unused)
@@ -499,6 +505,8 @@ updateBBCache(cpShape *shape, void *unused)
void
cpSpaceReindexStatic(cpSpace *space)
{
cpAssertHard(!space->locked, "You cannot manually reindex objects while the space is locked. Wait until the current query or step is complete.");
cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)&updateBBCache, NULL);
cpSpatialIndexReindex(space->staticShapes);
}
@@ -506,6 +514,8 @@ cpSpaceReindexStatic(cpSpace *space)
void
cpSpaceReindexShape(cpSpace *space, cpShape *shape)
{
cpAssertHard(!space->locked, "You cannot manually reindex objects while the space is locked. Wait until the current query or step is complete.");
cpBody *body = shape->body;
cpShapeUpdate(shape, body->p, body->rot);

View File

@@ -19,18 +19,16 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "chipmunk_private.h"
#pragma mark Sleeping Functions
//MARK: Sleeping Functions
void
cpSpaceActivateBody(cpSpace *space, cpBody *body)
{
cpAssertSoft(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rouge body.");
cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rouge body.");
if(space->locked){
// cpSpaceActivateBody() is called again once the space is unlocked
@@ -57,7 +55,7 @@ cpSpaceActivateBody(cpSpace *space, cpBody *body)
// Reinsert the arbiter into the arbiter cache
cpShape *a = arb->a, *b = arb->b;
cpShape *shape_pair[] = {a, b};
cpHashValue arbHashID = CP_HASH_PAIR((size_t)a, (size_t)b);
cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);
cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, arb, NULL);
// Update the arbiter's state
@@ -79,7 +77,7 @@ cpSpaceActivateBody(cpSpace *space, cpBody *body)
static void
cpSpaceDeactivateBody(cpSpace *space, cpBody *body)
{
cpAssertSoft(!cpBodyIsRogue(body), "Internal error: Attempting to deactivate a rouge body.");
cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to deactivate a rouge body.");
cpArrayDeleteObj(space->bodies, body);
@@ -117,13 +115,14 @@ static inline void
ComponentActivate(cpBody *root)
{
if(!root || !cpBodyIsSleeping(root)) return;
cpAssertSoft(!cpBodyIsRogue(root), "Internal Error: ComponentActivate() called on a rogue body.");
cpAssertHard(!cpBodyIsRogue(root), "Internal Error: ComponentActivate() called on a rogue body.");
cpSpace *space = root->space;
cpBody *body = root;
while(body){
cpBody *next = body->node.next;
body->node.idleTime = 0.0f;
body->node.root = NULL;
body->node.next = NULL;
cpSpaceActivateBody(space, body);
@@ -134,16 +133,6 @@ ComponentActivate(cpBody *root)
cpArrayDeleteObj(space->sleepingComponents, root);
}
static inline void
ComponentAdd(cpBody *root, cpBody *body){
body->node.root = root;
if(body != root){
body->node.next = root->node.next;
root->node.next = body;
}
}
void
cpBodyActivate(cpBody *body)
{
@@ -163,34 +152,10 @@ cpBodyActivateStatic(cpBody *body, cpShape *filter)
cpBodyActivate(arb->body_a == body ? arb->body_b : arb->body_a);
}
}
}
static inline cpBool
ComponentActive(cpBody *root, cpFloat threshold)
{
CP_BODY_FOREACH_COMPONENT(root, body){
if(body->node.idleTime < threshold) return cpTrue;
}
return cpFalse;
// TODO should also activate joints?
}
static inline void
FloodFillComponent(cpBody *root, cpBody *body)
{
if(!cpBodyIsStatic(body) && !cpBodyIsRogue(body)){
cpBody *other_root = ComponentRoot(body);
if(other_root == NULL){
ComponentAdd(root, body);
CP_BODY_FOREACH_ARBITER(body, arb) FloodFillComponent(root, (body == arb->body_a ? arb->body_b : arb->body_a));
CP_BODY_FOREACH_CONSTRAINT(body, constraint) FloodFillComponent(root, (body == constraint->a ? constraint->b : constraint->a));
} else {
cpAssertSoft(other_root == root, "Internal Error: Inconsistency dectected in the contact graph.");
}
}
}
static inline void
cpBodyPushArbiter(cpBody *body, cpArbiter *arb)
{
@@ -205,24 +170,72 @@ cpBodyPushArbiter(cpBody *body, cpArbiter *arb)
body->arbiterList = arb;
}
static inline void
ComponentAdd(cpBody *root, cpBody *body){
body->node.root = root;
if(body != root){
body->node.next = root->node.next;
root->node.next = body;
}
}
static inline void
FloodFillComponent(cpBody *root, cpBody *body)
{
// Rogue bodies cannot be put to sleep and prevent bodies they are touching from sleepining anyway.
// Static bodies (which are a type of rogue body) are effectively sleeping all the time.
if(!cpBodyIsRogue(body)){
cpBody *other_root = ComponentRoot(body);
if(other_root == NULL){
ComponentAdd(root, body);
CP_BODY_FOREACH_ARBITER(body, arb) FloodFillComponent(root, (body == arb->body_a ? arb->body_b : arb->body_a));
CP_BODY_FOREACH_CONSTRAINT(body, constraint) FloodFillComponent(root, (body == constraint->a ? constraint->b : constraint->a));
} else {
cpAssertSoft(other_root == root, "Internal Error: Inconsistency dectected in the contact graph.");
}
}
}
static inline cpBool
ComponentActive(cpBody *root, cpFloat threshold)
{
CP_BODY_FOREACH_COMPONENT(root, body){
if(body->node.idleTime < threshold) return cpTrue;
}
return cpFalse;
}
void
cpSpaceProcessComponents(cpSpace *space, cpFloat dt)
{
cpFloat dv = space->idleSpeedThreshold;
cpFloat dvsq = (dv ? dv*dv : cpvlengthsq(space->gravity)*dt*dt);
// update idling and reset component nodes
cpBool sleep = (space->sleepTimeThreshold != INFINITY);
cpArray *bodies = space->bodies;
#ifndef NDEBUG
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody*)bodies->arr[i];
// Need to deal with infinite mass objects
cpFloat keThreshold = (dvsq ? body->m*dvsq : 0.0f);
body->node.idleTime = (cpBodyKineticEnergy(body) > keThreshold ? 0.0f : body->node.idleTime + dt);
cpAssertSoft(body->node.next == NULL, "Internal Error: Dangling next pointer detected in contact graph.");
cpAssertSoft(body->node.root == NULL, "Internal Error: Dangling root pointer detected in contact graph.");
}
#endif
// Calculate the kinetic energy of all the bodies.
if(sleep){
cpFloat dv = space->idleSpeedThreshold;
cpFloat dvsq = (dv ? dv*dv : cpvlengthsq(space->gravity)*dt*dt);
// update idling and reset component nodes
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody*)bodies->arr[i];
// Need to deal with infinite mass objects
cpFloat keThreshold = (dvsq ? body->m*dvsq : 0.0f);
body->node.idleTime = (cpBodyKineticEnergy(body) > keThreshold ? 0.0f : body->node.idleTime + dt);
}
}
// Awaken any sleeping bodies found and then push arbiters to the bodies' lists.
cpArray *arbiters = space->arbiters;
@@ -230,48 +243,52 @@ cpSpaceProcessComponents(cpSpace *space, cpFloat dt)
cpArbiter *arb = (cpArbiter*)arbiters->arr[i];
cpBody *a = arb->body_a, *b = arb->body_b;
if((cpBodyIsRogue(b) && !cpBodyIsStatic(b)) || cpBodyIsSleeping(a)) cpBodyActivate(a);
if((cpBodyIsRogue(a) && !cpBodyIsStatic(a)) || cpBodyIsSleeping(b)) cpBodyActivate(b);
if(sleep){
if((cpBodyIsRogue(b) && !cpBodyIsStatic(b)) || cpBodyIsSleeping(a)) cpBodyActivate(a);
if((cpBodyIsRogue(a) && !cpBodyIsStatic(a)) || cpBodyIsSleeping(b)) cpBodyActivate(b);
}
cpBodyPushArbiter(a, arb);
cpBodyPushArbiter(b, arb);
}
// Bodies should be held active if connected by a joint to a non-static rouge body.
cpArray *constraints = space->constraints;
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
cpBody *a = constraint->a, *b = constraint->b;
if(cpBodyIsRogue(b) && !cpBodyIsStatic(b)) cpBodyActivate(a);
if(cpBodyIsRogue(a) && !cpBodyIsStatic(a)) cpBodyActivate(b);
}
// Generate components and deactivate sleeping ones
for(int i=0; i<bodies->num;){
cpBody *body = (cpBody*)bodies->arr[i];
if(ComponentRoot(body) == NULL){
// Body not in a component yet. Perform a DFS to flood fill mark
// the component in the contact graph using this body as the root.
FloodFillComponent(body, body);
if(sleep){
// Bodies should be held active if connected by a joint to a non-static rouge body.
cpArray *constraints = space->constraints;
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
cpBody *a = constraint->a, *b = constraint->b;
// Check if the component should be put to sleep.
if(!ComponentActive(body, space->sleepTimeThreshold)){
cpArrayPush(space->sleepingComponents, body);
CP_BODY_FOREACH_COMPONENT(body, other) cpSpaceDeactivateBody(space, other);
// cpSpaceDeactivateBody() removed the current body from the list.
// Skip incrementing the index counter.
continue;
}
if(cpBodyIsRogue(b) && !cpBodyIsStatic(b)) cpBodyActivate(a);
if(cpBodyIsRogue(a) && !cpBodyIsStatic(a)) cpBodyActivate(b);
}
i++;
// Only sleeping bodies retain their component node pointers.
body->node.root = NULL;
body->node.next = NULL;
// Generate components and deactivate sleeping ones
for(int i=0; i<bodies->num;){
cpBody *body = (cpBody*)bodies->arr[i];
if(ComponentRoot(body) == NULL){
// Body not in a component yet. Perform a DFS to flood fill mark
// the component in the contact graph using this body as the root.
FloodFillComponent(body, body);
// Check if the component should be put to sleep.
if(!ComponentActive(body, space->sleepTimeThreshold)){
cpArrayPush(space->sleepingComponents, body);
CP_BODY_FOREACH_COMPONENT(body, other) cpSpaceDeactivateBody(space, other);
// cpSpaceDeactivateBody() removed the current body from the list.
// Skip incrementing the index counter.
continue;
}
}
i++;
// Only sleeping bodies retain their component node pointers.
body->node.root = NULL;
body->node.next = NULL;
}
}
}

View File

@@ -19,9 +19,6 @@
* SOFTWARE.
*/
#include <math.h>
#include <stdlib.h>
#include "chipmunk_private.h"
#include "prime.h"
@@ -45,7 +42,7 @@ struct cpSpaceHash {
};
#pragma mark Handle Functions
//MARK: Handle Functions
struct cpHandle {
void *obj;
@@ -80,7 +77,7 @@ handleSetTrans(void *obj, cpSpaceHash *hash)
if(hash->pooledHandles->num == 0){
// handle pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(cpHandle);
cpAssertSoft(count, "Buffer size is too small.");
cpAssertHard(count, "Internal Error: Buffer size is too small.");
cpHandle *buffer = (cpHandle *)cpcalloc(1, CP_BUFFER_BYTES);
cpArrayPush(hash->allocatedBuffers, buffer);
@@ -94,7 +91,7 @@ handleSetTrans(void *obj, cpSpaceHash *hash)
return hand;
}
#pragma mark Bin Functions
//MARK: Bin Functions
struct cpSpaceHashBin {
cpHandle *handle;
@@ -142,7 +139,7 @@ getEmptyBin(cpSpaceHash *hash)
} else {
// Pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin);
cpAssertSoft(count, "Buffer size is too small.");
cpAssertHard(count, "Internal Error: Buffer size is too small.");
cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpcalloc(1, CP_BUFFER_BYTES);
cpArrayPush(hash->allocatedBuffers, buffer);
@@ -153,7 +150,7 @@ getEmptyBin(cpSpaceHash *hash)
}
}
#pragma mark Memory Management Functions
//MARK: Memory Management Functions
cpSpaceHash *
cpSpaceHashAlloc(void)
@@ -212,7 +209,7 @@ cpSpaceHashDestroy(cpSpaceHash *hash)
cpArrayFree(hash->pooledHandles);
}
#pragma mark Helper Functions
//MARK: Helper Functions
static inline cpBool
containsHandle(cpSpaceHashBin *bin, cpHandle *hand)
@@ -254,7 +251,7 @@ hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
int n = hash->numcells;
for(int i=l; i<=r; i++){
for(int j=b; j<=t; j++){
int idx = hash_func(i,j,n);
cpHashValue idx = hash_func(i,j,n);
cpSpaceHashBin *bin = hash->table[idx];
// Don't add an object twice to the same cell.
@@ -270,7 +267,7 @@ hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
}
}
#pragma mark Basic Operations
//MARK: Basic Operations
static void
cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid)
@@ -352,7 +349,7 @@ remove_orphaned_handles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr)
}
}
#pragma mark Query Functions
//MARK: Query Functions
static inline void
query_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpatialIndexQueryFunc func, void *data)
@@ -376,16 +373,6 @@ query_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpatialIn
}
}
static void
cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpatialIndexQueryFunc func, void *data)
{
cpFloat dim = hash->celldim;
int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells); // Fix by ShiftZ
query_helper(hash, &hash->table[idx], &point, func, data);
hash->stamp++;
}
static void
cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)
{
@@ -439,7 +426,7 @@ queryRehash_helper(cpHandle *hand, queryRehashContext *context)
for(int i=l; i<=r; i++){
for(int j=b; j<=t; j++){
int idx = hash_func(i,j,n);
cpHashValue idx = hash_func(i,j,n);
cpSpaceHashBin *bin = table[idx];
if(containsHandle(bin, hand)) continue;
@@ -497,7 +484,7 @@ segmentQuery_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSp
}
// modified from http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
void
static void
cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)
{
a = cpvmult(a, 1.0f/hash->celldim);
@@ -538,7 +525,7 @@ cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloa
cpSpaceHashBin **table = hash->table;
while(t < t_exit){
int idx = hash_func(cell_x, cell_y, n);
cpHashValue idx = hash_func(cell_x, cell_y, n);
t_exit = cpfmin(t_exit, segmentQuery_helper(hash, &table[idx], obj, func, data));
if (next_v < next_h){
@@ -555,7 +542,7 @@ cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloa
hash->stamp++;
}
#pragma mark Misc
//MARK: Misc
void
cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)
@@ -597,14 +584,13 @@ static cpSpatialIndexClass klass = {
(cpSpatialIndexReindexObjectImpl)cpSpaceHashRehashObject,
(cpSpatialIndexReindexQueryImpl)cpSpaceHashReindexQuery,
(cpSpatialIndexPointQueryImpl)cpSpaceHashPointQuery,
(cpSpatialIndexSegmentQueryImpl)cpSpaceHashSegmentQuery,
(cpSpatialIndexQueryImpl)cpSpaceHashQuery,
(cpSpatialIndexSegmentQueryImpl)cpSpaceHashSegmentQuery,
};
static inline cpSpatialIndexClass *Klass(){return &klass;}
#pragma mark Debug Drawing
//MARK: Debug Drawing
//#define CP_BBTREE_DEBUG_DRAW
#ifdef CP_BBTREE_DEBUG_DRAW

View File

@@ -19,25 +19,24 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include "chipmunk_private.h"
#pragma mark Point Query Functions
//MARK: Point Query Functions
typedef struct pointQueryContext {
struct PointQueryContext {
cpVect point;
cpLayers layers;
cpGroup group;
cpSpacePointQueryFunc func;
void *data;
} pointQueryContext;
};
static void
pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
PointQuery(struct PointQueryContext *context, cpShape *shape, void *data)
{
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
cpShapePointQuery(shape, *point)
cpShapePointQuery(shape, context->point)
){
context->func(shape, context->data);
}
@@ -46,16 +45,17 @@ pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
void
cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)
{
pointQueryContext context = {layers, group, func, data};
struct PointQueryContext context = {point, layers, group, func, data};
cpBB bb = cpBBNewForCircle(point, 0.0f);
cpSpaceLock(space); {
cpSpatialIndexPointQuery(space->activeShapes, point, (cpSpatialIndexQueryFunc)pointQueryHelper, &context);
cpSpatialIndexPointQuery(space->staticShapes, point, (cpSpatialIndexQueryFunc)pointQueryHelper, &context);
cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)PointQuery, data);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)PointQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
static void
rememberLastPointQuery(cpShape *shape, cpShape **outShape)
PointQueryFirst(cpShape *shape, cpShape **outShape)
{
if(!shape->sensor) *outShape = shape;
}
@@ -64,23 +64,94 @@ cpShape *
cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)
{
cpShape *shape = NULL;
cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)rememberLastPointQuery, &shape);
cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)PointQueryFirst, &shape);
return shape;
}
//MARK: Nearest Point Query Functions
#pragma mark Segment Query Functions
struct NearestPointQueryContext {
cpVect point;
cpFloat maxDistance;
cpLayers layers;
cpGroup group;
cpSpaceNearestPointQueryFunc func;
};
typedef struct segQueryContext {
static void
NearestPointQuery(struct NearestPointQueryContext *context, cpShape *shape, void *data)
{
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers)
){
cpNearestPointQueryInfo info;
cpShapeNearestPointQuery(shape, context->point, &info);
if(info.shape && info.d < context->maxDistance) context->func(shape, info.d, info.p, data);
}
}
void
cpSpaceNearestPointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpSpaceNearestPointQueryFunc func, void *data)
{
struct NearestPointQueryContext context = {point, maxDistance, layers, group, func};
cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
cpSpaceLock(space); {
cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
static void
NearestPointQueryNearest(struct NearestPointQueryContext *context, cpShape *shape, cpNearestPointQueryInfo *out)
{
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) && !shape->sensor
){
cpNearestPointQueryInfo info;
cpShapeNearestPointQuery(shape, context->point, &info);
if(info.d < out->d) (*out) = info;
}
}
cpShape *
cpSpaceNearestPointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpLayers layers, cpGroup group, cpNearestPointQueryInfo *out)
{
cpNearestPointQueryInfo info = {NULL, cpvzero, maxDistance};
if(out){
(*out) = info;
} else {
out = &info;
}
struct NearestPointQueryContext context = {
point, maxDistance,
layers, group,
NULL
};
cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));
cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);
return out->shape;
}
//MARK: Segment Query Functions
struct SegmentQueryContext {
cpVect start, end;
cpLayers layers;
cpGroup group;
cpSpaceSegmentQueryFunc func;
} segQueryContext;
};
static cpFloat
segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
SegmentQuery(struct SegmentQueryContext *context, cpShape *shape, void *data)
{
cpSegmentQueryInfo info;
@@ -97,26 +168,20 @@ segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
void
cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
{
segQueryContext context = {
struct SegmentQueryContext context = {
start, end,
layers, group,
func,
};
cpSpaceLock(space); {
cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)segQueryFunc, data);
cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)segQueryFunc, data);
cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
typedef struct segQueryFirstContext {
cpVect start, end;
cpLayers layers;
cpGroup group;
} segQueryFirstContext;
static cpFloat
segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo *out)
SegmentQueryFirst(struct SegmentQueryContext *context, cpShape *shape, cpSegmentQueryInfo *out)
{
cpSegmentQueryInfo info;
@@ -126,7 +191,7 @@ segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo
cpShapeSegmentQuery(shape, context->start, context->end, &info) &&
info.t < out->t
){
*out = info;
(*out) = info;
}
return out->t;
@@ -142,59 +207,60 @@ cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers laye
out = &info;
}
segQueryFirstContext context = {
struct SegmentQueryContext context = {
start, end,
layers, group
layers, group,
NULL
};
cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)segQueryFirst, out);
cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpatialIndexSegmentQueryFunc)segQueryFirst, out);
cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
cpSpatialIndexSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);
return out->shape;
}
#pragma mark BB Query Functions
//MARK: BB Query Functions
typedef struct bbQueryContext {
struct BBQueryContext {
cpBB bb;
cpLayers layers;
cpGroup group;
cpSpaceBBQueryFunc func;
void *data;
} bbQueryContext;
};
static void
bbQueryHelper(cpBB *bb, cpShape *shape, bbQueryContext *context)
BBQuery(struct BBQueryContext *context, cpShape *shape, void *data)
{
if(
!(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
cpBBIntersects(*bb, shape->bb)
cpBBIntersects(context->bb, shape->bb)
){
context->func(shape, context->data);
context->func(shape, data);
}
}
void
cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data)
{
bbQueryContext context = {layers, group, func, data};
struct BBQueryContext context = {bb, layers, group, func};
cpSpaceLock(space); {
cpSpatialIndexQuery(space->activeShapes, &bb, bb, (cpSpatialIndexQueryFunc)bbQueryHelper, &context);
cpSpatialIndexQuery(space->staticShapes, &bb, bb, (cpSpatialIndexQueryFunc)bbQueryHelper, &context);
cpSpatialIndexQuery(space->activeShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);
} cpSpaceUnlock(space, cpTrue);
}
#pragma mark Shape Query Functions
//MARK: Shape Query Functions
typedef struct shapeQueryContext {
struct ShapeQueryContext {
cpSpaceShapeQueryFunc func;
void *data;
cpBool anyCollision;
} shapeQueryContext;
};
// Callback from the spatial hash.
static void
shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
ShapeQuery(cpShape *a, cpShape *b, struct ShapeQueryContext *context)
{
// Reject any of the simple cases
if(
@@ -218,10 +284,12 @@ shapeQueryHelper(cpShape *a, cpShape *b, shapeQueryContext *context)
context->anyCollision = !(a->sensor || b->sensor);
if(context->func){
cpContactPointSet set = {numContacts, {}};
cpContactPointSet set;
set.count = numContacts;
for(int i=0; i<set.count; i++){
set.points[i].point = contacts[i].p;
set.points[i].normal = contacts[i].p;
set.points[i].normal = contacts[i].n;
set.points[i].dist = contacts[i].dist;
}
@@ -235,11 +303,11 @@ cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, vo
{
cpBody *body = shape->body;
cpBB bb = (body ? cpShapeUpdate(shape, body->p, body->rot) : shape->bb);
shapeQueryContext context = {func, data, cpFalse};
struct ShapeQueryContext context = {func, data, cpFalse};
cpSpaceLock(space); {
cpSpatialIndexQuery(space->activeShapes, shape, bb, (cpSpatialIndexQueryFunc)shapeQueryHelper, &context);
cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)shapeQueryHelper, &context);
cpSpatialIndexQuery(space->activeShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);
} cpSpaceUnlock(space, cpTrue);
return context.anyCollision;

View File

@@ -19,82 +19,45 @@
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "chipmunk_private.h"
#pragma mark Post Step Callback Functions
//MARK: Post Step Callback Functions
typedef struct cpPostStepCallback {
cpPostStepFunc func;
void *obj;
void *data;
} cpPostStepCallback;
static cpBool
postStepFuncSetEql(cpPostStepCallback *a, cpPostStepCallback *b){
return a->obj == b->obj;
}
static void *
postStepFuncSetTrans(cpPostStepCallback *callback, void *ignored)
cpPostStepCallback *
cpSpaceGetPostStepCallback(cpSpace *space, void *key)
{
cpPostStepCallback *value = (cpPostStepCallback *)cpcalloc(1, sizeof(cpPostStepCallback));
(*value) = (*callback);
cpArray *arr = space->postStepCallbacks;
for(int i=0; i<arr->num; i++){
cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
if(callback->key == key) return callback;
}
return value;
return NULL;
}
void
cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data)
static void PostStepDoNothing(cpSpace *space, void *obj, void *data){}
cpBool
cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data)
{
cpAssertWarn(space->locked,
"Adding a post-step callback when the space is not locked is unnecessary. "
"Post-step callbacks will not called until the end of the next call to cpSpaceStep() or the next query.");
if(!space->postStepCallbacks){
space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql);
}
cpPostStepCallback callback = {func, obj, data};
cpHashSetInsert(space->postStepCallbacks, (cpHashValue)(size_t)obj, &callback, NULL, (cpHashSetTransFunc)postStepFuncSetTrans);
}
void *
cpSpaceGetPostStepData(cpSpace *space, void *obj)
{
if(space->postStepCallbacks){
cpPostStepCallback query = {NULL, obj, NULL};
cpPostStepCallback *callback = (cpPostStepCallback *)cpHashSetFind(space->postStepCallbacks, (cpHashValue)(size_t)obj, &query);
return (callback ? callback->data : NULL);
} else {
return NULL;
}
}
static void
cpSpacePostStepCallbackSetIter(cpPostStepCallback *callback, cpSpace *space)
{
callback->func(space, callback->obj, callback->data);
cpfree(callback);
}
static void
cpSpaceRunPostStepCallbacks(cpSpace *space)
{
// Loop because post step callbacks may add more post step callbacks directly or indirectly.
while(space->postStepCallbacks){
cpHashSet *callbacks = space->postStepCallbacks;
space->postStepCallbacks = NULL;
if(!cpSpaceGetPostStepCallback(space, key)){
cpPostStepCallback *callback = (cpPostStepCallback *)cpcalloc(1, sizeof(cpPostStepCallback));
callback->func = (func ? func : PostStepDoNothing);
callback->key = key;
callback->data = data;
cpHashSetEach(callbacks, (cpHashSetIteratorFunc)cpSpacePostStepCallbackSetIter, space);
cpHashSetFree(callbacks);
cpArrayPush(space->postStepCallbacks, callback);
return cpTrue;
} else {
return cpFalse;
}
}
#pragma mark Locking Functions
//MARK: Locking Functions
void
cpSpaceLock(cpSpace *space)
@@ -106,21 +69,37 @@ void
cpSpaceUnlock(cpSpace *space, cpBool runPostStep)
{
space->locked--;
cpAssertSoft(space->locked >= 0, "Internal Error: Space lock underflow.");
cpAssertHard(space->locked >= 0, "Internal Error: Space lock underflow.");
if(!space->locked){
if(space->locked == 0 && runPostStep && !space->skipPostStep){
space->skipPostStep = cpTrue;
cpArray *waking = space->rousedBodies;
for(int i=0, count=waking->num; i<count; i++){
cpSpaceActivateBody(space, (cpBody *)waking->arr[i]);
waking->arr[i] = NULL;
}
cpArray *arr = space->postStepCallbacks;
for(int i=0; i<arr->num; i++){
cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
cpPostStepFunc func = callback->func;
// Mark the func as NULL in case calling it calls cpSpaceRunPostStepCallbacks() again.
callback->func = NULL;
if(func) func(space, callback->key, callback->data);
arr->arr[i] = NULL;
cpfree(callback);
}
waking->num = 0;
cpSpaceRunPostStepCallbacks(space);
arr->num = 0;
space->skipPostStep = cpFalse;
}
}
#pragma mark Contact Buffer Functions
//MARK: Contact Buffer Functions
struct cpContactBufferHeader {
cpTimestamp stamp;
@@ -152,7 +131,7 @@ cpContactBufferHeaderInit(cpContactBufferHeader *header, cpTimestamp stamp, cpCo
return header;
}
static void
void
cpSpacePushFreshContactBuffer(cpSpace *space)
{
cpTimestamp stamp = space->stamp;
@@ -189,7 +168,7 @@ cpContactBufferGetArray(cpSpace *space)
void
cpSpacePushContacts(cpSpace *space, int count)
{
cpAssertSoft(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error:contact buffer overflow!");
cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!");
space->contactBuffersHead->numContacts += count;
}
@@ -198,7 +177,7 @@ cpSpacePopContacts(cpSpace *space, int count){
space->contactBuffersHead->numContacts -= count;
}
#pragma mark Collision Detection Functions
//MARK: Collision Detection Functions
static void *
cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space)
@@ -206,7 +185,7 @@ cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space)
if(space->pooledArbiters->num == 0){
// arbiter pool is exhausted, make more
int count = CP_BUFFER_BYTES/sizeof(cpArbiter);
cpAssertSoft(count, "Buffer size too small.");
cpAssertHard(count, "Internal Error: Buffer size too small.");
cpArbiter *buffer = (cpArbiter *)cpcalloc(1, CP_BUFFER_BYTES);
cpArrayPush(space->allocatedBuffers, buffer);
@@ -229,12 +208,14 @@ queryReject(cpShape *a, cpShape *b)
|| (a->group && a->group == b->group)
// Don't collide objects that don't share at least on layer.
|| !(a->layers & b->layers)
// Don't collide infinite mass objects
|| (a->body->m == INFINITY && b->body->m == INFINITY)
);
}
// Callback from the spatial hash.
static void
collideShapes(cpShape *a, cpShape *b, cpSpace *space)
void
cpSpaceCollideShapes(cpShape *a, cpShape *b, cpSpace *space)
{
// Reject any of the simple cases
if(queryReject(a,b)) return;
@@ -260,7 +241,7 @@ collideShapes(cpShape *a, cpShape *b, cpSpace *space)
// Get an arbiter from space->arbiterSet 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);
cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);
cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, space, (cpHashSetTransFunc)cpSpaceArbiterSetTrans);
cpArbiterUpdate(arb, contacts, numContacts, handler, a, b);
@@ -294,7 +275,7 @@ collideShapes(cpShape *a, cpShape *b, cpSpace *space)
}
// Hashset filter func to throw away old arbiters.
static cpBool
cpBool
cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space)
{
cpTimestamp ticks = space->stamp - arb->stamp;
@@ -303,6 +284,7 @@ cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space)
// TODO should make an arbiter state for this so it doesn't require filtering arbiters for dangling body pointers on body removal.
// Preserve arbiters on sensors and rejected arbiters for sleeping objects.
// This prevents errant separate callbacks from happenening.
if(
(cpBodyIsStatic(a) || cpBodyIsSleeping(a)) &&
(cpBodyIsStatic(b) || cpBodyIsSleeping(b))
@@ -312,8 +294,8 @@ cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space)
// Arbiter was used last frame, but not this one
if(ticks >= 1 && arb->state != cpArbiterStateCached){
cpArbiterCallSeparate(arb, space);
arb->state = cpArbiterStateCached;
cpArbiterCallSeparate(arb, space);
}
if(ticks >= space->collisionPersistence){
@@ -327,9 +309,9 @@ cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space)
return cpTrue;
}
#pragma mark All Important cpSpaceStep() Function
//MARK: All Important cpSpaceStep() Function
static void
void
cpShapeUpdateFunc(cpShape *shape, void *unused)
{
cpBody *body = shape->body;
@@ -339,13 +321,19 @@ cpShapeUpdateFunc(cpShape *shape, void *unused)
void
cpSpaceStep(cpSpace *space, cpFloat dt)
{
if(dt == 0.0f) return; // don't step if the timestep is 0!
// don't step if the timestep is 0!
if(dt == 0.0f) return;
space->stamp++;
cpFloat prev_dt = space->curr_dt;
space->curr_dt = dt;
// Reset and empty the arbiter list.
cpArray *bodies = space->bodies;
cpArray *constraints = space->constraints;
cpArray *arbiters = space->arbiters;
// Reset and empty the arbiter lists.
for(int i=0; i<arbiters->num; i++){
cpArbiter *arb = (cpArbiter *)arbiters->arr[i];
arb->state = cpArbiterStateNormal;
@@ -357,82 +345,87 @@ cpSpaceStep(cpSpace *space, cpFloat dt)
}
arbiters->num = 0;
// Integrate positions
cpArray *bodies = space->bodies;
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody *)bodies->arr[i];
body->position_func(body, dt);
}
// Find colliding pairs.
cpSpaceLock(space); {
// Integrate positions
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody *)bodies->arr[i];
body->position_func(body, dt);
}
// Find colliding pairs.
cpSpacePushFreshContactBuffer(space);
cpSpatialIndexEach(space->activeShapes, (cpSpatialIndexIteratorFunc)cpShapeUpdateFunc, NULL);
cpSpatialIndexReindexQuery(space->activeShapes, (cpSpatialIndexQueryFunc)collideShapes, space);
cpSpatialIndexReindexQuery(space->activeShapes, (cpSpatialIndexQueryFunc)cpSpaceCollideShapes, space);
} cpSpaceUnlock(space, cpFalse);
// If body sleeping is enabled, do that now.
if(space->sleepTimeThreshold != INFINITY || space->enableContactGraph){
cpSpaceProcessComponents(space, dt);
}
// Rebuild the contact graph (and detect sleeping components if sleeping is enabled)
cpSpaceProcessComponents(space, dt);
// Clear out old cached arbiters and call separate callbacks
cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cpSpaceArbiterSetFilter, space);
cpSpaceLock(space); {
// Clear out old cached arbiters and call separate callbacks
cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cpSpaceArbiterSetFilter, space);
// Prestep the arbiters and constraints.
cpFloat slop = space->collisionSlop;
cpFloat biasCoef = 1.0f - cpfpow(space->collisionBias, dt);
for(int i=0; i<arbiters->num; i++){
cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt, slop, biasCoef);
}
cpArray *constraints = space->constraints;
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
constraint->klass->preStep(constraint, dt);
}
// Integrate velocities.
cpFloat damping = cpfpow(space->damping, dt);
cpVect gravity = space->gravity;
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody *)bodies->arr[i];
body->velocity_func(body, gravity, damping, dt);
}
// Apply cached impulses
cpFloat dt_coef = (space->stamp ? dt/prev_dt : 0.0f);
for(int i=0; i<arbiters->num; i++){
cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i], dt_coef);
}
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
constraint->klass->applyCachedImpulse(constraint, dt_coef);
}
// 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]);
// Prestep the arbiters and constraints.
cpFloat slop = space->collisionSlop;
cpFloat biasCoef = 1.0f - cpfpow(space->collisionBias, dt);
for(int i=0; i<arbiters->num; i++){
cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt, slop, biasCoef);
}
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
for(int j=0; j<constraints->num; j++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
constraint->klass->applyImpulse(constraint);
cpConstraintPreSolveFunc preSolve = constraint->preSolve;
if(preSolve) preSolve(constraint, space);
constraint->klass->preStep(constraint, dt);
}
}
// run the post-solve callbacks
cpSpaceLock(space);
for(int i=0; i<arbiters->num; i++){
cpArbiter *arb = (cpArbiter *) arbiters->arr[i];
// Integrate velocities.
cpFloat damping = cpfpow(space->damping, dt);
cpVect gravity = space->gravity;
for(int i=0; i<bodies->num; i++){
cpBody *body = (cpBody *)bodies->arr[i];
body->velocity_func(body, gravity, damping, dt);
}
cpCollisionHandler *handler = arb->handler;
handler->postSolve(arb, space, handler->data);
}
cpSpaceUnlock(space, cpTrue);
// Increment the stamp.
space->stamp++;
// Apply cached impulses
cpFloat dt_coef = (prev_dt == 0.0f ? 0.0f : dt/prev_dt);
for(int i=0; i<arbiters->num; i++){
cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i], dt_coef);
}
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
constraint->klass->applyCachedImpulse(constraint, dt_coef);
}
// 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]);
}
for(int j=0; j<constraints->num; j++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
constraint->klass->applyImpulse(constraint, dt);
}
}
// Run the constraint post-solve callbacks
for(int i=0; i<constraints->num; i++){
cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
cpConstraintPostSolveFunc postSolve = constraint->postSolve;
if(postSolve) postSolve(constraint, space);
}
// 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);
}
} cpSpaceUnlock(space, cpTrue);
}

View File

@@ -1,4 +1,23 @@
#include <stdlib.h>
/* Copyright (c) 2010 Scott Lembcke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "chipmunk_private.h"
@@ -19,7 +38,7 @@ cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialI
index->staticIndex = staticIndex;
if(staticIndex){
cpAssertHard(!staticIndex->dynamicIndex, "This static index is already is already associated with a dynamic index.");
cpAssertHard(!staticIndex->dynamicIndex, "This static index is already associated with a dynamic index.");
staticIndex->dynamicIndex = index;
}
@@ -42,7 +61,7 @@ dynamicToStaticIter(void *obj, dynamicToStaticContext *context)
void
cpSpatialIndexCollideStatic(cpSpatialIndex *dynamicIndex, cpSpatialIndex *staticIndex, cpSpatialIndexQueryFunc func, void *data)
{
if(cpSpatialIndexCount(staticIndex) > 0){
if(staticIndex && cpSpatialIndexCount(staticIndex) > 0){
dynamicToStaticContext context = {dynamicIndex->bbfunc, staticIndex, func, data};
cpSpatialIndexEach(dynamicIndex, (cpSpatialIndexIteratorFunc)dynamicToStaticIter, &context);
}

View File

@@ -19,14 +19,11 @@
* SOFTWARE.
*/
#include <math.h>
#include <stdlib.h>
#include "chipmunk_private.h"
static inline cpSpatialIndexClass *Klass();
#pragma mark Basic Structures
//MARK: Basic Structures
typedef struct Bounds {
cpFloat min, max;
@@ -66,7 +63,7 @@ MakeTableCell(cpSweep1D *sweep, void *obj)
return cell;
}
#pragma mark Memory Management Functions
//MARK: Memory Management Functions
cpSweep1D *
cpSweep1DAlloc(void)
@@ -105,7 +102,7 @@ cpSweep1DDestroy(cpSweep1D *sweep)
sweep->table = NULL;
}
#pragma mark Misc
//MARK: Misc
static int
cpSweep1DCount(cpSweep1D *sweep)
@@ -131,7 +128,7 @@ cpSweep1DContains(cpSweep1D *sweep, void *obj, cpHashValue hashid)
return cpFalse;
}
#pragma mark Basic Operations
//MARK: Basic Operations
static void
cpSweep1DInsert(cpSweep1D *sweep, void *obj, cpHashValue hashid)
@@ -158,7 +155,7 @@ cpSweep1DRemove(cpSweep1D *sweep, void *obj, cpHashValue hashid)
}
}
#pragma mark Reindexing Functions
//MARK: Reindexing Functions
static void
cpSweep1DReindexObject(cpSweep1D *sweep, void *obj, cpHashValue hashid)
@@ -173,7 +170,7 @@ cpSweep1DReindex(cpSweep1D *sweep)
// Could perform a sort, but queries are not accelerated anyway.
}
#pragma mark Query Functions
//MARK: Query Functions
static void
cpSweep1DQuery(cpSweep1D *sweep, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)
@@ -191,12 +188,6 @@ cpSweep1DQuery(cpSweep1D *sweep, void *obj, cpBB bb, cpSpatialIndexQueryFunc fun
}
static void
cpSweep1DPointQuery(cpSweep1D *sweep, cpVect point, cpSpatialIndexQueryFunc func, void *data)
{
cpSweep1DQuery(sweep, &point, cpBBNew(point.x, point.y, point.x, point.y), func, data);
}
void
cpSweep1DSegmentQuery(cpSweep1D *sweep, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)
{
cpBB bb = cpBBExpand(cpBBNew(a.x, a.y, a.x, a.y), b);
@@ -209,7 +200,7 @@ cpSweep1DSegmentQuery(cpSweep1D *sweep, void *obj, cpVect a, cpVect b, cpFloat t
}
}
#pragma mark Reindex/Query
//MARK: Reindex/Query
static int
TableSort(TableCell *a, TableCell *b)
@@ -255,9 +246,8 @@ static cpSpatialIndexClass klass = {
(cpSpatialIndexReindexObjectImpl)cpSweep1DReindexObject,
(cpSpatialIndexReindexQueryImpl)cpSweep1DReindexQuery,
(cpSpatialIndexPointQueryImpl)cpSweep1DPointQuery,
(cpSpatialIndexSegmentQueryImpl)cpSweep1DSegmentQuery,
(cpSpatialIndexQueryImpl)cpSweep1DQuery,
(cpSpatialIndexSegmentQueryImpl)cpSweep1DSegmentQuery,
};
static inline cpSpatialIndexClass *Klass(){return &klass;}

View File

@@ -20,46 +20,30 @@
*/
#include <stdio.h>
#include <math.h>
#include "chipmunk_private.h"
cpFloat
cpvlength(const cpVect v)
{
return cpfsqrt(cpvdot(v, v));
}
inline cpVect
cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t)
{
cpFloat omega = cpfacos(cpvdot(v1, v2));
cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2));
cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f));
if(omega){
if(omega == 0.0){
return v1;
} else {
cpFloat denom = 1.0f/cpfsin(omega);
return cpvadd(cpvmult(v1, cpfsin((1.0f - t)*omega)*denom), cpvmult(v2, cpfsin(t*omega)*denom));
} else {
return v1;
}
}
cpVect
cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a)
{
cpFloat angle = cpfacos(cpvdot(v1, v2));
return cpvslerp(v1, v2, cpfmin(a, angle)/angle);
}
cpVect
cpvforangle(const cpFloat a)
{
return cpv(cpfcos(a), cpfsin(a));
}
cpFloat
cpvtoangle(const cpVect v)
{
return cpfatan2(v.y, v.x);
cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2));
cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f));
return cpvslerp(v1, v2, cpfmin(a, omega)/omega);
}
char*