chipmunk-ffi 1.0.0 → 1.1.0

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.
@@ -10,10 +10,15 @@ module CP
10
10
  func :cpSimpleMotorNew, [:pointer, :pointer, CP_FLOAT], :pointer
11
11
 
12
12
  class SimpleMotor
13
- attr_reader :struct
13
+ include Constraint
14
+ struct_accessor SimpleMotorStruct, :rate
14
15
  def initialize(a_body, b_body, rate)
16
+ @body_a, @body_b = a_body, b_body
15
17
  @struct = SimpleMotorStruct.new(CP.cpSimpleMotorNew(
16
18
  a_body.struct.pointer,b_body.struct.pointer,rate))
17
19
  end
18
20
  end
19
21
  end
22
+
23
+ # Alias for compatibility with chipmunk C-Ruby bindings.
24
+ CP::Constraint::SimpleMotor = CP::SimpleMotor
@@ -18,10 +18,15 @@ module CP
18
18
  func :cpSlideJointNew, [:pointer, :pointer, Vect.by_value, Vect.by_value, CP_FLOAT, CP_FLOAT], :pointer
19
19
 
20
20
  class SlideJoint
21
- attr_reader :struct
21
+ include Constraint
22
+ struct_accessor SlideJointStruct, :anchr1, :anchr2, :min, :max
22
23
  def initialize(a_body, b_body, anchr_one, anchr_two, min, max)
24
+ @body_a, @body_b = a_body, b_body
23
25
  @struct = SlideJointStruct.new(CP.cpSlideJointNew(
24
26
  a_body.struct.pointer,b_body.struct.pointer,anchr_one.struct,anchr_two.struct,min,max))
25
27
  end
26
28
  end
27
29
  end
30
+
31
+ # Alias for compatibility with chipmunk C-Ruby bindings.
32
+ CP::Constraint::SlideJoint = CP::SlideJoint
@@ -30,7 +30,7 @@ module CP
30
30
 
31
31
  func :cpMomentForSegment, [CP_FLOAT,Vect.by_value,Vect.by_value], CP_FLOAT
32
32
  def self.moment_for_segment(m,v1,v2)
33
- cpMomentForCircle(m, v1.struct, v2.struct)
33
+ cpMomentForSegment(m, v1.struct, v2.struct)
34
34
  end
35
35
 
36
36
  func :cpMomentForPoly, [CP_FLOAT,:int,:pointer,Vect.by_value], CP_FLOAT
@@ -51,6 +51,7 @@ module CP
51
51
  func :cpResetShapeIdCounter, [], :void
52
52
  func :cpShapePointQuery, [:pointer, Vect.by_value], :int
53
53
  func :cpShapeSegmentQuery, [:pointer, Vect.by_value, Vect.by_value, :pointer], :int
54
+ func :cpPolyValidate, [:pointer, :int], :int
54
55
 
55
56
  module Shape
56
57
  class SegmentQueryInfo
@@ -200,6 +201,15 @@ module CP
200
201
  include Shape
201
202
  def initialize(body, verts, offset_vec)
202
203
  @body = body
204
+ verts = CP::Shape::Poly.make_vertices_valid(verts)
205
+ mem_pointer = CP::Shape::Poly.pointer_for_verts(verts)
206
+
207
+ ptr = CP.cpPolyShapeNew body.struct.pointer, verts.size, mem_pointer, offset_vec.struct
208
+ @struct = ShapeStruct.new ptr
209
+ set_data_pointer
210
+ end
211
+
212
+ def self.pointer_for_verts(verts)
203
213
  mem_pointer = FFI::MemoryPointer.new Vect, verts.size
204
214
  vert_structs = verts.collect{|s|s.struct}
205
215
 
@@ -209,9 +219,28 @@ module CP
209
219
  tmp.send(:put_bytes, 0, i.to_bytes, 0, size)
210
220
  tmp += size unless j == vert_structs.length-1 # avoid OOB
211
221
  }
