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.
Files changed (73) hide show
  1. data/ext/chipmunk/chipmunk.c +199 -28
  2. data/ext/chipmunk/chipmunk.h +123 -68
  3. data/ext/chipmunk/chipmunk_ffi.h +129 -11
  4. data/ext/chipmunk/chipmunk_private.h +232 -16
  5. data/ext/chipmunk/chipmunk_types.h +94 -30
  6. data/ext/chipmunk/chipmunk_unsafe.h +12 -3
  7. data/ext/chipmunk/constraints/cpConstraint.h +90 -34
  8. data/ext/chipmunk/{cpDampedRotarySpring.h → constraints/cpDampedRotarySpring.h} +18 -8
  9. data/ext/chipmunk/{cpDampedSpring.h → constraints/cpDampedSpring.h} +27 -16
  10. data/ext/chipmunk/constraints/cpGearJoint.h +17 -7
  11. data/ext/chipmunk/constraints/cpGrooveJoint.h +19 -10
  12. data/ext/chipmunk/constraints/cpPinJoint.h +17 -8
  13. data/ext/chipmunk/constraints/cpPivotJoint.h +18 -9
  14. data/ext/chipmunk/constraints/cpRatchetJoint.h +17 -8
  15. data/ext/chipmunk/constraints/cpRotaryLimitJoint.h +16 -7
  16. data/ext/chipmunk/{cpSimpleMotor.h → constraints/cpSimpleMotor.h} +15 -6
  17. data/ext/chipmunk/constraints/cpSlideJoint.h +18 -9
  18. data/ext/chipmunk/constraints/util.h +36 -44
  19. data/ext/chipmunk/cpArbiter.c +159 -94
  20. data/ext/chipmunk/cpArbiter.h +135 -129
  21. data/ext/chipmunk/cpArray.c +37 -56
  22. data/ext/chipmunk/cpBB.c +1 -12
  23. data/ext/chipmunk/cpBB.h +80 -18
  24. data/ext/chipmunk/cpBBTree.c +891 -0
  25. data/ext/chipmunk/cpBody.c +185 -47
  26. data/ext/chipmunk/cpBody.h +156 -124
  27. data/ext/chipmunk/cpCollision.c +126 -115
  28. data/ext/chipmunk/cpConstraint.c +10 -6
  29. data/ext/chipmunk/cpDampedRotarySpring.c +26 -17
  30. data/ext/chipmunk/cpDampedSpring.c +25 -18
  31. data/ext/chipmunk/cpGearJoint.c +23 -17
  32. data/ext/chipmunk/cpGrooveJoint.c +26 -22
  33. data/ext/chipmunk/cpHashSet.c +51 -51
  34. data/ext/chipmunk/cpPinJoint.c +26 -19
  35. data/ext/chipmunk/cpPivotJoint.c +23 -19
  36. data/ext/chipmunk/cpPolyShape.c +93 -69
  37. data/ext/chipmunk/cpPolyShape.h +33 -69
  38. data/ext/chipmunk/cpRatchetJoint.c +26 -21
  39. data/ext/chipmunk/cpRotaryLimitJoint.c +28 -22
  40. data/ext/chipmunk/cpShape.c +122 -133
  41. data/ext/chipmunk/cpShape.h +146 -95
  42. data/ext/chipmunk/cpSimpleMotor.c +24 -17
  43. data/ext/chipmunk/cpSlideJoint.c +28 -26
  44. data/ext/chipmunk/cpSpace.c +251 -196
  45. data/ext/chipmunk/cpSpace.h +173 -103
  46. data/ext/chipmunk/cpSpaceComponent.c +236 -159
  47. data/ext/chipmunk/cpSpaceHash.c +259 -159
  48. data/ext/chipmunk/cpSpaceQuery.c +127 -59
  49. data/ext/chipmunk/cpSpaceStep.c +235 -197
  50. data/ext/chipmunk/cpSpatialIndex.c +69 -0
  51. data/ext/chipmunk/cpSpatialIndex.h +227 -0
  52. data/ext/chipmunk/cpSweep1D.c +254 -0
  53. data/ext/chipmunk/cpVect.c +11 -26
  54. data/ext/chipmunk/cpVect.h +76 -71
  55. data/ext/chipmunk/extconf.rb +4 -31
  56. data/ext/chipmunk/prime.h +1 -1
  57. data/ext/chipmunk/rb_chipmunk.c +36 -45
  58. data/ext/chipmunk/rb_chipmunk.h +6 -3
  59. data/ext/chipmunk/rb_cpArbiter.c +2 -2
  60. data/ext/chipmunk/rb_cpBB.c +116 -35
  61. data/ext/chipmunk/rb_cpBody.c +5 -12
  62. data/ext/chipmunk/rb_cpConstraint.c +144 -9
  63. data/ext/chipmunk/rb_cpShape.c +69 -78
  64. data/ext/chipmunk/rb_cpSpace.c +81 -76
  65. metadata +61 -61
  66. data/LICENSE +0 -22
  67. data/README +0 -110
  68. data/Rakefile +0 -102
  69. data/ext/chipmunk/cpArray.h +0 -49
  70. data/ext/chipmunk/cpCollision.h +0 -28
  71. data/ext/chipmunk/cpHashSet.h +0 -82
  72. data/ext/chipmunk/cpSpaceHash.h +0 -110
  73. data/lib/chipmunk.rb +0 -194
