sdl2_ffi 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1fbda9790c93fa1061e680eb19b56d27ef5e9b2e
4
- data.tar.gz: 8947768e9c0f8d504f6cb154624cec7a2f220c37
3
+ metadata.gz: 7b7b0f26850cdb76060ffc915bd52f8979d58374
4
+ data.tar.gz: 568de3aef8a7ef88a2f381f1cb3eb0d2fdd9fb70
5
5
  SHA512:
6
- metadata.gz: 8b8f386629bc6ff085e64450ad026b4669ee4251dfe924f6eae89772905b3474f4c0a0bf647f9a22f5ca6024651b655a785aed12e48e647ed0d5b01ddc50e015
7
- data.tar.gz: e1afed2d1d6dc466bdaeb9b3a3aac67d93e597972bccdebe0dc692415f4989290638c61594eb0fcfcfe01df4ae045352a9537970df290733f6d12e1abc9ae1c3
6
+ metadata.gz: d7b43f365d9b052889db92e63437e46a82634f11c6f7ccd13d06b6dd7468fc5766c6dd4817e307655034d72a35b04628c91149ff6c26d309fe9e3df20fd048e1
7
+ data.tar.gz: 2f64f961c415e03f1b47cbbae7d04cd881b22c0c2e1ae11b527b4b1b912f8e48eef40d99c98caf8208f525d87efb617a101f0f40f8305b8bdd4c2fd3aa38920a
data/Guardfile CHANGED
@@ -4,12 +4,12 @@
4
4
  guard :minitest do
5
5
  # with Minitest::Unit
6
6
  watch(%r{^test/(.*)\/?test_(.*)\.rb})
