rb_sdl2 0.1.0 → 0.2.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -0
  3. data/README.md +15 -1
  4. data/lib/rb_sdl2/audio/audio.rb +162 -0
  5. data/lib/rb_sdl2/audio/audio_buffer.rb +12 -19
  6. data/lib/rb_sdl2/audio/audio_device.rb +17 -23
  7. data/lib/rb_sdl2/audio/audio_spec.rb +38 -6
  8. data/lib/rb_sdl2/audio/audio_spec_reader.rb +10 -0
  9. data/lib/rb_sdl2/clipboard.rb +31 -31
  10. data/lib/rb_sdl2/cpu_info.rb +34 -17
  11. data/lib/rb_sdl2/cursor.rb +105 -24
  12. data/lib/rb_sdl2/display.rb +16 -16
  13. data/lib/rb_sdl2/display_mode.rb +1 -1
  14. data/lib/rb_sdl2/error.rb +14 -3
  15. data/lib/rb_sdl2/errors.rb +7 -0
  16. data/lib/rb_sdl2/event/event.rb +130 -0
  17. data/lib/rb_sdl2/event/event_filter.rb +34 -70
  18. data/lib/rb_sdl2/event/event_pointer.rb +26 -0
  19. data/lib/rb_sdl2/event/event_queue.rb +97 -120
  20. data/lib/rb_sdl2/event/event_type.rb +147 -205
  21. data/lib/rb_sdl2/filesystem.rb +8 -9
  22. data/lib/rb_sdl2/hint.rb +26 -24
  23. data/lib/rb_sdl2/keyboard/keyboard.rb +50 -0
  24. data/lib/rb_sdl2/keyboard/mod_state.rb +68 -0
  25. data/lib/rb_sdl2/keyboard/state.rb +39 -0
  26. data/lib/rb_sdl2/message_box.rb +69 -102
  27. data/lib/rb_sdl2/mouse/global_mouse.rb +10 -3
  28. data/lib/rb_sdl2/mouse/mouse.rb +64 -0
  29. data/lib/rb_sdl2/mouse/mouse_button.rb +13 -11
  30. data/lib/rb_sdl2/mouse/mouse_class.rb +9 -17
  31. data/lib/rb_sdl2/mouse/mouse_wheel.rb +21 -37
  32. data/lib/rb_sdl2/mouse/relative_mouse.rb +15 -1
  33. data/lib/rb_sdl2/palette.rb +15 -11
  34. data/lib/rb_sdl2/pixel_format_enum.rb +87 -55
  35. data/lib/rb_sdl2/platform.rb +3 -1
  36. data/lib/rb_sdl2/power_info.rb +34 -23
  37. data/lib/rb_sdl2/rect.rb +7 -1
  38. data/lib/rb_sdl2/ref_count_pointer.rb +25 -10
  39. data/lib/rb_sdl2/rw_ops/rw_file.rb +19 -0
  40. data/lib/rb_sdl2/rw_ops/rw_memory.rb +18 -0
  41. data/lib/rb_sdl2/rw_ops/rw_object.rb +126 -0
  42. data/lib/rb_sdl2/rw_ops/rw_ops.rb +104 -0
  43. data/lib/rb_sdl2/rw_ops/rw_ops_pointer.rb +14 -0
  44. data/lib/rb_sdl2/sdl.rb +72 -21
  45. data/lib/rb_sdl2/sdl_pointer.rb +22 -0
  46. data/lib/rb_sdl2/surface/blend_mode.rb +41 -41
  47. data/lib/rb_sdl2/surface/pixel_format.rb +34 -33
  48. data/lib/rb_sdl2/surface.rb +280 -244
  49. data/lib/rb_sdl2/text_input.rb +21 -15
  50. data/lib/rb_sdl2/timer.rb +36 -22
  51. data/lib/rb_sdl2/version.rb +5 -3
  52. data/lib/rb_sdl2/video.rb +17 -5
  53. data/lib/rb_sdl2/window/accessor.rb +135 -0
  54. data/lib/rb_sdl2/window/display.rb +8 -8
  55. data/lib/rb_sdl2/window/flash.rb +22 -0
  56. data/lib/rb_sdl2/window/hit_test.rb +22 -43
  57. data/lib/rb_sdl2/window/shape.rb +55 -40
  58. data/lib/rb_sdl2/window/state.rb +178 -0
  59. data/lib/rb_sdl2/window/window.rb +149 -0
  60. data/lib/rb_sdl2.rb +79 -17
  61. data/rb_sdl2.gemspec +12 -4
  62. metadata +38 -37
  63. data/lib/rb_sdl2/audio/audio_allowed_changes.rb +0 -17
  64. data/lib/rb_sdl2/audio/audio_format.rb +0 -23
  65. data/lib/rb_sdl2/audio.rb +0 -132
  66. data/lib/rb_sdl2/cursor/color_cursor.rb +0 -19
  67. data/lib/rb_sdl2/cursor/cursor_class.rb +0 -24
  68. data/lib/rb_sdl2/cursor/cursor_pointer.rb +0 -12
  69. data/lib/rb_sdl2/cursor/default_cursor.rb +0 -18
  70. data/lib/rb_sdl2/cursor/system_cursor.rb +0 -45
  71. data/lib/rb_sdl2/event.rb +0 -161
  72. data/lib/rb_sdl2/keyboard/key_mod.rb +0 -37
  73. data/lib/rb_sdl2/keyboard/keyboard_state.rb +0 -34
  74. data/lib/rb_sdl2/keyboard.rb +0 -50
  75. data/lib/rb_sdl2/mouse/window_mouse.rb +0 -17
  76. data/lib/rb_sdl2/mouse.rb +0 -74
  77. data/lib/rb_sdl2/rw_ops/rw_operator.rb +0 -102
  78. data/lib/rb_sdl2/rw_ops.rb +0 -124
  79. data/lib/rb_sdl2/screen_saver.rb +0 -11
  80. data/lib/rb_sdl2/window/dialog.rb +0 -19
  81. data/lib/rb_sdl2/window/grab.rb +0 -23
  82. data/lib/rb_sdl2/window/position.rb +0 -38
  83. data/lib/rb_sdl2/window/size.rb +0 -59
  84. data/lib/rb_sdl2/window/window_flags.rb +0 -78
  85. data/lib/rb_sdl2/window.rb +0 -242