@@ -19,10 +19,6 @@
19
19
  * SOFTWARE.
20
20
  */
21
21
 
22
- #include <stdlib.h>
23
- #include <math.h>
24
- //#include <stdio.h>
25
-
26
22
  #include "chipmunk_private.h"
27
23
 
28
24
  typedef int (*collisionFunc)(const cpShape *, const cpShape *, cpContact *);
@@ -55,60 +51,36 @@ circle2circleQuery(const cpVect p1, const cpVect p2, const cpFloat r1, const cpF
55
51
  static int
56
52
  circle2circle(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
57
53
  {
58
- cpCircleShape *circ1 = (cpCircleShape *)shape1;
54
+ cpCircleShape *circ1 = (cpCircleShape *)shape1; //TODO
59
55
  cpCircleShape *circ2 = (cpCircleShape *)shape2;
60
56
 
61
57
  return circle2circleQuery(circ1->tc, circ2->tc, circ1->r, circ2->r, arr);
62
58
  }
63
59
 
64
- // Collide circles to segment shapes.
65
60
  static int
66
- circle2segment(const cpShape *circleShape, const cpShape *segmentShape, cpContact *con)
61
+ circle2segment(const cpCircleShape *circleShape, const cpSegmentShape *segmentShape, cpContact *con)
67
62
  {
68
- cpCircleShape *circ = (cpCircleShape *)circleShape;
69
- cpSegmentShape *seg = (cpSegmentShape *)segmentShape;
70
-
71
- // Radius sum
72
- cpFloat rsum = circ->r + seg->r;
63
+ cpVect seg_a = segmentShape->ta;
64
+ cpVect seg_b = segmentShape->tb;
65
+ cpVect center = circleShape->tc;
73
66
 
74
- // Calculate normal distance from segment.
75
- cpFloat dn = cpvdot(seg->tn, circ->tc) - cpvdot(seg->ta, seg->tn);
76
- cpFloat dist = cpfabs(dn) - rsum;
77
- if(dist > 0.0f) return 0;
67
+ cpVect seg_delta = cpvsub(seg_b, seg_a);
68
+ cpFloat closest_t = cpfclamp01(cpvdot(seg_delta, cpvsub(center, seg_a))/cpvlengthsq(seg_delta));
69
+ cpVect closest = cpvadd(seg_a, cpvmult(seg_delta, closest_t));
78
70
 
79
- // Calculate tangential distance along segment.
80
- cpFloat dt = -cpvcross(seg->tn, circ->tc);
81
- cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
82
- cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
83
-
84
- // Decision tree to decide which feature of the segment to collide with.
85
- if(dt < dtMin){
86
- if(dt < (dtMin - rsum)){
87
- return 0;
88
- } else {
89
- return circle2circleQuery(circ->tc, seg->ta, circ->r, seg->r, con);
90
- }
71
+ if(circle2circleQuery(center, closest, circleShape->r, segmentShape->r, con)){
72
+ cpVect n = con[0].n;
73
+
74
+ // Reject endcap collisions if tangents are provided.
75
+ if(
76
+ (closest_t == 0.0f && cpvdot(n, segmentShape->a_tangent) < 0.0) ||
77
+ (closest_t == 1.0f && cpvdot(n, segmentShape->b_tangent) < 0.0)
78
+ ) return 0;
79
+
80
+ return 1;
91
81
  } else {
92
- if(dt < dtMax){
93
- cpVect n = (dn < 0.0f) ? seg->tn : cpvneg(seg->tn);
94
- cpContactInit(
95
- con,
96
- cpvadd(circ->tc, cpvmult(n, circ->r + dist*0.5f)),
97
- n,
98
- dist,
99
- 0
100
- );
101
- return 1;
102
- } else {
103
- if(dt < (dtMax + rsum)) {
104
- return circle2circleQuery(circ->tc, seg->tb, circ->r, seg->r, con);
105
- } else {
106
- return 0;
107
- }
108
- }
82
+ return 0;
109
83
  }
110
-
111
- return 1;
112
84
  }
113
85
 
114
86
  // Helper function for working with contact buffers
@@ -128,14 +100,14 @@ nextContactPoint(cpContact *arr, int *numPtr)
128
100
 
129
101
  // Find the minimum separating axis for the give poly and axis list.
130
102
  static inline int
131
- findMSA(const cpPolyShape *poly, const cpPolyShapeAxis *axes, const int num, cpFloat *min_out)
103
+ findMSA(const cpPolyShape *poly, const cpSplittingPlane *planes, const int num, cpFloat *min_out)
132
104
  {
133
105
  int min_index = 0;
134
- cpFloat min = cpPolyShapeValueOnAxis(poly, axes->n, axes->d);
106
+ cpFloat min = cpPolyShapeValueOnAxis(poly, planes->n, planes->d);
135
107
  if(min > 0.0f) return -1;
136
108
 
137
109
  for(int i=1; i<num; i++){
138
- cpFloat dist = cpPolyShapeValueOnAxis(poly, axes[i].n, axes[i].d);
110
+ cpFloat dist = cpPolyShapeValueOnAxis(poly, planes[i].n, planes[i].d);
139
111
  if(dist > 0.0f) {
140
112
  return -1;
141
113
  } else if(dist > min){
@@ -200,18 +172,18 @@ poly2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
200
172
  cpPolyShape *poly2 = (cpPolyShape *)shape2;
201
173
 
202
174
  cpFloat min1;
203
- int mini1 = findMSA(poly2, poly1->tAxes, poly1->numVerts, &min1);
175
+ int mini1 = findMSA(poly2, poly1->tPlanes, poly1->numVerts, &min1);
204
176
  if(mini1 == -1) return 0;
205
177
 
206
178
  cpFloat min2;
207
- int mini2 = findMSA(poly1, poly2->tAxes, poly2->numVerts, &min2);
179
+ int mini2 = findMSA(poly1, poly2->tPlanes, poly2->numVerts, &min2);
208
180
  if(mini2 == -1) return 0;
209
181
 
210
182
  // There is overlap, find the penetrating verts
211
183
  if(min1 > min2)
212
- return findVerts(arr, poly1, poly2, poly1->tAxes[mini1].n, min1);
184
+ return findVerts(arr, poly1, poly2, poly1->tPlanes[mini1].n, min1);
213
185
  else
214
- return findVerts(arr, poly1, poly2, cpvneg(poly2->tAxes[mini2].n), min2);
186
+ return findVerts(arr, poly1, poly2, cpvneg(poly2->tPlanes[mini2].n), min2);
215
187
  }
216
188
 
217
189
  // Like cpPolyValueOnAxis(), but for segments.
@@ -249,7 +221,7 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
249
221
  {
250
222
  cpSegmentShape *seg = (cpSegmentShape *)shape1;
251
223
  cpPolyShape *poly = (cpPolyShape *)shape2;
252
- cpPolyShapeAxis *axes = poly->tAxes;
224
+ cpSplittingPlane *planes = poly->tPlanes;
253
225
 
254
226
  cpFloat segD = cpvdot(seg->tn, seg->ta);
255
227
  cpFloat minNorm = cpPolyShapeValueOnAxis(poly, seg->tn, segD) - seg->r;
@@ -257,10 +229,10 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
257
229
  if(minNeg > 0.0f || minNorm > 0.0f) return 0;
258
230
 
259
231
  int mini = 0;
260
- cpFloat poly_min = segValueOnAxis(seg, axes->n, axes->d);
232
+ cpFloat poly_min = segValueOnAxis(seg, planes->n, planes->d);
261
233
  if(poly_min > 0.0f) return 0;
262
234
  for(int i=0; i<poly->numVerts; i++){
263
- cpFloat dist = segValueOnAxis(seg, axes[i].n, axes[i].d);
235
+ cpFloat dist = segValueOnAxis(seg, planes[i].n, planes[i].d);
264
236
  if(dist > 0.0f){
265
237
  return 0;
266
238
  } else if(dist > poly_min){
@@ -271,7 +243,7 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
271
243
 
272
244
  int num = 0;
273
245
 
274
- cpVect poly_n = cpvneg(axes[mini].n);
246
+ cpVect poly_n = cpvneg(planes[mini].n);
275
247
 
276
248
  cpVect va = cpvadd(seg->ta, cpvmult(poly_n, seg->r));
277
249
  cpVect vb = cpvadd(seg->tb, cpvmult(poly_n, seg->r));
@@ -279,10 +251,11 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
279
251
  cpContactInit(nextContactPoint(arr, &num), va, poly_n, poly_min, CP_HASH_PAIR(seg->shape.hashid, 0));
280
252
  if(cpPolyShapeContainsVert(poly, vb))
281
253
  cpContactInit(nextContactPoint(arr, &num), vb, poly_n, poly_min, CP_HASH_PAIR(seg->shape.hashid, 1));
282
-
254
+
283
255
  // Floating point precision problems here.
284
256
  // This will have to do for now.
285
- poly_min -= cp_collision_slop;
257
+ // poly_min -= cp_collision_slop; // TODO is this needed anymore?
258
+
286
259
  if(minNorm >= poly_min || minNeg >= poly_min) {
287
260
  if(minNorm > minNeg)
288
261
  findPointsBehindSeg(arr, &num, seg, poly, minNorm, 1.0f);
@@ -295,17 +268,10 @@ seg2poly(const cpShape *shape1, const cpShape *shape2, cpContact *arr)
295
268
  cpVect poly_a = poly->tVerts[mini];
296
269
  cpVect poly_b = poly->tVerts[(mini + 1)%poly->numVerts];
297
270
 
298
- if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr))
299
- return 1;
300
-
301
- if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr))
302
- return 1;
303
-
304
- if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr))
305
- return 1;
306
-
307
- if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr))
308
- return 1;
271
+ if(circle2circleQuery(seg->ta, poly_a, seg->r, 0.0f, arr)) return 1;
272
+ if(circle2circleQuery(seg->tb, poly_a, seg->r, 0.0f, arr)) return 1;
273
+ if(circle2circleQuery(seg->ta, poly_b, seg->r, 0.0f, arr)) return 1;
274
+ if(circle2circleQuery(seg->tb, poly_b, seg->r, 0.0f, arr)) return 1;
309
275
  }
