From e7701217119fa639d1cc2406890dd15ecc04a256 Mon Sep 17 00:00:00 2001 From: Ricardo Quesada Date: Tue, 11 Jun 2013 17:03:20 -0700 Subject: [PATCH] updates chipmunk2d to v6.1.5 --- external/chipmunk/include/chipmunk/chipmunk.h | 22 +++-- .../chipmunk/include/chipmunk/chipmunk_ffi.h | 4 + .../include/chipmunk/chipmunk_types.h | 2 +- .../constraints/cpDampedRotarySpring.h | 1 + .../chipmunk/constraints/cpDampedSpring.h | 2 + .../chipmunk/include/chipmunk/cpArbiter.h | 19 +++- external/chipmunk/include/chipmunk/cpBody.h | 1 + external/chipmunk/include/chipmunk/cpSpace.h | 7 ++ external/chipmunk/src/CMakeLists.txt | 12 ++- .../src/constraints/cpDampedRotarySpring.c | 10 ++- .../chipmunk/src/constraints/cpDampedSpring.c | 13 ++- external/chipmunk/src/cpArbiter.c | 87 +++++++++++-------- external/chipmunk/src/cpShape.c | 24 +++-- external/chipmunk/src/cpSpace.c | 57 ++++++++++-- external/chipmunk/src/cpSpaceComponent.c | 20 ++++- external/chipmunk/src/cpSpaceStep.c | 43 +++++---- external/chipmunk/src/cpVect.c | 7 +- 17 files changed, 233 insertions(+), 98 deletions(-) diff --git a/external/chipmunk/include/chipmunk/chipmunk.h b/external/chipmunk/include/chipmunk/chipmunk.h index abc50b0c99..49023a343e 100644 --- a/external/chipmunk/include/chipmunk/chipmunk.h +++ b/external/chipmunk/include/chipmunk/chipmunk.h @@ -22,6 +22,10 @@ #ifndef CHIPMUNK_HEADER #define CHIPMUNK_HEADER +#ifdef _MSC_VER + #define _USE_MATH_DEFINES +#endif + #include #include @@ -34,26 +38,26 @@ extern "C" { #endif #if CP_ALLOW_PRIVATE_ACCESS == 1 - #define CP_PRIVATE(symbol) symbol + #define CP_PRIVATE(__symbol__) __symbol__ #else - #define CP_PRIVATE(symbol) symbol##_private + #define CP_PRIVATE(__symbol__) __symbol__##_private #endif void cpMessage(const char *condition, const char *file, int line, int isError, int isHardError, const char *message, ...); #ifdef NDEBUG - #define cpAssertWarn(condition, ...) + #define cpAssertWarn(__condition__, ...) #else - #define cpAssertWarn(condition, ...) if(!(condition)) cpMessage(#condition, __FILE__, __LINE__, 0, 0, __VA_ARGS__) + #define cpAssertWarn(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 0, 0, __VA_ARGS__) #endif #ifdef NDEBUG - #define cpAssertSoft(condition, ...) + #define cpAssertSoft(__condition__, ...) #else - #define cpAssertSoft(condition, ...) if(!(condition)) cpMessage(#condition, __FILE__, __LINE__, 1, 0, __VA_ARGS__) + #define cpAssertSoft(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 1, 0, __VA_ARGS__) #endif // Hard assertions are important and cheap to execute. They are not disabled by compiling as debug. -#define cpAssertHard(condition, ...) if(!(condition)) cpMessage(#condition, __FILE__, __LINE__, 1, 1, __VA_ARGS__) +#define cpAssertHard(__condition__, ...) if(!(__condition__)) cpMessage(#__condition__, __FILE__, __LINE__, 1, 1, __VA_ARGS__) #include "chipmunk_types.h" @@ -106,10 +110,10 @@ typedef struct cpSpace cpSpace; #include "cpSpace.h" -// Chipmunk 6.1.2 +// Chipmunk 6.1.5 #define CP_VERSION_MAJOR 6 #define CP_VERSION_MINOR 1 -#define CP_VERSION_RELEASE 2 +#define CP_VERSION_RELEASE 5 /// Version string. extern const char *cpVersionString; diff --git a/external/chipmunk/include/chipmunk/chipmunk_ffi.h b/external/chipmunk/include/chipmunk/chipmunk_ffi.h index 1960f5cb5a..53ac6937c2 100644 --- a/external/chipmunk/include/chipmunk/chipmunk_ffi.h +++ b/external/chipmunk/include/chipmunk/chipmunk_ffi.h @@ -27,9 +27,12 @@ MAKE_REF(cpvcross); MAKE_REF(cpvperp); MAKE_REF(cpvrperp); MAKE_REF(cpvproject); +MAKE_REF(cpvforangle); +MAKE_REF(cpvtoangle); MAKE_REF(cpvrotate); MAKE_REF(cpvunrotate); MAKE_REF(cpvlengthsq); +MAKE_REF(cpvlength); MAKE_REF(cpvlerp); MAKE_REF(cpvnormalize); MAKE_REF(cpvnormalize_safe); @@ -57,6 +60,7 @@ MAKE_REF(cpBBArea); MAKE_REF(cpBBMergedArea); MAKE_REF(cpBBSegmentQuery); MAKE_REF(cpBBIntersectsSegment); +MAKE_REF(cpBBClampVect); MAKE_REF(cpBodyGetMass); MAKE_REF(cpBodyGetMoment); diff --git a/external/chipmunk/include/chipmunk/chipmunk_types.h b/external/chipmunk/include/chipmunk/chipmunk_types.h index 5124d4868f..8b27d709b5 100644 --- a/external/chipmunk/include/chipmunk/chipmunk_types.h +++ b/external/chipmunk/include/chipmunk/chipmunk_types.h @@ -4,7 +4,7 @@ #include "TargetConditionals.h" #endif -#if (TARGET_OS_IPHONE == 1) || (TARGET_OS_MAC == 1) && (!defined CP_USE_CGPOINTS) +#if ((TARGET_OS_IPHONE == 1) || (TARGET_OS_MAC == 1)) && (!defined CP_USE_CGPOINTS) #define CP_USE_CGPOINTS 1 #endif diff --git a/external/chipmunk/include/chipmunk/constraints/cpDampedRotarySpring.h b/external/chipmunk/include/chipmunk/constraints/cpDampedRotarySpring.h index ea0540ca94..86cf915b2d 100644 --- a/external/chipmunk/include/chipmunk/constraints/cpDampedRotarySpring.h +++ b/external/chipmunk/include/chipmunk/constraints/cpDampedRotarySpring.h @@ -38,6 +38,7 @@ typedef struct cpDampedRotarySpring { cpFloat w_coef; cpFloat iSum; + cpFloat jAcc; } cpDampedRotarySpring; /// Allocate a damped rotary spring. diff --git a/external/chipmunk/include/chipmunk/constraints/cpDampedSpring.h b/external/chipmunk/include/chipmunk/constraints/cpDampedSpring.h index a3185ef4d6..f5120647f9 100644 --- a/external/chipmunk/include/chipmunk/constraints/cpDampedSpring.h +++ b/external/chipmunk/include/chipmunk/constraints/cpDampedSpring.h @@ -43,6 +43,8 @@ struct cpDampedSpring { cpVect r1, r2; cpFloat nMass; cpVect n; + + cpFloat jAcc; }; /// Allocate a damped spring. diff --git a/external/chipmunk/include/chipmunk/cpArbiter.h b/external/chipmunk/include/chipmunk/cpArbiter.h index 94e141bf55..4891948184 100644 --- a/external/chipmunk/include/chipmunk/cpArbiter.h +++ b/external/chipmunk/include/chipmunk/cpArbiter.h @@ -117,7 +117,15 @@ CP_DefineArbiterStructSetter(type, member, name) CP_DefineArbiterStructProperty(cpFloat, e, Elasticity) CP_DefineArbiterStructProperty(cpFloat, u, Friction) -CP_DefineArbiterStructProperty(cpVect, surface_vr, SurfaceVelocity) + +// Get the relative surface velocity of the two shapes in contact. +cpVect cpArbiterGetSurfaceVelocity(cpArbiter *arb); + +// Override the relative surface velocity of the two shapes in contact. +// By default this is calculated to be the difference of the two +// surface velocities clamped to the tangent plane. +void cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr); + CP_DefineArbiterStructProperty(cpDataPointer, data, UserData) /// Calculate the total impulse that was applied by this arbiter. @@ -148,7 +156,7 @@ static inline void cpArbiterGetShapes(const cpArbiter *arb, cpShape **a, cpShape } } /// 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); +#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 @@ -160,7 +168,7 @@ static inline void cpArbiterGetBodies(const cpArbiter *arb, cpBody **a, cpBody * (*b) = shape_b->body; } /// A macro shortcut for defining and retrieving the bodies from an arbiter. -#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b); +#define CP_ARBITER_GET_BODIES(__arb__, __a__, __b__) cpBody *__a__, *__b__; cpArbiterGetBodies(__arb__, &__a__, &__b__); /// A struct that wraps up the important collision data for an arbiter. typedef struct cpContactPointSet { @@ -177,9 +185,14 @@ typedef struct cpContactPointSet { cpFloat dist; } points[CP_MAX_CONTACTS_PER_ARBITER]; } cpContactPointSet; + /// Return a contact set from an arbiter. cpContactPointSet cpArbiterGetContactPointSet(const cpArbiter *arb); +/// Replace the contact point set for an arbiter. +/// This can be a very powerful feature, but use it with caution! +void cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set); + /// Returns true if this is the first step a pair of objects started colliding. cpBool cpArbiterIsFirstContact(const cpArbiter *arb); /// Get the number of contact points for this arbiter. diff --git a/external/chipmunk/include/chipmunk/cpBody.h b/external/chipmunk/include/chipmunk/cpBody.h index eadd991db3..6168b0fe67 100644 --- a/external/chipmunk/include/chipmunk/cpBody.h +++ b/external/chipmunk/include/chipmunk/cpBody.h @@ -148,6 +148,7 @@ static inline cpBool cpBodyIsStatic(const cpBody *body) } /// Returns true if the body has not been added to a space. +/// Note: Static bodies are a subtype of rogue bodies. static inline cpBool cpBodyIsRogue(const cpBody *body) { return (body->CP_PRIVATE(space) == ((cpSpace*)0)); diff --git a/external/chipmunk/include/chipmunk/cpSpace.h b/external/chipmunk/include/chipmunk/cpSpace.h index 58461eab7e..26439f76c3 100644 --- a/external/chipmunk/include/chipmunk/cpSpace.h +++ b/external/chipmunk/include/chipmunk/cpSpace.h @@ -201,6 +201,13 @@ cpBool cpSpaceContainsBody(cpSpace *space, cpBody *body); /// Test if a constraint has been added to the space. cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint); +/// Convert a dynamic rogue body to a static one. +/// If the body is active, you must remove it from the space first. +void cpSpaceConvertBodyToStatic(cpSpace *space, cpBody *body); +/// Convert a body to a dynamic rogue body. +/// If you want the body to be active after the transition, you must add it to the space also. +void cpSpaceConvertBodyToDynamic(cpSpace *space, cpBody *body, cpFloat mass, cpFloat moment); + /// Post Step callback function type. typedef void (*cpPostStepFunc)(cpSpace *space, void *key, void *data); /// Schedule a post-step callback to be called when cpSpaceStep() finishes. diff --git a/external/chipmunk/src/CMakeLists.txt b/external/chipmunk/src/CMakeLists.txt index d55ebe6365..6f10d0177d 100644 --- a/external/chipmunk/src/CMakeLists.txt +++ b/external/chipmunk/src/CMakeLists.txt @@ -8,8 +8,13 @@ if(BUILD_SHARED) add_library(chipmunk SHARED ${chipmunk_source_files} ) + # Tell MSVC to compile the code as C++. + if(MSVC) + set_source_files_properties(${chipmunk_source_files} PROPERTIES LANGUAGE CXX) + set_target_properties(chipmunk PROPERTIES LINKER_LANGUAGE CXX) + endif(MSVC) # set the lib's version number - set_target_properties(chipmunk PROPERTIES VERSION 6.1.2) + set_target_properties(chipmunk PROPERTIES VERSION 6.1.5) install(TARGETS chipmunk RUNTIME DESTINATION lib LIBRARY DESTINATION lib) endif(BUILD_SHARED) @@ -17,6 +22,11 @@ if(BUILD_STATIC) add_library(chipmunk_static STATIC ${chipmunk_source_files} ) + # Tell MSVC to compile the code as C++. + if(MSVC) + set_source_files_properties(${chipmunk_source_files} PROPERTIES LANGUAGE CXX) + set_target_properties(chipmunk_static PROPERTIES LINKER_LANGUAGE CXX) + endif(MSVC) # Sets chipmunk_static to output "libchipmunk.a" not "libchipmunk_static.a" set_target_properties(chipmunk_static PROPERTIES OUTPUT_NAME chipmunk) if(INSTALL_STATIC) diff --git a/external/chipmunk/src/constraints/cpDampedRotarySpring.c b/external/chipmunk/src/constraints/cpDampedRotarySpring.c index 5bc20950a5..f57c289e7f 100644 --- a/external/chipmunk/src/constraints/cpDampedRotarySpring.c +++ b/external/chipmunk/src/constraints/cpDampedRotarySpring.c @@ -42,6 +42,8 @@ preStep(cpDampedRotarySpring *spring, cpFloat dt) // 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; } @@ -64,14 +66,16 @@ applyImpulse(cpDampedRotarySpring *spring, cpFloat dt) //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(cpConstraint *constraint) +getImpulse(cpDampedRotarySpring *spring) { - return 0.0f; + return spring->jAcc; } static const cpConstraintClass klass = { @@ -98,6 +102,8 @@ cpDampedRotarySpringInit(cpDampedRotarySpring *spring, cpBody *a, cpBody *b, cpF spring->damping = damping; spring->springTorqueFunc = (cpDampedRotarySpringTorqueFunc)defaultSpringTorque; + spring->jAcc = 0.0f; + return spring; } diff --git a/external/chipmunk/src/constraints/cpDampedSpring.c b/external/chipmunk/src/constraints/cpDampedSpring.c index adf888b0cb..5a855f818d 100644 --- a/external/chipmunk/src/constraints/cpDampedSpring.c +++ b/external/chipmunk/src/constraints/cpDampedSpring.c @@ -49,7 +49,8 @@ preStep(cpDampedSpring *spring, cpFloat dt) // apply spring force cpFloat f_spring = spring->springForceFunc((cpConstraint *)spring, dist); - apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, f_spring*dt)); + 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){} @@ -71,13 +72,15 @@ applyImpulse(cpDampedSpring *spring, cpFloat dt) cpFloat v_damp = (spring->target_vrn - vrn)*spring->v_coef; spring->target_vrn = vrn + v_damp; - apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass)); + 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(cpConstraint *constraint) +getImpulse(cpDampedSpring *spring) { - return 0.0f; + return spring->jAcc; } static const cpConstraintClass klass = { @@ -107,6 +110,8 @@ cpDampedSpringInit(cpDampedSpring *spring, cpBody *a, cpBody *b, cpVect anchr1, spring->damping = damping; spring->springForceFunc = (cpDampedSpringForceFunc)defaultSpringForce; + spring->jAcc = 0.0f; + return spring; } diff --git a/external/chipmunk/src/cpArbiter.c b/external/chipmunk/src/cpArbiter.c index 690d2fd136..ef6f09809c 100644 --- a/external/chipmunk/src/cpArbiter.c +++ b/external/chipmunk/src/cpArbiter.c @@ -48,7 +48,10 @@ unthreadHelper(cpArbiter *arb, cpBody *body) if(prev){ cpArbiterThreadForBody(prev, body)->next = next; - } else { + } 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; } @@ -107,8 +110,7 @@ cpArbiterGetContactPointSet(const cpArbiter *arb) cpContactPointSet set; set.count = cpArbiterGetCount(arb); - int i; - for(i=0; iCP_PRIVATE(contacts)[i].CP_PRIVATE(p); set.points[i].normal = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(n); set.points[i].dist = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist); @@ -117,6 +119,18 @@ cpArbiterGetContactPointSet(const cpArbiter *arb) return set; } +void +cpArbiterSetContactPointSet(cpArbiter *arb, cpContactPointSet *set) +{ + int count = set->count; + cpAssertHard(count == arb->numContacts, "The number of contact points cannot be changed."); + + for(int i=0; icontacts[i].p = set->points[i].point; + arb->contacts[i].n = set->points[i].normal; + arb->contacts[i].dist = set->points[i].dist; + } +} cpVect cpArbiterTotalImpulse(const cpArbiter *arb) @@ -164,30 +178,25 @@ cpArbiterTotalKE(const cpArbiter *arb) return sum; } -//cpFloat -//cpContactsEstimateCrushingImpulse(cpContact *contacts, int numContacts) -//{ -// cpFloat fsum = 0.0f; -// cpVect vsum = cpvzero; -// -// for(int i=0; in, cpv(con->jnAcc, con->jtAcc)); -// -// fsum += cpvlength(j); -// vsum = cpvadd(vsum, j); -// } -// -// cpFloat vmag = cpvlength(vsum); -// return (1.0f - vmag/fsum); -//} - void cpArbiterIgnore(cpArbiter *arb) { arb->state = cpArbiterStateIgnore; } +cpVect +cpArbiterGetSurfaceVelocity(cpArbiter *arb) +{ + return cpvmult(arb->surface_vr, arb->swappedColl ? -1.0f : 1.0); +} + +void +cpArbiterSetSurfaceVelocity(cpArbiter *arb, cpVect vr) +{ + arb->surface_vr = cpvmult(vr, arb->swappedColl ? -1.0f : 1.0); +} + + cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b) { @@ -220,21 +229,18 @@ cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b) void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, cpCollisionHandler *handler, cpShape *a, cpShape *b) { - // Arbiters without contact data may exist if a collision function rejected the collision. - if(arb->contacts){ - // Iterate over the possible pairs to look for hash value matches. - for(int i=0; inumContacts; i++){ - cpContact *old = &arb->contacts[i]; + // Iterate over the possible pairs to look for hash value matches. + for(int i=0; inumContacts; j++){ + cpContact *old = &arb->contacts[j]; - for(int j=0; jhash == old->hash){ - // Copy the persistant contact information. - new_contact->jnAcc = old->jnAcc; - new_contact->jtAcc = old->jtAcc; - } + // 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; } } } @@ -247,7 +253,12 @@ cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, cpCollisio arb->e = a->e * b->e; arb->u = a->u * b->u; - arb->surface_vr = cpvsub(a->surface_v, b->surface_v); + + // Currently all contacts will have the same normal. + // This may change in the future. + cpVect n = (numContacts ? contacts[0].n : cpvzero); + cpVect surface_vr = cpvsub(a->surface_v, b->surface_v); + arb->surface_vr = cpvsub(surface_vr, cpvmult(n, cpvdot(surface_vr, n))); // For collisions between two similar primitive types, the order could have been swapped. arb->a = a; arb->body_a = a->body; @@ -317,11 +328,11 @@ cpArbiterApplyImpulse(cpArbiter *arb) 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 = relative_velocity(a, b, r1, r2); + 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(cpvadd(vr, surface_vr), cpvperp(n)); + cpFloat vrt = cpvdot(vr, cpvperp(n)); cpFloat jbn = (con->bias - vbn)*nMass; cpFloat jbnOld = con->jBias; diff --git a/external/chipmunk/src/cpShape.c b/external/chipmunk/src/cpShape.c index daaba77b29..a07cc5da75 100644 --- a/external/chipmunk/src/cpShape.c +++ b/external/chipmunk/src/cpShape.c @@ -133,7 +133,16 @@ cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info info = ␣ } - shape->klass->segmentQuery(shape, a, b, info); + cpNearestPointQueryInfo nearest; + shape->klass->nearestPointQuery(shape, a, &nearest); + if(nearest.d <= 0.0){ + info->shape = shape; + info->t = 0.0; + info->n = cpvnormalize(cpvsub(a, nearest.p)); + } else { + shape->klass->segmentQuery(shape, a, b, info); + } + return (info->shape != NULL); } @@ -165,13 +174,12 @@ cpCicleShapeNearestPointQuery(cpCircleShape *circle, cpVect p, cpNearestPointQue static void circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info) { - // offset the line to be relative to the circle - a = cpvsub(a, center); - b = cpvsub(b, center); + cpVect da = cpvsub(a, center); + cpVect db = cpvsub(b, center); - cpFloat qa = cpvdot(a, a) - 2.0f*cpvdot(a, b) + cpvdot(b, b); - cpFloat qb = -2.0f*cpvdot(a, a) + 2.0f*cpvdot(a, b); - cpFloat qc = cpvdot(a, a) - r*r; + cpFloat qa = cpvdot(da, da) - 2.0f*cpvdot(da, db) + cpvdot(db, db); + cpFloat qb = -2.0f*cpvdot(da, da) + 2.0f*cpvdot(da, db); + cpFloat qc = cpvdot(da, da) - r*r; cpFloat det = qb*qb - 4.0f*qa*qc; @@ -180,7 +188,7 @@ circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, if(0.0f<= t && t <= 1.0f){ info->shape = shape; info->t = t; - info->n = cpvnormalize(cpvlerp(a, b, t)); + info->n = cpvnormalize(cpvlerp(da, db, t)); } } } diff --git a/external/chipmunk/src/cpSpace.c b/external/chipmunk/src/cpSpace.c index 6501bca05b..111d0d2444 100644 --- a/external/chipmunk/src/cpSpace.c +++ b/external/chipmunk/src/cpSpace.c @@ -185,7 +185,7 @@ cpSpaceFree(cpSpace *space) #define cpAssertSpaceUnlocked(space) \ cpAssertHard(!space->locked, \ - "This addition/removal cannot be done safely during a call to cpSpaceStep() or during a query. " \ + "This operation cannot be done safely during a call to cpSpaceStep() or during a query. " \ "Put these calls into a post-step callback." \ ); @@ -259,7 +259,8 @@ cpSpaceAddShape(cpSpace *space, cpShape *shape) cpBody *body = shape->body; if(cpBodyIsStatic(body)) return cpSpaceAddStaticShape(space, shape); - cpAssertHard(!shape->space, "This shape is already added to a space and cannot be added to another."); + 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."); cpAssertSpaceUnlocked(space); cpBodyActivate(body); @@ -275,7 +276,9 @@ cpSpaceAddShape(cpSpace *space, cpShape *shape) cpShape * cpSpaceAddStaticShape(cpSpace *space, cpShape *shape) { - cpAssertHard(!shape->space, "This shape is already added to a space and cannot be added to another."); + 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(cpBodyIsRogue(shape->body), "You are adding a static shape to a dynamic body. Did you mean to attach it to a static or rogue body? See the documentation for more information."); cpAssertSpaceUnlocked(space); cpBody *body = shape->body; @@ -290,8 +293,9 @@ cpSpaceAddStaticShape(cpSpace *space, cpShape *shape) cpBody * cpSpaceAddBody(cpSpace *space, cpBody *body) { - cpAssertHard(!cpBodyIsStatic(body), "Static bodies cannot be added to a space as they are not meant to be simulated."); - cpAssertHard(!body->space, "This body is already added to a space and cannot be added to another."); + cpAssertHard(!cpBodyIsStatic(body), "Do not add static bodies to a space. Static bodies do not move and should not be simulated."); + 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(space->bodies, body); @@ -303,7 +307,9 @@ cpSpaceAddBody(cpSpace *space, cpBody *body) cpConstraint * cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint) { - cpAssertHard(!constraint->space, "This shape is already added to a space and cannot be added to another."); + 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."); + cpAssertHard(constraint->a && constraint->b, "Constraint is attached to a NULL body."); cpAssertSpaceUnlocked(space); cpBodyActivate(constraint->a); @@ -433,6 +439,45 @@ cpBool cpSpaceContainsConstraint(cpSpace *space, cpConstraint *constraint) return (constraint->space == space); } +//MARK: Static/rogue body conversion. + +void +cpSpaceConvertBodyToStatic(cpSpace *space, cpBody *body) +{ + cpAssertHard(!cpBodyIsStatic(body), "Body is already static."); + cpAssertHard(cpBodyIsRogue(body), "Remove the body from the space before calling this function."); + cpAssertSpaceUnlocked(space); + + cpBodySetMass(body, INFINITY); + cpBodySetMoment(body, INFINITY); + + cpBodySetVel(body, cpvzero); + cpBodySetAngVel(body, 0.0f); + + body->node.idleTime = INFINITY; + CP_BODY_FOREACH_SHAPE(body, shape){ + cpSpatialIndexRemove(space->activeShapes, shape, shape->hashid); + cpSpatialIndexInsert(space->staticShapes, shape, shape->hashid); + } +} + +void +cpSpaceConvertBodyToDynamic(cpSpace *space, cpBody *body, cpFloat m, cpFloat i) +{ + cpAssertHard(cpBodyIsStatic(body), "Body is already dynamic."); + cpAssertSpaceUnlocked(space); + + cpBodyActivateStatic(body, NULL); + + cpBodySetMass(body, m); + cpBodySetMoment(body, i); + + body->node.idleTime = 0.0f; + CP_BODY_FOREACH_SHAPE(body, shape){ + cpSpatialIndexRemove(space->staticShapes, shape, shape->hashid); + cpSpatialIndexInsert(space->activeShapes, shape, shape->hashid); + } +} //MARK: Iteration diff --git a/external/chipmunk/src/cpSpaceComponent.c b/external/chipmunk/src/cpSpaceComponent.c index 612ada0ce5..fe3ac84ebb 100644 --- a/external/chipmunk/src/cpSpaceComponent.c +++ b/external/chipmunk/src/cpSpaceComponent.c @@ -28,12 +28,13 @@ void cpSpaceActivateBody(cpSpace *space, cpBody *body) { - cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rouge body."); - + cpAssertHard(!cpBodyIsRogue(body), "Internal error: Attempting to activate a rogue 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->node.root == NULL && body->node.next == NULL, "Internal error: Activating body non-NULL node pointers."); cpArrayPush(space->bodies, body); CP_BODY_FOREACH_SHAPE(body, shape){ @@ -43,6 +44,11 @@ cpSpaceActivateBody(cpSpace *space, cpBody *body) 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 || cpBodyIsStatic(bodyA)){ int numContacts = arb->numContacts; cpContact *contacts = arb->contacts; @@ -140,6 +146,13 @@ cpBodyActivate(cpBody *body) body->node.idleTime = 0.0f; ComponentActivate(ComponentRoot(body)); } + + 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(!cpBodyIsStatic(other)) other->node.idleTime = 0.0f; + } } void @@ -300,10 +313,9 @@ cpBodySleep(cpBody *body) void cpBodySleepWithGroup(cpBody *body, cpBody *group){ - cpAssertHard(!cpBodyIsStatic(body) && !cpBodyIsRogue(body), "Rogue and static bodies cannot be put to sleep."); + cpAssertHard(!cpBodyIsRogue(body), "Rogue (and static) bodies cannot be put to sleep."); cpSpace *space = body->space; - cpAssertHard(space, "Cannot put a rogue body to sleep."); cpAssertHard(!space->locked, "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback."); cpAssertHard(group == NULL || cpBodyIsSleeping(group), "Cannot use a non-sleeping body as a group identifier."); diff --git a/external/chipmunk/src/cpSpaceStep.c b/external/chipmunk/src/cpSpaceStep.c index b5cd201035..f80b8d0e6a 100644 --- a/external/chipmunk/src/cpSpaceStep.c +++ b/external/chipmunk/src/cpSpaceStep.c @@ -29,7 +29,7 @@ cpSpaceGetPostStepCallback(cpSpace *space, void *key) cpArray *arr = space->postStepCallbacks; for(int i=0; inum; i++){ cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i]; - if(callback->key == key) return callback; + if(callback && callback->key == key) return callback; } return NULL; @@ -71,31 +71,36 @@ cpSpaceUnlock(cpSpace *space, cpBool runPostStep) space->locked--; cpAssertHard(space->locked >= 0, "Internal Error: Space lock underflow."); - if(space->locked == 0 && runPostStep && !space->skipPostStep){ - space->skipPostStep = cpTrue; - + if(space->locked == 0){ cpArray *waking = space->rousedBodies; + for(int i=0, count=waking->num; iarr[i]); waking->arr[i] = NULL; } - cpArray *arr = space->postStepCallbacks; - for(int i=0; inum; i++){ - cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i]; - cpPostStepFunc func = callback->func; - - // Mark the func as NULL in case calling it calls cpSpaceRunPostStepCallbacks() again. - callback->func = NULL; - if(func) func(space, callback->key, callback->data); - - arr->arr[i] = NULL; - cpfree(callback); - } - waking->num = 0; - arr->num = 0; - space->skipPostStep = cpFalse; + + if(space->locked == 0 && runPostStep && !space->skipPostStep){ + space->skipPostStep = cpTrue; + + cpArray *arr = space->postStepCallbacks; + for(int i=0; inum; 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; + } } } diff --git a/external/chipmunk/src/cpVect.c b/external/chipmunk/src/cpVect.c index ecd9960496..64d16639ef 100644 --- a/external/chipmunk/src/cpVect.c +++ b/external/chipmunk/src/cpVect.c @@ -23,14 +23,15 @@ #include "chipmunk_private.h" -inline cpVect +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 == 0.0){ - return v1; + 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));