chipmunk-ffi 0.2.1 → 1.0.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.
@@ -1,8 +1,13 @@
1
1
  module CP
2
+ # used for layers; will only work on 32 bit values
3
+ # (chipmunk cheats and sets these to -1)
4
+ ALL_ONES = 2**32-1
5
+
2
6
  callback :cpCollisionBeginFunc, [:pointer,:pointer,:pointer], :int
3
7
  callback :cpCollisionPreSolveFunc, [:pointer,:pointer,:pointer], :int
4
8
  callback :cpCollisionPostSolveFunc, [:pointer,:pointer,:pointer], :int
5
9
  callback :cpCollisionSeparateFunc, [:pointer,:pointer,:pointer], :int
10
+ callback :cpSpacePointQueryFunc, [:pointer,:pointer], :void
6
11
 
7
12
  class CollisionHandlerStruct < NiceFFI::Struct
8
13
  layout(
@@ -16,22 +21,6 @@ module CP
16
21
  )
17
22
  end
18
23
 
19
- class ArbiterStruct < NiceFFI::Struct
20
- layout(
21
- :num_contacts, :int,
22
- :contacts, :pointer,
23
- :a, :pointer,
24
- :b, :pointer,
25
- :e, CP_FLOAT,
26
- :u, CP_FLOAT,
27
- :surf_vr, Vect.by_value,
28
- :stamp, :int,
29
- :handler, :pointer,
30
- :swapped_col, :char,
31
- :first_col, :char
32
- )
33
- end
34
-
35
24
  class SpaceStruct < NiceFFI::Struct
36
25
  layout( :iterations, :int,
37
26
  :elastic_iterations, :int,
@@ -79,6 +68,8 @@ module CP
79
68
  :cpCollisionBeginFunc, :cpCollisionPreSolveFunc, :cpCollisionPostSolveFunc, :cpCollisionSeparateFunc, :pointer], :void
80
69
  func :cpSpaceRemoveCollisionHandler, [:pointer, :uint, :uint], :void
81
70
 
71
+ func :cpSpacePointQuery, [:pointer, Vect.by_value, :uint, :uint, :cpSpacePointQueryFunc, :pointer], :pointer
72
+ func :cpSpacePointQueryFirst, [:pointer, Vect.by_value, :uint, :uint], :pointer
82
73
 
83
74
  class Space
84
75
  attr_reader :struct
@@ -133,11 +124,11 @@ module CP
133
124
  arbb = swapped ? arb.a : arb.b
134
125
 
135
126
  as = ShapeStruct.new(arba)
136
- a_obj_id = as.data.get_ulong 0
127
+ a_obj_id = as.data.get_long 0
137
128
  rb_a = ObjectSpace._id2ref a_obj_id
138
129
 
139
130
  bs = ShapeStruct.new(arbb)
140
- b_obj_id = bs.data.get_ulong 0
131
+ b_obj_id = bs.data.get_long 0
141
132
  rb_b = ObjectSpace._id2ref b_obj_id
142
133
 
143
134
  block.call rb_a, rb_b
@@ -179,27 +170,17 @@ module CP
179
170
  end
180
171
 
181
172
  def wrap_collision_callback(a,b,type,handler)
173
+ arity = handler.method(type).arity
182
174
  callback = Proc.new do |arb_ptr,space_ptr,data_ptr|
183
- arb = ArbiterStruct.new(arb_ptr)
184
-
185
- swapped = arb.swapped_col == 0 ? false : true
186
- arba = swapped ? arb.b : arb.a
187
- arbb = swapped ? arb.a : arb.b
188
-
189
- as = ShapeStruct.new(arba)
190
- a_obj_id = as.data.get_ulong 0
191
- rb_a = ObjectSpace._id2ref a_obj_id
192
-
193
- bs = ShapeStruct.new(arbb)
194
- b_obj_id = bs.data.get_ulong 0
195
- rb_b = ObjectSpace._id2ref b_obj_id
196
-
197
- ret = handler.send type, rb_a, rb_b
198
- if ret
199
- 1
200
- else
201
- 0
175
+ arbiter = Arbiter.new(arb_ptr)
176
+
177
+ ret = case arity
178
+ when 1 then handler.send type, arbiter
179
+ when 2 then handler.send type, *arbiter.shapes
180
+ when 3 then handler.send type, arbiter, *arbiter.shapes
181
+ else raise ArgumentError
202
182
  end
183
+ ret ? 1 : 0
203
184
  end
204
185
  @callbacks[[a,b,type]] = [handler,callback]