@@ -1,24 +0,0 @@
1
- module RbSDL2
2
- module Cursor
3
- class CursorClass
4
- def initialize(ptr)
5
- @ptr = ptr
6
- end
7
-
8
- def current! = Cursor.current = self
9
-
10
- def current? = Cursor.current?(self)
11
-
12
- def hide = Cursor.hide
13
-
14
- def show
15
- current!
16
- Cursor.show
17
- end
18
-
19
- def shown? = Cursor.shown? && current?
20
-
21
- def to_ptr = @ptr
22
- end
23
- end
24
- end
@@ -1,12 +0,0 @@
1
- module RbSDL2
2
- module Cursor
3
- class CursorPointer < ::FFI::AutoPointer
4
- class << self
5
- # カーソルポインターはいつでも開放してよい。
6
- # SDL はカレントカーソルが開放されたときはデフォルトカーソルをカレントカーソルに設定する。
7
- # デフォルトカーソルは SDL_FreeCursorを呼び出しても開放されない。
8
- def release(ptr) = ::SDL2.SDL_FreeCursor(ptr)
9
- end
10
- end
11
- end
12
- end
@@ -1,18 +0,0 @@
1
- module RbSDL2
2
- module Cursor
3
- require_relative 'cursor_class'
4
-
5
- class DefaultCursor < CursorClass
6
- class << self
7
- def new
8
- ptr = ::SDL2.SDL_GetDefaultCursor
9
- raise RbSDL2Error if ptr.null?
10
- super(ptr)
11
- end
12
- end
13
-
14
- require 'singleton'
15
- include Singleton
16
- end
17
- end
18
- end
@@ -1,45 +0,0 @@
1
- module RbSDL2
2
- module Cursor
3
- require_relative 'cursor_class'
4
-
5
- class SystemCursor < CursorClass
6
- require_relative 'cursor_pointer'
7
-
8
- @cursors = Array.new(::SDL2::SDL_NUM_SYSTEM_CURSORS)
9
-
10
- class << self
11
- private def new(id)
12
- return @cursors[id] if @cursors[id]
13
-
14
- ptr = CursorPointer.new(::SDL2.SDL_CreateSystemCursor(id))
15
- raise RbSDL2Error if ptr.null?
16
- @cursors[id] = super(ptr)
17
- end
18
-
19
- def arrow_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_ARROW)
20
-
21
- def crosshair_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_CROSSHAIR)
22
-
23
- def hand_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_HAND)
24
-
25
- def i_beam_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_IBEAM)
26
-
27
- def no_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_NO)
28
-
29
- def size_all_cursor = new(SDL_SYSTEM_CURSOR_SIZEALL)
30
-
31
- def size_ne_sw_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_SIZENESW)
32
-
33
- def size_ns_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_SIZENS)
34
-
35
- def size_nw_se_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_SIZENWSE)
36
-
37
- def size_we_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_SIZEWE)
38
-
39
- def wait_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_WAIT)
40
-
41
- def wait_arrow_cursor = new(::SDL2::SDL_SYSTEM_CURSOR_WAITARROW)
42
- end
43
- end
44
- end
45
- end
data/lib/rb_sdl2/event.rb DELETED
@@ -1,161 +0,0 @@
1
- module RbSDL2
2
- class Event
3
- class EventPointer < ::FFI::AutoPointer
4
- class << self
5
- def malloc
6
- ptr = new(::SDL2.SDL_calloc(1, ::SDL2::SDL_Event.size))
7
- raise NoMemoryError if ptr.null?
8
- ptr
9
- end
10
-
11
- def release(ptr)
12
- # メンバーのポインターを開放する。
13
- Event.to_ptr(ptr).clear
14
- ::SDL2.SDL_free(ptr)
15
- end
16
- end
17
- end
18
-
19
- require 'forwardable'
20
- extend SingleForwardable
21
-
22
- require_relative 'event/event_filter'
23
- def_single_delegators "Event::EventFilter",
24
- *%i(add_watch_callback filter_callback_set filter_callback_defined?
25
- remove_watch_callback)
26
-
27
- require_relative 'event/event_queue'
28
- def_single_delegators "Event::EventQueue",
29
- *%i(clear count deq each empty? enq get length peep poll pump push push!
30
- quit? size reject! wait)
31
-
32
- require_relative 'event/event_type'
33
- def_single_delegators "Event::EventQueue", *%i(define_user_event disable enable ignore?)
34
-
35
- class << self
36
- def new(type: 0, **members)
37
- ptr = EventPointer.malloc
38
- num = Numeric === type ? type : EventType.to_num(type)
39
- ptr.write_uint32(num)
40
- obj = super(ptr)
41
- if obj.typed?
42
- members.each_pair { |sym, val| obj[sym] = val }
43
- end
44
- obj
45
- end
46
-
47
- def to_ptr(ptr)
48
- obj = allocate
49
- obj.__send__(:initialize, ptr)
50
- obj
51
- end
52
- end
53
-
54
- # UserEvent の data1, data2 メンバー、SysWMEvent の msg メンバーはポインターである。
55
- # ポインターとしての読み書きの対応はしている。しかしポインターが指し示すメモリーの管理は行わない。
56
- def initialize(ptr)
57
- @ptr = ptr
58
- end
59
-
60
- def [](sym)
61
- raise ArgumentError unless member?(sym)
62
-
63
- case sym
64
- when :data
65
- member[:data].to_a
66
- when :file
67
- member[:file].then { |ptr| ptr.null? ? nil : ptr.read_string }
68
- when :keysym
69
- member[:keysym].then { |st| {scancode: st[:scancode], sym: st[:sym], mod: st[:mod]} }
70
- when :text
71
- member[:text].to_s
72
- else
73
- member[sym]
74
- end
75
- end
76
-
77
- # DropEvent の file メンバーのポインターの管理は行われる。
78
- # UserEvent の data1, data2 メンバーと SysWMEvent の msg メンバーはポインターである。
79
- # これらのポインターの管理は行ない。アプリケーション側で実装を行うこと。
80
- def []=(sym, val)
81
- raise FrozenError if frozen?
82
- raise ArgumentError unless member?(sym)
83
-
84
- case sym
85
- when :data
86
- val.each.with_index { |v, i| member[:data][i] = v }
87
- when :file
88
- if drop_file? || drop_text?
89
- _ptr = member[:file]
90
-
91
- member[:file] = if val.nil?
92
- nil
93
- else
94
- c_str = "#{val}\x00"
95
- ptr = ::SDL2.SDL_malloc(c_str.size)
96
- raise NoMemoryError if ptr.null?
97
- ptr.write_bytes(c_str)
98
- end
99
-
100
- ::SDL2.SDL_free(_ptr)
101
- else
102
- raise ArgumentError
103
- end
104
- when :keysym
105
- val.each { |k, v| member[:keysym][k] = v }
106
- when :msg
107
- if val.nil? || val.respond_to?(:null?) && val.null? || val.respond_to?(:zero?) && val.zero?
108
- raise ArgumentError
109
- end
110
- member[:msg] = val
111
- when :type
112
- raise ArgumentError
113
- else
114
- member[sym] = val
115
- end
116
- end
117
-
118
- def clear
119
- raise FrozenError if frozen?
120
- if drop_file? || drop_text?
121
- self[:file] = nil
122
- end
123
- member.clear
124
- @st = nil
125
- self
126
- end
127
-
128
- # deep copy を行う。
129
- # これは @ptr が イベントキューの一部(SDL の管理領域)を指している場合があるためである。
130
- def initialize_copy(obj)
131
- super
132
- @ptr = EventPointer.malloc.write_bytes(obj.to_ptr.read_bytes(::SDL2::SDL_Event.size))
133
- if drop_file? || drop_text?
134
- self[:file] = obj[:file]
135
- end
136
- end
137
-
138
- def inspect
139
- "#<#{self.class.name} ptr=#{@ptr.inspect} name=#{name.inspect} #{to_h}>"
140
- end
141
-
142
- protected def member = @st ||= ::SDL2::SDL_Event.new(@ptr)[EventType.to_type(type)]
143
-
144
- def member?(name) = members.include?(name)
145
-
146
- def members = member.members.grep_v(/\Apadding/)
147
-
148
- def name = EventType.to_name(type)
149
- alias to_s name
150
-
151
- def to_h = members.map { |sym| [sym, self[sym]] }.to_h
152
-
153
- def to_ptr = @ptr
154
-
155
- def type = to_ptr.read_uint32
156
-
157
- include EventType
158
-
159
- def typed? = type != 0
160
- end
161
- end
@@ -1,37 +0,0 @@
1
- module RbSDL2
2
- module Keyboard
3
- module KeyMod
4
- def mod_key? = ::SDL2::KMOD_NONE != mod
5
-
6
- def l_shift_key? = ::SDL2::KMOD_LSHIFT & mod != 0
7
-
8
- def r_shift_key? = ::SDL2::KMOD_RSHIFT & mod != 0
9
-
10
- def l_ctrl_key? = ::SDL2::KMOD_LCTRL & mod != 0
11
-
12
- def r_ctrl_key? = ::SDL2::KMOD_RCTRL & mod != 0
13
-
14
- def l_alt_key? = ::SDL2::KMOD_LALT & mod != 0
15
-
16
- def r_alt_key? = ::SDL2::KMOD_RALT & mod != 0
17
-
18
- def l_gui_key? = ::SDL2::KMOD_LGUI & mod != 0
19
-
20
- def r_gui_key? = ::SDL2::KMOD_RGUI & mod != 0
21
-
22
- def alt_key? = ::SDL2::KMOD_ALT & mod != 0
23
-
24
- def caps_key? = ::SDL2::KMOD_CAPS & mod != 0
25
-
26
- def ctrl_key? = ::SDL2::KMOD_CTRL & mod != 0
27
-
28
- def gui_key? = ::SDL2::KMOD_GUI & mod != 0
29
-
30
- def mode_key? = ::SDL2::KMOD_MODE & mod != 0
31
-
32
- def num_key? = ::SDL2::KMOD_NUM & mod != 0
33
-
34
- def shift_key? = ::SDL2::KMOD_SHIFT & mod != 0
35
- end
36
- end
37
- end
@@ -1,34 +0,0 @@
1
- module RbSDL2
2
- class KeyboardState
3
- require 'singleton'
4
- include Singleton
5
-
6
- def initialize
7
- num_keys = ::FFI::MemoryPointer.new(:int)
8
- # SDL_GetKeyboardState が戻すポインターは SDL がロードされた時点でメモリー確保している。
9
- # 戻されたポインターは不変と考えてよい。
10
- # SDL_GetKeyboardState は SDL_init より前に呼ぶことができる。
11
- # SDL_GetKeyboardState は引数に NULL ポインターを与えた場合にエラーを戻す。
12
- @ptr = ::SDL2.SDL_GetKeyboardState(num_keys)
13
- raise RbSDL2Error if @ptr.null?
14
- @size = num_keys.read_int
15
- end
16
-
17
- # nth のキーが押されている場合、nth を戻す。
18
- # nth のキーが押されていない、nth が範囲外の場合は nil を戻す。
19
- # 真偽値を戻すようにしなかったのは、このメソッドを応用したコードを書く際に index 情報を不要にするためである。
20
- # 戻り値が nil | obj なのは Numeric#nonzero? を参考にした。(この戻り値は Ruby において真偽値と同等である)
21
- def [](nth)
22
- if 0 <= nth && nth < size && @ptr[nth].read_uint8 == ::SDL2::SDL_PRESSED
23
- nth
24
- end
25
- end
26
-
27
- def each = block_given? ? size.times { |i| yield(self[i]) } : to_enum
28
-
29
- attr_reader :size
30
- alias length size
31
-
32
- def to_str = @ptr.read_bytes(size)
33
- end
34
- end
@@ -1,50 +0,0 @@
1
- module RbSDL2
2
- module Keyboard
3
- class << self
4
- def keycode_to_name(keycode) = ::SDL2.SDL_GetKeyName(keycode).read_string
5
-
6
- # 対応するコードが存在しない場合 0 を戻す。戻り値 は nonzero? メソッドをチェーンすることができる。
7
- # これは KeyboardState#[] での利用を考慮して設計した。
8
- def keycode_to_scancode(keycode) = ::SDL2.SDL_GetScancodeFromKey(keycode)
9
-
10
- def name_to_keycode(name) = ::SDL2.SDL_GetKeyFromName(name)
11
-
12
- def name_to_scancode(name) = ::SDL2.SDL_GetScancodeFromName(name)
13
-
14
- def scancode_to_keycode(scancode) = ::SDL2.SDL_GetKeyFromScancode(scancode)
15
-
16
- def scancode_to_name(scancode) = ::SDL2.SDL_GetScancodeName(scancode).read_string
17
- end
18
-
19
- require 'forwardable'
20
- extend SingleForwardable
21
- require_relative 'keyboard/keyboard_state'
22
- def_single_delegators 'KeyboardState.instance', *%i([] each to_str)
23
-
24
- class << self
25
- # いずれかのキーが押されている場合に true を戻す。つまり *any key* が押されたということ。
26
- def any_key? = each.any?
27
-
28
- # 引数に与えたキー名のキーが押されている場合に対応するスキャンコードを戻す。
29
- # 押されていない場合は nil を戻す。
30
- # 不正な名前の場合でも例外を戻さない、その場合 0 または nil を戻す。
31
- # キー名は SDL が定義したものである。
32
- def key?(name) = self[name_to_scancode(name)]
33
-
34
- # 現在押されているキーの名前を配列で戻す。
35
- def names = scancodes.map { |num| scancode_to_name(num) }
36
-
37
- # 現在押されているキーのスキャンコードを配列で戻す。
38
- def scancodes = each.to_a.compact!
39
-
40
- def mod = ::SDL2.SDL_GetModState
41
-
42
- require_relative 'keyboard/key_mod'
43
- include KeyMod
44
-
45
- def mod=(state)
46
- ::SDL2::SDL_SetModState(state)
47
- end
48
- end
49
- end
50
- end
@@ -1,17 +0,0 @@
1
- module RbSDL2
2
- module Mouse
3
- require_relative 'mouse_class'
4
-
5
- class WindowMouse < MouseClass
6
- def position=(*x_y)
7
- ptr = ::SDL2.SDL_GetMouseFocus
8
- ::SDL2.SDL_WarpMouseInWindow(ptr, *x_y) unless ptr.null?
9
- end
10
-
11
- def update
12
- self.button = ::SDL2.SDL_GetMouseState(x_ptr, y_ptr)
13
- self
14
- end
15
- end
16
- end
17
- end
data/lib/rb_sdl2/mouse.rb DELETED
@@ -1,74 +0,0 @@
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
@@ -1,102 +0,0 @@
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