212
- ptr = CP.cpPolyShapeNew body.struct.pointer, verts.size, mem_pointer, offset_vec.struct
213
- @struct = ShapeStruct.new ptr
214
- set_data_pointer
222
+ return mem_pointer
223
+ end
224
+
225
+ def self.strictly_valid_vertices?(verts)
226
+ mem_pointer = CP::Shape::Poly.pointer_for_verts(verts)
227
+ result = CP.cpPolyValidate(mem_pointer,verts.size)
228
+ return (result != 0)
229
+ end
230
+
231
+ def self.valid_vertices?(verts)
232
+ CP::Shape::Poly.strictly_valid_vertices?(verts) ||
233
+ CP::Shape::Poly.strictly_valid_vertices?(verts.reverse)
234
+ end
235
+
236
+ def self.make_vertices_valid(verts)
237
+ if CP::Shape::Poly.strictly_valid_vertices?(verts)
238
+ return verts
239
+ elsif CP::Shape::Poly.strictly_valid_vertices?(verts.reverse)
240
+ return verts.reverse
241
+ else
242
+ raise "Chipmunk-FFI Error: Vertices do not form convex polygon."
243
+ end
215
244
  end
216
245
  end
217
246
  end
@@ -8,6 +8,7 @@ module CP
8
8
  callback :cpCollisionPostSolveFunc, [:pointer,:pointer,:pointer], :int
9
9
  callback :cpCollisionSeparateFunc, [:pointer,:pointer,:pointer], :int
10
10
  callback :cpSpacePointQueryFunc, [:pointer,:pointer], :void
11
+ callback :cpSpaceSegmentQueryFunc, [:pointer, :float, Vect.by_value, :pointer], :void
11
12
 
12
13
  class CollisionHandlerStruct < NiceFFI::Struct