205
186
  callback
@@ -284,20 +265,47 @@ module CP
284
265
  CP.cpSpaceStep @struct.pointer, dt
285
266
  end
286
267
 
287
- def shape_point_query(*args)
288
- raise "Not Implmented yet"
268
+ def each_body(&block)
269
+ @bodies.each &block
270
+ # typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
271
+ # void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
272
+ end
273
+
274
+ def shape_point_query(pt)
275
+ point_query_first pt, ALL_ONES, 0
289
276
  end
290
277
 
291
- def static_shape_point_query(*args)
278
+ def static_shape_point_query(pt)
292
279
  raise "Not Implmented yet"
293
280
  end
294
281
 
295
- def each_body(&block)
296
- @bodies.each &block
297
- # typedef void (*cpSpaceBodyIterator)(cpBody *body, void *data);
298
- # void cpSpaceEachBody(cpSpace *space, cpSpaceBodyIterator func, void *data);
282
+ def point_query_first(point, layers, group)
283
+ shape_ptr = CP.cpSpacePointQueryFirst(@struct.pointer, point.struct, layers, group)
284
+ if shape_ptr.null?
285
+ nil
286
+ else
287
+ shape = ShapeStruct.new(shape_ptr)
288
+ obj_id = shape.data.get_long 0
289
+ ObjectSpace._id2ref obj_id
290
+ end
291
+ end
292
+
293
+ def active_shapes_hash
294
+ SpaceHash.new(SpaceHashStruct.new(@struct.active_shapes))
299
295
  end
300
296
 
297
+ def point_query(point, layers, group, &block)
298
+ return nil unless block_given?
299
+
300
+ query_proc = Proc.new do |shape_ptr,data|
301
+ shape = ShapeStruct.new(shape_ptr)
302
+ obj_id = shape.data.get_long 0
303
+ shape = ObjectSpace._id2ref obj_id
304
+ block.call shape
305
+ end
306
+
307
+ CP.cpSpacePointQuery(@struct.pointer, point.struct, layers, group,query_proc,nil)
308
+ end
301
309
 
302
310
  end
303
311
  end
@@ -0,0 +1,63 @@
1
+ module CP
2
+
3
+ callback :cpSpaceHashBBFunc, [:pointer], BBStruct.by_value
4
+ callback :cpSpaceHashQueryFunc, [:pointer, :pointer, :pointer], :void
5
+
6
+ class SpaceHashStruct < NiceFFI::Struct
7
+ layout(:num_cells, :int,
8
+ :cell_dim, CP_FLOAT,
9
+ :bb_func, :cpSpaceHashBBFunc,
10
+ :handle_set, :pointer,
11
+ :table, :pointer,
12
+ :bins, :pointer,
13
+ :stamp, :int)
14
+ end
15
+ func :cpSpaceHashNew, [CP_FLOAT,:int,:cpSpaceHashBBFunc], :pointer
16
+ func :cpSpaceHashQuery, [:pointer, :pointer, BBStruct.by_value, :cpSpaceHashQueryFunc, :pointer], :void
17
+ func :cpSpaceHashInsert, [:pointer, :pointer, :uint, BBStruct.by_value], :void
18
+ func :cpSpaceHashRemove, [:pointer, :pointer, :uint], :void
19
+
20
+ class SpaceHash
21
+ attr_reader :struct
22
+ def initialize(*args, &bb_func)
23
+ case args.size
24
+ when 1
25
+ @struct = args.first
26
+ when 2
27
+ raise "need bb func" unless block_given?
28
+ cell_dim = args[0]
29
+ cells = args[1]
30
+ @struct = SpaceHashStruct.new(CP.cpSpaceHashNew(cell_dim, cells, bb_func))
31
+ end
32
+ end
33
+
34
+ def num_cells;@struct.num_cells;end
35
+ def cell_dim;@struct.cell_dim;end
36
+
37
+ def insert(obj, bb)
38
+ CP.cpSpaceHashInsert(@struct.pointer, obj.struct.pointer, obj.struct.hash_value, bb.struct)
39
+ end
40
+
41
+ def remove(obj)
42
+ CP.cpSpaceHashRemove(@struct.pointer, obj.struct.pointer, obj.struct.hash_value)
43
+ end
44
+
45
+ def query_func
46
+ @query_func ||= Proc.new do |obj,other,data|
47
+ s = ShapeStruct.new(other)
48
+ obj_id = s.data.get_long 0
49
+ @shapes << ObjectSpace._id2ref(obj_id)
50
+ end
51
+ end
52
+
53
+ def query_by_bb(bb)
54
+ @shapes = []
55
+ CP.cpSpaceHashQuery(@struct.pointer, nil, bb.struct, query_func, nil)
56
+ @shapes
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+
@@ -0,0 +1,47 @@
1
+ require 'chipmunk-ffi'
2
+
3
+ module CP
4
+ func :cpCircleShapeSetRadius, [:pointer, CP_FLOAT], :void
5
+ func :cpCircleShapeSetOffset, [:pointer, Vect.by_value], :void
6
+
7
+ func :cpSegmentShapeSetEndpoints, [:pointer, Vect.by_value, Vect.by_value], :void
8
+ func :cpSegmentShapeSetRadius, [:pointer, CP_FLOAT], :void
9
+
10
+ func :cpPolyShapeSetVerts, [:pointer, :int, :pointer, Vect.by_value], :void
11
+
12
+ module Shape
13
+ class Circle
14
+ def radius=(new_radius)
15
+ CP.cpCircleShapeSetRadius(@struct, new_radius)
16
+ end
17
+ def offset=(new_offset)
18
+ CP.cpCircleShapeSetOffset(@struct, new_offset.struct)
19
+ end
20
+ end
21
+ class Segment
22
+ def endpoints=(new_endpoints)
23
+ new_a, new_b = *new_endpoints.map { |v| v.struct }
24
+ CP.cpSegmentShapeSetEndpoints(@struct, new_a, new_b)
25
+ end
26
+ def radius=(new_radius)
27
+ CP.cpSegmentShapeSetRadius(@struct, new_radius)
28
+ end
29
+ end
30
+ class Poly
31
+ def verts=(new_verts_and_offset)
32
+ new_verts, new_offset = *new_verts_and_offset
33
+
34
+ new_verts_pointer = FFI::MemoryPointer.new Vect, new_verts.count
35
+
36
+ size = Vect.size
37
+ tmp = new_verts_pointer
38
+ new_verts.each_with_index do |vert, i|
39
+ tmp.send(:put_bytes, 0, vert.struct.to_bytes, 0, size)
40
+ tmp += size unless i == new_verts.length - 1 # avoid OOB
41
+ end
42
+
43
+ CP.cpPolyShapeSetVerts(@struct.pointer, new_verts.count, new_verts_pointer, new_offset.struct)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,7 +1,24 @@
1
1
  module CP