7
- watch(%r{^lib/(.*/)?([^/]+)\.rb}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
7
+ watch(%r{^lib/(.*/)?([^/]+)\.rb}) { |m| "test/unit/#{m[1]}test_#{m[2]}.rb" }
8
8
  watch(%r{^test/test_helper\.rb}) { 'test' }
9
9
 
10
10
  # with Minitest::Spec
11
11
  watch(%r{^spec/(.*)_spec\.rb})
12
- watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
12
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/unit/#{m[1]}_spec.rb" }
13
13
  watch(%r{^spec/spec_helper\.rb}) { 'spec' }
14
14
 
15
15
  # Rails 4
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # sdl2_ffi
2
2
 
3
- This is a simple interface to SDL2 for Ruby using FFI. This effort has barely started.
3
+ This is a simple interface to SDL2 for Ruby using FFI. It also supports SDL_image and SDL_ttf.
4
+ Most of the procedural API has been linked with a few large exceptions like SDL_opengl.
5
+ The "Object Oriented" part of this interface has barely started.
6
+
7
+ # Documentation/API Reference:
8
+
9
+ The documentation is embedded within the code. Generate the RDoc
4
10
 
5
11
  # How to start:
6
12
 
@@ -18,6 +24,8 @@ The SDL2 module is defined and it is where the raw SDL API is loaded and linked.
18
24
 
19
25
  SDL2.init(SDL2::INIT_EVERYTHING)
20
26
 
27
+
28
+
21
29
  ### Gotchas:
22
30
 
23
31
  * Remember that SDL uses the 'SDL_Bool' enum instead of actual ruby Boolean, so instead of 'true' and 'false', you get ':true' and ':false'
@@ -2,23 +2,105 @@ require 'ffi'
2
2
  require 'sdl2/sdl_module'
3
3
  require 'active_support/inflector'
4
4
 
5
+ # libSDL2's interface
5
6
  module SDL2
6
7
  extend FFI::Library
8
+ ffi_lib SDL_MODULE
9
+
10
+ [:int, :uint8, :int8, :uint16, :int16, :uint32, :int32, :uint64, :int64, :float, :double].each do |type|
11
+ typedef :pointer, "p_#{type}".to_sym
12
+ end
13
+
14
+ #Filter Proc, True when arg equals zero
15
+ TRUE_WHEN_ZERO = Proc.new do |result|
16
+ result == 0
17
+ end
18
+
19
+ # Filter Proc, True when arg not null?
20
+ TRUE_WHEN_NOT_NULL = Proc.new do |result|
21
+ (!result.null?)
22
+ end
7
23
 
8
-
9
24
  # This converts the SDL Function Prototype name "SDL_XxxYyyyyZzz" to ruby's
10
25
  # "xxx_yyyy_zzz" convetion
11
- def self.api(func_name, args, type)
26
+ def self.api(func_name, args, type, options = {})
27
+
28
+ options = {
29
+ :error => false,
30
+ :filter => TRUE_WHEN_ZERO
31
+ }.merge(options)
32
+
12
33
  camelCaseName = func_name.to_s.gsub('SDL_','')
13
34
  methodName = ActiveSupport::Inflector.underscore(camelCaseName).to_sym
14
- print "Linking #{func_name} -> #{methodName}...."
35
+
15
36
  self.attach_function methodName, func_name, args, type
16
- puts "OK!"
37
+
38
+ if options[:error]
39
+ returns_error(methodName, options[:filter])
40
+ end
41
+
42
+ if type == :bool
43
+ boolean?(methodName)
44
+ end
45
+
17
46
  return methodName
18
47
  end
19
48
 
49
+ # Returns the 'singleton class' so we can define class-level methods on the
50
+ # fly.
51
+ # There may be a better place to put this.
52
+ def self.metaclass
53
+
54
+ class << self; self; end
55
+ end
56
+
57
+ # Generates an alternative version of methodName that will raise a SDL Error
58
+ # when the return value fails the filter test. The alternative version has
59
+ # the same name, but with an exclamation mark ("!") at the end, indicating the
60
+ # danger.
61
+ def self.returns_error(methodName, filter)
62
+ metaclass.instance_eval do
63
+ define_method "#{methodName}!".to_sym do |*args|
64
+ result = self.send(methodName, *args)
65
+ raise_error_unless filter.call(result)
66
+ result
67
+ end
68
+ end
69
+ end
70
+
71
+ # Generates an alternative version of methodName that will return Ruby's `true`
72
+ # if the method named returns SDL_true/:true enum value. The alternative
73
+ # method has the same name with a question mark ("?") appended, to indicate its
74
+ # boolean nature.
75
+ def self.boolean?(methodName)
76
+ metaclass.instance_eval do
77
+ define_method("#{methodName}?".to_sym) do |*args|
78
+ self.send(methodName, *args) == :true
79
+ end
80
+ end
81
+ end
82
+
83
+ # Define a four character code as a Uint32
84
+ #MACRO: SDL_FOURCC(A, B, C, D) \
85
+ # ((SDL_static_cast(Uint32, SDL_static_cast(Uint8, (A))) << 0) | \
86
+ # (SDL_static_cast(Uint32, SDL_static_cast(Uint8, (B))) << 8) | \
87
+ # (SDL_static_cast(Uint32, SDL_static_cast(Uint8, (C))) << 16) | \
88
+ # (SDL_static_cast(Uint32, SDL_static_cast(Uint8, (D))) << 24))
89
+ def self.fourcc(*args)
90
+ bit_cnt = 0
91
+ result = 0
92
+ args.each do |arg|
93
+ arg = arg.codepoints[0] if arg.kind_of? String
94
+ result = result | (arg << bit_cnt)
95
+ bit_cnt += 8
96
+ end
97
+ return result
98
+ end
99
+
100
+ # FFI::Struct class with some useful additions.
20
101
  class Struct < FFI::Struct
21
102
 
103
+ # Allows creation and use within block, automatically freeing pointer after block.
22
104
  def initialize(*args, &block)
23
105
  super(*args)
24
106
  if block_given?
@@ -27,54 +109,97 @@ module SDL2
27
109
  self.class.release(self.pointer)
28
110
  end
29
111
  end
112
+
113
+ # A default release scheme is defined, but should be redefined where appropriate.
114
+ def self.release(pointer)
115
+ pointer.free
116
+ end
117
+
118
+ # A human-readable representation of the struct and it's values.
119
+ def inspect
120
+ report = "struct #{self.class.to_s}{"
121
+ report += self.class.members.collect do |field|
122
+ "#{field}->#{self[field].inspect}"
123
+ end.join(' ')
124
+ report += "}"
125
+ end
126
+
127
+ # Compare two structures by class and values.
128
+ def ==(other)
129
+ return false unless self.class == other.class
130
+ self.class.members.each do |field|
131
+ return false unless self[field] == other[field]
132
+ end
133
+ true # return true if we get this far.
134
+ end
30
135
  end
31
136
 
137
+ # FFI::ManagedStruct possibly with useful additions.
32
138
  class ManagedStruct < FFI::ManagedStruct
33
139
 
140
+ # Allows create and use the struct within a block.
34
141
  def initialize(*args, &block)
35
142
  super(*args)
36
143
  if block_given?
37
- throw 'Release must be defined to use block' unless self.class.respond_to?(:release)
38
144
  yield self
39
- self.class.release(self.pointer)
40
145
  end
41
146
  end
42
- end
43
147
 
44
- # TODO: Review default/hard-coded load paths?
45
- ffi_lib SDL_MODULE
148
+ end
46
149
 
47
- # SDL_Bool
150
+ # SDL_Bool: SDL's TRUE/FALSE enumeration.
151
+ # Ruby does not automatically evaluate 0 as false.
48
152
  enum :bool, [:false, 0, :true, 1]
49
153
 
50
- def self.throw_error_unless(condition)
51
- throw get_error() unless condition
154
+ # Raise the current error value as a RuntimeException
155
+ def self.raise_error
156
+ raise "SDL Error: #{SDL2.get_error()}"
157
+ end
158
+
159
+ # Conditionally raise an error, unless true
160
+ def self.raise_error_unless(condition)
161
+ raise_error unless condition
52
162
  end
53
163
 
54
- def self.throw_error_if(condition)
55
- throw get_error() if condition
164
+ # Conditionally raise an error, unless false
165
+ def self.raise_error_if(condition)
166
+ raise_error if condition
167
+ end
168
+
169
+ class TypedPointer < Struct
170
+ def self.type(kind)
171
+ layout :value, kind
172
+ end
173
+
174
+ def value
175
+ self[value]
176
+ end
177
+
178
+ alias_method :deref, :value
56
179
  end
57
180
 
58
181
  # Simple Type Structures to interface 'typed-pointers'
59
182
  # TODO: Research if this is the best way to handle 'typed-pointers'
60
- class FloatStruct < FFI::Struct
61
- layout :value, :float
183
+ class FloatPointer < TypedPointer
184
+ type :float
62
185
  end
63
186
 
64
- class IntStruct < FFI::Struct
65
- layout :value, :int
187
+ # Int-typed pointer
188
+ class IntStruct < TypedPointer
189
+ type :int
66
190
  end
67
191
 
68
- class UInt16Struct < FFI::Struct
69
- layout :value, :uint16
192
+ #
193
+ class UInt16Struct < TypedPointer
194
+ type :uint16
70
195
  end
71
196
 
72
- class UInt32Struct < FFI::Struct
73
- layout :value, :uint32
197
+ class UInt32Struct < TypedPointer
198
+ type :uint32
74
199
  end
75
200
 
76
- class UInt8Struct < FFI::Struct
77
- layout :value, :uint8
201
+ class UInt8Struct < TypedPointer
202
+ type :uint8
78
203
  end
79
204
 
80
205
  # TODO: Review if this is the best place to put it.
@@ -87,7 +212,7 @@ module SDL2
87
212
  :mod, 0x00000004
88
213
  ]
