rb_sdl2 0.1.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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +17 -0
  4. data/README.md +40 -0
  5. data/lib/rb_sdl2/audio/audio_allowed_changes.rb +17 -0
  6. data/lib/rb_sdl2/audio/audio_buffer.rb +49 -0
  7. data/lib/rb_sdl2/audio/audio_device.rb +44 -0
  8. data/lib/rb_sdl2/audio/audio_format.rb +23 -0
  9. data/lib/rb_sdl2/audio/audio_spec.rb +29 -0
  10. data/lib/rb_sdl2/audio.rb +132 -0
  11. data/lib/rb_sdl2/clipboard.rb +44 -0
  12. data/lib/rb_sdl2/cpu_info.rb +39 -0
  13. data/lib/rb_sdl2/cursor/color_cursor.rb +19 -0
  14. data/lib/rb_sdl2/cursor/cursor_class.rb +24 -0
  15. data/lib/rb_sdl2/cursor/cursor_pointer.rb +12 -0
  16. data/lib/rb_sdl2/cursor/default_cursor.rb +18 -0
  17. data/lib/rb_sdl2/cursor/system_cursor.rb +45 -0
  18. data/lib/rb_sdl2/cursor.rb +39 -0
  19. data/lib/rb_sdl2/display.rb +103 -0
  20. data/lib/rb_sdl2/display_mode.rb +35 -0
  21. data/lib/rb_sdl2/error.rb +9 -0
  22. data/lib/rb_sdl2/event/event_filter.rb +83 -0
  23. data/lib/rb_sdl2/event/event_queue.rb +137 -0
  24. data/lib/rb_sdl2/event/event_type.rb +271 -0
  25. data/lib/rb_sdl2/event.rb +161 -0
  26. data/lib/rb_sdl2/filesystem.rb +40 -0
  27. data/lib/rb_sdl2/hint.rb +24 -0
  28. data/lib/rb_sdl2/keyboard/key_mod.rb +37 -0
  29. data/lib/rb_sdl2/keyboard/keyboard_state.rb +34 -0
  30. data/lib/rb_sdl2/keyboard.rb +50 -0
  31. data/lib/rb_sdl2/message_box.rb +121 -0
  32. data/lib/rb_sdl2/mouse/global_mouse.rb +18 -0
  33. data/lib/rb_sdl2/mouse/mouse_button.rb +24 -0
  34. data/lib/rb_sdl2/mouse/mouse_class.rb +33 -0
  35. data/lib/rb_sdl2/mouse/mouse_wheel.rb +53 -0
  36. data/lib/rb_sdl2/mouse/relative_mouse.rb +12 -0
  37. data/lib/rb_sdl2/mouse/window_mouse.rb +17 -0
  38. data/lib/rb_sdl2/mouse.rb +74 -0
  39. data/lib/rb_sdl2/palette.rb +70 -0
  40. data/lib/rb_sdl2/pixel_format_enum.rb +73 -0
  41. data/lib/rb_sdl2/platform.rb +7 -0
  42. data/lib/rb_sdl2/power_info.rb +36 -0
  43. data/lib/rb_sdl2/rect.rb +14 -0
  44. data/lib/rb_sdl2/ref_count_pointer.rb +20 -0
  45. data/lib/rb_sdl2/rw_ops/rw_operator.rb +102 -0
  46. data/lib/rb_sdl2/rw_ops.rb +124 -0
  47. data/lib/rb_sdl2/screen_saver.rb +11 -0
  48. data/lib/rb_sdl2/sdl.rb +32 -0
  49. data/lib/rb_sdl2/surface/blend_mode.rb +41 -0
  50. data/lib/rb_sdl2/surface/pixel_format.rb +89 -0
  51. data/lib/rb_sdl2/surface.rb +244 -0
  52. data/lib/rb_sdl2/text_input.rb +15 -0
  53. data/lib/rb_sdl2/timer.rb +22 -0
  54. data/lib/rb_sdl2/version.rb +13 -0
  55. data/lib/rb_sdl2/video.rb +25 -0
  56. data/lib/rb_sdl2/window/dialog.rb +19 -0
  57. data/lib/rb_sdl2/window/display.rb +85 -0
  58. data/lib/rb_sdl2/window/grab.rb +23 -0
  59. data/lib/rb_sdl2/window/hit_test.rb +52 -0
  60. data/lib/rb_sdl2/window/position.rb +38 -0
  61. data/lib/rb_sdl2/window/shape.rb +76 -0
  62. data/lib/rb_sdl2/window/size.rb +59 -0
  63. data/lib/rb_sdl2/window/window_flags.rb +78 -0
  64. data/lib/rb_sdl2/window.rb +242 -0
  65. data/lib/rb_sdl2.rb +53 -0
  66. data/rb_sdl2.gemspec +19 -0
  67. metadata +135 -0