2
- class Vect < NiceFFI::Struct
2
+ class Vect < FFI::Struct
3
3
  layout( :x, CP_FLOAT,
4
- :y, CP_FLOAT )
4
+ :y, CP_FLOAT )
5
+
6
+ def self.release( ptr )
7
+ free ptr
8
+ end
9
+
10
+ def initialize( ptr )
11
+ case ptr
12
+ when FFI::MemoryPointer, FFI::Buffer, FFI::AutoPointer
13
+ super ptr
14
+ else
15
+ super FFI::AutoPointer.new(ptr, self.class.method(:release))
16
+ end
17
+ end
18
+
19
+ def to_bytes
20
+ return self.pointer.get_bytes(0, self.size)
21
+ end
5
22
  end
6
23
 
7
24
  cp_static_inline :cpv, [CP_FLOAT,CP_FLOAT], Vect.by_value
@@ -9,8 +26,8 @@ module CP
9
26
  cp_static_inline :cpvadd, [Vect.by_value,Vect.by_value], Vect.by_value
10
27
  cp_static_inline :cpvsub, [Vect.by_value,Vect.by_value], Vect.by_value
11
28
  cp_static_inline :cpvmult, [Vect.by_value,CP_FLOAT], Vect.by_value
12
- cp_static_inline :cpvdot, [Vect.by_value,Vect.by_value], Vect.by_value
13
- cp_static_inline :cpvcross, [Vect.by_value,Vect.by_value], Vect.by_value
29
+ cp_static_inline :cpvdot, [Vect.by_value,Vect.by_value], CP_FLOAT
30
+ cp_static_inline :cpvcross, [Vect.by_value,Vect.by_value], CP_FLOAT
14
31
 
15
32
  cp_static_inline :cpvperp, [Vect.by_value], Vect.by_value
16
33
  cp_static_inline :cpvrperp, [Vect.by_value], Vect.by_value
@@ -20,13 +37,13 @@ module CP
20
37
 
21
38
  cp_static_inline :cpvlengthsq, [Vect.by_value], CP_FLOAT
22
39
 
