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.
@@ -0,0 +1,36 @@
1
+ Chipmunk-FFI
2
+ ====
3
+
4
+ Why should I use Chipmunk-FFI
5
+ ----------------------
6
+
7
+ * To use chipmunk's latest features that are not yet present in their bundle or other gems.
8
+ * To use chipmunk from within jruby.
9
+ * To make shawn42 feel better about spending time on this gem.
10
+
11
+
12
+ Install
13
+ -------
14
+
15
+ You will need:
16
+
17
+ * Ruby 1.8.6+ or JRuby 1.4+
18
+ * Chipmunk > 5.0 (svn right now... http://code.google.com/p/chipmunk-physics/ )
19
+ * FFI > 0.6.0 (git right now... http://github.com/ffi/ffi/ )
20
+
21
+ Then...
22
+
23
+ gem install chipmunk-ffi
24
+
25
+
26
+ License
27
+ -------
28
+
29
+ MIT
30
+ Copyright 2009 Shawn Anderson
31
+
32
+
33
+ Author
34
+ ------
35
+
36
+ Shawn Anderson <shawn42+chipmunk@gmail.com>
data/Rakefile CHANGED
@@ -8,6 +8,8 @@ begin
8
8
  gem.email = "shawn42@gmail.com"
9
9
  gem.homepage = "http://shawn42.github.com/chipmunk-ffi"
10
10
  gem.authors = ["Shawn Anderson"]
11
+ gem.add_dependency "ffi", ">= 0.6.0"
12
+ gem.add_dependency "nice-ffi"
11
13
  gem.add_development_dependency "rspec"
12
14
  gem.add_development_dependency "jeweler"
13
15
  gem.test_files = FileList['{spec,test}/**/*.rb']
@@ -18,11 +20,15 @@ rescue LoadError
18
20
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
21
  end
20
22
 
21
- require 'spec/rake/spectask'
22
- desc "Run all rspecs"
23
- Spec::Rake::SpecTask.new(:spec) do |t|
24
- t.spec_files = FileList['spec/*_spec.rb']
25
- end
26
- task :default => :spec
23
+ begin
24
+ require 'spec/rake/spectask'
25
+ desc "Run all rspecs"
26
+ Spec::Rake::SpecTask.new(:spec) do |t|
27
+ t.spec_files = FileList['spec/*_spec.rb']
28
+ end
29
+ task :default => :spec
27
30
 
31
+ rescue LoadError
32
+ puts "Rspec (or a dependency) not available. Install it with: sudo gem install rspec"
33
+ end
28
34
  # vim: syntax=Ruby
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 1.0.0
@@ -1,22 +1,27 @@
1
1
  # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{chipmunk-ffi}
8
- s.version = "0.2.1"
8
+ s.version = "1.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Shawn Anderson"]
12
- s.date = %q{2009-12-16}
12
+ s.date = %q{2010-01-04}
13
13
  s.description = %q{FFI bindings for chipmunk physics lib.}
14
14
  s.email = %q{shawn42@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.markdown"
17
+ ]
15
18
  s.files = [
16
- "Rakefile",
19
+ "README.markdown",
20
+ "Rakefile",
17
21
  "VERSION",
18
22
  "chipmunk-ffi.gemspec",
19
23
  "lib/chipmunk-ffi.rb",
24
+ "lib/chipmunk-ffi/arbiter.rb",
20
25
  "lib/chipmunk-ffi/bb.rb",
21
26
  "lib/chipmunk-ffi/body.rb",
22
27
  "lib/chipmunk-ffi/constraint.rb",
@@ -32,14 +37,19 @@ Gem::Specification.new do |s|
32
37
  "lib/chipmunk-ffi/core.rb",
33
38
  "lib/chipmunk-ffi/shape.rb",
34
39
  "lib/chipmunk-ffi/space.rb",
40
+ "lib/chipmunk-ffi/space_hash.rb",
41
+ "lib/chipmunk-ffi/unsafe.rb",
35
42
  "lib/chipmunk-ffi/vec2.rb",
36
43
  "spec/bb_spec.rb",
37
44
  "spec/body_spec.rb",
38
45
  "spec/constraint_spec.rb",
39
46
  "spec/core_spec.rb",
47
+ "spec/perf.rb",
40
48
  "spec/shape_spec.rb",
49
+ "spec/space_hash_spec.rb",
41
50
  "spec/space_spec.rb",
42
51
  "spec/spec_helper.rb",
52
+ "spec/unsafe_spec.rb",
43
53
  "spec/vec2_spec.rb"
44
54
  ]
45
55
  s.homepage = %q{http://shawn42.github.com/chipmunk-ffi}
@@ -53,9 +63,12 @@ Gem::Specification.new do |s|
53
63
  "spec/body_spec.rb",
54
64
  "spec/constraint_spec.rb",
55
65
  "spec/core_spec.rb",
66
+ "spec/perf.rb",
56
67
  "spec/shape_spec.rb",
68
+ "spec/space_hash_spec.rb",
57
69
  "spec/space_spec.rb",
58
70
  "spec/spec_helper.rb",
71
+ "spec/unsafe_spec.rb",
59
72
  "spec/vec2_spec.rb"
60
73
  ]
61
74
 
@@ -64,14 +77,21 @@ Gem::Specification.new do |s|
64
77
  s.specification_version = 3
65
78
 
66
79
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
80
+ s.add_runtime_dependency(%q<ffi>, [">= 0.6.0"])
81
+ s.add_runtime_dependency(%q<nice-ffi>, [">= 0"])
67
82
  s.add_development_dependency(%q<rspec>, [">= 0"])
68
83
  s.add_development_dependency(%q<jeweler>, [">= 0"])
69
84
  else
85
+ s.add_dependency(%q<ffi>, [">= 0.6.0"])
86
+ s.add_dependency(%q<nice-ffi>, [">= 0"])
70
87
  s.add_dependency(%q<rspec>, [">= 0"])
71
88
  s.add_dependency(%q<jeweler>, [">= 0"])
72
89
  end
73
90
  else
91
+ s.add_dependency(%q<ffi>, [">= 0.6.0"])
92
+ s.add_dependency(%q<nice-ffi>, [">= 0"])
74
93
  s.add_dependency(%q<rspec>, [">= 0"])
75
94
  s.add_dependency(%q<jeweler>, [">= 0"])
76
95
  end
77
96
  end
97
+
@@ -33,7 +33,7 @@ module CP
33
33
  CP_FLOAT = :double
34
34
 
35
35
  end
36
- libs = %w{vec2 core bb body shape space constraint}
36
+ libs = %w{vec2 core bb body shape arbiter space constraint space_hash}
37
37
  $: << File.dirname(__FILE__)
38
38
  libs.each do |lib|
39
39
  require "chipmunk-ffi/#{lib}"
@@ -0,0 +1,108 @@
1
+ module CP
2
+ # FIXME tell Scott Lembcke that this function is missing from chipmunk_ffi.h
3
+ # cp_static_inline :cpArbiterIsFirstContact, [:pointer], :int
4
+
5
+ cp_static_inline :cpArbiterGetNormal, [:pointer, :int], Vect.by_value
6
+ cp_static_inline :cpArbiterGetPoint, [:pointer, :int], Vect.by_value
7
+
8
+ func :cpArbiterTotalImpulse, [:pointer], Vect.by_value
9
+ func :cpArbiterTotalImpulseWithFriction, [:pointer], Vect.by_value
10
+
11
+ class ArbiterStruct < NiceFFI::Struct
12
+ layout(
13
+ :num_contacts, :int,
14
+ :contacts, :pointer,
15
+ :a, :pointer,
16
+ :b, :pointer,
17
+ :e, CP_FLOAT,
18
+ :u, CP_FLOAT,
19
+ :surf_vr, Vect.by_value,
20
+ :stamp, :int,
21
+ :handler, :pointer,
22
+ :swapped_col, :char,
23
+ :first_col, :char
24
+ )
25
+ end
26
+
27
+ class Arbiter
28
+ attr_reader :struct
29
+ def initialize(ptr)
30
+ @struct = ArbiterStruct.new(ptr)
31
+ @shapes = nil
32
+
33
+ # Temporary workaround for a bug in chipmunk, fixed in r342.
34
+ @struct.num_contacts = 0 if @struct.contacts.null?
35
+ end
36
+
37
+ def first_contact?
38
+ # CP.cpArbiterIsFirstContact(@struct.pointer).nonzero?
39
+ @struct.first_col.nonzero?
40
+ end
41
+
42
+ def point(index = 0)
43
+ raise IndexError unless (0...@struct.num_contacts).include? index
44
+ Vec2.new CP.cpArbiterGetPoint(@struct.pointer, index)
45
+ end
46
+
47
+ def normal(index = 0)
48
+ raise IndexError unless (0...@struct.num_contacts).include? index
49
+ Vec2.new CP.cpArbiterGetNormal(@struct.pointer, index)
50
+ end
51
+
52
+ def impulse with_friction = false
53
+ if with_friction
54
+ Vec2.new CP.cpArbiterTotalImpulseWithFriction(@struct.pointer)
55
+ else
56
+ Vec2.new CP.cpArbiterTotalImpulse(@struct.pointer)
57
+ end
58
+ end
59
+
60
+ def shapes
61
+ return @shapes if @shapes
62
+
63
+ swapped = @struct.swapped_col.nonzero?
64
+ arba = swapped ? @struct.b : @struct.a
65
+ arbb = swapped ? @struct.a : @struct.b
66
+
67
+ as = ShapeStruct.new(arba)
68
+ a_obj_id = as.data.get_long 0
69
+ rb_a = ObjectSpace._id2ref a_obj_id
70
+
71
+ bs = ShapeStruct.new(arbb)
72
+ b_obj_id = bs.data.get_long 0
73
+ rb_b = ObjectSpace._id2ref b_obj_id
74
+
75
+ @shapes = [ rb_a, rb_b ]
76
+ end
77
+
78
+ def a
79
+ self.shapes[0]
80
+ end
81
+
82
+ def b
83
+ self.shapes[1]
84
+ end
85
+
86
+ def e
87
+ @struct.e
88
+ end
89
+ def e=(new_e)
90
+ @struct.e = new_e
91
+ end
92
+
93
+ def u
94
+ @struct.u
95
+ end
96
+ def u=(new_u)
97
+ @struct.u = new_u
98
+ end
99
+
100
+ def each_contact
101
+ (0...@struct.num_contacts).each do |index|
102
+ yield CP.cpArbiterGetPoint(@struct, index), CP.cpArbiterGetNormal(@struct, index)
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+
@@ -41,6 +41,10 @@ module CP
41
41
  cp_static_inline :cpBodyWorld2Local, [:pointer, Vect.by_value], Vect.by_value
42
42
  cp_static_inline :cpBodyApplyImpulse, [:pointer, Vect.by_value, Vect.by_value], :void
43
43
 
44
+ func :cpBodySetMass, [:pointer, CP_FLOAT], :void
45
+ func :cpBodySetMoment, [:pointer, CP_FLOAT], :void
46
+ func :cpBodySetAngle, [:pointer, CP_FLOAT], :void
47
+
44
48
  class Body
45
49
  attr_reader :struct
46
50
  def initialize(*args)
@@ -59,20 +63,30 @@ module CP
59
63
  @struct.m
60
64
  end
61
65
  def m=(pm)
62
- @struct.m = pm
66
+ CP.cpBodySetMass(@struct.pointer, pm)
63
67
  end
64
68
  alias :mass :m
65
69
  alias :mass= :m=
66
70
 
71
+ def m_inv
72
+ @struct.m_inv
73
+ end
74
+ alias :mass_inv :m_inv
75
+
67
76
  def i
68
77
  @struct.i
69
78
  end
70
79
  def i=(pi)
71
- @struct.i = pi
80
+ CP.cpBodySetMoment(@struct.pointer, pi)
72
81
  end
73
82
  alias :moment :i
74
83
  alias :moment= :i=
75
84
 
85
+ def i_inv
86
+ @struct.i_inv
87
+ end
88
+ alias :moment_inv :i_inv
89
+
76
90
  def p
77
91
  Vec2.new @struct.p
78
92
  end
@@ -107,7 +121,7 @@ module CP
107
121
  @struct.a
108
122
  end
109
123
  def a=(pa)
110
- @struct.a = pa
124
+ CP.cpBodySetAngle(@struct.pointer, pa)
111
125
  end
112
126
  alias :angle :a
113
127
  alias :angle= :a=
@@ -134,12 +148,30 @@ module CP
134
148
  Vec2.new @struct.rot
135
149
  end
136
150
 
151
+ def v_limit
152
+ @struct.v_limit
153
+ end
154
+ def v_limit=(new_v_limit)
155
+ @struct.v_limit = new_v_limit
156
+ end
157
+ alias :vel_limit :v_limit
158
+ alias :vel_limit= :v_limit=
159
+
160
+ def w_limit
161
+ @struct.w_limit
162
+ end
163
+ def w_limit=(new_w_limit)
164
+ @struct.w_limit = new_w_limit
165
+ end
166
+ alias :ang_vel_limit :w_limit
167
+ alias :ang_vel_limit= :w_limit=
168
+
137
169
  def local2world(v)
138
- CP.cpBodyLocal2World(@struct.pointer,v.struct)
170
+ Vec2.new CP.cpBodyLocal2World(@struct.pointer,v.struct)
139
171
  end
140
172
 
141
173
  def world2local(v)
142
- CP.cpBodyWorld2Local(@struct.pointer,v.struct)
174
+ Vec2.new CP.cpBodyWorld2Local(@struct.pointer,v.struct)
143
175
  end
144
176
 
145
177
  def reset_forces
@@ -155,7 +187,7 @@ module CP
155
187
  end
156
188
 
157
189
  def update_velocity(g,dmp,dt)
158
- CP.cpBodyUpdateVelocity(@struct.pointer,g,dmp,dt)
190
+ CP.cpBodyUpdateVelocity(@struct.pointer,g.struct,dmp,dt)
159
191
  end
160
192
 
161
193
  def update_position(dt)
@@ -24,17 +24,17 @@ module CP
24
24
  end
25
25
 
26
26
  func :cpMomentForCircle, [CP_FLOAT,CP_FLOAT,CP_FLOAT,Vect.by_value], CP_FLOAT
27
- def moment_for_circle(m,r1,r2,offset)
27
+ def self.moment_for_circle(m,r1,r2,offset)
28
28
  cpMomentForCircle(m, r1, r2, offset.struct);
29
29
  end
30
30
 
31
31
  func :cpMomentForSegment, [CP_FLOAT,Vect.by_value,Vect.by_value], CP_FLOAT
32
- def moment_for_segment(m,v1,v2)
32
+ def self.moment_for_segment(m,v1,v2)
33
33
  cpMomentForCircle(m, v1.struct, v2.struct)
34
34
  end
35
35
 
36
36
  func :cpMomentForPoly, [CP_FLOAT,:int,:pointer,Vect.by_value], CP_FLOAT
37
- def moment_for_poly(m,verts,offset)
37
+ def self.moment_for_poly(m,verts,offset)
38
38
  mem_pointer = FFI::MemoryPointer.new Vect, verts.size
39
39
  vert_structs = verts.collect{|s|s.struct}
40
40
 
@@ -47,6 +47,9 @@ module CP
47
47
  cpMomentForPoly(m, verts.size, mem_pointer, offset.struct)
48
48
  end
49
49
 
50
+ def moment_for_circle(*args);CP.moment_for_circle(*args);end
51
+ def moment_for_poly(*args);CP.moment_for_poly(*args);end
52
+ def moment_for_segment(*args);CP.moment_for_segment(*args);end
50
53
  func :cpInitChipmunk, [], :void
51
54
  cpInitChipmunk
52
55
 
@@ -37,19 +37,33 @@ module CP
37
37
  )