310
276
 
311
277
  return num;
@@ -318,12 +284,12 @@ circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
318
284
  {
319
285
  cpCircleShape *circ = (cpCircleShape *)shape1;
320
286
  cpPolyShape *poly = (cpPolyShape *)shape2;
321
- cpPolyShapeAxis *axes = poly->tAxes;
287
+ cpSplittingPlane *planes = poly->tPlanes;
322
288
 
323
289
  int mini = 0;
324
- cpFloat min = cpvdot(axes->n, circ->tc) - axes->d - circ->r;
290
+ cpFloat min = cpSplittingPlaneCompare(planes[0], circ->tc) - circ->r;
325
291
  for(int i=0; i<poly->numVerts; i++){
326
- cpFloat dist = cpvdot(axes[i].n, circ->tc) - axes[i].d - circ->r;
292
+ cpFloat dist = cpSplittingPlaneCompare(planes[i], circ->tc) - circ->r;
327
293
  if(dist > 0.0f){
328
294
  return 0;
329
295
  } else if(dist > min) {
@@ -332,7 +298,7 @@ circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
332
298
  }
333
299
  }
334
300
 
335
- cpVect n = axes[mini].n;
301
+ cpVect n = planes[mini].n;
336
302
  cpVect a = poly->tVerts[mini];
337
303
  cpVect b = poly->tVerts[(mini + 1)%poly->numVerts];
338
304
  cpFloat dta = cpvcross(n, a);
@@ -356,55 +322,100 @@ circle2poly(const cpShape *shape1, const cpShape *shape2, cpContact *con)
356
322
  }
