chipmunk 5.3.4.5 → 6.1.3.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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;
|