89
214
 
90
- class BlendModeStruct < FFI::Struct
215
+ class BlendModeStruct < Struct
91
216
  layout :value, :blend_mode
92
217
  end
93
218
 
@@ -1,12 +1,35 @@
1
1
  require 'sdl2'
2
2
 
3
3
  module SDL2
4
+
4
5
  #SDL_pixels.h:252~258
5
6
  class Color < Struct
6
7
  layout :r, :uint8,
7
- :g, :uint8,
8
- :b, :uint8,
9
- :a, :uint8
8
+ :g, :uint8,
9
+ :b, :uint8,
10
+ :a, :uint8
11
+
12
+ [:r,:g,:b,:a].each do |field|
13
+ define_method field do
14
+ self[field]
15
+ end
16
+ define_method "#{field}=".to_sym do |value|
17
+ self[field]=value
18
+ end
19
+ end
20
+
21
+ def set(r,g,b,a=nil)
22
+ self.r = r
23
+ self.g = g
24
+ self.b = b
25
+ self.a = a unless a.nil?
26
+ end
27
+
28
+ def copy_from(color)
29
+ [:r, :g, :b, :a].each do |c|
30
+ self.send("#{c}=", color.send(c))
31
+ end
32
+ end
10
33
  end
11
- Colour = Color # Because SDL does it
34
+ Colour = Color # Because SDL does it
12
35
  end