357
323
  }
358
324
 
359
- //static const collisionFunc builtinCollisionFuncs[9] = {
360
- // circle2circle,
361
- // NULL,
362
- // NULL,
363
- // circle2segment,
364
- // NULL,
365
- // NULL,
366
- // circle2poly,
367
- // seg2poly,
368
- // poly2poly,
369
- //};
370
- //static const collisionFunc *colfuncs = builtinCollisionFuncs;
371
-
372
- static collisionFunc *colfuncs = NULL;
373
-
374
- static void
375
- addColFunc(const cpShapeType a, const cpShapeType b, const collisionFunc func)
325
+ // Submitted by LegoCyclon
326
+ static int
327
+ seg2seg(const cpShape* shape1, const cpShape* shape2, cpContact* con)
376
328
  {
377
- colfuncs[a + b*CP_NUM_SHAPES] = func;
329
+ cpSegmentShape* seg1 = (cpSegmentShape *)shape1;
330
+ cpSegmentShape* seg2 = (cpSegmentShape *)shape2;
331
+
332
+ cpVect v1 = cpvsub(seg1->tb, seg1->ta);
333
+ cpVect v2 = cpvsub(seg2->tb, seg2->ta);
334
+ cpFloat v1lsq = cpvlengthsq(v1);
335
+ cpFloat v2lsq = cpvlengthsq(v2);
336
+ // project seg2 onto seg1
337
+ cpVect p1a = cpvproject(cpvsub(seg2->ta, seg1->ta), v1);
338
+ cpVect p1b = cpvproject(cpvsub(seg2->tb, seg1->ta), v1);
339
+ // project seg1 onto seg2
340
+ cpVect p2a = cpvproject(cpvsub(seg1->ta, seg2->ta), v2);
341
+ cpVect p2b = cpvproject(cpvsub(seg1->tb, seg2->ta), v2);
342
+
343
+ // clamp projections to segment endcaps
344
+ if (cpvdot(p1a, v1) < 0.0f)
345
+ p1a = cpvzero;
346
+ else if (cpvdot(p1a, v1) > 0.0f && cpvlengthsq(p1a) > v1lsq)
347
+ p1a = v1;
348
+ if (cpvdot(p1b, v1) < 0.0f)
349
+ p1b = cpvzero;
350
+ else if (cpvdot(p1b, v1) > 0.0f && cpvlengthsq(p1b) > v1lsq)
351
+ p1b = v1;
352
+ if (cpvdot(p2a, v2) < 0.0f)
353
+ p2a = cpvzero;
354
+ else if (cpvdot(p2a, v2) > 0.0f && cpvlengthsq(p2a) > v2lsq)
355
+ p2a = v2;
356
+ if (cpvdot(p2b, v2) < 0.0f)
357
+ p2b = cpvzero;
358
+ else if (cpvdot(p2b, v2) > 0.0f && cpvlengthsq(p2b) > v2lsq)
359
+ p2b = v2;
360
+
361
+ p1a = cpvadd(p1a, seg1->ta);
362
+ p1b = cpvadd(p1b, seg1->ta);
363
+ p2a = cpvadd(p2a, seg2->ta);
364
+ p2b = cpvadd(p2b, seg2->ta);
365
+
366
+ int num = 0;
367
+
368
+ if (!circle2circleQuery(p1a, p2a, seg1->r, seg2->r, nextContactPoint(con, &num)))
369
+ --num;
370
+
371
+ if (!circle2circleQuery(p1b, p2b, seg1->r, seg2->r, nextContactPoint(con, &num)))
372
+ --num;
373
+
374
+ if (!circle2circleQuery(p1a, p2b, seg1->r, seg2->r, nextContactPoint(con, &num)))
375
+ --num;
376
+
377
+ if (!circle2circleQuery(p1b, p2a, seg1->r, seg2->r, nextContactPoint(con, &num)))
378
+ --num;
379
+
380
+ return num;
378
381
  }