38
38
  end
39
39
  class SegmentQueryInfoStruct < NiceFFI::Struct
40
- layout(:shape, ShapeStruct,
40
+ layout(:shape, :pointer,
41
41
  :t, CP_FLOAT,
42
42
  :n, Vect
43
43
  )
44
44
  end
45
45
 
46
+
46
47
  func :cpCircleShapeNew, [BodyStruct,CP_FLOAT,Vect.by_value], ShapeStruct
47
48
  func :cpSegmentShapeNew, [BodyStruct,Vect.by_value,Vect.by_value,CP_FLOAT], ShapeStruct
48
49
  func :cpPolyShapeNew, [BodyStruct,:int,:pointer,Vect.by_value], ShapeStruct
49
50
  func :cpShapeCacheBB, [ShapeStruct], :void
50
51
  func :cpResetShapeIdCounter, [], :void
52
+ func :cpShapePointQuery, [:pointer, Vect.by_value], :int
53
+ func :cpShapeSegmentQuery, [:pointer, Vect.by_value, Vect.by_value, :pointer], :int
51
54
 
52
55
  module Shape
56
+ class SegmentQueryInfo
57
+ attr_reader :hit, :t, :n
58
+ def initialize(hit,t=nil,n=nil,info=nil,ptr=nil)
59
+ @hit = hit
60
+ @t = t
61
+ @n = n
62
+ @info = info
63
+ @ptr = ptr
64
+ end
65
+ end
66
+
53
67
  attr_reader :struct
54
68
 
55
69
  def body
@@ -92,10 +106,9 @@ module CP
92
106
  end
93
107
 
94
108
  def cache_bb
95
- CP.cpShapeCacheBB(@struct.bb)
109
+ CP.cpShapeCacheBB(@struct.bb)
96
110
  bb
97
111
  end
98
-
99
112
  def e
100
113
  @struct.e
101
114
  end
@@ -119,14 +132,26 @@ module CP
119
132
 
120
133
  def surface_v
121
134
  Vec2.new @struct.surface_v
122
- end
135
+ end
123
136
  def surface_v=(new_sv)
124
137
  @struct.surface_v.pointer.put_bytes 0, new_sv.struct.to_bytes, 0,Vect.size
125
138
  end
126
139
 
140
+ def sensor?
141
+ @struct.sensor == 0 ? false : true
142
+ end
143
+ def sensor=(new_sensor)
144
+ @struct.sensor = new_sensor ? 1 : 0
145
+ end
146
+
147
+ def point_query(point)
148
+ bool_int = CP.cpShapePointQuery(@struct.pointer, point.struct)
149
+ bool_int == 0 ? false : true
150
+ end
151
+
127
152
  def set_data_pointer
128
- mem = FFI::MemoryPointer.new(:ulong)
129
- mem.put_ulong 0, object_id
153
+ mem = FFI::MemoryPointer.new(:long)
154
+ mem.put_long 0, object_id
130
155
  # this is needed to prevent data corruption by GC
131
156
  @shape_pointer = mem
132
157
  @struct.data = mem
@@ -136,6 +161,23 @@ module CP
136
161
  CP.cpResetShapeIdCounter
137
162
  end
138
163
 
164
+ def segment_query(a,b)
165
+ ptr = FFI::MemoryPointer.new(SegmentQueryInfoStruct.size)
166
+ info = SegmentQueryInfoStruct.new ptr
167
+
168
+ bool_int = CP.cpShapeSegmentQuery(@struct.pointer, a.struct.pointer, b.struct.pointer, ptr)
169
+ hit = bool_int == 0 ? false : true
170
+ if hit
171
+ #obj_id = info.shape.data.get_long 0
172
+ #shape = ObjectSpace._id2ref obj_id
173
+ # TODO prob need to dup these things
174
+ n = Vec2.new(info.n)
175
+ SegmentQueryInfo.new hit, info.t, n, info, ptr
176
+ else
177
+ SegmentQueryInfo.new hit
178
+ end
179
+ end
180
+
139
181
  class Circle
140
182
  include Shape
141
183
  def initialize(body, rad, offset_vec)