@@ -0,0 +1,74 @@
1
+ module RbSDL2
2
+ module Mouse
3
+ class << self
4
+ def capture=(bool)
5
+ err = ::SDL2.SDL_CaptureMouse(bool ? ::SDL2::SDL_TRUE : ::SDL2::SDL_FALSE)
6
+ raise RbSDL2Error if err < 0
7
+ end
8
+
9
+ def relative=(bool)
10
+ err = ::SDL2.SDL_SetRelativeMouseMode(bool ? ::SDL2::SDL_TRUE : ::SDL2::SDL_FALSE)
11
+ raise RbSDL2Error if err < 0
12
+ end
13
+
14
+ def relative? = ::SDL2.SDL_GetRelativeMouseMode == ::SDL2::SDL_TRUE
15
+ end
16
+
17
+ require 'forwardable'
18
+ extend SingleForwardable
19
+
20
+ class << self
21
+ require_relative 'mouse/global_mouse'
22
+
23
+ def global_mouse = GlobalMouse.instance
24
+ end
25
+
26
+ def_single_delegator "global_mouse.update", :position, :global_position
27
+ def_single_delegator "global_mouse.update", :position=, :global_position=
28
+ def_single_delegator "global_mouse.update", :x, :global_x
29
+ def_single_delegator "global_mouse.update", :y, :global_y
30
+
31
+ class << self
32
+ require_relative 'mouse/mouse_wheel'
33
+
34
+ def mouse_wheel = MouseWheel.instance
35
+ end
36
+
37
+ def_single_delegator "mouse_wheel.update", :position, :wheel_position
38
+ def_single_delegator "Mouse::MouseWheel", :wheel=
39
+ def_single_delegator "mouse_wheel.update", :x, :wheel_x
40
+ def_single_delegator "mouse_wheel.update", :y, :wheel_y
41
+
42
+ class << self
43
+ require_relative 'mouse/relative_mouse'
44
+
45
+ def relative_mouse = RelativeMouse.instance
46
+
47
+ def relative_position=(rx_ry)
48
+ rx, ry = rx_ry
49
+ px, py = position
50
+ self.position = [px + rx, py + ry]
51
+ end
52
+ end
53
+
54
+ def_single_delegator "relative_mouse.update", :position, :relative_position
55
+ def_single_delegator "relative_mouse.update", :x, :relative_x
56
+ def_single_delegator "relative_mouse.update", :y, :relative_y
57
+
58
+ class << self
59
+ require_relative 'mouse/window_mouse'
60
+
61
+ def window_mouse = WindowMouse.instance
62
+ end
63
+
64
+ def_single_delegator "window_mouse.update", :button
65
+
66
+ require_relative 'mouse/mouse_button'
67
+ extend MouseButton
68
+
69
+ def_single_delegator "window_mouse.update", :position
70
+ def_single_delegator "window_mouse.update", :position=
71
+ def_single_delegator "window_mouse.update", :x
72
+ def_single_delegator "window_mouse.update", :y
73
+ end
74
+ end
@@ -0,0 +1,70 @@
1
+ module RbSDL2
2
+ class Palette
3
+ require_relative 'ref_count_pointer'
4
+
5
+ class PalettePointer < RefCountPointer
6
+ class << self
7
+ def release(ptr) = ::SDL2.SDL_FreePalette(ptr)
8
+
9
+ def entity_class = ::SDL2::SDL_Palette
10
+ end
11
+ end
12
+
13
+ class << self
14
+ def [](*color)
15
+ plt = new(color.length)
16
+ color.each.with_index { |c, nth| plt[nth] = c }
17
+ plt
18
+ end
19
+
20
+ def new(num_colors)
21
+ ptr = PalettePointer.new(::SDL2.SDL_AllocPalette(num_colors))
22
+ raise RbSDL2Error if ptr.null?
23
+ super(ptr)
24
+ end
25
+
26
+ def to_ptr(ptr)
27
+ obj = allocate
28
+ obj.__send__(:initialize, PalettePointer.to_ptr(ptr))
29
+ obj
30
+ end
31
+ end
32
+
33
+ def initialize(ptr)
34
+ @st = ::SDL2::SDL_Palette.new(ptr)
35
+ end
36
+
37
+ def ==(other)
38
+ other.respond_to?(:to_ptr) && to_ptr == other.to_ptr
39
+ end
40
+
41
+ def [](nth)
42
+ raise ArgumentError if nth < 0 || length <= nth
43
+ ::SDL2::SDL_Color.new(@st[:colors] + ::SDL2::SDL_Color.size * nth).values
44
+ end
45
+
46
+ # color 引数には 3要素以上の配列であること。4要素目以降は無視される。
47
+ # color 引数は内部で splat する。これに対応していれば配列以外のオブジェクトでもよい。
48
+ # パレットのカラーが描画に使われるときはアルファ値は無視されて不透明(SDL_ALPHA_OPAQUE)として扱わられる。
49
+ # パレットのカラーは作成時に全て [255, 255, 255, 255] で埋められている。
50
+ def []=(nth, color)
51
+ raise ArgumentError if nth < 0 || length <= nth
52
+ c = ::SDL2::SDL_Color.new
53
+ c[:r], c[:g], c[:b] = color
54
+ err = ::SDL2.SDL_SetPaletteColors(self, c, nth, 1)
55
+ raise RbSDL2Error if err < 0
56
+ end
57
+
58
+ def each = length.times { |nth| yield(self[nth]) }
59
+
60
+ def length = @st[:ncolors]
61
+
62
+ alias size length
63
+
64
+ def to_a = to_enum.to_a
65
+
66
+ def to_ptr = @st.to_ptr
67
+
68
+ def version = @st[:version]
69
+ end
70
+ end
@@ -0,0 +1,73 @@
1
+ module RbSDL2
2
+ module PixelFormatEnum
3
+ names = ::SDL2.constants.grep(/\ASDL_PIXELFORMAT_/)
4
+ values = names.map { |n| ::SDL2.const_get(n) }
5
+ FORMAT_MAP = names.zip(values).to_h.freeze
6
+
7
+ INDEXED_TYPES = [::SDL2::SDL_PIXELTYPE_INDEX1, ::SDL2::SDL_PIXELTYPE_INDEX4,
8
+ ::SDL2::SDL_PIXELTYPE_INDEX8].freeze
9
+
10
+ PACKED_TYPES = [::SDL2::SDL_PIXELTYPE_PACKED8, ::SDL2::SDL_PIXELTYPE_PACKED16,
11
+ ::SDL2::SDL_PIXELTYPE_PACKED32].freeze
12
+
13
+ ARRAY_TYPES = [::SDL2::SDL_PIXELTYPE_ARRAYU8, ::SDL2::SDL_PIXELTYPE_ARRAYU16,
14
+ ::SDL2::SDL_PIXELTYPE_ARRAYU32, ::SDL2::SDL_PIXELTYPE_ARRAYF16,
15
+ ::SDL2::SDL_PIXELTYPE_ARRAYF32].freeze
16
+
17
+ PACKED_ORDERS = [::SDL2::SDL_PACKEDORDER_ARGB, ::SDL2::SDL_PACKEDORDER_RGBA,
18
+ ::SDL2::SDL_PACKEDORDER_ABGR, ::SDL2::SDL_PACKEDORDER_BGRA].freeze
19
+
20
+ ARRAY_ORDERS = [::SDL2::SDL_ARRAYORDER_ARGB, ::SDL2::SDL_ARRAYORDER_RGBA,
21
+ ::SDL2::SDL_ARRAYORDER_ABGR, ::SDL2::SDL_ARRAYORDER_BGRA].freeze
22
+
23
+ class << self
24
+ def array_type?(num) = !fourcc?(num) && ARRAY_TYPES.include?(to_type(num))
25
+
26
+ def fourcc?(num) = (num >> 28) & 0x0F != 1
27
+
28
+ def indexed_type?(num) = !fourcc?(num) && INDEXED_TYPES.include?(to_type(num))
29
+
30
+ def packed_type?(num) = !fourcc?(num) && PACKED_TYPES.include?(to_type(num))
31
+
32
+ def to_fourcc(num)
33
+ 4.times.inject([]) { |n, i| n << (num >> i * 8) % 0x100 }.pack("c4") if fourcc?
34
+ end
35
+
36
+ def to_name(num) = ::SDL2.SDL_GetPixelFormatName(num).read_string
37
+
38
+ # obj は SDL の SDL_PIXELFORMAT_* 定数のどれか、または定数名でもよい。
39
+ # 定数名は RGBA32 のような短縮した名前でもよい。"UNKNOWN" も受け取れる(値は 0)。
40
+ # 該当するフォーマットがない場合は 0 (SDL_PIXELFORMAT_UNKNOWN) を戻す。
41
+ # SDL はオリジナルのフォーマットを処理しないことに注意。
42
+ def to_num(obj)
43
+ name = if Symbol === obj || String === obj
44
+ obj.match?(/\ASDL_PIXELFORMAT_/) ? obj : "SDL_PIXELFORMAT_#{obj.upcase}"
45
+ else
46
+ to_name(obj)
47
+ end
48
+ FORMAT_MAP[name.to_sym].to_i
49
+ end
50
+
51
+ def to_order(num) = fourcc?(num) ? 0 : (num >> 20) & 0x0F
52
+
53
+ def to_type(num) = fourcc?(num) ? 0 : (num >> 24) & 0x0F
54
+
55
+ def with_alpha?(num)
56
+ packed_type?(num) && PACKED_ORDERS.include?(to_order(num)) ||
57
+ array_type?(num) && ARRAY_ORDERS.include?(to_order(num))
58
+ end
59
+ end
60
+
61
+ def fourcc = PixelFormatEnum.to_fourcc(format)
62
+
63
+ def fourcc? = PixelFormatEnum.fourcc?(format)
64
+
65
+ def format_name = PixelFormatEnum.to_name(format)
66
+
67
+ def indexed_color? = PixelFormatEnum.indexed_type?(format)
68
+
69
+ def rgb? = !(fourcc? || indexed_color? || rgba?)
70
+
71
+ def rgba? = PixelFormatEnum.with_alpha?(format)
72
+ end
73
+ end
@@ -0,0 +1,7 @@
1
+ module RbSDL2
2
+ module Platform
3
+ class << self
4
+ def platform = ::SDL2.SDL_GetPlatform.read_string
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ module RbSDL2
2
+ module PowerInfo
3
+ @secs_ptr, @pct_ptr = Array.new(2) { ::FFI::MemoryPointer.new(:int) }
4
+
5
+ class << self
6
+ attr_reader :battery_capacity, :battery_time, :state
7
+
8
+ # バッテリーが搭載されているか?
9
+ def battery? = on_battery? || battery_charging? || battery_charged?
10
+
11
+ # 電源あり、バッテリー満充電
12
+ def battery_charged? = ::SDL2::SDL_POWERSTATE_CHARGED == state
13
+
14
+ # 電源あり、バッテリー充電中
15
+ def battery_charging? = ::SDL2::SDL_POWERSTATE_CHARGING == state
16
+
17
+ # 電源あり、バッテリー非搭載(デスクトップパソコンなど)
18
+ def no_battery? = ::SDL2::SDL_POWERSTATE_NO_BATTERY == state
19
+
20
+ # 電源なし、バッテリー使用中
21
+ def on_battery? = ::SDL2::SDL_POWERSTATE_ON_BATTERY == state
22
+
23
+ # 電源に接続されているか?
24
+ def plugged_in? = no_battery? || battery_charging? || battery_charged?
25
+
26
+ def update
27
+ @state = ::SDL2.SDL_GetPowerInfo(@secs_ptr, @pct_ptr)
28
+ @battery_time, @battery_capacity = @secs_ptr.read_int, @pct_ptr.read_int
29
+ self
30
+ end
31
+
32
+ # 電源、バッテリーの情報なし
33
+ def unknown? = ::SDL2::SDL_POWERSTATE_UNKNOWN == state
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ module RbSDL2
2
+ class Rect
3
+ def initialize(x = 0, y = 0, w = 0, h = 0)
4
+ @st = ::SDL2::SDL_Rect.new
5
+ @st[:x], @st[:y], @st[:w], @st[:h] = x, y, w, h
6
+ end
7
+
8
+ def to_a = @st.values
9
+
10
+ alias to_ary to_a
11
+
12
+ def to_ptr = @st.to_ptr
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module RbSDL2
2
+ class RefCountPointer < ::FFI::AutoPointer
3
+ class << self
4
+ def entity_class
5
+ raise NotImplementedError
6
+ end
7
+
8
+ def to_ptr(ptr)
9
+ raise ArgumentError, 'Invalid pointer, ptr is NULL' if ptr.null?
10
+ # refcount の増加を AutoPointer 化する前に成功させる必要がある。
11
+ # AutoPointer になった後に失敗すると、GC に回収されたとき refcount が実際の参照数より少なくなる。
12
+ entity_class.new(ptr)[:refcount] += 1
13
+ new(ptr)
14
+ end
15
+ end
16
+
17
+ # for debug
18
+ def refcount = self.class.entity_class.new(self)[:refcount]
19
+ end
20
+ end
@@ -0,0 +1,102 @@
1
+ module RbSDL2
2
+ class RWOperator
3
+ # コールバック関数からの例外は全てコールバック中で拾いエラーを表す戻り値に変える。
4
+ # SDL がコールバック関数を呼び出すときに与える引数はチェックされていないことを前提とするべきである。
5
+ # SDL が期待するコールバック関数の戻り値は成功か失敗(エラー)かであり、
6
+ # read, write などの戻り値を考慮した動作を行わない。
7
+ # コールバック関数を実装する際には Ruby アプリケーションが困らない設計を行えばよい。
8
+
9
+ class CloseCallback < ::FFI::Function
10
+ def initialize(obj)
11
+ # int (* close) (struct SDL_RWops * context);
12
+ super(:int, [:pointer]) do |_context|
13
+ # close の際に _context ポインターを開放してはならない。
14
+ (obj.close; 0) rescue -1
15
+ end
16
+ end
17
+ end
18
+
19
+ class ReadCallback < ::FFI::Function
20
+ def initialize(obj)
21
+ # size_t (* read) (struct SDL_RWops * context, void *ptr, size_t size, size_t maxnum);
22
+ super(:size_t, [:pointer, :pointer, :size_t, :size_t]) do |_context, ptr, size, max_num|
23
+ return 0 if ptr.null?
24
+ max = size * max_num
25
+ str = obj.read(max)
26
+ len = str.size
27
+ # len > max は obj.read が壊れている。
28
+ return 0 if str.nil? || len > max
29
+ ptr.write_bytes(str, 0, len)
30
+ len / size
31
+ rescue
32
+ 0
33
+ end
34
+ end
35
+ end
36
+
37
+ class SeekCallback < ::FFI::Function
38
+ def initialize(obj)
39
+ # Sint64 (* seek) (struct SDL_RWops * context, Sint64 offset, int whence);
40
+ super(:int64, [:pointer, :int64, :int]) do |_context, offset, whence|
41
+ obj.seek(offset, whence) rescue -1
42
+ end
43
+ end
44
+ end
45
+
46
+ class SizeCallback < ::FFI::Function
47
+ def initialize(obj)
48
+ # Sint64 (* size) (struct SDL_RWops * context);
49
+ super(:int64, [:pointer]) do |_context|
50
+ # 不明な時は -1。Ruby では size が不明確なオブジェクトは size メソッドがないだろう。
51
+ obj.size rescue -1
52
+ end
53
+ end
54
+ end
55
+
56
+ class WriteCallback < ::FFI::Function
57
+ def initialize(obj)
58
+ # size_t (* write) (struct SDL_RWops * context, const void *ptr, size_t size, size_t num);
59
+ super(:size_t, [:pointer, :pointer, :size_t, :size_t]) do |_context, ptr, size, max_num|
60
+ return 0 if ptr.null?
61
+ obj.write(ptr.read_bytes(size * max_num)) / size rescue 0
62
+ end
63
+ end
64
+ end
65
+
66
+ class RWopsPointer < ::FFI::AutoPointer
67
+ class << self
68
+ # SDL_AllocRW で確保したポインターのみ SDL_FreeRW で開放できる。
69
+ def release(ptr) = ::SDL2.SDL_FreeRW(ptr)
70
+ end
71
+ end
72
+
73
+ class << self
74
+ # obj は Ruby IO と同じようにふるまうことを期待している。
75
+ # obj に対して close, seek, size, read, write のメソッドを呼び出す。
76
+ # メソッドの呼び出し引数は Ruby IO と同様である。
77
+ # メソッドの戻り値は Ruby IO と同じ値を返せばよい。
78
+ # メソッド内での例外は SDL のエラーに変換され、Ruby 側には反映されない。
79
+ # obj がメソッド呼び出しに応答しない場合も安全である。その場合は SDL 側にエラーが通知される。
80
+ def new(io)
81
+ ptr = RWopsPointer.new(::SDL2.SDL_AllocRW)
82
+ raise RbSDL2Error if ptr.null?
83
+ super(ptr, io)
84
+ end
85
+ end
86
+
87
+ def initialize(ptr, obj)
88
+ st = ::SDL2::SDL_RWops.new(ptr)
89
+ st[:close] = @close = CloseCallback.new(obj)
90
+ st[:read] = @read = ReadCallback.new(obj)
91
+ st[:seek] = @seek = SeekCallback.new(obj)
92
+ st[:size] = @size = SizeCallback.new(obj)
93
+ st[:write] = @write = WriteCallback.new(obj)
94
+ @obj = obj
95
+ @ptr = ptr
96
+ end
97
+
98
+ def __getobj__ = @obj
99
+
100
+ def to_ptr = @ptr
101
+ end
102
+ end
@@ -0,0 +1,124 @@
1
+ module RbSDL2
2
+ class RWOps
3
+ class Releaser < ::FFI::AutoPointer
4
+ class << self
5
+ def release(ptr)
6
+ # SDL_RWclose は RWOps構造体を開放する。そのため呼び出しは1回しかできない。
7
+ # ::FFI::AutoPointer を使うことで2重開放を防ぐ。
8
+ raise RbSDL2Error if ::SDL2.SDL_RWclose(ptr) < 0
9
+ end
10
+ end
11
+
12
+ def free
13
+ @released = true
14
+ super
15
+ end
16
+
17
+ def released? = @released
18
+ end
19
+
20
+ # マルチスレッド対応はしていない。
21
+ # close メソッドは SDL 側からクローズされていた場合に対応していない。
22
+ class << self
23
+ def from_memory(mem, size, autoclose: true, readonly: true)
24
+ ptr = if readonly
25
+ ::SDL2.SDL_RWFromConstMem(mem, size)
26
+ else
27
+ ::SDL2.SDL_RWFromMem(mem, size)
28
+ end
29
+ raise RbSDL2Error if ptr.null?
30
+ obj = allocate
31
+ obj.__send__(:initialize, ptr, mem, autoclose: autoclose)
32
+ end
33
+
34
+ # mode は一般的なファイルAPIと同じ文字列が使用できる。
35
+ def new(file, _mode = "rb", autoclose: true, mode: _mode)
36
+ ptr = ::SDL2.SDL_RWFromFile(file.to_s, mode)
37
+ raise RbSDL2Error if ptr.null?
38
+ obj = super(ptr, autoclose: autoclose)
39
+ if block_given?
40
+ begin
41
+ yield(obj)
42
+ ensure
43
+ obj.close
44
+ end
45
+ else
46
+ obj
47
+ end
48
+ end
49
+ alias open new
50
+
51
+ def to_ptr(ptr)
52
+ obj = allocate
53
+ obj.__send__(:initialize, ptr, autoclose: false)
54
+ obj
55
+ end
56
+
57
+ require_relative 'rw_ops/rw_operator'
58
+
59
+ def with_object(obj)
60
+ rw = RWOperator.new(obj)
61
+ obj = allocate
62
+ obj.__send__(:initialize, rw.to_ptr, rw, autoclose: false)
63
+ end
64
+ end
65
+
66
+ def initialize(ptr, obj = nil, autoclose:)
67
+ @obj = obj
68
+ @ptr = Releaser.new(ptr)
69
+ self.autoclose = autoclose
70
+ end
71
+
72
+ def autoclose=(bool)
73
+ @ptr.autorelease = bool
74
+ end
75
+
76
+ def autoclose? = @ptr.autorelease
77
+
78
+ def close = @ptr.free
79
+
80
+ def closed? = @ptr.released?
81
+
82
+ def read(length = nil)
83
+ raise IOError if closed?
84
+ len = length.nil? ? size : length.to_i
85
+ raise ArgumentError if len < 0
86
+ return "" if len == 0
87
+ ptr = ::FFI::MemoryPointer.new(len)
88
+ num = ::SDL2.SDL_RWread(self, ptr, 1, len)
89
+ raise RbSDL2Error if num == 0
90
+ ptr.read_bytes(num)
91
+ end
92
+
93
+ def seek(offset, whence = IO::SEEK_SET)
94
+ raise IOError if closed?
95
+ raise RbSDL2Error if ::SDL2.SDL_RWseek(self, offset, whence) == -1
96
+ 0
97
+ end
98
+
99
+ def size
100
+ raise IOError if closed?
101
+ num = ::SDL2.SDL_RWsize(self)
102
+ raise RbSDL2Error if num < 0
103
+ num
104
+ end
105
+
106
+ def to_ptr
107
+ raise IOError if closed?
108
+ @ptr
109
+ end
110
+
111
+ def write(*str)
112
+ raise FrozenError if frozen?
113
+ raise IOError if closed?
114
+ str.inject(0) do |sum, obj|
115
+ bytes = obj.to_s
116
+ len = bytes.size
117
+ ptr = ::FFI::MemoryPointer.new(len).write_bytes(bytes)
118
+ num = ::SDL2.SDL_RWwrite(self, ptr, 1, len)
119
+ raise RbSDL2Error if num < len
120
+ sum + len
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,11 @@
1
+ module RbSDL2
2
+ module ScreenSaver
3
+ class << self
4
+ def enable = ::SDL2.SDL_EnableScreenSaver
5
+
6
+ def enabled? = ::SDL2.SDL_IsScreenSaverEnabled == ::SDL2::SDL_TRUE
7
+
8
+ def disable = ::SDL2.SDL_DisableScreenSaver
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ module RbSDL2
2
+ module SDL
3
+ module InitFlags
4
+ class << self
5
+ def to_num(audio: false, events: false, game_controller: false, haptic: false,
6
+ joystick: false, sensor: false, timer: false, video: false)
7
+ num = 0 |
8
+ (audio ? ::SDL2::SDL_INIT_TIMER : 0) |
9
+ (events ? ::SDL2::SDL_INIT_EVENTS : 0) |
10
+ (game_controller ? ::SDL2::SDL_INIT_GAMECONTROLLER : 0) |
11
+ (haptic ? ::SDL2::SDL_INIT_HAPTIC : 0) |
12
+ (joystick ? ::SDL2::SDL_INIT_JOYSTICK : 0) |
13
+ (sensor ? ::SDL2::SDL_INIT_SENSOR : 0) |
14
+ (timer ? ::SDL2::SDL_INIT_TIMER : 0) |
15
+ (video ? ::SDL2::SDL_INIT_VIDEO : 0)
16
+ num == 0 ? ::SDL2::SDL_INIT_EVERYTHING : num
17
+ end
18
+ end
19
+ end
20
+
21
+ class << self
22
+ def init(**flags)
23
+ err = ::SDL2.SDL_Init(InitFlags.to_num(**flags))
24
+ raise RbSDL2Error if err < 0
25
+ end
26
+
27
+ def init?(**flags) = ::SDL2.SDL_WasInit(mask = InitFlags.to_num(**flags)) == mask
28
+
29
+ def quit = ::SDL2.SDL_Quit
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ module RbSDL2
2
+ class Surface
3
+ module BlendMode
4
+ class << self
5
+ def to_num(obj)
6
+ case obj
7
+ when /\Aadd/ then ::SDL2::SDL_BLENDMODE_ADD
8
+ when /\Aalpha/, /\Ablend/ then ::SDL2::SDL_BLENDMODE_BLEND
9
+ when /\Amod/ then ::SDL2::SDL_BLENDMODE_MOD
10
+ when /\Amul/ then ::SDL2::SDL_BLENDMODE_MUL
11
+ when /\Anone/, /\Anormal/ then ::SDL2::SDL_BLENDMODE_NONE
12
+ else
13
+ obj.to_i
14
+ end
15
+ end
16
+
17
+ def to_name(num)
18
+ case num
19
+ when ::SDL2::SDL_BLENDMODE_ADD then "additive"
20
+ when ::SDL2::SDL_BLENDMODE_BLEND then "alpha"
21
+ when ::SDL2::SDL_BLENDMODE_MOD then "modulate"
22
+ when ::SDL2::SDL_BLENDMODE_MUL then "multiply"
23
+ when ::SDL2::SDL_BLENDMODE_NONE then "normal"
24
+ else
25
+ ""
26
+ end
27
+ end
28
+ end
29
+
30
+ def additive_blend_mode? = ::SDL2::SDL_BLENDMODE_ADD == blend_mode
31
+
32
+ def alpha_blend_mode? = ::SDL2::SDL_BLENDMODE_BLEND == blend_mode
33
+
34
+ def modulate_blend_mode? = ::SDL2::SDL_BLENDMODE_MOD == blend_mode
35
+
36
+ def multiply_blend_mode? = ::SDL2::SDL_BLENDMODE_MUL == blend_mode
37
+
38
+ def normal_blend_mode? = ::SDL2::SDL_BLENDMODE_NONE == blend_mode
39
+ end
40
+ end
41
+ end