@@ -33,7 +33,7 @@ module SDL2
33
33
 
34
34
  def self.count!
35
35
  total = count
36
- SDL2.throw_error_if total < 0
36
+ SDL2.raise_error_if total < 0
37
37
  return total
38
38
  end
39
39
 
@@ -48,7 +48,7 @@ module SDL2
48
48
 
49
49
  def closest_display_mode!(wanted)
50
50
  found = closest_display_mode(wanted)
51
- SDL2.throw_error_if(found.nil?)
51
+ SDL2.raise_error_if(found.nil?)
52
52
  return found
53
53
  end
54
54
 
@@ -64,7 +64,7 @@ module SDL2
64
64
 
65
65
  def bounds!
66
66
  rect = bounds()
67
- SDL2.throw_error_if rect.nil?
67
+ SDL2.raise_error_if rect.nil?
68
68
  return rect
69
69
  end
70
70
 
@@ -1,4 +1,4 @@
1
1
 
2
2
  module SDL2
3
- GEM_VERSION = "0.0.2"
3
+ GEM_VERSION = "0.0.3"
4
4
  end
@@ -0,0 +1,68 @@
1
+ require 'sdl2'
2
+ require 'sdl2/surface'
3
+ require 'sdl2/image/sdl_image_module'
4
+ require 'active_support/inflector'
5
+
6
+ module SDL2
7
+
8
+ module Image
9
+
10
+ extend FFI::Library
11
+ ffi_lib SDL_IMAGE_MODULE
12
+
13
+ def self.api(func_name, args, type)
14
+ camelCaseName = func_name.to_s.gsub('IMG_', '')
15
+ methodName = ActiveSupport::Inflector.underscore(camelCaseName).to_sym
16
+ self.attach_function methodName, func_name, args, type
17
+ return methodName
18
+ end
19
+
20
+ enum :init_flags, [:JPG, :PNG, :TIF, :WEBP]
21
+
22
+ api :IMG_Init, [:init_flags], :int
23
+ api :IMG_Quit, [], :void
24
+ api :IMG_LoadTyped_RW, [RWops.by_ref, :int, :string], Surface.auto_ptr
25
+ api :IMG_Load, [:string], Surface.auto_ptr
26
+ api :IMG_Load_RW, [RWops.by_ref, :int], Surface.auto_ptr
27
+
28
+ api :IMG_isICO, [RWops.by_ref], :int
29
+ api :IMG_isCUR, [RWops.by_ref], :int
30
+ api :IMG_isBMP, [RWops.by_ref], :int
31
+ api :IMG_isGIF, [RWops.by_ref], :int
32
+ api :IMG_isJPG, [RWops.by_ref], :int
33
+ api :IMG_isLBM, [RWops.by_ref], :int
34
+ api :IMG_isPCX, [RWops.by_ref], :int
35
+ api :IMG_isPNG, [RWops.by_ref], :int
36
+ api :IMG_isPNM, [RWops.by_ref], :int
37
+ api :IMG_isTIF, [RWops.by_ref], :int
38
+ api :IMG_isXCF, [RWops.by_ref], :int
39
+ api :IMG_isXPM, [RWops.by_ref], :int
40
+ api :IMG_isXV, [RWops.by_ref], :int
41
+ api :IMG_isWEBP, [RWops.by_ref], :int
42
+
43
+ api :IMG_LoadICO_RW, [RWops.by_ref], Surface.auto_ptr
44
+ api :IMG_LoadCUR_RW, [RWops.by_ref], Surface.auto_ptr
45
+ api :IMG_LoadBMP_RW, [RWops.by_ref], Surface.auto_ptr
46
+ api :IMG_LoadGIF_RW, [RWops.by_ref], Surface.auto_ptr
47
+ api :IMG_LoadJPG_RW, [RWops.by_ref], Surface.auto_ptr
48
+ api :IMG_LoadLBM_RW, [RWops.by_ref], Surface.auto_ptr
49
+ api :IMG_LoadPCX_RW, [RWops.by_ref], Surface.auto_ptr
50
+ api :IMG_LoadPNG_RW, [RWops.by_ref], Surface.auto_ptr
51
+ api :IMG_LoadPNM_RW, [RWops.by_ref], Surface.auto_ptr
52
+ api :IMG_LoadTGA_RW, [RWops.by_ref], Surface.auto_ptr
53
+ api :IMG_LoadTIF_RW, [RWops.by_ref], Surface.auto_ptr
54
+ api :IMG_LoadXCF_RW, [RWops.by_ref], Surface.auto_ptr
55
+ api :IMG_LoadXPM_RW, [RWops.by_ref], Surface.auto_ptr
56
+ api :IMG_LoadXV_RW, [RWops.by_ref], Surface.auto_ptr
57
+ api :IMG_LoadWEBP_RW, [RWops.by_ref], Surface.auto_ptr
58
+
59
+ api :IMG_ReadXPMFromArray, [:pointer], Surface.auto_ptr
60
+
61
+ api :IMG_SavePNG, [Surface.by_ref, :string], :int
62
+ api :IMG_SavePNG_RW, [Surface.by_ref, RWops.by_ref, :int], :int
63
+
64
+ end
65
+
66
+ IMG = Image # Alias to follow IMG_xxx convention
67
+
68
+ end
@@ -0,0 +1,8 @@
1
+ module SDL2
2
+
3
+ module Image
4
+
5
+ SDL_IMAGE_MODULE = ['libSDL2_image', '/usr/local/lib/libSDL2_image.so']
6
+
7
+ end
8
+ end
@@ -28,16 +28,16 @@ module SDL2
28
28
  :everything, INIT_EVERYTHING
29
29
  ]
30
30
 
31
- api :SDL_Init, [:init_flag], :int
31
+ api :SDL_Init, [:init_flag], :int, {error: true}
32
32
 
33
- def self.init!(flags)
34
- error_code = init(flags)
35
- if (error_code != 0)
36
- throw get_error()
37
- end
38
- end
33
+ #def self.init!(flags)
34
+ # error_code = init(flags)
35
+ # if (error_code != 0)
36
+ # throw get_error()
37
+ # end
38
+ #end
39
39
 
40
- api :SDL_InitSubSystem, [:init_flag], :int
40
+ api :SDL_InitSubSystem, [:init_flag], :int, {error: true}
41
41
 
42
42
  def init_sub_system!(flags)
43
43
  error_code = init_sub_system(flags)