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,89 @@
1
+ module RbSDL2
2
+ class Surface
3
+ class PixelFormat
4
+ require_relative '../ref_count_pointer'
5
+
6
+ class PixelFormatPointer < RefCountPointer
7
+ class << self
8
+ def release(ptr) = ::SDL2.SDL_FreeFormat(ptr)
9
+
10
+ def entity_class = ::SDL2::SDL_PixelFormat
11
+ end
12
+ end
13
+
14
+ class << self
15
+ require_relative '../pixel_format_enum'
16
+
17
+ def new(format)
18
+ ptr = PixelFormatPointer.new(::SDL2::SDL_AllocFormat(PixelFormatEnum.to_num(format)))
19
+ raise RbSDL2Error if ptr.null?
20
+ super(ptr)
21
+ end
22
+
23
+ def to_ptr(ptr)
24
+ obj = allocate
25
+ obj.__send__(:initialize, PixelFormatPointer.to_ptr(ptr))
26
+ obj
27
+ end
28
+ end
29
+
30
+ def initialize(ptr)
31
+ @st = ::SDL2::SDL_PixelFormat.new(ptr)
32
+ end
33
+
34
+ def ==(other)
35
+ other.respond_to?(:to_ptr) && to_ptr == other.to_ptr
36
+ end
37
+
38
+ def alpha_mask? = @st[:Amask] > 0
39
+
40
+ def bits_per_pixel = @st[:BitsPerPixel]
41
+ alias bpp bits_per_pixel
42
+
43
+ def bytes_per_pixel = @st[:BytesPerPixel]
44
+
45
+ def format = @st[:format]
46
+
47
+ require_relative '../pixel_format_enum'
48
+ include PixelFormatEnum
49
+
50
+ # indexed format のときはパレット番号を戻す。
51
+ def pack_color(color)
52
+ r, g, b, a = color
53
+ if alpha_mask?
54
+ ::SDL2.SDL_MapRGBA(self, r, g, b, a || ::SDL2::SDL_ALPHA_OPAQUE)
55
+ else
56
+ ::SDL2.SDL_MapRGB(self, r, g, b)
57
+ end
58
+ end
59
+
60
+ require_relative '../palette'
61
+
62
+ def palette
63
+ # パレットは参照カウンターで生存の保証がある。
64
+ # Ruby 側がパレットを保持している限り同一アドレスに違うパレットが作成されることはない。
65
+ # SDL では PixelFormat の palette メンバーは(行儀よく SDL_SetPixelFormatPalette を使う場合は)
66
+ # 後から NULL に書き換わることはない。
67
+ (ptr = @st[:palette]) == @palette&.to_ptr ? @palette : @palette = Palette.to_ptr(ptr)
68
+ end
69
+
70
+ def palette=(pal)
71
+ err = ::SDL2.SDL_SetPixelFormatPalette(self, pal)
72
+ raise RbSDL2Error if err < 0
73
+ @palette = nil
74
+ end
75
+
76
+ def to_ptr = @st.to_ptr
77
+
78
+ # indexed format のときはパレット番号を引数へ与える。
79
+ def unpack_color(pixel)
80
+ if alpha_mask?
81
+ ::SDL2.SDL_GetRGBA(pixel, self, *Array.new(4) { ::FFI::MemoryPointer.new(:uint8) })
82
+ else
83
+ ::SDL2.SDL_GetRGB(pixel, self, *Array.new(3) { ::FFI::MemoryPointer.new(:uint8) })
84
+ end
85
+ color.map(&:read_uint8)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,244 @@
1
+ module RbSDL2
2
+ class Surface
3
+ require_relative 'ref_count_pointer'
4
+
5
+ class SurfacePointer < RefCountPointer
6
+ class << self
7
+ def release(ptr)
8
+ # 備考:SDL では参照カウンターを操作する際にロックを行っていない。
9
+ #
10
+ # SDL_Surface ポインターの参照カウンターの扱いでは SDL_DONTFREE フラグを考慮する必要がある。
11
+ # SDL_DONTFREE フラグが設定されていると SDL_FreeSurface を呼び出しても参照カウントが減少しない。
12
+ # SDL_DONTFREE フラグの状態に関わらず Ruby 側ではポインターを正しく扱えるので参照カウントを増減する。
13
+ # 備考:Window から SDL_Surface ポインターを取り出す際にこのフラグが設定されている。
14
+ st = entity_class.new(ptr)
15
+ if st[:flags] & ::SDL2::SDL_DONTFREE != 0
16
+ st[:refcount] -= 1
17
+ # SDL_DONTFREE が設定されているので参照カウントの値によらず SDL_FreeSurface を呼び出さない。
18
+ # スレッドでの競合によりポインターを開放されない可能性(=メモリーリーク)はある。
19
+ # 具体的にはこのセクションを実行中に SDL_EventPump が実行され、ウィンドウのリサイズ・イベントが発生
20
+ # したときに起きる。この競合が起きないようにアプリケーションを実装する必要がある。
21
+ else
22
+ ::SDL2.SDL_FreeSurface(ptr)
23
+ end
24
+ end
25
+
26
+ def entity_class = ::SDL2::SDL_Surface
27
+ end
28
+ end
29
+
30
+ require_relative 'pixel_format_enum'
31
+
32
+ class << self
33
+ # 変換ができない場合はエラーを発生させる。
34
+ # 変換先がインデックスカラー(INDEX8)の時は期待する変換は行われない。
35
+ def convert(surface, new_format)
36
+ ptr = SurfacePointer.new(
37
+ ::SDL2.SDL_ConvertSurfaceFormat(surface, PixelFormatEnum.to_num(new_format), 0))
38
+ raise RbSDL2Error if ptr.null?
39
+ obj = allocate
40
+ obj.__send__(:initialize, ptr)
41
+ obj
42
+ end
43
+
44
+ require_relative 'rw_ops'
45
+
46
+ def load(file) = RWOps.new(file, "rb") { |rw| load_rw(rw) }
47
+
48
+ # load_rw は与えられたオブジェクトをオートクローズしません。
49
+ def load_rw(rw)
50
+ ptr = SurfacePointer.new(::SDL2.SDL_LoadBMP_RW(rw, 0))
51
+ raise RbSDL2Error if ptr.null?
52
+ obj = allocate
53
+ obj.__send__(:initialize, ptr)
54
+ obj
55
+ end
56
+
57
+ def new(w, h, format)
58
+ ptr = SurfacePointer.new(
59
+ ::SDL2.SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, PixelFormatEnum.to_num(format)))
60
+ raise RbSDL2Error if ptr.null?
61
+ super(ptr)
62
+ end
63
+
64
+ def to_ptr(ptr)
65
+ obj = allocate
66
+ obj.__send__(:initialize, SurfacePointer.to_ptr(ptr))
67
+ obj
68
+ end
69
+
70
+ def yuv_conversion_mode_name
71
+ case ::SDL2.SDL_GetYUVConversionMode
72
+ when ::SDL2::SDL_YUV_CONVERSION_JPEG then "JPEG"
73
+ when ::SDL2::SDL_YUV_CONVERSION_BT601 then "BT601"
74
+ when ::SDL2::SDL_YUV_CONVERSION_BT709 then "BT709"
75
+ when ::SDL2::SDL_YUV_CONVERSION_AUTOMATIC then "AUTOMATIC"
76
+ else ""
77
+ end
78
+ end
79
+
80
+ def yuv_conversion_mode=(mode)
81
+ ::SDL2.SDL_SetYUVConversionMode(mode)
82
+ end
83
+ end
84
+
85
+ def initialize(ptr)
86
+ @st = ::SDL2::SDL_Surface.new(ptr)
87
+ end
88
+
89
+ def ==(other)
90
+ other.respond_to?(:to_ptr) && to_ptr == other.to_ptr
91
+ end
92
+
93
+ def alpha_mod
94
+ alpha = ::FFI::MemoryPointer.new(:uint8)
95
+ num = ::SDL2.SDL_GetSurfaceAlphaMod(self, alpha)
96
+ raise RbSDL2Error if num < 0
97
+ alpha.read_uint8
98
+ end
99
+
100
+ def alpha_mod=(alpha)
101
+ num = ::SDL2.SDL_SetSurfaceAlphaMod(self, alpha)
102
+ raise RbSDL2Error if num < 0
103
+ end
104
+
105
+ def blend_mode
106
+ blend = ::FFI::MemoryPointer.new(:int)
107
+ err = ::SDL2.SDL_GetSurfaceBlendMode(self, blend)
108
+ raise RbSDL2Error if err < 0
109
+ blend.read_int
110
+ end
111
+
112
+ require_relative 'surface/blend_mode'
113
+ include BlendMode
114
+
115
+ def blend_mode_name = BlendMode.to_name(blend_mode)
116
+
117
+ def blend_mode=(blend)
118
+ err = ::SDL2.SDL_SetSurfaceBlendMode(self, BlendMode.to_num(blend))
119
+ raise RbSDL2Error if err < 0
120
+ end
121
+
122
+ def blit(other, from: nil, to: nil, scale: false)
123
+ from &&= Rect.new(*from)
124
+ to &&= Rect.new(*to)
125
+ err = if scale
126
+ ::SDL2.SDL_UpperBlitScaled(other, from, self, to)
127
+ else
128
+ ::SDL2.SDL_UpperBlit(other, from, self, to)
129
+ end
130
+ raise RbSDL2Error if err < 0
131
+ end
132
+
133
+ def bounds = [0, 0, w, h]
134
+
135
+ def bytesize = pitch * height
136
+
137
+ def clip
138
+ rect = Rect.new
139
+ ::SDL2.SDL_GetClipRect(self, rect)
140
+ rect.to_a
141
+ end
142
+
143
+ # nil の場合はサーフェィス全域がクリップになる。
144
+ def clip=(rect)
145
+ rect &&= Rect.new(*rect)
146
+ bool = ::SDL2.SDL_SetClipRect(self, rect)
147
+ raise "out of bounds" if bool == ::SDL2::SDL_FALSE
148
+ end
149
+
150
+ def clear(color = [0, 0, 0, 0]) = fill(bounds, color)
151
+
152
+ def color_key
153
+ return unless color_key?
154
+ key = ::FFI::MemoryPointer.new(:uint32)
155
+ err = ::SDL2.SDL_GetColorKey(self, key)
156
+ return RbSDL2Error if err < 0
157
+ pixel_format.unpack_color(key.read_uint32)
158
+ end
159
+
160
+ def color_key=(color)
161
+ err = if color
162
+ ::SDL2.SDL_SetColorKey(self, ::SDL2::SDL_TRUE, pixel_format.pack_color(color))
163
+ else
164
+ ::SDL2.SDL_SetColorKey(self, ::SDL2::SDL_FALSE, 0)
165
+ end
166
+ raise RbSDL2Error if err < 0
167
+ end
168
+
169
+ def color_key? = ::SDL2.SDL_HasColorKey(self) == ::SDL2::SDL_TRUE
170
+
171
+ def color_mod
172
+ rgb = Array.new(3) { ::FFI::MemoryPointer.new(:uint8) }
173
+ err = ::SDL2.SDL_GetSurfaceColorMod(self, *rgb)
174
+ raise RbSDL2Error if err < 0
175
+ rgb.map(&:read_uint8)
176
+ end
177
+
178
+ def color_mod=(color)
179
+ r, g, b = color
180
+ err = ::SDL2.SDL_SetSurfaceColorMod(self, r, g, b)
181
+ raise RbSDL2Error if err < 0
182
+ end
183
+
184
+ def convert(new_format = format) = Surface.convert(self, new_format)
185
+
186
+ def fill(rect = clip, color = [0, 0, 0, 0])
187
+ err = ::SDL2.SDL_FillRect(self, Rect.new(*rect), pixel_format.pack_color(color))
188
+ raise RbSDL2Error if err < 0
189
+ end
190
+
191
+ def height = @st[:h]
192
+
193
+ alias h height
194
+
195
+ def pitch = @st[:pitch]
196
+
197
+ require_relative 'surface/pixel_format'
198
+
199
+ def pixel_format
200
+ # SDL_Surface の format メンバーは読み取り専用である。作成時の値が不変であることを前提としている。
201
+ @pixel_format ||= PixelFormat.to_ptr(@st[:format])
202
+ end
203
+
204
+ require 'forwardable'
205
+ extend Forwardable
206
+ def_delegators :pixel_format, *%i(bits_per_pixel bpp format palette palette=)
207
+
208
+ require_relative 'pixel_format_enum'
209
+ include PixelFormatEnum
210
+
211
+ def rle=(bool)
212
+ err = ::SDL2.SDL_SetSurfaceRLE(self, bool ? 1 : 0)
213
+ raise RbSDL2Error if err < 0
214
+ end
215
+
216
+ def rle? = ::SDL2.SDL_HasSurfaceRLE(self) == ::SDL2::SDL_TRUE
217
+
218
+ require_relative 'rw_ops'
219
+
220
+ def save(file) = RWOps.new(file, "wb") { |rw| save_rw(rw); nil }
221
+
222
+ # save_rw は与えられたオブジェクトをオートクローズしません。
223
+ def save_rw(rw)
224
+ err = ::SDL2.SDL_SaveBMP_RW(rw, 0)
225
+ raise RbSDL2Error if err < 0
226
+ rw
227
+ end
228
+
229
+ def size = [width, height]
230
+
231
+ def synchronize
232
+ ::SDL2.SDL_LockSurface(self)
233
+ yield(self)
234
+ ensure
235
+ ::SDL2.SDL_UnlockSurface(self)
236
+ end
237
+
238
+ def to_ptr = @st.to_ptr
239
+
240
+ def width = @st[:w]
241
+
242
+ alias w width
243
+ end
244
+ end
@@ -0,0 +1,15 @@
1
+ module RbSDL2
2
+ module TextInput
3
+ class << self
4
+ def active? = ::SDL2.SDL_IsTextInputActive == ::SDL2::SDL_TRUE
5
+
6
+ def bounds=(rect)
7
+ ::SDL2.SDL_SetTextInputRect(Rect.new(*rect))
8
+ end
9
+
10
+ def start = ::SDL2.SDL_StartTextInput
11
+
12
+ def stop = ::SDL2.SDL_StopTextInput
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module RbSDL2
2
+ module Timer
3
+ class << self
4
+ def delay(ms)
5
+ raise ArgumentError if ms < 0
6
+ ::SDL2.SDL_Delay(ms)
7
+ end
8
+
9
+ def performance_frequency = ::SDL2.SDL_GetPerformanceFrequency
10
+
11
+ def performance_count = ::SDL2.SDL_GetPerformanceCounter
12
+
13
+ def realtime
14
+ t = performance_count
15
+ yield
16
+ (performance_count - t).fdiv(performance_frequency)
17
+ end
18
+
19
+ def ticks = ::SDL2.SDL_GetTicks
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module RbSDL2
2
+ module Version
3
+ class << self
4
+ def revision = ::SDL2.SDL_GetRevision.read_string
5
+
6
+ def version
7
+ st = ::SDL2::SDL_version.new
8
+ ::SDL2.SDL_GetVersion(st)
9
+ "#{st[:major]}.#{st[:minor]}.#{st[:patch]}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ module RbSDL2
2
+ module Video
3
+ class << self
4
+ def init(driver = nil)
5
+ raise RbSDL2Error if ::SDL2.SDL_VideoInit(driver) < 0
6
+ end
7
+
8
+ def current
9
+ ptr = ::SDL2.SDL_GetCurrentVideoDriver
10
+ raise RbSDL2Error if ptr.null?
11
+ ptr.read_string
12
+ end
13
+
14
+ def drivers
15
+ ::SDL2.SDL_GetNumVideoDrivers.times.map do |num|
16
+ ptr = ::SDL2.SDL_GetVideoDriver(num)
17
+ raise RbSDL2Error if ptr.null?
18
+ ptr.read_string
19
+ end
20
+ end
21
+
22
+ def quit = ::SDL2.SDL_VideoQuit
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module RbSDL2
2
+ class Window
3
+ module Dialog
4
+ require_relative '../message_box'
5
+
6
+ def alert(message, **opts) = MessageBox.alert(message, self, **opts)
7
+
8
+ def confirm(message, **opts) = MessageBox.confirm(message, self, **opts)
9
+
10
+ def dialog(message, **opts) = MessageBox.dialog(message, self, **opts)
11
+
12
+ def error_alert(message, **opts) = MessageBox.error(message, self, **opts)
13
+
14
+ def info_alert(message, **opts) = MessageBox.info(message, self, **opts)
15
+
16
+ def warn_alert(message, **opts) = MessageBox.warn(message, self, **opts)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,85 @@
1
+ module RbSDL2
2
+ class Window
3
+ module Display
4
+ # Brightness はウィンドウ単体ではなくウインドウの中心があるディスプレイの輝度の取得、変更を行う。
5
+ # 対象となるディスプレイの取得は Window#display メソッドを呼び出す。
6
+ def brightness = ::SDL2.SDL_GetWindowBrightness(self)
7
+
8
+ def brightness=(float)
9
+ err = ::SDL2.SDL_SetWindowBrightness(self, float)
10
+ raise RbSDL2Error if err < 0
11
+ end
12
+
13
+ require_relative '../display'
14
+
15
+ def display = Display.new(display_index)
16
+
17
+ def display_index
18
+ index = ::SDL2.SDL_GetWindowDisplayIndex(to_ptr)
19
+ raise RbSDL2Error if index < 0
20
+ index
21
+ end
22
+
23
+ require_relative '../display_mode'
24
+ def fullscreen_display_mode
25
+ obj = DisplayMode.new
26
+ err = ::SDL2.SDL_GetWindowDisplayMode(self, obj)
27
+ raise RbSDL2Error if err < 0
28
+ obj
29
+ end
30
+
31
+ def fullscreen_display_mode=(display_mode)
32
+ err = ::SDL2.SDL_SetWindowDisplayMode(self, display_mode)
33
+ raise RbSDL2Error if err < 0
34
+ end
35
+
36
+ class GammaRamp
37
+ class << self
38
+ def [](*a)
39
+ raise ArgumentError if a.length != 256
40
+ ptr = ::FFI::MemoryPointer.new(:uint16, 256).write_array_of_uint16(a)
41
+ obj = allocate
42
+ obj.__send__(:initialize, ptr)
43
+ obj
44
+ end
45
+
46
+ def new(gamma)
47
+ ptr = ::FFI::MemoryPointer.new(:uint16, 256)
48
+ ::SDL2.SDL_CalculateGammaRamp(gamma, ptr)
49
+ super(ptr)
50
+ end
51
+ end
52
+
53
+ def initialize(ptr)
54
+ @ptr = ptr
55
+ end
56
+
57
+ def to_ptr = @ptr
58
+
59
+ def to_a = @ptr.read_array_of_uint16(256)
60
+ alias to_ary to_a
61
+ end
62
+
63
+ # [r_gamma, g_gamma, b_gamma] | gamma
64
+ def gamma=(rgb)
65
+ r, g, b = *rgb
66
+ self.gamma_ramp = (!g && !b ? [r, r, r] : [r, g, b]).map { |f| GammaRamp.new(f) }
67
+ end
68
+
69
+ def gamma_ramp
70
+ rgb = Array.new(3) { GammaRamp.new }
71
+ err = ::SDL2.SDL_GetWindowGammaRamp(self, *rgb)
72
+ raise RbSDL2Error if err < 0
73
+ rgb.map(&:to_a)
74
+ end
75
+
76
+ # r_g_b: [[r,...],[g,...],[b,...]]
77
+ # 画面全体に影響を与える。OSからリセットされることもある。
78
+ # アプリケーションが終了しても永続的に影響をあたえる。ユーザにとって望ましくないだろう。
79
+ def gamma_ramp=(r_g_b)
80
+ err = ::SDL2.SDL_SetWindowGammaRamp(self, *r_g_b.map { |a| GammaRamp[*a] })
81
+ raise RbSDL2Error if err < 0
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,23 @@
1
+ module RbSDL2
2
+ class Window
3
+ module Grab
4
+ def grab=(bool)
5
+ ::SDL2.SDL_SetWindowGrab(self, bool ? ::SDL2::SDL_TRUE : ::SDL2::SDL_FALSE)
6
+ end
7
+
8
+ def grabbed? = ::SDL2.SDL_GetWindowGrab(self) == ::SDL2::SDL_TRUE
9
+
10
+ def grabbed_keyboard? = ::SDL2.SDL_GetWindowKeyboardGrab(self) == ::SDL2::SDL_TRUE
11
+
12
+ def grabbed_mouse? = ::SDL2.SDL_GetWindowMouseGrab(self) == ::SDL2::SDL_TRUE
13
+
14
+ def keyboard_grab=(bool)
15
+ ::SDL2.SDL_SetWindowKeyboardGrab(self, bool ? ::SDL2::SDL_TRUE : ::SDL2::SDL_FALSE)
16
+ end
17
+
18
+ def mouse_grab=(bool)
19
+ ::SDL2.SDL_SetWindowMouseGrab(self, bool ? ::SDL2::SDL_TRUE : ::SDL2::SDL_FALSE)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ module RbSDL2
2
+ class Window
3
+ class HitTest < ::FFI::Function
4
+ @callbacks = {}
5
+ @mutex = Mutex.new
6
+
7
+ class << self
8
+ def callback_set(window, obj, userdata = nil)
9
+ func = if Proc === obj
10
+ new(&obj)
11
+ else
12
+ obj
13
+ end
14
+ @mutex.synchronize do
15
+ err = ::SDL2.SDL_SetWindowHitTest(window, func, userdata)
16
+ raise RbSDL2Error if err < 0
17
+ id = window.id
18
+ if obj
19
+ @callbacks[id] = [func, userdata]
20
+ else
21
+ @callbacks.delete(id)
22
+ end
23
+ end
24
+ [obj, userdata]
25
+ end
26
+ end
27
+
28
+ HIT_TEST_RESULT = Hash.new(::SDL2::SDL_HITTEST_NORMAL).merge!(
29
+ :normal => ::SDL2::SDL_HITTEST_NORMAL,
30
+ :draggable => ::SDL2::SDL_HITTEST_DRAGGABLE,
31
+ :top_left => ::SDL2::SDL_HITTEST_RESIZE_TOPLEFT,
32
+ :top => ::SDL2::SDL_HITTEST_RESIZE_TOP,
33
+ :top_right => ::SDL2::SDL_HITTEST_RESIZE_TOPRIGHT,
34
+ :resize_right => ::SDL2::SDL_HITTEST_RESIZE_RIGHT,
35
+ :bottom_right => ::SDL2::SDL_HITTEST_RESIZE_BOTTOMRIGHT,
36
+ :bottom => ::SDL2::SDL_HITTEST_RESIZE_BOTTOM,
37
+ :bottom_left => ::SDL2::SDL_HITTEST_RESIZE_BOTTOMLEFT,
38
+ :resize_left => ::SDL2::SDL_HITTEST_RESIZE_LEFT,
39
+ ).freeze
40
+
41
+ def initialize(&block)
42
+ # typedef SDL_HitTestResult (*SDL_HitTest)(SDL_Window *win,
43
+ # const SDL_Point *area, void *data);
44
+ super(:int, [:pointer, :pointer, :pointer]) do |win, area, _data|
45
+ # コールバック実行終了を OS が待つようなので、与えらえた window ポインターは有効なものとしてよいだろう。
46
+ # area には SDL_Point のアドレスが入る。SDL_Point は x, y の2つの int 型メンバーである。
47
+ HIT_TEST_RESULT[yield(Window.to_ptr(win), ::SDL2::SDL_Point.new(area).values)]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,38 @@
1
+ module RbSDL2
2
+ class Window
3
+ module Position
4
+ def position
5
+ x_y = Array.new(2) { ::FFI::MemoryPointer.new(:int) }
6
+ ::SDL2.SDL_GetWindowPosition(self, *x_y)
7
+ x_y.map(&:read_int)
8
+ end
9
+
10
+ def position=(x_y)
11
+ wx, wy = x_y
12
+ wx ||= ::SDL2::SDL_WINDOWPOS_CENTERED_MASK
13
+ wy ||= ::SDL2::SDL_WINDOWPOS_CENTERED_MASK
14
+ ::SDL2.SDL_SetWindowPosition(self, wx, wy)
15
+ end
16
+
17
+ def x
18
+ ptr = ::FFI::MemoryPointer.new(:int)
19
+ ::SDL2.SDL_GetWindowPosition(self, ptr, nil)
20
+ ptr.read_int
21
+ end
22
+
23
+ def x=(num)
24
+ self.position = [num, y]
25
+ end
26
+
27
+ def y
28
+ ptr = ::FFI::MemoryPointer.new(:int)
29
+ ::SDL2.SDL_GetWindowPosition(self, nil, ptr)
30
+ ptr.read_int
31
+ end
32
+
33
+ def y=(num)
34
+ self.position = [x, num]
35
+ end
36
+ end
37
+ end
38
+ end