379
382
 
380
- #ifdef __cplusplus
381
- extern "C" {
382
- #endif
383
- void cpInitCollisionFuncs(void);
384
-
385
- // Initializes the array of collision functions.
386
- // Called by cpInitChipmunk().
387
- void
388
- cpInitCollisionFuncs(void)
389
- {
390
- if(!colfuncs)
391
- colfuncs = (collisionFunc *)cpcalloc(CP_NUM_SHAPES*CP_NUM_SHAPES, sizeof(collisionFunc));
392
-
393
- addColFunc(CP_CIRCLE_SHAPE, CP_CIRCLE_SHAPE, circle2circle);
394
- addColFunc(CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, circle2segment);
395
- addColFunc(CP_SEGMENT_SHAPE, CP_POLY_SHAPE, seg2poly);
396
- addColFunc(CP_CIRCLE_SHAPE, CP_POLY_SHAPE, circle2poly);
397
- addColFunc(CP_POLY_SHAPE, CP_POLY_SHAPE, poly2poly);
398
- }
399
- #ifdef __cplusplus
383
+ static const collisionFunc builtinCollisionFuncs[9] = {
384
+ circle2circle,
385
+ NULL,
386
+ NULL,
387
+ (collisionFunc)circle2segment,
388
+ NULL,
389
+ NULL,
390
+ circle2poly,
391
+ seg2poly,
392
+ poly2poly,
393
+ };
394
+ static const collisionFunc *colfuncs = builtinCollisionFuncs;
395
+
396
+ static const collisionFunc segmentCollisions[9] = {
397
+ circle2circle,
398
+ NULL,
399
+ NULL,
400
+ (collisionFunc)circle2segment,
401
+ seg2seg,
402
+ NULL,
403
+ circle2poly,
404
+ seg2poly,
405
+ poly2poly,
406
+ };
407
+
408
+ void
409
+ cpEnableSegmentToSegmentCollisions(void)
410
+ {
411
+ colfuncs = segmentCollisions;
400
412
  }
401
- #endif
402
413
 
403
414
  int
404
415
  cpCollideShapes(const cpShape *a, const cpShape *b, cpContact *arr)
405
416
  {
406
417
  // Their shape types must be in order.
407
- cpAssert(a->klass->type <= b->klass->type, "Collision shapes passed to cpCollideShapes() are not sorted.");
418
+ cpAssertSoft(a->klass->type <= b->klass->type, "Collision shapes passed to cpCollideShapes() are not sorted.");
408
419
 
409
420
  collisionFunc cfunc = colfuncs[a->klass->type + b->klass->type*CP_NUM_SHAPES];
410
421
  return (cfunc) ? cfunc(a, b, arr) : 0;
@@ -19,15 +19,11 @@
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
  // TODO: Comment me!
28
26
 
29
- cpFloat cp_constraint_bias_coef = 0.1f;
30
-
31
27
  void cpConstraintDestroy(cpConstraint *constraint){}
32
28
 
33
29
  void
@@ -39,16 +35,24 @@ cpConstraintFree(cpConstraint *constraint)
39
35
  }
40
36
  }
41
37
 
42
- // *** defined in util.h
38
+ // *** declared in util.h TODO move declaration to chipmunk_private.h
43
39
 
44
40
  void
45
41
  cpConstraintInit(cpConstraint *constraint, const cpConstraintClass *klass, cpBody *a, cpBody *b)
46
42
  {
47
43
  constraint->klass = klass;
44
+
48
45
  constraint->a = a;
49
46
  constraint->b = b;
47
+ constraint->space = NULL;
48
+
49
+ constraint->next_a = NULL;
50
+ constraint->next_b = NULL;
50
51
 
51
52
  constraint->maxForce = (cpFloat)INFINITY;
52
- constraint->biasCoef = cp_constraint_bias_coef;
53
+ constraint->errorBias = cpfpow(1.0f - 0.1f, 60.0f);
53
54
  constraint->maxBias = (cpFloat)INFINITY;
55
+
56
+ constraint->preSolve = NULL;
57
+ constraint->postSolve = NULL;
54
58
  }
@@ -19,9 +19,6 @@
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
 
@@ -31,11 +28,13 @@ defaultSpringTorque(cpDampedRotarySpring *spring, cpFloat relativeAngle){
31
28
  }
32
29
 
33
30
  static void
34
- preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv)
31
+ preStep(cpDampedRotarySpring *spring, cpFloat dt)
35
32
  {
36
- CONSTRAINT_BEGIN(spring, a, b);
33
+ cpBody *a = spring->constraint.a;
34
+ cpBody *b = spring->constraint.b;
37
35
 
38
36
  cpFloat moment = a->i_inv + b->i_inv;
37
+ cpAssertSoft(moment != 0.0, "Unsolvable spring.");
39
38
  spring->iSum = 1.0f/moment;
40
39
 
41
40
  spring->w_coef = 1.0f - cpfexp(-spring->damping*dt*moment);
@@ -43,46 +42,54 @@ preStep(cpDampedRotarySpring *spring, cpFloat dt, cpFloat dt_inv)
43
42
 
44
43
  // apply spring torque
45
44
  cpFloat j_spring = spring->springTorqueFunc((cpConstraint *)spring, a->a - b->a)*dt;
45
+ spring->jAcc = j_spring;
46
+
46
47
  a->w -= j_spring*a->i_inv;
47
48
  b->w += j_spring*b->i_inv;
48
49
  }