23
- cp_static_inline :cpvlerp, [Vect.by_value,Vect.by_value], Vect.by_value
40
+ cp_static_inline :cpvlerp, [Vect.by_value,Vect.by_value,CP_FLOAT], Vect.by_value
24
41
 
25
42
  cp_static_inline :cpvnormalize, [Vect.by_value], Vect.by_value
26
43
  cp_static_inline :cpvnormalize_safe, [Vect.by_value], Vect.by_value
27
44
 
28
45
  cp_static_inline :cpvclamp, [Vect.by_value,Vect.by_value], Vect.by_value
29
- cp_static_inline :cpvlerpconst, [Vect.by_value,Vect.by_value], Vect.by_value
46
+ cp_static_inline :cpvlerpconst, [Vect.by_value,Vect.by_value, CP_FLOAT], Vect.by_value
30
47
  cp_static_inline :cpvdist, [Vect.by_value,Vect.by_value], CP_FLOAT
31
48
  cp_static_inline :cpvdistsq, [Vect.by_value,Vect.by_value], CP_FLOAT
32
49
 
@@ -48,23 +65,23 @@ module CP
48
65
  when 2
49
66
  @struct = CP.cpv(*args)
50
67
  else
51
- raise "wrong number of args for Vec, got #{args.size}, but expected 2"
68
+ raise "wrong number of arguments (#{args.size} for 2)"
52
69
  end
53
70
  end
54
71
 
55
72
  def x
56
- @struct.x
73
+ @struct[:x]
57
74
  end
58
75
  def x=(new_x)
59
- raise TypeError "cant't modify frozen object" if frozen?
60
- @struct.x = new_x
76
+ raise TypeError, "can't modify frozen vec2" if frozen?
77
+ @struct[:x] = new_x
61
78
  end
62
79
  def y
63
- @struct.y
80
+ @struct[:y]
64
81
  end
65
82
  def y=(new_y)
66
- raise TypeError "cant't modify frozen object" if frozen?
67
- @struct.y = new_y
83
+ raise TypeError, "can't modify frozen vec2" if frozen?
84
+ @struct[:y] = new_y
68
85
  end
69
86
 
70
87
  def self.for_angle(angle)
@@ -80,7 +97,7 @@ module CP
80
97
  end
81
98
 
82
99
  def to_a
83
- [@struct.x,@struct.y]
100
+ [@struct[:x],@struct[:y]]
84
101
  end
85
102
 
86
103
  def -@
@@ -117,7 +134,7 @@ module CP
117
134
  end
118
135
 
119
136
  def rperp
120
- Vec2.new CP.cpvperp(@struct)
137
+ Vec2.new CP.cpvrperp(@struct)
121
138
  end
122
139
 
123
140
  def project(other_vec)
@@ -136,8 +153,8 @@ module CP
136
153
  CP.cpvlengthsq(@struct)
137
154
  end
138
155
 
139
- def lerp(other_vec)
140
- Vec2.new CP.cpvlerp(@struct, other_vec.struct)
156
+ def lerp(other_vec, t)
157
+ Vec2.new CP.cpvlerp(@struct, other_vec.struct, t)
141
158
  end
142
159
 
143
160
  def normalize
@@ -157,16 +174,16 @@ module CP
157
174
  Vec2.new CP.cpvclamp(@struct)
158
175
  end
159
176
 
160
- def lerpconst(other_vec)
161
- Vec2.new CP.cpvlerpconst(@struct)
177
+ def lerpconst(other_vec, d)
178
+ Vec2.new CP.cpvlerpconst(@struct, other_vec.struct, d)
162
179
  end
163
180
 
164
181
  def dist(other_vec)
165
- CP.cpvdist(@struct)
182
+ CP.cpvdist(@struct, other_vec.struct)
166
183
  end
167
184
 
168
185
  def distsq(other_vec)
169
- CP.cpvdistsq(@struct)
186
+ CP.cpvdistsq(@struct, other_vec.struct)
170
187
  end
171
188
 
172
189
  def near?(other_vec, dist)
@@ -9,6 +9,7 @@ describe 'A new Body' do
9
9
  b = CP::Body.new(5, 7)
10
10
  b.m = 900
11
11
  b.m.should == 900
12
+ b.m_inv.should be_close(1.0/900, 0.001)
12
13
  end
13
14
 
14
15
  it 'can set its pos' do
@@ -31,21 +32,125 @@ describe 'A new Body' do
31
32
  b.v.y.should == 6
32
33
  end
33
34
 