13
14
  layout(
@@ -26,6 +27,7 @@ module CP
26
27
  :elastic_iterations, :int,
27
28
  :gravity, Vect.by_value,
28
29
  :damping, CP_FLOAT,
30
+ :locked, :int,
29
31
  :stamp, :int,
30
32
  :static_shapes, :pointer,
31
33
  :active_shapes, :pointer,
@@ -42,7 +44,6 @@ module CP
42
44
  end
43
45
  end
44
46
 
45
-
46
47
  func :cpSpaceNew, [], :pointer
47
48
  func :cpSpaceFreeChildren, [:pointer], :void
48
49
 
@@ -71,7 +72,10 @@ module CP
71
72
  func :cpSpacePointQuery, [:pointer, Vect.by_value, :uint, :uint, :cpSpacePointQueryFunc, :pointer], :pointer
72
73
  func :cpSpacePointQueryFirst, [:pointer, Vect.by_value, :uint, :uint], :pointer
73
74
 
74
- class Space
75
+ func :cpSpaceSegmentQuery, [:pointer, Vect.by_value, Vect.by_value, :uint, :uint, :cpSpaceSegmentQueryFunc, :pointer], :int
76
+ func :cpSpaceSegmentQueryFirst, [:pointer, Vect.by_value, Vect.by_value, :uint, :uint, :pointer], :pointer
77
+
78
+ class Space
75
79
  attr_reader :struct
76
80
  def initialize
77
81
  @struct = SpaceStruct.new(CP.cpSpaceNew)
@@ -81,6 +85,7 @@ module CP
81
85
  @constraints = []
82
86
  @blocks = {}
83
87
  @callbacks = {}
88
+ @test_callbacks = Hash.new {|h,k| h[k] = {:begin => nil, :pre => nil, :post => nil, :sep => nil}}
84
89
  end
85
90
 
86
91
  def iterations
@@ -111,58 +116,58 @@ module CP
111
116
  @struct.gravity.pointer.put_bytes 0, v.struct.to_bytes, 0,Vect.size
112
117
  end
113
118
 
114
- def add_collision_func(a,b,&block)
115
- beg = nil
116
- pre = nil
117
- unless block.nil?
118
- pre = Proc.new do |arb_ptr,space_ptr,data_ptr|
119
- begin
120
- arb = ArbiterStruct.new(arb_ptr)
121
-
122
- swapped = arb.swapped_col == 0 ? false : true
123
- arba = swapped ? arb.b : arb.a
124
- arbb = swapped ? arb.a : arb.b
125
-
126
- as = ShapeStruct.new(arba)
127
- a_obj_id = as.data.get_long 0
128
- rb_a = ObjectSpace._id2ref a_obj_id
129
-
130
- bs = ShapeStruct.new(arbb)
131
- b_obj_id = bs.data.get_long 0
132
- rb_b = ObjectSpace._id2ref b_obj_id
133
-
134
- block.call rb_a, rb_b
135
- 1
136
- rescue Exception => ex
137
- puts ex.message
138
- puts ex.backtrace
139
- 0
140
- end
141
- end
142
- else
143
- # needed for old chipmunk style
144
- pre = Proc.new do |arb_ptr,space_ptr,data_ptr|
145
- 0
146
- end
147
- end
148
- post = nil
149
- sep = nil
150
- data = nil
151
- a_id = a.object_id
152
- b_id = b.object_id
153
- CP.cpSpaceAddCollisionHandler(@struct.pointer, a_id, b_id,
154
- beg,pre,post,sep,data)
155
- @blocks[[a_id,b_id]] = pre
156
- nil
157
- end
158
-
159
- def remove_collision_func(a,b)
160
- a_id = a.object_id
161
- b_id = b.object_id
162
- CP.cpSpaceRemoveCollisionHandler(@struct.pointer, a_id, b_id)
163
- @blocks.delete [a_id,b_id]
164
- nil
165
- end
119
+ #def add_collision_func(a,b,&block)
120
+ # beg = nil
121
+ # pre = nil
122
+ # unless block.nil?
123
+ # pre = Proc.new do |arb_ptr,space_ptr,data_ptr|
124
+ # begin
125
+ # arb = ArbiterStruct.new(arb_ptr)
126
+ #
127
+ # swapped = arb.swapped_col == 0 ? false : true
128
+ # arba = swapped ? arb.b : arb.a
129
+ # arbb = swapped ? arb.a : arb.b
130
+ #
131
+ # as = ShapeStruct.new(arba)
132
+ # a_obj_id = as.data.get_long 0
133
+ # rb_a = ObjectSpace._id2ref a_obj_id
134
+ #
135
+ # bs = ShapeStruct.new(arbb)
136
+ # b_obj_id = bs.data.get_long 0
137
+ # rb_b = ObjectSpace._id2ref b_obj_id
138
+ #
139
+ # block.call rb_a, rb_b
140
+ # 1
141
+ # rescue Exception => ex
142
+ # puts ex.message
143
+ # puts ex.backtrace
144
+ # 0
145
+ # end
146
+ # end
147
+ # else
148
+ # # needed for old chipmunk style
149
+ # pre = Proc.new do |arb_ptr,space_ptr,data_ptr|
150
+ # 0
151
+ # end
152
+ # end
153
+ # post = nil
154
+ # sep = nil
155
+ # data = nil
156
+ # a_id = a.object_id
157
+ # b_id = b.object_id
158
+ # CP.cpSpaceAddCollisionHandler(@struct.pointer, a_id, b_id,
159
+ # beg,pre,post,sep,data)
160
+ # @blocks[[a_id,b_id]] = pre
161
+ # nil
162
+ #end
163
+
164
+ #def remove_collision_func(a,b)
165
+ # a_id = a.object_id
166
+ # b_id = b.object_id
167
+ # CP.cpSpaceRemoveCollisionHandler(@struct.pointer, a_id, b_id)
168
+ # @blocks.delete [a_id,b_id]
169
+ # nil
170
+ #end
166
171
 
167
172
  def set_default_collision_func(&block)
168
173
  raise "Not Implmented yet"
@@ -183,6 +188,7 @@ module CP
183
188
  ret ? 1 : 0
184
189
  end
185
190
  @callbacks[[a,b,type]] = [handler,callback]
191
+ @test_callbacks[[a,b]][type] = callback
186
192
  callback
187
193
  end
188
194
 
@@ -201,6 +207,35 @@ module CP
201
207
  a_id, b_id, beg,pre,post,sep,data)
202
208
  end
203
209
 
