packages feed

chiphunk (empty) → 0.1.0.0

raw patch · 81 files changed

+18438/−0 lines, 81 filesdep +StateVardep +asyncdep +basesetup-changed

Dependencies added: StateVar, async, base, chiphunk, nanovg, nanovg-simple, safe-exceptions, vector-space

Files

+ Chipmunk2D-7.0.2/include/chipmunk/chipmunk.h view
@@ -0,0 +1,232 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_H+#define CHIPMUNK_H++#include <stdlib.h>+#include <math.h>++#ifndef alloca+	#ifdef _WIN32+		#include <malloc.h>+	#elif defined(__FreeBSD__)+		/* already included in <stdlib.h> */+	#else+		#include <alloca.h>+	#endif+#endif++#ifdef _WIN32+	#define CP_EXPORT __declspec(dllexport)+#else+	#define CP_EXPORT+#endif++#ifdef __cplusplus+extern "C" {+#endif++CP_EXPORT void cpMessage(const char *condition, const char *file, int line, int isError, int isHardError, const char *message, ...);+#ifdef NDEBUG+	#define	cpAssertWarn(__condition__, ...)+	#define	cpAssertSoft(__condition__, ...)+#else+	#define cpAssertSoft(__condition__, ...) if(!(__condition__)){cpMessage(#__condition__, __FILE__, __LINE__, 1, 0, __VA_ARGS__); abort();}+	#define cpAssertWarn(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 0, 0, __VA_ARGS__)+#endif++// Hard assertions are used in situations where the program definitely will crash anyway, and the reason is inexpensive to detect.+#define cpAssertHard(__condition__, ...) if(!(__condition__)){cpMessage(#__condition__, __FILE__, __LINE__, 1, 1, __VA_ARGS__); abort();}++#include "chipmunk_types.h"+	+/// @defgroup misc Misc+/// @{++/// Allocated size for various Chipmunk buffers+#ifndef CP_BUFFER_BYTES+	#define CP_BUFFER_BYTES (32*1024)+#endif++#ifndef cpcalloc+	/// Chipmunk calloc() alias.+	#define cpcalloc calloc+#endif++#ifndef cprealloc+	/// Chipmunk realloc() alias.+	#define cprealloc realloc+#endif++#ifndef cpfree+	/// Chipmunk free() alias.+	#define cpfree free+#endif++typedef struct cpArray cpArray;+typedef struct cpHashSet cpHashSet;++typedef struct cpBody cpBody;++typedef struct cpShape cpShape;+typedef struct cpCircleShape cpCircleShape;+typedef struct cpSegmentShape cpSegmentShape;+typedef struct cpPolyShape cpPolyShape;++typedef struct cpConstraint cpConstraint;+typedef struct cpPinJoint cpPinJoint;+typedef struct cpSlideJoint cpSlideJoint;+typedef struct cpPivotJoint cpPivotJoint;+typedef struct cpGrooveJoint cpGrooveJoint;+typedef struct cpDampedSpring cpDampedSpring;+typedef struct cpDampedRotarySpring cpDampedRotarySpring;+typedef struct cpRotaryLimitJoint cpRotaryLimitJoint;+typedef struct cpRatchetJoint cpRatchetJoint;+typedef struct cpGearJoint cpGearJoint;+typedef struct cpSimpleMotorJoint cpSimpleMotorJoint;++typedef struct cpCollisionHandler cpCollisionHandler;+typedef struct cpContactPointSet cpContactPointSet;+typedef struct cpArbiter cpArbiter;++typedef struct cpSpace cpSpace;++#include "cpVect.h"+#include "cpBB.h"+#include "cpTransform.h"+#include "cpSpatialIndex.h"++#include "cpArbiter.h"	++#include "cpBody.h"+#include "cpShape.h"+#include "cpPolyShape.h"++#include "cpConstraint.h"++#include "cpSpace.h"++// Chipmunk 7.0.2+#define CP_VERSION_MAJOR 7+#define CP_VERSION_MINOR 0+#define CP_VERSION_RELEASE 2++/// Version string.+CP_EXPORT extern const char *cpVersionString;++/// 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.+CP_EXPORT cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);++/// Calculate area of a hollow circle.+/// @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.+CP_EXPORT cpFloat cpAreaForCircle(cpFloat r1, cpFloat r2);++/// Calculate the moment of inertia for a line segment.+/// Beveling radius is not supported.+CP_EXPORT cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b, cpFloat radius);++/// Calculate the area of a fattened (capsule shaped) line segment.+CP_EXPORT cpFloat cpAreaForSegment(cpVect a, cpVect b, cpFloat radius);++/// Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex.+CP_EXPORT cpFloat cpMomentForPoly(cpFloat m, int count, const cpVect *verts, cpVect offset, cpFloat radius);++/// Calculate the signed area of a polygon. A Clockwise winding gives positive area.+/// This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes.+CP_EXPORT cpFloat cpAreaForPoly(const int count, const cpVect *verts, cpFloat radius);++/// Calculate the natural centroid of a polygon.+CP_EXPORT cpVect cpCentroidForPoly(const int count, const cpVect *verts);++/// Calculate the moment of inertia for a solid box.+CP_EXPORT cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height);++/// Calculate the moment of inertia for a solid box.+CP_EXPORT 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 verts == @c result, then @c verts will be reduced inplace.+/// @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.+CP_EXPORT int cpConvexHull(int count, const cpVect *verts, cpVect *result, int *first, cpFloat tol);++/// 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); \++/// Returns the closest point on the line segment ab, to the point p.+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));+}++#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 (^cpSpacePointQueryBlock)(cpShape *shape, cpVect point, cpFloat distance, cpVect gradient);+void cpSpacePointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpSpacePointQueryBlock block);++typedef void (^cpSpaceSegmentQueryBlock)(cpShape *shape, cpVect point, cpVect normal, cpFloat alpha);+void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSpaceSegmentQueryBlock block);++typedef void (^cpSpaceBBQueryBlock)(cpShape *shape);+void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpShapeFilter filter, cpSpaceBBQueryBlock block);++typedef void (^cpSpaceShapeQueryBlock)(cpShape *shape, cpContactPointSet *points);+cpBool cpSpaceShapeQuery_b(cpSpace *space, cpShape *shape, cpSpaceShapeQueryBlock block);++#endif+#endif+++//@}++#ifdef __cplusplus+}++static inline cpVect operator *(const cpVect v, const cpFloat s){return cpvmult(v, s);}+static inline cpVect operator +(const cpVect v1, const cpVect v2){return cpvadd(v1, v2);}+static inline cpVect operator -(const cpVect v1, const cpVect v2){return cpvsub(v1, v2);}+static inline cpBool operator ==(const cpVect v1, const cpVect v2){return cpveql(v1, v2);}+static inline cpVect operator -(const cpVect v){return cpvneg(v);}++#endif+#endif
+ Chipmunk2D-7.0.2/include/chipmunk/chipmunk_ffi.h view
@@ -0,0 +1,105 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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.+ */++#ifdef CHIPMUNK_FFI++// Create non static inlined copies of Chipmunk functions, useful for working with dynamic FFIs+// For many languages, it may be faster to reimplement these functions natively instead.+// Note: This file should only be included by chipmunk.c.++#ifdef _MSC_VER+ #if _MSC_VER >= 1600+  #define MAKE_REF(name) CP_EXPORT decltype(name) *_##name = name+ #else+  #define MAKE_REF(name)+ #endif+#else+ #define MAKE_REF(name) __typeof__(name) *_##name = name+#endif++#ifdef __cplusplus+extern "C" {+#endif++MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv()+MAKE_REF(cpveql);+MAKE_REF(cpvadd);+MAKE_REF(cpvneg);+MAKE_REF(cpvsub);+MAKE_REF(cpvmult);+MAKE_REF(cpvdot);+MAKE_REF(cpvcross);+MAKE_REF(cpvperp);+MAKE_REF(cpvrperp);+MAKE_REF(cpvproject);+MAKE_REF(cpvforangle);+MAKE_REF(cpvtoangle);+MAKE_REF(cpvrotate);+MAKE_REF(cpvunrotate);+MAKE_REF(cpvlengthsq);+MAKE_REF(cpvlength);+MAKE_REF(cpvlerp);+MAKE_REF(cpvnormalize);+MAKE_REF(cpvclamp);+MAKE_REF(cpvlerpconst);+MAKE_REF(cpvdist);+MAKE_REF(cpvdistsq);+MAKE_REF(cpvnear);++MAKE_REF(cpfmax);+MAKE_REF(cpfmin);+MAKE_REF(cpfabs);+MAKE_REF(cpfclamp);+MAKE_REF(cpflerp);+MAKE_REF(cpflerpconst);++MAKE_REF(cpBBNew);+MAKE_REF(cpBBNewForExtents);+MAKE_REF(cpBBNewForCircle);+MAKE_REF(cpBBIntersects);+MAKE_REF(cpBBContainsBB);+MAKE_REF(cpBBContainsVect);+MAKE_REF(cpBBMerge);+MAKE_REF(cpBBExpand);+MAKE_REF(cpBBCenter);+MAKE_REF(cpBBArea);+MAKE_REF(cpBBMergedArea);+MAKE_REF(cpBBSegmentQuery);+MAKE_REF(cpBBIntersectsSegment);+MAKE_REF(cpBBClampVect);++MAKE_REF(cpSpatialIndexDestroy);+MAKE_REF(cpSpatialIndexCount);+MAKE_REF(cpSpatialIndexEach);+MAKE_REF(cpSpatialIndexContains);+MAKE_REF(cpSpatialIndexInsert);+MAKE_REF(cpSpatialIndexRemove);+MAKE_REF(cpSpatialIndexReindex);+MAKE_REF(cpSpatialIndexReindexObject);+MAKE_REF(cpSpatialIndexSegmentQuery);+MAKE_REF(cpSpatialIndexQuery);+MAKE_REF(cpSpatialIndexReindexQuery);++#ifdef __cplusplus+}+#endif++#endif
+ Chipmunk2D-7.0.2/include/chipmunk/chipmunk_private.h view
@@ -0,0 +1,344 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_PRIVATE_H+#define CHIPMUNK_PRIVATE_H++#include "chipmunk/chipmunk.h"+#include "chipmunk/chipmunk_structs.h"++#define CP_HASH_COEF (3344921057ul)+#define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF)++// TODO: Eww. Magic numbers.+#define MAGIC_EPSILON 1e-5+++//MARK: cpArray++cpArray *cpArrayNew(int size);++void cpArrayFree(cpArray *arr);++void cpArrayPush(cpArray *arr, void *object);+void *cpArrayPop(cpArray *arr);+void cpArrayDeleteObj(cpArray *arr, void *obj);+cpBool cpArrayContains(cpArray *arr, void *ptr);++void cpArrayFreeEach(cpArray *arr, void (freeFunc)(void*));+++//MARK: cpHashSet++typedef cpBool (*cpHashSetEqlFunc)(void *ptr, void *elt);+typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);++cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc);+void cpHashSetSetDefaultValue(cpHashSet *set, void *default_value);++void cpHashSetFree(cpHashSet *set);++int cpHashSetCount(cpHashSet *set);+void *cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, cpHashSetTransFunc trans, void *data);+void *cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr);+void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr);++typedef void (*cpHashSetIteratorFunc)(void *elt, void *data);+void cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data);++typedef cpBool (*cpHashSetFilterFunc)(void *elt, void *data);+void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data);+++//MARK: Bodies++void cpBodyAddShape(cpBody *body, cpShape *shape);+void cpBodyRemoveShape(cpBody *body, cpShape *shape);++//void cpBodyAccumulateMassForShape(cpBody *body, cpShape *shape);+void cpBodyAccumulateMassFromShapes(cpBody *body);++void cpBodyRemoveConstraint(cpBody *body, cpConstraint *constraint);+++//MARK: Spatial Index Functions++cpSpatialIndex *cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);+++//MARK: Arbiters++cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b);++static inline struct cpArbiterThread *+cpArbiterThreadForBody(cpArbiter *arb, cpBody *body)+{+	return (arb->body_a == body ? &arb->thread_a : &arb->thread_b);+}++void cpArbiterUnthread(cpArbiter *arb);++void cpArbiterUpdate(cpArbiter *arb, struct cpCollisionInfo *info, cpSpace *space);+void cpArbiterPreStep(cpArbiter *arb, cpFloat dt, cpFloat bias, cpFloat slop);+void cpArbiterApplyCachedImpulse(cpArbiter *arb, cpFloat dt_coef);+void cpArbiterApplyImpulse(cpArbiter *arb);+++//MARK: Shapes/Collisions++cpShape *cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body, struct cpShapeMassInfo massInfo);++static inline cpBool+cpShapeActive(cpShape *shape)+{+	// checks if the shape is added to a shape list.+	// TODO could this just check the space now?+	return (shape->prev || (shape->body && shape->body->shapeList == shape));+}++// Note: This function returns contact points with r1/r2 in absolute coordinates, not body relative.+struct cpCollisionInfo cpCollide(const cpShape *a, const cpShape *b, cpCollisionID id, struct cpContact *contacts);++static inline void+CircleSegmentQuery(cpShape *shape, cpVect center, cpFloat r1, cpVect a, cpVect b, cpFloat r2, cpSegmentQueryInfo *info)+{+	cpVect da = cpvsub(a, center);+	cpVect db = cpvsub(b, center);+	cpFloat rsum = r1 + r2;+	+	cpFloat qa = cpvdot(da, da) - 2.0f*cpvdot(da, db) + cpvdot(db, db);+	cpFloat qb = cpvdot(da, db) - cpvdot(da, da);+	cpFloat det = qb*qb - qa*(cpvdot(da, da) - rsum*rsum);+	+	if(det >= 0.0f){+		cpFloat t = (-qb - cpfsqrt(det))/(qa);+		if(0.0f<= t && t <= 1.0f){+			cpVect n = cpvnormalize(cpvlerp(da, db, t));+			+			info->shape = shape;+			info->point = cpvsub(cpvlerp(a, b, t), cpvmult(n, r2));+			info->normal = n;+			info->alpha = t;+		}+	}+}++static inline cpBool+cpShapeFilterReject(cpShapeFilter a, cpShapeFilter b)+{+	// Reject the collision if:+	return (+		// They are in the same non-zero group.+		(a.group != 0 && a.group == b.group) ||+		// One of the category/mask combinations fails.+		(a.categories & b.mask) == 0 ||+		(b.categories & a.mask) == 0+	);+}++void cpLoopIndexes(const cpVect *verts, int count, int *start, int *end);+++//MARK: Constraints+// TODO naming conventions here++void cpConstraintInit(cpConstraint *constraint, const struct cpConstraintClass *klass, cpBody *a, cpBody *b);++static inline void+cpConstraintActivateBodies(cpConstraint *constraint)+{+	cpBody *a = constraint->a; cpBodyActivate(a);+	cpBody *b = constraint->b; cpBodyActivate(b);+}++static inline cpVect+relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){+	cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));+	cpVect v2_sum = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));+	+	return cpvsub(v2_sum, v1_sum);+}++static inline cpFloat+normal_relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n){+	return cpvdot(relative_velocity(a, b, r1, r2), n);+}++static inline void+apply_impulse(cpBody *body, cpVect j, cpVect r){+	body->v = cpvadd(body->v, cpvmult(j, body->m_inv));+	body->w += body->i_inv*cpvcross(r, j);+}++static inline void+apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)+{+	apply_impulse(a, cpvneg(j), r1);+	apply_impulse(b, j, r2);+}++static inline void+apply_bias_impulse(cpBody *body, cpVect j, cpVect r)+{+	body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));+	body->w_bias += body->i_inv*cpvcross(r, j);+}++static inline void+apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)+{+	apply_bias_impulse(a, cpvneg(j), r1);+	apply_bias_impulse(b, j, r2);+}++static inline cpFloat+k_scalar_body(cpBody *body, cpVect r, cpVect n)+{+	cpFloat rcn = cpvcross(r, n);+	return body->m_inv + body->i_inv*rcn*rcn;+}++static inline cpFloat+k_scalar(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)+{+	cpFloat value = k_scalar_body(a, r1, n) + k_scalar_body(b, r2, n);+	cpAssertSoft(value != 0.0, "Unsolvable collision or constraint.");+	+	return value;+}++static inline cpMat2x2+k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2)+{+	cpFloat m_sum = a->m_inv + b->m_inv;+	+	// start with Identity*m_sum+	cpFloat k11 = m_sum, k12 = 0.0f;+	cpFloat k21 = 0.0f,  k22 = m_sum;+	+	// add the influence from r1+	cpFloat a_i_inv = a->i_inv;+	cpFloat r1xsq =  r1.x * r1.x * a_i_inv;+	cpFloat r1ysq =  r1.y * r1.y * a_i_inv;+	cpFloat r1nxy = -r1.x * r1.y * a_i_inv;+	k11 += r1ysq; k12 += r1nxy;+	k21 += r1nxy; k22 += r1xsq;+	+	// add the influnce from r2+	cpFloat b_i_inv = b->i_inv;+	cpFloat r2xsq =  r2.x * r2.x * b_i_inv;+	cpFloat r2ysq =  r2.y * r2.y * b_i_inv;+	cpFloat r2nxy = -r2.x * r2.y * b_i_inv;+	k11 += r2ysq; k12 += r2nxy;+	k21 += r2nxy; k22 += r2xsq;+	+	// invert+	cpFloat det = k11*k22 - k12*k21;+	cpAssertSoft(det != 0.0, "Unsolvable constraint.");+	+	cpFloat det_inv = 1.0f/det;+	return cpMat2x2New(+		 k22*det_inv, -k12*det_inv,+		-k21*det_inv,  k11*det_inv+ 	);+}++static inline cpFloat+bias_coef(cpFloat errorBias, cpFloat dt)+{+	return 1.0f - cpfpow(errorBias, dt);+}+++//MARK: Spaces++#define cpAssertSpaceUnlocked(space) \+	cpAssertHard(!space->locked, \+		"This operation cannot be done safely during a call to cpSpaceStep() or during a query. " \+		"Put these calls into a post-step callback." \+	);++void cpSpaceSetStaticBody(cpSpace *space, cpBody *body);++extern cpCollisionHandler cpCollisionHandlerDoNothing;++void cpSpaceProcessComponents(cpSpace *space, cpFloat dt);++void cpSpacePushFreshContactBuffer(cpSpace *space);+struct cpContact *cpContactBufferGetArray(cpSpace *space);+void cpSpacePushContacts(cpSpace *space, int count);++cpPostStepCallback *cpSpaceGetPostStepCallback(cpSpace *space, void *key);++cpBool cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space);+void cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter);++void cpSpaceActivateBody(cpSpace *space, cpBody *body);+void cpSpaceLock(cpSpace *space);+void cpSpaceUnlock(cpSpace *space, cpBool runPostStep);++static inline void+cpSpaceUncacheArbiter(cpSpace *space, cpArbiter *arb)+{+	const cpShape *a = arb->a, *b = arb->b;+	const cpShape *shape_pair[] = {a, b};+	cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);+	cpHashSetRemove(space->cachedArbiters, arbHashID, shape_pair);+	cpArrayDeleteObj(space->arbiters, arb);+}++static inline cpArray *+cpSpaceArrayForBodyType(cpSpace *space, cpBodyType type)+{+	return (type == CP_BODY_TYPE_STATIC ? space->staticBodies : space->dynamicBodies);+}++void cpShapeUpdateFunc(cpShape *shape, void *unused);+cpCollisionID cpSpaceCollideShapes(cpShape *a, cpShape *b, cpCollisionID id, cpSpace *space);+++//MARK: Foreach loops++static inline cpConstraint *+cpConstraintNext(cpConstraint *node, cpBody *body)+{+	return (node->a == body ? node->next_a : node->next_b);+}++#define CP_BODY_FOREACH_CONSTRAINT(bdy, var)\+	for(cpConstraint *var = bdy->constraintList; var; var = cpConstraintNext(var, bdy))++static inline cpArbiter *+cpArbiterNext(cpArbiter *node, cpBody *body)+{+	return (node->body_a == body ? node->thread_a.next : node->thread_b.next);+}++#define CP_BODY_FOREACH_ARBITER(bdy, var)\+	for(cpArbiter *var = bdy->arbiterList; var; var = cpArbiterNext(var, bdy))++#define CP_BODY_FOREACH_SHAPE(body, var)\+	for(cpShape *var = body->shapeList; var; var = var->next)++#define CP_BODY_FOREACH_COMPONENT(root, var)\+	for(cpBody *var = root; var; var = var->sleeping.next)++#endif
+ Chipmunk2D-7.0.2/include/chipmunk/chipmunk_structs.h view
@@ -0,0 +1,450 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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.+ */++// All of the struct definitions for Chipmunk should be considered part of the private API.+// However, it is very valuable to know the struct sizes for preallocating memory.++#ifndef CHIPMUNK_STRUCTS_H+#define CHIPMUNK_STRUCTS_H++#include "chipmunk/chipmunk.h"++struct cpArray {+	int num, max;+	void **arr;+};++struct cpBody {+	// Integration functions+	cpBodyVelocityFunc velocity_func;+	cpBodyPositionFunc position_func;+	+	// mass and it's inverse+	cpFloat m;+	cpFloat m_inv;+	+	// moment of inertia and it's inverse+	cpFloat i;+	cpFloat i_inv;+	+	// center of gravity+	cpVect cog;+	+	// position, velocity, force+	cpVect p;+	cpVect v;+	cpVect f;+	+	// Angle, angular velocity, torque (radians)+	cpFloat a;+	cpFloat w;+	cpFloat t;+	+	cpTransform transform;+	+	cpDataPointer userData;+	+	// "pseudo-velocities" used for eliminating overlap.+	// Erin Catto has some papers that talk about what these are.+	cpVect v_bias;+	cpFloat w_bias;+	+	cpSpace *space;+	+	cpShape *shapeList;+	cpArbiter *arbiterList;+	cpConstraint *constraintList;+	+	struct {+		cpBody *root;+		cpBody *next;+		cpFloat idleTime;+	} sleeping;+};++enum cpArbiterState {+	// Arbiter is active and its the first collision.+	CP_ARBITER_STATE_FIRST_COLLISION,+	// Arbiter is active and its not the first collision.+	CP_ARBITER_STATE_NORMAL,+	// Collision has been explicitly ignored.+	// Either by returning false from a begin collision handler or calling cpArbiterIgnore().+	CP_ARBITER_STATE_IGNORE,+	// Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.+	CP_ARBITER_STATE_CACHED,+	// Collison arbiter is invalid because one of the shapes was removed.+	CP_ARBITER_STATE_INVALIDATED,+};++struct cpArbiterThread {+	struct cpArbiter *next, *prev;+};++struct cpContact {+	cpVect r1, r2;+	+	cpFloat nMass, tMass;+	cpFloat bounce; // TODO: look for an alternate bounce solution.++	cpFloat jnAcc, jtAcc, jBias;+	cpFloat bias;+	+	cpHashValue hash;+};++struct cpCollisionInfo {+	const cpShape *a, *b;+	cpCollisionID id;+	+	cpVect n;+	+	int count;+	// TODO Should this be a unique struct type?+	struct cpContact *arr;+};++struct cpArbiter {+	cpFloat e;+	cpFloat u;+	cpVect surface_vr;+	+	cpDataPointer data;+	+	const cpShape *a, *b;+	cpBody *body_a, *body_b;+	struct cpArbiterThread thread_a, thread_b;+	+	int count;+	struct cpContact *contacts;+	cpVect n;+	+	// Regular, wildcard A and wildcard B collision handlers.+	cpCollisionHandler *handler, *handlerA, *handlerB;+	cpBool swapped;+	+	cpTimestamp stamp;+	enum cpArbiterState state;+};++struct cpShapeMassInfo {+	cpFloat m;+	cpFloat i;+	cpVect cog;+	cpFloat area;+};++typedef enum cpShapeType{+	CP_CIRCLE_SHAPE,+	CP_SEGMENT_SHAPE,+	CP_POLY_SHAPE,+	CP_NUM_SHAPES+} cpShapeType;++typedef cpBB (*cpShapeCacheDataImpl)(cpShape *shape, cpTransform transform);+typedef void (*cpShapeDestroyImpl)(cpShape *shape);+typedef void (*cpShapePointQueryImpl)(const cpShape *shape, cpVect p, cpPointQueryInfo *info);+typedef void (*cpShapeSegmentQueryImpl)(const cpShape *shape, cpVect a, cpVect b, cpFloat radius, cpSegmentQueryInfo *info);++typedef struct cpShapeClass cpShapeClass;++struct cpShapeClass {+	cpShapeType type;+	+	cpShapeCacheDataImpl cacheData;+	cpShapeDestroyImpl destroy;+	cpShapePointQueryImpl pointQuery;+	cpShapeSegmentQueryImpl segmentQuery;+};++struct cpShape {+	const cpShapeClass *klass;+	+	cpSpace *space;+	cpBody *body;+	struct cpShapeMassInfo massInfo;+	cpBB bb;+	+	cpBool sensor;+	+	cpFloat e;+	cpFloat u;+	cpVect surfaceV;++	cpDataPointer userData;+	+	cpCollisionType type;+	cpShapeFilter filter;+	+	cpShape *next;+	cpShape *prev;+	+	cpHashValue hashid;+};++struct cpCircleShape {+	cpShape shape;+	+	cpVect c, tc;+	cpFloat r;+};++struct cpSegmentShape {+	cpShape shape;+	+	cpVect a, b, n;+	cpVect ta, tb, tn;+	cpFloat r;+	+	cpVect a_tangent, b_tangent;+};++struct cpSplittingPlane {+	cpVect v0, n;+};++#define CP_POLY_SHAPE_INLINE_ALLOC 6++struct cpPolyShape {+	cpShape shape;+	+	cpFloat r;+	+	int count;+	// The untransformed planes are appended at the end of the transformed planes.+	struct cpSplittingPlane *planes;+	+	// Allocate a small number of splitting planes internally for simple poly.+	struct cpSplittingPlane _planes[2*CP_POLY_SHAPE_INLINE_ALLOC];+};++typedef void (*cpConstraintPreStepImpl)(cpConstraint *constraint, cpFloat dt);+typedef void (*cpConstraintApplyCachedImpulseImpl)(cpConstraint *constraint, cpFloat dt_coef);+typedef void (*cpConstraintApplyImpulseImpl)(cpConstraint *constraint, cpFloat dt);+typedef cpFloat (*cpConstraintGetImpulseImpl)(cpConstraint *constraint);++typedef struct cpConstraintClass {+	cpConstraintPreStepImpl preStep;+	cpConstraintApplyCachedImpulseImpl applyCachedImpulse;+	cpConstraintApplyImpulseImpl applyImpulse;+	cpConstraintGetImpulseImpl getImpulse;+} cpConstraintClass;++struct cpConstraint {+	const cpConstraintClass *klass;+	+	cpSpace *space;+	+	cpBody *a, *b;+	cpConstraint *next_a, *next_b;+	+	cpFloat maxForce;+	cpFloat errorBias;+	cpFloat maxBias;+	+	cpBool collideBodies;+	+	cpConstraintPreSolveFunc preSolve;+	cpConstraintPostSolveFunc postSolve;+	+	cpDataPointer userData;+};++struct cpPinJoint {+	cpConstraint constraint;+	cpVect anchorA, anchorB;+	cpFloat dist;+	+	cpVect r1, r2;+	cpVect n;+	cpFloat nMass;+	+	cpFloat jnAcc;+	cpFloat bias;+};++struct cpSlideJoint {+	cpConstraint constraint;+	cpVect anchorA, anchorB;+	cpFloat min, max;+	+	cpVect r1, r2;+	cpVect n;+	cpFloat nMass;+	+	cpFloat jnAcc;+	cpFloat bias;+};++struct cpPivotJoint {+	cpConstraint constraint;+	cpVect anchorA, anchorB;+	+	cpVect r1, r2;+	cpMat2x2 k;+	+	cpVect jAcc;+	cpVect bias;+};++struct cpGrooveJoint {+	cpConstraint constraint;+	cpVect grv_n, grv_a, grv_b;+	cpVect  anchorB;+	+	cpVect grv_tn;+	cpFloat clamp;+	cpVect r1, r2;+	cpMat2x2 k;+	+	cpVect jAcc;+	cpVect bias;+};++struct cpDampedSpring {+	cpConstraint constraint;+	cpVect anchorA, anchorB;+	cpFloat restLength;+	cpFloat stiffness;+	cpFloat damping;+	cpDampedSpringForceFunc springForceFunc;+	+	cpFloat target_vrn;+	cpFloat v_coef;+	+	cpVect r1, r2;+	cpFloat nMass;+	cpVect n;+	+	cpFloat jAcc;+};++struct cpDampedRotarySpring {+	cpConstraint constraint;+	cpFloat restAngle;+	cpFloat stiffness;+	cpFloat damping;+	cpDampedRotarySpringTorqueFunc springTorqueFunc;+	+	cpFloat target_wrn;+	cpFloat w_coef;+	+	cpFloat iSum;+	cpFloat jAcc;+};++struct cpRotaryLimitJoint {+	cpConstraint constraint;+	cpFloat min, max;+	+	cpFloat iSum;+		+	cpFloat bias;+	cpFloat jAcc;+};++struct cpRatchetJoint {+	cpConstraint constraint;+	cpFloat angle, phase, ratchet;+	+	cpFloat iSum;+		+	cpFloat bias;+	cpFloat jAcc;+};++struct cpGearJoint {+	cpConstraint constraint;+	cpFloat phase, ratio;+	cpFloat ratio_inv;+	+	cpFloat iSum;+		+	cpFloat bias;+	cpFloat jAcc;+};++struct cpSimpleMotor {+	cpConstraint constraint;+	cpFloat rate;+	+	cpFloat iSum;+		+	cpFloat jAcc;+};++typedef struct cpContactBufferHeader cpContactBufferHeader;+typedef void (*cpSpaceArbiterApplyImpulseFunc)(cpArbiter *arb);++struct cpSpace {+	int iterations;+	+	cpVect gravity;+	cpFloat damping;+	+	cpFloat idleSpeedThreshold;+	cpFloat sleepTimeThreshold;+	+	cpFloat collisionSlop;+	cpFloat collisionBias;+	cpTimestamp collisionPersistence;+	+	cpDataPointer userData;+	+	cpTimestamp stamp;+	cpFloat curr_dt;++	cpArray *dynamicBodies;+	cpArray *staticBodies;+	cpArray *rousedBodies;+	cpArray *sleepingComponents;+	+	cpHashValue shapeIDCounter;+	cpSpatialIndex *staticShapes;+	cpSpatialIndex *dynamicShapes;+	+	cpArray *constraints;+	+	cpArray *arbiters;+	cpContactBufferHeader *contactBuffersHead;+	cpHashSet *cachedArbiters;+	cpArray *pooledArbiters;+	+	cpArray *allocatedBuffers;+	unsigned int locked;+	+	cpBool usesWildcards;+	cpHashSet *collisionHandlers;+	cpCollisionHandler defaultHandler;+	+	cpBool skipPostStep;+	cpArray *postStepCallbacks;+	+	cpBody *staticBody;+	cpBody _staticBody;+};++typedef struct cpPostStepCallback {+	cpPostStepFunc func;+	void *key;+	void *data;+} cpPostStepCallback;++#endif
+ Chipmunk2D-7.0.2/include/chipmunk/chipmunk_types.h view
@@ -0,0 +1,268 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_TYPES_H+#define CHIPMUNK_TYPES_H++#include <stdint.h>+#include <float.h>+#include <math.h>++#ifdef __APPLE__+   #include "TargetConditionals.h"+#endif++// Use CGTypes by default on iOS and Mac.+// Also enables usage of doubles on 64 bit.+// Performance is usually very comparable when the CPU cache is well utilised.+#if (TARGET_OS_IPHONE || TARGET_OS_MAC) && (!defined CP_USE_CGTYPES)+	#define CP_USE_CGTYPES 1+#endif++#if CP_USE_CGTYPES+	#if TARGET_OS_IPHONE+		#include <CoreGraphics/CGGeometry.h>+		#include <CoreGraphics/CGAffineTransform.h>+	#elif TARGET_OS_MAC+		#include <ApplicationServices/ApplicationServices.h>+	#endif+	+	#if defined(__LP64__) && __LP64__+		#define CP_USE_DOUBLES 1+	#else+		#define CP_USE_DOUBLES 0+	#endif+#endif++#ifndef CP_USE_DOUBLES+	// Use doubles by default for higher precision.+	#define CP_USE_DOUBLES 1+#endif++/// @defgroup basicTypes Basic Types+/// Most of these types can be configured at compile time.+/// @{++#if CP_USE_DOUBLES+/// Chipmunk's floating point type.+/// Can be reconfigured at compile time.+	typedef double cpFloat;+	#define cpfsqrt sqrt+	#define cpfsin sin+	#define cpfcos cos+	#define cpfacos acos+	#define cpfatan2 atan2+	#define cpfmod fmod+	#define cpfexp exp+	#define cpfpow pow+	#define cpffloor floor+	#define cpfceil ceil+	#define CPFLOAT_MIN DBL_MIN+#else+	typedef float cpFloat;+	#define cpfsqrt sqrtf+	#define cpfsin sinf+	#define cpfcos cosf+	#define cpfacos acosf+	#define cpfatan2 atan2f+	#define cpfmod fmodf+	#define cpfexp expf+	#define cpfpow powf+	#define cpffloor floorf+	#define cpfceil ceilf+	#define CPFLOAT_MIN FLT_MIN+#endif++#ifndef INFINITY+	#ifdef _MSC_VER+		union MSVC_EVIL_FLOAT_HACK+		{+			unsigned __int8 Bytes[4];+			float Value;+		};+		static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}};+		#define INFINITY (INFINITY_HACK.Value)+	#endif+	+	#ifdef __GNUC__+		#define INFINITY (__builtin_inf())+	#endif+	+	#ifndef INFINITY+		#define INFINITY (1e1000)+	#endif+#endif+++#define CP_PI ((cpFloat)3.14159265358979323846264338327950288)+++/// Return the max of two cpFloats.+static inline cpFloat cpfmax(cpFloat a, cpFloat b)+{+	return (a > b) ? a : b;+}++/// Return the min of two cpFloats.+static inline cpFloat cpfmin(cpFloat a, cpFloat b)+{+	return (a < b) ? a : b;+}++/// Return the absolute value of a cpFloat.+static inline cpFloat cpfabs(cpFloat f)+{+	return (f < 0) ? -f : f;+}++/// Clamp @c f to be between @c min and @c max.+static inline cpFloat cpfclamp(cpFloat f, cpFloat min, cpFloat max)+{+	return cpfmin(cpfmax(f, min), max);+}++/// Clamp @c f to be between 0 and 1.+static inline cpFloat cpfclamp01(cpFloat f)+{+	return cpfmax(0.0f, cpfmin(f, 1.0f));+}++++/// Linearly interpolate (or extrapolate) between @c f1 and @c f2 by @c t percent.+static inline cpFloat cpflerp(cpFloat f1, cpFloat f2, cpFloat t)+{+	return f1*(1.0f - t) + f2*t;+}++/// Linearly interpolate from @c f1 to @c f2 by no more than @c d.+static inline cpFloat cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)+{+	return f1 + cpfclamp(f2 - f1, -d, d);+}++/// Hash value type.+#ifdef CP_HASH_VALUE_TYPE+	typedef CP_HASH_VALUE_TYPE cpHashValue;+#else+	typedef uintptr_t cpHashValue;+#endif++/// Type used internally to cache colliding object info for cpCollideShapes().+/// Should be at least 32 bits.+typedef uint32_t cpCollisionID;++// Oh C, how we love to define our own boolean types to get compiler compatibility+/// Chipmunk's boolean type.+#ifdef CP_BOOL_TYPE+	typedef CP_BOOL_TYPE cpBool;+#else+	typedef unsigned char cpBool;+#endif++#ifndef cpTrue+/// true value.+	#define cpTrue 1+#endif++#ifndef cpFalse+/// false value.+	#define cpFalse 0+#endif++#ifdef CP_DATA_POINTER_TYPE+	typedef CP_DATA_POINTER_TYPE cpDataPointer;+#else+/// Type used for user data pointers.+	typedef void * cpDataPointer;+#endif++#ifdef CP_COLLISION_TYPE_TYPE+	typedef CP_COLLISION_TYPE_TYPE cpCollisionType;+#else+/// Type used for cpSpace.collision_type.+	typedef uintptr_t cpCollisionType;+#endif++#ifdef CP_GROUP_TYPE+	typedef CP_GROUP_TYPE cpGroup;+#else+/// Type used for cpShape.group.+	typedef uintptr_t cpGroup;+#endif++#ifdef CP_BITMASK_TYPE+	typedef CP_BITMASK_TYPE cpBitmask;+#else+/// Type used for cpShapeFilter category and mask.+	typedef unsigned int cpBitmask;+#endif++#ifdef CP_TIMESTAMP_TYPE+	typedef CP_TIMESTAMP_TYPE cpTimestamp;+#else+/// Type used for various timestamps in Chipmunk.+	typedef unsigned int cpTimestamp;+#endif++#ifndef CP_NO_GROUP+/// Value for cpShape.group signifying that a shape is in no group.+	#define CP_NO_GROUP ((cpGroup)0)+#endif++#ifndef CP_ALL_CATEGORIES+/// Value for cpShape.layers signifying that a shape is in every layer.+	#define CP_ALL_CATEGORIES (~(cpBitmask)0)+#endif++#ifndef CP_WILDCARD_COLLISION_TYPE+/// cpCollisionType value internally reserved for hashing wildcard handlers.+	#define CP_WILDCARD_COLLISION_TYPE (~(cpCollisionType)0)+#endif++/// @}++// CGPoints are structurally the same, and allow+// easy interoperability with other Cocoa libraries+#if CP_USE_CGTYPES+	typedef CGPoint cpVect;+#else+/// Chipmunk's 2D vector type.+/// @addtogroup cpVect+	typedef struct cpVect{cpFloat x,y;} cpVect;+#endif++#if CP_USE_CGTYPES+	typedef CGAffineTransform cpTransform;+#else+	/// Column major affine transform.+	typedef struct cpTransform {+		cpFloat a, b, c, d, tx, ty;+	} cpTransform;+#endif++// NUKE+typedef struct cpMat2x2 {+	// Row major [[a, b][c d]]+	cpFloat a, b, c, d;+} cpMat2x2;++#endif
+ Chipmunk2D-7.0.2/include/chipmunk/chipmunk_unsafe.h view
@@ -0,0 +1,66 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/* This header defines a number of "unsafe" operations on Chipmunk objects.+ * In this case "unsafe" is referring to operations which may reduce the+ * physical accuracy or numerical stability of the simulation, but will not+ * cause crashes.+ *+ * The prime example is mutating collision shapes. Chipmunk does not support+ * this directly. Mutating shapes using this API will caused objects in contact+ * to be pushed apart using Chipmunk's overlap solver, but not using real+ * persistent velocities. Probably not what you meant, but perhaps close enough.+ */++/// @defgroup unsafe Chipmunk Unsafe Shape Operations+/// These functions are used for mutating collision shapes.+/// Chipmunk does not have any way to get velocity information on changing shapes,+/// so the results will be unrealistic. You must explicity include the chipmunk_unsafe.h header to use them.+/// @{++#ifndef CHIPMUNK_UNSAFE_H+#define CHIPMUNK_UNSAFE_H++#ifdef __cplusplus+extern "C" {+#endif++/// Set the radius of a circle shape.+CP_EXPORT void cpCircleShapeSetRadius(cpShape *shape, cpFloat radius);+/// Set the offset of a circle shape.+CP_EXPORT void cpCircleShapeSetOffset(cpShape *shape, cpVect offset);++/// Set the endpoints of a segment shape.+CP_EXPORT void cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b);+/// Set the radius of a segment shape.+CP_EXPORT void cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius);++/// Set the vertexes of a poly shape.+CP_EXPORT void cpPolyShapeSetVerts(cpShape *shape, int count, cpVect *verts, cpTransform transform);+CP_EXPORT void cpPolyShapeSetVertsRaw(cpShape *shape, int count, cpVect *verts);+/// Set the radius of a poly shape.+CP_EXPORT void cpPolyShapeSetRadius(cpShape *shape, cpFloat radius);++#ifdef __cplusplus+}+#endif+#endif+/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpArbiter.h view
@@ -0,0 +1,145 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpArbiter cpArbiter+/// The cpArbiter struct tracks pairs of colliding shapes.+/// They are also used in conjuction with collision handler callbacks+/// allowing you to retrieve information on the collision or change it.+/// A unique arbiter value is used for each pair of colliding objects. It persists until the shapes separate.+/// @{++#define CP_MAX_CONTACTS_PER_ARBITER 2++/// Get the restitution (elasticity) that will be applied to the pair of colliding objects.+CP_EXPORT cpFloat cpArbiterGetRestitution(const cpArbiter *arb);+/// Override the restitution (elasticity) that will be applied to the pair of colliding objects.+CP_EXPORT void cpArbiterSetRestitution(cpArbiter *arb, cpFloat restitution);+/// Get the friction coefficient that will be applied to the pair of colliding objects.+CP_EXPORT cpFloat cpArbiterGetFriction(const cpArbiter *arb);+/// Override the friction coefficient that will be applied to the pair of colliding objects.+CP_EXPORT void cpArbiterSetFriction(cpArbiter *arb, cpFloat friction);++// Get the relative surface velocity of the two shapes in contact.+CP_EXPORT cpVect cpArbiterGetSurfaceVelocity(cpArbiter *arb);++// Override the relative surface velocity of the two shapes in contact.+// By default this is calculated to be the difference of the two surface velocities clamped to the tangent plane.+CP_EXPORT void cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr);++/// Get the user data pointer associated with this pair of colliding objects.+CP_EXPORT cpDataPointer cpArbiterGetUserData(const cpArbiter *arb);+/// Set a user data point associated with this pair of colliding objects.+/// If you need to perform any cleanup for this pointer, you must do it yourself, in the separate callback for instance.+CP_EXPORT void cpArbiterSetUserData(cpArbiter *arb, cpDataPointer userData);++/// Calculate the total impulse including the friction that was applied by this arbiter.+/// This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.+CP_EXPORT cpVect cpArbiterTotalImpulse(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.+CP_EXPORT cpFloat cpArbiterTotalKE(const cpArbiter *arb);++/// Mark a collision pair to be ignored until the two objects separate.+/// Pre-solve and post-solve callbacks will not be called, but the separate callback will be called.+CP_EXPORT cpBool cpArbiterIgnore(cpArbiter *arb);++/// Return the colliding shapes involved for this arbiter.+/// The order of their cpSpace.collision_type values will match+/// the order set when the collision handler was registered.+CP_EXPORT void cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b);++/// A macro shortcut for defining and retrieving the shapes from an arbiter.+#define CP_ARBITER_GET_SHAPES(__arb__, __a__, __b__) cpShape *__a__, *__b__; cpArbiterGetShapes(__arb__, &__a__, &__b__);++/// Return the colliding bodies involved for this arbiter.+/// The order of the cpSpace.collision_type the bodies are associated with values will match+/// the order set when the collision handler was registered.+CP_EXPORT void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b);++/// A macro shortcut for defining and retrieving the bodies from an arbiter.+#define CP_ARBITER_GET_BODIES(__arb__, __a__, __b__) cpBody *__a__, *__b__; cpArbiterGetBodies(__arb__, &__a__, &__b__);++/// A struct that wraps up the important collision data for an arbiter.+struct cpContactPointSet {+	/// The number of contact points in the set.+	int count;+	+	/// The normal of the collision.+	cpVect normal;+	+	/// The array of contact points.+	struct {+		/// The position of the contact on the surface of each shape.+		cpVect pointA, pointB;+		/// Penetration distance of the two shapes. Overlapping means it will be negative.+		/// This value is calculated as cpvdot(cpvsub(point2, point1), normal) and is ignored by cpArbiterSetContactPointSet().+		cpFloat distance;+	} points[CP_MAX_CONTACTS_PER_ARBITER];+};++/// Return a contact set from an arbiter.+CP_EXPORT cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb);++/// Replace the contact point set for an arbiter.+/// This can be a very powerful feature, but use it with caution!+CP_EXPORT void cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set);++/// Returns true if this is the first step a pair of objects started colliding.+CP_EXPORT cpBool cpArbiterIsFirstContact(const cpArbiter *arb);+/// Returns true if the separate callback is due to a shape being removed from the space.+CP_EXPORT cpBool cpArbiterIsRemoval(const cpArbiter *arb);++/// Get the number of contact points for this arbiter.+CP_EXPORT int cpArbiterGetCount(const cpArbiter *arb);+/// Get the normal of the collision.+CP_EXPORT cpVect cpArbiterGetNormal(const cpArbiter *arb);+/// Get the position of the @c ith contact point on the surface of the first shape.+CP_EXPORT cpVect cpArbiterGetPointA(const cpArbiter *arb, int i);+/// Get the position of the @c ith contact point on the surface of the second shape.+CP_EXPORT cpVect cpArbiterGetPointB(const cpArbiter *arb, int i);+/// Get the depth of the @c ith contact point.+CP_EXPORT cpFloat cpArbiterGetDepth(const cpArbiter *arb, int i);++/// If you want a custom callback to invoke the wildcard callback for the first collision type, you must call this function explicitly.+/// You must decide how to handle the wildcard's return value since it may disagree with the other wildcard handler's return value or your own.+CP_EXPORT cpBool cpArbiterCallWildcardBeginA(cpArbiter *arb, cpSpace *space);+/// If you want a custom callback to invoke the wildcard callback for the second collision type, you must call this function explicitly.+/// You must decide how to handle the wildcard's return value since it may disagree with the other wildcard handler's return value or your own.+CP_EXPORT cpBool cpArbiterCallWildcardBeginB(cpArbiter *arb, cpSpace *space);++/// If you want a custom callback to invoke the wildcard callback for the first collision type, you must call this function explicitly.+/// You must decide how to handle the wildcard's return value since it may disagree with the other wildcard handler's return value or your own.+CP_EXPORT cpBool cpArbiterCallWildcardPreSolveA(cpArbiter *arb, cpSpace *space);+/// If you want a custom callback to invoke the wildcard callback for the second collision type, you must call this function explicitly.+/// You must decide how to handle the wildcard's return value since it may disagree with the other wildcard handler's return value or your own.+CP_EXPORT cpBool cpArbiterCallWildcardPreSolveB(cpArbiter *arb, cpSpace *space);++/// If you want a custom callback to invoke the wildcard callback for the first collision type, you must call this function explicitly.+CP_EXPORT void cpArbiterCallWildcardPostSolveA(cpArbiter *arb, cpSpace *space);+/// If you want a custom callback to invoke the wildcard callback for the second collision type, you must call this function explicitly.+CP_EXPORT void cpArbiterCallWildcardPostSolveB(cpArbiter *arb, cpSpace *space);++/// If you want a custom callback to invoke the wildcard callback for the first collision type, you must call this function explicitly.+CP_EXPORT void cpArbiterCallWildcardSeparateA(cpArbiter *arb, cpSpace *space);+/// If you want a custom callback to invoke the wildcard callback for the second collision type, you must call this function explicitly.+CP_EXPORT void cpArbiterCallWildcardSeparateB(cpArbiter *arb, cpSpace *space);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpBB.h view
@@ -0,0 +1,187 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_BB_H+#define CHIPMUNK_BB_H++#include "chipmunk_types.h"+#include "cpVect.h"++/// @defgroup cpBBB cpBB+/// Chipmunk's axis-aligned 2D bounding box type along with a few handy routines.+/// @{++/// Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top)+typedef struct cpBB{+	cpFloat l, b, r ,t;+} cpBB;++/// Convenience constructor for cpBB structs.+static inline cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t)+{+	cpBB bb = {l, b, r, t};+	return bb;+}++/// Constructs a cpBB centered on a point with the given extents (half sizes).+static inline cpBB+cpBBNewForExtents(const cpVect c, const cpFloat hw, const cpFloat hh)+{+	return cpBBNew(c.x - hw, c.y - hh, c.x + hw, c.y + hh);+}++/// Constructs a cpBB for a circle with the given position and radius.+static inline cpBB cpBBNewForCircle(const cpVect p, const cpFloat r)+{+	return cpBBNewForExtents(p, r, r);+}++/// Returns true if @c a and @c b intersect.+static inline cpBool cpBBIntersects(const cpBB a, const cpBB b)+{+	return (a.l <= b.r && b.l <= a.r && a.b <= b.t && b.b <= a.t);+}++/// Returns true if @c other lies completely within @c bb.+static inline cpBool cpBBContainsBB(const cpBB bb, const cpBB other)+{+	return (bb.l <= other.l && bb.r >= other.r && bb.b <= other.b && bb.t >= other.t);+}++/// Returns true if @c bb contains @c v.+static inline cpBool cpBBContainsVect(const cpBB bb, const cpVect v)+{+	return (bb.l <= v.x && bb.r >= v.x && bb.b <= v.y && bb.t >= v.y);+}++/// Returns a bounding box that holds both bounding boxes.+static inline cpBB cpBBMerge(const cpBB a, const cpBB b){+	return cpBBNew(+		cpfmin(a.l, b.l),+		cpfmin(a.b, b.b),+		cpfmax(a.r, b.r),+		cpfmax(a.t, b.t)+	);+}++/// Returns a bounding box that holds both @c bb and @c v.+static inline cpBB cpBBExpand(const cpBB bb, const cpVect v){+	return cpBBNew(+		cpfmin(bb.l, v.x),+		cpfmin(bb.b, v.y),+		cpfmax(bb.r, v.x),+		cpfmax(bb.t, v.y)+	);+}++/// Returns the center of a bounding box.+static inline cpVect+cpBBCenter(cpBB bb)+{+	return cpvlerp(cpv(bb.l, bb.b), cpv(bb.r, bb.t), 0.5f);+}++/// Returns the area of the bounding box.+static inline cpFloat cpBBArea(cpBB bb)+{+	return (bb.r - bb.l)*(bb.t - bb.b);+}++/// Merges @c a and @c b and returns the area of the merged bounding box.+static inline cpFloat cpBBMergedArea(cpBB a, cpBB b)+{+	return (cpfmax(a.r, b.r) - cpfmin(a.l, b.l))*(cpfmax(a.t, b.t) - cpfmin(a.b, b.b));+}++/// Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn't hit.+static inline cpFloat cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b)+{+	cpVect delta = cpvsub(b, a);+	cpFloat tmin = -INFINITY, tmax = INFINITY;+	+	if(delta.x == 0.0f){+		if(a.x < bb.l || bb.r < a.x) return INFINITY;+	} else {+		cpFloat t1 = (bb.l - a.x)/delta.x;+		cpFloat t2 = (bb.r - a.x)/delta.x;+		tmin = cpfmax(tmin, cpfmin(t1, t2));+		tmax = cpfmin(tmax, cpfmax(t1, t2));+	}+	+	if(delta.y == 0.0f){+		if(a.y < bb.b || bb.t < a.y) return INFINITY;+	} else {+		cpFloat t1 = (bb.b - a.y)/delta.y;+		cpFloat t2 = (bb.t - a.y)/delta.y;+		tmin = cpfmax(tmin, cpfmin(t1, t2));+		tmax = cpfmin(tmax, cpfmax(t1, t2));+	}+	+	if(tmin <= tmax && 0.0f <= tmax && tmin <= 1.0f){+		return cpfmax(tmin, 0.0f);+	} else {+		return INFINITY;+	}+}++/// Return true if the bounding box intersects the line segment with ends @c a and @c b.+static inline cpBool cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b)+{+	return (cpBBSegmentQuery(bb, a, b) != INFINITY);+}++/// Clamp a vector to a bounding box.+static inline cpVect+cpBBClampVect(const cpBB bb, const cpVect v)+{+	return cpv(cpfclamp(v.x, bb.l, bb.r), cpfclamp(v.y, bb.b, bb.t));+}++/// Wrap a vector to a bounding box.+static inline cpVect+cpBBWrapVect(const cpBB bb, const cpVect v)+{+	cpFloat dx = cpfabs(bb.r - bb.l);+	cpFloat modx = cpfmod(v.x - bb.l, dx);+	cpFloat x = (modx > 0.0f) ? modx : modx + dx;+	+	cpFloat dy = cpfabs(bb.t - bb.b);+	cpFloat mody = cpfmod(v.y - bb.b, dy);+	cpFloat y = (mody > 0.0f) ? mody : mody + dy;+	+	return cpv(x + bb.l, y + bb.b);+}++/// Returns a bounding box offseted by @c v.+static inline cpBB+cpBBOffset(const cpBB bb, const cpVect v)+{+	return cpBBNew(+		bb.l + v.x,+		bb.b + v.y,+		bb.r + v.x,+		bb.t + v.y+	);+}++///@}++#endif
+ Chipmunk2D-7.0.2/include/chipmunk/cpBody.h view
@@ -0,0 +1,189 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpBody cpBody+/// Chipmunk's rigid body type. Rigid bodies hold the physical properties of an object like+/// it's mass, and position and velocity of it's center of gravity. They don't have an shape on their own.+/// They are given a shape by creating collision shapes (cpShape) that point to the body.+/// @{++typedef enum cpBodyType {+	/// A dynamic body is one that is affected by gravity, forces, and collisions.+	/// This is the default body type.+	CP_BODY_TYPE_DYNAMIC,+	/// A kinematic body is an infinite mass, user controlled body that is not affected by gravity, forces or collisions.+	/// Instead the body only moves based on it's velocity.+	/// Dynamic bodies collide normally with kinematic bodies, though the kinematic body will be unaffected.+	/// Collisions between two kinematic bodies, or a kinematic body and a static body produce collision callbacks, but no collision response.+	CP_BODY_TYPE_KINEMATIC,+	/// A static body is a body that never (or rarely) moves. If you move a static body, you must call one of the cpSpaceReindex*() functions.+	/// Chipmunk uses this information to optimize the collision detection.+	/// Static bodies do not produce collision callbacks when colliding with other static bodies.+	CP_BODY_TYPE_STATIC,+} cpBodyType;++/// Rigid body velocity update function type.+typedef void (*cpBodyVelocityFunc)(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);+/// Rigid body position update function type.+typedef void (*cpBodyPositionFunc)(cpBody *body, cpFloat dt);++/// Allocate a cpBody.+CP_EXPORT cpBody* cpBodyAlloc(void);+/// Initialize a cpBody.+CP_EXPORT cpBody* cpBodyInit(cpBody *body, cpFloat mass, cpFloat moment);+/// Allocate and initialize a cpBody.+CP_EXPORT cpBody* cpBodyNew(cpFloat mass, cpFloat moment);++/// Allocate and initialize a cpBody, and set it as a kinematic body.+CP_EXPORT cpBody* cpBodyNewKinematic(void);+/// Allocate and initialize a cpBody, and set it as a static body.+CP_EXPORT cpBody* cpBodyNewStatic(void);++/// Destroy a cpBody.+CP_EXPORT void cpBodyDestroy(cpBody *body);+/// Destroy and free a cpBody.+CP_EXPORT void cpBodyFree(cpBody *body);++// Defined in cpSpace.c+/// Wake up a sleeping or idle body.+CP_EXPORT void cpBodyActivate(cpBody *body);+/// Wake up any sleeping or idle bodies touching a static body.+CP_EXPORT void cpBodyActivateStatic(cpBody *body, cpShape *filter);++/// Force a body to fall asleep immediately.+CP_EXPORT void cpBodySleep(cpBody *body);+/// Force a body to fall asleep immediately along with other bodies in a group.+CP_EXPORT void cpBodySleepWithGroup(cpBody *body, cpBody *group);++/// Returns true if the body is sleeping.+CP_EXPORT cpBool cpBodyIsSleeping(const cpBody *body);++/// Get the type of the body.+CP_EXPORT cpBodyType cpBodyGetType(cpBody *body);+/// Set the type of the body.+CP_EXPORT void cpBodySetType(cpBody *body, cpBodyType type);++/// Get the space this body is added to.+CP_EXPORT cpSpace* cpBodyGetSpace(const cpBody *body);++/// Get the mass of the body.+CP_EXPORT cpFloat cpBodyGetMass(const cpBody *body);+/// Set the mass of the body.+CP_EXPORT void cpBodySetMass(cpBody *body, cpFloat m);++/// Get the moment of inertia of the body.+CP_EXPORT cpFloat cpBodyGetMoment(const cpBody *body);+/// Set the moment of inertia of the body.+CP_EXPORT void cpBodySetMoment(cpBody *body, cpFloat i);++/// Set the position of a body.+CP_EXPORT cpVect cpBodyGetPosition(const cpBody *body);+/// Set the position of the body.+CP_EXPORT void cpBodySetPosition(cpBody *body, cpVect pos);++/// Get the offset of the center of gravity in body local coordinates.+CP_EXPORT cpVect cpBodyGetCenterOfGravity(const cpBody *body);+/// Set the offset of the center of gravity in body local coordinates.+CP_EXPORT void cpBodySetCenterOfGravity(cpBody *body, cpVect cog);++/// Get the velocity of the body.+CP_EXPORT cpVect cpBodyGetVelocity(const cpBody *body);+/// Set the velocity of the body.+CP_EXPORT void cpBodySetVelocity(cpBody *body, cpVect velocity);++/// Get the force applied to the body for the next time step.+CP_EXPORT cpVect cpBodyGetForce(const cpBody *body);+/// Set the force applied to the body for the next time step.+CP_EXPORT void cpBodySetForce(cpBody *body, cpVect force);++/// Get the angle of the body.+CP_EXPORT cpFloat cpBodyGetAngle(const cpBody *body);+/// Set the angle of a body.+CP_EXPORT void cpBodySetAngle(cpBody *body, cpFloat a);++/// Get the angular velocity of the body.+CP_EXPORT cpFloat cpBodyGetAngularVelocity(const cpBody *body);+/// Set the angular velocity of the body.+CP_EXPORT void cpBodySetAngularVelocity(cpBody *body, cpFloat angularVelocity);++/// Get the torque applied to the body for the next time step.+CP_EXPORT cpFloat cpBodyGetTorque(const cpBody *body);+/// Set the torque applied to the body for the next time step.+CP_EXPORT void cpBodySetTorque(cpBody *body, cpFloat torque);++/// Get the rotation vector of the body. (The x basis vector of it's transform.)+CP_EXPORT cpVect cpBodyGetRotation(const cpBody *body);++/// Get the user data pointer assigned to the body.+CP_EXPORT cpDataPointer cpBodyGetUserData(const cpBody *body);+/// Set the user data pointer assigned to the body.+CP_EXPORT void cpBodySetUserData(cpBody *body, cpDataPointer userData);++/// Set the callback used to update a body's velocity.+CP_EXPORT void cpBodySetVelocityUpdateFunc(cpBody *body, cpBodyVelocityFunc velocityFunc);+/// Set the callback used to update a body's position.+/// NOTE: It's not generally recommended to override this unless you call the default position update function.+CP_EXPORT void cpBodySetPositionUpdateFunc(cpBody *body, cpBodyPositionFunc positionFunc);++/// Default velocity integration function..+CP_EXPORT void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);+/// Default position integration function.+CP_EXPORT void cpBodyUpdatePosition(cpBody *body, cpFloat dt);++/// Convert body relative/local coordinates to absolute/world coordinates.+CP_EXPORT cpVect cpBodyLocalToWorld(const cpBody *body, const cpVect point);+/// Convert body absolute/world coordinates to  relative/local coordinates.+CP_EXPORT cpVect cpBodyWorldToLocal(const cpBody *body, const cpVect point);++/// Apply a force to a body. Both the force and point are expressed in world coordinates.+CP_EXPORT void cpBodyApplyForceAtWorldPoint(cpBody *body, cpVect force, cpVect point);+/// Apply a force to a body. Both the force and point are expressed in body local coordinates.+CP_EXPORT void cpBodyApplyForceAtLocalPoint(cpBody *body, cpVect force, cpVect point);++/// Apply an impulse to a body. Both the impulse and point are expressed in world coordinates.+CP_EXPORT void cpBodyApplyImpulseAtWorldPoint(cpBody *body, cpVect impulse, cpVect point);+/// Apply an impulse to a body. Both the impulse and point are expressed in body local coordinates.+CP_EXPORT void cpBodyApplyImpulseAtLocalPoint(cpBody *body, cpVect impulse, cpVect point);++/// Get the velocity on a body (in world units) at a point on the body in world coordinates.+CP_EXPORT cpVect cpBodyGetVelocityAtWorldPoint(const cpBody *body, cpVect point);+/// Get the velocity on a body (in world units) at a point on the body in local coordinates.+CP_EXPORT cpVect cpBodyGetVelocityAtLocalPoint(const cpBody *body, cpVect point);++/// Get the amount of kinetic energy contained by the body.+CP_EXPORT cpFloat cpBodyKineticEnergy(const cpBody *body);++/// Body/shape iterator callback function type. +typedef void (*cpBodyShapeIteratorFunc)(cpBody *body, cpShape *shape, void *data);+/// Call @c func once for each shape attached to @c body and added to the space.+CP_EXPORT void cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data);++/// Body/constraint iterator callback function type. +typedef void (*cpBodyConstraintIteratorFunc)(cpBody *body, cpConstraint *constraint, void *data);+/// Call @c func once for each constraint attached to @c body and added to the space.+CP_EXPORT void cpBodyEachConstraint(cpBody *body, cpBodyConstraintIteratorFunc func, void *data);++/// Body/arbiter iterator callback function type. +typedef void (*cpBodyArbiterIteratorFunc)(cpBody *body, cpArbiter *arbiter, void *data);+/// Call @c func once for each arbiter that is currently active on the body.+CP_EXPORT void cpBodyEachArbiter(cpBody *body, cpBodyArbiterIteratorFunc func, void *data);++///@}
+ Chipmunk2D-7.0.2/include/chipmunk/cpConstraint.h view
@@ -0,0 +1,95 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpConstraint cpConstraint+/// @{++/// 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);++/// Destroy a constraint.+CP_EXPORT void cpConstraintDestroy(cpConstraint *constraint);+/// Destroy and free a constraint.+CP_EXPORT void cpConstraintFree(cpConstraint *constraint);++/// Get the cpSpace this constraint is added to.+CP_EXPORT cpSpace* cpConstraintGetSpace(const cpConstraint *constraint);++/// Get the first body the constraint is attached to.+CP_EXPORT cpBody* cpConstraintGetBodyA(const cpConstraint *constraint);++/// Get the second body the constraint is attached to.+CP_EXPORT cpBody* cpConstraintGetBodyB(const cpConstraint *constraint);++/// Get the maximum force that this constraint is allowed to use.+CP_EXPORT cpFloat cpConstraintGetMaxForce(const cpConstraint *constraint);+/// Set the maximum force that this constraint is allowed to use. (defaults to INFINITY)+CP_EXPORT void cpConstraintSetMaxForce(cpConstraint *constraint, cpFloat maxForce);++/// Get rate at which joint error is corrected.+CP_EXPORT cpFloat cpConstraintGetErrorBias(const cpConstraint *constraint);+/// Set rate at which joint error is corrected.+/// Defaults to pow(1.0 - 0.1, 60.0) meaning that it will+/// correct 10% of the error every 1/60th of a second.+CP_EXPORT void cpConstraintSetErrorBias(cpConstraint *constraint, cpFloat errorBias);++/// Get the maximum rate at which joint error is corrected.+CP_EXPORT cpFloat cpConstraintGetMaxBias(const cpConstraint *constraint);+/// Set the maximum rate at which joint error is corrected. (defaults to INFINITY)+CP_EXPORT void cpConstraintSetMaxBias(cpConstraint *constraint, cpFloat maxBias);++/// Get if the two bodies connected by the constraint are allowed to collide or not.+CP_EXPORT cpBool cpConstraintGetCollideBodies(const cpConstraint *constraint);+/// Set if the two bodies connected by the constraint are allowed to collide or not. (defaults to cpFalse)+CP_EXPORT void cpConstraintSetCollideBodies(cpConstraint *constraint, cpBool collideBodies);++/// Get the pre-solve function that is called before the solver runs.+CP_EXPORT cpConstraintPreSolveFunc cpConstraintGetPreSolveFunc(const cpConstraint *constraint);+/// Set the pre-solve function that is called before the solver runs.+CP_EXPORT void cpConstraintSetPreSolveFunc(cpConstraint *constraint, cpConstraintPreSolveFunc preSolveFunc);++/// Get the post-solve function that is called before the solver runs.+CP_EXPORT cpConstraintPostSolveFunc cpConstraintGetPostSolveFunc(const cpConstraint *constraint);+/// Set the post-solve function that is called before the solver runs.+CP_EXPORT void cpConstraintSetPostSolveFunc(cpConstraint *constraint, cpConstraintPostSolveFunc postSolveFunc);++/// Get the user definable data pointer for this constraint+CP_EXPORT cpDataPointer cpConstraintGetUserData(const cpConstraint *constraint);+/// Set the user definable data pointer for this constraint+CP_EXPORT void cpConstraintSetUserData(cpConstraint *constraint, cpDataPointer userData);++/// Get the last impulse applied by this constraint.+CP_EXPORT cpFloat cpConstraintGetImpulse(cpConstraint *constraint);++#include "cpPinJoint.h"+#include "cpSlideJoint.h"+#include "cpPivotJoint.h"+#include "cpGrooveJoint.h"+#include "cpDampedSpring.h"+#include "cpDampedRotarySpring.h"+#include "cpRotaryLimitJoint.h"+#include "cpRatchetJoint.h"+#include "cpGearJoint.h"+#include "cpSimpleMotor.h"++///@}
+ Chipmunk2D-7.0.2/include/chipmunk/cpDampedRotarySpring.h view
@@ -0,0 +1,58 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpDampedRotarySpring cpDampedRotarySpring+/// @{++/// Check if a constraint is a damped rotary springs.+CP_EXPORT cpBool cpConstraintIsDampedRotarySpring(const cpConstraint *constraint);++/// Function type used for damped rotary spring force callbacks.+typedef cpFloat (*cpDampedRotarySpringTorqueFunc)(struct cpConstraint *spring, cpFloat relativeAngle);++/// Allocate a damped rotary spring.+CP_EXPORT cpDampedRotarySpring* cpDampedRotarySpringAlloc(void);+/// Initialize a damped rotary spring.+CP_EXPORT cpDampedRotarySpring* cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);+/// Allocate and initialize a damped rotary spring.+CP_EXPORT cpConstraint* cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);++/// Get the rest length of the spring.+CP_EXPORT cpFloat cpDampedRotarySpringGetRestAngle(const cpConstraint *constraint);+/// Set the rest length of the spring.+CP_EXPORT void cpDampedRotarySpringSetRestAngle(cpConstraint *constraint, cpFloat restAngle);++/// Get the stiffness of the spring in force/distance.+CP_EXPORT cpFloat cpDampedRotarySpringGetStiffness(const cpConstraint *constraint);+/// Set the stiffness of the spring in force/distance.+CP_EXPORT void cpDampedRotarySpringSetStiffness(cpConstraint *constraint, cpFloat stiffness);++/// Get the damping of the spring.+CP_EXPORT cpFloat cpDampedRotarySpringGetDamping(const cpConstraint *constraint);+/// Set the damping of the spring.+CP_EXPORT void cpDampedRotarySpringSetDamping(cpConstraint *constraint, cpFloat damping);++/// Get the damping of the spring.+CP_EXPORT cpDampedRotarySpringTorqueFunc cpDampedRotarySpringGetSpringTorqueFunc(const cpConstraint *constraint);+/// Set the damping of the spring.+CP_EXPORT void cpDampedRotarySpringSetSpringTorqueFunc(cpConstraint *constraint, cpDampedRotarySpringTorqueFunc springTorqueFunc);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpDampedSpring.h view
@@ -0,0 +1,68 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpDampedSpring cpDampedSpring+/// @{++/// Check if a constraint is a slide joint.+CP_EXPORT cpBool cpConstraintIsDampedSpring(const cpConstraint *constraint);++/// Function type used for damped spring force callbacks.+typedef cpFloat (*cpDampedSpringForceFunc)(cpConstraint *spring, cpFloat dist);++/// Allocate a damped spring.+CP_EXPORT cpDampedSpring* cpDampedSpringAlloc(void);+/// Initialize a damped spring.+CP_EXPORT cpDampedSpring* cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat restLength, cpFloat stiffness, cpFloat damping);+/// Allocate and initialize a damped spring.+CP_EXPORT cpConstraint* cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat restLength, cpFloat stiffness, cpFloat damping);++/// Get the location of the first anchor relative to the first body.+CP_EXPORT cpVect cpDampedSpringGetAnchorA(const cpConstraint *constraint);+/// Set the location of the first anchor relative to the first body.+CP_EXPORT void cpDampedSpringSetAnchorA(cpConstraint *constraint, cpVect anchorA);++/// Get the location of the second anchor relative to the second body.+CP_EXPORT cpVect cpDampedSpringGetAnchorB(const cpConstraint *constraint);+/// Set the location of the second anchor relative to the second body.+CP_EXPORT void cpDampedSpringSetAnchorB(cpConstraint *constraint, cpVect anchorB);++/// Get the rest length of the spring.+CP_EXPORT cpFloat cpDampedSpringGetRestLength(const cpConstraint *constraint);+/// Set the rest length of the spring.+CP_EXPORT void cpDampedSpringSetRestLength(cpConstraint *constraint, cpFloat restLength);++/// Get the stiffness of the spring in force/distance.+CP_EXPORT cpFloat cpDampedSpringGetStiffness(const cpConstraint *constraint);+/// Set the stiffness of the spring in force/distance.+CP_EXPORT void cpDampedSpringSetStiffness(cpConstraint *constraint, cpFloat stiffness);++/// Get the damping of the spring.+CP_EXPORT cpFloat cpDampedSpringGetDamping(const cpConstraint *constraint);+/// Set the damping of the spring.+CP_EXPORT void cpDampedSpringSetDamping(cpConstraint *constraint, cpFloat damping);++/// Get the damping of the spring.+CP_EXPORT cpDampedSpringForceFunc cpDampedSpringGetSpringForceFunc(const cpConstraint *constraint);+/// Set the damping of the spring.+CP_EXPORT void cpDampedSpringSetSpringForceFunc(cpConstraint *constraint, cpDampedSpringForceFunc springForceFunc);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpGearJoint.h view
@@ -0,0 +1,45 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpGearJoint cpGearJoint+/// @{++/// Check if a constraint is a damped rotary springs.+CP_EXPORT cpBool cpConstraintIsGearJoint(const cpConstraint *constraint);++/// Allocate a gear joint.+CP_EXPORT cpGearJoint* cpGearJointAlloc(void);+/// Initialize a gear joint.+CP_EXPORT cpGearJoint* cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);+/// Allocate and initialize a gear joint.+CP_EXPORT cpConstraint* cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);++/// Get the phase offset of the gears.+CP_EXPORT cpFloat cpGearJointGetPhase(const cpConstraint *constraint);+/// Set the phase offset of the gears.+CP_EXPORT void cpGearJointSetPhase(cpConstraint *constraint, cpFloat phase);++/// Get the angular distance of each ratchet.+CP_EXPORT cpFloat cpGearJointGetRatio(const cpConstraint *constraint);+/// Set the ratio of a gear joint.+CP_EXPORT void cpGearJointSetRatio(cpConstraint *constraint, cpFloat ratio);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpGrooveJoint.h view
@@ -0,0 +1,50 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpGrooveJoint cpGrooveJoint+/// @{++/// Check if a constraint is a slide joint.+CP_EXPORT cpBool cpConstraintIsGrooveJoint(const cpConstraint *constraint);++/// Allocate a groove joint.+CP_EXPORT cpGrooveJoint* cpGrooveJointAlloc(void);+/// Initialize a groove joint.+CP_EXPORT cpGrooveJoint* cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchorB);+/// Allocate and initialize a groove joint.+CP_EXPORT cpConstraint* cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchorB);++/// Get the first endpoint of the groove relative to the first body.+CP_EXPORT cpVect cpGrooveJointGetGrooveA(const cpConstraint *constraint);+/// Set the first endpoint of the groove relative to the first body.+CP_EXPORT void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect grooveA);++/// Get the first endpoint of the groove relative to the first body.+CP_EXPORT cpVect cpGrooveJointGetGrooveB(const cpConstraint *constraint);+/// Set the first endpoint of the groove relative to the first body.+CP_EXPORT void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect grooveB);++/// Get the location of the second anchor relative to the second body.+CP_EXPORT cpVect cpGrooveJointGetAnchorB(const cpConstraint *constraint);+/// Set the location of the second anchor relative to the second body.+CP_EXPORT void cpGrooveJointSetAnchorB(cpConstraint *constraint, cpVect anchorB);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpHastySpace.h view
@@ -0,0 +1,27 @@+// Copyright 2013 Howling Moon Software. All rights reserved.+// See http://chipmunk2d.net/legal.php for more information.++/// cpHastySpace is exclusive to Chipmunk Pro+/// Currently it enables ARM NEON optimizations in the solver, but in the future will include other optimizations such as+/// a multi-threaded solver and multi-threaded collision broadphases.++struct cpHastySpace;+typedef struct cpHastySpace cpHastySpace;++/// Create a new hasty space.+/// On ARM platforms that support NEON, this will enable the vectorized solver.+/// cpHastySpace also supports multiple threads, but runs single threaded by default for determinism.+CP_EXPORT cpSpace *cpHastySpaceNew(void);+CP_EXPORT void cpHastySpaceFree(cpSpace *space);++/// Set the number of threads to use for the solver.+/// Currently Chipmunk is limited to 2 threads as using more generally provides very minimal performance gains.+/// Passing 0 as the thread count on iOS or OS X will cause Chipmunk to automatically detect the number of threads it should use.+/// On other platforms passing 0 for the thread count will set 1 thread.+CP_EXPORT void cpHastySpaceSetThreads(cpSpace *space, unsigned long threads);++/// Returns the number of threads the solver is using to run.+CP_EXPORT unsigned long cpHastySpaceGetThreads(cpSpace *space);++/// When stepping a hasty space, you must use this function.+CP_EXPORT void cpHastySpaceStep(cpSpace *space, cpFloat dt);
+ Chipmunk2D-7.0.2/include/chipmunk/cpMarch.h view
@@ -0,0 +1,28 @@+// Copyright 2013 Howling Moon Software. All rights reserved.+// See http://chipmunk2d.net/legal.php for more information.++/// Function type used as a callback from the marching squares algorithm to sample an image function.+/// It passes you the point to sample and your context pointer, and you return the density.+typedef cpFloat (*cpMarchSampleFunc)(cpVect point, void *data);++/// Function type used as a callback from the marching squares algorithm to output a line segment.+/// It passes you the two endpoints and your context pointer.+typedef void (*cpMarchSegmentFunc)(cpVect v0, cpVect v1, void *data);++/// Trace an anti-aliased contour of an image along a particular threshold.+/// The given number of samples will be taken and spread across the bounding box area using the sampling function and context.+/// The segment function will be called for each segment detected that lies along the density contour for @c threshold.+CP_EXPORT void cpMarchSoft(+  cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat threshold,+  cpMarchSegmentFunc segment, void *segment_data,+  cpMarchSampleFunc sample, void *sample_data+);++/// Trace an aliased curve of an image along a particular threshold.+/// The given number of samples will be taken and spread across the bounding box area using the sampling function and context.+/// The segment function will be called for each segment detected that lies along the density contour for @c threshold.+CP_EXPORT void cpMarchHard(+  cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat threshold,+  cpMarchSegmentFunc segment, void *segment_data,+  cpMarchSampleFunc sample, void *sample_data+);
+ Chipmunk2D-7.0.2/include/chipmunk/cpPinJoint.h view
@@ -0,0 +1,50 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpPinJoint cpPinJoint+/// @{++/// Check if a constraint is a pin joint.+CP_EXPORT cpBool cpConstraintIsPinJoint(const cpConstraint *constraint);++/// Allocate a pin joint.+CP_EXPORT cpPinJoint* cpPinJointAlloc(void);+/// Initialize a pin joint.+CP_EXPORT cpPinJoint* cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB);+/// Allocate and initialize a pin joint.+CP_EXPORT cpConstraint* cpPinJointNew(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB);++/// Get the location of the first anchor relative to the first body.+CP_EXPORT cpVect cpPinJointGetAnchorA(const cpConstraint *constraint);+/// Set the location of the first anchor relative to the first body.+CP_EXPORT void cpPinJointSetAnchorA(cpConstraint *constraint, cpVect anchorA);++/// Get the location of the second anchor relative to the second body.+CP_EXPORT cpVect cpPinJointGetAnchorB(const cpConstraint *constraint);+/// Set the location of the second anchor relative to the second body.+CP_EXPORT void cpPinJointSetAnchorB(cpConstraint *constraint, cpVect anchorB);++/// Get the distance the joint will maintain between the two anchors.+CP_EXPORT cpFloat cpPinJointGetDist(const cpConstraint *constraint);+/// Set the distance the joint will maintain between the two anchors.+CP_EXPORT void cpPinJointSetDist(cpConstraint *constraint, cpFloat dist);++///@}
+ Chipmunk2D-7.0.2/include/chipmunk/cpPivotJoint.h view
@@ -0,0 +1,47 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpPivotJoint cpPivotJoint+/// @{++/// Check if a constraint is a slide joint.+CP_EXPORT cpBool cpConstraintIsPivotJoint(const cpConstraint *constraint);++/// Allocate a pivot joint+CP_EXPORT cpPivotJoint* cpPivotJointAlloc(void);+/// Initialize a pivot joint.+CP_EXPORT cpPivotJoint* cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB);+/// Allocate and initialize a pivot joint.+CP_EXPORT cpConstraint* cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);+/// Allocate and initialize a pivot joint with specific anchors.+CP_EXPORT cpConstraint* cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB);++/// Get the location of the first anchor relative to the first body.+CP_EXPORT cpVect cpPivotJointGetAnchorA(const cpConstraint *constraint);+/// Set the location of the first anchor relative to the first body.+CP_EXPORT void cpPivotJointSetAnchorA(cpConstraint *constraint, cpVect anchorA);++/// Get the location of the second anchor relative to the second body.+CP_EXPORT cpVect cpPivotJointGetAnchorB(const cpConstraint *constraint);+/// Set the location of the second anchor relative to the second body.+CP_EXPORT void cpPivotJointSetAnchorB(cpConstraint *constraint, cpVect anchorB);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpPolyShape.h view
@@ -0,0 +1,56 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpPolyShape cpPolyShape+/// @{++/// Allocate a polygon shape.+CP_EXPORT cpPolyShape* cpPolyShapeAlloc(void);+/// Initialize a polygon shape with rounded corners.+/// A convex hull will be created from the vertexes.+CP_EXPORT cpPolyShape* cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int count, const cpVect *verts, cpTransform transform, cpFloat radius);+/// Initialize a polygon shape with rounded corners.+/// The vertexes must be convex with a counter-clockwise winding.+CP_EXPORT cpPolyShape* cpPolyShapeInitRaw(cpPolyShape *poly, cpBody *body, int count, const cpVect *verts, cpFloat radius);+/// Allocate and initialize a polygon shape with rounded corners.+/// A convex hull will be created from the vertexes.+CP_EXPORT cpShape* cpPolyShapeNew(cpBody *body, int count, const cpVect *verts, cpTransform transform, cpFloat radius);+/// Allocate and initialize a polygon shape with rounded corners.+/// The vertexes must be convex with a counter-clockwise winding.+CP_EXPORT cpShape* cpPolyShapeNewRaw(cpBody *body, int count, const cpVect *verts, cpFloat radius);++/// Initialize a box shaped polygon shape with rounded corners.+CP_EXPORT cpPolyShape* cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height, cpFloat radius);+/// Initialize an offset box shaped polygon shape with rounded corners.+CP_EXPORT cpPolyShape* cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box, cpFloat radius);+/// Allocate and initialize a box shaped polygon shape.+CP_EXPORT cpShape* cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height, cpFloat radius);+/// Allocate and initialize an offset box shaped polygon shape.+CP_EXPORT cpShape* cpBoxShapeNew2(cpBody *body, cpBB box, cpFloat radius);++/// Get the number of verts in a polygon shape.+CP_EXPORT int cpPolyShapeGetCount(const cpShape *shape);+/// Get the @c ith vertex of a polygon shape.+CP_EXPORT cpVect cpPolyShapeGetVert(const cpShape *shape, int index);+/// Get the radius of a polygon shape.+CP_EXPORT cpFloat cpPolyShapeGetRadius(const cpShape *shape);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpPolyline.h view
@@ -0,0 +1,70 @@+// Copyright 2013 Howling Moon Software. All rights reserved.+// See http://chipmunk2d.net/legal.php for more information.++// Polylines are just arrays of vertexes.+// They are looped if the first vertex is equal to the last.+// cpPolyline structs are intended to be passed by value and destroyed when you are done with them.+typedef struct cpPolyline {+  int count, capacity;+  cpVect verts[];+} cpPolyline;++/// Destroy and free a polyline instance.+CP_EXPORT void cpPolylineFree(cpPolyline *line);++/// Returns true if the first vertex is equal to the last.+CP_EXPORT cpBool cpPolylineIsClosed(cpPolyline *line);++/**+	Returns a copy of a polyline simplified by using the Douglas-Peucker algorithm.+	This works very well on smooth or gently curved shapes, but not well on straight edged or angular shapes.+*/+CP_EXPORT cpPolyline *cpPolylineSimplifyCurves(cpPolyline *line, cpFloat tol);++/**+	Returns a copy of a polyline simplified by discarding "flat" vertexes.+	This works well on straigt edged or angular shapes, not as well on smooth shapes.+*/+CP_EXPORT cpPolyline *cpPolylineSimplifyVertexes(cpPolyline *line, cpFloat tol);++/// Get the convex hull of a polyline as a looped polyline.+CP_EXPORT cpPolyline *cpPolylineToConvexHull(cpPolyline *line, cpFloat tol);+++/// Polyline sets are collections of polylines, generally built by cpMarchSoft() or cpMarchHard().+typedef struct cpPolylineSet {+  int count, capacity;+  cpPolyline **lines;+} cpPolylineSet;++/// Allocate a new polyline set.+CP_EXPORT cpPolylineSet *cpPolylineSetAlloc(void);++/// Initialize a new polyline set.+CP_EXPORT cpPolylineSet *cpPolylineSetInit(cpPolylineSet *set);++/// Allocate and initialize a polyline set.+CP_EXPORT cpPolylineSet *cpPolylineSetNew(void);++/// Destroy a polyline set.+CP_EXPORT void cpPolylineSetDestroy(cpPolylineSet *set, cpBool freePolylines);++/// Destroy and free a polyline set.+CP_EXPORT void cpPolylineSetFree(cpPolylineSet *set, cpBool freePolylines);++/**+	Add a line segment to a polyline set.+	A segment will either start a new polyline, join two others, or add to or loop an existing polyline.+	This is mostly intended to be used as a callback directly from cpMarchSoft() or cpMarchHard().+*/+CP_EXPORT void cpPolylineSetCollectSegment(cpVect v0, cpVect v1, cpPolylineSet *lines);++/**+	Get an approximate convex decomposition from a polyline.+	Returns a cpPolylineSet of convex hulls that match the original shape to within 'tol'.+	NOTE: If the input is a self intersecting polygon, the output might end up overly simplified.+*/++CP_EXPORT cpPolylineSet *cpPolylineConvexDecomposition(cpPolyline *line, cpFloat tol);++#define cpPolylineConvexDecomposition_BETA cpPolylineConvexDecomposition
+ Chipmunk2D-7.0.2/include/chipmunk/cpRatchetJoint.h view
@@ -0,0 +1,50 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpRatchetJoint cpRatchetJoint+/// @{++/// Check if a constraint is a damped rotary springs.+CP_EXPORT cpBool cpConstraintIsRatchetJoint(const cpConstraint *constraint);++/// Allocate a ratchet joint.+CP_EXPORT cpRatchetJoint* cpRatchetJointAlloc(void);+/// Initialize a ratched joint.+CP_EXPORT cpRatchetJoint* cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);+/// Allocate and initialize a ratchet joint.+CP_EXPORT cpConstraint* cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);++/// Get the angle of the current ratchet tooth.+CP_EXPORT cpFloat cpRatchetJointGetAngle(const cpConstraint *constraint);+/// Set the angle of the current ratchet tooth.+CP_EXPORT void cpRatchetJointSetAngle(cpConstraint *constraint, cpFloat angle);++/// Get the phase offset of the ratchet.+CP_EXPORT cpFloat cpRatchetJointGetPhase(const cpConstraint *constraint);+/// Get the phase offset of the ratchet.+CP_EXPORT void cpRatchetJointSetPhase(cpConstraint *constraint, cpFloat phase);++/// Get the angular distance of each ratchet.+CP_EXPORT cpFloat cpRatchetJointGetRatchet(const cpConstraint *constraint);+/// Set the angular distance of each ratchet.+CP_EXPORT void cpRatchetJointSetRatchet(cpConstraint *constraint, cpFloat ratchet);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpRobust.h view
@@ -0,0 +1,11 @@+#include "chipmunk/cpVect.h"++// This is a private header for functions (currently just one) that need strict floating point results.+// It was easier to put this in it's own file than to fiddle with 4 different compiler specific pragmas or attributes.+// "Fast math" should be disabled here.++// Check if c is to the left of segment (a, b).+cpBool cpCheckPointGreater(const cpVect a, const cpVect b, const cpVect c);++// Check if p is behind one of v0 or v1 on axis n.+cpBool cpCheckAxis(cpVect v0, cpVect v1, cpVect p, cpVect n);
+ Chipmunk2D-7.0.2/include/chipmunk/cpRotaryLimitJoint.h view
@@ -0,0 +1,45 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpRotaryLimitJoint cpRotaryLimitJoint+/// @{++/// Check if a constraint is a damped rotary springs.+CP_EXPORT cpBool cpConstraintIsRotaryLimitJoint(const cpConstraint *constraint);++/// Allocate a damped rotary limit joint.+CP_EXPORT cpRotaryLimitJoint* cpRotaryLimitJointAlloc(void);+/// Initialize a damped rotary limit joint.+CP_EXPORT cpRotaryLimitJoint* cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max);+/// Allocate and initialize a damped rotary limit joint.+CP_EXPORT cpConstraint* cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max);++/// Get the minimum distance the joint will maintain between the two anchors.+CP_EXPORT cpFloat cpRotaryLimitJointGetMin(const cpConstraint *constraint);+/// Set the minimum distance the joint will maintain between the two anchors.+CP_EXPORT void cpRotaryLimitJointSetMin(cpConstraint *constraint, cpFloat min);++/// Get the maximum distance the joint will maintain between the two anchors.+CP_EXPORT cpFloat cpRotaryLimitJointGetMax(const cpConstraint *constraint);+/// Set the maximum distance the joint will maintain between the two anchors.+CP_EXPORT void cpRotaryLimitJointSetMax(cpConstraint *constraint, cpFloat max);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpShape.h view
@@ -0,0 +1,199 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpShape cpShape+/// The cpShape struct defines the shape of a rigid body.+/// @{++/// Point query info struct.+typedef struct cpPointQueryInfo {+	/// The nearest shape, NULL if no shape was within range.+	const cpShape *shape;+	/// The closest point on the shape's surface. (in world space coordinates)+	cpVect point;+	/// The distance to the point. The distance is negative if the point is inside the shape.+	cpFloat distance;+	/// The gradient of the signed distance function.+	/// The value should be similar to info.p/info.d, but accurate even for very small values of info.d.+	cpVect gradient;+} cpPointQueryInfo;++/// Segment query info struct.+typedef struct cpSegmentQueryInfo {+	/// The shape that was hit, or NULL if no collision occured.+	const cpShape *shape;+	/// The point of impact.+	cpVect point;+	/// The normal of the surface hit.+	cpVect normal;+	/// The normalized distance along the query segment in the range [0, 1].+	cpFloat alpha;+} cpSegmentQueryInfo;++/// Fast collision filtering type that is used to determine if two objects collide before calling collision or query callbacks.+typedef struct cpShapeFilter {+	/// Two objects with the same non-zero group value do not collide.+	/// This is generally used to group objects in a composite object together to disable self collisions.+	cpGroup group;+	/// A bitmask of user definable categories that this object belongs to.+	/// The category/mask combinations of both objects in a collision must agree for a collision to occur.+	cpBitmask categories;+	/// A bitmask of user definable category types that this object object collides with.+	/// The category/mask combinations of both objects in a collision must agree for a collision to occur.+	cpBitmask mask;+} cpShapeFilter;++/// Collision filter value for a shape that will collide with anything except CP_SHAPE_FILTER_NONE.+static const cpShapeFilter CP_SHAPE_FILTER_ALL = {CP_NO_GROUP, CP_ALL_CATEGORIES, CP_ALL_CATEGORIES};+/// Collision filter value for a shape that does not collide with anything.+static const cpShapeFilter CP_SHAPE_FILTER_NONE = {CP_NO_GROUP, ~CP_ALL_CATEGORIES, ~CP_ALL_CATEGORIES};++/// Create a new collision filter.+static inline cpShapeFilter+cpShapeFilterNew(cpGroup group, cpBitmask categories, cpBitmask mask)+{+	cpShapeFilter filter = {group, categories, mask};+	return filter;+}++/// Destroy a shape.+CP_EXPORT void cpShapeDestroy(cpShape *shape);+/// Destroy and Free a shape.+CP_EXPORT void cpShapeFree(cpShape *shape);++/// Update, cache and return the bounding box of a shape based on the body it's attached to.+CP_EXPORT cpBB cpShapeCacheBB(cpShape *shape);+/// Update, cache and return the bounding box of a shape with an explicit transformation.+CP_EXPORT cpBB cpShapeUpdate(cpShape *shape, cpTransform transform);++/// 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.+CP_EXPORT cpFloat cpShapePointQuery(const cpShape *shape, cpVect p, cpPointQueryInfo *out);++/// Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure.+CP_EXPORT cpBool cpShapeSegmentQuery(const cpShape *shape, cpVect a, cpVect b, cpFloat radius, cpSegmentQueryInfo *info);++/// Return contact information about two shapes.+CP_EXPORT cpContactPointSet cpShapesCollide(const cpShape *a, const cpShape *b);++/// The cpSpace this body is added to.+CP_EXPORT cpSpace* cpShapeGetSpace(const cpShape *shape);++/// The cpBody this shape is connected to.+CP_EXPORT cpBody* cpShapeGetBody(const cpShape *shape);+/// Set the cpBody this shape is connected to.+/// Can only be used if the shape is not currently added to a space.+CP_EXPORT void cpShapeSetBody(cpShape *shape, cpBody *body);++/// Get the mass of the shape if you are having Chipmunk calculate mass properties for you.+CP_EXPORT cpFloat cpShapeGetMass(cpShape *shape);+/// Set the mass of this shape to have Chipmunk calculate mass properties for you.+CP_EXPORT void cpShapeSetMass(cpShape *shape, cpFloat mass);++/// Get the density of the shape if you are having Chipmunk calculate mass properties for you.+CP_EXPORT cpFloat cpShapeGetDensity(cpShape *shape);+/// Set the density  of this shape to have Chipmunk calculate mass properties for you.+CP_EXPORT void cpShapeSetDensity(cpShape *shape, cpFloat density);++/// Get the calculated moment of inertia for this shape.+CP_EXPORT cpFloat cpShapeGetMoment(cpShape *shape);+/// Get the calculated area of this shape.+CP_EXPORT cpFloat cpShapeGetArea(cpShape *shape);+/// Get the centroid of this shape.+CP_EXPORT cpVect cpShapeGetCenterOfGravity(cpShape *shape);++/// Get the bounding box that contains the shape given it's current position and angle.+CP_EXPORT cpBB cpShapeGetBB(const cpShape *shape);++/// Get if the shape is set to be a sensor or not.+CP_EXPORT cpBool cpShapeGetSensor(const cpShape *shape);+/// Set if the shape is a sensor or not.+CP_EXPORT void cpShapeSetSensor(cpShape *shape, cpBool sensor);++/// Get the elasticity of this shape.+CP_EXPORT cpFloat cpShapeGetElasticity(const cpShape *shape);+/// Set the elasticity of this shape.+CP_EXPORT void cpShapeSetElasticity(cpShape *shape, cpFloat elasticity);++/// Get the friction of this shape.+CP_EXPORT cpFloat cpShapeGetFriction(const cpShape *shape);+/// Set the friction of this shape.+CP_EXPORT void cpShapeSetFriction(cpShape *shape, cpFloat friction);++/// Get the surface velocity of this shape.+CP_EXPORT cpVect cpShapeGetSurfaceVelocity(const cpShape *shape);+/// Set the surface velocity of this shape.+CP_EXPORT void cpShapeSetSurfaceVelocity(cpShape *shape, cpVect surfaceVelocity);++/// Get the user definable data pointer of this shape.+CP_EXPORT cpDataPointer cpShapeGetUserData(const cpShape *shape);+/// Set the user definable data pointer of this shape.+CP_EXPORT void cpShapeSetUserData(cpShape *shape, cpDataPointer userData);++/// Set the collision type of this shape.+CP_EXPORT cpCollisionType cpShapeGetCollisionType(const cpShape *shape);+/// Get the collision type of this shape.+CP_EXPORT void cpShapeSetCollisionType(cpShape *shape, cpCollisionType collisionType);++/// Get the collision filtering parameters of this shape.+CP_EXPORT cpShapeFilter cpShapeGetFilter(const cpShape *shape);+/// Set the collision filtering parameters of this shape.+CP_EXPORT void cpShapeSetFilter(cpShape *shape, cpShapeFilter filter);+++/// @}+/// @defgroup cpCircleShape cpCircleShape++/// Allocate a circle shape.+CP_EXPORT cpCircleShape* cpCircleShapeAlloc(void);+/// Initialize a circle shape.+CP_EXPORT cpCircleShape* cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);+/// Allocate and initialize a circle shape.+CP_EXPORT cpShape* cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);++/// Get the offset of a circle shape.+CP_EXPORT cpVect cpCircleShapeGetOffset(const cpShape *shape);+/// Get the radius of a circle shape.+CP_EXPORT cpFloat cpCircleShapeGetRadius(const cpShape *shape);++/// @}+/// @defgroup cpSegmentShape cpSegmentShape++/// Allocate a segment shape.+CP_EXPORT cpSegmentShape* cpSegmentShapeAlloc(void);+/// Initialize a segment shape.+CP_EXPORT cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius);+/// Allocate and initialize a segment shape.+CP_EXPORT cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius);++/// Let Chipmunk know about the geometry of adjacent segments to avoid colliding with endcaps.+CP_EXPORT void cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next);++/// Get the first endpoint of a segment shape.+CP_EXPORT cpVect cpSegmentShapeGetA(const cpShape *shape);+/// Get the second endpoint of a segment shape.+CP_EXPORT cpVect cpSegmentShapeGetB(const cpShape *shape);+/// Get the normal of a segment shape.+CP_EXPORT cpVect cpSegmentShapeGetNormal(const cpShape *shape);+/// Get the first endpoint of a segment shape.+CP_EXPORT cpFloat cpSegmentShapeGetRadius(const cpShape *shape);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpSimpleMotor.h view
@@ -0,0 +1,43 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpSimpleMotor cpSimpleMotor+/// @{++/// Opaque struct type for damped rotary springs.+typedef struct cpSimpleMotor cpSimpleMotor;++/// Check if a constraint is a damped rotary springs.+CP_EXPORT cpBool cpConstraintIsSimpleMotor(const cpConstraint *constraint);++/// Allocate a simple motor.+CP_EXPORT cpSimpleMotor* cpSimpleMotorAlloc(void);+/// initialize a simple motor.+CP_EXPORT cpSimpleMotor* cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);+/// Allocate and initialize a simple motor.+CP_EXPORT cpConstraint* cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);++/// Get the rate of the motor.+CP_EXPORT cpFloat cpSimpleMotorGetRate(const cpConstraint *constraint);+/// Set the rate of the motor.+CP_EXPORT void cpSimpleMotorSetRate(cpConstraint *constraint, cpFloat rate);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpSlideJoint.h view
@@ -0,0 +1,55 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpSlideJoint cpSlideJoint+/// @{++/// Check if a constraint is a slide joint.+CP_EXPORT cpBool cpConstraintIsSlideJoint(const cpConstraint *constraint);++/// Allocate a slide joint.+CP_EXPORT cpSlideJoint* cpSlideJointAlloc(void);+/// Initialize a slide joint.+CP_EXPORT cpSlideJoint* cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat min, cpFloat max);+/// Allocate and initialize a slide joint.+CP_EXPORT cpConstraint* cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat min, cpFloat max);++/// Get the location of the first anchor relative to the first body.+CP_EXPORT cpVect cpSlideJointGetAnchorA(const cpConstraint *constraint);+/// Set the location of the first anchor relative to the first body.+CP_EXPORT void cpSlideJointSetAnchorA(cpConstraint *constraint, cpVect anchorA);++/// Get the location of the second anchor relative to the second body.+CP_EXPORT cpVect cpSlideJointGetAnchorB(const cpConstraint *constraint);+/// Set the location of the second anchor relative to the second body.+CP_EXPORT void cpSlideJointSetAnchorB(cpConstraint *constraint, cpVect anchorB);++/// Get the minimum distance the joint will maintain between the two anchors.+CP_EXPORT cpFloat cpSlideJointGetMin(const cpConstraint *constraint);+/// Set the minimum distance the joint will maintain between the two anchors.+CP_EXPORT void cpSlideJointSetMin(cpConstraint *constraint, cpFloat min);++/// Get the maximum distance the joint will maintain between the two anchors.+CP_EXPORT cpFloat cpSlideJointGetMax(const cpConstraint *constraint);+/// Set the maximum distance the joint will maintain between the two anchors.+CP_EXPORT void cpSlideJointSetMax(cpConstraint *constraint, cpFloat max);++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpSpace.h view
@@ -0,0 +1,319 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/// @defgroup cpSpace cpSpace+/// @{++//MARK: Definitions++/// Collision begin event function callback type.+/// Returning false from a begin callback causes the collision to be ignored until+/// the the separate callback is called when the objects stop colliding.+typedef cpBool (*cpCollisionBeginFunc)(cpArbiter *arb, cpSpace *space, cpDataPointer userData);+/// Collision pre-solve event function callback type.+/// Returning false from a pre-step callback causes the collision to be ignored until the next step.+typedef cpBool (*cpCollisionPreSolveFunc)(cpArbiter *arb, cpSpace *space, cpDataPointer userData);+/// Collision post-solve event function callback type.+typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, cpSpace *space, cpDataPointer userData);+/// Collision separate event function callback type.+typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, cpSpace *space, cpDataPointer userData);++/// Struct that holds function callback pointers to configure custom collision handling.+/// Collision handlers have a pair of types; when a collision occurs between two shapes that have these types, the collision handler functions are triggered.+struct cpCollisionHandler {+	/// Collision type identifier of the first shape that this handler recognizes.+	/// In the collision handler callback, the shape with this type will be the first argument. Read only.+	const cpCollisionType typeA;+	/// Collision type identifier of the second shape that this handler recognizes.+	/// In the collision handler callback, the shape with this type will be the second argument. Read only.+	const cpCollisionType typeB;+	/// This function is called when two shapes with types that match this collision handler begin colliding.+	cpCollisionBeginFunc beginFunc;+	/// This function is called each step when two shapes with types that match this collision handler are colliding.+	/// It's called before the collision solver runs so that you can affect a collision's outcome.+	cpCollisionPreSolveFunc preSolveFunc;+	/// This function is called each step when two shapes with types that match this collision handler are colliding.+	/// It's called after the collision solver runs so that you can read back information about the collision to trigger events in your game.+	cpCollisionPostSolveFunc postSolveFunc;+	/// This function is called when two shapes with types that match this collision handler stop colliding.+	cpCollisionSeparateFunc separateFunc;+	/// This is a user definable context pointer that is passed to all of the collision handler functions.+	cpDataPointer userData;+};++// TODO: Make timestep a parameter?+++//MARK: Memory and Initialization++/// Allocate a cpSpace.+CP_EXPORT cpSpace* cpSpaceAlloc(void);+/// Initialize a cpSpace.+CP_EXPORT cpSpace* cpSpaceInit(cpSpace *space);+/// Allocate and initialize a cpSpace.+CP_EXPORT cpSpace* cpSpaceNew(void);++/// Destroy a cpSpace.+CP_EXPORT void cpSpaceDestroy(cpSpace *space);+/// Destroy and free a cpSpace.+CP_EXPORT void cpSpaceFree(cpSpace *space);+++//MARK: Properties++/// Number of iterations to use in the impulse solver to solve contacts and other constraints.+CP_EXPORT int cpSpaceGetIterations(const cpSpace *space);+CP_EXPORT void cpSpaceSetIterations(cpSpace *space, int iterations);++/// Gravity to pass to rigid bodies when integrating velocity.+CP_EXPORT cpVect cpSpaceGetGravity(const cpSpace *space);+CP_EXPORT void cpSpaceSetGravity(cpSpace *space, cpVect gravity);++/// Damping rate expressed as the fraction of velocity bodies retain each second.+/// A value of 0.9 would mean that each body's velocity will drop 10% per second.+/// The default value is 1.0, meaning no damping is applied.+/// @note This damping value is different than those of cpDampedSpring and cpDampedRotarySpring.+CP_EXPORT cpFloat cpSpaceGetDamping(const cpSpace *space);+CP_EXPORT void cpSpaceSetDamping(cpSpace *space, cpFloat damping);++/// Speed threshold for a body to be considered idle.+/// The default value of 0 means to let the space guess a good threshold based on gravity.+CP_EXPORT cpFloat cpSpaceGetIdleSpeedThreshold(const cpSpace *space);+CP_EXPORT void cpSpaceSetIdleSpeedThreshold(cpSpace *space, cpFloat idleSpeedThreshold);++/// Time a group of bodies must remain idle in order to fall asleep.+/// Enabling sleeping also implicitly enables the the contact graph.+/// The default value of INFINITY disables the sleeping algorithm.+CP_EXPORT cpFloat cpSpaceGetSleepTimeThreshold(const cpSpace *space);+CP_EXPORT void cpSpaceSetSleepTimeThreshold(cpSpace *space, cpFloat sleepTimeThreshold);++/// Amount of encouraged penetration between colliding shapes.+/// Used to reduce oscillating contacts and keep the collision cache warm.+/// Defaults to 0.1. If you have poor simulation quality,+/// increase this number as much as possible without allowing visible amounts of overlap.+CP_EXPORT cpFloat cpSpaceGetCollisionSlop(const cpSpace *space);+CP_EXPORT void cpSpaceSetCollisionSlop(cpSpace *space, cpFloat collisionSlop);++/// Determines how fast overlapping shapes are pushed apart.+/// Expressed as a fraction of the error remaining after each second.+/// Defaults to pow(1.0 - 0.1, 60.0) meaning that Chipmunk fixes 10% of overlap each frame at 60Hz.+CP_EXPORT cpFloat cpSpaceGetCollisionBias(const cpSpace *space);+CP_EXPORT void cpSpaceSetCollisionBias(cpSpace *space, cpFloat collisionBias);++/// Number of frames that contact information should persist.+/// Defaults to 3. There is probably never a reason to change this value.+CP_EXPORT cpTimestamp cpSpaceGetCollisionPersistence(const cpSpace *space);+CP_EXPORT void cpSpaceSetCollisionPersistence(cpSpace *space, cpTimestamp collisionPersistence);++/// User definable data pointer.+/// Generally this points to your game's controller or game state+/// class so you can access it when given a cpSpace reference in a callback.+CP_EXPORT cpDataPointer cpSpaceGetUserData(const cpSpace *space);+CP_EXPORT void cpSpaceSetUserData(cpSpace *space, cpDataPointer userData);++/// The Space provided static body for a given cpSpace.+/// This is merely provided for convenience and you are not required to use it.+CP_EXPORT cpBody* cpSpaceGetStaticBody(const cpSpace *space);++/// Returns the current (or most recent) time step used with the given space.+/// Useful from callbacks if your time step is not a compile-time global.+CP_EXPORT cpFloat cpSpaceGetCurrentTimeStep(const cpSpace *space);++/// returns true from inside a callback when objects cannot be added/removed.+CP_EXPORT cpBool cpSpaceIsLocked(cpSpace *space);+++//MARK: Collision Handlers++/// Create or return the existing collision handler that is called for all collisions that are not handled by a more specific collision handler.+CP_EXPORT cpCollisionHandler *cpSpaceAddDefaultCollisionHandler(cpSpace *space);+/// Create or return the existing collision handler for the specified pair of collision types.+/// If wildcard handlers are used with either of the collision types, it's the responibility of the custom handler to invoke the wildcard handlers.+CP_EXPORT cpCollisionHandler *cpSpaceAddCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b);+/// Create or return the existing wildcard collision handler for the specified type.+CP_EXPORT cpCollisionHandler *cpSpaceAddWildcardHandler(cpSpace *space, cpCollisionType type);+++//MARK: Add/Remove objects++/// Add a collision shape to the simulation.+/// If the shape is attached to a static body, it will be added as a static shape.+CP_EXPORT cpShape* cpSpaceAddShape(cpSpace *space, cpShape *shape);+/// Add a rigid body to the simulation.+CP_EXPORT cpBody* cpSpaceAddBody(cpSpace *space, cpBody *body);+/// Add a constraint to the simulation.+CP_EXPORT cpConstraint* cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);++/// Remove a collision shape from the simulation.+CP_EXPORT void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);+/// Remove a rigid body from the simulation.+CP_EXPORT void cpSpaceRemoveBody(cpSpace *space, cpBody *body);+/// Remove a constraint from the simulation.+CP_EXPORT void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint);++/// Test if a collision shape has been added to the space.+CP_EXPORT cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape);+/// Test if a rigid body has been added to the space.+CP_EXPORT cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body);+/// Test if a constraint has been added to the space.+CP_EXPORT cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint);++//MARK: Post-Step Callbacks++/// Post Step callback function type.+typedef void (*cpPostStepFunc)(cpSpace *space, void *key, void *data);+/// Schedule a post-step callback to be called when cpSpaceStep() finishes.+/// You can only register one callback per unique value for @c key.+/// Returns true only if @c key has never been scheduled before.+/// It's possible to pass @c NULL for @c func if you only want to mark @c key as being used.+CP_EXPORT cpBool cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *key, void *data);+++//MARK: Queries++// TODO: Queries and iterators should take a cpSpace parametery.+// TODO: They should also be abortable.++/// Nearest point query callback function type.+typedef void (*cpSpacePointQueryFunc)(cpShape *shape, cpVect point, cpFloat distance, cpVect gradient, void *data);+/// Query the space at a point and call @c func for each shape found.+CP_EXPORT void cpSpacePointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpSpacePointQueryFunc func, void *data);+/// Query the space at a point and return the nearest shape found. Returns NULL if no shapes were found.+CP_EXPORT cpShape *cpSpacePointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpPointQueryInfo *out);++/// Segment query callback function type.+typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpVect point, cpVect normal, cpFloat alpha, void *data);+/// Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.+CP_EXPORT void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSpaceSegmentQueryFunc func, void *data);+/// Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.+CP_EXPORT cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSegmentQueryInfo *out);++/// Rectangle Query callback function type.+typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data);+/// Perform a fast rectangle query on the space calling @c func for each shape found.+/// Only the shape's bounding boxes are checked for overlap, not their full shape.+CP_EXPORT void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpShapeFilter filter, cpSpaceBBQueryFunc func, void *data);++/// Shape query callback function type.+typedef void (*cpSpaceShapeQueryFunc)(cpShape *shape, cpContactPointSet *points, void *data);+/// Query a space for any shapes overlapping the given shape and call @c func for each shape found.+CP_EXPORT cpBool cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data);+++//MARK: Iteration++/// Space/body iterator callback function type.+typedef void (*cpSpaceBodyIteratorFunc)(cpBody *body, void *data);+/// Call @c func for each body in the space.+CP_EXPORT void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data);++/// Space/body iterator callback function type.+typedef void (*cpSpaceShapeIteratorFunc)(cpShape *shape, void *data);+/// Call @c func for each shape in the space.+CP_EXPORT void cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data);++/// Space/constraint iterator callback function type.+typedef void (*cpSpaceConstraintIteratorFunc)(cpConstraint *constraint, void *data);+/// Call @c func for each shape in the space.+CP_EXPORT void cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data);+++//MARK: Indexing++/// Update the collision detection info for the static shapes in the space.+CP_EXPORT void cpSpaceReindexStatic(cpSpace *space);+/// Update the collision detection data for a specific shape in the space.+CP_EXPORT void cpSpaceReindexShape(cpSpace *space, cpShape *shape);+/// Update the collision detection data for all shapes attached to a body.+CP_EXPORT void cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body);++/// Switch the space to use a spatial has as it's spatial index.+CP_EXPORT void cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count);+++//MARK: Time Stepping++/// Step the space forward in time by @c dt.+CP_EXPORT void cpSpaceStep(cpSpace *space, cpFloat dt);+++//MARK: Debug API++#ifndef CP_SPACE_DISABLE_DEBUG_API++/// Color type to use with the space debug drawing API.+typedef struct cpSpaceDebugColor {+	float r, g, b, a;+} cpSpaceDebugColor;++/// Callback type for a function that draws a filled, stroked circle.+typedef void (*cpSpaceDebugDrawCircleImpl)(cpVect pos, cpFloat angle, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor, cpDataPointer data);+/// Callback type for a function that draws a line segment.+typedef void (*cpSpaceDebugDrawSegmentImpl)(cpVect a, cpVect b, cpSpaceDebugColor color, cpDataPointer data);+/// Callback type for a function that draws a thick line segment.+typedef void (*cpSpaceDebugDrawFatSegmentImpl)(cpVect a, cpVect b, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor, cpDataPointer data);+/// Callback type for a function that draws a convex polygon.+typedef void (*cpSpaceDebugDrawPolygonImpl)(int count, const cpVect *verts, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor, cpDataPointer data);+/// Callback type for a function that draws a dot.+typedef void (*cpSpaceDebugDrawDotImpl)(cpFloat size, cpVect pos, cpSpaceDebugColor color, cpDataPointer data);+/// Callback type for a function that returns a color for a given shape. This gives you an opportunity to color shapes based on how they are used in your engine.+typedef cpSpaceDebugColor (*cpSpaceDebugDrawColorForShapeImpl)(cpShape *shape, cpDataPointer data);++typedef enum cpSpaceDebugDrawFlags {+	CP_SPACE_DEBUG_DRAW_SHAPES = 1<<0,+	CP_SPACE_DEBUG_DRAW_CONSTRAINTS = 1<<1,+	CP_SPACE_DEBUG_DRAW_COLLISION_POINTS = 1<<2,+} cpSpaceDebugDrawFlags;++/// Struct used with cpSpaceDebugDraw() containing drawing callbacks and other drawing settings.+typedef struct cpSpaceDebugDrawOptions {+	/// Function that will be invoked to draw circles.+	cpSpaceDebugDrawCircleImpl drawCircle;+	/// Function that will be invoked to draw line segments.+	cpSpaceDebugDrawSegmentImpl drawSegment;+	/// Function that will be invoked to draw thick line segments.+	cpSpaceDebugDrawFatSegmentImpl drawFatSegment;+	/// Function that will be invoked to draw convex polygons.+	cpSpaceDebugDrawPolygonImpl drawPolygon;+	/// Function that will be invoked to draw dots.+	cpSpaceDebugDrawDotImpl drawDot;+	+	/// Flags that request which things to draw (collision shapes, constraints, contact points).+	cpSpaceDebugDrawFlags flags;+	/// Outline color passed to the drawing function.+	cpSpaceDebugColor shapeOutlineColor;+	/// Function that decides what fill color to draw shapes using.+	cpSpaceDebugDrawColorForShapeImpl colorForShape;+	/// Color passed to drawing functions for constraints.+	cpSpaceDebugColor constraintColor;+	/// Color passed to drawing functions for collision points.+	cpSpaceDebugColor collisionPointColor;+	+	/// User defined context pointer passed to all of the callback functions as the 'data' argument.+	cpDataPointer data;+} cpSpaceDebugDrawOptions;++/// Debug draw the current state of the space using the supplied drawing options.+CP_EXPORT void cpSpaceDebugDraw(cpSpace *space, cpSpaceDebugDrawOptions *options);++#endif++/// @}
+ Chipmunk2D-7.0.2/include/chipmunk/cpSpatialIndex.h view
@@ -0,0 +1,227 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++/**+	@defgroup cpSpatialIndex cpSpatialIndex+	+	Spatial indexes are data structures that are used to accelerate collision detection+	and spatial queries. Chipmunk provides a number of spatial index algorithms to pick from+	and they are programmed in a generic way so that you can use them for holding more than+	just cpShape structs.+	+	It works by using @c void pointers to the objects you add and using a callback to ask your code+	for bounding boxes when it needs them. Several types of queries can be performed an index as well+	as reindexing and full collision information. All communication to the spatial indexes is performed+	through callback functions.+	+	Spatial indexes should be treated as opaque structs.+	This meanns you shouldn't be reading any of the struct fields.+	@{+*/++//MARK: Spatial Index++/// Spatial index bounding box callback function type.+/// The spatial index calls this function and passes you a pointer to an object you added+/// when it needs to get the bounding box associated with that object.+typedef cpBB (*cpSpatialIndexBBFunc)(void *obj);+/// Spatial index/object iterator callback function type.+typedef void (*cpSpatialIndexIteratorFunc)(void *obj, void *data);+/// Spatial query callback function type.+typedef cpCollisionID (*cpSpatialIndexQueryFunc)(void *obj1, void *obj2, cpCollisionID id, void *data);+/// Spatial segment query callback function type.+typedef cpFloat (*cpSpatialIndexSegmentQueryFunc)(void *obj1, void *obj2, void *data);+++typedef struct cpSpatialIndexClass cpSpatialIndexClass;+typedef struct cpSpatialIndex cpSpatialIndex;++/// @private+struct cpSpatialIndex {+	cpSpatialIndexClass *klass;+	+	cpSpatialIndexBBFunc bbfunc;+	+	cpSpatialIndex *staticIndex, *dynamicIndex;+};+++//MARK: Spatial Hash++typedef struct cpSpaceHash cpSpaceHash;++/// Allocate a spatial hash.+CP_EXPORT cpSpaceHash* cpSpaceHashAlloc(void);+/// Initialize a spatial hash. +CP_EXPORT cpSpatialIndex* cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);+/// Allocate and initialize a spatial hash.+CP_EXPORT cpSpatialIndex* cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);++/// Change the cell dimensions and table size of the spatial hash to tune it.+/// The cell dimensions should roughly match the average size of your objects+/// and the table size should be ~10 larger than the number of objects inserted.+/// Some trial and error is required to find the optimum numbers for efficiency.+CP_EXPORT void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);++//MARK: AABB Tree++typedef struct cpBBTree cpBBTree;++/// Allocate a bounding box tree.+CP_EXPORT cpBBTree* cpBBTreeAlloc(void);+/// Initialize a bounding box tree.+CP_EXPORT cpSpatialIndex* cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);+/// Allocate and initialize a bounding box tree.+CP_EXPORT cpSpatialIndex* cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);++/// Perform a static top down optimization of the tree.+CP_EXPORT void cpBBTreeOptimize(cpSpatialIndex *index);++/// Bounding box tree velocity callback function.+/// This function should return an estimate for the object's velocity.+typedef cpVect (*cpBBTreeVelocityFunc)(void *obj);+/// Set the velocity function for the bounding box tree to enable temporal coherence.+CP_EXPORT void cpBBTreeSetVelocityFunc(cpSpatialIndex *index, cpBBTreeVelocityFunc func);++//MARK: Single Axis Sweep++typedef struct cpSweep1D cpSweep1D;++/// Allocate a 1D sort and sweep broadphase.+CP_EXPORT cpSweep1D* cpSweep1DAlloc(void);+/// Initialize a 1D sort and sweep broadphase.+CP_EXPORT cpSpatialIndex* cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);+/// Allocate and initialize a 1D sort and sweep broadphase.+CP_EXPORT cpSpatialIndex* cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex);++//MARK: Spatial Index Implementation++typedef void (*cpSpatialIndexDestroyImpl)(cpSpatialIndex *index);++typedef int (*cpSpatialIndexCountImpl)(cpSpatialIndex *index);+typedef void (*cpSpatialIndexEachImpl)(cpSpatialIndex *index, cpSpatialIndexIteratorFunc func, void *data);++typedef cpBool (*cpSpatialIndexContainsImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);+typedef void (*cpSpatialIndexInsertImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);+typedef void (*cpSpatialIndexRemoveImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);++typedef void (*cpSpatialIndexReindexImpl)(cpSpatialIndex *index);+typedef void (*cpSpatialIndexReindexObjectImpl)(cpSpatialIndex *index, void *obj, cpHashValue hashid);+typedef void (*cpSpatialIndexReindexQueryImpl)(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data);++typedef void (*cpSpatialIndexQueryImpl)(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data);+typedef void (*cpSpatialIndexSegmentQueryImpl)(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data);++struct cpSpatialIndexClass {+	cpSpatialIndexDestroyImpl destroy;+	+	cpSpatialIndexCountImpl count;+	cpSpatialIndexEachImpl each;+	+	cpSpatialIndexContainsImpl contains;+	cpSpatialIndexInsertImpl insert;+	cpSpatialIndexRemoveImpl remove;+	+	cpSpatialIndexReindexImpl reindex;+	cpSpatialIndexReindexObjectImpl reindexObject;+	cpSpatialIndexReindexQueryImpl reindexQuery;+	+	cpSpatialIndexQueryImpl query;+	cpSpatialIndexSegmentQueryImpl segmentQuery;+};++/// Destroy and free a spatial index.+CP_EXPORT void cpSpatialIndexFree(cpSpatialIndex *index);+/// Collide the objects in @c dynamicIndex against the objects in @c staticIndex using the query callback function.+CP_EXPORT void cpSpatialIndexCollideStatic(cpSpatialIndex *dynamicIndex, cpSpatialIndex *staticIndex, cpSpatialIndexQueryFunc func, void *data);++/// Destroy a spatial index.+static inline void cpSpatialIndexDestroy(cpSpatialIndex *index)+{+	if(index->klass) index->klass->destroy(index);+}++/// Get the number of objects in the spatial index.+static inline int cpSpatialIndexCount(cpSpatialIndex *index)+{+	return index->klass->count(index);+}++/// Iterate the objects in the spatial index. @c func will be called once for each object.+static inline void cpSpatialIndexEach(cpSpatialIndex *index, cpSpatialIndexIteratorFunc func, void *data)+{+	index->klass->each(index, func, data);+}++/// Returns true if the spatial index contains the given object.+/// Most spatial indexes use hashed storage, so you must provide a hash value too.+static inline cpBool cpSpatialIndexContains(cpSpatialIndex *index, void *obj, cpHashValue hashid)+{+	return index->klass->contains(index, obj, hashid);+}++/// Add an object to a spatial index.+/// Most spatial indexes use hashed storage, so you must provide a hash value too.+static inline void cpSpatialIndexInsert(cpSpatialIndex *index, void *obj, cpHashValue hashid)+{+	index->klass->insert(index, obj, hashid);+}++/// Remove an object from a spatial index.+/// Most spatial indexes use hashed storage, so you must provide a hash value too.+static inline void cpSpatialIndexRemove(cpSpatialIndex *index, void *obj, cpHashValue hashid)+{+	index->klass->remove(index, obj, hashid);+}++/// Perform a full reindex of a spatial index.+static inline void cpSpatialIndexReindex(cpSpatialIndex *index)+{+	index->klass->reindex(index);+}++/// Reindex a single object in the spatial index.+static inline void cpSpatialIndexReindexObject(cpSpatialIndex *index, void *obj, cpHashValue hashid)+{+	index->klass->reindexObject(index, obj, hashid);+}++/// Perform a rectangle query against the spatial index, calling @c func for each potential match.+static inline void cpSpatialIndexQuery(cpSpatialIndex *index, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)+{+	index->klass->query(index, obj, bb, func, data);+}++/// Perform a segment query against the spatial index, calling @c func for each potential match.+static inline void cpSpatialIndexSegmentQuery(cpSpatialIndex *index, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *data)+{+	index->klass->segmentQuery(index, obj, a, b, t_exit, func, data);+}++/// Simultaneously reindex and find all colliding objects.+/// @c func will be called once for each potentially overlapping pair of objects found.+/// If the spatial index was initialized with a static index, it will collide it's objects against that as well.+static inline void cpSpatialIndexReindexQuery(cpSpatialIndex *index, cpSpatialIndexQueryFunc func, void *data)+{+	index->klass->reindexQuery(index, func, data);+}++///@}
+ Chipmunk2D-7.0.2/include/chipmunk/cpTransform.h view
@@ -0,0 +1,198 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_TRANSFORM_H+#define CHIPMUNK_TRANSFORM_H++#include "chipmunk_types.h"+#include "cpVect.h"+#include "cpBB.h"++/// Identity transform matrix.+static const cpTransform cpTransformIdentity = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};++/// Construct a new transform matrix.+/// (a, b) is the x basis vector.+/// (c, d) is the y basis vector.+/// (tx, ty) is the translation.+static inline cpTransform+cpTransformNew(cpFloat a, cpFloat b, cpFloat c, cpFloat d, cpFloat tx, cpFloat ty)+{+	cpTransform t = {a, b, c, d, tx, ty};+	return t;+}++/// Construct a new transform matrix in transposed order.+static inline cpTransform+cpTransformNewTranspose(cpFloat a, cpFloat c, cpFloat tx, cpFloat b, cpFloat d, cpFloat ty)+{+	cpTransform t = {a, b, c, d, tx, ty};+	return t;+}++/// Get the inverse of a transform matrix.+static inline cpTransform+cpTransformInverse(cpTransform t)+{+  cpFloat inv_det = 1.0/(t.a*t.d - t.c*t.b);+  return cpTransformNewTranspose(+     t.d*inv_det, -t.c*inv_det, (t.c*t.ty - t.tx*t.d)*inv_det,+    -t.b*inv_det,  t.a*inv_det, (t.tx*t.b - t.a*t.ty)*inv_det+  );+}++/// Multiply two transformation matrices.+static inline cpTransform+cpTransformMult(cpTransform t1, cpTransform t2)+{+  return cpTransformNewTranspose(+    t1.a*t2.a + t1.c*t2.b, t1.a*t2.c + t1.c*t2.d, t1.a*t2.tx + t1.c*t2.ty + t1.tx,+    t1.b*t2.a + t1.d*t2.b, t1.b*t2.c + t1.d*t2.d, t1.b*t2.tx + t1.d*t2.ty + t1.ty+  );+}++/// Transform an absolute point. (i.e. a vertex)+static inline cpVect+cpTransformPoint(cpTransform t, cpVect p)+{+  return cpv(t.a*p.x + t.c*p.y + t.tx, t.b*p.x + t.d*p.y + t.ty);+}++/// Transform a vector (i.e. a normal)+static inline cpVect+cpTransformVect(cpTransform t, cpVect v)+{+  return cpv(t.a*v.x + t.c*v.y, t.b*v.x + t.d*v.y);+}++/// Transform a cpBB.+static inline cpBB+cpTransformbBB(cpTransform t, cpBB bb)+{+	cpVect center = cpBBCenter(bb);+	cpFloat hw = (bb.r - bb.l)*0.5;+	cpFloat hh = (bb.t - bb.b)*0.5;+	+	cpFloat a = t.a*hw, b = t.c*hh, d = t.b*hw, e = t.d*hh;+	cpFloat hw_max = cpfmax(cpfabs(a + b), cpfabs(a - b));+	cpFloat hh_max = cpfmax(cpfabs(d + e), cpfabs(d - e));+	return cpBBNewForExtents(cpTransformPoint(t, center), hw_max, hh_max);+}++/// Create a transation matrix.+static inline cpTransform+cpTransformTranslate(cpVect translate)+{+  return cpTransformNewTranspose(+    1.0, 0.0, translate.x,+    0.0, 1.0, translate.y+  );+}++/// Create a scale matrix.+static inline cpTransform+cpTransformScale(cpFloat scaleX, cpFloat scaleY)+{+	return cpTransformNewTranspose(+		scaleX,    0.0, 0.0,+		   0.0, scaleY, 0.0+	);+}++/// Create a rotation matrix.+static inline cpTransform+cpTransformRotate(cpFloat radians)+{+	cpVect rot = cpvforangle(radians);+	return cpTransformNewTranspose(+		rot.x, -rot.y, 0.0,+		rot.y,  rot.x, 0.0+	);+}++/// Create a rigid transformation matrix. (transation + rotation)+static inline cpTransform+cpTransformRigid(cpVect translate, cpFloat radians)+{+	cpVect rot = cpvforangle(radians);+	return cpTransformNewTranspose(+		rot.x, -rot.y, translate.x,+		rot.y,  rot.x, translate.y+	);+}++/// Fast inverse of a rigid transformation matrix.+static inline cpTransform+cpTransformRigidInverse(cpTransform t)+{+  return cpTransformNewTranspose(+     t.d, -t.c, (t.c*t.ty - t.tx*t.d),+    -t.b,  t.a, (t.tx*t.b - t.a*t.ty)+  );+}++//MARK: Miscellaneous (but useful) transformation matrices.+// See source for documentation...++static inline cpTransform+cpTransformWrap(cpTransform outer, cpTransform inner)+{+  return cpTransformMult(cpTransformInverse(outer), cpTransformMult(inner, outer));+}++static inline cpTransform+cpTransformWrapInverse(cpTransform outer, cpTransform inner)+{+  return cpTransformMult(outer, cpTransformMult(inner, cpTransformInverse(outer)));+}++static inline cpTransform+cpTransformOrtho(cpBB bb)+{+  return cpTransformNewTranspose(+    2.0/(bb.r - bb.l), 0.0, -(bb.r + bb.l)/(bb.r - bb.l),+    0.0, 2.0/(bb.t - bb.b), -(bb.t + bb.b)/(bb.t - bb.b)+  );+}++static inline cpTransform+cpTransformBoneScale(cpVect v0, cpVect v1)+{+  cpVect d = cpvsub(v1, v0); +  return cpTransformNewTranspose(+    d.x, -d.y, v0.x,+    d.y,  d.x, v0.y+  );+}++static inline cpTransform+cpTransformAxialScale(cpVect axis, cpVect pivot, cpFloat scale)+{+  cpFloat A = axis.x*axis.y*(scale - 1.0);+  cpFloat B = cpvdot(axis, pivot)*(1.0 - scale);+  +  return cpTransformNewTranspose(+    scale*axis.x*axis.x + axis.y*axis.y, A, axis.x*B,+    A, axis.x*axis.x + scale*axis.y*axis.y, axis.y*B+  );+}++#endif
+ Chipmunk2D-7.0.2/include/chipmunk/cpVect.h view
@@ -0,0 +1,230 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */++#ifndef CHIPMUNK_VECT_H+#define CHIPMUNK_VECT_H++#include "chipmunk_types.h"++/// @defgroup cpVect cpVect+/// Chipmunk's 2D vector type along with a handy 2D vector math lib.+/// @{++/// Constant for the zero vector.+static const cpVect cpvzero = {0.0f,0.0f};++/// Convenience constructor for cpVect structs.+static inline cpVect cpv(const cpFloat x, const cpFloat y)+{+	cpVect v = {x, y};+	return v;+}++/// Check if two vectors are equal. (Be careful when comparing floating point numbers!)+static inline cpBool cpveql(const cpVect v1, const cpVect v2)+{+	return (v1.x == v2.x && v1.y == v2.y);+}++/// Add two vectors+static inline cpVect cpvadd(const cpVect v1, const cpVect v2)+{+	return cpv(v1.x + v2.x, v1.y + v2.y);+}++/// Subtract two vectors.+static inline cpVect cpvsub(const cpVect v1, const cpVect v2)+{+	return cpv(v1.x - v2.x, v1.y - v2.y);+}++/// Negate a vector.+static inline cpVect cpvneg(const cpVect v)+{+	return cpv(-v.x, -v.y);+}++/// Scalar multiplication.+static inline cpVect cpvmult(const cpVect v, const cpFloat s)+{+	return cpv(v.x*s, v.y*s);+}++/// Vector dot product.+static inline cpFloat cpvdot(const cpVect v1, const cpVect v2)+{+	return v1.x*v2.x + v1.y*v2.y;+}++/// 2D vector cross product analog.+/// The cross product of 2D vectors results in a 3D vector with only a z component.+/// This function returns the magnitude of the z value.+static inline cpFloat cpvcross(const cpVect v1, const cpVect v2)+{+	return v1.x*v2.y - v1.y*v2.x;+}++/// Returns a perpendicular vector. (90 degree rotation)+static inline cpVect cpvperp(const cpVect v)+{+	return cpv(-v.y, v.x);+}++/// Returns a perpendicular vector. (-90 degree rotation)+static inline cpVect cpvrperp(const cpVect v)+{+	return cpv(v.y, -v.x);+}++/// Returns the vector projection of v1 onto v2.+static inline cpVect cpvproject(const cpVect v1, const cpVect v2)+{+	return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));+}++/// Returns the unit length vector for the given angle (in radians).+static inline cpVect cpvforangle(const cpFloat a)+{+	return cpv(cpfcos(a), cpfsin(a));+}++/// Returns the angular direction v is pointing in (in radians).+static inline cpFloat cpvtoangle(const cpVect v)+{+	return cpfatan2(v.y, v.x);+}++/// Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.+static inline cpVect cpvrotate(const cpVect v1, const cpVect v2)+{+	return cpv(v1.x*v2.x - v1.y*v2.y, v1.x*v2.y + v1.y*v2.x);+}++/// Inverse of cpvrotate().+static inline cpVect cpvunrotate(const cpVect v1, const cpVect v2)+{+	return cpv(v1.x*v2.x + v1.y*v2.y, v1.y*v2.x - v1.x*v2.y);+}++/// Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.+static inline cpFloat cpvlengthsq(const cpVect v)+{+	return cpvdot(v, v);+}++/// Returns the length of v.+static inline cpFloat cpvlength(const cpVect v)+{+	return cpfsqrt(cpvdot(v, v));+}++/// Linearly interpolate between v1 and v2.+static inline cpVect cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)+{+	return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));+}++/// Returns a normalized copy of v.+static inline cpVect cpvnormalize(const cpVect v)+{+	// Neat trick I saw somewhere to avoid div/0.+	return cpvmult(v, 1.0f/(cpvlength(v) + CPFLOAT_MIN));+}++/// Spherical linearly interpolate between v1 and v2.+static inline cpVect+cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t)+{+	cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2));+	cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f));+	+	if(omega < 1e-3){+		// If the angle between two vectors is very small, lerp instead to avoid precision issues.+		return cpvlerp(v1, v2, t);+	} else {+		cpFloat denom = 1.0f/cpfsin(omega);+		return cpvadd(cpvmult(v1, cpfsin((1.0f - t)*omega)*denom), cpvmult(v2, cpfsin(t*omega)*denom));+	}+}++/// Spherical linearly interpolate between v1 towards v2 by no more than angle a radians+static inline cpVect+cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a)+{+	cpFloat dot = cpvdot(cpvnormalize(v1), cpvnormalize(v2));+	cpFloat omega = cpfacos(cpfclamp(dot, -1.0f, 1.0f));+	+	return cpvslerp(v1, v2, cpfmin(a, omega)/omega);+}++/// Clamp v to length len.+static inline cpVect cpvclamp(const cpVect v, const cpFloat len)+{+	return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;+}++/// Linearly interpolate between v1 towards v2 by distance d.+static inline cpVect cpvlerpconst(cpVect v1, cpVect v2, cpFloat d)+{+	return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d));+}++/// Returns the distance between v1 and v2.+static inline cpFloat cpvdist(const cpVect v1, const cpVect v2)+{+	return cpvlength(cpvsub(v1, v2));+}++/// Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.+static inline cpFloat cpvdistsq(const cpVect v1, const cpVect v2)+{+	return cpvlengthsq(cpvsub(v1, v2));+}++/// Returns true if the distance between v1 and v2 is less than dist.+static inline cpBool cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)+{+	return cpvdistsq(v1, v2) < dist*dist;+}++/// @}++/// @defgroup cpMat2x2 cpMat2x2+/// 2x2 matrix type used for tensors and such.+/// @{++// NUKE+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);+}++///@}++#endif
+ Chipmunk2D-7.0.2/src/chipmunk.c view
@@ -0,0 +1,331 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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 <stdio.h>+#include <string.h>+#include <stdarg.h>+#if defined(ANDROID)+#	include <android/log.h>+#endif++#include "chipmunk/chipmunk_private.h"++void+cpMessage(const char *condition, const char *file, int line, int isError, int isHardError, const char *message, ...)+{+	fprintf(stderr, (isError ? "Aborting due to Chipmunk error: " : "Chipmunk warning: "));+	+	va_list vargs;+	va_start(vargs, message); {+#if defined(ANDROID)+		__android_log_print( ANDROID_LOG_INFO, "Chipmunk", "%s(%d)", file, line );+		__android_log_print( ANDROID_LOG_INFO, "Chipmunk", message, vargs );+#else+		vfprintf(stderr, message, vargs);+		fprintf(stderr, "\n");+#endif+	} va_end(vargs);+	+#if defined(ANDROID)+	__android_log_print(ANDROID_LOG_INFO, "Chipmunk", "\tFailed condition: %s\n", condition);+	__android_log_print(ANDROID_LOG_INFO, "Chipmunk", "\tSource:%s:%d\n", file, line);+#else+	fprintf(stderr, "\tFailed condition: %s\n", condition);+	fprintf(stderr, "\tSource:%s:%d\n", file, line);+#endif+}++#define STR(s) #s+#define XSTR(s) STR(s)++const char *cpVersionString = XSTR(CP_VERSION_MAJOR) "." XSTR(CP_VERSION_MINOR) "." XSTR(CP_VERSION_RELEASE);++//MARK: Misc Functions++cpFloat+cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)+{+	return m*(0.5f*(r1*r1 + r2*r2) + cpvlengthsq(offset));+}++cpFloat+cpAreaForCircle(cpFloat r1, cpFloat r2)+{+	return (cpFloat)CP_PI*cpfabs(r1*r1 - r2*r2);+}++cpFloat+cpMomentForSegment(cpFloat m, cpVect a, cpVect b, cpFloat r)+{+	cpVect offset = cpvlerp(a, b, 0.5f);+	+	// This approximates the shape as a box for rounded segments, but it's quite close.+	cpFloat length = cpvdist(b, a) + 2.0f*r;+	return m*((length*length + 4.0f*r*r)/12.0f + cpvlengthsq(offset));+}++cpFloat+cpAreaForSegment(cpVect a, cpVect b, cpFloat r)+{+	return r*((cpFloat)CP_PI*r + 2.0f*cpvdist(a, b));+}++cpFloat+cpMomentForPoly(cpFloat m, const int count, const cpVect *verts, cpVect offset, cpFloat r)+{+	// TODO account for radius.+	if(count == 2) return cpMomentForSegment(m, verts[0], verts[1], 0.0f);+	+	cpFloat sum1 = 0.0f;+	cpFloat sum2 = 0.0f;+	for(int i=0; i<count; i++){+		cpVect v1 = cpvadd(verts[i], offset);+		cpVect v2 = cpvadd(verts[(i+1)%count], offset);+		+		cpFloat a = cpvcross(v2, v1);+		cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2);+		+		sum1 += a*b;+		sum2 += a;+	}+	+	return (m*sum1)/(6.0f*sum2);+}++cpFloat+cpAreaForPoly(const int count, const cpVect *verts, cpFloat r)+{+	cpFloat area = 0.0f;+	cpFloat perimeter = 0.0f;+	for(int i=0; i<count; i++){+		cpVect v1 = verts[i];+		cpVect v2 = verts[(i+1)%count];+		+		area += cpvcross(v1, v2);+		perimeter += cpvdist(v1, v2);+	}+	+	return r*(CP_PI*cpfabs(r) + perimeter) + area/2.0f;+}++cpVect+cpCentroidForPoly(const int count, const cpVect *verts)+{+	cpFloat sum = 0.0f;+	cpVect vsum = cpvzero;+	+	for(int i=0; i<count; i++){+		cpVect v1 = verts[i];+		cpVect v2 = verts[(i+1)%count];+		cpFloat cross = cpvcross(v1, v2);+		+		sum += cross;+		vsum = cpvadd(vsum, cpvmult(cpvadd(v1, v2), cross));+	}+	+	return cpvmult(vsum, 1.0f/(3.0f*sum));+}++//void+//cpRecenterPoly(const int count, cpVect *verts){+//	cpVect centroid = cpCentroidForPoly(count, verts);+//	+//	for(int i=0; i<count; i++){+//		verts[i] = cpvsub(verts[i], centroid);+//	}+//}++cpFloat+cpMomentForBox(cpFloat m, cpFloat width, cpFloat height)+{+	return m*(width*width + height*height)/12.0f;+}++cpFloat+cpMomentForBox2(cpFloat m, cpBB box)+{+	cpFloat width = box.r - box.l;+	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(const 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(cpvsub(verts[head], a), delta);+		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, const cpVect *verts, cpVect *result, int *first, cpFloat tol)+{+	if(verts != 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));+	}+	+	// Degenerate case, all points 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;+	return QHullReduce(tol, result + 2, count - 2, a, b, a, result + 1) + 1;+}++//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 PointQueryIteratorFunc(cpShape *shape, cpVect p, cpFloat d, cpVect g, cpSpacePointQueryBlock block){block(shape, p, d, g);}+void cpSpacePointQuery_b(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpSpacePointQueryBlock block){+	cpSpacePointQuery(space, point, maxDistance, filter, (cpSpacePointQueryFunc)PointQueryIteratorFunc, block);+}++static void SegmentQueryIteratorFunc(cpShape *shape, cpVect p, cpVect n, cpFloat t, cpSpaceSegmentQueryBlock block){block(shape, p, n, t);}+void cpSpaceSegmentQuery_b(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSpaceSegmentQueryBlock block){+	cpSpaceSegmentQuery(space, start, end, radius, filter, (cpSpaceSegmentQueryFunc)SegmentQueryIteratorFunc, block);+}++void cpSpaceBBQuery_b(cpSpace *space, cpBB bb, cpShapeFilter filter, cpSpaceBBQueryBlock block){+	cpSpaceBBQuery(space, bb, filter, (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/chipmunk_ffi.h"
+ Chipmunk2D-7.0.2/src/cpArbiter.c view
@@ -0,0 +1,496 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++// TODO: make this generic so I can reuse it for constraints also.+static inline void+unthreadHelper(cpArbiter *arb, cpBody *body)+{+	struct cpArbiterThread *thread = cpArbiterThreadForBody(arb, body);+	cpArbiter *prev = thread->prev;+	cpArbiter *next = thread->next;+	+	if(prev){+		cpArbiterThreadForBody(prev, body)->next = next;+	} else if(body->arbiterList == arb) {+		// IFF prev is NULL and body->arbiterList == arb, is arb at the head of the list.+		// This function may be called for an arbiter that was never in a list.+		// In that case, we need to protect it from wiping out the body->arbiterList pointer.+		body->arbiterList = next;+	}+	+	if(next) cpArbiterThreadForBody(next, body)->prev = prev;+	+	thread->prev = NULL;+	thread->next = NULL;+}++void+cpArbiterUnthread(cpArbiter *arb)+{+	unthreadHelper(arb, arb->body_a);+	unthreadHelper(arb, arb->body_b);+}++cpBool cpArbiterIsFirstContact(const cpArbiter *arb)+{+	return arb->state == CP_ARBITER_STATE_FIRST_COLLISION;+}++cpBool cpArbiterIsRemoval(const cpArbiter *arb)+{+	return arb->state == CP_ARBITER_STATE_INVALIDATED;+}++int cpArbiterGetCount(const cpArbiter *arb)+{+	// Return 0 contacts if we are in a separate callback.+	return (arb->state < CP_ARBITER_STATE_CACHED ? arb->count : 0);+}++cpVect+cpArbiterGetNormal(const cpArbiter *arb)+{+	return cpvmult(arb->n, arb->swapped ? -1.0f : 1.0);+}++cpVect+cpArbiterGetPointA(const cpArbiter *arb, int i)+{+	cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter");+	return cpvadd(arb->body_a->p, arb->contacts[i].r1);+}++cpVect+cpArbiterGetPointB(const cpArbiter *arb, int i)+{+	cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter");+	return cpvadd(arb->body_b->p, arb->contacts[i].r2);+}++cpFloat+cpArbiterGetDepth(const cpArbiter *arb, int i)+{+	cpAssertHard(0 <= i && i < cpArbiterGetCount(arb), "Index error: The specified contact index is invalid for this arbiter");+	+	struct cpContact *con = &arb->contacts[i];+	return cpvdot(cpvadd(cpvsub(con->r2, con->r1), cpvsub(arb->body_b->p, arb->body_a->p)), arb->n);+}++cpContactPointSet+cpArbiterGetContactPointSet(const cpArbiter *arb)+{+	cpContactPointSet set;+	set.count = cpArbiterGetCount(arb);+	+	cpBool swapped = arb->swapped;+	cpVect n = arb->n;+	set.normal = (swapped ? cpvneg(n) : n);+	+	for(int i=0; i<set.count; i++){+		// Contact points are relative to body CoGs;+		cpVect p1 = cpvadd(arb->body_a->p, arb->contacts[i].r1);+		cpVect p2 = cpvadd(arb->body_b->p, arb->contacts[i].r2);+		+		set.points[i].pointA = (swapped ? p2 : p1);+		set.points[i].pointB = (swapped ? p1 : p2);+		set.points[i].distance = cpvdot(cpvsub(p2, p1), n);+	}+	+	return set;+}++void+cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set)+{+	int count = set->count;+	cpAssertHard(count == arb->count, "The number of contact points cannot be changed.");+	+	cpBool swapped = arb->swapped;+	arb->n = (swapped ? cpvneg(set->normal) : set->normal);+	+	for(int i=0; i<count; i++){+		// Convert back to CoG relative offsets.+		cpVect p1 = set->points[i].pointA;+		cpVect p2 = set->points[i].pointB;+		+		arb->contacts[i].r1 = cpvsub(swapped ? p2 : p1, arb->body_a->p);+		arb->contacts[i].r2 = cpvsub(swapped ? p1 : p2, arb->body_b->p);+	}+}++cpVect+cpArbiterTotalImpulse(const cpArbiter *arb)+{+	struct cpContact *contacts = arb->contacts;+	cpVect n = arb->n;+	cpVect sum = cpvzero;+	+	for(int i=0, count=cpArbiterGetCount(arb); i<count; i++){+		struct cpContact *con = &contacts[i];+		sum = cpvadd(sum, cpvrotate(n, cpv(con->jnAcc, con->jtAcc)));+	}+		+	return (arb->swapped ? sum : cpvneg(sum));+	return cpvzero;+}++cpFloat+cpArbiterTotalKE(const cpArbiter *arb)+{+	cpFloat eCoef = (1 - arb->e)/(1 + arb->e);+	cpFloat sum = 0.0;+	+	struct cpContact *contacts = arb->contacts;+	for(int i=0, count=cpArbiterGetCount(arb); i<count; i++){+		struct cpContact *con = &contacts[i];+		cpFloat jnAcc = con->jnAcc;+		cpFloat jtAcc = con->jtAcc;+		+		sum += eCoef*jnAcc*jnAcc/con->nMass + jtAcc*jtAcc/con->tMass;+	}+	+	return sum;+}++cpBool+cpArbiterIgnore(cpArbiter *arb)+{+	arb->state = CP_ARBITER_STATE_IGNORE;+	return cpFalse;+}++cpFloat+cpArbiterGetRestitution(const cpArbiter *arb)+{+	return arb->e;+}++void+cpArbiterSetRestitution(cpArbiter *arb, cpFloat restitution)+{+	arb->e = restitution;+}++cpFloat+cpArbiterGetFriction(const cpArbiter *arb)+{+	return arb->u;+}++void+cpArbiterSetFriction(cpArbiter *arb, cpFloat friction)+{+	arb->u = friction;+}++cpVect+cpArbiterGetSurfaceVelocity(cpArbiter *arb)+{+	return cpvmult(arb->surface_vr, arb->swapped ? -1.0f : 1.0);+}++void+cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr)+{+	arb->surface_vr = cpvmult(vr, arb->swapped ? -1.0f : 1.0);+}++cpDataPointer+cpArbiterGetUserData(const cpArbiter *arb)+{+	return arb->data;+}++void+cpArbiterSetUserData(cpArbiter *arb, cpDataPointer userData)+{+	arb->data = userData;+}++void+cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b)+{+	if(arb->swapped){+		(*a) = (cpShape *)arb->b, (*b) = (cpShape *)arb->a;+	} else {+		(*a) = (cpShape *)arb->a, (*b) = (cpShape *)arb->b;+	}+}++void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b)+{+	CP_ARBITER_GET_SHAPES(arb, shape_a, shape_b);+	(*a) = shape_a->body;+	(*b) = shape_b->body;+}++cpBool+cpArbiterCallWildcardBeginA(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerA;+	return handler->beginFunc(arb, space, handler->userData);+}++cpBool+cpArbiterCallWildcardBeginB(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerB;+	arb->swapped = !arb->swapped;+	cpBool retval = handler->beginFunc(arb, space, handler->userData);+	arb->swapped = !arb->swapped;+	return retval;+}++cpBool+cpArbiterCallWildcardPreSolveA(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerA;+	return handler->preSolveFunc(arb, space, handler->userData);+}++cpBool+cpArbiterCallWildcardPreSolveB(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerB;+	arb->swapped = !arb->swapped;+	cpBool retval = handler->preSolveFunc(arb, space, handler->userData);+	arb->swapped = !arb->swapped;+	return retval;+}++void+cpArbiterCallWildcardPostSolveA(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerA;+	handler->postSolveFunc(arb, space, handler->userData);+}++void+cpArbiterCallWildcardPostSolveB(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerB;+	arb->swapped = !arb->swapped;+	handler->postSolveFunc(arb, space, handler->userData);+	arb->swapped = !arb->swapped;+}++void+cpArbiterCallWildcardSeparateA(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerA;+	handler->separateFunc(arb, space, handler->userData);+}++void+cpArbiterCallWildcardSeparateB(cpArbiter *arb, cpSpace *space)+{+	cpCollisionHandler *handler = arb->handlerB;+	arb->swapped = !arb->swapped;+	handler->separateFunc(arb, space, handler->userData);+	arb->swapped = !arb->swapped;+}++cpArbiter*+cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b)+{+	arb->handler = NULL;+	arb->swapped = cpFalse;+	+	arb->handler = NULL;+	arb->handlerA = NULL;+	arb->handlerB = NULL;+	+	arb->e = 0.0f;+	arb->u = 0.0f;+	arb->surface_vr = cpvzero;+	+	arb->count = 0;+	arb->contacts = NULL;+	+	arb->a = a; arb->body_a = a->body;+	arb->b = b; arb->body_b = b->body;+	+	arb->thread_a.next = NULL;+	arb->thread_b.next = NULL;+	arb->thread_a.prev = NULL;+	arb->thread_b.prev = NULL;+	+	arb->stamp = 0;+	arb->state = CP_ARBITER_STATE_FIRST_COLLISION;+	+	arb->data = NULL;+	+	return arb;+}++static inline cpCollisionHandler *+cpSpaceLookupHandler(cpSpace *space, cpCollisionType a, cpCollisionType b, cpCollisionHandler *defaultValue)+{+	cpCollisionType types[] = {a, b};+	cpCollisionHandler *handler = (cpCollisionHandler *)cpHashSetFind(space->collisionHandlers, CP_HASH_PAIR(a, b), types);+	return (handler ? handler : defaultValue);+}++void+cpArbiterUpdate(cpArbiter *arb, struct cpCollisionInfo *info, cpSpace *space)+{+	const cpShape *a = info->a, *b = info->b;+	+	// For collisions between two similar primitive types, the order could have been swapped since the last frame.+	arb->a = a; arb->body_a = a->body;+	arb->b = b; arb->body_b = b->body;+	+	// Iterate over the possible pairs to look for hash value matches.+	for(int i=0; i<info->count; i++){+		struct cpContact *con = &info->arr[i];+		+		// r1 and r2 store absolute offsets at init time.+		// Need to convert them to relative offsets.+		con->r1 = cpvsub(con->r1, a->body->p);+		con->r2 = cpvsub(con->r2, b->body->p);+		+		// Cached impulses are not zeroed at init time.+		con->jnAcc = con->jtAcc = 0.0f;+		+		for(int j=0; j<arb->count; j++){+			struct cpContact *old = &arb->contacts[j];+			+			// This could trigger false positives, but is fairly unlikely nor serious if it does.+			if(con->hash == old->hash){+				// Copy the persistant contact information.+				con->jnAcc = old->jnAcc;+				con->jtAcc = old->jtAcc;+			}+		}+	}+	+	arb->contacts = info->arr;+	arb->count = info->count;+	arb->n = info->n;+	+	arb->e = a->e * b->e;+	arb->u = a->u * b->u;+	+	cpVect surface_vr = cpvsub(b->surfaceV, a->surfaceV);+	arb->surface_vr = cpvsub(surface_vr, cpvmult(info->n, cpvdot(surface_vr, info->n)));+	+	cpCollisionType typeA = info->a->type, typeB = info->b->type;+	cpCollisionHandler *defaultHandler = &space->defaultHandler;+	cpCollisionHandler *handler = arb->handler = cpSpaceLookupHandler(space, typeA, typeB, defaultHandler);+	+	// Check if the types match, but don't swap for a default handler which use the wildcard for type A.+	cpBool swapped = arb->swapped = (typeA != handler->typeA && handler->typeA != CP_WILDCARD_COLLISION_TYPE);+	+	if(handler != defaultHandler || space->usesWildcards){+		// The order of the main handler swaps the wildcard handlers too. Uffda.+		arb->handlerA = cpSpaceLookupHandler(space, (swapped ? typeB : typeA), CP_WILDCARD_COLLISION_TYPE, &cpCollisionHandlerDoNothing);+		arb->handlerB = cpSpaceLookupHandler(space, (swapped ? typeA : typeB), CP_WILDCARD_COLLISION_TYPE, &cpCollisionHandlerDoNothing);+	}+		+	// mark it as new if it's been cached+	if(arb->state == CP_ARBITER_STATE_CACHED) arb->state = CP_ARBITER_STATE_FIRST_COLLISION;+}++void+cpArbiterPreStep(cpArbiter *arb, cpFloat dt, cpFloat slop, cpFloat bias)+{+	cpBody *a = arb->body_a;+	cpBody *b = arb->body_b;+	cpVect n = arb->n;+	cpVect body_delta = cpvsub(b->p, a->p);+	+	for(int i=0; i<arb->count; i++){+		struct cpContact *con = &arb->contacts[i];+		+		// Calculate the mass normal and mass tangent.+		con->nMass = 1.0f/k_scalar(a, b, con->r1, con->r2, n);+		con->tMass = 1.0f/k_scalar(a, b, con->r1, con->r2, cpvperp(n));+				+		// Calculate the target bias velocity.+		cpFloat dist = cpvdot(cpvadd(cpvsub(con->r2, con->r1), body_delta), n);+		con->bias = -bias*cpfmin(0.0f, dist + slop)/dt;+		con->jBias = 0.0f;+		+		// Calculate the target bounce velocity.+		con->bounce = normal_relative_velocity(a, b, con->r1, con->r2, n)*arb->e;+	}+}++void+cpArbiterApplyCachedImpulse(cpArbiter *arb, cpFloat dt_coef)+{+	if(cpArbiterIsFirstContact(arb)) return;+	+	cpBody *a = arb->body_a;+	cpBody *b = arb->body_b;+	cpVect n = arb->n;+	+	for(int i=0; i<arb->count; i++){+		struct cpContact *con = &arb->contacts[i];+		cpVect j = cpvrotate(n, cpv(con->jnAcc, con->jtAcc));+		apply_impulses(a, b, con->r1, con->r2, cpvmult(j, dt_coef));+	}+}++// TODO: is it worth splitting velocity/position correction?++void+cpArbiterApplyImpulse(cpArbiter *arb)+{+	cpBody *a = arb->body_a;+	cpBody *b = arb->body_b;+	cpVect n = arb->n;+	cpVect surface_vr = arb->surface_vr;+	cpFloat friction = arb->u;++	for(int i=0; i<arb->count; i++){+		struct cpContact *con = &arb->contacts[i];+		cpFloat nMass = con->nMass;+		cpVect r1 = con->r1;+		cpVect r2 = con->r2;+		+		cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias));+		cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias));+		cpVect vr = cpvadd(relative_velocity(a, b, r1, r2), surface_vr);+		+		cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);+		cpFloat vrn = cpvdot(vr, n);+		cpFloat vrt = cpvdot(vr, cpvperp(n));+		+		cpFloat jbn = (con->bias - vbn)*nMass;+		cpFloat jbnOld = con->jBias;+		con->jBias = cpfmax(jbnOld + jbn, 0.0f);+		+		cpFloat jn = -(con->bounce + vrn)*nMass;+		cpFloat jnOld = con->jnAcc;+		con->jnAcc = cpfmax(jnOld + jn, 0.0f);+		+		cpFloat jtMax = friction*con->jnAcc;+		cpFloat jt = -vrt*con->tMass;+		cpFloat jtOld = con->jtAcc;+		con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax);+		+		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)));+	}+}
+ Chipmunk2D-7.0.2/src/cpArray.c view
@@ -0,0 +1,101 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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 <string.h>++#include "chipmunk/chipmunk_private.h"+++cpArray *+cpArrayNew(int size)+{+	cpArray *arr = (cpArray *)cpcalloc(1, sizeof(cpArray));+	+	arr->num = 0;+	arr->max = (size ? size : 4);+	arr->arr = (void **)cpcalloc(arr->max, sizeof(void*));+	+	return arr;+}++void+cpArrayFree(cpArray *arr)+{+	if(arr){+		cpfree(arr->arr);+		arr->arr = NULL;+		+		cpfree(arr);+	}+}++void+cpArrayPush(cpArray *arr, void *object)+{+	if(arr->num == arr->max){+		arr->max = 3*(arr->max + 1)/2;+		arr->arr = (void **)cprealloc(arr->arr, arr->max*sizeof(void*));+	}+	+	arr->arr[arr->num] = object;+	arr->num++;+}++void *+cpArrayPop(cpArray *arr)+{+	arr->num--;+	+	void *value = arr->arr[arr->num];+	arr->arr[arr->num] = NULL;+	+	return value;+}++void+cpArrayDeleteObj(cpArray *arr, void *obj)+{+	for(int i=0; i<arr->num; i++){+		if(arr->arr[i] == obj){+			arr->num--;+			+			arr->arr[i] = arr->arr[arr->num];+			arr->arr[arr->num] = NULL;+			+			return;+		}+	}+}++void+cpArrayFreeEach(cpArray *arr, void (freeFunc)(void*))+{+	for(int i=0; i<arr->num; i++) freeFunc(arr->arr[i]);+}++cpBool+cpArrayContains(cpArray *arr, void *ptr)+{+	for(int i=0; i<arr->num; i++)+		if(arr->arr[i] == ptr) return cpTrue;+	+	return cpFalse;+}
+ Chipmunk2D-7.0.2/src/cpBBTree.c view
@@ -0,0 +1,896 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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 "stdlib.h"+#include "stdio.h"++#include "chipmunk/chipmunk_private.h"++static inline cpSpatialIndexClass *Klass();++typedef struct Node Node;+typedef struct Pair Pair;++struct cpBBTree {+	cpSpatialIndex spatialIndex;+	cpBBTreeVelocityFunc velocityFunc;+	+	cpHashSet *leaves;+	Node *root;+	+	Node *pooledNodes;+	Pair *pooledPairs;+	cpArray *allocatedBuffers;+	+	cpTimestamp stamp;+};++struct Node {+	void *obj;+	cpBB bb;+	Node *parent;+	+	union {+		// Internal nodes+		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;+	Pair *next;+} Thread;++struct Pair {+	Thread a, b;+	cpCollisionID id;+};++//MARK: Misc Functions++static inline cpBB+GetBB(cpBBTree *tree, void *obj)+{+	cpBB bb = tree->spatialIndex.bbfunc(obj);+	+	cpBBTreeVelocityFunc velocityFunc = tree->velocityFunc;+	if(velocityFunc){+		cpFloat coef = 0.1f;+		cpFloat x = (bb.r - bb.l)*coef;+		cpFloat y = (bb.t - bb.b)*coef;+		+		cpVect v = cpvmult(velocityFunc(obj), 0.1f);+		return cpBBNew(bb.l + cpfmin(-x, v.x), bb.b + cpfmin(-y, v.y), bb.r + cpfmax(x, v.x), bb.t + cpfmax(y, v.y));+	} else {+		return bb;+	}+}++static inline cpBBTree *+GetTree(cpSpatialIndex *index)+{+	return (index && index->klass == Klass() ? (cpBBTree *)index : NULL);+}++static inline Node *+GetRootIfTree(cpSpatialIndex *index){+	return (index && index->klass == Klass() ? ((cpBBTree *)index)->root : NULL);+}++static inline cpBBTree *+GetMasterTree(cpBBTree *tree)+{+	cpBBTree *dynamicTree = GetTree(tree->spatialIndex.dynamicIndex);+	return (dynamicTree ? dynamicTree : tree);+}++static inline void+IncrementStamp(cpBBTree *tree)+{+	cpBBTree *dynamicTree = GetTree(tree->spatialIndex.dynamicIndex);+	if(dynamicTree){+		dynamicTree->stamp++;+	} else {+		tree->stamp++;+	}+}++//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;+}++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){+		tree->pooledPairs = pair->a.next;+		return pair;+	} else {+		// Pool is exhausted, make more+		int count = CP_BUFFER_BYTES/sizeof(Pair);+		cpAssertHard(count, "Internal Error: Buffer size is too small.");+		+		Pair *buffer = (Pair *)cpcalloc(1, CP_BUFFER_BYTES);+		cpArrayPush(tree->allocatedBuffers, buffer);+		+		// push all but the first one, return the first instead+		for(int i=1; i<count; i++) PairRecycle(tree, buffer + i);+		return buffer;+	}+}++static inline void+ThreadUnlink(Thread thread)+{+	Pair *next = thread.next;+	Pair *prev = thread.prev;+	+	if(next){+		if(next->a.leaf == thread.leaf) next->a.prev = prev; else next->b.prev = prev;+	}+	+	if(prev){+		if(prev->a.leaf == thread.leaf) prev->a.next = next; else prev->b.next = next;+	} else {+		thread.leaf->PAIRS = next;+	}+}++static void+PairsClear(Node *leaf, cpBBTree *tree)+{+	Pair *pair = leaf->PAIRS;+	leaf->PAIRS = NULL;+	+	while(pair){+		if(pair->a.leaf == leaf){+			Pair *next = pair->a.next;+			ThreadUnlink(pair->b);+			PairRecycle(tree, pair);+			pair = next;+		} else {+			Pair *next = pair->b.next;+			ThreadUnlink(pair->a);+			PairRecycle(tree, pair);+			pair = next;+		}+	}+}++static void+PairInsert(Node *a, Node *b, cpBBTree *tree)+{+	Pair *nextA = a->PAIRS, *nextB = b->PAIRS;+	Pair *pair = PairFromPool(tree);+	Pair temp = {{NULL, a, nextA},{NULL, b, nextB}, 0};+	+	a->PAIRS = b->PAIRS = pair;+	*pair = temp;+	+	if(nextA){+		if(nextA->a.leaf == a) nextA->a.prev = pair; else nextA->b.prev = pair;+	}+	+	if(nextB){+		if(nextB->a.leaf == b) nextB->a.prev = pair; else nextB->b.prev = pair;+	}+}+++//MARK: Node Functions++static void+NodeRecycle(cpBBTree *tree, Node *node)+{+	node->parent = tree->pooledNodes;+	tree->pooledNodes = node;+}++static Node *+NodeFromPool(cpBBTree *tree)+{+	Node *node = tree->pooledNodes;+	+	if(node){+		tree->pooledNodes = node->parent;+		return node;+	} else {+		// Pool is exhausted, make more+		int count = CP_BUFFER_BYTES/sizeof(Node);+		cpAssertHard(count, "Internal Error: Buffer size is too small.");+		+		Node *buffer = (Node *)cpcalloc(1, CP_BUFFER_BYTES);+		cpArrayPush(tree->allocatedBuffers, buffer);+		+		// push all but the first one, return the first instead+		for(int i=1; i<count; i++) NodeRecycle(tree, buffer + i);+		return buffer;+	}+}++static inline void+NodeSetA(Node *node, Node *value)+{+	node->A = value;+	value->parent = node;+}++static inline void+NodeSetB(Node *node, Node *value)+{+	node->B = value;+	value->parent = node;+}++static Node *+NodeNew(cpBBTree *tree, Node *a, Node *b)+{+	Node *node = NodeFromPool(tree);+	+	node->obj = NULL;+	node->bb = cpBBMerge(a->bb, b->bb);+	node->parent = NULL;+	+	NodeSetA(node, a);+	NodeSetB(node, b);+	+	return node;+}++static inline cpBool+NodeIsLeaf(Node *node)+{+	return (node->obj != NULL);+}++static inline Node *+NodeOther(Node *node, Node *child)+{+	return (node->A == child ? node->B : node->A);+}++static inline void+NodeReplaceChild(Node *parent, Node *child, Node *value, cpBBTree *tree)+{+	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);+		NodeSetA(parent, value);+	} else {+		NodeRecycle(tree, parent->B);+		NodeSetB(parent, value);+	}+	+	for(Node *node=parent; node; node = node->parent){+		node->bb = cpBBMerge(node->A->bb, node->B->bb);+	}+}++//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)+{+	if(subtree == NULL){+		return leaf;+	} 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);+		+		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));+		} else {+			NodeSetA(subtree, SubtreeInsert(subtree->A, leaf, tree));+		}+		+		subtree->bb = cpBBMerge(subtree->bb, leaf->bb);+		return subtree;+	}+}++static void+SubtreeQuery(Node *subtree, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)+{+	if(cpBBIntersects(subtree->bb, bb)){+		if(NodeIsLeaf(subtree)){+			func(obj, subtree->obj, 0, data);+		} else {+			SubtreeQuery(subtree->A, obj, bb, func, data);+			SubtreeQuery(subtree->B, obj, bb, func, data);+		}+	}+}+++static cpFloat+SubtreeSegmentQuery(Node *subtree, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpatialIndexSegmentQueryFunc func, void *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 {+			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;+	}+}++static void+SubtreeRecycle(cpBBTree *tree, Node *node)+{+	if(!NodeIsLeaf(node)){+		SubtreeRecycle(tree, node->A);+		SubtreeRecycle(tree, node->B);+		NodeRecycle(tree, node);+	}+}++static inline Node *+SubtreeRemove(Node *subtree, Node *leaf, cpBBTree *tree)+{+	if(leaf == subtree){+		return NULL;+	} else {+		Node *parent = leaf->parent;+		if(parent == subtree){+			Node *other = NodeOther(subtree, leaf);+			other->parent = subtree->parent;+			NodeRecycle(tree, subtree);+			return other;+		} else {+			NodeReplaceChild(parent->parent, parent, NodeOther(parent, leaf), tree);+			return subtree;+		}+	}+}++//MARK: Marking Functions++typedef struct MarkContext {+	cpBBTree *tree;+	Node *staticRoot;+	cpSpatialIndexQueryFunc func;+	void *data;+} MarkContext;++static void+MarkLeafQuery(Node *subtree, Node *leaf, cpBool left, MarkContext *context)+{+	if(cpBBIntersects(leaf->bb, subtree->bb)){+		if(NodeIsLeaf(subtree)){+			if(left){+				PairInsert(leaf, subtree, context->tree);+			} else {+				if(subtree->STAMP < leaf->STAMP) PairInsert(subtree, leaf, context->tree);+				context->func(leaf->obj, subtree->obj, 0, context->data);+			}+		} else {+			MarkLeafQuery(subtree->A, leaf, left, context);+			MarkLeafQuery(subtree->B, leaf, left, context);+		}+	}+}++static void+MarkLeaf(Node *leaf, MarkContext *context)+{+	cpBBTree *tree = context->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);+			} else {+				MarkLeafQuery(node->parent->A, leaf, cpFalse, context);+			}+		}+	} else {+		Pair *pair = leaf->PAIRS;+		while(pair){+			if(leaf == pair->b.leaf){+				pair->id = context->func(pair->a.leaf->obj, leaf->obj, pair->id, context->data);+				pair = pair->b.next;+			} else {+				pair = pair->a.next;+			}+		}+	}+}++static void+MarkSubtree(Node *subtree, MarkContext *context)+{+	if(NodeIsLeaf(subtree)){+		MarkLeaf(subtree, context);+	} else {+		MarkSubtree(subtree->A, context);+		MarkSubtree(subtree->B, context); // TODO: Force TCO here?+	}+}++//MARK: Leaf Functions++static Node *+LeafNew(cpBBTree *tree, void *obj, cpBB bb)+{+	Node *node = NodeFromPool(tree);+	node->obj = obj;+	node->bb = GetBB(tree, obj);+	+	node->parent = NULL;+	node->STAMP = 0;+	node->PAIRS = NULL;+	+	return node;+}++static cpBool+LeafUpdate(Node *leaf, cpBBTree *tree)+{+	Node *root = tree->root;+	cpBB bb = tree->spatialIndex.bbfunc(leaf->obj);+	+	if(!cpBBContainsBB(leaf->bb, bb)){+		leaf->bb = GetBB(tree, leaf->obj);+		+		root = SubtreeRemove(root, leaf, tree);+		tree->root = SubtreeInsert(root, leaf, tree);+		+		PairsClear(leaf, tree);+		leaf->STAMP = GetMasterTree(tree)->stamp;+		+		return cpTrue;+	} else {+		return cpFalse;+	}+}++static cpCollisionID VoidQueryFunc(void *obj1, void *obj2, cpCollisionID id, void *data){return id;}++static void+LeafAddPairs(Node *leaf, cpBBTree *tree)+{+	cpSpatialIndex *dynamicIndex = tree->spatialIndex.dynamicIndex;+	if(dynamicIndex){+		Node *dynamicRoot = GetRootIfTree(dynamicIndex);+		if(dynamicRoot){+			cpBBTree *dynamicTree = GetTree(dynamicIndex);+			MarkContext context = {dynamicTree, NULL, NULL, NULL};+			MarkLeafQuery(dynamicRoot, leaf, cpTrue, &context);+		}+	} else {+		Node *staticRoot = GetRootIfTree(tree->spatialIndex.staticIndex);+		MarkContext context = {tree, staticRoot, VoidQueryFunc, NULL};+		MarkLeaf(leaf, &context);+	}+}++//MARK: Memory Management Functions++cpBBTree *+cpBBTreeAlloc(void)+{+	return (cpBBTree *)cpcalloc(1, sizeof(cpBBTree));+}++static int+leafSetEql(void *obj, Node *node)+{+	return (obj == node->obj);+}++static void *+leafSetTrans(void *obj, cpBBTree *tree)+{+	return LeafNew(tree, obj, tree->spatialIndex.bbfunc(obj));+}++cpSpatialIndex *+cpBBTreeInit(cpBBTree *tree, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	cpSpatialIndexInit((cpSpatialIndex *)tree, Klass(), bbfunc, staticIndex);+	+	tree->velocityFunc = NULL;+	+	tree->leaves = cpHashSetNew(0, (cpHashSetEqlFunc)leafSetEql);+	tree->root = NULL;+	+	tree->pooledNodes = NULL;+	tree->allocatedBuffers = cpArrayNew(0);+	+	tree->stamp = 0;+	+	return (cpSpatialIndex *)tree;+}++void+cpBBTreeSetVelocityFunc(cpSpatialIndex *index, cpBBTreeVelocityFunc func)+{+	if(index->klass != Klass()){+		cpAssertWarn(cpFalse, "Ignoring cpBBTreeSetVelocityFunc() call to non-tree spatial index.");+		return;+	}+	+	((cpBBTree *)index)->velocityFunc = func;+}++cpSpatialIndex *+cpBBTreeNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	return cpBBTreeInit(cpBBTreeAlloc(), bbfunc, staticIndex);+}++static void+cpBBTreeDestroy(cpBBTree *tree)+{+	cpHashSetFree(tree->leaves);+	+	if(tree->allocatedBuffers) cpArrayFreeEach(tree->allocatedBuffers, cpfree);+	cpArrayFree(tree->allocatedBuffers);+}++//MARK: Insert/Remove++static void+cpBBTreeInsert(cpBBTree *tree, void *obj, cpHashValue hashid)+{+	Node *leaf = (Node *)cpHashSetInsert(tree->leaves, hashid, obj, (cpHashSetTransFunc)leafSetTrans, tree);+	+	Node *root = tree->root;+	tree->root = SubtreeInsert(root, leaf, tree);+	+	leaf->STAMP = GetMasterTree(tree)->stamp;+	LeafAddPairs(leaf, tree);+	IncrementStamp(tree);+}++static void+cpBBTreeRemove(cpBBTree *tree, void *obj, cpHashValue hashid)+{+	Node *leaf = (Node *)cpHashSetRemove(tree->leaves, hashid, obj);+	+	tree->root = SubtreeRemove(tree->root, leaf, tree);+	PairsClear(leaf, tree);+	NodeRecycle(tree, leaf);+}++static cpBool+cpBBTreeContains(cpBBTree *tree, void *obj, cpHashValue hashid)+{+	return (cpHashSetFind(tree->leaves, hashid, obj) != NULL);+}++//MARK: Reindex++static void LeafUpdateWrap(Node *leaf, cpBBTree *tree) {LeafUpdate(leaf, tree);}++static void+cpBBTreeReindexQuery(cpBBTree *tree, cpSpatialIndexQueryFunc func, void *data)+{+	if(!tree->root) return;+	+	// LeafUpdate() may modify tree->root. Don't cache it.+	cpHashSetEach(tree->leaves, (cpHashSetIteratorFunc)LeafUpdateWrap, tree);+	+	cpSpatialIndex *staticIndex = tree->spatialIndex.staticIndex;+	Node *staticRoot = (staticIndex && staticIndex->klass == Klass() ? ((cpBBTree *)staticIndex)->root : NULL);+	+	MarkContext context = {tree, staticRoot, func, data};+	MarkSubtree(tree->root, &context);+	if(staticIndex && !staticRoot) cpSpatialIndexCollideStatic((cpSpatialIndex *)tree, staticIndex, func, data);+	+	IncrementStamp(tree);+}++static void+cpBBTreeReindex(cpBBTree *tree)+{+	cpBBTreeReindexQuery(tree, VoidQueryFunc, NULL);+}++static void+cpBBTreeReindexObject(cpBBTree *tree, void *obj, cpHashValue hashid)+{+	Node *leaf = (Node *)cpHashSetFind(tree->leaves, hashid, obj);+	if(leaf){+		if(LeafUpdate(leaf, tree)) LeafAddPairs(leaf, tree);+		IncrementStamp(tree);+	}+}++//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, t_exit, func, data);+}++static void+cpBBTreeQuery(cpBBTree *tree, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)+{+	if(tree->root) SubtreeQuery(tree->root, obj, bb, func, data);+}++//MARK: Misc++static int+cpBBTreeCount(cpBBTree *tree)+{+	return cpHashSetCount(tree->leaves);+}++typedef struct eachContext {+	cpSpatialIndexIteratorFunc func;+	void *data;+} eachContext;++static void each_helper(Node *node, eachContext *context){context->func(node->obj, context->data);}++static void+cpBBTreeEach(cpBBTree *tree, cpSpatialIndexIteratorFunc func, void *data)+{+	eachContext context = {func, data};+	cpHashSetEach(tree->leaves, (cpHashSetIteratorFunc)each_helper, &context);+}++static cpSpatialIndexClass klass = {+	(cpSpatialIndexDestroyImpl)cpBBTreeDestroy,+	+	(cpSpatialIndexCountImpl)cpBBTreeCount,+	(cpSpatialIndexEachImpl)cpBBTreeEach,+	+	(cpSpatialIndexContainsImpl)cpBBTreeContains,+	(cpSpatialIndexInsertImpl)cpBBTreeInsert,+	(cpSpatialIndexRemoveImpl)cpBBTreeRemove,+	+	(cpSpatialIndexReindexImpl)cpBBTreeReindex,+	(cpSpatialIndexReindexObjectImpl)cpBBTreeReindexObject,+	(cpSpatialIndexReindexQueryImpl)cpBBTreeReindexQuery,+	+	(cpSpatialIndexQueryImpl)cpBBTreeQuery,+	(cpSpatialIndexSegmentQueryImpl)cpBBTreeSegmentQuery,+};++static inline cpSpatialIndexClass *Klass(){return &klass;}+++//MARK: Tree Optimization++static int+cpfcompare(const cpFloat *a, const cpFloat *b){+	return (*a < *b ? -1 : (*b < *a ? 1 : 0));+}++static void+fillNodeArray(Node *node, Node ***cursor){+	(**cursor) = node;+	(*cursor)++;+}++static Node *+partitionNodes(cpBBTree *tree, Node **nodes, int count)+{+	if(count == 1){+		return nodes[0];+	} else if(count == 2) {+		return NodeNew(tree, nodes[0], nodes[1]);+	}+	+	// Find the AABB for these nodes+	cpBB bb = nodes[0]->bb;+	for(int i=1; i<count; i++) bb = cpBBMerge(bb, nodes[i]->bb);+	+	// Split it on it's longest axis+	cpBool splitWidth = (bb.r - bb.l > bb.t - bb.b);+	+	// Sort the bounds and use the median as the splitting point+	cpFloat *bounds = (cpFloat *)cpcalloc(count*2, sizeof(cpFloat));+	if(splitWidth){+		for(int i=0; i<count; i++){+			bounds[2*i + 0] = nodes[i]->bb.l;+			bounds[2*i + 1] = nodes[i]->bb.r;+		}+	} else {+		for(int i=0; i<count; i++){+			bounds[2*i + 0] = nodes[i]->bb.b;+			bounds[2*i + 1] = nodes[i]->bb.t;+		}+	}+	+	qsort(bounds, count*2, sizeof(cpFloat), (int (*)(const void *, const void *))cpfcompare);+	cpFloat split = (bounds[count - 1] + bounds[count])*0.5f; // use the medain as the split+	cpfree(bounds);++	// Generate the child BBs+	cpBB a = bb, b = bb;+	if(splitWidth) a.r = b.l = split; else a.t = b.b = split;+	+	// Partition the nodes+	int right = count;+	for(int left=0; left < right;){+		Node *node = nodes[left];+		if(cpBBMergedArea(node->bb, b) < cpBBMergedArea(node->bb, a)){+//		if(cpBBProximity(node->bb, b) < cpBBProximity(node->bb, a)){+			right--;+			nodes[left] = nodes[right];+			nodes[right] = node;+		} else {+			left++;+		}+	}+	+	if(right == count){+		Node *node = NULL;+		for(int i=0; i<count; i++) node = SubtreeInsert(node, nodes[i], tree);+		return node;+	}+	+	// Recurse and build the node!+	return NodeNew(tree,+		partitionNodes(tree, nodes, right),+		partitionNodes(tree, nodes + right, count - right)+	);+}++//static void+//cpBBTreeOptimizeIncremental(cpBBTree *tree, int passes)+//{+//	for(int i=0; i<passes; i++){+//		Node *root = tree->root;+//		Node *node = root;+//		int bit = 0;+//		unsigned int path = tree->opath;+//		+//		while(!NodeIsLeaf(node)){+//			node = (path&(1<<bit) ? node->a : node->b);+//			bit = (bit + 1)&(sizeof(unsigned int)*8 - 1);+//		}+//		+//		root = subtreeRemove(root, node, tree);+//		tree->root = subtreeInsert(root, node, tree);+//	}+//}++void+cpBBTreeOptimize(cpSpatialIndex *index)+{+	if(index->klass != &klass){+		cpAssertWarn(cpFalse, "Ignoring cpBBTreeOptimize() call to non-tree spatial index.");+		return;+	}+	+	cpBBTree *tree = (cpBBTree *)index;+	Node *root = tree->root;+	if(!root) return;+	+	int count = cpBBTreeCount(tree);+	Node **nodes = (Node **)cpcalloc(count, sizeof(Node *));+	Node **cursor = nodes;+	+	cpHashSetEach(tree->leaves, (cpHashSetIteratorFunc)fillNodeArray, &cursor);+	+	SubtreeRecycle(tree, root);+	tree->root = partitionNodes(tree, nodes, count);+	cpfree(nodes);+}++//MARK: Debug Draw++//#define CP_BBTREE_DEBUG_DRAW+#ifdef CP_BBTREE_DEBUG_DRAW+#include "OpenGL/gl.h"+#include "OpenGL/glu.h"+#include <GLUT/glut.h>++static void+NodeRender(Node *node, int depth)+{+	if(!NodeIsLeaf(node) && depth <= 10){+		NodeRender(node->a, depth + 1);+		NodeRender(node->b, depth + 1);+	}+	+	cpBB bb = node->bb;+	+//	GLfloat v = depth/2.0f;	+//	glColor3f(1.0f - v, v, 0.0f);+	glLineWidth(cpfmax(5.0f - depth, 1.0f));+	glBegin(GL_LINES); {+		glVertex2f(bb.l, bb.b);+		glVertex2f(bb.l, bb.t);+		+		glVertex2f(bb.l, bb.t);+		glVertex2f(bb.r, bb.t);+		+		glVertex2f(bb.r, bb.t);+		glVertex2f(bb.r, bb.b);+		+		glVertex2f(bb.r, bb.b);+		glVertex2f(bb.l, bb.b);+	}; glEnd();+}++void+cpBBTreeRenderDebug(cpSpatialIndex *index){+	if(index->klass != &klass){+		cpAssertWarn(cpFalse, "Ignoring cpBBTreeRenderDebug() call to non-tree spatial index.");+		return;+	}+	+	cpBBTree *tree = (cpBBTree *)index;+	if(tree->root) NodeRender(tree->root, 0);+}+#endif
+ Chipmunk2D-7.0.2/src/cpBody.c view
@@ -0,0 +1,626 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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 <float.h>+#include <stdarg.h>++#include "chipmunk/chipmunk_private.h"++cpBody*+cpBodyAlloc(void)+{+	return (cpBody *)cpcalloc(1, sizeof(cpBody));+}++cpBody *+cpBodyInit(cpBody *body, cpFloat mass, cpFloat moment)+{+	body->space = NULL;+	body->shapeList = NULL;+	body->arbiterList = NULL;+	body->constraintList = NULL;+	+	body->velocity_func = cpBodyUpdateVelocity;+	body->position_func = cpBodyUpdatePosition;+	+	body->sleeping.root = NULL;+	body->sleeping.next = NULL;+	body->sleeping.idleTime = 0.0f;+	+	body->p = cpvzero;+	body->v = cpvzero;+	body->f = cpvzero;+	+	body->w = 0.0f;+	body->t = 0.0f;+	+	body->v_bias = cpvzero;+	body->w_bias = 0.0f;+	+	body->userData = NULL;+	+	// Setters must be called after full initialization so the sanity checks don't assert on garbage data.+	cpBodySetMass(body, mass);+	cpBodySetMoment(body, moment);+	cpBodySetAngle(body, 0.0f);+	+	return body;+}++cpBody*+cpBodyNew(cpFloat mass, cpFloat moment)+{+	return cpBodyInit(cpBodyAlloc(), mass, moment);+}++cpBody*+cpBodyNewKinematic()+{+	cpBody *body = cpBodyNew(0.0f, 0.0f);+	cpBodySetType(body, CP_BODY_TYPE_KINEMATIC);+	+	return body;+}++cpBody*+cpBodyNewStatic()+{+	cpBody *body = cpBodyNew(0.0f, 0.0f);+	cpBodySetType(body, CP_BODY_TYPE_STATIC);+	+	return body;+}++void cpBodyDestroy(cpBody *body){}++void+cpBodyFree(cpBody *body)+{+	if(body){+		cpBodyDestroy(body);+		cpfree(body);+	}+}++#ifdef NDEBUG+	#define	cpAssertSaneBody(body)+#else+	static void cpv_assert_nan(cpVect v, char *message){cpAssertHard(v.x == v.x && v.y == v.y, message);}+	static void cpv_assert_infinite(cpVect v, char *message){cpAssertHard(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);}+	+	static void+	cpBodySanityCheck(const cpBody *body)+	{+		cpAssertHard(body->m == body->m && body->m_inv == body->m_inv, "Body's mass is NaN.");+		cpAssertHard(body->i == body->i && body->i_inv == body->i_inv, "Body's moment is NaN.");+		cpAssertHard(body->m >= 0.0f, "Body's mass is negative.");+		cpAssertHard(body->i >= 0.0f, "Body's moment is negative.");+		+		cpv_assert_sane(body->p, "Body's position is invalid.");+		cpv_assert_sane(body->v, "Body's velocity is invalid.");+		cpv_assert_sane(body->f, "Body's force is invalid.");++		cpAssertHard(body->a == body->a && cpfabs(body->a) != INFINITY, "Body's angle is invalid.");+		cpAssertHard(body->w == body->w && cpfabs(body->w) != INFINITY, "Body's angular velocity is invalid.");+		cpAssertHard(body->t == body->t && cpfabs(body->t) != INFINITY, "Body's torque is invalid.");+	}+	+	#define	cpAssertSaneBody(body) cpBodySanityCheck(body)+#endif++cpBool+cpBodyIsSleeping(const cpBody *body)+{+	return (body->sleeping.root != ((cpBody*)0));+}++cpBodyType+cpBodyGetType(cpBody *body)+{+	if(body->sleeping.idleTime == INFINITY){+		return CP_BODY_TYPE_STATIC;+	} else if(body->m == INFINITY){+		return CP_BODY_TYPE_KINEMATIC;+	} else {+		return CP_BODY_TYPE_DYNAMIC;+	}+}++void+cpBodySetType(cpBody *body, cpBodyType type)+{+	cpBodyType oldType = cpBodyGetType(body);+	if(oldType == type) return;+	+	// Static bodies have their idle timers set to infinity.+	// Non-static bodies should have their idle timer reset.+	body->sleeping.idleTime = (type == CP_BODY_TYPE_STATIC ? INFINITY : 0.0f);+	+	if(type == CP_BODY_TYPE_DYNAMIC){+		body->m = body->i = 0.0f;+		body->m_inv = body->i_inv = INFINITY;+		+		cpBodyAccumulateMassFromShapes(body);+	} else {+		body->m = body->i = INFINITY;+		body->m_inv = body->i_inv = 0.0f;+		+		body->v = cpvzero;+		body->w = 0.0f;+	}+	+	// If the body is added to a space already, we'll need to update some space data structures.+	cpSpace *space = cpBodyGetSpace(body);+	if(space != NULL){+		cpAssertSpaceUnlocked(space);+		+		if(oldType == CP_BODY_TYPE_STATIC){+			// TODO This is probably not necessary+//			cpBodyActivateStatic(body, NULL);+		} else {+			cpBodyActivate(body);+		}+		+		// Move the bodies to the correct array.+		cpArray *fromArray = cpSpaceArrayForBodyType(space, oldType);+		cpArray *toArray = cpSpaceArrayForBodyType(space, type);+		if(fromArray != toArray){+			cpArrayDeleteObj(fromArray, body);+			cpArrayPush(toArray, body);+		}+		+		// Move the body's shapes to the correct spatial index.+		cpSpatialIndex *fromIndex = (oldType == CP_BODY_TYPE_STATIC ? space->staticShapes : space->dynamicShapes);+		cpSpatialIndex *toIndex = (type == CP_BODY_TYPE_STATIC ? space->staticShapes : space->dynamicShapes);+		if(fromIndex != toIndex){+			CP_BODY_FOREACH_SHAPE(body, shape){+				cpSpatialIndexRemove(fromIndex, shape, shape->hashid);+				cpSpatialIndexInsert(toIndex, shape, shape->hashid);+			}+		}+	}+}++++// Should *only* be called when shapes with mass info are modified, added or removed.+void+cpBodyAccumulateMassFromShapes(cpBody *body)+{+	if(body == NULL || cpBodyGetType(body) != CP_BODY_TYPE_DYNAMIC) return;+	+	// Reset the body's mass data.+	body->m = body->i = 0.0f;+	body->cog = cpvzero;+	+	// Cache the position to realign it at the end.+	cpVect pos = cpBodyGetPosition(body);+	+	// Accumulate mass from shapes.+	CP_BODY_FOREACH_SHAPE(body, shape){+		struct cpShapeMassInfo *info = &shape->massInfo;+		cpFloat m = info->m;+		+		if(m > 0.0f){+			cpFloat msum = body->m + m;+			+			body->i += m*info->i + cpvdistsq(body->cog, info->cog)*(m*body->m)/msum;+			body->cog = cpvlerp(body->cog, info->cog, m/msum);+			body->m = msum;+		}+	}+	+	// Recalculate the inverses.+	body->m_inv = 1.0f/body->m;+	body->i_inv = 1.0f/body->i;+	+	// Realign the body since the CoG has probably moved.+	cpBodySetPosition(body, pos);+	cpAssertSaneBody(body);+}++cpSpace *+cpBodyGetSpace(const cpBody *body)+{+	return body->space;+}++cpFloat+cpBodyGetMass(const cpBody *body)+{+	return body->m;+}++void+cpBodySetMass(cpBody *body, cpFloat mass)+{+	cpAssertHard(cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC, "You cannot set the mass of kinematic or static bodies.");+	cpAssertHard(0.0f <= mass && mass < INFINITY, "Mass must be positive and finite.");+	+	cpBodyActivate(body);+	body->m = mass;+	body->m_inv = 1.0f/mass;+	cpAssertSaneBody(body);+}++cpFloat+cpBodyGetMoment(const cpBody *body)+{+	return body->i;+}++void+cpBodySetMoment(cpBody *body, cpFloat moment)+{+	cpAssertHard(moment >= 0.0f, "Moment of Inertia must be positive.");+	+	cpBodyActivate(body);+	body->i = moment;+	body->i_inv = 1.0f/moment;+	cpAssertSaneBody(body);+}++cpVect+cpBodyGetRotation(const cpBody *body)+{+	return cpv(body->transform.a, body->transform.b);+}++void+cpBodyAddShape(cpBody *body, cpShape *shape)+{+	cpShape *next = body->shapeList;+	if(next) next->prev = shape;+	+	shape->next = next;+	body->shapeList = shape;+	+	if(shape->massInfo.m > 0.0f){+		cpBodyAccumulateMassFromShapes(body);+	}+}++void+cpBodyRemoveShape(cpBody *body, cpShape *shape)+{+  cpShape *prev = shape->prev;+  cpShape *next = shape->next;+  +  if(prev){+		prev->next = next;+  } else {+		body->shapeList = next;+  }+  +  if(next){+		next->prev = prev;+	}+  +  shape->prev = NULL;+  shape->next = NULL;+	+	if(cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC && shape->massInfo.m > 0.0f){+		cpBodyAccumulateMassFromShapes(body);+	}+}++static cpConstraint *+filterConstraints(cpConstraint *node, cpBody *body, cpConstraint *filter)+{+	if(node == filter){+		return cpConstraintNext(node, body);+	} else if(node->a == body){+		node->next_a = filterConstraints(node->next_a, body, filter);+	} else {+		node->next_b = filterConstraints(node->next_b, body, filter);+	}+	+	return node;+}++void+cpBodyRemoveConstraint(cpBody *body, cpConstraint *constraint)+{+	body->constraintList = filterConstraints(body->constraintList, body, constraint);+}++// 'p' is the position of the CoG+static void+SetTransform(cpBody *body, cpVect p, cpFloat a)+{+	cpVect rot = cpvforangle(a);+	cpVect c = body->cog;+	+	body->transform = cpTransformNewTranspose(+		rot.x, -rot.y, p.x - (c.x*rot.x - c.y*rot.y),+		rot.y,  rot.x, p.y - (c.x*rot.y + c.y*rot.x)+	);+}++static inline cpFloat+SetAngle(cpBody *body, cpFloat a)+{+	body->a = a;+	cpAssertSaneBody(body);+	+	return a;+}++cpVect+cpBodyGetPosition(const cpBody *body)+{+	return cpTransformPoint(body->transform, cpvzero);+}++void+cpBodySetPosition(cpBody *body, cpVect position)+{+	cpBodyActivate(body);+	cpVect p = body->p = cpvadd(cpTransformVect(body->transform, body->cog), position);+	cpAssertSaneBody(body);+	+	SetTransform(body, p, body->a);+}++cpVect+cpBodyGetCenterOfGravity(const cpBody *body)+{+	return body->cog;+}++void+cpBodySetCenterOfGravity(cpBody *body, cpVect cog)+{+	cpBodyActivate(body);+	body->cog = cog;+	cpAssertSaneBody(body);+}++cpVect+cpBodyGetVelocity(const cpBody *body)+{+	return body->v;+}++void+cpBodySetVelocity(cpBody *body, cpVect velocity)+{+	cpBodyActivate(body);+	body->v = velocity;+	cpAssertSaneBody(body);+}++cpVect+cpBodyGetForce(const cpBody *body)+{+	return body->f;+}++void+cpBodySetForce(cpBody *body, cpVect force)+{+	cpBodyActivate(body);+	body->f = force;+	cpAssertSaneBody(body);+}++cpFloat+cpBodyGetAngle(const cpBody *body)+{+	return body->a;+}++void+cpBodySetAngle(cpBody *body, cpFloat angle)+{+	cpBodyActivate(body);+	SetAngle(body, angle);+	+	SetTransform(body, body->p, angle);+}++cpFloat+cpBodyGetAngularVelocity(const cpBody *body)+{+	return body->w;+}++void+cpBodySetAngularVelocity(cpBody *body, cpFloat angularVelocity)+{+	cpBodyActivate(body);+	body->w = angularVelocity;+	cpAssertSaneBody(body);+}++cpFloat+cpBodyGetTorque(const cpBody *body)+{+	return body->t;+}++void+cpBodySetTorque(cpBody *body, cpFloat torque)+{+	cpBodyActivate(body);+	body->t = torque;+	cpAssertSaneBody(body);+}++cpDataPointer+cpBodyGetUserData(const cpBody *body)+{+	return body->userData;+}++void+cpBodySetUserData(cpBody *body, cpDataPointer userData)+{+	body->userData = userData;+}++void+cpBodySetVelocityUpdateFunc(cpBody *body, cpBodyVelocityFunc velocityFunc)+{+	body->velocity_func = velocityFunc;+}++void+cpBodySetPositionUpdateFunc(cpBody *body, cpBodyPositionFunc positionFunc)+{+	body->position_func = positionFunc;+}++void+cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)+{+	// Skip kinematic bodies.+	if(cpBodyGetType(body) == CP_BODY_TYPE_KINEMATIC) return;+	+	cpAssertSoft(body->m > 0.0f && body->i > 0.0f, "Body's mass and moment must be positive to simulate. (Mass: %f Moment: %f)", body->m, body->i);+	+	body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));+	body->w = body->w*damping + body->t*body->i_inv*dt;+	+	// Reset forces.+	body->f = cpvzero;+	body->t = 0.0f;+	+	cpAssertSaneBody(body);+}++void+cpBodyUpdatePosition(cpBody *body, cpFloat dt)+{+	cpVect p = body->p = cpvadd(body->p, cpvmult(cpvadd(body->v, body->v_bias), dt));+	cpFloat a = SetAngle(body, body->a + (body->w + body->w_bias)*dt);+	SetTransform(body, p, a);+	+	body->v_bias = cpvzero;+	body->w_bias = 0.0f;+	+	cpAssertSaneBody(body);+}++cpVect+cpBodyLocalToWorld(const cpBody *body, const cpVect point)+{+	return cpTransformPoint(body->transform, point);+}++cpVect+cpBodyWorldToLocal(const cpBody *body, const cpVect point)+{+	return cpTransformPoint(cpTransformRigidInverse(body->transform), point);+}++void+cpBodyApplyForceAtWorldPoint(cpBody *body, cpVect force, cpVect point)+{+	cpBodyActivate(body);+	body->f = cpvadd(body->f, force);+	+	cpVect r = cpvsub(point, cpTransformPoint(body->transform, body->cog));+	body->t += cpvcross(r, force);+}++void+cpBodyApplyForceAtLocalPoint(cpBody *body, cpVect force, cpVect point)+{+	cpBodyApplyForceAtWorldPoint(body, cpTransformVect(body->transform, force), cpTransformPoint(body->transform, point));+}++void+cpBodyApplyImpulseAtWorldPoint(cpBody *body, cpVect impulse, cpVect point)+{+	cpBodyActivate(body);+	+	cpVect r = cpvsub(point, cpTransformPoint(body->transform, body->cog));+	apply_impulse(body, impulse, r);+}++void+cpBodyApplyImpulseAtLocalPoint(cpBody *body, cpVect impulse, cpVect point)+{+	cpBodyApplyImpulseAtWorldPoint(body, cpTransformVect(body->transform, impulse), cpTransformPoint(body->transform, point));+}++cpVect+cpBodyGetVelocityAtLocalPoint(const cpBody *body, cpVect point)+{+	cpVect r = cpTransformVect(body->transform, cpvsub(point, body->cog));+	return cpvadd(body->v, cpvmult(cpvperp(r), body->w));+}++cpVect+cpBodyGetVelocityAtWorldPoint(const cpBody *body, cpVect point)+{+	cpVect r = cpvsub(point, cpTransformPoint(body->transform, body->cog));+	return cpvadd(body->v, cpvmult(cpvperp(r), body->w));+}++cpFloat+cpBodyKineticEnergy(const cpBody *body)+{+	// Need to do some fudging to avoid NaNs+	cpFloat vsq = cpvdot(body->v, body->v);+	cpFloat wsq = body->w*body->w;+	return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f);+}++void+cpBodyEachShape(cpBody *body, cpBodyShapeIteratorFunc func, void *data)+{+	cpShape *shape = body->shapeList;+	while(shape){+		cpShape *next = shape->next;+		func(body, shape, data);+		shape = next;+	}+}++void+cpBodyEachConstraint(cpBody *body, cpBodyConstraintIteratorFunc func, void *data)+{+	cpConstraint *constraint = body->constraintList;+	while(constraint){+		cpConstraint *next = cpConstraintNext(constraint, body);+		func(body, constraint, data);+		constraint = next;+	}+}++void+cpBodyEachArbiter(cpBody *body, cpBodyArbiterIteratorFunc func, void *data)+{+	cpArbiter *arb = body->arbiterList;+	while(arb){+		cpArbiter *next = cpArbiterNext(arb, body);+		+		cpBool swapped = arb->swapped; {+			arb->swapped = (body == arb->body_b);+			func(body, arb, data);+		} arb->swapped = swapped;+		+		arb = next;+	}+}
+ Chipmunk2D-7.0.2/src/cpCollision.c view
@@ -0,0 +1,726 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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 <stdio.h>+#include <string.h>++#include "chipmunk/chipmunk_private.h"+#include "chipmunk/cpRobust.h"++#if DEBUG && 0+#include "ChipmunkDemo.h"+#define DRAW_ALL 0+#define DRAW_GJK (0 || DRAW_ALL)+#define DRAW_EPA (0 || DRAW_ALL)+#define DRAW_CLOSEST (0 || DRAW_ALL)+#define DRAW_CLIP (0 || DRAW_ALL)++#define PRINT_LOG 0+#endif++#define MAX_GJK_ITERATIONS 30+#define MAX_EPA_ITERATIONS 30+#define WARN_GJK_ITERATIONS 20+#define WARN_EPA_ITERATIONS 20++static inline void+cpCollisionInfoPushContact(struct cpCollisionInfo *info, cpVect p1, cpVect p2, cpHashValue hash)+{+	cpAssertSoft(info->count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal error: Tried to push too many contacts.");+	+	struct cpContact *con = &info->arr[info->count];+	con->r1 = p1;+	con->r2 = p2;+	con->hash = hash;+	+	info->count++;+}++//MARK: Support Points and Edges:++// Support points are the maximal points on a shape's perimeter along a certain axis.+// The GJK and EPA algorithms use support points to iteratively sample the surface of the two shapes' minkowski difference.++static inline int+PolySupportPointIndex(const int count, const struct cpSplittingPlane *planes, const cpVect n)+{+	cpFloat max = -INFINITY;+	int index = 0;+	+	for(int i=0; i<count; i++){+		cpVect v = planes[i].v0;+		cpFloat d = cpvdot(v, n);+		if(d > max){+			max = d;+			index = i;+		}+	}+	+	return index;+}++struct SupportPoint {+	cpVect p;+	// Save an index of the point so it can be cheaply looked up as a starting point for the next frame.+	cpCollisionID index;+};++static inline struct SupportPoint+SupportPointNew(cpVect p, cpCollisionID index)+{+	struct SupportPoint point = {p, index};+	return point;+}++typedef struct SupportPoint (*SupportPointFunc)(const cpShape *shape, const cpVect n);++static inline struct SupportPoint+CircleSupportPoint(const cpCircleShape *circle, const cpVect n)+{+	return SupportPointNew(circle->tc, 0);+}++static inline struct SupportPoint+SegmentSupportPoint(const cpSegmentShape *seg, const cpVect n)+{+	if(cpvdot(seg->ta, n) > cpvdot(seg->tb, n)){+		return SupportPointNew(seg->ta, 0);+	} else {+		return SupportPointNew(seg->tb, 1);+	}+}++static inline struct SupportPoint+PolySupportPoint(const cpPolyShape *poly, const cpVect n)+{+	const struct cpSplittingPlane *planes = poly->planes;+	int i = PolySupportPointIndex(poly->count, planes, n);+	return SupportPointNew(planes[i].v0, i);+}++// A point on the surface of two shape's minkowski difference.+struct MinkowskiPoint {+	// Cache the two original support points.+	cpVect a, b;+	// b - a+	cpVect ab;+	// Concatenate the two support point indexes.+	cpCollisionID id;+};++static inline struct MinkowskiPoint+MinkowskiPointNew(const struct SupportPoint a, const struct SupportPoint b)+{+	struct MinkowskiPoint point = {a.p, b.p, cpvsub(b.p, a.p), (a.index & 0xFF)<<8 | (b.index & 0xFF)};+	return point;+}++struct SupportContext {+	const cpShape *shape1, *shape2;+	SupportPointFunc func1, func2;+};++// Calculate the maximal point on the minkowski difference of two shapes along a particular axis.+static inline struct MinkowskiPoint+Support(const struct SupportContext *ctx, const cpVect n)+{+	struct SupportPoint a = ctx->func1(ctx->shape1, cpvneg(n));+	struct SupportPoint b = ctx->func2(ctx->shape2, n);+	return MinkowskiPointNew(a, b);+}++struct EdgePoint {+	cpVect p;+	// Keep a hash value for Chipmunk's collision hashing mechanism.+	cpHashValue hash;+};++// Support edges are the edges of a polygon or segment shape that are in contact.+struct Edge {+	struct EdgePoint a, b;+	cpFloat r;+	cpVect n;+};++static struct Edge+SupportEdgeForPoly(const cpPolyShape *poly, const cpVect n)+{+	int count = poly->count;+	int i1 = PolySupportPointIndex(poly->count, poly->planes, n);+	+	// TODO: get rid of mod eventually, very expensive on ARM+	int i0 = (i1 - 1 + count)%count;+	int i2 = (i1 + 1)%count;+	+	const struct cpSplittingPlane *planes = poly->planes;+	cpHashValue hashid = poly->shape.hashid;+	if(cpvdot(n, planes[i1].n) > cpvdot(n, planes[i2].n)){+		struct Edge edge = {{planes[i0].v0, CP_HASH_PAIR(hashid, i0)}, {planes[i1].v0, CP_HASH_PAIR(hashid, i1)}, poly->r, planes[i1].n};+		return edge;+	} else {+		struct Edge edge = {{planes[i1].v0, CP_HASH_PAIR(hashid, i1)}, {planes[i2].v0, CP_HASH_PAIR(hashid, i2)}, poly->r, planes[i2].n};+		return edge;+	}+}++static struct Edge+SupportEdgeForSegment(const cpSegmentShape *seg, const cpVect n)+{+	cpHashValue hashid = seg->shape.hashid;+	if(cpvdot(seg->tn, n) > 0.0){+		struct Edge edge = {{seg->ta, CP_HASH_PAIR(hashid, 0)}, {seg->tb, CP_HASH_PAIR(hashid, 1)}, seg->r, seg->tn};+		return edge;+	} else {+		struct Edge edge = {{seg->tb, CP_HASH_PAIR(hashid, 1)}, {seg->ta, CP_HASH_PAIR(hashid, 0)}, seg->r, cpvneg(seg->tn)};+		return edge;+	}+}++// Find the closest p(t) to (0, 0) where p(t) = a*(1-t)/2 + b*(1+t)/2+// The range for t is [-1, 1] to avoid floating point issues if the parameters are swapped.+static inline cpFloat+ClosestT(const cpVect a, const cpVect b)+{+	cpVect delta = cpvsub(b, a);+	return -cpfclamp(cpvdot(delta, cpvadd(a, b))/cpvlengthsq(delta), -1.0f, 1.0f);+}++// Basically the same as cpvlerp(), except t = [-1, 1]+static inline cpVect+LerpT(const cpVect a, const cpVect b, const cpFloat t)+{+	cpFloat ht = 0.5f*t;+	return cpvadd(cpvmult(a, 0.5f - ht), cpvmult(b, 0.5f + ht));+}++// Closest points on the surface of two shapes.+struct ClosestPoints {+	// Surface points in absolute coordinates.+	cpVect a, b;+	// Minimum separating axis of the two shapes.+	cpVect n;+	// Signed distance between the points.+	cpFloat d;+	// Concatenation of the id's of the minkoski points.+	cpCollisionID id;+};++// Calculate the closest points on two shapes given the closest edge on their minkowski difference to (0, 0)+static inline struct ClosestPoints+ClosestPointsNew(const struct MinkowskiPoint v0, const struct MinkowskiPoint v1)+{+	// Find the closest p(t) on the minkowski difference to (0, 0)+	cpFloat t = ClosestT(v0.ab, v1.ab);+	cpVect p = LerpT(v0.ab, v1.ab, t);+	+	// Interpolate the original support points using the same 't' value as above.+	// This gives you the closest surface points in absolute coordinates. NEAT!+	cpVect pa = LerpT(v0.a, v1.a, t);+	cpVect pb = LerpT(v0.b, v1.b, t);+	cpCollisionID id = (v0.id & 0xFFFF)<<16 | (v1.id & 0xFFFF);+	+	// First try calculating the MSA from the minkowski difference edge.+	// This gives us a nice, accurate MSA when the surfaces are close together.+	cpVect delta = cpvsub(v1.ab, v0.ab);+	cpVect n = cpvnormalize(cpvrperp(delta));+	cpFloat d = cpvdot(n, p);+	+	if(d <= 0.0f || (-1.0f < t && t < 1.0f)){+		// If the shapes are overlapping, or we have a regular vertex/edge collision, we are done.+		struct ClosestPoints points = {pa, pb, n, d, id};+		return points;+	} else {+		// Vertex/vertex collisions need special treatment since the MSA won't be shared with an axis of the minkowski difference.+		cpFloat d2 = cpvlength(p);+		cpVect n2 = cpvmult(p, 1.0f/(d2 + CPFLOAT_MIN));+		+		struct ClosestPoints points = {pa, pb, n2, d2, id};+		return points;+	}+}++//MARK: EPA Functions++static inline cpFloat+ClosestDist(const cpVect v0,const cpVect v1)+{+	return cpvlengthsq(LerpT(v0, v1, ClosestT(v0, v1)));+}++// Recursive implementation of the EPA loop.+// Each recursion adds a point to the convex hull until it's known that we have the closest point on the surface.+static struct ClosestPoints+EPARecurse(const struct SupportContext *ctx, const int count, const struct MinkowskiPoint *hull, const int iteration)+{+	int mini = 0;+	cpFloat minDist = INFINITY;+	+	// TODO: precalculate this when building the hull and save a step.+	// Find the closest segment hull[i] and hull[i + 1] to (0, 0)+	for(int j=0, i=count-1; j<count; i=j, j++){+		cpFloat d = ClosestDist(hull[i].ab, hull[j].ab);+		if(d < minDist){+			minDist = d;+			mini = i;+		}+	}+	+	struct MinkowskiPoint v0 = hull[mini];+	struct MinkowskiPoint v1 = hull[(mini + 1)%count];+	cpAssertSoft(!cpveql(v0.ab, v1.ab), "Internal Error: EPA vertexes are the same (%d and %d)", mini, (mini + 1)%count);+	+	// Check if there is a point on the minkowski difference beyond this edge.+	struct MinkowskiPoint p = Support(ctx, cpvperp(cpvsub(v1.ab, v0.ab)));+	+#if DRAW_EPA+	cpVect verts[count];+	for(int i=0; i<count; i++) verts[i] = hull[i].ab;+	+	ChipmunkDebugDrawPolygon(count, verts, 0.0, RGBAColor(1, 1, 0, 1), RGBAColor(1, 1, 0, 0.25));+	ChipmunkDebugDrawSegment(v0.ab, v1.ab, RGBAColor(1, 0, 0, 1));+	+	ChipmunkDebugDrawDot(5, p.ab, LAColor(1, 1));+#endif+	+	// The usual exit condition is a duplicated vertex.+	// Much faster to check the ids than to check the signed area.+	cpBool duplicate = (p.id == v0.id || p.id == v1.id);+	+	if(!duplicate && cpCheckPointGreater(v0.ab, v1.ab, p.ab) && iteration < MAX_EPA_ITERATIONS){+		// Rebuild the convex hull by inserting p.+		struct MinkowskiPoint *hull2 = (struct MinkowskiPoint *)alloca((count + 1)*sizeof(struct MinkowskiPoint));+		int count2 = 1;+		hull2[0] = p;+		+		for(int i=0; i<count; i++){+			int index = (mini + 1 + i)%count;+			+			cpVect h0 = hull2[count2 - 1].ab;+			cpVect h1 = hull[index].ab;+			cpVect h2 = (i + 1 < count ? hull[(index + 1)%count] : p).ab;+			+			if(cpCheckPointGreater(h0, h2, h1)){+				hull2[count2] = hull[index];+				count2++;+			}+		}+		+		return EPARecurse(ctx, count2, hull2, iteration + 1);+	} else {+		// Could not find a new point to insert, so we have found the closest edge of the minkowski difference.+		cpAssertWarn(iteration < WARN_EPA_ITERATIONS, "High EPA iterations: %d", iteration);+		return ClosestPointsNew(v0, v1);+	}+}++// Find the closest points on the surface of two overlapping shapes using the EPA algorithm.+// EPA is called from GJK when two shapes overlap.+// This is a moderately expensive step! Avoid it by adding radii to your shapes so their inner polygons won't overlap.+static struct ClosestPoints+EPA(const struct SupportContext *ctx, const struct MinkowskiPoint v0, const struct MinkowskiPoint v1, const struct MinkowskiPoint v2)+{+	// TODO: allocate a NxM array here and do an in place convex hull reduction in EPARecurse?+	struct MinkowskiPoint hull[3] = {v0, v1, v2};+	return EPARecurse(ctx, 3, hull, 1);+}++//MARK: GJK Functions.++// Recursive implementation of the GJK loop.+static inline struct ClosestPoints+GJKRecurse(const struct SupportContext *ctx, const struct MinkowskiPoint v0, const struct MinkowskiPoint v1, const int iteration)+{+	if(iteration > MAX_GJK_ITERATIONS){+		cpAssertWarn(iteration < WARN_GJK_ITERATIONS, "High GJK iterations: %d", iteration);+		return ClosestPointsNew(v0, v1);+	}+	+	if(cpCheckPointGreater(v1.ab, v0.ab, cpvzero)){+		// Origin is behind axis. Flip and try again.+		return GJKRecurse(ctx, v1, v0, iteration);+	} else {+		cpFloat t = ClosestT(v0.ab, v1.ab);+		cpVect n = (-1.0f < t && t < 1.0f ? cpvperp(cpvsub(v1.ab, v0.ab)) : cpvneg(LerpT(v0.ab, v1.ab, t)));+		struct MinkowskiPoint p = Support(ctx, n);+		+#if DRAW_GJK+		ChipmunkDebugDrawSegment(v0.ab, v1.ab, RGBAColor(1, 1, 1, 1));+		cpVect c = cpvlerp(v0.ab, v1.ab, 0.5);+		ChipmunkDebugDrawSegment(c, cpvadd(c, cpvmult(cpvnormalize(n), 5.0)), RGBAColor(1, 0, 0, 1));+		+		ChipmunkDebugDrawDot(5.0, p.ab, LAColor(1, 1));+#endif+		+		if(cpCheckPointGreater(p.ab, v0.ab, cpvzero) && cpCheckPointGreater(v1.ab, p.ab, cpvzero)){+			// The triangle v0, p, v1 contains the origin. Use EPA to find the MSA.+			cpAssertWarn(iteration < WARN_GJK_ITERATIONS, "High GJK->EPA iterations: %d", iteration);+			return EPA(ctx, v0, p, v1);+		} else {+			if(cpCheckAxis(v0.ab, v1.ab, p.ab, n)){+				// The edge v0, v1 that we already have is the closest to (0, 0) since p was not closer.+				cpAssertWarn(iteration < WARN_GJK_ITERATIONS, "High GJK iterations: %d", iteration);+				return ClosestPointsNew(v0, v1);+			} else {+				// p was closer to the origin than our existing edge.+				// Need to figure out which existing point to drop.+				if(ClosestDist(v0.ab, p.ab) < ClosestDist(p.ab, v1.ab)){+					return GJKRecurse(ctx, v0, p, iteration + 1);+				} else {+					return GJKRecurse(ctx, p, v1, iteration + 1);+				}+			}+		}+	}+}++// Get a SupportPoint from a cached shape and index.+static struct SupportPoint+ShapePoint(const cpShape *shape, const int i)+{+	switch(shape->klass->type){+		case CP_CIRCLE_SHAPE: {+			return SupportPointNew(((cpCircleShape *)shape)->tc, 0);+		} case CP_SEGMENT_SHAPE: {+			cpSegmentShape *seg = (cpSegmentShape *)shape;+			return SupportPointNew(i == 0 ? seg->ta : seg->tb, i);+		} case CP_POLY_SHAPE: {+			cpPolyShape *poly = (cpPolyShape *)shape;+			// Poly shapes may change vertex count.+			int index = (i < poly->count ? i : 0);+			return SupportPointNew(poly->planes[index].v0, index);+		} default: {+			return SupportPointNew(cpvzero, 0);+		}+	}+}++// Find the closest points between two shapes using the GJK algorithm.+static struct ClosestPoints+GJK(const struct SupportContext *ctx, cpCollisionID *id)+{+#if DRAW_GJK || DRAW_EPA+	int count1 = 1;+	int count2 = 1;+	+	switch(ctx->shape1->klass->type){+		case CP_SEGMENT_SHAPE: count1 = 2; break;+		case CP_POLY_SHAPE: count1 = ((cpPolyShape *)ctx->shape1)->count; break;+		default: break;+	}+	+	switch(ctx->shape2->klass->type){+		case CP_SEGMENT_SHAPE: count1 = 2; break;+		case CP_POLY_SHAPE: count2 = ((cpPolyShape *)ctx->shape2)->count; break;+		default: break;+	}+	+	+	// draw the minkowski difference origin+	cpVect origin = cpvzero;+	ChipmunkDebugDrawDot(5.0, origin, RGBAColor(1,0,0,1));+	+	int mdiffCount = count1*count2;+	cpVect *mdiffVerts = alloca(mdiffCount*sizeof(cpVect));+	+	for(int i=0; i<count1; i++){+		for(int j=0; j<count2; j++){+			cpVect v = cpvsub(ShapePoint(ctx->shape2, j).p, ShapePoint(ctx->shape1, i).p);+			mdiffVerts[i*count2 + j] = v;+			ChipmunkDebugDrawDot(2.0, v, RGBAColor(1, 0, 0, 1));+		}+	}+	 +	cpVect *hullVerts = alloca(mdiffCount*sizeof(cpVect));+	int hullCount = cpConvexHull(mdiffCount, mdiffVerts, hullVerts, NULL, 0.0);+	+	ChipmunkDebugDrawPolygon(hullCount, hullVerts, 0.0, RGBAColor(1, 0, 0, 1), RGBAColor(1, 0, 0, 0.25));+#endif+	+	struct MinkowskiPoint v0, v1;+	if(*id){+		// Use the minkowski points from the last frame as a starting point using the cached indexes.+		v0 = MinkowskiPointNew(ShapePoint(ctx->shape1, (*id>>24)&0xFF), ShapePoint(ctx->shape2, (*id>>16)&0xFF));+		v1 = MinkowskiPointNew(ShapePoint(ctx->shape1, (*id>> 8)&0xFF), ShapePoint(ctx->shape2, (*id    )&0xFF));+	} else {+		// No cached indexes, use the shapes' bounding box centers as a guess for a starting axis.+		cpVect axis = cpvperp(cpvsub(cpBBCenter(ctx->shape1->bb), cpBBCenter(ctx->shape2->bb)));+		v0 = Support(ctx, axis);+		v1 = Support(ctx, cpvneg(axis));+	}+	+	struct ClosestPoints points = GJKRecurse(ctx, v0, v1, 1);+	*id = points.id;+	return points;+}++//MARK: Contact Clipping++// Given two support edges, find contact point pairs on their surfaces.+static inline void+ContactPoints(const struct Edge e1, const struct Edge e2, const struct ClosestPoints points, struct cpCollisionInfo *info)+{+	cpFloat mindist = e1.r + e2.r;+	if(points.d <= mindist){+#ifdef DRAW_CLIP+	ChipmunkDebugDrawFatSegment(e1.a.p, e1.b.p, e1.r, RGBAColor(0, 1, 0, 1), LAColor(0, 0));+	ChipmunkDebugDrawFatSegment(e2.a.p, e2.b.p, e2.r, RGBAColor(1, 0, 0, 1), LAColor(0, 0));+#endif+		cpVect n = info->n = points.n;+		+		// Distances along the axis parallel to n+		cpFloat d_e1_a = cpvcross(e1.a.p, n);+		cpFloat d_e1_b = cpvcross(e1.b.p, n);+		cpFloat d_e2_a = cpvcross(e2.a.p, n);+		cpFloat d_e2_b = cpvcross(e2.b.p, n);+		+		// TODO + min isn't a complete fix.+		cpFloat e1_denom = 1.0f/(d_e1_b - d_e1_a + CPFLOAT_MIN);+		cpFloat e2_denom = 1.0f/(d_e2_b - d_e2_a + CPFLOAT_MIN);+		+		// Project the endpoints of the two edges onto the opposing edge, clamping them as necessary.+		// Compare the projected points to the collision normal to see if the shapes overlap there.+		{+			cpVect p1 = cpvadd(cpvmult(n,  e1.r), cpvlerp(e1.a.p, e1.b.p, cpfclamp01((d_e2_b - d_e1_a)*e1_denom)));+			cpVect p2 = cpvadd(cpvmult(n, -e2.r), cpvlerp(e2.a.p, e2.b.p, cpfclamp01((d_e1_a - d_e2_a)*e2_denom)));+			cpFloat dist = cpvdot(cpvsub(p2, p1), n);+			if(dist <= 0.0f){+				cpHashValue hash_1a2b = CP_HASH_PAIR(e1.a.hash, e2.b.hash);+				cpCollisionInfoPushContact(info, p1, p2, hash_1a2b);+			}+		}{+			cpVect p1 = cpvadd(cpvmult(n,  e1.r), cpvlerp(e1.a.p, e1.b.p, cpfclamp01((d_e2_a - d_e1_a)*e1_denom)));+			cpVect p2 = cpvadd(cpvmult(n, -e2.r), cpvlerp(e2.a.p, e2.b.p, cpfclamp01((d_e1_b - d_e2_a)*e2_denom)));+			cpFloat dist = cpvdot(cpvsub(p2, p1), n);+			if(dist <= 0.0f){+				cpHashValue hash_1b2a = CP_HASH_PAIR(e1.b.hash, e2.a.hash);+				cpCollisionInfoPushContact(info, p1, p2, hash_1b2a);+			}+		}+	}+}++//MARK: Collision Functions++typedef void (*CollisionFunc)(const cpShape *a, const cpShape *b, struct cpCollisionInfo *info);++// Collide circle shapes.+static void+CircleToCircle(const cpCircleShape *c1, const cpCircleShape *c2, struct cpCollisionInfo *info)+{+	cpFloat mindist = c1->r + c2->r;+	cpVect delta = cpvsub(c2->tc, c1->tc);+	cpFloat distsq = cpvlengthsq(delta);+	+	if(distsq < mindist*mindist){+		cpFloat dist = cpfsqrt(distsq);+		cpVect n = info->n = (dist ? cpvmult(delta, 1.0f/dist) : cpv(1.0f, 0.0f));+		cpCollisionInfoPushContact(info, cpvadd(c1->tc, cpvmult(n, c1->r)), cpvadd(c2->tc, cpvmult(n, -c2->r)), 0);+	}+}++static void+CircleToSegment(const cpCircleShape *circle, const cpSegmentShape *segment, struct cpCollisionInfo *info)+{+	cpVect seg_a = segment->ta;+	cpVect seg_b = segment->tb;+	cpVect center = circle->tc;+	+	// Find the closest point on the segment to the circle.+	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));+	+	// Compare the radii of the two shapes to see if they are colliding.+	cpFloat mindist = circle->r + segment->r;+	cpVect delta = cpvsub(closest, center);+	cpFloat distsq = cpvlengthsq(delta);+	if(distsq < mindist*mindist){+		cpFloat dist = cpfsqrt(distsq);+		// Handle coincident shapes as gracefully as possible.+		cpVect n = info->n = (dist ? cpvmult(delta, 1.0f/dist) : segment->tn);+		+		// Reject endcap collisions if tangents are provided.+		cpVect rot = cpBodyGetRotation(segment->shape.body);+		if(+			(closest_t != 0.0f || cpvdot(n, cpvrotate(segment->a_tangent, rot)) >= 0.0) &&+			(closest_t != 1.0f || cpvdot(n, cpvrotate(segment->b_tangent, rot)) >= 0.0)+		){+			cpCollisionInfoPushContact(info, cpvadd(center, cpvmult(n, circle->r)), cpvadd(closest, cpvmult(n, -segment->r)), 0);+		}+	}+}++static void+SegmentToSegment(const cpSegmentShape *seg1, const cpSegmentShape *seg2, struct cpCollisionInfo *info)+{+	struct SupportContext context = {(cpShape *)seg1, (cpShape *)seg2, (SupportPointFunc)SegmentSupportPoint, (SupportPointFunc)SegmentSupportPoint};+	struct ClosestPoints points = GJK(&context, &info->id);+	+#if DRAW_CLOSEST+#if PRINT_LOG+//	ChipmunkDemoPrintString("Distance: %.2f\n", points.d);+#endif+	+	ChipmunkDebugDrawDot(6.0, points.a, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawDot(6.0, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, cpvadd(points.a, cpvmult(points.n, 10.0)), RGBAColor(1, 0, 0, 1));+#endif+	+	cpVect n = points.n;+	cpVect rot1 = cpBodyGetRotation(seg1->shape.body);+	cpVect rot2 = cpBodyGetRotation(seg2->shape.body);+	+	// If the closest points are nearer than the sum of the radii...+	if(+		points.d <= (seg1->r + seg2->r) && (+			// Reject endcap collisions if tangents are provided.+			(!cpveql(points.a, seg1->ta) || cpvdot(n, cpvrotate(seg1->a_tangent, rot1)) <= 0.0) &&+			(!cpveql(points.a, seg1->tb) || cpvdot(n, cpvrotate(seg1->b_tangent, rot1)) <= 0.0) &&+			(!cpveql(points.b, seg2->ta) || cpvdot(n, cpvrotate(seg2->a_tangent, rot2)) >= 0.0) &&+			(!cpveql(points.b, seg2->tb) || cpvdot(n, cpvrotate(seg2->b_tangent, rot2)) >= 0.0)+		)+	){+		ContactPoints(SupportEdgeForSegment(seg1, n), SupportEdgeForSegment(seg2, cpvneg(n)), points, info);+	}+}++static void+PolyToPoly(const cpPolyShape *poly1, const cpPolyShape *poly2, struct cpCollisionInfo *info)+{+	struct SupportContext context = {(cpShape *)poly1, (cpShape *)poly2, (SupportPointFunc)PolySupportPoint, (SupportPointFunc)PolySupportPoint};+	struct ClosestPoints points = GJK(&context, &info->id);+	+#if DRAW_CLOSEST+#if PRINT_LOG+//	ChipmunkDemoPrintString("Distance: %.2f\n", points.d);+#endif+	+	ChipmunkDebugDrawDot(3.0, points.a, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawDot(3.0, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, cpvadd(points.a, cpvmult(points.n, 10.0)), RGBAColor(1, 0, 0, 1));+#endif+	+	// If the closest points are nearer than the sum of the radii...+	if(points.d - poly1->r - poly2->r <= 0.0){+		ContactPoints(SupportEdgeForPoly(poly1, points.n), SupportEdgeForPoly(poly2, cpvneg(points.n)), points, info);+	}+}++static void+SegmentToPoly(const cpSegmentShape *seg, const cpPolyShape *poly, struct cpCollisionInfo *info)+{+	struct SupportContext context = {(cpShape *)seg, (cpShape *)poly, (SupportPointFunc)SegmentSupportPoint, (SupportPointFunc)PolySupportPoint};+	struct ClosestPoints points = GJK(&context, &info->id);+	+#if DRAW_CLOSEST+#if PRINT_LOG+//	ChipmunkDemoPrintString("Distance: %.2f\n", points.d);+#endif+	+	ChipmunkDebugDrawDot(3.0, points.a, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawDot(3.0, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, cpvadd(points.a, cpvmult(points.n, 10.0)), RGBAColor(1, 0, 0, 1));+#endif+	+	cpVect n = points.n;+	cpVect rot = cpBodyGetRotation(seg->shape.body);+	+	if(+		// If the closest points are nearer than the sum of the radii...+		points.d - seg->r - poly->r <= 0.0 && (+			// Reject endcap collisions if tangents are provided.+			(!cpveql(points.a, seg->ta) || cpvdot(n, cpvrotate(seg->a_tangent, rot)) <= 0.0) &&+			(!cpveql(points.a, seg->tb) || cpvdot(n, cpvrotate(seg->b_tangent, rot)) <= 0.0)+		)+	){+		ContactPoints(SupportEdgeForSegment(seg, n), SupportEdgeForPoly(poly, cpvneg(n)), points, info);+	}+}++static void+CircleToPoly(const cpCircleShape *circle, const cpPolyShape *poly, struct cpCollisionInfo *info)+{+	struct SupportContext context = {(cpShape *)circle, (cpShape *)poly, (SupportPointFunc)CircleSupportPoint, (SupportPointFunc)PolySupportPoint};+	struct ClosestPoints points = GJK(&context, &info->id);+	+#if DRAW_CLOSEST+	ChipmunkDebugDrawDot(3.0, points.a, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawDot(3.0, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, points.b, RGBAColor(1, 1, 1, 1));+	ChipmunkDebugDrawSegment(points.a, cpvadd(points.a, cpvmult(points.n, 10.0)), RGBAColor(1, 0, 0, 1));+#endif+	+	// If the closest points are nearer than the sum of the radii...+	if(points.d <= circle->r + poly->r){+		cpVect n = info->n = points.n;+		cpCollisionInfoPushContact(info, cpvadd(points.a, cpvmult(n, circle->r)), cpvadd(points.b, cpvmult(n, poly->r)), 0);+	}+}++static void+CollisionError(const cpShape *circle, const cpShape *poly, struct cpCollisionInfo *info)+{+	cpAssertHard(cpFalse, "Internal Error: Shape types are not sorted.");+}+++static const CollisionFunc BuiltinCollisionFuncs[9] = {+	(CollisionFunc)CircleToCircle,+	CollisionError,+	CollisionError,+	(CollisionFunc)CircleToSegment,+	(CollisionFunc)SegmentToSegment,+	CollisionError,+	(CollisionFunc)CircleToPoly,+	(CollisionFunc)SegmentToPoly,+	(CollisionFunc)PolyToPoly,+};+static const CollisionFunc *CollisionFuncs = BuiltinCollisionFuncs;++struct cpCollisionInfo+cpCollide(const cpShape *a, const cpShape *b, cpCollisionID id, struct cpContact *contacts)+{+	struct cpCollisionInfo info = {a, b, id, cpvzero, 0, contacts};+	+	// Make sure the shape types are in order.+	if(a->klass->type > b->klass->type){+		info.a = b;+		info.b = a;+	}+	+	CollisionFuncs[info.a->klass->type + info.b->klass->type*CP_NUM_SHAPES](info.a, info.b, &info);+	+//	if(0){+//		for(int i=0; i<info.count; i++){+//			cpVect r1 = info.arr[i].r1;+//			cpVect r2 = info.arr[i].r2;+//			cpVect mid = cpvlerp(r1, r2, 0.5f);+//			+//			ChipmunkDebugDrawSegment(r1, mid, RGBAColor(1, 0, 0, 1));+//			ChipmunkDebugDrawSegment(r2, mid, RGBAColor(0, 0, 1, 1));+//		}+//	}+	+	return info;+}
+ Chipmunk2D-7.0.2/src/cpConstraint.c view
@@ -0,0 +1,173 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++// TODO: Comment me!++void cpConstraintDestroy(cpConstraint *constraint){}++void+cpConstraintFree(cpConstraint *constraint)+{+	if(constraint){+		cpConstraintDestroy(constraint);+		cpfree(constraint);+	}+}++void+cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b)+{+	constraint->klass = klass;+	+	constraint->a = a;+	constraint->b = b;+	constraint->space = NULL;+	+	constraint->next_a = NULL;+	constraint->next_b = NULL;+	+	constraint->maxForce = (cpFloat)INFINITY;+	constraint->errorBias = cpfpow(1.0f - 0.1f, 60.0f);+	constraint->maxBias = (cpFloat)INFINITY;+	+	constraint->collideBodies = cpTrue;+	+	constraint->preSolve = NULL;+	constraint->postSolve = NULL;+}++cpSpace *+cpConstraintGetSpace(const cpConstraint *constraint)+{+	return constraint->space;+}++cpBody *+cpConstraintGetBodyA(const cpConstraint *constraint)+{+	return constraint->a;+}++cpBody *+cpConstraintGetBodyB(const cpConstraint *constraint)+{+	return constraint->b;+}++cpFloat+cpConstraintGetMaxForce(const cpConstraint *constraint)+{+	return constraint->maxForce;+}++void+cpConstraintSetMaxForce(cpConstraint *constraint, cpFloat maxForce)+{+	cpAssertHard(maxForce >= 0.0f, "maxForce must be positive.");+	cpConstraintActivateBodies(constraint);+	constraint->maxForce = maxForce;+}++cpFloat+cpConstraintGetErrorBias(const cpConstraint *constraint)+{+	return constraint->errorBias;+}++void+cpConstraintSetErrorBias(cpConstraint *constraint, cpFloat errorBias)+{+	cpAssertHard(errorBias >= 0.0f, "errorBias must be positive.");+	cpConstraintActivateBodies(constraint);+	constraint->errorBias = errorBias;+}++cpFloat+cpConstraintGetMaxBias(const cpConstraint *constraint)+{+	return constraint->maxBias;+}++void+cpConstraintSetMaxBias(cpConstraint *constraint, cpFloat maxBias)+{+	cpAssertHard(maxBias >= 0.0f, "maxBias must be positive.");+	cpConstraintActivateBodies(constraint);+	constraint->maxBias = maxBias;+}++cpBool+cpConstraintGetCollideBodies(const cpConstraint *constraint)+{+	return constraint->collideBodies;+}++void+cpConstraintSetCollideBodies(cpConstraint *constraint, cpBool collideBodies)+{+	cpConstraintActivateBodies(constraint);+	constraint->collideBodies = collideBodies;+}++cpConstraintPreSolveFunc+cpConstraintGetPreSolveFunc(const cpConstraint *constraint)+{+	return constraint->preSolve;+}++void+cpConstraintSetPreSolveFunc(cpConstraint *constraint, cpConstraintPreSolveFunc preSolveFunc)+{+	constraint->preSolve = preSolveFunc;+}++cpConstraintPostSolveFunc+cpConstraintGetPostSolveFunc(const cpConstraint *constraint)+{+	return constraint->postSolve;+}++void+cpConstraintSetPostSolveFunc(cpConstraint *constraint, cpConstraintPostSolveFunc postSolveFunc)+{+	constraint->postSolve = postSolveFunc;+}++cpDataPointer+cpConstraintGetUserData(const cpConstraint *constraint)+{+	return constraint->userData;+}++void+cpConstraintSetUserData(cpConstraint *constraint, cpDataPointer userData)+{+	constraint->userData = userData;+}+++cpFloat+cpConstraintGetImpulse(cpConstraint *constraint)+{+	return constraint->klass->getImpulse(constraint);+}
+ Chipmunk2D-7.0.2/src/cpDampedRotarySpring.c view
@@ -0,0 +1,178 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static cpFloat+defaultSpringTorque(cpDampedRotarySpring *spring, cpFloat relativeAngle){+	return (relativeAngle - spring->restAngle)*spring->stiffness;+}++static void+preStep(cpDampedRotarySpring *spring, cpFloat dt)+{+	cpBody *a = spring->constraint.a;+	cpBody *b = spring->constraint.b;+	+	cpFloat moment = a->i_inv + b->i_inv;+	cpAssertSoft(moment != 0.0, "Unsolvable spring.");+	spring->iSum = 1.0f/moment;++	spring->w_coef = 1.0f - cpfexp(-spring->damping*dt*moment);+	spring->target_wrn = 0.0f;++	// apply spring torque+	cpFloat j_spring = spring->springTorqueFunc((cpConstraint *)spring, a->a - b->a)*dt;+	spring->jAcc = j_spring;+	+	a->w -= j_spring*a->i_inv;+	b->w += j_spring*b->i_inv;+}++static void applyCachedImpulse(cpDampedRotarySpring *spring, cpFloat dt_coef){}++static void+applyImpulse(cpDampedRotarySpring *spring, cpFloat dt)+{+	cpBody *a = spring->constraint.a;+	cpBody *b = spring->constraint.b;+	+	// compute relative velocity+	cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;+	+	// compute velocity loss from drag+	// not 100% certain this is derived correctly, though it makes sense+	cpFloat w_damp = (spring->target_wrn - wrn)*spring->w_coef;+	spring->target_wrn = wrn + w_damp;+	+	//apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));+	cpFloat j_damp = w_damp*spring->iSum;+	spring->jAcc += j_damp;+	+	a->w += j_damp*a->i_inv;+	b->w -= j_damp*b->i_inv;+}++static cpFloat+getImpulse(cpDampedRotarySpring *spring)+{+	return spring->jAcc;+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpDampedRotarySpring *+cpDampedRotarySpringAlloc(void)+{+	return (cpDampedRotarySpring *)cpcalloc(1, sizeof(cpDampedRotarySpring));+}++cpDampedRotarySpring *+cpDampedRotarySpringInit(cpDampedRotarySpring *spring, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)+{+	cpConstraintInit((cpConstraint *)spring, &klass, a, b);+	+	spring->restAngle = restAngle;+	spring->stiffness = stiffness;+	spring->damping = damping;+	spring->springTorqueFunc = (cpDampedRotarySpringTorqueFunc)defaultSpringTorque;+	+	spring->jAcc = 0.0f;+	+	return spring;+}++cpConstraint *+cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)+{+	return (cpConstraint *)cpDampedRotarySpringInit(cpDampedRotarySpringAlloc(), a, b, restAngle, stiffness, damping);+}++cpBool+cpConstraintIsDampedRotarySpring(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpFloat+cpDampedRotarySpringGetRestAngle(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	return ((cpDampedRotarySpring *)constraint)->restAngle;+}++void+cpDampedRotarySpringSetRestAngle(cpConstraint *constraint, cpFloat restAngle)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedRotarySpring *)constraint)->restAngle = restAngle;+}++cpFloat+cpDampedRotarySpringGetStiffness(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	return ((cpDampedRotarySpring *)constraint)->stiffness;+}++void+cpDampedRotarySpringSetStiffness(cpConstraint *constraint, cpFloat stiffness)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedRotarySpring *)constraint)->stiffness = stiffness;+}++cpFloat+cpDampedRotarySpringGetDamping(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	return ((cpDampedRotarySpring *)constraint)->damping;+}++void+cpDampedRotarySpringSetDamping(cpConstraint *constraint, cpFloat damping)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedRotarySpring *)constraint)->damping = damping;+}++cpDampedRotarySpringTorqueFunc+cpDampedRotarySpringGetSpringTorqueFunc(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	return ((cpDampedRotarySpring *)constraint)->springTorqueFunc;+}++void+cpDampedRotarySpringSetSpringTorqueFunc(cpConstraint *constraint, cpDampedRotarySpringTorqueFunc springTorqueFunc)+{+	cpAssertHard(cpConstraintIsDampedRotarySpring(constraint), "Constraint is not a damped rotary spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedRotarySpring *)constraint)->springTorqueFunc = springTorqueFunc;+}
+ Chipmunk2D-7.0.2/src/cpDampedSpring.c view
@@ -0,0 +1,216 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static cpFloat+defaultSpringForce(cpDampedSpring *spring, cpFloat dist){+	return (spring->restLength - dist)*spring->stiffness;+}++static void+preStep(cpDampedSpring *spring, cpFloat dt)+{+	cpBody *a = spring->constraint.a;+	cpBody *b = spring->constraint.b;+	+	spring->r1 = cpTransformVect(a->transform, cpvsub(spring->anchorA, a->cog));+	spring->r2 = cpTransformVect(b->transform, cpvsub(spring->anchorB, b->cog));+	+	cpVect delta = cpvsub(cpvadd(b->p, spring->r2), cpvadd(a->p, spring->r1));+	cpFloat dist = cpvlength(delta);+	spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));+	+	cpFloat k = k_scalar(a, b, spring->r1, spring->r2, spring->n);+	cpAssertSoft(k != 0.0, "Unsolvable spring.");+	spring->nMass = 1.0f/k;+	+	spring->target_vrn = 0.0f;+	spring->v_coef = 1.0f - cpfexp(-spring->damping*dt*k);++	// apply spring force+	cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist);+	cpFloat j_spring = spring->jAcc = f_spring*dt;+	apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, j_spring));+}++static void applyCachedImpulse(cpDampedSpring *spring, cpFloat dt_coef){}++static void+applyImpulse(cpDampedSpring *spring, cpFloat dt)+{+	cpBody *a = spring->constraint.a;+	cpBody *b = spring->constraint.b;+	+	cpVect n = spring->n;+	cpVect r1 = spring->r1;+	cpVect r2 = spring->r2;++	// compute relative velocity+	cpFloat vrn = normal_relative_velocity(a, b, r1, r2, n);+	+	// compute velocity loss from drag+	cpFloat v_damp = (spring->target_vrn - vrn)*spring->v_coef;+	spring->target_vrn = vrn + v_damp;+	+	cpFloat j_damp = v_damp*spring->nMass;+	spring->jAcc += j_damp;+	apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, j_damp));+}++static cpFloat+getImpulse(cpDampedSpring *spring)+{+	return spring->jAcc;+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpDampedSpring *+cpDampedSpringAlloc(void)+{+	return (cpDampedSpring *)cpcalloc(1, sizeof(cpDampedSpring));+}++cpDampedSpring *+cpDampedSpringInit(cpDampedSpring *spring, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat restLength, cpFloat stiffness, cpFloat damping)+{+	cpConstraintInit((cpConstraint *)spring, &klass, a, b);+	+	spring->anchorA = anchorA;+	spring->anchorB = anchorB;+	+	spring->restLength = restLength;+	spring->stiffness = stiffness;+	spring->damping = damping;+	spring->springForceFunc = (cpDampedSpringForceFunc)defaultSpringForce;+	+	spring->jAcc = 0.0f;+	+	return spring;+}++cpConstraint *+cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat restLength, cpFloat stiffness, cpFloat damping)+{+	return (cpConstraint *)cpDampedSpringInit(cpDampedSpringAlloc(), a, b, anchorA, anchorB, restLength, stiffness, damping);+}++cpBool+cpConstraintIsDampedSpring(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpVect+cpDampedSpringGetAnchorA(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	return ((cpDampedSpring *)constraint)->anchorA;+}++void+cpDampedSpringSetAnchorA(cpConstraint *constraint, cpVect anchorA)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedSpring *)constraint)->anchorA = anchorA;+}++cpVect+cpDampedSpringGetAnchorB(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	return ((cpDampedSpring *)constraint)->anchorB;+}++void+cpDampedSpringSetAnchorB(cpConstraint *constraint, cpVect anchorB)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedSpring *)constraint)->anchorB = anchorB;+}++cpFloat+cpDampedSpringGetRestLength(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	return ((cpDampedSpring *)constraint)->restLength;+}++void+cpDampedSpringSetRestLength(cpConstraint *constraint, cpFloat restLength)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedSpring *)constraint)->restLength = restLength;+}++cpFloat+cpDampedSpringGetStiffness(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	return ((cpDampedSpring *)constraint)->stiffness;+}++void+cpDampedSpringSetStiffness(cpConstraint *constraint, cpFloat stiffness)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedSpring *)constraint)->stiffness = stiffness;+}++cpFloat+cpDampedSpringGetDamping(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	return ((cpDampedSpring *)constraint)->damping;+}++void+cpDampedSpringSetDamping(cpConstraint *constraint, cpFloat damping)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedSpring *)constraint)->damping = damping;+}++cpDampedSpringForceFunc+cpDampedSpringGetSpringForceFunc(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	return ((cpDampedSpring *)constraint)->springForceFunc;+}++void+cpDampedSpringSetSpringForceFunc(cpConstraint *constraint, cpDampedSpringForceFunc springForceFunc)+{+	cpAssertHard(cpConstraintIsDampedSpring(constraint), "Constraint is not a damped spring.");+	cpConstraintActivateBodies(constraint);+	((cpDampedSpring *)constraint)->springForceFunc = springForceFunc;+}
+ Chipmunk2D-7.0.2/src/cpGearJoint.c view
@@ -0,0 +1,145 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpGearJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// calculate moment of inertia coefficient.+	joint->iSum = 1.0f/(a->i_inv*joint->ratio_inv + joint->ratio*b->i_inv);+	+	// 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);+}++static void+applyCachedImpulse(cpGearJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpFloat j = joint->jAcc*dt_coef;+	a->w -= j*a->i_inv*joint->ratio_inv;+	b->w += j*b->i_inv;+}++static void+applyImpulse(cpGearJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// 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, -jMax, jMax);+	j = joint->jAcc - jOld;+	+	// apply impulse+	a->w -= j*a->i_inv*joint->ratio_inv;+	b->w += j*b->i_inv;+}++static cpFloat+getImpulse(cpGearJoint *joint)+{+	return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpGearJoint *+cpGearJointAlloc(void)+{+	return (cpGearJoint *)cpcalloc(1, sizeof(cpGearJoint));+}++cpGearJoint *+cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->phase = phase;+	joint->ratio = ratio;+	joint->ratio_inv = 1.0f/ratio;+	+	joint->jAcc = 0.0f;+	+	return joint;+}++cpConstraint *+cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)+{+	return (cpConstraint *)cpGearJointInit(cpGearJointAlloc(), a, b, phase, ratio);+}++cpBool+cpConstraintIsGearJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpFloat+cpGearJointGetPhase(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsGearJoint(constraint), "Constraint is not a ratchet joint.");+	return ((cpGearJoint *)constraint)->phase;+}++void+cpGearJointSetPhase(cpConstraint *constraint, cpFloat phase)+{+	cpAssertHard(cpConstraintIsGearJoint(constraint), "Constraint is not a ratchet joint.");+	cpConstraintActivateBodies(constraint);+	((cpGearJoint *)constraint)->phase = phase;+}++cpFloat+cpGearJointGetRatio(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsGearJoint(constraint), "Constraint is not a ratchet joint.");+	return ((cpGearJoint *)constraint)->ratio;+}++void+cpGearJointSetRatio(cpConstraint *constraint, cpFloat ratio)+{+	cpAssertHard(cpConstraintIsGearJoint(constraint), "Constraint is not a ratchet joint.");+	cpConstraintActivateBodies(constraint);+	((cpGearJoint *)constraint)->ratio = ratio;+	((cpGearJoint *)constraint)->ratio_inv = 1.0f/ratio;+}
+ Chipmunk2D-7.0.2/src/cpGrooveJoint.c view
@@ -0,0 +1,197 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpGrooveJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// calculate endpoints in worldspace+	cpVect ta = cpTransformPoint(a->transform, joint->grv_a);+	cpVect tb = cpTransformPoint(a->transform, joint->grv_b);++	// calculate axis+	cpVect n = cpTransformVect(a->transform, joint->grv_n);+	cpFloat d = cpvdot(ta, n);+	+	joint->grv_tn = n;+	joint->r2 = cpTransformVect(b->transform, cpvsub(joint->anchorB, b->cog));+	+	// calculate tangential distance along the axis of r2+	cpFloat td = cpvcross(cpvadd(b->p, joint->r2), n);+	// calculate clamping factor and r2+	if(td <= cpvcross(ta, n)){+		joint->clamp = 1.0f;+		joint->r1 = cpvsub(ta, a->p);+	} else if(td >= cpvcross(tb, n)){+		joint->clamp = -1.0f;+		joint->r1 = cpvsub(tb, a->p);+	} else {+		joint->clamp = 0.0f;+		joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);+	}+	+	// Calculate mass tensor+	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));+	joint->bias = cpvclamp(cpvmult(delta, -bias_coef(joint->constraint.errorBias, dt)/dt), joint->constraint.maxBias);+}++static void+applyCachedImpulse(cpGrooveJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+		+	apply_impulses(a, b, joint->r1, joint->r2, cpvmult(joint->jAcc, dt_coef));+}++static inline cpVect+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->constraint.maxForce*dt);+}++static void+applyImpulse(cpGrooveJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpVect r1 = joint->r1;+	cpVect r2 = joint->r2;+	+	// compute impulse+	cpVect vr = relative_velocity(a, b, r1, r2);++	cpVect j = cpMat2x2Transform(joint->k, cpvsub(joint->bias, vr));+	cpVect jOld = joint->jAcc;+	joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j), dt);+	j = cpvsub(joint->jAcc, jOld);+	+	// apply impulse+	apply_impulses(a, b, joint->r1, joint->r2, j);+}++static cpFloat+getImpulse(cpGrooveJoint *joint)+{+	return cpvlength(joint->jAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpGrooveJoint *+cpGrooveJointAlloc(void)+{+	return (cpGrooveJoint *)cpcalloc(1, sizeof(cpGrooveJoint));+}++cpGrooveJoint *+cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchorB)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->grv_a = groove_a;+	joint->grv_b = groove_b;+	joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));+	joint->anchorB = anchorB;+	+	joint->jAcc = cpvzero;+	+	return joint;+}++cpConstraint *+cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchorB)+{+	return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchorB);+}++cpBool+cpConstraintIsGrooveJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpVect+cpGrooveJointGetGrooveA(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsGrooveJoint(constraint), "Constraint is not a groove joint.");+	return ((cpGrooveJoint *)constraint)->grv_a;+}++void+cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value)+{+	cpAssertHard(cpConstraintIsGrooveJoint(constraint), "Constraint is not a groove joint.");+	cpGrooveJoint *g = (cpGrooveJoint *)constraint;+	+	g->grv_a = value;+	g->grv_n = cpvperp(cpvnormalize(cpvsub(g->grv_b, value)));+	+	cpConstraintActivateBodies(constraint);+}++cpVect+cpGrooveJointGetGrooveB(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsGrooveJoint(constraint), "Constraint is not a groove joint.");+	return ((cpGrooveJoint *)constraint)->grv_b;+}++void+cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value)+{+	cpAssertHard(cpConstraintIsGrooveJoint(constraint), "Constraint is not a groove joint.");+	cpGrooveJoint *g = (cpGrooveJoint *)constraint;+	+	g->grv_b = value;+	g->grv_n = cpvperp(cpvnormalize(cpvsub(value, g->grv_a)));+	+	cpConstraintActivateBodies(constraint);+}++cpVect+cpGrooveJointGetAnchorB(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsGrooveJoint(constraint), "Constraint is not a groove joint.");+	return ((cpGrooveJoint *)constraint)->anchorB;+}++void+cpGrooveJointSetAnchorB(cpConstraint *constraint, cpVect anchorB)+{+	cpAssertHard(cpConstraintIsGrooveJoint(constraint), "Constraint is not a groove joint.");+	cpConstraintActivateBodies(constraint);+	((cpGrooveJoint *)constraint)->anchorB = anchorB;+}
+ Chipmunk2D-7.0.2/src/cpHashSet.c view
@@ -0,0 +1,253 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"+#include "prime.h"++typedef struct cpHashSetBin {+	void *elt;+	cpHashValue hash;+	struct cpHashSetBin *next;+} cpHashSetBin;++struct cpHashSet {+	unsigned int entries, size;+	+	cpHashSetEqlFunc eql;+	void *default_value;+	+	cpHashSetBin **table;+	cpHashSetBin *pooledBins;+	+	cpArray *allocatedBuffers;+};++void+cpHashSetFree(cpHashSet *set)+{+	if(set){+		cpfree(set->table);+		+		cpArrayFreeEach(set->allocatedBuffers, cpfree);+		cpArrayFree(set->allocatedBuffers);+		+		cpfree(set);+	}+}++cpHashSet *+cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc)+{+	cpHashSet *set = (cpHashSet *)cpcalloc(1, sizeof(cpHashSet));+	+	set->size = next_prime(size);+	set->entries = 0;+	+	set->eql = eqlFunc;+	set->default_value = NULL;+	+	set->table = (cpHashSetBin **)cpcalloc(set->size, sizeof(cpHashSetBin *));+	set->pooledBins = NULL;+	+	set->allocatedBuffers = cpArrayNew(0);+	+	return set;+}++void+cpHashSetSetDefaultValue(cpHashSet *set, void *default_value)+{+	set->default_value = default_value;+}++static int+setIsFull(cpHashSet *set)+{+	return (set->entries >= set->size);+}++static void+cpHashSetResize(cpHashSet *set)+{+	// Get the next approximate doubled prime.+	unsigned int newSize = next_prime(set->size + 1);+	// Allocate a new table.+	cpHashSetBin **newTable = (cpHashSetBin **)cpcalloc(newSize, sizeof(cpHashSetBin *));+	+	// Iterate over the chains.+	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;+			+			cpHashValue idx = bin->hash%newSize;+			bin->next = newTable[idx];+			newTable[idx] = bin;+			+			bin = next;+		}+	}+	+	cpfree(set->table);+	+	set->table = newTable;+	set->size = newSize;+}++static inline void+recycleBin(cpHashSet *set, cpHashSetBin *bin)+{+	bin->next = set->pooledBins;+	set->pooledBins = bin;+	bin->elt = NULL;+}++static cpHashSetBin *+getUnusedBin(cpHashSet *set)+{+	cpHashSetBin *bin = set->pooledBins;+	+	if(bin){+		set->pooledBins = bin->next;+		return bin;+	} else {+		// Pool is exhausted, make more+		int count = CP_BUFFER_BYTES/sizeof(cpHashSetBin);+		cpAssertHard(count, "Internal Error: Buffer size is too small.");+		+		cpHashSetBin *buffer = (cpHashSetBin *)cpcalloc(1, CP_BUFFER_BYTES);+		cpArrayPush(set->allocatedBuffers, buffer);+		+		// push all but the first one, return it instead+		for(int i=1; i<count; i++) recycleBin(set, buffer + i);+		return buffer;+	}+}++int+cpHashSetCount(cpHashSet *set)+{+	return set->entries;+}++void *+cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, cpHashSetTransFunc trans, void *data)+{+	cpHashValue idx = hash%set->size;+	+	// Find the bin with the matching element.+	cpHashSetBin *bin = set->table[idx];+	while(bin && !set->eql(ptr, bin->elt))+		bin = bin->next;+	+	// Create it if necessary.+	if(!bin){+		bin = getUnusedBin(set);+		bin->hash = hash;+		bin->elt = (trans ? trans(ptr, data) : data);+		+		bin->next = set->table[idx];+		set->table[idx] = bin;+		+		set->entries++;+		if(setIsFull(set)) cpHashSetResize(set);+	}+	+	return bin->elt;+}++void *+cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr)+{+	cpHashValue idx = hash%set->size;+	+	cpHashSetBin **prev_ptr = &set->table[idx];+	cpHashSetBin *bin = set->table[idx];+	+	// Find the bin+	while(bin && !set->eql(ptr, bin->elt)){+		prev_ptr = &bin->next;+		bin = bin->next;+	}+	+	// Remove it if it exists.+	if(bin){+		// Update the previous linked list pointer+		(*prev_ptr) = bin->next;+		set->entries--;+		+		void *elt = bin->elt;+		recycleBin(set, bin);+		+		return elt;+	}+	+	return NULL;+}++void *+cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr)+{	+	cpHashValue idx = hash%set->size;+	cpHashSetBin *bin = set->table[idx];+	while(bin && !set->eql(ptr, bin->elt))+		bin = bin->next;+		+	return (bin ? bin->elt : set->default_value);+}++void+cpHashSetEach(cpHashSet *set, cpHashSetIteratorFunc func, void *data)+{+	for(unsigned int i=0; i<set->size; i++){+		cpHashSetBin *bin = set->table[i];+		while(bin){+			cpHashSetBin *next = bin->next;+			func(bin->elt, data);+			bin = next;+		}+	}+}++void+cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data)+{+	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];+		while(bin){+			cpHashSetBin *next = bin->next;+			+			if(func(bin->elt, data)){+				prev_ptr = &bin->next;+			} else {+				(*prev_ptr) = next;++				set->entries--;+				recycleBin(set, bin);+			}+			+			bin = next;+		}+	}+}
+ Chipmunk2D-7.0.2/src/cpHastySpace.c view
@@ -0,0 +1,694 @@+// Copyright 2013 Howling Moon Software. All rights reserved.+// See http://chipmunk2d.net/legal.php for more information.++#include <stdlib.h>+#include <stdio.h>++//TODO: Move all the thread stuff to another file++//#include <sys/param.h >+#ifndef _WIN32+#include <sys/sysctl.h>+#include <pthread.h>+#else+#ifndef WIN32_LEAN_AND_MEAN+#define WIN32_LEAN_AND_MEAN+#endif++#ifndef NOMINMAX+#define NOMINMAX+#endif++#include <process.h> // _beginthreadex+#include <windows.h>++#ifndef ETIMEDOUT+#define ETIMEDOUT 1+#endif++// Simple pthread implementation for Windows+// Made from scratch to avoid the LGPL licence from pthread-win32+enum {+	SIGNAL = 0,+	BROADCAST = 1,+	MAX_EVENTS = 2+};++typedef HANDLE pthread_t;+typedef struct+{+	// Based on http://www.cs.wustl.edu/~schmidt/win32-cv-1.html since Windows has no condition variable until NT6+	UINT waiters_count;+	// Count of the number of waiters.++	CRITICAL_SECTION waiters_count_lock;+	// Serialize access to <waiters_count_>.++	HANDLE events[MAX_EVENTS];+} pthread_cond_t;+typedef CRITICAL_SECTION pthread_mutex_t;++typedef struct {} pthread_condattr_t; // Dummy;++int pthread_cond_destroy(pthread_cond_t* cv)+{+	CloseHandle(cv->events[BROADCAST]);+	CloseHandle(cv->events[SIGNAL]);++	DeleteCriticalSection(&cv->waiters_count_lock);++	return 0;+}++int pthread_cond_init(pthread_cond_t* cv, const pthread_condattr_t* attr)+{+	// Initialize the count to 0.+	cv->waiters_count = 0;++	// Create an auto-reset event.+	cv->events[SIGNAL] = CreateEvent(NULL,  // no security+	                                 FALSE, // auto-reset event+	                                 FALSE, // non-signaled initially+	                                 NULL); // unnamed++	// Create a manual-reset event.+	cv->events[BROADCAST] = CreateEvent(NULL,  // no security+	                                    TRUE,  // manual-reset+	                                    FALSE, // non-signaled initially+	                                    NULL); // unnamed++	InitializeCriticalSection(&cv->waiters_count_lock);++	return 0;+}++int pthread_cond_broadcast(pthread_cond_t *cv)+{+	// Avoid race conditions.+	EnterCriticalSection(&cv->waiters_count_lock);+	int have_waiters = cv->waiters_count > 0;+	LeaveCriticalSection(&cv->waiters_count_lock);++	if (have_waiters)+		SetEvent(cv->events[BROADCAST]);++	return 0;+}++int pthread_cond_signal(pthread_cond_t* cv)+{+	// Avoid race conditions.+	EnterCriticalSection(&cv->waiters_count_lock);+	int have_waiters = cv->waiters_count > 0;+	LeaveCriticalSection(&cv->waiters_count_lock);++	if (have_waiters)+		SetEvent(cv->events[SIGNAL]);++	return 0;+}++int pthread_cond_wait(pthread_cond_t* cv, pthread_mutex_t* external_mutex)+{+	// Avoid race conditions.+	EnterCriticalSection(&cv->waiters_count_lock);+	cv->waiters_count++;+	LeaveCriticalSection(&cv->waiters_count_lock);++	// It's ok to release the <external_mutex> here since Win32+	// manual-reset events maintain state when used with+	// <SetEvent>.  This avoids the "lost wakeup" bug...+	LeaveCriticalSection(external_mutex);++	// Wait for either event to become signaled due to <pthread_cond_signal>+	// being called or <pthread_cond_broadcast> being called.+	int result = WaitForMultipleObjects(2, cv->events, FALSE, INFINITE);++	EnterCriticalSection(&cv->waiters_count_lock);+	cv->waiters_count--;+	int last_waiter =+		result == WAIT_OBJECT_0 + BROADCAST+		&& cv->waiters_count == 0;+	LeaveCriticalSection(&cv->waiters_count_lock);++	// Some thread called <pthread_cond_broadcast>.+	if (last_waiter)+		// We're the last waiter to be notified or to stop waiting, so+		// reset the manual event. +		ResetEvent(cv->events[BROADCAST]);++	// Reacquire the <external_mutex>.+	EnterCriticalSection(external_mutex);++	return result == WAIT_TIMEOUT ? ETIMEDOUT : 0;+}++typedef struct {} pthread_mutexattr_t; //< Dummy++int pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* attr)+{+	InitializeCriticalSection(mutex);+	return 0;+}++int pthread_mutex_destroy(pthread_mutex_t* mutex)+{+	DeleteCriticalSection(mutex);+	return 0;+}++int pthread_mutex_lock(pthread_mutex_t* mutex)+{+	EnterCriticalSection(mutex);+	return 0;+}++int pthread_mutex_unlock(pthread_mutex_t* mutex)+{+	LeaveCriticalSection(mutex);+	return 0;+}++typedef struct {} pthread_attr_t;++typedef struct+{+	void *(*start_routine) (void *);+	void* arg;+} pthread_internal_thread;++unsigned int __stdcall ThreadProc(void* userdata)+{+	pthread_internal_thread* ud = (pthread_internal_thread*) userdata;+	ud->start_routine(ud->arg);++	free(ud);++	return 0;+}++int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void *(*start_routine) (void *), void *arg)+{+	pthread_internal_thread* ud = (pthread_internal_thread*) malloc(sizeof(pthread_internal_thread));+	ud->start_routine = start_routine;+	ud->arg = arg;++	*thread = (HANDLE) (_beginthreadex(NULL, 0, &ThreadProc, ud, 0, NULL));+	if (!*thread)+		return 1;++	return 0;+}++int pthread_join(pthread_t thread, void **value_ptr)+{+	WaitForSingleObject(thread, INFINITE);+	CloseHandle(thread);++	return 0;+}++#endif++#include "chipmunk/chipmunk_private.h"+#include "chipmunk/cpHastySpace.h"+++//MARK: ARM NEON Solver++#if __ARM_NEON__+#include <arm_neon.h>++// Tested and known to work fine with Clang 3.0 and GCC 4.2+// Doesn't work with Clang 1.6, and I have no idea why.+#if defined(__clang_major__) && __clang_major__ < 3+	#error Compiler not supported.+#endif++#if CP_USE_DOUBLES+	#if !__arm64+		#error Cannot use CP_USE_DOUBLES on 32 bit ARM.+	#endif+	+	typedef float64_t cpFloat_t;+	typedef float64x2_t cpFloatx2_t;+	#define vld vld1q_f64+	#define vdup_n vdupq_n_f64+	#define vst vst1q_f64+	#define vst_lane vst1q_lane_f64+	#define vadd vaddq_f64+	#define vsub vsubq_f64+	#define vpadd vpaddq_f64+	#define vmul vmulq_f64+	#define vmul_n vmulq_n_f64+	#define vneg vnegq_f64+	#define vget_lane vgetq_lane_f64+	#define vset_lane vsetq_lane_f64+	#define vmin vminq_f64+	#define vmax vmaxq_f64+	#define vrev(__a) __builtin_shufflevector(__a, __a, 1, 0)+#else+	typedef float32_t cpFloat_t;+	typedef float32x2_t cpFloatx2_t;+	#define vld vld1_f32+	#define vdup_n vdup_n_f32+	#define vst vst1_f32+	#define vst_lane vst1_lane_f32+	#define vadd vadd_f32+	#define vsub vsub_f32+	#define vpadd vpadd_f32+	#define vmul vmul_f32+	#define vmul_n vmul_n_f32+	#define vneg vneg_f32+	#define vget_lane vget_lane_f32+	#define vset_lane vset_lane_f32+	#define vmin vmin_f32+	#define vmax vmax_f32+	#define vrev vrev64_f32+#endif++// TODO could probably do better here, maybe using vcreate?+// especially for the constants+// Maybe use the {} notation for GCC/Clang?+static inline cpFloatx2_t+vmake(cpFloat_t x, cpFloat_t y)+{+//	cpFloatx2_t v = {};+//	v = vset_lane(x, v, 0);+//	v = vset_lane(y, v, 1);+//	+//	return v;+	+	// This might not be super compatible, but all the NEON headers use it...+	return (cpFloatx2_t){x, y};+}++static void+cpArbiterApplyImpulse_NEON(cpArbiter *arb)+{+	cpBody *a = arb->body_a;+	cpBody *b = arb->body_b;+	cpFloatx2_t surface_vr = vld((cpFloat_t *)&arb->surface_vr);+	cpFloatx2_t n = vld((cpFloat_t *)&arb->n);+	cpFloat_t friction = arb->u;+	+	int numContacts = arb->count;+	struct cpContact *contacts = arb->contacts;+	for(int i=0; i<numContacts; i++){+		struct cpContact *con = contacts + i;+		cpFloatx2_t r1 = vld((cpFloat_t *)&con->r1);+		cpFloatx2_t r2 = vld((cpFloat_t *)&con->r2);+		+		cpFloatx2_t perp = vmake(-1.0, 1.0);+		cpFloatx2_t r1p = vmul(vrev(r1), perp);+		cpFloatx2_t r2p = vmul(vrev(r2), perp);+		+		cpFloatx2_t vBias_a = vld((cpFloat_t *)&a->v_bias);+		cpFloatx2_t vBias_b = vld((cpFloat_t *)&b->v_bias);+		cpFloatx2_t wBias = vmake(a->w_bias, b->w_bias);+		+		cpFloatx2_t vb1 = vadd(vBias_a, vmul_n(r1p, vget_lane(wBias, 0)));+		cpFloatx2_t vb2 = vadd(vBias_b, vmul_n(r2p, vget_lane(wBias, 1)));+		cpFloatx2_t vbr = vsub(vb2, vb1);+		+		cpFloatx2_t v_a = vld((cpFloat_t *)&a->v);+		cpFloatx2_t v_b = vld((cpFloat_t *)&b->v);+		cpFloatx2_t w = vmake(a->w, b->w);+		cpFloatx2_t v1 = vadd(v_a, vmul_n(r1p, vget_lane(w, 0)));+		cpFloatx2_t v2 = vadd(v_b, vmul_n(r2p, vget_lane(w, 1)));+		cpFloatx2_t vr = vsub(v2, v1);+		+		cpFloatx2_t vbn_vrn = vpadd(vmul(vbr, n), vmul(vr, n));+		+		cpFloatx2_t v_offset = vmake(con->bias, -con->bounce);+		cpFloatx2_t jOld = vmake(con->jBias, con->jnAcc);+		cpFloatx2_t jbn_jn = vmul_n(vsub(v_offset, vbn_vrn), con->nMass);+		jbn_jn = vmax(vadd(jOld, jbn_jn), vdup_n(0.0));+		cpFloatx2_t jApply = vsub(jbn_jn, jOld);+		+		cpFloatx2_t t = vmul(vrev(n), perp);+		cpFloatx2_t vrt_tmp = vmul(vadd(vr, surface_vr), t);+		cpFloatx2_t vrt = vpadd(vrt_tmp, vrt_tmp);+		+		cpFloatx2_t jtOld = {}; jtOld = vset_lane(con->jtAcc, jtOld, 0);+		cpFloatx2_t jtMax = vrev(vmul_n(jbn_jn, friction));+		cpFloatx2_t jt = vmul_n(vrt, -con->tMass);+		jt = vmax(vneg(jtMax), vmin(vadd(jtOld, jt), jtMax));+		cpFloatx2_t jtApply = vsub(jt, jtOld);+		+		cpFloatx2_t i_inv = vmake(-a->i_inv, b->i_inv);+		cpFloatx2_t nperp = vmake(1.0, -1.0);+		+		cpFloatx2_t jBias = vmul_n(n, vget_lane(jApply, 0));+		cpFloatx2_t jBiasCross = vmul(vrev(jBias), nperp);+		cpFloatx2_t biasCrosses = vpadd(vmul(r1, jBiasCross), vmul(r2, jBiasCross));+		wBias = vadd(wBias, vmul(i_inv, biasCrosses));+		+		vBias_a = vsub(vBias_a, vmul_n(jBias, a->m_inv));+		vBias_b = vadd(vBias_b, vmul_n(jBias, b->m_inv));+		+		cpFloatx2_t j = vadd(vmul_n(n, vget_lane(jApply, 1)), vmul_n(t, vget_lane(jtApply, 0)));+		cpFloatx2_t jCross = vmul(vrev(j), nperp);+		cpFloatx2_t crosses = vpadd(vmul(r1, jCross), vmul(r2, jCross));+		w = vadd(w, vmul(i_inv, crosses));+		+		v_a = vsub(v_a, vmul_n(j, a->m_inv));+		v_b = vadd(v_b, vmul_n(j, b->m_inv));+		+		// TODO would moving these earlier help pipeline them better?+		vst((cpFloat_t *)&a->v_bias, vBias_a);+		vst((cpFloat_t *)&b->v_bias, vBias_b);+		vst_lane((cpFloat_t *)&a->w_bias, wBias, 0);+		vst_lane((cpFloat_t *)&b->w_bias, wBias, 1);+		+		vst((cpFloat_t *)&a->v, v_a);+		vst((cpFloat_t *)&b->v, v_b);+		vst_lane((cpFloat_t *)&a->w, w, 0);+		vst_lane((cpFloat_t *)&b->w, w, 1);+		+		vst_lane((cpFloat_t *)&con->jBias, jbn_jn, 0);+		vst_lane((cpFloat_t *)&con->jnAcc, jbn_jn, 1);+		vst_lane((cpFloat_t *)&con->jtAcc, jt, 0);+	}+}++#endif++//MARK: PThreads++// Right now using more than 2 threads probably wont help your performance any.+// If you are using a ridiculous number of iterations it could help though.+#define MAX_THREADS 2++struct ThreadContext {+	pthread_t thread;+	cpHastySpace *space;+	unsigned long thread_num;+};++typedef	void (*cpHastySpaceWorkFunction)(cpSpace *space, unsigned long worker, unsigned long worker_count);++struct cpHastySpace {+	cpSpace space;+	+	// Number of worker threads (including the main thread)+	unsigned long num_threads;+	+	// Number of worker threads currently executing. (also including the main thread)+	unsigned long num_working;+	+	// Number of constraints (plus contacts) that must exist per step to start the worker threads.+	unsigned long constraint_count_threshold;+	+	pthread_mutex_t mutex;+	pthread_cond_t cond_work, cond_resume;+	+	// Work function to invoke.+	cpHastySpaceWorkFunction work;+	+	struct ThreadContext workers[MAX_THREADS - 1];+};++static void *+WorkerThreadLoop(struct ThreadContext *context)+{+	cpHastySpace *hasty = context->space;+	+	unsigned long thread = context->thread_num;+	unsigned long num_threads = hasty->num_threads;+	+	for(;;){+		pthread_mutex_lock(&hasty->mutex); {+			if(--hasty->num_working == 0){+				pthread_cond_signal(&hasty->cond_resume);+			}+			+			pthread_cond_wait(&hasty->cond_work, &hasty->mutex);+		} pthread_mutex_unlock(&hasty->mutex);+		+		cpHastySpaceWorkFunction func = hasty->work;+		if(func){+			hasty->work(&hasty->space, thread, num_threads);+		} else {+			break;+		}+	}+	+	return NULL;+}++static void+RunWorkers(cpHastySpace *hasty, cpHastySpaceWorkFunction func)+{+	hasty->num_working = hasty->num_threads - 1;+	hasty->work = func;+	+	if(hasty->num_working > 0){+		pthread_mutex_lock(&hasty->mutex); {+			pthread_cond_broadcast(&hasty->cond_work);+		} pthread_mutex_unlock(&hasty->mutex);+		+		func((cpSpace *)hasty, 0, hasty->num_threads);+			+		pthread_mutex_lock(&hasty->mutex); {+			if(hasty->num_working > 0){+				pthread_cond_wait(&hasty->cond_resume, &hasty->mutex);+			}+		} pthread_mutex_unlock(&hasty->mutex);+	} else {+		func((cpSpace *)hasty, 0, hasty->num_threads);+	}+	+	hasty->work = NULL;+}++static void+Solver(cpSpace *space, unsigned long worker, unsigned long worker_count)+{+	cpArray *constraints = space->constraints;+	cpArray *arbiters = space->arbiters;+	+	cpFloat dt = space->curr_dt;+	unsigned long iterations = (space->iterations + worker_count - 1)/worker_count;+	+	for(unsigned long i=0; i<iterations; i++){+		for(int j=0; j<arbiters->num; j++){+			cpArbiter *arb = (cpArbiter *)arbiters->arr[j];+			#ifdef __ARM_NEON__+				cpArbiterApplyImpulse_NEON(arb);+			#else+				cpArbiterApplyImpulse(arb);+			#endif+		}+			+		for(int j=0; j<constraints->num; j++){+			cpConstraint *constraint = (cpConstraint *)constraints->arr[j];+			constraint->klass->applyImpulse(constraint, dt);+		}+	}+}++//MARK: Thread Management Functions++static void+HaltThreads(cpHastySpace *hasty)+{+	pthread_mutex_t *mutex = &hasty->mutex;+	pthread_mutex_lock(mutex); {+		hasty->work = NULL; // NULL work function means break and exit+		pthread_cond_broadcast(&hasty->cond_work);+	} pthread_mutex_unlock(mutex);+	+	for(unsigned long i=0; i<(hasty->num_threads-1); i++){+		pthread_join(hasty->workers[i].thread, NULL);+	}+}++void+cpHastySpaceSetThreads(cpSpace *space, unsigned long threads)+{+#if TARGET_IPHONE_SIMULATOR == 1+	// Individual values appear to be written non-atomically when compiled as debug for the simulator.+	// No idea why, so threads are disabled.+	threads = 1;+#endif	+	+	cpHastySpace *hasty = (cpHastySpace *)space;+	HaltThreads(hasty);+	+#ifdef __APPLE__+	if(threads == 0){+		size_t size = sizeof(threads);+		sysctlbyname("hw.ncpu", &threads, &size, NULL, 0);+	}+#else+	if(threads == 0) threads = 1;+#endif+	+	hasty->num_threads = (threads < MAX_THREADS ? threads : MAX_THREADS);+	hasty->num_working = hasty->num_threads - 1;+	+	// Create the worker threads and wait for them to signal ready.+	if(hasty->num_working > 0){+		pthread_mutex_lock(&hasty->mutex);+		for(unsigned long i=0; i<(hasty->num_threads-1); i++){+			hasty->workers[i].space = hasty;+			hasty->workers[i].thread_num = i + 1;+			+			pthread_create(&hasty->workers[i].thread, NULL, (void*(*)(void*))WorkerThreadLoop, &hasty->workers[i]);+		}+		+		pthread_cond_wait(&hasty->cond_resume, &hasty->mutex);+		pthread_mutex_unlock(&hasty->mutex);+	}+}++unsigned long+cpHastySpaceGetThreads(cpSpace *space)+{+	return ((cpHastySpace *)space)->num_threads;+}++//MARK: Overriden cpSpace Functions.++cpSpace *+cpHastySpaceNew(void)+{+	cpHastySpace *hasty = (cpHastySpace *)cpcalloc(1, sizeof(cpHastySpace));+	cpSpaceInit((cpSpace *)hasty);+	+	pthread_mutex_init(&hasty->mutex, NULL);+	pthread_cond_init(&hasty->cond_work, NULL);+	pthread_cond_init(&hasty->cond_resume, NULL);+	+	// TODO magic number, should test this more thoroughly.+	hasty->constraint_count_threshold = 50;+	+	// Default to 1 thread for determinism.+	hasty->num_threads = 1;+	cpHastySpaceSetThreads((cpSpace *)hasty, 1);++	return (cpSpace *)hasty;+}++void+cpHastySpaceFree(cpSpace *space)+{+	cpHastySpace *hasty = (cpHastySpace *)space;+	+	HaltThreads(hasty);+	+	pthread_mutex_destroy(&hasty->mutex);+	pthread_cond_destroy(&hasty->cond_work);+	pthread_cond_destroy(&hasty->cond_resume);+	+	cpSpaceFree(space);+}++void+cpHastySpaceStep(cpSpace *space, cpFloat dt)+{+	// 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;+		+	cpArray *bodies = space->dynamicBodies;+	cpArray *constraints = space->constraints;+	cpArray *arbiters = space->arbiters;+	+	// Reset and empty the arbiter list.+	for(int i=0; i<arbiters->num; i++){+		cpArbiter *arb = (cpArbiter *)arbiters->arr[i];+		arb->state = CP_ARBITER_STATE_NORMAL;+		+		// If both bodies are awake, unthread the arbiter from the contact graph.+		if(!cpBodyIsSleeping(arb->body_a) && !cpBodyIsSleeping(arb->body_b)){+			cpArbiterUnthread(arb);+		}+	}+	arbiters->num = 0;+	+	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->dynamicShapes, (cpSpatialIndexIteratorFunc)cpShapeUpdateFunc, NULL);+		cpSpatialIndexReindexQuery(space->dynamicShapes, (cpSpatialIndexQueryFunc)cpSpaceCollideShapes, space);+	} cpSpaceUnlock(space, cpFalse);+	+	// Rebuild the contact graph (and detect sleeping components if sleeping is enabled)+	cpSpaceProcessComponents(space, dt);+	+	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);+		}++		for(int i=0; i<constraints->num; i++){+			cpConstraint *constraint = (cpConstraint *)constraints->arr[i];+			+			cpConstraintPreSolveFunc preSolve = constraint->preSolve;+			if(preSolve) preSolve(constraint, space);+			+			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 = (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.+		cpHastySpace *hasty = (cpHastySpace *)space;+		if((unsigned long)(arbiters->num + constraints->num) > hasty->constraint_count_threshold){+			RunWorkers(hasty, Solver);+		} else {+			Solver(space, 0, 1);+		}+		+		// 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->postSolveFunc(arb, space, handler->userData);+		}+	} cpSpaceUnlock(space, cpTrue);+}
+ Chipmunk2D-7.0.2/src/cpMarch.c view
@@ -0,0 +1,157 @@+// Copyright 2013 Howling Moon Software. All rights reserved.+// See http://chipmunk2d.net/legal.php for more information.++#include <stdlib.h>+#include <stdio.h>+#include <math.h>++#include "chipmunk/chipmunk.h"+#include "chipmunk/cpMarch.h"+++typedef void (*cpMarchCellFunc)(+	cpFloat t, cpFloat a, cpFloat b, cpFloat c, cpFloat d,+	cpFloat x0, cpFloat x1, cpFloat y0, cpFloat y1,+	cpMarchSegmentFunc segment, void *segment_data+);++// The looping and sample caching code is shared between cpMarchHard() and cpMarchSoft().+static void+cpMarchCells(+  cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t,+  cpMarchSegmentFunc segment, void *segment_data,+  cpMarchSampleFunc sample, void *sample_data,+	cpMarchCellFunc cell+){+	cpFloat x_denom = 1.0/(cpFloat)(x_samples - 1);+	cpFloat y_denom = 1.0/(cpFloat)(y_samples - 1);+	+	// TODO range assertions and short circuit for 0 sized windows.+	+	// Keep a copy of the previous row to avoid double lookups.+	cpFloat *buffer = (cpFloat *)cpcalloc(x_samples, sizeof(cpFloat));+	for(unsigned long i=0; i<x_samples; i++) buffer[i] = sample(cpv(cpflerp(bb.l, bb.r, i*x_denom), bb.b), sample_data);+	+	for(unsigned long j=0; j<y_samples-1; j++){+		cpFloat y0 = cpflerp(bb.b, bb.t, (j+0)*y_denom);+		cpFloat y1 = cpflerp(bb.b, bb.t, (j+1)*y_denom);+		+		cpFloat a, b = buffer[0];+		cpFloat c, d = sample(cpv(bb.l, y1), sample_data);+		buffer[0] = d;+		+		for(unsigned long i=0; i<x_samples-1; i++){+			cpFloat x0 = cpflerp(bb.l, bb.r, (i+0)*x_denom);+			cpFloat x1 = cpflerp(bb.l, bb.r, (i+1)*x_denom);+			+			a = b, b = buffer[i + 1];+			c = d, d = sample(cpv(x1, y1), sample_data);+			buffer[i + 1] = d;+			+			cell(t, a, b, c, d, x0, x1, y0, y1, segment, segment_data);+		}+	}+	+	cpfree(buffer);+}+++// TODO should flip this around eventually.+static inline void+seg(cpVect v0, cpVect v1, cpMarchSegmentFunc f, void *data)+{+	if(!cpveql(v0, v1)) f(v1, v0, data);+}++// Lerps between two positions based on their sample values.+static inline cpFloat+midlerp(cpFloat x0, cpFloat x1, cpFloat s0, cpFloat s1, cpFloat t)+{+	return cpflerp(x0, x1, (t - s0)/(s1 - s0));+}++static void+cpMarchCellSoft(+	cpFloat t, cpFloat a, cpFloat b, cpFloat c, cpFloat d,+	cpFloat x0, cpFloat x1, cpFloat y0, cpFloat y1,+	cpMarchSegmentFunc segment, void *segment_data+){+	// TODO this switch part is super expensive, can it be NEONized?+	switch((a>t)<<0 | (b>t)<<1 | (c>t)<<2 | (d>t)<<3){+		case 0x1: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); break;+		case 0x2: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); break;+		case 0x3: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); break;+		case 0x4: seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break;+		case 0x5: seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); break;+		case 0x6: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data);+							seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break;+		case 0x7: seg(cpv(midlerp(x0,x1,c,d,t), y1), cpv(x1, midlerp(y0,y1,b,d,t)), segment, segment_data); break;+		case 0x8: seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break;+		case 0x9: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data);+							seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break;+		case 0xA: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break;+		case 0xB: seg(cpv(x0, midlerp(y0,y1,a,c,t)), cpv(midlerp(x0,x1,c,d,t), y1), segment, segment_data); break;+		case 0xC: seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break;+		case 0xD: seg(cpv(x1, midlerp(y0,y1,b,d,t)), cpv(midlerp(x0,x1,a,b,t), y0), segment, segment_data); break;+		case 0xE: seg(cpv(midlerp(x0,x1,a,b,t), y0), cpv(x0, midlerp(y0,y1,a,c,t)), segment, segment_data); break;+		default: break; // 0x0 and 0xF+	}+}++void+cpMarchSoft(+  cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t,+  cpMarchSegmentFunc segment, void *segment_data,+  cpMarchSampleFunc sample, void *sample_data+){+	cpMarchCells(bb, x_samples, y_samples, t, segment, segment_data, sample, sample_data, cpMarchCellSoft);+}+++// TODO should flip this around eventually.+static inline void+segs(cpVect a, cpVect b, cpVect c, cpMarchSegmentFunc f, void *data)+{+	seg(b, c, f, data);+	seg(a, b, f, data);+}++static void+cpMarchCellHard(+	cpFloat t, cpFloat a, cpFloat b, cpFloat c, cpFloat d,+	cpFloat x0, cpFloat x1, cpFloat y0, cpFloat y1,+	cpMarchSegmentFunc segment, void *segment_data+){+	// midpoints+	cpFloat xm = cpflerp(x0, x1, 0.5f);+	cpFloat ym = cpflerp(y0, y1, 0.5f);+	+	switch((a>t)<<0 | (b>t)<<1 | (c>t)<<2 | (d>t)<<3){+		case 0x1: segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); break;+		case 0x2: segs(cpv(xm, y0), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break;+		case 0x3: seg(cpv(x0, ym), cpv(x1, ym), segment, segment_data); break;+		case 0x4: segs(cpv(xm, y1), cpv(xm, ym), cpv(x0, ym), segment, segment_data); break;+		case 0x5: seg(cpv(xm, y1), cpv(xm, y0), segment, segment_data); break;+		case 0x6: segs(cpv(xm, y0), cpv(xm, ym), cpv(x0, ym), segment, segment_data);+		          segs(cpv(xm, y1), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break;+		case 0x7: segs(cpv(xm, y1), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break;+		case 0x8: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break;+		case 0x9: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data);+		          segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break;+		case 0xA: seg(cpv(xm, y0), cpv(xm, y1), segment, segment_data); break;+		case 0xB: segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break;+		case 0xC: seg(cpv(x1, ym), cpv(x0, ym), segment, segment_data); break;+		case 0xD: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); break;+		case 0xE: segs(cpv(xm, y0), cpv(xm, ym), cpv(x0, ym), segment, segment_data); break;+		default: break; // 0x0 and 0xF+	}+}++void+cpMarchHard(+  cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t,+  cpMarchSegmentFunc segment, void *segment_data,+  cpMarchSampleFunc sample, void *sample_data+){+	cpMarchCells(bb, x_samples, y_samples, t, segment, segment_data, sample, sample_data, cpMarchCellHard);+}
+ Chipmunk2D-7.0.2/src/cpPinJoint.c view
@@ -0,0 +1,172 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpPinJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	joint->r1 = cpTransformVect(a->transform, cpvsub(joint->anchorA, a->cog));+	joint->r2 = cpTransformVect(b->transform, cpvsub(joint->anchorB, b->cog));+	+	cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));+	cpFloat dist = cpvlength(delta);+	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);+	+	// calculate bias velocity+	cpFloat maxBias = joint->constraint.maxBias;+	joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*(dist - joint->dist)/dt, -maxBias, maxBias);+}++static void+applyCachedImpulse(cpPinJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpVect j = cpvmult(joint->n, joint->jnAcc*dt_coef);+	apply_impulses(a, b, joint->r1, joint->r2, j);+}++static void+applyImpulse(cpPinJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	cpVect n = joint->n;++	// 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, -jnMax, jnMax);+	jn = joint->jnAcc - jnOld;+	+	// apply impulse+	apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));+}++static cpFloat+getImpulse(cpPinJoint *joint)+{+	return cpfabs(joint->jnAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};+++cpPinJoint *+cpPinJointAlloc(void)+{+	return (cpPinJoint *)cpcalloc(1, sizeof(cpPinJoint));+}++cpPinJoint *+cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->anchorA = anchorA;+	joint->anchorB = anchorB;+	+	// STATIC_BODY_CHECK+	cpVect p1 = (a ? cpTransformPoint(a->transform, anchorA) : anchorA);+	cpVect p2 = (b ? cpTransformPoint(b->transform, anchorB) : anchorB);+	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;+	+	return joint;+}++cpConstraint *+cpPinJointNew(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB)+{+	return (cpConstraint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchorA, anchorB);+}++cpBool+cpConstraintIsPinJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpVect+cpPinJointGetAnchorA(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsPinJoint(constraint), "Constraint is not a pin joint.");+	return ((cpPinJoint *)constraint)->anchorA;+}++void+cpPinJointSetAnchorA(cpConstraint *constraint, cpVect anchorA)+{+	cpAssertHard(cpConstraintIsPinJoint(constraint), "Constraint is not a pin joint.");+	cpConstraintActivateBodies(constraint);+	((cpPinJoint *)constraint)->anchorA = anchorA;+}++cpVect+cpPinJointGetAnchorB(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsPinJoint(constraint), "Constraint is not a pin joint.");+	return ((cpPinJoint *)constraint)->anchorB;+}++void+cpPinJointSetAnchorB(cpConstraint *constraint, cpVect anchorB)+{+	cpAssertHard(cpConstraintIsPinJoint(constraint), "Constraint is not a pin joint.");+	cpConstraintActivateBodies(constraint);+	((cpPinJoint *)constraint)->anchorB = anchorB;+}++cpFloat+cpPinJointGetDist(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsPinJoint(constraint), "Constraint is not a pin joint.");+	return ((cpPinJoint *)constraint)->dist;+}++void+cpPinJointSetDist(cpConstraint *constraint, cpFloat dist)+{+	cpAssertHard(cpConstraintIsPinJoint(constraint), "Constraint is not a pin joint.");+	cpConstraintActivateBodies(constraint);+	((cpPinJoint *)constraint)->dist = dist;+}
+ Chipmunk2D-7.0.2/src/cpPivotJoint.c view
@@ -0,0 +1,152 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpPivotJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	joint->r1 = cpTransformVect(a->transform, cpvsub(joint->anchorA, a->cog));+	joint->r2 = cpTransformVect(b->transform, cpvsub(joint->anchorB, b->cog));+	+	// Calculate mass tensor+	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));+	joint->bias = cpvclamp(cpvmult(delta, -bias_coef(joint->constraint.errorBias, dt)/dt), joint->constraint.maxBias);+}++static void+applyCachedImpulse(cpPivotJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	apply_impulses(a, b, joint->r1, joint->r2, cpvmult(joint->jAcc, dt_coef));+}++static void+applyImpulse(cpPivotJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpVect r1 = joint->r1;+	cpVect r2 = joint->r2;+		+	// compute relative velocity+	cpVect vr = relative_velocity(a, b, r1, r2);+	+	// compute normal impulse+	cpVect j = cpMat2x2Transform(joint->k, cpvsub(joint->bias, vr));+	cpVect jOld = joint->jAcc;+	joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->constraint.maxForce*dt);+	j = cpvsub(joint->jAcc, jOld);+	+	// apply impulse+	apply_impulses(a, b, joint->r1, joint->r2, j);+}++static cpFloat+getImpulse(cpConstraint *joint)+{+	return cpvlength(((cpPivotJoint *)joint)->jAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpPivotJoint *+cpPivotJointAlloc(void)+{+	return (cpPivotJoint *)cpcalloc(1, sizeof(cpPivotJoint));+}++cpPivotJoint *+cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->anchorA = anchorA;+	joint->anchorB = anchorB;+	+	joint->jAcc = cpvzero;+	+	return joint;+}++cpConstraint *+cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB)+{+	return (cpConstraint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, anchorA, anchorB);+}++cpConstraint *+cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)+{+	cpVect anchorA = (a ? cpBodyWorldToLocal(a, pivot) : pivot);+	cpVect anchorB = (b ? cpBodyWorldToLocal(b, pivot) : pivot);+	return cpPivotJointNew2(a, b, anchorA, anchorB);+}++cpBool+cpConstraintIsPivotJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpVect+cpPivotJointGetAnchorA(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsPivotJoint(constraint), "Constraint is not a pivot joint.");+	return ((cpPivotJoint *)constraint)->anchorA;+}++void+cpPivotJointSetAnchorA(cpConstraint *constraint, cpVect anchorA)+{+	cpAssertHard(cpConstraintIsPivotJoint(constraint), "Constraint is not a pivot joint.");+	cpConstraintActivateBodies(constraint);+	((cpPivotJoint *)constraint)->anchorA = anchorA;+}++cpVect+cpPivotJointGetAnchorB(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsPivotJoint(constraint), "Constraint is not a pivot joint.");+	return ((cpPivotJoint *)constraint)->anchorB;+}++void+cpPivotJointSetAnchorB(cpConstraint *constraint, cpVect anchorB)+{+	cpAssertHard(cpConstraintIsPivotJoint(constraint), "Constraint is not a pivot joint.");+	cpConstraintActivateBodies(constraint);+	((cpPivotJoint *)constraint)->anchorB = anchorB;+}
+ Chipmunk2D-7.0.2/src/cpPolyShape.c view
@@ -0,0 +1,323 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"+#include "chipmunk/chipmunk_unsafe.h"++cpPolyShape *+cpPolyShapeAlloc(void)+{+	return (cpPolyShape *)cpcalloc(1, sizeof(cpPolyShape));+}++static void+cpPolyShapeDestroy(cpPolyShape *poly)+{+	if(poly->count > CP_POLY_SHAPE_INLINE_ALLOC){+		cpfree(poly->planes);+	}+}++static cpBB+cpPolyShapeCacheData(cpPolyShape *poly, cpTransform transform)+{+	int count = poly->count;+	struct cpSplittingPlane *dst = poly->planes;+	struct cpSplittingPlane *src = dst + count;+	+	cpFloat l = (cpFloat)INFINITY, r = -(cpFloat)INFINITY;+	cpFloat b = (cpFloat)INFINITY, t = -(cpFloat)INFINITY;+	+	for(int i=0; i<count; i++){+		cpVect v = cpTransformPoint(transform, src[i].v0);+		cpVect n = cpTransformVect(transform, src[i].n);+		+		dst[i].v0 = v;+		dst[i].n = n;+		+		l = cpfmin(l, v.x);+		r = cpfmax(r, v.x);+		b = cpfmin(b, v.y);+		t = cpfmax(t, v.y);+	}+	+	cpFloat radius = poly->r;+	return (poly->shape.bb = cpBBNew(l - radius, b - radius, r + radius, t + radius));+}++static void+cpPolyShapePointQuery(cpPolyShape *poly, cpVect p, cpPointQueryInfo *info){+	int count = poly->count;+	struct cpSplittingPlane *planes = poly->planes;+	cpFloat r = poly->r;+	+	cpVect v0 = planes[count - 1].v0;+	cpFloat minDist = INFINITY;+	cpVect closestPoint = cpvzero;+	cpVect closestNormal = cpvzero;+	cpBool outside = cpFalse;+	+	for(int i=0; i<count; i++){+		cpVect v1 = planes[i].v0;+		outside = outside || (cpvdot(planes[i].n, cpvsub(p,v1)) > 0.0f);+		+		cpVect closest = cpClosetPointOnSegment(p, v0, v1);+		+		cpFloat dist = cpvdist(p, closest);+		if(dist < minDist){+			minDist = dist;+			closestPoint = closest;+			closestNormal = planes[i].n;+		}+		+		v0 = v1;+	}+	+	cpFloat dist = (outside ? minDist : -minDist);+	cpVect g = cpvmult(cpvsub(p, closestPoint), 1.0f/dist);+	+	info->shape = (cpShape *)poly;+	info->point = cpvadd(closestPoint, cpvmult(g, r));+	info->distance = dist - r;+	+	// Use the normal of the closest segment if the distance is small.+	info->gradient = (minDist > MAGIC_EPSILON ? g : closestNormal);+}++static void+cpPolyShapeSegmentQuery(cpPolyShape *poly, cpVect a, cpVect b, cpFloat r2, cpSegmentQueryInfo *info)+{+	struct cpSplittingPlane *planes = poly->planes;+	int count = poly->count;+	cpFloat r = poly->r;+	cpFloat rsum = r + r2;+	+	for(int i=0; i<count; i++){+		cpVect n = planes[i].n;+		cpFloat an = cpvdot(a, n);+		cpFloat d =  an - cpvdot(planes[i].v0, n) - rsum;+		if(d < 0.0f) continue;+		+		cpFloat bn = cpvdot(b, n);+		cpFloat t = d/(an - bn);+		if(t < 0.0f || 1.0f < t) continue;+		+		cpVect point = cpvlerp(a, b, t);+		cpFloat dt = cpvcross(n, point);+		cpFloat dtMin = cpvcross(n, planes[(i - 1 + count)%count].v0);+		cpFloat dtMax = cpvcross(n, planes[i].v0);+		+		if(dtMin <= dt && dt <= dtMax){+			info->shape = (cpShape *)poly;+			info->point = cpvsub(cpvlerp(a, b, t), cpvmult(n, r2));+			info->normal = n;+			info->alpha = t;+		}+	}+	+	// Also check against the beveled vertexes.+	if(rsum > 0.0f){+		for(int i=0; i<count; i++){+			cpSegmentQueryInfo circle_info = {NULL, b, cpvzero, 1.0f};+			CircleSegmentQuery(&poly->shape, planes[i].v0, r, a, b, r2, &circle_info);+			if(circle_info.alpha < info->alpha) (*info) = circle_info;+		}+	}+}++static void+SetVerts(cpPolyShape *poly, int count, const cpVect *verts)+{+	poly->count = count;+	if(count <= CP_POLY_SHAPE_INLINE_ALLOC){+		poly->planes = poly->_planes;+	} else {+		poly->planes = (struct cpSplittingPlane *)cpcalloc(2*count, sizeof(struct cpSplittingPlane));+	}+	+	for(int i=0; i<count; i++){+		cpVect a = verts[(i - 1 + count)%count];+		cpVect b = verts[i];+		cpVect n = cpvnormalize(cpvrperp(cpvsub(b, a)));+		+		poly->planes[i + count].v0 = b;+		poly->planes[i + count].n = n;+	}+}++static struct cpShapeMassInfo+cpPolyShapeMassInfo(cpFloat mass, int count, const cpVect *verts, cpFloat radius)+{+	// TODO moment is approximate due to radius.+	+	cpVect centroid = cpCentroidForPoly(count, verts);+	struct cpShapeMassInfo info = {+		mass, cpMomentForPoly(1.0f, count, verts, cpvneg(centroid), radius),+		centroid,+		cpAreaForPoly(count, verts, radius),+	};+	+	return info;+}++static const cpShapeClass polyClass = {+	CP_POLY_SHAPE,+	(cpShapeCacheDataImpl)cpPolyShapeCacheData,+	(cpShapeDestroyImpl)cpPolyShapeDestroy,+	(cpShapePointQueryImpl)cpPolyShapePointQuery,+	(cpShapeSegmentQueryImpl)cpPolyShapeSegmentQuery,+};++cpPolyShape *+cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int count, const cpVect *verts, cpTransform transform, cpFloat radius)+{+	cpVect *hullVerts = (cpVect *)alloca(count*sizeof(cpVect));+	+	// Transform the verts before building the hull in case of a negative scale.+	for(int i=0; i<count; i++) hullVerts[i] = cpTransformPoint(transform, verts[i]);+	+	unsigned int hullCount = cpConvexHull(count, hullVerts, hullVerts, NULL, 0.0);+	return cpPolyShapeInitRaw(poly, body, hullCount, hullVerts, radius);+}++cpPolyShape *+cpPolyShapeInitRaw(cpPolyShape *poly, cpBody *body, int count, const cpVect *verts, cpFloat radius)+{+	cpShapeInit((cpShape *)poly, &polyClass, body, cpPolyShapeMassInfo(0.0f, count, verts, radius));+	+	SetVerts(poly, count, verts);+	poly->r = radius;++	return poly;+}++cpShape *+cpPolyShapeNew(cpBody *body, int count, const cpVect *verts, cpTransform transform, cpFloat radius)+{+	return (cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), body, count, verts, transform, radius);+}++cpShape *+cpPolyShapeNewRaw(cpBody *body, int count, const cpVect *verts, cpFloat radius)+{+	return (cpShape *)cpPolyShapeInitRaw(cpPolyShapeAlloc(), body, count, verts, radius);+}++cpPolyShape *+cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height, cpFloat radius)+{+	cpFloat hw = width/2.0f;+	cpFloat hh = height/2.0f;+	+	return cpBoxShapeInit2(poly, body, cpBBNew(-hw, -hh, hw, hh), radius);+}++cpPolyShape *+cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box, cpFloat radius)+{+	cpVect verts[] = {+		cpv(box.r, box.b),+		cpv(box.r, box.t),+		cpv(box.l, box.t),+		cpv(box.l, box.b),+	};+	+	return cpPolyShapeInitRaw(poly, body, 4, verts, radius);+}++cpShape *+cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height, cpFloat radius)+{+	return (cpShape *)cpBoxShapeInit(cpPolyShapeAlloc(), body, width, height, radius);+}++cpShape *+cpBoxShapeNew2(cpBody *body, cpBB box, cpFloat radius)+{+	return (cpShape *)cpBoxShapeInit2(cpPolyShapeAlloc(), body, box, radius);+}++int+cpPolyShapeGetCount(const cpShape *shape)+{+	cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape.");+	return ((cpPolyShape *)shape)->count;+}++cpVect+cpPolyShapeGetVert(const cpShape *shape, int i)+{+	cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape.");+	+	int count = cpPolyShapeGetCount(shape);+	cpAssertHard(0 <= i && i < count, "Index out of range.");+	+	return ((cpPolyShape *)shape)->planes[i + count].v0;+}++cpFloat+cpPolyShapeGetRadius(const cpShape *shape)+{+	cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape.");+	return ((cpPolyShape *)shape)->r;+}++// Unsafe API (chipmunk_unsafe.h)++void+cpPolyShapeSetVerts(cpShape *shape, int count, cpVect *verts, cpTransform transform)+{+	cpVect *hullVerts = (cpVect *)alloca(count*sizeof(cpVect));+	+	// Transform the verts before building the hull in case of a negative scale.+	for(int i=0; i<count; i++) hullVerts[i] = cpTransformPoint(transform, verts[i]);+	+	unsigned int hullCount = cpConvexHull(count, hullVerts, hullVerts, NULL, 0.0);+	cpPolyShapeSetVertsRaw(shape, hullCount, hullVerts);+}++void+cpPolyShapeSetVertsRaw(cpShape *shape, int count, cpVect *verts)+{+	cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape.");+	cpPolyShape *poly = (cpPolyShape *)shape;+	cpPolyShapeDestroy(poly);+	+	SetVerts(poly, count, verts);+	+	cpFloat mass = shape->massInfo.m;+	shape->massInfo = cpPolyShapeMassInfo(shape->massInfo.m, count, verts, poly->r);+	if(mass > 0.0f) cpBodyAccumulateMassFromShapes(shape->body);+}++void+cpPolyShapeSetRadius(cpShape *shape, cpFloat radius)+{+	cpAssertHard(shape->klass == &polyClass, "Shape is not a poly shape.");+	cpPolyShape *poly = (cpPolyShape *)shape;+	poly->r = radius;+	+	+	// TODO radius is not handled by moment/area+//	cpFloat mass = shape->massInfo.m;+//	shape->massInfo = cpPolyShapeMassInfo(shape->massInfo.m, poly->count, poly->verts, poly->r);+//	if(mass > 0.0f) cpBodyAccumulateMassFromShapes(shape->body);+}
+ Chipmunk2D-7.0.2/src/cpPolyline.c view
@@ -0,0 +1,652 @@+// Copyright 2013 Howling Moon Software. All rights reserved.+// See http://chipmunk2d.net/legal.php for more information.++#include <stdlib.h>+#include <stdio.h>+#include <string.h>+#include <math.h>++#include "chipmunk/chipmunk_private.h"+#include "chipmunk/cpPolyline.h"+++static inline int Next(int i, int count){return (i+1)%count;}++//MARK: Polylines++#define DEFAULT_POLYLINE_CAPACITY 16++static int+cpPolylineSizeForCapacity(int capacity)+{+	return sizeof(cpPolyline) + capacity*sizeof(cpVect);+}++static cpPolyline *+cpPolylineMake(int capacity)+{+	capacity = (capacity > DEFAULT_POLYLINE_CAPACITY ? capacity : DEFAULT_POLYLINE_CAPACITY);+	+	cpPolyline *line = (cpPolyline *)cpcalloc(1, cpPolylineSizeForCapacity(capacity));+	line->count = 0;+	line->capacity = capacity;+	+	return line;+}++static cpPolyline *+cpPolylineMake2(int capacity, cpVect a, cpVect b)+{+	cpPolyline *line = cpPolylineMake(capacity);+	line->count = 2;+	line->verts[0] = a;+	line->verts[1] = b;+	+	return line;+}++static cpPolyline *+cpPolylineShrink(cpPolyline *line)+{+	line->capacity = line->count;+	return (cpPolyline*) cprealloc(line, cpPolylineSizeForCapacity(line->count));+}++void+cpPolylineFree(cpPolyline *line)+{+	cpfree(line);+}++// Grow the allocated memory for a polyline.+static cpPolyline *+cpPolylineGrow(cpPolyline *line, int count)+{+  line->count += count;+  +  int capacity = line->capacity;+  while(line->count > capacity) capacity *= 2;+  +  if(line->capacity < capacity){+    line->capacity = capacity;+		line = (cpPolyline*) cprealloc(line, cpPolylineSizeForCapacity(capacity));+  }+	+	return line;+}++// Push v onto the end of line.+static cpPolyline *+cpPolylinePush(cpPolyline *line, cpVect v)+{+  int count = line->count;+  line = cpPolylineGrow(line, 1);+  line->verts[count] = v;+	+	return line;+}++// Push v onto the beginning of line.+static cpPolyline *+cpPolylineEnqueue(cpPolyline *line, cpVect v)+{+	// TODO could optimize this to grow in both directions.+	// Probably doesn't matter though.+  int count = line->count;+  line = cpPolylineGrow(line, 1);+  memmove(line->verts + 1, line->verts, count*sizeof(cpVect));+  line->verts[0] = v;+	+	return line;+}++// Returns true if the polyline starts and ends with the same vertex.+cpBool+cpPolylineIsClosed(cpPolyline *line)+{+	return (line->count > 1 && cpveql(line->verts[0], line->verts[line->count-1]));+}++// Check if a cpPolyline is longer than a certain length+// Takes a range which can wrap around if the polyline is looped.+static cpBool+cpPolylineIsShort(cpVect *points, int count, int start, int end, cpFloat min)+{+  cpFloat length = 0.0f;+	for(int i=start; i!=end; i=Next(i, count)){+		length += cpvdist(points[i], points[Next(i, count)]);+		if(length > min) return cpFalse;+	}+  +  return cpTrue;+}++//MARK: Polyline Simplification++static inline cpFloat+Sharpness(cpVect a, cpVect b, cpVect c)+{+	// TODO could speed this up by caching the normals instead of calculating each twice.+  return cpvdot(cpvnormalize(cpvsub(a, b)), cpvnormalize(cpvsub(c, b)));+}++// Join similar adjacent line segments together. Works well for hard edged shapes.+// 'tol' is the minimum anglular difference in radians of a vertex.+cpPolyline *+cpPolylineSimplifyVertexes(cpPolyline *line, cpFloat tol)+{+	cpPolyline *reduced = cpPolylineMake2(0, line->verts[0], line->verts[1]);+	+	cpFloat minSharp = -cpfcos(tol);+	+	for(int i=2; i<line->count; i++){+		cpVect vert = line->verts[i];+		cpFloat sharp = Sharpness(reduced->verts[reduced->count - 2], reduced->verts[reduced->count - 1], vert);+		+		if(sharp <= minSharp){+			reduced->verts[reduced->count - 1] = vert;+		} else {+			reduced = cpPolylinePush(reduced, vert);+		}+	}+	+	if(+		cpPolylineIsClosed(line) &&+		Sharpness(reduced->verts[reduced->count - 2], reduced->verts[0], reduced->verts[1]) < minSharp+	){+		reduced->verts[0] = reduced->verts[reduced->count - 2];+		reduced->count--;+	}+	+	// TODO shrink+	return reduced;+}++// Recursive function used by cpPolylineSimplifyCurves().+static cpPolyline *+DouglasPeucker(+	cpVect *verts, cpPolyline *reduced,+	int length, int start, int end,+	cpFloat min, cpFloat tol+){+	// Early exit if the points are adjacent+  if((end - start + length)%length < 2) return reduced;+  +	cpVect a = verts[start];+	cpVect b = verts[end];+	+	// Check if the length is below the threshold+	if(cpvnear(a, b, min) && cpPolylineIsShort(verts, length, start, end, min)) return reduced;+	+	// Find the maximal vertex to split and recurse on+	cpFloat max = 0.0;+	int maxi = start;+	+	cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));+	cpFloat d = cpvdot(n, a);+	+	for(int i=Next(start, length); i!=end; i=Next(i, length)){+		cpFloat dist = fabs(cpvdot(n, verts[i]) - d);+		+		if(dist > max){+			max = dist;+			maxi = i;+		}+	}+	+	if(max > tol){+    reduced = DouglasPeucker(verts, reduced, length, start, maxi, min, tol);+		reduced = cpPolylinePush(reduced, verts[maxi]);+    reduced = DouglasPeucker(verts, reduced, length, maxi, end, min, tol);+	}+	+	return reduced;+}++// Recursively reduce the vertex count on a polyline. Works best for smooth shapes.+// 'tol' is the maximum error for the reduction.+// The reduced polyline will never be farther than this distance from the original polyline.+cpPolyline *+cpPolylineSimplifyCurves(cpPolyline *line, cpFloat tol)+{+	cpPolyline *reduced = cpPolylineMake(line->count);+	+	cpFloat min = tol/2.0f;+  +  if(cpPolylineIsClosed(line)){+		int start, end;+    cpLoopIndexes(line->verts, line->count - 1, &start, &end);+    +		reduced = cpPolylinePush(reduced, line->verts[start]);+		reduced = DouglasPeucker(line->verts, reduced, line->count - 1, start, end, min, tol);+		reduced = cpPolylinePush(reduced, line->verts[end]);+		reduced = DouglasPeucker(line->verts, reduced, line->count - 1, end, start, min, tol);+		reduced = cpPolylinePush(reduced, line->verts[start]);+  } else {+		reduced = cpPolylinePush(reduced, line->verts[0]);+		reduced = DouglasPeucker(line->verts, reduced, line->count, 0, line->count - 1, min, tol);+		reduced = cpPolylinePush(reduced, line->verts[line->count - 1]);+  }+	+	return cpPolylineShrink(reduced);+}++//MARK: Polyline Sets++cpPolylineSet *+cpPolylineSetAlloc(void)+{+	return (cpPolylineSet *)cpcalloc(1, sizeof(cpPolylineSet));+}++cpPolylineSet *+cpPolylineSetInit(cpPolylineSet *set)+{+	set->count = 0;+	set->capacity = 8;+	set->lines = (cpPolyline**) cpcalloc(set->capacity, sizeof(cpPolyline));+	+  return set;+}+++cpPolylineSet *+cpPolylineSetNew(void)+{+	return cpPolylineSetInit(cpPolylineSetAlloc());+}++void+cpPolylineSetDestroy(cpPolylineSet *set, cpBool freePolylines)+{+	if(freePolylines){+		for(int i=0; i<set->count; i++){+			cpPolylineFree(set->lines[i]);+		}+	}+	+	cpfree(set->lines);+}+++void+cpPolylineSetFree(cpPolylineSet *set, cpBool freePolylines)+{+	if(set){+		cpPolylineSetDestroy(set, freePolylines);+		cpfree(set);+	}+}++// Find the polyline that ends with v.+static int+cpPolylineSetFindEnds(cpPolylineSet *set, cpVect v){+	int count = set->count;+	cpPolyline **lines = set->lines;+	+  for(int i=0; i<count; i++){+		cpPolyline *line = lines[i];+    if(cpveql(line->verts[line->count - 1], v)) return i;+  }+  +  return -1;+}++// Find the polyline that starts with v.+static int+cpPolylineSetFindStarts(cpPolylineSet *set, cpVect v){+	int count = set->count;+	cpPolyline **lines = set->lines;+	+  for(int i=0; i<count; i++){+    if(cpveql(lines[i]->verts[0], v)) return i;+  }+  +  return -1;+}++// Add a new polyline to a polyline set.+static void+cpPolylineSetPush(cpPolylineSet *set, cpPolyline *line)+{+  // grow set+  set->count++;+  if(set->count > set->capacity){+    set->capacity *= 2;+    set->lines = (cpPolyline**) cprealloc(set->lines, set->capacity*sizeof(cpPolyline));+  }+  +	set->lines[set->count - 1] = line;+}++// Add a new polyline to a polyline set.+static void+cpPolylineSetAdd(cpPolylineSet *set, cpVect v0, cpVect v1)+{+	cpPolylineSetPush(set, cpPolylineMake2(DEFAULT_POLYLINE_CAPACITY, v0, v1));+}++// Join two cpPolylines in a polyline set together.+static void+cpPolylineSetJoin(cpPolylineSet *set, int before, int after)+{+  cpPolyline *lbefore = set->lines[before];+  cpPolyline *lafter = set->lines[after];+  +  // append+  int count = lbefore->count;+  lbefore = cpPolylineGrow(lbefore, lafter->count);+  memmove(lbefore->verts + count, lafter->verts, lafter->count*sizeof(cpVect));+	set->lines[before] = lbefore;+  +  // delete lafter+  set->count--;+	cpPolylineFree(set->lines[after]);+  set->lines[after] = set->lines[set->count];+}++// Add a segment to a polyline set.+// A segment will either start a new polyline, join two others, or add to or loop an existing polyline.+void+cpPolylineSetCollectSegment(cpVect v0, cpVect v1, cpPolylineSet *lines)+{+  int before = cpPolylineSetFindEnds(lines, v0);+  int after = cpPolylineSetFindStarts(lines, v1);+  +  if(before >= 0 && after >= 0){+    if(before == after){+      // loop by pushing v1 onto before+      lines->lines[before] = cpPolylinePush(lines->lines[before], v1);+    } else {+      // join before and after+      cpPolylineSetJoin(lines, before, after);+    }+  } else if(before >= 0){+    // push v1 onto before+    lines->lines[before] = cpPolylinePush(lines->lines[before], v1);+  } else if(after >= 0){+    // enqueue v0 onto after+    lines->lines[after] = cpPolylineEnqueue(lines->lines[after], v0);+  } else {+    // create new line from v0 and v1+    cpPolylineSetAdd(lines, v0, v1);+  }+}++//MARK: Convex Hull Functions++cpPolyline *+cpPolylineToConvexHull(cpPolyline *line, cpFloat tol)+{+	cpPolyline *hull = cpPolylineMake(line->count + 1);+	hull->count = cpConvexHull(line->count, line->verts, hull->verts, NULL, tol);+	hull = cpPolylinePush(hull, hull->verts[0]);+	+	return cpPolylineShrink(hull);+}++//MARK: Approximate Concave Decompostition++struct Notch {+	int i;+	cpFloat d;+	cpVect v;+	cpVect n;+};++static cpFloat+FindSteiner(int count, cpVect *verts, struct Notch notch)+{+	cpFloat min = INFINITY;+	cpFloat feature = -1.0;+	+	for(int i=1; i<count-1; i++){+		int index = (notch.i + i)%count;+		+		cpVect seg_a = verts[index];+		cpVect seg_b = verts[Next(index, count)];+		+		cpFloat thing_a = cpvcross(notch.n, cpvsub(seg_a, notch.v));+		cpFloat thing_b = cpvcross(notch.n, cpvsub(seg_b, notch.v));+		if(thing_a*thing_b <= 0.0){+			cpFloat t = thing_a/(thing_a - thing_b);+			cpFloat dist = cpvdot(notch.n, cpvsub(cpvlerp(seg_a, seg_b, t), notch.v));+			+			if(dist >= 0.0 && dist <= min){+				min = dist;+				feature = index + t;+			}+		}+	}+	+	return feature;+}++//static cpFloat+//FindSteiner2(cpVect *verts, int count, struct Notch notch)+//{+//	cpVect a = verts[(notch.i + count - 1)%count];+//	cpVect b = verts[(notch.i + 1)%count];+//	cpVect n = cpvnormalize(cpvadd(cpvnormalize(cpvsub(notch.v, a)), cpvnormalize(cpvsub(notch.v, b))));+//	+//	cpFloat min = INFINITY;+//	cpFloat feature = -1.0;+//	+//	for(int i=1; i<count-1; i++){+//		int index = (notch.i + i)%count;+//		+//		cpVect seg_a = verts[index];+//		cpVect seg_b = verts[Next(index, count)];+//		+//		cpFloat thing_a = cpvcross(n, cpvsub(seg_a, notch.v));+//		cpFloat thing_b = cpvcross(n, cpvsub(seg_b, notch.v));+//		if(thing_a*thing_b <= 0.0){+//			cpFloat t = thing_a/(thing_a - thing_b);+//			cpFloat dist = cpvdot(n, cpvsub(cpvlerp(seg_a, seg_b, t), notch.v));+//			+//			if(dist >= 0.0 && dist <= min){+//				min = dist;+//				feature = index + t;+//			}+//		}+//	}+//	+//	cpAssertSoft(feature >= 0.0, "No closest features detected. This is likely due to a self intersecting polygon.");+//	return feature;+//}++//struct Range {cpFloat min, max;};+//static inline struct Range+//clip_range(cpVect delta_a, cpVect delta_b, cpVect clip)+//{+//	cpFloat da = cpvcross(delta_a, clip);+//	cpFloat db = cpvcross(delta_b, clip);+//	cpFloat clamp = da/(da - db);+//	if(da > db){+//		return (struct Range){-INFINITY, clamp};+//	} else if(da < db){+//		return (struct Range){clamp, INFINITY};+//	} else {+//		return (struct Range){-INFINITY, INFINITY};+//	}+//}+//+//static cpFloat+//FindSteiner3(cpVect *verts, int count, struct Notch notch)+//{+//	cpFloat min = INFINITY;+//	cpFloat feature = -1.0;+//	+//	cpVect support_a = verts[(notch.i - 1 + count)%count];+//	cpVect support_b = verts[(notch.i + 1)%count];+//	+//	cpVect clip_a = cpvlerp(support_a, support_b, 0.1);+//	cpVect clip_b = cpvlerp(support_b, support_b, 0.9);+//	+//	for(int i=1; i<count - 1; i++){+//		int index = (notch.i + i)%count;+//		cpVect seg_a = verts[index];+//		cpVect seg_b = verts[Next(index, count)];+//		+//		cpVect delta_a = cpvsub(seg_a, notch.v);+//		cpVect delta_b = cpvsub(seg_b, notch.v);+//		+//		// Ignore if the segment faces away from the point.+//		if(cpvcross(delta_b, delta_a) > 0.0){+//			struct Range range1 = clip_range(delta_a, delta_b, cpvsub(notch.v, clip_a));+//			struct Range range2 = clip_range(delta_a, delta_b, cpvsub(clip_b, notch.v));+//			+//			cpFloat min_t = cpfmax(0.0, cpfmax(range1.min, range2.min));+//			cpFloat max_t = cpfmin(1.0, cpfmin(range1.max, range2.max));+//			+//			// Ignore if the segment has been completely clipped away.+//			if(min_t < max_t){+//				cpVect seg_delta = cpvsub(seg_b, seg_a);+//				cpFloat closest_t = cpfclamp(cpvdot(seg_delta, cpvsub(notch.v, seg_a))/cpvlengthsq(seg_delta), min_t, max_t);+//				cpVect closest = cpvlerp(seg_a, seg_b, closest_t);+//				+//				cpFloat dist = cpvdistsq(notch.v, closest);+//				if(dist < min){+//					min = dist;+//					feature = index + closest_t;+//				}+//			}+//		}+//	}+//	+//	cpAssertWarn(feature >= 0.0, "Internal Error: No closest features detected.");+//	return feature;+//}++//static cpBool+//VertexUnobscured(int count, cpVect *verts, int index, int notch_i)+//{+//	cpVect v = verts[notch_i];+//	cpVect n = cpvnormalize(cpvsub(verts[index], v));+//	+//	for(int i=0; i<count; i++){+//		if(i == index || i == Next(i, count) || i == notch_i || i == Next(notch_i, count)) continue;+//		+//		cpVect seg_a = verts[i];+//		cpVect seg_b = verts[Next(i, count)];+//		+//		cpFloat thing_a = cpvcross(n, cpvsub(seg_a, v));+//		cpFloat thing_b = cpvcross(n, cpvsub(seg_b, v));+//		if(thing_a*thing_b <= 0.0) return cpTrue;+//	}+//	+//	return cpFalse;+//}+//+//static cpFloat+//FindSteiner4(int count, cpVect *verts, struct Notch notch, cpFloat *convexity)+//{+//	cpFloat min = INFINITY;+//	cpFloat feature = -1.0;+//	+//	for(int i=Next(notch.b, count); i!=notch.a; i=Next(i, count)){+//		cpVect v = verts[i];+//		cpFloat weight = (1.0 + 0.1*convexity[i])/(1.0*cpvdist(notch.v, v));+//		+//		if(weight <= min && VertexUnobscured(count, verts, i, notch.i)){+//			min = weight;+//			feature = i;+//		}+//	}+//	+//	cpAssertSoft(feature >= 0.0, "No closest features detected. This is likely due to a self intersecting polygon.");+//	return feature;+//}++static struct Notch+DeepestNotch(int count, cpVect *verts, int hullCount, cpVect *hullVerts, int first, cpFloat tol)+{+	struct Notch notch = {};+	int j = Next(first, count);+	+	for(int i=0; i<hullCount; i++){+		cpVect a = hullVerts[i];+		cpVect b = hullVerts[Next(i, hullCount)];+		+		// TODO use a cross check instead?+		cpVect n = cpvnormalize(cpvrperp(cpvsub(a, b)));+		cpFloat d = cpvdot(n, a);+		+		cpVect v = verts[j];+		while(!cpveql(v, b)){+			cpFloat depth = cpvdot(n, v) - d;+			+			if(depth > notch.d){+				notch.d = depth;+				notch.i = j;+				notch.v = v;+				notch.n = n;+			}+			+			j = Next(j, count);+			v = verts[j];+		}+		+		j = Next(j, count);+	}+	+	return notch;+}++static inline int IMAX(int a, int b){return (a > b ? a : b);}++static void+ApproximateConcaveDecomposition(cpVect *verts, int count, cpFloat tol, cpPolylineSet *set)+{+	int first;+	cpVect *hullVerts = (cpVect*) alloca(count*sizeof(cpVect));+	int hullCount = cpConvexHull(count, verts, hullVerts, &first, 0.0);+	+	if(hullCount != count){+		struct Notch notch = DeepestNotch(count, verts, hullCount, hullVerts, first, tol);+		+		if(notch.d > tol){+			cpFloat steiner_it = FindSteiner(count, verts, notch);+			+			if(steiner_it >= 0.0){+				int steiner_i = (int)steiner_it;+				cpVect steiner = cpvlerp(verts[steiner_i], verts[Next(steiner_i, count)], steiner_it - steiner_i);+				+				// Vertex counts NOT including the steiner point.+				int sub1_count = (steiner_i - notch.i + count)%count + 1;+				int sub2_count = count - (steiner_i - notch.i + count)%count;+				cpVect *scratch = (cpVect*) alloca((IMAX(sub1_count, sub2_count) + 1)*sizeof(cpVect));+				+				for(int i=0; i<sub1_count; i++) scratch[i] = verts[(notch.i + i)%count];+				scratch[sub1_count] = steiner;+				ApproximateConcaveDecomposition(scratch, sub1_count + 1, tol, set);+				+				for(int i=0; i<sub2_count; i++) scratch[i] = verts[(steiner_i + 1 + i)%count];+				scratch[sub2_count] = steiner;+				ApproximateConcaveDecomposition(scratch, sub2_count + 1, tol, set);+				+				return;+			}+		}+	}+	+	cpPolyline *hull = cpPolylineMake(hullCount + 1);+	+	memcpy(hull->verts, hullVerts, hullCount*sizeof(cpVect));+	hull->verts[hullCount] = hullVerts[0];+	hull->count = hullCount + 1;+	+	cpPolylineSetPush(set, hull);+}++cpPolylineSet *+cpPolylineConvexDecomposition_BETA(cpPolyline *line, cpFloat tol)+{+	cpAssertSoft(cpPolylineIsClosed(line), "Cannot decompose an open polygon.");+	cpAssertSoft(cpAreaForPoly(line->count, line->verts, 0.0) >= 0.0, "Winding is backwards. (Are you passing a hole?)");+	+	cpPolylineSet *set = cpPolylineSetNew();+	ApproximateConcaveDecomposition(line->verts, line->count - 1, tol, set);+	+	return set;+}
+ Chipmunk2D-7.0.2/src/cpRatchetJoint.c view
@@ -0,0 +1,179 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpRatchetJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpFloat angle = joint->angle;+	cpFloat phase = joint->phase;+	cpFloat ratchet = joint->ratchet;+	+	cpFloat delta = b->a - a->a;+	cpFloat diff = angle - delta;+	cpFloat pdist = 0.0f;+	+	if(diff*ratchet > 0.0f){+		pdist = diff;+	} else {+		joint->angle = cpffloor((delta - phase)/ratchet)*ratchet + phase;+	}+	+	// calculate moment of inertia coefficient.+	joint->iSum = 1.0f/(a->i_inv + b->i_inv);+	+	// calculate bias velocity+	cpFloat maxBias = joint->constraint.maxBias;+	joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);++	// If the bias is 0, the joint is not at a limit. Reset the impulse.+	if(!joint->bias) joint->jAcc = 0.0f;+}++static void+applyCachedImpulse(cpRatchetJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpFloat j = joint->jAcc*dt_coef;+	a->w -= j*a->i_inv;+	b->w += j*b->i_inv;+}++static void+applyImpulse(cpRatchetJoint *joint, cpFloat dt)+{+	if(!joint->bias) return; // early exit++	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// compute relative rotational velocity+	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, jMax*cpfabs(ratchet))/ratchet;+	j = joint->jAcc - jOld;+	+	// apply impulse+	a->w -= j*a->i_inv;+	b->w += j*b->i_inv;+}++static cpFloat+getImpulse(cpRatchetJoint *joint)+{+	return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpRatchetJoint *+cpRatchetJointAlloc(void)+{+	return (cpRatchetJoint *)cpcalloc(1, sizeof(cpRatchetJoint));+}++cpRatchetJoint *+cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->angle = 0.0f;+	joint->phase = phase;+	joint->ratchet = ratchet;+	+	// STATIC_BODY_CHECK+	joint->angle = (b ? b->a : 0.0f) - (a ? a->a : 0.0f);+	+	return joint;+}++cpConstraint *+cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet)+{+	return (cpConstraint *)cpRatchetJointInit(cpRatchetJointAlloc(), a, b, phase, ratchet);+}++cpBool+cpConstraintIsRatchetJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpFloat+cpRatchetJointGetAngle(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsRatchetJoint(constraint), "Constraint is not a ratchet joint.");+	return ((cpRatchetJoint *)constraint)->angle;+}++void+cpRatchetJointSetAngle(cpConstraint *constraint, cpFloat angle)+{+	cpAssertHard(cpConstraintIsRatchetJoint(constraint), "Constraint is not a ratchet joint.");+	cpConstraintActivateBodies(constraint);+	((cpRatchetJoint *)constraint)->angle = angle;+}++cpFloat+cpRatchetJointGetPhase(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsRatchetJoint(constraint), "Constraint is not a ratchet joint.");+	return ((cpRatchetJoint *)constraint)->phase;+}++void+cpRatchetJointSetPhase(cpConstraint *constraint, cpFloat phase)+{+	cpAssertHard(cpConstraintIsRatchetJoint(constraint), "Constraint is not a ratchet joint.");+	cpConstraintActivateBodies(constraint);+	((cpRatchetJoint *)constraint)->phase = phase;+}+cpFloat+cpRatchetJointGetRatchet(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsRatchetJoint(constraint), "Constraint is not a ratchet joint.");+	return ((cpRatchetJoint *)constraint)->ratchet;+}++void+cpRatchetJointSetRatchet(cpConstraint *constraint, cpFloat ratchet)+{+	cpAssertHard(cpConstraintIsRatchetJoint(constraint), "Constraint is not a ratchet joint.");+	cpConstraintActivateBodies(constraint);+	((cpRatchetJoint *)constraint)->ratchet = ratchet;+}
+ Chipmunk2D-7.0.2/src/cpRobust.c view
@@ -0,0 +1,13 @@+#include "chipmunk/cpRobust.h"+++cpBool+cpCheckPointGreater(const cpVect a, const cpVect b, const cpVect c)+{+	return (b.y - a.y)*(a.x + b.x - 2*c.x) > (b.x - a.x)*(a.y + b.y - 2*c.y);+}++cpBool+cpCheckAxis(cpVect v0, cpVect v1, cpVect p, cpVect n){+	return cpvdot(p, n) <= cpfmax(cpvdot(v0, n), cpvdot(v1, n));+}
+ Chipmunk2D-7.0.2/src/cpRotaryLimitJoint.c view
@@ -0,0 +1,160 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpRotaryLimitJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpFloat dist = b->a - a->a;+	cpFloat pdist = 0.0f;+	if(dist > joint->max) {+		pdist = joint->max - dist;+	} else if(dist < joint->min) {+		pdist = joint->min - dist;+	}+	+	// calculate moment of inertia coefficient.+	joint->iSum = 1.0f/(a->i_inv + b->i_inv);+	+	// calculate bias velocity+	cpFloat maxBias = joint->constraint.maxBias;+	joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);++	// If the bias is 0, the joint is not at a limit. Reset the impulse.+	if(!joint->bias) joint->jAcc = 0.0f;+}++static void+applyCachedImpulse(cpRotaryLimitJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpFloat j = joint->jAcc*dt_coef;+	a->w -= j*a->i_inv;+	b->w += j*b->i_inv;+}++static void+applyImpulse(cpRotaryLimitJoint *joint, cpFloat dt)+{+	if(!joint->bias) return; // early exit++	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// 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, jMax);+	} else {+		joint->jAcc = cpfclamp(jOld + j, -jMax, 0.0f);+	}+	j = joint->jAcc - jOld;+	+	// apply impulse+	a->w -= j*a->i_inv;+	b->w += j*b->i_inv;+}++static cpFloat+getImpulse(cpRotaryLimitJoint *joint)+{+	return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpRotaryLimitJoint *+cpRotaryLimitJointAlloc(void)+{+	return (cpRotaryLimitJoint *)cpcalloc(1, sizeof(cpRotaryLimitJoint));+}++cpRotaryLimitJoint *+cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->min = min;+	joint->max  = max;+	+	joint->jAcc = 0.0f;+	+	return joint;+}++cpConstraint *+cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max)+{+	return (cpConstraint *)cpRotaryLimitJointInit(cpRotaryLimitJointAlloc(), a, b, min, max);+}++cpBool+cpConstraintIsRotaryLimitJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpFloat+cpRotaryLimitJointGetMin(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsRotaryLimitJoint(constraint), "Constraint is not a rotary limit joint.");+	return ((cpRotaryLimitJoint *)constraint)->min;+}++void+cpRotaryLimitJointSetMin(cpConstraint *constraint, cpFloat min)+{+	cpAssertHard(cpConstraintIsRotaryLimitJoint(constraint), "Constraint is not a rotary limit joint.");+	cpConstraintActivateBodies(constraint);+	((cpRotaryLimitJoint *)constraint)->min = min;+}++cpFloat+cpRotaryLimitJointGetMax(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsRotaryLimitJoint(constraint), "Constraint is not a rotary limit joint.");+	return ((cpRotaryLimitJoint *)constraint)->max;+}++void+cpRotaryLimitJointSetMax(cpConstraint *constraint, cpFloat max)+{+	cpAssertHard(cpConstraintIsRotaryLimitJoint(constraint), "Constraint is not a rotary limit joint.");+	cpConstraintActivateBodies(constraint);+	((cpRotaryLimitJoint *)constraint)->max = max;+}
+ Chipmunk2D-7.0.2/src/cpShape.c view
@@ -0,0 +1,603 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"+#include "chipmunk/chipmunk_unsafe.h"++#define CP_DefineShapeGetter(struct, type, member, name) \+CP_DeclareShapeGetter(struct, type, name){ \+	cpAssertHard(shape->klass == &struct##Class, "shape is not a "#struct); \+	return ((struct *)shape)->member; \+}++cpShape *+cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body, struct cpShapeMassInfo massInfo)+{+	shape->klass = klass;+	+	shape->body = body;+	shape->massInfo = massInfo;+	+	shape->sensor = 0;+	+	shape->e = 0.0f;+	shape->u = 0.0f;+	shape->surfaceV = cpvzero;+	+	shape->type = 0;+	shape->filter.group = CP_NO_GROUP;+	shape->filter.categories = CP_ALL_CATEGORIES;+	shape->filter.mask = CP_ALL_CATEGORIES;+	+	shape->userData = NULL;+	+	shape->space = NULL;+	+	shape->next = NULL;+	shape->prev = NULL;+	+	return shape;+}++void+cpShapeDestroy(cpShape *shape)+{+	if(shape->klass && shape->klass->destroy) shape->klass->destroy(shape);+}++void+cpShapeFree(cpShape *shape)+{+	if(shape){+		cpShapeDestroy(shape);+		cpfree(shape);+	}+}++cpSpace *+cpShapeGetSpace(const cpShape *shape)+{+	return shape->space;+}++cpBody *+cpShapeGetBody(const cpShape *shape)+{+	return shape->body;+}++void+cpShapeSetBody(cpShape *shape, cpBody *body)+{+	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;+}++cpFloat cpShapeGetMass(cpShape *shape){ return shape->massInfo.m; }++void+cpShapeSetMass(cpShape *shape, cpFloat mass){+	cpBody *body = shape->body;+	cpBodyActivate(body);+	+	shape->massInfo.m = mass;+	cpBodyAccumulateMassFromShapes(body);+}++cpFloat cpShapeGetDensity(cpShape *shape){ return shape->massInfo.m/shape->massInfo.area; }+void cpShapeSetDensity(cpShape *shape, cpFloat density){ cpShapeSetMass(shape, density*shape->massInfo.area); }++cpFloat cpShapeGetMoment(cpShape *shape){ return shape->massInfo.m*shape->massInfo.i; }+cpFloat cpShapeGetArea(cpShape *shape){ return shape->massInfo.area; }+cpVect cpShapeGetCenterOfGravity(cpShape *shape) { return shape->massInfo.cog; }++cpBB+cpShapeGetBB(const cpShape *shape)+{+	return shape->bb;+}++cpBool+cpShapeGetSensor(const cpShape *shape)+{+	return shape->sensor;+}++void+cpShapeSetSensor(cpShape *shape, cpBool sensor)+{+	cpBodyActivate(shape->body);+	shape->sensor = sensor;+}++cpFloat+cpShapeGetElasticity(const cpShape *shape)+{+	return shape->e;+}++void+cpShapeSetElasticity(cpShape *shape, cpFloat elasticity)+{+	cpAssertHard(elasticity >= 0.0f, "Elasticity must be positive.");+	cpBodyActivate(shape->body);+	shape->e = elasticity;+}++cpFloat+cpShapeGetFriction(const cpShape *shape)+{+	return shape->u;+}++void+cpShapeSetFriction(cpShape *shape, cpFloat friction)+{+	cpAssertHard(friction >= 0.0f, "Friction must be postive.");+	cpBodyActivate(shape->body);+	shape->u = friction;+}++cpVect+cpShapeGetSurfaceVelocity(const cpShape *shape)+{+	return shape->surfaceV;+}++void+cpShapeSetSurfaceVelocity(cpShape *shape, cpVect surfaceVelocity)+{+	cpBodyActivate(shape->body);+	shape->surfaceV = surfaceVelocity;+}++cpDataPointer+cpShapeGetUserData(const cpShape *shape)+{+	return shape->userData;+}++void+cpShapeSetUserData(cpShape *shape, cpDataPointer userData)+{+	shape->userData = userData;+}++cpCollisionType+cpShapeGetCollisionType(const cpShape *shape)+{+	return shape->type;+}++void+cpShapeSetCollisionType(cpShape *shape, cpCollisionType collisionType)+{+	cpBodyActivate(shape->body);+	shape->type = collisionType;+}++cpShapeFilter+cpShapeGetFilter(const cpShape *shape)+{+	return shape->filter;+}++void+cpShapeSetFilter(cpShape *shape, cpShapeFilter filter)+{+	cpBodyActivate(shape->body);+	shape->filter = filter;+}++cpBB+cpShapeCacheBB(cpShape *shape)+{+	return cpShapeUpdate(shape, shape->body->transform);+}++cpBB+cpShapeUpdate(cpShape *shape, cpTransform transform)+{+	return (shape->bb = shape->klass->cacheData(shape, transform));+}++cpFloat+cpShapePointQuery(const cpShape *shape, cpVect p, cpPointQueryInfo *info)+{+	cpPointQueryInfo blank = {NULL, cpvzero, INFINITY, cpvzero};+	if(info){+		(*info) = blank;+	} else {+		info = &blank;+	}+	+	shape->klass->pointQuery(shape, p, info);+	return info->distance;+}+++cpBool+cpShapeSegmentQuery(const cpShape *shape, cpVect a, cpVect b, cpFloat radius, cpSegmentQueryInfo *info){+	cpSegmentQueryInfo blank = {NULL, b, cpvzero, 1.0f};+	if(info){+		(*info) = blank;+	} else {+		info = &blank;+	}+	+	cpPointQueryInfo nearest;+	shape->klass->pointQuery(shape, a, &nearest);+	if(nearest.distance <= radius){+		info->shape = shape;+		info->alpha = 0.0;+		info->normal = cpvnormalize(cpvsub(a, nearest.point));+	} else {+		shape->klass->segmentQuery(shape, a, b, radius, info);+	}+	+	return (info->shape != NULL);+}++cpContactPointSet+cpShapesCollide(const cpShape *a, const cpShape *b)+{+	struct cpContact contacts[CP_MAX_CONTACTS_PER_ARBITER];+	struct cpCollisionInfo info = cpCollide(a, b, 0, contacts);+	+	cpContactPointSet set;+	set.count = info.count;+	+	// cpCollideShapes() may have swapped the contact order. Flip the normal.+	cpBool swapped = (a != info.a);+	set.normal = (swapped ? cpvneg(info.n) : info.n);+	+	for(int i=0; i<info.count; i++){+		// cpCollideShapesInfo() returns contacts with absolute positions.+		cpVect p1 = contacts[i].r1;+		cpVect p2 = contacts[i].r2;+		+		set.points[i].pointA = (swapped ? p2 : p1);+		set.points[i].pointB = (swapped ? p1 : p2);+		set.points[i].distance = cpvdot(cpvsub(p2, p1), set.normal);+	}+	+	return set;+}++cpCircleShape *+cpCircleShapeAlloc(void)+{+	return (cpCircleShape *)cpcalloc(1, sizeof(cpCircleShape));+}++static cpBB+cpCircleShapeCacheData(cpCircleShape *circle, cpTransform transform)+{+	cpVect c = circle->tc = cpTransformPoint(transform, circle->c);+	return cpBBNewForCircle(c, circle->r);+}++static void+cpCircleShapePointQuery(cpCircleShape *circle, cpVect p, cpPointQueryInfo *info)+{+	cpVect delta = cpvsub(p, circle->tc);+	cpFloat d = cpvlength(delta);+	cpFloat r = circle->r;+	+	info->shape = (cpShape *)circle;+	info->point = cpvadd(circle->tc, cpvmult(delta, r/d)); // TODO: div/0+	info->distance = d - r;+	+	// Use up for the gradient if the distance is very small.+	info->gradient = (d > MAGIC_EPSILON ? cpvmult(delta, 1.0f/d) : cpv(0.0f, 1.0f));+}++static void+cpCircleShapeSegmentQuery(cpCircleShape *circle, cpVect a, cpVect b, cpFloat radius, cpSegmentQueryInfo *info)+{+	CircleSegmentQuery((cpShape *)circle, circle->tc, circle->r, a, b, radius, info);+}++static struct cpShapeMassInfo+cpCircleShapeMassInfo(cpFloat mass, cpFloat radius, cpVect center)+{+	struct cpShapeMassInfo info = {+		mass, cpMomentForCircle(1.0f, 0.0f, radius, cpvzero),+		center,+		cpAreaForCircle(0.0f, radius),+	};+	+	return info;+}++static const cpShapeClass cpCircleShapeClass = {+	CP_CIRCLE_SHAPE,+	(cpShapeCacheDataImpl)cpCircleShapeCacheData,+	NULL,+	(cpShapePointQueryImpl)cpCircleShapePointQuery,+	(cpShapeSegmentQueryImpl)cpCircleShapeSegmentQuery,+};++cpCircleShape *+cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)+{+	circle->c = offset;+	circle->r = radius;+	+	cpShapeInit((cpShape *)circle, &cpCircleShapeClass, body, cpCircleShapeMassInfo(0.0f, radius, offset));+	+	return circle;+}++cpShape *+cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)+{+	return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset);+}++cpVect+cpCircleShapeGetOffset(const cpShape *shape)+{+	cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");+	return ((cpCircleShape *)shape)->c;+}++cpFloat+cpCircleShapeGetRadius(const cpShape *shape)+{+	cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");+	return ((cpCircleShape *)shape)->r;+}+++cpSegmentShape *+cpSegmentShapeAlloc(void)+{+	return (cpSegmentShape *)cpcalloc(1, sizeof(cpSegmentShape));+}++static cpBB+cpSegmentShapeCacheData(cpSegmentShape *seg, cpTransform transform)+{+	seg->ta = cpTransformPoint(transform, seg->a);+	seg->tb = cpTransformPoint(transform, seg->b);+	seg->tn = cpTransformVect(transform, seg->n);+	+	cpFloat l,r,b,t;+	+	if(seg->ta.x < seg->tb.x){+		l = seg->ta.x;+		r = seg->tb.x;+	} else {+		l = seg->tb.x;+		r = seg->ta.x;+	}+	+	if(seg->ta.y < seg->tb.y){+		b = seg->ta.y;+		t = seg->tb.y;+	} else {+		b = seg->tb.y;+		t = seg->ta.y;+	}+	+	cpFloat rad = seg->r;+	return cpBBNew(l - rad, b - rad, r + rad, t + rad);+}++static void+cpSegmentShapePointQuery(cpSegmentShape *seg, cpVect p, cpPointQueryInfo *info)+{+	cpVect closest = cpClosetPointOnSegment(p, seg->ta, seg->tb);+	+	cpVect delta = cpvsub(p, closest);+	cpFloat d = cpvlength(delta);+	cpFloat r = seg->r;+	cpVect g = cpvmult(delta, 1.0f/d);+	+	info->shape = (cpShape *)seg;+	info->point = (d ? cpvadd(closest, cpvmult(g, r)) : closest);+	info->distance = d - r;+	+	// Use the segment's normal if the distance is very small.+	info->gradient = (d > MAGIC_EPSILON ? g : seg->n);+}++static void+cpSegmentShapeSegmentQuery(cpSegmentShape *seg, cpVect a, cpVect b, cpFloat r2, cpSegmentQueryInfo *info)+{+	cpVect n = seg->tn;+	cpFloat d = cpvdot(cpvsub(seg->ta, a), n);+	cpFloat r = seg->r + r2;+	+	cpVect flipped_n = (d > 0.0f ? cpvneg(n) : n);+	cpVect seg_offset = cpvsub(cpvmult(flipped_n, r), a);+	+	// 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(ad*bd < 0.0f){+			cpFloat t = ad/(ad - bd);+			+			info->shape = (cpShape *)seg;+			info->point = cpvsub(cpvlerp(a, b, t), cpvmult(flipped_n, r2));+			info->normal = flipped_n;+			info->alpha = t;+		}+	} else if(r != 0.0f){+		cpSegmentQueryInfo info1 = {NULL, b, cpvzero, 1.0f};+		cpSegmentQueryInfo info2 = {NULL, b, cpvzero, 1.0f};+		CircleSegmentQuery((cpShape *)seg, seg->ta, seg->r, a, b, r2, &info1);+		CircleSegmentQuery((cpShape *)seg, seg->tb, seg->r, a, b, r2, &info2);+		+		if(info1.alpha < info2.alpha){+			(*info) = info1;+		} else {+			(*info) = info2;+		}+	}+}++static struct cpShapeMassInfo+cpSegmentShapeMassInfo(cpFloat mass, cpVect a, cpVect b, cpFloat r)+{+	struct cpShapeMassInfo info = {+		mass, cpMomentForBox(1.0f, cpvdist(a, b) + 2.0f*r, 2.0f*r), // TODO is an approximation.+		cpvlerp(a, b, 0.5f),+		cpAreaForSegment(a, b, r),+	};+	+	return info;+}++static const cpShapeClass cpSegmentShapeClass = {+	CP_SEGMENT_SHAPE,+	(cpShapeCacheDataImpl)cpSegmentShapeCacheData,+	NULL,+	(cpShapePointQueryImpl)cpSegmentShapePointQuery,+	(cpShapeSegmentQueryImpl)cpSegmentShapeSegmentQuery,+};++cpSegmentShape *+cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r)+{+	seg->a = a;+	seg->b = b;+	seg->n = cpvrperp(cpvnormalize(cpvsub(b, a)));+	+	seg->r = r;+	+	seg->a_tangent = cpvzero;+	seg->b_tangent = cpvzero;+	+	cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body, cpSegmentShapeMassInfo(0.0f, a, b, r));+	+	return seg;+}++cpShape*+cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r)+{+	return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r);+}++cpVect+cpSegmentShapeGetA(const cpShape *shape)+{+	cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");+	return ((cpSegmentShape *)shape)->a;+}++cpVect+cpSegmentShapeGetB(const cpShape *shape)+{+	cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");+	return ((cpSegmentShape *)shape)->b;+}++cpVect+cpSegmentShapeGetNormal(const cpShape *shape)+{+	cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");+	return ((cpSegmentShape *)shape)->n;+}++cpFloat+cpSegmentShapeGetRadius(const cpShape *shape)+{+	cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");+	return ((cpSegmentShape *)shape)->r;+}++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)++// TODO setters should wake the shape up?++void+cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)+{+	cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");+	cpCircleShape *circle = (cpCircleShape *)shape;+	+	circle->r = radius;+	+	cpFloat mass = shape->massInfo.m;+	shape->massInfo = cpCircleShapeMassInfo(mass, circle->r, circle->c);+	if(mass > 0.0f) cpBodyAccumulateMassFromShapes(shape->body);+}++void+cpCircleShapeSetOffset(cpShape *shape, cpVect offset)+{+	cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");+	cpCircleShape *circle = (cpCircleShape *)shape;+	+	circle->c = offset;++	cpFloat mass = shape->massInfo.m;+	shape->massInfo = cpCircleShapeMassInfo(shape->massInfo.m, circle->r, circle->c);+	if(mass > 0.0f) cpBodyAccumulateMassFromShapes(shape->body);+}++void+cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)+{+	cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");+	cpSegmentShape *seg = (cpSegmentShape *)shape;+	+	seg->a = a;+	seg->b = b;+	seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));++	cpFloat mass = shape->massInfo.m;+	shape->massInfo = cpSegmentShapeMassInfo(shape->massInfo.m, seg->a, seg->b, seg->r);+	if(mass > 0.0f) cpBodyAccumulateMassFromShapes(shape->body);+}++void+cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius)+{+	cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");+	cpSegmentShape *seg = (cpSegmentShape *)shape;+	+	seg->r = radius;++	cpFloat mass = shape->massInfo.m;+	shape->massInfo = cpSegmentShapeMassInfo(shape->massInfo.m, seg->a, seg->b, seg->r);+	if(mass > 0.0f) cpBodyAccumulateMassFromShapes(shape->body);+}
+ Chipmunk2D-7.0.2/src/cpSimpleMotor.c view
@@ -0,0 +1,123 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpSimpleMotor *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// calculate moment of inertia coefficient.+	joint->iSum = 1.0f/(a->i_inv + b->i_inv);+}++static void+applyCachedImpulse(cpSimpleMotor *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpFloat j = joint->jAcc*dt_coef;+	a->w -= j*a->i_inv;+	b->w += j*b->i_inv;+}++static void+applyImpulse(cpSimpleMotor *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	// 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, -jMax, jMax);+	j = joint->jAcc - jOld;+	+	// apply impulse+	a->w -= j*a->i_inv;+	b->w += j*b->i_inv;+}++static cpFloat+getImpulse(cpSimpleMotor *joint)+{+	return cpfabs(joint->jAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpSimpleMotor *+cpSimpleMotorAlloc(void)+{+	return (cpSimpleMotor *)cpcalloc(1, sizeof(cpSimpleMotor));+}++cpSimpleMotor *+cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->rate = rate;+	+	joint->jAcc = 0.0f;+	+	return joint;+}++cpConstraint *+cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate)+{+	return (cpConstraint *)cpSimpleMotorInit(cpSimpleMotorAlloc(), a, b, rate);+}++cpBool+cpConstraintIsSimpleMotor(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpFloat+cpSimpleMotorGetRate(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsSimpleMotor(constraint), "Constraint is not a pin joint.");+	return ((cpSimpleMotor *)constraint)->rate;+}++void+cpSimpleMotorSetRate(cpConstraint *constraint, cpFloat rate)+{+	cpAssertHard(cpConstraintIsSimpleMotor(constraint), "Constraint is not a pin joint.");+	cpConstraintActivateBodies(constraint);+	((cpSimpleMotor *)constraint)->rate = rate;+}
+ Chipmunk2D-7.0.2/src/cpSlideJoint.c view
@@ -0,0 +1,195 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static void+preStep(cpSlideJoint *joint, cpFloat dt)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	joint->r1 = cpTransformVect(a->transform, cpvsub(joint->anchorA, a->cog));+	joint->r2 = cpTransformVect(b->transform, cpvsub(joint->anchorB, b->cog));+	+	cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));+	cpFloat dist = cpvlength(delta);+	cpFloat pdist = 0.0f;+	if(dist > joint->max) {+		pdist = dist - joint->max;+		joint->n = cpvnormalize(delta);+	} else if(dist < joint->min) {+		pdist = joint->min - dist;+		joint->n = cpvneg(cpvnormalize(delta));+	} else {+		joint->n = cpvzero;+		joint->jnAcc = 0.0f;+	}+	+	// calculate mass normal+	joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);+	+	// calculate bias velocity+	cpFloat maxBias = joint->constraint.maxBias;+	joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);+}++static void+applyCachedImpulse(cpSlideJoint *joint, cpFloat dt_coef)+{+	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpVect j = cpvmult(joint->n, joint->jnAcc*dt_coef);+	apply_impulses(a, b, joint->r1, joint->r2, j);+}++static void+applyImpulse(cpSlideJoint *joint, cpFloat dt)+{+	if(cpveql(joint->n, cpvzero)) return;  // early exit++	cpBody *a = joint->constraint.a;+	cpBody *b = joint->constraint.b;+	+	cpVect n = joint->n;+	cpVect r1 = joint->r1;+	cpVect r2 = joint->r2;+		+	// compute relative velocity+	cpVect vr = relative_velocity(a, b, r1, r2);+	cpFloat vrn = cpvdot(vr, n);+	+	// compute normal impulse+	cpFloat jn = (joint->bias - vrn)*joint->nMass;+	cpFloat jnOld = joint->jnAcc;+	joint->jnAcc = cpfclamp(jnOld + jn, -joint->constraint.maxForce*dt, 0.0f);+	jn = joint->jnAcc - jnOld;+	+	// apply impulse+	apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));+}++static cpFloat+getImpulse(cpConstraint *joint)+{+	return cpfabs(((cpSlideJoint *)joint)->jnAcc);+}++static const cpConstraintClass klass = {+	(cpConstraintPreStepImpl)preStep,+	(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,+	(cpConstraintApplyImpulseImpl)applyImpulse,+	(cpConstraintGetImpulseImpl)getImpulse,+};++cpSlideJoint *+cpSlideJointAlloc(void)+{+	return (cpSlideJoint *)cpcalloc(1, sizeof(cpSlideJoint));+}++cpSlideJoint *+cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat min, cpFloat max)+{+	cpConstraintInit((cpConstraint *)joint, &klass, a, b);+	+	joint->anchorA = anchorA;+	joint->anchorB = anchorB;+	joint->min = min;+	joint->max = max;+	+	joint->jnAcc = 0.0f;+	+	return joint;+}++cpConstraint *+cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchorA, cpVect anchorB, cpFloat min, cpFloat max)+{+	return (cpConstraint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchorA, anchorB, min, max);+}++cpBool+cpConstraintIsSlideJoint(const cpConstraint *constraint)+{+	return (constraint->klass == &klass);+}++cpVect+cpSlideJointGetAnchorA(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	return ((cpSlideJoint *)constraint)->anchorA;+}++void+cpSlideJointSetAnchorA(cpConstraint *constraint, cpVect anchorA)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	cpConstraintActivateBodies(constraint);+	((cpSlideJoint *)constraint)->anchorA = anchorA;+}++cpVect+cpSlideJointGetAnchorB(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	return ((cpSlideJoint *)constraint)->anchorB;+}++void+cpSlideJointSetAnchorB(cpConstraint *constraint, cpVect anchorB)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	cpConstraintActivateBodies(constraint);+	((cpSlideJoint *)constraint)->anchorB = anchorB;+}++cpFloat+cpSlideJointGetMin(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	return ((cpSlideJoint *)constraint)->min;+}++void+cpSlideJointSetMin(cpConstraint *constraint, cpFloat min)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	cpConstraintActivateBodies(constraint);+	((cpSlideJoint *)constraint)->min = min;+}++cpFloat+cpSlideJointGetMax(const cpConstraint *constraint)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	return ((cpSlideJoint *)constraint)->max;+}++void+cpSlideJointSetMax(cpConstraint *constraint, cpFloat max)+{+	cpAssertHard(cpConstraintIsSlideJoint(constraint), "Constraint is not a slide joint.");+	cpConstraintActivateBodies(constraint);+	((cpSlideJoint *)constraint)->max = max;+}
+ Chipmunk2D-7.0.2/src/cpSpace.c view
@@ -0,0 +1,700 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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 <stdio.h>+#include <string.h>++#include "chipmunk/chipmunk_private.h"++//MARK: Contact Set Helpers++// Equal function for arbiterSet.+static cpBool+arbiterSetEql(cpShape **shapes, cpArbiter *arb)+{+	cpShape *a = shapes[0];+	cpShape *b = shapes[1];+	+	return ((a == arb->a && b == arb->b) || (b == arb->a && a == arb->b));+}++//MARK: Collision Handler Set HelperFunctions++// Equals function for collisionHandlers.+static cpBool+handlerSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)+{+	return (+		(check->typeA == pair->typeA && check->typeB == pair->typeB) ||+		(check->typeB == pair->typeA && check->typeA == pair->typeB)+	);+}++// Transformation function for collisionHandlers.+static void *+handlerSetTrans(cpCollisionHandler *handler, void *unused)+{+	cpCollisionHandler *copy = (cpCollisionHandler *)cpcalloc(1, sizeof(cpCollisionHandler));+	memcpy(copy, handler, sizeof(cpCollisionHandler));+	+	return copy;+}++//MARK: Misc Helper Funcs++// Default collision functions.++static cpBool+DefaultBegin(cpArbiter *arb, cpSpace *space, void *data){+	cpBool retA = cpArbiterCallWildcardBeginA(arb, space);+	cpBool retB = cpArbiterCallWildcardBeginB(arb, space);+	return retA && retB;+}++static cpBool+DefaultPreSolve(cpArbiter *arb, cpSpace *space, void *data){+	cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space);+	cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space);+	return retA && retB;+}++static void+DefaultPostSolve(cpArbiter *arb, cpSpace *space, void *data){+	cpArbiterCallWildcardPostSolveA(arb, space);+	cpArbiterCallWildcardPostSolveB(arb, space);+}++static void+DefaultSeparate(cpArbiter *arb, cpSpace *space, void *data){+	cpArbiterCallWildcardSeparateA(arb, space);+	cpArbiterCallWildcardSeparateB(arb, space);+}++// Use the wildcard identifier since  the default handler should never match any type pair.+static cpCollisionHandler cpCollisionHandlerDefault = {+	CP_WILDCARD_COLLISION_TYPE, CP_WILDCARD_COLLISION_TYPE,+	DefaultBegin, DefaultPreSolve, DefaultPostSolve, DefaultSeparate, NULL+};++static cpBool AlwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return cpTrue;}+static void DoNothing(cpArbiter *arb, cpSpace *space, void *data){}++cpCollisionHandler cpCollisionHandlerDoNothing = {+	CP_WILDCARD_COLLISION_TYPE, CP_WILDCARD_COLLISION_TYPE,+	AlwaysCollide, AlwaysCollide, DoNothing, DoNothing, NULL+};++// function to get the estimated velocity of a shape for the cpBBTree.+static cpVect ShapeVelocityFunc(cpShape *shape){return shape->body->v;}++// Used for disposing of collision handlers.+static void FreeWrap(void *ptr, void *unused){cpfree(ptr);}++//MARK: Memory Management Functions++cpSpace *+cpSpaceAlloc(void)+{+	return (cpSpace *)cpcalloc(1, sizeof(cpSpace));+}++cpSpace*+cpSpaceInit(cpSpace *space)+{+#ifndef NDEBUG+	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;+	+	space->gravity = cpvzero;+	space->damping = 1.0f;+	+	space->collisionSlop = 0.1f;+	space->collisionBias = cpfpow(1.0f - 0.1f, 60.0f);+	space->collisionPersistence = 3;+	+	space->locked = 0;+	space->stamp = 0;+	+	space->shapeIDCounter = 0;+	space->staticShapes = cpBBTreeNew((cpSpatialIndexBBFunc)cpShapeGetBB, NULL);+	space->dynamicShapes = cpBBTreeNew((cpSpatialIndexBBFunc)cpShapeGetBB, space->staticShapes);+	cpBBTreeSetVelocityFunc(space->dynamicShapes, (cpBBTreeVelocityFunc)ShapeVelocityFunc);+	+	space->allocatedBuffers = cpArrayNew(0);+	+	space->dynamicBodies = cpArrayNew(0);+	space->staticBodies = cpArrayNew(0);+	space->sleepingComponents = cpArrayNew(0);+	space->rousedBodies = cpArrayNew(0);+	+	space->sleepTimeThreshold = INFINITY;+	space->idleSpeedThreshold = 0.0f;+	+	space->arbiters = cpArrayNew(0);+	space->pooledArbiters = cpArrayNew(0);+	+	space->contactBuffersHead = NULL;+	space->cachedArbiters = cpHashSetNew(0, (cpHashSetEqlFunc)arbiterSetEql);+	+	space->constraints = cpArrayNew(0);+	+	space->usesWildcards = cpFalse;+	memcpy(&space->defaultHandler, &cpCollisionHandlerDoNothing, sizeof(cpCollisionHandler));+	space->collisionHandlers = cpHashSetNew(0, (cpHashSetEqlFunc)handlerSetEql);+	+	space->postStepCallbacks = cpArrayNew(0);+	space->skipPostStep = cpFalse;+	+	cpBody *staticBody = cpBodyInit(&space->_staticBody, 0.0f, 0.0f);+	cpBodySetType(staticBody, CP_BODY_TYPE_STATIC);+	cpSpaceSetStaticBody(space, staticBody);+	+	return space;+}++cpSpace*+cpSpaceNew(void)+{+	return cpSpaceInit(cpSpaceAlloc());+}++static void cpBodyActivateWrap(cpBody *body, void *unused){cpBodyActivate(body);}++void+cpSpaceDestroy(cpSpace *space)+{+	cpSpaceEachBody(space, (cpSpaceBodyIteratorFunc)cpBodyActivateWrap, NULL);+	+	cpSpatialIndexFree(space->staticShapes);+	cpSpatialIndexFree(space->dynamicShapes);+	+	cpArrayFree(space->dynamicBodies);+	cpArrayFree(space->staticBodies);+	cpArrayFree(space->sleepingComponents);+	cpArrayFree(space->rousedBodies);+	+	cpArrayFree(space->constraints);+	+	cpHashSetFree(space->cachedArbiters);+	+	cpArrayFree(space->arbiters);+	cpArrayFree(space->pooledArbiters);+	+	if(space->allocatedBuffers){+		cpArrayFreeEach(space->allocatedBuffers, cpfree);+		cpArrayFree(space->allocatedBuffers);+	}+	+	if(space->postStepCallbacks){+		cpArrayFreeEach(space->postStepCallbacks, cpfree);+		cpArrayFree(space->postStepCallbacks);+	}+	+	if(space->collisionHandlers) cpHashSetEach(space->collisionHandlers, FreeWrap, NULL);+	cpHashSetFree(space->collisionHandlers);+}++void+cpSpaceFree(cpSpace *space)+{+	if(space){+		cpSpaceDestroy(space);+		cpfree(space);+	}+}+++//MARK: Basic properties:++int+cpSpaceGetIterations(const cpSpace *space)+{+	return space->iterations;+}++void+cpSpaceSetIterations(cpSpace *space, int iterations)+{+	cpAssertHard(iterations > 0, "Iterations must be positive and non-zero.");+	space->iterations = iterations;+}++cpVect+cpSpaceGetGravity(const cpSpace *space)+{+	return space->gravity;+}++void+cpSpaceSetGravity(cpSpace *space, cpVect gravity)+{+	space->gravity = gravity;+	+	// Wake up all of the bodies since the gravity changed.+	cpArray *components = space->sleepingComponents;+	for(int i=0; i<components->num; i++){+		cpBodyActivate((cpBody *)components->arr[i]);+	}+}++cpFloat+cpSpaceGetDamping(const cpSpace *space)+{+	return space->damping;+}++void+cpSpaceSetDamping(cpSpace *space, cpFloat damping)+{+	cpAssertHard(damping >= 0.0, "Damping must be positive.");+	space->damping = damping;+}++cpFloat+cpSpaceGetIdleSpeedThreshold(const cpSpace *space)+{+	return space->idleSpeedThreshold;+}++void+cpSpaceSetIdleSpeedThreshold(cpSpace *space, cpFloat idleSpeedThreshold)+{+	space->idleSpeedThreshold = idleSpeedThreshold;+}++cpFloat+cpSpaceGetSleepTimeThreshold(const cpSpace *space)+{+	return space->sleepTimeThreshold;+}++void+cpSpaceSetSleepTimeThreshold(cpSpace *space, cpFloat sleepTimeThreshold)+{+	space->sleepTimeThreshold = sleepTimeThreshold;+}++cpFloat+cpSpaceGetCollisionSlop(const cpSpace *space)+{+	return space->collisionSlop;+}++void+cpSpaceSetCollisionSlop(cpSpace *space, cpFloat collisionSlop)+{+	space->collisionSlop = collisionSlop;+}++cpFloat+cpSpaceGetCollisionBias(const cpSpace *space)+{+	return space->collisionBias;+}++void+cpSpaceSetCollisionBias(cpSpace *space, cpFloat collisionBias)+{+	space->collisionBias = collisionBias;+}++cpTimestamp+cpSpaceGetCollisionPersistence(const cpSpace *space)+{+	return space->collisionPersistence;+}++void+cpSpaceSetCollisionPersistence(cpSpace *space, cpTimestamp collisionPersistence)+{+	space->collisionPersistence = collisionPersistence;+}++cpDataPointer+cpSpaceGetUserData(const cpSpace *space)+{+	return space->userData;+}++void+cpSpaceSetUserData(cpSpace *space, cpDataPointer userData)+{+	space->userData = userData;+}++cpBody *+cpSpaceGetStaticBody(const cpSpace *space)+{+	return space->staticBody;+}++cpFloat+cpSpaceGetCurrentTimeStep(const cpSpace *space)+{+	return space->curr_dt;+}++void+cpSpaceSetStaticBody(cpSpace *space, cpBody *body)+{+	if(space->staticBody != NULL){+		cpAssertHard(space->staticBody->shapeList == NULL, "Internal Error: Changing the designated static body while the old one still had shapes attached.");+		space->staticBody->space = NULL;+	}+	+	space->staticBody = body;+	body->space = space;+}++cpBool+cpSpaceIsLocked(cpSpace *space)+{+	return (space->locked > 0);+}++//MARK: Collision Handler Function Management++static void+cpSpaceUseWildcardDefaultHandler(cpSpace *space)+{+	// Spaces default to using the slightly faster "do nothing" default handler until wildcards are potentially needed.+	if(!space->usesWildcards){+		space->usesWildcards = cpTrue;+		memcpy(&space->defaultHandler, &cpCollisionHandlerDefault, sizeof(cpCollisionHandler));+	}+}++cpCollisionHandler *cpSpaceAddDefaultCollisionHandler(cpSpace *space)+{+	cpSpaceUseWildcardDefaultHandler(space);+	return &space->defaultHandler;+}++cpCollisionHandler *cpSpaceAddCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)+{+	cpHashValue hash = CP_HASH_PAIR(a, b);+	cpCollisionHandler handler = {a, b, DefaultBegin, DefaultPreSolve, DefaultPostSolve, DefaultSeparate, NULL};+	return (cpCollisionHandler*)cpHashSetInsert(space->collisionHandlers, hash, &handler, (cpHashSetTransFunc)handlerSetTrans, NULL);+}++cpCollisionHandler *+cpSpaceAddWildcardHandler(cpSpace *space, cpCollisionType type)+{+	cpSpaceUseWildcardDefaultHandler(space);+	+	cpHashValue hash = CP_HASH_PAIR(type, CP_WILDCARD_COLLISION_TYPE);+	cpCollisionHandler handler = {type, CP_WILDCARD_COLLISION_TYPE, AlwaysCollide, AlwaysCollide, DoNothing, DoNothing, NULL};+	return (cpCollisionHandler*)cpHashSetInsert(space->collisionHandlers, hash, &handler, (cpHashSetTransFunc)handlerSetTrans, NULL);+}+++//MARK: Body, Shape, and Joint Management+cpShape *+cpSpaceAddShape(cpSpace *space, cpShape *shape)+{+	cpBody *body = shape->body;+	+	cpAssertHard(shape->space != space, "You have already added this shape to this space. You must not add it a second time.");+	cpAssertHard(!shape->space, "You have already added this shape to another space. You cannot add it to a second.");+//	cpAssertHard(body->space == space, "The shape's body must be added to the space before the shape.");+	cpAssertSpaceUnlocked(space);+	+	cpBool isStatic = (cpBodyGetType(body) == CP_BODY_TYPE_STATIC);+	if(!isStatic) cpBodyActivate(body);+	cpBodyAddShape(body, shape);+	+	shape->hashid = space->shapeIDCounter++;+	cpShapeUpdate(shape, body->transform);+	cpSpatialIndexInsert(isStatic ? space->staticShapes : space->dynamicShapes, shape, shape->hashid);+	shape->space = space;+		+	return shape;+}++cpBody *+cpSpaceAddBody(cpSpace *space, cpBody *body)+{+	cpAssertHard(body->space != space, "You have already added this body to this space. You must not add it a second time.");+	cpAssertHard(!body->space, "You have already added this body to another space. You cannot add it to a second.");+	cpAssertSpaceUnlocked(space);+	+	cpArrayPush(cpSpaceArrayForBodyType(space, cpBodyGetType(body)), body);+	body->space = space;+	+	return body;+}++cpConstraint *+cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)+{+	cpAssertHard(constraint->space != space, "You have already added this constraint to this space. You must not add it a second time.");+	cpAssertHard(!constraint->space, "You have already added this constraint to another space. You cannot add it to a second.");+	cpAssertSpaceUnlocked(space);+	+	cpBody *a = constraint->a, *b = constraint->b;+	cpAssertHard(a != NULL && b != NULL, "Constraint is attached to a NULL body.");+//	cpAssertHard(a->space == space && b->space == space, "The constraint's bodies must be added to the space before the constraint.");+	+	cpBodyActivate(a);+	cpBodyActivate(b);+	cpArrayPush(space->constraints, constraint);+	+	// Push onto the heads of the bodies' constraint lists+	constraint->next_a = a->constraintList; a->constraintList = constraint;+	constraint->next_b = b->constraintList; b->constraintList = constraint;+	constraint->space = space;+	+	return constraint;+}++struct arbiterFilterContext {+	cpSpace *space;+	cpBody *body;+	cpShape *shape;+};++static cpBool+cachedArbitersFilter(cpArbiter *arb, struct arbiterFilterContext *context)+{+	cpShape *shape = context->shape;+	cpBody *body = context->body;+	+	+	// 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 != CP_ARBITER_STATE_CACHED){+			// Invalidate the arbiter since one of the shapes was removed.+			arb->state = CP_ARBITER_STATE_INVALIDATED;+			+			cpCollisionHandler *handler = arb->handler;+			handler->separateFunc(arb, context->space, handler->userData);+		}+		+		cpArbiterUnthread(arb);+		cpArrayDeleteObj(context->space->arbiters, arb);+		cpArrayPush(context->space->pooledArbiters, arb);+		+		return cpFalse;+	}+	+	return cpTrue;+}++void+cpSpaceFilterArbiters(cpSpace *space, cpBody *body, cpShape *filter)+{+	cpSpaceLock(space); {+		struct arbiterFilterContext context = {space, body, filter};+		cpHashSetFilter(space->cachedArbiters, (cpHashSetFilterFunc)cachedArbitersFilter, &context);+	} cpSpaceUnlock(space, cpTrue);+}++void+cpSpaceRemoveShape(cpSpace *space, cpShape *shape)+{+	cpBody *body = shape->body;+	cpAssertHard(cpSpaceContainsShape(space, shape), "Cannot remove a shape that was not added to the space. (Removed twice maybe?)");+	cpAssertSpaceUnlocked(space);+	+	cpBool isStatic = (cpBodyGetType(body) == CP_BODY_TYPE_STATIC);+	if(isStatic){+		cpBodyActivateStatic(body, shape);+	} else {+		cpBodyActivate(body);+	}++	cpBodyRemoveShape(body, shape);+	cpSpaceFilterArbiters(space, body, shape);+	cpSpatialIndexRemove(isStatic ? space->staticShapes : space->dynamicShapes, shape, shape->hashid);+	shape->space = NULL;+	shape->hashid = 0;+}++void+cpSpaceRemoveBody(cpSpace *space, cpBody *body)+{+	cpAssertHard(body != cpSpaceGetStaticBody(space), "Cannot remove the designated static body for the space.");+	cpAssertHard(cpSpaceContainsBody(space, body), "Cannot remove a body that was not added to the space. (Removed twice maybe?)");+//	cpAssertHard(body->shapeList == NULL, "Cannot remove a body from the space before removing the bodies attached to it.");+//	cpAssertHard(body->constraintList == NULL, "Cannot remove a body from the space before removing the constraints attached to it.");+	cpAssertSpaceUnlocked(space);+	+	cpBodyActivate(body);+//	cpSpaceFilterArbiters(space, body, NULL);+	cpArrayDeleteObj(cpSpaceArrayForBodyType(space, cpBodyGetType(body)), body);+	body->space = NULL;+}++void+cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)+{+	cpAssertHard(cpSpaceContainsConstraint(space, constraint), "Cannot remove a constraint that was not added to the space. (Removed twice maybe?)");+	cpAssertSpaceUnlocked(space);+	+	cpBodyActivate(constraint->a);+	cpBodyActivate(constraint->b);+	cpArrayDeleteObj(space->constraints, constraint);+	+	cpBodyRemoveConstraint(constraint->a, constraint);+	cpBodyRemoveConstraint(constraint->b, constraint);+	constraint->space = NULL;+}++cpBool cpSpaceContainsShape(cpSpace *space, cpShape *shape)+{+	return (shape->space == space);+}++cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body)+{+	return (body->space == space);+}++cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint)+{+	return (constraint->space == space);+}++//MARK: Iteration++void+cpSpaceEachBody(cpSpace *space, cpSpaceBodyIteratorFunc func, void *data)+{+	cpSpaceLock(space); {+		cpArray *bodies = space->dynamicBodies;+		for(int i=0; i<bodies->num; i++){+			func((cpBody *)bodies->arr[i], data);+		}+		+		cpArray *otherBodies = space->staticBodies;+		for(int i=0; i<otherBodies->num; i++){+			func((cpBody *)otherBodies->arr[i], data);+		}+		+		cpArray *components = space->sleepingComponents;+		for(int i=0; i<components->num; i++){+			cpBody *root = (cpBody *)components->arr[i];+			+			cpBody *body = root;+			while(body){+				cpBody *next = body->sleeping.next;+				func(body, data);+				body = next;+			}+		}+	} cpSpaceUnlock(space, cpTrue);+}++typedef struct spaceShapeContext {+	cpSpaceShapeIteratorFunc func;+	void *data;+} spaceShapeContext;++static void+spaceEachShapeIterator(cpShape *shape, spaceShapeContext *context)+{+	context->func(shape, context->data);+}++void+cpSpaceEachShape(cpSpace *space, cpSpaceShapeIteratorFunc func, void *data)+{+	cpSpaceLock(space); {+		spaceShapeContext context = {func, data};+		cpSpatialIndexEach(space->dynamicShapes, (cpSpatialIndexIteratorFunc)spaceEachShapeIterator, &context);+		cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)spaceEachShapeIterator, &context);+	} cpSpaceUnlock(space, cpTrue);+}++void+cpSpaceEachConstraint(cpSpace *space, cpSpaceConstraintIteratorFunc func, void *data)+{+	cpSpaceLock(space); {+		cpArray *constraints = space->constraints;+		+		for(int i=0; i<constraints->num; i++){+			func((cpConstraint *)constraints->arr[i], data);+		}+	} cpSpaceUnlock(space, cpTrue);+}++//MARK: Spatial Index Management++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)&cpShapeUpdateFunc, NULL);+	cpSpatialIndexReindex(space->staticShapes);+}++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.");+	+	cpShapeCacheBB(shape);+	+	// attempt to rehash the shape in both hashes+	cpSpatialIndexReindexObject(space->dynamicShapes, shape, shape->hashid);+	cpSpatialIndexReindexObject(space->staticShapes, shape, shape->hashid);+}++void+cpSpaceReindexShapesForBody(cpSpace *space, cpBody *body)+{+	CP_BODY_FOREACH_SHAPE(body, shape) cpSpaceReindexShape(space, shape);+}+++static void+copyShapes(cpShape *shape, cpSpatialIndex *index)+{+	cpSpatialIndexInsert(index, shape, shape->hashid);+}++void+cpSpaceUseSpatialHash(cpSpace *space, cpFloat dim, int count)+{+	cpSpatialIndex *staticShapes = cpSpaceHashNew(dim, count, (cpSpatialIndexBBFunc)cpShapeGetBB, NULL);+	cpSpatialIndex *dynamicShapes = cpSpaceHashNew(dim, count, (cpSpatialIndexBBFunc)cpShapeGetBB, staticShapes);+	+	cpSpatialIndexEach(space->staticShapes, (cpSpatialIndexIteratorFunc)copyShapes, staticShapes);+	cpSpatialIndexEach(space->dynamicShapes, (cpSpatialIndexIteratorFunc)copyShapes, dynamicShapes);+	+	cpSpatialIndexFree(space->staticShapes);+	cpSpatialIndexFree(space->dynamicShapes);+	+	space->staticShapes = staticShapes;+	space->dynamicShapes = dynamicShapes;+}
+ Chipmunk2D-7.0.2/src/cpSpaceComponent.c view
@@ -0,0 +1,349 @@+/* Copyright (c) 2007 Scott Lembcke+ * + * Permission is hereby granted, free of charge, to any person obtaining a copy+ * of this software and associated documentation files (the "Software"), to deal+ * in the Software without restriction, including without limitation the rights+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+ * copies of the Software, and to permit persons to whom the Software is+ * furnished to do so, subject to the following conditions:+ * + * The above copyright notice and this permission notice shall be included in+ * all copies or substantial portions of the Software.+ * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+ * SOFTWARE.+ */+ +#include <string.h>++#include "chipmunk/chipmunk_private.h"++//MARK: Sleeping Functions++void+cpSpaceActivateBody(cpSpace *space, cpBody *body)+{+	cpAssertHard(cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC, "Internal error: Attempting to activate a non-dynamic body.");+		+	if(space->locked){+		// cpSpaceActivateBody() is called again once the space is unlocked+		if(!cpArrayContains(space->rousedBodies, body)) cpArrayPush(space->rousedBodies, body);+	} else {+		cpAssertSoft(body->sleeping.root == NULL && body->sleeping.next == NULL, "Internal error: Activating body non-NULL node pointers.");+		cpArrayPush(space->dynamicBodies, body);++		CP_BODY_FOREACH_SHAPE(body, shape){+			cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid);+			cpSpatialIndexInsert(space->dynamicShapes, shape, shape->hashid);+		}+		+		CP_BODY_FOREACH_ARBITER(body, arb){+			cpBody *bodyA = arb->body_a;+			+			// Arbiters are shared between two bodies that are always woken up together.+			// You only want to restore the arbiter once, so bodyA is arbitrarily chosen to own the arbiter.+			// The edge case is when static bodies are involved as the static bodies never actually sleep.+			// If the static body is bodyB then all is good. If the static body is bodyA, that can easily be checked.+			if(body == bodyA || cpBodyGetType(bodyA) == CP_BODY_TYPE_STATIC){+				int numContacts = arb->count;+				struct cpContact *contacts = arb->contacts;+				+				// Restore contact values back to the space's contact buffer memory+				arb->contacts = cpContactBufferGetArray(space);+				memcpy(arb->contacts, contacts, numContacts*sizeof(struct cpContact));+				cpSpacePushContacts(space, numContacts);+				+				// Reinsert the arbiter into the arbiter cache+				const cpShape *a = arb->a, *b = arb->b;+				const cpShape *shape_pair[] = {a, b};+				cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)a, (cpHashValue)b);+				cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, NULL, arb);+				+				// Update the arbiter's state+				arb->stamp = space->stamp;+				cpArrayPush(space->arbiters, arb);+				+				cpfree(contacts);+			}+		}+		+		CP_BODY_FOREACH_CONSTRAINT(body, constraint){+			cpBody *bodyA = constraint->a;+			if(body == bodyA || cpBodyGetType(bodyA) == CP_BODY_TYPE_STATIC) cpArrayPush(space->constraints, constraint);+		}+	}+}++static void+cpSpaceDeactivateBody(cpSpace *space, cpBody *body)+{+	cpAssertHard(cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC, "Internal error: Attempting to deactivate a non-dynamic body.");+	+	cpArrayDeleteObj(space->dynamicBodies, body);+	+	CP_BODY_FOREACH_SHAPE(body, shape){+		cpSpatialIndexRemove(space->dynamicShapes, shape, shape->hashid);+		cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid);+	}+	+	CP_BODY_FOREACH_ARBITER(body, arb){+		cpBody *bodyA = arb->body_a;+		if(body == bodyA || cpBodyGetType(bodyA) == CP_BODY_TYPE_STATIC){+			cpSpaceUncacheArbiter(space, arb);+			+			// Save contact values to a new block of memory so they won't time out+			size_t bytes = arb->count*sizeof(struct cpContact);+			struct cpContact *contacts = (struct cpContact *)cpcalloc(1, bytes);+			memcpy(contacts, arb->contacts, bytes);+			arb->contacts = contacts;+		}+	}+		+	CP_BODY_FOREACH_CONSTRAINT(body, constraint){+		cpBody *bodyA = constraint->a;+		if(body == bodyA || cpBodyGetType(bodyA) == CP_BODY_TYPE_STATIC) cpArrayDeleteObj(space->constraints, constraint);+	}+}++static inline cpBody *+ComponentRoot(cpBody *body)+{+	return (body ? body->sleeping.root : NULL);+}++void+cpBodyActivate(cpBody *body)+{+	if(body != NULL && cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC){+		body->sleeping.idleTime = 0.0f;+		+		cpBody *root = ComponentRoot(body);+		if(root && cpBodyIsSleeping(root)){+			// TODO should cpBodyIsSleeping(root) be an assertion?+			cpAssertSoft(cpBodyGetType(root) == CP_BODY_TYPE_DYNAMIC, "Internal Error: Non-dynamic body component root detected.");+			+			cpSpace *space = root->space;+			cpBody *body = root;+			while(body){+				cpBody *next = body->sleeping.next;+				+				body->sleeping.idleTime = 0.0f;+				body->sleeping.root = NULL;+				body->sleeping.next = NULL;+				cpSpaceActivateBody(space, body);+				+				body = next;+			}+			+			cpArrayDeleteObj(space->sleepingComponents, root);+		}+		+		CP_BODY_FOREACH_ARBITER(body, arb){+			// Reset the idle timer of things the body is touching as well.+			// That way things don't get left hanging in the air.+			cpBody *other = (arb->body_a == body ? arb->body_b : arb->body_a);+			if(cpBodyGetType(other) != CP_BODY_TYPE_STATIC) other->sleeping.idleTime = 0.0f;+		}+	}+}++void+cpBodyActivateStatic(cpBody *body, cpShape *filter)+{+	cpAssertHard(cpBodyGetType(body) == CP_BODY_TYPE_STATIC, "cpBodyActivateStatic() called on a non-static body.");+	+	CP_BODY_FOREACH_ARBITER(body, arb){+		if(!filter || filter == arb->a || filter == arb->b){+			cpBodyActivate(arb->body_a == body ? arb->body_b : arb->body_a);+		}+	}+	+	// TODO: should also activate joints?+}++static inline void+cpBodyPushArbiter(cpBody *body, cpArbiter *arb)+{+	cpAssertSoft(cpArbiterThreadForBody(arb, body)->next == NULL, "Internal Error: Dangling contact graph pointers detected. (A)");+	cpAssertSoft(cpArbiterThreadForBody(arb, body)->prev == NULL, "Internal Error: Dangling contact graph pointers detected. (B)");+	+	cpArbiter *next = body->arbiterList;+	cpAssertSoft(next == NULL || cpArbiterThreadForBody(next, body)->prev == NULL, "Internal Error: Dangling contact graph pointers detected. (C)");+	cpArbiterThreadForBody(arb, body)->next = next;+	+	if(next) cpArbiterThreadForBody(next, body)->prev = arb;+	body->arbiterList = arb;+}++static inline void+ComponentAdd(cpBody *root, cpBody *body){+	body->sleeping.root = root;++	if(body != root){+		body->sleeping.next = root->sleeping.next;+		root->sleeping.next = body;+	}+}++static inline void+FloodFillComponent(cpBody *root, cpBody *body)+{+	// Kinematic bodies cannot be put to sleep and prevent bodies they are touching from sleeping.+	// Static bodies are effectively sleeping all the time.+	if(cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC){+		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->sleeping.idleTime < threshold) return cpTrue;+	}+	+	return cpFalse;+}++void+cpSpaceProcessComponents(cpSpace *space, cpFloat dt)+{+	cpBool sleep = (space->sleepTimeThreshold != INFINITY);+	cpArray *bodies = space->dynamicBodies;+	+#ifndef NDEBUG+	for(int i=0; i<bodies->num; i++){+		cpBody *body = (cpBody*)bodies->arr[i];+		+		cpAssertSoft(body->sleeping.next == NULL, "Internal Error: Dangling next pointer detected in contact graph.");+		cpAssertSoft(body->sleeping.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];+			+			// TODO should make a separate array for kinematic bodies.+			if(cpBodyGetType(body) != CP_BODY_TYPE_DYNAMIC) continue;+			+			// Need to deal with infinite mass objects+			cpFloat keThreshold = (dvsq ? body->m*dvsq : 0.0f);+			body->sleeping.idleTime = (cpBodyKineticEnergy(body) > keThreshold ? 0.0f : body->sleeping.idleTime + dt);+		}+	}+	+	// Awaken any sleeping bodies found and then push arbiters to the bodies' lists.+	cpArray *arbiters = space->arbiters;+	for(int i=0, count=arbiters->num; i<count; i++){+		cpArbiter *arb = (cpArbiter*)arbiters->arr[i];+		cpBody *a = arb->body_a, *b = arb->body_b;+		+		if(sleep){+			// TODO checking cpBodyIsSleepin() redundant?+			if(cpBodyGetType(b) == CP_BODY_TYPE_KINEMATIC || cpBodyIsSleeping(a)) cpBodyActivate(a);+			if(cpBodyGetType(a) == CP_BODY_TYPE_KINEMATIC || cpBodyIsSleeping(b)) cpBodyActivate(b);+		}+		+		cpBodyPushArbiter(a, arb);+		cpBodyPushArbiter(b, arb);+	}+	+	if(sleep){+		// Bodies should be held active if connected by a joint to a kinematic.+		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(cpBodyGetType(b) == CP_BODY_TYPE_KINEMATIC) cpBodyActivate(a);+			if(cpBodyGetType(a) == CP_BODY_TYPE_KINEMATIC) 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);+				+				// 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->sleeping.root = NULL;+			body->sleeping.next = NULL;+		}+	}+}++void+cpBodySleep(cpBody *body)+{+	cpBodySleepWithGroup(body, NULL);+}++void+cpBodySleepWithGroup(cpBody *body, cpBody *group){+	cpAssertHard(cpBodyGetType(body) == CP_BODY_TYPE_DYNAMIC, "Non-dynamic bodies cannot be put to sleep.");+	+	cpSpace *space = body->space;+	cpAssertHard(!cpSpaceIsLocked(space), "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback.");+	cpAssertHard(cpSpaceGetSleepTimeThreshold(space) < INFINITY, "Sleeping is not enabled on the space. You cannot sleep a body without setting a sleep time threshold on the space.");+	cpAssertHard(group == NULL || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier.");+	+	if(cpBodyIsSleeping(body)){+		cpAssertHard(ComponentRoot(body) == ComponentRoot(group), "The body is already sleeping and it's group cannot be reassigned.");+		return;+	}+	+	CP_BODY_FOREACH_SHAPE(body, shape) cpShapeCacheBB(shape);+	cpSpaceDeactivateBody(space, body);+	+	if(group){+		cpBody *root = ComponentRoot(group);+		+		body->sleeping.root = root;+		body->sleeping.next = root->sleeping.next;+		body->sleeping.idleTime = 0.0f;+		+		root->sleeping.next = body;+	} else {+		body->sleeping.root = body;+		body->sleeping.next = NULL;+		body->sleeping.idleTime = 0.0f;+		+		cpArrayPush(space->sleepingComponents, body);+	}+	+	cpArrayDeleteObj(space->dynamicBodies, body);+}
+ Chipmunk2D-7.0.2/src/cpSpaceDebug.c view
@@ -0,0 +1,189 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++#ifndef CP_SPACE_DISABLE_DEBUG_API++static void+cpSpaceDebugDrawShape(cpShape *shape, cpSpaceDebugDrawOptions *options)+{+	cpBody *body = shape->body;+	cpDataPointer data = options->data;+	+	cpSpaceDebugColor outline_color = options->shapeOutlineColor;+	cpSpaceDebugColor fill_color = options->colorForShape(shape, data);+	+	switch(shape->klass->type){+		case CP_CIRCLE_SHAPE: {+			cpCircleShape *circle = (cpCircleShape *)shape;+			options->drawCircle(circle->tc, body->a, circle->r, outline_color, fill_color, data);+			break;+		}+		case CP_SEGMENT_SHAPE: {+			cpSegmentShape *seg = (cpSegmentShape *)shape;+			options->drawFatSegment(seg->ta, seg->tb, seg->r, outline_color, fill_color, data);+			break;+		}+		case CP_POLY_SHAPE: {+			cpPolyShape *poly = (cpPolyShape *)shape;+			+			int count = poly->count;+			struct cpSplittingPlane *planes = poly->planes;+			cpVect *verts = (cpVect *)alloca(count*sizeof(cpVect));+			+			for(int i=0; i<count; i++) verts[i] = planes[i].v0;+			options->drawPolygon(count, verts, poly->r, outline_color, fill_color, data);+			break;+		}+		default: break;+	}+}++static const cpVect spring_verts[] = {+	{0.00f, 0.0f},+	{0.20f, 0.0f},+	{0.25f, 3.0f},+	{0.30f,-6.0f},+	{0.35f, 6.0f},+	{0.40f,-6.0f},+	{0.45f, 6.0f},+	{0.50f,-6.0f},+	{0.55f, 6.0f},+	{0.60f,-6.0f},+	{0.65f, 6.0f},+	{0.70f,-3.0f},+	{0.75f, 6.0f},+	{0.80f, 0.0f},+	{1.00f, 0.0f},+};+static const int spring_count = sizeof(spring_verts)/sizeof(cpVect);++static void+cpSpaceDebugDrawConstraint(cpConstraint *constraint, cpSpaceDebugDrawOptions *options)+{+	cpDataPointer data = options->data;+	cpSpaceDebugColor color = options->constraintColor;+	+	cpBody *body_a = constraint->a;+	cpBody *body_b = constraint->b;++	if(cpConstraintIsPinJoint(constraint)){+		cpPinJoint *joint = (cpPinJoint *)constraint;+		+		cpVect a = cpTransformPoint(body_a->transform, joint->anchorA);+		cpVect b = cpTransformPoint(body_b->transform, joint->anchorB);+		+		options->drawDot(5, a, color, data);+		options->drawDot(5, b, color, data);+		options->drawSegment(a, b, color, data);+	} else if(cpConstraintIsSlideJoint(constraint)){+		cpSlideJoint *joint = (cpSlideJoint *)constraint;+	+		cpVect a = cpTransformPoint(body_a->transform, joint->anchorA);+		cpVect b = cpTransformPoint(body_b->transform, joint->anchorB);+		+		options->drawDot(5, a, color, data);+		options->drawDot(5, b, color, data);+		options->drawSegment(a, b, color, data);+	} else if(cpConstraintIsPivotJoint(constraint)){+		cpPivotJoint *joint = (cpPivotJoint *)constraint;+	+		cpVect a = cpTransformPoint(body_a->transform, joint->anchorA);+		cpVect b = cpTransformPoint(body_b->transform, joint->anchorB);++		options->drawDot(5, a, color, data);+		options->drawDot(5, b, color, data);+	} else if(cpConstraintIsGrooveJoint(constraint)){+		cpGrooveJoint *joint = (cpGrooveJoint *)constraint;+	+		cpVect a = cpTransformPoint(body_a->transform, joint->grv_a);+		cpVect b = cpTransformPoint(body_a->transform, joint->grv_b);+		cpVect c = cpTransformPoint(body_b->transform, joint->anchorB);+		+		options->drawDot(5, c, color, data);+		options->drawSegment(a, b, color, data);+	} else if(cpConstraintIsDampedSpring(constraint)){+		cpDampedSpring *spring = (cpDampedSpring *)constraint;+		cpDataPointer data = options->data;+		cpSpaceDebugColor color = options->constraintColor;+		+		cpVect a = cpTransformPoint(body_a->transform, spring->anchorA);+		cpVect b = cpTransformPoint(body_b->transform, spring->anchorB);+		+		options->drawDot(5, a, color, data);+		options->drawDot(5, b, color, data);++		cpVect delta = cpvsub(b, a);+		cpFloat cos = delta.x;+		cpFloat sin = delta.y;+		cpFloat s = 1.0f/cpvlength(delta);+		+		cpVect r1 = cpv(cos, -sin*s);+		cpVect r2 = cpv(sin,  cos*s);+		+		cpVect *verts = (cpVect *)alloca(spring_count*sizeof(cpVect));+		for(int i=0; i<spring_count; i++){+			cpVect v = spring_verts[i];+			verts[i] = cpv(cpvdot(v, r1) + a.x, cpvdot(v, r2) + a.y);+		}+		+		for(int i=0; i<spring_count-1; i++){+			options->drawSegment(verts[i], verts[i + 1], color, data);+		}+	}+}++void+cpSpaceDebugDraw(cpSpace *space, cpSpaceDebugDrawOptions *options)+{+	if(options->flags & CP_SPACE_DEBUG_DRAW_SHAPES){+		cpSpaceEachShape(space, (cpSpaceShapeIteratorFunc)cpSpaceDebugDrawShape, options);+	}+	+	if(options->flags & CP_SPACE_DEBUG_DRAW_CONSTRAINTS){+		cpSpaceEachConstraint(space, (cpSpaceConstraintIteratorFunc)cpSpaceDebugDrawConstraint, options);+	}+	+	if(options->flags & CP_SPACE_DEBUG_DRAW_COLLISION_POINTS){+		cpArray *arbiters = space->arbiters;+		cpSpaceDebugColor color = options->collisionPointColor;+		cpSpaceDebugDrawSegmentImpl draw_seg = options->drawSegment;+		cpDataPointer data = options->data;+		+		for(int i=0; i<arbiters->num; i++){+			cpArbiter *arb = (cpArbiter*)arbiters->arr[i];+			cpVect n = arb->n;+			+			for(int j=0; j<arb->count; j++){+				cpVect p1 = cpvadd(arb->body_a->p, arb->contacts[j].r1);+				cpVect p2 = cpvadd(arb->body_b->p, arb->contacts[j].r2);+				+				cpFloat d = 2.0f;+				cpVect a = cpvadd(p1, cpvmult(n, -d));+				cpVect b = cpvadd(p2, cpvmult(n,  d));+				draw_seg(a, b, color, data);+			}+		}+	}+}++#endif
+ Chipmunk2D-7.0.2/src/cpSpaceHash.c view
@@ -0,0 +1,634 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"+#include "prime.h"++typedef struct cpSpaceHashBin cpSpaceHashBin;+typedef struct cpHandle cpHandle;++struct cpSpaceHash {+	cpSpatialIndex spatialIndex;+	+	int numcells;+	cpFloat celldim;+	+	cpSpaceHashBin **table;+	cpHashSet *handleSet;+	+	cpSpaceHashBin *pooledBins;+	cpArray *pooledHandles;+	cpArray *allocatedBuffers;+	+	cpTimestamp stamp;+};+++//MARK: Handle Functions++struct cpHandle {+	void *obj;+	int retain;+	cpTimestamp stamp;+};++static cpHandle*+cpHandleInit(cpHandle *hand, void *obj)+{+	hand->obj = obj;+	hand->retain = 0;+	hand->stamp = 0;+	+	return hand;+}++static inline void cpHandleRetain(cpHandle *hand){hand->retain++;}++static inline void+cpHandleRelease(cpHandle *hand, cpArray *pooledHandles)+{+	hand->retain--;+	if(hand->retain == 0) cpArrayPush(pooledHandles, hand);+}++static int handleSetEql(void *obj, cpHandle *hand){return (obj == hand->obj);}++static void *+handleSetTrans(void *obj, cpSpaceHash *hash)+{+	if(hash->pooledHandles->num == 0){+		// handle pool is exhausted, make more+		int count = CP_BUFFER_BYTES/sizeof(cpHandle);+		cpAssertHard(count, "Internal Error: Buffer size is too small.");+		+		cpHandle *buffer = (cpHandle *)cpcalloc(1, CP_BUFFER_BYTES);+		cpArrayPush(hash->allocatedBuffers, buffer);+		+		for(int i=0; i<count; i++) cpArrayPush(hash->pooledHandles, buffer + i);+	}+	+	cpHandle *hand = cpHandleInit((cpHandle *)cpArrayPop(hash->pooledHandles), obj);+	cpHandleRetain(hand);+	+	return hand;+}++//MARK: Bin Functions++struct cpSpaceHashBin {+	cpHandle *handle;+	cpSpaceHashBin *next;+};++static inline void+recycleBin(cpSpaceHash *hash, cpSpaceHashBin *bin)+{+	bin->next = hash->pooledBins;+	hash->pooledBins = bin;+}++static inline void+clearTableCell(cpSpaceHash *hash, int idx)+{+	cpSpaceHashBin *bin = hash->table[idx];+	while(bin){+		cpSpaceHashBin *next = bin->next;+		+		cpHandleRelease(bin->handle, hash->pooledHandles);+		recycleBin(hash, bin);+		+		bin = next;+	}+	+	hash->table[idx] = NULL;+}++static void+clearTable(cpSpaceHash *hash)+{+	for(int i=0; i<hash->numcells; i++) clearTableCell(hash, i);+}++// Get a recycled or new bin.+static inline cpSpaceHashBin *+getEmptyBin(cpSpaceHash *hash)+{+	cpSpaceHashBin *bin = hash->pooledBins;+	+	if(bin){+		hash->pooledBins = bin->next;+		return bin;+	} else {+		// Pool is exhausted, make more+		int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin);+		cpAssertHard(count, "Internal Error: Buffer size is too small.");+		+		cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpcalloc(1, CP_BUFFER_BYTES);+		cpArrayPush(hash->allocatedBuffers, buffer);+		+		// push all but the first one, return the first instead+		for(int i=1; i<count; i++) recycleBin(hash, buffer + i);+		return buffer;+	}+}++//MARK: Memory Management Functions++cpSpaceHash *+cpSpaceHashAlloc(void)+{+	return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash));+}++// Frees the old table, and allocate a new one.+static void+cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)+{+	cpfree(hash->table);+	+	hash->numcells = numcells;+	hash->table = (cpSpaceHashBin **)cpcalloc(numcells, sizeof(cpSpaceHashBin *));+}++static inline cpSpatialIndexClass *Klass();++cpSpatialIndex *+cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	cpSpatialIndexInit((cpSpatialIndex *)hash, Klass(), bbfunc, staticIndex);+	+	cpSpaceHashAllocTable(hash, next_prime(numcells));+	hash->celldim = celldim;+	+	hash->handleSet = cpHashSetNew(0, (cpHashSetEqlFunc)handleSetEql);+	+	hash->pooledHandles = cpArrayNew(0);+	+	hash->pooledBins = NULL;+	hash->allocatedBuffers = cpArrayNew(0);+	+	hash->stamp = 1;+	+	return (cpSpatialIndex *)hash;+}++cpSpatialIndex *+cpSpaceHashNew(cpFloat celldim, int cells, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc, staticIndex);+}++static void+cpSpaceHashDestroy(cpSpaceHash *hash)+{+	if(hash->table) clearTable(hash);+	cpfree(hash->table);+	+	cpHashSetFree(hash->handleSet);+	+	cpArrayFreeEach(hash->allocatedBuffers, cpfree);+	cpArrayFree(hash->allocatedBuffers);+	cpArrayFree(hash->pooledHandles);+}++//MARK: Helper Functions++static inline cpBool+containsHandle(cpSpaceHashBin *bin, cpHandle *hand)+{+	while(bin){+		if(bin->handle == hand) return cpTrue;+		bin = bin->next;+	}+	+	return cpFalse;+}++// The hash function itself.+static inline cpHashValue+hash_func(cpHashValue x, cpHashValue y, cpHashValue n)+{+	return (x*1640531513ul ^ y*2654435789ul) % n;+}++// Much faster than (int)floor(f)+// Profiling showed floor() to be a sizable performance hog+static inline int+floor_int(cpFloat f)+{+	int i = (int)f;+	return (f < 0.0f && f != i ? i - 1 : i);+}++static inline void+hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)+{+	// Find the dimensions in cell coordinates.+	cpFloat dim = hash->celldim;+	int l = floor_int(bb.l/dim); // Fix by ShiftZ+	int r = floor_int(bb.r/dim);+	int b = floor_int(bb.b/dim);+	int t = floor_int(bb.t/dim);+	+	int n = hash->numcells;+	for(int i=l; i<=r; i++){+		for(int j=b; j<=t; j++){+			cpHashValue idx = hash_func(i,j,n);+			cpSpaceHashBin *bin = hash->table[idx];+			+			// Don't add an object twice to the same cell.+			if(containsHandle(bin, hand)) continue;++			cpHandleRetain(hand);+			// Insert a new bin for the handle in this cell.+			cpSpaceHashBin *newBin = getEmptyBin(hash);+			newBin->handle = hand;+			newBin->next = bin;+			hash->table[idx] = newBin;+		}+	}+}++//MARK: Basic Operations++static void+cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid)+{+	cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, (cpHashSetTransFunc)handleSetTrans, hash);+	hashHandle(hash, hand, hash->spatialIndex.bbfunc(obj));+}++static void+cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid)+{+	cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);+	+	if(hand){+		hand->obj = NULL;+		cpHandleRelease(hand, hash->pooledHandles);+		+		cpSpaceHashInsert(hash, obj, hashid);+	}+}++static void+rehash_helper(cpHandle *hand, cpSpaceHash *hash)+{+	hashHandle(hash, hand, hash->spatialIndex.bbfunc(hand->obj));+}++static void+cpSpaceHashRehash(cpSpaceHash *hash)+{+	clearTable(hash);+	cpHashSetEach(hash->handleSet, (cpHashSetIteratorFunc)rehash_helper, hash);+}++static void+cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid)+{+	cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);+	+	if(hand){+		hand->obj = NULL;+		cpHandleRelease(hand, hash->pooledHandles);+	}+}++typedef struct eachContext {+	cpSpatialIndexIteratorFunc func;+	void *data;+} eachContext;++static void eachHelper(cpHandle *hand, eachContext *context){context->func(hand->obj, context->data);}++static void+cpSpaceHashEach(cpSpaceHash *hash, cpSpatialIndexIteratorFunc func, void *data)+{+	eachContext context = {func, data};+	cpHashSetEach(hash->handleSet, (cpHashSetIteratorFunc)eachHelper, &context);+}++static void+remove_orphaned_handles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr)+{+	cpSpaceHashBin *bin = *bin_ptr;+	while(bin){+		cpHandle *hand = bin->handle;+		cpSpaceHashBin *next = bin->next;+		+		if(!hand->obj){+			// orphaned handle, unlink and recycle the bin+			(*bin_ptr) = bin->next;+			recycleBin(hash, bin);+			+			cpHandleRelease(hand, hash->pooledHandles);+		} else {+			bin_ptr = &bin->next;+		}+		+		bin = next;+	}+}++//MARK: Query Functions++static inline void+query_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpatialIndexQueryFunc func, void *data)+{+	restart:+	for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){+		cpHandle *hand = bin->handle;+		void *other = hand->obj;+		+		if(hand->stamp == hash->stamp || obj == other){+			continue;+		} else if(other){+			func(obj, other, 0, data);+			hand->stamp = hash->stamp;+		} else {+			// The object for this handle has been removed+			// cleanup this cell and restart the query+			remove_orphaned_handles(hash, bin_ptr);+			goto restart; // GCC not smart enough/able to tail call an inlined function.+		}+	}+}++static void+cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)+{+	// Get the dimensions in cell coordinates.+	cpFloat dim = hash->celldim;+	int l = floor_int(bb.l/dim);  // Fix by ShiftZ+	int r = floor_int(bb.r/dim);+	int b = floor_int(bb.b/dim);+	int t = floor_int(bb.t/dim);+	+	int n = hash->numcells;+	cpSpaceHashBin **table = hash->table;+	+	// Iterate over the cells and query them.+	for(int i=l; i<=r; i++){+		for(int j=b; j<=t; j++){+			query_helper(hash, &table[hash_func(i,j,n)], obj, func, data);+		}+	}+	+	hash->stamp++;+}++// Similar to struct eachPair above.+typedef struct queryRehashContext {+	cpSpaceHash *hash;+	cpSpatialIndexQueryFunc func;+	void *data;+} queryRehashContext;++// Hashset iterator func used with cpSpaceHashQueryRehash().+static void+queryRehash_helper(cpHandle *hand, queryRehashContext *context)+{+	cpSpaceHash *hash = context->hash;+	cpSpatialIndexQueryFunc func = context->func;+	void *data = context->data;++	cpFloat dim = hash->celldim;+	int n = hash->numcells;++	void *obj = hand->obj;+	cpBB bb = hash->spatialIndex.bbfunc(obj);++	int l = floor_int(bb.l/dim);+	int r = floor_int(bb.r/dim);+	int b = floor_int(bb.b/dim);+	int t = floor_int(bb.t/dim);+	+	cpSpaceHashBin **table = hash->table;++	for(int i=l; i<=r; i++){+		for(int j=b; j<=t; j++){+			cpHashValue idx = hash_func(i,j,n);+			cpSpaceHashBin *bin = table[idx];+			+			if(containsHandle(bin, hand)) continue;+			+			cpHandleRetain(hand); // this MUST be done first in case the object is removed in func()+			query_helper(hash, &bin, obj, func, data);+			+			cpSpaceHashBin *newBin = getEmptyBin(hash);+			newBin->handle = hand;+			newBin->next = bin;+			table[idx] = newBin;+		}+	}+	+	// Increment the stamp for each object hashed.+	hash->stamp++;+}++static void+cpSpaceHashReindexQuery(cpSpaceHash *hash, cpSpatialIndexQueryFunc func, void *data)+{+	clearTable(hash);+	+	queryRehashContext context = {hash, func, data};+	cpHashSetEach(hash->handleSet, (cpHashSetIteratorFunc)queryRehash_helper, &context);+	+	cpSpatialIndexCollideStatic((cpSpatialIndex *)hash, hash->spatialIndex.staticIndex, func, data);+}++static inline cpFloat+segmentQuery_helper(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpatialIndexSegmentQueryFunc func, void *data)+{+	cpFloat t = 1.0f;+	 +	restart:+	for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){+		cpHandle *hand = bin->handle;+		void *other = hand->obj;+		+		// Skip over certain conditions+		if(hand->stamp == hash->stamp){+			continue;+		} else if(other){+			t = cpfmin(t, func(obj, other, data));+			hand->stamp = hash->stamp;+		} else {+			// The object for this handle has been removed+			// cleanup this cell and restart the query+			remove_orphaned_handles(hash, bin_ptr);+			goto restart; // GCC not smart enough/able to tail call an inlined function.+		}+	}+	+	return t;+}++// modified from http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html+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);+	b = cpvmult(b, 1.0f/hash->celldim);+	+	int cell_x = floor_int(a.x), cell_y = floor_int(a.y);++	cpFloat t = 0;++	int x_inc, y_inc;+	cpFloat temp_v, temp_h;++	if (b.x > a.x){+		x_inc = 1;+		temp_h = (cpffloor(a.x + 1.0f) - a.x);+	} else {+		x_inc = -1;+		temp_h = (a.x - cpffloor(a.x));+	}++	if (b.y > a.y){+		y_inc = 1;+		temp_v = (cpffloor(a.y + 1.0f) - a.y);+	} else {+		y_inc = -1;+		temp_v = (a.y - cpffloor(a.y));+	}+	+	// Division by zero is *very* slow on ARM+	cpFloat dx = cpfabs(b.x - a.x), dy = cpfabs(b.y - a.y);+	cpFloat dt_dx = (dx ? 1.0f/dx : INFINITY), dt_dy = (dy ? 1.0f/dy : INFINITY);+	+	// fix NANs in horizontal directions+	cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx);+	cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy);+	+	int n = hash->numcells;+	cpSpaceHashBin **table = hash->table;++	while(t < t_exit){+		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){+			cell_y += y_inc;+			t = next_v;+			next_v += dt_dy;+		} else {+			cell_x += x_inc;+			t = next_h;+			next_h += dt_dx;+		}+	}+	+	hash->stamp++;+}++//MARK: Misc++void+cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)+{+	if(hash->spatialIndex.klass != Klass()){+		cpAssertWarn(cpFalse, "Ignoring cpSpaceHashResize() call to non-cpSpaceHash spatial index.");+		return;+	}+	+	clearTable(hash);+	+	hash->celldim = celldim;+	cpSpaceHashAllocTable(hash, next_prime(numcells));+}++static int+cpSpaceHashCount(cpSpaceHash *hash)+{+	return cpHashSetCount(hash->handleSet);+}++static int+cpSpaceHashContains(cpSpaceHash *hash, void *obj, cpHashValue hashid)+{+	return cpHashSetFind(hash->handleSet, hashid, obj) != NULL;+}++static cpSpatialIndexClass klass = {+	(cpSpatialIndexDestroyImpl)cpSpaceHashDestroy,+	+	(cpSpatialIndexCountImpl)cpSpaceHashCount,+	(cpSpatialIndexEachImpl)cpSpaceHashEach,+	(cpSpatialIndexContainsImpl)cpSpaceHashContains,+	+	(cpSpatialIndexInsertImpl)cpSpaceHashInsert,+	(cpSpatialIndexRemoveImpl)cpSpaceHashRemove,+	+	(cpSpatialIndexReindexImpl)cpSpaceHashRehash,+	(cpSpatialIndexReindexObjectImpl)cpSpaceHashRehashObject,+	(cpSpatialIndexReindexQueryImpl)cpSpaceHashReindexQuery,+	+	(cpSpatialIndexQueryImpl)cpSpaceHashQuery,+	(cpSpatialIndexSegmentQueryImpl)cpSpaceHashSegmentQuery,+};++static inline cpSpatialIndexClass *Klass(){return &klass;}++//MARK: Debug Drawing++//#define CP_BBTREE_DEBUG_DRAW+#ifdef CP_BBTREE_DEBUG_DRAW+#include "OpenGL/gl.h"+#include "OpenGL/glu.h"+#include <GLUT/glut.h>++void+cpSpaceHashRenderDebug(cpSpatialIndex *index)+{+	if(index->klass != &klass){+		cpAssertWarn(cpFalse, "Ignoring cpSpaceHashRenderDebug() call to non-spatial hash spatial index.");+		return;+	}+	+	cpSpaceHash *hash = (cpSpaceHash *)index;+	cpBB bb = cpBBNew(-320, -240, 320, 240);+	+	cpFloat dim = hash->celldim;+	int n = hash->numcells;+	+	int l = (int)floor(bb.l/dim);+	int r = (int)floor(bb.r/dim);+	int b = (int)floor(bb.b/dim);+	int t = (int)floor(bb.t/dim);+	+	for(int i=l; i<=r; i++){+		for(int j=b; j<=t; j++){+			int cell_count = 0;+			+			int index = hash_func(i,j,n);+			for(cpSpaceHashBin *bin = hash->table[index]; bin; bin = bin->next)+				cell_count++;+			+			GLfloat v = 1.0f - (GLfloat)cell_count/10.0f;+			glColor3f(v,v,v);+			glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim);+		}+	}+}+#endif
+ Chipmunk2D-7.0.2/src/cpSpaceQuery.c view
@@ -0,0 +1,246 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++//MARK: Nearest Point Query Functions++struct PointQueryContext {+	cpVect point;+	cpFloat maxDistance;+	cpShapeFilter filter;+	cpSpacePointQueryFunc func;+};++static cpCollisionID+NearestPointQuery(struct PointQueryContext *context, cpShape *shape, cpCollisionID id, void *data)+{+	if(+		!cpShapeFilterReject(shape->filter, context->filter)+	){+		cpPointQueryInfo info;+		cpShapePointQuery(shape, context->point, &info);+		+		if(info.shape && info.distance < context->maxDistance) context->func(shape, info.point, info.distance, info.gradient, data);+	}+	+	return id;+}++void+cpSpacePointQuery(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpSpacePointQueryFunc func, void *data)+{+	struct PointQueryContext context = {point, maxDistance, filter, func};+	cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));+	+	cpSpaceLock(space); {+		cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);+		cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQuery, data);+	} cpSpaceUnlock(space, cpTrue);+}++static cpCollisionID+NearestPointQueryNearest(struct PointQueryContext *context, cpShape *shape, cpCollisionID id, cpPointQueryInfo *out)+{+	if(+		!cpShapeFilterReject(shape->filter, context->filter) && !shape->sensor+	){+		cpPointQueryInfo info;+		cpShapePointQuery(shape, context->point, &info);+		+		if(info.distance < out->distance) (*out) = info;+	}+	+	return id;+}++cpShape *+cpSpacePointQueryNearest(cpSpace *space, cpVect point, cpFloat maxDistance, cpShapeFilter filter, cpPointQueryInfo *out)+{+	cpPointQueryInfo info = {NULL, cpvzero, maxDistance, cpvzero};+	if(out){+		(*out) = info;+  } else {+		out = &info;+	}+	+	struct PointQueryContext context = {+		point, maxDistance,+		filter,+		NULL+	};+	+	cpBB bb = cpBBNewForCircle(point, cpfmax(maxDistance, 0.0f));+	cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);+	cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)NearestPointQueryNearest, out);+	+	return (cpShape *)out->shape;+}+++//MARK: Segment Query Functions++struct SegmentQueryContext {+	cpVect start, end;+	cpFloat radius;+	cpShapeFilter filter;+	cpSpaceSegmentQueryFunc func;+};++static cpFloat+SegmentQuery(struct SegmentQueryContext *context, cpShape *shape, void *data)+{+	cpSegmentQueryInfo info;+	+	if(+		!cpShapeFilterReject(shape->filter, context->filter) &&+		cpShapeSegmentQuery(shape, context->start, context->end, context->radius, &info)+	){+		context->func(shape, info.point, info.normal, info.alpha, data);+	}+	+	return 1.0f;+}++void+cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSpaceSegmentQueryFunc func, void *data)+{+	struct SegmentQueryContext context = {+		start, end,+		radius,+		filter,+		func,+	};+	+	cpSpaceLock(space); {+    cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);+    cpSpatialIndexSegmentQuery(space->dynamicShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQuery, data);+	} cpSpaceUnlock(space, cpTrue);+}++static cpFloat+SegmentQueryFirst(struct SegmentQueryContext *context, cpShape *shape, cpSegmentQueryInfo *out)+{+	cpSegmentQueryInfo info;+	+	if(+		!cpShapeFilterReject(shape->filter, context->filter) && !shape->sensor &&+		cpShapeSegmentQuery(shape, context->start, context->end, context->radius, &info) &&+		info.alpha < out->alpha+	){+		(*out) = info;+	}+	+	return out->alpha;+}++cpShape *+cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpFloat radius, cpShapeFilter filter, cpSegmentQueryInfo *out)+{+	cpSegmentQueryInfo info = {NULL, end, cpvzero, 1.0f};+	if(out){+		(*out) = info;+  } else {+		out = &info;+	}+	+	struct SegmentQueryContext context = {+		start, end,+		radius,+		filter,+		NULL+	};+	+	cpSpatialIndexSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);+	cpSpatialIndexSegmentQuery(space->dynamicShapes, &context, start, end, out->alpha, (cpSpatialIndexSegmentQueryFunc)SegmentQueryFirst, out);+	+	return (cpShape *)out->shape;+}++//MARK: BB Query Functions++struct BBQueryContext {+	cpBB bb;+	cpShapeFilter filter;+	cpSpaceBBQueryFunc func;+};++static cpCollisionID+BBQuery(struct BBQueryContext *context, cpShape *shape, cpCollisionID id, void *data)+{+	if(+		!cpShapeFilterReject(shape->filter, context->filter) &&+		cpBBIntersects(context->bb, shape->bb)+	){+		context->func(shape, data);+	}+	+	return id;+}++void+cpSpaceBBQuery(cpSpace *space, cpBB bb, cpShapeFilter filter, cpSpaceBBQueryFunc func, void *data)+{+	struct BBQueryContext context = {bb, filter, func};+	+	cpSpaceLock(space); {+    cpSpatialIndexQuery(space->dynamicShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);+    cpSpatialIndexQuery(space->staticShapes, &context, bb, (cpSpatialIndexQueryFunc)BBQuery, data);+	} cpSpaceUnlock(space, cpTrue);+}++//MARK: Shape Query Functions++struct ShapeQueryContext {+	cpSpaceShapeQueryFunc func;+	void *data;+	cpBool anyCollision;+};++// Callback from the spatial hash.+static cpCollisionID+ShapeQuery(cpShape *a, cpShape *b, cpCollisionID id, struct ShapeQueryContext *context)+{+	if(cpShapeFilterReject(a->filter, b->filter) || a == b) return id;+	+	cpContactPointSet set = cpShapesCollide(a, b);+	if(set.count){+		if(context->func) context->func(b, &set, context->data);+		context->anyCollision = !(a->sensor || b->sensor);+	}+	+	return id;+}++cpBool+cpSpaceShapeQuery(cpSpace *space, cpShape *shape, cpSpaceShapeQueryFunc func, void *data)+{+	cpBody *body = shape->body;+	cpBB bb = (body ? cpShapeUpdate(shape, body->transform) : shape->bb);+	struct ShapeQueryContext context = {func, data, cpFalse};+	+	cpSpaceLock(space); {+    cpSpatialIndexQuery(space->dynamicShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);+    cpSpatialIndexQuery(space->staticShapes, shape, bb, (cpSpatialIndexQueryFunc)ShapeQuery, &context);+	} cpSpaceUnlock(space, cpTrue);+	+	return context.anyCollision;+}
+ Chipmunk2D-7.0.2/src/cpSpaceStep.c view
@@ -0,0 +1,445 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++//MARK: Post Step Callback Functions++cpPostStepCallback *+cpSpaceGetPostStepCallback(cpSpace *space, void *key)+{+	cpArray *arr = space->postStepCallbacks;+	for(int i=0; i<arr->num; i++){+		cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];+		if(callback && callback->key == key) return callback;+	}+	+	return NULL;+}++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(!cpSpaceGetPostStepCallback(space, key)){+		cpPostStepCallback *callback = (cpPostStepCallback *)cpcalloc(1, sizeof(cpPostStepCallback));+		callback->func = (func ? func : PostStepDoNothing);+		callback->key = key;+		callback->data = data;+		+		cpArrayPush(space->postStepCallbacks, callback);+		return cpTrue;+	} else {+		return cpFalse;+	}+}++//MARK: Locking Functions++void+cpSpaceLock(cpSpace *space)+{+	space->locked++;+}++void+cpSpaceUnlock(cpSpace *space, cpBool runPostStep)+{+	space->locked--;+	cpAssertHard(space->locked >= 0, "Internal Error: Space lock underflow.");+	+	if(space->locked == 0){+		cpArray *waking = space->rousedBodies;+		+		for(int i=0, count=waking->num; i<count; i++){+			cpSpaceActivateBody(space, (cpBody *)waking->arr[i]);+			waking->arr[i] = NULL;+		}+		+		waking->num = 0;+		+		if(space->locked == 0 && runPostStep && !space->skipPostStep){+			space->skipPostStep = cpTrue;+			+			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.+				// TODO: need more tests around this case I think.+				callback->func = NULL;+				if(func) func(space, callback->key, callback->data);+				+				arr->arr[i] = NULL;+				cpfree(callback);+			}+			+			arr->num = 0;+			space->skipPostStep = cpFalse;+		}+	}+}++//MARK: Contact Buffer Functions++struct cpContactBufferHeader {+	cpTimestamp stamp;+	cpContactBufferHeader *next;+	unsigned int numContacts;+};++#define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(struct cpContact))+typedef struct cpContactBuffer {+	cpContactBufferHeader header;+	struct cpContact contacts[CP_CONTACTS_BUFFER_SIZE];+} cpContactBuffer;++static cpContactBufferHeader *+cpSpaceAllocContactBuffer(cpSpace *space)+{+	cpContactBuffer *buffer = (cpContactBuffer *)cpcalloc(1, sizeof(cpContactBuffer));+	cpArrayPush(space->allocatedBuffers, buffer);+	return (cpContactBufferHeader *)buffer;+}++static cpContactBufferHeader *+cpContactBufferHeaderInit(cpContactBufferHeader *header, cpTimestamp stamp, cpContactBufferHeader *splice)+{+	header->stamp = stamp;+	header->next = (splice ? splice->next : header);+	header->numContacts = 0;+	+	return header;+}++void+cpSpacePushFreshContactBuffer(cpSpace *space)+{+	cpTimestamp stamp = space->stamp;+	+	cpContactBufferHeader *head = space->contactBuffersHead;+	+	if(!head){+		// No buffers have been allocated, make one+		space->contactBuffersHead = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, NULL);+	} else if(stamp - head->next->stamp > space->collisionPersistence){+		// The tail buffer is available, rotate the ring+	cpContactBufferHeader *tail = head->next;+		space->contactBuffersHead = cpContactBufferHeaderInit(tail, stamp, tail);+	} else {+		// Allocate a new buffer and push it into the ring+		cpContactBufferHeader *buffer = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), stamp, head);+		space->contactBuffersHead = head->next = buffer;+	}+}+++struct cpContact *+cpContactBufferGetArray(cpSpace *space)+{+	if(space->contactBuffersHead->numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){+		// contact buffer could overflow on the next collision, push a fresh one.+		cpSpacePushFreshContactBuffer(space);+	}+	+	cpContactBufferHeader *head = space->contactBuffersHead;+	return ((cpContactBuffer *)head)->contacts + head->numContacts;+}++void+cpSpacePushContacts(cpSpace *space, int count)+{+	cpAssertHard(count <= CP_MAX_CONTACTS_PER_ARBITER, "Internal Error: Contact buffer overflow!");+	space->contactBuffersHead->numContacts += count;+}++static void+cpSpacePopContacts(cpSpace *space, int count){+	space->contactBuffersHead->numContacts -= count;+}++//MARK: Collision Detection Functions++static void *+cpSpaceArbiterSetTrans(cpShape **shapes, cpSpace *space)+{+	if(space->pooledArbiters->num == 0){+		// arbiter pool is exhausted, make more+		int count = CP_BUFFER_BYTES/sizeof(cpArbiter);+		cpAssertHard(count, "Internal Error: Buffer size too small.");+		+		cpArbiter *buffer = (cpArbiter *)cpcalloc(1, CP_BUFFER_BYTES);+		cpArrayPush(space->allocatedBuffers, buffer);+		+		for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);+	}+	+	return cpArbiterInit((cpArbiter *)cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);+}++static inline cpBool+QueryRejectConstraint(cpBody *a, cpBody *b)+{+	CP_BODY_FOREACH_CONSTRAINT(a, constraint){+		if(+			!constraint->collideBodies && (+				(constraint->a == a && constraint->b == b) ||+				(constraint->a == b && constraint->b == a)+			)+		) return cpTrue;+	}+	+	return cpFalse;+}++static inline cpBool+QueryReject(cpShape *a, cpShape *b)+{+	return (+		// BBoxes must overlap+		!cpBBIntersects(a->bb, b->bb)+		// Don't collide shapes attached to the same body.+		|| a->body == b->body+		// Don't collide shapes that are filtered.+		|| cpShapeFilterReject(a->filter, b->filter)+		// Don't collide bodies if they have a constraint with collideBodies == cpFalse.+		|| QueryRejectConstraint(a->body, b->body)+	);+}++// Callback from the spatial hash.+cpCollisionID+cpSpaceCollideShapes(cpShape *a, cpShape *b, cpCollisionID id, cpSpace *space)+{+	// Reject any of the simple cases+	if(QueryReject(a,b)) return id;+	+	// Narrow-phase collision detection.+	struct cpCollisionInfo info = cpCollide(a, b, id, cpContactBufferGetArray(space));+	+	if(info.count == 0) return info.id; // Shapes are not colliding.+	cpSpacePushContacts(space, info.count);+	+	// Get an arbiter from space->arbiterSet for the two shapes.+	// This is where the persistant contact magic comes from.+	const cpShape *shape_pair[] = {info.a, info.b};+	cpHashValue arbHashID = CP_HASH_PAIR((cpHashValue)info.a, (cpHashValue)info.b);+	cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->cachedArbiters, arbHashID, shape_pair, (cpHashSetTransFunc)cpSpaceArbiterSetTrans, space);+	cpArbiterUpdate(arb, &info, space);+	+	cpCollisionHandler *handler = arb->handler;+	+	// Call the begin function first if it's the first step+	if(arb->state == CP_ARBITER_STATE_FIRST_COLLISION && !handler->beginFunc(arb, space, handler->userData)){+		cpArbiterIgnore(arb); // permanently ignore the collision until separation+	}+	+	if(+		// Ignore the arbiter if it has been flagged+		(arb->state != CP_ARBITER_STATE_IGNORE) && +		// Call preSolve+		handler->preSolveFunc(arb, space, handler->userData) &&+		// Check (again) in case the pre-solve() callback called cpArbiterIgnored().+		arb->state != CP_ARBITER_STATE_IGNORE &&+		// Process, but don't add collisions for sensors.+		!(a->sensor || b->sensor) &&+		// Don't process collisions between two infinite mass bodies.+		// This includes collisions between two kinematic bodies, or a kinematic body and a static body.+		!(a->body->m == INFINITY && b->body->m == INFINITY)+	){+		cpArrayPush(space->arbiters, arb);+	} else {+		cpSpacePopContacts(space, info.count);+		+		arb->contacts = NULL;+		arb->count = 0;+		+		// Normally arbiters are set as used after calling the post-solve callback.+		// However, post-solve() callbacks are not called for sensors or arbiters rejected from pre-solve.+		if(arb->state != CP_ARBITER_STATE_IGNORE) arb->state = CP_ARBITER_STATE_NORMAL;+	}+	+	// Time stamp the arbiter so we know it was used recently.+	arb->stamp = space->stamp;+	return info.id;+}++// Hashset filter func to throw away old arbiters.+cpBool+cpSpaceArbiterSetFilter(cpArbiter *arb, cpSpace *space)+{+	cpTimestamp ticks = space->stamp - arb->stamp;+	+	cpBody *a = arb->body_a, *b = arb->body_b;+	+	// 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(+		(cpBodyGetType(a) == CP_BODY_TYPE_STATIC || cpBodyIsSleeping(a)) &&+		(cpBodyGetType(b) == CP_BODY_TYPE_STATIC || cpBodyIsSleeping(b))+	){+		return cpTrue;+	}+	+	// Arbiter was used last frame, but not this one+	if(ticks >= 1 && arb->state != CP_ARBITER_STATE_CACHED){+		arb->state = CP_ARBITER_STATE_CACHED;+		cpCollisionHandler *handler = arb->handler;+		handler->separateFunc(arb, space, handler->userData);+	}+	+	if(ticks >= space->collisionPersistence){+		arb->contacts = NULL;+		arb->count = 0;+		+		cpArrayPush(space->pooledArbiters, arb);+		return cpFalse;+	}+	+	return cpTrue;+}++//MARK: All Important cpSpaceStep() Function++ void+cpShapeUpdateFunc(cpShape *shape, void *unused)+{+	cpShapeCacheBB(shape);+}++void+cpSpaceStep(cpSpace *space, cpFloat dt)+{+	// 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;+		+	cpArray *bodies = space->dynamicBodies;+	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 = CP_ARBITER_STATE_NORMAL;+		+		// If both bodies are awake, unthread the arbiter from the contact graph.+		if(!cpBodyIsSleeping(arb->body_a) && !cpBodyIsSleeping(arb->body_b)){+			cpArbiterUnthread(arb);+		}+	}+	arbiters->num = 0;++	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->dynamicShapes, (cpSpatialIndexIteratorFunc)cpShapeUpdateFunc, NULL);+		cpSpatialIndexReindexQuery(space->dynamicShapes, (cpSpatialIndexQueryFunc)cpSpaceCollideShapes, space);+	} cpSpaceUnlock(space, cpFalse);+	+	// Rebuild the contact graph (and detect sleeping components if sleeping is enabled)+	cpSpaceProcessComponents(space, dt);+	+	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);+		}++		for(int i=0; i<constraints->num; i++){+			cpConstraint *constraint = (cpConstraint *)constraints->arr[i];+			+			cpConstraintPreSolveFunc preSolve = constraint->preSolve;+			if(preSolve) preSolve(constraint, space);+			+			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 = (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->postSolveFunc(arb, space, handler->userData);+		}+	} cpSpaceUnlock(space, cpTrue);+}
+ Chipmunk2D-7.0.2/src/cpSpatialIndex.c view
@@ -0,0 +1,69 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++void+cpSpatialIndexFree(cpSpatialIndex *index)+{+	if(index){+		cpSpatialIndexDestroy(index);+		cpfree(index);+	}+}++cpSpatialIndex *+cpSpatialIndexInit(cpSpatialIndex *index, cpSpatialIndexClass *klass, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	index->klass = klass;+	index->bbfunc = bbfunc;+	index->staticIndex = staticIndex;+	+	if(staticIndex){+		cpAssertHard(!staticIndex->dynamicIndex, "This static index is already associated with a dynamic index.");+		staticIndex->dynamicIndex = index;+	}+	+	return index;+}++typedef struct dynamicToStaticContext {+	cpSpatialIndexBBFunc bbfunc;+	cpSpatialIndex *staticIndex;+	cpSpatialIndexQueryFunc queryFunc;+	void *data;+} dynamicToStaticContext;++static void+dynamicToStaticIter(void *obj, dynamicToStaticContext *context)+{+	cpSpatialIndexQuery(context->staticIndex, obj, context->bbfunc(obj), context->queryFunc, context->data);+}++void+cpSpatialIndexCollideStatic(cpSpatialIndex *dynamicIndex, cpSpatialIndex *staticIndex, cpSpatialIndexQueryFunc func, void *data)+{+	if(staticIndex && cpSpatialIndexCount(staticIndex) > 0){+		dynamicToStaticContext context = {dynamicIndex->bbfunc, staticIndex, func, data};+		cpSpatialIndexEach(dynamicIndex, (cpSpatialIndexIteratorFunc)dynamicToStaticIter, &context);+	}+}+
+ Chipmunk2D-7.0.2/src/cpSweep1D.c view
@@ -0,0 +1,254 @@+/* Copyright (c) 2013 Scott Lembcke and Howling Moon Software+ * + * 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/chipmunk_private.h"++static inline cpSpatialIndexClass *Klass();++//MARK: Basic Structures++typedef struct Bounds {+	cpFloat min, max;+} Bounds;++typedef struct TableCell {+	void *obj;+	Bounds bounds;+} TableCell;++struct cpSweep1D+{+	cpSpatialIndex spatialIndex;+	+	int num;+	int max;+	TableCell *table;+};++static inline cpBool+BoundsOverlap(Bounds a, Bounds b)+{+	return (a.min <= b.max && b.min <= a.max);+}++static inline Bounds+BBToBounds(cpSweep1D *sweep, cpBB bb)+{+	Bounds bounds = {bb.l, bb.r};+	return bounds;+}++static inline TableCell+MakeTableCell(cpSweep1D *sweep, void *obj)+{+	TableCell cell = {obj, BBToBounds(sweep, sweep->spatialIndex.bbfunc(obj))};+	return cell;+}++//MARK: Memory Management Functions++cpSweep1D *+cpSweep1DAlloc(void)+{+	return (cpSweep1D *)cpcalloc(1, sizeof(cpSweep1D));+}++static void+ResizeTable(cpSweep1D *sweep, int size)+{+	sweep->max = size;+	sweep->table = (TableCell *)cprealloc(sweep->table, size*sizeof(TableCell));+}++cpSpatialIndex *+cpSweep1DInit(cpSweep1D *sweep, cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	cpSpatialIndexInit((cpSpatialIndex *)sweep, Klass(), bbfunc, staticIndex);+	+	sweep->num = 0;+	ResizeTable(sweep, 32);+	+	return (cpSpatialIndex *)sweep;+}++cpSpatialIndex *+cpSweep1DNew(cpSpatialIndexBBFunc bbfunc, cpSpatialIndex *staticIndex)+{+	return cpSweep1DInit(cpSweep1DAlloc(), bbfunc, staticIndex);+}++static void+cpSweep1DDestroy(cpSweep1D *sweep)+{+	cpfree(sweep->table);+	sweep->table = NULL;+}++//MARK: Misc++static int+cpSweep1DCount(cpSweep1D *sweep)+{+	return sweep->num;+}++static void+cpSweep1DEach(cpSweep1D *sweep, cpSpatialIndexIteratorFunc func, void *data)+{+	TableCell *table = sweep->table;+	for(int i=0, count=sweep->num; i<count; i++) func(table[i].obj, data);+}++static int+cpSweep1DContains(cpSweep1D *sweep, void *obj, cpHashValue hashid)+{+	TableCell *table = sweep->table;+	for(int i=0, count=sweep->num; i<count; i++){+		if(table[i].obj == obj) return cpTrue;+	}+	+	return cpFalse;+}++//MARK: Basic Operations++static void+cpSweep1DInsert(cpSweep1D *sweep, void *obj, cpHashValue hashid)+{+	if(sweep->num == sweep->max) ResizeTable(sweep, sweep->max*2);+	+	sweep->table[sweep->num] = MakeTableCell(sweep, obj);+	sweep->num++;+}++static void+cpSweep1DRemove(cpSweep1D *sweep, void *obj, cpHashValue hashid)+{+	TableCell *table = sweep->table;+	for(int i=0, count=sweep->num; i<count; i++){+		if(table[i].obj == obj){+			int num = --sweep->num;+			+			table[i] = table[num];+			table[num].obj = NULL;+			+			return;+		}+	}+}++//MARK: Reindexing Functions++static void+cpSweep1DReindexObject(cpSweep1D *sweep, void *obj, cpHashValue hashid)+{+	// Nothing to do here+}++static void+cpSweep1DReindex(cpSweep1D *sweep)+{+	// Nothing to do here+	// Could perform a sort, but queries are not accelerated anyway.+}++//MARK: Query Functions++static void+cpSweep1DQuery(cpSweep1D *sweep, void *obj, cpBB bb, cpSpatialIndexQueryFunc func, void *data)+{+	// Implementing binary search here would allow you to find an upper limit+	// but not a lower limit. Probably not worth the hassle.+	+	Bounds bounds = BBToBounds(sweep, bb);+	+	TableCell *table = sweep->table;+	for(int i=0, count=sweep->num; i<count; i++){+		TableCell cell = table[i];+		if(BoundsOverlap(bounds, cell.bounds) && obj != cell.obj) func(obj, cell.obj, 0, data);+	}+}++static 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);+	Bounds bounds = BBToBounds(sweep, bb);+	+	TableCell *table = sweep->table;+	for(int i=0, count=sweep->num; i<count; i++){+		TableCell cell = table[i];+		if(BoundsOverlap(bounds, cell.bounds)) func(obj, cell.obj, data);+	}+}++//MARK: Reindex/Query++static int+TableSort(TableCell *a, TableCell *b)+{+	return (a->bounds.min < b->bounds.min ? -1 : (a->bounds.min > b->bounds.min ? 1 : 0));+}++static void+cpSweep1DReindexQuery(cpSweep1D *sweep, cpSpatialIndexQueryFunc func, void *data)+{+	TableCell *table = sweep->table;+	int count = sweep->num;+	+	// Update bounds and sort+	for(int i=0; i<count; i++) table[i] = MakeTableCell(sweep, table[i].obj);+	qsort(table, count, sizeof(TableCell), (int (*)(const void *, const void *))TableSort); // TODO: use insertion sort instead+	+	for(int i=0; i<count; i++){+		TableCell cell = table[i];+		cpFloat max = cell.bounds.max;+		+		for(int j=i+1; table[j].bounds.min < max && j<count; j++){+			func(cell.obj, table[j].obj, 0, data);+		}+	}+	+	// Reindex query is also responsible for colliding against the static index.+	// Fortunately there is a helper function for that.+	cpSpatialIndexCollideStatic((cpSpatialIndex *)sweep, sweep->spatialIndex.staticIndex, func, data);+}++static cpSpatialIndexClass klass = {+	(cpSpatialIndexDestroyImpl)cpSweep1DDestroy,+	+	(cpSpatialIndexCountImpl)cpSweep1DCount,+	(cpSpatialIndexEachImpl)cpSweep1DEach,+	(cpSpatialIndexContainsImpl)cpSweep1DContains,+	+	(cpSpatialIndexInsertImpl)cpSweep1DInsert,+	(cpSpatialIndexRemoveImpl)cpSweep1DRemove,+	+	(cpSpatialIndexReindexImpl)cpSweep1DReindex,+	(cpSpatialIndexReindexObjectImpl)cpSweep1DReindexObject,+	(cpSpatialIndexReindexQueryImpl)cpSweep1DReindexQuery,+	+	(cpSpatialIndexQueryImpl)cpSweep1DQuery,+	(cpSpatialIndexSegmentQueryImpl)cpSweep1DSegmentQuery,+};++static inline cpSpatialIndexClass *Klass(){return &klass;}+
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Cthulhu (c) 2018++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Cthulhu nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,3 @@+# chiphunk++Chiphunk is a Haskell bindings for Chipmunk2D physics library. See `Chiphunk.Low` module for documentation.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,168 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Chiphunk.Low+import Data.Functor+import Text.Printf (printf)+import Control.Monad+import Control.Concurrent.MVar+import Control.Concurrent (threadDelay)+import Control.Concurrent.Async++import qualified Graphics.NanoVG.Simple as N+import qualified Graphics.NanoVG.Picture as N+import qualified NanoVG                 as NVG+import           Data.IORef++main :: IO ()+main = do+  dm <- newEmptyMVar+  race_+    (simulate dm)+    (display dm)++simulate :: MVar [VisObj] -> IO ()+simulate dm = do+  let gravity = Vect 0 (-100)+  -- Create an empty space.+  space <- spaceNew+  spaceGravity space $= gravity++  static <- get $ spaceStaticBody space++  -- Add a static line segment shape for the ground.+  -- We'll make it slightly tilted so the ball will roll off.+  -- We attach it to a static body to tell Chipmunk it shouldn't be movable.+  let (segA, segB) = (Vect (-20) (-5), Vect 20 (-25))+  ground <- segmentShapeNew static segA segB 0+  shapeElasticity ground $= 0.6+  shapeFriction ground $= 1++  spaceAddShape space ground++  -- Now let's make a ball that falls onto the line and rolls off.+  -- First we need to make a cpBody to hold the physical properties of the object.+  -- These include the mass, position, velocity, angle, etc. of the object.+  -- Then we attach collision shapes to the cpBody to give it a size and shape.++  let radius = 5+  let mass = 1+  let mass100 = 100++  -- The moment of inertia is like mass for rotation+  -- Use the cpMomentFor*() functions to help you approximate it.+  let moment = momentForCircle mass 0 radius (Vect 0 0)+  let moment100 = momentForCircle mass100 0 radius (Vect 0 0)++  -- The cpSpaceAdd*() functions return the thing that you are adding.+  -- It's convenient to create and add an object in one line.+  ballBody <- bodyNew mass moment+  spaceAddBody space ballBody++  -- Now we create the collision shape for the ball.+  -- You can create multiple collision shapes that point to the same body.+  -- They will all be attached to the body and move around to follow it.+  ballShape <- circleShapeNew ballBody radius (Vect 0 0)+  shapeFriction ballShape $= 0.9+  shapeElasticity ballShape $= 1+  spaceAddShape space ballShape++  anotherBall <- bodyNew mass100 moment100+  spaceAddBody space anotherBall++  anotherBallShape <- circleShapeNew anotherBall radius (Vect 0 0)+  shapeFriction anotherBallShape $= 0.9+  shapeElasticity anotherBallShape $= 0.4+  spaceAddShape space anotherBallShape++  putMVar dm+    [ mkStaticObj $ Segment segA segB+    , mkBallBody ballBody radius+    , mkBallBody anotherBall radius+    ]++  void $ forever $ do+    bodyPosition ballBody $= Vect (-15) 30+    bodyPosition anotherBall $= Vect (-5) 75+    -- need to reset ball velocity after previous iteration+    bodyVelocity ballBody $= Vect 0 0+    bodyAngularVelocity ballBody $= 0+    bodyVelocity anotherBall $= Vect 0 0+    bodyAngularVelocity anotherBall $= 0++    -- Now that it's all set up, we simulate all the objects in the space by+    -- stepping forward through time in small increments called steps.+    -- It is *highly* recommended to use a fixed size time step.+    let timeStep = 1/60+    runFor 3 timeStep $ \time -> do+      pos <- get $ bodyPosition ballBody+      vel <- get $ bodyVelocity ballBody+      printf "Time is %4.2f. ballBody is at (%6.2f, %6.2f), it's velocity is (%6.2f, %6.2f).\n"+             time (vX pos) (vY pos) (vX vel) (vY vel)++      threadDelay $ round $ timeStep * 1000 * 1000+      spaceStep space timeStep++  shapeFree ballShape+  bodyFree ballBody+  shapeFree ground+  spaceFree space+  where+    runFor time step inner = go time+      where+        go time'+          | time' <= 0 = pure ()+          | otherwise  = inner (time - time') *> go (time' - step)++display :: MVar [VisObj] -> IO ()+display dm = do+  d <- takeMVar dm+  N.run 800 600 "Chiphunk" $+    N.showFPS "Liberation Sans" $+    N.loadFont "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf" "Liberation Sans" $+    N.asWindow $+      N.translateP 400 300 .+      N.scaleP' (0, 0) 10 .+      N.scalePy (0, 0) (-1) .+      N.pictures <$>+        sequence ((render <$>) . runVisObj <$> d)+  where+    render = \case+      Segment (Vect ax ay) (Vect bx by) -> N.stroke (NVG.Color 1 1 1 1) $+        N.line (realToFrac ax, realToFrac ay) (realToFrac bx, realToFrac by)+      Ball (Vect x y) r a ->+        let c = (realToFrac x, realToFrac y)+        in N.stroke (NVG.Color 1 1 1 1) $+            N.rotateS c (realToFrac a) $+            N.shapes+              [ N.circle c (realToFrac r)+              , N.line c (realToFrac $ x - r / 2, realToFrac y)+              ]++data VisShape =+    Segment+    { segEndpointA :: Vect+    , segEndpointB :: Vect+    }+  | Ball+    { ballCenter :: Vect+    , ballRadius :: Double+    , ballAngle :: Double+    }+  deriving Show++newtype VisObj = VisObj+  { runVisObj :: IO VisShape+  }++mkRefObj :: IORef VisShape -> VisObj+mkRefObj r = VisObj $ readIORef r++mkStaticObj :: VisShape -> VisObj+mkStaticObj = VisObj . pure++mkBallBody :: Body -> Double -> VisObj+mkBallBody b r = VisObj $ Ball <$> get (bodyPosition b)+                               <*> pure r+                               <*> get (bodyAngle b)
+ chiphunk.cabal view
@@ -0,0 +1,137 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.30.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 6654f10bfcf93a216508e1f3fa7c6a251033427487355ade61c5dea7ad87e255++name:           chiphunk+version:        0.1.0.0+synopsis:       Haskell bindings for Chipmunk2D physics engine+description:    Please see the README on GitHub at <https://github.com/CthulhuDen/chiphunk#readme>+category:       Physics+homepage:       https://github.com/CthulhuDen/chiphunk#readme+author:         Cthulhu+maintainer:     cthulhu.den@gmail.com+copyright:      Cthulhu (c) 2018+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    Chipmunk2D-7.0.2/include/chipmunk/chipmunk_ffi.h+    Chipmunk2D-7.0.2/include/chipmunk/chipmunk.h+    Chipmunk2D-7.0.2/include/chipmunk/chipmunk_private.h+    Chipmunk2D-7.0.2/include/chipmunk/chipmunk_structs.h+    Chipmunk2D-7.0.2/include/chipmunk/chipmunk_types.h+    Chipmunk2D-7.0.2/include/chipmunk/chipmunk_unsafe.h+    Chipmunk2D-7.0.2/include/chipmunk/cpArbiter.h+    Chipmunk2D-7.0.2/include/chipmunk/cpBB.h+    Chipmunk2D-7.0.2/include/chipmunk/cpBody.h+    Chipmunk2D-7.0.2/include/chipmunk/cpConstraint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpDampedRotarySpring.h+    Chipmunk2D-7.0.2/include/chipmunk/cpDampedSpring.h+    Chipmunk2D-7.0.2/include/chipmunk/cpGearJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpGrooveJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpHastySpace.h+    Chipmunk2D-7.0.2/include/chipmunk/cpMarch.h+    Chipmunk2D-7.0.2/include/chipmunk/cpPinJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpPivotJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpPolyline.h+    Chipmunk2D-7.0.2/include/chipmunk/cpPolyShape.h+    Chipmunk2D-7.0.2/include/chipmunk/cpRatchetJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpRobust.h+    Chipmunk2D-7.0.2/include/chipmunk/cpRotaryLimitJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpShape.h+    Chipmunk2D-7.0.2/include/chipmunk/cpSimpleMotor.h+    Chipmunk2D-7.0.2/include/chipmunk/cpSlideJoint.h+    Chipmunk2D-7.0.2/include/chipmunk/cpSpace.h+    Chipmunk2D-7.0.2/include/chipmunk/cpSpatialIndex.h+    Chipmunk2D-7.0.2/include/chipmunk/cpTransform.h+    Chipmunk2D-7.0.2/include/chipmunk/cpVect.h++flag library-only+  manual: False+  default: True++library+  exposed-modules:+      Chiphunk.Low+  other-modules:+      Chiphunk.Low.Math+      Chiphunk.Low.Types+      Chiphunk.Low.Internal+      Chiphunk.Low.Helper+      Chiphunk.Low.Vect+      Chiphunk.Low.BB+      Chiphunk.Low.Body+      Chiphunk.Low.Shape+      Chiphunk.Low.Space+      Chiphunk.Low.Constraint+      Chiphunk.Low.Callback+      Chiphunk.Low.Arbiter+  hs-source-dirs:+      src+  ghc-options: -Wall+  include-dirs:+      Chipmunk2D-7.0.2/include+      src/Chiphunk+  c-sources:+      Chipmunk2D-7.0.2/src/chipmunk.c+      Chipmunk2D-7.0.2/src/cpConstraint.c+      Chipmunk2D-7.0.2/src/cpSpaceStep.c+      Chipmunk2D-7.0.2/src/cpShape.c+      Chipmunk2D-7.0.2/src/cpSpace.c+      Chipmunk2D-7.0.2/src/cpArbiter.c+      Chipmunk2D-7.0.2/src/cpArray.c+      Chipmunk2D-7.0.2/src/cpBBTree.c+      Chipmunk2D-7.0.2/src/cpBody.c+      Chipmunk2D-7.0.2/src/cpCollision.c+      Chipmunk2D-7.0.2/src/cpDampedRotarySpring.c+      Chipmunk2D-7.0.2/src/cpDampedSpring.c+      Chipmunk2D-7.0.2/src/cpGearJoint.c+      Chipmunk2D-7.0.2/src/cpGrooveJoint.c+      Chipmunk2D-7.0.2/src/cpHashSet.c+      Chipmunk2D-7.0.2/src/cpHastySpace.c+      Chipmunk2D-7.0.2/src/cpMarch.c+      Chipmunk2D-7.0.2/src/cpPinJoint.c+      Chipmunk2D-7.0.2/src/cpPivotJoint.c+      Chipmunk2D-7.0.2/src/cpPolyline.c+      Chipmunk2D-7.0.2/src/cpPolyShape.c+      Chipmunk2D-7.0.2/src/cpRatchetJoint.c+      Chipmunk2D-7.0.2/src/cpRobust.c+      Chipmunk2D-7.0.2/src/cpRotaryLimitJoint.c+      Chipmunk2D-7.0.2/src/cpSimpleMotor.c+      Chipmunk2D-7.0.2/src/cpSlideJoint.c+      Chipmunk2D-7.0.2/src/cpSpaceComponent.c+      Chipmunk2D-7.0.2/src/cpSpaceDebug.c+      Chipmunk2D-7.0.2/src/cpSpaceHash.c+      Chipmunk2D-7.0.2/src/cpSpaceQuery.c+      Chipmunk2D-7.0.2/src/cpSpatialIndex.c+      Chipmunk2D-7.0.2/src/cpSweep1D.c+      +      src/Chiphunk/wrapper.c+  build-depends:+      StateVar >=1.1.1.1 && <1.2+    , base >=4.7 && <5+    , safe-exceptions >=0.1.7.0 && <0.2+    , vector-space >=0.13 && <0.16+  default-language: Haskell2010++executable chiphunk+  main-is: Main.hs+  other-modules:+      Paths_chiphunk+  hs-source-dirs:+      app+  ghc-options: -Wall -O2 -threaded -rtsopts -with-rtsopts=-N2+  build-depends:+      async >=2.2.1 && <2.3+    , base >=4.7 && <5+    , chiphunk+    , nanovg >=0.6.0.0 && <0.7+    , nanovg-simple >=0.4.0.0 && <0.5+  if flag(library-only)+    buildable: False+  default-language: Haskell2010
+ src/Chiphunk/Low.hs view
@@ -0,0 +1,998 @@+-- | Description: Low-level Haskell bindings to Chipmunk2D physics library+-- Chiphunk is a __low-level__ Haskell bindings for the <https://chipmunk-physics.net/ Chipmunk2D physics engine>.+-- It includes most (almost all) of the functions mentioned in the main documentation for Chipmunk2D,+-- except for some (relatively) exotic ones, which may be added later per request.+module Chiphunk.Low+  ( -- * Disclaymer++    -- | This bindings are so low-level so that they even require you to free the memory the Chipmunk2D has allocated+    -- for your objects. Module with more high-level api can be built around this low-level bingings at some point,+    -- in the meantime, however, you're advised to provide wrapper layer for your games so that you do not have to+    -- keep track of such things in the core of your game's logic.+    --+    -- See below for an adoptation of the original Chipmunk documentation available+    -- <https://chipmunk-physics.net/release/ChipmunkLatest-Docs/ here>. I've skipped some sections not related+    -- to the bindings, like the reason author chose C language in the first place and limitations of the C api.+    -- Obviously, it's thanks to that choice that I was able to write bindings around the library in Haskell.+    --+    -- __Howling Moon Software is not affiliated with this bindings.__+    -- __In all of the following \"I\" refers to the original documentation author for Chipmunk2D.__++    -- * Chipmunk2D 7.0.2++    -- | Chipmunk2D is a 2D rigid body physics library distributed under the MIT license.+    -- It is blazingly fast, portable, numerically stable, and easy to use.+    -- For this reason it has been used in hundreds of games across just about every system you can name.+    -- This includes top quality titles such as Night Sky for the Wii and many #1 sellers on the iPhone App Store!+    -- I’ve put thousands of hours of work over many years to make Chipmunk2D what it is today.+    -- If you find Chipmunk2D has saved you a lot of time, please consider+    -- <https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6666552 donating>.+    -- You’ll make an indie game developer very happy!++    -- | First of all, I would like to give a Erin Catto a big thank you, as Chipmunk2D’s impulse solver+    -- was directly inspired by his example code way back in 2006.+    -- (Now a full fledged physics engine all its own: <http://www.box2d.org/ Box2D.org>).+    -- His contact persistence idea allows for stable stacks of objects with very few iterations of the solver.+    -- My previous solver produced mushy piles of objects or required a large amount of CPU to operate stably.++    -- ** Support++    -- | The best way to get support is to visit the <http://www.slembcke.net/forums/viewforum.php?f=1 Chipmunk Forums>.+    -- There are plenty of people around using Chipmunk on the just about every platform+    -- I’ve ever heard of. If you are working on a commercial project, Howling Moon Software+    -- (my company) is <http://howlingmoonsoftware.com/contracting.php available for contracting>.+    -- We can help with implementing custom Chipmunk behaviors,+    -- as well as priority bug fixes and performance tuning.++    -- ** Contact++    -- | If you find any bugs in Chipmunk, errors or broken links in this document,+    -- or have a question or comment about Chipmunk you can contact me at+    -- slembcke(at)gmail(dot)com. (email or GTalk)++    -- ** License++    -- | Chipmunk is licensed under the MIT license.+    --+    -- @+    -- Copyright (c) 2007-2015 Scott Lembcke and Howling Moon Software+    --+    -- Permission is hereby granted, free of charge, to any person obtaining a copy+    -- of this software and associated documentation files (the "Software"), to deal+    -- in the Software without restriction, including without limitation the rights+    -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+    -- copies of the Software, and to permit persons to whom the Software is+    -- furnished to do so, subject to the following conditions:+    --+    -- The above copyright notice and this permission notice shall be included in+    -- all copies or substantial portions of the Software.+    --+    -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+    -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+    -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+    -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+    -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+    -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+    -- SOFTWARE.+    -- @+    --+    -- This means that you do not have to buy a license or pay to use Chipmunk in commercial projects. (Though we really appreciate donations)++    -- ** Links++    -- |+    -- * <http://chipmunk2d.net/forum Chipmunk Forums> – The official forum Chipmunk2D forum.+    --+    -- * <http://howlingmoonsoftware.com/ Howling Moon Software> – The software company I co-founded.+    -- (We are available for contract work!)+    --+    -- * <http://chipmunk2d.net/games.php Games> – A small list of games we know that use Chipmunk.++    -- * Hello Chipmunk (World)++    -- | Hello world Chipmunk style. Create a simple simulation where a ball falls onto a static line segment,+    -- then rolls off. Print out the coordinates of the ball.+    --+    -- @+    -- main :: IO ()+    -- main = do+    --   let gravity = 'Vect' 0 (-100)+    --+    --   -- Create an empty space.+    --   space <- 'spaceNew'+    --   'spaceGravity' space $= gravity+    --+    --   -- Add a static line segment shape for the ground.+    --   -- We'll make it slightly tilted so the ball will roll off.+    --   -- We attach it to a static body to tell Chipmunk it shouldn't be movable.+    --   static <- get $ 'spaceStaticBody' space+    --   ground <- 'segmentShapeNew' static (Vect (-20) 5) (Vect 20 (-5)) 0+    --   'shapeFriction' ground $= 1+    --   'spaceAddShape' space ground+    --+    --   -- Now let's make a ball that falls onto the line and rolls off.+    --   -- First we need to make a cpBody to hold the physical properties of the object.+    --   -- These include the mass, position, velocity, angle, etc. of the object.+    --   -- Then we attach collision shapes to the 'Body' to give it a size and shape.+    --+    --   let radius = 5+    --   let mass = 1+    --+    --   -- The moment of inertia is like mass for rotation+    --   -- Use the momentFor* functions to help you approximate it.+    --   let moment = 'momentForCircle' mass 0 radius (Vect 0 0)+    --+    --   -- The spaceAdd* functions return the thing that you are adding.+    --   ballBody <- 'bodyNew' mass moment+    --   'spaceAddBody' space ballBody+    --   'bodyPosition' ballBody $= Vect 0 15+    --+    --   -- Now we create the collision shape for the ball.+    --   -- You can create multiple collision shapes that point to the same body.+    --   -- They will all be attached to the body and move around to follow it.+    --   ballShape <- 'circleShapeNew' ballBody radius (Vect 0 0)+    --   'spaceAddShape' space ballShape+    --   'shapeFriction' ballShape $= 0.7+    --+    --   -- Now that it's all set up, we simulate all the objects in the space by+    --   -- stepping forward through time in small increments called steps.+    --   -- It is *highly* recommended to use a fixed size time step.+    --   let timeStep = 1/60+    --   runFor 2 timeStep $ \time -> do+    --     pos <- get $ 'bodyPosition' ballBody+    --     vel <- get $ 'bodyVelocity' ballBody+    --     printf "Time is %4.2f. ballBody is at (%6.2f, %6.2f), it's velocity is (%6.2f, %6.2f).\n"+    --            time (vX pos) (vY pos) (vX vel) (vY vel)+    --+    --     'spaceStep' space timeStep+    --+    --   'shapeFree' ballShape+    --   'bodyFree' ballBody+    --   'shapeFree' ground+    --   'spaceFree' space+    --   where+    --     runFor time step inner = go time+    --       where+    --         go time'+    --           | time' <= 0 = pure ()+    --           | otherwise  = inner (time - time') *> go (time' - step)+    -- @++    -- * Chipmunk2D Basics++    -- ** Overview++    -- | There are 4 basic object types you will use in Chipmunk.++    -- |+    -- * __Rigid Bodies__ ('Body'): A rigid body holds the physical properties of an object.+    -- (mass, position, rotation, velocity, etc.) It does not have a shape until you attach one or more collision shapes+    -- to it. If you’ve done physics with particles before, rigid bodies differ in that they are able to rotate.+    -- Rigid bodies generally tend to have a 1:1 correlation to sprites in a game.+    -- You should structure your game so that you use the position and rotation of the rigid body+    -- for drawing your sprite.+    --+    -- * __Collision Shapes__ ('Shape'): By attaching shapes to bodies, you can define the a body’s shape.+    -- You can attach as many shapes to a single body as you need to in order to define a complex shape.+    -- Shapes contain the surface properties of an object such as how much friction or elasticity it has.+    --+    -- * __Constraints/Joints__ ('Constraint'): Constraints and joints describe how bodies are attached to each other.+    --+    -- * __Spaces__ ('Space'): Spaces are containers for simulating objects in Chipmunk.+    -- You add bodies, shapes and joints to a space and then update the space as a whole.+    -- They control how all the rigid bodies, shapes, and constraints interact together.+    --+    -- There is often confusion between rigid bodies and their collision shapes in Chipmunk+    -- and how they relate to sprites. A sprite would be a visual representation of an object,+    -- while a collision shape is an invisible property that defines how objects should collide.+    -- Both the sprite’s and the collision shape’s position and rotation are controlled by the motion of a rigid body.+    -- Generally you want to create a game object type that ties these things all together.++    -- ** Memory Management the Chipmunk way++    -- | For most of the structures you will use, Chipmunk uses a more or less standard and straightforward set+    -- of memory management functions. Take the 'Space' struct for example:+    --+    -- * 'spaceNew' — Allocates and initializes a 'Space' struct.+    --+    -- * 'spaceFree' — Destroys and frees the 'Space' struct.+    --+    -- You are responsible for freeing any structs that you allocate. Chipmunk does not do reference counting or garbage collection. If you call a new function, you must call the matching free function or you will leak memory.++    -- ** Math the Chipmunk way++    -- | First of all, Chipmunk uses double precision floating point numbers throughout its calculations by default.+    -- This is likely to be faster on most modern desktop processors,+    -- and means you don’t have to worry as much about floating point accuracy.+    --+    -- However, there are a few unique functions you will probably find very useful:+    fClamp+  , fLerp+  , fLerpConst++    -- * Chipmunk Vectors++    -- ** Struct Definition, Constants and Constructors+  , Vect (..)+  , vZero+  , cpv++  -- ** Operations++  -- | (__Note for bindings__: Most of these are Chipmunk2D-style aliases for 'Vect' typeclasses methods:+  -- 'Eq', 'Data.VectorSpace.AdditiveGroup', 'Data.VectorSpace.VectorSpace', 'Data.VectorSpace.InnerSpace',+  -- 'Data.Cross.HasCross2')+  , vEql+  , vAdd+  , vSub+  , vNeg+  , vMult+  , vDot+  , vCross+  , vPerp+  , vRPerp+  , vProject+  , vRotate+  , vUnRotate+  , vLength+  , vLengthSq+  , vLerp+  , vLerpConst+  , vSLerp+  , vSLerpConst+  , vNormalize+  , vClamp+  , vDist+  , vDistSq+  , vNear+  , vForAngle+  , vToAngle++    -- * Chipmunk Axis Aligned Bounding Boxes++    -- ** Struct Definition and Constructors++  , BB (..)+  , bbNew+  , bbNewForExtents+  , bbNewForCircle++    -- ** Operations++  , bbIntersects+  , bbContainsBB+  , bbContainsVect+  , bbMerge+  , bbExpand+  , bbCenter+  , bbArea+  , bbMergedArea+  , bbSegmentQuery+  , bbIntersectsSegment+  , bbClampVect+  , bbWrapVect++    -- * Chipmunk Rigid Bodies+  , Body++    -- ** Dynamic, Kinematic, and Static Bodies+  , BodyType (..)++    -- ** Movement, Teleportation, and Velocity++    -- | A graphics engine only needs to know the position of an object for each frame that its drawn.+    -- For a physics engine, this isn’t enough information to calculate a collision response.+    -- When you set the position of a body, you are effectively asking it to teleport itself.+    -- This means that it will instantly move to its new position instead of moving through space and time+    -- like a normal object. If you teleport an object so that it overlaps another one,+    -- the best the physics engine can do is to attempt to push the objects apart again+    -- since there is no information about their movement. This generally results in very mushy looking collisions.+    -- So instead of setting the position of an object, it’s better to set its velocity and allow the physics engine+    -- to update the position. That way it can resolve any resulting colisions natuarally since it knows+    -- how the objects were moving. This is why kinematic bodies work the way they do.+    -- You set the velocity, and the physics updates their position so the two are never out of sync.+    --+    -- For dynamic bodies, setting the velocity explicitly every frame can cause problems.+    -- For example, a problem occurs when a light dynamic body (like a person) is pressed against a heavy dynamic body+    -- (like a car), and you set velocity of the small object so that it’s pushing it into the big body.+    -- To the physics engine, the change in velocity is the same as applying a large impulse+    -- (a very short, very large force). Even if the velocity is low, the large force can allow the small body+    -- to push the big body, even when it normally wouldn’t be able to. For example, a person walking into a car+    -- can overpower the car’s friction and cause it to creep along the ground slowly.+    -- Additionally, when you set the velocity of an object that is already in contact,+    -- it can cause the two objects to overlap by a small amount. The easiest way to avoid both of these problems+    -- is to make smaller changes to the body’s velocity, accelerating it over a fraction of a second+    -- instead of a single frame. An even better solution, which is covered more thoroughly later,+    -- is to use constraints to move the object.++    -- ** Memory Management Functions++    -- | Standard set of Chipmunk memory management functions.+  , bodyNew+  , bodyNewKinematic+  , bodyNewStatic+  , bodyFree++    -- ** Creating Dynamic Bodies++    -- | There are two ways to set up a dynamic body. The easiest option is to create a body+    -- with a mass and moment of 0, and set the mass or density of each collision shape added to the body.+    -- Chipmunk will automatically calculate the mass, moment of inertia, and center of gravity for you.+    -- This is probably preferred in most cases.+    --+    -- The other option is to set the mass of the body when it’s created, and leave the mass of the shapes+    -- added to it as 0.0. This approach is more flexible, but is not as easy to use.+    -- __Don’t__ set the mass of both the body and the shapes. If you do so,+    -- it will recalculate and overwite your custom mass value when the shapes are added to the body.++    -- ** Properties++    -- | Chipmunk provides getter/setter functions for a number of properties on rigid bodies.+    -- Setting most properties automatically wakes the rigid bodies up if they were sleeping.++  , bodyType+  , bodyMass+  , bodyMoment+  , bodyPosition+  , bodyCenterOfGravity+  , bodyVelocity+  , bodyForce+  , bodyAngle+  , bodyAngularVelocity+  , bodyTorque+  , bodyRotation+  , bodySpace+  , bodyUserData++    -- ** Moment of Inertia and Area Helper Functions++    -- | Use the following functions to approximate the moment of inertia for your body,+    -- adding the results together if you want to use more than one.+  , momentForCircle+  , momentForSegment+  , momentForPoly+  , momentForBox++    -- | Use the following functions to get the area for common Chipmunk shapes if you want to approximate masses+    -- or density or whatnot.+  , areaForCircle+  , areaForSegment+  , areaForPoly++    -- ** Coordinate Conversion Functions++    -- | Many things are defined in coordinates local to a body meaning that the (0,0) is at the center of gravity+    -- of the body and the axis rotate along with the body.+  , bodyLocalToWorld+  , bodyWorldToLocal++    -- ** Velocity Conversion Functions++    -- | It’s often useful to know the absolute velocity of a point on the surface of a body+    -- since the angular velocity affects everything except the center of gravity.+  , bodyVelocityAtWorldPoint++    -- ** Applying Forces and Torques++    -- | People are sometimes confused by the difference between a force and an impulse.+    -- An impulse is a very large force applied over a very short period of time.+    -- Some examples are a ball hitting a wall or cannon firing. Chipmunk treats impulses as if they occur+    -- instantaneously by adding directly to the velocity of an object.+    -- Both impulses and forces are affected the mass of an object.+    -- Doubling the mass of the object will halve the effect.+  , bodyApplyForceAtWorldPoint+  , bodyApplyForceAtLocalPoint+  , bodyApplyImpulseAtWorldPoint+  , bodyApplyImpulseAtLocalPoint++    -- ** Sleeping Functions++    -- | Chipmunk supports a sleeping feature which improves performance by not simulating groups of objects+    -- that aren’t moving. Read more about it in the 'Space' section.+  , bodyIsSleeping+  , bodyActivate+  , bodySleep+  , bodyActivateStatic+  , bodySleepWithGroup++    -- ** Iterators+  , BodyShapeIteratorFunc+  , bodyEachShape+  , BodyConstraintIteratorFunc+  , bodyEachConstraint+  , BodyArbiterIteratorFunc+  , bodyEachArbiter++    -- * Chipmunk Collision Shapes++  , Shape++    -- ** Properties++    -- | Chipmunk provides getter/setter functions for a number of properties on collision shapes.+    -- Setting most properties will automatically wake the attached rigid body, if it’s sleeping.++  , shapeBody+  , shapeBB+  , shapeSensor+  , shapeElasticity+  , shapeFriction+  , shapeSurfaceVelocity+  , shapeCollisionType+  , ShapeFilter (..)+  , shapeFilter+  , shapeSpace+  , shapeUserData++    -- ** Fast Collision Filtering using ShapeFilter++    -- | Chipmunk has two primary means of ignoring collisions: groups and category masks.+    --+    -- __Groups__ are used to ignore collisions between parts on a complex object.+    -- A ragdoll is a good example. When jointing an arm onto the torso, you’ll want them to allow them to overlap.+    -- Groups allow you to do exactly that. Shapes that have the same group don’t generate collisions.+    -- So by placing all of the shapes in a ragdoll in the same group, you’ll prevent it from colliding+    -- against other parts of itself.+    -- __Category__ masks allow you to mark which categories an object belongs to+    -- and which categories it collidies with.+    --+    -- For example, a game has four collision categories: player (0), enemy (1), player bullet (2),+    -- and enemy bullet (3). Neither players nor enemies should not collide with their own bullets,+    -- and bullets should not collide with other bullets.+    -- However, players collide with enemy bullets, and enemies collide with player bullets.+    --+    -- +-----------------+-----------------+---------------++    -- | Object          | Object Category | Category Mask |+    -- +=================+=================+===============++    -- | \"Player\"      | 1               | 4, 5          |+    -- +-----------------+-----------------+---------------++    -- | \"Enemy\"       | 2               | 2, 3, 5       |+    -- +-----------------+-----------------+---------------++    -- | "Player Bullet" | 3               | 1, 5          |+    -- +-----------------+-----------------+---------------++    -- | "Enemy Bullet"  | 4               | 2, 5          |+    -- +-----------------+-----------------+---------------++    -- | \"Walls\"       | 5               | 1, 2, 3, 4    |+    -- +-----------------+-----------------+---------------++    --+    -- Note that everything in this example collides with walls. Additionally, the enemies collide with eachother.+    --+    -- By default, objects exist in every category and collide with every category.+    --+    -- Objects can fall into multiple categories. For instance, you might have a category for a red team,+    -- and have a red player bullet. In the above example, each object only has one category.+    --+    -- There is one last way of filtering collisions using collision handlers. See the section on callbacks+    -- for more information. Collision handlers can be more flexible, but can be slower.+    -- Fast collision filtering rejects collisions before running the expensive collision detection code,+    -- so using groups or category masks is preferred.++    -- ** Memory Management Functions+  , shapeFree++    -- ** Misc functions+  , shapeCacheBB+  , shapeUpdate++    -- ** Working With Circle Shapes+  , circleShapeNew++    -- ** Working With Segment Shapes+  , segmentShapeNew+  , segmentShapeNeighbors++    -- ** Working With Polygon Shapes+  , polyShapeNew+  , polyShapeNewRaw++    -- *** Boxes++    -- | Because boxes are so common in physics games, Chipmunk provides shortcuts to create box shaped polygons.+    -- The boxes will always be centered at the center of gravity of the body you are attaching them to.+    -- Adding a small radius will bevel the corners and can significantly reduce problems+    -- where the box gets stuck on seams in your geometry. If you want to create an off-center box,+    -- you will need to use 'polyShapeNew'.+  , boxShapeNew+  , boxShapeNew2++    -- *** Poly Shape Helper Functions+  , centroidForPoly++    -- *** Convex Hull Helper Functions+  , convexHull++    -- ** Modifying 'Shape's++    -- | The short answer is that you can’t because the changes would be only picked up as a change to the position+    -- of the shape’s surface, but not its velocity.++    -- ** Notes++    -- |+    -- * You can attach multiple collision shapes to a rigid body. This should allow you to create almost any shape+    -- you could possibly need.+    --+    -- * Shapes attached to the same rigid body will never generate collisions. You don’t have to worry+    -- about overlap when attaching multiple shapes to a rigid body.+    --+    -- * Make sure you add both the body and its collision shapes to a space.++    -- * Chipmunk Spaces+  , Space++    -- ** What Are Iterations, and Why Should I Care?++    -- | Chipmunk uses an iterative solver to figure out the forces between objects in the space.+    -- What this means is that it builds a big list of all of the collisions, joints, and other constraints+    -- between the bodies and makes several passes over the list considering each one individually.+    -- The number of passes it makes is the iteration count, and each iteration makes the solution more accurate.+    -- If you use too many iterations, the physics should look nice and solid, but may use up too much CPU time.+    -- If you use too few iterations, the simulation may seem mushy or bouncy when the objects should be solid.+    -- Setting the number of iterations lets you balance between CPU usage and the accuracy of the physics.+    -- Chipmunk’s default of 10 iterations is sufficient for most simple games.++    -- ** Sleeping++    -- | Spaces can disable entire groups of objects that have stopped moving to save CPU time and battery life.+    -- In order to use this feature you must do two things. You must enable sleeping explicitly+    -- by choosing a time threshold value with 'spaceSetSleepTimeThreshold'. This threshold is the amount of time+    -- something must be idle before it falls asleep. 'spaceSetIdleSpeedThreshold' defines what is considered idle.+    -- If you do not set idle speed threshold explicitly, a value will be chosen automatically+    -- based on the current amount of gravity. Be mindful that objects cannot fall asleep if they are touching+    -- or jointed to a kinematic body.++    -- ** Properties++  , spaceIterations+  , spaceGravity+  , spaceDamping+  , spaceIdleSpeedThreshold+  , spaceSleepTimeThreshold+  , spaceCollisionSlop+  , spaceCollisionBias+  , spaceCollisionPersistence+  , spaceCurrentTimeStep+  , spaceIsLocked+  , spaceUserData+  , spaceStaticBody++    -- ** Memory Management Functions++    -- | More standard Chipmunk memory functions.+  , spaceNew+  , spaceFree++    -- ** Operations++    -- | These functions add and remove shapes, bodies and constraints from space. The add/remove functions+    -- cannot be called from within a callback other than a 'postStep' callback (which is different than a 'postSolve'+    -- callback!). Attempting to add or remove objects from the space while 'spaceStep' is still executing+    -- will throw an assertion. See the callbacks section for more information. Be careful not to free bodies+    -- before removing shapes and constraints attached to them or you will cause crashes..+    -- The contains functions allow you to check if an object has been added to the space or not.+  , spaceAddShape+  , spaceAddBody+  , spaceAddConstraint+  , spaceRemoveShape+  , spaceRemoveBody+  , spaceRemoveConstraint+  , spaceContainsShape+  , spaceContainsBody+  , spaceContainsConstraint++    -- ** Spatial Indexing++    -- | Occasionally, you might want to update the collision detection data for a shape.+    -- If you move a static shape or a static body you must do this to let Chipmunk know+    -- it needs to have its collision detection data updated. You may also want to manually update the collision data+    -- for normal shapes if you move them and still want to perform queries against them+    -- before the next call to 'spaceStep'.+  , spaceReindexShape+  , spaceReindexShapesForBody+  , spaceReindexStatic++    -- ** Iterators+  , SpaceBodyIteratorFunc+  , spaceEachBody+  , SpaceShapeIteratorFunc+  , spaceEachShape+  , SpaceConstraintIteratorFunc+  , spaceEachConstraint++    -- ** Simulating the Space+  , spaceStep++    -- * Notes++    -- |+    -- * When removing objects from the space, make sure you remove any other objects that reference it.+    -- For instance, when you remove a body, remove the joints and shapes attached to it.+    --+    -- * Using more iterations or smaller time steps will increase the physics quality, but also increase the CPU usage.++    -- * Chipmunk Constraints+  , Constraint++    -- ** What constraints are and what they are not++    -- | Constraints in Chipmunk are all velocity based constraints.+    -- This means that they act primarily by synchronizing the velocity of two bodies.+    -- A pivot joint holds two anchor points on two separate bodies together by defining equations that say+    -- that the velocity of the anchor points must be the same and calculating impulses to apply to the bodies+    -- to try and keep it that way. A constraint takes a velocity as it’s primary input and produces a velocity change+    -- as its output. Some constraints, (joints in particular) apply velocity changes to correct differences+    -- in positions. More about this in the next section.+    --+    -- A spring connected between two bodies is not a constraint. It’s very constraint-like as it creates forces+    -- that affect the velocities of the two bodies, but a spring takes distances as input and produces forces+    -- as its output. If a spring is not a constraint, then why do I have two varieties of spring constraints you ask?+    -- The reason is because they are damped springs. The damping associated with the spring is a true constraint+    -- that creates velocity changes based on the relative velocities of the two bodies it links.+    -- As it is convenient to put a damper and a spring together most of the time, I figured I might as well just apply+    -- the spring force as part of the constraint instead of having a damper constraint and having the user+    -- calculate and apply their own spring forces separately.++    -- ** Properties++  , constraintBodyA+  , constraintBodyB+  , constraintMaxForce+  , constraintErrorBias+  , constraintMaxBias+  , constraintSpace+  , constraintCollideBodies+  , constraintUserData+  , constraintImpulse++    -- ** Error correction by Feedback++    -- | Joints in Chipmunk are not perfect. A pin joint can’t maintain the exact correct distance between its anchor+    -- points, nor can a pivot joint hold its anchor points completely together. Instead, they are designed+    -- to deal with this by correcting themselves over time. Since Chipmunk 5, you have a fair amount of extra control+    -- over how joints correct themselves and can even use this ability to create physical effects+    -- that allow you to use joints in unique ways:+    --+    -- * Servo motors – Ex: open/close doors or rotate things without going over a maximum force.+    --+    -- * Winches – Pull one object towards another at a constant speed without going over a maximum force.+    --+    -- * Mouse manipulation – Interact with objects smoothly given coarse/shaky mouse input.+    --+    -- There are three properties of 'Constraint' structs that control the error correction,+    -- maxForce, maxBias, and biasCoef. maxForce is pretty self explanatory, a joint or constraint+    -- will not be able to use more than this amount of force in order to function. If it needs more force+    -- to be able to hold itself together, it will fall apart. maxBias is the maximum speed at which error correction+    -- can be applied. If you change a property on a joint so that the joint will have to correct itself,+    -- it normally does so very quickly. By setting a maxSpeed you can make the joint work like a servo,+    -- correcting itself at a constant rate over a longer period of time. Lastly, biasCoef is the percentage+    -- of error corrected every step before clamping to a maximum speed. You can use this+    -- to make joints correct themselves smoothly instead of at a constant speed, but is probably the least useful+    -- of the three properties by far.++    -- ** Constraints and Collision Shapes++    -- | Neither constraints or collision shapes have any knowledge of the other.+    -- When connecting joints to a body the anchor points don’t need to be inside of any shapes attached to the body+    -- and it often makes sense that they shouldn’t. Also, adding a constraint between two bodies+    -- doesn’t prevent their collision shapes from colliding. In fact, this is the primary reason+    -- that the collision group property exists.++    -- ** Video Tour of Current Joint Types++    -- | http://www.youtube.com/watch?v=ZgJJZTS0aMM++    -- ** Shared Memory Management Functions+  , constraintFree++    -- ** Constraint Types++    -- *** Pin Joints+  , pinJointNew++    -- **** Properties+  , pinJointAnchorA+  , pinJointAnchorB+  , pinJointDist++    -- *** Slide Joints+  , slideJointNew++    -- **** Properties+  , slideJointAnchorA+  , slideJointAnchorB+  , slideJointMin+  , slideJointMax++    -- *** Pivot Joints++    -- | (__Note for bindings__: So each instance of pivot joint can be replaced with pin joint with dist of 0?)++  , pivotJointNew+  , pivotJointNew2++    -- **** Properties+  , pivotJointAnchorA+  , pivotJointAnchorB++    -- *** Groove Joint+  , grooveJointNew++    -- **** Properties+  , grooveJointGrooveA+  , grooveJointGrooveB+  , grooveJointAnchorB++    -- *** Damped Spring+  , dampedSpringNew++    -- **** Properties+  , dampedSpringAnchorA+  , dampedSpringAnchorB+  , dampedSpringRestLength+  , dampedSpringStiffness+  , dampedSpringDamping++    -- *** Damped Rotary Spring++    -- | Like a damped spring, but works in an angular fashion.+  , dampedRotarySpringNew++    -- **** Properties+  , dampedRotarySpringRestAngle+  , dampedRotarySpringStiffness+  , dampedRotarySpringDamping++    -- *** Rotary Limit Joint++    -- | Constrains the relative rotations of two bodies.+    -- It is implemented so that it’s possible to for the range to be greater than a full revolution.+  , rotaryLimitJointNew++    -- **** Properties+  , rotaryLimitJointMin+  , rotaryLimitJointMax++    -- *** Ratchet Joint++    -- | Works like a socket wrench.+  , ratchetJointNew++    -- **** Properties+  , ratchetJointAngle+  , ratchetJointPhase+  , ratchetJointRatchet++    -- *** Gear Joint++    -- | Keeps the angular velocity ratio of a pair of bodies constant.+  , gearJointNew++    -- **** Properties+  , gearJointPhase+  , gearJointRatio++    -- *** Simple Motor++    -- | Keeps the relative angular velocity of a pair of bodies constant.+    -- You will usually want to set an force (torque) maximum for motors as otherwise+    -- they will be able to apply a nearly infinite torque to keep the bodies moving.+  , simpleMotorNew++    -- **** Properties+  , simpleMotorRate++    -- ** Notes++    -- | * You can add multiple joints between two bodies, but make sure that they don’t fight.+    -- Doing so can cause the bodies jitter or spin violently.++    -- * Overview of Collision Detection in Chipmunk++    -- | In order to make collision detection in Chipmunk as fast as possible, the process is broken down+    -- into several stages. While I’ve tried to keep it conceptually simple, the implementation can be a bit daunting.+    -- Fortunately as a user of the library, you don’t need to understand everything about how it works.+    -- Though if you are trying to squeeze every bit of performance out of Chipmunk, understanding this section+    -- can be helpful.++    -- ** Spatial Indexing++    -- | A for loop that checks every object against every other object in the scene would be very slow.+    -- So the first stage of the collision detection, commonly called the broadphase, uses a high level+    -- spatial algorithm to decide which pairs of objects to check for collisions.+    -- Currently Chipmunk supports two spatial indexes, an axis-aligned bounding box tree and a spatial hash.+    -- These spatial indexes are able to quickly identify which pairs of shapes are near each other+    -- and should be checked for a collision.++    -- ** Fast Collision Filtering++    -- | After the spatial index figures out which pairs of shapes are likely to be near each other,+    -- it passes each pair back to the space using a callback to perform some additional filtering on the pairs.+    -- Before doing anything else, Chipmunk performs a few quick tests to check if shapes should collide.+    --+    -- * __Bounding Box Test__: The shapes are not colliding if their bounding boxes are not overlapping.+    -- Objects like diagonal line segments can trigger a lot of false positives here,+    -- but it’s unlikely to be something you should worry about.+    --+    -- * __Category Mask Test__: The categories of each shape are bitwise ANDed against the category mask+    -- of the other shape. If either result is 0, the shapes do not collide.+    --+    -- * __Group Test__: Shapes shouldn’t collide with other shapes in the same non-zero group.++    -- ** Constraint Based Filtering++    -- | After fast collision filtering, Chipmunk checks the list of joints on one of the bodies+    -- to see if it has a constraint that attaches it to the other body. If that constraint’s collideBodies+    -- property is false, the collision will be ignored. This check is often very fast+    -- since most scenes don’t contain a lot of constraints.++    -- ** Primitive Shape to Shape Collision Detection++    -- | The most expensive test is to actually check for overlap based on their geometry.+    -- Circle to circle and circle to line collisions are very fast. Segment to segment and poly to poly collisions+    -- are handled using the GJK/EPA algorithms, and get more expensive as the number of vertexes increases.+    -- Simpler shapes make for faster collisions, and often more important, fewer collision points+    -- for the solver to run. Chipmunk uses a small dispatch table to figure out which function to use to check+    -- if the shapes overlap.+    --+    -- Without going into too much detail, the GJK algorithm checks the distance between two objects,+    -- and the EPA algorithm checks how much they are overlapping. If you give you segment and poly shapes+    -- a small radius when creating them, the EPA algorithm can usually be skipped, speeding up the collision detection+    -- considerably. The radius should be at least as big as the amount of allowed collision slop.++    -- ** Collision Handler Filtering++    -- | After checking if two shapes overlap Chipmunk will look to see if you have defined a collision handler+    -- for the collision types of the shapes. This is vital to process collisions events for the gameplay,+    -- but also gives you a very flexible way to filter out collisions. The return value of the begin and preSolve+    -- callbacks determines whether or not the colliding pair of shapes is discarded or not.+    -- Returning true will keep the pair, false will discard it. Rejecting a collision from a begin callback+    -- is permanent, rejecting it from the preSolve only applies to the step it occured in. If you don’t define+    -- a handler for the given collision types, Chipmunk will call the space’s default handler, which by default+    -- is defined to simply accept all collisions.+    --+    -- Wildcard collisions can also return a value, but they are handled in a more complicated way.+    -- When you create a collision handler between two specific collision types, it’s your responsibility+    -- to decide when to call the wildcard handlers and what to do with their return values.+    -- Otherwise, the default is to call the wildcard handler for the first type, then the second type,+    -- and use a logical AND of their return values as filtering value. See DefaultBegin() in cpSpace.c+    -- for more information.+    --+    -- While using callbacks to filter collisions is the most flexible way, keep in mind that by the time your callback+    -- is called all of the most expensive collision detection has already been done. For simulations+    -- with a lot of colliding objects each frame, the time spent finding collisions is small compared to the time+    -- spent solving the physics for them so it may not be a big deal. Fast collision filtering should be preferred+    -- if possible.++    -- * Collision Callbacks++    -- | A physics library without any events or feedback would not be very useful for games.+    -- How would you know when the player bumped into an enemy so that you could take some health points away?+    -- How would you know how hard the car hit something so you don’t play a loud crash noise when a pebble hits it?+    -- What if you need to decide if a collision should be ignored based on specific conditions,+    -- like implementing one way platforms? Chipmunk has a number of powerful callback systems+    -- that you can use to solve these problems.++    -- ** Collision Handlers++    -- | Collision handler function types. While all of them take an arbiter, space, and a user data pointer,+    -- only the begin and preSolve callbacks return a value. See above for more information.+  , CollisionCallback+    -- Collision callbacks are closely associated with 'Arbiter' structs.+    -- You should familiarize yourself with those as well.+    --+    -- __Note__: Shapes tagged as sensors (cpShape.sensor == true) never generate collisions that get processed,+    -- so collisions between sensors shapes and other shapes will never call the postSolve callback.+    -- They still generate begin, and separate callbacks, and the preSolve callback is also called+    -- every frame even though there is no collision response.+    --+    -- __Note #2__: preSolve callbacks are called before the sleeping algorithm runs.+    -- If an object falls asleep, its postSolve callback won’t be called until it’s reawoken.++  , CollisionType+  , CollisionHandler (..)+  , CollisionHandlerPtr+  , spaceAddCollisionHandler+  , spaceAddWildcardHandler+  , spaceAddDefaultCollisionHandler+  , modifyCollisionHandler+  , mkCallback+  , mkCallbackB++    -- ** Post-Step Callbacks++    -- | Post-step callbacks are the one place where you can break the rules about adding or removing objects+    -- from within a callback. In fact, their primary function is to help you safely remove objects from the space+    -- that you wanted to disable or destroy in a collision or query callback.+    --+    -- Post step callbacks are registered as a function and a pointer that is used as a key.+    -- You can only register one postStep callback per key. This prevents you from accidentally removing+    -- an object more than once. For instance, say that you get a collision callback between a bullet and object A.+    -- You want to destroy both the bullet and object A, so you register a postStep callback+    -- to safely remove them from your game. Then you get a second collision callback between the bullet and object B.+    -- You register a postStep callback to remove object B, and a second postStep callback to remove the bullet.+    -- Because you can only register one callback per key, the postStep callback for the bullet+    -- will only be called once and you can’t accidentally try to remove it twice.+  , PostStepFunc+  , spaceAddPostStepCallback++    -- ** Examples++    -- | See+    -- <https://chipmunk-physics.net/release/ChipmunkLatest-Docs/examples.html#CollisionCallbacks the callback examples>+    -- for more information.++    -- * Chipmunk Collision Pairs+  , Arbiter++    -- ** Memory Management++    -- | You will never need to create or free an arbiter. More importantly,+    -- because they are entirely managed by the space you should never store a reference to an arbiter+    -- as you don’t know when they will be freed or reused. Use them within the callback where they are given to you+    -- and then forget about them or copy out the information you need.++    -- ** Properties++  , arbiterRestitution+  , arbiterFriction+  , arbiterSurfaceVelocity+  , arbiterUserData++    -- *** Collision Point(s)+  , arbiterCount+  , arbiterNormal+  , arbiterPointA+  , arbiterPointB+  , arbiterDepth++    -- *** Other+  , arbiterIsFirstContact+  , arbiterIsRemoval++    -- *** Bodies and shapes+  , arbiterShapes+  , arbiterBodies++    -- *** Running wildcard handlers++    -- | These functions invoke the wildcard handlers for a given collision. For custom collision handlers+    -- between specific types or overriding the default handler, you must decide how to invoke the wildcard handlers+    -- since it may be important to call the wildcards first, last, or possibly skip them entirely.+    -- For the begin and preSolve callbacks, you also need to decide what to do with their return values+    -- since they may not agree with each other or the specific handler they were called from.+    -- Every collision handler is defined for two types, the “A” variants of these functions call the wildcard handler+    -- for the first type, and the “B” variants call the handler for the second type.++  , arbiterCallWildcardBeginA+  , arbiterCallWildcardBeginB+  , arbiterCallWildcardPreSolveA+  , arbiterCallWildcardPreSolveB+  , arbiterCallWildcardPostSolveA+  , arbiterCallWildcardPostSolveB+  , arbiterCallWildcardSeparateA+  , arbiterCallWildcardSeparateB++    -- * Misc+  , DataPtr+  , Transform (..)++    -- * Re-exports+  , nullPtr+  , HasGetter (..)+  , HasSetter (..)+  ) where++import Foreign+import Data.StateVar++import Chiphunk.Low.Types+import Chiphunk.Low.Math+import Chiphunk.Low.Helper+import Chiphunk.Low.Vect+import Chiphunk.Low.BB+import Chiphunk.Low.Body+import Chiphunk.Low.Shape+import Chiphunk.Low.Space+import Chiphunk.Low.Constraint+import Chiphunk.Low.Callback+import Chiphunk.Low.Arbiter
+ src/Chiphunk/Low/Arbiter.chs view
@@ -0,0 +1,172 @@+module Chiphunk.Low.Arbiter+  ( Arbiter+  , arbiterRestitution+  , arbiterFriction+  , arbiterSurfaceVelocity+  , arbiterUserData+  , arbiterCount+  , arbiterNormal+  , arbiterPointA+  , arbiterPointB+  , arbiterDepth+  , arbiterIsFirstContact+  , arbiterIsRemoval+  , arbiterShapes+  , arbiterBodies+  , arbiterCallWildcardBeginA+  , arbiterCallWildcardBeginB+  , arbiterCallWildcardPreSolveA+  , arbiterCallWildcardPreSolveB+  , arbiterCallWildcardPostSolveA+  , arbiterCallWildcardPostSolveB+  , arbiterCallWildcardSeparateA+  , arbiterCallWildcardSeparateB+  ) where++import Data.StateVar+import Foreign++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++{# fun unsafe cpArbiterGetRestitution {`Arbiter'} -> `Double' #}++{# fun unsafe cpArbiterSetRestitution {`Arbiter', `Double'} -> `()' #}++-- | The calculated elasticity for this collision pair.+-- Setting the value in a preSolve() callback will override the value calculated by the space.+-- The default calculation multiplies the elasticity of the two shapes together.+arbiterRestitution :: Arbiter -> StateVar Double+arbiterRestitution = mkStateVar cpArbiterGetRestitution cpArbiterSetRestitution++{# fun unsafe cpArbiterGetFriction {`Arbiter'} -> `Double' #}++{# fun unsafe cpArbiterSetFriction {`Arbiter', `Double'} -> `()' #}++-- | The calculated friction for this collision pair.+-- Setting the value in a preSolve() callback will override the value calculated by the space.+-- The default calculation multiplies the friction of the two shapes together.+arbiterFriction :: Arbiter -> StateVar Double+arbiterFriction = mkStateVar cpArbiterGetFriction cpArbiterSetFriction++{# fun unsafe w_cpArbiterGetSurfaceVelocity {`Arbiter', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpArbiterSetSurfaceVelocity {`Arbiter', with* %`Vect'} -> `()' #}++-- | The calculated surface velocity for this collision pair.+-- Setting the value in a preSolve() callback will override the value calculated by the space.+-- The default calculation subtracts the surface velocity of the second shape+-- from the first and then projects that onto the tangent of the collision.+-- This is so that only friction is affected by default calculation.+--+-- Using a custom calculation, you can make something that responds like a pinball bumper,+-- or where the surface velocity is dependent on the location of the contact point.+arbiterSurfaceVelocity :: Arbiter -> StateVar Vect+arbiterSurfaceVelocity = mkStateVar w_cpArbiterGetSurfaceVelocity cpArbiterSetSurfaceVelocity++{# fun unsafe cpArbiterGetUserData {`Arbiter'} -> `DataPtr' #}++{# fun unsafe cpArbiterSetUserData {`Arbiter', `DataPtr'} -> `()' #}++-- | A user definable context pointer.+-- The value will persist until just after the separate callback is called for the pair.+--+-- __Note__: If you need to clean up this pointer, you should implement the separate callback to do it.+-- Also be careful when destroying the space as there may be active collisions still.+-- In order to trigger the separate callbacks and clean up your data,+-- you’ll need to remove all the shapes from the space before disposing of it.+-- This is something I’d suggest doing anyway.+-- See ChipmunkDemo.c:ChipmunkDemoFreeSpaceChildren() for an example of how to do it easily.+arbiterUserData :: Arbiter -> StateVar DataPtr+arbiterUserData = mkStateVar cpArbiterGetUserData cpArbiterSetUserData++{# fun unsafe cpArbiterGetCount {`Arbiter'} -> `Int' #}++-- | The number of contacts tracked by this arbiter.+-- For the forseeable future, the maximum number of contacts will be two.+arbiterCount :: Arbiter -> GettableStateVar Int+arbiterCount = makeGettableStateVar . cpArbiterGetCount++{# fun unsafe w_cpArbiterGetNormal {`Arbiter', alloca- `Vect' peek*} -> `()' #}++-- | Collision normal in a specific point tracked by this collision.+arbiterNormal :: Arbiter -> GettableStateVar Vect+arbiterNormal = makeGettableStateVar . w_cpArbiterGetNormal++{# fun unsafe w_cpArbiterGetPointA {`Arbiter', `Int', alloca- `Vect' peek*} -> `()' #}++-- | Collision point of a specific point on first body.+arbiterPointA :: Arbiter -> Int -> GettableStateVar Vect+arbiterPointA arbiter = makeGettableStateVar . w_cpArbiterGetPointA arbiter++{# fun unsafe w_cpArbiterGetPointB {`Arbiter', `Int', alloca- `Vect' peek*} -> `()' #}++-- | Collision point of a specific point on second body.+arbiterPointB :: Arbiter -> Int -> GettableStateVar Vect+arbiterPointB arbiter = makeGettableStateVar . w_cpArbiterGetPointB arbiter++{# fun unsafe cpArbiterGetDepth {`Arbiter', `Int'} -> `Double' #}++-- | Penetration depth of a collision point.+arbiterDepth :: Arbiter -> Int -> GettableStateVar Double+arbiterDepth arbiter = makeGettableStateVar . cpArbiterGetDepth arbiter++-- | Returns true if this is the first step the two shapes started touching. This can be useful for sound effects+-- for instance. If its the first frame for a certain collision, check the energy of the collision in a postStep+-- callbock and use that to determine the volume of a sound effect to play.+{# fun unsafe cpArbiterIsFirstContact as arbiterIsFirstContact {`Arbiter'} -> `Bool' #}++-- | Returns 'True' during a separate callback if the callback was invoked due to an object removal.+{# fun unsafe cpArbiterIsRemoval as arbiterIsRemoval {`Arbiter'} -> `Bool' #}++{# fun unsafe cpArbiterGetShapes+  { `Arbiter'+  , alloca- `Shape' peek*+  , alloca- `Shape' peek*+  } -> `()' #}++-- | The colliding shapes in the order that they were defined in the collision handler+-- associated with this arbiter.+-- If you defined the handler as cpSpaceAddCollisionHandler(space, 1, 2, ...),+-- you you will find that a->collision_type == 1 and b->collision_type == 2.+arbiterShapes :: Arbiter -> GettableStateVar (Shape, Shape)+arbiterShapes = makeGettableStateVar . cpArbiterGetShapes++{# fun unsafe cpArbiterGetBodies+  { `Arbiter'+  , alloca- `Body' peek*+  , alloca- `Body' peek*+  } -> `()' #}++-- | The colliding bodies in the order that they were defined in the collision handler+-- associated with this arbiter.+-- If you defined the handler as cpSpaceAddCollisionHandler(space, 1, 2, ...),+-- you you will find that a->collision_type == 1 and b->collision_type == 2.+arbiterBodies :: Arbiter -> GettableStateVar (Body, Body)+arbiterBodies = makeGettableStateVar . cpArbiterGetBodies++-- | Run begin wildcard callback for first body.+{# fun cpArbiterCallWildcardBeginA as arbiterCallWildcardBeginA {`Arbiter', `Space'} -> `Bool' #}++-- | Run begin wildcard callback for second body.+{# fun cpArbiterCallWildcardBeginB as arbiterCallWildcardBeginB {`Arbiter', `Space'} -> `Bool' #}++-- | Run preSolve wildcard callback for first body.+{# fun cpArbiterCallWildcardPreSolveA as arbiterCallWildcardPreSolveA {`Arbiter', `Space'} -> `Bool' #}++-- | Run preSolve wildcard callback for second body.+{# fun cpArbiterCallWildcardPreSolveB as arbiterCallWildcardPreSolveB {`Arbiter', `Space'} -> `Bool' #}++-- | Run postSolve wildcard callback for first body.+{# fun cpArbiterCallWildcardPostSolveA as arbiterCallWildcardPostSolveA {`Arbiter', `Space'} -> `()' #}++-- | Run postSolve wildcard callback for second body.+{# fun cpArbiterCallWildcardPostSolveB as arbiterCallWildcardPostSolveB {`Arbiter', `Space'} -> `()' #}++-- | Run separate wildcard callback for first body.+{# fun cpArbiterCallWildcardSeparateA as arbiterCallWildcardSeparateA {`Arbiter', `Space'} -> `()' #}++-- | Run separate wildcard callback for second body.+{# fun cpArbiterCallWildcardSeparateB as arbiterCallWildcardSeparateB {`Arbiter', `Space'} -> `()' #}
+ src/Chiphunk/Low/BB.chs view
@@ -0,0 +1,128 @@+-- | Description: Utilities for working with bounding box.+-- Module provides utilities for working with bounding box.+module Chiphunk.Low.BB+  ( BB (..)+  , bbNew+  , bbNewForExtents+  , bbNewForCircle+  , bbIntersects+  , bbContainsBB+  , bbContainsVect+  , bbMerge+  , bbExpand+  , bbCenter+  , bbArea+  , bbMergedArea+  , bbSegmentQuery+  , bbIntersectsSegment+  , bbClampVect+  , bbWrapVect+  ) where++import Data.Fixed+import Foreign++import Chiphunk.Low.Math++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++-- | Convenience constructor for 'BB' structs.+bbNew :: Double -> Double -> Double -> Double -> BB+bbNew = BB++-- | Convenience constructor for making a 'BB' fitting with a center point and half width and height.+bbNewForExtents+  :: Vect   -- ^ Center point+  -> Double -- ^ Half width+  -> Double -- ^ Half height+  -> BB+bbNewForExtents (Vect x y) hw hh = BB (x - hw) (y - hh) (x + hw) (y + hh)++-- | Convenience constructor for making a 'BB' fitting a circle at position @p@ with radius @r@.+bbNewForCircle+  :: Vect   -- ^ p+  -> Double -- ^ r+  -> BB+bbNewForCircle v r = bbNewForExtents v r r++-- | Returns true if the bounding boxes intersect.+bbIntersects :: BB -> BB -> Bool+BB l1 b1 r1 t1 `bbIntersects` BB l2 b2 r2 t2 = r1 >= l1 && r2 >= l2 && t1 >= b1 && t2 >= b2++-- | Returns true if @bb@ completely contains @other@.+bbContainsBB+  :: BB   -- ^ bb+  -> BB   -- ^ other+  -> Bool+BB l1 b1 r1 t1 `bbContainsBB` BB l2 b2 r2 t2 = l1 <= l2 && r1 >= r2 && t1 >= t2 && b1 <= b2++-- | Returns true if @bb@ contains @v@.+bbContainsVect+  :: BB   -- ^ bb+  -> Vect -- ^ v+  -> Bool+BB l b r t `bbContainsVect` Vect x y = l <= x && r >= x && b <= y && t >= y++-- | Return the minimal bounding box that contains both @a@ and @b@.+bbMerge+  :: BB -- ^ a+  -> BB -- ^ b+  -> BB+BB l1 b1 r1 t1 `bbMerge` BB l2 b2 r2 t2 = BB (min l1 l2) (min b1 b2) (max r1 r2) (max t1 t2)++-- | Return the minimal bounding box that contains both @bb@ and @v@.+bbExpand+  :: BB   -- ^ bb+  -> Vect -- ^ v+  -> BB+BB l b r t `bbExpand` Vect x y = BB (min l x) (min b y) (max r x) (max t y)++-- | Return the center of @bb@.+bbCenter+  :: BB   -- ^ bb+  -> Vect+bbCenter (BB l b r t) = Vect ((l + r) / 2) ((b + t) / 2)++-- | Return the area of @bb@.+bbArea+  :: BB     -- ^ bb+  -> Double+bbArea (BB l b r t) = (r - l) * (t - b)++-- | Merges @a@ and @b@ then returns the area of the merged bounding box.+bbMergedArea+  :: BB     -- ^ a+  -> BB     -- ^ b+  -> Double+BB l1 b1 r1 t1 `bbMergedArea` BB l2 b2 r2 t2 = (max r1 r2 - min l1 l2) * (max t1 t2 - min b1 b2)++-- | Returns the fraction along the segment query the 'BB' is hit. Returns INFINITY if it doesn’t hit.+{# fun pure unsafe w_cpBBSegmentQuery as bbSegmentQuery+  { with* %`BB'   -- ^ Box+  , with* %`Vect' -- ^ One segment end+  , with* %`Vect' -- ^ Other segment end+  } -> `Double' #}++-- | Returns true if the segment defined by endpoints @a@ and @b@ intersect @bb@.+{# fun pure unsafe w_cpBBIntersectsSegment as bbIntersectsSegment+  { with* %`BB'   -- ^ bb+  , with* %`Vect' -- ^ a+  , with* %`Vect' -- ^ b+  } -> `Bool' #}++-- | Returns a copy of @v@ clamped to the bounding box @bb@.+bbClampVect+  :: BB   -- ^ bb+  -> Vect -- ^ v+  -> Vect+BB l b r t `bbClampVect` Vect x y = Vect (fClamp x l r) (fClamp y b t)++-- | Returns a copy of @v@ wrapped to the bounding box @bb@.+bbWrapVect+  :: BB   -- ^ bb+  -> Vect -- ^ v+  -> Vect+BB l b r t `bbWrapVect` Vect x y = Vect (l + ((x - l) `mod'` abs (r - l))) (b + ((y - b) `mod'` abs (t - b)))
+ src/Chiphunk/Low/Body.chs view
@@ -0,0 +1,319 @@+-- | Description: Rigid bodies manipulations+-- Module provides access to the rigid bodies which are at the core of the physics simulation.+module Chiphunk.Low.Body+  ( Body+  , BodyType (..)+  , bodyNew+  , bodyNewKinematic+  , bodyNewStatic+  , bodyFree+  , bodyType+  , bodyMass+  , bodyMoment+  , bodyPosition+  , bodyCenterOfGravity+  , bodyVelocity+  , bodyForce+  , bodyAngle+  , bodyAngularVelocity+  , bodyTorque+  , bodyRotation+  , bodySpace+  , bodyUserData+  , bodyLocalToWorld+  , bodyWorldToLocal+  , bodyVelocityAtWorldPoint+  , bodyVelocityAtLocalPoint+  , bodyApplyForceAtWorldPoint+  , bodyApplyForceAtLocalPoint+  , bodyApplyImpulseAtWorldPoint+  , bodyApplyImpulseAtLocalPoint+  , bodyIsSleeping+  , bodyActivate+  , bodySleep+  , bodyActivateStatic+  , bodySleepWithGroup+  , BodyShapeIteratorFunc+  , bodyEachShape+  , BodyConstraintIteratorFunc+  , bodyEachConstraint+  , BodyArbiterIteratorFunc+  , bodyEachArbiter+  ) where++import Chiphunk.Low.Vect+import Control.Exception.Safe+import Data.StateVar+import Foreign++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++-- | Creates body of type 'BodyTypeDynamic'.+{# fun unsafe cpBodyNew as bodyNew+  { `Double' -- ^ Mass of the body. Guessing is usually fine.++  , `Double' -- ^ Moment of inertia of the body.+             -- Guessing a moment of inertia can lead to a very poor simulation+             -- so it’s recommended to use Chipmunk’s moment calculations+             -- to estimate the moment for you.+  } -> `Body' #}++-- | Create body of type 'BodyTypeKimenatic'.+{# fun unsafe cpBodyNewKinematic as bodyNewKinematic {} -> `Body' #}++-- | Create body of type 'BodyTypeStatic'.+{# fun unsafe cpBodyNewStatic as bodyNewStatic {} -> `Body' #}++-- | Be careful not to free a body before any shapes or constraints attached to it+-- have been removed from a space.+{# fun cpBodyFree as bodyFree {`Body'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger callbacks++-- | Get the type of a body (dynamic, kinematic, static).+{# fun unsafe cpBodyGetType {`Body'} -> `BodyType' #}++{# fun unsafe cpBodySetType {`Body', `BodyType'} -> `()' #}++-- | Type of a body (dynamic, kinematic, static).+-- When changing an body to a dynamic body, the mass and moment of inertia+-- are recalculated from the shapes added to the body.+-- Custom calculated moments of inertia are not preseved when changing types.+-- This function cannot be called directly in a collision callback.+bodyType :: Body -> StateVar BodyType+bodyType = mkStateVar cpBodyGetType cpBodySetType++{# fun unsafe cpBodyGetMass {`Body'} -> `Double' #}++{# fun unsafe cpBodySetMass {`Body', `Double'} -> `()' #}++-- | Mass of the body.+bodyMass :: Body -> StateVar Double+bodyMass = mkStateVar cpBodyGetMass cpBodySetMass++{# fun unsafe cpBodyGetMoment {`Body'} -> `Double' #}++{# fun unsafe cpBodySetMoment {`Body', `Double'} -> `()' #}++-- | Moment of inertia (MoI or sometimes just moment) of the body.+-- The moment is like the rotational mass of a body.+-- See below for function to help calculate the moment.+bodyMoment :: Body -> StateVar Double+bodyMoment = mkStateVar cpBodyGetMoment cpBodySetMoment++{# fun unsafe w_cpBodyGetPosition {`Body', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpBodySetPosition {`Body', with* %`Vect'} -> `()' #}++-- | Position of the body. When changing the position you may also want to call+-- 'spaceReindexShapesForBody' to update the collision detection information+-- for the attached shapes if plan to make any queries against the space.+bodyPosition :: Body -> StateVar Vect+bodyPosition = mkStateVar w_cpBodyGetPosition cpBodySetPosition++{# fun unsafe w_cpBodyGetCenterOfGravity {`Body', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpBodySetCenterOfGravity {`Body', with* %`Vect'} -> `()' #}++-- | Location of the center of gravity in body local coordinates.+-- The default value is (0, 0), meaning the center of gravity+-- is the same as the position of the body.+bodyCenterOfGravity :: Body -> StateVar Vect+bodyCenterOfGravity = mkStateVar w_cpBodyGetCenterOfGravity cpBodySetCenterOfGravity++{# fun unsafe w_cpBodyGetVelocity {`Body', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpBodySetVelocity {`Body', with* %`Vect'} -> `()' #}++-- | Linear velocity of the center of gravity of the body.+bodyVelocity :: Body -> StateVar Vect+bodyVelocity = mkStateVar w_cpBodyGetVelocity cpBodySetVelocity++{# fun unsafe w_cpBodyGetForce {`Body', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpBodySetForce {`Body', with* %`Vect'} -> `()' #}++-- | Force applied to the center of gravity of the body.+-- This value is reset for every time step.+bodyForce :: Body -> StateVar Vect+bodyForce = mkStateVar w_cpBodyGetForce cpBodySetForce++{# fun unsafe cpBodyGetAngle {`Body'} -> `Double' #}++{# fun unsafe cpBodySetAngle {`Body', `Double'} -> `()' #}++-- | Set rotation of the body in radians.+-- When changing the rotation you may also want to call 'spaceReindexShapesForBody'+-- to update the collision detection information for the attached shapes+-- if you plan to make any queries against the space.+-- A body rotates around its center of gravity, not its position.+bodyAngle :: Body -> StateVar Double+bodyAngle = mkStateVar cpBodyGetAngle cpBodySetAngle++{# fun unsafe cpBodyGetAngularVelocity {`Body'} -> `Double' #}++{# fun unsafe cpBodySetAngularVelocity {`Body', `Double'} -> `()' #}++-- | Angular velocity of the body in radians per second.+bodyAngularVelocity :: Body -> StateVar Double+bodyAngularVelocity = mkStateVar cpBodyGetAngularVelocity cpBodySetAngularVelocity++{# fun unsafe cpBodyGetTorque {`Body'} -> `Double' #}++{# fun unsafe cpBodySetTorque {`Body', `Double'} -> `()' #}++-- | Torque applied to the body. This value is reset for every time step.+bodyTorque :: Body -> StateVar Double+bodyTorque = mkStateVar cpBodyGetTorque cpBodySetTorque++{# fun unsafe w_cpBodyGetRotation {`Body', alloca- `Vect' peek*} -> `()' #}++-- | The rotation vector for the body.+-- Can be used with 'vRotate' or 'vUnRotate' to perform fast rotations.+bodyRotation :: Body -> GettableStateVar Vect+bodyRotation = makeGettableStateVar . w_cpBodyGetRotation++{# fun unsafe cpBodyGetSpace {`Body'} -> `Space' #}++-- | The 'Space' that body has been added to.+bodySpace :: Body -> GettableStateVar Space+bodySpace = makeGettableStateVar . cpBodyGetSpace++{# fun unsafe cpBodyGetUserData {`Body'} -> `DataPtr' #}++{# fun unsafe cpBodySetUserData {`Body', `DataPtr'} -> `()' #}++-- | User data pointer. Use this pointer to get a reference to the game object+-- that owns this body from callbacks.+bodyUserData :: Body -> StateVar DataPtr+bodyUserData = mkStateVar cpBodyGetUserData cpBodySetUserData++-- | Convert from body local coordinates to world space coordinates.+{# fun unsafe w_cpBodyLocalToWorld as bodyLocalToWorld {`Body', with* %`Vect', alloca- `Vect' peek*} -> `()' #}++-- | Convert from world space coordinates to body local coordinates.+{# fun unsafe w_cpBodyWorldToLocal as bodyWorldToLocal {`Body', with* %`Vect', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe w_cpBodyGetVelocityAtWorldPoint+  {`Body', with* %`Vect', alloca- `Vect' peek*} -> `()' #}++-- | Absolute velocity of the rigid body at the given world point.+bodyVelocityAtWorldPoint :: Body -> Vect -> GettableStateVar Vect+bodyVelocityAtWorldPoint body = makeGettableStateVar . w_cpBodyGetVelocityAtWorldPoint body++{# fun unsafe w_cpBodyGetVelocityAtLocalPoint+  {`Body', with* %`Vect', alloca- `Vect' peek*} -> `()' #}++-- | Absolute velocity of the rigid body at the given body local point.+bodyVelocityAtLocalPoint :: Body -> Vect -> GettableStateVar Vect+bodyVelocityAtLocalPoint body = makeGettableStateVar . w_cpBodyGetVelocityAtLocalPoint body++-- | Add the @force@ to @body@ as if applied from the world @point@.+{# fun unsafe cpBodyApplyForceAtWorldPoint as bodyApplyForceAtWorldPoint+  { `Body'        -- ^ body+  , with* %`Vect' -- ^ force+  , with* %`Vect' -- ^ point+  } -> `()' #}++-- | Add the local @force@ to @body@ as if applied from the body local @point@.+{# fun unsafe cpBodyApplyForceAtLocalPoint as bodyApplyForceAtLocalPoint+  { `Body'        -- ^ body+  , with* %`Vect' -- ^ force+  , with* %`Vect' -- ^ point+  } -> `()' #}++-- | Add the @impulse@ to @body@ as if applied from the world @ point@.+{# fun unsafe cpBodyApplyImpulseAtWorldPoint as bodyApplyImpulseAtWorldPoint+  { `Body'        -- ^ body+  , with* %`Vect' -- ^ impulse+  , with* %`Vect' -- ^ point+  } -> `()' #}++-- | Add the local @impulse@ to @body@ as if applied from the body local @point@.+{# fun unsafe cpBodyApplyImpulseAtLocalPoint as bodyApplyImpulseAtLocalPoint+  { `Body'        -- ^ body+  , with* %`Vect' -- ^ impulse+  , with* %`Vect' -- ^ point+  } -> `()' #}++-- | Returns true if body is sleeping.+{# fun unsafe cpBodyIsSleeping as bodyIsSleeping {`Body'} -> `Bool' #}++-- | Reset the idle timer on a body. If it was sleeping, wake it and any other bodies it was touching.+{# fun unsafe cpBodyActivate as bodyActivate {`Body'} -> `()' #}++-- | Forces a body to fall asleep immediately even if it’s in midair. Cannot be called from a callback.+{# fun unsafe cpBodySleep as bodySleep {`Body'} -> `()' #}++-- | Activates all bodies touching @body@.+-- If @filter@ is not 'nullPtr', then only bodies touching through @filter@ will be awoken.+{# fun unsafe cpBodyActivateStatic as bodyActivateStatic+  { `Body'  -- ^ body+  , `Shape' -- ^ filter+  } -> `()' #}++-- | When objects in Chipmunk sleep, they sleep as a group of all objects that are touching or jointed together.+-- When an object is woken up, all of the objects in its group are woken up.+-- 'bodySleepWithGroup' allows you group sleeping objects together.+-- It acts identically to 'bodySleep' if you pass 'nullPtr' as @group@ by starting a new group.+-- If you pass a sleeping body for @group@, @body@ will be awoken when group is awoken.+-- You can use this to initialize levels and start stacks of objects in a pre-sleeping state.+{# fun unsafe cpBodySleepWithGroup as bodySleepWithGroup+  { `Body' -- ^ body+  , `Body' -- ^ group+  } -> `()' #}++-- | Type of callback which can be used to iterate all 'Shape's in a 'Body'.+type BodyShapeIteratorFunc = Body -> Shape -> Ptr () -> IO ()++foreign import ccall unsafe "wrapper"+  mkBodyShapeIteratorFunc :: BodyShapeIteratorFunc -> IO (FunPtr BodyShapeIteratorFunc)++-- | Call @func@ once for each shape that is attached to @body@ and added to a space.+-- @data@ is passed along as a context value. It is safe to remove shapes using these callbacks.+{# fun cpBodyEachShape as bodyEachShape+  { `Body'                                -- ^ body+  , withIterator* `BodyShapeIteratorFunc' -- ^ func+  , `Ptr ()'                              -- ^ data+  } -> `()' #}+  where+    withIterator i = mkBodyShapeIteratorFunc i `bracket` freeHaskellFunPtr++-- | Type of callback which can be used to iterate all 'Constraint's in a 'Body'.+type BodyConstraintIteratorFunc = Body -> Constraint -> Ptr () -> IO ()++foreign import ccall unsafe "wrapper"+  mkBodyConstraintIteratorFunc :: BodyConstraintIteratorFunc -> IO (FunPtr BodyConstraintIteratorFunc)++-- | Call @func@ once for each constraint that is attached to @body@ and added to a space.+-- @data@ is passed along as a context value. It is safe to remove constraints using thes callbacks.+{# fun cpBodyEachConstraint as bodyEachConstraint+  { `Body'                                     -- ^ body+  , withIterator* `BodyConstraintIteratorFunc' -- ^ func+  , `Ptr ()'                                   -- ^ data+  } -> `()' #}+  where+    withIterator i = mkBodyConstraintIteratorFunc i `bracket` freeHaskellFunPtr++-- | Type of callback which can be used to iterate all 'Arbiter's in a 'Body'.+type BodyArbiterIteratorFunc = Body -> Arbiter -> Ptr () -> IO ()++foreign import ccall unsafe "wrapper"+  mkBodyArbiterIteratorFunc :: BodyArbiterIteratorFunc -> IO (FunPtr BodyArbiterIteratorFunc)++-- | This one is more interesting. Calls @func@ once for each collision pair that @body@ is involved in.+-- Calling 'arbiterGetBodies'/'arbiterGetShapes' will return the body or shape for body as the first argument.+-- You can use this to check all sorts of collision information for a body like if it’s touching the ground,+-- another particular object, how much collision force is being applied to an object, etc.+--+-- Sensor shapes and arbiters that have been rejected by a collision handler callback or 'arbiterIgnore'+-- are not tracked by the contact graph.+{# fun cpBodyEachArbiter as bodyEachArbiter+  { `Body'                                  -- ^ body+  , withIterator* `BodyArbiterIteratorFunc' -- ^ func+  , `Ptr ()'                                -- ^ data+  } -> `()' #}+  where+    withIterator i = mkBodyArbiterIteratorFunc i `bracket` freeHaskellFunPtr
+ src/Chiphunk/Low/Callback.chs view
@@ -0,0 +1,159 @@+-- | Description: Collision handler definition+-- Module provides definitions for collision handlers.+module Chiphunk.Low.Callback+  ( CollisionCallback+  , CollisionHandler (..)+  , CollisionHandlerPtr+  , spaceAddCollisionHandler+  , spaceAddWildcardHandler+  , spaceAddDefaultCollisionHandler+  , modifyCollisionHandler+  , mkCallback+  , mkCallbackB+  , PostStepFunc+  , spaceAddPostStepCallback+  ) where++import Control.Applicative (liftA)+import Control.Exception.Safe+import Data.Bool (bool)+import Foreign++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>++-- | Collision callback+type CollisionCallback ret = Arbiter -> Space -> DataPtr -> IO ret++-- | This collision handler processes collisions between objects of type @typeA@ and @typeB@.+-- Fill the desired collision callback functions- they are documented above. A user definable context pointer+-- @userData@ is included for your convenience. This pointer is provided as an argument in each callback function.+--+-- A collision handler is a set of 4 function callbacks for the different collision events that Chipmunk recognizes.+data CollisionHandler = CollisionHandler+  { chTypeA         :: !CollisionType                   -- ^ typeA+  , chTypeB         :: !CollisionType                   -- ^ typeB+  , chBeginFunc     :: !(FunPtr (CollisionCallback CPBool))+    -- ^ Two shapes just started touching for the first time this step. Return true from the callback+    -- to process the collision normally or false to cause Chipmunk to ignore the collision entirely.+    -- If you return false, the preSolve and postSolve callbacks will never be run, but you will still recieve+    -- a separate event when the shapes stop overlapping.+  , chPreSolveFunc  :: !(FunPtr (CollisionCallback CPBool))+    -- ^ Two shapes are touching during this step. Return false from the callback to make Chipmunk ignore the collision+    -- this step or true to process it normally. Additionally, you may override collision values using+    -- 'Chiphunk.Low.Arbiter.arbiterFriction', 'Chiphunk.Low.Arbiter.arbiterRestitution' or+    -- 'Chiphunk.Low.arbiterSurfaceVelocity' to provide custom friction, elasticity, or surface velocity values.+    -- See 'Arbiter' for more info.+  , chPostSolveFunc :: !(FunPtr (CollisionCallback ()))+    -- ^ Two shapes are touching and their collision response has been processed. You can retrieve the collision+    -- impulse or kinetic energy at this time if you want to use it to calculate sound volumes or damage amounts.+    -- See 'Arbiter' for more info.+  , chSeparateFunc  :: !(FunPtr (CollisionCallback ()))+    -- ^ Two shapes have just stopped touching for the first time this step. To ensure that begin/separate+    -- are always called in balanced pairs, it will also be called when removing a shape while its in contact+    -- with something or when deallocating the space.+  , cpUserData      :: !DataPtr                         -- ^ userData+  } deriving Show++instance Storable CollisionHandler where+  sizeOf _ = {# sizeof cpCollisionHandler #}+  alignment _ = {# alignof cpCollisionHandler #}+  poke p (CollisionHandler typA typB beginFunc preSolveFunc postSolveFunc separateFunc userData) = do+    {# set cpCollisionHandler->typeA #} p $ fromIntegral typA+    {# set cpCollisionHandler->typeB #} p $ fromIntegral typB+    {# set cpCollisionHandler->beginFunc #} p beginFunc+    {# set cpCollisionHandler->preSolveFunc #} p preSolveFunc+    {# set cpCollisionHandler->postSolveFunc #} p postSolveFunc+    {# set cpCollisionHandler->separateFunc #} p separateFunc+    {# set cpCollisionHandler->userData #} p userData+  peek p = CollisionHandler <$> (fromIntegral <$> {# get cpCollisionHandler->typeA #} p)+                            <*> (fromIntegral <$> {# get cpCollisionHandler->typeB #} p)+                            <*> {# get cpCollisionHandler->beginFunc #} p+                            <*> {# get cpCollisionHandler->preSolveFunc #} p+                            <*> {# get cpCollisionHandler->postSolveFunc #} p+                            <*> {# get cpCollisionHandler->separateFunc #} p+                            <*> {# get cpCollisionHandler->userData #} p++foreign import ccall unsafe "wrapper"+  mkCallback' :: CollisionCallback () -> IO (FunPtr (CollisionCallback ()))++-- | Make callback. Need to free afterwards.+mkCallback :: CollisionCallback () -> IO (FunPtr (CollisionCallback ()))+mkCallback = mkCallback'++foreign import ccall unsafe "wrapper"+  mkCallbackB' :: CollisionCallback CPBool -> IO (FunPtr (CollisionCallback CPBool))++-- | Make callback. Need to free afterwards.+mkCallbackB :: CollisionCallback Bool -> IO (FunPtr (CollisionCallback CPBool))+mkCallbackB = mkCallbackB' . liftA (liftA $ liftA $ liftA $ bool 0 1)++-- | Pointer to collision handler+{# pointer *cpCollisionHandler as CollisionHandlerPtr -> CollisionHandler #}++-- | Add a 'CollisionHandler' for specific collision type pair or return the existing handler for the type pair.+-- Whenever shapes with collision types (cpShape.collision_type) a and b collide,+-- this handler will be used to process the collision events. When a new collision handler is created,+-- the callbacks will all be set to builtin callbacks that perform the default behavior+-- (call the wildcard handlers, and accept all collisions).+{# fun unsafe cpSpaceAddCollisionHandler as spaceAddCollisionHandler+  { `Space'+  , fromIntegral `CollisionType' -- ^ a+  , fromIntegral `CollisionType' -- ^ b+  } -> `CollisionHandlerPtr' #}++-- | Add a wildcard collision handler for given collision type. This handler will be used any time an object+-- with this type collides with another object, regardless of its type. A good example is a projectile+-- that should be destroyed the first time it hits anything. There may be a specific collision handler+-- and two wildcard handlers. It’s up to the specific handler to decide if and when to call the wildcard handlers+-- and what to do with their return values. (See arbiterCallWildcard* below)+-- When a new wildcard handler is created, the callbacks will all be set to builtin callbacks+-- that perform the default behavior. (accept all collisions in begin and preSolve, or do nothing for postSolve+-- and separate.+{# fun unsafe cpSpaceAddWildcardHandler as spaceAddWildcardHandler+  { `Space'+  , fromIntegral `CollisionType' -- ^ type+  } -> `CollisionHandlerPtr' #}++-- | Return a reference to the default collision handler or that is used to process all collisions+-- that don’t have a more specific handler. The default behavior for each of the callbacks+-- is to call the wildcard handlers, ANDing their return values together if applicable.+{# fun unsafe cpSpaceAddDefaultCollisionHandler as spaceAddDefaultCollisionHandler+  { `Space'+  } -> `CollisionHandlerPtr' #}++-- | Use this helper function to modify collision handler.+--+-- @+-- spaceAddCollisionHandler s t1 t2 >>= flip modifyColliionHandler (\ch -> pure ch {chSeparateFunc = separateCollback})+-- @+modifyCollisionHandler :: CollisionHandlerPtr -> (CollisionHandler -> IO CollisionHandler) -> IO ()+modifyCollisionHandler chPtr inner = peek chPtr >>= inner >>= poke chPtr++-- | Function type used for postStep callbacks. @space@ is the space the callback was registered on,+-- @obj@ is the pointer value you supplied as the key, and @data@ is a user definable pointer you can use+-- to pass in as a context value.+type PostStepFunc+  = Space   -- ^ space+  -> Ptr () -- ^ obj+  -> Ptr () -- ^ data+  -> IO ()++foreign import ccall "wrapper"+  mkPostStep :: PostStepFunc -> IO (FunPtr PostStepFunc)++-- | Add @func@ to be called before 'spaceStep' returns. @key@ and @data@ will be passed to your function.+-- Only the first callback registered for any unique value of @key@ will be recorded.+--+-- It returns 'True' if the callback is scheduled and 'False' when the key has already been used.+--+-- __The behavior of adding a postStep callback from outside of a collision handler or query callback is undefined.__+{# fun unsafe cpSpaceAddPostStepCallback as spaceAddPostStepCallback+  { `Space'            -- ^ space+  , mk* `PostStepFunc' -- ^ func+  , `Ptr ()'           -- ^ key+  , `Ptr ()'           -- ^ data+  } -> `Bool' #}+  where+    mk f = mkPostStep f `bracket` freeHaskellFunPtr
+ src/Chiphunk/Low/Constraint.chs view
@@ -0,0 +1,467 @@+-- | Description: Dealing with joints/constraints+-- Module defines utilities for operations with constraints.+module Chiphunk.Low.Constraint+  ( Constraint+  , constraintBodyA+  , constraintBodyB+  , constraintMaxForce+  , constraintErrorBias+  , constraintMaxBias+  , constraintSpace+  , constraintCollideBodies+  , constraintUserData+  , constraintImpulse+  , constraintFree+  , pinJointNew+  , pinJointAnchorA+  , pinJointAnchorB+  , pinJointDist+  , slideJointNew+  , slideJointAnchorA+  , slideJointAnchorB+  , slideJointMin+  , slideJointMax+  , pivotJointNew+  , pivotJointNew2+  , pivotJointAnchorA+  , pivotJointAnchorB+  , grooveJointNew+  , grooveJointGrooveA+  , grooveJointGrooveB+  , grooveJointAnchorB+  , dampedSpringNew+  , dampedSpringAnchorA+  , dampedSpringAnchorB+  , dampedSpringRestLength+  , dampedSpringStiffness+  , dampedSpringDamping+  , dampedRotarySpringNew+  , dampedRotarySpringRestAngle+  , dampedRotarySpringStiffness+  , dampedRotarySpringDamping+  , rotaryLimitJointNew+  , rotaryLimitJointMin+  , rotaryLimitJointMax+  , ratchetJointNew+  , ratchetJointAngle+  , ratchetJointPhase+  , ratchetJointRatchet+  , gearJointNew+  , gearJointPhase+  , gearJointRatio++  , simpleMotorNew+  , simpleMotorRate+  ) where++import Data.StateVar+import Foreign++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++{# fun unsafe cpConstraintGetBodyA {`Constraint'} -> `Body' #}++-- | The first body constraint is attached to+constraintBodyA :: Constraint -> GettableStateVar Body+constraintBodyA = makeGettableStateVar . cpConstraintGetBodyA++{# fun unsafe cpConstraintGetBodyB {`Constraint'} -> `Body' #}++-- | The second body constraint is attached to+constraintBodyB :: Constraint -> GettableStateVar Body+constraintBodyB = makeGettableStateVar . cpConstraintGetBodyB++{# fun unsafe cpConstraintGetMaxForce {`Constraint'} -> `Double' #}++{# fun unsafe cpConstraintSetMaxForce {`Constraint', `Double'} -> `()' #}++-- | The maximum force that the constraint can use to act on the two bodies.+-- Defaults to INFINITY.+constraintMaxForce :: Constraint -> StateVar Double+constraintMaxForce = mkStateVar cpConstraintGetMaxForce cpConstraintSetMaxForce++{# fun unsafe cpConstraintGetErrorBias {`Constraint'} -> `Double' #}++{# fun unsafe cpConstraintSetErrorBias {`Constraint', `Double'} -> `()' #}++-- | The percentage of joint error that remains unfixed after a second.+-- This works exactly the same as the collision bias property of a space,+-- but applies to fixing error (stretching) of joints instead of overlapping collisions.+constraintErrorBias :: Constraint -> StateVar Double+constraintErrorBias = mkStateVar cpConstraintGetErrorBias cpConstraintSetErrorBias++{# fun unsafe cpConstraintGetMaxBias {`Constraint'} -> `Double' #}++{# fun unsafe cpConstraintSetMaxBias {`Constraint', `Double'} -> `()' #}++-- | Get the maximum speed at which the constraint can apply error correction.+-- Defaults to INFINITY.+constraintMaxBias :: Constraint -> StateVar Double+constraintMaxBias = mkStateVar cpConstraintGetMaxBias cpConstraintSetMaxBias++{# fun unsafe cpConstraintGetSpace {`Constraint'} -> `Space' #}++-- | The 'Space' that constraint has been added to.+constraintSpace :: Constraint -> GettableStateVar Space+constraintSpace = makeGettableStateVar . cpConstraintGetSpace++{# fun unsafe cpConstraintGetCollideBodies {`Constraint'} -> `Bool' #}++{# fun unsafe cpConstraintSetCollideBodies {`Constraint', `Bool'} -> `()' #}++-- | Constraints can be used for filtering collisions too.+-- When two bodies collide, Chipmunk ignores the collisions+-- if this property is set to @False@ on any constraint that connects the two bodies.+-- Defaults to @True@.+--+-- This can be used to create a chain that self collides,+-- but adjacent links in the chain do not collide.+constraintCollideBodies :: Constraint -> StateVar Bool+constraintCollideBodies = mkStateVar cpConstraintGetCollideBodies cpConstraintSetCollideBodies++{# fun unsafe cpConstraintGetUserData {`Constraint'} -> `DataPtr' #}++{# fun unsafe cpConstraintSetUserData {`Constraint', `DataPtr'} -> `()' #}++-- | A user definable data pointer.+-- Use this pointer to get a reference to the game object that owns this constraint+-- from callbacks.+constraintUserData :: Constraint -> StateVar DataPtr+constraintUserData = mkStateVar cpConstraintGetUserData cpConstraintSetUserData++{# fun unsafe cpConstraintGetImpulse {`Constraint'} -> `Double' #}++-- | The most recent impulse that constraint applied.+-- To convert this to a force, divide by the timestep passed to 'spaceStep'.+-- You can use this to implement breakable joints to check+-- if the force they attempted to apply exceeded a certain threshold.+constraintImpulse :: Constraint -> GettableStateVar Double+constraintImpulse = makeGettableStateVar . cpConstraintGetImpulse++-- | Free function is shared by all joint types. Allocation functions are specific to each joint type.+{# fun cpConstraintFree as constraintFree {`Constraint'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger separte callbacks++-- | Connect two bodies via anchor points on those bodies. The distance between the two anchor points is measured+-- when the joint is created. If you want to set a specific distance, use the setter function to override it.+{# fun unsafe cpPinJointNew as pinJointNew+  { `Body'        -- ^ First body to connect+  , `Body'        -- ^ Second body to connect+  , with* %`Vect' -- ^ First anchor+  , with* %`Vect' -- ^ Second anchor+  } -> `Constraint' #}++{# fun unsafe w_cpPinJointGetAnchorA {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpPinJointSetAnchorA {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on first body.+pinJointAnchorA :: Constraint -> StateVar Vect+pinJointAnchorA = mkStateVar w_cpPinJointGetAnchorA cpPinJointSetAnchorA++{# fun unsafe w_cpPinJointGetAnchorB {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpPinJointSetAnchorB {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on second body.+pinJointAnchorB :: Constraint -> StateVar Vect+pinJointAnchorB = mkStateVar w_cpPinJointGetAnchorB cpPinJointSetAnchorB++{# fun unsafe cpPinJointGetDist {`Constraint'} -> `Double' #}++{# fun unsafe cpPinJointSetDist {`Constraint', `Double'} -> `()' #}++-- | Desired distance the joint will try to enforce.+pinJointDist :: Constraint -> StateVar Double+pinJointDist = mkStateVar cpPinJointGetDist cpPinJointSetDist++-- | Connect two bodies via anchor points forcing distance to remain in range.+{# fun unsafe cpSlideJointNew as slideJointNew+  { `Body'        -- ^ First body to connect+  , `Body'        -- ^ Second body to connect+  , with* %`Vect' -- ^ First anchor+  , with* %`Vect' -- ^ Second anchor+  , `Double'      -- ^ Minimum allowed distance+  , `Double'      -- ^ Maximum allowed distance+  } -> `Constraint' #}++{# fun unsafe w_cpSlideJointGetAnchorA {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpSlideJointSetAnchorA  {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on first body.+slideJointAnchorA :: Constraint -> StateVar Vect+slideJointAnchorA = mkStateVar w_cpSlideJointGetAnchorA cpSlideJointSetAnchorA++{# fun unsafe w_cpSlideJointGetAnchorB {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpSlideJointSetAnchorB {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on second body.+slideJointAnchorB :: Constraint -> StateVar Vect+slideJointAnchorB = mkStateVar w_cpSlideJointGetAnchorB cpSlideJointSetAnchorB++{# fun unsafe cpSlideJointGetMin {`Constraint'} -> `Double' #}++{# fun unsafe cpSlideJointSetMin {`Constraint', `Double'} -> `()' #}++-- | The minimum distance the joint will try to enforce.+slideJointMin :: Constraint -> StateVar Double+slideJointMin = mkStateVar cpSlideJointGetMin cpSlideJointSetMin++{# fun unsafe cpSlideJointGetMax {`Constraint'} -> `Double' #}++{# fun unsafe cpSlideJointSetMax {`Constraint', `Double'} -> `()' #}++-- | The maximum distance the joint will try to enforce.+slideJointMax :: Constraint -> StateVar Double+slideJointMax = mkStateVar cpSlideJointGetMax cpSlideJointSetMax++-- | Because the pivot location is given in world coordinates,+-- you must have the bodies moved into the correct positions already.+{# fun unsafe cpPivotJointNew as pivotJointNew+  { `Body'        -- ^ First body to connect+  , `Body'        -- ^ Second body to connect+  , with* %`Vect' -- ^ Point in the world coordinates of the pivot+  } -> `Constraint' #}++-- | Alternatively you can specify the joint based on a pair of anchor points,+-- but make sure you have the bodies in the right place as the joint will fix itself+-- as soon as you start simulating the space.+{# fun unsafe cpPivotJointNew2 as pivotJointNew2+  { `Body'        -- ^ First body to connect+  , `Body'        -- ^ Second body to connect+  , with* %`Vect' -- ^ Anchor on first body+  , with* %`Vect' -- ^ Anchor on second body+  } -> `Constraint' #}++{# fun unsafe w_cpPivotJointGetAnchorA {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpPivotJointSetAnchorA {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on first body.+pivotJointAnchorA :: Constraint -> StateVar Vect+pivotJointAnchorA = mkStateVar w_cpPivotJointGetAnchorA cpPivotJointSetAnchorA++{# fun unsafe w_cpPivotJointGetAnchorB {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpPivotJointSetAnchorB {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on second body.+pivotJointAnchorB :: Constraint -> StateVar Vect+pivotJointAnchorB = mkStateVar w_cpPivotJointGetAnchorB cpPivotJointSetAnchorB++-- | Pivot is attached to groove on first body and to anchor on the second. All coordinates are body local.+{# fun unsafe cpGrooveJointNew as grooveJointNew+  { `Body'        -- ^ First body to connect+  , `Body'        -- ^ Second body to connect+  , with* %`Vect' -- ^ First endpoint of groove (on first body)+  , with* %`Vect' -- ^ Second endpoint of groove (on first body)+  , with* %`Vect' -- ^ Anchor (on second body)+  } -> `Constraint' #}++{# fun unsafe w_cpGrooveJointGetGrooveA {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpGrooveJointSetGrooveA {`Constraint', with* %`Vect'} -> `()' #}++-- | First endpoint of groove (on first body).+grooveJointGrooveA :: Constraint -> StateVar Vect+grooveJointGrooveA = mkStateVar w_cpGrooveJointGetGrooveA cpGrooveJointSetGrooveA++{# fun unsafe w_cpGrooveJointGetGrooveB {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpGrooveJointSetGrooveB {`Constraint', with* %`Vect'} -> `()' #}++-- | Second endpoint of groove (on first body).+grooveJointGrooveB :: Constraint -> StateVar Vect+grooveJointGrooveB = mkStateVar w_cpGrooveJointGetGrooveB cpGrooveJointSetGrooveB++{# fun unsafe w_cpGrooveJointGetAnchorB {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpGrooveJointSetAnchorB {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on second body.+grooveJointAnchorB :: Constraint -> StateVar Vect+grooveJointAnchorB = mkStateVar w_cpGrooveJointGetAnchorB cpGrooveJointSetAnchorB++-- | Defined much like a slide joint.+{# fun unsafe cpDampedSpringNew as dampedSpringNew+  { `Body'        -- ^ First body to connect+  , `Body'        -- ^ Second body to connect+  , with* %`Vect' -- ^ First anchor+  , with* %`Vect' -- ^ Second anchor+  , `Double'      -- ^ Distance the spring wants to be+  , `Double'      -- ^ Spring constant (<http://en.wikipedia.org/wiki/Young%27s_modulus Young's modulus>)+  , `Double'      -- ^ How soft to make damping of the spring+  } -> `Constraint' #}++{# fun unsafe w_cpDampedSpringGetAnchorA {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpDampedSpringSetAnchorA {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on first body.+dampedSpringAnchorA :: Constraint -> StateVar Vect+dampedSpringAnchorA = mkStateVar w_cpDampedSpringGetAnchorA cpDampedSpringSetAnchorA++{# fun unsafe w_cpDampedSpringGetAnchorB {`Constraint', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpDampedSpringSetAnchorB {`Constraint', with* %`Vect'} -> `()' #}++-- | Anchor on second body.+dampedSpringAnchorB :: Constraint -> StateVar Vect+dampedSpringAnchorB = mkStateVar w_cpDampedSpringGetAnchorB cpDampedSpringSetAnchorB++{# fun unsafe cpDampedSpringGetRestLength {`Constraint'} -> `Double' #}++{# fun unsafe cpDampedSpringSetRestLength {`Constraint', `Double'} -> `()' #}++-- | Desired distance the spring will try to enforce.+dampedSpringRestLength :: Constraint -> StateVar Double+dampedSpringRestLength = mkStateVar cpDampedSpringGetRestLength cpDampedSpringSetRestLength++{# fun unsafe cpDampedSpringGetStiffness {`Constraint'} -> `Double' #}++{# fun unsafe cpDampedSpringSetStiffness {`Constraint', `Double'} -> `()' #}++-- | Spring stiffness+dampedSpringStiffness :: Constraint -> StateVar Double+dampedSpringStiffness = mkStateVar cpDampedSpringGetStiffness cpDampedSpringSetStiffness++{# fun unsafe cpDampedSpringGetDamping {`Constraint'} -> `Double' #}++{# fun unsafe cpDampedSpringSetDamping {`Constraint', `Double'} -> `()' #}++-- | Spring damping+dampedSpringDamping :: Constraint -> StateVar Double+dampedSpringDamping = mkStateVar cpDampedSpringGetDamping cpDampedSpringSetDamping++-- | Create new damped rotary spring constraint+{# fun unsafe cpDampedRotarySpringNew as dampedRotarySpringNew+  { `Body'    -- ^ First body to connect+  , `Body'    -- ^ Second body to connect+  , `Double'  -- ^ Relative angle in radians that the bodies want to have+  , `Double'  -- ^ Spring constant (stiffness)+  , `Double'  -- ^ Spring damping+  } -> `Constraint' #}++{# fun unsafe cpDampedRotarySpringGetRestAngle {`Constraint'} -> `Double' #}++{# fun unsafe cpDampedRotarySpringSetRestAngle {`Constraint', `Double'} -> `()' #}++-- | Set desired angle in radians the spring will try to enforce.+dampedRotarySpringRestAngle :: Constraint -> StateVar Double+dampedRotarySpringRestAngle = mkStateVar cpDampedRotarySpringGetRestAngle cpDampedRotarySpringSetRestAngle++{# fun unsafe cpDampedRotarySpringGetStiffness {`Constraint'} -> `Double' #}++{# fun unsafe cpDampedRotarySpringSetStiffness {`Constraint', `Double'} -> `()' #}++-- | Spring stiffness.+dampedRotarySpringStiffness :: Constraint -> StateVar Double+dampedRotarySpringStiffness = mkStateVar cpDampedRotarySpringGetStiffness cpDampedRotarySpringSetStiffness++{# fun unsafe cpDampedRotarySpringGetDamping {`Constraint'} -> `Double' #}++{# fun unsafe cpDampedRotarySpringSetDamping {`Constraint', `Double'} -> `()' #}++-- | Spring damping.+dampedRotarySpringDamping :: Constraint -> StateVar Double+dampedRotarySpringDamping = mkStateVar cpDampedRotarySpringGetDamping cpDampedRotarySpringSetDamping++-- | Create new rotation limiting joint+{# fun unsafe cpRotaryLimitJointNew as rotaryLimitJointNew+  { `Body'    -- ^ First body to connect+  , `Body'    -- ^ Second body to connect+  , `Double'  -- ^ Minimum angle in radians the joint will enforce+  , `Double'  -- ^ Maximum angle in radians the joint will enforce+  } -> `Constraint' #}++{# fun unsafe cpRotaryLimitJointGetMin {`Constraint'} -> `Double' #}++{# fun unsafe cpRotaryLimitJointSetMin {`Constraint', `Double'} -> `()' #}++-- | Minimum angle in radians the joint will try to enforce.+rotaryLimitJointMin :: Constraint -> StateVar Double+rotaryLimitJointMin = mkStateVar cpRotaryLimitJointGetMin cpRotaryLimitJointSetMin++{# fun unsafe cpRotaryLimitJointGetMax {`Constraint'} -> `Double' #}++{# fun unsafe cpRotaryLimitJointSetMax {`Constraint', `Double'} -> `()' #}++-- | Maximum angle in radians the joint will try to enforce.+rotaryLimitJointMax :: Constraint -> StateVar Double+rotaryLimitJointMax = mkStateVar cpRotaryLimitJointGetMax cpRotaryLimitJointSetMax++-- | Allocate and initialize a ratchet joint.+{# fun unsafe cpRatchetJointNew as ratchetJointNew+  { `Body'    -- ^ First body to connect+  , `Body'    -- ^ Second body to connect+  , `Double'  -- ^ The initial offset to use when deciding where the ratchet angles are.+  , `Double'  -- ^ The distance between “clicks”+  } -> `Constraint' #}++{# fun unsafe cpRatchetJointGetAngle {`Constraint'} -> `Double' #}++{# fun unsafe cpRatchetJointSetAngle {`Constraint', `Double'} -> `()' #}++-- | The angle of the current ratchet tooth.+ratchetJointAngle :: Constraint -> StateVar Double+ratchetJointAngle = mkStateVar cpRatchetJointGetAngle cpRatchetJointSetAngle++{# fun unsafe cpRatchetJointGetPhase {`Constraint'} -> `Double' #}++{# fun unsafe cpRatchetJointSetPhase {`Constraint', `Double'} -> `()' #}++-- | The phase offset of the ratchet.+ratchetJointPhase :: Constraint -> StateVar Double+ratchetJointPhase = mkStateVar cpRatchetJointGetPhase cpRatchetJointSetPhase++{# fun unsafe cpRatchetJointGetRatchet {`Constraint'} -> `Double' #}++{# fun unsafe cpRatchetJointSetRatchet {`Constraint', `Double'} -> `()' #}++-- | The angular distance of each ratchet.+ratchetJointRatchet :: Constraint -> StateVar Double+ratchetJointRatchet = mkStateVar cpRatchetJointGetRatchet cpRatchetJointSetRatchet++-- | Allocate and initialize a gear joint.+{# fun unsafe cpGearJointNew as gearJointNew+  { `Body'    -- ^ First body to connect+  , `Body'    -- ^ Second body to connect+  , `Double'  -- ^ The initial angular offset of the two bodies.+  , `Double'  -- ^ Ratio measures in absolute terms+  } -> `Constraint' #}++{# fun unsafe cpGearJointGetPhase {`Constraint'} -> `Double' #}++{# fun unsafe cpGearJointSetPhase {`Constraint', `Double'} -> `()' #}++-- | Phase offset of the ratchet.+gearJointPhase :: Constraint -> StateVar Double+gearJointPhase = mkStateVar cpGearJointGetPhase cpGearJointSetPhase++{# fun unsafe cpGearJointGetRatio {`Constraint'} -> `Double' #}++{# fun unsafe cpGearJointSetRatio {`Constraint', `Double'} -> `()' #}++-- | Ratio of the ratchet+gearJointRatio :: Constraint -> StateVar Double+gearJointRatio = mkStateVar cpGearJointGetRatio cpGearJointSetRatio++-- | Allocate and initialize a simple motor.+{# fun unsafe cpSimpleMotorNew as simpleMotorNew+  { `Body'    -- ^ First body to connect+  , `Body'    -- ^ Second body to connect+  , `Double'  -- ^ The desired relative angular velocity.+  } -> `Constraint' #}++{# fun unsafe cpSimpleMotorGetRate {`Constraint'} -> `Double' #}++{# fun unsafe cpSimpleMotorSetRate {`Constraint', `Double'} -> `()' #}++-- | Ratio of angular velocities.+simpleMotorRate :: Constraint -> StateVar Double+simpleMotorRate = mkStateVar cpSimpleMotorGetRate cpSimpleMotorSetRate
+ src/Chiphunk/Low/Helper.chs view
@@ -0,0 +1,99 @@+-- | Description: Helpers functions mostly for estimating certain measures.+-- Module provides helper function mostly for estimating certain measures.+module Chiphunk.Low.Helper+  ( momentForCircle+  , momentForSegment+  , momentForPoly+  , momentForBox+  , areaForCircle+  , areaForSegment+  , areaForPoly+  , centroidForPoly+  , convexHull+  ) where++import Data.VectorSpace+import Foreign+import System.IO.Unsafe++import Chiphunk.Low.Internal++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++-- | Calculate the moment of inertia for a hollow circle, @r1@ and @r2@ are the inner and outer diameters+-- in no particular order. (A solid circle has an inner diameter of 0)+momentForCircle+  :: Double -- ^ Mass+  -> Double -- ^ r1+  -> Double -- ^ r2+  -> Vect   -- ^ Offset+  -> Double+momentForCircle m r1 r2 offs = m * (0.5 * (r1 * r1 + r2 * r2) + magnitudeSq offs)++-- | Calculate the moment of inertia for a line segment. The endpoints @a@ and @b@ are relative to the body.+momentForSegment+  :: Double -- ^ Mass+  -> Vect   -- ^ a+  -> Vect   -- ^ b+  -> Double -- ^ Thickness+  -> Double+momentForSegment m a b r = m * ((len * len + 4 * r * r) / 12 + magnitudeSq offs)+  where+    offs = lerp a b 0.5+    len  = magnitude (b ^-^ a) + 2 * r++-- | Calculate the moment of inertia for a solid polygon shape assuming its center of gravity is at its centroid.+-- The offset is added to each vertex.+{# fun pure unsafe cpMomentForPoly as momentForPoly+  { `Double'            -- ^ Mass+  , withList* `[Vect]'& -- ^ Vertexes+  , with* %`Vect'       -- ^ Offset+  , `Double'            -- ^ Thickness+  } -> `Double' #}++-- | Calculate the moment of inertia for a solid box centered on the body.+momentForBox+  :: Double -- ^ Mass+  -> Double -- ^ Width+  -> Double -- ^ Height+  -> Double+momentForBox m w h = m * (w * w + h * h) / 12++-- | Area of a hollow circle.+areaForCircle+  :: Double -- ^ r1+  -> Double -- ^ r2+  -> Double+areaForCircle r1 r2 = pi * abs (r1 * r1 - r2 * r2)++-- | Area of a beveled segment. (Will always be zero if radius is zero)+areaForSegment+  :: Vect   -- ^ One end+  -> Vect   -- ^ Other end+  -> Double -- ^ Thickness+  -> Double+areaForSegment v1 v2 r = magnitude (v1 ^-^ v2) * 2 * r + pi * r * r++-- | Signed area of a polygon shape. Returns a negative number for polygons with a clockwise winding.+{# fun pure unsafe cpAreaForPoly as areaForPoly+  { withList* `[Vect]'& -- ^ Vertexes+  , `Double'            -- ^ Thickness+  } -> `Double' #}++-- | Calculate the centroid for a polygon.+{# fun pure unsafe w_cpCentroidForPoly as centroidForPoly {withList* `[Vect]'&, alloca- `Vect' peek*} -> `()' #}++-- | Calculate the convex hull of a given set of points.+convexHull+  :: [Vect]        -- ^ Set of vertexes+  -> Double        -- ^ Allowed amount to shrink the hull when simplifying it. A tolerance of 0 creates an exact hull.+  -> ([Vect], Int) -- ^ Second element is index of first output vertex in input list.+convexHull vs tol = unsafePerformIO $+  withArray vs $ \pVs ->+  allocaArray (length vs) $ \pRes ->+  alloca $ \pFst -> do+    n <- {# call cpConvexHull as c_convexHull #} (fromIntegral $ length vs) pVs pRes pFst (realToFrac tol)+    (,) <$> peekArray (fromIntegral n) pRes <*> (fromIntegral <$> peek pFst)
+ src/Chiphunk/Low/Internal.hs view
@@ -0,0 +1,9 @@+module Chiphunk.Low.Internal where++import Foreign+import Foreign.C.Types++-- | Internal helper function to convert list of storable elements to tuple of length and elements stored in memory+-- and executes IO actions, cleaning up afterwards.+withList :: Storable a => [a] -> ((CInt, Ptr a) -> IO b) -> IO b+withList xs inner = withArray xs $ \p -> inner (fromIntegral $ length xs, castPtr p)
+ src/Chiphunk/Low/Math.hs view
@@ -0,0 +1,32 @@+-- | Description: Math helpers.+-- Module provides mathematics helper functions.+module Chiphunk.Low.Math where++import Data.VectorSpace++-- | Clamp @f@ to be between @min@ and @max@+fClamp+  :: Double -- ^ f+  -> Double -- ^ min+  -> Double -- ^ max+  -> Double+fClamp x a b+  | x < a     = a+  | x > b     = b+  | otherwise = x++-- | Linearly interpolate between @f1@ and @f2@+fLerp+  :: Double -- ^ f1+  -> Double -- ^ f2+  -> Double+  -> Double+fLerp = lerp++-- | Linearly interpolate from @f1@ towards @f2@ by no more than @d@.+fLerpConst+  :: Double -- ^ f1+  -> Double -- ^ f2+  -> Double -- ^ d+  -> Double+fLerpConst x y d = x + fClamp (y - x) (-d) d
+ src/Chiphunk/Low/Shape.chs view
@@ -0,0 +1,226 @@+-- | Description: Shapes manipulations+-- Module provides access to the shapes which define collisions of rigid bodies.+module Chiphunk.Low.Shape+  ( Shape+  , shapeBody+  , shapeBB+  , shapeSensor+  , shapeElasticity+  , shapeFriction+  , shapeSurfaceVelocity+  , shapeCollisionType+  , ShapeFilter (..)+  , ShapeFilterPtr+  , shapeFilter+  , shapeSpace+  , shapeUserData+  , shapeFree+  , shapeCacheBB+  , shapeUpdate+  , circleShapeNew+  , segmentShapeNew+  , segmentShapeNeighbors+  , polyShapeNew+  , polyShapeNewRaw+  , boxShapeNew+  , boxShapeNew2+  ) where++import Foreign++import Chiphunk.Low.Internal+import Data.StateVar++{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++{# fun unsafe cpShapeGetBody {`Shape'} -> `Body' #}++{# fun unsafe cpShapeSetBody {`Shape', `Body'} -> `()' #}++-- | The rigid body the shape is attached to.+-- Can only be set when the shape is not added to a space.+shapeBody :: Shape -> StateVar Body+shapeBody = mkStateVar cpShapeGetBody cpShapeSetBody++{# fun unsafe w_cpShapeGetBB {`Shape', alloca- `BB' peek*} -> `()' #}++-- | The bounding box of the shape.+-- Only guaranteed to be valid after 'shapeCacheBB' or 'spaceStep' is called.+-- Moving a body that a shape is connected to does not update its bounding box.+-- For shapes used for queries that aren’t attached to bodies, you can also use 'shapeUpdate'.+shapeBB :: Shape -> GettableStateVar BB+shapeBB = makeGettableStateVar . w_cpShapeGetBB++{# fun unsafe cpShapeGetSensor {`Shape'} -> `Bool' #}++{# fun unsafe cpShapeSetSensor {`Shape', `Bool'} -> `()' #}++-- | A boolean value if this shape is a sensor or not.+-- Sensors only call collision callbacks, and never generate real collisions.+shapeSensor :: Shape -> StateVar Bool+shapeSensor = mkStateVar cpShapeGetSensor cpShapeSetSensor++{# fun unsafe cpShapeGetElasticity {`Shape'} -> `Double' #}++{# fun unsafe cpShapeSetElasticity {`Shape', `Double'} -> `()' #}++-- | Elasticity of the shape.+-- A value of 0.0 gives no bounce, while a value of 1.0 will give a “perfect” bounce.+-- However due to inaccuracies in the simulation using 1.0 or greater is not recommended however.+--+-- The elasticity for a collision is found by multiplying the elasticity of the individual shapes together.+shapeElasticity :: Shape -> StateVar Double+shapeElasticity = mkStateVar cpShapeGetElasticity cpShapeSetElasticity++{# fun unsafe cpShapeGetFriction {`Shape'} -> `Double' #}++{# fun unsafe cpShapeSetFriction {`Shape', `Double'} -> `()' #}++-- | Friction coefficient.+-- Chipmunk uses the Coulomb friction model, a value of 0.0 is frictionless.+--+-- The friction for a collision is found by multiplying the friction of the individual shapes together.+-- <http://www.roymech.co.uk/Useful_Tables/Tribology/co_of_frict.htm Table of friction coefficients.>+shapeFriction :: Shape -> StateVar Double+shapeFriction = mkStateVar cpShapeGetFriction cpShapeSetFriction++{# fun unsafe w_cpShapeGetSurfaceVelocity {`Shape', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpShapeSetSurfaceVelocity {`Shape', with* %`Vect'} -> `()' #}++-- | The surface velocity of the object.+-- Useful for creating conveyor belts or players that move around.+-- This value is only used when calculating friction, not resolving the collision.+shapeSurfaceVelocity :: Shape -> StateVar Vect+shapeSurfaceVelocity = mkStateVar w_cpShapeGetSurfaceVelocity cpShapeSetSurfaceVelocity++{# fun unsafe cpShapeGetCollisionType {`Shape'} -> `CollisionType' fromIntegral #}++{# fun unsafe cpShapeSetCollisionType {`Shape', fromIntegral `CollisionType'} -> `()' #}++-- | Collision type of this shape.+-- | You can assign types to Chipmunk collision shapes+-- that trigger callbacks when objects of certain types touch.+-- See the callbacks section for more information.+shapeCollisionType :: Shape -> StateVar CollisionType+shapeCollisionType = mkStateVar cpShapeGetCollisionType cpShapeSetCollisionType++-- | Fast collision filtering type that is used to determine if two objects collide+-- before calling collision or query callbacks.+data ShapeFilter = ShapeFilter+  { sfGroup :: !WordPtr+  , sfCategories :: !Word32+  , sfMask :: !Word32+  } deriving Show++instance Storable ShapeFilter where+  sizeOf _    = {# sizeof cpShapeFilter #}+  alignment _ = {# alignof cpShapeFilter #}+  poke p (ShapeFilter g c m) = do+    {# set cpShapeFilter->group #} p      $ fromIntegral g+    {# set cpShapeFilter->categories #} p $ fromIntegral c+    {# set cpShapeFilter->mask #} p       $ fromIntegral m+  peek p = ShapeFilter <$> (fromIntegral <$> {# get cpShapeFilter->group #} p)+                       <*> (fromIntegral <$> {# get cpShapeFilter->categories #} p)+                       <*> (fromIntegral <$> {# get cpShapeFilter->mask #} p)++-- | Pointer to 'ShapeFilter'+{# pointer *cpShapeFilter as ShapeFilterPtr -> ShapeFilter #}++{# fun unsafe w_cpShapeGetFilter {`Shape', alloca- `ShapeFilter' peek*} -> `()' #}++{# fun unsafe cpShapeSetFilter {`Shape', with* %`ShapeFilter'} -> `()' #}++-- | The collision filter for this shape. See Filtering Collisions for more information.+shapeFilter :: Shape -> StateVar ShapeFilter+shapeFilter = mkStateVar w_cpShapeGetFilter cpShapeSetFilter++{# fun unsafe cpShapeGetSpace {`Shape'} -> `Space' #}++-- | The 'Space' that @shape@ has been added to.+shapeSpace :: Shape -> GettableStateVar Space+shapeSpace = makeGettableStateVar . cpShapeGetSpace++{# fun unsafe cpShapeGetUserData {`Shape'} -> `DataPtr' #}++{# fun unsafe cpShapeSetUserData {`Shape', `DataPtr'} -> `()' #}++-- | A user definable data pointer.+-- If you set this to point at the game object the shapes is for,+-- then you can access your game object from Chipmunk callbacks.+shapeUserData :: Shape -> StateVar DataPtr+shapeUserData = mkStateVar cpShapeGetUserData cpShapeSetUserData++-- | Deallocates shape.+{# fun cpShapeFree as shapeFree {`Shape'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger separte callbacks++-- | Synchronizes @shape@ with the body its attached to.+{# fun unsafe w_cpShapeCacheBB as shapeCacheBB+  { `Shape'            -- ^ shape+  , alloca- `BB' peek*+  } -> `()' #}++-- | Sets the position and rotation of the shape+{# fun unsafe w_cpShapeUpdate as shapeUpdate+  { `Shape'            -- ^ @shape@+  , with* %`Transform'+  , alloca- `BB' peek*+  } -> `()' #}++-- | Create new circle-like shape.+{# fun unsafe cpCircleShapeNew as circleShapeNew+  { `Body'        -- ^ The body to attach the circle to.+  , `Double'      -- ^ Radius of the circle.+  , with* %`Vect' -- ^ Offset from the body's center of gravity in body local coordinates.+  } -> `Shape' #}++-- | Create new segment-shaped shape.+{# fun unsafe cpSegmentShapeNew as segmentShapeNew+  { `Body'        -- ^ The body to attach the segment to.+  , with* %`Vect' -- ^ One endpoint.+  , with* %`Vect' -- ^ Another endpoint.+  , `Double'      -- ^ The thickness of the segment.+  } -> `Shape' #}++{# fun unsafe cpSegmentShapeSetNeighbors {`Shape', with* %`Vect', with* %`Vect'} -> `()' #}++-- | When you have a number of segment shapes that are all joined together,+-- things can still collide with the “cracks” between the segments.+-- By setting the neighbor segment endpoints+-- you can tell Chipmunk to avoid colliding with the inner parts of the crack.+segmentShapeNeighbors :: Shape -> SettableStateVar (Vect, Vect)+segmentShapeNeighbors shape =+  makeSettableStateVar $ \(v1, v2) ->+    cpSegmentShapeSetNeighbors shape v1 v2++-- | A convex hull will be calculated from the vertexes automatically.+-- The polygon shape will be created with a radius, increasing the size of the shape.+{# fun unsafe cpPolyShapeNew as polyShapeNew+  { `Body'              -- ^ The body to attach the poly to.+  , withList* `[Vect]'& -- ^ The array of 'Vect' structs.+  , with* %`Transform'  -- ^ The transform that will be applied to every vertex.+  , `Double'            -- ^ Radius.+  } -> `Shape' #}++-- | Alternate constructors for poly shapes. This version does not apply a transform nor does it create a convex hull.+-- Verticies must be provided with a counter-clockwise winding.+{# fun unsafe cpPolyShapeNewRaw as polyShapeNewRaw {`Body', withList* `[Vect]'&, `Double'} -> `Shape' #}++-- | Createa box shape from dimensions.+{# fun unsafe cpBoxShapeNew as boxShapeNew+  { `Body'    -- ^ The body to attach to+  , `Double'  -- ^ Box width+  , `Double'  -- ^ Box height+  , `Double'  -- ^ Radius+  } -> `Shape' #}++-- | Alternative to 'boxShapeNew' using 'BB' to set size.+{# fun unsafe cpBoxShapeNew2 as boxShapeNew2+  { `Body'      -- ^ The body to attach to+  , with* %`BB' -- ^ Shape size+  , `Double'    -- ^ Radius+  } -> `Shape' #}
+ src/Chiphunk/Low/Space.chs view
@@ -0,0 +1,266 @@+-- | Description: Manipulate space+-- Module defined utilities for manipulating spaces.+module Chiphunk.Low.Space+  ( Space+  , spaceIterations+  , spaceGravity+  , spaceDamping+  , spaceIdleSpeedThreshold+  , spaceSleepTimeThreshold+  , spaceCollisionSlop+  , spaceCollisionBias+  , spaceCollisionPersistence+  , spaceCurrentTimeStep+  , spaceIsLocked+  , spaceUserData+  , spaceStaticBody+  , spaceNew+  , spaceFree+  , spaceAddShape+  , spaceAddBody+  , spaceAddConstraint+  , spaceRemoveShape+  , spaceRemoveBody+  , spaceRemoveConstraint+  , spaceContainsShape+  , spaceContainsBody+  , spaceContainsConstraint+  , spaceReindexShape+  , spaceReindexShapesForBody+  , spaceReindexStatic+  , SpaceBodyIteratorFunc+  , spaceEachBody+  , SpaceShapeIteratorFunc+  , spaceEachShape+  , SpaceConstraintIteratorFunc+  , spaceEachConstraint+  , spaceStep+  ) where++import Control.Exception.Safe+import Data.StateVar+import Foreign++import Chiphunk.Low.Vect+{# import Chiphunk.Low.Types #}++#include <chipmunk/chipmunk.h>+#include <wrapper.h>++{# fun unsafe cpSpaceGetIterations {`Space'} -> `Int' #}++{# fun unsafe cpSpaceSetIterations {`Space', `Int'} -> `()' #}++-- | Iterations allow you to control the accuracy of the solver.+-- Defaults to 10. See above for more information.+spaceIterations :: Space -> StateVar Int+spaceIterations = mkStateVar cpSpaceGetIterations cpSpaceSetIterations++{# fun unsafe w_cpSpaceGetGravity {`Space', alloca- `Vect' peek*} -> `()' #}++{# fun unsafe cpSpaceSetGravity {`Space', with* %`Vect'} -> `()' #}++-- | Global gravity applied to the space. Defaults to 'vZero'.+-- Can be overridden on a per body basis by writing custom integration functions.+-- Changing the gravity will activate all sleeping bodies in the space.+spaceGravity :: Space -> StateVar Vect+spaceGravity = mkStateVar w_cpSpaceGetGravity cpSpaceSetGravity++{# fun unsafe cpSpaceGetDamping {`Space'} -> `Double' #}++{# fun unsafe cpSpaceSetDamping {`Space', `Double'} -> `()' #}++-- | Amount of simple damping to apply to the space.+-- A value of 0.9 means that each body will lose 10% of its velocity per second.+-- Defaults to 1. Like gravity, it can be overridden on a per body basis.+spaceDamping :: Space -> StateVar Double+spaceDamping = mkStateVar cpSpaceGetDamping cpSpaceSetDamping++{# fun unsafe cpSpaceGetIdleSpeedThreshold {`Space'} -> `Double' #}++{# fun unsafe cpSpaceSetIdleSpeedThreshold {`Space', `Double'} -> `()' #}++-- | Speed threshold for a body to be considered idle.+-- The default value of 0 means the space estimates a good threshold based on gravity.+spaceIdleSpeedThreshold :: Space -> StateVar Double+spaceIdleSpeedThreshold = mkStateVar cpSpaceGetIdleSpeedThreshold cpSpaceSetIdleSpeedThreshold++{# fun unsafe cpSpaceGetSleepTimeThreshold {`Space'} -> `Double' #}++{# fun unsafe cpSpaceSetSleepTimeThreshold {`Space', `Double'} -> `()' #}++-- | Time a group of bodies must remain idle in order to fall asleep.+-- The default value of INFINITY disables the sleeping feature.+spaceSleepTimeThreshold :: Space -> StateVar Double+spaceSleepTimeThreshold = mkStateVar cpSpaceGetSleepTimeThreshold cpSpaceSetSleepTimeThreshold++{# fun unsafe cpSpaceGetCollisionSlop {`Space'} -> `Double' #}++{# fun unsafe cpSpaceSetCollisionSlop {`Space', `Double'} -> `()' #}++-- | Amount of overlap between shapes that is allowed.+-- To improve stability, set this as high as you can without noticable overlapping.+-- It defaults to @0.1@.+spaceCollisionSlop :: Space -> StateVar Double+spaceCollisionSlop = mkStateVar cpSpaceGetCollisionSlop cpSpaceSetCollisionSlop++{# fun unsafe cpSpaceGetCollisionBias {`Space'} -> `Double' #}++{# fun unsafe cpSpaceSetCollisionBias {`Space', `Double'} -> `()' #}++-- | Chipmunk allows fast moving objects to overlap, then fixes the overlap over time.+-- Overlapping objects are unavoidable even if swept collisions are supported,+-- and this is an efficient and stable way to deal with overlapping objects.+-- The bias value controls what percentage of overlap remains unfixed+-- after a second and defaults to ~0.2%.+--+-- Valid values are in the range from 0 to 1,+-- but using 0 is not recommended for stability reasons.+--+-- The default value is calculated as @(1.0 - 0.1) ^ 60@+-- meaning that Chipmunk attempts to correct 10% of error ever 1/60th of a second.+--+-- __Note__: Very very few games will need to change this value.+spaceCollisionBias :: Space -> StateVar Double+spaceCollisionBias = mkStateVar cpSpaceGetCollisionBias cpSpaceSetCollisionBias++{# fun unsafe cpSpaceGetCollisionPersistence {`Space'} -> `Word32' #}++{# fun unsafe cpSpaceSetCollisionPersistence {`Space', `Word32'} -> `()' #}++-- | The number of frames the space keeps collision solutions around for.+-- Helps prevent jittering contacts from getting worse.+-- This defaults to 3 and very very very few games will need to change this value.+spaceCollisionPersistence :: Space -> StateVar Word32+spaceCollisionPersistence = mkStateVar cpSpaceGetCollisionPersistence cpSpaceSetCollisionPersistence++{# fun unsafe cpSpaceGetCurrentTimeStep {`Space'} -> `Double' #}++-- | The current (if you are in a callback from 'spaceStep')+-- or most recent (outside of a 'spaceStep' call) timestep.+spaceCurrentTimeStep :: Space -> GettableStateVar Double+spaceCurrentTimeStep = makeGettableStateVar . cpSpaceGetCurrentTimeStep++-- | Returns true when you cannot add/remove objects from the space.+-- In particular, spaces are locked when in a collision callback.+-- Instead, run your code in a post-step callback instead.+{# fun unsafe cpSpaceIsLocked as spaceIsLocked {`Space'} -> `Bool' #}++{# fun unsafe cpSpaceGetUserData {`Space'} -> `DataPtr' #}++{# fun unsafe cpSpaceSetUserData {`Space', `DataPtr'} -> `()' #}++-- | A user definable data pointer.+-- It is often useful to point this at the gamestate object+-- or scene management object that owns the space.+spaceUserData :: Space -> StateVar DataPtr+spaceUserData = mkStateVar cpSpaceGetUserData cpSpaceSetUserData++{# fun unsafe cpSpaceGetStaticBody {`Space'} -> `Body' #}++-- | A dedicated static body for the space.+-- You don’t have to use it,+-- but because its memory is managed automatically with the space its very convenient.+-- You can set its user data pointer to something helpful if you want for callbacks.+spaceStaticBody :: Space -> GettableStateVar Body+spaceStaticBody = makeGettableStateVar . cpSpaceGetStaticBody++-- | Standard Chipmunk allocation function.+{# fun unsafe cpSpaceNew as spaceNew {} -> `Space' #}++-- | Standard Chipmunk deallocation function.+{# fun cpSpaceFree as spaceFree {`Space'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger separte callbacks++-- | Add shape to the space.+{# fun unsafe cpSpaceAddShape as spaceAddShape {`Space', `Shape'} -> `()' #}++-- | Add body to the space.+{# fun unsafe cpSpaceAddBody as spaceAddBody {`Space', `Body'} -> `()' #}++-- | Add constraint to the space.+{# fun unsafe cpSpaceAddConstraint as spaceAddConstraint {`Space', `Constraint'} -> `()' #}++-- | Remove shape from the space.+{# fun cpSpaceRemoveShape as spaceRemoveShape {`Space', `Shape'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger separte callbacks++-- | Remove body from the space.+{# fun cpSpaceRemoveBody as spaceRemoveBody {`Space', `Body'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger separte callbacks++-- | Remove constraint from the space.+{# fun cpSpaceRemoveConstraint as spaceRemoveConstraint {`Space', `Constraint'} -> `()' #}+-- no "unsafe" qualifier because I think it may trigger separte callbacks++-- | Check if shape is attached to the space.+{# fun unsafe cpSpaceContainsShape as spaceContainsShape {`Space', `Shape'} -> `Bool' #}++-- | Check if body is attached to the space.+{# fun unsafe cpSpaceContainsBody as spaceContainsBody {`Space', `Body'} -> `Bool' #}++-- | Check if constraint is attached to the space.+{# fun unsafe cpSpaceContainsConstraint as spaceContainsConstraint {`Space', `Constraint'} -> `Bool' #}++-- | Reindex a specific shape.+{# fun unsafe cpSpaceReindexShape as spaceReindexShape {`Space', `Shape'} -> `()' #}++-- | Reindex all the shapes for a certain body.+{# fun unsafe cpSpaceReindexShapesForBody as spaceReindexShapesForBody {`Space', `Body'} -> `()' #}++-- | Reindex all static shapes. Generally updating only the shapes that changed is faster.+{# fun unsafe cpSpaceReindexStatic as spaceReindexStatic {`Space'} -> `()' #}++-- | Type of callback which can be used to iterate all 'Body's in a 'Space'.+type SpaceBodyIteratorFunc = Body -> Ptr () -> IO ()++foreign import ccall unsafe "wrapper"+  mkSpaceBodyIteratorFunc :: SpaceBodyIteratorFunc -> IO (FunPtr SpaceBodyIteratorFunc)++-- | Call @func@ for each body in the @space@ also passing along your @data@ pointer.+-- Sleeping bodies are included, but static and kinematic bodies are not as they aren’t added to the space.+{# fun cpSpaceEachBody as spaceEachBody+  { `Space'                               -- ^ space+  , withIterator* `SpaceBodyIteratorFunc' -- ^ func+  , `Ptr ()'                              -- ^ data+  } -> `()' #}+  where+    withIterator i = mkSpaceBodyIteratorFunc i `bracket` freeHaskellFunPtr++-- | Type of callback which can be used to iterate all 'Shape's in a 'Space'.+type SpaceShapeIteratorFunc = Shape -> Ptr () -> IO ()++foreign import ccall unsafe "wrapper"+  mkSpaceShapeIteratorFunc :: SpaceShapeIteratorFunc -> IO (FunPtr SpaceShapeIteratorFunc)++-- | Call @func@ for each shape in the @space@ also passing along your @data@ pointer.+-- Sleeping and static shapes are included.+{# fun cpSpaceEachShape as spaceEachShape+  { `Space'                                -- ^ space+  , withIterator* `SpaceShapeIteratorFunc' -- ^ func+  , `Ptr ()'                               -- ^ data+  } -> `()' #}+  where+    withIterator i = mkSpaceShapeIteratorFunc i `bracket` freeHaskellFunPtr++-- | Type of callback which can be used to iterate all 'Constraint's in a 'Space'.+type SpaceConstraintIteratorFunc = Constraint -> Ptr () -> IO ()++foreign import ccall unsafe "wrapper"+  mkSpaceConstraintIteratorFunc :: SpaceConstraintIteratorFunc -> IO (FunPtr SpaceConstraintIteratorFunc)++-- | Call func for each constraint in the space also passing along your data pointer.+{# fun cpSpaceEachConstraint as spaceEachConstraint+  { `Space'                                     -- ^ space+  , withIterator* `SpaceConstraintIteratorFunc' -- ^ func+  , `Ptr ()'                                    -- ^ data+  } -> `()' #}+  where+    withIterator i = mkSpaceConstraintIteratorFunc i `bracket` freeHaskellFunPtr++-- | Update the space for the given time step. Using a fixed time step is highly recommended.+-- Doing so can greatly increase the quality of the simulation.+-- The easiest way to do constant timesteps is to simple step forward by 1/60th of a second+-- (or whatever your target framerate is) for each frame regardless of how long it took to render.+-- This works fine for many games, but a better way to do it is to separate your physics timestep and rendering.+{# fun cpSpaceStep as spaceStep {`Space', `Double'} -> `()' #}
+ src/Chiphunk/Low/Types.chs view
@@ -0,0 +1,224 @@+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}++-- | Description: Basic Chipmunk data types.+-- Module provides basic Chipmunk data types.+module Chiphunk.Low.Types+  ( Vect (..)+  , VectPtr+  , BB (..)+  , BBPtr+  , DataPtr+  , Body (..)+  , BodyType (..)+  , Space (..)+  , Shape (..)+  , Constraint (..)+  , Arbiter (..)+  , Transform (..)+  , TransformPtr+  , CollisionType+  , CPBool+  , mkStateVar+  ) where++import Data.Cross+import Data.StateVar+import Data.VectorSpace+import Foreign++#include <chipmunk/chipmunk.h>++-- | 2D vector packed into a struct.+data Vect = Vect+  { vX :: !Double, vY :: !Double+  } deriving (Eq, Show)++instance AdditiveGroup Vect where+  zeroV = Vect 0 0+  negateV (Vect x y) = Vect (-x) (-y)+  Vect x1 y1 ^+^ Vect x2 y2 = Vect (x1 + x2) (y1 + y2)+  Vect x1 y1 ^-^ Vect x2 y2 = Vect (x1 - x2) (y1 - y2)++instance VectorSpace Vect where+  type Scalar Vect = Double+  f *^ Vect x y = Vect (f * x) (f * y)++instance InnerSpace Vect where+  Vect x1 y1 <.> Vect x2 y2 = x1 * x2 + y1 * y2++instance HasCross2 Vect where+  cross2 (Vect x y) = Vect (-y) x++instance Storable Vect where+  sizeOf _    = {# sizeof cpVect #}+  alignment _ = {# alignof cpVect #}+  poke p (Vect x y) = do+    {# set cpVect->x #} p $ realToFrac x+    {# set cpVect->y #} p $ realToFrac y+  peek p = Vect <$> (realToFrac <$> {# get cpVect->x #} p)+                <*> (realToFrac <$> {# get cpVect->y #} p)++-- | Pointer to vector.+{# pointer *cpVect as VectPtr -> Vect #}++-- | Simple bounding box struct. Stored as left, bottom, right, top values.+data BB = BB+  { bbL :: !Double, bbB :: !Double, bbR :: !Double, bbT :: !Double+  } deriving (Show)++instance Storable BB where+  sizeOf _    = {# sizeof cpBB #}+  alignment _ = {# alignof cpBB #}+  poke p (BB l b r t) = do+    {# set cpBB->l #} p $ realToFrac l+    {# set cpBB->b #} p $ realToFrac b+    {# set cpBB->r #} p $ realToFrac r+    {# set cpBB->t #} p $ realToFrac t+  peek p = BB <$> (realToFrac <$> {# get cpBB->l #} p)+              <*> (realToFrac <$> {# get cpBB->b #} p)+              <*> (realToFrac <$> {# get cpBB->r #} p)+              <*> (realToFrac <$> {# get cpBB->t #} p)++-- | Pointer to bounding box.+{# pointer *cpBB as BBPtr -> BB #}++-- | Pointer to user data.+{# pointer cpDataPointer as DataPtr #}++-- | Rigid body somewhere in C code.+{# pointer *cpBody as Body newtype #}++instance Storable Body where+  sizeOf (Body p)    = sizeOf p+  alignment (Body p) = alignment p+  poke p (Body b)    = poke (castPtr p) b+  peek p             = Body <$> peek (castPtr p)++-- | Chipmunk supports three different types of bodies with unique behavioral and performance characteristics.+data BodyType =+    BodyTypeDynamic+    -- ^ Dynamic bodies are the default body type.+    -- They react to collisions, are affected by forces and gravity, and have a finite amount of mass.+    -- These are the type of bodies that you want the physics engine to simulate for you.+    -- Dynamic bodies interact with all types of bodies and can generate collision callbacks.+  | BodyTypeKimenatic+    -- ^ Kinematic bodies are bodies that are controlled from your code instead of inside the physics engine.+    -- They arent affected by gravity+    -- and they have an infinite amount of mass so they don’t react to collisions or forces with other bodies.+    -- Kinematic bodies are controlled by setting their velocity, which will cause them to move.+    -- Good examples of kinematic bodies might include things like moving platforms.+    -- Objects that are touching or jointed to a kinematic body are never allowed to fall asleep.+  | BodyTypeStatic+    -- ^ Static bodies are bodies that never (or rarely) move.+    -- Using static bodies for things like terrain offers a big performance boost over other body types —+    -- because Chipmunk doesn’t need to check for collisions between static objects+    -- and it never needs to update their collision information.+    -- Additionally, because static bodies don’t move,+    -- Chipmunk knows it’s safe to let objects that are touching or jointed to them fall asleep.+    -- Generally all of your level geometry will be attached to a static body+    -- except for things like moving platforms or doors.+    -- Every space provide a built-in static body for your convenience.+    -- Static bodies can be moved, but there is a performance penalty as the collision information is recalculated.+    -- There is no penalty for having multiple static bodies, and it can be useful for simplifying your code+    -- by allowing different parts of your static geometry to be initialized or moved separately.++{# enum cpBodyType as BodyType nocode+  { CP_BODY_TYPE_DYNAMIC as BodyTypeDynamic+  , CP_BODY_TYPE_KINEMATIC as BodyTypeKimenatic+  , CP_BODY_TYPE_STATIC as BodyTypeStatic+  } #}++deriving instance Show BodyType++-- | Spaces in Chipmunk are the basic unit of simulation. You add rigid bodies, shapes, and constraints to the space+-- and then step them all forward through time together.+{# pointer *cpSpace as Space newtype #}++instance Storable Space where+  sizeOf (Space p)    = sizeOf p+  alignment (Space p) = alignment p+  poke p (Space b)    = poke (castPtr p) b+  peek p              = Space <$> peek (castPtr p)++-- | There are currently 3 collision shape types:+--+-- * __Circles__: Fastest and simplest collision shape.+--+-- * __Line segments__: Meant mainly as a static shape. Can be beveled in order to give them a thickness.+--+-- * __Convex polygons__: Slowest, but most flexible collision shape.+--+-- You can add as many shapes to a body as you wish. That is why the two types are separate.+--+-- Combining multiple shapes gives you the flexibility to make any object you want+-- as well as providing different areas of the same object with different friction, elasticity or callback values.+{# pointer *cpShape as Shape newtype #}++instance Storable Shape where+  sizeOf (Shape p)    = sizeOf p+  alignment (Shape p) = alignment p+  poke p (Shape b)    = poke (castPtr p) b+  peek p              = Shape <$> peek (castPtr p)++-- | A constraint is something that describes how two bodies interact with each other. (how they constrain each other)+-- Constraints can be simple joints that allow bodies to pivot around each other like the bones in your body,+-- or they can be more abstract like the gear joint or motors.+{# pointer *cpConstraint as Constraint newtype #}++instance Storable Constraint where+  sizeOf (Constraint p)    = sizeOf p+  alignment (Constraint p) = alignment p+  poke p (Constraint b)    = poke (castPtr p) b+  peek p                   = Constraint <$> peek (castPtr p)++-- | Chipmunk’s 'Arbiter' struct encapsulates a pair of colliding shapes and all of the data about their collision.+-- 'Arbiter' is created when a collision starts, and persist until those shapes are no longer colliding.+--+-- Why are they called arbiters? The short answer is that I kept using the word “arbitrates”+-- to describe the way that collisions were resolved and then I saw that Box2D actually called them arbiters+-- way back in 2006 when I was looking at its solver.+-- An arbiter is like a judge, a person that has authority to settle disputes between two people.+-- It was a fun, fitting name and was shorter to type than CollisionPair which I had been using.+-- It was originally meant to be a private internal structure only, but evolved to be useful from callbacks.+{# pointer *cpArbiter as Arbiter newtype #}++instance Storable Arbiter where+  sizeOf (Arbiter p)    = sizeOf p+  alignment (Arbiter p) = alignment p+  poke p (Arbiter b)    = poke (castPtr p) b+  peek p                = Arbiter <$> peek (castPtr p)++-- | Type used for 2×3 affine transforms in Chipmunk.+data Transform = Transform+  { tA :: !Double, tB :: !Double, tC :: !Double, tD :: !Double, tTx :: !Double, tTy :: !Double+  } deriving Show++instance Storable Transform where+  sizeOf _    = {# sizeof cpTransform #}+  alignment _ = {# alignof cpTransform #}+  poke p (Transform a b c d tx ty) = do+    {# set cpTransform->a #} p  $ realToFrac a+    {# set cpTransform->b #} p  $ realToFrac b+    {# set cpTransform->c #} p  $ realToFrac c+    {# set cpTransform->d #} p  $ realToFrac d+    {# set cpTransform->tx #} p $ realToFrac tx+    {# set cpTransform->ty #} p $ realToFrac ty+  peek p = Transform <$> (realToFrac <$> {# get cpTransform->a #} p)+                     <*> (realToFrac <$> {# get cpTransform->b #} p)+                     <*> (realToFrac <$> {# get cpTransform->c #} p)+                     <*> (realToFrac <$> {# get cpTransform->d #} p)+                     <*> (realToFrac <$> {# get cpTransform->tx #} p)+                     <*> (realToFrac <$> {# get cpTransform->ty #} p)++-- | Pointer to 'Transform'+{# pointer *cpTransform as TransformPtr -> Transform #}++-- | Collision type+type CollisionType = WordPtr++type CPBool = {# type cpBool #}++-- | 'makeStateVar' lifted to reader monad+mkStateVar :: (a -> IO b) -> (a -> b -> IO ()) -> a -> StateVar b+mkStateVar g s i = makeStateVar (g i) (s i)
+ src/Chiphunk/Low/Vect.chs view
@@ -0,0 +1,219 @@+-- | Description: 2D vector manipulations.+-- Module provides utilities to manipulate 2D vectors. Most of the code is re-implemented in Haskell (mirrorring C)+-- to avoid unnecessary foreign calls/marshalling, but only for simple operations.+--+-- Also note that 'Vect' has 'Eq', 'AdditiveGroup', 'VectorSpace', 'InnerSpace' and 'HasCross2' instances.+-- Large part of functions in this module just provides Chiphunk-compatible aliases for those instances' methods.+module Chiphunk.Low.Vect+  ( Vect (..)+  , cpv+  , vZero+  , vEql+  , vAdd+  , vSub+  , vNeg+  , vMult+  , vDot+  , vCross+  , vPerp+  , vRPerp+  , vProject+  , vRotate+  , vUnRotate+  , vLength+  , vLengthSq+  , vLerp+  , vLerpConst+  , vSLerp+  , vSLerpConst+  , vNormalize+  , vClamp+  , vDist+  , vDistSq+  , vNear+  , vForAngle+  , vToAngle+  ) where++import Data.Cross+import Data.VectorSpace+import Foreign++{# import Chiphunk.Low.Types #}++#include <wrapper.h>++-- | Convenience constructor for creating new cpVect structs.+-- Alias for 'Vect'+cpv :: Double -> Double -> Vect+cpv = Vect++-- | Constant for the zero vector.+--+-- Alias for 'zeroV'+vZero :: Vect+vZero = zeroV++-- | Check if two vectors are equal. (Be careful when comparing floating point numbers!)+--+-- Alias for '=='.+vEql :: Vect -> Vect -> Bool+vEql = (==)++-- | Add two vectors.+--+-- Alias for '^+^'.+vAdd :: Vect -> Vect -> Vect+vAdd = (^+^)++-- | Subtract two vectors.+--+-- Alias for '^-^'.+vSub :: Vect -> Vect -> Vect+vSub = (^-^)++-- | Negate a vector.+--+-- Alias for 'negateV'.+vNeg :: Vect -> Vect+vNeg = negateV++-- | Scalar multiplication.+--+-- Alias for '^*'.+vMult :: Vect -> Double -> Vect+vMult = (^*)++-- | Vector dot product.+--+-- Alias for '<.>'.+vDot :: Vect -> Vect -> Double+vDot = (<.>)++-- | 2D vector cross product analog. The cross product of 2D vectors results in a 3D vector with only a z component.+-- This function returns the value along the z-axis.+vCross :: Vect -> Vect -> Double+Vect x1 y1 `vCross` Vect x2 y2 = x1 * y2 - y1 * x2++-- | Returns a perpendicular vector. (90 degree rotation)+--+-- Alias for 'cross2'.+vPerp :: Vect -> Vect+vPerp = cross2++-- | Returns a perpendicular vector. (-90 degree rotation)+vRPerp :: Vect -> Vect+vRPerp v = negateV $ cross2 v++-- | Returns the vector projection of @v1@ onto @v2@.+--+-- Alias for 'project'.+vProject+  :: Vect -- ^ v1+  -> Vect -- ^ v2+  -> Vect+vProject = project++-- | Uses complex multiplication to rotate @v1@ by @v2@. Scaling will occur if @v1@ is not a unit vector.+vRotate+  :: Vect -- ^ v1+  -> Vect -- ^ v2+  -> Vect+Vect x1 y1 `vRotate` Vect x2 y2 = Vect (x1 * x2 - y1 * y2) (x1 * y2 + x2 * y1)++-- | Inverse of 'vRotate'.+vUnRotate :: Vect -> Vect -> Vect+Vect x1 y1 `vUnRotate` Vect x2 y2 = Vect (x1 * x2 + y1 * y2) (x2 * y1 - x1 * y2)++-- | Returns the length of v.+--+-- Alias for 'magnitude'.+vLength :: Vect -> Double+vLength = magnitude++-- | Returns the squared length of @v@. Faster than 'vLength' when you only need to compare lengths.+--+-- Alias for 'magnitudeSq'.+vLengthSq :: Vect -> Double+vLengthSq = magnitudeSq++-- | Linearly interpolate between @v1@ and @v2@.+--+-- Alias for 'lerp'.+vLerp+  :: Vect   -- ^ v1+  -> Vect   -- ^ v2+  -> Double+  -> Vect+vLerp = lerp++-- | Linearly interpolate between @v1@ towards @v2@ by distance @d@.+vLerpConst+  :: Vect   -- ^ v1+  -> Vect   -- ^ v2+  -> Double -- ^ d+  -> Vect+vLerpConst a b l = a ^+^ vClamp (b ^-^ a) l++-- | Spherical linearly interpolate between v1 and v2.+{# fun pure unsafe w_cpvslerp as vSLerp+  { with* %`Vect'        -- ^ v1+  , with* %`Vect'        -- ^ v2+  , `Double'+  , alloca- `Vect' peek*+  } -> `()' #}++-- | Spherical linearly interpolate between @v1@ towards @v2@ by no more than angle @a@ in radians.+{# fun pure unsafe w_cpvslerpconst as vSLerpConst+  { with* %`Vect'        -- ^ v1+  , with* %`Vect'        -- ^ v2+  , `Double'             -- ^ a+  , alloca- `Vect' peek*+  } -> `()' #}++-- | Returns a normalized copy of @v@. As a special case, it returns 'vZero' when called on 'vZero'.+--+-- Alias for 'normalized'.+vNormalize :: Vect -> Vect+vNormalize = normalized++-- | Clamp @v@ to length @len@.+vClamp+  :: Vect   -- ^ v+  -> Double -- ^ len+  -> Vect+vClamp v l+  | magnitudeSq v > l * l = l *^ normalized v+  | otherwise             = v++-- | Returns the distance between @v1@ and @v2@.+vDist+  :: Vect   -- ^ v1+  -> Vect   -- ^ v2+  -> Double+vDist v1 v2 = magnitude $ v1 ^-^ v2++-- | Returns the squared distance between @v1@ and @v2@. Faster than 'vDist' when you only need to compare distances.+vDistSq+  :: Vect   -- ^ v1+  -> Vect   -- ^ v2+  -> Double+vDistSq v1 v2 = magnitudeSq $ v1 ^-^ v2++-- | Returns true if the distance between @v1@ and @v2@ is less than @dist@.+vNear+  :: Vect   -- ^ v1+  -> Vect   -- ^ v2+  -> Double -- ^ dist+  -> Bool+vNear v1 v2 d = vDistSq v1 v2 < d * d++-- | Returns the unit length vector for the given angle (in radians).+vForAngle :: Double -> Vect+vForAngle alpha = Vect (cos alpha) (sin alpha)++-- | Returns the angular direction @v@ is pointing in (in radians).+vToAngle+  :: Vect   -- ^ v+  -> Double+vToAngle (Vect x y) = atan2 y x
+ src/Chiphunk/wrapper.c view
@@ -0,0 +1,176 @@+#include <wrapper.h>++void w_cpvslerp(cpVect v1, cpVect v2, cpFloat t, cpVect *out)+{+  *out = cpvslerp(v1, v2, t);+}++void w_cpvslerpconst(cpVect v1, cpVect v2, cpFloat a, cpVect *out)+{+  *out = cpvslerpconst(v1, v2, a);+}++void w_cpBodyGetPosition(const cpBody *body, cpVect *out)+{+  *out = cpBodyGetPosition(body);+}++void w_cpBodyGetCenterOfGravity(const cpBody *body, cpVect *out)+{+  *out = cpBodyGetCenterOfGravity(body);+}++void w_cpBodyGetVelocity(const cpBody *body, cpVect *out)+{+  *out = cpBodyGetVelocity(body);+}++void w_cpBodyGetForce(const cpBody *body, cpVect *out)+{+  *out = cpBodyGetForce(body);+}++void w_cpBodyGetRotation(const cpBody *body, cpVect *out)+{+  *out = cpBodyGetRotation(body);+}++void w_cpBodyLocalToWorld(const cpBody *body, cpVect point, cpVect *out)+{+  *out = cpBodyLocalToWorld(body, point);+}++void w_cpBodyWorldToLocal(const cpBody *body, cpVect point, cpVect *out)+{+  *out = cpBodyWorldToLocal(body, point);+}++void w_cpBodyGetVelocityAtWorldPoint(const cpBody *body, cpVect point, cpVect *out)+{+  *out = cpBodyGetVelocityAtWorldPoint(body, point);+}++void w_cpBodyGetVelocityAtLocalPoint(const cpBody *body, cpVect point, cpVect *out)+{+  *out = cpBodyGetVelocityAtLocalPoint(body, point);+}++void w_cpShapeGetBB(const cpShape *shape, cpBB *out)+{+  *out = cpShapeGetBB(shape);+}++void w_cpShapeGetSurfaceVelocity(const cpShape *shape, cpVect *out)+{+  *out = cpShapeGetSurfaceVelocity(shape);+}++void w_cpShapeGetFilter(const cpShape *shape, cpShapeFilter *out)+{+  *out = cpShapeGetFilter(shape);+}++void w_cpShapeCacheBB(cpShape *shape, cpBB *out)+{+  *out = cpShapeCacheBB(shape);+}++void w_cpShapeUpdate(cpShape *shape, cpTransform transform, cpBB *out)+{+  *out = cpShapeUpdate(shape, transform);+}++void w_cpCentroidForPoly(int count, const cpVect *vects, cpVect *out)+{+  *out = cpCentroidForPoly(count, vects);+}++cpFloat w_cpBBSegmentQuery(cpBB bb, cpVect a, cpVect b)+{+  return cpBBSegmentQuery(bb, a, b);+}++cpBool w_cpBBIntersectsSegment(cpBB bb, cpVect a, cpVect b)+{+  return cpBBIntersectsSegment(bb, a, b);+}++void w_cpSpaceGetGravity(cpSpace *space, cpVect *out)+{+  *out = cpSpaceGetGravity(space);+}++void w_cpPinJointGetAnchorA(const cpConstraint *constraint, cpVect *out)+{+  *out = cpPinJointGetAnchorA(constraint);+}++void w_cpPinJointGetAnchorB(const cpConstraint *constraint, cpVect *out)+{+  *out = cpPinJointGetAnchorB(constraint);+}++void w_cpSlideJointGetAnchorA(const cpConstraint *constraint, cpVect *out)+{+  *out = cpSlideJointGetAnchorA(constraint);+}++void w_cpSlideJointGetAnchorB(const cpConstraint *constraint, cpVect *out)+{+  *out = cpSlideJointGetAnchorB(constraint);+}++void w_cpPivotJointGetAnchorA(const cpConstraint *constraint, cpVect *out)+{+  *out = cpPivotJointGetAnchorA(constraint);+}++void w_cpPivotJointGetAnchorB(const cpConstraint *constraint, cpVect *out)+{+  *out = cpPivotJointGetAnchorB(constraint);+}++void w_cpGrooveJointGetGrooveA(const cpConstraint *constraint, cpVect *out)+{+  *out = cpGrooveJointGetGrooveA(constraint);+}++void w_cpGrooveJointGetGrooveB(const cpConstraint *constraint, cpVect *out)+{+  *out = cpGrooveJointGetGrooveB(constraint);+}++void w_cpGrooveJointGetAnchorB(const cpConstraint *constraint, cpVect *out)+{+  *out = cpGrooveJointGetAnchorB(constraint);+}++void w_cpDampedSpringGetAnchorA(const cpConstraint *constraint, cpVect *out)+{+  *out = cpDampedSpringGetAnchorA(constraint);+}++void w_cpDampedSpringGetAnchorB(const cpConstraint *constraint, cpVect *out)+{+  *out = cpDampedSpringGetAnchorB(constraint);+}++void w_cpArbiterGetSurfaceVelocity(cpArbiter *arbiter, cpVect *out)+{+  *out = cpArbiterGetSurfaceVelocity(arbiter);+}++void w_cpArbiterGetNormal(const cpArbiter *arbiter, cpVect *out)+{+  *out = cpArbiterGetNormal(arbiter);+}++void w_cpArbiterGetPointA(const cpArbiter *arbiter, int i, cpVect *out)+{+  *out = cpArbiterGetPointA(arbiter, i);+}++void w_cpArbiterGetPointB(const cpArbiter *arbiter, int i, cpVect *out)+{+  *out = cpArbiterGetPointB(arbiter, i);+}