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