sdl2_ffi 0.0.2 → 0.0.3

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.
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)