210
+ def add_collision_func(a,b,type=:pre,&block)
211
+ arity = block.arity
212
+ callback = Proc.new do |arb_ptr,space_ptr,data_ptr|
213
+ arbiter = Arbiter.new(arb_ptr)
214
+ ret = case arity
215
+ when 1 then block.call(arbiter)
216
+ when 2 then block.call(*arbiter.shapes)
217
+ when 3 then block.call(arbiter,*arbiter.shapes)
218
+ else raise ArgumentError
219
+ end
220
+ ret ? 1 : 0
221
+ end
222
+ @test_callbacks[[a,b]][type] = callback
223
+ setup_callbacks(a,b)
224
+ end
225
+
226
+ def remove_collision_func(a,b,type=:pre)
227
+ @test_callbacks[[a,b]][type] = nil
228
+ setup_callbacks(a,b)
229
+ end
230
+
231
+ def setup_callbacks(a,b)
232
+ a_id = a.object_id
233
+ b_id = b.object_id
234
+ cbs = @test_callbacks[[a,b]]
235
+ CP.cpSpaceAddCollisionHandler(@struct.pointer,a_id,b_id,
236
+ cbs[:begin],cbs[:pre],cbs[:post],cbs[:sep],nil)
237
+ end
238
+
204
239
  def add_shape(shape)
205
240
  CP.cpSpaceAddShape(@struct.pointer, shape.struct.pointer)
206
241
  @active_shapes << shape
@@ -307,6 +342,53 @@ module CP
307
342
  CP.cpSpacePointQuery(@struct.pointer, point.struct, layers, group,query_proc,nil)
308
343
  end
309
344
 
345
+ class SegmentQueryInfo
346
+ attr_reader :hit,:shape, :t, :n
347
+ def initialize(hit,shape,t=nil,n=nil,info=nil)
348
+ @hit = hit
349
+ @shape = shape
350
+ @t = t
351
+ @n = n
352
+ @info = info
353
+ end
354
+ end
355
+
356
+ def shape_segment_query(a,b,layers=ALL_ONES,group=0)
357
+ segment_query_first(a,b,layers,group).shape
358
+ end
359
+
360
+ def info_segment_query(a,b,layers=ALL_ONES,group=0)
361
+ segment_query_first(a,b,layers,group)
362
+ end
363
+
364
+ def segment_query_first(a,b,layers,group)
365
+ out_ptr = FFI::MemoryPointer.new(SegmentQueryInfoStruct.size)
366
+ info = SegmentQueryInfoStruct.new out_ptr
367
+
368
+ shape_ptr = CP.cpSpaceSegmentQueryFirst(@struct.pointer, a.struct.pointer, b.struct.pointer,layers,group,out_ptr)
369
+ if shape_ptr.null?
370
+ SegmentQueryInfo.new(false,nil,nil,nil,info)
371
+ else
372
+ shape_struct = ShapeStruct.new(shape_ptr)
373
+ obj_id = shape_struct.data.get_long(0)
374
+ shape = ObjectSpace._id2ref(obj_id)
375
+ n_vec = Vec2.new(info.n)
376
+ SegmentQueryInfo.new(true,shape,info.t,n_vec,info)
377
+ end
378
+ end
379
+
380
+ def segment_query(a,b,layers,group,&block)
381
+ return nil unless block_given?
382
+ query_proc = Proc.new do |shape_ptr,t,n,data|
383
+ shape_struct = ShapeStruct.new(shape_ptr)
384
+ obj_id = shape_struct.data.get_long(0)
385
+ shape = ObjectSpace._id2ref(obj_id)
386
+ block.call(shape,t,n)
387
+ end
388
+
389
+ CP.cpSpaceSegmentQuery(@struct.pointer, a.struct, b.struct, layers, group, query_proc, nil)
390
+ end
391
+
310
392
  end
311
393
  end
312
394
 
@@ -8,8 +8,10 @@ module CP
8
8
  :cell_dim, CP_FLOAT,
9
9
  :bb_func, :cpSpaceHashBBFunc,
10
10
  :handle_set, :pointer,
11
+ :pooled_handles, :pointer,
11
12
  :table, :pointer,
12
13
  :bins, :pointer,
14
+ :allocated_buffers, :pointer,
13
15
  :stamp, :int)
14
16
  end
15
17
  func :cpSpaceHashNew, [CP_FLOAT,:int,:cpSpaceHashBBFunc], :pointer
