mirror of https://github.com/axmolengine/axmol.git
Merge pull request #2876 from ricardoquesada/chipmunk_6_1_5
updates chipmunk2d to v6.1.5
This commit is contained in:
commit
6ef681bfff
|
@ -22,6 +22,10 @@
|
|||
#ifndef CHIPMUNK_HEADER
|
||||
#define CHIPMUNK_HEADER
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ typedef struct cpDampedRotarySpring {
|
|||
cpFloat w_coef;
|
||||
|
||||
cpFloat iSum;
|
||||
cpFloat jAcc;
|
||||
} cpDampedRotarySpring;
|
||||
|
||||
/// Allocate a damped rotary spring.
|
||||
|
|
|
@ -43,6 +43,8 @@ struct cpDampedSpring {
|
|||
cpVect r1, r2;
|
||||
cpFloat nMass;
|
||||
cpVect n;
|
||||
|
||||
cpFloat jAcc;
|
||||
};
|
||||
|
||||
/// Allocate a damped spring.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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; i<set.count; i++){
|
||||
for(int i=0; i<set.count; i++){
|
||||
set.points[i].point = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(p);
|
||||
set.points[i].normal = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(n);
|
||||
set.points[i].dist = arb->CP_PRIVATE(contacts)[i].CP_PRIVATE(dist);
|
||||
|
@ -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; i<count; i++){
|
||||
arb->contacts[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; i<numContacts; i++){
|
||||
// cpContact *con = &contacts[i];
|
||||
// cpVect j = cpvrotate(con->n, 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; i<arb->numContacts; i++){
|
||||
cpContact *old = &arb->contacts[i];
|
||||
// Iterate over the possible pairs to look for hash value matches.
|
||||
for(int i=0; i<numContacts; i++){
|
||||
cpContact *con = &contacts[i];
|
||||
|
||||
for(int j=0; j<arb->numContacts; j++){
|
||||
cpContact *old = &arb->contacts[j];
|
||||
|
||||
for(int j=0; j<numContacts; j++){
|
||||
cpContact *new_contact = &contacts[j];
|
||||
|
||||
// This could trigger false positives, but is fairly unlikely nor serious if it does.
|
||||
if(new_contact->hash == 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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.");
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ cpSpaceGetPostStepCallback(cpSpace *space, void *key)
|
|||
cpArray *arr = space->postStepCallbacks;
|
||||
for(int i=0; i<arr->num; i++){
|
||||
cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
|
||||
if(callback->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; i<count; i++){
|
||||
cpSpaceActivateBody(space, (cpBody *)waking->arr[i]);
|
||||
waking->arr[i] = NULL;
|
||||
}
|
||||
|
||||
cpArray *arr = space->postStepCallbacks;
|
||||
for(int i=0; i<arr->num; i++){
|
||||
cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
|
||||
cpPostStepFunc func = callback->func;
|
||||
|
||||
// Mark the func as NULL in case calling it calls cpSpaceRunPostStepCallbacks() again.
|
||||
callback->func = NULL;
|
||||
if(func) func(space, callback->key, callback->data);
|
||||
|
||||
arr->arr[i] = NULL;
|
||||
cpfree(callback);
|
||||
}
|
||||
|
||||
waking->num = 0;
|
||||
arr->num = 0;
|
||||
space->skipPostStep = cpFalse;
|
||||
|
||||
if(space->locked == 0 && runPostStep && !space->skipPostStep){
|
||||
space->skipPostStep = cpTrue;
|
||||
|
||||
cpArray *arr = space->postStepCallbacks;
|
||||
for(int i=0; i<arr->num; i++){
|
||||
cpPostStepCallback *callback = (cpPostStepCallback *)arr->arr[i];
|
||||
cpPostStepFunc func = callback->func;
|
||||
|
||||
// Mark the func as NULL in case calling it calls cpSpaceRunPostStepCallbacks() again.
|
||||
// TODO need more tests around this case I think.
|
||||
callback->func = NULL;
|
||||
if(func) func(space, callback->key, callback->data);
|
||||
|
||||
arr->arr[i] = NULL;
|
||||
cpfree(callback);
|
||||
}
|
||||
|
||||
arr->num = 0;
|
||||
space->skipPostStep = cpFalse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue