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
@@ -33,6 +33,8 @@ extern VALUE c_cpSpace;
33
33
  extern VALUE c_cpArbiter;
34
34
  extern VALUE c_cpStaticBody;
35
35
  extern VALUE c_cpSegmentQueryInfo;
36
+ extern VALUE c_cpNearestPointQueryInfo;
37
+ extern VALUE cpObjectToIntHash;
36
38
 
37
39
  extern ID id_parent;
38
40
 
@@ -51,6 +53,8 @@ VWRAP(VALUE parent, cpVect *v) {
51
53
  return vec_obj;
52
54
  }
53
55
 
56
+ int cp_rb_obj_method_arity(VALUE self, ID id);
57
+
54
58
  #define GETTER_TEMPLATE(func_name, klass, type) \
55
59
  static inline type * \
56
60
  func_name(VALUE self) \
@@ -85,10 +89,9 @@ VGET_ZERO(VALUE value) {
85
89
  return *VGET(value);
86
90
  }
87
91
 
88
- //Helper that allocates and initializes a SegmenQueryInfo struct
92
+ int CP_OBJ2INT(VALUE object);
89
93
  VALUE rb_cpSegmentQueryInfoNew(VALUE shape, VALUE t, VALUE n);
90
-
91
- // Helper that allocates and initializes a ContactPoint struct.
94
+ VALUE rb_cpNearestPointQueryInfoNew(VALUE shape, VALUE p, VALUE d);
92
95
  VALUE rb_cpContactPointNew(VALUE point, VALUE normal, VALUE dist);
93
96
 
94
97
 
@@ -193,8 +193,8 @@ rb_cpArbiterGetDepth(VALUE self, VALUE index) {
193
193
  if (arbiterBadIndex(arb, i)) {
194
194
  rb_raise(rb_eIndexError, "No such depth.");
195
195
  }
196
- // there"s a typo in the cpArbiter.h class.
197
- return rb_float_new(cpArbiteGetDepth(arb, i));
196
+ // there was a typo in the cpArbiter.h class but ,no more in 6.0.3.
197
+ return rb_float_new(cpArbiterGetDepth(arb, i));
198
198
  }
199
199
 
200
200
 
@@ -41,45 +41,94 @@ rb_cpBBAlloc(VALUE klass) {
41
41
  }
42
42
 
43
43
  static VALUE