@@ -0,0 +1,48 @@
1
+ module CP
2
+ module StructAccessor
3
+ private
4
+
5
+ def struct_reader(struct,*args)
6
+ raise(ArgumentError,"First argument must be an FFI::Struct subclass, got #{struct.inspect} instead.") unless struct < FFI::Struct
7
+ args.each {|attribute| add_struct_reader(struct,attribute) }
8
+ end
9
+
10
+ def struct_writer(struct,*args)
11
+ raise(ArgumentError,"First argument must be an FFI::Struct subclass, got #{struct.inspect} instead.") unless struct < FFI::Struct
12
+ args.each {|attribute| add_struct_writer(struct,attribute) }
13
+ end
14
+
15
+ def struct_accessor(struct,*args)
16
+ struct_reader(struct,*args)
17
+ struct_writer(struct,*args)
18
+ end
19
+
20
+ def add_struct_reader(struct,attribute)
21
+ type = resolve_type(struct,attribute)
22
+ if type == CP::Vect
23
+ define_method(attribute) { Vec2.new(self.struct[attribute]) }
24
+ else
25
+ define_method(attribute) { self.struct[attribute] }
26
+ end
27
+ end
28
+
29
+ def add_struct_writer(struct,attribute)
30
+ type = resolve_type(struct,attribute)
31
+ if type == CP::Vect
32
+ define_method("#{attribute}=") {|val| self.struct[attribute].pointer.put_bytes(0,val.struct.to_bytes,0,Vect.size) }
33
+ else
34
+ define_method("#{attribute}=") {|val| self.struct[attribute] = val }
35
+ end
36
+ end
37
+
38
+ def resolve_type(struct,attribute)
39
+ t = struct.layout[attribute].type
40
+ if t.is_a?(FFI::StructByValue)
41
+ t.struct_class
42
+ else
43
+ t
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -195,9 +195,15 @@ module CP
195
195
  CP::cpvlength @struct
196
196
  end
197
197
 
198
+ def ==(other)
199
+ self.x == other.x && self.y == other.y
200
+ end
201
+
198
202
  end
199
203
  ZERO_VEC_2 = Vec2.new(0,0).freeze
200
-
204
+ def zero
205
+ ZERO_VEC_2
206
+ end
201
207
  end
202
208
  def vec2(x,y)
203
209
  CP::Vec2.new x, y
@@ -152,5 +152,49 @@ describe 'A new Body' do
152
152
  b.v.x.should be_close(0.1,0.001)
153
153
  b.v.y.should be_close(0,0.001)
154
154
  end
155
+
156
+ it 'can get its velocity function' do
157
+ b = CP::Body.new(5, 7)
158
+ b.apply_impulse(vec2(1,0), ZERO_VEC_2)
159
+ b.velocity_func.call(b,vec2(0,0), 0.5, 25)
160
+ b.v.x.should be_close(0.1,0.001)
161
+ b.v.y.should be_close(0,0.001)
162
+ end
163
+
164
+ it 'can set its velocity function' do
165
+ b = CP::Body.new(5, 7)
166
+
167
+ b.velocity_func = Proc.new do |body,gravity,damping,dt|
168
+ d = body.p - vec2(5,5)
169
+ g = (d * (-500.0/(d.dot(d))))
170
+ body.update_velocity(g,damping,dt)
171
+ end
172
+
173
+ b.velocity_func.call(b,ZERO_VEC_2,0.5,25)
174
+ b.v.x.should be_close(1250.0,10)
175
+ b.v.y.should be_close(1250.0,10)
176
+
177
+ end
178
+
179
+ it 'can get its position function' do
180
+ b = CP::Body.new(5, 7)
181
+ b.apply_impulse(vec2(1,0), ZERO_VEC_2)
182
+ b.position_func.call(b,25)
183
+ b.p.x.should be_close(5,0.001)
184
+ b.p.y.should be_close(0,0.001)
185
+ end
186
+
187
+ it 'can set its position function' do
188
+ b = CP::Body.new(5,7)
189
+
190
+ b.position_func = Proc.new do |body,dt|
191
+ body.p = vec2(5,5)
192
+ end
193
+
194
+ b.position_func.call(b,25)
195
+ b.p.should == vec2(5,5)
196
+ end
197
+
198
+
155
199
 
156
200
  end