34
- it 'can set its moment'
35
- it 'can set its force'
36
- it 'can set its angle'
37
- it 'can set its angle_vel'
38
- it 'can set its torque'
39
- it 'can get its rot'
40
- it 'can get local2world'
41
- it 'can get world2local'
42
- it 'can reset its forces'
43
- it 'can apply force'
44
- it 'can apply impulse'
45
- it 'can update its velocity over a timestep'
35
+ it 'can set its moment' do
36
+ b = CP::Body.new(5, 7)
37
+ b.moment = 37
38
+ b.moment.should == 37
39
+ b.moment_inv.should be_close(1.0/37, 0.001)
40
+ end
41
+
42
+ it 'can set its force' do
43
+ b = CP::Body.new(5, 7)
44
+ b.f.x.should == 0
45
+ b.f.y.should == 0
46
+
47
+ b.f = vec2(4,6)
48
+ b.f.x.should == 4
49
+ b.f.y.should == 6
50
+ end
51
+
52
+ it 'can set its angle' do
53
+ b = CP::Body.new(5, 7)
54
+ b.a = 37
55
+ b.a.should == 37
56
+ end
57
+
58
+ it 'can set its angle_vel' do
59
+ b = CP::Body.new(5, 7)
60
+ b.w = 37
61
+ b.w.should == 37
62
+ end
63
+
64
+ it 'can set its torque' do
65
+ b = CP::Body.new(5, 7)
66
+ b.t = 37
67
+ b.t.should == 37
68
+ end
69
+
70
+ it 'can get its rot' do
71
+ b = CP::Body.new(5, 7)
72
+ b.rot.x.should == 1
73
+ b.rot.y.should == 0
74
+ end
75
+
76
+ it 'can set its v_limit' do
77
+ b = CP::Body.new(5, 7)
78
+ b.v_limit = 37
79
+ b.v_limit.should == 37
80
+ end
81
+
82
+ it 'can get its v_limit' do
83
+ b = CP::Body.new(5, 7)
84
+ b.v_limit.should === CP::INFINITY
85
+ end
86
+
87
+ it 'can set its w_limit' do
88
+ b = CP::Body.new(5, 7)
89
+ b.w_limit = 37
90
+ b.w_limit.should == 37
91
+ end
92
+
93
+ it 'can get its w_limit' do
94
+ b = CP::Body.new(5, 7)
95
+ b.w_limit.should === CP::INFINITY
96
+ end
97
+
98
+ it 'can get local2world' do
99
+ b = CP::Body.new(5, 7)
100
+ b.pos = vec2(4,6)
101
+ v = b.local2world(vec2(0,0))
102
+ v.x.should == 4
103
+ v.y.should == 6
104
+ end
105
+
106
+ it 'can get world2local' do
107
+ b = CP::Body.new(5, 7)
108
+ b.pos = vec2(4,6)
109
+ v = b.world2local(vec2(4,6))
110
+ v.x.should == 0
111
+ v.y.should == 0
112
+ end
113
+
114
+ it 'can reset its forces' do
115
+ b = CP::Body.new(5, 7)
116
+ b.f = vec2(4,6)
117
+ b.reset_forces
118
+ b.f.x.should == 0
119
+ b.f.y.should == 0
120
+ end
121
+
122
+ it 'can apply force' do
123
+ b = CP::Body.new(5, 7)
124
+ b.apply_force(vec2(1,0), ZERO_VEC_2)
125
+ b.f.x.should == 1
126
+ b.f.y.should == 0
127
+ end
128
+
129
+ it 'can apply impulse' do
130
+ b = CP::Body.new(5, 7)
131
+ b.apply_impulse(vec2(1,0), ZERO_VEC_2)
132
+ # shouldn't mess with force
133
+ b.f.x.should == 0
134
+ b.f.y.should == 0
135
+
136
+ b.v.x.should == 0.2
137
+ b.v.y.should == 0
138
+ end
46
139
 
47
140
  it 'should be able to update its position' do
48
141
  b = CP::Body.new(5, 7)
142
+ b.apply_impulse(vec2(1,0), ZERO_VEC_2)
49
143
  b.update_position 25
144
+ b.p.x.should be_close(5,0.001)
145
+ b.p.y.should be_close(0,0.001)
146
+ end
147
+
148
+ it 'can update its velocity over a timestep' do
149
+ b = CP::Body.new(5, 7)
150
+ b.apply_impulse(vec2(1,0), ZERO_VEC_2)
151
+ b.update_velocity vec2(0,0), 0.5, 25
152
+ b.v.x.should be_close(0.1,0.001)
153
+ b.v.y.should be_close(0,0.001)
50
154
  end
155
+
51
156
  end