mirror of https://github.com/axmolengine/axmol.git
fixed #124, chipmunk done!
This commit is contained in:
parent
4226dcede9
commit
fee1ce8f09
|
@ -0,0 +1,124 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 3;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_box()
|
||||
{
|
||||
const cpFloat size = 10.0f;
|
||||
const cpFloat mass = 1.0f;
|
||||
|
||||
cpVect verts[] = {
|
||||
cpv(-size,-size),
|
||||
cpv(-size, size),
|
||||
cpv( size, size),
|
||||
cpv( size,-size),
|
||||
};
|
||||
|
||||
cpFloat radius = cpvlength(cpv(size, size));
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 4, verts, cpvzero)));
|
||||
body->p = cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius));
|
||||
body->v = cpvmult(cpv(2*frand() - 1, 2*frand() - 1), 200);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 4, verts, cpvzero));
|
||||
shape->e = 1.0f; shape->u = 0.0f;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 1000);
|
||||
space->iterations = 10;
|
||||
|
||||
cpShape *shape;
|
||||
|
||||
// Create segments around the edge of the screen.
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
for(int i=0; i<10; i++)
|
||||
add_box();
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(100.0f, 10000.0f));
|
||||
|
||||
shape = cpSpaceAddShape(space, cpSegmentShapeNew(body, cpv(-75,0), cpv(75,0), 5.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(body, staticBody, cpvzero, cpvzero));
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Bounce = {
|
||||
"Bounce",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
struct chipmunkDemo;
|
||||
|
||||
typedef cpSpace *(*demoInitFunc)(void);
|
||||
typedef void (*demoUpdateFunc)(int ticks);
|
||||
typedef void (*demoDestroyFunc)(void);
|
||||
|
||||
typedef struct chipmunkDemo {
|
||||
char *name;
|
||||
|
||||
drawSpaceOptions *drawOptions;
|
||||
|
||||
demoInitFunc initFunc;
|
||||
demoUpdateFunc updateFunc;
|
||||
demoDestroyFunc destroyFunc;
|
||||
} chipmunkDemo;
|
||||
|
||||
static inline cpFloat
|
||||
frand(void)
|
||||
{
|
||||
return (cpFloat)rand()/(cpFloat)RAND_MAX;
|
||||
}
|
||||
|
||||
extern cpVect arrowDirection;
|
||||
extern char messageString[1024];
|
||||
|
||||
#define GRABABLE_MASK_BIT (1<<31)
|
||||
#define NOT_GRABABLE_MASK (~GRABABLE_MASK_BIT)
|
|
@ -0,0 +1,296 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static cpBody *
|
||||
addBall(cpVect pos, cpVect boxOffset)
|
||||
{
|
||||
cpFloat radius = 15.0f;
|
||||
cpFloat mass = 1.0f;
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero)));
|
||||
body->p = cpvadd(pos, boxOffset);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpBody *
|
||||
addLever(cpVect pos, cpVect boxOffset)
|
||||
{
|
||||
cpFloat mass = 1.0f;
|
||||
cpVect a = cpv(0, 15);
|
||||
cpVect b = cpv(0, -15);
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b)));
|
||||
body->p = cpvadd(pos, cpvadd(boxOffset, cpv(0, -15)));
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(body, a, b, 5.0f));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpBody *
|
||||
addBar(cpVect pos, cpVect boxOffset)
|
||||
{
|
||||
cpFloat mass = 2.0f;
|
||||
cpVect a = cpv(0, 30);
|
||||
cpVect b = cpv(0, -30);
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b)));
|
||||
body->p = cpvadd(pos, boxOffset);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(body, a, b, 5.0f));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpBody *
|
||||
addWheel(cpVect pos, cpVect boxOffset)
|
||||
{
|
||||
cpFloat radius = 15.0f;
|
||||
cpFloat mass = 1.0f;
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero)));
|
||||
body->p = cpvadd(pos, boxOffset);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
shape->group = 1; // use a group to keep the car parts from colliding
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpBody *
|
||||
addChassis(cpVect pos, cpVect boxOffset)
|
||||
{
|
||||
int num = 4;
|
||||
cpVect verts[] = {
|
||||
cpv(-40,-15),
|
||||
cpv(-40, 15),
|
||||
cpv( 40, 15),
|
||||
cpv( 40,-15),
|
||||
};
|
||||
|
||||
|
||||
cpFloat mass = 5.0f;
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, num, verts, cpvzero)));
|
||||
body->p = cpvadd(pos, boxOffset);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
shape->group = 1; // use a group to keep the car parts from colliding
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 10;
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
cpShape *shape;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,120), cpv(320,120), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,0), cpv(320,0), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-120), cpv(320,-120), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-160,-240), cpv(-160,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(0,-240), cpv(0,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(160,-240), cpv(160,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
cpVect boxOffset;
|
||||
cpBody *body1, *body2;
|
||||
|
||||
cpVect posA = cpv( 50, 60);
|
||||
cpVect posB = cpv(110, 60);
|
||||
|
||||
#define POS_A cpvadd(boxOffset, posA)
|
||||
#define POS_B cpvadd(boxOffset, posB)
|
||||
|
||||
// Pin Joints - Link shapes with a solid bar or pin.
|
||||
// Keeps the anchor points the same distance apart from when the joint was created.
|
||||
boxOffset = cpv(-320, -240);
|
||||
body1 = addBall(posA, boxOffset);
|
||||
body2 = addBall(posB, boxOffset);
|
||||
cpSpaceAddConstraint(space, cpPinJointNew(body1, body2, cpv(15,0), cpv(-15,0)));
|
||||
|
||||
// Slide Joints - Like pin joints but with a min/max distance.
|
||||
// Can be used for a cheap approximation of a rope.
|
||||
boxOffset = cpv(-160, -240);
|
||||
body1 = addBall(posA, boxOffset);
|
||||
body2 = addBall(posB, boxOffset);
|
||||
cpSpaceAddConstraint(space, cpSlideJointNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 40.0f));
|
||||
|
||||
// Pivot Joints - Holds the two anchor points together. Like a swivel.
|
||||
boxOffset = cpv(0, -240);
|
||||
body1 = addBall(posA, boxOffset);
|
||||
body2 = addBall(posB, boxOffset);
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body1, body2, cpvadd(boxOffset, cpv(80,60))));
|
||||
// cpPivotJointNew() takes it's anchor parameter in world coordinates. The anchors are calculated from that
|
||||
// cpPivotJointNew2() lets you specify the two anchor points explicitly
|
||||
|
||||
// Groove Joints - Like a pivot joint, but one of the anchors is a line segment that the pivot can slide in
|
||||
boxOffset = cpv(160, -240);
|
||||
body1 = addBall(posA, boxOffset);
|
||||
body2 = addBall(posB, boxOffset);
|
||||
cpSpaceAddConstraint(space, cpGrooveJointNew(body1, body2, cpv(30,30), cpv(30,-30), cpv(-30,0)));
|
||||
|
||||
// Damped Springs
|
||||
boxOffset = cpv(-320, -120);
|
||||
body1 = addBall(posA, boxOffset);
|
||||
body2 = addBall(posB, boxOffset);
|
||||
cpSpaceAddConstraint(space, cpDampedSpringNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 5.0f, 0.3f));
|
||||
|
||||
// Damped Rotary Springs
|
||||
boxOffset = cpv(-160, -120);
|
||||
body1 = addBar(posA, boxOffset);
|
||||
body2 = addBar(posB, boxOffset);
|
||||
// Add some pin joints to hold the circles in place.
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
|
||||
cpSpaceAddConstraint(space, cpDampedRotarySpringNew(body1, body2, 0.0f, 3000.0f, 60.0f));
|
||||
|
||||
// Rotary Limit Joint
|
||||
boxOffset = cpv(0, -120);
|
||||
body1 = addLever(posA, boxOffset);
|
||||
body2 = addLever(posB, boxOffset);
|
||||
// Add some pin joints to hold the circles in place.
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
|
||||
// Hold their rotation within 90 degrees of each other.
|
||||
cpSpaceAddConstraint(space, cpRotaryLimitJointNew(body1, body2, -(cpFloat)M_PI_2, (cpFloat)M_PI_2));
|
||||
|
||||
// Ratchet Joint - A rotary ratchet, like a socket wrench
|
||||
boxOffset = cpv(160, -120);
|
||||
body1 = addLever(posA, boxOffset);
|
||||
body2 = addLever(posB, boxOffset);
|
||||
// Add some pin joints to hold the circles in place.
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
|
||||
// Ratchet every 90 degrees
|
||||
cpSpaceAddConstraint(space, cpRatchetJointNew(body1, body2, 0.0f, (cpFloat)M_PI_2));
|
||||
|
||||
// Gear Joint - Maintain a specific angular velocity ratio
|
||||
boxOffset = cpv(-320, 0);
|
||||
body1 = addBar(posA, boxOffset);
|
||||
body2 = addBar(posB, boxOffset);
|
||||
// Add some pin joints to hold the circles in place.
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
|
||||
// Force one to sping 2x as fast as the other
|
||||
cpSpaceAddConstraint(space, cpGearJointNew(body1, body2, 0.0f, 2.0f));
|
||||
|
||||
// Simple Motor - Maintain a specific angular relative velocity
|
||||
boxOffset = cpv(-160, 0);
|
||||
body1 = addBar(posA, boxOffset);
|
||||
body2 = addBar(posB, boxOffset);
|
||||
// Add some pin joints to hold the circles in place.
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, POS_A));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, POS_B));
|
||||
// Make them spin at 1/2 revolution per second in relation to each other.
|
||||
cpSpaceAddConstraint(space, cpSimpleMotorNew(body1, body2, (cpFloat)M_PI));
|
||||
|
||||
// Make a car with some nice soft suspension
|
||||
boxOffset = cpv(0, 0);
|
||||
cpBody *wheel1 = addWheel(posA, boxOffset);
|
||||
cpBody *wheel2 = addWheel(posB, boxOffset);
|
||||
cpBody *chassis = addChassis(cpv(80, 100), boxOffset);
|
||||
|
||||
cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel1, cpv(-30, -10), cpv(-30, -40), cpvzero));
|
||||
cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel2, cpv( 30, -10), cpv( 30, -40), cpvzero));
|
||||
|
||||
cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel1, cpv(-30, 0), cpvzero, 50.0f, 20.0f, 1.5f));
|
||||
cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel2, cpv( 30, 0), cpvzero, 50.0f, 20.0f, 1.5f));
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
cpSpaceStep(space, 1.0f/60.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Joints = {
|
||||
"Joints and Constraints",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,152 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static const int image_width = 188;
|
||||
static const int image_height = 35;
|
||||
static const int image_row_length = 24;
|
||||
|
||||
static const unsigned char image_bitmap[] = {
|
||||
15,-16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-64,15,63,-32,-2,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,31,-64,15,127,-125,-1,-128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,127,-64,15,127,15,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-2,
|
||||
31,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,0,-4,63,-1,-32,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-8,127,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,-1,-64,0,-8,-15,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-31,-1,-64,15,-8,-32,
|
||||
-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-15,-1,-64,9,-15,-32,-1,-32,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,31,-15,-1,-64,0,-15,-32,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,63,-7,-1,-64,9,-29,-32,127,-61,-16,63,15,-61,-1,-8,31,-16,15,-8,126,7,-31,
|
||||
-8,31,-65,-7,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13,
|
||||
-4,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13,
|
||||
-2,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13,
|
||||
-2,63,-33,-1,-1,-32,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13,
|
||||
-1,63,-33,-1,-1,-16,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13,
|
||||
-1,63,-49,-1,-1,-8,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13,
|
||||
-1,-65,-49,-1,-1,-4,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13,
|
||||
-1,-65,-57,-1,-1,-2,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13,
|
||||
-1,-1,-57,-1,-1,-1,9,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1,
|
||||
-1,-61,-1,-1,-1,-119,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1,
|
||||
-1,-61,-1,-1,-1,-55,-49,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1,
|
||||
-1,-63,-1,-1,-1,-23,-49,-32,127,-57,-1,-1,-97,-25,-1,-1,63,-1,-1,-4,-1,15,-13,
|
||||
-1,-1,-63,-1,-1,-1,-16,-49,-32,-1,-25,-1,-1,-97,-25,-1,-1,63,-33,-5,-4,-1,15,
|
||||
-13,-1,-1,-64,-1,-9,-1,-7,-49,-32,-1,-25,-8,127,-97,-25,-1,-1,63,-33,-5,-4,-1,
|
||||
15,-13,-1,-1,-64,-1,-13,-1,-32,-49,-32,-1,-25,-8,127,-97,-25,-1,-2,63,-49,-13,
|
||||
-4,-1,15,-13,-1,-1,-64,127,-7,-1,-119,-17,-15,-1,-25,-8,127,-97,-25,-1,-2,63,
|
||||
-49,-13,-4,-1,15,-13,-3,-1,-64,127,-8,-2,15,-17,-1,-1,-25,-8,127,-97,-25,-1,
|
||||
-8,63,-49,-13,-4,-1,15,-13,-3,-1,-64,63,-4,120,0,-17,-1,-1,-25,-8,127,-97,-25,
|
||||
-8,0,63,-57,-29,-4,-1,15,-13,-4,-1,-64,63,-4,0,15,-17,-1,-1,-25,-8,127,-97,
|
||||
-25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,-1,-64,31,-2,0,0,103,-1,-1,-57,-8,127,-97,
|
||||
-25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,127,-64,31,-2,0,15,103,-1,-1,-57,-8,127,
|
||||
-97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,127,-64,15,-8,0,0,55,-1,-1,-121,-8,
|
||||
127,-97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,63,-64,15,-32,0,0,23,-1,-2,3,-16,
|
||||
63,15,-61,-16,0,31,-127,-127,-8,31,-1,-127,-8,31,-128,7,-128,0,0
|
||||
};
|
||||
|
||||
static inline int
|
||||
get_pixel(int x, int y)
|
||||
{
|
||||
return (image_bitmap[(x>>3) + y*image_row_length]>>(~x&0x7)) & 1;
|
||||
}
|
||||
|
||||
static cpSpace *space;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpShape *
|
||||
make_ball(cpFloat x, cpFloat y)
|
||||
{
|
||||
cpBody *body = cpBodyNew(1.0f, INFINITY);
|
||||
body->p = cpv(x, y);
|
||||
|
||||
cpShape *shape = cpCircleShapeNew(body, 0.95f, cpvzero);
|
||||
shape->e = 0.0f; shape->u = 0.0f;
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
space = cpSpaceNew();
|
||||
cpSpaceResizeActiveHash(space, 2.0f, 10000);
|
||||
space->iterations = 1;
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
for(int y=0; y<image_height; y++){
|
||||
for(int x=0; x<image_width; x++){
|
||||
if(!get_pixel(x, y)) continue;
|
||||
|
||||
cpFloat x_jitter = 0.05f*frand();
|
||||
cpFloat y_jitter = 0.05f*frand();
|
||||
|
||||
shape = make_ball(2*(x - image_width/2 + x_jitter), 2*(image_height/2 - y + y_jitter));
|
||||
cpSpaceAddBody(space, shape->body);
|
||||
cpSpaceAddShape(space, shape);
|
||||
}
|
||||
}
|
||||
|
||||
body = cpSpaceAddBody(space, cpBodyNew(INFINITY, INFINITY));
|
||||
body->p = cpv(-1000.0f, -10.0f);
|
||||
body->v = cpv(400.0f, 0.0f);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpCircleShapeNew(body, 8.0f, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
drawSpaceOptions draw_options = {
|
||||
0, 0, 0, 2.0f, 3.0f, 0.0f,
|
||||
};
|
||||
|
||||
chipmunkDemo LogoSmash = {
|
||||
"Logo Smash",
|
||||
&draw_options,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,506 @@
|
|||
// This Demo was written by Juan Pablo Carbajal. Nov 2008.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
#define WIDTH 600
|
||||
#define HEIGHT 400
|
||||
|
||||
#define SINGMAX 10 // Maximum number of singularities per body
|
||||
#define NMAG 10 // Number of magnets
|
||||
#define NCHG 10 // Number of charged bodies
|
||||
#define NMIX 10 // Number of charged magnets
|
||||
|
||||
#define COU_MKS 8.987551787e9 // Some physical constants
|
||||
#define MAG_MKS 1e-7
|
||||
|
||||
// Prototypes
|
||||
struct DataforForce;
|
||||
typedef void (*SingForceFunc)(struct DataforForce* data);
|
||||
|
||||
// Structures
|
||||
// Singularities
|
||||
typedef struct ActorSingularity{
|
||||
// Number of singularities
|
||||
int Nsing;
|
||||
// Value of the singularities
|
||||
cpFloat value[SINGMAX];
|
||||
// Type of the singularities
|
||||
char type[SINGMAX][100];
|
||||
// Global position of the singularities
|
||||
cpVect Gpos[SINGMAX];
|
||||
// Local position of the singularities
|
||||
cpVect position[SINGMAX];
|
||||
// Angle of the singularities measured in the body axes
|
||||
cpFloat angle[SINGMAX];
|
||||
// Angle of the singularities measured from x
|
||||
cpFloat Gangle[SINGMAX];
|
||||
// Force function
|
||||
SingForceFunc force_func[SINGMAX];
|
||||
// Force function
|
||||
SingForceFunc torque_func[SINGMAX];
|
||||
}Sing;
|
||||
|
||||
// Data for the force functions
|
||||
typedef struct DataforForce{
|
||||
//Everything in global coordinates
|
||||
// Position of the source
|
||||
cpVect p0;
|
||||
// Observed position
|
||||
cpVect p;
|
||||
// Relative position source-observed
|
||||
cpVect relp;
|
||||
// distance, disntace^2, ditance ^3
|
||||
cpFloat r[3];
|
||||
// angle of the source
|
||||
cpFloat ang0;
|
||||
// angle of the observed singularity
|
||||
cpFloat ang;
|
||||
// Foce value
|
||||
cpVect F;
|
||||
// Torque value
|
||||
cpFloat T;
|
||||
}ForceData;
|
||||
|
||||
// Global Varibales
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
|
||||
// **** Forces ****** //
|
||||
// Calculate the forces between two bodies. all this functions requieres
|
||||
// a pointer to an structure with the necessary fields.
|
||||
|
||||
// forces between charges
|
||||
static void
|
||||
CoulombForce(ForceData* data){
|
||||
data->F=cpvmult(cpvnormalize(data->relp),(cpFloat)COU_MKS/data->r[1]);
|
||||
}
|
||||
|
||||
// forces between magnets
|
||||
static void
|
||||
MagDipoleForce(ForceData* data){
|
||||
static cpFloat phi,alpha,beta,Fr,Fphi;
|
||||
|
||||
// Angle of the relative position vector
|
||||
phi=cpvtoangle(data->relp);
|
||||
alpha=data->ang0;
|
||||
beta=data->ang;
|
||||
|
||||
alpha =phi - alpha;
|
||||
beta = phi - beta;
|
||||
|
||||
|
||||
// Components in polar coordinates
|
||||
Fr=((cpFloat)2.0e0*cpfcos(alpha)*cpfcos(beta) - cpfsin(alpha)*cpfsin(beta));
|
||||
Fphi=cpfsin(alpha+beta);
|
||||
// printf("%g %g %g %g %g\n",phi,alpha,beta,Fphi);
|
||||
|
||||
// Cartesian coordinates
|
||||
data->F=cpv(Fr*cpfcos(phi)-Fphi*cpfsin(phi),Fr*cpfsin(phi)+Fphi*cpfcos(phi));
|
||||
data->F=cpvmult(data->F,(cpFloat)-3.e0*(cpFloat)MAG_MKS/(data->r[1]*data->r[1]));
|
||||
}
|
||||
|
||||
static void
|
||||
MagDipoleTorque(ForceData* data){
|
||||
static cpFloat phi,alpha,beta;
|
||||
|
||||
phi=cpvtoangle(data->relp);
|
||||
alpha=data->ang0;
|
||||
beta=data->ang;
|
||||
alpha =phi - alpha;
|
||||
beta = phi - beta;
|
||||
|
||||
// Torque. Though we could use a component of F to save some space,
|
||||
// we use another variables for the sake of clarity.
|
||||
|
||||
data->T=((cpFloat)MAG_MKS/data->r[2])*((cpFloat)3.0e0*cpfcos(alpha)*cpfsin(beta) + cpfsin(alpha-beta));
|
||||
}
|
||||
// ******* //
|
||||
|
||||
// This function fills the data structure for the force functions
|
||||
// The structure Sing has the information about the singularity (charge or magnet)
|
||||
static void
|
||||
FillForceData(Sing* source,int inds, Sing* obs,int indo, ForceData* data)
|
||||
{
|
||||
// Global Position and orientation of the source singularity
|
||||
data->p0=source->Gpos[inds];
|
||||
data->ang0=source->Gangle[inds];
|
||||
|
||||
// Global Position and orientation of the observed singularity
|
||||
data->p=obs->Gpos[indo];
|
||||
data->ang=obs->Gangle[indo];
|
||||
|
||||
// Derived magnitudes
|
||||
data->relp=cpvsub(data->p,data->p0); //Relative position
|
||||
data->r[0]=cpvlength(data->relp); // Distance
|
||||
data->r[1]=cpvlengthsq(data->relp); // Square Distance
|
||||
data->r[2]=data->r[0]*data->r[1]; // Cubic distance
|
||||
|
||||
source->force_func[inds](data); // The value of the force
|
||||
data->F= cpvmult(data->F,source->value[inds]*obs->value[indo]);
|
||||
}
|
||||
|
||||
// Calculation of the interaction
|
||||
static void
|
||||
LRangeForceApply(cpBody *a, cpBody *b){
|
||||
|
||||
Sing* aux = (Sing*)a->data;
|
||||
Sing* aux2 = (Sing*)b->data;
|
||||
cpVect delta;
|
||||
// General data needed to calculate interaction
|
||||
static ForceData fdata;
|
||||
fdata.F=cpvzero;
|
||||
|
||||
// Calculate the forces between the charges of different bodies
|
||||
for (int i=0; i<aux->Nsing; i++)
|
||||
{
|
||||
for (int j=0; j<aux2->Nsing; j++)
|
||||
{
|
||||
if(!strcmp(aux->type[i],aux2->type[j]))
|
||||
{
|
||||
//printf("%s %s\n",aux->type[i],aux2->type[j]);
|
||||
FillForceData (aux2,j,aux,i,&fdata);
|
||||
|
||||
//Force applied to body A
|
||||
delta=cpvsub(aux->Gpos[i], a->p);
|
||||
cpBodyApplyForce(a,fdata.F, delta);
|
||||
|
||||
if(aux->torque_func[i] != NULL)
|
||||
{
|
||||
//Torque on A
|
||||
aux->torque_func[i](&fdata);
|
||||
a->t += aux->value[i]*aux2->value[j]*fdata.T;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// function for the integration of the positions
|
||||
// The following functions are variations to the starndrd integration in Chipmunk
|
||||
// you can go ack to the standard ones by doing the appropiate changes.
|
||||
static void
|
||||
ChargedBodyUpdatePositionVerlet(cpBody *body, cpFloat dt)
|
||||
{
|
||||
// Long range interaction
|
||||
cpArray *bodies = space->bodies;
|
||||
static cpBody* B;
|
||||
Sing* aux=(Sing*)body->data;
|
||||
Sing* aux2;
|
||||
|
||||
// General data needed to calculate interaction
|
||||
static ForceData fdata;
|
||||
fdata.F=cpvzero;
|
||||
|
||||
for(int i=0; i< bodies->num; i++)
|
||||
{
|
||||
B=(cpBody*)bodies->arr[i];
|
||||
aux2=(Sing*)B->data;
|
||||
|
||||
if(B != body)
|
||||
{
|
||||
// Calculate the forces between the singularities of different bodies
|
||||
LRangeForceApply(body, B);
|
||||
}
|
||||
}
|
||||
|
||||
cpVect dp = cpvmult(cpvadd(body->v, body->v_bias), dt);
|
||||
dp = cpvadd(dp,cpvmult(cpvmult(body->f, body->m_inv), (cpFloat)0.5e0*dt*dt));
|
||||
body->p = cpvadd(body->p, dp);
|
||||
|
||||
cpBodySetAngle(body, body->a + (body->w + body->w_bias)*dt
|
||||
+ 0.5f*body->t*body->i_inv*dt*dt);
|
||||
|
||||
// Update position of the singularities
|
||||
aux = (Sing*)body->data;
|
||||
for (int i=0; i<aux->Nsing; i++)
|
||||
{
|
||||
aux->Gpos[i]=cpvadd(body->p,cpvrotate(cpv(aux->position[i].x,
|
||||
aux->position[i].y), body->rot));
|
||||
aux->Gangle[i]= aux->angle[i] + body->a;
|
||||
}
|
||||
|
||||
|
||||
body->v_bias = cpvzero;
|
||||
body->w_bias = 0.0f;
|
||||
}
|
||||
|
||||
// function for the integration of the velocities
|
||||
static void
|
||||
ChargedBodyUpdateVelocityVerlet(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
|
||||
{
|
||||
body->v = cpvadd(body->v, cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), (cpFloat)0.5e0*dt));
|
||||
body->w = body->w + body->t*body->i_inv*(cpFloat)0.5e0*dt;
|
||||
|
||||
body->f = cpvzero;
|
||||
body->t = 0;
|
||||
|
||||
// Long range interaction
|
||||
cpArray *bodies = space->bodies;
|
||||
static cpBody* B;
|
||||
|
||||
// General data needed to calculate interaction
|
||||
static ForceData fdata;
|
||||
fdata.F=cpvzero;
|
||||
|
||||
for(int i=0; i< bodies->num; i++)
|
||||
{
|
||||
B=(cpBody*)bodies->arr[i];
|
||||
|
||||
if(B != body)
|
||||
{
|
||||
// Calculate the forces between the singularities of different bodies
|
||||
LRangeForceApply(body, B);
|
||||
}
|
||||
}
|
||||
body->v = cpvadd(cpvmult(body->v,damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), (cpFloat)0.5e0*dt));
|
||||
body->w = body->w*damping + body->t*body->i_inv*(cpFloat)0.5e0*dt;
|
||||
}
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 10;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
cpArray *bodies = space->bodies;
|
||||
|
||||
for(int i=0; i< bodies->num; i++)
|
||||
cpBodyResetForces((cpBody*)bodies->arr[i]);
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
make_mag(cpVect p, cpFloat ang, cpFloat mag)
|
||||
{
|
||||
int nverts=6;
|
||||
cpVect verts[] = {
|
||||
cpv(-10,-10),
|
||||
cpv(-10, 10),
|
||||
cpv( 10, 10),
|
||||
cpv( 15, 5),
|
||||
cpv( 15, -5),
|
||||
cpv( 10,-10)
|
||||
};
|
||||
|
||||
cpBody *body = cpBodyNew(1, cpMomentForPoly(1, nverts, verts, cpvzero));
|
||||
body->p = p;
|
||||
body->v = cpvzero;
|
||||
cpBodySetAngle(body, ang);
|
||||
body->w = 0;
|
||||
|
||||
// Load the singularities
|
||||
Sing *magnet=(Sing*)cpmalloc(sizeof(Sing));
|
||||
magnet->Nsing=1;
|
||||
magnet->value[0]=mag;
|
||||
sprintf(magnet->type[0],"magdipole");
|
||||
|
||||
// The position and angle could be different form the one of the body
|
||||
magnet->position[0]=cpvzero;
|
||||
magnet->Gpos[0]=cpvadd(p,magnet->position[0]);
|
||||
magnet->angle[0]=0.0f;
|
||||
magnet->Gangle[0]=ang;
|
||||
|
||||
magnet->force_func[0]=MagDipoleForce;
|
||||
magnet->torque_func[0]=MagDipoleTorque;
|
||||
|
||||
body->data=magnet;
|
||||
|
||||
body->position_func=ChargedBodyUpdatePositionVerlet;
|
||||
body->velocity_func=ChargedBodyUpdateVelocityVerlet;
|
||||
cpSpaceAddBody(space, body);
|
||||
|
||||
cpShape *shape = cpPolyShapeNew(body, nverts, verts, cpvzero);
|
||||
shape->e = 0; shape->u = 0.7f;
|
||||
cpSpaceAddShape(space, shape);
|
||||
}
|
||||
|
||||
static void
|
||||
make_charged(cpVect p, cpFloat chg)
|
||||
{
|
||||
int nverts=4;
|
||||
cpVect verts[] = {
|
||||
cpv(-10,-10),
|
||||
cpv(-10, 10),
|
||||
cpv( 10, 10),
|
||||
cpv( 10,-10)
|
||||
};
|
||||
|
||||
cpBody *body = cpBodyNew(1, cpMomentForPoly(1, nverts, verts, cpvzero));
|
||||
body->p = p;
|
||||
body->v = cpvzero;
|
||||
cpBodySetAngle(body, 0);
|
||||
body->w = 0;
|
||||
|
||||
// Load the singularities
|
||||
Sing *charge=(Sing*)cpmalloc(sizeof(Sing));;
|
||||
charge->Nsing=1;
|
||||
charge->value[0]=chg;
|
||||
sprintf(charge->type[0],"electrical");
|
||||
|
||||
// The position and angle could be different form the one of the body
|
||||
charge->position[0]=cpvzero;
|
||||
charge->Gpos[0]=cpvadd(p,charge->position[0]);
|
||||
charge->Gangle[0]=0;
|
||||
|
||||
charge->force_func[0]=CoulombForce;
|
||||
charge->torque_func[0]=NULL;
|
||||
|
||||
body->data=charge;
|
||||
|
||||
body->position_func=ChargedBodyUpdatePositionVerlet;
|
||||
body->velocity_func=ChargedBodyUpdateVelocityVerlet;
|
||||
cpSpaceAddBody(space, body);
|
||||
|
||||
cpShape *shape = cpPolyShapeNew(body, nverts, verts, cpvzero);
|
||||
shape->e = 0; shape->u = 0.7f;
|
||||
cpSpaceAddShape(space, shape);
|
||||
}
|
||||
void
|
||||
make_mix(cpVect p, cpFloat ang, cpFloat mag,cpFloat chg)
|
||||
{
|
||||
int nverts=5;
|
||||
cpVect verts[] = {
|
||||
cpv(-10,-10),
|
||||
cpv(-10, 10),
|
||||
cpv( 10, 10),
|
||||
cpv( 20, 0),
|
||||
cpv( 10,-10)
|
||||
};
|
||||
|
||||
cpBody *body = cpBodyNew(1, cpMomentForPoly(1, nverts, verts, cpvzero));
|
||||
body->p = p;
|
||||
body->v = cpvzero;
|
||||
cpBodySetAngle(body, ang);
|
||||
body->w = 0;
|
||||
|
||||
// Load the singularities
|
||||
Sing *mix=(Sing*)cpmalloc(sizeof(Sing));;
|
||||
mix->Nsing=2;
|
||||
mix->value[0]=mag;
|
||||
mix->value[1]=chg;
|
||||
sprintf(mix->type[0],"magdipole");
|
||||
sprintf(mix->type[1],"electrical");
|
||||
|
||||
// The position and angle could be different form the one of the body
|
||||
mix->position[0]=cpvzero;
|
||||
mix->Gpos[0]=cpvadd(p,mix->position[0]);
|
||||
mix->position[1]=cpvzero;
|
||||
mix->Gpos[1]=cpvadd(p,mix->position[1]);
|
||||
mix->Gangle[0]=ang;
|
||||
mix->Gangle[1]=ang;
|
||||
|
||||
mix->force_func[0]=MagDipoleForce;
|
||||
mix->force_func[1]=CoulombForce;
|
||||
mix->torque_func[0]=MagDipoleTorque;
|
||||
mix->torque_func[1]=NULL;
|
||||
|
||||
body->data=mix;
|
||||
|
||||
body->position_func=ChargedBodyUpdatePositionVerlet;
|
||||
body->velocity_func=ChargedBodyUpdateVelocityVerlet;
|
||||
cpSpaceAddBody(space, body);
|
||||
|
||||
cpShape *shape = cpPolyShapeNew(body, nverts, verts, cpvzero);
|
||||
shape->e = 0; shape->u = 0.7f;
|
||||
cpSpaceAddShape(space, shape);
|
||||
}
|
||||
|
||||
|
||||
static cpSpace*
|
||||
init(void)
|
||||
{
|
||||
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 5;
|
||||
space->gravity = cpvzero; //cpv(0,-100);
|
||||
|
||||
cpSpaceResizeActiveHash(space, 30, 2999);
|
||||
|
||||
// Screen border
|
||||
/* shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f);
|
||||
shape->e = 1.0; shape->u = 1.0;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
|
||||
shape = cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f);
|
||||
shape->e = 1.0; shape->u = 1.0;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
|
||||
shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f);
|
||||
shape->e = 1.0; shape->u = 1.0;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
|
||||
// Reference line
|
||||
// Does not collide with other objects, we just want to draw it.
|
||||
shape = cpSegmentShapeNew(staticBody, cpv(-320,0), cpv(320,0), 0.0f);
|
||||
shape->collision_type = 1;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
// Add a collision pair function to filter collisions
|
||||
cpSpaceAddCollisionPairFunc(space, 0, 1, NULL, NULL);
|
||||
*/
|
||||
|
||||
srand(time(NULL));
|
||||
cpVect p;
|
||||
cpFloat ang;
|
||||
|
||||
// Create magnets
|
||||
for(int i=0; i<NMAG; i++)
|
||||
{
|
||||
p.x=(2*rand()/((cpFloat)RAND_MAX) - 1)*WIDTH/2.0f;
|
||||
p.y=(2*rand()/((cpFloat)RAND_MAX) - 1)*HEIGHT/2.0f;
|
||||
ang=(2*rand()/((cpFloat)RAND_MAX) - 1)*(cpFloat)3.1415;
|
||||
make_mag(p, ang,(cpFloat)1.0e7);
|
||||
}
|
||||
|
||||
// Create charged objects
|
||||
for(int i=0; i<NCHG; i++)
|
||||
{
|
||||
p.x=(2*rand()/((cpFloat)RAND_MAX) - 1)*WIDTH/2.0f;
|
||||
p.y=(2*rand()/((cpFloat)RAND_MAX) - 1)*HEIGHT/2.0f;
|
||||
ang=(2*rand()/((cpFloat)RAND_MAX) - 1)* (cpFloat)3.1415;
|
||||
make_charged(p,(cpFloat)1.0e-3*cpfpow( (float)-1,(float)(i%2) ));
|
||||
}
|
||||
|
||||
// Create charged magnets objects
|
||||
for(int i=0; i<NMIX; i++)
|
||||
{
|
||||
p.x=(2*rand()/((cpFloat)RAND_MAX) - 1)*WIDTH/2.0f;
|
||||
p.y=(2*rand()/((cpFloat)RAND_MAX) - 1)*HEIGHT/2.0f;
|
||||
ang=(2*rand()/((cpFloat)RAND_MAX) - 1)*(cpFloat)3.1415;
|
||||
make_mix(p, ang,(cpFloat)1.0e7*cpfpow( (float)-1,(float)(i%2) ), (cpFloat)1.0e-3*cpfpow( (float)-1,(float)(i%2)) );
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
|
||||
}
|
||||
chipmunkDemo MagnetsElectric = {
|
||||
"Magnets and Electric Charges (By: Juan Pablo Carbajal)",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,152 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
typedef struct OneWayPlatform {
|
||||
cpVect n; // direction objects may pass through
|
||||
cpArray *passThruList; // list of objects passing through
|
||||
} OneWayPlatform;
|
||||
|
||||
static OneWayPlatform platformInstance;
|
||||
|
||||
static int
|
||||
preSolve(cpArbiter *arb, cpSpace *space, void *ignore)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
OneWayPlatform *platform = (OneWayPlatform*)(a->data);
|
||||
|
||||
if(cpArrayContains(platform->passThruList, b)){
|
||||
// The object is in the pass thru list, ignore it until separates.
|
||||
return 0;
|
||||
} else {
|
||||
cpFloat dot = cpvdot(cpArbiterGetNormal(arb, 0), platform->n);
|
||||
|
||||
if(dot < 0){
|
||||
// Add the object to the pass thrru list
|
||||
cpArrayPush(platform->passThruList, b);
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
separate(cpArbiter *arb, cpSpace *space, void *ignore)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
|
||||
// remove the object from the pass thru list
|
||||
cpArrayDeleteObj(((OneWayPlatform *)a->data)->passThruList, b);
|
||||
}
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 10;
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
// Create segments around the edge of the screen.
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
// Add our one way segment
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-160,-100), cpv(160,-100), 10.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->collision_type = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
// We'll use the data pointer for the OneWayPlatform struct
|
||||
platformInstance.n = cpv(0, 1); // let objects pass upwards
|
||||
platformInstance.passThruList = cpArrayNew(0);
|
||||
shape->data = &platformInstance;
|
||||
|
||||
|
||||
// Add a ball to make things more interesting
|
||||
cpFloat radius = 15.0f;
|
||||
body = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero)));
|
||||
body->p = cpv(0, -200);
|
||||
body->v = cpv(0, 170);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.9f;
|
||||
shape->collision_type = 2;
|
||||
|
||||
cpSpaceAddCollisionHandler(space, 1, 2, NULL, preSolve, NULL, separate, NULL);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
|
||||
cpArrayFree(platformInstance.passThruList);
|
||||
}
|
||||
|
||||
chipmunkDemo OneWay = {
|
||||
"One Way Platforms",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,127 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
|
||||
// Update the static body spin so that it looks like it's rotating.
|
||||
cpBodyUpdatePosition(staticBody, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
planetGravityVelocityFunc(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
|
||||
{
|
||||
cpVect p = body->p;
|
||||
cpVect g = cpvmult(p, -50000.0f/cpvdot(p, p));
|
||||
|
||||
cpBodyUpdateVelocity(body, g, damping, dt);
|
||||
}
|
||||
|
||||
static cpVect
|
||||
rand_pos(cpFloat radius)
|
||||
{
|
||||
cpVect v;
|
||||
do {
|
||||
v = cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius));
|
||||
} while(cpvlength(v) < 100.0f);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static void
|
||||
add_box()
|
||||
{
|
||||
const cpFloat size = 10.0f;
|
||||
const cpFloat mass = 1.0f;
|
||||
|
||||
cpVect verts[] = {
|
||||
cpv(-size,-size),
|
||||
cpv(-size, size),
|
||||
cpv( size, size),
|
||||
cpv( size,-size),
|
||||
};
|
||||
|
||||
cpFloat radius = cpvlength(cpv(size, size));
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 4, verts, cpvzero)));
|
||||
body->velocity_func = planetGravityVelocityFunc;
|
||||
body->p = rand_pos(radius);
|
||||
body->v = cpvmult(cpv(2*frand() - 1, 2*frand() - 1), 200);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 4, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
staticBody->w = 0.2f;
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 10000);
|
||||
space->iterations = 20;
|
||||
|
||||
for(int i=0; i<30; i++)
|
||||
add_box();
|
||||
|
||||
cpShape *shape = cpSpaceAddStaticShape(space, cpCircleShapeNew(staticBody, 70.0f, cpvzero));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Planet = {
|
||||
"Planet",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,227 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
typedef struct PlayerStruct {
|
||||
cpFloat u;
|
||||
cpShape *shape;
|
||||
cpVect groundNormal;
|
||||
cpArray *groundShapes;
|
||||
} PlayerStruct;
|
||||
|
||||
PlayerStruct playerInstance;
|
||||
|
||||
static int
|
||||
begin(cpArbiter *arb, cpSpace *space, void *ignore)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
PlayerStruct *player = (PlayerStruct*)(a->data);
|
||||
|
||||
cpVect n = cpvneg(cpArbiterGetNormal(arb, 0));
|
||||
if(n.y > 0.0f){
|
||||
cpArrayPush(player->groundShapes, b);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
preSolve(cpArbiter *arb, cpSpace *space, void *ignore)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
PlayerStruct *player = (PlayerStruct*)(a->data);
|
||||
|
||||
if(arb->stamp > 0){
|
||||
a->u = player->u;
|
||||
|
||||
// pick the most upright jump normal each frame
|
||||
cpVect n = cpvneg(cpArbiterGetNormal(arb, 0));
|
||||
if(n.y >= player->groundNormal.y){
|
||||
player->groundNormal = n;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
separate(cpArbiter *arb, cpSpace *space, void *ignore)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
PlayerStruct *player = (PlayerStruct*)(a->data);
|
||||
|
||||
cpArrayDeleteObj(player->groundShapes, b);
|
||||
|
||||
if(player->groundShapes->num == 0){
|
||||
a->u = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
playerUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
|
||||
{
|
||||
cpBodyUpdateVelocity(body, gravity, damping, dt);
|
||||
body->v.y = cpfmax(body->v.y, -700);
|
||||
body->v.x = cpfclamp(body->v.x, -400, 400);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
static int lastJumpState = 0;
|
||||
int jumpState = (arrowDirection.y > 0.0f);
|
||||
|
||||
cpVect groundNormal = playerInstance.groundNormal;
|
||||
if(groundNormal.y > 0.0f){
|
||||
playerInstance.shape->surface_v = cpvmult(cpvperp(groundNormal), 400.0f*arrowDirection.x);
|
||||
} else {
|
||||
playerInstance.shape->surface_v = cpvzero;
|
||||
}
|
||||
|
||||
cpBody *body = playerInstance.shape->body;
|
||||
|
||||
// apply jump
|
||||
if(jumpState && !lastJumpState && cpvlengthsq(groundNormal)){
|
||||
// body->v = cpvmult(cpvslerp(groundNormal, cpv(0.0f, 1.0f), 0.5f), 500.0f);
|
||||
body->v = cpvadd(body->v, cpvmult(cpvslerp(groundNormal, cpv(0.0f, 1.0f), 0.75f), 500.0f));
|
||||
}
|
||||
|
||||
if(playerInstance.groundShapes->num == 0){
|
||||
cpFloat air_accel = body->v.x + arrowDirection.x*(2000.0f);
|
||||
body->f.x = body->m*air_accel;
|
||||
// body->v.x = cpflerpconst(body->v.x, 400.0f*arrowDirection.x, 2000.0f/60.0f);
|
||||
}
|
||||
|
||||
int steps = 3;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
playerInstance.groundNormal = cpvzero;
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
|
||||
lastJumpState = jumpState;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 10;
|
||||
space->gravity = cpv(0, -1500);
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
// Create segments around the edge of the screen.
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
// add some other segments to play with
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-220,-200), cpv(-220,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(0,-240), cpv(320,-200), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(200,-240), cpv(320,-100), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-220,-80), cpv(200,-80), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
shape->collision_type = 2;
|
||||
|
||||
// Set up the player
|
||||
cpFloat radius = 15.0f;
|
||||
body = cpSpaceAddBody(space, cpBodyNew(10.0f, INFINITY));
|
||||
body->p = cpv(0, -220);
|
||||
body->velocity_func = playerUpdateVelocity;
|
||||
|
||||
shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 2.0f;
|
||||
shape->collision_type = 1;
|
||||
|
||||
playerInstance.u = shape->u;
|
||||
playerInstance.shape = shape;
|
||||
playerInstance.groundShapes = cpArrayNew(0);
|
||||
shape->data = &playerInstance;
|
||||
|
||||
cpSpaceAddCollisionHandler(space, 1, 2, begin, preSolve, NULL, separate, NULL);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
|
||||
cpArrayFree(playerInstance.groundShapes);
|
||||
}
|
||||
|
||||
chipmunkDemo Player = {
|
||||
"Player",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,126 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
// Iterate over all of the bodies and reset the ones that have fallen offscreen.
|
||||
static void
|
||||
eachBody(cpBody *body, void *unused)
|
||||
{
|
||||
if(body->p.y < -260 || fabsf(body->p.x) > 340){
|
||||
cpFloat x = rand()/(cpFloat)RAND_MAX*640 - 320;
|
||||
body->p = cpv(x, 260);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
cpSpaceEachBody(space, &eachBody, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
#define NUM_VERTS 5
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 5;
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
cpSpaceResizeStaticHash(space, 40.0f, 999);
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 2999);
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
// Create vertexes for a pentagon shape.
|
||||
cpVect verts[NUM_VERTS];
|
||||
for(int i=0; i<NUM_VERTS; i++){
|
||||
cpFloat angle = -2*(cpFloat)M_PI*i/((cpFloat) NUM_VERTS);
|
||||
verts[i] = cpv(10*cpfcos(angle), 10*cpfsin(angle));
|
||||
}
|
||||
|
||||
// Vertexes for a triangle shape.
|
||||
cpVect tris[] = {
|
||||
cpv(-15,-15),
|
||||
cpv( 0, 10),
|
||||
cpv( 15,-15),
|
||||
};
|
||||
|
||||
// Create the static triangles.
|
||||
for(int i=0; i<9; i++){
|
||||
for(int j=0; j<6; j++){
|
||||
cpFloat stagger = (j%2)*40;
|
||||
cpVect offset = cpv(i*80 - 320 + stagger, j*70 - 240);
|
||||
shape = cpSpaceAddStaticShape(space, cpPolyShapeNew(staticBody, 3, tris, offset));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
}
|
||||
}
|
||||
|
||||
// Add lots of pentagons.
|
||||
for(int i=0; i<300; i++){
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, NUM_VERTS, verts, cpvzero)));
|
||||
cpFloat x = rand()/(cpFloat)RAND_MAX*640 - 320;
|
||||
body->p = cpv(x, 350);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, NUM_VERTS, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.4f;
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Plink = {
|
||||
"Plink",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,188 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
static cpConstraint *motor;
|
||||
|
||||
#define numBalls 5
|
||||
static cpBody *balls[numBalls];
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
cpFloat coef = (2.0f + arrowDirection.y)/3.0f;
|
||||
cpFloat rate = arrowDirection.x*30.0f*coef;
|
||||
cpSimpleMotorSetRate(motor, rate);
|
||||
motor->maxForce = (rate) ? 1000000.0f : 0.0f;
|
||||
|
||||
int steps = 2;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
|
||||
for(int i=0; i<numBalls; i++){
|
||||
cpBody *ball = balls[i];
|
||||
if(ball->p.x > 320.0f){
|
||||
ball->v = cpvzero;
|
||||
ball->p = cpv(-224.0f, 200.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static cpBody *
|
||||
add_ball(cpVect pos)
|
||||
{
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 30, 0, cpvzero)));
|
||||
body->p = pos;
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, 30, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.5f;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->gravity = cpv(0, -600);
|
||||
|
||||
cpShape *shape;
|
||||
|
||||
// beveling all of the line segments helps prevent things from getting stuck on cracks
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-256,16), cpv(-256,240), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-256,16), cpv(-192,0), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-192,0), cpv(-192, -64), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-128,-64), cpv(-128,144), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-192,80), cpv(-192,176), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-192,176), cpv(-128,240), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-128,144), cpv(192,64), 2.0f));
|
||||
shape->e = 0.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
cpVect verts[] = {
|
||||
cpv(-30,-80),
|
||||
cpv(-30, 80),
|
||||
cpv( 30, 64),
|
||||
cpv( 30,-80),
|
||||
};
|
||||
|
||||
cpBody *plunger = cpSpaceAddBody(space, cpBodyNew(1.0f, INFINITY));
|
||||
plunger->p = cpv(-160,-80);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(plunger, 4, verts, cpvzero));
|
||||
shape->e = 1.0f; shape->u = 0.5f; shape->layers = 1;
|
||||
|
||||
// add balls to hopper
|
||||
for(int i=0; i<numBalls; i++)
|
||||
balls[i] = add_ball(cpv(-224,80 + 64*i));
|
||||
|
||||
// add small gear
|
||||
cpBody *smallGear = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 80, 0, cpvzero)));
|
||||
smallGear->p = cpv(-160,-160);
|
||||
cpBodySetAngle(smallGear, (cpFloat)-M_PI_2);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpCircleShapeNew(smallGear, 80.0f, cpvzero));
|
||||
shape->layers = 0;
|
||||
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, smallGear, cpv(-160,-160), cpvzero));
|
||||
|
||||
// add big gear
|
||||
cpBody *bigGear = cpSpaceAddBody(space, cpBodyNew(40.0f, cpMomentForCircle(40.0f, 160, 0, cpvzero)));
|
||||
bigGear->p = cpv(80,-160);
|
||||
cpBodySetAngle(bigGear, (cpFloat)M_PI_2);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpCircleShapeNew(bigGear, 160.0f, cpvzero));
|
||||
shape->layers = 0;
|
||||
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, bigGear, cpv(80,-160), cpvzero));
|
||||
|
||||
// connect the plunger to the small gear.
|
||||
cpSpaceAddConstraint(space, cpPinJointNew(smallGear, plunger, cpv(80,0), cpv(0,0)));
|
||||
// connect the gears.
|
||||
cpSpaceAddConstraint(space, cpGearJointNew(smallGear, bigGear, (cpFloat)-M_PI_2, -2.0f));
|
||||
|
||||
|
||||
// feeder mechanism
|
||||
cpFloat bottom = -300.0f;
|
||||
cpFloat top = 32.0f;
|
||||
cpBody *feeder = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForSegment(1.0f, cpv(-224.0f, bottom), cpv(-224.0f, top))));
|
||||
feeder->p = cpv(-224, (bottom + top)/2.0f);
|
||||
|
||||
cpFloat len = top - bottom;
|
||||
cpSpaceAddShape(space, cpSegmentShapeNew(feeder, cpv(0.0f, len/2.0f), cpv(0.0f, -len/2.0f), 20.0f));
|
||||
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, feeder, cpv(-224.0f, bottom), cpv(0.0f, -len/2.0f)));
|
||||
cpVect anchr = cpBodyWorld2Local(feeder, cpv(-224.0f, -160.0f));
|
||||
cpSpaceAddConstraint(space, cpPinJointNew(feeder, smallGear, anchr, cpv(0.0f, 80.0f)));
|
||||
|
||||
// motorize the second gear
|
||||
motor = cpSpaceAddConstraint(space, cpSimpleMotorNew(staticBody, bigGear, 3.0f));
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Pump = {
|
||||
"Pump",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,118 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 3;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 20;
|
||||
cpSpaceResizeStaticHash(space, 40.0f, 1000);
|
||||
cpSpaceResizeActiveHash(space, 40.0f, 1000);
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
int num = 4;
|
||||
cpVect verts[] = {
|
||||
cpv(-15,-15),
|
||||
cpv(-15, 15),
|
||||
cpv( 15, 15),
|
||||
cpv( 15,-15),
|
||||
};
|
||||
|
||||
// Create segments around the edge of the screen.
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
// Add lots of boxes.
|
||||
for(int i=0; i<14; i++){
|
||||
for(int j=0; j<=i; j++){
|
||||
body = cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero));
|
||||
body->p = cpv(j*32 - i*16, 300 - i*32);
|
||||
cpSpaceAddBody(space, body);
|
||||
shape = cpPolyShapeNew(body, num, verts, cpvzero);
|
||||
shape->e = 0.0f; shape->u = 0.8f;
|
||||
cpSpaceAddShape(space, shape);
|
||||
}
|
||||
}
|
||||
|
||||
// Add a ball to make things more interesting
|
||||
cpFloat radius = 15.0f;
|
||||
body = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero)));
|
||||
body->p = cpv(0, -240 + radius+5);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.9f;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo PyramidStack = {
|
||||
"Pyramid Stack",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,141 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 2;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++)
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 20;
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 2999);
|
||||
cpSpaceResizeStaticHash(space, 30.0f, 999);
|
||||
space->gravity = cpv(0, -300);
|
||||
|
||||
cpBody *body;
|
||||
|
||||
cpShape *shape;
|
||||
|
||||
// Vertexes for the dominos.
|
||||
int num = 4;
|
||||
cpVect verts[] = {
|
||||
cpv(-3,-20),
|
||||
cpv(-3, 20),
|
||||
cpv( 3, 20),
|
||||
cpv( 3,-20),
|
||||
};
|
||||
|
||||
// Add a floor.
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-600,-240), cpv(600,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
// Shared friction constant.
|
||||
cpFloat u = 0.6f;
|
||||
|
||||
// Add the dominoes. Skim over this. It doesn't do anything fancy, and it's hard to follow.
|
||||
int n = 9;
|
||||
for(int i=1; i<=n; i++){
|
||||
cpVect offset = cpv(-i*60/2.0f, (n - i)*52);
|
||||
|
||||
for(int j=0; j<i; j++){
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
|
||||
body->p = cpvadd(cpv(j*60, -220), offset);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = u;
|
||||
|
||||
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
|
||||
body->p = cpvadd(cpv(j*60, -197), offset);
|
||||
cpBodySetAngle(body, (cpFloat)M_PI/2.0f);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = u;
|
||||
|
||||
|
||||
if(j == (i - 1)) continue;
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
|
||||
body->p = cpvadd(cpv(j*60 + 30, -191), offset);
|
||||
cpBodySetAngle(body, (cpFloat)M_PI/2.0f);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = u;
|
||||
}
|
||||
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
|
||||
body->p = cpvadd(cpv(-17, -174), offset);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = u;
|
||||
|
||||
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
|
||||
body->p = cpvadd(cpv((i - 1)*60 + 17, -174), offset);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = u;
|
||||
}
|
||||
|
||||
// Give the last domino a little tap.
|
||||
// body->w = -1;
|
||||
// body->v = cpv(-body->w*20, 0);
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo PyramidTopple = {
|
||||
"Pyramid Topple",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,158 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
#include "chipmunk_unsafe.h"
|
||||
|
||||
extern cpSpace *space;
|
||||
extern cpBody *staticBody;
|
||||
extern cpVect mousePoint;
|
||||
|
||||
cpShape *querySeg = NULL;
|
||||
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
messageString[0] = '\0';
|
||||
|
||||
cpVect start = cpvzero;
|
||||
cpVect end = /*cpv(0, 85);//*/mousePoint;
|
||||
cpVect lineEnd = end;
|
||||
|
||||
{
|
||||
char infoString[1024];
|
||||
sprintf(infoString, "Query: Dist(%f) Point%s, ", cpvdist(start, end), cpvstr(end));
|
||||
strcat(messageString, infoString);
|
||||
}
|
||||
|
||||
cpSegmentQueryInfo info = {};
|
||||
if(cpSpaceSegmentQueryFirst(space, start, end, -1, 0, &info)){
|
||||
cpVect point = cpSegmentQueryHitPoint(start, end, info);
|
||||
lineEnd = cpvadd(point, cpvzero);//cpvmult(info.n, 4.0f));
|
||||
|
||||
char infoString[1024];
|
||||
sprintf(infoString, "Segment Query: Dist(%f) Normal%s", cpSegmentQueryHitDist(start, end, info), cpvstr(info.n));
|
||||
strcat(messageString, infoString);
|
||||
} else {
|
||||
strcat(messageString, "Segment Query (None)");
|
||||
}
|
||||
|
||||
cpSegmentShapeSetEndpoints(querySeg, cpvzero, lineEnd);
|
||||
|
||||
// normal other stuff.
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->elasticIterations = 0;
|
||||
space->iterations = 5;
|
||||
|
||||
cpSpaceResizeStaticHash(space, 40.0f, 999);
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 2999);
|
||||
|
||||
cpShape *shape;
|
||||
|
||||
// add a non-collidable segment as a quick and dirty way to draw the query line
|
||||
shape = cpSegmentShapeNew(staticBody, cpvzero, cpv(100.0f, 0.0f), 4.0f);
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
shape->layers = 0;
|
||||
querySeg = shape;
|
||||
|
||||
{ // add a fat segment
|
||||
cpFloat mass = 1.0f;
|
||||
cpFloat length = 100.0f;
|
||||
cpVect a = cpv(-length/2.0f, 0.0f), b = cpv(length/2.0f, 0.0f);
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b)));
|
||||
body->p = cpv(0.0f, 100.0f);
|
||||
|
||||
cpSpaceAddShape(space, cpSegmentShapeNew(body, a, b, 20.0f));
|
||||
}
|
||||
|
||||
{ // add a static segment
|
||||
cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(0, 300), cpv(300, 0), 0.0f));
|
||||
}
|
||||
|
||||
{ // add a pentagon
|
||||
cpFloat mass = 1.0f;
|
||||
const int NUM_VERTS = 5;
|
||||
|
||||
cpVect verts[NUM_VERTS];
|
||||
for(int i=0; i<NUM_VERTS; i++){
|
||||
cpFloat angle = -2*(cpFloat)M_PI*i/((cpFloat) NUM_VERTS);
|
||||
verts[i] = cpv(30*cpfcos(angle), 30*cpfsin(angle));
|
||||
}
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, NUM_VERTS, verts, cpvzero)));
|
||||
body->p = cpv(50.0f, 50.0f);
|
||||
|
||||
cpSpaceAddShape(space, cpPolyShapeNew(body, NUM_VERTS, verts, cpvzero));
|
||||
}
|
||||
|
||||
{ // add a circle
|
||||
cpFloat mass = 1.0f;
|
||||
cpFloat r = 20.0f;
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, r, cpvzero)));
|
||||
body->p = cpv(100.0f, 100.0f);
|
||||
|
||||
cpSpaceAddShape(space, cpCircleShapeNew(body, r, cpvzero));
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
const chipmunkDemo Query = {
|
||||
"Segment Query",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,165 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
enum {
|
||||
BALL_TYPE,
|
||||
BLOCKING_SENSOR_TYPE,
|
||||
CATCH_SENSOR_TYPE,
|
||||
} CollisionTypes;
|
||||
|
||||
typedef struct Emitter {
|
||||
int queue;
|
||||
int blocked;
|
||||
cpVect position;
|
||||
} Emitter;
|
||||
|
||||
static Emitter emitterInstance;
|
||||
|
||||
static int
|
||||
blockerBegin(cpArbiter *arb, cpSpace *space, void *unused)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
Emitter *emitter = (Emitter*)(a->data);
|
||||
|
||||
emitter->blocked++;
|
||||
|
||||
return 0; // Return values from sensors callbacks are ignored,
|
||||
}
|
||||
|
||||
static void
|
||||
blockerSeparate(cpArbiter *arb, cpSpace *space, void *unused)
|
||||
{
|
||||
CP_ARBITER_GET_SHAPES(arb, a, b);
|
||||
Emitter *emitter = (Emitter*)(a->data);
|
||||
|
||||
emitter->blocked--;
|
||||
}
|
||||
|
||||
static void
|
||||
postStepRemove(cpSpace *space, cpShape *shape, void *unused)
|
||||
{
|
||||
cpSpaceRemoveBody(space, shape->body);
|
||||
cpBodyFree(shape->body);
|
||||
|
||||
cpSpaceRemoveShape(space, shape);
|
||||
cpShapeFree(shape);
|
||||
}
|
||||
|
||||
static int
|
||||
catcherBarBegin(cpArbiter *arb, cpSpace *space, void *unused)
|
||||
{
|
||||
cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
|
||||
Emitter *emitter = (Emitter*)(a->data);
|
||||
|
||||
emitter->queue++;
|
||||
cpSpaceAddPostStepCallback(space, (cpPostStepFunc)postStepRemove, b, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static cpFloat frand_unit(){return 2.0f*((cpFloat)rand()/(cpFloat)RAND_MAX) - 1.0f;}
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
if(!emitterInstance.blocked && emitterInstance.queue){
|
||||
emitterInstance.queue--;
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 15.0f, 0.0f, cpvzero)));
|
||||
body->p = emitterInstance.position;
|
||||
body->v = cpvmult(cpv(frand_unit(), frand_unit()), 100.0f);
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, 15.0f, cpvzero));
|
||||
shape->collision_type = BALL_TYPE;
|
||||
}
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 10;
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
cpShape *shape;
|
||||
|
||||
// Data structure for our ball emitter
|
||||
// We'll use two sensors for it, one to see if the emitter is blocked
|
||||
// a second to catch the balls and add them back to the emitter
|
||||
emitterInstance.queue = 5;
|
||||
emitterInstance.blocked = 0;
|
||||
emitterInstance.position = cpv(0, 150);
|
||||
|
||||
// Create our blocking sensor, so we know when the emitter is clear to emit another ball
|
||||
shape = cpSpaceAddStaticShape(space, cpCircleShapeNew(staticBody, 15.0f, emitterInstance.position));
|
||||
shape->sensor = 1;
|
||||
shape->collision_type = BLOCKING_SENSOR_TYPE;
|
||||
shape->data = &emitterInstance;
|
||||
|
||||
// Create our catch sensor to requeue the balls when they reach the bottom of the screen
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-2000, -200), cpv(2000, -200), 15.0f));
|
||||
shape->sensor = 1;
|
||||
shape->collision_type = CATCH_SENSOR_TYPE;
|
||||
shape->data = &emitterInstance;
|
||||
|
||||
cpSpaceAddCollisionHandler(space, BLOCKING_SENSOR_TYPE, BALL_TYPE, blockerBegin, NULL, NULL, blockerSeparate, NULL);
|
||||
cpSpaceAddCollisionHandler(space, CATCH_SENSOR_TYPE, BALL_TYPE, catcherBarBegin, NULL, NULL, NULL, NULL);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Sensors = {
|
||||
"Sensors",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,115 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
// Init is called by the demo code to set up the demo.
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
// Create an infinite mass body to attach ground segments and other static geometry to.
|
||||
// We won't be adding this body to the space, because we don't want it to be simulated at all.
|
||||
// Adding bodies to the space simulates them. (fall under the influence of gravity, etc)
|
||||
// We want the static body to stay right where it is at all times.
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
// Create a space, a space is a simulation world. It simulates the motions of rigid bodies,
|
||||
// handles collisions between them, and simulates the joints between them.
|
||||
space = cpSpaceNew();
|
||||
|
||||
// Lets set some parameters of the space:
|
||||
// More iterations make the simulation more accurate but slower
|
||||
space->iterations = 10;
|
||||
// These parameters tune the efficiency of the collision detection.
|
||||
// For more info: http://code.google.com/p/chipmunk-physics/wiki/cpSpace
|
||||
cpSpaceResizeStaticHash(space, 30.0f, 1000);
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 1000);
|
||||
// Give it some gravity
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
// Create A ground segment along the bottom of the screen
|
||||
cpShape *ground = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f);
|
||||
// Set some parameters of the shape.
|
||||
// For more info: http://code.google.com/p/chipmunk-physics/wiki/cpShape
|
||||
ground->e = 1.0f; ground->u = 1.0f;
|
||||
ground->layers = NOT_GRABABLE_MASK; // Used by the Demo mouse grabbing code
|
||||
// Add the shape to the space as a static shape
|
||||
// If a shape never changes position, add it as static so Chipmunk knows it only needs to
|
||||
// calculate collision information for it once when it is added.
|
||||
// Do not change the postion of a static shape after adding it.
|
||||
cpSpaceAddStaticShape(space, ground);
|
||||
|
||||
// Add a moving circle object.
|
||||
cpFloat radius = 15.0f;
|
||||
cpFloat mass = 10.0f;
|
||||
// This time we need to give a mass and moment of inertia when creating the circle.
|
||||
cpBody *ballBody = cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero));
|
||||
// Set some parameters of the body:
|
||||
// For more info: http://code.google.com/p/chipmunk-physics/wiki/cpBody
|
||||
ballBody->p = cpv(0, -240 + radius+5);
|
||||
// Add the body to the space so it will be simulated and move around.
|
||||
cpSpaceAddBody(space, ballBody);
|
||||
|
||||
|
||||
// Add a circle shape for the ball.
|
||||
// Shapes are always defined relative to the center of gravity of the body they are attached to.
|
||||
// When the body moves or rotates, the shape will move with it.
|
||||
// Additionally, all of the cpSpaceAdd*() functions return the thing they added so you can create and add in one go.
|
||||
cpShape *ballShape = cpSpaceAddShape(space, cpCircleShapeNew(ballBody, radius, cpvzero));
|
||||
ballShape->e = 0.0f; ballShape->u = 0.9f;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
// Update is called by the demo code each frame.
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
// Chipmunk allows you to use a different timestep each frame, but it works much better when you use a fixed timestep.
|
||||
// An excellent article on why fixed timesteps for game logic can be found here: http://gafferongames.com/game-physics/fix-your-timestep/
|
||||
cpSpaceStep(space, 1.0f/60.0f);
|
||||
}
|
||||
|
||||
// destroy is called by the demo code to free all the memory we've allocated
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Simple = {
|
||||
"Simple",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,175 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static cpFloat
|
||||
springForce(cpConstraint *spring, cpFloat dist)
|
||||
{
|
||||
cpFloat clamp = 20.0f;
|
||||
return cpfclamp(cpDampedSpringGetRestLength(spring) - dist, -clamp, clamp)*cpDampedSpringGetStiffness(spring);
|
||||
}
|
||||
|
||||
static cpConstraint *
|
||||
new_spring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiff, cpFloat damp)
|
||||
{
|
||||
cpConstraint *spring = cpDampedSpringNew(a, b, anchr1, anchr2, restLength, stiff, damp);
|
||||
cpDampedSpringSetSpringForceFunc(spring, springForce);
|
||||
|
||||
return spring;
|
||||
}
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpBody *
|
||||
add_bar(cpVect a, cpVect b, int group)
|
||||
{
|
||||
cpVect center = cpvmult(cpvadd(a, b), 1.0f/2.0f);
|
||||
cpFloat length = cpvlength(cpvsub(b, a));
|
||||
cpFloat mass = length/160.0f;
|
||||
|
||||
cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, mass*length*length/12.0f));
|
||||
body->p = center;
|
||||
|
||||
cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(body, cpvsub(a, center), cpvsub(b, center), 10.0f));
|
||||
shape->group = group;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
space = cpSpaceNew();
|
||||
|
||||
cpBody *body1 = add_bar(cpv(-240, 160), cpv(-160, 80), 1);
|
||||
cpBody *body2 = add_bar(cpv(-160, 80), cpv( -80, 160), 1);
|
||||
cpBody *body3 = add_bar(cpv( 0, 160), cpv( 80, 0), 0);
|
||||
cpBody *body4 = add_bar(cpv( 160, 160), cpv( 240, 160), 0);
|
||||
cpBody *body5 = add_bar(cpv(-240, 0), cpv(-160, -80), 2);
|
||||
cpBody *body6 = add_bar(cpv(-160, -80), cpv( -80, 0), 2);
|
||||
cpBody *body7 = add_bar(cpv( -80, 0), cpv( 0, 0), 2);
|
||||
cpBody *body8 = add_bar(cpv( 0, -80), cpv( 80, -80), 0);
|
||||
cpBody *body9 = add_bar(cpv( 240, 80), cpv( 160, 0), 3);
|
||||
cpBody *body10 = add_bar(cpv( 160, 0), cpv( 240, -80), 3);
|
||||
cpBody *body11 = add_bar(cpv(-240, -80), cpv(-160, -160), 4);
|
||||
cpBody *body12 = add_bar(cpv(-160, -160), cpv( -80, -160), 0);
|
||||
cpBody *body13 = add_bar(cpv( 0, -160), cpv( 80, -160), 0);
|
||||
cpBody *body14 = add_bar(cpv( 160, -160), cpv( 240, -160), 0);
|
||||
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2( body1, body2, cpv( 40,-40), cpv(-40,-40)));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2( body5, body6, cpv( 40,-40), cpv(-40,-40)));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2( body6, body7, cpv( 40, 40), cpv(-40, 0)));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2( body9, body10, cpv(-40,-40), cpv(-40, 40)));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(body11, body12, cpv( 40,-40), cpv(-40, 0)));
|
||||
|
||||
cpFloat stiff = 100.0f;
|
||||
cpFloat damp = 0.5f;
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body1, cpv(-320, 240), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body1, cpv(-320, 80), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body1, cpv(-160, 240), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body2, cpv(-160, 240), cpv( 40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body2, cpv( 0, 240), cpv( 40, 40), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body3, cpv( 80, 240), cpv(-40, 80), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body4, cpv( 80, 240), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body4, cpv( 320, 240), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body5, cpv(-320, 80), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body9, cpv( 320, 80), cpv( 40, 40), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body10, cpv( 320, 0), cpv( 40,-40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body10, cpv( 320,-160), cpv( 40,-40), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body11, cpv(-320,-160), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body12, cpv(-240,-240), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body12, cpv( 0,-240), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body13, cpv( 0,-240), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body13, cpv( 80,-240), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body14, cpv( 80,-240), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body14, cpv( 240,-240), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(staticBody, body14, cpv( 320,-160), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
|
||||
cpSpaceAddConstraint(space, new_spring( body1, body5, cpv( 40,-40), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body1, body6, cpv( 40,-40), cpv( 40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body2, body3, cpv( 40, 40), cpv(-40, 80), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body3, body4, cpv(-40, 80), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body3, body4, cpv( 40,-80), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body3, body7, cpv( 40,-80), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body3, body7, cpv(-40, 80), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body3, body8, cpv( 40,-80), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body3, body9, cpv( 40,-80), cpv(-40,-40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body4, body9, cpv( 40, 0), cpv( 40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body5, body11, cpv(-40, 40), cpv(-40, 40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body5, body11, cpv( 40,-40), cpv( 40,-40), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body7, body8, cpv( 40, 0), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body8, body12, cpv(-40, 0), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body8, body13, cpv(-40, 0), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body8, body13, cpv( 40, 0), cpv( 40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring( body8, body14, cpv( 40, 0), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(body10, body14, cpv( 40,-40), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
cpSpaceAddConstraint(space, new_spring(body10, body14, cpv( 40,-40), cpv(-40, 0), 0.0f, stiff, damp));
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Springies = {
|
||||
"Springies",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,181 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The previous WalkBot demo I designed was fairly disappointing, so I implemented
|
||||
* the mechanism that Theo Jansen uses in his kinetic sculptures. Brilliant.
|
||||
* Read more here: http://en.wikipedia.org/wiki/Theo_Jansen
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static cpConstraint *motor;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
cpFloat coef = (2.0f + arrowDirection.y)/3.0f;
|
||||
cpFloat rate = arrowDirection.x*10.0f*coef;
|
||||
cpSimpleMotorSetRate(motor, rate);
|
||||
motor->maxForce = (rate) ? 100000.0f : 0.0f;
|
||||
|
||||
int steps = 3;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpFloat seg_radius = 3.0f;
|
||||
|
||||
static void
|
||||
make_leg(cpFloat side, cpFloat offset, cpBody *chassis, cpBody *crank, cpVect anchor)
|
||||
{
|
||||
cpVect a, b;
|
||||
cpShape *shape;
|
||||
|
||||
cpFloat leg_mass = 1.0f;
|
||||
|
||||
// make leg
|
||||
a = cpvzero, b = cpv(0.0f, side);
|
||||
cpBody *upper_leg = cpBodyNew(leg_mass, cpMomentForSegment(leg_mass, a, b));
|
||||
upper_leg->p = cpv(offset, 0.0f);
|
||||
cpSpaceAddBody(space, upper_leg);
|
||||
cpSpaceAddShape(space, cpSegmentShapeNew(upper_leg, a, b, seg_radius));
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(chassis, upper_leg, cpv(offset, 0.0f), cpvzero));
|
||||
|
||||
// lower leg
|
||||
a = cpvzero, b = cpv(0.0f, -1.0f*side);
|
||||
cpBody *lower_leg = cpBodyNew(leg_mass, cpMomentForSegment(leg_mass, a, b));
|
||||
lower_leg->p = cpv(offset, -side);
|
||||
cpSpaceAddBody(space, lower_leg);
|
||||
shape = cpSegmentShapeNew(lower_leg, a, b, seg_radius);
|
||||
shape->group = 1;
|
||||
cpSpaceAddShape(space, shape);
|
||||
shape = cpCircleShapeNew(lower_leg, seg_radius*2.0f, b);
|
||||
shape->group = 1;
|
||||
shape->e = 0.0f; shape->u = 1.0f;
|
||||
cpSpaceAddShape(space, shape);
|
||||
cpSpaceAddConstraint(space, cpPinJointNew(chassis, lower_leg, cpv(offset, 0.0f), cpvzero));
|
||||
|
||||
cpSpaceAddConstraint(space, cpGearJointNew(upper_leg, lower_leg, 0.0f, 1.0f));
|
||||
|
||||
cpConstraint *constraint;
|
||||
cpFloat diag = sqrtf(side*side + offset*offset);
|
||||
|
||||
constraint = cpPinJointNew(crank, upper_leg, anchor, cpv(0.0f, side));
|
||||
cpPinJointSetDist(constraint, diag);
|
||||
cpSpaceAddConstraint(space, constraint);
|
||||
constraint = cpPinJointNew(crank, lower_leg, anchor, cpvzero);
|
||||
cpPinJointSetDist(constraint, diag);
|
||||
cpSpaceAddConstraint(space, constraint);
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
space = cpSpaceNew();
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 20;
|
||||
space->gravity = cpv(0,-500);
|
||||
|
||||
cpShape *shape;
|
||||
cpVect a, b;
|
||||
|
||||
// Create segments around the edge of the screen.
|
||||
shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f);
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
|
||||
shape = cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f);
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
|
||||
shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f);
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
cpSpaceAddStaticShape(space, shape);
|
||||
|
||||
cpFloat offset = 30.0f;
|
||||
|
||||
// make chassis
|
||||
cpFloat chassis_mass = 2.0f;
|
||||
a = cpv(-offset, 0.0f), b = cpv(offset, 0.0f);
|
||||
cpBody *chassis = cpBodyNew(chassis_mass, cpMomentForSegment(chassis_mass, a, b));
|
||||
cpSpaceAddBody(space, chassis);
|
||||
shape = cpSegmentShapeNew(chassis, a, b, seg_radius);
|
||||
shape->group = 1;
|
||||
cpSpaceAddShape(space, shape);
|
||||
|
||||
// make crank
|
||||
cpFloat crank_mass = 1.0f;
|
||||
cpFloat crank_radius = 13.0f;
|
||||
cpBody *crank = cpBodyNew(crank_mass, cpMomentForCircle(crank_mass, crank_radius, 0.0f, cpvzero));
|
||||
cpSpaceAddBody(space, crank);
|
||||
shape = cpCircleShapeNew(crank, crank_radius, cpvzero);
|
||||
shape->group = 1;
|
||||
cpSpaceAddShape(space, shape);
|
||||
cpSpaceAddConstraint(space, cpPivotJointNew2(chassis, crank, cpvzero, cpvzero));
|
||||
|
||||
cpFloat side = 30.0f;
|
||||
|
||||
int num_legs = 2;
|
||||
for(int i=0; i<num_legs; i++){
|
||||
make_leg(side, offset, chassis, crank, cpvmult(cpvforangle((cpFloat)(2*i+0)/(cpFloat)num_legs*(cpFloat)M_PI), crank_radius));
|
||||
make_leg(side, -offset, chassis, crank, cpvmult(cpvforangle((cpFloat)(2*i+1)/(cpFloat)num_legs*(cpFloat)M_PI), crank_radius));
|
||||
}
|
||||
|
||||
motor = cpSimpleMotorNew(chassis, crank, 6.0f);
|
||||
cpSpaceAddConstraint(space, motor);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo TheoJansen = {
|
||||
"Theo Jansen Machine",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,133 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
int steps = 3;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
|
||||
// Manually update the position of the static shape so that
|
||||
// the box rotates.
|
||||
cpBodyUpdatePosition(staticBody, dt);
|
||||
|
||||
// Because the box was added as a static shape and we moved it
|
||||
// we need to manually rehash the static spatial hash.
|
||||
cpSpaceRehashStatic(space);
|
||||
}
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
cpSpaceResizeActiveHash(space, 40.0f, 999);
|
||||
cpSpaceResizeStaticHash(space, 40.0f, 99);
|
||||
space->gravity = cpv(0, -600);
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
// Vertexes for the bricks
|
||||
int num = 4;
|
||||
cpVect verts[] = {
|
||||
cpv(-30,-15),
|
||||
cpv(-30, 15),
|
||||
cpv( 30, 15),
|
||||
cpv( 30,-15),
|
||||
};
|
||||
|
||||
// Set up the static box.
|
||||
cpVect a = cpv(-200, -200);
|
||||
cpVect b = cpv(-200, 200);
|
||||
cpVect c = cpv( 200, 200);
|
||||
cpVect d = cpv( 200, -200);
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, a, b, 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, b, c, 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, c, d, 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, d, a, 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
// Give the box a little spin.
|
||||
// Because staticBody is never added to the space, we will need to
|
||||
// update it ourselves. (see above).
|
||||
// NOTE: Normally you would want to add the segments as normal and not static shapes.
|
||||
// I'm just doing it to demonstrate the cpSpaceRehashStatic() function.
|
||||
staticBody->w = 0.4f;
|
||||
|
||||
// Add the bricks.
|
||||
for(int i=0; i<3; i++){
|
||||
for(int j=0; j<7; j++){
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
|
||||
body->p = cpv(i*60 - 150, j*30 - 150);
|
||||
|
||||
shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 0.7f;
|
||||
}
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo Tumble = {
|
||||
"Tumble",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,116 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "chipmunk_unsafe.h"
|
||||
#include "drawSpace.h"
|
||||
#include "ChipmunkDemo.h"
|
||||
|
||||
static cpSpace *space;
|
||||
static cpBody *staticBody;
|
||||
|
||||
#define NUM_CIRCLES 30
|
||||
cpShape *circles[NUM_CIRCLES];
|
||||
cpFloat circleRadius = 30.0f;
|
||||
|
||||
static void
|
||||
update(int ticks)
|
||||
{
|
||||
if(arrowDirection.y){
|
||||
circleRadius = cpfmax(10.0f, circleRadius + arrowDirection.y);
|
||||
|
||||
for(int i=0; i<NUM_CIRCLES; i++){
|
||||
circles[i]->body->m = cpMomentForCircle(1.0f, 0.0f, circleRadius, cpvzero);
|
||||
cpCircleShapeSetRadius(circles[i], circleRadius);
|
||||
}
|
||||
}
|
||||
|
||||
int steps = 1;
|
||||
cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
|
||||
|
||||
for(int i=0; i<steps; i++){
|
||||
cpSpaceStep(space, dt);
|
||||
}
|
||||
}
|
||||
|
||||
static cpSpace *
|
||||
init(void)
|
||||
{
|
||||
staticBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
cpResetShapeIdCounter();
|
||||
|
||||
space = cpSpaceNew();
|
||||
space->iterations = 5;
|
||||
space->gravity = cpv(0, -100);
|
||||
|
||||
cpSpaceResizeStaticHash(space, 40.0f, 999);
|
||||
cpSpaceResizeActiveHash(space, 30.0f, 2999);
|
||||
|
||||
cpBody *body;
|
||||
cpShape *shape;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
|
||||
shape->e = 1.0f; shape->u = 1.0f;
|
||||
shape->layers = NOT_GRABABLE_MASK;
|
||||
|
||||
for(int i=0; i<NUM_CIRCLES; i++){
|
||||
body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 0.0f, circleRadius, cpvzero)));
|
||||
body->p = cpvmult(cpv(frand()*2.0f - 1.0f, frand()*2.0f - 1.0f), circleRadius*5.0f);
|
||||
|
||||
circles[i] = shape = cpSpaceAddShape(space, cpCircleShapeNew(body, circleRadius, cpvzero));
|
||||
shape->e = 0.0f; shape->u = 1.0f;
|
||||
}
|
||||
|
||||
strcat(messageString,
|
||||
"chipmunk_unsafe.h Contains functions for changing shapes, but they can cause severe stability problems if used incorrectly.\n"
|
||||
"Shape changes occur as instantaneous changes to position without an accompanying velocity change. USE WITH CAUTION!");
|
||||
return space;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy(void)
|
||||
{
|
||||
cpBodyFree(staticBody);
|
||||
cpSpaceFreeChildren(space);
|
||||
cpSpaceFree(space);
|
||||
}
|
||||
|
||||
chipmunkDemo UnsafeOps = {
|
||||
"Unsafe Operations",
|
||||
NULL,
|
||||
init,
|
||||
update,
|
||||
destroy,
|
||||
};
|
|
@ -0,0 +1,628 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
IMPORTANT - READ ME!
|
||||
|
||||
This file sets up a simple interface that the individual demos can use to get
|
||||
a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
|
||||
examples clean and simple, they contain no graphics code. All drawing is done
|
||||
by accessing the Chipmunk structures at a very low level. It is NOT
|
||||
recommended to write a game or application this way as it does not scale
|
||||
beyond simple shape drawing and is very dependent on implementation details
|
||||
about Chipmunk which may change with little to no warning.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "cocos2d.h"
|
||||
#include "cocos2dChipmunkDemo.h"
|
||||
|
||||
#define SLEEP_TICKS 16
|
||||
|
||||
//extern chipmunkDemo Test;
|
||||
extern chipmunkDemo LogoSmash;
|
||||
extern chipmunkDemo Simple;
|
||||
extern chipmunkDemo PyramidStack;
|
||||
extern chipmunkDemo Plink;
|
||||
extern chipmunkDemo Tumble;
|
||||
extern chipmunkDemo PyramidTopple;
|
||||
extern chipmunkDemo Bounce;
|
||||
extern chipmunkDemo Planet;
|
||||
extern chipmunkDemo Springies;
|
||||
extern chipmunkDemo Pump;
|
||||
extern chipmunkDemo TheoJansen;
|
||||
extern chipmunkDemo MagnetsElectric;
|
||||
extern chipmunkDemo UnsafeOps;
|
||||
extern chipmunkDemo Query;
|
||||
extern chipmunkDemo OneWay;
|
||||
extern chipmunkDemo Player;
|
||||
extern chipmunkDemo Sensors;
|
||||
extern chipmunkDemo Joints;
|
||||
|
||||
//extern chipmunkDemo Test;
|
||||
|
||||
static chipmunkDemo *demos[] = {
|
||||
&LogoSmash,
|
||||
&Simple,
|
||||
&PyramidStack,
|
||||
&Plink,
|
||||
&Tumble,
|
||||
&PyramidTopple,
|
||||
&Bounce,
|
||||
&Planet,
|
||||
&Springies,
|
||||
&Pump,
|
||||
&TheoJansen,
|
||||
&MagnetsElectric,
|
||||
&UnsafeOps,
|
||||
// &Query,
|
||||
&OneWay,
|
||||
&Player,
|
||||
&Sensors,
|
||||
&Joints,
|
||||
};
|
||||
|
||||
static int maxDemos = sizeof(demos) / sizeof(demos[0]);
|
||||
|
||||
static const int demoCount = sizeof(demos)/sizeof(chipmunkDemo *);
|
||||
static chipmunkDemo *currDemo = NULL;
|
||||
static const int firstDemoIndex = 'a' - 'a';
|
||||
|
||||
static int ticks = 0;
|
||||
static cpSpace *space;
|
||||
|
||||
cpVect mousePoint;
|
||||
cpVect mousePoint_last;
|
||||
cpBody *mouseBody = NULL;
|
||||
cpConstraint *mouseJoint = NULL;
|
||||
|
||||
char messageString[1024] = {};
|
||||
|
||||
int key_up = 0;
|
||||
int key_down = 0;
|
||||
int key_left = 0;
|
||||
int key_right = 0;
|
||||
|
||||
cpVect arrowDirection = {};
|
||||
|
||||
drawSpaceOptions options = {
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
4.0f,
|
||||
0.0f,
|
||||
1.5f,
|
||||
};
|
||||
|
||||
static void
|
||||
drawString(int x, int y, char *str)
|
||||
{
|
||||
// implement me
|
||||
}
|
||||
|
||||
static void
|
||||
drawInstructions()
|
||||
{
|
||||
drawString(-300, 220,
|
||||
"Controls:\n"
|
||||
"A - * Switch demos. (return restarts)\n"
|
||||
"Use the mouse to grab objects.\n"
|
||||
"Arrow keys control some demos.\n"
|
||||
"\\ enables anti-aliasing.\n"
|
||||
"- toggles spatial hash visualization.\n"
|
||||
"= toggles bounding boxes."
|
||||
);
|
||||
}
|
||||
|
||||
static int maxArbiters = 0;
|
||||
static int maxPoints = 0;
|
||||
static int maxConstraints = 0;
|
||||
|
||||
static void
|
||||
drawInfo()
|
||||
{
|
||||
int arbiters = space->arbiters->num;
|
||||
int points = 0;
|
||||
|
||||
for(int i=0; i<arbiters; i++)
|
||||
points += ((cpArbiter *)(space->arbiters->arr[i]))->numContacts;
|
||||
|
||||
int constraints = (space->constraints->num + points)*(space->iterations + space->elasticIterations);
|
||||
|
||||
maxArbiters = arbiters > maxArbiters ? arbiters : maxArbiters;
|
||||
maxPoints = points > maxPoints ? points : maxPoints;
|
||||
maxConstraints = constraints > maxConstraints ? constraints : maxConstraints;
|
||||
|
||||
char buffer[1000];
|
||||
char *format =
|
||||
"Arbiters: %d (%d) - "
|
||||
"Contact Points: %d (%d)\n"
|
||||
"Other Constraints: %d, Iterations: %d\n"
|
||||
"Constraints x Iterations: %d (%d)";
|
||||
|
||||
sprintf(buffer, format,
|
||||
arbiters, maxArbiters,
|
||||
points, maxPoints,
|
||||
space->constraints->num, space->iterations + space->elasticIterations,
|
||||
constraints, maxConstraints
|
||||
);
|
||||
|
||||
drawString(0, 220, buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
display(void)
|
||||
{
|
||||
// glClear(GL_COLOR_BUFFER_BIT);
|
||||
//
|
||||
// drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
|
||||
// drawInstructions();
|
||||
// drawInfo();
|
||||
// drawString(-300, -210, messageString);
|
||||
//
|
||||
// glutSwapBuffers();
|
||||
ticks++;
|
||||
|
||||
cpVect newPoint = cpvlerp(mousePoint_last, mousePoint, 0.25f);
|
||||
mouseBody->p = newPoint;
|
||||
mouseBody->v = cpvmult(cpvsub(newPoint, mousePoint_last), 60.0f);
|
||||
mousePoint_last = newPoint;
|
||||
currDemo->updateFunc(ticks);
|
||||
}
|
||||
|
||||
static char *
|
||||
demoTitle(chipmunkDemo *demo)
|
||||
{
|
||||
static char title[1024];
|
||||
sprintf(title, "Demo: %s", demo->name);
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
static void
|
||||
runDemo(chipmunkDemo *demo)
|
||||
{
|
||||
if(currDemo)
|
||||
currDemo->destroyFunc();
|
||||
|
||||
currDemo = demo;
|
||||
ticks = 0;
|
||||
mouseJoint = NULL;
|
||||
messageString[0] = '\0';
|
||||
maxArbiters = 0;
|
||||
maxPoints = 0;
|
||||
maxConstraints = 0;
|
||||
space = currDemo->initFunc();
|
||||
|
||||
// glutSetWindowTitle(demoTitle(currDemo));
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard(unsigned char key, int x, int y)
|
||||
{
|
||||
int index = key - 'a';
|
||||
|
||||
if(0 <= index && index < demoCount){
|
||||
runDemo(demos[index]);
|
||||
} else if(key == '\r'){
|
||||
runDemo(currDemo);
|
||||
} else if(key == '-'){
|
||||
options.drawHash = !options.drawHash;
|
||||
} else if(key == '='){
|
||||
options.drawBBs = !options.drawBBs;
|
||||
} else if(key == '\\'){
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
|
||||
}
|
||||
}
|
||||
|
||||
static cpVect
|
||||
mouseToSpace(int x, int y)
|
||||
{
|
||||
// GLdouble model[16];
|
||||
// glGetDoublev(GL_MODELVIEW_MATRIX, model);
|
||||
//
|
||||
// GLdouble proj[16];
|
||||
// glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
||||
//
|
||||
// GLint view[4];
|
||||
// glGetIntegerv(GL_VIEWPORT, view);
|
||||
//
|
||||
// GLdouble mx, my, mz;
|
||||
// gluUnProject(x, glutGet(GLUT_WINDOW_HEIGHT) - y, 0.0f, model, proj, view, &mx, &my, &mz);
|
||||
|
||||
// return cpv(mx, my);
|
||||
return cpv(x,y);
|
||||
}
|
||||
|
||||
static void
|
||||
mouse(int x, int y)
|
||||
{
|
||||
mousePoint = mouseToSpace(x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
click(int button, int state, int x, int y)
|
||||
{
|
||||
// if(button == GLUT_LEFT_BUTTON){
|
||||
// if(state == GLUT_DOWN){
|
||||
// cpVect point = mouseToSpace(x, y);
|
||||
//
|
||||
// cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, 0);
|
||||
// if(shape){
|
||||
// cpBody *body = shape->body;
|
||||
// mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, point));
|
||||
// mouseJoint->maxForce = 50000.0f;
|
||||
// mouseJoint->biasCoef = 0.15f;
|
||||
// cpSpaceAddConstraint(space, mouseJoint);
|
||||
// }
|
||||
// } else if(mouseJoint){
|
||||
// cpSpaceRemoveConstraint(space, mouseJoint);
|
||||
// cpConstraintFree(mouseJoint);
|
||||
// mouseJoint = NULL;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
static void
|
||||
timercall(int value)
|
||||
{
|
||||
// glutTimerFunc(SLEEP_TICKS, timercall, 0);
|
||||
//
|
||||
// glutPostRedisplay();
|
||||
}
|
||||
|
||||
static void
|
||||
set_arrowDirection()
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
|
||||
if(key_up) y += 1;
|
||||
if(key_down) y -= 1;
|
||||
if(key_right) x += 1;
|
||||
if(key_left) x -= 1;
|
||||
|
||||
arrowDirection = cpv(x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
arrowKeyDownFunc(int key, int x, int y)
|
||||
{
|
||||
// if(key == GLUT_KEY_UP) key_up = 1;
|
||||
// else if(key == GLUT_KEY_DOWN) key_down = 1;
|
||||
// else if(key == GLUT_KEY_LEFT) key_left = 1;
|
||||
// else if(key == GLUT_KEY_RIGHT) key_right = 1;
|
||||
|
||||
set_arrowDirection();
|
||||
}
|
||||
|
||||
static void
|
||||
arrowKeyUpFunc(int key, int x, int y)
|
||||
{
|
||||
// if(key == GLUT_KEY_UP) key_up = 0;
|
||||
// else if(key == GLUT_KEY_DOWN) key_down = 0;
|
||||
// else if(key == GLUT_KEY_LEFT) key_left = 0;
|
||||
// else if(key == GLUT_KEY_RIGHT) key_right = 0;
|
||||
|
||||
set_arrowDirection();
|
||||
}
|
||||
|
||||
static void
|
||||
idle(void)
|
||||
{
|
||||
// glutPostRedisplay();
|
||||
}
|
||||
|
||||
static void
|
||||
initGL(void)
|
||||
{
|
||||
// glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
//
|
||||
// glMatrixMode(GL_PROJECTION);
|
||||
// glLoadIdentity();
|
||||
// glOrtho(-320.0f, 320.0f, -240.0f, 240.0f, -1.0f, 1.0f);
|
||||
// glTranslatef(0.5f, 0.5f, 0.0f);
|
||||
//
|
||||
// glEnableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
static void
|
||||
glutStuff(int argc, const char *argv[])
|
||||
{
|
||||
// glutInit(&argc, (char**)argv);
|
||||
//
|
||||
// glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
|
||||
//
|
||||
// glutInitWindowSize(640, 480);
|
||||
// glutCreateWindow(demoTitle(demos[firstDemoIndex]));
|
||||
//
|
||||
// initGL();
|
||||
//
|
||||
// glutDisplayFunc(display);
|
||||
//// glutIdleFunc(idle);
|
||||
// glutTimerFunc(SLEEP_TICKS, timercall, 0);
|
||||
//
|
||||
// glutIgnoreKeyRepeat(1);
|
||||
// glutKeyboardFunc(keyboard);
|
||||
//
|
||||
// glutSpecialFunc(arrowKeyDownFunc);
|
||||
// glutSpecialUpFunc(arrowKeyUpFunc);
|
||||
//
|
||||
// glutMotionFunc(mouse);
|
||||
// glutPassiveMotionFunc(mouse);
|
||||
// glutMouseFunc(click);
|
||||
}
|
||||
|
||||
//#include <sys/time.h>
|
||||
//void time_trial(char index, int count)
|
||||
//{
|
||||
// currDemo = demos[index];
|
||||
// space = currDemo->initFunc();
|
||||
//
|
||||
// struct timeval start_time, end_time;
|
||||
// gettimeofday(&start_time, NULL);
|
||||
//
|
||||
// for(int i=0; i<count; i++)
|
||||
// currDemo->updateFunc(i);
|
||||
//
|
||||
// gettimeofday(&end_time, NULL);
|
||||
// long millisecs = (end_time.tv_sec - start_time.tv_sec)*1000;
|
||||
// millisecs += (end_time.tv_usec - start_time.tv_usec)/1000;
|
||||
//
|
||||
// currDemo->destroyFunc();
|
||||
//
|
||||
// printf("Time(%c) = %ldms\n", index + 'a', millisecs);
|
||||
//}
|
||||
|
||||
#if 1
|
||||
void ChipmunkTestScene::runThisTest()
|
||||
{
|
||||
// create layer
|
||||
ChipmunkTestLayer* pLayer = new ChipmunkTestLayer();
|
||||
pLayer->init();
|
||||
pLayer->autorelease();
|
||||
|
||||
addChild(pLayer);
|
||||
|
||||
CCDirector::getSharedDirector()->replaceScene(this);
|
||||
}
|
||||
|
||||
void ChipmunkTestLayer::init()
|
||||
{
|
||||
CCLayer::init();
|
||||
CCLayer::setIsTouchEnabled(TRUE);
|
||||
|
||||
demoIndex = 0;
|
||||
|
||||
cpInitChipmunk();
|
||||
mouseBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
runDemo(demos[firstDemoIndex]);
|
||||
|
||||
label = CCLabel::labelWithString(demos[firstDemoIndex]->name, "Arial", 32);
|
||||
label->setPosition( CGPointMake(0, -300) );
|
||||
label->setColor(ccBLACK);
|
||||
addChild(label);
|
||||
|
||||
// [self schedule: @selector(step:)];
|
||||
schedule( schedule_selector(ChipmunkTestLayer::step));
|
||||
}
|
||||
|
||||
void ChipmunkTestLayer::onEnter()
|
||||
{
|
||||
CCLayer::onEnter();
|
||||
|
||||
glClearColor(1,1,1,1);
|
||||
float factor = 1.0f;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
// portraint
|
||||
glOrthof(-320/factor, 320/factor, -480/factor, 480/factor, -1.0f, 1.0f);
|
||||
// landscape
|
||||
// glOrthof(-480/factor, 480/factor, -320/factor, 320/factor, 1.0f, -1.0f);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glPointSize(3.0f);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glLineWidth(1.5f);
|
||||
}
|
||||
|
||||
void ChipmunkTestLayer::step(ccTime dt)
|
||||
{
|
||||
// call chipmunk demo c function
|
||||
display();
|
||||
}
|
||||
|
||||
void ChipmunkTestLayer::draw()
|
||||
{
|
||||
drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
|
||||
}
|
||||
|
||||
void ChipmunkTestLayer::ccTouchesEnded(NSSet* touches, UIEvent *event)
|
||||
{
|
||||
demoIndex++;
|
||||
if( demoIndex >= maxDemos )
|
||||
demoIndex = 0;
|
||||
|
||||
runDemo(demos[demoIndex]);
|
||||
|
||||
label->setString( demos[demoIndex]->name );
|
||||
}
|
||||
|
||||
#else
|
||||
#pragma mark -
|
||||
#pragma mark MainLayer
|
||||
|
||||
@implementation MainLayer
|
||||
-(id) init
|
||||
{
|
||||
if( (self=[super init]) ) {
|
||||
self.isTouchEnabled = YES;
|
||||
cpInitChipmunk();
|
||||
mouseBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
runDemo(demos[firstDemoIndex]);
|
||||
|
||||
label = [CCLabel labelWithString:[NSString stringWithUTF8String:demos[firstDemoIndex]->name ] fontName:@"Marker Felt" fontSize:32];
|
||||
label.position = ccp(0,-300);
|
||||
label.color = ccBLACK;
|
||||
[self addChild:label];
|
||||
|
||||
[self schedule: @selector(step:)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) onEnter
|
||||
{
|
||||
[super onEnter];
|
||||
|
||||
glClearColor(1,1,1,1);
|
||||
float factor = 1.0f;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrthof(-320/factor, 320/factor, -480/factor, 480/factor, -1.0f, 1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glPointSize(3.0f);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glLineWidth(1.5f);
|
||||
}
|
||||
|
||||
-(void) step: (ccTime) dt
|
||||
{
|
||||
display();
|
||||
}
|
||||
|
||||
-(void) draw
|
||||
{
|
||||
drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
|
||||
}
|
||||
|
||||
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
|
||||
demoIndex++;
|
||||
if( demoIndex >= maxDemos )
|
||||
demoIndex = 0;
|
||||
|
||||
runDemo(demos[demoIndex]);
|
||||
|
||||
[label setString: [NSString stringWithUTF8String:demos[demoIndex]->name ] ];
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark AppController
|
||||
|
||||
@implementation AppController
|
||||
- (void) applicationDidFinishLaunching:(UIApplication*)application
|
||||
{
|
||||
// CC_DIRECTOR_INIT()
|
||||
//
|
||||
// 1. Initializes an EAGLView with 0-bit depth format, and RGB565 render buffer
|
||||
// 2. Attaches to the main window
|
||||
// 3. Creates Display Link Director
|
||||
// 3a. If it fails, it will use an NSTimer director
|
||||
// 4. It will try to run at 60 FPS
|
||||
// 4. Display FPS: NO
|
||||
// 5. Device orientation: Portrait
|
||||
// 6. Connect the director to the EAGLView
|
||||
//
|
||||
CC_DIRECTOR_INIT();
|
||||
|
||||
// Obtain the shared director in order to...
|
||||
CCDirector *director = [CCDirector sharedDirector];
|
||||
|
||||
// Turn on display FPS
|
||||
[director setDisplayFPS:YES];
|
||||
|
||||
CCScene *scene = [CCScene node];
|
||||
|
||||
MainLayer * mainLayer =[MainLayer node];
|
||||
|
||||
[scene addChild: mainLayer];
|
||||
|
||||
[director runWithScene: scene];
|
||||
}
|
||||
|
||||
// getting a call, pause the game
|
||||
-(void) applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
[[CCDirector sharedDirector] pause];
|
||||
}
|
||||
|
||||
// call got rejected
|
||||
-(void) applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
[[CCDirector sharedDirector] resume];
|
||||
}
|
||||
|
||||
// next delta time will be zero
|
||||
-(void) applicationSignificantTimeChange:(UIApplication *)application
|
||||
{
|
||||
[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[window release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
UIApplicationMain(argc, argv, nil, @"AppController");
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,79 @@
|
|||
/* 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 "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "testBasic.h"
|
||||
|
||||
struct chipmunkDemo;
|
||||
|
||||
typedef cpSpace *(*demoInitFunc)(void);
|
||||
typedef void (*demoUpdateFunc)(int ticks);
|
||||
typedef void (*demoDestroyFunc)(void);
|
||||
|
||||
typedef struct chipmunkDemo {
|
||||
char *name;
|
||||
|
||||
drawSpaceOptions *drawOptions;
|
||||
|
||||
demoInitFunc initFunc;
|
||||
demoUpdateFunc updateFunc;
|
||||
demoDestroyFunc destroyFunc;
|
||||
} chipmunkDemo;
|
||||
|
||||
static inline cpFloat
|
||||
frand(void)
|
||||
{
|
||||
return (cpFloat)rand()/(cpFloat)RAND_MAX;
|
||||
}
|
||||
|
||||
extern cpVect arrowDirection;
|
||||
extern char messageString[1024];
|
||||
|
||||
#define GRABABLE_MASK_BIT (1<<31)
|
||||
#define NOT_GRABABLE_MASK (~GRABABLE_MASK_BIT)
|
||||
|
||||
// cocos2d-x test interface decalre
|
||||
class ChipmunkTestScene : public TestScene
|
||||
{
|
||||
public:
|
||||
virtual void runThisTest();
|
||||
};
|
||||
|
||||
class ChipmunkTestLayer : public CCLayer
|
||||
{
|
||||
protected:
|
||||
std::string m_strTitle;
|
||||
int demoIndex;
|
||||
CCLabel *label;
|
||||
|
||||
public:
|
||||
void init();
|
||||
// virtual std::string title();
|
||||
virtual void onEnter();
|
||||
void step(ccTime dt);
|
||||
void draw();
|
||||
void ccTouchesEnded(NSSet* touches, UIEvent *event);
|
||||
|
||||
// void restartCallback(NSObject* pSender);
|
||||
// void nextCallback(NSObject* pSender);
|
||||
// void backCallback(NSObject* pSender);
|
||||
};
|
|
@ -0,0 +1,516 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "cocos2d.h"
|
||||
|
||||
/*
|
||||
IMPORTANT - READ ME!
|
||||
|
||||
This file sets up a simple interface that the individual demos can use to get
|
||||
a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
|
||||
examples clean and simple, they contain no graphics code. All drawing is done
|
||||
by accessing the Chipmunk structures at a very low level. It is NOT
|
||||
recommended to write a game or application this way as it does not scale
|
||||
beyond simple shape drawing and is very dependent on implementation details
|
||||
about Chipmunk which may change with little to no warning.
|
||||
*/
|
||||
|
||||
#define LINE_COLOR 0.0f, 0.0f, 0.0f, 1.0f
|
||||
#define COLLISION_COLOR 1.0f, 0.0f, 0.0f, 1.0f
|
||||
#define BODY_COLOR 0.0f, 0.0f, 1.0f
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
static void
|
||||
glColor_from_pointer(void *ptr)
|
||||
{
|
||||
unsigned long val = (long)ptr;
|
||||
|
||||
// hash the pointer up nicely
|
||||
val = (val+0x7ed55d16) + (val<<12);
|
||||
val = (val^0xc761c23c) ^ (val>>19);
|
||||
val = (val+0x165667b1) + (val<<5);
|
||||
val = (val+0xd3a2646c) ^ (val<<9);
|
||||
val = (val+0xfd7046c5) + (val<<3);
|
||||
val = (val^0xb55a4f09) ^ (val>>16);
|
||||
|
||||
// GLfloat v = (GLfloat)val/(GLfloat)ULONG_MAX;
|
||||
// v = 0.95f - v*0.15f;
|
||||
//
|
||||
// glColor3f(v, v, v);
|
||||
|
||||
GLubyte r = (val>>0) & 0xFF;
|
||||
GLubyte g = (val>>8) & 0xFF;
|
||||
GLubyte b = (val>>16) & 0xFF;
|
||||
|
||||
GLubyte max = r>g ? (r>b ? r : b) : (g>b ? g : b);
|
||||
|
||||
const int mult = 127;
|
||||
const int add = 63;
|
||||
r = (r*mult)/max + add;
|
||||
g = (g*mult)/max + add;
|
||||
b = (b*mult)/max + add;
|
||||
|
||||
glColor4ub(r, g, b, 255);
|
||||
}
|
||||
|
||||
static const GLfloat circleVAR[] = {
|
||||
0.0000f, 1.0000f,
|
||||
0.2588f, 0.9659f,
|
||||
0.5000f, 0.8660f,
|
||||
0.7071f, 0.7071f,
|
||||
0.8660f, 0.5000f,
|
||||
0.9659f, 0.2588f,
|
||||
1.0000f, 0.0000f,
|
||||
0.9659f, -0.2588f,
|
||||
0.8660f, -0.5000f,
|
||||
0.7071f, -0.7071f,
|
||||
0.5000f, -0.8660f,
|
||||
0.2588f, -0.9659f,
|
||||
0.0000f, -1.0000f,
|
||||
-0.2588f, -0.9659f,
|
||||
-0.5000f, -0.8660f,
|
||||
-0.7071f, -0.7071f,
|
||||
-0.8660f, -0.5000f,
|
||||
-0.9659f, -0.2588f,
|
||||
-1.0000f, -0.0000f,
|
||||
-0.9659f, 0.2588f,
|
||||
-0.8660f, 0.5000f,
|
||||
-0.7071f, 0.7071f,
|
||||
-0.5000f, 0.8660f,
|
||||
-0.2588f, 0.9659f,
|
||||
0.0000f, 1.0000f,
|
||||
0.0f, 0.0f, // For an extra line to see the rotation.
|
||||
};
|
||||
static const int circleVAR_count = sizeof(circleVAR)/sizeof(GLfloat)/2;
|
||||
|
||||
static void
|
||||
drawCircleShape(cpBody *body, cpCircleShape *circle)
|
||||
{
|
||||
glVertexPointer(2, GL_FLOAT, 0, circleVAR);
|
||||
|
||||
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
// Needed states: GL_VERTEX_ARRAY,
|
||||
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glPushMatrix(); {
|
||||
cpVect center = cpvadd(body->p, cpvrotate(circle->c, body->rot));
|
||||
glTranslatef(center.x, center.y, 0.0f);
|
||||
glRotatef(body->a*180.0f/(cpFloat)M_PI, 0.0f, 0.0f, 1.0f);
|
||||
glScalef(circle->r, circle->r, 1.0f);
|
||||
|
||||
if(!circle->shape.sensor){
|
||||
glColor_from_pointer(circle);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, circleVAR_count - 1);
|
||||
}
|
||||
|
||||
glColor4f(LINE_COLOR);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, circleVAR_count);
|
||||
} glPopMatrix();
|
||||
|
||||
// restore default GL state
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
static const GLfloat pillVAR[] = {
|
||||
0.0000f, 1.0000f,
|
||||
0.2588f, 0.9659f,
|
||||
0.5000f, 0.8660f,
|
||||
0.7071f, 0.7071f,
|
||||
0.8660f, 0.5000f,
|
||||
0.9659f, 0.2588f,
|
||||
1.0000f, 0.0000f,
|
||||
0.9659f, -0.2588f,
|
||||
0.8660f, -0.5000f,
|
||||
0.7071f, -0.7071f,
|
||||
0.5000f, -0.8660f,
|
||||
0.2588f, -0.9659f,
|
||||
0.0000f, -1.0000f,
|
||||
|
||||
0.0000f, -1.0000f,
|
||||
-0.2588f, -0.9659f,
|
||||
-0.5000f, -0.8660f,
|
||||
-0.7071f, -0.7071f,
|
||||
-0.8660f, -0.5000f,
|
||||
-0.9659f, -0.2588f,
|
||||
-1.0000f, -0.0000f,
|
||||
-0.9659f, 0.2588f,
|
||||
-0.8660f, 0.5000f,
|
||||
-0.7071f, 0.7071f,
|
||||
-0.5000f, 0.8660f,
|
||||
-0.2588f, 0.9659f,
|
||||
0.0000f, 1.0000f,
|
||||
};
|
||||
static const int pillVAR_count = sizeof(pillVAR)/sizeof(GLfloat)/2;
|
||||
|
||||
static void
|
||||
drawSegmentShape(cpBody *body, cpSegmentShape *seg)
|
||||
{
|
||||
cpVect a = cpvadd(body->p, cpvrotate(seg->a, body->rot));
|
||||
cpVect b = cpvadd(body->p, cpvrotate(seg->b, body->rot));
|
||||
|
||||
if(seg->r){
|
||||
cpVect delta = cpvsub(b, a);
|
||||
cpFloat len = cpvlength(delta)/seg->r;
|
||||
|
||||
GLfloat VAR[pillVAR_count*2];
|
||||
memcpy(VAR, pillVAR, sizeof(pillVAR));
|
||||
|
||||
for(int i=0, half=pillVAR_count; i<half; i+=2)
|
||||
VAR[i] += len;
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, VAR);
|
||||
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
// Needed states: GL_VERTEX_ARRAY,
|
||||
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glPushMatrix(); {
|
||||
GLfloat x = a.x;
|
||||
GLfloat y = a.y;
|
||||
GLfloat cos = delta.x/len;
|
||||
GLfloat sin = delta.y/len;
|
||||
|
||||
const GLfloat matrix[] = {
|
||||
cos, sin, 0.0f, 0.0f,
|
||||
-sin, cos, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 1.0f,
|
||||
x, y, 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
glMultMatrixf(matrix);
|
||||
|
||||
if(!seg->shape.sensor){
|
||||
glColor_from_pointer(seg);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, pillVAR_count);
|
||||
}
|
||||
|
||||
glColor4f(LINE_COLOR);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, pillVAR_count);
|
||||
} glPopMatrix();
|
||||
|
||||
// Restore Default GL states
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
} else {
|
||||
glColor4f(LINE_COLOR);
|
||||
ccDrawLine(ccp(a.x, a.y),ccp(b.x, b.y));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drawPolyShape(cpBody *body, cpPolyShape *poly)
|
||||
{
|
||||
int count = count=poly->numVerts;
|
||||
//GLfloat VAR[count*2];
|
||||
GLfloat *VAR = new GLfloat[count*2];
|
||||
|
||||
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
// Needed states: GL_VERTEX_ARRAY,
|
||||
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, VAR);
|
||||
|
||||
cpVect *verts = poly->verts;
|
||||
for(int i=0; i<count; i++){
|
||||
cpVect v = cpvadd(body->p, cpvrotate(verts[i], body->rot));
|
||||
VAR[2*i ] = v.x;
|
||||
VAR[2*i + 1] = v.y;
|
||||
}
|
||||
|
||||
|
||||
if(!poly->shape.sensor){
|
||||
glColor_from_pointer(poly);
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, count);
|
||||
}
|
||||
|
||||
glColor4f(LINE_COLOR);
|
||||
glDrawArrays(GL_LINE_LOOP, 0, count);
|
||||
|
||||
// Restore Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
delete VAR;
|
||||
}
|
||||
|
||||
static void
|
||||
drawObject(void *ptr, void *unused)
|
||||
{
|
||||
cpShape *shape = (cpShape *)ptr;
|
||||
cpBody *body = shape->body;
|
||||
|
||||
switch(shape->klass->type){
|
||||
case CP_CIRCLE_SHAPE:
|
||||
drawCircleShape(body, (cpCircleShape *)shape);
|
||||
break;
|
||||
case CP_SEGMENT_SHAPE:
|
||||
drawSegmentShape(body, (cpSegmentShape *)shape);
|
||||
break;
|
||||
case CP_POLY_SHAPE:
|
||||
drawPolyShape(body, (cpPolyShape *)shape);
|
||||
break;
|
||||
default:
|
||||
// printf("Bad enumeration in drawObject().\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const GLfloat springVAR[] = {
|
||||
0.00f, 0.0f,
|
||||
0.20f, 0.0f,
|
||||
0.25f, 3.0f,
|
||||
0.30f,-6.0f,
|
||||
0.35f, 6.0f,
|
||||
0.40f,-6.0f,
|
||||
0.45f, 6.0f,
|
||||
0.50f,-6.0f,
|
||||
0.55f, 6.0f,
|
||||
0.60f,-6.0f,
|
||||
0.65f, 6.0f,
|
||||
0.70f,-3.0f,
|
||||
0.75f, 6.0f,
|
||||
0.80f, 0.0f,
|
||||
1.00f, 0.0f,
|
||||
};
|
||||
static const int springVAR_count = sizeof(springVAR)/sizeof(GLfloat)/2;
|
||||
|
||||
static void
|
||||
drawSpring(cpDampedSpring *spring, cpBody *body_a, cpBody *body_b)
|
||||
{
|
||||
cpVect a = cpvadd(body_a->p, cpvrotate(spring->anchr1, body_a->rot));
|
||||
cpVect b = cpvadd(body_b->p, cpvrotate(spring->anchr2, body_b->rot));
|
||||
|
||||
glPointSize(5.0f);
|
||||
ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );
|
||||
|
||||
cpVect delta = cpvsub(b, a);
|
||||
|
||||
// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
// Needed states: GL_VERTEX_ARRAY,
|
||||
// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glVertexPointer(2, GL_FLOAT, 0, springVAR);
|
||||
glPushMatrix(); {
|
||||
GLfloat x = a.x;
|
||||
GLfloat y = a.y;
|
||||
GLfloat cos = delta.x;
|
||||
GLfloat sin = delta.y;
|
||||
GLfloat s = 1.0f/cpvlength(delta);
|
||||
|
||||
const GLfloat matrix[] = {
|
||||
cos, sin, 0.0f, 0.0f,
|
||||
-sin*s, cos*s, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 1.0f,
|
||||
x, y, 0.0f, 1.0f,
|
||||
};
|
||||
|
||||
glMultMatrixf(matrix);
|
||||
glDrawArrays(GL_LINE_STRIP, 0, springVAR_count);
|
||||
} glPopMatrix();
|
||||
|
||||
// Restore Default GL states
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
static void
|
||||
drawConstraint(cpConstraint *constraint)
|
||||
{
|
||||
cpBody *body_a = constraint->a;
|
||||
cpBody *body_b = constraint->b;
|
||||
|
||||
const cpConstraintClass *klass = constraint->klass;
|
||||
if(klass == cpPinJointGetClass()){
|
||||
cpPinJoint *joint = (cpPinJoint *)constraint;
|
||||
|
||||
cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot));
|
||||
cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));
|
||||
|
||||
glPointSize(5.0f);
|
||||
ccDrawPoint( ccp(a.x, a.y) );
|
||||
ccDrawPoint( ccp(b.x, b.y) );
|
||||
|
||||
ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );
|
||||
} else if(klass == cpSlideJointGetClass()){
|
||||
cpSlideJoint *joint = (cpSlideJoint *)constraint;
|
||||
|
||||
cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot));
|
||||
cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));
|
||||
|
||||
glPointSize(5.0f);
|
||||
ccDrawPoint( ccp(a.x, a.y) );
|
||||
ccDrawPoint( ccp(b.x, b.y) );
|
||||
|
||||
ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );
|
||||
} else if(klass == cpPivotJointGetClass()){
|
||||
cpPivotJoint *joint = (cpPivotJoint *)constraint;
|
||||
|
||||
cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot));
|
||||
cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));
|
||||
|
||||
glPointSize(10.0f);
|
||||
ccDrawPoint( ccp(a.x, a.y) );
|
||||
ccDrawPoint( ccp(b.x, b.y) );
|
||||
} else if(klass == cpGrooveJointGetClass()){
|
||||
cpGrooveJoint *joint = (cpGrooveJoint *)constraint;
|
||||
|
||||
cpVect a = cpvadd(body_a->p, cpvrotate(joint->grv_a, body_a->rot));
|
||||
cpVect b = cpvadd(body_a->p, cpvrotate(joint->grv_b, body_a->rot));
|
||||
cpVect c = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));
|
||||
|
||||
glPointSize(5.0f);
|
||||
ccDrawPoint( ccp(c.x, c.y) );
|
||||
ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );
|
||||
} else if(klass == cpDampedSpringGetClass()){
|
||||
drawSpring((cpDampedSpring *)constraint, body_a, body_b);
|
||||
} else {
|
||||
// printf("Cannot draw constraint\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drawBB(void *ptr, void *unused)
|
||||
{
|
||||
cpShape *shape = (cpShape *)ptr;
|
||||
|
||||
CGPoint vertices[] = {
|
||||
ccp(shape->bb.l, shape->bb.b),
|
||||
ccp(shape->bb.l, shape->bb.t),
|
||||
ccp(shape->bb.r, shape->bb.t),
|
||||
ccp(shape->bb.r, shape->bb.b),
|
||||
};
|
||||
|
||||
ccDrawPoly(vertices, 4, false);
|
||||
}
|
||||
|
||||
static void
|
||||
drawCollisions(void *ptr, void *data)
|
||||
{
|
||||
cpArbiter *arb = (cpArbiter *)ptr;
|
||||
for(int i=0; i<arb->numContacts; i++){
|
||||
cpVect v = arb->contacts[i].p;
|
||||
ccDrawPoint( ccp(v.x, v.y) );
|
||||
}
|
||||
}
|
||||
|
||||
// copied from cpSpaceHash.c
|
||||
static inline cpHashValue
|
||||
hash_func(cpHashValue x, cpHashValue y, cpHashValue n)
|
||||
{
|
||||
return (x*1640531513ul ^ y*2654435789ul) % n;
|
||||
}
|
||||
|
||||
static void
|
||||
drawSpatialHash(cpSpaceHash *hash)
|
||||
{
|
||||
cpBB bb = cpBBNew(-320, -240, 320, 240);
|
||||
|
||||
cpFloat dim = hash->celldim;
|
||||
int n = hash->numcells;
|
||||
|
||||
int l = (int)floor(bb.l/dim);
|
||||
int r = (int)floor(bb.r/dim);
|
||||
int b = (int)floor(bb.b/dim);
|
||||
int t = (int)floor(bb.t/dim);
|
||||
|
||||
for(int i=l; i<=r; i++){
|
||||
for(int j=b; j<=t; j++){
|
||||
int cell_count = 0;
|
||||
|
||||
int index = hash_func(i,j,n);
|
||||
for(cpSpaceHashBin *bin = hash->table[index]; bin; bin = bin->next)
|
||||
cell_count++;
|
||||
|
||||
GLfloat v = 1.0f - (GLfloat)cell_count/10.0f;
|
||||
glColor4f(v,v,v,1.0f);
|
||||
// glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drawSpace(cpSpace *space, drawSpaceOptions *options)
|
||||
{
|
||||
if(options->drawHash)
|
||||
drawSpatialHash(space->activeShapes);
|
||||
|
||||
glLineWidth(1.0f);
|
||||
if(options->drawBBs){
|
||||
glColor4f(0.3f, 0.5f, 0.3f, 1.0f);
|
||||
cpSpaceHashEach(space->activeShapes, &drawBB, NULL);
|
||||
cpSpaceHashEach(space->staticShapes, &drawBB, NULL);
|
||||
}
|
||||
|
||||
glLineWidth(options->lineThickness);
|
||||
if(options->drawShapes){
|
||||
cpSpaceHashEach(space->activeShapes, &drawObject, NULL);
|
||||
cpSpaceHashEach(space->staticShapes, &drawObject, NULL);
|
||||
}
|
||||
|
||||
cpArray *constraints = space->constraints;
|
||||
|
||||
glColor4f(0.5f, 1.0f, 0.5f, 1.0f);
|
||||
for(int i=0, count = constraints->num; i<count; i++){
|
||||
drawConstraint( (cpConstraint*)(constraints->arr[i]) );
|
||||
}
|
||||
|
||||
if(options->bodyPointSize){
|
||||
cpArray *bodies = space->bodies;
|
||||
|
||||
glPointSize(options->bodyPointSize);
|
||||
glColor4f(LINE_COLOR);
|
||||
for(int i=0, count = bodies->num; i<count; i++){
|
||||
cpBody *body = (cpBody *)bodies->arr[i];
|
||||
ccDrawPoint( ccp(body->p.x, body->p.y) );
|
||||
}
|
||||
}
|
||||
|
||||
if(options->collisionPointSize){
|
||||
glPointSize(options->collisionPointSize);
|
||||
glColor4f(COLLISION_COLOR);
|
||||
cpArrayEach(space->arbiters, &drawCollisions, NULL);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef _DRAW_SPACE_H_
|
||||
#define _DRAW_SPACE_H_
|
||||
|
||||
typedef struct drawSpaceOptions {
|
||||
int drawHash;
|
||||
int drawBBs;
|
||||
int drawShapes;
|
||||
float collisionPointSize;
|
||||
float bodyPointSize;
|
||||
float lineThickness;
|
||||
} drawSpaceOptions;
|
||||
|
||||
void drawSpace(cpSpace *space, drawSpaceOptions *options);
|
||||
|
||||
#endif //_DRAW_SPACE_H_
|
|
@ -0,0 +1,67 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
|
||||
struct chipmunkDemo;
|
||||
|
||||
typedef cpSpace *(*demoInitFunc)(void);
|
||||
typedef void (*demoUpdateFunc)(int ticks);
|
||||
typedef void (*demoDestroyFunc)(void);
|
||||
|
||||
typedef struct chipmunkDemo {
|
||||
char *name;
|
||||
|
||||
drawSpaceOptions *drawOptions;
|
||||
|
||||
demoInitFunc initFunc;
|
||||
demoUpdateFunc updateFunc;
|
||||
demoDestroyFunc destroyFunc;
|
||||
} chipmunkDemo;
|
||||
|
||||
static inline cpFloat
|
||||
frand(void)
|
||||
{
|
||||
return (cpFloat)rand()/(cpFloat)RAND_MAX;
|
||||
}
|
||||
|
||||
extern cpVect arrowDirection;
|
||||
extern char messageString[1024];
|
||||
|
||||
#define GRABABLE_MASK_BIT (1<<31)
|
||||
#define NOT_GRABABLE_MASK (~GRABABLE_MASK_BIT)
|
||||
|
||||
|
||||
//CLASS INTERFACE
|
||||
|
||||
#import "cocos2d.h"
|
||||
|
||||
@interface AppController : NSObject <UIAccelerometerDelegate, UIAlertViewDelegate, UITextFieldDelegate>
|
||||
{
|
||||
UIWindow *window;
|
||||
}
|
||||
@end
|
||||
|
||||
@interface MainLayer : CCLayer
|
||||
{
|
||||
int demoIndex;
|
||||
CCLabel *label;
|
||||
}
|
||||
@end
|
|
@ -0,0 +1,548 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
IMPORTANT - READ ME!
|
||||
|
||||
This file sets up a simple interface that the individual demos can use to get
|
||||
a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
|
||||
examples clean and simple, they contain no graphics code. All drawing is done
|
||||
by accessing the Chipmunk structures at a very low level. It is NOT
|
||||
recommended to write a game or application this way as it does not scale
|
||||
beyond simple shape drawing and is very dependent on implementation details
|
||||
about Chipmunk which may change with little to no warning.
|
||||
*/
|
||||
|
||||
#import "cocos2d.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __IPHONE_2_0
|
||||
#endif
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "drawSpace.h"
|
||||
#include "cocos2dChipmunkDemo.h"
|
||||
|
||||
#define SLEEP_TICKS 16
|
||||
|
||||
//extern chipmunkDemo Test;
|
||||
extern chipmunkDemo LogoSmash;
|
||||
extern chipmunkDemo Simple;
|
||||
extern chipmunkDemo PyramidStack;
|
||||
extern chipmunkDemo Plink;
|
||||
extern chipmunkDemo Tumble;
|
||||
extern chipmunkDemo PyramidTopple;
|
||||
extern chipmunkDemo Bounce;
|
||||
extern chipmunkDemo Planet;
|
||||
extern chipmunkDemo Springies;
|
||||
extern chipmunkDemo Pump;
|
||||
extern chipmunkDemo TheoJansen;
|
||||
extern chipmunkDemo MagnetsElectric;
|
||||
extern chipmunkDemo UnsafeOps;
|
||||
extern chipmunkDemo Query;
|
||||
extern chipmunkDemo OneWay;
|
||||
extern chipmunkDemo Player;
|
||||
extern chipmunkDemo Sensors;
|
||||
extern chipmunkDemo Joints;
|
||||
|
||||
//extern chipmunkDemo Test;
|
||||
|
||||
static chipmunkDemo *demos[] = {
|
||||
&LogoSmash,
|
||||
&Simple,
|
||||
&PyramidStack,
|
||||
&Plink,
|
||||
&Tumble,
|
||||
&PyramidTopple,
|
||||
&Bounce,
|
||||
&Planet,
|
||||
&Springies,
|
||||
&Pump,
|
||||
&TheoJansen,
|
||||
&MagnetsElectric,
|
||||
&UnsafeOps,
|
||||
// &Query,
|
||||
&OneWay,
|
||||
&Player,
|
||||
&Sensors,
|
||||
&Joints,
|
||||
};
|
||||
|
||||
static int maxDemos = sizeof(demos) / sizeof(demos[0]);
|
||||
|
||||
static const int demoCount = sizeof(demos)/sizeof(chipmunkDemo *);
|
||||
static chipmunkDemo *currDemo = NULL;
|
||||
static const int firstDemoIndex = 'a' - 'a';
|
||||
|
||||
static int ticks = 0;
|
||||
static cpSpace *space;
|
||||
|
||||
cpVect mousePoint;
|
||||
cpVect mousePoint_last;
|
||||
cpBody *mouseBody = NULL;
|
||||
cpConstraint *mouseJoint = NULL;
|
||||
|
||||
char messageString[1024] = {};
|
||||
|
||||
int key_up = 0;
|
||||
int key_down = 0;
|
||||
int key_left = 0;
|
||||
int key_right = 0;
|
||||
|
||||
cpVect arrowDirection = {};
|
||||
|
||||
drawSpaceOptions options = {
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
4.0f,
|
||||
0.0f,
|
||||
1.5f,
|
||||
};
|
||||
|
||||
static void
|
||||
drawString(int x, int y, char *str)
|
||||
{
|
||||
// implement me
|
||||
}
|
||||
|
||||
static void
|
||||
drawInstructions()
|
||||
{
|
||||
drawString(-300, 220,
|
||||
"Controls:\n"
|
||||
"A - * Switch demos. (return restarts)\n"
|
||||
"Use the mouse to grab objects.\n"
|
||||
"Arrow keys control some demos.\n"
|
||||
"\\ enables anti-aliasing.\n"
|
||||
"- toggles spatial hash visualization.\n"
|
||||
"= toggles bounding boxes."
|
||||
);
|
||||
}
|
||||
|
||||
static int maxArbiters = 0;
|
||||
static int maxPoints = 0;
|
||||
static int maxConstraints = 0;
|
||||
|
||||
static void
|
||||
drawInfo()
|
||||
{
|
||||
int arbiters = space->arbiters->num;
|
||||
int points = 0;
|
||||
|
||||
for(int i=0; i<arbiters; i++)
|
||||
points += ((cpArbiter *)(space->arbiters->arr[i]))->numContacts;
|
||||
|
||||
int constraints = (space->constraints->num + points)*(space->iterations + space->elasticIterations);
|
||||
|
||||
maxArbiters = arbiters > maxArbiters ? arbiters : maxArbiters;
|
||||
maxPoints = points > maxPoints ? points : maxPoints;
|
||||
maxConstraints = constraints > maxConstraints ? constraints : maxConstraints;
|
||||
|
||||
char buffer[1000];
|
||||
char *format =
|
||||
"Arbiters: %d (%d) - "
|
||||
"Contact Points: %d (%d)\n"
|
||||
"Other Constraints: %d, Iterations: %d\n"
|
||||
"Constraints x Iterations: %d (%d)";
|
||||
|
||||
snprintf(buffer, 1000, format,
|
||||
arbiters, maxArbiters,
|
||||
points, maxPoints,
|
||||
space->constraints->num, space->iterations + space->elasticIterations,
|
||||
constraints, maxConstraints
|
||||
);
|
||||
|
||||
drawString(0, 220, buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
display(void)
|
||||
{
|
||||
// glClear(GL_COLOR_BUFFER_BIT);
|
||||
//
|
||||
// drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
|
||||
// drawInstructions();
|
||||
// drawInfo();
|
||||
// drawString(-300, -210, messageString);
|
||||
//
|
||||
// glutSwapBuffers();
|
||||
ticks++;
|
||||
|
||||
cpVect newPoint = cpvlerp(mousePoint_last, mousePoint, 0.25f);
|
||||
mouseBody->p = newPoint;
|
||||
mouseBody->v = cpvmult(cpvsub(newPoint, mousePoint_last), 60.0f);
|
||||
mousePoint_last = newPoint;
|
||||
currDemo->updateFunc(ticks);
|
||||
}
|
||||
|
||||
static char *
|
||||
demoTitle(chipmunkDemo *demo)
|
||||
{
|
||||
static char title[1024];
|
||||
sprintf(title, "Demo: %s", demo->name);
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
static void
|
||||
runDemo(chipmunkDemo *demo)
|
||||
{
|
||||
if(currDemo)
|
||||
currDemo->destroyFunc();
|
||||
|
||||
currDemo = demo;
|
||||
ticks = 0;
|
||||
mouseJoint = NULL;
|
||||
messageString[0] = '\0';
|
||||
maxArbiters = 0;
|
||||
maxPoints = 0;
|
||||
maxConstraints = 0;
|
||||
space = currDemo->initFunc();
|
||||
|
||||
// glutSetWindowTitle(demoTitle(currDemo));
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard(unsigned char key, int x, int y)
|
||||
{
|
||||
int index = key - 'a';
|
||||
|
||||
if(0 <= index && index < demoCount){
|
||||
runDemo(demos[index]);
|
||||
} else if(key == '\r'){
|
||||
runDemo(currDemo);
|
||||
} else if(key == '-'){
|
||||
options.drawHash = !options.drawHash;
|
||||
} else if(key == '='){
|
||||
options.drawBBs = !options.drawBBs;
|
||||
} else if(key == '\\'){
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
|
||||
}
|
||||
}
|
||||
|
||||
static cpVect
|
||||
mouseToSpace(int x, int y)
|
||||
{
|
||||
// GLdouble model[16];
|
||||
// glGetDoublev(GL_MODELVIEW_MATRIX, model);
|
||||
//
|
||||
// GLdouble proj[16];
|
||||
// glGetDoublev(GL_PROJECTION_MATRIX, proj);
|
||||
//
|
||||
// GLint view[4];
|
||||
// glGetIntegerv(GL_VIEWPORT, view);
|
||||
//
|
||||
// GLdouble mx, my, mz;
|
||||
// gluUnProject(x, glutGet(GLUT_WINDOW_HEIGHT) - y, 0.0f, model, proj, view, &mx, &my, &mz);
|
||||
|
||||
// return cpv(mx, my);
|
||||
return cpv(x,y);
|
||||
}
|
||||
|
||||
static void
|
||||
mouse(int x, int y)
|
||||
{
|
||||
mousePoint = mouseToSpace(x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
click(int button, int state, int x, int y)
|
||||
{
|
||||
// if(button == GLUT_LEFT_BUTTON){
|
||||
// if(state == GLUT_DOWN){
|
||||
// cpVect point = mouseToSpace(x, y);
|
||||
//
|
||||
// cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, 0);
|
||||
// if(shape){
|
||||
// cpBody *body = shape->body;
|
||||
// mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, point));
|
||||
// mouseJoint->maxForce = 50000.0f;
|
||||
// mouseJoint->biasCoef = 0.15f;
|
||||
// cpSpaceAddConstraint(space, mouseJoint);
|
||||
// }
|
||||
// } else if(mouseJoint){
|
||||
// cpSpaceRemoveConstraint(space, mouseJoint);
|
||||
// cpConstraintFree(mouseJoint);
|
||||
// mouseJoint = NULL;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
static void
|
||||
timercall(int value)
|
||||
{
|
||||
// glutTimerFunc(SLEEP_TICKS, timercall, 0);
|
||||
//
|
||||
// glutPostRedisplay();
|
||||
}
|
||||
|
||||
static void
|
||||
set_arrowDirection()
|
||||
{
|
||||
int x = 0, y = 0;
|
||||
|
||||
if(key_up) y += 1;
|
||||
if(key_down) y -= 1;
|
||||
if(key_right) x += 1;
|
||||
if(key_left) x -= 1;
|
||||
|
||||
arrowDirection = cpv(x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
arrowKeyDownFunc(int key, int x, int y)
|
||||
{
|
||||
// if(key == GLUT_KEY_UP) key_up = 1;
|
||||
// else if(key == GLUT_KEY_DOWN) key_down = 1;
|
||||
// else if(key == GLUT_KEY_LEFT) key_left = 1;
|
||||
// else if(key == GLUT_KEY_RIGHT) key_right = 1;
|
||||
|
||||
set_arrowDirection();
|
||||
}
|
||||
|
||||
static void
|
||||
arrowKeyUpFunc(int key, int x, int y)
|
||||
{
|
||||
// if(key == GLUT_KEY_UP) key_up = 0;
|
||||
// else if(key == GLUT_KEY_DOWN) key_down = 0;
|
||||
// else if(key == GLUT_KEY_LEFT) key_left = 0;
|
||||
// else if(key == GLUT_KEY_RIGHT) key_right = 0;
|
||||
|
||||
set_arrowDirection();
|
||||
}
|
||||
|
||||
static void
|
||||
idle(void)
|
||||
{
|
||||
// glutPostRedisplay();
|
||||
}
|
||||
|
||||
static void
|
||||
initGL(void)
|
||||
{
|
||||
// glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
//
|
||||
// glMatrixMode(GL_PROJECTION);
|
||||
// glLoadIdentity();
|
||||
// glOrtho(-320.0f, 320.0f, -240.0f, 240.0f, -1.0f, 1.0f);
|
||||
// glTranslatef(0.5f, 0.5f, 0.0f);
|
||||
//
|
||||
// glEnableClientState(GL_VERTEX_ARRAY);
|
||||
}
|
||||
|
||||
static void
|
||||
glutStuff(int argc, const char *argv[])
|
||||
{
|
||||
// glutInit(&argc, (char**)argv);
|
||||
//
|
||||
// glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
|
||||
//
|
||||
// glutInitWindowSize(640, 480);
|
||||
// glutCreateWindow(demoTitle(demos[firstDemoIndex]));
|
||||
//
|
||||
// initGL();
|
||||
//
|
||||
// glutDisplayFunc(display);
|
||||
//// glutIdleFunc(idle);
|
||||
// glutTimerFunc(SLEEP_TICKS, timercall, 0);
|
||||
//
|
||||
// glutIgnoreKeyRepeat(1);
|
||||
// glutKeyboardFunc(keyboard);
|
||||
//
|
||||
// glutSpecialFunc(arrowKeyDownFunc);
|
||||
// glutSpecialUpFunc(arrowKeyUpFunc);
|
||||
//
|
||||
// glutMotionFunc(mouse);
|
||||
// glutPassiveMotionFunc(mouse);
|
||||
// glutMouseFunc(click);
|
||||
}
|
||||
|
||||
//#include <sys/time.h>
|
||||
//void time_trial(char index, int count)
|
||||
//{
|
||||
// currDemo = demos[index];
|
||||
// space = currDemo->initFunc();
|
||||
//
|
||||
// struct timeval start_time, end_time;
|
||||
// gettimeofday(&start_time, NULL);
|
||||
//
|
||||
// for(int i=0; i<count; i++)
|
||||
// currDemo->updateFunc(i);
|
||||
//
|
||||
// gettimeofday(&end_time, NULL);
|
||||
// long millisecs = (end_time.tv_sec - start_time.tv_sec)*1000;
|
||||
// millisecs += (end_time.tv_usec - start_time.tv_usec)/1000;
|
||||
//
|
||||
// currDemo->destroyFunc();
|
||||
//
|
||||
// printf("Time(%c) = %ldms\n", index + 'a', millisecs);
|
||||
//}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark MainLayer
|
||||
|
||||
@implementation MainLayer
|
||||
-(id) init
|
||||
{
|
||||
if( (self=[super init]) ) {
|
||||
self.isTouchEnabled = YES;
|
||||
cpInitChipmunk();
|
||||
mouseBody = cpBodyNew(INFINITY, INFINITY);
|
||||
|
||||
runDemo(demos[firstDemoIndex]);
|
||||
|
||||
label = [CCLabel labelWithString:[NSString stringWithUTF8String:demos[firstDemoIndex]->name ] fontName:@"Marker Felt" fontSize:32];
|
||||
label.position = ccp(0,-300);
|
||||
label.color = ccBLACK;
|
||||
[self addChild:label];
|
||||
|
||||
[self schedule: @selector(step:)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) onEnter
|
||||
{
|
||||
[super onEnter];
|
||||
|
||||
glClearColor(1,1,1,1);
|
||||
float factor = 1.0f;
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrthof(-320/factor, 320/factor, -480/factor, 480/factor, -1.0f, 1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glPointSize(3.0f);
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
|
||||
glLineWidth(1.5f);
|
||||
}
|
||||
|
||||
-(void) step: (ccTime) dt
|
||||
{
|
||||
display();
|
||||
}
|
||||
|
||||
-(void) draw
|
||||
{
|
||||
drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
|
||||
}
|
||||
|
||||
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
|
||||
demoIndex++;
|
||||
if( demoIndex >= maxDemos )
|
||||
demoIndex = 0;
|
||||
|
||||
runDemo(demos[demoIndex]);
|
||||
|
||||
[label setString: [NSString stringWithUTF8String:demos[demoIndex]->name ] ];
|
||||
}
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark AppController
|
||||
|
||||
@implementation AppController
|
||||
- (void) applicationDidFinishLaunching:(UIApplication*)application
|
||||
{
|
||||
// CC_DIRECTOR_INIT()
|
||||
//
|
||||
// 1. Initializes an EAGLView with 0-bit depth format, and RGB565 render buffer
|
||||
// 2. Attaches to the main window
|
||||
// 3. Creates Display Link Director
|
||||
// 3a. If it fails, it will use an NSTimer director
|
||||
// 4. It will try to run at 60 FPS
|
||||
// 4. Display FPS: NO
|
||||
// 5. Device orientation: Portrait
|
||||
// 6. Connect the director to the EAGLView
|
||||
//
|
||||
CC_DIRECTOR_INIT();
|
||||
|
||||
// Obtain the shared director in order to...
|
||||
CCDirector *director = [CCDirector sharedDirector];
|
||||
|
||||
// Turn on display FPS
|
||||
[director setDisplayFPS:YES];
|
||||
|
||||
CCScene *scene = [CCScene node];
|
||||
|
||||
MainLayer * mainLayer =[MainLayer node];
|
||||
|
||||
[scene addChild: mainLayer];
|
||||
|
||||
[director runWithScene: scene];
|
||||
}
|
||||
|
||||
// getting a call, pause the game
|
||||
-(void) applicationWillResignActive:(UIApplication *)application
|
||||
{
|
||||
[[CCDirector sharedDirector] pause];
|
||||
}
|
||||
|
||||
// call got rejected
|
||||
-(void) applicationDidBecomeActive:(UIApplication *)application
|
||||
{
|
||||
[[CCDirector sharedDirector] resume];
|
||||
}
|
||||
|
||||
// next delta time will be zero
|
||||
-(void) applicationSignificantTimeChange:(UIApplication *)application
|
||||
{
|
||||
[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[window release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
UIApplicationMain(argc, argv, nil, @"AppController");
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2007 Scott Lembcke and Howling Moon Software
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1 @@
|
|||
this file need to run .tmk3 file to rebuild.
|
|
@ -0,0 +1 @@
|
|||
this file need to run .tmk3 file to rebuild.
|
|
@ -0,0 +1,46 @@
|
|||
ABOUT:
|
||||
Chipmunk is a simple, lightweight and fast 2D rigid body physics library written in C. It's licensed under the unrestrictive, OSI approved MIT license. My aim is to give 2D developers access the same quality of physics you find in newer 3D games. I hope you enjoy using Chipmunk, and please consider donating to help make it worth our time to continue to support Chipmunk with great new features.
|
||||
|
||||
CONTRACTING:
|
||||
Howling Moon Software (my company) is available for contracting if you want to make the physics in your game really stand out. Given our unique experience with the library, we can help you use Chipmunk to it's fullest potential. Feel free to contact us through our webpage: http://howlingmoonsoftware.com/contracting.php
|
||||
|
||||
BUILDING:
|
||||
Mac OS X: There is an included XCode project file for building the static library and demo application. Alteratively you could use the CMake files.
|
||||
|
||||
iPhone: The XCode project can build a static library with all the proper compiler settings. Additionally, if you run the iphonestatic.sh script in the macosx/ directory, it will build you a fat library compiled as release for the device and debug for the simulator. After building that, just copy the static lib and include/chipmunk/ directory to your project.
|
||||
|
||||
UNIX: A forum user was kind enough to make a set of CMake files for Chipmunk. This will require you to have CMake installed. To build run 'cmake .' then 'make'. This should build a dynamic library, a static library, and the demo application.
|
||||
|
||||
Windows: There is an included MSVC project for building the library and demo application. I do not personally maintain the MSVC project and it apparently hasn't worked for a while. If you are a MSVC whiz, consider lending a hand.
|
||||
|
||||
Ruby: I've been using maintaining a Ruby extension for Chipmunk, but at this time is not up to date with all the latest changes. A forum member has been working on an FFI based extention, and that may be a better way to take advantage of Chipmunk from Ruby. Another forum user has offered to maintain the non-FFI version of the extension. Stay tuned.
|
||||
|
||||
GETTING STARTED:
|
||||
First of all, you can find the C API documentation here: http://code.google.com/p/chipmunk-physics/wiki/Documentation
|
||||
|
||||
A good starting point is to take a look at the included Demo application. The demos all just set up a Chipmunk simulation space and the demo app draws the graphics directly out of that. This makes it easy to see how the Chipmunk API works without worrying about the graphics code. You are free to use the demo drawing routines in your own projects, though it is certainly not the recommended way of drawing Chipmunk objects as it pokes around at the undocumented parts of Chipmunk.
|
||||
|
||||
FORUM:
|
||||
http://www.slembcke.net/forums
|
||||
|
||||
CONTACT:
|
||||
slembcke@gmail.com (also on Google Talk)
|
||||
|
||||
CHANGES SINCE 5.0.0:
|
||||
* Fixed a NaN issue where raycasts for horizontal or vertical lines would end up in an infinite loop.
|
||||
* Fixed a number of memory leaks.
|
||||
* Fixed a number of warnings for various compiler/OS combinations.
|
||||
* Fixed a number of API issues:
|
||||
* Rejecting a collision from a begin() callback permanently rejects the collision until separation.
|
||||
* Erroneous collision type parameterns removed from cpSpaceDefaulteCollisionHandler().
|
||||
* Moved FFI declarations of inlined functions into their own header.
|
||||
* Rearranged the project structure to separate out the header files into a separate include/ directory.
|
||||
* Added a static library target for the iPhone.
|
||||
* Type changes when building on the iPhone to make it friendlier to other APIs.
|
||||
* Added an AABB query to complement point and segment queries.
|
||||
* Added CP_NO_GROUP and CP_ALL_LAYERS constants.
|
||||
|
||||
CHANGES SINCE 4.x:
|
||||
* Brand new Joint/Constraint API: New constraints can be added easily and are much more flexible than the old joint system
|
||||
* Efficient Segment Queries - Like raycasting, but with line segments.
|
||||
* Brand new collision callback API: Collision begin/separate events, API for removal of objects within callbacks, more programable control over collision handling.
|
|
@ -0,0 +1,944 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>Chipmunk Game Dynamics Documentation</title>
|
||||
<style type="text/css">
|
||||
h1 {
|
||||
text-align: center;
|
||||
font-size: 300%;
|
||||
}
|
||||
|
||||
h2, h3 {
|
||||
background-color: BurlyWood;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
p.expl {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: lightGrey;
|
||||
padding: 3px;
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>Chipmunk Game Dynamics</h1>
|
||||
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
|
||||
<p>First of all, Chipmunk is a 2D rigid body physics library distributed under the <span class="caps">MIT</span> license. Though not yet complete, it is intended to be fast, numerically stable, and easy to use.</p>
|
||||
|
||||
|
||||
<p>It’s been a long time in coming, but I’ve finally made a stable and usable physics implementation. While not feature complete yet, it’s well on it’s way. I would like to give a Erin Catto a big thank you, as the most of the ideas for the constraint solver come from his Box2D example code. (<a href="http://www.gphysics.com/">gPhysics Website</a>). His contact persistence idea allows for stable stacks of objects with very few iterations of the contact solution. Couldn’t have gotten that working without his help.</p>
|
||||
|
||||
|
||||
<h2>Overview</h2>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><strong>rigid bodies:</strong> A rigid body holds the physical properties of an object. (mass, position, rotation, velocity, etc.) It does not have a shape by itself. If you’ve done physics with particles before, rigid bodies differ mostly in that they are able to rotate.</li>
|
||||
<li><strong>collision shapes:</strong> By attaching shapes to bodies, you can define the a body’s shape. You can attach many shapes to a single body to define a complex shape, or none if it doesn’t require a shape.</li>
|
||||
<li><strong>joints:</strong> You can attach joints between two bodies to constrain their behavior.</li>
|
||||
<li><strong>spaces:</strong> Spaces are the basic simulation unit in Chipmunk. You add bodies, shapes and joints to a space, and then update the space as a whole.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p><strong>Rigid bodies, collision shapes and sprites:</strong></p>
|
||||
|
||||
|
||||
<p>There is often confusion between rigid bodies and their collision shapes in Chipmunk and how they relate to sprites. A sprite would be a visual representation of an object, the sprite is drawn at the position of the rigid body. The collision shape would be the material representation of the object, and how it should collide with other objects. A sprite and collision shape have little to do with one another other than you probably want the collision shape to match the sprite’s shape.</p>
|
||||
|
||||
|
||||
<h2><span class="caps">C API</span> Documentation</h2>
|
||||
|
||||
|
||||
<h3>Initializing Chipmunk</h3>
|
||||
|
||||
|
||||
<p>Initializing Chipmunk is an extremely complicated process. The following code snippet steps you through the process:</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpInitChipmunk(); /* Actually, that's pretty much it */
|
||||
</code></pre>
|
||||
|
||||
<h3>Chipmunk memory management</h3>
|
||||
|
||||
|
||||
<p>For many of the structures you will use, Chipmunk uses a more or less standard set of memory management functions. For instance:</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><code>cpSpaceAlloc()</code> allocates but does not initialize a <code>cpSpace</code> struct.</li>
|
||||
<li><code>cpSpaceInit(space, other_args)</code> initializes a <code>cpSpace</code> struct.</li>
|
||||
<li><code>cpSpaceNew(args)</code> allocates and initializes a <code>cpSpace</code> struct using <code>args</code>.</li>
|
||||
<li><code>cpSpaceDestroy(space)</code> frees all dependancies, but does not free the <code>cpSpace</code> struct.</li>
|
||||
<li><code>cpSpaceFree(space)</code> frees all dependancies and the <code>cpSpace</code> struct.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>While you will probably use the new/free versions exclusively, the others can be helpful when writing language extensions.</p>
|
||||
|
||||
|
||||
<p>In general, you are responsible for freeing any structs that you allocate. The only exception is that <code>cpShapeDestroy()</code> also destroys the specific shape struct that was passed to the constructor.</p>
|
||||
|
||||
|
||||
<h3>Chipmunk floats: <code>cpFloat</code></h3>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef float cpFloat;
|
||||
</code></pre>
|
||||
|
||||
<p>All Chipmunk code should be <code>double</code> safe, so feel free to redefine this.</p>
|
||||
|
||||
|
||||
<h3>Chipmunk vectors: <code>cpVect</code></h3>
|
||||
|
||||
|
||||
<p><strong>User accessible fields:</strong></p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef struct cpVect{
|
||||
cpFloat x,y;
|
||||
} cpVect
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Simply a 2D vector packed into a struct. May change in the future to take advantage of <span class="caps">SIMD</span>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
#define cpvzero ((cpVect){0.0f, 0.0f})
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Constant for the zero vector.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpv(const cpFloat x, const cpFloat y)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Convenience constructor for creating new <code>cpVect</code> structs.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvadd(const cpVect v1, const cpVect v2)
|
||||
cpVect cpvsub(const cpVect v1, const cpVect v2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Add or subtract two vectors.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvneg(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Negate a vector.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvmult(const cpVect v, const cpFloat s)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Scalar multiplication.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpvdot(const cpVect v1, const cpVect v2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Vector dot product.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpvcross(const cpVect v1, const cpVect v2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">2D vector cross product analog. The cross product of 2D vectors exists only in the z component, so only that value is returned.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvperp(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns the perpendicular vector. (90 degree rotation)</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvproject(const cpVect v1, const cpVect v2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns the vector projection of <code>v1</code> onto <code>v2</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvrotate(const cpVect v1, const cpVect v2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Uses complex multiplication to rotate (and scale) <code>v1</code> by <code>v2</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvunrotate(const cpVect v1, const cpVect v2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Inverse of <code>cpvrotate()</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpvlength(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns the length of <code>v</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpvlengthsq(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns the squared length of <code>v</code>. Faster than <code>cpvlength()</code> when you only need to compare lengths.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvnormalize(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns a normalized copy of <code>v</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpvforangle(const cpFloat a)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns the unit length vector for the given angle (in radians).</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpvtoangle(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns the angular direction <code>v</code> is pointing in (in radians).</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
*cpvstr(const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns a string representation of <code>v</code>. <strong><span class="caps">NOTE</span>:</strong> <em>The string points to a static local and is reset every time the function is called.</em></p>
|
||||
|
||||
|
||||
<h3>Chipmunk bounding boxes: <code>cpBB</code></h3>
|
||||
|
||||
|
||||
<p><strong>User accessible fields:</strong></p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef struct cpBB{
|
||||
cpFloat l, b, r ,t;
|
||||
} cpBB
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Simple bounding box struct. Stored as left, bottom, right, top values.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpBB cpBBNew(const cpFloat l, const cpFloat b, const cpFloat r, const cpFloat t)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Convenience constructor for <code>cpBB</code> structs.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
int cpBBintersects(const cpBB a, const cpBB b)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns true if the bounding boxes intersect.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
int cpBBcontainsBB(const cpBB bb, const cpBB other)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns true if <code>bb</code> completely contains <code>other</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
int cpBBcontainsVect(const cpBB bb, const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns true if <code>bb</code> contains <code>v</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpBBClampVect(const cpBB bb, const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns a copy of <code>v</code> clamped to the bounding box.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpBBWrapVect(const cpBB bb, const cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Returns a copy of <code>v</code> wrapped to the bounding box.</p>
|
||||
|
||||
|
||||
<h3>Chipmunk spatial hashes: <code>cpSpaceHash</code></h3>
|
||||
|
||||
|
||||
<p><em>The spatial hash isn’t yet ready for user use. However, it has been made in a generic manner that would allow it to be used for more than just Chipmunk’s collision detection needs.</em></p>
|
||||
|
||||
|
||||
<h3>Chipmunk rigid bodies: <code>cpBody</code></h3>
|
||||
|
||||
|
||||
<p><strong>User accessible fields:</strong></p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef struct cpBody{
|
||||
cpFloat m, m_inv;
|
||||
cpFloat i, i_inv;
|
||||
|
||||
cpVect p, v, f;
|
||||
cpFloat a, w, t;
|
||||
cpVect rot;
|
||||
} cpBody
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
<li><code>m</code>, and <code>m_inv</code> are the mass and its inverse.</li>
|
||||
<li><code>i</code>, and <code>i_inv</code> are the moment of inertia and its inverse.</li>
|
||||
<li><code>p</code>, <code>v</code>, and <code>f</code> are the position, velocity and force respectively.</li>
|
||||
<li><code>a</code>, <code>w</code>, and <code>t</code> are the angle (in radians), angular velocity (rad/sec), and torque respectively.</li>
|
||||
<li><code>rot</code> is the rotation of the body as a unit length vector. (can be used with <code>cpvrotate()</code>)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpBody *cpBodyAlloc(void)
|
||||
cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i)
|
||||
cpBody *cpBodyNew(cpFloat m, cpFloat i)
|
||||
|
||||
void cpBodyDestroy(cpBody *body)
|
||||
void cpBodyFree(cpBody *body)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Uses the standard suite of Chipmunk memory functions. <code>m</code> and <code>i</code> are the mass and moment of inertia for the body.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpBodySetMass(cpBody *body, cpFloat m);
|
||||
void cpBodySetMoment(cpBody *body, cpFloat i);
|
||||
void cpBodySetAngle(cpBody *body, cpFloat a);
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Because several of the values are linked, (m/m_inv, i/i_inv, a/rot) don’t set them explicitly, use these setter functions instead.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpBodyLocal2World(cpBody *body, cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Convert from body local coordinates to world space coordinates.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpBodyWorld2Local(cpBody *body, cpVect v)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Convert from world space coordinates to body local coordinates.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpBodyApplyImpulse(cpBody *body, cpVect j, cpVect r)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Apply the impulse <code>j</code> to <code>body</code> with offset <code>r</code>. Both <code>j</code> and <code>r</code> should be in world coordinates.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpBodyResetForces(cpBody *body)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Zero both the forces and torques accumulated on <code>body</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpBodyApplyForce(cpBody *body, cpVect f, cpVect r)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Apply (accumulate) the force <code>f</code> on <code>body</code> with offset <code>r</code>. Both <code>f</code> and <code>r</code> should be in world coordinates.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Updates the velocity of the body using Euler integration. You don’t need to call this unless you are managing the object manually instead of adding it to a <code>cpSpace</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpBodyUpdatePosition(cpBody *body, cpFloat dt)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Updates the position of the body using Euler integration. Like <code>cpBodyUpdateVelocity()</code> you shouldn’t normally need to call this yourself.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Apply a spring force between bodies <code>a</code> and <code>b</code> at anchors <code>anchr1</code> and <code>anchr2</code> respectively. <code>k</code> is the spring constant (force/distance), <code>rlen</code> is the rest length of the spring, <code>dmp</code> is the damping constant (force/velocity), and <code>dt</code> is the time step to apply the force over. <strong>Note:</strong> <em>not solving the damping forces in the impulse solver causes problems with large damping values. This function will eventually be replaced by a new constraint (joint) type.</em></p>
|
||||
|
||||
|
||||
<p><strong>Notes:</strong></p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>Use forces to modify the rigid bodies if possible. This is likely to be the most stable.</li>
|
||||
<li>Modifying a body’s velocity shouldn’t necessarily be avoided, but applying large changes can cause strange results in the simulation. Experiment freely, but be warned.</li>
|
||||
<li><strong>Don’t</strong> modify a body’s position every step unless you really know what you are doing. Otherwise you’re likely to get the position/velocity badly out of sync.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Chipmunk collision shapes: <code>cpShape</code></h3>
|
||||
|
||||
|
||||
<p>There are currently 3 possible collision shapes:</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><strong>Circles</strong>: Fastest collision shape. They also roll smoothly.</li>
|
||||
<li><strong>Line segments</strong>: Meant mainly as a static shape. They can be attached to moving bodies, but they don’t generate collisions with other line segments.</li>
|
||||
<li><strong>Convex polygons</strong>: Slowest, but most flexible collision shape.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p><strong>User accessible fields:</strong></p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef struct cpShape{
|
||||
cpBB bb;
|
||||
|
||||
unsigned long collision_type;
|
||||
unsigned long group;
|
||||
unsigned long layers;
|
||||
|
||||
void *data;
|
||||
|
||||
cpBody *body;
|
||||
cpFloat e, u;
|
||||
cpVect surface_v;
|
||||
} cpShape;
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
<li><code>bb</code>: The bounding box of the shape. Only guaranteed to be valid after <code>cpShapeCacheBB()</code> is called.</li>
|
||||
<li><code>collision_type</code>: A user definable field, see the collision pair function section below for more information.</li>
|
||||
<li><code>group</code>: Shapes in the same non-zero group do not generate collisions. Useful when creating an object out of many shapes that you don’t want to self collide. Defaults to <code>0</code>;</li>
|
||||
<li><code>layers</code>: Shapes only collide if they are in the same bit-planes. i.e. <code>(a->layers & b->layers) != 0</code> By default, a shape occupies all 32 bit-planes.</li>
|
||||
<li><code>data</code>: A user definable field.</li>
|
||||
<li><code>body</code>: The rigid body the shape is attached to.</li>
|
||||
<li><code>e</code>: Elasticity of the shape. A value of 0.0 gives no bounce, while a value of 1.0 will give a “perfect” bounce. However due to inaccuracies in the simulation using 1.0 or greater is not recommended however. <em>See the notes at the end of the section.</em></li>
|
||||
<li><code>u</code>: Friction coefficient. Chipmunk uses the Coulomb friction model, a value of 0.0 is frictionless. <a href="http://www.roymech.co.uk/Useful_Tables/Tribology/co_of_frict.htm">Tables of friction coefficients</a>. <em>See the notes at the end of the section.</em></li>
|
||||
<li><code>surface_v</code>: The surface velocity of the object. Useful for creating conveyor belts or players that move around. This value is only used when calculating friction, not the collision.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpShapeDestroy(cpShape *shape)
|
||||
void cpShapeFree(cpShape *shape)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>Destroy</code> and <code>Free</code> functions are shared by all shape types.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpBB cpShapeCacheBB(cpShape *shape)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Updates and returns the bounding box of <code>shape</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpResetShapeIdCounter(void)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Chipmunk keeps a counter so that every new shape is given a unique hash value to be used in the spatial hash. Because this affects the order in which the collisions are found and handled, you should reset the shape counter every time you populate a space with new shapes. If you don’t, there might be (very) slight differences in the simulation.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpCircleShape *cpCircleShapeAlloc(void)
|
||||
cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpVect offset, cpFloat radius)
|
||||
cpShape *cpCircleShapeNew(cpBody *body, cpVect offset, cpFloat radius)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>body</code> is the body to attach the circle to, <code>offset</code> is the offset from the body’s center of gravity in body local coordinates.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpSegmentShape* cpSegmentShapeAlloc(void)
|
||||
cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius)
|
||||
cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>body</code> is the body to attach the segment to, <code>a</code> and <code>b</code> are the endpoints, and <code>radius</code> is the thickness of the segment.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpPolyShape *cpPolyShapeAlloc(void)
|
||||
cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)
|
||||
cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>body</code> is the body to attach the poly to, <code>verts</code> is an array of <code>cpVect</code>’s defining a convex hull with a counterclockwise winding, <code>offset</code> is the offset from the body’s center of gravity in body local coordinates.</p>
|
||||
|
||||
|
||||
<strong>Notes:</strong>
|
||||
<ul>
|
||||
<li>You can attach multiple collision shapes to a rigid body. This should allow you to create almost any shape you could possibly need.</li>
|
||||
<li>Shapes attached to the same rigid body will never generate collisions. You don’t have to worry about overlap when attaching multiple shapes to a rigid body.</li>
|
||||
<li>The amount of elasticity applied during a collision is determined by multiplying the elasticity of both shapes together. The same is done for determining the friction.</li>
|
||||
<li>Make sure you add both the body and it’s collision shapes to a space. The exception is when you want to have a static body or a body that you integrate yourself. In that case, only add the shape.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Chipmunk joints: <code>cpJoint</code></h3>
|
||||
|
||||
|
||||
<p>There are currently 4 kinds of joints:</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><strong>Pin Joints</strong> connect two rigid bodies with a solid pin or rod. It keeps the anchor points at a set distance from one another.</li>
|
||||
<li><strong>Slide Joints</strong> are like pin joints, but have a minimum and maximum distance. A chain could be modeled using this joint. It keeps the anchor points from getting to far apart, but will allow them to get closer together.</li>
|
||||
<li><strong>Pivot Joints</strong> simply allow two objects to pivot about a single point.</li>
|
||||
<li><strong>Groove Joints</strong> attach a point on one body to a groove on the other. Think of it as a sliding pivot joint.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpJointDestroy(cpJoint *joint)
|
||||
void cpJointFree(cpJoint *joint)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>Destroy</code> and <code>Free</code> functions are shared by all joint types.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpPinJoint *cpPinJointAlloc(void)
|
||||
cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
||||
cpJoint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>a</code> and <code>b</code> are the two bodies to connect, and <code>anchr1</code> and <code>anchr2</code> are the anchor points on those bodies.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpSlideJoint *cpSlideJointAlloc(void)
|
||||
cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
|
||||
cpJoint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>a</code> and <code>b</code> are the two bodies to connect, <code>anchr1</code> and <code>anchr2</code> are the anchor points on those bodies, and <code>min</code> and <code>max</code> define the allowed distances of the anchor points.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpPivotJoint *cpPivotJointAlloc(void)
|
||||
cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect pivot)
|
||||
cpJoint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl"><code>a</code> and <code>b</code> are the two bodies to connect, and <code>pivot</code> is the point in world coordinates of the pivot. Because the pivot location is given in world coordinates, you must have the bodies moved into the correct positions already.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpGrooveJoint *cpGrooveJointAlloc(void)
|
||||
cpGrooveJoint *cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
|
||||
cpJoint *cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">The groove goes from <em>groov_a</em> to <em>groove_b</em> on body <em>a_, and the pivot is attached to _anchr2</em> on body <em>b</em>. All coordinates are body local.</p>
|
||||
|
||||
|
||||
<p><strong>Notes:</strong></p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>You can add multiple joints between two bodies, but make sure that they don’t fight. It can cause the bodies to explode.</li>
|
||||
<li>Make sure you add both of the connected bodies and the joint to a space.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Chipmunk spaces: <code>cpSpace</code></h3>
|
||||
|
||||
|
||||
<p><strong>User accessible fields:</strong></p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef struct cpSpace{
|
||||
int iterations;
|
||||
|
||||
cpVect gravity;
|
||||
cpFloat damping;
|
||||
|
||||
int stamp;
|
||||
} cpSpace;
|
||||
</code></pre>
|
||||
|
||||
<ul>
|
||||
<li><code>iterations</code>: The number of iterations to use when solving constraints (collisions and joints). Defaults to 10.</li>
|
||||
<li><code>gravity</code>: The amount of gravity applied to the system.</li>
|
||||
<li><code>damping</code>: The amount of viscous damping applied to the system.</li>
|
||||
<li><code>stamp</code>: The tick stamp. Incremented every time <code>cpSpaceStep()</code> is called. <em>read only</em></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceFreeChildren(cpSpace *space)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Frees all bodies, shapes and joints added to the system.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpSpace* cpSpaceAlloc(void)
|
||||
cpSpace* cpSpaceInit(cpSpace *space, int iterations)
|
||||
cpSpace* cpSpaceNew(int iterations)
|
||||
|
||||
void cpSpaceDestroy(cpSpace *space)
|
||||
void cpSpaceFree(cpSpace *space)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">More standard Chipmunk memory functions.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceFreeChildren(cpSpace *space)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">This function will free all of the shapes, bodies and joints that have been added to <code>space</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceAddShape(cpSpace *space, cpShape *shape)
|
||||
void cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
|
||||
void cpSpaceAddBody(cpSpace *space, cpBody *body)
|
||||
void cpSpaceAddJoint(cpSpace *space, cpJoint *joint)
|
||||
|
||||
void cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
|
||||
void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
|
||||
void cpSpaceRemoveBody(cpSpace *space, cpBody *body)
|
||||
void cpSpaceRemoveJoint(cpSpace *space, cpJoint *joint)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">These functions add and remove shapes, bodies and joints from <code>space</code>. Shapes added as static are assumed not to move. Static shapes should be be attached to a rigid body with an infinite mass and moment of inertia. Also, don’t add the rigid body used to the space, as that will cause it to fall under the effects of gravity.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
|
||||
void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">The spatial hashes used by Chipmunk’s collision detection are fairly size sensitive. <code>dim</code> is the size of the hash cells. Setting <code>dim</code> to the average objects size is likely to give the best performance.</p>
|
||||
|
||||
|
||||
<p class="expl"><code>count</code> is the suggested minimum number of cells in the hash table. Bigger is better, but only to a point. Setting <code>count</code> to ~10x the number of objects in the hash is probably a good starting point.</p>
|
||||
|
||||
|
||||
<p class="expl">By default, <code>dim</code> is 100.0, and <code>count</code> is 1000.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceRehashStatic(cpSpace *space)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Rehashes the shapes in the static spatial hash. You only need to call this if you move one of the static shapes.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceStep(cpSpace *space, cpFloat dt)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Update the space for the given time step. Using a fixed time step is <em>highly</em> recommended. Doing so will increase the efficiency of the contact persistence, requiring an order of magnitude fewer iterations to resolve the collisions in the usual case.</p>
|
||||
|
||||
|
||||
<p><strong>Notes:</strong></p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>When removing objects from the space, make sure you remove any other objects that reference it. For instance, when you remove a body, remove the joints and shapes attached to it.</li>
|
||||
<li>The number of iterations, and the size of the time step determine the quality of the simulation. More iterations, or smaller time steps increase the quality.</li>
|
||||
<li>Because static shapes are only rehashed when you request it, it’s possible to use a much higher <code>count</code> argument to <code>cpHashResizeStaticHash()</code> than to <code>cpHashResizeStaticHash()</code>. Doing so will use more memory though.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Miscellaneous.</h3>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Calculate the moment of inertia for a circle. Arguments are similar to <code>cpCircleShapeInit()</code>. <em>m_ is the mass, _r1</em> and <em>r2</em> define an inner and outer radius, and <em>offset</em> is the offset of the center from the center of gravity of the rigid body.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpFloat cpMomentForPoly(cpFloat m, int numVerts, cpVect *verts, cpVect offset)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Calculate the moment of inertia for a poly. Arguments are similar to <code>cpPolyShapeInit()</code> <em>m_ is the mass, _numVerts</em> is the number of vertexes in <em>verts</em>, and <em>offset</em> is the offset of the poly coordinates from the center of gravity of the rigid body.</p>
|
||||
|
||||
|
||||
<h3>Collision pair functions</h3>
|
||||
|
||||
|
||||
<p>Collision pair functions allow you to add callbacks for certain collision events. Each <code>cpShape</code> structure has a user definable <code>collision_type</code> field that is used to identify its type. For instance, you could define an enumeration of collision types such as bullets and players, and then register a collision pair function to reduce the players health when a collision is found between the two.</p>
|
||||
|
||||
|
||||
<p>Additionally, the return value of a collision pair function determines whether or not a collision will be processed. If the function returns false, the collision will be ignored. One use for this functionality is to allow a rock object to break a vase object. If the approximated energy of the collision is above a certain level, flag the vase to be removed from the space, apply an impulse to the rock to slow it down, and return false. After the <code>cpSpaceStep()</code> returns, remove the vase from the space.</p>
|
||||
|
||||
|
||||
<p><strong><span class="caps">WARNING</span>:</strong> <em>It is not safe for collision pair functions to remove or free shapes or bodies from a space. Doing so will likely end in a segfault as an earlier collision may already be referencing the shape or body. You must wait until after the <code>cpSpaceStep()</code> function returns.</em></p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef struct cpContact{
|
||||
cpVect p, n;
|
||||
cpFloat dist;
|
||||
|
||||
cpFloat jnAcc, jtAcc;
|
||||
} cpContact;
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">An array of <code>cpContact</code> structs are passed to collision pair functions. Some user accessible fields include:</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li><code>p</code>: position of the collision.</li>
|
||||
<li><code>n</code>: normal of the collision.</li>
|
||||
<li><code>dist</code>: penetration distance of the collision.</li>
|
||||
<li><code>jnAcc</code> and <code>jtAcc</code>: The normal and tangential components of the accumulated (final) impulse applied to resolve the collision. Values will not be valid until after the call to <code>cpSpaceStep()</code> returns.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<pre><code>
|
||||
typedef int (*cpCollFunc)(cpShape *a, cpShape *b, cpContact *contacts, int numContacts, cpFloat normal_coef, void *data)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Prototype for a collision callback function. The two colliding shapes are passed as <code>a</code> and <code>b</code>, along with the contact points, and a user definable pointer are passed as arguments. The shapes are passed in the same order as their types were registered using <code>cpSpaceAddCollisionPairFunc()</code>. Because Chipmunk may swap the shapes to accommodate your collision pair function the normals may be backwards. Always multiply the normals by <em>normal_coef</em> before using the values. The <code>contacts</code> array may be freed on the next call to <code>cpSpaceStep()</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceAddCollisionPairFunc(cpSpace *space, unsigned long a, unsigned long b, cpCollFunc func, void *data)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Register <code>func</code> to be called when a collision is found between a shapes with <code>collision_type</code> fields that match <code>a</code> and <code>b</code>. <code>data</code> is passed to <code>func</code> as a parameter. The ordering of the collision types will match the ordering passed to the callback function.</p>
|
||||
|
||||
|
||||
<p class="expl">Passing <code>NULL</code> for <code>func</code> will reject any collision with the given collision type pair.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceRemoveCollisionPairFunc(cpSpace *space, unsigned long a, unsigned long b)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Remove the function for the given collision type pair. The order of <code>a</code> and <code>b</code> must match the original order used with <code>cpSpaceAddCollisionPairFunc()</code>.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
void cpSpaceSetDefaultCollisionPairFunc(cpSpace *space, cpCollFunc func, void *data)
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">The default function is called when no collision pair function is specified. By default, the default function simply accepts all collisions. Passing <code>NULL</code> for <code>func</code> will reset the default function back to the default. (You know what I mean.)</p>
|
||||
|
||||
|
||||
<p class="expl">Passing <code>NULL</code> for <code>func</code> will reject collisions by default.</p>
|
||||
|
||||
|
||||
<h2>Advanced topics</h2>
|
||||
|
||||
|
||||
<h3>Advanced collision processing</h3>
|
||||
|
||||
|
||||
<p>Using collision pair functions, it’s possible to get information about a collision such as the locations of the contact points and the normals, but you can’t get the impulse applied to each contact point at the time the callback is called. Because Chipmunk caches the impulses, it is possible to access them after the call to <code>cpSpaceStep()</code> returns.</p>
|
||||
|
||||
|
||||
<p>The impulse information is stored in the <code>jnAcc</code> and <code>jtAcc</code> fields of the <code>cpContact</code> structures passed to the collision pair function. So you must store a reference to the <code>contacts</code> array in the collision pair function so that you can access it later once the impulses have been calculated.</p>
|
||||
|
||||
|
||||
<pre><code>
|
||||
cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts);
|
||||
cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts);
|
||||
</code></pre>
|
||||
|
||||
<p class="expl">Sums the impulses applied to the the given contact points. <code>cpContactsSumImpulses()</code> sums only the normal components, while <code>cpContactsSumImpulsesWithFriction()</code> sums the normal and tangential componets.</p>
|
||||
|
||||
|
||||
<p><strong>Notes:</strong></p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>The <code>contact</code> array will either be destroyed or out of date after the next call to <code>cpSpaceStep()</code>. If you need to store the collision information permanently, you’ll have to copy it.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h3>Collision pair functions, groups, and layers</h3>
|
||||
|
||||
|
||||
<p>There are three ways that you can specify which shapes are allowed to collide in Chipmunk: collision pair functions, groups, and layers. What are their intended purposes?</p>
|
||||
|
||||
|
||||
<p><strong>Collision pair functions:</strong> More than just a callback, collision pair functions can conditionally allow a collision between two shapes. This is the only choice if you need to perform some logic based on the shapes or contact information before deciding to allow the collision.</p>
|
||||
|
||||
|
||||
<p><strong>Groups:</strong> Groups filter out collisions between objects in the same non-zero groups. A good example of when groups would be useful is to create a multi-body, multi-shape object such as a ragdoll. You don’t want the parts of the ragdoll to collide with itself, but you do want it to collide with other ragdolls.</p>
|
||||
|
||||
|
||||
<p><strong>Layers:</strong> Layers are another way of grouping shapes. Collision between shapes that don’t occupy one or more of the same layers are filtered out. Layers are implemented using a bitmask on an unsigned long, so there are up to 32 layers available.</p>
|
||||
|
||||
|
||||
<p>To be clear, for a collision to occur, all of the tests have to pass. Additionally, collisions between static shapes are not considered nor are collisions between shapes connected to the same rigid body.</p>
|
||||
|
||||
|
||||
<h3>Mysteries of <code>cpSpaceStep()</code> explained.</h3>
|
||||
|
||||
|
||||
<p>The <code>cpSpaceStep()</code> function is really the workhorse of Chipmunk. So what exactly does it do?</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>Persistent contacts with a stamp that is out of date by more than <code>cp_contact_persistence</code> are filtered out.</li>
|
||||
<li>Velocities of all rigid bodies in the space are integrated using <code>cpBodyUpdateVelocity()</code>.</li>
|
||||
<li>All active shapes have their bounding boxes calculated and cached.</li>
|
||||
<li>Collisions between the active shapes and static shapes are found. (collision pair functions are called)</li>
|
||||
<li>Collisions between the active shapes are found. (collision pair functions are called)</li>
|
||||
<li>Information about all constraints (collisions and joints) is pre-calculated.</li>
|
||||
<li>Impulses are found and applied to solve all constraints (joints and collisions).</li>
|
||||
<li>Positions of all rigid bodies in the space are integrated using <code>cpBodyUpdatePosition()</code>.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>Chipmunk does a lot of processing on the shapes in the system in order to provide robust and fast collision detection, but the same is not true of the rigid bodies. Really all <code>cpSpaceStep()</code> does to the bodies in the system is to integrate them and apply impulses to them.</p>
|
||||
|
||||
|
||||
<p>The integration step is really just for convenience. If you integrate the velocity of your rigid bodies before calling <code>cpSpaceStep()</code> and integrate their positions afterward, you don’t have to add them to the space at all. In fact, there are good reasons for not doing so. All bodies in the space are integrated using the same gravity and damping, and this prevents you from providing interesting objects such as moving platforms.</p>
|
||||
|
||||
|
||||
<p>If you are going to do the integration for your rigid bodies manually, I would highly recommend that you use <code>cpBodyUpdatePosition()</code> to integrate the position of the objects and only integrate the velocity. <code>cpBodyUpdatePosition()</code> is a required step for penetration resolution, and weird things could happen if it’s not called. Chipmunk uses Euler integration, so calculating the velocity required to move a body to a specific position is trivial if that is what you wish to do.</p>
|
||||
|
||||
|
||||
<h3>Chipmunk globals.</h3>
|
||||
|
||||
|
||||
<p>Chipmunk was designed with multithreading in mind, so very few globals are used. This shouldn’t be a problem in most cases as it’s likely you’ll only need to set them on a per application basis (if at all).</p>
|
||||
|
||||
|
||||
<p><code>int cp_contact_persistence</code>: This determines how long contacts should persist. This number should be fairly small as the cached contacts will only be close for a short time. <code>cp_contact_persistence</code> defaults to 3 as it is large enough to help prevent oscillating contacts, but doesn’t allow stale contact information to be used.</p>
|
||||
|
||||
|
||||
<p><code>cpFloat cp_collision_slop</code>: The amount that shapes are allowed to penetrate. Setting this to zero will work just fine, but using a small positive amount will help prevent oscillating contacts. <code>cp_collision_slop</code> defaults to 0.1.</p>
|
||||
|
||||
|
||||
<p><code>cpFloat cp_bias_coef</code>: The amount of penetration to reduce in each step. Values should range from 0 to 1. Using large values will eliminate penetration in fewer steps, but can cause vibration. <code>cp_bias_coef</code> defaults to 0.1.</p>
|
||||
|
||||
|
||||
<p><code>cpFloat cp_joint_bias_coef</code>: Similar to <code>cp_bias_coef</code>, but for joints. Defaults to 0.1. <em>In the future, joints might have their own bias coefficient instead.</em></p>
|
||||
|
||||
|
||||
<h2>Known Problems</h2>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>Fast moving objects sometimes pass right through one another. This is because I’m not doing swept volume collisions. Use smaller time steps if this is a problem.</li>
|
||||
<li>Pointy or thin polygons aren’t handled well. Collision points are generated at the poly’s vertexes. I haven’t decided what to do about this yet.</li>
|
||||
<li>Elastic shapes don’t stack well.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Performance/Quality tuning</h2>
|
||||
|
||||
|
||||
<p>There are a number of things you can do to increase the performance of Chipmunk:</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>Use simpler collision shapes when possible. It’s easier on the collision detection, you’ll generate fewer contact points, and require fewer iterations.</li>
|
||||
<li>Make sure you have your spatial hashes tuned properly. It may take some experimenting to find the optimal dim/count parameters.</li>
|
||||
<li>Use fewer iterations.</li>
|
||||
<li>Use a larger time step.</li>
|
||||
<li>Use a fixed time step. This allows contact persistence to work properly, reducing the number of iterations you need by an order of magnitude.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<p>If you have problems with jittery or vibrating objects, you need to do mostly the opposite:</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>Use simpler shapes. Simpler shapes generate fewer contacts, increasing the efficiency of each iteration.</li>
|
||||
<li>Use more iterations.</li>
|
||||
<li>Use a smaller time step.</li>
|
||||
<li>Use a fixed time step. By allowing the contact persistence to work properly, you can use more iterations without increasing the computational cost.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>To do</h2>
|
||||
|
||||
|
||||
There are a number of things left on my todo list:
|
||||
<ul>
|
||||
<li>More joint types.</li>
|
||||
<li>Post collision queries. Being able to query for all the impulses that were applied to an object would be useful.</li>
|
||||
<li>Python binding. (possibly others if I can get help)</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h2>Contact information</h2>
|
||||
|
||||
|
||||
<p>Drop me a line. Tell me how great you think Chipmunk is or how terribly buggy it is. I’d love to hear about any project that people are using Chipmunk for.</p>
|
||||
|
||||
|
||||
<p><strong><span class="caps">AIM</span>:</strong> slembcke@mac.com</p>
|
||||
|
||||
|
||||
<p><strong>Email:</strong> lemb0029(at)morris(dot)umn(dot)edu or slembcke(at)gmail(dot)com</p>
|
||||
|
||||
|
||||
<p>I can also be found lurking about the <a href="http://www.idevgames.com">iDevGames</a> forums.</p>
|
||||
|
||||
|
||||
<h2>License</h2>
|
||||
|
||||
|
||||
<p>Copyright© 2007 Scott Lembcke</p>
|
||||
|
||||
|
||||
<p>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:</p>
|
||||
|
||||
|
||||
<p>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.</p>
|
||||
|
||||
|
||||
<span class="caps">THE SOFTWARE IS PROVIDED</span> “AS IS”, <span class="caps">WITHOUT WARRANTY OF ANY KIND</span>, EXPRESS <span class="caps">OR IMPLIED</span>, INCLUDING <span class="caps">BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY</span>, FITNESS <span class="caps">FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT</span>. IN <span class="caps">NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM</span>, DAMAGES <span class="caps">OR OTHER LIABILITY</span>, WHETHER <span class="caps">IN AN ACTION OF CONTRACT</span>, TORT <span class="caps">OR OTHERWISE</span>, ARISING <span class="caps">FROM</span>, OUT <span class="caps">OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE</span>.
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,53 @@
|
|||
;
|
||||
; TG3 Makefile Auto Create Script
|
||||
;
|
||||
; 说明:
|
||||
; 1.在等号左边不要有空格
|
||||
; 2.所有的路径请使用"/"来分隔
|
||||
; 3.所有的文件名不可以有空格
|
||||
; 4.只能对当前目录及其子目录下的.c、.cpp生成Makefile
|
||||
;
|
||||
|
||||
;本TMK3文件目录位置到项目根目录之间的转换,不支持多个串,如果有多个,以最后一个为准
|
||||
;即 ./$(TO_PROJECT_ROOT)/ 就是项目的根目录
|
||||
TO_PROJECT_ROOT=../../PRJ_TG3
|
||||
|
||||
;输出目标的名字,不支持多个串,如果有多个,以最后一个为准
|
||||
OUTPUT_FILENAME=libchipmunk.so
|
||||
|
||||
;包含的其他的TMK3文件,此文件和本文件一起构成MakeFile的内容
|
||||
;此项可以出现在TMK3文件内的任意地方,与已经存在的项依次组合
|
||||
;注意:此项不支持绝对路径,但是可以使用$(TO_PROJECT_ROOT)构成文件名
|
||||
INCLUDE_TMK3=$(TO_PROJECT_ROOT)/MakeInclude/TG3_APP.TMK3 ;TOPS标准应用,包括动态库等
|
||||
|
||||
;预定义串,生成MakeFile的时候直接放在MakeFile的前面
|
||||
;格式:PRE_DEFINE=STRING,生成MakeFile的时候,"PRE_DEFINE="后面的所有非注释非续行字符都会放在MakeFile前面
|
||||
;例如:PRE_DEFINE=AAA=BBB,会放入AAA=BBB到MakeFile中
|
||||
;可以使用多个PRE_DEFINE串,也可以使用PRE_DEFINE1、PRE_DEFINE2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
;PRE_DEFINE=USE_IMAGEKIT=1 ;使用 ImageToolKit 库,此时生成的 Makefile 会自动连接有关的LIB
|
||||
;PRE_DEFINE=USE_ICU=1 ;使用 ICU 库,此时生成的 Makefile 会自动连接有关的LIB
|
||||
;PRE_DEFINE=USE_MTAPI=1 ;使用 MTAPI 库,此时生成的 Makefile 会自动连接有关的LIB
|
||||
|
||||
;C、C++预定义宏,可以使用多个DEFINES串,也可以使用DEFINES1、DEFINES2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
DEFINES=-D_MY_MARCO_ ;这里填入应用的自定义宏。注意:ITOPS自己的所需定义会自动包含,故此这里仅仅包含应用自己特有的定义即可
|
||||
;DEFINES=-D__TG3_PURE_DLL__ ;生成的是纯动态库(意思是:不是TOPS应用,但可以是TCOM组件)
|
||||
;DEFINES=-D__TCOM_SUPPORT__ ;生成的是TCOM组件(注意:TOPS应用也可以同时是TCOM组件)
|
||||
|
||||
;包含路径,可以使用多个INCLUDE_PATH串,也可以使用INCLUDE_PATH1、INCLUDE_PATH2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
INCLUDE_PATH= ;应用额外的包含路径。注意:ITOPS自己的所有路径都会自动包含,故此这里仅仅包含应用自己特有的路径即可
|
||||
|
||||
;连接的库文件,可以使用多个LIBS串,也可以使用LIBS1、LIBS2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
LIBS=-lMyLib ;应用额外的连接库。注意:ITOPS自己的所需库自动包含,而且库包含路径也已经包含,故此这里仅仅包含应用自己特有的库的名字即可
|
||||
|
||||
;强制包含文件的名字,不能使用通配符,一定要使用相对或者绝对路径
|
||||
;极力要求使用相对路径,多个文件之间使用“|”分隔
|
||||
;强制包含文件指的是不在本文件夹及其子文件夹下的.c、.cpp、.o文件
|
||||
;可以使用多个INCLUDEFILE串,也可以使用INCLUDEFILE1、INCLUDEFILE2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
INCLUDEFILE=
|
||||
|
||||
;强制排除文件,不能使用通配符,一定要使用相对路径
|
||||
;多个文件之间使用“|”分隔,路径必须以"./","../"开始
|
||||
;只能对.c、.cpp文件进行排除
|
||||
;如果要排除本目录的文件也要加入"./"
|
||||
;可以使用多个EXCLUDEFILE串,也可以使用EXCLUDEFILE1、EXCLUDEFILE2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
EXCLUDEFILE=
|
|
@ -0,0 +1,438 @@
|
|||
<?xml version="1.0" encoding="gb2312"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="chipmunk"
|
||||
ProjectGUID="{BA00DDF7-0F25-4C1E-B012-FA230C1F6463}"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="../../PRJ_TG3/LIB/Win32Lib"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".\Res;..\..\PRJ_TG3\Include;..\..\PRJ_TG3\Include\MTAPI;..\..\PRJ_TG3\Include\ThirdParty;..\..\PRJ_TG3\Include\TCOM;..\..\PRJ_TG3\TG3\Include;..\..\PRJ_TG3\TG3\TG3_Implement;..\..\PRJ_TG3\EOS_SYS;..\..\PRJ_TG3\Common\SoftSupport;..\..\PRJ_TG3\Common\ICU\Include;.\include\chipmunk"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TRANZDA_VM_;SS_MAKEDLL;__TG3_PURE_DLL__"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
StructMemberAlignment="3"
|
||||
TreatWChar_tAsBuiltInType="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="2"
|
||||
DisableSpecificWarnings="4068"
|
||||
ForcedIncludeFiles=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="../../PRJ_TG3/LIB/Win32Lib"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
|
||||
CharacterSet="2"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=".\Res;..\..\PRJ_TG3\Include;..\..\PRJ_TG3\Include\MTAPI;..\..\PRJ_TG3\Include\ThirdParty;..\..\PRJ_TG3\Include\TCOM;..\..\PRJ_TG3\TG3\Include;..\..\PRJ_TG3\TG3\TG3_Implement;..\..\PRJ_TG3\EOS_SYS;..\..\PRJ_TG3\Common\SoftSupport;..\..\PRJ_TG3\Common\ICU\Include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_TRANZDA_VM_;SS_MAKEDLL;__TG3_PURE_DLL__"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="2"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
OutputFile="$(OutDir)/chipmunk.dll"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
RandomizedBaseAddress="1"
|
||||
DataExecutionPrevention="0"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="src"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\chipmunk.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpArbiter.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpArray.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpBB.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpBody.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpCollision.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpHashSet.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpPolyShape.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpShape.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpSpace.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpSpaceHash.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\cpVect.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\prime.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="constraints"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpConstraint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpDampedRotarySpring.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpDampedSpring.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpGearJoint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpGrooveJoint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpPinJoint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpPivotJoint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpRatchetJoint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpRotaryLimitJoint.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpSimpleMotor.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\constraints\cpSlideJoint.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="include"
|
||||
>
|
||||
<Filter
|
||||
Name="chipmunk"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\chipmunk.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\chipmunk_ffi.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\chipmunk_types.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\chipmunk_unsafe.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpArbiter.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpArray.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpBB.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpBody.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpCollision.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpHashSet.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpPolyShape.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpShape.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpSpace.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpSpaceHash.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\cpVect.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="constraints"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpConstraint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpDampedRotarySpring.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpDampedSpring.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpGearJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpGrooveJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpPinJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpPivotJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpRatchetJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpRotaryLimitJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpSimpleMotor.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\cpSlideJoint.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\include\chipmunk\constraints\util.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Makefiles"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\chipmunk.TMK3"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\chipmunk_Arm.TMK3"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Makefile"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\Makefile.ARM"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="uphonefw"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\uphonefw\chipmunkUnicodeScript.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\uphonefw\chipmunkUnicodeScript_str.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\uphonefw\NewDeleteOp.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\uphonefw\TG3AppDllEntry.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\uphonefw\TG3AppDllEntry.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
|
@ -0,0 +1,53 @@
|
|||
;
|
||||
; TG3 Makefile Auto Create Script
|
||||
;
|
||||
; 说明:
|
||||
; 1.在等号左边不要有空格
|
||||
; 2.所有的路径请使用"/"来分隔
|
||||
; 3.所有的文件名不可以有空格
|
||||
; 4.只能对当前目录及其子目录下的.c、.cpp生成Makefile
|
||||
;
|
||||
|
||||
;本TMK3文件目录位置到项目根目录之间的转换,不支持多个串,如果有多个,以最后一个为准
|
||||
;即 ./$(TO_PROJECT_ROOT)/ 就是项目的根目录
|
||||
TO_PROJECT_ROOT=../../PRJ_TG3
|
||||
|
||||
;输出目标的名字,不支持多个串,如果有多个,以最后一个为准
|
||||
OUTPUT_FILENAME=libchipmunk.so
|
||||
|
||||
;包含的其他的TMK3文件,此文件和本文件一起构成MakeFile的内容
|
||||
;此项可以出现在TMK3文件内的任意地方,与已经存在的项依次组合
|
||||
;注意:此项不支持绝对路径,但是可以使用$(TO_PROJECT_ROOT)构成文件名
|
||||
INCLUDE_TMK3=$(TO_PROJECT_ROOT)/MakeInclude/TG3_APP_Arm.TMK3 ;TOPS标准应用,包括动态库等
|
||||
|
||||
;预定义串,生成MakeFile的时候直接放在MakeFile的前面
|
||||
;格式:PRE_DEFINE=STRING,生成MakeFile的时候,"PRE_DEFINE="后面的所有非注释非续行字符都会放在MakeFile前面
|
||||
;例如:PRE_DEFINE=AAA=BBB,会放入AAA=BBB到MakeFile中
|
||||
;可以使用多个PRE_DEFINE串,也可以使用PRE_DEFINE1、PRE_DEFINE2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
;PRE_DEFINE=USE_IMAGEKIT=1 ;使用 ImageToolKit 库,此时生成的 Makefile 会自动连接有关的LIB
|
||||
;PRE_DEFINE=USE_ICU=1 ;使用 ICU 库,此时生成的 Makefile 会自动连接有关的LIB
|
||||
;PRE_DEFINE=USE_MTAPI=1 ;使用 MTAPI 库,此时生成的 Makefile 会自动连接有关的LIB
|
||||
|
||||
;C、C++预定义宏,可以使用多个DEFINES串,也可以使用DEFINES1、DEFINES2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
DEFINES=-D_MY_MARCO_ ;这里填入应用的自定义宏。注意:ITOPS自己的所需定义会自动包含,故此这里仅仅包含应用自己特有的定义即可
|
||||
;DEFINES=-D__TG3_PURE_DLL__ ;生成的是纯动态库(意思是:不是TOPS应用,但可以是TCOM组件)
|
||||
;DEFINES=-D__TCOM_SUPPORT__ ;生成的是TCOM组件(注意:TOPS应用也可以同时是TCOM组件)
|
||||
|
||||
;包含路径,可以使用多个INCLUDE_PATH串,也可以使用INCLUDE_PATH1、INCLUDE_PATH2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
INCLUDE_PATH= ;应用额外的包含路径。注意:ITOPS自己的所有路径都会自动包含,故此这里仅仅包含应用自己特有的路径即可
|
||||
|
||||
;连接的库文件,可以使用多个LIBS串,也可以使用LIBS1、LIBS2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
LIBS=-lMyLib ;应用额外的连接库。注意:ITOPS自己的所需库自动包含,而且库包含路径也已经包含,故此这里仅仅包含应用自己特有的库的名字即可
|
||||
|
||||
;强制包含文件的名字,不能使用通配符,一定要使用相对或者绝对路径
|
||||
;极力要求使用相对路径,多个文件之间使用“|”分隔
|
||||
;强制包含文件指的是不在本文件夹及其子文件夹下的.c、.cpp、.o文件
|
||||
;可以使用多个INCLUDEFILE串,也可以使用INCLUDEFILE1、INCLUDEFILE2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
INCLUDEFILE=
|
||||
|
||||
;强制排除文件,不能使用通配符,一定要使用相对路径
|
||||
;多个文件之间使用“|”分隔,路径必须以"./","../"开始
|
||||
;只能对.c、.cpp文件进行排除
|
||||
;如果要排除本目录的文件也要加入"./"
|
||||
;可以使用多个EXCLUDEFILE串,也可以使用EXCLUDEFILE1、EXCLUDEFILE2等方式,MakeFile中依据出现顺序(不是数字大小)排列
|
||||
EXCLUDEFILE=
|
|
@ -0,0 +1,46 @@
|
|||
/****************************************************************************
|
||||
Copyright (c) 2010 cocos2d-x.org
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __CCX_COMMON_UPHONE__
|
||||
#define __CCX_COMMON_UPHONE__
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if defined(SS_MAKEDLL)
|
||||
#define CCX_DLL __declspec(dllexport)
|
||||
#elif defined(SS_IGNORE_EXPORT)
|
||||
#define CCX_DLL
|
||||
#else /* use a DLL library */
|
||||
#define CCX_DLL __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if defined(SS_SHARED)
|
||||
#define CCX_DLL __attribute__((visibility("default")))
|
||||
#elif defined(SS_IGNORE_EXPORT)
|
||||
#define CCX_DLL
|
||||
#else
|
||||
#define CCX_DLL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // end of __CCX_COMMON_UPHONE__
|
|
@ -0,0 +1,148 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#ifndef CHIPMUNK_HEADER
|
||||
#define CHIPMUNK_HEADER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cpMessage(char *message, char *condition, char *file, int line, int isError);
|
||||
#ifdef NDEBUG
|
||||
#define cpAssertWarn(condition, message)
|
||||
#else
|
||||
#define cpAssertWarn(condition, message) if(!(condition)) cpMessage(message, #condition, __FILE__, __LINE__, 0)
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define cpAssert(condition, message)
|
||||
#else
|
||||
#define cpAssert(condition, message) if(!(condition)) cpMessage(message, #condition, __FILE__, __LINE__, 1)
|
||||
#endif
|
||||
|
||||
#include "chipmunk_types.h"
|
||||
|
||||
static inline cpFloat
|
||||
cpfmax(cpFloat a, cpFloat b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpfmin(cpFloat a, cpFloat b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpfabs(cpFloat n)
|
||||
{
|
||||
return (n < 0) ? -n : n;
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpfclamp(cpFloat f, cpFloat min, cpFloat max)
|
||||
{
|
||||
return cpfmin(cpfmax(f, min), max);
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpflerp(cpFloat f1, cpFloat f2, cpFloat t)
|
||||
{
|
||||
return f1*(1.0f - t) + f2*t;
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpflerpconst(cpFloat f1, cpFloat f2, cpFloat d)
|
||||
{
|
||||
return f1 + cpfclamp(f2 - f1, -d, d);
|
||||
}
|
||||
|
||||
#ifndef INFINITY
|
||||
#ifdef _MSC_VER
|
||||
union MSVC_EVIL_FLOAT_HACK
|
||||
{
|
||||
unsigned __int8 Bytes[4];
|
||||
float Value;
|
||||
};
|
||||
static union MSVC_EVIL_FLOAT_HACK INFINITY_HACK = {{0x00, 0x00, 0x80, 0x7F}};
|
||||
#define INFINITY (INFINITY_HACK.Value)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define INFINITY (__builtin_inf())
|
||||
#endif
|
||||
|
||||
#ifndef INFINITY
|
||||
#define INFINITY (1e1000)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Maximum allocated size for various Chipmunk buffer sizes
|
||||
#define CP_BUFFER_BYTES (32*1024)
|
||||
|
||||
#define cpmalloc malloc
|
||||
#define cpcalloc calloc
|
||||
#define cprealloc realloc
|
||||
#define cpfree free
|
||||
|
||||
#include "cpVect.h"
|
||||
#include "cpBB.h"
|
||||
#include "cpBody.h"
|
||||
#include "cpArray.h"
|
||||
#include "cpHashSet.h"
|
||||
#include "cpSpaceHash.h"
|
||||
|
||||
#include "cpShape.h"
|
||||
#include "cpPolyShape.h"
|
||||
|
||||
#include "cpArbiter.h"
|
||||
#include "cpCollision.h"
|
||||
|
||||
#include "constraints/cpConstraint.h"
|
||||
|
||||
#include "cpSpace.h"
|
||||
|
||||
#define CP_HASH_COEF (3344921057ul)
|
||||
#define CP_HASH_PAIR(A, B) ((cpHashValue)(A)*CP_HASH_COEF ^ (cpHashValue)(B)*CP_HASH_COEF)
|
||||
|
||||
extern 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)
|
||||
cpFloat cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset);
|
||||
|
||||
// Calculate the moment of inertia for a line segment. (beveling radius not supported)
|
||||
cpFloat cpMomentForSegment(cpFloat m, cpVect a, cpVect b);
|
||||
|
||||
// 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.
|
||||
cpFloat cpMomentForBox(cpFloat m, cpFloat width, cpFloat height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
// Create non static inlined copies of Chipmunk functions, useful for working with dynamic FFIs
|
||||
// This file should only be included in chipmunk.c
|
||||
|
||||
#ifndef _CHIPMUNK_FFI_H_
|
||||
#define _CHIPMUNK_FFI_H_
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1600
|
||||
#define MAKE_REF(name) decltype(name) *_##name = name
|
||||
#else
|
||||
#define MAKE_REF(name)
|
||||
#endif
|
||||
#else
|
||||
#define MAKE_REF(name) __typeof__(name) *_##name = name
|
||||
#endif
|
||||
|
||||
MAKE_REF(cpv); // makes a variable named _cpv that contains the function pointer for cpv()
|
||||
MAKE_REF(cpvadd);
|
||||
MAKE_REF(cpvneg);
|
||||
MAKE_REF(cpvsub);
|
||||
MAKE_REF(cpvmult);
|
||||
MAKE_REF(cpvdot);
|
||||
MAKE_REF(cpvcross);
|
||||
MAKE_REF(cpvperp);
|
||||
MAKE_REF(cpvrperp);
|
||||
MAKE_REF(cpvproject);
|
||||
MAKE_REF(cpvrotate);
|
||||
MAKE_REF(cpvunrotate);
|
||||
MAKE_REF(cpvlengthsq);
|
||||
MAKE_REF(cpvlerp);
|
||||
MAKE_REF(cpvnormalize);
|
||||
MAKE_REF(cpvnormalize_safe);
|
||||
MAKE_REF(cpvclamp);
|
||||
MAKE_REF(cpvlerpconst);
|
||||
MAKE_REF(cpvdist);
|
||||
MAKE_REF(cpvnear);
|
||||
MAKE_REF(cpvdistsq);
|
||||
|
||||
MAKE_REF(cpBBNew);
|
||||
MAKE_REF(cpBBintersects);
|
||||
MAKE_REF(cpBBcontainsBB);
|
||||
MAKE_REF(cpBBcontainsVect);
|
||||
MAKE_REF(cpBBmerge);
|
||||
MAKE_REF(cpBBexpand);
|
||||
|
||||
MAKE_REF(cpBodyWorld2Local);
|
||||
MAKE_REF(cpBodyLocal2World);
|
||||
MAKE_REF(cpBodyApplyImpulse);
|
||||
|
||||
MAKE_REF(cpArbiterIsFirstContact);
|
||||
MAKE_REF(cpArbiterGetShapes);
|
||||
MAKE_REF(cpArbiterGetNormal);
|
||||
MAKE_REF(cpArbiterGetPoint);
|
||||
|
||||
#endif // _CHIPMUNK_FFI_H_
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef _CHIPMUNK_TYPES_H_
|
||||
#define _CHIPMUNK_TYPES_H_
|
||||
|
||||
#ifdef __APPLE__
|
||||
#import "TargetConditionals.h"
|
||||
#endif
|
||||
|
||||
// Use single precision floats on the iPhone.
|
||||
#if TARGET_OS_IPHONE==1
|
||||
#define CP_USE_DOUBLES 0
|
||||
#else
|
||||
// use doubles by default for higher precision
|
||||
#define CP_USE_DOUBLES 1
|
||||
#endif
|
||||
|
||||
#if CP_USE_DOUBLES
|
||||
typedef double cpFloat;
|
||||
#define cpfsqrt sqrt
|
||||
#define cpfsin sin
|
||||
#define cpfcos cos
|
||||
#define cpfacos acos
|
||||
#define cpfatan2 atan2
|
||||
#define cpfmod fmod
|
||||
#define cpfexp exp
|
||||
#define cpfpow pow
|
||||
#define cpffloor floor
|
||||
#define cpfceil ceil
|
||||
#else
|
||||
typedef float cpFloat;
|
||||
#define cpfsqrt sqrtf
|
||||
#define cpfsin sinf
|
||||
#define cpfcos cosf
|
||||
#define cpfacos acosf
|
||||
#define cpfatan2 atan2f
|
||||
#define cpfmod fmodf
|
||||
#define cpfexp expf
|
||||
#define cpfpow powf
|
||||
#define cpffloor floorf
|
||||
#define cpfceil ceilf
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
// CGPoints are structurally the same, and allow
|
||||
// easy interoperability with other iPhone libraries
|
||||
#import <CoreGraphics/CGGeometry.h>
|
||||
typedef CGPoint cpVect;
|
||||
#else
|
||||
typedef struct cpVect{cpFloat x,y;} cpVect;
|
||||
#endif
|
||||
|
||||
typedef unsigned int cpHashValue;
|
||||
|
||||
#ifdef CP_DATA_POINTER_TYPE
|
||||
typedef CP_DATA_POINTER_TYPE cpDataPointer;
|
||||
#else
|
||||
typedef void * cpDataPointer;
|
||||
#endif
|
||||
|
||||
#ifdef CP_COLLISION_TYPE_TYPE
|
||||
typedef CP_COLLISION_TYPE_TYPE cpCollisionType;
|
||||
#else
|
||||
typedef unsigned int cpCollisionType;
|
||||
#endif
|
||||
|
||||
#ifdef CP_GROUP_TYPE
|
||||
typedef CP_GROUP_TYPE cpGroup;
|
||||
#else
|
||||
typedef unsigned int cpGroup;
|
||||
#endif
|
||||
|
||||
#ifdef CP_LAYERS_TYPE
|
||||
typedef CP_GROUP_TYPE cpLayers;
|
||||
#else
|
||||
typedef unsigned int cpLayers;
|
||||
#endif
|
||||
|
||||
#ifndef CP_NO_GROUP
|
||||
#define CP_NO_GROUP ((cpGroup)0)
|
||||
#endif
|
||||
|
||||
#ifndef CP_ALL_LAYERS
|
||||
#define CP_ALL_LAYERS (~(cpLayers)0)
|
||||
#endif
|
||||
|
||||
#endif // _CHIPMUNK_TYPES_H_
|
|
@ -0,0 +1,54 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* This header defines a number of "unsafe" operations on Chipmunk objects.
|
||||
* In this case "unsafe" is referring to operations which may reduce the
|
||||
* physical accuracy or numerical stability of the simulation, but will not
|
||||
* cause crashes.
|
||||
*
|
||||
* The prime example is mutating collision shapes. Chipmunk does not support
|
||||
* this directly. Mutating shapes using this API will caused objects in contact
|
||||
* to be pushed apart using Chipmunk's overlap solver, but not using real
|
||||
* persistent velocities. Probably not what you meant, but perhaps close enough.
|
||||
*/
|
||||
|
||||
#ifndef CHIPMUNK_UNSAFE_HEADER
|
||||
#define CHIPMUNK_UNSAFE_HEADER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void cpCircleShapeSetRadius(cpShape *shape, cpFloat radius);
|
||||
void cpCircleShapeSetOffset(cpShape *shape, cpVect offset);
|
||||
|
||||
void cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b);
|
||||
void cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius);
|
||||
|
||||
void cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// TODO: Comment me!
|
||||
|
||||
extern cpFloat cp_constraint_bias_coef;
|
||||
|
||||
struct cpConstraintClass;
|
||||
struct cpConstraint;
|
||||
|
||||
typedef void (*cpConstraintPreStepFunction)(struct cpConstraint *constraint, cpFloat dt, cpFloat dt_inv);
|
||||
typedef void (*cpConstraintApplyImpulseFunction)(struct cpConstraint *constraint);
|
||||
typedef cpFloat (*cpConstraintGetImpulseFunction)(struct cpConstraint *constraint);
|
||||
|
||||
typedef struct cpConstraintClass {
|
||||
cpConstraintPreStepFunction preStep;
|
||||
cpConstraintApplyImpulseFunction applyImpulse;
|
||||
cpConstraintGetImpulseFunction getImpulse;
|
||||
} cpConstraintClass;
|
||||
|
||||
|
||||
|
||||
typedef struct cpConstraint {
|
||||
const cpConstraintClass *klass;
|
||||
|
||||
cpBody *a, *b;
|
||||
cpFloat maxForce;
|
||||
cpFloat biasCoef;
|
||||
cpFloat maxBias;
|
||||
|
||||
cpDataPointer data;
|
||||
} cpConstraint;
|
||||
|
||||
#ifdef CP_USE_DEPRECATED_API_4
|
||||
typedef cpConstraint cpJoint;
|
||||
#endif
|
||||
|
||||
void cpConstraintDestroy(cpConstraint *constraint);
|
||||
void cpConstraintFree(cpConstraint *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){ \
|
||||
cpConstraintCheckCast(constraint, struct); \
|
||||
return ((struct *)constraint)->member; \
|
||||
} \
|
||||
|
||||
#define CP_DefineConstraintSetter(struct, type, member, name) \
|
||||
static inline void \
|
||||
struct##Set##name(cpConstraint *constraint, type value){ \
|
||||
cpConstraintCheckCast(constraint, struct); \
|
||||
((struct *)constraint)->member = value; \
|
||||
} \
|
||||
|
||||
#define CP_DefineConstraintProperty(struct, type, member, name) \
|
||||
CP_DefineConstraintGetter(struct, type, member, name) \
|
||||
CP_DefineConstraintSetter(struct, type, member, name)
|
||||
|
||||
// Built in Joint types
|
||||
#include "cpPinJoint.h"
|
||||
#include "cpSlideJoint.h"
|
||||
#include "cpPivotJoint.h"
|
||||
#include "cpGrooveJoint.h"
|
||||
#include "cpDampedSpring.h"
|
||||
#include "cpDampedRotarySpring.h"
|
||||
#include "cpRotaryLimitJoint.h"
|
||||
#include "cpRatchetJoint.h"
|
||||
#include "cpGearJoint.h"
|
||||
#include "cpSimpleMotor.h"
|
|
@ -0,0 +1,46 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
typedef cpFloat (*cpDampedRotarySpringTorqueFunc)(struct cpConstraint *spring, cpFloat relativeAngle);
|
||||
|
||||
const cpConstraintClass *cpDampedRotarySpringGetClass();
|
||||
|
||||
typedef struct cpDampedRotarySpring {
|
||||
cpConstraint constraint;
|
||||
cpFloat restAngle;
|
||||
cpFloat stiffness;
|
||||
cpFloat damping;
|
||||
cpDampedRotarySpringTorqueFunc springTorqueFunc;
|
||||
|
||||
cpFloat dt;
|
||||
cpFloat target_wrn;
|
||||
|
||||
cpFloat iSum;
|
||||
} cpDampedRotarySpring;
|
||||
|
||||
cpDampedRotarySpring *cpDampedRotarySpringAlloc(void);
|
||||
cpDampedRotarySpring *cpDampedRotarySpringInit(cpDampedRotarySpring *joint, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
|
||||
cpConstraint *cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping);
|
||||
|
||||
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, restAngle, RestAngle);
|
||||
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, stiffness, Stiffness);
|
||||
CP_DefineConstraintProperty(cpDampedRotarySpring, cpFloat, damping, Damping);
|
||||
CP_DefineConstraintProperty(cpDampedRotarySpring, cpDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc);
|
|
@ -0,0 +1,53 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
struct cpDampedSpring;
|
||||
|
||||
typedef cpFloat (*cpDampedSpringForceFunc)(struct cpConstraint *spring, cpFloat dist);
|
||||
|
||||
const cpConstraintClass *cpDampedSpringGetClass();
|
||||
|
||||
typedef struct cpDampedSpring {
|
||||
cpConstraint constraint;
|
||||
cpVect anchr1, anchr2;
|
||||
cpFloat restLength;
|
||||
cpFloat stiffness;
|
||||
cpFloat damping;
|
||||
cpDampedSpringForceFunc springForceFunc;
|
||||
|
||||
cpFloat dt;
|
||||
cpFloat target_vrn;
|
||||
|
||||
cpVect r1, r2;
|
||||
cpFloat nMass;
|
||||
cpVect n;
|
||||
} cpDampedSpring;
|
||||
|
||||
cpDampedSpring *cpDampedSpringAlloc(void);
|
||||
cpDampedSpring *cpDampedSpringInit(cpDampedSpring *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
|
||||
cpConstraint *cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping);
|
||||
|
||||
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1);
|
||||
CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr2, Anchr2);
|
||||
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, restLength, RestLength);
|
||||
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, stiffness, Stiffness);
|
||||
CP_DefineConstraintProperty(cpDampedSpring, cpFloat, damping, Damping);
|
||||
CP_DefineConstraintProperty(cpDampedSpring, cpDampedSpringForceFunc, springForceFunc, SpringForceFunc);
|
|
@ -0,0 +1,41 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpGearJointGetClass();
|
||||
|
||||
typedef struct cpGearJoint {
|
||||
cpConstraint constraint;
|
||||
cpFloat phase, ratio;
|
||||
cpFloat ratio_inv;
|
||||
|
||||
cpFloat iSum;
|
||||
|
||||
cpFloat bias;
|
||||
cpFloat jAcc, jMax;
|
||||
} cpGearJoint;
|
||||
|
||||
cpGearJoint *cpGearJointAlloc(void);
|
||||
cpGearJoint *cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
|
||||
cpConstraint *cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio);
|
||||
|
||||
CP_DefineConstraintProperty(cpGearJoint, cpFloat, phase, Phase);
|
||||
CP_DefineConstraintGetter(cpGearJoint, cpFloat, ratio, Ratio);
|
||||
void cpGearJointSetRatio(cpConstraint *constraint, cpFloat value);
|
|
@ -0,0 +1,44 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpGrooveJointGetClass();
|
||||
|
||||
typedef struct cpGrooveJoint {
|
||||
cpConstraint constraint;
|
||||
cpVect grv_n, grv_a, grv_b;
|
||||
cpVect anchr2;
|
||||
|
||||
cpVect grv_tn;
|
||||
cpFloat clamp;
|
||||
cpVect r1, r2;
|
||||
cpVect k1, k2;
|
||||
|
||||
cpVect jAcc;
|
||||
cpFloat jMaxLen;
|
||||
cpVect bias;
|
||||
} cpGrooveJoint;
|
||||
|
||||
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_DefineConstraintProperty(cpGrooveJoint, cpVect, anchr2, Anchr2);
|
|
@ -0,0 +1,43 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpPinJointGetClass();
|
||||
|
||||
typedef struct cpPinJoint {
|
||||
cpConstraint constraint;
|
||||
cpVect anchr1, anchr2;
|
||||
cpFloat dist;
|
||||
|
||||
cpVect r1, r2;
|
||||
cpVect n;
|
||||
cpFloat nMass;
|
||||
|
||||
cpFloat jnAcc, jnMax;
|
||||
cpFloat bias;
|
||||
} cpPinJoint;
|
||||
|
||||
cpPinJoint *cpPinJointAlloc(void);
|
||||
cpPinJoint *cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
|
||||
cpConstraint *cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
|
||||
|
||||
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1);
|
||||
CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr2, Anchr2);
|
||||
CP_DefineConstraintProperty(cpPinJoint, cpFloat, dist, Dist);
|
|
@ -0,0 +1,42 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpPivotJointGetClass();
|
||||
|
||||
typedef struct cpPivotJoint {
|
||||
cpConstraint constraint;
|
||||
cpVect anchr1, anchr2;
|
||||
|
||||
cpVect r1, r2;
|
||||
cpVect k1, k2;
|
||||
|
||||
cpVect jAcc;
|
||||
cpFloat jMaxLen;
|
||||
cpVect bias;
|
||||
} cpPivotJoint;
|
||||
|
||||
cpPivotJoint *cpPivotJointAlloc(void);
|
||||
cpPivotJoint *cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
|
||||
cpConstraint *cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot);
|
||||
cpConstraint *cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2);
|
||||
|
||||
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr1, Anchr1);
|
||||
CP_DefineConstraintProperty(cpPivotJoint, cpVect, anchr2, Anchr2);
|
|
@ -0,0 +1,40 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpRatchetJointGetClass();
|
||||
|
||||
typedef struct cpRatchetJoint {
|
||||
cpConstraint constraint;
|
||||
cpFloat angle, phase, ratchet;
|
||||
|
||||
cpFloat iSum;
|
||||
|
||||
cpFloat bias;
|
||||
cpFloat jAcc, jMax;
|
||||
} cpRatchetJoint;
|
||||
|
||||
cpRatchetJoint *cpRatchetJointAlloc(void);
|
||||
cpRatchetJoint *cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
|
||||
cpConstraint *cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet);
|
||||
|
||||
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, angle, Angle);
|
||||
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, phase, Phase);
|
||||
CP_DefineConstraintProperty(cpRatchetJoint, cpFloat, ratchet, Ratchet);
|
|
@ -0,0 +1,39 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpRotaryLimitJointGetClass();
|
||||
|
||||
typedef struct cpRotaryLimitJoint {
|
||||
cpConstraint constraint;
|
||||
cpFloat min, max;
|
||||
|
||||
cpFloat iSum;
|
||||
|
||||
cpFloat bias;
|
||||
cpFloat jAcc, jMax;
|
||||
} cpRotaryLimitJoint;
|
||||
|
||||
cpRotaryLimitJoint *cpRotaryLimitJointAlloc(void);
|
||||
cpRotaryLimitJoint *cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max);
|
||||
cpConstraint *cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max);
|
||||
|
||||
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, min, Min);
|
||||
CP_DefineConstraintProperty(cpRotaryLimitJoint, cpFloat, max, Max);
|
|
@ -0,0 +1,37 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpSimpleMotorGetClass();
|
||||
|
||||
typedef struct cpSimpleMotor {
|
||||
cpConstraint constraint;
|
||||
cpFloat rate;
|
||||
|
||||
cpFloat iSum;
|
||||
|
||||
cpFloat jAcc, jMax;
|
||||
} cpSimpleMotor;
|
||||
|
||||
cpSimpleMotor *cpSimpleMotorAlloc(void);
|
||||
cpSimpleMotor *cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate);
|
||||
cpConstraint *cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate);
|
||||
|
||||
CP_DefineConstraintProperty(cpSimpleMotor, cpFloat, rate, Rate);
|
|
@ -0,0 +1,44 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
const cpConstraintClass *cpSlideJointGetClass();
|
||||
|
||||
typedef struct cpSlideJoint {
|
||||
cpConstraint constraint;
|
||||
cpVect anchr1, anchr2;
|
||||
cpFloat min, max;
|
||||
|
||||
cpVect r1, r2;
|
||||
cpVect n;
|
||||
cpFloat nMass;
|
||||
|
||||
cpFloat jnAcc, jnMax;
|
||||
cpFloat bias;
|
||||
} cpSlideJoint;
|
||||
|
||||
cpSlideJoint *cpSlideJointAlloc(void);
|
||||
cpSlideJoint *cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
|
||||
cpConstraint *cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max);
|
||||
|
||||
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr1, Anchr1);
|
||||
CP_DefineConstraintProperty(cpSlideJoint, cpVect, anchr2, Anchr2);
|
||||
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, min, Min);
|
||||
CP_DefineConstraintProperty(cpSlideJoint, cpFloat, max, Max);
|
|
@ -0,0 +1,116 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#define CP_DefineClassGetter(t) const cpConstraintClass * t##GetClass(){return (cpConstraintClass *)&klass;}
|
||||
|
||||
void cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b);
|
||||
|
||||
#define J_MAX(constraint, dt) (((cpConstraint *)constraint)->maxForce*(dt))
|
||||
|
||||
static inline cpVect
|
||||
relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2){
|
||||
cpVect v1_sum = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
|
||||
cpVect v2_sum = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));
|
||||
|
||||
return cpvsub(v2_sum, v1_sum);
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
normal_relative_velocity(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n){
|
||||
return cpvdot(relative_velocity(a, b, r1, r2), n);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
|
||||
{
|
||||
cpBodyApplyImpulse(a, cpvneg(j), r1);
|
||||
cpBodyApplyImpulse(b, j, r2);
|
||||
}
|
||||
|
||||
static inline void
|
||||
apply_bias_impulses(cpBody *a , cpBody *b, cpVect r1, cpVect r2, cpVect j)
|
||||
{
|
||||
cpBodyApplyBiasImpulse(a, cpvneg(j), r1);
|
||||
cpBodyApplyBiasImpulse(b, j, r2);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
clamp_vect(cpVect v, cpFloat len)
|
||||
{
|
||||
return cpvclamp(v, len);
|
||||
// return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
k_scalar(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect n)
|
||||
{
|
||||
cpFloat mass_sum = a->m_inv + b->m_inv;
|
||||
cpFloat r1cn = cpvcross(r1, n);
|
||||
cpFloat r2cn = cpvcross(r2, n);
|
||||
|
||||
cpFloat value = mass_sum + a->i_inv*r1cn*r1cn + b->i_inv*r2cn*r2cn;
|
||||
cpAssert(value != 0.0, "Unsolvable collision or constraint.");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void
|
||||
k_tensor(cpBody *a, cpBody *b, cpVect r1, cpVect r2, cpVect *k1, cpVect *k2)
|
||||
{
|
||||
// calculate mass matrix
|
||||
// If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross...
|
||||
cpFloat k11, k12, k21, k22;
|
||||
cpFloat m_sum = a->m_inv + b->m_inv;
|
||||
|
||||
// start with I*m_sum
|
||||
k11 = m_sum; k12 = 0.0f;
|
||||
k21 = 0.0f; k22 = m_sum;
|
||||
|
||||
// add the influence from r1
|
||||
cpFloat a_i_inv = a->i_inv;
|
||||
cpFloat r1xsq = r1.x * r1.x * a_i_inv;
|
||||
cpFloat r1ysq = r1.y * r1.y * a_i_inv;
|
||||
cpFloat r1nxy = -r1.x * r1.y * a_i_inv;
|
||||
k11 += r1ysq; k12 += r1nxy;
|
||||
k21 += r1nxy; k22 += r1xsq;
|
||||
|
||||
// add the influnce from r2
|
||||
cpFloat b_i_inv = b->i_inv;
|
||||
cpFloat r2xsq = r2.x * r2.x * b_i_inv;
|
||||
cpFloat r2ysq = r2.y * r2.y * b_i_inv;
|
||||
cpFloat r2nxy = -r2.x * r2.y * b_i_inv;
|
||||
k11 += r2ysq; k12 += r2nxy;
|
||||
k21 += r2nxy; k22 += r2xsq;
|
||||
|
||||
// invert
|
||||
cpFloat determinant = k11*k22 - k12*k21;
|
||||
cpAssert(determinant != 0.0, "Unsolvable constraint.");
|
||||
|
||||
cpFloat det_inv = 1.0f/determinant;
|
||||
*k1 = cpv( k22*det_inv, -k12*det_inv);
|
||||
*k2 = cpv(-k21*det_inv, k11*det_inv);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
mult_k(cpVect vr, cpVect k1, cpVect k2)
|
||||
{
|
||||
return cpv(cpvdot(vr, k1), cpvdot(vr, k2));
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
struct cpArbiter;
|
||||
struct cpSpace;
|
||||
struct cpCollisionHandler;
|
||||
|
||||
// Determines how fast penetrations resolve themselves.
|
||||
extern cpFloat cp_bias_coef;
|
||||
// Amount of allowed penetration. Used to reduce vibrating contacts.
|
||||
extern cpFloat cp_collision_slop;
|
||||
|
||||
// Data structure for contact points.
|
||||
typedef struct cpContact {
|
||||
// Contact point and normal.
|
||||
cpVect p, n;
|
||||
// Penetration distance.
|
||||
cpFloat dist;
|
||||
|
||||
// Calculated by cpArbiterPreStep().
|
||||
cpVect r1, r2;
|
||||
cpFloat nMass, tMass, bounce;
|
||||
|
||||
// Persistant contact information.
|
||||
cpFloat jnAcc, jtAcc, jBias;
|
||||
cpFloat bias;
|
||||
|
||||
// Hash value used to (mostly) uniquely identify a contact.
|
||||
cpHashValue hash;
|
||||
} cpContact;
|
||||
|
||||
// Contacts are always allocated in groups.
|
||||
cpContact* cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash);
|
||||
|
||||
// Sum the contact impulses. (Can be used after cpSpaceStep() returns)
|
||||
cpVect cpContactsSumImpulses(cpContact *contacts, int numContacts);
|
||||
cpVect cpContactsSumImpulsesWithFriction(cpContact *contacts, int numContacts);
|
||||
|
||||
typedef enum cpArbiterState {
|
||||
cpArbiterStateNormal,
|
||||
cpArbiterStateFirstColl,
|
||||
cpArbiterStateIgnore,
|
||||
} cpArbiterState;
|
||||
|
||||
// Data structure for tracking collisions between shapes.
|
||||
typedef struct cpArbiter {
|
||||
// Information on the contact points between the objects.
|
||||
int numContacts;
|
||||
cpContact *contacts;
|
||||
|
||||
// The two shapes involved in the collision.
|
||||
// These variables are NOT in the order defined by the collision handler.
|
||||
cpShape *private_a, *private_b;
|
||||
|
||||
// Calculated before calling the pre-solve collision handler
|
||||
// Override them with custom values if you want specialized behavior
|
||||
cpFloat e;
|
||||
cpFloat u;
|
||||
// Used for surface_v calculations, implementation may change
|
||||
cpVect surface_vr;
|
||||
|
||||
// Time stamp of the arbiter. (from cpSpace)
|
||||
int stamp;
|
||||
|
||||
struct cpCollisionHandler *handler;
|
||||
|
||||
// Are the shapes swapped in relation to the collision handler?
|
||||
char swappedColl;
|
||||
char state;
|
||||
} cpArbiter;
|
||||
|
||||
// Arbiters are allocated in large buffers by the space and don't require a destroy function
|
||||
cpArbiter* cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b);
|
||||
|
||||
// These functions are all intended to be used internally.
|
||||
// Inject new contact points into the arbiter while preserving contact history.
|
||||
void cpArbiterUpdate(cpArbiter *arb, cpContact *contacts, int numContacts, struct cpCollisionHandler *handler, cpShape *a, cpShape *b);
|
||||
// Precalculate values used by the solver.
|
||||
void cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv);
|
||||
void cpArbiterApplyCachedImpulse(cpArbiter *arb);
|
||||
// Run an iteration of the solver on the arbiter.
|
||||
void cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef);
|
||||
|
||||
// Arbiter Helper Functions
|
||||
cpVect cpArbiterTotalImpulse(cpArbiter *arb);
|
||||
cpVect cpArbiterTotalImpulseWithFriction(cpArbiter *arb);
|
||||
void cpArbiterIgnore(cpArbiter *arb);
|
||||
|
||||
|
||||
static inline void
|
||||
cpArbiterGetShapes(cpArbiter *arb, cpShape **a, cpShape **b)
|
||||
{
|
||||
if(arb->swappedColl){
|
||||
(*a) = arb->private_b, (*b) = arb->private_a;
|
||||
} else {
|
||||
(*a) = arb->private_a, (*b) = arb->private_b;
|
||||
}
|
||||
}
|
||||
#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
|
||||
|
||||
static inline int
|
||||
cpArbiterIsFirstContact(cpArbiter *arb)
|
||||
{
|
||||
return arb->state == cpArbiterStateFirstColl;
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpArbiterGetNormal(cpArbiter *arb, int i)
|
||||
{
|
||||
cpVect n = arb->contacts[i].n;
|
||||
return arb->swappedColl ? cpvneg(n) : n;
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpArbiterGetPoint(cpArbiter *arb, int i)
|
||||
{
|
||||
return arb->contacts[i].p;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// NOTE: cpArray is rarely used and will probably go away.
|
||||
|
||||
typedef struct cpArray{
|
||||
int num, max;
|
||||
void **arr;
|
||||
} cpArray;
|
||||
|
||||
typedef void (*cpArrayIter)(void *ptr, void *data);
|
||||
|
||||
cpArray *cpArrayAlloc(void);
|
||||
cpArray *cpArrayInit(cpArray *arr, int size);
|
||||
cpArray *cpArrayNew(int size);
|
||||
|
||||
void cpArrayDestroy(cpArray *arr);
|
||||
void cpArrayFree(cpArray *arr);
|
||||
|
||||
void cpArrayClear(cpArray *arr);
|
||||
|
||||
void cpArrayPush(cpArray *arr, void *object);
|
||||
void *cpArrayPop(cpArray *arr);
|
||||
void cpArrayDeleteIndex(cpArray *arr, int idx);
|
||||
void cpArrayDeleteObj(cpArray *arr, void *obj);
|
||||
|
||||
void cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data);
|
||||
int cpArrayContains(cpArray *arr, void *ptr);
|
|
@ -0,0 +1,74 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
typedef struct cpBB{
|
||||
cpFloat l, b, r ,t;
|
||||
} cpBB;
|
||||
|
||||
static inline cpBB
|
||||
cpBBNew(const cpFloat l, const cpFloat b,
|
||||
const cpFloat r, const cpFloat t)
|
||||
{
|
||||
cpBB bb = {l, b, r, t};
|
||||
return bb;
|
||||
}
|
||||
|
||||
static inline int
|
||||
cpBBintersects(const cpBB a, const cpBB b)
|
||||
{
|
||||
return (a.l<=b.r && b.l<=a.r && a.b<=b.t && b.b<=a.t);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cpBBcontainsBB(const cpBB bb, const cpBB other)
|
||||
{
|
||||
return (bb.l < other.l && bb.r > other.r && bb.b < other.b && bb.t > other.t);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cpBBcontainsVect(const cpBB bb, const cpVect v)
|
||||
{
|
||||
return (bb.l < v.x && bb.r > v.x && bb.b < v.y && bb.t > v.y);
|
||||
}
|
||||
|
||||
static inline cpBB
|
||||
cpBBmerge(const cpBB a, const cpBB b){
|
||||
return cpBBNew(
|
||||
cpfmin(a.l, b.l),
|
||||
cpfmin(a.b, b.b),
|
||||
cpfmax(a.r, b.r),
|
||||
cpfmax(a.t, b.t)
|
||||
);
|
||||
}
|
||||
|
||||
static inline cpBB
|
||||
cpBBexpand(const cpBB bb, const cpVect v){
|
||||
return cpBBNew(
|
||||
cpfmin(bb.l, v.x),
|
||||
cpfmin(bb.b, v.y),
|
||||
cpfmax(bb.r, v.x),
|
||||
cpfmax(bb.t, v.y)
|
||||
);
|
||||
}
|
||||
|
||||
cpVect cpBBClampVect(const cpBB bb, const cpVect v); // clamps the vector to lie within the bbox
|
||||
// TODO edge case issue
|
||||
cpVect cpBBWrapVect(const cpBB bb, const cpVect v); // wrap a vector to a bbox
|
|
@ -0,0 +1,160 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
struct cpBody;
|
||||
typedef void (*cpBodyVelocityFunc)(struct cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
|
||||
typedef void (*cpBodyPositionFunc)(struct cpBody *body, cpFloat dt);
|
||||
|
||||
extern cpBodyVelocityFunc cpBodyUpdateVelocityDefault;
|
||||
extern cpBodyPositionFunc cpBodyUpdatePositionDefault;
|
||||
|
||||
typedef struct cpBody{
|
||||
// *** Integration Functions.ntoehu
|
||||
|
||||
// Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)
|
||||
cpBodyVelocityFunc velocity_func;
|
||||
|
||||
// Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)
|
||||
cpBodyPositionFunc position_func;
|
||||
|
||||
// *** Mass Properties
|
||||
|
||||
// Mass and it's inverse.
|
||||
// Always use cpBodySetMass() whenever changing the mass as these values must agree.
|
||||
cpFloat m, m_inv;
|
||||
|
||||
// Moment of inertia and it's inverse.
|
||||
// Always use cpBodySetMoment() whenever changing the moment as these values must agree.
|
||||
cpFloat i, i_inv;
|
||||
|
||||
// *** Positional Properties
|
||||
|
||||
// Linear components of motion (position, velocity, and force)
|
||||
cpVect p, v, f;
|
||||
|
||||
// Angular components of motion (angle, angular velocity, and torque)
|
||||
// Always use cpBodySetAngle() to set the angle of the body as a and rot must agree.
|
||||
cpFloat a, w, t;
|
||||
|
||||
// Cached unit length vector representing the angle of the body.
|
||||
// Used for fast vector rotation using cpvrotate().
|
||||
cpVect rot;
|
||||
|
||||
// *** User Definable Fields
|
||||
|
||||
// User defined data pointer.
|
||||
cpDataPointer data;
|
||||
|
||||
// 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.
|
||||
cpVect v_bias;
|
||||
cpFloat w_bias;
|
||||
|
||||
// int active;
|
||||
} cpBody;
|
||||
|
||||
// Basic allocation/destruction functions
|
||||
cpBody *cpBodyAlloc(void);
|
||||
cpBody *cpBodyInit(cpBody *body, cpFloat m, cpFloat i);
|
||||
cpBody *cpBodyNew(cpFloat m, cpFloat i);
|
||||
|
||||
void cpBodyDestroy(cpBody *body);
|
||||
void cpBodyFree(cpBody *body);
|
||||
|
||||
#define CP_DefineBodyGetter(type, member, name) static inline type cpBodyGet##name(cpBody *body){return body->member;}
|
||||
#define CP_DefineBodySetter(type, member, name) static inline void cpBodySet##name(cpBody *body, type value){body->member = value;}
|
||||
|
||||
#define CP_DefineBodyProperty(type, member, name) \
|
||||
CP_DefineBodyGetter(type, member, name) \
|
||||
CP_DefineBodySetter(type, member, name)
|
||||
|
||||
|
||||
// Accessors for cpBody struct members
|
||||
CP_DefineBodyGetter(cpFloat, m, Mass);
|
||||
void cpBodySetMass(cpBody *body, cpFloat m);
|
||||
|
||||
CP_DefineBodyGetter(cpFloat, i, Moment);
|
||||
void cpBodySetMoment(cpBody *body, cpFloat i);
|
||||
|
||||
|
||||
CP_DefineBodyProperty(cpVect, p, Pos);
|
||||
CP_DefineBodyProperty(cpVect, v, Vel);
|
||||
CP_DefineBodyProperty(cpVect, f, Force);
|
||||
CP_DefineBodyGetter(cpFloat, a, Angle);
|
||||
void cpBodySetAngle(cpBody *body, cpFloat a);
|
||||
CP_DefineBodyProperty(cpFloat, w, AngVel);
|
||||
CP_DefineBodyProperty(cpFloat, t, Torque);
|
||||
CP_DefineBodyGetter(cpVect, rot, Rot);
|
||||
CP_DefineBodyProperty(cpFloat, v_limit, VelLimit);
|
||||
CP_DefineBodyProperty(cpFloat, w_limit, AngVelLimit);
|
||||
|
||||
// Modify the velocity of the body so that it will move to the specified absolute coordinates in the next timestep.
|
||||
// Intended for objects that are moved manually with a custom velocity integration function.
|
||||
void cpBodySlew(cpBody *body, cpVect pos, cpFloat dt);
|
||||
|
||||
// Default Integration functions.
|
||||
void cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt);
|
||||
void cpBodyUpdatePosition(cpBody *body, cpFloat dt);
|
||||
|
||||
// Convert body local to world coordinates
|
||||
static inline cpVect
|
||||
cpBodyLocal2World(cpBody *body, cpVect v)
|
||||
{
|
||||
return cpvadd(body->p, cpvrotate(v, body->rot));
|
||||
}
|
||||
|
||||
// Convert world to body local coordinates
|
||||
static inline cpVect
|
||||
cpBodyWorld2Local(cpBody *body, 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)
|
||||
{
|
||||
body->v = cpvadd(body->v, cpvmult(j, body->m_inv));
|
||||
body->w += body->i_inv*cpvcross(r, j);
|
||||
}
|
||||
|
||||
// Not intended for external use. Used by cpArbiter.c and cpConstraint.c.
|
||||
static inline void
|
||||
cpBodyApplyBiasImpulse(cpBody *body, cpVect j, cpVect r)
|
||||
{
|
||||
body->v_bias = cpvadd(body->v_bias, cpvmult(j, body->m_inv));
|
||||
body->w_bias += body->i_inv*cpvcross(r, j);
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Apply a damped spring force between two bodies.
|
||||
// Warning: Large damping values can be unstable. Use a cpDampedSpring constraint for this instead.
|
||||
void cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt);
|
||||
|
||||
//int cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max);
|
|
@ -0,0 +1,23 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// Collides two cpShape structures. (this function is lonely :( )
|
||||
int cpCollideShapes(cpShape *a, cpShape *b, cpContact *arr);
|
|
@ -0,0 +1,82 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// cpHashSet uses a chained hashtable implementation.
|
||||
// Other than the transformation functions, there is nothing fancy going on.
|
||||
|
||||
// cpHashSetBin's form the linked lists in the chained hash table.
|
||||
typedef struct cpHashSetBin {
|
||||
// Pointer to the element.
|
||||
void *elt;
|
||||
// Hash value of the element.
|
||||
cpHashValue hash;
|
||||
// Next element in the chain.
|
||||
struct cpHashSetBin *next;
|
||||
} cpHashSetBin;
|
||||
|
||||
// Equality function. Returns true if ptr is equal to elt.
|
||||
typedef int (*cpHashSetEqlFunc)(void *ptr, void *elt);
|
||||
// Used by cpHashSetInsert(). Called to transform the ptr into an element.
|
||||
typedef void *(*cpHashSetTransFunc)(void *ptr, void *data);
|
||||
// Iterator function for a hashset.
|
||||
typedef void (*cpHashSetIterFunc)(void *elt, void *data);
|
||||
// Filter function. Returns false if elt should be dropped.
|
||||
typedef int (*cpHashSetFilterFunc)(void *elt, void *data);
|
||||
|
||||
typedef struct cpHashSet {
|
||||
// Number of elements stored in the table.
|
||||
int entries;
|
||||
// Number of cells in the table.
|
||||
int size;
|
||||
|
||||
cpHashSetEqlFunc eql;
|
||||
cpHashSetTransFunc trans;
|
||||
|
||||
// Default value returned by cpHashSetFind() when no element is found.
|
||||
// Defaults to NULL.
|
||||
void *default_value;
|
||||
|
||||
// The table and recycled bins
|
||||
cpHashSetBin **table, *pooledBins;
|
||||
|
||||
cpArray *allocatedBuffers;
|
||||
} cpHashSet;
|
||||
|
||||
// Basic allocation/destruction functions.
|
||||
void cpHashSetDestroy(cpHashSet *set);
|
||||
void cpHashSetFree(cpHashSet *set);
|
||||
|
||||
cpHashSet *cpHashSetAlloc(void);
|
||||
cpHashSet *cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);
|
||||
cpHashSet *cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans);
|
||||
|
||||
// Insert an element into the set, returns the element.
|
||||
// If it doesn't already exist, the transformation function is applied.
|
||||
void *cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data);
|
||||
// Remove and return an element from the set.
|
||||
void *cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr);
|
||||
// Find an element in the set. Returns the default value if the element isn't found.
|
||||
void *cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr);
|
||||
|
||||
// Iterate over a hashset.
|
||||
void cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data);
|
||||
// Iterate over a hashset, retain .
|
||||
void cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data);
|
|
@ -0,0 +1,103 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// Axis structure used by cpPolyShape.
|
||||
typedef struct cpPolyShapeAxis{
|
||||
// normal
|
||||
cpVect n;
|
||||
// distance from origin
|
||||
cpFloat d;
|
||||
} cpPolyShapeAxis;
|
||||
|
||||
// Convex polygon shape structure.
|
||||
typedef struct cpPolyShape{
|
||||
cpShape shape;
|
||||
|
||||
// Vertex and axis lists.
|
||||
int numVerts;
|
||||
cpVect *verts;
|
||||
cpPolyShapeAxis *axes;
|
||||
|
||||
// Transformed vertex and axis lists.
|
||||
cpVect *tVerts;
|
||||
cpPolyShapeAxis *tAxes;
|
||||
} cpPolyShape;
|
||||
|
||||
// Basic allocation functions.
|
||||
cpPolyShape *cpPolyShapeAlloc(void);
|
||||
cpPolyShape *cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset);
|
||||
cpShape *cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
|
||||
|
||||
cpPolyShape *cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
|
||||
cpShape *cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
|
||||
|
||||
// Check that a set of vertexes has a correct winding and that they are convex
|
||||
int cpPolyValidate(cpVect *verts, int numVerts);
|
||||
|
||||
int cpPolyShapeGetNumVerts(cpShape *shape);
|
||||
cpVect cpPolyShapeGetVert(cpShape *shape, int idx);
|
||||
|
||||
// *** inlined utility functions
|
||||
|
||||
// Returns the minimum distance of the polygon to the axis.
|
||||
static inline cpFloat
|
||||
cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
|
||||
{
|
||||
cpVect *verts = poly->tVerts;
|
||||
cpFloat min = cpvdot(n, verts[0]);
|
||||
|
||||
int i;
|
||||
for(i=1; i<poly->numVerts; i++)
|
||||
min = cpfmin(min, cpvdot(n, verts[i]));
|
||||
|
||||
return min - d;
|
||||
}
|
||||
|
||||
// Returns true if the polygon contains the vertex.
|
||||
static inline int
|
||||
cpPolyShapeContainsVert(cpPolyShape *poly, cpVect v)
|
||||
{
|
||||
cpPolyShapeAxis *axes = poly->tAxes;
|
||||
|
||||
int i;
|
||||
for(i=0; i<poly->numVerts; i++){
|
||||
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
|
||||
if(dist > 0.0f) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.
|
||||
static inline int
|
||||
cpPolyShapeContainsVertPartial(cpPolyShape *poly, cpVect v, cpVect n)
|
||||
{
|
||||
cpPolyShapeAxis *axes = poly->tAxes;
|
||||
|
||||
int i;
|
||||
for(i=0; i<poly->numVerts; i++){
|
||||
if(cpvdot(axes[i].n, n) < 0.0f) continue;
|
||||
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
|
||||
if(dist > 0.0f) return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// Forward declarations required for defining other structs.
|
||||
struct cpShape;
|
||||
struct cpShapeClass;
|
||||
|
||||
typedef struct cpSegmentQueryInfo {
|
||||
struct cpShape *shape; // shape that was hit, NULL if no collision
|
||||
cpFloat t; // Distance along query segment, will always be in the range [0, 1].
|
||||
cpVect n; // normal of hit surface
|
||||
} cpSegmentQueryInfo;
|
||||
|
||||
// Enumeration of shape types.
|
||||
typedef enum cpShapeType{
|
||||
CP_CIRCLE_SHAPE,
|
||||
CP_SEGMENT_SHAPE,
|
||||
CP_POLY_SHAPE,
|
||||
CP_NUM_SHAPES
|
||||
} cpShapeType;
|
||||
|
||||
// Shape class. Holds function pointers and type data.
|
||||
typedef struct cpShapeClass {
|
||||
cpShapeType type;
|
||||
|
||||
// Called by cpShapeCacheBB().
|
||||
cpBB (*cacheData)(struct cpShape *shape, cpVect p, cpVect rot);
|
||||
// Called to by cpShapeDestroy().
|
||||
void (*destroy)(struct cpShape *shape);
|
||||
|
||||
// called by cpShapePointQuery().
|
||||
int (*pointQuery)(struct cpShape *shape, cpVect p);
|
||||
|
||||
// called by cpShapeSegmentQuery()
|
||||
void (*segmentQuery)(struct cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
|
||||
} cpShapeClass;
|
||||
|
||||
// Basic shape struct that the others inherit from.
|
||||
typedef struct cpShape{
|
||||
// The "class" of a shape as defined above
|
||||
const cpShapeClass *klass;
|
||||
|
||||
// cpBody that the shape is attached to.
|
||||
cpBody *body;
|
||||
|
||||
// Cached BBox for the shape.
|
||||
cpBB bb;
|
||||
|
||||
// Sensors invoke callbacks, but do not generate collisions
|
||||
int sensor;
|
||||
|
||||
// *** Surface properties.
|
||||
|
||||
// Coefficient of restitution. (elasticity)
|
||||
cpFloat e;
|
||||
// Coefficient of friction.
|
||||
cpFloat u;
|
||||
// Surface velocity used when solving for friction.
|
||||
cpVect surface_v;
|
||||
|
||||
// *** User Definable Fields
|
||||
|
||||
// User defined data pointer for the shape.
|
||||
cpDataPointer data;
|
||||
|
||||
// User defined collision type for the shape.
|
||||
cpCollisionType collision_type;
|
||||
// User defined collision group for the shape.
|
||||
cpGroup group;
|
||||
// User defined layer bitmask for the shape.
|
||||
cpLayers layers;
|
||||
|
||||
// *** Internally Used Fields
|
||||
|
||||
// Unique id used as the hash value.
|
||||
cpHashValue hashid;
|
||||
} cpShape;
|
||||
|
||||
// Low level shape initialization func.
|
||||
cpShape* cpShapeInit(cpShape *shape, const struct cpShapeClass *klass, cpBody *body);
|
||||
|
||||
// Basic destructor functions. (allocation functions are not shared)
|
||||
void cpShapeDestroy(cpShape *shape);
|
||||
void cpShapeFree(cpShape *shape);
|
||||
|
||||
// Cache the BBox of the shape.
|
||||
cpBB cpShapeCacheBB(cpShape *shape);
|
||||
|
||||
// Test if a point lies within a shape.
|
||||
int cpShapePointQuery(cpShape *shape, cpVect p);
|
||||
|
||||
#define CP_DeclareShapeGetter(struct, type, name) type struct##Get##name(cpShape *shape)
|
||||
|
||||
// Circle shape structure.
|
||||
typedef struct cpCircleShape{
|
||||
cpShape shape;
|
||||
|
||||
// Center in body space coordinates
|
||||
cpVect c;
|
||||
// Radius.
|
||||
cpFloat r;
|
||||
|
||||
// Transformed center. (world space coordinates)
|
||||
cpVect tc;
|
||||
} cpCircleShape;
|
||||
|
||||
// Basic allocation functions for cpCircleShape.
|
||||
cpCircleShape *cpCircleShapeAlloc(void);
|
||||
cpCircleShape *cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset);
|
||||
cpShape *cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset);
|
||||
|
||||
CP_DeclareShapeGetter(cpCircleShape, cpVect, Offset);
|
||||
CP_DeclareShapeGetter(cpCircleShape, cpFloat, Radius);
|
||||
|
||||
// Segment shape structure.
|
||||
typedef struct cpSegmentShape{
|
||||
cpShape shape;
|
||||
|
||||
// Endpoints and normal of the segment. (body space coordinates)
|
||||
cpVect a, b, n;
|
||||
// Radius of the segment. (Thickness)
|
||||
cpFloat r;
|
||||
|
||||
// Transformed endpoints and normal. (world space coordinates)
|
||||
cpVect ta, tb, tn;
|
||||
} cpSegmentShape;
|
||||
|
||||
// Basic allocation functions for cpSegmentShape.
|
||||
cpSegmentShape* cpSegmentShapeAlloc(void);
|
||||
cpSegmentShape* cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat radius);
|
||||
cpShape* cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat radius);
|
||||
|
||||
CP_DeclareShapeGetter(cpSegmentShape, cpVect, A);
|
||||
CP_DeclareShapeGetter(cpSegmentShape, cpVect, B);
|
||||
CP_DeclareShapeGetter(cpSegmentShape, cpVect, Normal);
|
||||
CP_DeclareShapeGetter(cpSegmentShape, cpFloat, Radius);
|
||||
|
||||
// For determinism, you can reset the shape id counter.
|
||||
void cpResetShapeIdCounter(void);
|
||||
|
||||
// Directed segment queries against individual shapes.
|
||||
void cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info);
|
||||
|
||||
int cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info);
|
||||
|
||||
static inline cpVect
|
||||
cpSegmentQueryHitPoint(cpVect start, cpVect end, cpSegmentQueryInfo info)
|
||||
{
|
||||
return cpvlerp(start, end, info.t);
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpSegmentQueryHitDist(cpVect start, cpVect end, cpSegmentQueryInfo info)
|
||||
{
|
||||
return cpvdist(start, end)*info.t;
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
struct cpSpace;
|
||||
|
||||
// Number of frames that contact information should persist.
|
||||
extern int cp_contact_persistence;
|
||||
|
||||
// User collision handler function types.
|
||||
typedef int (*cpCollisionBeginFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
|
||||
typedef int (*cpCollisionPreSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
|
||||
typedef void (*cpCollisionPostSolveFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
|
||||
typedef void (*cpCollisionSeparateFunc)(cpArbiter *arb, struct cpSpace *space, void *data);
|
||||
|
||||
// Structure for holding collision pair function information.
|
||||
// Used internally.
|
||||
typedef struct cpCollisionHandler {
|
||||
cpCollisionType a;
|
||||
cpCollisionType b;
|
||||
cpCollisionBeginFunc begin;
|
||||
cpCollisionPreSolveFunc preSolve;
|
||||
cpCollisionPostSolveFunc postSolve;
|
||||
cpCollisionSeparateFunc separate;
|
||||
void *data;
|
||||
} cpCollisionHandler;
|
||||
|
||||
#define CP_MAX_CONTACTS_PER_ARBITER 6
|
||||
typedef struct cpContactBufferHeader {
|
||||
int stamp;
|
||||
struct cpContactBufferHeader *next;
|
||||
unsigned int numContacts;
|
||||
} cpContactBufferHeader;
|
||||
|
||||
typedef struct cpSpace{
|
||||
// *** User definable fields
|
||||
|
||||
// Number of iterations to use in the impulse solver to solve contacts.
|
||||
int iterations;
|
||||
|
||||
// Number of iterations to use in the impulse solver to solve elastic collisions.
|
||||
int elasticIterations;
|
||||
|
||||
// Default gravity to supply when integrating rigid body motions.
|
||||
cpVect gravity;
|
||||
|
||||
// Default damping to supply when integrating rigid body motions.
|
||||
cpFloat damping;
|
||||
|
||||
// *** Internally Used Fields
|
||||
|
||||
// When the space is locked, you should not add or remove objects;
|
||||
int locked;
|
||||
|
||||
// Time stamp. Is incremented on every call to cpSpaceStep().
|
||||
int stamp;
|
||||
|
||||
// The static and active shape spatial hashes.
|
||||
cpSpaceHash *staticShapes;
|
||||
cpSpaceHash *activeShapes;
|
||||
|
||||
// List of bodies in the system.
|
||||
cpArray *bodies;
|
||||
|
||||
// List of active arbiters for the impulse solver.
|
||||
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;
|
||||
|
||||
// List of buffers to be free()ed when destroying the space.
|
||||
cpArray *allocatedBuffers;
|
||||
|
||||
// Persistant contact set.
|
||||
cpHashSet *contactSet;
|
||||
|
||||
// List of constraints in the system.
|
||||
cpArray *constraints;
|
||||
|
||||
// Set of collisionpair functions.
|
||||
cpHashSet *collFuncSet;
|
||||
// Default collision handler.
|
||||
cpCollisionHandler defaultHandler;
|
||||
|
||||
cpHashSet *postStepCallbacks;
|
||||
} cpSpace;
|
||||
|
||||
// Basic allocation/destruction functions.
|
||||
cpSpace* cpSpaceAlloc(void);
|
||||
cpSpace* cpSpaceInit(cpSpace *space);
|
||||
cpSpace* cpSpaceNew(void);
|
||||
|
||||
void cpSpaceDestroy(cpSpace *space);
|
||||
void cpSpaceFree(cpSpace *space);
|
||||
|
||||
// Convenience function. Frees all referenced entities. (bodies, shapes and constraints)
|
||||
void cpSpaceFreeChildren(cpSpace *space);
|
||||
|
||||
// Collision handler management functions.
|
||||
void cpSpaceSetDefaultCollisionHandler(
|
||||
cpSpace *space,
|
||||
cpCollisionBeginFunc begin,
|
||||
cpCollisionPreSolveFunc preSolve,
|
||||
cpCollisionPostSolveFunc postSolve,
|
||||
cpCollisionSeparateFunc separate,
|
||||
void *data
|
||||
);
|
||||
void cpSpaceAddCollisionHandler(
|
||||
cpSpace *space,
|
||||
cpCollisionType a, cpCollisionType b,
|
||||
cpCollisionBeginFunc begin,
|
||||
cpCollisionPreSolveFunc preSolve,
|
||||
cpCollisionPostSolveFunc postSolve,
|
||||
cpCollisionSeparateFunc separate,
|
||||
void *data
|
||||
);
|
||||
void cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b);
|
||||
|
||||
// Add and remove entities from the system.
|
||||
cpShape *cpSpaceAddShape(cpSpace *space, cpShape *shape);
|
||||
cpShape *cpSpaceAddStaticShape(cpSpace *space, cpShape *shape);
|
||||
cpBody *cpSpaceAddBody(cpSpace *space, cpBody *body);
|
||||
cpConstraint *cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint);
|
||||
|
||||
void cpSpaceRemoveShape(cpSpace *space, cpShape *shape);
|
||||
void cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape);
|
||||
void cpSpaceRemoveBody(cpSpace *space, cpBody *body);
|
||||
void cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint);
|
||||
|
||||
// Post Step function definition
|
||||
typedef void (*cpPostStepFunc)(cpSpace *space, void *obj, void *data);
|
||||
// Register a post step function to be called after cpSpaceStep() has finished.
|
||||
// obj is used a key, you can only register one callback per unique value for obj
|
||||
void cpSpaceAddPostStepCallback(cpSpace *space, cpPostStepFunc func, void *obj, void *data);
|
||||
|
||||
// Point query callback function
|
||||
typedef void (*cpSpacePointQueryFunc)(cpShape *shape, void *data);
|
||||
void cpSpacePointQuery(cpSpace *space, cpVect point, cpLayers layers, cpGroup group, cpSpacePointQueryFunc func, void *data);
|
||||
cpShape *cpSpacePointQueryFirst(cpSpace *space, cpVect point, cpLayers layers, cpGroup group);
|
||||
|
||||
// Segment query callback function
|
||||
typedef void (*cpSpaceSegmentQueryFunc)(cpShape *shape, cpFloat t, cpVect n, void *data);
|
||||
int 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
|
||||
typedef void (*cpSpaceBBQueryFunc)(cpShape *shape, void *data);
|
||||
void cpSpaceBBQuery(cpSpace *space, cpBB bb, cpLayers layers, cpGroup group, cpSpaceBBQueryFunc func, void *data);
|
||||
|
||||
|
||||
// Iterator function for iterating the bodies in a space.
|
||||
typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
|
||||
void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
|
||||
|
||||
// Spatial hash management functions.
|
||||
void cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count);
|
||||
void cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count);
|
||||
void cpSpaceRehashStatic(cpSpace *space);
|
||||
|
||||
// Update the space.
|
||||
void cpSpaceStep(cpSpace *space, cpFloat dt);
|
|
@ -0,0 +1,109 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// The spatial hash is Chipmunk's default (and currently only) spatial index type.
|
||||
// Based on a chained hash table.
|
||||
|
||||
// Used internally to track objects added to the hash
|
||||
typedef struct cpHandle{
|
||||
// Pointer to the object
|
||||
void *obj;
|
||||
// Retain count
|
||||
int retain;
|
||||
// Query stamp. Used to make sure two objects
|
||||
// aren't identified twice in the same query.
|
||||
int stamp;
|
||||
} cpHandle;
|
||||
|
||||
// Linked list element for in the chains.
|
||||
typedef struct cpSpaceHashBin{
|
||||
cpHandle *handle;
|
||||
struct cpSpaceHashBin *next;
|
||||
} cpSpaceHashBin;
|
||||
|
||||
// BBox callback. Called whenever the hash needs a bounding box from an object.
|
||||
typedef cpBB (*cpSpaceHashBBFunc)(void *obj);
|
||||
|
||||
typedef struct cpSpaceHash{
|
||||
// Number of cells in the table.
|
||||
int numcells;
|
||||
// Dimentions of the cells.
|
||||
cpFloat celldim;
|
||||
|
||||
// BBox callback.
|
||||
cpSpaceHashBBFunc bbfunc;
|
||||
|
||||
// Hashset of the handles and the recycled ones.
|
||||
cpHashSet *handleSet;
|
||||
cpArray *pooledHandles;
|
||||
|
||||
// The table and the recycled bins.
|
||||
cpSpaceHashBin **table, *pooledBins;
|
||||
|
||||
// list of buffers to free on destruction.
|
||||
cpArray *allocatedBuffers;
|
||||
|
||||
// Incremented on each query. See cpHandle.stamp.
|
||||
int stamp;
|
||||
} cpSpaceHash;
|
||||
|
||||
//Basic allocation/destruction functions.
|
||||
cpSpaceHash *cpSpaceHashAlloc(void);
|
||||
cpSpaceHash *cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);
|
||||
cpSpaceHash *cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc);
|
||||
|
||||
void cpSpaceHashDestroy(cpSpaceHash *hash);
|
||||
void cpSpaceHashFree(cpSpaceHash *hash);
|
||||
|
||||
// Resize the hashtable. (Does not rehash! You must call cpSpaceHashRehash() if needed.)
|
||||
void cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells);
|
||||
|
||||
// Add an object to the hash.
|
||||
void cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue id, cpBB bb);
|
||||
// Remove an object from the hash.
|
||||
void cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue id);
|
||||
|
||||
// Iterator function
|
||||
typedef void (*cpSpaceHashIterator)(void *obj, void *data);
|
||||
// Iterate over the objects in the hash.
|
||||
void cpSpaceHashEach(cpSpaceHash *hash, cpSpaceHashIterator func, void *data);
|
||||
|
||||
// Rehash the contents of the hash.
|
||||
void cpSpaceHashRehash(cpSpaceHash *hash);
|
||||
// Rehash only a specific object.
|
||||
void cpSpaceHashRehashObject(cpSpaceHash *hash, void *obj, cpHashValue id);
|
||||
|
||||
// Query callback.
|
||||
typedef void (*cpSpaceHashQueryFunc)(void *obj1, void *obj2, void *data);
|
||||
// Point query the hash. A reference to the query point is passed as obj1 to the query callback.
|
||||
void cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data);
|
||||
// Query the hash for a given BBox.
|
||||
void cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);
|
||||
// Run a query for the object, then insert it. (Optimized case)
|
||||
void cpSpaceHashQueryInsert(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data);
|
||||
// Rehashes while querying for each object. (Optimized case)
|
||||
void cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data);
|
||||
|
||||
// Segment Query callback.
|
||||
// Return value is uesd for early exits of the query.
|
||||
// If while traversing the grid, the raytrace function detects that an entire grid cell is beyond the hit point, it will stop the trace.
|
||||
typedef cpFloat (*cpSpaceHashSegmentQueryFunc)(void *obj1, void *obj2, void *data);
|
||||
void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpaceHashSegmentQueryFunc func, void *data);
|
|
@ -0,0 +1,157 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
static const cpVect cpvzero={0.0f,0.0f};
|
||||
|
||||
static inline cpVect
|
||||
cpv(const cpFloat x, const cpFloat y)
|
||||
{
|
||||
cpVect v = {x, y};
|
||||
return v;
|
||||
}
|
||||
|
||||
// non-inlined functions
|
||||
cpFloat cpvlength(const cpVect v);
|
||||
cpVect cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t);
|
||||
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
|
||||
|
||||
static inline cpVect
|
||||
cpvadd(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return cpv(v1.x + v2.x, v1.y + v2.y);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvneg(const cpVect v)
|
||||
{
|
||||
return cpv(-v.x, -v.y);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvsub(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return cpv(v1.x - v2.x, v1.y - v2.y);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvmult(const cpVect v, const cpFloat s)
|
||||
{
|
||||
return cpv(v.x*s, v.y*s);
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpvdot(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return v1.x*v2.x + v1.y*v2.y;
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpvcross(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return v1.x*v2.y - v1.y*v2.x;
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvperp(const cpVect v)
|
||||
{
|
||||
return cpv(-v.y, v.x);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvrperp(const cpVect v)
|
||||
{
|
||||
return cpv(v.y, -v.x);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvproject(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return cpvmult(v2, cpvdot(v1, v2)/cpvdot(v2, v2));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpvlengthsq(const cpVect v)
|
||||
{
|
||||
return cpvdot(v, v);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvlerp(const cpVect v1, const cpVect v2, const cpFloat t)
|
||||
{
|
||||
return cpvadd(cpvmult(v1, 1.0f - t), cpvmult(v2, t));
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvnormalize(const cpVect v)
|
||||
{
|
||||
return cpvmult(v, 1.0f/cpvlength(v));
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvnormalize_safe(const cpVect v)
|
||||
{
|
||||
return (v.x == 0.0f && v.y == 0.0f ? cpvzero : cpvnormalize(v));
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvclamp(const cpVect v, const cpFloat len)
|
||||
{
|
||||
return (cpvdot(v,v) > len*len) ? cpvmult(cpvnormalize(v), len) : v;
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
cpvlerpconst(cpVect v1, cpVect v2, cpFloat d)
|
||||
{
|
||||
return cpvadd(v1, cpvclamp(cpvsub(v2, v1), d));
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpvdist(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return cpvlength(cpvsub(v1, v2));
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
cpvdistsq(const cpVect v1, const cpVect v2)
|
||||
{
|
||||
return cpvlengthsq(cpvsub(v1, v2));
|
||||
}
|
||||
|
||||
static inline int
|
||||
cpvnear(const cpVect v1, const cpVect v2, const cpFloat dist)
|
||||
{
|
||||
return cpvdistsq(v1, v2) < dist*dist;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
file(GLOB chipmunk_source_files "*.c" "constraints/*.c")
|
||||
file(GLOB chipmunk_public_header "${chipmunk_SOURCE_DIR}/include/chipmunk/*.h")
|
||||
file(GLOB chipmunk_constraint_header "${chipmunk_SOURCE_DIR}/include/chipmunk/constraints/*.h")
|
||||
|
||||
include_directories(${chipmunk_SOURCE_DIR}/include/chipmunk)
|
||||
|
||||
if(BUILD_SHARED)
|
||||
add_library(chipmunk SHARED
|
||||
${chipmunk_source_files}
|
||||
)
|
||||
# set the lib's version number
|
||||
set_target_properties(chipmunk PROPERTIES VERSION 5.1)
|
||||
install(TARGETS chipmunk RUNTIME DESTINATION lib LIBRARY DESTINATION lib)
|
||||
endif(BUILD_SHARED)
|
||||
|
||||
if(BUILD_STATIC)
|
||||
add_library(chipmunk_static STATIC
|
||||
${chipmunk_source_files}
|
||||
)
|
||||
# Sets chipmunk_static to output "libchipmunk.a" not "libchipmunk_static.a"
|
||||
set_target_properties(chipmunk_static PROPERTIES OUTPUT_NAME chipmunk)
|
||||
if(INSTALL_STATIC)
|
||||
install(TARGETS chipmunk_static ARCHIVE DESTINATION lib)
|
||||
endif(INSTALL_STATIC)
|
||||
endif(BUILD_STATIC)
|
||||
|
||||
if(BUILD_SHARED OR INSTALL_STATIC)
|
||||
# FIXME: change to PUBLIC_HEADER to allow building frameworks
|
||||
install(FILES ${chipmunk_public_header} DESTINATION include/chipmunk)
|
||||
install(FILES ${chipmunk_constraint_header} DESTINATION include/chipmunk/constraints)
|
||||
endif(BUILD_SHARED OR INSTALL_STATIC)
|
|
@ -0,0 +1,105 @@
|
|||
/* 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 <stdio.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void cpInitCollisionFuncs(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
cpMessage(char *message, char *condition, char *file, int line, int isError)
|
||||
{
|
||||
fprintf(stderr, (isError ? "Aborting due to Chipmunk error: %s\n" : "Chipmunk warning: %s\n"), message);
|
||||
fprintf(stderr, "\tFailed condition: %s\n", condition);
|
||||
fprintf(stderr, "\tSource:%s:%d\n", file, line);
|
||||
|
||||
if(isError) abort();
|
||||
}
|
||||
|
||||
|
||||
char *cpVersionString = "5.x.x";
|
||||
|
||||
void
|
||||
cpInitChipmunk(void)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
printf("Initializing Chipmunk v%s (Debug Enabled)\n", cpVersionString);
|
||||
printf("Compile with -DNDEBUG defined to disable debug mode and runtime assertion checks\n");
|
||||
#endif
|
||||
|
||||
cpInitCollisionFuncs();
|
||||
}
|
||||
|
||||
cpFloat
|
||||
cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)
|
||||
{
|
||||
return (1.0f/2.0f)*m*(r1*r1 + r2*r2) + m*cpvdot(offset, offset);
|
||||
}
|
||||
|
||||
cpFloat
|
||||
cpMomentForSegment(cpFloat m, cpVect a, cpVect b)
|
||||
{
|
||||
cpFloat length = cpvlength(cpvsub(b, a));
|
||||
cpVect offset = cpvmult(cpvadd(a, b), 1.0f/2.0f);
|
||||
|
||||
return m*length*length/12.0f + m*cpvdot(offset, offset);
|
||||
}
|
||||
|
||||
cpFloat
|
||||
cpMomentForPoly(cpFloat m, const int numVerts, cpVect *verts, cpVect offset)
|
||||
{
|
||||
cpVect *tVerts = (cpVect *)cpcalloc(numVerts, sizeof(cpVect));
|
||||
for(int i=0; i<numVerts; i++)
|
||||
tVerts[i] = cpvadd(verts[i], offset);
|
||||
|
||||
cpFloat sum1 = 0.0f;
|
||||
cpFloat sum2 = 0.0f;
|
||||
for(int i=0; i<numVerts; i++){
|
||||
cpVect v1 = tVerts[i];
|
||||
cpVect v2 = tVerts[(i+1)%numVerts];
|
||||
|
||||
cpFloat a = cpvcross(v2, v1);
|
||||
cpFloat b = cpvdot(v1, v1) + cpvdot(v1, v2) + cpvdot(v2, v2);
|
||||
|
||||
sum1 += a*b;
|
||||
sum2 += a;
|
||||
}
|
||||
|
||||
cpfree(tVerts);
|
||||
return (m*sum1)/(6.0f*sum2);
|
||||
}
|
||||
|
||||
cpFloat
|
||||
cpMomentForBox(cpFloat m, cpFloat width, cpFloat height)
|
||||
{
|
||||
return m*(width*width + height*height)/12;
|
||||
}
|
||||
|
||||
|
||||
#include "chipmunk_ffi.h"
|
|
@ -0,0 +1,54 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
// TODO: Comment me!
|
||||
|
||||
cpFloat cp_constraint_bias_coef = 0.1f;
|
||||
|
||||
void cpConstraintDestroy(cpConstraint *constraint){}
|
||||
|
||||
void
|
||||
cpConstraintFree(cpConstraint *constraint)
|
||||
{
|
||||
if(constraint){
|
||||
cpConstraintDestroy(constraint);
|
||||
cpfree(constraint);
|
||||
}
|
||||
}
|
||||
|
||||
// *** defined in util.h
|
||||
|
||||
void
|
||||
cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b)
|
||||
{
|
||||
constraint->klass = klass;
|
||||
constraint->a = a;
|
||||
constraint->b = b;
|
||||
|
||||
constraint->maxForce = (cpFloat)INFINITY;
|
||||
constraint->biasCoef = cp_constraint_bias_coef;
|
||||
constraint->maxBias = (cpFloat)INFINITY;
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/* 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 <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static cpFloat
|
||||
defaultSpringTorque(cpDampedRotarySpring *spring, cpFloat relativeAngle){
|
||||
return (relativeAngle - spring->restAngle)*spring->stiffness;
|
||||
}
|
||||
|
||||
static void
|
||||
preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = spring->constraint.a;
|
||||
cpBody *b = spring->constraint.b;
|
||||
|
||||
spring->iSum = 1.0f/(a->i_inv + b->i_inv);
|
||||
|
||||
spring->dt = dt;
|
||||
spring->target_wrn = 0.0f;
|
||||
|
||||
// apply spring torque
|
||||
cpFloat j_spring = spring->springTorqueFunc((cpConstraint *)spring, a->a - b->a)*dt;
|
||||
a->w -= j_spring*a->i_inv;
|
||||
b->w += j_spring*b->i_inv;
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpDampedRotarySpring *spring)
|
||||
{
|
||||
cpBody *a = spring->constraint.a;
|
||||
cpBody *b = spring->constraint.b;
|
||||
|
||||
// compute relative velocity
|
||||
cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;
|
||||
|
||||
// compute velocity loss from drag
|
||||
// not 100% certain this is derived correctly, though it makes sense
|
||||
cpFloat w_damp = wrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->iSum));
|
||||
spring->target_wrn = wrn - w_damp;
|
||||
|
||||
//apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));
|
||||
cpFloat j_damp = w_damp*spring->iSum;
|
||||
a->w -= j_damp*a->i_inv;
|
||||
b->w += j_damp*b->i_inv;
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpConstraint *constraint)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpDampedRotarySpring)
|
||||
|
||||
cpDampedRotarySpring *
|
||||
cpDampedRotarySpringAlloc(void)
|
||||
{
|
||||
return (cpDampedRotarySpring *)cpmalloc(sizeof(cpDampedRotarySpring));
|
||||
}
|
||||
|
||||
cpDampedRotarySpring *
|
||||
cpDampedRotarySpringInit(cpDampedRotarySpring *spring, cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)spring, &klass, a, b);
|
||||
|
||||
spring->restAngle = restAngle;
|
||||
spring->stiffness = stiffness;
|
||||
spring->damping = damping;
|
||||
spring->springTorqueFunc = (cpDampedRotarySpringTorqueFunc)defaultSpringTorque;
|
||||
|
||||
return spring;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpDampedRotarySpringNew(cpBody *a, cpBody *b, cpFloat restAngle, cpFloat stiffness, cpFloat damping)
|
||||
{
|
||||
return (cpConstraint *)cpDampedRotarySpringInit(cpDampedRotarySpringAlloc(), a, b, restAngle, stiffness, damping);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/* 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 <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static cpFloat
|
||||
defaultSpringForce(cpDampedSpring *spring, cpFloat dist){
|
||||
return (spring->restLength - dist)*spring->stiffness;
|
||||
}
|
||||
|
||||
static void
|
||||
preStep(cpDampedSpring *spring, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = spring->constraint.a;
|
||||
cpBody *b = spring->constraint.b;
|
||||
|
||||
spring->r1 = cpvrotate(spring->anchr1, a->rot);
|
||||
spring->r2 = cpvrotate(spring->anchr2, b->rot);
|
||||
|
||||
cpVect delta = cpvsub(cpvadd(b->p, spring->r2), cpvadd(a->p, spring->r1));
|
||||
cpFloat dist = cpvlength(delta);
|
||||
spring->n = cpvmult(delta, 1.0f/(dist ? dist : INFINITY));
|
||||
|
||||
// calculate mass normal
|
||||
spring->nMass = 1.0f/k_scalar(a, b, spring->r1, spring->r2, spring->n);
|
||||
|
||||
spring->dt = dt;
|
||||
spring->target_vrn = 0.0f;
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpDampedSpring *spring)
|
||||
{
|
||||
cpBody *a = spring->constraint.a;
|
||||
cpBody *b = spring->constraint.b;
|
||||
|
||||
cpVect n = spring->n;
|
||||
cpVect r1 = spring->r1;
|
||||
cpVect r2 = spring->r2;
|
||||
|
||||
// compute relative velocity
|
||||
cpFloat vrn = normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;
|
||||
|
||||
// compute velocity loss from drag
|
||||
// not 100% certain this is derived correctly, though it makes sense
|
||||
cpFloat v_damp = -vrn*(1.0f - cpfexp(-spring->damping*spring->dt/spring->nMass));
|
||||
spring->target_vrn = vrn + v_damp;
|
||||
|
||||
apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpConstraint *constraint)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpDampedSpring)
|
||||
|
||||
cpDampedSpring *
|
||||
cpDampedSpringAlloc(void)
|
||||
{
|
||||
return (cpDampedSpring *)cpmalloc(sizeof(cpDampedSpring));
|
||||
}
|
||||
|
||||
cpDampedSpring *
|
||||
cpDampedSpringInit(cpDampedSpring *spring, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)spring, cpDampedSpringGetClass(), a, b);
|
||||
|
||||
spring->anchr1 = anchr1;
|
||||
spring->anchr2 = anchr2;
|
||||
|
||||
spring->restLength = restLength;
|
||||
spring->stiffness = stiffness;
|
||||
spring->damping = damping;
|
||||
spring->springForceFunc = (cpDampedSpringForceFunc)defaultSpringForce;
|
||||
|
||||
return spring;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpDampedSpringNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiffness, cpFloat damping)
|
||||
{
|
||||
return (cpConstraint *)cpDampedSpringInit(cpDampedSpringAlloc(), a, b, anchr1, anchr2, restLength, stiffness, damping);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpGearJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// calculate moment of inertia coefficient.
|
||||
joint->iSum = 1.0f/(a->i_inv*joint->ratio_inv + joint->ratio*b->i_inv);
|
||||
|
||||
// calculate bias velocity
|
||||
cpFloat maxBias = joint->constraint.maxBias;
|
||||
joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(b->a*joint->ratio - a->a - joint->phase), -maxBias, maxBias);
|
||||
|
||||
// compute max impulse
|
||||
joint->jMax = J_MAX(joint, dt);
|
||||
|
||||
// apply joint torque
|
||||
cpFloat j = joint->jAcc;
|
||||
a->w -= j*a->i_inv*joint->ratio_inv;
|
||||
b->w += j*b->i_inv;
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpGearJoint *joint)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// compute relative rotational velocity
|
||||
cpFloat wr = b->w*joint->ratio - a->w;
|
||||
|
||||
// compute normal impulse
|
||||
cpFloat j = (joint->bias - wr)*joint->iSum;
|
||||
cpFloat jOld = joint->jAcc;
|
||||
joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);
|
||||
j = joint->jAcc - jOld;
|
||||
|
||||
// apply impulse
|
||||
a->w -= j*a->i_inv*joint->ratio_inv;
|
||||
b->w += j*b->i_inv;
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpGearJoint *joint)
|
||||
{
|
||||
return cpfabs(joint->jAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpGearJoint)
|
||||
|
||||
cpGearJoint *
|
||||
cpGearJointAlloc(void)
|
||||
{
|
||||
return (cpGearJoint *)cpmalloc(sizeof(cpGearJoint));
|
||||
}
|
||||
|
||||
cpGearJoint *
|
||||
cpGearJointInit(cpGearJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->phase = phase;
|
||||
joint->ratio = ratio;
|
||||
joint->ratio_inv = 1.0f/ratio;
|
||||
|
||||
joint->jAcc = 0.0f;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpGearJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratio)
|
||||
{
|
||||
return (cpConstraint *)cpGearJointInit(cpGearJointAlloc(), a, b, phase, ratio);
|
||||
}
|
||||
|
||||
void
|
||||
cpGearJointSetRatio(cpConstraint *constraint, cpFloat value)
|
||||
{
|
||||
cpConstraintCheckCast(constraint, cpGearJoint);
|
||||
((cpGearJoint *)constraint)->ratio = value;
|
||||
((cpGearJoint *)constraint)->ratio_inv = 1.0f/value;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpGrooveJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// calculate endpoints in worldspace
|
||||
cpVect ta = cpBodyLocal2World(a, joint->grv_a);
|
||||
cpVect tb = cpBodyLocal2World(a, joint->grv_b);
|
||||
|
||||
// calculate axis
|
||||
cpVect n = cpvrotate(joint->grv_n, a->rot);
|
||||
cpFloat d = cpvdot(ta, n);
|
||||
|
||||
joint->grv_tn = n;
|
||||
joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
||||
|
||||
// calculate tangential distance along the axis of r2
|
||||
cpFloat td = cpvcross(cpvadd(b->p, joint->r2), n);
|
||||
// calculate clamping factor and r2
|
||||
if(td <= cpvcross(ta, n)){
|
||||
joint->clamp = 1.0f;
|
||||
joint->r1 = cpvsub(ta, a->p);
|
||||
} else if(td >= cpvcross(tb, n)){
|
||||
joint->clamp = -1.0f;
|
||||
joint->r1 = cpvsub(tb, a->p);
|
||||
} else {
|
||||
joint->clamp = 0.0f;
|
||||
joint->r1 = cpvsub(cpvadd(cpvmult(cpvperp(n), -td), cpvmult(n, d)), a->p);
|
||||
}
|
||||
|
||||
// Calculate mass tensor
|
||||
k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);
|
||||
|
||||
// compute max impulse
|
||||
joint->jMaxLen = J_MAX(joint, dt);
|
||||
|
||||
// calculate bias velocity
|
||||
cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
||||
joint->bias = cpvclamp(cpvmult(delta, -joint->constraint.biasCoef*dt_inv), joint->constraint.maxBias);
|
||||
|
||||
// apply accumulated impulse
|
||||
apply_impulses(a, b, joint->r1, joint->r2, joint->jAcc);
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
grooveConstrain(cpGrooveJoint *joint, cpVect j){
|
||||
cpVect n = joint->grv_tn;
|
||||
cpVect jClamp = (joint->clamp*cpvcross(j, n) > 0.0f) ? j : cpvproject(j, n);
|
||||
return cpvclamp(jClamp, joint->jMaxLen);
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpGrooveJoint *joint)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
cpVect r1 = joint->r1;
|
||||
cpVect r2 = joint->r2;
|
||||
|
||||
// compute impulse
|
||||
cpVect vr = relative_velocity(a, b, r1, r2);
|
||||
|
||||
cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);
|
||||
cpVect jOld = joint->jAcc;
|
||||
joint->jAcc = grooveConstrain(joint, cpvadd(jOld, j));
|
||||
j = cpvsub(joint->jAcc, jOld);
|
||||
|
||||
// apply impulse
|
||||
apply_impulses(a, b, joint->r1, joint->r2, j);
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpGrooveJoint *joint)
|
||||
{
|
||||
return cpvlength(joint->jAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpGrooveJoint)
|
||||
|
||||
cpGrooveJoint *
|
||||
cpGrooveJointAlloc(void)
|
||||
{
|
||||
return (cpGrooveJoint *)cpmalloc(sizeof(cpGrooveJoint));
|
||||
}
|
||||
|
||||
cpGrooveJoint *
|
||||
cpGrooveJointInit(cpGrooveJoint *joint, cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->grv_a = groove_a;
|
||||
joint->grv_b = groove_b;
|
||||
joint->grv_n = cpvperp(cpvnormalize(cpvsub(groove_b, groove_a)));
|
||||
joint->anchr2 = anchr2;
|
||||
|
||||
joint->jAcc = cpvzero;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpGrooveJointNew(cpBody *a, cpBody *b, cpVect groove_a, cpVect groove_b, cpVect anchr2)
|
||||
{
|
||||
return (cpConstraint *)cpGrooveJointInit(cpGrooveJointAlloc(), a, b, groove_a, groove_b, anchr2);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/* 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 <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpPinJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
joint->r1 = cpvrotate(joint->anchr1, a->rot);
|
||||
joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
||||
|
||||
cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
||||
cpFloat dist = cpvlength(delta);
|
||||
joint->n = cpvmult(delta, 1.0f/(dist ? dist : (cpFloat)INFINITY));
|
||||
|
||||
// calculate mass normal
|
||||
joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);
|
||||
|
||||
// calculate bias velocity
|
||||
cpFloat maxBias = joint->constraint.maxBias;
|
||||
joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(dist - joint->dist), -maxBias, maxBias);
|
||||
|
||||
// compute max impulse
|
||||
joint->jnMax = J_MAX(joint, dt);
|
||||
|
||||
// apply accumulated impulse
|
||||
cpVect j = cpvmult(joint->n, joint->jnAcc);
|
||||
apply_impulses(a, b, joint->r1, joint->r2, j);
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpPinJoint *joint)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
cpVect n = joint->n;
|
||||
|
||||
// compute relative velocity
|
||||
cpFloat vrn = normal_relative_velocity(a, b, joint->r1, joint->r2, n);
|
||||
|
||||
// compute normal impulse
|
||||
cpFloat jn = (joint->bias - vrn)*joint->nMass;
|
||||
cpFloat jnOld = joint->jnAcc;
|
||||
joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, joint->jnMax);
|
||||
jn = joint->jnAcc - jnOld;
|
||||
|
||||
// apply impulse
|
||||
apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpPinJoint *joint)
|
||||
{
|
||||
return cpfabs(joint->jnAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpPinJoint);
|
||||
|
||||
|
||||
cpPinJoint *
|
||||
cpPinJointAlloc(void)
|
||||
{
|
||||
return (cpPinJoint *)cpmalloc(sizeof(cpPinJoint));
|
||||
}
|
||||
|
||||
cpPinJoint *
|
||||
cpPinJointInit(cpPinJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->anchr1 = anchr1;
|
||||
joint->anchr2 = anchr2;
|
||||
|
||||
cpVect p1 = cpvadd(a->p, cpvrotate(anchr1, a->rot));
|
||||
cpVect p2 = cpvadd(b->p, cpvrotate(anchr2, b->rot));
|
||||
joint->dist = cpvlength(cpvsub(p2, p1));
|
||||
|
||||
joint->jnAcc = 0.0f;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpPinJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
||||
{
|
||||
return (cpConstraint *)cpPinJointInit(cpPinJointAlloc(), a, b, anchr1, anchr2);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpPivotJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
joint->r1 = cpvrotate(joint->anchr1, a->rot);
|
||||
joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
||||
|
||||
// Calculate mass tensor
|
||||
k_tensor(a, b, joint->r1, joint->r2, &joint->k1, &joint->k2);
|
||||
|
||||
// compute max impulse
|
||||
joint->jMaxLen = J_MAX(joint, dt);
|
||||
|
||||
// calculate bias velocity
|
||||
cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
||||
joint->bias = cpvclamp(cpvmult(delta, -joint->constraint.biasCoef*dt_inv), joint->constraint.maxBias);
|
||||
|
||||
// apply accumulated impulse
|
||||
apply_impulses(a, b, joint->r1, joint->r2, joint->jAcc);
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpPivotJoint *joint)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
cpVect r1 = joint->r1;
|
||||
cpVect r2 = joint->r2;
|
||||
|
||||
// compute relative velocity
|
||||
cpVect vr = relative_velocity(a, b, r1, r2);
|
||||
|
||||
// compute normal impulse
|
||||
cpVect j = mult_k(cpvsub(joint->bias, vr), joint->k1, joint->k2);
|
||||
cpVect jOld = joint->jAcc;
|
||||
joint->jAcc = cpvclamp(cpvadd(joint->jAcc, j), joint->jMaxLen);
|
||||
j = cpvsub(joint->jAcc, jOld);
|
||||
|
||||
// apply impulse
|
||||
apply_impulses(a, b, joint->r1, joint->r2, j);
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpConstraint *joint)
|
||||
{
|
||||
return cpvlength(((cpPivotJoint *)joint)->jAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpPivotJoint)
|
||||
|
||||
cpPivotJoint *
|
||||
cpPivotJointAlloc(void)
|
||||
{
|
||||
return (cpPivotJoint *)cpmalloc(sizeof(cpPivotJoint));
|
||||
}
|
||||
|
||||
cpPivotJoint *
|
||||
cpPivotJointInit(cpPivotJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->anchr1 = anchr1;
|
||||
joint->anchr2 = anchr2;
|
||||
|
||||
joint->jAcc = cpvzero;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpPivotJointNew2(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2)
|
||||
{
|
||||
return (cpConstraint *)cpPivotJointInit(cpPivotJointAlloc(), a, b, anchr1, anchr2);
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpPivotJointNew(cpBody *a, cpBody *b, cpVect pivot)
|
||||
{
|
||||
return cpPivotJointNew2(a, b, cpBodyWorld2Local(a, pivot), cpBodyWorld2Local(b, pivot));
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
cpFloat angle = joint->angle;
|
||||
cpFloat phase = joint->phase;
|
||||
cpFloat ratchet = joint->ratchet;
|
||||
|
||||
cpFloat delta = b->a - a->a;
|
||||
cpFloat diff = angle - delta;
|
||||
cpFloat pdist = 0.0f;
|
||||
|
||||
if(diff*ratchet > 0.0f){
|
||||
pdist = diff;
|
||||
} else {
|
||||
joint->angle = cpffloor((delta - phase)/ratchet)*ratchet + phase;
|
||||
}
|
||||
|
||||
// calculate moment of inertia coefficient.
|
||||
joint->iSum = 1.0f/(a->i_inv + b->i_inv);
|
||||
|
||||
// calculate bias velocity
|
||||
cpFloat maxBias = joint->constraint.maxBias;
|
||||
joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*pdist, -maxBias, maxBias);
|
||||
|
||||
// compute max impulse
|
||||
joint->jMax = J_MAX(joint, dt);
|
||||
|
||||
// If the bias is 0, the joint is not at a limit. Reset the impulse.
|
||||
if(!joint->bias)
|
||||
joint->jAcc = 0.0f;
|
||||
|
||||
// apply joint torque
|
||||
a->w -= joint->jAcc*a->i_inv;
|
||||
b->w += joint->jAcc*b->i_inv;
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpRatchetJoint *joint)
|
||||
{
|
||||
if(!joint->bias) return; // early exit
|
||||
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// compute relative rotational velocity
|
||||
cpFloat wr = b->w - a->w;
|
||||
cpFloat ratchet = joint->ratchet;
|
||||
|
||||
// compute normal impulse
|
||||
cpFloat j = -(joint->bias + wr)*joint->iSum;
|
||||
cpFloat jOld = joint->jAcc;
|
||||
joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, joint->jMax*cpfabs(ratchet))/ratchet;
|
||||
j = joint->jAcc - jOld;
|
||||
|
||||
// apply impulse
|
||||
a->w -= j*a->i_inv;
|
||||
b->w += j*b->i_inv;
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpRatchetJoint *joint)
|
||||
{
|
||||
return cpfabs(joint->jAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpRatchetJoint)
|
||||
|
||||
cpRatchetJoint *
|
||||
cpRatchetJointAlloc(void)
|
||||
{
|
||||
return (cpRatchetJoint *)cpmalloc(sizeof(cpRatchetJoint));
|
||||
}
|
||||
|
||||
cpRatchetJoint *
|
||||
cpRatchetJointInit(cpRatchetJoint *joint, cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->angle = 0.0f;
|
||||
joint->phase = phase;
|
||||
joint->ratchet = ratchet;
|
||||
|
||||
joint->angle = b->a - a->a;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpRatchetJointNew(cpBody *a, cpBody *b, cpFloat phase, cpFloat ratchet)
|
||||
{
|
||||
return (cpConstraint *)cpRatchetJointInit(cpRatchetJointAlloc(), a, b, phase, ratchet);
|
||||
}
|
|
@ -0,0 +1,122 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
cpFloat dist = b->a - a->a;
|
||||
cpFloat pdist = 0.0f;
|
||||
if(dist > joint->max) {
|
||||
pdist = joint->max - dist;
|
||||
} else if(dist < joint->min) {
|
||||
pdist = joint->min - dist;
|
||||
}
|
||||
|
||||
// calculate moment of inertia coefficient.
|
||||
joint->iSum = 1.0f/(a->i_inv + b->i_inv);
|
||||
|
||||
// calculate bias velocity
|
||||
cpFloat maxBias = joint->constraint.maxBias;
|
||||
joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);
|
||||
|
||||
// compute max impulse
|
||||
joint->jMax = J_MAX(joint, dt);
|
||||
|
||||
// If the bias is 0, the joint is not at a limit. Reset the impulse.
|
||||
if(!joint->bias)
|
||||
joint->jAcc = 0.0f;
|
||||
|
||||
// apply joint torque
|
||||
a->w -= joint->jAcc*a->i_inv;
|
||||
b->w += joint->jAcc*b->i_inv;
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpRotaryLimitJoint *joint)
|
||||
{
|
||||
if(!joint->bias) return; // early exit
|
||||
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// compute relative rotational velocity
|
||||
cpFloat wr = b->w - a->w;
|
||||
|
||||
// compute normal impulse
|
||||
cpFloat j = -(joint->bias + wr)*joint->iSum;
|
||||
cpFloat jOld = joint->jAcc;
|
||||
if(joint->bias < 0.0f){
|
||||
joint->jAcc = cpfclamp(jOld + j, 0.0f, joint->jMax);
|
||||
} else {
|
||||
joint->jAcc = cpfclamp(jOld + j, -joint->jMax, 0.0f);
|
||||
}
|
||||
j = joint->jAcc - jOld;
|
||||
|
||||
// apply impulse
|
||||
a->w -= j*a->i_inv;
|
||||
b->w += j*b->i_inv;
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpRotaryLimitJoint *joint)
|
||||
{
|
||||
return cpfabs(joint->jAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpRotaryLimitJoint)
|
||||
|
||||
cpRotaryLimitJoint *
|
||||
cpRotaryLimitJointAlloc(void)
|
||||
{
|
||||
return (cpRotaryLimitJoint *)cpmalloc(sizeof(cpRotaryLimitJoint));
|
||||
}
|
||||
|
||||
cpRotaryLimitJoint *
|
||||
cpRotaryLimitJointInit(cpRotaryLimitJoint *joint, cpBody *a, cpBody *b, cpFloat min, cpFloat max)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->min = min;
|
||||
joint->max = max;
|
||||
|
||||
joint->jAcc = 0.0f;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpRotaryLimitJointNew(cpBody *a, cpBody *b, cpFloat min, cpFloat max)
|
||||
{
|
||||
return (cpConstraint *)cpRotaryLimitJointInit(cpRotaryLimitJointAlloc(), a, b, min, max);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpSimpleMotor *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// calculate moment of inertia coefficient.
|
||||
joint->iSum = 1.0f/(a->i_inv + b->i_inv);
|
||||
|
||||
// compute max impulse
|
||||
joint->jMax = J_MAX(joint, dt);
|
||||
|
||||
// apply joint torque
|
||||
a->w -= joint->jAcc*a->i_inv;
|
||||
b->w += joint->jAcc*b->i_inv;
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpSimpleMotor *joint)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
// compute relative rotational velocity
|
||||
cpFloat wr = b->w - a->w + joint->rate;
|
||||
|
||||
// compute normal impulse
|
||||
cpFloat j = -wr*joint->iSum;
|
||||
cpFloat jOld = joint->jAcc;
|
||||
joint->jAcc = cpfclamp(jOld + j, -joint->jMax, joint->jMax);
|
||||
j = joint->jAcc - jOld;
|
||||
|
||||
// apply impulse
|
||||
a->w -= j*a->i_inv;
|
||||
b->w += j*b->i_inv;
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpSimpleMotor *joint)
|
||||
{
|
||||
return cpfabs(joint->jAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpSimpleMotor)
|
||||
|
||||
cpSimpleMotor *
|
||||
cpSimpleMotorAlloc(void)
|
||||
{
|
||||
return (cpSimpleMotor *)cpmalloc(sizeof(cpSimpleMotor));
|
||||
}
|
||||
|
||||
cpSimpleMotor *
|
||||
cpSimpleMotorInit(cpSimpleMotor *joint, cpBody *a, cpBody *b, cpFloat rate)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->rate = rate;
|
||||
|
||||
joint->jAcc = 0.0f;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpSimpleMotorNew(cpBody *a, cpBody *b, cpFloat rate)
|
||||
{
|
||||
return (cpConstraint *)cpSimpleMotorInit(cpSimpleMotorAlloc(), a, b, rate);
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
static void
|
||||
preStep(cpSlideJoint *joint, cpFloat dt, cpFloat dt_inv)
|
||||
{
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
joint->r1 = cpvrotate(joint->anchr1, a->rot);
|
||||
joint->r2 = cpvrotate(joint->anchr2, b->rot);
|
||||
|
||||
cpVect delta = cpvsub(cpvadd(b->p, joint->r2), cpvadd(a->p, joint->r1));
|
||||
cpFloat dist = cpvlength(delta);
|
||||
cpFloat pdist = 0.0f;
|
||||
if(dist > joint->max) {
|
||||
pdist = dist - joint->max;
|
||||
} else if(dist < joint->min) {
|
||||
pdist = joint->min - dist;
|
||||
dist = -dist;
|
||||
}
|
||||
joint->n = cpvmult(delta, 1.0f/(dist ? dist : (cpFloat)INFINITY));
|
||||
|
||||
// calculate mass normal
|
||||
joint->nMass = 1.0f/k_scalar(a, b, joint->r1, joint->r2, joint->n);
|
||||
|
||||
// calculate bias velocity
|
||||
cpFloat maxBias = joint->constraint.maxBias;
|
||||
joint->bias = cpfclamp(-joint->constraint.biasCoef*dt_inv*(pdist), -maxBias, maxBias);
|
||||
|
||||
// compute max impulse
|
||||
joint->jnMax = J_MAX(joint, dt);
|
||||
|
||||
// apply accumulated impulse
|
||||
if(!joint->bias) //{
|
||||
// if bias is 0, then the joint is not at a limit.
|
||||
joint->jnAcc = 0.0f;
|
||||
// } else {
|
||||
cpVect j = cpvmult(joint->n, joint->jnAcc);
|
||||
apply_impulses(a, b, joint->r1, joint->r2, j);
|
||||
// }
|
||||
}
|
||||
|
||||
static void
|
||||
applyImpulse(cpSlideJoint *joint)
|
||||
{
|
||||
if(!joint->bias) return; // early exit
|
||||
|
||||
cpBody *a = joint->constraint.a;
|
||||
cpBody *b = joint->constraint.b;
|
||||
|
||||
cpVect n = joint->n;
|
||||
cpVect r1 = joint->r1;
|
||||
cpVect r2 = joint->r2;
|
||||
|
||||
// compute relative velocity
|
||||
cpVect vr = relative_velocity(a, b, r1, r2);
|
||||
cpFloat vrn = cpvdot(vr, n);
|
||||
|
||||
// compute normal impulse
|
||||
cpFloat jn = (joint->bias - vrn)*joint->nMass;
|
||||
cpFloat jnOld = joint->jnAcc;
|
||||
joint->jnAcc = cpfclamp(jnOld + jn, -joint->jnMax, 0.0f);
|
||||
jn = joint->jnAcc - jnOld;
|
||||
|
||||
// apply impulse
|
||||
apply_impulses(a, b, joint->r1, joint->r2, cpvmult(n, jn));
|
||||
}
|
||||
|
||||
static cpFloat
|
||||
getImpulse(cpConstraint *joint)
|
||||
{
|
||||
return cpfabs(((cpSlideJoint *)joint)->jnAcc);
|
||||
}
|
||||
|
||||
static const cpConstraintClass klass = {
|
||||
(cpConstraintPreStepFunction)preStep,
|
||||
(cpConstraintApplyImpulseFunction)applyImpulse,
|
||||
(cpConstraintGetImpulseFunction)getImpulse,
|
||||
};
|
||||
CP_DefineClassGetter(cpSlideJoint)
|
||||
|
||||
cpSlideJoint *
|
||||
cpSlideJointAlloc(void)
|
||||
{
|
||||
return (cpSlideJoint *)cpmalloc(sizeof(cpSlideJoint));
|
||||
}
|
||||
|
||||
cpSlideJoint *
|
||||
cpSlideJointInit(cpSlideJoint *joint, cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
|
||||
{
|
||||
cpConstraintInit((cpConstraint *)joint, &klass, a, b);
|
||||
|
||||
joint->anchr1 = anchr1;
|
||||
joint->anchr2 = anchr2;
|
||||
joint->min = min;
|
||||
joint->max = max;
|
||||
|
||||
joint->jnAcc = 0.0f;
|
||||
|
||||
return joint;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpSlideJointNew(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat min, cpFloat max)
|
||||
{
|
||||
return (cpConstraint *)cpSlideJointInit(cpSlideJointAlloc(), a, b, anchr1, anchr2, min, max);
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/* 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"
|
||||
#include "constraints/util.h"
|
||||
|
||||
cpFloat cp_bias_coef = 0.1f;
|
||||
cpFloat cp_collision_slop = 0.1f;
|
||||
|
||||
cpContact*
|
||||
cpContactInit(cpContact *con, cpVect p, cpVect n, cpFloat dist, cpHashValue hash)
|
||||
{
|
||||
con->p = p;
|
||||
con->n = n;
|
||||
con->dist = dist;
|
||||
|
||||
con->jnAcc = 0.0f;
|
||||
con->jtAcc = 0.0f;
|
||||
con->jBias = 0.0f;
|
||||
|
||||
con->hash = hash;
|
||||
|
||||
return con;
|
||||
}
|
||||
|
||||
cpVect
|
||||
cpArbiterTotalImpulse(cpArbiter *arb)
|
||||
{
|
||||
cpContact *contacts = arb->contacts;
|
||||
cpVect sum = cpvzero;
|
||||
|
||||
for(int i=0, count=arb->numContacts; i<count; i++){
|
||||
cpContact *con = &contacts[i];
|
||||
sum = cpvadd(sum, cpvmult(con->n, con->jnAcc));
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
cpVect
|
||||
cpArbiterTotalImpulseWithFriction(cpArbiter *arb)
|
||||
{
|
||||
cpContact *contacts = arb->contacts;
|
||||
cpVect sum = cpvzero;
|
||||
|
||||
for(int i=0, count=arb->numContacts; i<count; i++){
|
||||
cpContact *con = &contacts[i];
|
||||
sum = cpvadd(sum, cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc)));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cpArbiter*
|
||||
cpArbiterAlloc(void)
|
||||
{
|
||||
return (cpArbiter *)cpcalloc(1, sizeof(cpArbiter));
|
||||
}
|
||||
|
||||
cpArbiter*
|
||||
cpArbiterInit(cpArbiter *arb, cpShape *a, cpShape *b)
|
||||
{
|
||||
arb->numContacts = 0;
|
||||
arb->contacts = NULL;
|
||||
|
||||
arb->private_a = a;
|
||||
arb->private_b = b;
|
||||
|
||||
arb->stamp = -1;
|
||||
arb->state = cpArbiterStateFirstColl;
|
||||
|
||||
return arb;
|
||||
}
|
||||
|
||||
cpArbiter*
|
||||
cpArbiterNew(cpShape *a, cpShape *b)
|
||||
{
|
||||
return cpArbiterInit(cpArbiterAlloc(), a, b);
|
||||
}
|
||||
|
||||
void
|
||||
cpArbiterDestroy(cpArbiter *arb)
|
||||
{
|
||||
// if(arb->contacts) cpfree(arb->contacts);
|
||||
}
|
||||
|
||||
void
|
||||
cpArbiterFree(cpArbiter *arb)
|
||||
{
|
||||
if(arb){
|
||||
cpArbiterDestroy(arb);
|
||||
cpfree(arb);
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cpfree(arb->contacts);
|
||||
}
|
||||
|
||||
arb->contacts = contacts;
|
||||
arb->numContacts = numContacts;
|
||||
|
||||
arb->handler = handler;
|
||||
arb->swappedColl = (a->collision_type != handler->a);
|
||||
|
||||
arb->e = a->e * b->e;
|
||||
arb->u = a->u * b->u;
|
||||
arb->surface_vr = cpvsub(a->surface_v, b->surface_v);
|
||||
|
||||
// For collisions between two similar primitive types, the order could have been swapped.
|
||||
arb->private_a = a; arb->private_b = b;
|
||||
}
|
||||
|
||||
void
|
||||
cpArbiterPreStep(cpArbiter *arb, cpFloat dt_inv)
|
||||
{
|
||||
cpShape *shapea = arb->private_a;
|
||||
cpShape *shapeb = arb->private_b;
|
||||
|
||||
cpBody *a = shapea->body;
|
||||
cpBody *b = shapeb->body;
|
||||
|
||||
for(int i=0; i<arb->numContacts; i++){
|
||||
cpContact *con = &arb->contacts[i];
|
||||
|
||||
// Calculate the offsets.
|
||||
con->r1 = cpvsub(con->p, a->p);
|
||||
con->r2 = cpvsub(con->p, b->p);
|
||||
|
||||
// Calculate the mass normal and mass tangent.
|
||||
con->nMass = 1.0f/k_scalar(a, b, con->r1, con->r2, con->n);
|
||||
con->tMass = 1.0f/k_scalar(a, b, con->r1, con->r2, cpvperp(con->n));
|
||||
|
||||
// Calculate the target bias velocity.
|
||||
con->bias = -cp_bias_coef*dt_inv*cpfmin(0.0f, con->dist + cp_collision_slop);
|
||||
con->jBias = 0.0f;
|
||||
|
||||
// Calculate the target bounce velocity.
|
||||
con->bounce = normal_relative_velocity(a, b, con->r1, con->r2, con->n)*arb->e;//cpvdot(con->n, cpvsub(v2, v1))*e;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpArbiterApplyCachedImpulse(cpArbiter *arb)
|
||||
{
|
||||
cpShape *shapea = arb->private_a;
|
||||
cpShape *shapeb = arb->private_b;
|
||||
|
||||
arb->u = shapea->u * shapeb->u;
|
||||
arb->surface_vr = cpvsub(shapeb->surface_v, shapea->surface_v);
|
||||
|
||||
cpBody *a = shapea->body;
|
||||
cpBody *b = shapeb->body;
|
||||
|
||||
for(int i=0; i<arb->numContacts; i++){
|
||||
cpContact *con = &arb->contacts[i];
|
||||
apply_impulses(a, b, con->r1, con->r2, cpvrotate(con->n, cpv(con->jnAcc, con->jtAcc)));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpArbiterApplyImpulse(cpArbiter *arb, cpFloat eCoef)
|
||||
{
|
||||
cpBody *a = arb->private_a->body;
|
||||
cpBody *b = arb->private_b->body;
|
||||
|
||||
for(int i=0; i<arb->numContacts; i++){
|
||||
cpContact *con = &arb->contacts[i];
|
||||
cpVect n = con->n;
|
||||
cpVect r1 = con->r1;
|
||||
cpVect r2 = con->r2;
|
||||
|
||||
// Calculate the relative bias velocities.
|
||||
cpVect vb1 = cpvadd(a->v_bias, cpvmult(cpvperp(r1), a->w_bias));
|
||||
cpVect vb2 = cpvadd(b->v_bias, cpvmult(cpvperp(r2), b->w_bias));
|
||||
cpFloat vbn = cpvdot(cpvsub(vb2, vb1), n);
|
||||
|
||||
// Calculate and clamp the bias impulse.
|
||||
cpFloat jbn = (con->bias - vbn)*con->nMass;
|
||||
cpFloat jbnOld = con->jBias;
|
||||
con->jBias = cpfmax(jbnOld + jbn, 0.0f);
|
||||
jbn = con->jBias - jbnOld;
|
||||
|
||||
// Apply the bias impulse.
|
||||
apply_bias_impulses(a, b, r1, r2, cpvmult(n, jbn));
|
||||
|
||||
// Calculate the relative velocity.
|
||||
cpVect vr = relative_velocity(a, b, r1, r2);
|
||||
cpFloat vrn = cpvdot(vr, n);
|
||||
|
||||
// Calculate and clamp the normal impulse.
|
||||
cpFloat jn = -(con->bounce*eCoef + vrn)*con->nMass;
|
||||
cpFloat jnOld = con->jnAcc;
|
||||
con->jnAcc = cpfmax(jnOld + jn, 0.0f);
|
||||
jn = con->jnAcc - jnOld;
|
||||
|
||||
// Calculate the relative tangent velocity.
|
||||
cpFloat vrt = cpvdot(cpvadd(vr, arb->surface_vr), cpvperp(n));
|
||||
|
||||
// Calculate and clamp the friction impulse.
|
||||
cpFloat jtMax = arb->u*con->jnAcc;
|
||||
cpFloat jt = -vrt*con->tMass;
|
||||
cpFloat jtOld = con->jtAcc;
|
||||
con->jtAcc = cpfclamp(jtOld + jt, -jtMax, jtMax);
|
||||
jt = con->jtAcc - jtOld;
|
||||
|
||||
// Apply the final impulse.
|
||||
apply_impulses(a, b, r1, r2, cpvrotate(n, cpv(jn, jt)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/* 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 <string.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
|
||||
//#define CP_ARRAY_INCREMENT 10
|
||||
|
||||
// NOTE: cpArray is rarely used and will probably go away.
|
||||
|
||||
cpArray*
|
||||
cpArrayAlloc(void)
|
||||
{
|
||||
return (cpArray *)cpcalloc(1, sizeof(cpArray));
|
||||
}
|
||||
|
||||
cpArray*
|
||||
cpArrayInit(cpArray *arr, int size)
|
||||
{
|
||||
arr->num = 0;
|
||||
|
||||
size = (size ? size : 4);
|
||||
arr->max = size;
|
||||
arr->arr = (void **)cpmalloc(size*sizeof(void**));
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
cpArray*
|
||||
cpArrayNew(int size)
|
||||
{
|
||||
return cpArrayInit(cpArrayAlloc(), size);
|
||||
}
|
||||
|
||||
void
|
||||
cpArrayDestroy(cpArray *arr)
|
||||
{
|
||||
cpfree(arr->arr);
|
||||
}
|
||||
|
||||
void
|
||||
cpArrayFree(cpArray *arr)
|
||||
{
|
||||
if(arr){
|
||||
cpArrayDestroy(arr);
|
||||
cpfree(arr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpArrayPush(cpArray *arr, void *object)
|
||||
{
|
||||
if(arr->num == arr->max){
|
||||
arr->max *= 2;
|
||||
arr->arr = (void **)cprealloc(arr->arr, arr->max*sizeof(void**));
|
||||
}
|
||||
|
||||
arr->arr[arr->num] = object;
|
||||
arr->num++;
|
||||
}
|
||||
|
||||
void *
|
||||
cpArrayPop(cpArray *arr)
|
||||
{
|
||||
arr->num--;
|
||||
|
||||
void *value = arr->arr[arr->num];
|
||||
arr->arr[arr->num] = NULL;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void
|
||||
cpArrayDeleteIndex(cpArray *arr, int idx)
|
||||
{
|
||||
arr->num--;
|
||||
|
||||
arr->arr[idx] = arr->arr[arr->num];
|
||||
arr->arr[arr->num] = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
cpArrayDeleteObj(cpArray *arr, void *obj)
|
||||
{
|
||||
for(int i=0; i<arr->num; i++){
|
||||
if(arr->arr[i] == obj){
|
||||
cpArrayDeleteIndex(arr, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpArrayEach(cpArray *arr, cpArrayIter iterFunc, void *data)
|
||||
{
|
||||
for(int i=0; i<arr->num; i++)
|
||||
iterFunc(arr->arr[i], data);
|
||||
}
|
||||
|
||||
int
|
||||
cpArrayContains(cpArray *arr, void *ptr)
|
||||
{
|
||||
for(int i=0; i<arr->num; i++)
|
||||
if(arr->arr[i] == ptr) return 1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* 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 <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
cpVect
|
||||
cpBBClampVect(const cpBB bb, const cpVect v)
|
||||
{
|
||||
cpFloat x = cpfmin(cpfmax(bb.l, v.x), bb.r);
|
||||
cpFloat y = cpfmin(cpfmax(bb.b, v.y), bb.t);
|
||||
return cpv(x, y);
|
||||
}
|
||||
|
||||
cpVect
|
||||
cpBBWrapVect(const cpBB bb, const cpVect v)
|
||||
{
|
||||
cpFloat ix = cpfabs(bb.r - bb.l);
|
||||
cpFloat modx = cpfmod(v.x - bb.l, ix);
|
||||
cpFloat x = (modx > 0.0f) ? modx : modx + ix;
|
||||
|
||||
cpFloat iy = cpfabs(bb.t - bb.b);
|
||||
cpFloat mody = cpfmod(v.y - bb.b, iy);
|
||||
cpFloat y = (mody > 0.0f) ? mody : mody + iy;
|
||||
|
||||
return cpv(x + bb.l, y + bb.b);
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/* 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 <float.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
cpBody*
|
||||
cpBodyAlloc(void)
|
||||
{
|
||||
return (cpBody *)cpmalloc(sizeof(cpBody));
|
||||
}
|
||||
|
||||
cpBodyVelocityFunc cpBodyUpdateVelocityDefault = cpBodyUpdateVelocity;
|
||||
cpBodyPositionFunc cpBodyUpdatePositionDefault = cpBodyUpdatePosition;
|
||||
|
||||
cpBody*
|
||||
cpBodyInit(cpBody *body, cpFloat m, cpFloat i)
|
||||
{
|
||||
body->velocity_func = cpBodyUpdateVelocityDefault;
|
||||
body->position_func = cpBodyUpdatePositionDefault;
|
||||
|
||||
cpBodySetMass(body, m);
|
||||
cpBodySetMoment(body, i);
|
||||
|
||||
body->p = cpvzero;
|
||||
body->v = cpvzero;
|
||||
body->f = cpvzero;
|
||||
|
||||
cpBodySetAngle(body, 0.0f);
|
||||
body->w = 0.0f;
|
||||
body->t = 0.0f;
|
||||
|
||||
body->v_bias = cpvzero;
|
||||
body->w_bias = 0.0f;
|
||||
|
||||
body->data = NULL;
|
||||
body->v_limit = (cpFloat)INFINITY;
|
||||
body->w_limit = (cpFloat)INFINITY;
|
||||
// body->active = 1;
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
cpBody*
|
||||
cpBodyNew(cpFloat m, cpFloat i)
|
||||
{
|
||||
return cpBodyInit(cpBodyAlloc(), m, i);
|
||||
}
|
||||
|
||||
void cpBodyDestroy(cpBody *body){}
|
||||
|
||||
void
|
||||
cpBodyFree(cpBody *body)
|
||||
{
|
||||
if(body){
|
||||
cpBodyDestroy(body);
|
||||
cpfree(body);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpBodySetMass(cpBody *body, cpFloat mass)
|
||||
{
|
||||
body->m = mass;
|
||||
body->m_inv = 1.0f/mass;
|
||||
}
|
||||
|
||||
void
|
||||
cpBodySetMoment(cpBody *body, cpFloat moment)
|
||||
{
|
||||
body->i = moment;
|
||||
body->i_inv = 1.0f/moment;
|
||||
}
|
||||
|
||||
void
|
||||
cpBodySetAngle(cpBody *body, cpFloat angle)
|
||||
{
|
||||
body->a = angle;//fmod(a, (cpFloat)M_PI*2.0f);
|
||||
body->rot = cpvforangle(angle);
|
||||
}
|
||||
|
||||
void
|
||||
cpBodySlew(cpBody *body, cpVect pos, cpFloat dt)
|
||||
{
|
||||
cpVect delta = cpvsub(pos, body->p);
|
||||
body->v = cpvmult(delta, 1.0f/dt);
|
||||
}
|
||||
|
||||
void
|
||||
cpBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
|
||||
{
|
||||
body->v = cpvclamp(cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt)), body->v_limit);
|
||||
|
||||
cpFloat w_limit = body->w_limit;
|
||||
body->w = cpfclamp(body->w*damping + body->t*body->i_inv*dt, -w_limit, w_limit);
|
||||
}
|
||||
|
||||
void
|
||||
cpBodyUpdatePosition(cpBody *body, cpFloat dt)
|
||||
{
|
||||
body->p = cpvadd(body->p, cpvmult(cpvadd(body->v, body->v_bias), dt));
|
||||
cpBodySetAngle(body, body->a + (body->w + body->w_bias)*dt);
|
||||
|
||||
body->v_bias = cpvzero;
|
||||
body->w_bias = 0.0f;
|
||||
}
|
||||
|
||||
void
|
||||
cpBodyResetForces(cpBody *body)
|
||||
{
|
||||
body->f = cpvzero;
|
||||
body->t = 0.0f;
|
||||
}
|
||||
|
||||
void
|
||||
cpBodyApplyForce(cpBody *body, cpVect force, cpVect r)
|
||||
{
|
||||
body->f = cpvadd(body->f, force);
|
||||
body->t += cpvcross(r, force);
|
||||
}
|
||||
|
||||
void
|
||||
cpApplyDampedSpring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat rlen, cpFloat k, cpFloat dmp, cpFloat dt)
|
||||
{
|
||||
// Calculate the world space anchor coordinates.
|
||||
cpVect r1 = cpvrotate(anchr1, a->rot);
|
||||
cpVect r2 = cpvrotate(anchr2, b->rot);
|
||||
|
||||
cpVect delta = cpvsub(cpvadd(b->p, r2), cpvadd(a->p, r1));
|
||||
cpFloat dist = cpvlength(delta);
|
||||
cpVect n = dist ? cpvmult(delta, 1.0f/dist) : cpvzero;
|
||||
|
||||
cpFloat f_spring = (dist - rlen)*k;
|
||||
|
||||
// Calculate the world relative velocities of the anchor points.
|
||||
cpVect v1 = cpvadd(a->v, cpvmult(cpvperp(r1), a->w));
|
||||
cpVect v2 = cpvadd(b->v, cpvmult(cpvperp(r2), b->w));
|
||||
|
||||
// Calculate the damping force.
|
||||
// This really should be in the impulse solver and can produce problems when using large damping values.
|
||||
cpFloat vrn = cpvdot(cpvsub(v2, v1), n);
|
||||
cpFloat f_damp = vrn*cpfmin(dmp, 1.0f/(dt*(a->m_inv + b->m_inv)));
|
||||
|
||||
// Apply!
|
||||
cpVect f = cpvmult(n, f_spring + f_damp);
|
||||
cpBodyApplyForce(a, f, r1);
|
||||
cpBodyApplyForce(b, cpvneg(f), r2);
|
||||
}
|
||||
|
||||
//int
|
||||
//cpBodyMarkLowEnergy(cpBody *body, cpFloat dvsq, int max)
|
||||
//{
|
||||
// cpFloat ke = body->m*cpvdot(body->v, body->v);
|
||||
// cpFloat re = body->i*body->w*body->w;
|
||||
//
|
||||
// if(ke + re > body->m*dvsq)
|
||||
// body->active = 1;
|
||||
// else if(body->active)
|
||||
// body->active = (body->active + 1)%(max + 1);
|
||||
// else {
|
||||
// body->v = cpvzero;
|
||||
// body->v_bias = cpvzero;
|
||||
// body->w = 0.0f;
|
||||
// body->w_bias = 0.0f;
|
||||
// }
|
||||
//
|
||||
// return body->active;
|
||||
//}
|
|
@ -0,0 +1,391 @@
|
|||
/* 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 <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
typedef int (*collisionFunc)(cpShape *, 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)
|
||||
{
|
||||
cpFloat mindist = r1 + r2;
|
||||
cpVect delta = cpvsub(p2, p1);
|
||||
cpFloat distsq = cpvlengthsq(delta);
|
||||
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),
|
||||
dist - mindist,
|
||||
0
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Collide circle shapes.
|
||||
static int
|
||||
circle2circle(cpShape *shape1, cpShape *shape2, cpContact *arr)
|
||||
{
|
||||
cpCircleShape *circ1 = (cpCircleShape *)shape1;
|
||||
cpCircleShape *circ2 = (cpCircleShape *)shape2;
|
||||
|
||||
return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr);
|
||||
}
|
||||
|
||||
// Collide circles to segment shapes.
|
||||
static int
|
||||
circle2segment(cpShape *circleShape, cpShape *segmentShape, cpContact *con)
|
||||
{
|
||||
cpCircleShape *circ = (cpCircleShape *)circleShape;
|
||||
cpSegmentShape *seg = (cpSegmentShape *)segmentShape;
|
||||
|
||||
// Radius sum
|
||||
cpFloat rsum = circ->r + seg->r;
|
||||
|
||||
// Calculate normal distance from segment.
|
||||
cpFloat dn = cpvdot(seg->tn, circ->tc) - cpvdot(seg->ta, seg->tn);
|
||||
cpFloat dist = cpfabs(dn) - rsum;
|
||||
if(dist > 0.0f) return 0;
|
||||
|
||||
// Calculate tangential distance along segment.
|
||||
cpFloat dt = -cpvcross(seg->tn, circ->tc);
|
||||
cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
|
||||
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
|
||||
|
||||
// Decision tree to decide which feature of the segment to collide with.
|
||||
if(dt < dtMin){
|
||||
if(dt < (dtMin - rsum)){
|
||||
return 0;
|
||||
} else {
|
||||
return circle2circleQuery(circ->tc, seg->ta, circ->r, seg->r, con);
|
||||
}
|
||||
} else {
|
||||
if(dt < dtMax){
|
||||
cpVect n = (dn < 0.0f) ? seg->tn : cpvneg(seg->tn);
|
||||
cpContactInit(
|
||||
con,
|
||||
cpvadd(circ->tc, cpvmult(n, circ->r + dist*0.5f)),
|
||||
n,
|
||||
dist,
|
||||
0
|
||||
);
|
||||
return 1;
|
||||
} else {
|
||||
if(dt < (dtMax + rsum)) {
|
||||
return circle2circleQuery(circ->tc, seg->tb, circ->r, seg->r, con);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Helper function for working with contact buffers
|
||||
// This used to malloc/realloc memory on the fly but was repurposed.
|
||||
static cpContact *
|
||||
nextContactPoint(cpContact *arr, int *numPtr)
|
||||
{
|
||||
int num = *numPtr;
|
||||
|
||||
if(num <= CP_MAX_CONTACTS_PER_ARBITER)
|
||||
(*numPtr) = num + 1;
|
||||
|
||||
return &arr[num];
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
int min_index = 0;
|
||||
cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);
|
||||
if(min > 0.0f) return -1;
|
||||
|
||||
for(int i=1; i<num; i++){
|
||||
cpFloat dist = cpPolyShapeValueOnAxis(poly, axes[i].n, axes[i].d);
|
||||
if(dist > 0.0f) {
|
||||
return -1;
|
||||
} else if(dist > min){
|
||||
min = dist;
|
||||
min_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
(*min_out) = min;
|
||||
return min_index;
|
||||
}
|
||||
|
||||
// Add contacts for penetrating vertexes.
|
||||
static inline int
|
||||
findVerts(cpContact *arr, cpPolyShape *poly1, cpPolyShape *poly2, cpVect n, cpFloat dist)
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
for(int i=0; i<poly1->numVerts; i++){
|
||||
cpVect v = poly1->tVerts[i];
|
||||
if(cpPolyShapeContainsVertPartial(poly2, v, cpvneg(n)))
|
||||
cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly1->shape.hashid, i));
|
||||
}
|
||||
|
||||
for(int i=0; i<poly2->numVerts; i++){
|
||||
cpVect v = poly2->tVerts[i];
|
||||
if(cpPolyShapeContainsVertPartial(poly1, v, n))
|
||||
cpContactInit(nextContactPoint(arr, &num), v, n, dist, CP_HASH_PAIR(poly2->shape.hashid, i));
|
||||
}
|
||||
|
||||
// if(!num)
|
||||
// addContactPoint(arr, &size, &num, cpContactNew(shape1->body->p, n, dist, 0));
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
// Collide poly shapes together.
|
||||
static int
|
||||
poly2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
|
||||
{
|
||||
cpPolyShape *poly1 = (cpPolyShape *)shape1;
|
||||
cpPolyShape *poly2 = (cpPolyShape *)shape2;
|
||||
|
||||
cpFloat min1;
|
||||
int mini1 = findMSA(poly2, poly1->tAxes, poly1->numVerts, &min1);
|
||||
if(mini1 == -1) return 0;
|
||||
|
||||
cpFloat min2;
|
||||
int mini2 = findMSA(poly1, poly2->tAxes, poly2->numVerts, &min2);
|
||||
if(mini2 == -1) return 0;
|
||||
|
||||
// There is overlap, find the penetrating verts
|
||||
if(min1 > min2)
|
||||
return findVerts(arr, poly1, poly2, poly1->tAxes[mini1].n, min1);
|
||||
else
|
||||
return findVerts(arr, poly1, poly2, cpvneg(poly2->tAxes[mini2].n), min2);
|
||||
}
|
||||
|
||||
// Like cpPolyValueOnAxis(), but for segments.
|
||||
static inline cpFloat
|
||||
segValueOnAxis(cpSegmentShape *seg, cpVect n, cpFloat d)
|
||||
{
|
||||
cpFloat a = cpvdot(n, seg->ta) - seg->r;
|
||||
cpFloat b = cpvdot(n, seg->tb) - seg->r;
|
||||
return cpfmin(a, b) - d;
|
||||
}
|
||||
|
||||
// Identify vertexes that have penetrated the segment.
|
||||
static inline void
|
||||
findPointsBehindSeg(cpContact *arr, int *num, cpSegmentShape *seg, cpPolyShape *poly, cpFloat pDist, cpFloat coef)
|
||||
{
|
||||
cpFloat dta = cpvcross(seg->tn, seg->ta);
|
||||
cpFloat dtb = cpvcross(seg->tn, seg->tb);
|
||||
cpVect n = cpvmult(seg->tn, coef);
|
||||
|
||||
for(int i=0; i<poly->numVerts; i++){
|
||||
cpVect v = poly->tVerts[i];
|
||||
if(cpvdot(v, n) < cpvdot(seg->tn, seg->ta)*coef + seg->r){
|
||||
cpFloat dt = cpvcross(seg->tn, v);
|
||||
if(dta >= dt && dt >= dtb){
|
||||
cpContactInit(nextContactPoint(arr, num), v, n, pDist, CP_HASH_PAIR(poly->shape.hashid, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This one is complicated and gross. Just don't go there...
|
||||
// TODO: Comment me!
|
||||
static int
|
||||
seg2poly(cpShape *shape1, cpShape *shape2, cpContact *arr)
|
||||
{
|
||||
cpSegmentShape *seg = (cpSegmentShape *)shape1;
|
||||
cpPolyShape *poly = (cpPolyShape *)shape2;
|
||||
cpPolyShapeAxis *axes = poly->tAxes;
|
||||
|
||||
cpFloat segD = cpvdot(seg->tn, seg->ta);
|
||||
cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r;
|
||||
cpFloat minNeg = cpPolyShapeValueOnAxis(poly, cpvneg(seg->tn), -segD) - seg->r;
|
||||
if(minNeg > 0.0f || minNorm > 0.0f) return 0;
|
||||
|
||||
int mini = 0;
|
||||
cpFloat poly_min = segValueOnAxis(seg, axes->n, axes->d);
|
||||
if(poly_min > 0.0f) return 0;
|
||||
for(int i=0; i<poly->numVerts; i++){
|
||||
cpFloat dist = segValueOnAxis(seg, axes[i].n, axes[i].d);
|
||||
if(dist > 0.0f){
|
||||
return 0;
|
||||
} else if(dist > poly_min){
|
||||
poly_min = dist;
|
||||
mini = i;
|
||||
}
|
||||
}
|
||||
|
||||
int num = 0;
|
||||
|
||||
cpVect poly_n = cpvneg(axes[mini].n);
|
||||
|
||||
cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r));
|
||||
cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r));
|
||||
if(cpPolyShapeContainsVert(poly, va))
|
||||
cpContactInit(nextContactPoint(arr, &num), va, poly_n, poly_min, CP_HASH_PAIR(seg->shape.hashid, 0));
|
||||
if(cpPolyShapeContainsVert(poly, vb))
|
||||
cpContactInit(nextContactPoint(arr, &num), vb, poly_n, poly_min, CP_HASH_PAIR(seg->shape.hashid, 1));
|
||||
|
||||
// Floating point precision problems here.
|
||||
// This will have to do for now.
|
||||
poly_min -= cp_collision_slop;
|
||||
if(minNorm >= poly_min || minNeg >= poly_min) {
|
||||
if(minNorm > minNeg)
|
||||
findPointsBehindSeg(arr, &num, seg, poly, minNorm, 1.0f);
|
||||
else
|
||||
findPointsBehindSeg(arr, &num, seg, poly, minNeg, -1.0f);
|
||||
}
|
||||
|
||||
// If no other collision points are found, try colliding endpoints.
|
||||
if(num == 0){
|
||||
cpVect poly_a = poly->tVerts[mini];
|
||||
cpVect poly_b = poly->tVerts[(mini + 1)%poly->numVerts];
|
||||
|
||||
if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr))
|
||||
return 1;
|
||||
|
||||
if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr))
|
||||
return 1;
|
||||
|
||||
if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr))
|
||||
return 1;
|
||||
|
||||
if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
// This one is less gross, but still gross.
|
||||
// TODO: Comment me!
|
||||
static int
|
||||
circle2poly(cpShape *shape1, cpShape *shape2, cpContact *con)
|
||||
{
|
||||
cpCircleShape *circ = (cpCircleShape *)shape1;
|
||||
cpPolyShape *poly = (cpPolyShape *)shape2;
|
||||
cpPolyShapeAxis *axes = poly->tAxes;
|
||||
|
||||
int mini = 0;
|
||||
cpFloat min = cpvdot(axes->n, circ->tc) - axes->d - circ->r;
|
||||
for(int i=0; i<poly->numVerts; i++){
|
||||
cpFloat dist = cpvdot(axes[i].n, circ->tc) - axes[i].d - circ->r;
|
||||
if(dist > 0.0f){
|
||||
return 0;
|
||||
} else if(dist > min) {
|
||||
min = dist;
|
||||
mini = i;
|
||||
}
|
||||
}
|
||||
|
||||
cpVect n = axes[mini].n;
|
||||
cpVect a = poly->tVerts[mini];
|
||||
cpVect b = poly->tVerts[(mini + 1)%poly->numVerts];
|
||||
cpFloat dta = cpvcross(n, a);
|
||||
cpFloat dtb = cpvcross(n, b);
|
||||
cpFloat dt = cpvcross(n, circ->tc);
|
||||
|
||||
if(dt < dtb){
|
||||
return circle2circleQuery(circ->tc, b, circ->r, 0.0f, con);
|
||||
} else if(dt < dta) {
|
||||
cpContactInit(
|
||||
con,
|
||||
cpvsub(circ->tc, cpvmult(n, circ->r + min/2.0f)),
|
||||
cpvneg(n),
|
||||
min,
|
||||
0
|
||||
);
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return circle2circleQuery(circ->tc, a, circ->r, 0.0f, con);
|
||||
}
|
||||
}
|
||||
|
||||
//static const collisionFunc builtinCollisionFuncs[9] = {
|
||||
// circle2circle,
|
||||
// NULL,
|
||||
// NULL,
|
||||
// circle2segment,
|
||||
// NULL,
|
||||
// NULL,
|
||||
// circle2poly,
|
||||
// seg2poly,
|
||||
// poly2poly,
|
||||
//};
|
||||
//static const collisionFunc *colfuncs = builtinCollisionFuncs;
|
||||
|
||||
static collisionFunc *colfuncs = NULL;
|
||||
|
||||
static void
|
||||
addColFunc(cpShapeType a, cpShapeType b, collisionFunc func)
|
||||
{
|
||||
colfuncs[a + b*CP_NUM_SHAPES] = func;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void cpInitCollisionFuncs(void);
|
||||
|
||||
// Initializes the array of collision functions.
|
||||
// Called by cpInitChipmunk().
|
||||
void
|
||||
cpInitCollisionFuncs(void)
|
||||
{
|
||||
if(!colfuncs)
|
||||
colfuncs = (collisionFunc *)cpcalloc(CP_NUM_SHAPES*CP_NUM_SHAPES, sizeof(collisionFunc));
|
||||
|
||||
addColFunc(CP_CIRCLE_SHAPE, CP_CIRCLE_SHAPE, circle2circle);
|
||||
addColFunc(CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, circle2segment);
|
||||
addColFunc(CP_SEGMENT_SHAPE, CP_POLY_SHAPE, seg2poly);
|
||||
addColFunc(CP_CIRCLE_SHAPE, CP_POLY_SHAPE, circle2poly);
|
||||
addColFunc(CP_POLY_SHAPE, CP_POLY_SHAPE, poly2poly);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
cpCollideShapes(cpShape *a, 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.");
|
||||
|
||||
collisionFunc cfunc = colfuncs[a->klass->type + b->klass->type*CP_NUM_SHAPES];
|
||||
return (cfunc) ? cfunc(a, b, arr) : 0;
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
/* 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 <assert.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "prime.h"
|
||||
|
||||
static void freeWrap(void *ptr, void *unused){cpfree(ptr);}
|
||||
|
||||
void
|
||||
cpHashSetDestroy(cpHashSet *set)
|
||||
{
|
||||
// Free the table.
|
||||
cpfree(set->table);
|
||||
|
||||
cpArrayEach(set->allocatedBuffers, freeWrap, NULL);
|
||||
cpArrayFree(set->allocatedBuffers);
|
||||
}
|
||||
|
||||
void
|
||||
cpHashSetFree(cpHashSet *set)
|
||||
{
|
||||
if(set){
|
||||
cpHashSetDestroy(set);
|
||||
cpfree(set);
|
||||
}
|
||||
}
|
||||
|
||||
cpHashSet *
|
||||
cpHashSetAlloc(void)
|
||||
{
|
||||
return (cpHashSet *)cpcalloc(1, sizeof(cpHashSet));
|
||||
}
|
||||
|
||||
cpHashSet *
|
||||
cpHashSetInit(cpHashSet *set, int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)
|
||||
{
|
||||
set->size = next_prime(size);
|
||||
set->entries = 0;
|
||||
|
||||
set->eql = eqlFunc;
|
||||
set->trans = trans;
|
||||
|
||||
set->default_value = NULL;
|
||||
|
||||
set->table = (cpHashSetBin **)cpcalloc(set->size, sizeof(cpHashSetBin *));
|
||||
set->pooledBins = NULL;
|
||||
|
||||
set->allocatedBuffers = cpArrayNew(0);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
cpHashSet *
|
||||
cpHashSetNew(int size, cpHashSetEqlFunc eqlFunc, cpHashSetTransFunc trans)
|
||||
{
|
||||
return cpHashSetInit(cpHashSetAlloc(), size, eqlFunc, trans);
|
||||
}
|
||||
|
||||
static int
|
||||
setIsFull(cpHashSet *set)
|
||||
{
|
||||
return (set->entries >= set->size);
|
||||
}
|
||||
|
||||
static void
|
||||
cpHashSetResize(cpHashSet *set)
|
||||
{
|
||||
// Get the next approximate doubled prime.
|
||||
int newSize = next_prime(set->size + 1);
|
||||
// Allocate a new table.
|
||||
cpHashSetBin **newTable = (cpHashSetBin **)cpcalloc(newSize, sizeof(cpHashSetBin *));
|
||||
|
||||
// Iterate over the chains.
|
||||
for(int i=0; i<set->size; i++){
|
||||
// Rehash the bins into the new table.
|
||||
cpHashSetBin *bin = set->table[i];
|
||||
while(bin){
|
||||
cpHashSetBin *next = bin->next;
|
||||
|
||||
int idx = bin->hash%newSize;
|
||||
bin->next = newTable[idx];
|
||||
newTable[idx] = bin;
|
||||
|
||||
bin = next;
|
||||
}
|
||||
}
|
||||
|
||||
cpfree(set->table);
|
||||
|
||||
set->table = newTable;
|
||||
set->size = newSize;
|
||||
}
|
||||
|
||||
static inline void
|
||||
recycleBin(cpHashSet *set, cpHashSetBin *bin)
|
||||
{
|
||||
bin->next = set->pooledBins;
|
||||
set->pooledBins = bin;
|
||||
bin->elt = NULL;
|
||||
}
|
||||
|
||||
static cpHashSetBin *
|
||||
getUnusedBin(cpHashSet *set)
|
||||
{
|
||||
cpHashSetBin *bin = set->pooledBins;
|
||||
|
||||
if(bin){
|
||||
set->pooledBins = bin->next;
|
||||
return bin;
|
||||
} else {
|
||||
// Pool is exhausted, make more
|
||||
int count = CP_BUFFER_BYTES/sizeof(cpHashSetBin);
|
||||
cpAssert(count, "Buffer size is too small.");
|
||||
|
||||
cpHashSetBin *buffer = (cpHashSetBin *)cpmalloc(CP_BUFFER_BYTES);
|
||||
cpArrayPush(set->allocatedBuffers, buffer);
|
||||
|
||||
// push all but the first one, return the first instead
|
||||
for(int i=1; i<count; i++) recycleBin(set, buffer + i);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
cpHashSetInsert(cpHashSet *set, cpHashValue hash, void *ptr, void *data)
|
||||
{
|
||||
int idx = hash%set->size;
|
||||
|
||||
// Find the bin with the matching element.
|
||||
cpHashSetBin *bin = set->table[idx];
|
||||
while(bin && !set->eql(ptr, bin->elt))
|
||||
bin = bin->next;
|
||||
|
||||
// Create it necessary.
|
||||
if(!bin){
|
||||
bin = getUnusedBin(set);
|
||||
bin->hash = hash;
|
||||
bin->elt = set->trans(ptr, data); // Transform the pointer.
|
||||
|
||||
bin->next = set->table[idx];
|
||||
set->table[idx] = bin;
|
||||
|
||||
set->entries++;
|
||||
|
||||
// Resize the set if it's full.
|
||||
if(setIsFull(set))
|
||||
cpHashSetResize(set);
|
||||
}
|
||||
|
||||
return bin->elt;
|
||||
}
|
||||
|
||||
void *
|
||||
cpHashSetRemove(cpHashSet *set, cpHashValue hash, void *ptr)
|
||||
{
|
||||
int idx = hash%set->size;
|
||||
|
||||
// Pointer to the previous bin pointer.
|
||||
cpHashSetBin **prev_ptr = &set->table[idx];
|
||||
// Pointer the the current bin.
|
||||
cpHashSetBin *bin = set->table[idx];
|
||||
|
||||
// Find the bin
|
||||
while(bin && !set->eql(ptr, bin->elt)){
|
||||
prev_ptr = &bin->next;
|
||||
bin = bin->next;
|
||||
}
|
||||
|
||||
// Remove it if it exists.
|
||||
if(bin){
|
||||
// Update the previous bin pointer to point to the next bin.
|
||||
(*prev_ptr) = bin->next;
|
||||
set->entries--;
|
||||
|
||||
void *return_value = bin->elt;
|
||||
|
||||
recycleBin(set, bin);
|
||||
|
||||
return return_value;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
cpHashSetFind(cpHashSet *set, cpHashValue hash, void *ptr)
|
||||
{
|
||||
int idx = hash%set->size;
|
||||
cpHashSetBin *bin = set->table[idx];
|
||||
while(bin && !set->eql(ptr, bin->elt))
|
||||
bin = bin->next;
|
||||
|
||||
return (bin ? bin->elt : set->default_value);
|
||||
}
|
||||
|
||||
void
|
||||
cpHashSetEach(cpHashSet *set, cpHashSetIterFunc func, void *data)
|
||||
{
|
||||
for(int i=0; i<set->size; i++){
|
||||
cpHashSetBin *bin = set->table[i];
|
||||
while(bin){
|
||||
cpHashSetBin *next = bin->next;
|
||||
func(bin->elt, data);
|
||||
bin = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpHashSetFilter(cpHashSet *set, cpHashSetFilterFunc func, void *data)
|
||||
{
|
||||
// Iterate over all the chains.
|
||||
for(int i=0; i<set->size; i++){
|
||||
// The rest works similarly to cpHashSetRemove() above.
|
||||
cpHashSetBin **prev_ptr = &set->table[i];
|
||||
cpHashSetBin *bin = set->table[i];
|
||||
while(bin){
|
||||
cpHashSetBin *next = bin->next;
|
||||
|
||||
if(func(bin->elt, data)){
|
||||
prev_ptr = &bin->next;
|
||||
} else {
|
||||
(*prev_ptr) = next;
|
||||
|
||||
set->entries--;
|
||||
recycleBin(set, bin);
|
||||
}
|
||||
|
||||
bin = next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
/* 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 <stdio.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "chipmunk_unsafe.h"
|
||||
|
||||
cpPolyShape *
|
||||
cpPolyShapeAlloc(void)
|
||||
{
|
||||
return (cpPolyShape *)cpcalloc(1, sizeof(cpPolyShape));
|
||||
}
|
||||
|
||||
static void
|
||||
cpPolyShapeTransformVerts(cpPolyShape *poly, cpVect p, cpVect rot)
|
||||
{
|
||||
cpVect *src = poly->verts;
|
||||
cpVect *dst = poly->tVerts;
|
||||
|
||||
for(int i=0; i<poly->numVerts; i++)
|
||||
dst[i] = cpvadd(p, cpvrotate(src[i], rot));
|
||||
}
|
||||
|
||||
static void
|
||||
cpPolyShapeTransformAxes(cpPolyShape *poly, cpVect p, cpVect rot)
|
||||
{
|
||||
cpPolyShapeAxis *src = poly->axes;
|
||||
cpPolyShapeAxis *dst = poly->tAxes;
|
||||
|
||||
for(int i=0; i<poly->numVerts; i++){
|
||||
cpVect n = cpvrotate(src[i].n, rot);
|
||||
dst[i].n = n;
|
||||
dst[i].d = cpvdot(p, n) + src[i].d;
|
||||
}
|
||||
}
|
||||
|
||||
static cpBB
|
||||
cpPolyShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
|
||||
{
|
||||
cpPolyShape *poly = (cpPolyShape *)shape;
|
||||
|
||||
cpFloat l, b, r, t;
|
||||
|
||||
cpPolyShapeTransformAxes(poly, p, rot);
|
||||
cpPolyShapeTransformVerts(poly, p, rot);
|
||||
|
||||
cpVect *verts = poly->tVerts;
|
||||
l = r = verts[0].x;
|
||||
b = t = verts[0].y;
|
||||
|
||||
// TODO do as part of cpPolyShapeTransformVerts?
|
||||
for(int i=1; i<poly->numVerts; i++){
|
||||
cpVect v = verts[i];
|
||||
|
||||
l = cpfmin(l, v.x);
|
||||
r = cpfmax(r, v.x);
|
||||
|
||||
b = cpfmin(b, v.y);
|
||||
t = cpfmax(t, v.y);
|
||||
}
|
||||
|
||||
return cpBBNew(l, b, r, t);
|
||||
}
|
||||
|
||||
static void
|
||||
cpPolyShapeDestroy(cpShape *shape)
|
||||
{
|
||||
cpPolyShape *poly = (cpPolyShape *)shape;
|
||||
|
||||
cpfree(poly->verts);
|
||||
cpfree(poly->tVerts);
|
||||
|
||||
cpfree(poly->axes);
|
||||
cpfree(poly->tAxes);
|
||||
}
|
||||
|
||||
static int
|
||||
cpPolyShapePointQuery(cpShape *shape, cpVect p){
|
||||
return cpBBcontainsVect(shape->bb, p) && cpPolyShapeContainsVert((cpPolyShape *)shape, p);
|
||||
}
|
||||
|
||||
static void
|
||||
cpPolyShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
|
||||
{
|
||||
cpPolyShape *poly = (cpPolyShape *)shape;
|
||||
cpPolyShapeAxis *axes = poly->tAxes;
|
||||
cpVect *verts = poly->tVerts;
|
||||
int numVerts = poly->numVerts;
|
||||
|
||||
for(int i=0; i<numVerts; i++){
|
||||
cpVect n = axes[i].n;
|
||||
cpFloat an = cpvdot(a, n);
|
||||
if(axes[i].d > an) continue;
|
||||
|
||||
cpFloat bn = cpvdot(b, n);
|
||||
cpFloat t = (axes[i].d - an)/(bn - an);
|
||||
if(t < 0.0f || 1.0f < t) continue;
|
||||
|
||||
cpVect point = cpvlerp(a, b, t);
|
||||
cpFloat dt = -cpvcross(n, point);
|
||||
cpFloat dtMin = -cpvcross(n, verts[i]);
|
||||
cpFloat dtMax = -cpvcross(n, verts[(i+1)%numVerts]);
|
||||
|
||||
if(dtMin <= dt && dt <= dtMax){
|
||||
info->shape = shape;
|
||||
info->t = t;
|
||||
info->n = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const cpShapeClass polyClass = {
|
||||
CP_POLY_SHAPE,
|
||||
cpPolyShapeCacheData,
|
||||
cpPolyShapeDestroy,
|
||||
cpPolyShapePointQuery,
|
||||
cpPolyShapeSegmentQuery,
|
||||
};
|
||||
|
||||
int
|
||||
cpPolyValidate(cpVect *verts, int numVerts)
|
||||
{
|
||||
for(int i=0; i<numVerts; i++){
|
||||
cpVect a = verts[i];
|
||||
cpVect b = verts[(i+1)%numVerts];
|
||||
cpVect c = verts[(i+2)%numVerts];
|
||||
|
||||
if(cpvcross(cpvsub(b, a), cpvsub(c, b)) > 0.0f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
cpPolyShapeGetNumVerts(cpShape *shape)
|
||||
{
|
||||
cpAssert(shape->klass == &polyClass, "Shape is not a poly shape.");
|
||||
return ((cpPolyShape *)shape)->numVerts;
|
||||
}
|
||||
|
||||
cpVect
|
||||
cpPolyShapeGetVert(cpShape *shape, int idx)
|
||||
{
|
||||
cpAssert(shape->klass == &polyClass, "Shape is not a poly shape.");
|
||||
cpAssert(0 <= idx && idx < cpPolyShapeGetNumVerts(shape), "Index out of range.");
|
||||
|
||||
return ((cpPolyShape *)shape)->verts[idx];
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
setUpVerts(cpPolyShape *poly, int numVerts, cpVect *verts, cpVect offset)
|
||||
{
|
||||
poly->numVerts = numVerts;
|
||||
|
||||
poly->verts = (cpVect *)cpcalloc(numVerts, sizeof(cpVect));
|
||||
poly->tVerts = (cpVect *)cpcalloc(numVerts, sizeof(cpVect));
|
||||
poly->axes = (cpPolyShapeAxis *)cpcalloc(numVerts, sizeof(cpPolyShapeAxis));
|
||||
poly->tAxes = (cpPolyShapeAxis *)cpcalloc(numVerts, sizeof(cpPolyShapeAxis));
|
||||
|
||||
for(int i=0; i<numVerts; i++){
|
||||
cpVect a = cpvadd(offset, verts[i]);
|
||||
cpVect b = cpvadd(offset, verts[(i+1)%numVerts]);
|
||||
cpVect n = cpvnormalize(cpvperp(cpvsub(b, a)));
|
||||
|
||||
poly->verts[i] = a;
|
||||
poly->axes[i].n = n;
|
||||
poly->axes[i].d = cpvdot(n, a);
|
||||
}
|
||||
}
|
||||
|
||||
cpPolyShape *
|
||||
cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, cpVect *verts, cpVect offset)
|
||||
{
|
||||
// Fail if the user attempts to pass a concave poly, or a bad winding.
|
||||
cpAssert(cpPolyValidate(verts, numVerts), "Polygon is concave or has a reversed winding.");
|
||||
|
||||
setUpVerts(poly, numVerts, verts, offset);
|
||||
cpShapeInit((cpShape *)poly, &polyClass, body);
|
||||
|
||||
return poly;
|
||||
}
|
||||
|
||||
cpShape *
|
||||
cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset)
|
||||
{
|
||||
return (cpShape *)cpPolyShapeInit(cpPolyShapeAlloc(), body, numVerts, verts, offset);
|
||||
}
|
||||
|
||||
cpPolyShape *
|
||||
cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height)
|
||||
{
|
||||
cpFloat hw = width/2;
|
||||
cpFloat hh = height/2;
|
||||
|
||||
cpVect verts[] = {
|
||||
cpv(-hw,-hh),
|
||||
cpv(-hw, hh),
|
||||
cpv( hw, hh),
|
||||
cpv( hw,-hh),
|
||||
};
|
||||
|
||||
return cpPolyShapeInit(poly, body, 4, verts, cpvzero);
|
||||
}
|
||||
|
||||
cpShape *
|
||||
cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height)
|
||||
{
|
||||
return (cpShape *)cpBoxShapeInit(cpPolyShapeAlloc(), body, width, height);
|
||||
}
|
||||
|
||||
// Unsafe API (chipmunk_unsafe.h)
|
||||
|
||||
void
|
||||
cpPolyShapeSetVerts(cpShape *shape, int numVerts, cpVect *verts, cpVect offset)
|
||||
{
|
||||
cpAssert(shape->klass == &polyClass, "Shape is not a poly shape.");
|
||||
cpPolyShapeDestroy(shape);
|
||||
setUpVerts((cpPolyShape *)shape, numVerts, verts, offset);
|
||||
}
|
|
@ -0,0 +1,400 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "chipmunk_unsafe.h"
|
||||
|
||||
#define CP_DefineShapeGetter(struct, type, member, name) \
|
||||
CP_DeclareShapeGetter(struct, type, name){ \
|
||||
cpAssert(shape->klass == &struct##Class, "shape is not a "#struct); \
|
||||
return ((struct *)shape)->member; \
|
||||
}
|
||||
cpHashValue SHAPE_ID_COUNTER = 0;
|
||||
|
||||
void
|
||||
cpResetShapeIdCounter(void)
|
||||
{
|
||||
SHAPE_ID_COUNTER = 0;
|
||||
}
|
||||
|
||||
|
||||
cpShape*
|
||||
cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
|
||||
{
|
||||
shape->klass = klass;
|
||||
|
||||
shape->hashid = SHAPE_ID_COUNTER;
|
||||
SHAPE_ID_COUNTER++;
|
||||
|
||||
shape->body = body;
|
||||
shape->sensor = 0;
|
||||
|
||||
shape->e = 0.0f;
|
||||
shape->u = 0.0f;
|
||||
shape->surface_v = cpvzero;
|
||||
|
||||
shape->collision_type = 0;
|
||||
shape->group = CP_NO_GROUP;
|
||||
shape->layers = CP_ALL_LAYERS;
|
||||
|
||||
shape->data = NULL;
|
||||
|
||||
cpShapeCacheBB(shape);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
void
|
||||
cpShapeDestroy(cpShape *shape)
|
||||
{
|
||||
if(shape->klass->destroy) shape->klass->destroy(shape);
|
||||
}
|
||||
|
||||
void
|
||||
cpShapeFree(cpShape *shape)
|
||||
{
|
||||
if(shape){
|
||||
cpShapeDestroy(shape);
|
||||
cpfree(shape);
|
||||
}
|
||||
}
|
||||
|
||||
cpBB
|
||||
cpShapeCacheBB(cpShape *shape)
|
||||
{
|
||||
cpBody *body = shape->body;
|
||||
|
||||
shape->bb = shape->klass->cacheData(shape, body->p, body->rot);
|
||||
return shape->bb;
|
||||
}
|
||||
|
||||
int
|
||||
cpShapePointQuery(cpShape *shape, cpVect p){
|
||||
return shape->klass->pointQuery(shape, p);
|
||||
}
|
||||
|
||||
int
|
||||
cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){
|
||||
cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero};
|
||||
(*info) = blank;
|
||||
|
||||
shape->klass->segmentQuery(shape, a, b, info);
|
||||
return (info->shape != NULL);
|
||||
}
|
||||
|
||||
void
|
||||
cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info)
|
||||
{
|
||||
printf("Segment Query:\n");
|
||||
printf("\tt: %f\n", info->t);
|
||||
// printf("\tdist: %f\n", info->dist);
|
||||
// printf("\tpoint: %s\n", cpvstr(info->point));
|
||||
printf("\tn: %s\n", cpvstr(info->n));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
cpCircleShape *
|
||||
cpCircleShapeAlloc(void)
|
||||
{
|
||||
return (cpCircleShape *)cpcalloc(1, sizeof(cpCircleShape));
|
||||
}
|
||||
|
||||
static inline cpBB
|
||||
bbFromCircle(const cpVect c, const cpFloat r)
|
||||
{
|
||||
return cpBBNew(c.x-r, c.y-r, c.x+r, c.y+r);
|
||||
}
|
||||
|
||||
static cpBB
|
||||
cpCircleShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
|
||||
{
|
||||
cpCircleShape *circle = (cpCircleShape *)shape;
|
||||
|
||||
circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
|
||||
return bbFromCircle(circle->tc, circle->r);
|
||||
}
|
||||
|
||||
static int
|
||||
cpCircleShapePointQuery(cpShape *shape, cpVect p){
|
||||
cpCircleShape *circle = (cpCircleShape *)shape;
|
||||
return cpvnear(circle->tc, p, circle->r);
|
||||
}
|
||||
|
||||
static void
|
||||
circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b, cpSegmentQueryInfo *info)
|
||||
{
|
||||
// umm... gross I normally frown upon such things
|
||||
a = cpvsub(a, center);
|
||||
b = 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 det = qb*qb - 4.0f*qa*qc;
|
||||
|
||||
if(det >= 0.0f){
|
||||
cpFloat t = (-qb - cpfsqrt(det))/(2.0f*qa);
|
||||
if(0.0f<= t && t <= 1.0f){
|
||||
info->shape = shape;
|
||||
info->t = t;
|
||||
info->n = cpvnormalize(cpvlerp(a, b, t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cpCircleShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
|
||||
{
|
||||
cpCircleShape *circle = (cpCircleShape *)shape;
|
||||
circleSegmentQuery(shape, circle->tc, circle->r, a, b, info);
|
||||
}
|
||||
|
||||
static const cpShapeClass cpCircleShapeClass = {
|
||||
CP_CIRCLE_SHAPE,
|
||||
cpCircleShapeCacheData,
|
||||
NULL,
|
||||
cpCircleShapePointQuery,
|
||||
cpCircleShapeSegmentQuery,
|
||||
};
|
||||
|
||||
cpCircleShape *
|
||||
cpCircleShapeInit(cpCircleShape *circle, cpBody *body, cpFloat radius, cpVect offset)
|
||||
{
|
||||
circle->c = offset;
|
||||
circle->r = radius;
|
||||
|
||||
cpShapeInit((cpShape *)circle, &cpCircleShapeClass, body);
|
||||
|
||||
return circle;
|
||||
}
|
||||
|
||||
cpShape *
|
||||
cpCircleShapeNew(cpBody *body, cpFloat radius, cpVect offset)
|
||||
{
|
||||
return (cpShape *)cpCircleShapeInit(cpCircleShapeAlloc(), body, radius, offset);
|
||||
}
|
||||
|
||||
CP_DefineShapeGetter(cpCircleShape, cpVect, c, Offset)
|
||||
CP_DefineShapeGetter(cpCircleShape, cpFloat, r, Radius)
|
||||
|
||||
cpSegmentShape *
|
||||
cpSegmentShapeAlloc(void)
|
||||
{
|
||||
return (cpSegmentShape *)cpcalloc(1, sizeof(cpSegmentShape));
|
||||
}
|
||||
|
||||
static cpBB
|
||||
cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
|
||||
{
|
||||
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
||||
|
||||
seg->ta = cpvadd(p, cpvrotate(seg->a, rot));
|
||||
seg->tb = cpvadd(p, cpvrotate(seg->b, rot));
|
||||
seg->tn = cpvrotate(seg->n, rot);
|
||||
|
||||
cpFloat l,r,s,t;
|
||||
|
||||
if(seg->ta.x < seg->tb.x){
|
||||
l = seg->ta.x;
|
||||
r = seg->tb.x;
|
||||
} else {
|
||||
l = seg->tb.x;
|
||||
r = seg->ta.x;
|
||||
}
|
||||
|
||||
if(seg->ta.y < seg->tb.y){
|
||||
s = seg->ta.y;
|
||||
t = seg->tb.y;
|
||||
} else {
|
||||
s = seg->tb.y;
|
||||
t = seg->ta.y;
|
||||
}
|
||||
|
||||
cpFloat rad = seg->r;
|
||||
return cpBBNew(l - rad, s - rad, r + rad, t + rad);
|
||||
}
|
||||
|
||||
static int
|
||||
cpSegmentShapePointQuery(cpShape *shape, cpVect p){
|
||||
if(!cpBBcontainsVect(shape->bb, p)) return 0;
|
||||
|
||||
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
||||
|
||||
// Calculate normal distance from segment.
|
||||
cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
|
||||
cpFloat dist = cpfabs(dn) - seg->r;
|
||||
if(dist > 0.0f) return 0;
|
||||
|
||||
// Calculate tangential distance along segment.
|
||||
cpFloat dt = -cpvcross(seg->tn, p);
|
||||
cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
|
||||
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
|
||||
|
||||
// Decision tree to decide which feature of the segment to collide with.
|
||||
if(dt <= dtMin){
|
||||
if(dt < (dtMin - seg->r)){
|
||||
return 0;
|
||||
} else {
|
||||
return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
|
||||
}
|
||||
} else {
|
||||
if(dt < dtMax){
|
||||
return 1;
|
||||
} else {
|
||||
if(dt < (dtMax + seg->r)) {
|
||||
return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info)
|
||||
{
|
||||
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
||||
cpVect n = seg->tn;
|
||||
// flip n if a is behind the axis
|
||||
if(cpvdot(a, n) < cpvdot(seg->ta, n))
|
||||
n = cpvneg(n);
|
||||
|
||||
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(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;
|
||||
circleSegmentQuery(shape, seg->ta, seg->r, a, b, &info1);
|
||||
circleSegmentQuery(shape, seg->tb, seg->r, a, b, &info2);
|
||||
|
||||
if(info1.shape && !info2.shape){
|
||||
(*info) = info1;
|
||||
} else if(info2.shape && !info1.shape){
|
||||
(*info) = info2;
|
||||
} else if(info1.shape && info2.shape){
|
||||
if(info1.t < info2.t){
|
||||
(*info) = info1;
|
||||
} else {
|
||||
(*info) = info2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const cpShapeClass cpSegmentShapeClass = {
|
||||
CP_SEGMENT_SHAPE,
|
||||
cpSegmentShapeCacheData,
|
||||
NULL,
|
||||
cpSegmentShapePointQuery,
|
||||
cpSegmentShapeSegmentQuery,
|
||||
};
|
||||
|
||||
cpSegmentShape *
|
||||
cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloat r)
|
||||
{
|
||||
seg->a = a;
|
||||
seg->b = b;
|
||||
seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));
|
||||
|
||||
seg->r = r;
|
||||
|
||||
cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body);
|
||||
|
||||
return seg;
|
||||
}
|
||||
|
||||
cpShape*
|
||||
cpSegmentShapeNew(cpBody *body, cpVect a, cpVect b, cpFloat r)
|
||||
{
|
||||
return (cpShape *)cpSegmentShapeInit(cpSegmentShapeAlloc(), body, a, b, r);
|
||||
}
|
||||
|
||||
CP_DefineShapeGetter(cpSegmentShape, cpVect, a, A)
|
||||
CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B)
|
||||
CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal)
|
||||
CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius)
|
||||
|
||||
// Unsafe API (chipmunk_unsafe.h)
|
||||
|
||||
void
|
||||
cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)
|
||||
{
|
||||
cpAssert(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
|
||||
cpCircleShape *circle = (cpCircleShape *)shape;
|
||||
|
||||
circle->r = radius;
|
||||
}
|
||||
|
||||
void
|
||||
cpCircleShapeSetOffset(cpShape *shape, cpVect offset)
|
||||
{
|
||||
cpAssert(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
|
||||
cpCircleShape *circle = (cpCircleShape *)shape;
|
||||
|
||||
circle->c = offset;
|
||||
}
|
||||
|
||||
void
|
||||
cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)
|
||||
{
|
||||
cpAssert(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
|
||||
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
||||
|
||||
seg->a = a;
|
||||
seg->b = b;
|
||||
seg->n = cpvperp(cpvnormalize(cpvsub(b, a)));
|
||||
}
|
||||
|
||||
void
|
||||
cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius)
|
||||
{
|
||||
cpAssert(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
|
||||
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
||||
|
||||
seg->r = radius;
|
||||
}
|
|
@ -0,0 +1,899 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
int cp_contact_persistence = 1;
|
||||
|
||||
#pragma mark Contact Set Helpers
|
||||
|
||||
// Equal function for contactSet.
|
||||
static int
|
||||
contactSetEql(cpShape **shapes, cpArbiter *arb)
|
||||
{
|
||||
cpShape *a = shapes[0];
|
||||
cpShape *b = shapes[1];
|
||||
|
||||
return ((a == arb->private_a && b == arb->private_b) || (b == arb->private_a && a == arb->private_b));
|
||||
}
|
||||
|
||||
// Transformation function for contactSet.
|
||||
static void *
|
||||
contactSetTrans(cpShape **shapes, cpSpace *space)
|
||||
{
|
||||
if(space->pooledArbiters->num == 0){
|
||||
// arbiter pool is exhausted, make more
|
||||
int count = CP_BUFFER_BYTES/sizeof(cpArbiter);
|
||||
cpAssert(count, "Buffer size too small.");
|
||||
|
||||
cpArbiter *buffer = (cpArbiter *)cpmalloc(CP_BUFFER_BYTES);
|
||||
cpArrayPush(space->allocatedBuffers, buffer);
|
||||
|
||||
for(int i=0; i<count; i++) cpArrayPush(space->pooledArbiters, buffer + i);
|
||||
}
|
||||
|
||||
return cpArbiterInit( (cpArbiter *)cpArrayPop(space->pooledArbiters), shapes[0], shapes[1]);
|
||||
}
|
||||
|
||||
#pragma mark Collision Pair Function Helpers
|
||||
|
||||
// Equals function for collFuncSet.
|
||||
static int
|
||||
collFuncSetEql(cpCollisionHandler *check, cpCollisionHandler *pair)
|
||||
{
|
||||
return ((check->a == pair->a && check->b == pair->b) || (check->b == pair->a && check->a == pair->b));
|
||||
}
|
||||
|
||||
// Transformation function for collFuncSet.
|
||||
static void *
|
||||
collFuncSetTrans(cpCollisionHandler *handler, void *unused)
|
||||
{
|
||||
cpCollisionHandler *copy = (cpCollisionHandler *)cpmalloc(sizeof(cpCollisionHandler));
|
||||
(*copy) = (*handler);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
#pragma mark Post Step Function Helpers
|
||||
|
||||
typedef struct postStepCallback {
|
||||
cpPostStepFunc func;
|
||||
void *obj;
|
||||
void *data;
|
||||
} postStepCallback;
|
||||
|
||||
static int
|
||||
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.
|
||||
static int alwaysCollide(cpArbiter *arb, cpSpace *space, void *data){return 1;}
|
||||
static void nothing(cpArbiter *arb, cpSpace *space, void *data){}
|
||||
|
||||
// BBfunc callback for the spatial hash.
|
||||
static cpBB shapeBBFunc(cpShape *shape){return shape->bb;}
|
||||
|
||||
// Iterator functions for destructors.
|
||||
static void freeWrap(void *ptr, void *unused){ cpfree(ptr);}
|
||||
static void shapeFreeWrap(cpShape *ptr, void *unused){ cpShapeFree(ptr);}
|
||||
static void bodyFreeWrap(cpBody *ptr, void *unused){ cpBodyFree(ptr);}
|
||||
static void constraintFreeWrap(cpConstraint *ptr, void *unused){cpConstraintFree(ptr);}
|
||||
|
||||
#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)
|
||||
{
|
||||
return (cpSpace *)cpcalloc(1, sizeof(cpSpace));
|
||||
}
|
||||
|
||||
#define DEFAULT_DIM_SIZE 100.0f
|
||||
#define DEFAULT_COUNT 1000
|
||||
#define DEFAULT_ITERATIONS 10
|
||||
#define DEFAULT_ELASTIC_ITERATIONS 0
|
||||
|
||||
#define MAX_CONTACTS 10000
|
||||
|
||||
cpCollisionHandler defaultHandler = {0, 0, alwaysCollide, alwaysCollide, nothing, nothing, NULL};
|
||||
|
||||
cpSpace*
|
||||
cpSpaceInit(cpSpace *space)
|
||||
{
|
||||
space->iterations = DEFAULT_ITERATIONS;
|
||||
space->elasticIterations = DEFAULT_ELASTIC_ITERATIONS;
|
||||
// space->sleepTicks = 300;
|
||||
|
||||
space->gravity = cpvzero;
|
||||
space->damping = 1.0f;
|
||||
|
||||
space->locked = 0;
|
||||
space->stamp = 0;
|
||||
|
||||
space->staticShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
|
||||
space->activeShapes = cpSpaceHashNew(DEFAULT_DIM_SIZE, DEFAULT_COUNT, (cpSpaceHashBBFunc)shapeBBFunc);
|
||||
|
||||
space->allocatedBuffers = cpArrayNew(0);
|
||||
|
||||
space->bodies = cpArrayNew(0);
|
||||
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->contactSet = cpHashSetNew(0, (cpHashSetEqlFunc)contactSetEql, (cpHashSetTransFunc)contactSetTrans);
|
||||
|
||||
space->constraints = cpArrayNew(0);
|
||||
|
||||
space->defaultHandler = defaultHandler;
|
||||
space->collFuncSet = cpHashSetNew(0, (cpHashSetEqlFunc)collFuncSetEql, (cpHashSetTransFunc)collFuncSetTrans);
|
||||
space->collFuncSet->default_value = &space->defaultHandler;
|
||||
|
||||
space->postStepCallbacks = cpHashSetNew(0, (cpHashSetEqlFunc)postStepFuncSetEql, (cpHashSetTransFunc)postStepFuncSetTrans);
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
cpSpace*
|
||||
cpSpaceNew(void)
|
||||
{
|
||||
return cpSpaceInit(cpSpaceAlloc());
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceDestroy(cpSpace *space)
|
||||
{
|
||||
cpSpaceHashFree(space->staticShapes);
|
||||
cpSpaceHashFree(space->activeShapes);
|
||||
|
||||
cpArrayFree(space->bodies);
|
||||
|
||||
cpArrayFree(space->constraints);
|
||||
|
||||
cpHashSetFree(space->contactSet);
|
||||
|
||||
cpArrayFree(space->arbiters);
|
||||
cpArrayFree(space->pooledArbiters);
|
||||
|
||||
if(space->allocatedBuffers){
|
||||
cpArrayEach(space->allocatedBuffers, freeWrap, NULL);
|
||||
cpArrayFree(space->allocatedBuffers);
|
||||
}
|
||||
|
||||
if(space->postStepCallbacks){
|
||||
cpHashSetEach(space->postStepCallbacks, freeWrap, NULL);
|
||||
cpHashSetFree(space->postStepCallbacks);
|
||||
}
|
||||
|
||||
if(space->collFuncSet){
|
||||
cpHashSetEach(space->collFuncSet, freeWrap, NULL);
|
||||
cpHashSetFree(space->collFuncSet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceFree(cpSpace *space)
|
||||
{
|
||||
if(space){
|
||||
cpSpaceDestroy(space);
|
||||
cpfree(space);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceFreeChildren(cpSpace *space)
|
||||
{
|
||||
cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
|
||||
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)&shapeFreeWrap, NULL);
|
||||
cpArrayEach(space->bodies, (cpArrayIter)&bodyFreeWrap, NULL);
|
||||
cpArrayEach(space->constraints, (cpArrayIter)&constraintFreeWrap, NULL);
|
||||
}
|
||||
|
||||
#pragma mark Collision Handler Function Management
|
||||
|
||||
void
|
||||
cpSpaceAddCollisionHandler(
|
||||
cpSpace *space,
|
||||
cpCollisionType a, cpCollisionType b,
|
||||
cpCollisionBeginFunc begin,
|
||||
cpCollisionPreSolveFunc preSolve,
|
||||
cpCollisionPostSolveFunc postSolve,
|
||||
cpCollisionSeparateFunc separate,
|
||||
void *data
|
||||
){
|
||||
// Remove any old function so the new one will get added.
|
||||
cpSpaceRemoveCollisionHandler(space, a, b);
|
||||
|
||||
cpCollisionHandler handler = {
|
||||
a, b,
|
||||
begin ? begin : alwaysCollide,
|
||||
preSolve ? preSolve : alwaysCollide,
|
||||
postSolve ? postSolve : nothing,
|
||||
separate ? separate : nothing,
|
||||
data
|
||||
};
|
||||
|
||||
cpHashSetInsert(space->collFuncSet, CP_HASH_PAIR(a, b), &handler, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceRemoveCollisionHandler(cpSpace *space, cpCollisionType a, cpCollisionType b)
|
||||
{
|
||||
struct{cpCollisionType a, b;} ids = {a, b};
|
||||
cpCollisionHandler *old_handler = (cpCollisionHandler *) cpHashSetRemove(space->collFuncSet, CP_HASH_PAIR(a, b), &ids);
|
||||
cpfree(old_handler);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceSetDefaultCollisionHandler(
|
||||
cpSpace *space,
|
||||
cpCollisionBeginFunc begin,
|
||||
cpCollisionPreSolveFunc preSolve,
|
||||
cpCollisionPostSolveFunc postSolve,
|
||||
cpCollisionSeparateFunc separate,
|
||||
void *data
|
||||
){
|
||||
cpCollisionHandler handler = {
|
||||
0, 0,
|
||||
begin ? begin : alwaysCollide,
|
||||
preSolve ? preSolve : alwaysCollide,
|
||||
postSolve ? postSolve : nothing,
|
||||
separate ? separate : nothing,
|
||||
data
|
||||
};
|
||||
|
||||
space->defaultHandler = handler;
|
||||
}
|
||||
|
||||
#pragma mark Body, Shape, and Joint Management
|
||||
|
||||
#define cpAssertSpaceUnlocked(space) \
|
||||
cpAssert(!space->locked, \
|
||||
"This addition/removal cannot be done safely during a call to cpSpaceStep(). " \
|
||||
"Put these calls into a Post Step Callback." \
|
||||
);
|
||||
|
||||
cpShape *
|
||||
cpSpaceAddShape(cpSpace *space, cpShape *shape)
|
||||
{
|
||||
cpAssert(shape->body, "Cannot add a shape with a NULL body.");
|
||||
cpAssert(!cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
|
||||
"Cannot add the same shape more than once.");
|
||||
cpAssertSpaceUnlocked(space);
|
||||
|
||||
cpSpaceHashInsert(space->activeShapes, shape, shape->hashid, shape->bb);
|
||||
return shape;
|
||||
}
|
||||
|
||||
cpShape *
|
||||
cpSpaceAddStaticShape(cpSpace *space, cpShape *shape)
|
||||
{
|
||||
cpAssert(shape->body, "Cannot add a static shape with a NULL body.");
|
||||
cpAssert(!cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
|
||||
"Cannot add the same static shape more than once.");
|
||||
cpAssertSpaceUnlocked(space);
|
||||
|
||||
cpShapeCacheBB(shape);
|
||||
cpSpaceHashInsert(space->staticShapes, shape, shape->hashid, shape->bb);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
cpBody *
|
||||
cpSpaceAddBody(cpSpace *space, cpBody *body)
|
||||
{
|
||||
cpAssert(!cpArrayContains(space->bodies, body), "Cannot add the same body more than once.");
|
||||
// cpAssertSpaceUnlocked(space); This should be safe as long as it's not from an integration callback
|
||||
|
||||
cpArrayPush(space->bodies, body);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
cpConstraint *
|
||||
cpSpaceAddConstraint(cpSpace *space, cpConstraint *constraint)
|
||||
{
|
||||
cpAssert(!cpArrayContains(space->constraints, constraint), "Cannot add the same constraint more than once.");
|
||||
// cpAssertSpaceUnlocked(space); This should be safe as long as its not from a constraint callback.
|
||||
|
||||
cpArrayPush(space->constraints, constraint);
|
||||
|
||||
return constraint;
|
||||
}
|
||||
|
||||
typedef struct removalContext {
|
||||
cpSpace *space;
|
||||
cpShape *shape;
|
||||
} removalContext;
|
||||
|
||||
// Hashset filter func to throw away old arbiters.
|
||||
static int
|
||||
contactSetFilterRemovedShape(cpArbiter *arb, removalContext *context)
|
||||
{
|
||||
if(context->shape == arb->private_a || context->shape == arb->private_b){
|
||||
arb->handler->separate(arb, context->space, arb->handler->data);
|
||||
cpArrayPush(context->space->pooledArbiters, arb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceRemoveShape(cpSpace *space, cpShape *shape)
|
||||
{
|
||||
cpAssertWarn(cpHashSetFind(space->activeShapes->handleSet, shape->hashid, shape),
|
||||
"Cannot remove a shape that was never added to the space. (Removed twice maybe?)");
|
||||
cpAssertSpaceUnlocked(space);
|
||||
|
||||
removalContext context = {space, shape};
|
||||
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
|
||||
cpSpaceHashRemove(space->activeShapes, shape, shape->hashid);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceRemoveStaticShape(cpSpace *space, cpShape *shape)
|
||||
{
|
||||
cpAssertWarn(cpHashSetFind(space->staticShapes->handleSet, shape->hashid, shape),
|
||||
"Cannot remove a static shape that was never added to the space. (Removed twice maybe?)");
|
||||
cpAssertSpaceUnlocked(space);
|
||||
|
||||
removalContext context = {space, shape};
|
||||
cpHashSetFilter(space->contactSet, (cpHashSetFilterFunc)contactSetFilterRemovedShape, &context);
|
||||
cpSpaceHashRemove(space->staticShapes, shape, shape->hashid);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceRemoveBody(cpSpace *space, cpBody *body)
|
||||
{
|
||||
cpAssertWarn(cpArrayContains(space->bodies, body),
|
||||
"Cannot remove a body that was never added to the space. (Removed twice maybe?)");
|
||||
cpAssertSpaceUnlocked(space);
|
||||
|
||||
cpArrayDeleteObj(space->bodies, body);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceRemoveConstraint(cpSpace *space, cpConstraint *constraint)
|
||||
{
|
||||
cpAssertWarn(cpArrayContains(space->constraints, constraint),
|
||||
"Cannot remove a constraint that was never added to the space. (Removed twice maybe?)");
|
||||
// cpAssertSpaceUnlocked(space); Should be safe as long as its not from a constraint callback.
|
||||
|
||||
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;
|
||||
int 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 = 1;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
int
|
||||
cpSpaceSegmentQuery(cpSpace *space, cpVect start, cpVect end, cpLayers layers, cpGroup group, cpSpaceSegmentQueryFunc func, void *data)
|
||||
{
|
||||
segQueryContext context = {
|
||||
start, end,
|
||||
layers, group,
|
||||
func,
|
||||
0,
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceResizeStaticHash(cpSpace *space, cpFloat dim, int count)
|
||||
{
|
||||
cpSpaceHashResize(space->staticShapes, dim, count);
|
||||
cpSpaceHashRehash(space->staticShapes);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceResizeActiveHash(cpSpace *space, cpFloat dim, int count)
|
||||
{
|
||||
cpSpaceHashResize(space->activeShapes, dim, count);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceRehashStatic(cpSpace *space)
|
||||
{
|
||||
cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)&updateBBCache, NULL);
|
||||
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)
|
||||
{
|
||||
// for(cpContactBuffer *buffer = space->contactBuffersTail; buffer != space->contactBuffersHead; buffer = buffer->next){
|
||||
// printf("%p -> ", buffer);
|
||||
// }
|
||||
// printf("%p (head)\n", space->contactBuffersHead);
|
||||
|
||||
cpContactBufferHeader *buffer = cpSpaceGetFreeContactBuffer(space);
|
||||
space->contactBuffersHead->next = buffer;
|
||||
space->contactBuffersHead = buffer;
|
||||
}
|
||||
|
||||
static inline int
|
||||
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);
|
||||
|
||||
int 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->stamp == -1 && !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 {
|
||||
// cpfree(arb->contacts);
|
||||
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 int
|
||||
contactSetFilter(cpArbiter *arb, cpSpace *space)
|
||||
{
|
||||
int ticks = space->stamp - arb->stamp;
|
||||
|
||||
// was used last frame, but not this one
|
||||
if(ticks == 1){
|
||||
arb->handler->separate(arb, space, arb->handler->data);
|
||||
arb->stamp = -1; // mark it as a new pair again.
|
||||
}
|
||||
|
||||
if(ticks >= cp_contact_persistence){
|
||||
cpArrayPush(space->pooledArbiters, arb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Hashset filter func to call and throw away post step callbacks.
|
||||
static int
|
||||
postStepCallbackSetFilter(postStepCallback *callback, cpSpace *space)
|
||||
{
|
||||
callback->func(space, callback->obj, callback->data);
|
||||
cpfree(callback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark All Important cpSpaceStep() Function
|
||||
|
||||
void
|
||||
cpSpaceStep(cpSpace *space, cpFloat dt)
|
||||
{
|
||||
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 = 1;
|
||||
|
||||
// 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);
|
||||
cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)active2staticIter, space);
|
||||
cpSpaceHashQueryRehash(space->activeShapes, (cpSpaceHashQueryFunc)queryFunc, space);
|
||||
|
||||
// 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 = 0;
|
||||
|
||||
// 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
|
||||
// Use filter as an easy way to clear out the queue as it runs
|
||||
cpHashSetFilter(space->postStepCallbacks, (cpHashSetFilterFunc)postStepCallbackSetFilter, space);
|
||||
|
||||
// cpFloat dvsq = cpvdot(space->gravity, space->gravity);
|
||||
// dvsq *= dt*dt * space->damping*space->damping;
|
||||
// for(int i=0; i<bodies->num; i++)
|
||||
// cpBodyMarkLowEnergy(bodies->arr[i], dvsq, space->sleepTicks);
|
||||
|
||||
// Increment the stamp.
|
||||
space->stamp++;
|
||||
}
|
|
@ -0,0 +1,541 @@
|
|||
/* 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 <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
#include "prime.h"
|
||||
|
||||
static cpHandle*
|
||||
cpHandleInit(cpHandle *hand, void *obj)
|
||||
{
|
||||
hand->obj = obj;
|
||||
hand->retain = 0;
|
||||
hand->stamp = 0;
|
||||
|
||||
return hand;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cpHandleRetain(cpHandle *hand)
|
||||
{
|
||||
hand->retain++;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cpHandleRelease(cpHandle *hand, cpArray *pooledHandles)
|
||||
{
|
||||
hand->retain--;
|
||||
if(hand->retain == 0) cpArrayPush(pooledHandles, hand);
|
||||
}
|
||||
|
||||
cpSpaceHash*
|
||||
cpSpaceHashAlloc(void)
|
||||
{
|
||||
return (cpSpaceHash *)cpcalloc(1, sizeof(cpSpaceHash));
|
||||
}
|
||||
|
||||
// Frees the old table, and allocates a new one.
|
||||
static void
|
||||
cpSpaceHashAllocTable(cpSpaceHash *hash, int numcells)
|
||||
{
|
||||
cpfree(hash->table);
|
||||
|
||||
hash->numcells = numcells;
|
||||
hash->table = (cpSpaceHashBin **)cpcalloc(numcells, sizeof(cpSpaceHashBin *));
|
||||
}
|
||||
|
||||
// Equality function for the handleset.
|
||||
static int
|
||||
handleSetEql(void *obj, void *elt)
|
||||
{
|
||||
cpHandle *hand = (cpHandle *)elt;
|
||||
return (obj == hand->obj);
|
||||
}
|
||||
|
||||
// Transformation function for the handleset.
|
||||
static void *
|
||||
handleSetTrans(void *obj, cpSpaceHash *hash)
|
||||
{
|
||||
if(hash->pooledHandles->num == 0){
|
||||
// handle pool is exhausted, make more
|
||||
int count = CP_BUFFER_BYTES/sizeof(cpHandle);
|
||||
cpAssert(count, "Buffer size is too small.");
|
||||
|
||||
cpHandle *buffer = (cpHandle *)cpmalloc(CP_BUFFER_BYTES);
|
||||
cpArrayPush(hash->allocatedBuffers, buffer);
|
||||
|
||||
for(int i=0; i<count; i++) cpArrayPush(hash->pooledHandles, buffer + i);
|
||||
}
|
||||
|
||||
cpHandle *hand = cpHandleInit((cpHandle *) cpArrayPop(hash->pooledHandles), obj);
|
||||
cpHandleRetain(hand);
|
||||
|
||||
return hand;
|
||||
}
|
||||
|
||||
cpSpaceHash*
|
||||
cpSpaceHashInit(cpSpaceHash *hash, cpFloat celldim, int numcells, cpSpaceHashBBFunc bbfunc)
|
||||
{
|
||||
cpSpaceHashAllocTable(hash, next_prime(numcells));
|
||||
hash->celldim = celldim;
|
||||
hash->bbfunc = bbfunc;
|
||||
|
||||
hash->handleSet = cpHashSetNew(0, handleSetEql, (cpHashSetTransFunc)handleSetTrans);
|
||||
hash->pooledHandles = cpArrayNew(0);
|
||||
|
||||
hash->pooledBins = NULL;
|
||||
hash->allocatedBuffers = cpArrayNew(0);
|
||||
|
||||
hash->stamp = 1;
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
cpSpaceHash*
|
||||
cpSpaceHashNew(cpFloat celldim, int cells, cpSpaceHashBBFunc bbfunc)
|
||||
{
|
||||
return cpSpaceHashInit(cpSpaceHashAlloc(), celldim, cells, bbfunc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
recycleBin(cpSpaceHash *hash, cpSpaceHashBin *bin)
|
||||
{
|
||||
bin->next = hash->pooledBins;
|
||||
hash->pooledBins = bin;
|
||||
}
|
||||
|
||||
static inline void
|
||||
clearHashCell(cpSpaceHash *hash, int idx)
|
||||
{
|
||||
cpSpaceHashBin *bin = hash->table[idx];
|
||||
while(bin){
|
||||
cpSpaceHashBin *next = bin->next;
|
||||
|
||||
// Release the lock on the handle.
|
||||
cpHandleRelease(bin->handle, hash->pooledHandles);
|
||||
recycleBin(hash, bin);
|
||||
|
||||
bin = next;
|
||||
}
|
||||
|
||||
hash->table[idx] = NULL;
|
||||
}
|
||||
|
||||
// Clear all cells in the hashtable.
|
||||
static void
|
||||
clearHash(cpSpaceHash *hash)
|
||||
{
|
||||
for(int i=0; i<hash->numcells; i++)
|
||||
clearHashCell(hash, i);
|
||||
}
|
||||
|
||||
static void freeWrap(void *ptr, void *unused){cpfree(ptr);}
|
||||
|
||||
void
|
||||
cpSpaceHashDestroy(cpSpaceHash *hash)
|
||||
{
|
||||
clearHash(hash);
|
||||
|
||||
cpHashSetFree(hash->handleSet);
|
||||
|
||||
cpArrayEach(hash->allocatedBuffers, freeWrap, NULL);
|
||||
cpArrayFree(hash->allocatedBuffers);
|
||||
cpArrayFree(hash->pooledHandles);
|
||||
|
||||
cpfree(hash->table);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashFree(cpSpaceHash *hash)
|
||||
{
|
||||
if(hash){
|
||||
cpSpaceHashDestroy(hash);
|
||||
cpfree(hash);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashResize(cpSpaceHash *hash, cpFloat celldim, int numcells)
|
||||
{
|
||||
// Clear the hash to release the old handle locks.
|
||||
clearHash(hash);
|
||||
|
||||
hash->celldim = celldim;
|
||||
cpSpaceHashAllocTable(hash, next_prime(numcells));
|
||||
}
|
||||
|
||||
// Return true if the chain contains the handle.
|
||||
static inline int
|
||||
containsHandle(cpSpaceHashBin *bin, cpHandle *hand)
|
||||
{
|
||||
while(bin){
|
||||
if(bin->handle == hand) return 1;
|
||||
bin = bin->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get a recycled or new bin.
|
||||
static inline cpSpaceHashBin *
|
||||
getEmptyBin(cpSpaceHash *hash)
|
||||
{
|
||||
cpSpaceHashBin *bin = hash->pooledBins;
|
||||
|
||||
if(bin){
|
||||
hash->pooledBins = bin->next;
|
||||
return bin;
|
||||
} else {
|
||||
// Pool is exhausted, make more
|
||||
int count = CP_BUFFER_BYTES/sizeof(cpSpaceHashBin);
|
||||
cpAssert(count, "Buffer size is too small.");
|
||||
|
||||
cpSpaceHashBin *buffer = (cpSpaceHashBin *)cpmalloc(CP_BUFFER_BYTES);
|
||||
cpArrayPush(hash->allocatedBuffers, buffer);
|
||||
|
||||
// push all but the first one, return the first instead
|
||||
for(int i=1; i<count; i++) recycleBin(hash, buffer + i);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
// The hash function itself.
|
||||
static inline cpHashValue
|
||||
hash_func(cpHashValue x, cpHashValue y, cpHashValue n)
|
||||
{
|
||||
return (x*1640531513ul ^ y*2654435789ul) % n;
|
||||
}
|
||||
|
||||
// Much faster than (int)floor(f)
|
||||
// Profiling showed floor() to be a sizable performance hog
|
||||
static inline int
|
||||
floor_int(cpFloat f)
|
||||
{
|
||||
int i = (int)f;
|
||||
return (f < 0.0f && f != i ? i - 1 : i);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hashHandle(cpSpaceHash *hash, cpHandle *hand, cpBB bb)
|
||||
{
|
||||
// Find the dimensions in cell coordinates.
|
||||
cpFloat dim = hash->celldim;
|
||||
int l = floor_int(bb.l/dim); // Fix by ShiftZ
|
||||
int r = floor_int(bb.r/dim);
|
||||
int b = floor_int(bb.b/dim);
|
||||
int t = floor_int(bb.t/dim);
|
||||
|
||||
int n = hash->numcells;
|
||||
for(int i=l; i<=r; i++){
|
||||
for(int j=b; j<=t; j++){
|
||||
int idx = hash_func(i,j,n);
|
||||
cpSpaceHashBin *bin = hash->table[idx];
|
||||
|
||||
// Don't add an object twice to the same cell.
|
||||
if(containsHandle(bin, hand)) continue;
|
||||
|
||||
cpHandleRetain(hand);
|
||||
// Insert a new bin for the handle in this cell.
|
||||
cpSpaceHashBin *newBin = getEmptyBin(hash);
|
||||
newBin->handle = hand;
|
||||
newBin->next = bin;
|
||||
hash->table[idx] = newBin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashInsert(cpSpaceHash *hash, void *obj, cpHashValue hashid, cpBB bb)
|
||||
{
|
||||
cpHandle *hand = (cpHandle *)cpHashSetInsert(hash->handleSet, hashid, obj, hash);
|
||||
hashHandle(hash, hand, bb);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
hashHandle(hash, hand, hash->bbfunc(hand->obj));
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashRehash(cpSpaceHash *hash)
|
||||
{
|
||||
clearHash(hash);
|
||||
|
||||
// Rehash all of the handles.
|
||||
cpHashSetEach(hash->handleSet, &handleRehashHelper, hash);
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashRemove(cpSpaceHash *hash, void *obj, cpHashValue hashid)
|
||||
{
|
||||
cpHandle *hand = (cpHandle *)cpHashSetRemove(hash->handleSet, hashid, obj);
|
||||
|
||||
if(hand){
|
||||
hand->obj = NULL;
|
||||
cpHandleRelease(hand, hash->pooledHandles);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Calls the callback function for the objects in a given chain.
|
||||
static inline void
|
||||
query(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashQueryFunc func, void *data)
|
||||
{
|
||||
for(; 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
|
||||
// Is obj the same as other?
|
||||
|| obj == other
|
||||
// Has other been removed since the last rehash?
|
||||
|| !other
|
||||
) continue;
|
||||
|
||||
func(obj, other, data);
|
||||
|
||||
// Stamp that the handle was checked already against this object.
|
||||
hand->stamp = hash->stamp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashPointQuery(cpSpaceHash *hash, cpVect point, cpSpaceHashQueryFunc func, void *data)
|
||||
{
|
||||
cpFloat dim = hash->celldim;
|
||||
int idx = hash_func(floor_int(point.x/dim), floor_int(point.y/dim), hash->numcells); // Fix by ShiftZ
|
||||
|
||||
query(hash, hash->table[idx], &point, func, data);
|
||||
|
||||
// Increment the stamp.
|
||||
// Only one cell is checked, but query() requires it anyway.
|
||||
hash->stamp++;
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashQuery(cpSpaceHash *hash, void *obj, cpBB bb, cpSpaceHashQueryFunc func, void *data)
|
||||
{
|
||||
// Get the dimensions in cell coordinates.
|
||||
cpFloat dim = hash->celldim;
|
||||
int l = floor_int(bb.l/dim); // Fix by ShiftZ
|
||||
int r = floor_int(bb.r/dim);
|
||||
int b = floor_int(bb.b/dim);
|
||||
int t = floor_int(bb.t/dim);
|
||||
|
||||
int n = hash->numcells;
|
||||
|
||||
// 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, hash->table[idx], obj, func, data);
|
||||
}
|
||||
}
|
||||
|
||||
// Increment the stamp.
|
||||
hash->stamp++;
|
||||
}
|
||||
|
||||
// Similar to struct eachPair above.
|
||||
typedef struct queryRehashPair {
|
||||
cpSpaceHash *hash;
|
||||
cpSpaceHashQueryFunc func;
|
||||
void *data;
|
||||
} queryRehashPair;
|
||||
|
||||
// Hashset iterator func used with cpSpaceHashQueryRehash().
|
||||
static void
|
||||
handleQueryRehashHelper(void *elt, void *data)
|
||||
{
|
||||
cpHandle *hand = (cpHandle *)elt;
|
||||
|
||||
// Unpack the user callback data.
|
||||
queryRehashPair *pair = (queryRehashPair *)data;
|
||||
cpSpaceHash *hash = pair->hash;
|
||||
cpSpaceHashQueryFunc func = pair->func;
|
||||
|
||||
cpFloat dim = hash->celldim;
|
||||
int n = hash->numcells;
|
||||
|
||||
void *obj = hand->obj;
|
||||
cpBB bb = hash->bbfunc(obj);
|
||||
|
||||
int l = floor_int(bb.l/dim);
|
||||
int r = floor_int(bb.r/dim);
|
||||
int b = floor_int(bb.b/dim);
|
||||
int t = floor_int(bb.t/dim);
|
||||
|
||||
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 = hash->table[idx];
|
||||
|
||||
if(containsHandle(bin, hand)) continue;
|
||||
|
||||
cpHandleRetain(hand); // this MUST be done first in case the object is removed in func()
|
||||
query(hash, bin, obj, func, pair->data);
|
||||
|
||||
cpSpaceHashBin *newBin = getEmptyBin(hash);
|
||||
newBin->handle = hand;
|
||||
newBin->next = bin;
|
||||
hash->table[idx] = newBin;
|
||||
}
|
||||
}
|
||||
|
||||
// break_out:
|
||||
// Increment the stamp for each object we hash.
|
||||
hash->stamp++;
|
||||
}
|
||||
|
||||
void
|
||||
cpSpaceHashQueryRehash(cpSpaceHash *hash, cpSpaceHashQueryFunc func, void *data)
|
||||
{
|
||||
clearHash(hash);
|
||||
|
||||
queryRehashPair pair = {hash, func, data};
|
||||
cpHashSetEach(hash->handleSet, &handleQueryRehashHelper, &pair);
|
||||
}
|
||||
|
||||
static inline cpFloat
|
||||
segmentQuery(cpSpaceHash *hash, cpSpaceHashBin *bin, void *obj, cpSpaceHashSegmentQueryFunc func, void *data)
|
||||
{
|
||||
cpFloat t = 1.0f;
|
||||
|
||||
for(; 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));
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
// modified from http://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
|
||||
void cpSpaceHashSegmentQuery(cpSpaceHash *hash, void *obj, cpVect a, cpVect b, cpFloat t_exit, cpSpaceHashSegmentQueryFunc func, void *data)
|
||||
{
|
||||
a = cpvmult(a, 1.0f/hash->celldim);
|
||||
b = cpvmult(b, 1.0f/hash->celldim);
|
||||
|
||||
cpFloat dt_dx = 1.0f/cpfabs(b.x - a.x), dt_dy = 1.0f/cpfabs(b.y - a.y);
|
||||
|
||||
int cell_x = floor_int(a.x), cell_y = floor_int(a.y);
|
||||
|
||||
cpFloat t = 0;
|
||||
|
||||
int x_inc, y_inc;
|
||||
cpFloat temp_v, temp_h;
|
||||
|
||||
if (b.x > a.x){
|
||||
x_inc = 1;
|
||||
temp_h = (cpffloor(a.x + 1.0f) - a.x);
|
||||
} else {
|
||||
x_inc = -1;
|
||||
temp_h = (a.x - cpffloor(a.x));
|
||||
}
|
||||
|
||||
if (b.y > a.y){
|
||||
y_inc = 1;
|
||||
temp_v = (cpffloor(a.y + 1.0f) - a.y);
|
||||
} else {
|
||||
y_inc = -1;
|
||||
temp_v = (a.y - cpffloor(a.y));
|
||||
}
|
||||
|
||||
// fix NANs in horizontal directions
|
||||
cpFloat next_h = (temp_h ? temp_h*dt_dx : dt_dx);
|
||||
cpFloat next_v = (temp_v ? temp_v*dt_dy : dt_dy);
|
||||
|
||||
int n = hash->numcells;
|
||||
while(t < t_exit){
|
||||
int idx = hash_func(cell_x, cell_y, n);
|
||||
t_exit = cpfmin(t_exit, segmentQuery(hash, hash->table[idx], obj, func, data));
|
||||
|
||||
if (next_v < next_h){
|
||||
cell_y += y_inc;
|
||||
t = next_v;
|
||||
next_v += dt_dy;
|
||||
} else {
|
||||
cell_x += x_inc;
|
||||
t = next_h;
|
||||
next_h += dt_dx;
|
||||
}
|
||||
}
|
||||
|
||||
hash->stamp++;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/* 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 <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "chipmunk.h"
|
||||
|
||||
cpFloat
|
||||
cpvlength(const cpVect v)
|
||||
{
|
||||
return cpfsqrt( cpvdot(v, v) );
|
||||
}
|
||||
|
||||
inline cpVect
|
||||
cpvslerp(const cpVect v1, const cpVect v2, const cpFloat t)
|
||||
{
|
||||
cpFloat omega = cpfacos(cpvdot(v1, v2));
|
||||
|
||||
if(omega){
|
||||
cpFloat denom = 1.0f/cpfsin(omega);
|
||||
return cpvadd(cpvmult(v1, cpfsin((1.0f - t)*omega)*denom), cpvmult(v2, cpfsin(t*omega)*denom));
|
||||
} else {
|
||||
return v1;
|
||||
}
|
||||
}
|
||||
|
||||
cpVect
|
||||
cpvslerpconst(const cpVect v1, const cpVect v2, const cpFloat a)
|
||||
{
|
||||
cpFloat angle = cpfacos(cpvdot(v1, v2));
|
||||
return cpvslerp(v1, v2, cpfmin(a, angle)/angle);
|
||||
}
|
||||
|
||||
cpVect
|
||||
cpvforangle(const cpFloat a)
|
||||
{
|
||||
return cpv(cpfcos(a), cpfsin(a));
|
||||
}
|
||||
|
||||
cpFloat
|
||||
cpvtoangle(const cpVect v)
|
||||
{
|
||||
return cpfatan2(v.y, v.x);
|
||||
}
|
||||
|
||||
char*
|
||||
cpvstr(const cpVect v)
|
||||
{
|
||||
static char str[256];
|
||||
sprintf(str, "(% .3f, % .3f)", v.x, v.y);
|
||||
return str;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
// Used for resizing hash tables.
|
||||
// Values approximately double.
|
||||
// http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
|
||||
static int primes[] = {
|
||||
5,
|
||||
13,
|
||||
23,
|
||||
47,
|
||||
97,
|
||||
193,
|
||||
389,
|
||||
769,
|
||||
1543,
|
||||
3079,
|
||||
6151,
|
||||
12289,
|
||||
24593,
|
||||
49157,
|
||||
98317,
|
||||
196613,
|
||||
393241,
|
||||
786433,
|
||||
1572869,
|
||||
3145739,
|
||||
6291469,
|
||||
12582917,
|
||||
25165843,
|
||||
50331653,
|
||||
100663319,
|
||||
201326611,
|
||||
402653189,
|
||||
805306457,
|
||||
1610612741,
|
||||
0,
|
||||
};
|
||||
|
||||
static inline int
|
||||
next_prime(int n)
|
||||
{
|
||||
int i = 0;
|
||||
while(n > primes[i]){
|
||||
i++;
|
||||
cpAssert(primes[i], "Tried to resize a hash table to a size greater than 1610612741 O_o"); // realistically this should never happen
|
||||
}
|
||||
|
||||
return primes[i];
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
|
||||
/*!
|
||||
* @file NewDeleteOp.cpp
|
||||
* @author 全智达
|
||||
* @brief
|
||||
*
|
||||
* @section Copyright
|
||||
* =======================================================================<br>
|
||||
* <br>
|
||||
* Copyright (c) 2005-2010 Tranzda Technologies Co.,Ltd. <br>
|
||||
* 深圳市全智达科技有限公司 版权所有2005-2010<br>
|
||||
* <br>
|
||||
* PROPRIETARY RIGHTS of Tranzda Technologies Co.,Ltd. are involved in <br>
|
||||
* the subject matter of this material. All manufacturing, reproduction, <br>
|
||||
* use, and sales rights pertaining to this subject matter are governed <br>
|
||||
* by the license agreement. The recipient of this software implicitly <br>
|
||||
* accepts the terms of the license. <br>
|
||||
* 本软件文档资料是深圳市全智达科技有限公司的合法资产,任何人士阅读和使<br>
|
||||
* 用本资料必须获得相应的书面授权,承担保密责任和接受相应的法律约束。<br>
|
||||
* <br>
|
||||
* 公司网址:<a href="http://www.tranzda.com"> http://www.tranzda.com </a> <br>
|
||||
* 公司邮箱:<a mailto="support@tranzda.com">support@tranzda.com</a> <br>
|
||||
* =======================================================================<br>
|
||||
*/
|
||||
|
||||
#include "ssTypes.h"
|
||||
#include "TG3_Type.h"
|
||||
#include "TG3_Memory.h"
|
||||
|
||||
#ifdef new
|
||||
#undef new
|
||||
#endif
|
||||
|
||||
#ifdef delete
|
||||
#undef delete
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#define __cdecl
|
||||
#endif
|
||||
|
||||
void * __cdecl operator new(unsigned int size)
|
||||
{
|
||||
return TMalloc(size);
|
||||
}
|
||||
|
||||
void * __cdecl operator new[](unsigned int size)
|
||||
{
|
||||
return TMalloc(size);
|
||||
}
|
||||
|
||||
void * __cdecl operator new(unsigned int size, const unsigned short * fileName, int lineNo)
|
||||
{
|
||||
return TMallocEx(size, fileName, lineNo);
|
||||
}
|
||||
|
||||
void * __cdecl operator new[](unsigned int size, const unsigned short * fileName, int lineNo)
|
||||
{
|
||||
return TMallocEx(size, fileName, lineNo);
|
||||
}
|
||||
|
||||
void __cdecl operator delete(void *p)
|
||||
{
|
||||
TFree(p);
|
||||
}
|
||||
|
||||
void __cdecl operator delete[](void *p)
|
||||
{
|
||||
TFree(p);
|
||||
}
|
||||
|
||||
void __cdecl operator delete(void *p, const unsigned short * fileName, int lineNo)
|
||||
{
|
||||
TFreeEx(p, fileName, lineNo);
|
||||
}
|
||||
|
||||
void __cdecl operator delete[](void *p, const unsigned short * fileName, int lineNo)
|
||||
{
|
||||
TFreeEx(p, fileName, lineNo);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
#include "ssGlobal.h"
|
||||
#include "ssTsd.h"
|
||||
#include "TG3_Type.h"
|
||||
#include <stdio.h>
|
||||
#include "TCOM.h"
|
||||
#include "ssAppMgr.h"
|
||||
#include "TG3AppDllEntry.h"
|
||||
|
||||
#ifdef __TCOM_SUPPORT__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//实现TCOM所需要的DLL函数
|
||||
|
||||
//DLL提供的获取指定CLSID的指定接口
|
||||
SS_EXPORT HRESULT TDllGetClassObject(TREFCLSID rclsid, TREFIID riid, LPVOID * ppv);
|
||||
|
||||
//DLL提供的查询DLL能否被Unload
|
||||
SS_EXPORT HRESULT TDllCanUnloadNow(void);
|
||||
|
||||
//DLL提供的把DLL的TCOM信息加入到注册表
|
||||
SS_EXPORT HRESULT TDllRegisterServer(void);
|
||||
|
||||
//DLL提供的把DLL的TCOM信息从注册表中删除
|
||||
SS_EXPORT HRESULT TDllUnregisterServer(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __TCOM_OUTPUT_DEBUG_INFO__
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
//TCOM实现中需要用到的函数和数据
|
||||
|
||||
//实例对象被引用的次数
|
||||
static Int32 __TCOM_ClsidInstanceRefCount;
|
||||
|
||||
//ClassFactory被Locked的次数
|
||||
static Int32 __TCOM_CalssFactoryLockedCount;
|
||||
|
||||
//做必要的初始化
|
||||
static Int32 __TCOM_Init()
|
||||
{
|
||||
__TCOM_ClsidInstanceRefCount = 0;
|
||||
__TCOM_CalssFactoryLockedCount = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//做必要的清除工作
|
||||
static Int32 __TCOM_DeInit()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//DLL全局使用:增加对象实例被引用次数
|
||||
Int32 TCOM_AddClsidInstanceRefCount()
|
||||
{
|
||||
__TCOM_ClsidInstanceRefCount++;
|
||||
#ifdef __TCOM_OUTPUT_DEBUG_INFO__
|
||||
SS_printf("[TCOM_SYSTEM] TCOM_AddClsidInstanceRefCount: address: %p, value: %d.\n",
|
||||
&__TCOM_ClsidInstanceRefCount, __TCOM_ClsidInstanceRefCount);
|
||||
#endif
|
||||
if(__TCOM_ClsidInstanceRefCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return __TCOM_ClsidInstanceRefCount;
|
||||
}
|
||||
|
||||
//DLL全局使用:减少对象实例被引用次数
|
||||
Int32 TCOM_DecClsidInstanceRefCount()
|
||||
{
|
||||
__TCOM_ClsidInstanceRefCount--;
|
||||
#ifdef __TCOM_OUTPUT_DEBUG_INFO__
|
||||
SS_printf("[TCOM_SYSTEM] TCOM_DecClsidInstanceRefCount: address: %p, value: %d.\n",
|
||||
&__TCOM_ClsidInstanceRefCount, __TCOM_ClsidInstanceRefCount);
|
||||
#endif
|
||||
if(__TCOM_ClsidInstanceRefCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return __TCOM_ClsidInstanceRefCount;
|
||||
}
|
||||
|
||||
//DLL全局使用:增加ClassFactory被Locked的次数
|
||||
Int32 TCOM_AddCalssFactoryLockedCount()
|
||||
{
|
||||
__TCOM_CalssFactoryLockedCount++;
|
||||
#ifdef __TCOM_OUTPUT_DEBUG_INFO__
|
||||
SS_printf("[TCOM_SYSTEM] TCOM_AddCalssFactoryLockedCount: address: %p, value: %d.\n",
|
||||
&__TCOM_CalssFactoryLockedCount, __TCOM_CalssFactoryLockedCount);
|
||||
#endif
|
||||
if(__TCOM_CalssFactoryLockedCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return __TCOM_CalssFactoryLockedCount;
|
||||
}
|
||||
|
||||
//DLL全局使用:减少ClassFactory被Locked的次数
|
||||
Int32 TCOM_DecCalssFactoryLockedCount()
|
||||
{
|
||||
__TCOM_CalssFactoryLockedCount--;
|
||||
#ifdef __TCOM_OUTPUT_DEBUG_INFO__
|
||||
SS_printf("[TCOM_SYSTEM] TCOM_DecCalssFactoryLockedCount: address: %p, value: %d.\n",
|
||||
&__TCOM_CalssFactoryLockedCount, __TCOM_CalssFactoryLockedCount);
|
||||
#endif
|
||||
if(__TCOM_CalssFactoryLockedCount <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return __TCOM_CalssFactoryLockedCount;
|
||||
}
|
||||
|
||||
//实现TCOM所需要的DLL函数
|
||||
|
||||
//DLL提供的获取指定CLSID的指定接口
|
||||
SS_EXPORT HRESULT TDllGetClassObject(TREFCLSID rclsid, TREFIID riid, LPVOID * ppv)
|
||||
{
|
||||
return TCOM_Srv_GetClassObject(rclsid, riid, ppv);
|
||||
}
|
||||
|
||||
//DLL提供的查询DLL能否被Unload
|
||||
SS_EXPORT HRESULT TDllCanUnloadNow(void)
|
||||
{
|
||||
#ifdef __TCOM_OUTPUT_DEBUG_INFO__
|
||||
SS_printf("[TCOM_SYSTEM] TDllCanUnloadNow: address1: %p, address2: %p, value1: %d, value2: %d.\n",
|
||||
&__TCOM_ClsidInstanceRefCount, &__TCOM_CalssFactoryLockedCount, __TCOM_ClsidInstanceRefCount,
|
||||
__TCOM_CalssFactoryLockedCount);
|
||||
#endif
|
||||
if((__TCOM_ClsidInstanceRefCount <= 0) && (__TCOM_CalssFactoryLockedCount <= 0))
|
||||
return TCOM_S_TRUE;
|
||||
return TCOM_S_FALSE;
|
||||
}
|
||||
|
||||
//DLL提供的把DLL的TCOM信息加入到注册表
|
||||
SS_EXPORT HRESULT TDllRegisterServer(void)
|
||||
{
|
||||
return TCOM_Srv_RegisterServer();
|
||||
}
|
||||
|
||||
//DLL提供的把DLL的TCOM信息从注册表中删除
|
||||
SS_EXPORT HRESULT TDllUnregisterServer(void)
|
||||
{
|
||||
return TCOM_Srv_UnregisterServer();
|
||||
}
|
||||
|
||||
#endif //__TCOM_SUPPORT__
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef SS_MAKEDLL
|
||||
#error Error!!! SS_MAKEDLL Must defined!
|
||||
#endif
|
||||
|
||||
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
//进程加载动态库进行的操作
|
||||
#ifdef __TCOM_SUPPORT__
|
||||
__TCOM_Init();
|
||||
#endif
|
||||
break;
|
||||
case DLL_THREAD_ATTACH:
|
||||
//线程加载动态库进行的操作
|
||||
break;
|
||||
case DLL_THREAD_DETACH:
|
||||
//线程卸载动态库进行的操作
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
//进程卸载动态库进行的操作
|
||||
#ifdef __TCOM_SUPPORT__
|
||||
__TCOM_DeInit();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#else //linux
|
||||
|
||||
#ifndef SS_SHARED
|
||||
#error Error!!! SS_SHARED Must defined!
|
||||
#endif
|
||||
|
||||
void __attribute((constructor)) TG3_Dll_Attach()
|
||||
{
|
||||
//进程加载动态库进行的操作
|
||||
#ifdef __TCOM_SUPPORT__
|
||||
__TCOM_Init();
|
||||
#endif
|
||||
}
|
||||
|
||||
void __attribute((destructor)) TG3_Dll_Detach()
|
||||
{
|
||||
//进程卸载动态库进行的操作
|
||||
#ifdef __TCOM_SUPPORT__
|
||||
__TCOM_DeInit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//如果不是作为TG3的动态库应用,请在VC项目中和TMK3文件中定义 __TG3_PURE_DLL__ 宏
|
||||
#ifndef __TG3_PURE_DLL__
|
||||
|
||||
//动态库应用使用的统一导出名字的入口函数
|
||||
SS_EXPORT Int32 TDllTG3AppMain(const TUChar * pAppID, UInt32 nCmd, void * pCmdParam)
|
||||
{
|
||||
Int32 retValue;
|
||||
|
||||
//初始化TCOM
|
||||
TCoInitialize(NULL);
|
||||
|
||||
retValue = TG3AppMain(pAppID, nCmd, pCmdParam);
|
||||
|
||||
//释放TCOM
|
||||
TCoUninitialize();
|
||||
|
||||
return retValue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
#ifndef __TG3_APP_DLL_ENTRY_H__
|
||||
#define __TG3_APP_DLL_ENTRY_H__
|
||||
|
||||
#ifndef __cplusplus
|
||||
#error This file need C++ support
|
||||
#endif
|
||||
|
||||
#if TG3_APP_ENTRY_MINIMUM_VERSION > 200
|
||||
#error Please replace TG3AppDllEntry.h and TG3AppDllEntry.cpp to newest version!
|
||||
#endif
|
||||
|
||||
#ifdef __TCOM_SUPPORT__
|
||||
|
||||
#include "TCOM.h"
|
||||
|
||||
//提供给DLL实现者调用的函数,用于在全局记录实例和ClassFactory被引用的次数,
|
||||
//这两个计数影响DLL是否可能被从内存中卸载,请大家在实例中内部实现计数的同时更新全局计数,
|
||||
//否则DLL很有可能会在实例还存在的时候被系统自动强制卸载
|
||||
|
||||
//DLL全局使用:增加对象实例被引用次数
|
||||
Int32 TCOM_AddClsidInstanceRefCount();
|
||||
|
||||
//DLL全局使用:减少对象实例被引用次数
|
||||
Int32 TCOM_DecClsidInstanceRefCount();
|
||||
|
||||
//DLL全局使用:增加ClassFactory被Locked的次数
|
||||
Int32 TCOM_AddCalssFactoryLockedCount();
|
||||
|
||||
//DLL全局使用:减少ClassFactory被Locked的次数
|
||||
Int32 TCOM_DecCalssFactoryLockedCount();
|
||||
|
||||
|
||||
//应用DLL在支持TCOM的时候提供给导出函数使用的函数
|
||||
|
||||
//应用根据给出的CLSID和ClassFactory接口IID返回ClassFactory的接口
|
||||
//返回值:参考TCOM_S_系列宏定义
|
||||
HRESULT TCOM_Srv_GetClassObject(TREFCLSID rclsid, TREFIID riid, LPVOID * ppv);
|
||||
|
||||
//应用提供的把TCOM信息加入到注册表
|
||||
//返回值:参考TCOM_S_系列宏定义
|
||||
HRESULT TCOM_Srv_RegisterServer(void);
|
||||
|
||||
//应用提供的把TCOM信息从注册表中删除
|
||||
//返回值:参考TCOM_S_系列宏定义
|
||||
HRESULT TCOM_Srv_UnregisterServer(void);
|
||||
|
||||
#endif //__TCOM_SUPPORT__
|
||||
|
||||
#endif //__TG3_APP_DLL_ENTRY_H__
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Unicode string resource scrip file,DOT NOT include it.
|
||||
|
||||
// Original file name: chipmunkUnicodeScript.h
|
||||
// Generated by TOPS Builder:Project wizard,Date:2010-09-03
|
||||
|
||||
|
||||
|
||||
#define TZD_CONV(x, y)
|
||||
TZD_CONV(AppName_chipmunk, "chipmunk")
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
// Unicode string resource file
|
||||
|
||||
// Original file name: chipmunkUnicodeScript_str.h
|
||||
// Generated by TOPS Builder:Project wizard,Date:2010-09-03
|
||||
|
||||
|
||||
#ifndef __chipmunk_STR_STR_H__
|
||||
#define __chipmunk_STR_STR_H__
|
||||
|
||||
|
||||
#define AppName_chipmunk__N \
|
||||
"A\x00p\x00p\x00_\x00T\x00\x65\x00s\x00t\x00"
|
||||
#define AppName_chipmunk__C \
|
||||
AppName_chipmunk__N"\x00\x00"
|
||||
#define AppName_chipmunk \
|
||||
((const unsigned short *)(AppName_chipmunk__C))
|
||||
#define AppName_chipmunk__N16 \
|
||||
0x0041,0x0070,0x0070,0x005f,0x0054,0x0065,0x0073,0x0074
|
||||
#define AppName_chipmunk_16 \
|
||||
{AppName_chipmunk__N16,0x0000}
|
||||
// Ôʼ´®ÐÅÏ¢£º
|
||||
// chipmunk
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -6,6 +6,7 @@ EndProject
|
|||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_uphone", "test_uphone\test_uphone.vcproj", "{33819ACD-9774-4E68-AFBE-7A88BBA7B19D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{6AC43F51-A036-4653-B910-BDDC346D15E7} = {6AC43F51-A036-4653-B910-BDDC346D15E7}
|
||||
{BA00DDF7-0F25-4C1E-B012-FA230C1F6463} = {BA00DDF7-0F25-4C1E-B012-FA230C1F6463}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_sprite", "test_sprite\test_sprite.vcproj", "{E67615DB-B3DF-4AC5-B3CF-C1E8EAE99626}"
|
||||
|
@ -18,6 +19,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HelloWorld", "HelloWorld\He
|
|||
{6AC43F51-A036-4653-B910-BDDC346D15E7} = {6AC43F51-A036-4653-B910-BDDC346D15E7}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chipmunk", "chipmunk\chipmunk.vcproj", "{BA00DDF7-0F25-4C1E-B012-FA230C1F6463}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
|
@ -40,6 +43,10 @@ Global
|
|||
{90D08657-A80A-41CD-8AAC-3A3DC8C33041}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{90D08657-A80A-41CD-8AAC-3A3DC8C33041}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{90D08657-A80A-41CD-8AAC-3A3DC8C33041}.Release|Win32.Build.0 = Release|Win32
|
||||
{BA00DDF7-0F25-4C1E-B012-FA230C1F6463}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{BA00DDF7-0F25-4C1E-B012-FA230C1F6463}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{BA00DDF7-0F25-4C1E-B012-FA230C1F6463}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{BA00DDF7-0F25-4C1E-B012-FA230C1F6463}.Release|Win32.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -24,7 +24,6 @@ THE SOFTWARE.
|
|||
|
||||
#include "CCDrawingPrimitives.h"
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <GLES/gl.h>
|
||||
|
@ -66,7 +65,6 @@ void ccDrawPoints(CGPoint *points, unsigned int numberOfPoints)
|
|||
glEnable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
|
||||
void ccDrawLine(CGPoint origin, CGPoint destination)
|
||||
{
|
||||
CGPoint vertices[2];
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\PRJ_TG3\Include\ThirdParty\iconv;..\..\PRJ_TG3\Include\ThirdParty\zlib;..\..\PRJ_TG3\Include\ThirdParty\libpng;..\..\PRJ_TG3\Include\ThirdParty\libxml2;.\include;.\Res;..\..\PRJ_TG3\Include;..\..\PRJ_TG3\Include\MTAPI;..\..\PRJ_TG3\Include\OpenGL;..\..\PRJ_TG3\Include\TCOM;..\..\PRJ_TG3\TG3\Include;..\..\PRJ_TG3\TG3\TG3_Implement;..\..\PRJ_TG3\EOS_SYS;..\..\PRJ_TG3\Common\SoftSupport;..\..\PRJ_TG3\Common\ICU\Include;.\"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TRANZDA_VM_;SS_MAKEDLL;__TG3_PURE_DLL__"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TRANZDA_VM_;SS_MAKEDLL;__TG3_PURE_DLL__;_USE_MATH_DEFINES"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
|
@ -50,7 +50,7 @@
|
|||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
DisableSpecificWarnings="4996"
|
||||
DisableSpecificWarnings="4996;4251"
|
||||
ForcedIncludeFiles=""
|
||||
/>
|
||||
<Tool
|
||||
|
|
|
@ -25,7 +25,10 @@ THE SOFTWARE.
|
|||
#ifndef __CCMACROS_H__
|
||||
#define __CCMACROS_H__
|
||||
|
||||
#ifndef _USE_MATH_DEFINES
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <cstdio>
|
||||
|
||||
|
|
|
@ -41,8 +41,8 @@
|
|||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=".\Res;..\..\PRJ_TG3\Include;..\..\PRJ_TG3\Include\MTAPI;..\..\PRJ_TG3\Include\OpenGL;..\..\PRJ_TG3\Include\TCOM;..\..\PRJ_TG3\TG3\Include;..\..\PRJ_TG3\TG3\TG3_Implement;..\..\PRJ_TG3\EOS_SYS;..\..\PRJ_TG3\Common\SoftSupport;..\..\PRJ_TG3\Common\ICU\Include;..\cocos2dx\include;..\cocos2dx"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TRANZDA_VM_;SS_MAKEDLL"
|
||||
AdditionalIncludeDirectories=".\Res;..\..\PRJ_TG3\Include;..\..\PRJ_TG3\Include\MTAPI;..\..\PRJ_TG3\Include\OpenGL;..\..\PRJ_TG3\Include\TCOM;..\..\PRJ_TG3\TG3\Include;..\..\PRJ_TG3\TG3\TG3_Implement;..\..\PRJ_TG3\EOS_SYS;..\..\PRJ_TG3\Common\SoftSupport;..\..\PRJ_TG3\Common\ICU\Include;..\cocos2dx\include;..\cocos2dx;..\chipmunk\include\chipmunk;..\chipmunk\Demo;.\tests"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TRANZDA_VM_;SS_MAKEDLL;_USE_MATH_DEFINES"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="3"
|
||||
|
@ -51,6 +51,8 @@
|
|||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="4"
|
||||
CompileAs="2"
|
||||
DisableSpecificWarnings="4251;4244;4996"
|
||||
ForcedIncludeFiles=""
|
||||
/>
|
||||
<Tool
|
||||
|
@ -549,6 +551,102 @@
|
|||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="ChipmunkTest"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\cocos2dChipmunkDemo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\cocos2dChipmunkDemo.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="TestCases"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Bounce.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\drawSpace.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\drawSpace.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Joints.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\LogoSmash.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\MagnetsElectric.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\OneWay.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Planet.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Player.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Plink.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Pump.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\PyramidStack.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\PyramidTopple.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Query.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Sensors.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Simple.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Springies.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\TheoJansen.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\Tumble.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\chipmunk\Demo\UnsafeOps.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath=".\test_uphoneUnicodeScript.h"
|
||||
|
|
|
@ -53,6 +53,9 @@ static TestScene* CreateTestScene(int nIdx)
|
|||
pScene = new TileMapTestScene(); break;
|
||||
// case TEST_INTERVAL:
|
||||
// pScene = new IntervalTestScene(); break;
|
||||
case TESTS_CHIPMUNK:
|
||||
CCDirector::getSharedDirector()->setDeviceOrientation(kCCDeviceOrientationPortrait);
|
||||
pScene = new ChipmunkTestScene(); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "SceneTest/SceneTest.h"
|
||||
#include "ParallaxTest/ParallaxTest.h"
|
||||
#include "TileMapTest/TileMapTest.h"
|
||||
#include "cocos2dChipmunkDemo.h"
|
||||
//#include "IntervalTest/IntervalTest.h"
|
||||
|
||||
enum
|
||||
|
@ -42,6 +43,7 @@ enum
|
|||
TEST_PARALLAX,
|
||||
TEST_TILE_MAP,
|
||||
// TEST_INTERVAL,
|
||||
TESTS_CHIPMUNK,
|
||||
TESTS_COUNT,
|
||||
};
|
||||
|
||||
|
@ -65,6 +67,7 @@ const std::string g_aTestNames[TESTS_COUNT] = {
|
|||
"ParallaxTest",
|
||||
"TileMapTest",
|
||||
// "IntervalTest",
|
||||
"ChipmunkTest"
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue