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.
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