chipmunk-ffi 0.2.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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