44
- rb_cpBBInitialize(VALUE self, VALUE l, VALUE b, VALUE r, VALUE t) {
44
+ rb_cpBBInitialize(int argc, VALUE *argv, VALUE self) {
45
+ VALUE l, b, r, t;
45
46
  cpBB *bb = BBGET(self);
46
- bb->l = NUM2DBL(l);
47
- bb->b = NUM2DBL(b);
48
- bb->r = NUM2DBL(r);
49
- bb->t = NUM2DBL(t);
50
47
 
48
+ rb_scan_args(argc, argv, "04", &l, &b, &r, &t);
49
+ // initialize as a circle bounds box if ony 2 params
50
+ if (NIL_P(r)) {
51
+ if(NIL_P(l)) {
52
+ (*bb) = cpBBNew(0, 0, 1, 1); // unit box.
53
+ } else {
54
+ cpVect * p = VGET(l);
55
+ (*bb) = cpBBNewForCircle(*p, NUM2DBL(b));
56
+ }
57
+ } else {
58
+ (*bb) = cpBBNew(NUM2DBL(l), NUM2DBL(b), NUM2DBL(r), NUM2DBL(t));
59
+ }
51
60
  return self;
52
61
  }
53
62
 
63
+ /*
54
64
  static VALUE
55
- rb_cpBBintersects(VALUE self, VALUE other) {
56
- int value = cpBBintersects(*BBGET(self), *BBGET(other));
57
- return value ? Qtrue : Qfalse;
65
+ rb_cpBBintersects(VALUE self, VALUE a, VALUE b) {
66
+ cpVect *a, *b;
67
+ if(IS_NIL(b)) { // box/box intersect
68
+ return CP_INT_BOOL(cpBBIntersects(*BBGET(self), *BBGET(a)));
69
+ }
70
+ // If we get here it's a box/segment intersect
71
+ a = VGET(va);
72
+ b = VGET(vb);
73
+ if(a && b) {
74
+ return CP_INT_BOOL(cpBBIntersectsSegment(*BBGET(self), *a, *b));
75
+ }
76
+ rb_raise(rb_eArgError, "intersects needs 1 Box or 2 Vect2 arguments");
77
+ return Qnil;
58
78
  }
79
+ */
59
80
 
60
81
  static VALUE
61
- rb_cpBBcontainsBB(VALUE self, VALUE other) {
62
- int value = cpBBcontainsBB(*BBGET(self), *BBGET(other));
63
- return value ? Qtrue : Qfalse;
82
+ rb_cpBBContainsBB(VALUE self, VALUE other) {
83
+ int value = cpBBContainsBB(*BBGET(self), *BBGET(other));
84
+ return CP_INT_BOOL(value);
64
85
  }
65
86
 
66
87
  static VALUE
67
- rb_cpBBcontainsVect(VALUE self, VALUE other) {
68
- int value = cpBBcontainsVect(*BBGET(self), *VGET(other));
69
- return value ? Qtrue : Qfalse;
88
+ rb_cpBBContainsVect(VALUE self, VALUE other) {
89
+ int value = cpBBContainsVect(*BBGET(self), *VGET(other));
90
+ return CP_INT_BOOL(value);
70
91
  }
71
92
 
72
93
  static VALUE
73
94
  rb_cpBBcontains(VALUE self, VALUE other) {
74
95
  if (rb_class_of(other) == c_cpBB) {
75
- return rb_cpBBcontainsBB(self, other);
96
+ return rb_cpBBContainsBB(self, other);
76
97
  } else if (rb_class_of(other) == c_cpVect) {
77
- return rb_cpBBcontainsVect(self, other);
98
+ return rb_cpBBContainsVect(self, other);
78
99
  }
79
- rb_raise(rb_eArgError, "contains works only with a BB or A Vect2 argument");
100
+ rb_raise(rb_eArgError, "contains requires a BB or a Vect2 argument");
80
101
  return Qnil;
81
102
  }
82
103
 
104
+ static VALUE
105
+ rb_cpBBIntersectsBB(VALUE self, VALUE other) {
106
+ int value = cpBBIntersects(*BBGET(self), *BBGET(other));
107
+ return CP_INT_BOOL(value);
108
+ }
109
+
110
+ static VALUE
111
+ rb_cpBBIntersectsSegment(VALUE self, VALUE a, VALUE b) {
112
+ int value = cpBBIntersectsSegment(*BBGET(self), *VGET(a), *VGET(b));
113
+ return CP_INT_BOOL(value);
114
+ }
115
+
116
+ static VALUE
117
+ rb_cpBBintersects(int argc, VALUE *argv, VALUE self) {
118
+ VALUE other, b;
119
+
120
+ rb_scan_args(argc, argv, "11", &other, &b);
121
+
122
+ if (rb_class_of(other) == c_cpBB) {
123
+ return rb_cpBBIntersectsBB(self, other);
124
+ } else if ((rb_class_of(other) == c_cpVect) && (rb_class_of(b) == c_cpVect)) {
125
+ return rb_cpBBIntersectsSegment(self, other, b);
126
+ }
127
+ rb_raise(rb_eArgError, "contains requires a BB or 2 Vect2 arguments");
128
+ return Qnil;
129
+ }
130
+
131
+
83
132
  static VALUE
84
133
  rb_cpBBClampVect(VALUE self, VALUE v) {
85
134
  return VNEW(cpBBClampVect(*BBGET(self), *VGET(v)));
@@ -146,12 +195,35 @@ rb_cpBBToString(VALUE self) {
146
195
 
147
196
  static VALUE
148
197
  rb_cpBBmerge(VALUE self, VALUE other) {
149
- return BBNEW(cpBBmerge(*BBGET(self), *BBGET(other)));
198
+ return BBNEW(cpBBMerge(*BBGET(self), *BBGET(other)));
150
199
  }
151
200
 
152
201
  static VALUE
153
202
  rb_cpBBexpand(VALUE self, VALUE other) {
154
- return BBNEW(cpBBexpand(*BBGET(self), *VGET(other)));
203
+ return BBNEW(cpBBExpand(*BBGET(self), *VGET(other)));
204
+ }
205
+
206
+ static VALUE
207
+ rb_cpBBArea(VALUE self) {
208
+ return DBL2NUM(cpBBArea(*BBGET(self)));
209
+ }
210
+
211
+ static VALUE
212
+ rb_cpBBMergedArea(VALUE self, VALUE other) {
213
+ return DBL2NUM(cpBBMergedArea(*BBGET(self), *BBGET(other)));
214
+ }
215
+
216
+ /// Returns the fraction along the segment query the cpBB is hit. Returns INFINITY if it doesn't hit.
217
+ static VALUE
218
+ rb_cpBBSegmentQuery(VALUE self, VALUE va, VALUE vb) {
219
+ cpVect *a, *b;
220
+ a = VGET(va);
221
+ b = VGET(vb);
222
+ if(a && b) {
223
+ return DBL2NUM(cpBBSegmentQuery(*BBGET(self), *a, *b));
224
+ }
225
+ rb_raise(rb_eArgError, "query requires 2 Vect2 arguments");
226
+ return Qnil;
155
227
  }
156
228
 
157
229
 
@@ -159,7 +231,7 @@ void
159
231
  Init_cpBB(void) {
160
232
  c_cpBB = rb_define_class_under(m_Chipmunk, "BB", rb_cObject);
161
233
  rb_define_alloc_func(c_cpBB, rb_cpBBAlloc);
162
- rb_define_method(c_cpBB, "initialize", rb_cpBBInitialize, 4);
234
+ rb_define_method(c_cpBB, "initialize", rb_cpBBInitialize, -1);
163
235
 
164
236
  rb_define_method(c_cpBB, "l", rb_cpBBGetL, 0);
165
237
  rb_define_method(c_cpBB, "b", rb_cpBBGetB, 0);
@@ -171,23 +243,32 @@ Init_cpBB(void) {
171
243
  rb_define_method(c_cpBB, "r=", rb_cpBBSetR, 1);
172
244
  rb_define_method(c_cpBB, "t=", rb_cpBBSetT, 1);
173
245
 
174
- rb_define_method(c_cpBB, "intersect?", rb_cpBBintersects, 1);
175
- rb_define_method(c_cpBB, "intersects?", rb_cpBBintersects, 1);
246
+ rb_define_method(c_cpBB, "intersect?", rb_cpBBintersects, -1);
247
+ rb_define_method(c_cpBB, "intersects?", rb_cpBBintersects, -1);
248
+
176
249
  //containsBB
177
250
  //containsVect
178
- rb_define_method(c_cpBB, "contains?", rb_cpBBcontains, 1);
179
- rb_define_method(c_cpBB, "contain?", rb_cpBBcontains, 1);
180
-
181
- rb_define_method(c_cpBB, "contains_bb?", rb_cpBBcontainsBB, 1);
182
- rb_define_method(c_cpBB, "contain_bb?", rb_cpBBcontainsBB, 1);
183
- rb_define_method(c_cpBB, "contains_vect?", rb_cpBBcontainsVect, 1);
184
- rb_define_method(c_cpBB, "contain_vect?", rb_cpBBcontainsVect, 1);
185
-
186
- rb_define_method(c_cpBB, "clamp_vect", rb_cpBBClampVect, 1);
187
- rb_define_method(c_cpBB, "wrap_vect", rb_cpBBWrapVect, 1);
188
- rb_define_method(c_cpBB, "merge", rb_cpBBmerge, 1);
189
- rb_define_method(c_cpBB, "expand", rb_cpBBexpand, 1);
190
-
251
+ rb_define_method(c_cpBB, "contains?" , rb_cpBBcontains, 1);
252
+ rb_define_method(c_cpBB, "contain?" , rb_cpBBcontains, 1);
253
+
254
+ rb_define_method(c_cpBB, "contains_bb?", rb_cpBBContainsBB, 1);
255
+ rb_define_method(c_cpBB, "contain_bb?", rb_cpBBContainsBB, 1);
256
+ rb_define_method(c_cpBB, "contains_vect?", rb_cpBBContainsVect, 1);
257
+ rb_define_method(c_cpBB, "contain_vect?", rb_cpBBContainsVect, 1);
258
+
259
+ rb_define_method(c_cpBB, "clamp_vect" , rb_cpBBClampVect, 1);
260
+ rb_define_method(c_cpBB, "wrap_vect" , rb_cpBBWrapVect, 1);
261
+ rb_define_method(c_cpBB, "merge" , rb_cpBBmerge, 1);
262
+ rb_define_method(c_cpBB, "expand" , rb_cpBBexpand, 1);
263
+
264
+ rb_define_method(c_cpBB, "area" , rb_cpBBArea, 0);
265
+ rb_define_method(c_cpBB, "merged_area" , rb_cpBBMergedArea, 1);
266
+
267
+ rb_define_method(c_cpBB, "intersect_bb?", rb_cpBBIntersectsBB, 1);
268
+ rb_define_method(c_cpBB, "intersects_bb?", rb_cpBBIntersectsBB, 1);
269
+ rb_define_method(c_cpBB, "intersect_segment?", rb_cpBBIntersectsSegment, 2);
270
+ rb_define_method(c_cpBB, "intersects_segment?", rb_cpBBIntersectsSegment, 2);
271
+ rb_define_method(c_cpBB, "segment_query", rb_cpBBSegmentQuery, 2);
191
272
 
192
273
  rb_define_method(c_cpBB, "to_s", rb_cpBBToString, 0);
193
274
  }
@@ -242,7 +242,7 @@ rb_cpBodyActivate(VALUE self) {
242
242
  static cpBody *
243
243
  rb_cpBodySleepValidate(VALUE vbody) {
244
244
  cpBody * body = BODY(vbody);
245
- cpSpace *space = body->space;
245
+ cpSpace *space = body->CP_PRIVATE(space);
246
246
  if(!space) {
247
247
  rb_raise(rb_eArgError, "Cannot put a body to sleep that has not been added to a space.");
248
248
  return NULL;
@@ -251,7 +251,7 @@ rb_cpBodySleepValidate(VALUE vbody) {
251
251
  rb_raise(rb_eArgError, "Rogue AND static bodies cannot be put to sleep.");
252
252
  return NULL;
253
253
  }
254
- if(space->locked) {
254
+ if(cpSpaceIsLocked(space)) {
255
255
  rb_raise(rb_eArgError, "Bodies can not be put to sleep during a query or a call to Space#add_collision_func. Put these calls into a post-step callback using Space#add_collision_handler.");
256
256
  return NULL;
257
257
  }
@@ -301,11 +301,13 @@ rb_cpBodyIsRogue(VALUE self) {
301
301
  ID id_velocity_func;
302
302
  ID id_speed_func;
303
303
 
304
+ /*
304
305
  static int
305
306
  respondsTo(VALUE obj, ID method) {
306
307
  VALUE value = rb_funcall(obj, rb_intern("respond_to?"), 1, ID2SYM(method));
307
308
  return RTEST(value);
308
309
  }
310
+ */
309
311
 
310
312
  /*
311
313
 
@@ -327,7 +329,7 @@ static VALUE
327
329
  rb_cpBodySetVelocityFunc(int argc, VALUE *argv, VALUE self) {
328
330
  VALUE block;
329
331
  cpBody * body = BODY(self);
330
- rb_scan_args(argc, argv, "&", &block);
332
+ rb_scan_args(argc, argv, "0&", &block);
331
333
  // Restore defaults if no block
332
334
  if (NIL_P(block)) {
333
335
  body->velocity_func = cpBodyUpdateVelocity; //Default;
@@ -374,19 +376,11 @@ rb_cpBodySetData(VALUE self, VALUE val) {
374
376
  return val;
375
377
  }
376
378
 
377
-
378
- static VALUE
379
- rb_cpBodySlew(VALUE self, VALUE pos, VALUE dt) {
380
- cpBodySlew(BODY(self), *VGET(pos), NUM2DBL(dt));
381
- return self;
382
- }
383
-
384
379
  static VALUE
385
380
  rb_cpBodyKineticEnergy(VALUE self) {
386
381
  return DBL2NUM(cpBodyKineticEnergy(BODY(self)));
387
382
  }
388
383
 
389
-
390
384
  void
391
385
  Init_cpBody(void) {
392
386
  c_cpBody = rb_define_class_under(m_Chipmunk, "Body", rb_cObject);
@@ -459,7 +453,6 @@ Init_cpBody(void) {
459
453
 
460
454
  rb_define_method(c_cpBody, "update_velocity", rb_cpBodyUpdateVelocity, 3);
461
455
  rb_define_method(c_cpBody, "update_position", rb_cpBodyUpdatePosition, 1);
462
- rb_define_method(c_cpBody, "slew", rb_cpBodySlew, 2);
463
456
 
464
457
  rb_define_method(c_cpBody, "static?", rb_cpBodyIsStatic, 0);
465
458
  rb_define_method(c_cpBody, "rogue?", rb_cpBodyIsRogue, 0);
@@ -34,7 +34,7 @@ VALUE m_cpConstraint;
34
34
  { CONSTRAINT(self)->member = NUM2DBL(value); return value;}
35
35
 
36
36
  CONSTRAINT_GETSET_FUNCS(maxForce)
37
- CONSTRAINT_GETSET_FUNCS(biasCoef)
37
+ CONSTRAINT_GETSET_FUNCS(errorBias)
38
38
  CONSTRAINT_GETSET_FUNCS(maxBias)
39
39
 
40
40
 
@@ -65,7 +65,12 @@ CONSTRAINT_GETSET_FUNCS(maxBias)
65
65
 
66
66
  #define ALLOC_TEMPLATE(s, alloc) \
67
67
  static VALUE rb_ ## s ## _alloc(VALUE klass) \
68
- { return Data_Wrap_Struct(klass, NULL, cpConstraintFree, alloc);}
68
+ { \
69
+ s * rb_cpStruct = alloc; \
70
+ VALUE rb_constraint = Data_Wrap_Struct(klass, NULL, cpConstraintFree, rb_cpStruct); \
71
+ rb_cpStruct->constraint.data = (void*)rb_constraint; \
72
+ return rb_constraint; \
73
+ }
69
74
 
70
75
  ALLOC_TEMPLATE(cpPinJoint, cpPinJointAlloc())
71
76
 
@@ -139,9 +144,22 @@ MAKE_FLT_ACCESSORS(cpGearJoint, Ratio);
139
144
  ALLOC_TEMPLATE(cpPivotJoint, cpPivotJointAlloc())
140
145
 
141
146
  static VALUE
142
- rb_cpPivotJoint_init(VALUE self, VALUE a, VALUE b, VALUE anchr1, VALUE anchr2) {
147
+ rb_cpPivotJoint_init(int argc, VALUE *argv, VALUE self) {
148
+ /* rb_cpPivotJoint_init(VALUE self, VALUE a, VALUE b, VALUE anchr1, VALUE anchr2) { */
149
+ VALUE a, b, pivotOrAnchr1, anchr2;
150
+
151
+ rb_scan_args(argc, argv, "31", &a, &b, &pivotOrAnchr1, &anchr2);
152
+
143
153
  cpPivotJoint *joint = (cpPivotJoint *)CONSTRAINT(self);
144
- cpPivotJointInit(joint, BODY(a), BODY(b), *VGET(anchr1), *VGET(anchr2));
154
+
155
+ if(NIL_P(anchr2)) {
156
+ cpVect a1 = (a ? cpBodyWorld2Local(BODY(a), *VGET(pivotOrAnchr1)) : *VGET(pivotOrAnchr1));
157
+ cpVect a2 = (b ? cpBodyWorld2Local(BODY(b), *VGET(pivotOrAnchr1)) : *VGET(pivotOrAnchr1));
158
+ cpPivotJointInit(joint, BODY(a), BODY(b), a1, a2);
159
+ } else {
160
+ cpPivotJointInit(joint, BODY(a), BODY(b), *VGET(pivotOrAnchr1), *VGET(anchr2));
161
+ }
162
+
145
163
  rb_iv_set(self, "@body_a", a);
146
164
  rb_iv_set(self, "@body_b", b);
147
165
 
@@ -213,9 +231,9 @@ rb_cpGrooveJoint_init(VALUE self, VALUE a, VALUE b, VALUE grv_a, VALUE grv_b, VA
213
231
  return self;
214
232
  }
215
233
 
234
+ MAKE_VEC_ACCESSORS(cpGrooveJoint, Anchr2)
216
235
  MAKE_VEC_ACCESSORS(cpGrooveJoint, GrooveA)
217
236
  MAKE_VEC_ACCESSORS(cpGrooveJoint, GrooveB)
218
- MAKE_VEC_ACCESSORS(cpGrooveJoint, Anchr2)
219
237
 
220
238
 
221
239
  ALLOC_TEMPLATE(cpRatchetJoint, cpRatchetJointAlloc())
@@ -239,6 +257,118 @@ rb_cpConstraintGetImpulse(VALUE self) {
239
257
  return rb_float_new(cpConstraintGetImpulse(CONSTRAINT(self)));
240
258
  }
241
259
 
260
+ static void
261
+ rb_cpConstraintPreSolveFunc(cpConstraint *constraint, cpSpace *space) {
262
+ VALUE rb_constraint = (VALUE)constraint->data;
263
+ VALUE callback_block = rb_iv_get(rb_constraint, "@_cp_pre_solve");
264
+
265
+ ID call_id = rb_intern("call");
266
+ int arity = NUM2INT(rb_funcall(callback_block, rb_intern("arity"), 0));
267
+ switch(arity) {
268
+ case 1:
269
+ rb_funcall(callback_block, call_id, 1, (VALUE)space->data);
270
+ break;
271
+ default:
272
+ rb_funcall(callback_block, call_id, 0);
273
+ }
274
+
275
+ }
276
+
277
+ static void
278
+ rb_cpConstraintPostSolveFunc(cpConstraint *constraint, cpSpace *space) {
279
+ VALUE rb_constraint = (VALUE)constraint->data;
280
+ VALUE callback_block = rb_iv_get(rb_constraint, "@_cp_post_solve");
281
+
282
+ ID call_id = rb_intern("call");
283
+ int arity = NUM2INT(rb_funcall(callback_block, rb_intern("arity"), 0));
284
+ switch(arity) {
285
+ case 1:
286
+ rb_funcall(callback_block, call_id, 1, (VALUE)space->data);
287
+ break;
288
+ default:
289
+ rb_funcall(callback_block, call_id, 0);
290
+ }
291
+
292
+ }
293
+
294
+ static cpFloat
295
+ rb_cpDampedSpringForceFunc(cpConstraint *constraint, cpFloat dist) {
296
+ VALUE rb_constraint = (VALUE)constraint->data;
297
+ VALUE callback_block = rb_iv_get(rb_constraint, "@_cp_force_func");
298
+
299
+ ID call_id = rb_intern("call");
300
+ int arity = NUM2INT(rb_funcall(callback_block, rb_intern("arity"), 0));
301
+ switch(arity) {
302
+ case 1:
303
+ // TODO is NUM2DBL what I want here?
304
+ return NUM2DBL(rb_funcall(callback_block, call_id, 1, rb_float_new(dist)));
305
+ default:
306
+ return NUM2DBL(rb_funcall(callback_block, call_id, 0));
307
+ }
308
+
309
+ }
310
+
311
+ static cpFloat
312
+ rb_cpDampedRotarySpringTorqueFunc(cpConstraint *constraint, cpFloat relativeAngle) {
313
+ VALUE rb_constraint = (VALUE)constraint->data;
314
+ VALUE callback_block = rb_iv_get(rb_constraint, "@_cp_torque_func");
315
+
316
+ ID call_id = rb_intern("call");
317
+ int arity = NUM2INT(rb_funcall(callback_block, rb_intern("arity"), 0));
318
+ switch(arity) {
319
+ case 1:
320
+ // TODO is NUM2DBL what I want here?
321
+ return NUM2DBL(rb_funcall(callback_block, call_id, 1, rb_float_new(relativeAngle)));
322
+ default:
323
+ return NUM2DBL(rb_funcall(callback_block, call_id, 0));
324
+ }
325
+
326
+ }
327
+
328
+ static VALUE
329
+ rb_cpConstraintSetPreSolve(int argc, VALUE * argv, VALUE self) {
330
+ VALUE callback_block;
331
+ rb_scan_args(argc, argv, "0&", &callback_block);
332
+ rb_iv_set(self, "@_cp_pre_solve", callback_block);
333
+
334
+ cpConstraintSetPreSolveFunc(CONSTRAINT(self), rb_cpConstraintPreSolveFunc);
335
+
336
+ return Qnil;
337
+ }
338
+
339
+ static VALUE
340
+ rb_cpConstraintSetPostSolve(int argc, VALUE * argv, VALUE self) {
341
+ VALUE callback_block;
342
+ rb_scan_args(argc, argv, "0&", &callback_block);
343
+ rb_iv_set(self, "@_cp_post_solve", callback_block);
344
+
345
+ cpConstraintSetPostSolveFunc(CONSTRAINT(self), rb_cpConstraintPostSolveFunc);
346
+
347
+ return Qnil;
348
+ }
349
+
350
+ static VALUE
351
+ rb_cpDampedSpringSetForceFunc(int argc, VALUE * argv, VALUE self) {
352
+ VALUE callback_block;
353
+ rb_scan_args(argc, argv, "0&", &callback_block);
354
+ rb_iv_set(self, "@_cp_force_func", callback_block);
355
+
356
+ cpDampedSpringSetSpringForceFunc(CONSTRAINT(self), rb_cpDampedSpringForceFunc);
357
+
358
+ return Qnil;
359
+ }
360
+
361
+ static VALUE
362
+ rb_cpDampedRotarySpringSetTorqueFunc(int argc, VALUE * argv, VALUE self) {
363
+ VALUE callback_block;
364
+ rb_scan_args(argc, argv, "0&", &callback_block);
365
+ rb_iv_set(self, "@_cp_torque_func", callback_block);
366
+
367
+ cpDampedRotarySpringSetSpringTorqueFunc(CONSTRAINT(self), rb_cpDampedRotarySpringTorqueFunc);
368
+
369
+ return Qnil;
370
+ }
371
+
242
372
 
243
373
  #define STRINGIFY(v) # v
244
374
  #define ACCESSOR_METHODS(s, m, name) \
@@ -262,17 +392,19 @@ Init_cpConstraint(void) {
262
392
  rb_define_attr(m_cpConstraint, "body_b", 1, 0);
263
393
  rb_define_method(m_cpConstraint, "max_force", rb_cpConstraint_get_maxForce, 0);
264
394
  rb_define_method(m_cpConstraint, "max_force=", rb_cpConstraint_set_maxForce, 1);
265
- rb_define_method(m_cpConstraint, "bias_coef", rb_cpConstraint_get_biasCoef, 0);
266
- rb_define_method(m_cpConstraint, "bias_coef=", rb_cpConstraint_set_biasCoef, 1);
395
+ rb_define_method(m_cpConstraint, "error_bias", rb_cpConstraint_get_errorBias, 0);
396
+ rb_define_method(m_cpConstraint, "error_bias=", rb_cpConstraint_set_errorBias, 1);
267
397
  rb_define_method(m_cpConstraint, "max_bias", rb_cpConstraint_get_maxBias, 0);
268
398
  rb_define_method(m_cpConstraint, "max_bias=", rb_cpConstraint_set_maxBias, 1);
269
399
  rb_define_method(m_cpConstraint, "impulse", rb_cpConstraintGetImpulse, 0);
270
-
400
+ rb_define_method(m_cpConstraint, "pre_solve", rb_cpConstraintSetPreSolve, -1);
401
+ rb_define_method(m_cpConstraint, "post_solve", rb_cpConstraintSetPostSolve, -1);
271
402
 
272
403
  VALUE c_cpDampedRotarySpring = make_class("DampedRotarySpring", rb_cpDampedRotarySpring_alloc, rb_cpDampedRotarySpring_init, 5);
273
404
  ACCESSOR_METHODS(cpDampedRotarySpring, RestAngle, rest_angle)
274
405
  ACCESSOR_METHODS(cpDampedRotarySpring, Stiffness, stiffness)
275
406
  ACCESSOR_METHODS(cpDampedRotarySpring, Damping, damping)
407
+ rb_define_method(c_cpDampedRotarySpring, "torque", rb_cpDampedRotarySpringSetTorqueFunc, -1);
276
408
 
277
409
  VALUE c_cpDampedSpring = make_class("DampedSpring", rb_cpDampedSpring_alloc, rb_cpDampedSpring_init, 7);
278
410
  ACCESSOR_METHODS(cpDampedSpring, Anchr1, anchr1)
@@ -280,6 +412,7 @@ Init_cpConstraint(void) {
280
412
  ACCESSOR_METHODS(cpDampedSpring, RestLength, rest_length)
281
413
  ACCESSOR_METHODS(cpDampedSpring, Stiffness, stiffness)
282
414
  ACCESSOR_METHODS(cpDampedSpring, Damping, damping)
415
+ rb_define_method(c_cpDampedSpring, "force", rb_cpDampedSpringSetForceFunc, -1);
283
416
 
284
417
  VALUE c_cpGearJoint = make_class("GearJoint", rb_cpGearJoint_alloc, rb_cpGearJoint_init, 4);
285
418
  ACCESSOR_METHODS(cpGearJoint, Phase, phase)
@@ -287,6 +420,8 @@ Init_cpConstraint(void) {
287
420
 
288
421
  VALUE c_cpGrooveJoint = make_class("GrooveJoint", rb_cpGrooveJoint_alloc, rb_cpGrooveJoint_init, 5);
289
422
  ACCESSOR_METHODS(cpGrooveJoint, Anchr2, anchr2)
423
+ ACCESSOR_METHODS(cpGrooveJoint, GrooveA, groove_a)
424
+ ACCESSOR_METHODS(cpGrooveJoint, GrooveB, groove_b)
290
425
 
291
426
 
292
427
  VALUE c_cpPinJoint = make_class("PinJoint", rb_cpPinJoint_alloc, rb_cpPinJoint_init, 4);
@@ -295,7 +430,7 @@ Init_cpConstraint(void) {
295
430
  ACCESSOR_METHODS(cpPinJoint, Dist, dist)
296
431
 
297
432
 
298
- VALUE c_cpPivotJoint = make_class("PivotJoint", rb_cpPivotJoint_alloc, rb_cpPivotJoint_init, 4);
433
+ VALUE c_cpPivotJoint = make_class("PivotJoint", rb_cpPivotJoint_alloc, rb_cpPivotJoint_init, -1);
299
434
  ACCESSOR_METHODS(cpPivotJoint, Anchr1, anchr1)
300
435
  ACCESSOR_METHODS(cpPivotJoint, Anchr2, anchr2)
301
436