49
50
 
51
+ static void applyCachedImpulse(cpDampedRotarySpring *spring, cpFloat dt_coef){}
52
+
50
53
  static void
51
- applyImpulse(cpDampedRotarySpring *spring)
54
+ applyImpulse(cpDampedRotarySpring *spring, cpFloat dt)
52
55
  {
53
- CONSTRAINT_BEGIN(spring, a, b);
56
+ cpBody *a = spring->constraint.a;
57
+ cpBody *b = spring->constraint.b;
54
58
 
55
59
  // compute relative velocity
56
60
  cpFloat wrn = a->w - b->w;//normal_relative_velocity(a, b, r1, r2, n) - spring->target_vrn;
57
61
 
58
62
  // compute velocity loss from drag
59
63
  // not 100% certain this is derived correctly, though it makes sense
60
- cpFloat w_damp = wrn*spring->w_coef;
61
- spring->target_wrn = wrn - w_damp;
64
+ cpFloat w_damp = (spring->target_wrn - wrn)*spring->w_coef;
65
+ spring->target_wrn = wrn + w_damp;
62
66
 
63
67
  //apply_impulses(a, b, spring->r1, spring->r2, cpvmult(spring->n, v_damp*spring->nMass));
64
68
  cpFloat j_damp = w_damp*spring->iSum;
65
- a->w -= j_damp*a->i_inv;
66
- b->w += j_damp*b->i_inv;
69
+ spring->jAcc += j_damp;
70
+
71
+ a->w += j_damp*a->i_inv;
72
+ b->w -= j_damp*b->i_inv;
67
73
  }
68
74
 
69
75
  static cpFloat
70
- getImpulse(cpConstraint *constraint)
76
+ getImpulse(cpDampedRotarySpring *spring)
71
77
  {
72
- return 0.0f;
78
+ return spring->jAcc;
73
79
  }
74
80
 
75
81
  static const cpConstraintClass klass = {
76
- (cpConstraintPreStepFunction)preStep,
77
- (cpConstraintApplyImpulseFunction)applyImpulse,
78
- (cpConstraintGetImpulseFunction)getImpulse,
82
+ (cpConstraintPreStepImpl)preStep,
83
+ (cpConstraintApplyCachedImpulseImpl)applyCachedImpulse,
84
+ (cpConstraintApplyImpulseImpl)applyImpulse,
85
+ (cpConstraintGetImpulseImpl)getImpulse,
79
86
  };
80
87
  CP_DefineClassGetter(cpDampedRotarySpring)
81
88
 
82
89
  cpDampedRotarySpring *
83
90
  cpDampedRotarySpringAlloc(void)
84
91
  {
85
- return (cpDampedRotarySpring *)cpmalloc(sizeof(cpDampedRotarySpring));
92
+ return (cpDampedRotarySpring *)cpcalloc(1, sizeof(cpDampedRotarySpring));
86
93
  }
87
94
 
88
95
  cpDampedRotarySpring *
@@ -95,6 +102,8 @@ cpDampedRotarySpringInit(cpDampedRotarySpring *spring, cpBody *a, cpBody *b, cpF
95
102
  spring->damping = damping;
96
103
  spring->springTorqueFunc = (cpDampedRotarySpringTorqueFunc)defaultSpringTorque;
97
104
 
105
+ spring->jAcc = 0.0f;
106
+
98
107
  return spring;
99
108
  }
100
109