chipmunk 5.3.4.5 → 6.1.3.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/chipmunk/chipmunk.c +199 -28
- data/ext/chipmunk/chipmunk.h +123 -68
- data/ext/chipmunk/chipmunk_ffi.h +129 -11
- data/ext/chipmunk/chipmunk_private.h +232 -16
- data/ext/chipmunk/chipmunk_types.h +94 -30
- data/ext/chipmunk/chipmunk_unsafe.h +12 -3
- data/ext/chipmunk/constraints/cpConstraint.h +90 -34
- data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
- data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
- data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
- data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
- data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
- data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
- data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
- data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
- data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
- data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
- data/ext/chipmunk/constraints/util.h +36 -44
- data/ext/chipmunk/cpArbiter.c +159 -94
- data/ext/chipmunk/cpArbiter.h +135 -129
- data/ext/chipmunk/cpArray.c +37 -56
- data/ext/chipmunk/cpBB.c +1 -12
- data/ext/chipmunk/cpBB.h +80 -18
- data/ext/chipmunk/cpBBTree.c +891 -0
- data/ext/chipmunk/cpBody.c +185 -47
- data/ext/chipmunk/cpBody.h +156 -124
- data/ext/chipmunk/cpCollision.c +126 -115
- data/ext/chipmunk/cpConstraint.c +10 -6
- data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
- data/ext/chipmunk/cpDampedSpring.c +25 -18
- data/ext/chipmunk/cpGearJoint.c +23 -17
- data/ext/chipmunk/cpGrooveJoint.c +26 -22
- data/ext/chipmunk/cpHashSet.c +51 -51
- data/ext/chipmunk/cpPinJoint.c +26 -19
- data/ext/chipmunk/cpPivotJoint.c +23 -19
- data/ext/chipmunk/cpPolyShape.c +93 -69
- data/ext/chipmunk/cpPolyShape.h +33 -69
- data/ext/chipmunk/cpRatchetJoint.c +26 -21
- data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
- data/ext/chipmunk/cpShape.c +122 -133
- data/ext/chipmunk/cpShape.h +146 -95
- data/ext/chipmunk/cpSimpleMotor.c +24 -17
- data/ext/chipmunk/cpSlideJoint.c +28 -26
- data/ext/chipmunk/cpSpace.c +251 -196
- data/ext/chipmunk/cpSpace.h +173 -103
- data/ext/chipmunk/cpSpaceComponent.c +236 -159
- data/ext/chipmunk/cpSpaceHash.c +259 -159
- data/ext/chipmunk/cpSpaceQuery.c +127 -59
- data/ext/chipmunk/cpSpaceStep.c +235 -197
- data/ext/chipmunk/cpSpatialIndex.c +69 -0
- data/ext/chipmunk/cpSpatialIndex.h +227 -0
- data/ext/chipmunk/cpSweep1D.c +254 -0
- data/ext/chipmunk/cpVect.c +11 -26
- data/ext/chipmunk/cpVect.h +76 -71
- data/ext/chipmunk/extconf.rb +4 -31
- data/ext/chipmunk/prime.h +1 -1
- data/ext/chipmunk/rb_chipmunk.c +36 -45
- data/ext/chipmunk/rb_chipmunk.h +6 -3
- data/ext/chipmunk/rb_cpArbiter.c +2 -2
- data/ext/chipmunk/rb_cpBB.c +116 -35
- data/ext/chipmunk/rb_cpBody.c +5 -12
- data/ext/chipmunk/rb_cpConstraint.c +144 -9
- data/ext/chipmunk/rb_cpShape.c +69 -78
- data/ext/chipmunk/rb_cpSpace.c +81 -76
- metadata +61 -61
- data/LICENSE +0 -22
- data/README +0 -110
- data/Rakefile +0 -102
- data/ext/chipmunk/cpArray.h +0 -49
- data/ext/chipmunk/cpCollision.h +0 -28
- data/ext/chipmunk/cpHashSet.h +0 -82
- data/ext/chipmunk/cpSpaceHash.h +0 -110
- data/lib/chipmunk.rb +0 -194
data/ext/chipmunk/cpPolyShape.h
CHANGED
@@ -19,85 +19,49 @@
|
|
19
19
|
* SOFTWARE.
|
20
20
|
*/
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
/// @defgroup cpPolyShape cpPolyShape
|
23
|
+
/// @{
|
24
|
+
|
25
|
+
/// @private
|
26
|
+
typedef struct cpSplittingPlane {
|
25
27
|
cpVect n;
|
26
|
-
// distance from origin
|
27
28
|
cpFloat d;
|
28
|
-
}
|
29
|
+
} cpSplittingPlane;
|
29
30
|
|
30
|
-
|
31
|
-
typedef struct cpPolyShape{
|
32
|
-
|
31
|
+
/// @private
|
32
|
+
typedef struct cpPolyShape {
|
33
|
+
cpShape shape;
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
CP_PRIVATE(cpPolyShapeAxis *axes);
|
38
|
-
|
39
|
-
// Transformed vertex and axis lists.
|
40
|
-
CP_PRIVATE(cpVect *tVerts);
|
41
|
-
CP_PRIVATE(cpPolyShapeAxis *tAxes);
|
35
|
+
int numVerts;
|
36
|
+
cpVect *verts, *tVerts;
|
37
|
+
cpSplittingPlane *planes, *tPlanes;
|
42
38
|
} cpPolyShape;
|
43
39
|
|
44
|
-
|
45
|
-
cpPolyShape
|
46
|
-
|
47
|
-
|
40
|
+
/// Allocate a polygon shape.
|
41
|
+
cpPolyShape* cpPolyShapeAlloc(void);
|
42
|
+
/// Initialize a polygon shape.
|
43
|
+
/// A convex hull will be created from the vertexes.
|
44
|
+
cpPolyShape* cpPolyShapeInit(cpPolyShape *poly, cpBody *body, int numVerts, const cpVect *verts, cpVect offset);
|
45
|
+
/// Allocate and initialize a polygon shape.
|
46
|
+
/// A convex hull will be created from the vertexes.
|
47
|
+
cpShape* cpPolyShapeNew(cpBody *body, int numVerts, cpVect *verts, cpVect offset);
|
48
48
|
|
49
|
-
|
50
|
-
|
49
|
+
/// Initialize a box shaped polygon shape.
|
50
|
+
cpPolyShape* cpBoxShapeInit(cpPolyShape *poly, cpBody *body, cpFloat width, cpFloat height);
|
51
|
+
/// Initialize an offset box shaped polygon shape.
|
52
|
+
cpPolyShape* cpBoxShapeInit2(cpPolyShape *poly, cpBody *body, cpBB box);
|
53
|
+
/// Allocate and initialize a box shaped polygon shape.
|
54
|
+
cpShape* cpBoxShapeNew(cpBody *body, cpFloat width, cpFloat height);
|
55
|
+
/// Allocate and initialize an offset box shaped polygon shape.
|
56
|
+
cpShape* cpBoxShapeNew2(cpBody *body, cpBB box);
|
51
57
|
|
52
|
-
|
58
|
+
/// Check that a set of vertexes is convex and has a clockwise winding.
|
59
|
+
/// NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
|
53
60
|
cpBool cpPolyValidate(const cpVect *verts, const int numVerts);
|
54
61
|
|
62
|
+
/// Get the number of verts in a polygon shape.
|
55
63
|
int cpPolyShapeGetNumVerts(cpShape *shape);
|
64
|
+
/// Get the @c ith vertex of a polygon shape.
|
56
65
|
cpVect cpPolyShapeGetVert(cpShape *shape, int idx);
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
// Returns the minimum distance of the polygon to the axis.
|
61
|
-
static inline cpFloat
|
62
|
-
cpPolyShapeValueOnAxis(const cpPolyShape *poly, const cpVect n, const cpFloat d)
|
63
|
-
{
|
64
|
-
cpVect *verts = poly->CP_PRIVATE(tVerts);
|
65
|
-
cpFloat min = cpvdot(n, verts[0]);
|
66
|
-
|
67
|
-
int i;
|
68
|
-
for(i=1; i<poly->CP_PRIVATE(numVerts); i++)
|
69
|
-
min = cpfmin(min, cpvdot(n, verts[i]));
|
70
|
-
|
71
|
-
return min - d;
|
72
|
-
}
|
73
|
-
|
74
|
-
// Returns true if the polygon contains the vertex.
|
75
|
-
static inline cpBool
|
76
|
-
cpPolyShapeContainsVert(const cpPolyShape *poly, const cpVect v)
|
77
|
-
{
|
78
|
-
cpPolyShapeAxis *axes = poly->CP_PRIVATE(tAxes);
|
79
|
-
|
80
|
-
int i;
|
81
|
-
for(i=0; i<poly->CP_PRIVATE(numVerts); i++){
|
82
|
-
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
|
83
|
-
if(dist > 0.0f) return cpFalse;
|
84
|
-
}
|
85
|
-
|
86
|
-
return cpTrue;
|
87
|
-
}
|
88
|
-
|
89
|
-
// Same as cpPolyShapeContainsVert() but ignores faces pointing away from the normal.
|
90
|
-
static inline cpBool
|
91
|
-
cpPolyShapeContainsVertPartial(const cpPolyShape *poly, const cpVect v, const cpVect n)
|
92
|
-
{
|
93
|
-
cpPolyShapeAxis *axes = poly->CP_PRIVATE(tAxes);
|
94
|
-
|
95
|
-
int i;
|
96
|
-
for(i=0; i<poly->CP_PRIVATE(numVerts); i++){
|
97
|
-
if(cpvdot(axes[i].n, n) < 0.0f) continue;
|
98
|
-
cpFloat dist = cpvdot(axes[i].n, v) - axes[i].d;
|
99
|
-
if(dist > 0.0f) return cpFalse;
|
100
|
-
}
|
101
|
-
|
102
|
-
return cpTrue;
|
103
|
-
}
|
67
|
+
/// @}
|
@@ -19,16 +19,14 @@
|
|
19
19
|
* SOFTWARE.
|
20
20
|
*/
|
21
21
|
|
22
|
-
#include <stdlib.h>
|
23
|
-
#include <math.h>
|
24
|
-
|
25
22
|
#include "chipmunk_private.h"
|
26
23
|
#include "constraints/util.h"
|
27
24
|
|
28
25
|
static void
|
29
|
-
preStep(cpRatchetJoint *joint, cpFloat dt
|
26
|
+
preStep(cpRatchetJoint *joint, cpFloat dt)
|
30
27
|
{
|
31
|
-
|
28
|
+
cpBody *a = joint->constraint.a;
|
29
|
+
cpBody *b = joint->constraint.b;
|
32
30
|
|
33
31
|
cpFloat angle = joint->angle;
|
34
32
|
cpFloat phase = joint->phase;
|
@@ -49,35 +47,41 @@ preStep(cpRatchetJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
49
47
|
|
50
48
|
// calculate bias velocity
|
51
49
|
cpFloat maxBias = joint->constraint.maxBias;
|
52
|
-
joint->bias = cpfclamp(-joint->constraint.
|
53
|
-
|
54
|
-
// compute max impulse
|
55
|
-
joint->jMax = J_MAX(joint, dt);
|
50
|
+
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
|
56
51
|
|
57
52
|
// If the bias is 0, the joint is not at a limit. Reset the impulse.
|
58
|
-
if(!joint->bias)
|
59
|
-
|
53
|
+
if(!joint->bias) joint->jAcc = 0.0f;
|
54
|
+
}
|
60
55
|
|
61
|
-
|
62
|
-
|
63
|
-
|
56
|
+
static void
|
57
|
+
applyCachedImpulse(cpRatchetJoint *joint, cpFloat dt_coef)
|
58
|
+
{
|
59
|
+
cpBody *a = joint->constraint.a;
|
60
|
+
cpBody *b = joint->constraint.b;
|
61
|
+
|
62
|
+
cpFloat j = joint->jAcc*dt_coef;
|
63
|
+
a->w -= j*a->i_inv;
|
64
|
+
b->w += j*b->i_inv;
|
64
65
|
}
|
65
66
|
|
66
67
|
static void
|
67
|
-
applyImpulse(cpRatchetJoint *joint)
|
68
|
+
applyImpulse(cpRatchetJoint *joint, cpFloat dt)
|
68
69
|
{
|
69
70
|
if(!joint->bias) return; // early exit
|
70
71
|
|
71
|
-
|
72
|
+
cpBody *a = joint->constraint.a;
|
73
|
+
cpBody *b = joint->constraint.b;
|
72
74
|
|
73
75
|
// compute relative rotational velocity
|
74
76
|
cpFloat wr = b->w - a->w;
|
75
77
|
cpFloat ratchet = joint->ratchet;
|
76
78
|
|
79
|
+
cpFloat jMax = joint->constraint.maxForce*dt;
|
80
|
+
|
77
81
|
// compute normal impulse
|
78
82
|
cpFloat j = -(joint->bias + wr)*joint->iSum;
|
79
83
|
cpFloat jOld = joint->jAcc;
|
80
|
-
joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f,
|
84
|
+
joint->jAcc = cpfclamp((jOld + j)*ratchet, 0.0f, jMax*cpfabs(ratchet))/ratchet;
|
81
85
|
j = joint->jAcc - jOld;
|
82
86
|
|
83
87
|
// apply impulse
|
@@ -92,16 +96,17 @@ getImpulse(cpRatchetJoint *joint)
|
|
92
96
|
}
|
93
97
|
|
94
98
|
static const cpConstraintClass klass = {
|
95
|
-
(
|
96
|
-
(
|
97
|
-
(
|
99
|
+
(cpConstraintPreStepImpl)preStep,
|
100
|
+
(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,
|
101
|
+
(cpConstraintApplyImpulseImpl)applyImpulse,
|
102
|
+
(cpConstraintGetImpulseImpl)getImpulse,
|
98
103
|
};
|
99
104
|
CP_DefineClassGetter(cpRatchetJoint)
|
100
105
|
|
101
106
|
cpRatchetJoint *
|
102
107
|
cpRatchetJointAlloc(void)
|
103
108
|
{
|
104
|
-
return (cpRatchetJoint *)
|
109
|
+
return (cpRatchetJoint *)cpcalloc(1, sizeof(cpRatchetJoint));
|
105
110
|
}
|
106
111
|
|
107
112
|
cpRatchetJoint *
|
@@ -19,15 +19,14 @@
|
|
19
19
|
* SOFTWARE.
|
20
20
|
*/
|
21
21
|
|
22
|
-
#include <stdlib.h>
|
23
|
-
|
24
22
|
#include "chipmunk_private.h"
|
25
23
|
#include "constraints/util.h"
|
26
24
|
|
27
25
|
static void
|
28
|
-
preStep(cpRotaryLimitJoint *joint, cpFloat dt
|
26
|
+
preStep(cpRotaryLimitJoint *joint, cpFloat dt)
|
29
27
|
{
|
30
|
-
|
28
|
+
cpBody *a = joint->constraint.a;
|
29
|
+
cpBody *b = joint->constraint.b;
|
31
30
|
|
32
31
|
cpFloat dist = b->a - a->a;
|
33
32
|
cpFloat pdist = 0.0f;
|
@@ -38,41 +37,47 @@ preStep(cpRotaryLimitJoint *joint, cpFloat dt, cpFloat dt_inv)
|
|
38
37
|
}
|
39
38
|
|
40
39
|
// calculate moment of inertia coefficient.
|
41
|
-
joint->iSum = 1.0f/(a->
|
40
|
+
joint->iSum = 1.0f/(1.0f/a->i + 1.0f/b->i);
|
42
41
|
|
43
42
|
// calculate bias velocity
|
44
43
|
cpFloat maxBias = joint->constraint.maxBias;
|
45
|
-
joint->bias = cpfclamp(-joint->constraint.
|
46
|
-
|
47
|
-
// compute max impulse
|
48
|
-
joint->jMax = J_MAX(joint, dt);
|
44
|
+
joint->bias = cpfclamp(-bias_coef(joint->constraint.errorBias, dt)*pdist/dt, -maxBias, maxBias);
|
49
45
|
|
50
46
|
// If the bias is 0, the joint is not at a limit. Reset the impulse.
|
51
|
-
if(!joint->bias)
|
52
|
-
|
47
|
+
if(!joint->bias) joint->jAcc = 0.0f;
|
48
|
+
}
|
53
49
|
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
static void
|
51
|
+
applyCachedImpulse(cpRotaryLimitJoint *joint, cpFloat dt_coef)
|
52
|
+
{
|
53
|
+
cpBody *a = joint->constraint.a;
|
54
|
+
cpBody *b = joint->constraint.b;
|
55
|
+
|
56
|
+
cpFloat j = joint->jAcc*dt_coef;
|
57
|
+
a->w -= j*a->i_inv;
|
58
|
+
b->w += j*b->i_inv;
|
57
59
|
}
|
58
60
|
|
59
61
|
static void
|
60
|
-
applyImpulse(cpRotaryLimitJoint *joint)
|
62
|
+
applyImpulse(cpRotaryLimitJoint *joint, cpFloat dt)
|
61
63
|
{
|
62
64
|
if(!joint->bias) return; // early exit
|
63
65
|
|
64
|
-
|
66
|
+
cpBody *a = joint->constraint.a;
|
67
|
+
cpBody *b = joint->constraint.b;
|
65
68
|
|
66
69
|
// compute relative rotational velocity
|
67
70
|
cpFloat wr = b->w - a->w;
|
68
71
|
|
72
|
+
cpFloat jMax = joint->constraint.maxForce*dt;
|
73
|
+
|
69
74
|
// compute normal impulse
|
70
75
|
cpFloat j = -(joint->bias + wr)*joint->iSum;
|
71
76
|
cpFloat jOld = joint->jAcc;
|
72
77
|
if(joint->bias < 0.0f){
|
73
|
-
joint->jAcc = cpfclamp(jOld + j, 0.0f,
|
78
|
+
joint->jAcc = cpfclamp(jOld + j, 0.0f, jMax);
|
74
79
|
} else {
|
75
|
-
joint->jAcc = cpfclamp(jOld + j, -
|
80
|
+
joint->jAcc = cpfclamp(jOld + j, -jMax, 0.0f);
|
76
81
|
}
|
77
82
|
j = joint->jAcc - jOld;
|
78
83
|
|
@@ -88,16 +93,17 @@ getImpulse(cpRotaryLimitJoint *joint)
|
|
88
93
|
}
|
89
94
|
|
90
95
|
static const cpConstraintClass klass = {
|
91
|
-
(
|
92
|
-
(
|
93
|
-
(
|
96
|
+
(cpConstraintPreStepImpl)preStep,
|
97
|
+
(cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,
|
98
|
+
(cpConstraintApplyImpulseImpl)applyImpulse,
|
99
|
+
(cpConstraintGetImpulseImpl)getImpulse,
|
94
100
|
};
|
95
101
|
CP_DefineClassGetter(cpRotaryLimitJoint)
|
96
102
|
|
97
103
|
cpRotaryLimitJoint *
|
98
104
|
cpRotaryLimitJointAlloc(void)
|
99
105
|
{
|
100
|
-
return (cpRotaryLimitJoint *)
|
106
|
+
return (cpRotaryLimitJoint *)cpcalloc(1, sizeof(cpRotaryLimitJoint));
|
101
107
|
}
|
102
108
|
|
103
109
|
cpRotaryLimitJoint *
|
data/ext/chipmunk/cpShape.c
CHANGED
@@ -19,24 +19,21 @@
|
|
19
19
|
* SOFTWARE.
|
20
20
|
*/
|
21
21
|
|
22
|
-
#include <stdlib.h>
|
23
|
-
#include <stdio.h>
|
24
|
-
#include <math.h>
|
25
|
-
|
26
22
|
#include "chipmunk_private.h"
|
27
23
|
#include "chipmunk_unsafe.h"
|
28
24
|
|
29
25
|
#define CP_DefineShapeGetter(struct, type, member, name) \
|
30
26
|
CP_DeclareShapeGetter(struct, type, name){ \
|
31
|
-
|
27
|
+
cpAssertHard(shape->klass == &struct##Class, "shape is not a "#struct); \
|
32
28
|
return ((struct *)shape)->member; \
|
33
29
|
}
|
34
|
-
|
30
|
+
|
31
|
+
static cpHashValue cpShapeIDCounter = 0;
|
35
32
|
|
36
33
|
void
|
37
34
|
cpResetShapeIdCounter(void)
|
38
35
|
{
|
39
|
-
|
36
|
+
cpShapeIDCounter = 0;
|
40
37
|
}
|
41
38
|
|
42
39
|
|
@@ -45,8 +42,8 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
|
|
45
42
|
{
|
46
43
|
shape->klass = klass;
|
47
44
|
|
48
|
-
shape->hashid =
|
49
|
-
|
45
|
+
shape->hashid = cpShapeIDCounter;
|
46
|
+
cpShapeIDCounter++;
|
50
47
|
|
51
48
|
shape->body = body;
|
52
49
|
shape->sensor = 0;
|
@@ -60,9 +57,11 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
|
|
60
57
|
shape->layers = CP_ALL_LAYERS;
|
61
58
|
|
62
59
|
shape->data = NULL;
|
63
|
-
shape->next = NULL;
|
64
60
|
|
65
|
-
|
61
|
+
shape->space = NULL;
|
62
|
+
|
63
|
+
shape->next = NULL;
|
64
|
+
shape->prev = NULL;
|
66
65
|
|
67
66
|
return shape;
|
68
67
|
}
|
@@ -70,9 +69,7 @@ cpShapeInit(cpShape *shape, const cpShapeClass *klass, cpBody *body)
|
|
70
69
|
void
|
71
70
|
cpShapeDestroy(cpShape *shape)
|
72
71
|
{
|
73
|
-
if(shape->klass && shape->klass->destroy)
|
74
|
-
shape->klass->destroy(shape);
|
75
|
-
}
|
72
|
+
if(shape->klass && shape->klass->destroy) shape->klass->destroy(shape);
|
76
73
|
}
|
77
74
|
|
78
75
|
void
|
@@ -84,68 +81,85 @@ cpShapeFree(cpShape *shape)
|
|
84
81
|
}
|
85
82
|
}
|
86
83
|
|
87
|
-
|
84
|
+
void
|
85
|
+
cpShapeSetBody(cpShape *shape, cpBody *body)
|
86
|
+
{
|
87
|
+
cpAssertHard(!cpShapeActive(shape), "You cannot change the body on an active shape. You must remove the shape from the space before changing the body.");
|
88
|
+
shape->body = body;
|
89
|
+
}
|
90
|
+
|
88
91
|
cpBB
|
89
92
|
cpShapeCacheBB(cpShape *shape)
|
90
93
|
{
|
91
94
|
cpBody *body = shape->body;
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
+
return cpShapeUpdate(shape, body->p, body->rot);
|
96
|
+
}
|
97
|
+
|
98
|
+
cpBB
|
99
|
+
cpShapeUpdate(cpShape *shape, cpVect pos, cpVect rot)
|
100
|
+
{
|
101
|
+
return (shape->bb = shape->klass->cacheData(shape, pos, rot));
|
95
102
|
}
|
96
103
|
|
97
104
|
cpBool
|
98
105
|
cpShapePointQuery(cpShape *shape, cpVect p){
|
99
|
-
|
106
|
+
cpNearestPointQueryInfo info = {NULL, cpvzero, INFINITY};
|
107
|
+
cpShapeNearestPointQuery(shape, p, &info);
|
108
|
+
|
109
|
+
return (info.d < 0.0f);
|
110
|
+
}
|
111
|
+
|
112
|
+
cpFloat
|
113
|
+
cpShapeNearestPointQuery(cpShape *shape, cpVect p, cpNearestPointQueryInfo *info)
|
114
|
+
{
|
115
|
+
cpNearestPointQueryInfo blank = {NULL, cpvzero, INFINITY};
|
116
|
+
if(info){
|
117
|
+
(*info) = blank;
|
118
|
+
} else {
|
119
|
+
info = ␣
|
120
|
+
}
|
121
|
+
|
122
|
+
shape->klass->nearestPointQuery(shape, p, info);
|
123
|
+
return info->d;
|
100
124
|
}
|
101
125
|
|
126
|
+
|
102
127
|
cpBool
|
103
128
|
cpShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInfo *info){
|
104
129
|
cpSegmentQueryInfo blank = {NULL, 0.0f, cpvzero};
|
105
|
-
(
|
130
|
+
if(info){
|
131
|
+
(*info) = blank;
|
132
|
+
} else {
|
133
|
+
info = ␣
|
134
|
+
}
|
106
135
|
|
107
136
|
shape->klass->segmentQuery(shape, a, b, info);
|
108
137
|
return (info->shape != NULL);
|
109
138
|
}
|
110
139
|
|
111
|
-
void
|
112
|
-
cpSegmentQueryInfoPrint(cpSegmentQueryInfo *info)
|
113
|
-
{
|
114
|
-
printf("Segment Query:\n");
|
115
|
-
printf("\tt: %f\n", info->t);
|
116
|
-
// printf("\tdist: %f\n", info->dist);
|
117
|
-
// printf("\tpoint: %s\n", cpvstr(info->point));
|
118
|
-
printf("\tn: %s\n", cpvstr(info->n));
|
119
|
-
}
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
140
|
cpCircleShape *
|
125
141
|
cpCircleShapeAlloc(void)
|
126
142
|
{
|
127
143
|
return (cpCircleShape *)cpcalloc(1, sizeof(cpCircleShape));
|
128
144
|
}
|
129
145
|
|
130
|
-
static
|
131
|
-
|
146
|
+
static cpBB
|
147
|
+
cpCircleShapeCacheData(cpCircleShape *circle, cpVect p, cpVect rot)
|
132
148
|
{
|
133
|
-
|
149
|
+
cpVect c = circle->tc = cpvadd(p, cpvrotate(circle->c, rot));
|
150
|
+
return cpBBNewForCircle(c, circle->r);
|
134
151
|
}
|
135
152
|
|
136
|
-
static
|
137
|
-
|
153
|
+
static void
|
154
|
+
cpCicleShapeNearestPointQuery(cpCircleShape *circle, cpVect p, cpNearestPointQueryInfo *info)
|
138
155
|
{
|
139
|
-
|
156
|
+
cpVect delta = cpvsub(p, circle->tc);
|
157
|
+
cpFloat d = cpvlength(delta);
|
158
|
+
cpFloat r = circle->r;
|
140
159
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
static cpBool
|
146
|
-
cpCircleShapePointQuery(cpShape *shape, cpVect p){
|
147
|
-
cpCircleShape *circle = (cpCircleShape *)shape;
|
148
|
-
return cpvnear(circle->tc, p, circle->r);
|
160
|
+
info->shape = (cpShape *)circle;
|
161
|
+
info->p = cpvadd(circle->tc, cpvmult(delta, r/d)); // TODO div/0
|
162
|
+
info->d = d - r;
|
149
163
|
}
|
150
164
|
|
151
165
|
static void
|
@@ -172,18 +186,17 @@ circleSegmentQuery(cpShape *shape, cpVect center, cpFloat r, cpVect a, cpVect b,
|
|
172
186
|
}
|
173
187
|
|
174
188
|
static void
|
175
|
-
cpCircleShapeSegmentQuery(
|
189
|
+
cpCircleShapeSegmentQuery(cpCircleShape *circle, cpVect a, cpVect b, cpSegmentQueryInfo *info)
|
176
190
|
{
|
177
|
-
|
178
|
-
circleSegmentQuery(shape, circle->tc, circle->r, a, b, info);
|
191
|
+
circleSegmentQuery((cpShape *)circle, circle->tc, circle->r, a, b, info);
|
179
192
|
}
|
180
193
|
|
181
194
|
static const cpShapeClass cpCircleShapeClass = {
|
182
195
|
CP_CIRCLE_SHAPE,
|
183
|
-
cpCircleShapeCacheData,
|
196
|
+
(cpShapeCacheDataImpl)cpCircleShapeCacheData,
|
184
197
|
NULL,
|
185
|
-
|
186
|
-
cpCircleShapeSegmentQuery,
|
198
|
+
(cpShapeNearestPointQueryImpl)cpCicleShapeNearestPointQuery,
|
199
|
+
(cpShapeSegmentQueryImpl)cpCircleShapeSegmentQuery,
|
187
200
|
};
|
188
201
|
|
189
202
|
cpCircleShape *
|
@@ -213,15 +226,13 @@ cpSegmentShapeAlloc(void)
|
|
213
226
|
}
|
214
227
|
|
215
228
|
static cpBB
|
216
|
-
cpSegmentShapeCacheData(
|
229
|
+
cpSegmentShapeCacheData(cpSegmentShape *seg, cpVect p, cpVect rot)
|
217
230
|
{
|
218
|
-
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
219
|
-
|
220
231
|
seg->ta = cpvadd(p, cpvrotate(seg->a, rot));
|
221
232
|
seg->tb = cpvadd(p, cpvrotate(seg->b, rot));
|
222
233
|
seg->tn = cpvrotate(seg->n, rot);
|
223
234
|
|
224
|
-
cpFloat l,r,
|
235
|
+
cpFloat l,r,b,t;
|
225
236
|
|
226
237
|
if(seg->ta.x < seg->tb.x){
|
227
238
|
l = seg->ta.x;
|
@@ -232,96 +243,61 @@ cpSegmentShapeCacheData(cpShape *shape, cpVect p, cpVect rot)
|
|
232
243
|
}
|
233
244
|
|
234
245
|
if(seg->ta.y < seg->tb.y){
|
235
|
-
|
246
|
+
b = seg->ta.y;
|
236
247
|
t = seg->tb.y;
|
237
248
|
} else {
|
238
|
-
|
249
|
+
b = seg->tb.y;
|
239
250
|
t = seg->ta.y;
|
240
251
|
}
|
241
252
|
|
242
253
|
cpFloat rad = seg->r;
|
243
|
-
return cpBBNew(l - rad,
|
254
|
+
return cpBBNew(l - rad, b - rad, r + rad, t + rad);
|
244
255
|
}
|
245
256
|
|
246
|
-
static
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
251
|
-
|
252
|
-
// Calculate normal distance from segment.
|
253
|
-
cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
|
254
|
-
cpFloat dist = cpfabs(dn) - seg->r;
|
255
|
-
if(dist > 0.0f) return cpFalse;
|
257
|
+
static void
|
258
|
+
cpSegmentShapeNearestPointQuery(cpSegmentShape *seg, cpVect p, cpNearestPointQueryInfo *info)
|
259
|
+
{
|
260
|
+
cpVect closest = cpClosetPointOnSegment(p, seg->ta, seg->tb);
|
256
261
|
|
257
|
-
|
258
|
-
cpFloat
|
259
|
-
cpFloat
|
260
|
-
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
|
262
|
+
cpVect delta = cpvsub(p, closest);
|
263
|
+
cpFloat d = cpvlength(delta);
|
264
|
+
cpFloat r = seg->r;
|
261
265
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
return cpFalse;
|
266
|
-
} else {
|
267
|
-
return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
|
268
|
-
}
|
269
|
-
} else {
|
270
|
-
if(dt < dtMax){
|
271
|
-
return cpTrue;
|
272
|
-
} else {
|
273
|
-
if(dt < (dtMax + seg->r)) {
|
274
|
-
return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
|
275
|
-
} else {
|
276
|
-
return cpFalse;
|
277
|
-
}
|
278
|
-
}
|
279
|
-
}
|
280
|
-
|
281
|
-
return cpTrue;
|
266
|
+
info->shape = (cpShape *)seg;
|
267
|
+
info->p = (d ? cpvadd(closest, cpvmult(delta, r/d)) : closest);
|
268
|
+
info->d = d - r;
|
282
269
|
}
|
283
270
|
|
284
|
-
static inline cpBool inUnitRange(cpFloat t){return (0.0f < t && t < 1.0f);}
|
285
|
-
|
286
271
|
static void
|
287
|
-
cpSegmentShapeSegmentQuery(
|
272
|
+
cpSegmentShapeSegmentQuery(cpSegmentShape *seg, cpVect a, cpVect b, cpSegmentQueryInfo *info)
|
288
273
|
{
|
289
|
-
// TODO this function could be optimized better.
|
290
|
-
|
291
|
-
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
292
274
|
cpVect n = seg->tn;
|
293
|
-
|
294
|
-
|
295
|
-
n = cpvneg(n);
|
275
|
+
cpFloat d = cpvdot(cpvsub(seg->ta, a), n);
|
276
|
+
cpFloat r = seg->r;
|
296
277
|
|
297
|
-
|
298
|
-
|
278
|
+
cpVect flipped_n = (d > 0.0f ? cpvneg(n) : n);
|
279
|
+
cpVect seg_offset = cpvsub(cpvmult(flipped_n, r), a);
|
299
280
|
|
300
|
-
|
301
|
-
|
302
|
-
|
281
|
+
// Make the endpoints relative to 'a' and move them by the thickness of the segment.
|
282
|
+
cpVect seg_a = cpvadd(seg->ta, seg_offset);
|
283
|
+
cpVect seg_b = cpvadd(seg->tb, seg_offset);
|
284
|
+
cpVect delta = cpvsub(b, a);
|
285
|
+
|
286
|
+
if(cpvcross(delta, seg_a)*cpvcross(delta, seg_b) <= 0.0f){
|
287
|
+
cpFloat d_offset = d + (d > 0.0f ? -r : r);
|
288
|
+
cpFloat ad = -d_offset;
|
289
|
+
cpFloat bd = cpvdot(delta, n) - d_offset;
|
303
290
|
|
304
|
-
if(
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
|
309
|
-
|
310
|
-
if(dtMin < dt && dt < dtMax){
|
311
|
-
info->shape = shape;
|
312
|
-
info->t = t;
|
313
|
-
info->n = n;
|
314
|
-
|
315
|
-
return; // don't continue on and check endcaps
|
316
|
-
}
|
291
|
+
if(ad*bd < 0.0f){
|
292
|
+
info->shape = (cpShape *)seg;
|
293
|
+
info->t = ad/(ad - bd);
|
294
|
+
info->n = flipped_n;
|
317
295
|
}
|
318
|
-
}
|
319
|
-
|
320
|
-
if(seg->r) {
|
296
|
+
} else if(r != 0.0f){
|
321
297
|
cpSegmentQueryInfo info1 = {NULL, 1.0f, cpvzero};
|
322
298
|
cpSegmentQueryInfo info2 = {NULL, 1.0f, cpvzero};
|
323
|
-
circleSegmentQuery(
|
324
|
-
circleSegmentQuery(
|
299
|
+
circleSegmentQuery((cpShape *)seg, seg->ta, seg->r, a, b, &info1);
|
300
|
+
circleSegmentQuery((cpShape *)seg, seg->tb, seg->r, a, b, &info2);
|
325
301
|
|
326
302
|
if(info1.t < info2.t){
|
327
303
|
(*info) = info1;
|
@@ -333,10 +309,10 @@ cpSegmentShapeSegmentQuery(cpShape *shape, cpVect a, cpVect b, cpSegmentQueryInf
|
|
333
309
|
|
334
310
|
static const cpShapeClass cpSegmentShapeClass = {
|
335
311
|
CP_SEGMENT_SHAPE,
|
336
|
-
cpSegmentShapeCacheData,
|
312
|
+
(cpShapeCacheDataImpl)cpSegmentShapeCacheData,
|
337
313
|
NULL,
|
338
|
-
|
339
|
-
cpSegmentShapeSegmentQuery,
|
314
|
+
(cpShapeNearestPointQueryImpl)cpSegmentShapeNearestPointQuery,
|
315
|
+
(cpShapeSegmentQueryImpl)cpSegmentShapeSegmentQuery,
|
340
316
|
};
|
341
317
|
|
342
318
|
cpSegmentShape *
|
@@ -348,6 +324,9 @@ cpSegmentShapeInit(cpSegmentShape *seg, cpBody *body, cpVect a, cpVect b, cpFloa
|
|
348
324
|
|
349
325
|
seg->r = r;
|
350
326
|
|
327
|
+
seg->a_tangent = cpvzero;
|
328
|
+
seg->b_tangent = cpvzero;
|
329
|
+
|
351
330
|
cpShapeInit((cpShape *)seg, &cpSegmentShapeClass, body);
|
352
331
|
|
353
332
|
return seg;
|
@@ -364,12 +343,22 @@ CP_DefineShapeGetter(cpSegmentShape, cpVect, b, B)
|
|
364
343
|
CP_DefineShapeGetter(cpSegmentShape, cpVect, n, Normal)
|
365
344
|
CP_DefineShapeGetter(cpSegmentShape, cpFloat, r, Radius)
|
366
345
|
|
346
|
+
void
|
347
|
+
cpSegmentShapeSetNeighbors(cpShape *shape, cpVect prev, cpVect next)
|
348
|
+
{
|
349
|
+
cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
|
350
|
+
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
351
|
+
|
352
|
+
seg->a_tangent = cpvsub(prev, seg->a);
|
353
|
+
seg->b_tangent = cpvsub(next, seg->b);
|
354
|
+
}
|
355
|
+
|
367
356
|
// Unsafe API (chipmunk_unsafe.h)
|
368
357
|
|
369
358
|
void
|
370
359
|
cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)
|
371
360
|
{
|
372
|
-
|
361
|
+
cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
|
373
362
|
cpCircleShape *circle = (cpCircleShape *)shape;
|
374
363
|
|
375
364
|
circle->r = radius;
|
@@ -378,7 +367,7 @@ cpCircleShapeSetRadius(cpShape *shape, cpFloat radius)
|
|
378
367
|
void
|
379
368
|
cpCircleShapeSetOffset(cpShape *shape, cpVect offset)
|
380
369
|
{
|
381
|
-
|
370
|
+
cpAssertHard(shape->klass == &cpCircleShapeClass, "Shape is not a circle shape.");
|
382
371
|
cpCircleShape *circle = (cpCircleShape *)shape;
|
383
372
|
|
384
373
|
circle->c = offset;
|
@@ -387,7 +376,7 @@ cpCircleShapeSetOffset(cpShape *shape, cpVect offset)
|
|
387
376
|
void
|
388
377
|
cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)
|
389
378
|
{
|
390
|
-
|
379
|
+
cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
|
391
380
|
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
392
381
|
|
393
382
|
seg->a = a;
|
@@ -398,7 +387,7 @@ cpSegmentShapeSetEndpoints(cpShape *shape, cpVect a, cpVect b)
|
|
398
387
|
void
|
399
388
|
cpSegmentShapeSetRadius(cpShape *shape, cpFloat radius)
|
400
389
|
{
|
401
|
-
|
390
|
+
cpAssertHard(shape->klass == &cpSegmentShapeClass, "Shape is not a segment shape.");
|
402
391
|
cpSegmentShape *seg = (cpSegmentShape *)shape;
|
403
392
|
|
404
393
|
seg->r = radius;
|