Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added Chipmunk v5.3.2

Chipmunk template's updated
  • Loading branch information...
commit c2a449b166bd47d31700cc8def9ff1cad8aa157b 1 parent 299c5a3
@ricardoquesada ricardoquesada authored
Showing with 1,241 additions and 1,040 deletions.
  1. +3 −0  CHANGELOG
  2. +12 −0 cocos2d-ios.xcodeproj/project.pbxproj
  3. +14 −5 external/Chipmunk/include/chipmunk/chipmunk.h
  4. +10 −1 external/Chipmunk/include/chipmunk/chipmunk_ffi.h
  5. +8 −1 external/Chipmunk/include/chipmunk/constraints/cpConstraint.h
  6. +5 −1 external/Chipmunk/include/chipmunk/constraints/cpGrooveJoint.h
  7. +5 −5 external/Chipmunk/include/chipmunk/cpArbiter.h
  8. +21 −18 external/Chipmunk/include/chipmunk/cpBody.h
  9. +1 −1  external/Chipmunk/include/chipmunk/cpCollision.h
  10. +2 −2 external/Chipmunk/include/chipmunk/cpPolyShape.h
  11. +2 −2 external/Chipmunk/include/chipmunk/cpShape.h
  12. +6 −12 external/Chipmunk/include/chipmunk/cpSpace.h
  13. +1 −1  external/Chipmunk/include/chipmunk/cpSpaceHash.h
  14. +48 −4 external/Chipmunk/include/chipmunk/cpVect.h
  15. +2 −2 external/Chipmunk/src/chipmunk.c
  16. +25 −0 external/Chipmunk/src/constraints/cpGrooveJoint.c
  17. +21 −5 external/Chipmunk/src/cpBody.c
  18. +16 −18 external/Chipmunk/src/cpCollision.c
  19. +2 −2 external/Chipmunk/src/cpPolyShape.c
  20. +24 −23 external/Chipmunk/src/cpShape.c
  21. +16 −732 external/Chipmunk/src/cpSpace.c
  22. +237 −0 external/Chipmunk/src/cpSpaceComponent.c
  23. +67 −93 external/Chipmunk/src/cpSpaceHash.c
  24. +186 −0 external/Chipmunk/src/cpSpaceQuery.c
  25. +383 −0 external/Chipmunk/src/cpSpaceStep.c
  26. +124 −112 templates/cocos2d_chipmunk_app/___PROJECTNAME___.xcodeproj/project.pbxproj
View
3  CHANGELOG
@@ -1,3 +1,6 @@
+version 0.99.5-rc0 - XX-XXX-2010
+. [3RD] Chipmunk: Using version 5.3.2
+
version 0.99.5-beta3 23-Sep-2010
. [NEW] RetinaDisplay supported automatically:
Director: winSize returns size in Points. Use winSizeInPixels for pixels
View
12 cocos2d-ios.xcodeproj/project.pbxproj
@@ -2198,6 +2198,9 @@
E0B0E71111F8CF9F00414246 /* texture1024x1024.png in Resources */ = {isa = PBXBuildFile; fileRef = E0B0E70D11F8CF9F00414246 /* texture1024x1024.png */; };
E0B0E71211F8CF9F00414246 /* texture2048x2048.png in Resources */ = {isa = PBXBuildFile; fileRef = E0B0E70E11F8CF9F00414246 /* texture2048x2048.png */; };
E0B0E71311F8CF9F00414246 /* texture4096x4096.png in Resources */ = {isa = PBXBuildFile; fileRef = E0B0E70F11F8CF9F00414246 /* texture4096x4096.png */; };
+ E0B1E8021261F9E300ACD961 /* cpSpaceComponent.c in Sources */ = {isa = PBXBuildFile; fileRef = E0B1E7FF1261F9E300ACD961 /* cpSpaceComponent.c */; };
+ E0B1E8031261F9E300ACD961 /* cpSpaceQuery.c in Sources */ = {isa = PBXBuildFile; fileRef = E0B1E8001261F9E300ACD961 /* cpSpaceQuery.c */; };
+ E0B1E8041261F9E300ACD961 /* cpSpaceStep.c in Sources */ = {isa = PBXBuildFile; fileRef = E0B1E8011261F9E300ACD961 /* cpSpaceStep.c */; };
E0C3655B11F0AE9B001C08F9 /* CCSpriteBatchNode.h in Headers */ = {isa = PBXBuildFile; fileRef = E0C3655911F0AE9B001C08F9 /* CCSpriteBatchNode.h */; };
E0C3655C11F0AE9B001C08F9 /* CCSpriteBatchNode.m in Sources */ = {isa = PBXBuildFile; fileRef = E0C3655A11F0AE9B001C08F9 /* CCSpriteBatchNode.m */; };
E0C54DCA11F9CF2700B9E4CB /* ccUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = E0C54DC811F9CF2700B9E4CB /* ccUtils.c */; };
@@ -4088,6 +4091,9 @@
E0B0E70D11F8CF9F00414246 /* texture1024x1024.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = texture1024x1024.png; sourceTree = "<group>"; };
E0B0E70E11F8CF9F00414246 /* texture2048x2048.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = texture2048x2048.png; sourceTree = "<group>"; };
E0B0E70F11F8CF9F00414246 /* texture4096x4096.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = texture4096x4096.png; sourceTree = "<group>"; };
+ E0B1E7FF1261F9E300ACD961 /* cpSpaceComponent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSpaceComponent.c; sourceTree = "<group>"; };
+ E0B1E8001261F9E300ACD961 /* cpSpaceQuery.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSpaceQuery.c; sourceTree = "<group>"; };
+ E0B1E8011261F9E300ACD961 /* cpSpaceStep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cpSpaceStep.c; sourceTree = "<group>"; };
E0C3655911F0AE9B001C08F9 /* CCSpriteBatchNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CCSpriteBatchNode.h; sourceTree = "<group>"; };
E0C3655A11F0AE9B001C08F9 /* CCSpriteBatchNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CCSpriteBatchNode.m; sourceTree = "<group>"; };
E0C54DC811F9CF2700B9E4CB /* ccUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ccUtils.c; sourceTree = "<group>"; };
@@ -6608,6 +6614,9 @@
50E5F2D1110690C600E3FCF5 /* cpShape.c */,
50E5F2D2110690C600E3FCF5 /* cpSpace.c */,
50E5F2D3110690C600E3FCF5 /* cpSpaceHash.c */,
+ E0B1E7FF1261F9E300ACD961 /* cpSpaceComponent.c */,
+ E0B1E8001261F9E300ACD961 /* cpSpaceQuery.c */,
+ E0B1E8011261F9E300ACD961 /* cpSpaceStep.c */,
50E5F2D4110690C600E3FCF5 /* cpVect.c */,
50E5F2D5110690C600E3FCF5 /* prime.h */,
);
@@ -10729,6 +10738,9 @@
50E5F305110690C600E3FCF5 /* cpSpace.c in Sources */,
50E5F306110690C600E3FCF5 /* cpSpaceHash.c in Sources */,
50E5F307110690C600E3FCF5 /* cpVect.c in Sources */,
+ E0B1E8021261F9E300ACD961 /* cpSpaceComponent.c in Sources */,
+ E0B1E8031261F9E300ACD961 /* cpSpaceQuery.c in Sources */,
+ E0B1E8041261F9E300ACD961 /* cpSpaceStep.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
19 external/Chipmunk/include/chipmunk/chipmunk.h
@@ -92,17 +92,26 @@ void cpMessage(const char *message, const char *condition, const char *file, int
extern const char *cpVersionString;
void cpInitChipmunk(void);
-// Calculate the moment of inertia for a circle, r1 and r2 are the inner and outer diameters.
-// (A solid circle has an inner diameter of 0)
+/**
+ Calculate the moment of inertia for a circle.
+ r1 and r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+*/
cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);
-// Calculate the moment of inertia for a line segment. (beveling radius not supported)
+/**
+ Calculate the moment of inertia for a line segment.
+ Beveling radius is not supported.
+*/
cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b);
-// Calculate the moment of inertia for a solid polygon shape.
+/**
+ Calculate the moment of inertia for a solid polygon shape.
+*/
cpFloat cpMomentForPoly(cpFloat m, int numVerts, cpVect *verts, cpVect offset);
-// Calculate the moment of inertia for a solid box.
+/**
+ Calculate the moment of inertia for a solid box.
+*/
cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height);
#ifdef __cplusplus
View
11 external/Chipmunk/include/chipmunk/chipmunk_ffi.h
@@ -12,6 +12,7 @@
#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);
@@ -30,8 +31,8 @@ MAKE_REF(cpvnormalize_safe);
MAKE_REF(cpvclamp);
MAKE_REF(cpvlerpconst);
MAKE_REF(cpvdist);
-MAKE_REF(cpvnear);
MAKE_REF(cpvdistsq);
+MAKE_REF(cpvnear);
MAKE_REF(cpBBNew);
MAKE_REF(cpBBintersects);
@@ -43,8 +44,16 @@ MAKE_REF(cpBBexpand);
MAKE_REF(cpBodyWorld2Local);
MAKE_REF(cpBodyLocal2World);
MAKE_REF(cpBodyApplyImpulse);
+MAKE_REF(cpBodyIsSleeping);
+MAKE_REF(cpBodyIsRogue);
+MAKE_REF(cpBodyKineticEnergy);
MAKE_REF(cpArbiterIsFirstContact);
MAKE_REF(cpArbiterGetShapes);
MAKE_REF(cpArbiterGetNormal);
MAKE_REF(cpArbiterGetPoint);
+
+MAKE_REF(cpConstraintGetImpulse);
+
+MAKE_REF(cpSegmentQueryHitPoint);
+MAKE_REF(cpSegmentQueryHitDist);
View
9 external/Chipmunk/include/chipmunk/constraints/cpConstraint.h
@@ -63,13 +63,19 @@ cpConstraintActivateBodies(cpConstraint *constraint)
cpBody *b = constraint->b; if(b) cpBodyActivate(b);
}
+static inline cpFloat
+cpConstraintGetImpulse(cpConstraint *constraint)
+{
+ return constraint->klass->getImpulse(constraint);
+}
+
#define cpConstraintCheckCast(constraint, struct) \
cpAssert(constraint->klass == struct##GetClass(), "Constraint is not a "#struct);
#define CP_DefineConstraintGetter(struct, type, member, name) \
static inline type \
-struct##Get##name(cpConstraint *constraint){ \
+struct##Get##name(const cpConstraint *constraint){ \
cpConstraintCheckCast(constraint, struct); \
return ((struct *)constraint)->member; \
} \
@@ -78,6 +84,7 @@ struct##Get##name(cpConstraint *constraint){ \
static inline void \
struct##Set##name(cpConstraint *constraint, type value){ \
cpConstraintCheckCast(constraint, struct); \
+ cpConstraintActivateBodies(constraint); \
((struct *)constraint)->member = value; \
} \
View
6 external/Chipmunk/include/chipmunk/constraints/cpGrooveJoint.h
@@ -40,5 +40,9 @@ cpGrooveJoint *cpGrooveJointAlloc(void);
cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
cpConstraint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2);
-// TODO setters for the groove.
+
+CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_a, GrooveA);
+void cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value);
+CP_DefineConstraintGetter(cpGrooveJoint, cpVect, grv_b, GrooveB);
+void cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value);
CP_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2);
View
10 external/Chipmunk/include/chipmunk/cpArbiter.h
@@ -110,7 +110,7 @@ void cpArbiterIgnore(cpArbiter *arb);
static inline void
-cpArbiterGetShapes(cpArbiter *arb, cpShape **a, cpShape **b)
+cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape **b)
{
if(arb->swappedColl){
(*a) = arb->private_b, (*b) = arb->private_a;
@@ -121,7 +121,7 @@ cpArbiterGetShapes(cpArbiter *arb, cpShape **a, cpShape **b)
#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
static inline void
-cpArbiterGetBodies(cpArbiter *arb, cpBody **a, cpBody **b)
+cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody **b)
{
CP_ARBITER_GET_SHAPES(arb, shape_a, shape_b);
(*a) = shape_a->body;
@@ -130,20 +130,20 @@ cpArbiterGetBodies(cpArbiter *arb, cpBody **a, cpBody **b)
#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
static inline cpBool
-cpArbiterIsFirstContact(cpArbiter *arb)
+cpArbiterIsFirstContact(const cpArbiter *arb)
{
return arb->state == cpArbiterStateFirstColl;
}
static inline cpVect
-cpArbiterGetNormal(cpArbiter *arb, int i)
+cpArbiterGetNormal(const cpArbiter *arb, int i)
{
cpVect n = arb->contacts[i].n;
return arb->swappedColl ? cpvneg(n) : n;
}
static inline cpVect
-cpArbiterGetPoint(cpArbiter *arb, int i)
+cpArbiterGetPoint(const cpArbiter *arb, int i)
{
return arb->contacts[i].p;
}
View
39 external/Chipmunk/include/chipmunk/cpBody.h
@@ -71,16 +71,16 @@ typedef struct cpBody{
// Used for fast vector rotation using cpvrotate().
cpVect rot;
- // *** Other Fields
-
- // Maximum velocities this body can move at after integrating velocity
- cpFloat v_limit, w_limit;
-
// *** User Definable Fields
// User defined data pointer.
cpDataPointer data;
+ // *** Other Fields
+
+ // Maximum velocities this body can move at after integrating velocity
+ cpFloat v_limit, w_limit;
+
// *** Internally Used Fields
// Velocity bias values used when solving penetrations and correcting constraints.
@@ -106,32 +106,35 @@ cpBody *cpBodyNew(cpFloat m, cpFloat i);
void cpBodyDestroy(cpBody *body);
void cpBodyFree(cpBody *body);
-// Wake up a sleeping or idle body.
+// Wake up a sleeping or idle body. (defined in cpSpace.c)
void cpBodyActivate(cpBody *body);
+// Force a body to sleep;
+void cpBodySleep(cpBody *body);
+//void cpBodySleepGroup(cpBody *body, ...);
+
static inline cpBool
-cpBodyIsSleeping(cpBody *body)
+cpBodyIsSleeping(const cpBody *body)
{
return (body->node.next != ((cpBody*)0));
}
-// defined in cpSpace.h after the cpSpace type has been defined
-static inline cpBool
-cpBodyIsStatic(cpBody *body);
+cpBool cpBodyIsStatic(const cpBody *body);
static inline cpBool
-cpBodyIsRogue(cpBody *body)
+cpBodyIsRogue(const cpBody *body)
{
return (body->space == ((struct cpSpace*)0));
}
#define CP_DefineBodyGetter(type, member, name) \
-static inline type cpBodyGet##name(cpBody *body){return body->member;}
+static inline type cpBodyGet##name(const cpBody *body){return body->member;}
#define CP_DefineBodySetter(type, member, name) \
static inline void \
-cpBodySet##name(cpBody *body, type value){ \
+cpBodySet##name(cpBody *body, const type value){ \
+ cpBodyActivate(body); \
body->member = value; \
} \
@@ -169,21 +172,21 @@ void cpBodyUpdatePosition(cpBody *body, cpFloat dt);
// Convert body local to world coordinates
static inline cpVect
-cpBodyLocal2World(cpBody *body, cpVect v)
+cpBodyLocal2World(const cpBody *body, const cpVect v)
{
return cpvadd(body->p, cpvrotate(v, body->rot));
}
// Convert world to body local coordinates
static inline cpVect
-cpBodyWorld2Local(cpBody *body, cpVect v)
+cpBodyWorld2Local(const cpBody *body, const cpVect v)
{
return cpvunrotate(cpvsub(v, body->p), body->rot);
}
// Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
static inline void
-cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r)
+cpBodyApplyImpulse(cpBody *body, const cpVect j, const cpVect r)
{
body->v = cpvadd(body->v, cpvmult(j, body->m_inv));
body->w += body->i_inv*cpvcross(r, j);
@@ -192,10 +195,10 @@ cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r)
// Zero the forces on a body.
void cpBodyResetForces(cpBody *body);
// Apply a force (in world coordinates) to a body at a point relative to the center of gravity (also in world coordinates).
-void cpBodyApplyForce(cpBody *body, cpVect f, cpVect r);
+void cpBodyApplyForce(cpBody *body, const cpVect f, const cpVect r);
static inline cpFloat
-cpBodyKineticEnergy(cpBody *body)
+cpBodyKineticEnergy(const cpBody *body)
{
// Need to do some fudging to avoid NaNs
cpFloat vsq = cpvdot(body->v, body->v);
View
2  external/Chipmunk/include/chipmunk/cpCollision.h
@@ -23,4 +23,4 @@
// Returns the number of contact points added to arr
// which should be at least CP_MAX_CONTACTS_PER_ARBITER in length.
// This function is very lonely in this header :(
-int cpCollideShapes(cpShape *a, cpShape *b, cpContact *arr);
+int cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr);
View
4 external/Chipmunk/include/chipmunk/cpPolyShape.h
@@ -73,7 +73,7 @@ cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
// Returns true if the polygon contains the vertex.
static inline cpBool
-cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v)
+cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
{
cpPolyShapeAxis *axes = poly->tAxes;
@@ -88,7 +88,7 @@ cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v)
// Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.
static inline cpBool
-cpPolyShapeContainsVertPartial(cpPolyShape *poly, cpVect v, cpVect n)
+cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n)
{
cpPolyShapeAxis *axes = poly->tAxes;
View
4 external/Chipmunk/include/chipmunk/cpShape.h
@@ -165,13 +165,13 @@ void cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info);
cpBool cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
static inline cpVect
-cpSegmentQueryHitPoint(cpVect start, cpVect end, cpSegmentQueryInfo info)
+cpSegmentQueryHitPoint(const cpVect start, const cpVect end, const cpSegmentQueryInfo info)
{
return cpvlerp(start, end, info.t);
}
static inline cpFloat
-cpSegmentQueryHitDist(cpVect start, cpVect end, cpSegmentQueryInfo info)
+cpSegmentQueryHitDist(const cpVect start, const cpVect end, const cpSegmentQueryInfo info)
{
return cpvdist(start, end)*info.t;
}
View
18 external/Chipmunk/include/chipmunk/cpSpace.h
@@ -94,9 +94,9 @@ typedef struct cpSpace{
cpArray *arbiters, *pooledArbiters;
// Linked list ring of contact buffers.
- // Head is the current buffer. Tail is the oldest buffer.
- // The list points in the direction of tail->head.
- cpContactBufferHeader *contactBuffersHead, *contactBuffersTail;
+ // Head is the newest buffer, and each buffer points to a newer buffer.
+ // Head wraps around and points to the oldest (tail) buffer.
+ cpContactBufferHeader *contactBuffersHead, *_contactBuffersTail;
// List of buffers to be free()ed when destroying the space.
cpArray *allocatedBuffers;
@@ -128,14 +128,6 @@ void cpSpaceFree(cpSpace *space);
// Convenience function. Frees all referenced entities. (bodies, shapes and constraints)
void cpSpaceFreeChildren(cpSpace *space);
-// Needed to be defined after the cpSpace type was closed
-static inline cpBool
-cpBodyIsStatic(cpBody *body)
-{
- cpSpace *space = body->space;
- return (space != ((cpSpace*)0) && body == &space->staticBody);
-}
-
// Collision handler management functions.
void cpSpaceSetDefaultCollisionHandler(
cpSpace *space,
@@ -180,7 +172,7 @@ cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, c
// Segment query callback function
typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data);
-cpBool cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data);
+void cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data);
cpShape *cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out);
// BB query callback function
@@ -197,5 +189,7 @@ void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);
void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);
void cpSpaceRehashStatic(cpSpace *space);
+void cpSpaceRehashShape(cpSpace *space, cpShape *shape);
+
// Update the space.
void cpSpaceStep(cpSpace *space, cpFloat dt);
View
2  external/Chipmunk/include/chipmunk/cpSpaceHash.h
@@ -77,7 +77,7 @@ void cpSpaceHashFree(cpSpaceHash *hash);
void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);
// Add an object to the hash.
-void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB bb);
+void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB _deprecated_ignored);
// Remove an object from the hash.
void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue id);
View
52 external/Chipmunk/include/chipmunk/cpVect.h
@@ -19,8 +19,10 @@
* SOFTWARE.
*/
-static const cpVect cpvzero={0.0f,0.0f};
+/// Constant for the zero vector.
+static const cpVect cpvzero = {0.0f,0.0f};
+/// Convenience constructor for cpVect structs.
static inline cpVect
cpv(const cpFloat x, const cpFloat y)
{
@@ -29,133 +31,175 @@ cpv(const cpFloat x, const cpFloat y)
}
// non-inlined functions
+
+/// Returns the length of v.
cpFloat cpvlength(const cpVect v);
+
+/// Spherical linearly interpolate between v1 and v2.
cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t);
+
+/// Spherical linearly interpolate between v1 towards v2 by no more than angle a radians
cpVect cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a);
-cpVect cpvforangle(const cpFloat a); // convert radians to a normalized vector
-cpFloat cpvtoangle(const cpVect v); // convert a vector to radians
-char *cpvstr(const cpVect v); // get a string representation of a vector
+/// Returns the unit length vector for the given angle (in radians).
+cpVect cpvforangle(const cpFloat a);
+
+/// Returns the angular direction v is pointing in (in radians).
+cpFloat cpvtoangle(const cpVect v);
+
+/**
+ Returns a string representation of v. Intended mostly for debugging purposes and not production use.
+
+ @attention The string points to a static local and is reset every time the function is called.
+ If you want to print more than one vector you will have to split up your printing onto separate lines.
+*/
+char *cpvstr(const cpVect v);
+
+/// Check if two vectors are equal. (Be careful when comparing floating point numbers!)
static inline cpBool
cpveql(const cpVect v1, const cpVect v2)
{
return (v1.x == v2.x && v1.y == v2.y);
}
+/// Add two vectors
static inline cpVect
cpvadd(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);
}
+/// Subtract two vectors.
static inline cpVect
cpvsub(const cpVect v1, const cpVect v2)
{
return cpv(v1.x - v2.x, v1.y - v2.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));
}
+/// 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);
}
+/// Linearly interpolate between v1 and v2.
static inline cpVect
cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)
{
return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));
}
+/// Returns a normalized copy of v.
static inline cpVect
cpvnormalize(const cpVect v)
{
return cpvmult(v, 1.0f/cpvlength(v));
}
+/// Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
static inline cpVect
cpvnormalize_safe(const cpVect v)
{
return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v));
}
+/// Clamp v to length len.
static inline cpVect
cpvclamp(const cpVect v, const cpFloat len)
{
return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
}
+/// Linearly interpolate between v1 towards v2 by distance d.
static inline cpVect
cpvlerpconst(cpVect v1, cpVect v2, cpFloat d)
{
return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d));
}
+/// Returns the distance between v1 and v2.
static inline cpFloat
cpvdist(const cpVect v1, const cpVect v2)
{
return cpvlength(cpvsub(v1, v2));
}
+/// Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
static inline cpFloat
cpvdistsq(const cpVect v1, const cpVect v2)
{
return cpvlengthsq(cpvsub(v1, v2));
}
+/// Returns true if the distance between v1 and v2 is less than dist.
static inline cpBool
cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)
{
View
4 external/Chipmunk/src/chipmunk.c
@@ -43,7 +43,7 @@ cpMessage(const char *message, const char *condition, const char *file, int line
}
-const char *cpVersionString = "5.3.x";
+const char *cpVersionString = "5.3.2";
void
cpInitChipmunk(void)
@@ -98,7 +98,7 @@ cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset)
cpFloat
cpMomentForBox(cpFloat m, cpFloat width, cpFloat height)
{
- return m*(width*width + height*height)/(cpFloat)12.0;
+ return m*(width*width + height*height)/12.0f;
}
View
25 external/Chipmunk/src/constraints/cpGrooveJoint.c
@@ -134,3 +134,28 @@ cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect
{
return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);
}
+
+void
+cpGrooveJointSetGrooveA(cpConstraint *constraint, cpVect value)
+{
+ cpGrooveJoint *g = (cpGrooveJoint *)constraint;
+ cpConstraintCheckCast(constraint, cpGrooveJoint);
+
+ g->grv_a = value;
+ g->grv_n = cpvperp(cpvnormalize(cpvsub(g->grv_b, value)));
+
+ cpConstraintActivateBodies(constraint);
+}
+
+void
+cpGrooveJointSetGrooveB(cpConstraint *constraint, cpVect value)
+{
+ cpGrooveJoint *g = (cpGrooveJoint *)constraint;
+ cpConstraintCheckCast(constraint, cpGrooveJoint);
+
+ g->grv_b = value;
+ g->grv_n = cpvperp(cpvnormalize(cpvsub(value, g->grv_a)));
+
+ cpConstraintActivateBodies(constraint);
+}
+
View
26 external/Chipmunk/src/cpBody.c
@@ -62,11 +62,9 @@ cpBodyInit(cpBody *body, cpFloat m, cpFloat i)
body->space = NULL;
body->shapesList = NULL;
-
- body->node.parent = NULL;
- body->node.next = NULL;
- body->node.rank = 0;
- body->node.idleTime = 0.0f;
+
+ cpComponentNode node = {NULL, NULL, 0, 0.0f};
+ body->node = node;
return body;
}
@@ -176,3 +174,21 @@ cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat
cpBodyApplyForce(a, f, r1);
cpBodyApplyForce(b, cpvneg(f), r2);
}
+
+cpBool
+cpBodyIsStatic(const cpBody *body)
+{
+ cpSpace *space = body->space;
+ return (space != ((cpSpace*)0) && body == &space->staticBody);
+}
+
+void cpSpaceSleepBody(cpSpace *space, cpBody *body);
+
+void
+cpBodySleep(cpBody *body)
+{
+ if(cpBodyIsSleeping(body)) return;
+
+ cpAssert(!cpBodyIsStatic(body) && !cpBodyIsRogue(body), "Rogue and static bodies cannot be put to sleep.");
+ cpSpaceSleepBody(body->space, body);
+}
View
34 external/Chipmunk/src/cpCollision.c
@@ -25,12 +25,12 @@
#include "chipmunk.h"
-typedef int (*collisionFunc)(cpShape *, cpShape *, cpContact *);
+typedef int (*collisionFunc)(const cpShape *, const cpShape *, cpContact *);
// Add contact points for circle to circle collisions.
// Used by several collision tests.
static int
-circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con)
+circle2circleQuery(const cpVect p1, const cpVect p2, const cpFloat r1, const cpFloat r2, cpContact *con)
{
cpFloat mindist = r1 + r2;
cpVect delta = cpvsub(p2, p1);
@@ -38,14 +38,12 @@ circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con)
if(distsq >= mindist*mindist) return 0;
cpFloat dist = cpfsqrt(distsq);
- // To avoid singularities, do nothing in the case of dist = 0.
- cpFloat non_zero_dist = (dist ? dist : INFINITY);
// Allocate and initialize the contact.
cpContactInit(
con,
- cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/non_zero_dist)),
- cpvmult(delta, 1.0f/non_zero_dist),
+ cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/(dist ? dist : INFINITY))),
+ (dist ? cpvmult(delta, 1.0f/dist) : cpv(1.0f, 0.0f)),
dist - mindist,
0
);
@@ -55,7 +53,7 @@ circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con)
// Collide circle shapes.
static int
-circle2circle(cpShape *shape1, cpShape *shape2, cpContact *arr)
+circle2circle(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{
cpCircleShape *circ1 = (cpCircleShape *)shape1;
cpCircleShape *circ2 = (cpCircleShape *)shape2;
@@ -65,7 +63,7 @@ circle2circle(cpShape *shape1, cpShape *shape2, cpContact *arr)
// Collide circles to segment shapes.
static int
-circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact *con)
+circle2segment(const cpShape *circleShape, const cpShape *segmentShape, cpContact *con)
{
cpCircleShape *circ = (cpCircleShape *)circleShape;
cpSegmentShape *seg = (cpSegmentShape *)segmentShape;
@@ -128,7 +126,7 @@ nextContactPoint(cpContact *arr, int *numPtr)
// Find the minimum separating axis for the give poly and axis list.
static inline int
-findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out)
+findMSA(const cpPolyShape *poly, const cpPolyShapeAxis *axes, const int num, cpFloat *min_out)
{
int min_index = 0;
cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);
@@ -152,7 +150,7 @@ findMSA(cpPolyShape *poly, cpPolyShapeAxis *axes, int num, cpFloat *min_out)
// This handles the degenerate case where an overlap was detected, but no vertexes fall inside
// the opposing polygon. (like a star of david)
static inline int
-findVertsFallback(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist)
+findVertsFallback(cpContact *arr, const cpPolyShape *poly1, const cpPolyShape *poly2, const cpVect n, const cpFloat dist)
{
int num = 0;
@@ -173,7 +171,7 @@ findVertsFallback(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect
// Add contacts for penetrating vertexes.
static inline int
-findVerts(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist)
+findVerts(cpContact *arr, const cpPolyShape *poly1, const cpPolyShape *poly2, const cpVect n, const cpFloat dist)
{
int num = 0;
@@ -194,7 +192,7 @@ findVerts(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFl
// Collide poly shapes together.
static int
-poly2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
+poly2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{
cpPolyShape *poly1 = (cpPolyShape *)shape1;
cpPolyShape *poly2 = (cpPolyShape *)shape2;
@@ -216,7 +214,7 @@ poly2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
// Like cpPolyValueOnAxis(), but for segments.
static inline cpFloat
-segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)
+segValueOnAxis(const cpSegmentShape *seg, const cpVect n, const cpFloat d)
{
cpFloat a = cpvdot(n, seg->ta) - seg->r;
cpFloat b = cpvdot(n, seg->tb) - seg->r;
@@ -225,7 +223,7 @@ segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)
// Identify vertexes that have penetrated the segment.
static inline void
-findPointsBehindSeg(cpContact *arr, int *num, cpSegmentShape *seg, cpPolyShape *poly, cpFloat pDist, cpFloat coef)
+findPointsBehindSeg(cpContact *arr, int *num, const cpSegmentShape *seg, const cpPolyShape *poly, const cpFloat pDist, const cpFloat coef)
{
cpFloat dta = cpvcross(seg->tn, seg->ta);
cpFloat dtb = cpvcross(seg->tn, seg->tb);
@@ -245,7 +243,7 @@ findPointsBehindSeg(cpContact *arr, int *num, cpSegmentShape *seg, cpPolyShape *
// This one is complicated and gross. Just don't go there...
// TODO: Comment me!
static int
-seg2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
+seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
{
cpSegmentShape *seg = (cpSegmentShape *)shape1;
cpPolyShape *poly = (cpPolyShape *)shape2;
@@ -314,7 +312,7 @@ seg2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
// This one is less gross, but still gross.
// TODO: Comment me!
static int
-circle2poly(cpShape *shape1, cpShape *shape2, cpContact *con)
+circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
{
cpCircleShape *circ = (cpCircleShape *)shape1;
cpPolyShape *poly = (cpPolyShape *)shape2;
@@ -372,7 +370,7 @@ circle2poly(cpShape *shape1, cpShape *shape2, cpContact *con)
static collisionFunc *colfuncs = NULL;
static void
-addColFunc(cpShapeType a, cpShapeType b, collisionFunc func)
+addColFunc(const cpShapeType a, const cpShapeType b, const collisionFunc func)
{
colfuncs[a + b*CP_NUM_SHAPES] = func;
}
@@ -401,7 +399,7 @@ extern "C" {
#endif
int
-cpCollideShapes(cpShape *a, cpShape *b, cpContact *arr)
+cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr)
{
// Their shape types must be in order.
cpAssert(a->klass->type <= b->klass->type, "Collision shapes passed to cpCollideShapes() are not sorted.");
View
4 external/Chipmunk/src/cpPolyShape.c
@@ -211,8 +211,8 @@ cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)
cpPolyShape *
cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height)
{
- cpFloat hw = width/(cpFloat)2.0;
- cpFloat hh = height/(cpFloat)2.0;
+ cpFloat hw = width/2.0f;
+ cpFloat hh = height/2.0f;
cpVect verts[] = {
cpv(-hw,-hh),
View
47 external/Chipmunk/src/cpShape.c
@@ -278,9 +278,13 @@ cpSegmentShapePointQuery(cpShape *shape, cpVect p){
return cpTrue;
}
+static inline cpBool inUnitRange(cpFloat t){return (0.0f < t && t < 1.0f);}
+
static void
cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
{
+ // TODO this function could be optimized better.
+
cpSegmentShape *seg = (cpSegmentShape *)shape;
cpVect n = seg->tn;
// flip n if a is behind the axis
@@ -289,40 +293,37 @@ cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInf
cpFloat an = cpvdot(a, n);
cpFloat bn = cpvdot(b, n);
- cpFloat d = cpvdot(seg->ta, n) + seg->r;
-
- cpFloat t = (d - an)/(bn - an);
- if(0.0f < t && t < 1.0f){
- cpVect point = cpvlerp(a, b, t);
- cpFloat dt = -cpvcross(seg->tn, point);
- cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
- cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
+
+ if(an != bn){
+ cpFloat d = cpvdot(seg->ta, n) + seg->r;
+ cpFloat t = (d - an)/(bn - an);
- if(dtMin < dt && dt < dtMax){
- info->shape = shape;
- info->t = t;
- info->n = n;
+ if(0.0f < t && t < 1.0f){
+ cpVect point = cpvlerp(a, b, t);
+ cpFloat dt = -cpvcross(seg->tn, point);
+ cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
+ cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
- return; // don't continue on and check endcaps
+ if(dtMin < dt && dt < dtMax){
+ info->shape = shape;
+ info->t = t;
+ info->n = n;
+
+ return; // don't continue on and check endcaps
+ }
}
}
if(seg->r) {
- cpSegmentQueryInfo info1; info1.shape = NULL;
- cpSegmentQueryInfo info2; info2.shape = NULL;
+ cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero};
+ cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero};
circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1);
circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2);
- if(info1.shape && !info2.shape){
+ if(info1.t < info2.t){
(*info) = info1;
- } else if(info2.shape && !info1.shape){
+ } else {
(*info) = info2;
- } else if(info1.shape && info2.shape){
- if(info1.t < info2.t){
- (*info) = info1;
- } else {
- (*info) = info2;
- }
}
}
}
View
748 external/Chipmunk/src/cpSpace.c
@@ -77,28 +77,6 @@ collFuncSetTrans(cpCollisionHandler *handler, void *unused)
return copy;
}
-#pragma mark Post Step Function Helpers
-
-typedef struct postStepCallback {
- cpPostStepFunc func;
- void *obj;
- void *data;
-} postStepCallback;
-
-static cpBool
-postStepFuncSetEql(postStepCallback *a, postStepCallback *b){
- return a->obj == b->obj;
-}
-
-static void *
-postStepFuncSetTrans(postStepCallback *callback, void *ignored)
-{
- postStepCallback *value = (postStepCallback *)cpmalloc(sizeof(postStepCallback));
- (*value) = (*callback);
-
- return value;
-}
-
#pragma mark Misc Helper Funcs
// Default collision functions.
@@ -116,30 +94,6 @@ static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFr
#pragma mark Memory Management Functions
-#define CP_CONTACTS_BUFFER_SIZE ((CP_BUFFER_BYTES - sizeof(cpContactBufferHeader))/sizeof(cpContact))
-typedef struct cpContactBuffer {
- cpContactBufferHeader header;
- cpContact contacts[CP_CONTACTS_BUFFER_SIZE];
-} cpContactBuffer;
-
-static cpContactBufferHeader *
-cpSpaceAllocContactBuffer(cpSpace *space)
-{
- cpContactBuffer *buffer = (cpContactBuffer *)malloc(sizeof(cpContactBuffer));
- cpArrayPush(space->allocatedBuffers, buffer);
- return (cpContactBufferHeader *)buffer;
-}
-
-static cpContactBufferHeader *
-cpContactBufferHeaderInit(cpContactBufferHeader *header, cpSpace *space)
-{
- header->stamp = space->stamp;
- header->next = space->contactBuffersTail;
- header->numContacts = 0;
-
- return header;
-}
-
cpSpace *
cpSpaceAlloc(void)
{
@@ -179,11 +133,7 @@ cpSpaceInit(cpSpace *space)
space->arbiters = cpArrayNew(0);
space->pooledArbiters = cpArrayNew(0);
- cpContactBufferHeader *header = cpContactBufferHeaderInit(cpSpaceAllocContactBuffer(space), space);
- space->contactBuffersHead = header;
- space->contactBuffersTail = header;
- header->next = header; // Buffers will form a ring, start the ring explicitly
-
+ space->contactBuffersHead = NULL;
space->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);
space->constraints = cpArrayNew(0);
@@ -192,7 +142,7 @@ cpSpaceInit(cpSpace *space)
space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);
space->collFuncSet->default_value = &space->defaultHandler;
- space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql, (cpHashSetTransFunc)postStepFuncSetTrans);
+ space->postStepCallbacks = NULL;
cpBodyInit(&space->staticBody, INFINITY, INFINITY);
space->staticBody.space = space;
@@ -345,18 +295,6 @@ cpBodyRemoveShape(cpBody *body, cpShape *shape)
(*prev_ptr) = node->next;
}
-static inline void
-addShapeRaw(cpShape *shape, cpSpaceHash *hash)
-{
- cpSpaceHashInsert(hash, shape, shape->hashid, shape->bb);
-}
-
-static inline void
-removeShapeRaw(cpShape *shape, cpSpaceHash *hash)
-{
- cpSpaceHashRemove(hash, shape, shape->hashid);
-}
-
cpShape *
cpSpaceAddShape(cpSpace *space, cpShape *shape)
{
@@ -369,7 +307,9 @@ cpSpaceAddShape(cpSpace *space, cpShape *shape)
cpBodyActivate(body);
cpBodyAddShape(body, shape);
- addShapeRaw(shape, space->activeShapes);
+
+ cpShapeCacheBB(shape);
+ cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
return shape;
}
@@ -384,7 +324,8 @@ static void
activateShapesTouchingShape(cpSpace *space, cpShape *shape)
{
// TODO this query should be more precise
- cpSpaceBBQuery(space, shape->bb, CP_ALL_LAYERS, CP_NO_GROUP, activateShapesTouchingShapeHelper, NULL);
+ // Use shape queries once they are written
+ cpSpaceBBQuery(space, shape->bb, shape->layers, shape->group, activateShapesTouchingShapeHelper, NULL);
}
cpShape *
@@ -398,7 +339,7 @@ cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
cpShapeCacheBB(shape);
activateShapesTouchingShape(space, shape);
- addShapeRaw(shape, space->staticShapes);
+ cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
return shape;
}
@@ -469,7 +410,7 @@ cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
removalContext context = {space, shape};
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
- removeShapeRaw(shape, space->activeShapes);
+ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
}
void
@@ -481,7 +422,7 @@ cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
removalContext context = {space, shape};
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
- removeShapeRaw(shape, space->staticShapes);
+ cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
activateShapesTouchingShape(space, shape);
}
@@ -510,210 +451,9 @@ cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
cpArrayDeleteObj(space->constraints, constraint);
}
-#pragma mark Post Step Functions
-
-void
-cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data)
-{
- postStepCallback callback = {func, obj, data};
- cpHashSetInsert(space->postStepCallbacks, (cpHashValue)(size_t)obj, &callback, NULL);
-}
-
-static void
-removeAndFreeShapeAndBody(cpShape *shape, cpSpace *space)
-{
- cpSpaceRemoveShape(space, shape);
- cpShapeFree(shape);
-}
-
-void
-cpSpacePostStepRemoveAndFreeShapeAndBody(cpSpace *space, cpShape *shape)
-{
- cpSpaceAddPostStepCallback(space, (cpPostStepFunc)removeAndFreeShapeAndBody, shape, space);
-}
-
-#pragma mark Point Query Functions
-
-typedef struct pointQueryContext {
- cpLayers layers;
- cpGroup group;
- cpSpacePointQueryFunc func;
- void *data;
-} pointQueryContext;
-
-static void
-pointQueryHelper(cpVect *point, cpShape *shape, pointQueryContext *context)
-{
- if(
- !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
- cpShapePointQuery(shape, *point)
- ){
- context->func(shape, context->data);
- }
-}
-
-void
-cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data)
-{
- pointQueryContext context = {layers, group, func, data};
- cpSpaceHashPointQuery(space->activeShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
- cpSpaceHashPointQuery(space->staticShapes, point, (cpSpaceHashQueryFunc)pointQueryHelper, &context);
-}
-
-static void
-rememberLastPointQuery(cpShape *shape, cpShape **outShape)
-{
- (*outShape) = shape;
-}
-
-cpShape *
-cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group)
-{
- cpShape *shape = NULL;
- cpSpacePointQuery(space, point, layers, group, (cpSpacePointQueryFunc)rememberLastPointQuery, &shape);
-
- return shape;
-}
-
-void
-cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data)
-{
- cpArray *bodies = space->bodies;
-
- for(int i=0; i<bodies->num; i++)
- func((cpBody *)bodies->arr[i], data);
-}
-
-#pragma mark Segment Query Functions
-
-typedef struct segQueryContext {
- cpVect start, end;
- cpLayers layers;
- cpGroup group;
- cpSpaceSegmentQueryFunc func;
- cpBool anyCollision;
-} segQueryContext;
-
-static cpFloat
-segQueryFunc(segQueryContext *context, cpShape *shape, void *data)
-{
- cpSegmentQueryInfo info;
-
- if(
- !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
- cpShapeSegmentQuery(shape, context->start, context->end, &info)
- ){
- if(context->func){
- context->func(shape, info.t, info.n, data);
- }
-
- context->anyCollision = cpTrue;
- }
-
- return 1.0f;
-}
-
-cpBool
-cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
-{
- segQueryContext context = {
- start, end,
- layers, group,
- func,
- cpFalse,
- };
-
- cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFunc, data);
- cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFunc, data);
-
- return context.anyCollision;
-}
-
-typedef struct segQueryFirstContext {
- cpVect start, end;
- cpLayers layers;
- cpGroup group;
-} segQueryFirstContext;
-
-static cpFloat
-segQueryFirst(segQueryFirstContext *context, cpShape *shape, cpSegmentQueryInfo *out)
-{
- cpSegmentQueryInfo info;// = {NULL, 1.0f, cpvzero};
- if(
- !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
- cpShapeSegmentQuery(shape, context->start, context->end, &info)
- ){
- if(info.t < out->t){
- out->shape = info.shape;
- out->t = info.t;
- out->n = info.n;
- }
-
- return info.t;
- }
-
- return 1.0f;
-}
-
-cpShape *
-cpSpaceSegmentQueryFirst(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSegmentQueryInfo *out)
-{
- cpSegmentQueryInfo info = {NULL, 1.0f, cpvzero};
- if(out){
- (*out) = info;
- } else {
- out = &info;
- }
-
- out->t = 1.0f;
-
- segQueryFirstContext context = {
- start, end,
- layers, group
- };
-
- cpSpaceHashSegmentQuery(space->staticShapes, &context, start, end, 1.0f, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
- cpSpaceHashSegmentQuery(space->activeShapes, &context, start, end, out->t, (cpSpaceHashSegmentQueryFunc)segQueryFirst, out);
-
- return out->shape;
-}
-
-#pragma mark BB Query functions
-
-typedef struct bbQueryContext {
- cpLayers layers;
- cpGroup group;
- cpSpaceBBQueryFunc func;
- void *data;
-} bbQueryContext;
-
-static void
-bbQueryHelper(cpBB *bb, cpShape *shape, bbQueryContext *context)
-{
- if(
- !(shape->group && context->group == shape->group) && (context->layers&shape->layers) &&
- cpBBintersects(*bb, shape->bb)
- ){
- context->func(shape, context->data);
- }
-}
-
-void
-cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data)
-{
- bbQueryContext context = {layers, group, func, data};
- cpSpaceHashQuery(space->activeShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
- cpSpaceHashQuery(space->staticShapes, &bb, bb, (cpSpaceHashQueryFunc)bbQueryHelper, &context);
-}
-
#pragma mark Spatial Hash Management
-// Iterator function used for updating shape BBoxes.
-static void
-updateBBCache(cpShape *shape, void *unused)
-{
- cpShapeCacheBB(shape);
-}
+static void updateBBCache(cpShape *shape, void *unused){cpShapeCacheBB(shape);}
void
cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
@@ -735,468 +475,12 @@ cpSpaceRehashStatic(cpSpace *space)
cpSpaceHashRehash(space->staticShapes);
}
-#pragma mark Collision Detection Functions
-
-static cpContactBufferHeader *
-cpSpaceGetFreeContactBuffer(cpSpace *space)
-{
- if(space->stamp - space->contactBuffersTail->stamp > cp_contact_persistence){
- cpContactBufferHeader *header = space->contactBuffersTail;
- space->contactBuffersTail = header->next;
-
- return cpContactBufferHeaderInit(header, space);
- } else {
- cpContactBufferHeader *header = cpSpaceAllocContactBuffer(space);
- return cpContactBufferHeaderInit(header, space);
- }
-}
-
-static void
-cpSpacePushNewContactBuffer(cpSpace *space)
-{
- cpContactBufferHeader *buffer = cpSpaceGetFreeContactBuffer(space);
- space->contactBuffersHead->next = buffer;
- space->contactBuffersHead = buffer;
-}
-
-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 objects in the same non-zero group
- || (a->group && b->group && a->group == b->group)
- // Don't collide objects that don't share at least on layer.
- || !(a->layers & b->layers);
-}
-
-// Callback from the spatial hash.
-static void
-queryFunc(cpShape *a, cpShape *b, cpSpace *space)
-{
- // Reject any of the simple cases
- if(queryReject(a,b)) return;
-
- // Find the collision pair function for the shapes.
- struct{cpCollisionType a, b;} ids = {a->collision_type, b->collision_type};
- cpHashValue collHashID = CP_HASH_PAIR(a->collision_type, b->collision_type);
- cpCollisionHandler *handler = (cpCollisionHandler *)cpHashSetFind(space->collFuncSet, collHashID, &ids);
-
- cpBool sensor = a->sensor || b->sensor;
- if(sensor && handler == &space->defaultHandler) return;
-
- // Shape 'a' should have the lower shape type. (required by cpCollideShapes() )
- if(a->klass->type > b->klass->type){
- cpShape *temp = a;
- a = b;
- b = temp;
- }
-
- if(space->contactBuffersHead->numContacts + CP_MAX_CONTACTS_PER_ARBITER > CP_CONTACTS_BUFFER_SIZE){
- // contact buffer could overflow on the next collision, push a fresh one.
- cpSpacePushNewContactBuffer(space);
- }
-
- // Narrow-phase collision detection.
- cpContact *contacts = ((cpContactBuffer *)(space->contactBuffersHead))->contacts + space->contactBuffersHead->numContacts;
- int numContacts = cpCollideShapes(a, b, contacts);
- if(!numContacts) return; // Shapes are not colliding.
- space->contactBuffersHead->numContacts += numContacts;
-
- // Get an arbiter from space->contactSet for the two shapes.
- // This is where the persistant contact magic comes from.
- cpShape *shape_pair[] = {a, b};
- cpHashValue arbHashID = CP_HASH_PAIR((size_t)a, (size_t)b);
- cpArbiter *arb = (cpArbiter *)cpHashSetInsert(space->contactSet, arbHashID, shape_pair, space);
- cpArbiterUpdate(arb, contacts, numContacts, handler, a, b); // retains the contacts array
-
- // Call the begin function first if it's the first step
- if(arb->state == cpArbiterStateFirstColl && !handler->begin(arb, space, handler->data)){
- cpArbiterIgnore(arb); // permanently ignore the collision until separation
- }
-
- if(
- // Ignore the arbiter if it has been flagged
- (arb->state != cpArbiterStateIgnore) &&
- // Call preSolve
- handler->preSolve(arb, space, handler->data) &&
- // Process, but don't add collisions for sensors.
- !sensor
- ){
- cpArrayPush(space->arbiters, arb);
- } else {
- space->contactBuffersHead->numContacts -= numContacts;
- arb->contacts = NULL;
- arb->numContacts = 0;
- }
-
- // Time stamp the arbiter so we know it was used recently.
- arb->stamp = space->stamp;
-}
-
-// Iterator for active/static hash collisions.
-static void
-active2staticIter(cpShape *shape, cpSpace *space)
-{
- cpSpaceHashQuery(space->staticShapes, shape, shape->bb, (cpSpaceHashQueryFunc)queryFunc, space);
-}
-
-// Hashset filter func to throw away old arbiters.
-static cpBool
-contactSetFilter(cpArbiter *arb, cpSpace *space)
-{
- if(space->sleepTimeThreshold != INFINITY){
- cpBody *a = arb->private_a->body;
- cpBody *b = arb->private_b->body;
-
- // both bodies are either static or sleeping
- cpBool sleepingNow =
- (cpBodyIsStatic(a) || cpBodyIsSleeping(a)) &&
- (cpBodyIsStatic(b) || cpBodyIsSleeping(b));
-
- if(sleepingNow){
- arb->state = cpArbiterStateSleep;
- return cpTrue;
- } else if(arb->state == cpArbiterStateSleep){
- // wake up the arbiter and continue as normal
- arb->state = cpArbiterStateNormal;
- // TODO is it possible that cpArbiterStateIgnore should be set here instead?
- }
- }
-
- cpTimestamp ticks = space->stamp - arb->stamp;
-
- // was used last frame, but not this one
- if(ticks >= 1 && arb->state != cpArbiterStateCached){
- arb->handler->separate(arb, space, arb->handler->data);
- arb->state = cpArbiterStateCached;
- }
-
- if(ticks >= cp_contact_persistence){
- arb->contacts = NULL;
- arb->numContacts = 0;
-
- cpArrayPush(space->pooledArbiters, arb);
- return cpFalse;
- }
-
- return cpTrue;
-}
-
-// Hashset filter func to call and throw away post step callbacks.
-static void
-postStepCallbackSetIter(postStepCallback *callback, cpSpace *space)
-{
- callback->func(space, callback->obj, callback->data);
- cpfree(callback);
-}
-
-#pragma mark Sleeping Functions
-
-// Chipmunk uses a data structure called a disjoint set forest.
-// My attempts to find a way to splice circularly linked lists in
-// constant time failed, and so I found this neat data structure instead.
-
-static inline cpBody *
-componentNodeRoot(cpBody *body)
-{
- cpBody *parent = body->node.parent;
-
- if(!parent){
- return body;
- } else {
- // path compression, attaches this node directly to the root
- return (body->node.parent = componentNodeRoot(parent));
- }
-}
-
-static inline void
-componentNodeMerge(cpBody *a_root, cpBody *b_root)
-{
- if(a_root->node.rank < b_root->node.rank){
- a_root->node.parent = b_root;
- } else if(a_root->node.rank > b_root->node.rank){
- b_root->node.parent = a_root;
- } else if(a_root != b_root){
- b_root->node.parent = a_root;
- a_root->node.rank++;
- }
-}
-
-static inline void
-componentActivate(cpBody *root)
-{
- if(!cpBodyIsSleeping(root)) return;
-
- cpSpace *space = root->space;
- cpAssert(space, "Trying to activate a body that was never added to a space.");
-
- cpBody *body = root, *next;
- do {
- next = body->node.next;
- body->node.next = NULL;
- body->node.idleTime = 0.0f;
- cpArrayPush(space->bodies, body);
-
- for(cpShape *shape=body->shapesList; shape; shape=shape->next){
- removeShapeRaw(shape, space->staticShapes);
- addShapeRaw(shape, space->activeShapes);
- }
- } while((body = next) != root);
-
- cpArrayDeleteObj(space->sleepingComponents, root);
-}
-
-void
-cpBodyActivate(cpBody *body)
-{
- // Force the body to wake up even if it's not in a currently sleeping component
- // Like a body resting on or jointed to a rogue body.
- body->node.idleTime = 0.0f;
-
- cpBody *root = componentNodeRoot(body);
- if(root) componentActivate(root);
-}
-
-static inline void
-mergeBodies(cpSpace *space, cpArray *components, cpArray *rogueBodies, cpBody *a, cpBody *b)
-{
- // Don't merge with the static body
- if(cpBodyIsStatic(a) || cpBodyIsStatic(b)) return;
-
- cpBody *a_root = componentNodeRoot(a);
- cpBody *b_root = componentNodeRoot(b);
-
- cpBool a_sleep = cpBodyIsSleeping(a_root);
- cpBool b_sleep = cpBodyIsSleeping(b_root);
-
- if(a_sleep && b_sleep){
- return;
- } else if(a_sleep || b_sleep){
- componentActivate(a_root);
- componentActivate(b_root);
- }
-
- // Add any rogue bodies (bodies not added to the space)
- if(!a->space) cpArrayPush(rogueBodies, a);
- if(!b->space) cpArrayPush(rogueBodies, b);
-
- componentNodeMerge(a_root, b_root);
-}
-
-static inline cpBool
-componentActive(cpBody *root, cpFloat threshold)
-{
- cpBody *body = root, *next;
- do {
- next = body->node.next;
- if(cpBodyIsRogue(body) || body->node.idleTime < threshold) return cpTrue;
- } while((body = next) != root);
-
- return cpFalse;
-}
-
-static inline void
-addToComponent(cpBody *body, cpArray *components)
-{
- // Check that the body is not already added to the component list
- if(body->node.next) return;
- cpBody *root = componentNodeRoot(body);
-
- cpBody *next = root->node.next;
- if(!next){
- // If the root isn't part of a list yet, then it hasn't been
- // added to the components list. Do that now.
- cpArrayPush(components, root);
- // Start the list
- body->node.next = root;
- root->node.next = body;
- } else if(root != body) {
- // Splice in body after the root.
- body->node.next = next;
- root->node.next = body;
- }
-}
-
-// TODO this function needs more commenting.
-static void
-processContactComponents(cpSpace *space, cpFloat dt)
-{
- cpArray *bodies = space->bodies;
- cpArray *newBodies = cpArrayNew(bodies->num);
- cpArray *rogueBodies = cpArrayNew(16);
- cpArray *arbiters = space->arbiters;
- cpArray *constraints = space->constraints;
- cpArray *components = cpArrayNew(bodies->num/8);
-
- cpFloat dv = space->idleSpeedThreshold;
- cpFloat dvsq = (dv ? dv*dv : cpvdot(space->gravity, space->gravity)*dt*dt);
- // update idling
- for(int i=0; i<bodies->num; i++){
- cpBody *body = (cpBody*)bodies->arr[i];
-
- cpFloat thresh = (dvsq ? body->m*dvsq : 0.0f);
- body->node.idleTime = (cpBodyKineticEnergy(body) > thresh ? 0.0f : body->node.idleTime + dt);
- }
-
- // iterate graph edges and build forests
- for(int i=0; i<arbiters->num; i++){
- cpArbiter *arb = (cpArbiter*)arbiters->arr[i];
- mergeBodies(space, components, rogueBodies, arb->private_a->body, arb->private_b->body);
- }
- for(int j=0; j<constraints->num; j++){
- cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
- mergeBodies(space, components, rogueBodies, constraint->a, constraint->b);
- }
-
- // iterate bodies and add them to their components
- for(int i=0; i<bodies->num; i++)
- addToComponent((cpBody*)bodies->arr[i], components);
- for(int i=0; i<rogueBodies->num; i++)
- addToComponent((cpBody*)rogueBodies->arr[i], components);
-
- // iterate components, copy or deactivate
- for(int i=0; i<components->num; i++){
- cpBody *root = (cpBody*)components->arr[i];
- if(componentActive(root, space->sleepTimeThreshold)){
- cpBody *body = root, *next;
- do {
- next = body->node.next;
-
- if(!cpBodyIsRogue(body)) cpArrayPush(newBodies, body);
- body->node.next = NULL;
- body->node.parent = NULL;
- body->node.rank = 0;
- } while((body = next) != root);
- } else {
- cpBody *body = root, *next;
- do {
- next = body->node.next;
-
- for(cpShape *shape = body->shapesList; shape; shape = shape->next){
- removeShapeRaw(shape, space->activeShapes);
- addShapeRaw(shape, space->staticShapes);
- }
- } while((body = next) != root);
-
- cpArrayPush(space->sleepingComponents, root);
- }
- }
-
- space->bodies = newBodies;
- cpArrayFree(bodies);
- cpArrayFree(rogueBodies);
- cpArrayFree(components);
-}
-
-#pragma mark All Important cpSpaceStep() Function
-
void
-cpSpaceStep(cpSpace *space, cpFloat dt)
+cpSpaceRehashShape(cpSpace *space, cpShape *shape)
{
- if(!dt) return; // don't step if the timestep is 0!
-
- cpFloat dt_inv = 1.0f/dt;
-
- cpArray *bodies = space->bodies;
- cpArray *constraints = space->constraints;
-
- space->locked = cpTrue;
-
- // Empty the arbiter list.
- space->arbiters->num = 0;
-
- // Integrate positions.
- for(int i=0; i<bodies->num; i++){
- cpBody *body = (cpBody *)bodies->arr[i];
- body->position_func(body, dt);
- }
-
- // Pre-cache BBoxes and shape data.
- cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)updateBBCache, NULL);
-
- // Collide!
- cpSpacePushNewContactBuffer(space);
- if(space->staticShapes->handleSet->entries)
- cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)active2staticIter, space);
- cpSpaceHashQueryRehash(space->activeShapes, (cpSpaceHashQueryFunc)queryFunc, space);
-
- // If body sleeping is enabled, do that now.
- if(space->sleepTimeThreshold != INFINITY){
- processContactComponents(space, dt);
- bodies = space->bodies; // rebuilt by processContactComponents()
- }
-
- // Clear out old cached arbiters and dispatch untouch functions
- cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilter, space);
-
- // Prestep the arbiters.
- cpArray *arbiters = space->arbiters;
- for(int i=0; i<arbiters->num; i++)
- cpArbiterPreStep((cpArbiter *)arbiters->arr[i], dt_inv);
-
- // Prestep the constraints.
- for(int i=0; i<constraints->num; i++){
- cpConstraint *constraint = (cpConstraint *)constraints->arr[i];
- constraint->klass->preStep(constraint, dt, dt_inv);
- }
-
- for(int i=0; i<space->elasticIterations; i++){
- for(int j=0; j<arbiters->num; j++)
- cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], 1.0f);
-
- for(int j=0; j<constraints->num; j++){
- cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
- constraint->klass->applyImpulse(constraint);
- }
- }
-
- // Integrate velocities.
- cpFloat damping = cpfpow(1.0f/space->damping, -dt);
- for(int i=0; i<bodies->num; i++){
- cpBody *body = (cpBody *)bodies->arr[i];
- body->velocity_func(body, space->gravity, damping, dt);
- }
-
- for(int i=0; i<arbiters->num; i++)
- cpArbiterApplyCachedImpulse((cpArbiter *)arbiters->arr[i]);
-
- // run the old-style elastic solver if elastic iterations are disabled
- cpFloat elasticCoef = (space->elasticIterations ? 0.0f : 1.0f);
-
- // Run the impulse solver.
- for(int i=0; i<space->iterations; i++){
- for(int j=0; j<arbiters->num; j++)
- cpArbiterApplyImpulse((cpArbiter *)arbiters->arr[j], elasticCoef);
-
- for(int j=0; j<constraints->num; j++){
- cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
- constraint->klass->applyImpulse(constraint);
- }
- }
-
- space->locked = cpFalse;
-
- // run the post solve callbacks
- for(int i=0; i<arbiters->num; i++){
- cpArbiter *arb = (cpArbiter *) arbiters->arr[i];
-
- cpCollisionHandler *handler = arb->handler;
- handler->postSolve(arb, space, handler->data);
-
- arb->state = cpArbiterStateNormal;
- }
-
- // Run the post step callbacks
- while(space->postStepCallbacks->entries){
- cpHashSet *callbacks = space->postStepCallbacks;
- space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql, (cpHashSetTransFunc)postStepFuncSetTrans);
- cpHashSetEach(callbacks, (cpHashSetIterFunc)postStepCallbackSetIter, space);
- }
+ cpShapeCacheBB(shape);
- // Increment the stamp.
- space->stamp++;
+ // attempt to rehash the shape in both hashes
+ cpSpaceHashRehashObject(space->activeShapes, shape, shape->hashid);
+ cpSpaceHashRehashObject(space->staticShapes, shape, shape->hashid);
}
View
237 external/Chipmunk/src/cpSpaceComponent.c
@@ -0,0 +1,237 @@
+/* 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 <stdlib.h>
+
+#include "chipmunk.h"
+
+#pragma mark Sleeping Functions
+
+// Chipmunk uses a data structure called a disjoint set forest.
+// My attempts to find a way to splice circularly linked lists in
+// constant time failed, and so I found this neat data structure instead.
+
+static inline cpBody *
+componentNodeRoot(cpBody *body)
+{
+ cpBody *parent = body->node.parent;
+
+ if(parent){
+ // path compression, attaches this node directly to the root
+ return (body->node.parent = componentNodeRoot(parent));
+ } else {
+ return body;
+ }
+}
+
+static inline void
+componentNodeMerge(cpBody *a_root, cpBody *b_root)
+{
+ if(a_root->node.rank < b_root->node.rank){
+ a_root->node.parent = b_root;
+ } else if(a_root->node.rank > b_root->node.rank){
+ b_root->node.parent = a_root;
+ } else if(a_root != b_root){
+ b_root->node.parent = a_root;
+ a_root->node.rank++;
+ }
+}
+
+static inline void
+componentActivate(cpBody *root)
+{
+ if(!cpBodyIsSleeping(root)) return;
+
+ cpSpace *space = root->space;
+ cpAssert(space, "Trying to activate a body that was never added to a space.");
+
+ cpBody *body = root, *next;
+ do {
+ next = body->node.next;
+
+ cpComponentNode node = {NULL, NULL, 0, 0.0f};
+ body->node = node;
+ cpArrayPush(space->bodies, body);
+
+ for(cpShape *shape=body->shapesList; shape; shape=shape->next){
+ cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
+ cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
+ }
+ } while((body = next) != root);
+
+ cpArrayDeleteObj(space->sleepingComponents, root);
+}
+
+void
+cpBodyActivate(cpBody *body)
+{
+ // Reset the idle time even if it's not in a currently sleeping component
+ // Like a body resting on or jointed to a rogue body.
+ body->node.idleTime = 0.0f;
+ componentActivate(componentNodeRoot(body));
+}
+
+static inline void
+mergeBodies(cpSpace *space, cpArray *components, cpArray *rogueBodies, cpBody *a, cpBody *b)
+{
+ // Don't merge with the static body
+ if(cpBodyIsStatic(a) || cpBodyIsStatic(b)) return;
+
+ cpBody *a_root = componentNodeRoot(a);
+ cpBody *b_root = componentNodeRoot(b);
+
+ cpBool a_sleep = cpBodyIsSleeping(a_root);
+ cpBool b_sleep = cpBodyIsSleeping(b_root);
+
+ if(a_sleep && b_sleep){
+ return;
+ } else if(a_sleep || b_sleep){
+ componentActivate(a_root);
+ componentActivate(b_root);
+ }
+
+ // Add any rogue bodies (bodies not added to the space)
+ if(!a->space) cpArrayPush(rogueBodies, a);
+ if(!b->space) cpArrayPush(rogueBodies, b);
+
+ componentNodeMerge(a_root, b_root);
+}
+
+static inline cpBool
+componentActive(cpBody *root, cpFloat threshold)
+{
+ cpBody *body = root, *next;
+ do {
+ next = body->node.next;
+ if(cpBodyIsRogue(body) || body->node.idleTime < threshold) return cpTrue;
+ } while((body = next) != root);
+
+ return cpFalse;
+}
+
+static inline void
+addToComponent(cpBody *body, cpArray *components)
+{
+ // Check that the body is not already added to the component list
+ if(body->node.next) return;
+ cpBody *root = componentNodeRoot(body);
+
+ cpBody *next = root->node.next;
+ if(!next){
+ // If the root isn't part of a list yet, then it hasn't been
+ // added to the components list. Do that now.
+ cpArrayPush(components, root);
+ // Start the list
+ body->node.next = root;
+ root->node.next = body;
+ } else if(root != body) {
+ // Splice in body after the root.
+ body->node.next = next;
+ root->node.next = body;
+ }
+}
+
+// TODO this function needs more commenting.
+void
+cpSpaceProcessComponents(cpSpace *space, cpFloat dt)
+{
+ cpArray *bodies = space->bodies;
+ cpArray *newBodies = cpArrayNew(bodies->num);
+ cpArray *rogueBodies = cpArrayNew(16);
+ cpArray *arbiters = space->arbiters;
+ cpArray *constraints = space->constraints;
+ cpArray *components = cpArrayNew(bodies->num/8);
+
+ cpFloat dv = space->idleSpeedThreshold;
+ cpFloat dvsq = (dv ? dv*dv : cpvdot(space->gravity, space->gravity)*dt*dt);
+ // update idling
+ for(int i=0; i<bodies->num; i++){
+ cpBody *body = (cpBody*)bodies->arr[i];
+
+ cpFloat thresh = (dvsq ? body->m*dvsq : 0.0f);
+ body->node.idleTime = (cpBodyKineticEnergy(body) > thresh ? 0.0f : body->node.idleTime + dt);
+ }
+
+ // iterate graph edges and build forests
+ for(int i=0; i<arbiters->num; i++){
+ cpArbiter *arb = (cpArbiter*)arbiters->arr[i];
+ mergeBodies(space, components, rogueBodies, arb->private_a->body, arb->private_b->body);
+ }
+ for(int j=0; j<constraints->num; j++){
+ cpConstraint *constraint = (cpConstraint *)constraints->arr[j];
+ mergeBodies(space, components, rogueBodies, constraint->a, constraint->b);
+ }
+
+ // iterate bodies and add them to their components
+ for(int i=0; i<bodies->num; i++)
+ addToComponent((cpBody*)bodies->arr[i], components);
+ for(int i=0; i<rogueBodies->num; i++)
+ addToComponent((cpBody*)rogueBodies->arr[i], components);
+
+ // iterate components, copy or deactivate
+ for(int i=0; i<components->num; i++){
+ cpBody *root = (cpBody*)components->arr[i];
+ if(componentActive(root, space->sleepTimeThreshold)){
+ cpBody *body = root, *next;
+ do {
+ next = body->node.next;
+
+ if(!cpBodyIsRogue(body)) cpArrayPush(newBodies, body);
+ body->node.next = NULL;
+ body->node.parent = NULL;
+ body->node.rank = 0;
+ } while((body = next) != root);
+ } else {
+ cpBody *body = root, *next;
+ do {
+ next = body->node.next;
+
+ for(cpShape *shape = body->shapesList; shape; shape = shape->next){
+ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
+ cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
+ }
+ } while((body = next) != root);
+
+ cpArrayPush(space->sleepingComponents, root);
+ }
+ }
+
+ space->bodies = newBodies;
+ cpArrayFree(bodies);
+ cpArrayFree(rogueBodies);
+ cpArrayFree(components);
+}
+
+void
+cpSpaceSleepBody(cpSpace *space, cpBody *body){
+ cpComponentNode node = {NULL, body, 0, 0.0f};
+ body->node = node;
+
+ for(cpShape *shape = body->shapesList; shape; shape = shape->next){
+ cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
+
+ cpShapeCacheBB(shape);
+ cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
+ }
+
+ cpArrayPush(space->sleepingComponents, body);
+ cpArrayDeleteObj(space->bodies, body);
+}
View
160 external/Chipmunk/src/cpSpaceHash.c
@@ -36,11 +36,7 @@ cpHandleInit(cpHandle *hand, void *obj)
return hand;
}
-static inline void
-cpHandleRetain(cpHandle *hand)
-{
- hand->retain++;
-}
+static inline void cpHandleRetain(cpHandle *hand){hand->retain++;}
static inline void
cpHandleRelease(cpHandle *hand, cpArray *pooledHandles)
@@ -55,7 +51,7 @@ cpSpaceHashAlloc(void)
return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash));
}
-// Frees the old table, and allocates a new one.
+// Frees the old table, and allocate a new one.
static void
cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
{
@@ -127,7 +123,6 @@ clearHashCell(cpSpaceHash *hash, int idx)
while(bin){
cpSpaceHashBin *next = bin->next;
- // Release the lock on the handle.
cpHandleRelease(bin->handle, hash->pooledHandles);
recycleBin(hash, bin);
@@ -261,36 +256,32 @@ hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
}
void
-cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB bb)
+cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB _deprecated_unused)
{
cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash);
- hashHandle(hash, hand, bb);
+ hashHandle(hash, hand, hash->bbfunc(obj));
}
void
cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue hashid)
{
- cpHandle *hand = (cpHandle *)cpHashSetFind(hash->handleSet, hashid, obj);
- hashHandle(hash, hand, hash->bbfunc(obj));
-}
-
-// Hashset iterator function for rehashing the spatial hash. (hash hash hash hash?)
-static void
-handleRehashHelper(void *elt, void *data)
-{
- cpHandle *hand = (cpHandle *)elt;
- cpSpaceHash *hash = (cpSpaceHash *)data;
+ cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
- hashHandle(hash, hand, hash->bbfunc(hand->obj));
+ if(hand){
+ hand->obj = NULL;
+ cpHandleRelease(hand, hash->pooledHandles);
+
+ cpSpaceHashInsert(hash, obj, hashid, cpBBNew(0.0f, 0.0f, 0.0f, 0.0f));
+ }
}
+static void handleRehashHelper(cpHandle *hand, cpSpaceHash *hash){hashHandle(hash, hand, hash->bbfunc(hand->obj));}
+
void
cpSpaceHashRehash(cpSpaceHash *hash)
{
clearHash(hash);
-
- // Rehash all of the handles.
- cpHashSetEach(hash->handleSet, &handleRehashHelper, hash);
+ cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)handleRehashHelper, hash);
}
void
@@ -304,73 +295,62 @@ cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid)
}
}
-// Used by the cpSpaceHashEach() iterator.
typedef struct eachPair {
cpSpaceHashIterator func;
void *data;
} eachPair;
-// Calls the user iterator function. (Gross I know.)
-static void
-eachHelper(void *elt, void *data)
-{
- cpHandle *hand = (cpHandle *)elt;
- eachPair *pair = (eachPair *)data;
-
- pair->func(hand->obj, pair->data);
-}
+static void eachHelper(cpHandle *hand, eachPair *pair){pair->func(hand->obj, pair->data);}
// Iterate over the objects in the spatial hash.
void
cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data)
{
- // Bundle the callback up to send to the hashset iterator.
eachPair pair = {func, data};
-
- cpHashSetEach(hash->handleSet, &eachHelper, &pair);
+ cpHashSetEach(hash->handleSet, (cpHashSetIterFunc)eachHelper, &pair);
}
-// Calls the callback function for the objects in a given chain.
static inline void
-query(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashQueryFunc func, void *data)
+removeOrphanedHandles(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr)
{
cpSpaceHashBin *bin = *bin_ptr;
while(bin){
-// for(cpSpaceHashBin *bin=*bin_ptr; bin; bin_ptr=&bin->next, bin=bin->next){
cpHandle *hand = bin->handle;
- void *other = hand->obj;
+ cpSpaceHashBin *next = bin->next;
- // Skip over certain conditions
- if(
- // Have we already tried this pair in the currnt query in a different cell?
- hand->stamp == hash->stamp
- // Is obj the same as other?
- || obj == other
- ){
+ 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 = bin->next;
- continue;
}
- if(other){
+ bin = next;
+ }
+}
+
+// Calls the callback function for the objects in a given chain.
+static inline void
+query(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashQueryFunc 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, data);
-
- // Stamp that the handle was checked already against this object.
hand->stamp = hash->stamp;
-
- bin_ptr = &bin->next;
- bin = bin->next;
- } else { // The object has been removed
- cpSpaceHashBin *next = bin->next;
-
- // unlink and recycle the bin
- (*bin_ptr) = bin->next;
- recycleBin(hash, bin);
-
- // release the reference to the handle
- cpHandleRelease(hand, hash->pooledHandles);
-
- bin = next;
+ } else {
+ // The object for this handle has been removed
+ // cleanup this cell and restart the query
+ removeOrphanedHandles(hash, bin_ptr);
+ goto restart; // GCC not smart enough/able to tail call an inlined function.
}
}
}
@@ -382,9 +362,6 @@ cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func
int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells); // Fix by ShiftZ
query(hash, &hash->table[idx], &point, func, data);
-
- // Increment the stamp.
- // Only one cell is checked, but query() requires it anyway.
hash->stamp++;
}
@@ -404,12 +381,10 @@ cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc fun
// Iterate over the cells and query them.
for(int i=l; i<=r; i++){
for(int j=b; j<=t; j++){
- int idx = hash_func(i,j,n);
- query(hash, &table[idx], obj, func, data);
+ query(hash, &table[hash_func(i,j,n)], obj, func, data);
}
}
- // Increment the stamp.
hash->stamp++;
}
@@ -446,9 +421,6 @@ handleQueryRehashHelper(void *elt, void *data)
for(int i=l; i<=r; i++){
for(int j=b; j<=t; j++){
-// // exit the loops if the object has been deleted in func().
-// if(!hand->obj) goto break_out;
-
int idx = hash_func(i,j,n);
cpSpaceHashBin *bin = table[idx];
@@ -464,8 +436,7 @@ handleQueryRehashHelper(void *elt, void *data)
}
}
-// break_out:
- // Increment the stamp for each object we hash.
+ // Increment the stamp for each object hashed.
hash->stamp++;
}
@@ -479,26 +450,27 @@ cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)
}
static inline cpFloat
-segmentQuery(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashSegmentQueryFunc func, void *data)
+segmentQuery(cpSpaceHash *hash, cpSpaceHashBin **bin_ptr, void *obj, cpSpaceHashSegmentQueryFunc func, void *data)
{
cpFloat t = 1.0f;
- for(; bin; bin = bin->next){
+ restart:
+ for(cpSpaceHashBin *bin = *bin_ptr; bin; bin = bin->next){
cpHandle *hand = bin->handle;
void *other = hand->obj;
// Skip over certain conditions
- if(
- // Have we already tried this pair in this query?
- hand->stamp == hash->stamp
- // Has other been removed since the last rehash?
- || !other
- ) continue;
-
- // Stamp that the handle was checked already against this object.
- hand->stamp = hash->stamp;
-
- t = cpfmin(t, func(obj, other, data));
+ 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
+ removeOrphanedHandles(hash, bin_ptr);
+ goto restart; // GCC not smart enough/able to tail call an inlined function.