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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +17 -0
- data/README.md +40 -0
- data/lib/rb_sdl2/audio/audio_allowed_changes.rb +17 -0
- data/lib/rb_sdl2/audio/audio_buffer.rb +49 -0
- data/lib/rb_sdl2/audio/audio_device.rb +44 -0
- data/lib/rb_sdl2/audio/audio_format.rb +23 -0
- data/lib/rb_sdl2/audio/audio_spec.rb +29 -0
- data/lib/rb_sdl2/audio.rb +132 -0
- data/lib/rb_sdl2/clipboard.rb +44 -0
- data/lib/rb_sdl2/cpu_info.rb +39 -0
- data/lib/rb_sdl2/cursor/color_cursor.rb +19 -0
- data/lib/rb_sdl2/cursor/cursor_class.rb +24 -0
- data/lib/rb_sdl2/cursor/cursor_pointer.rb +12 -0
- data/lib/rb_sdl2/cursor/default_cursor.rb +18 -0
- data/lib/rb_sdl2/cursor/system_cursor.rb +45 -0
- data/lib/rb_sdl2/cursor.rb +39 -0
- data/lib/rb_sdl2/display.rb +103 -0
- data/lib/rb_sdl2/display_mode.rb +35 -0
- data/lib/rb_sdl2/error.rb +9 -0
- data/lib/rb_sdl2/event/event_filter.rb +83 -0
- data/lib/rb_sdl2/event/event_queue.rb +137 -0
- data/lib/rb_sdl2/event/event_type.rb +271 -0
- data/lib/rb_sdl2/event.rb +161 -0
- data/lib/rb_sdl2/filesystem.rb +40 -0
- data/lib/rb_sdl2/hint.rb +24 -0
- data/lib/rb_sdl2/keyboard/key_mod.rb +37 -0
- data/lib/rb_sdl2/keyboard/keyboard_state.rb +34 -0
- data/lib/rb_sdl2/keyboard.rb +50 -0
- data/lib/rb_sdl2/message_box.rb +121 -0
- data/lib/rb_sdl2/mouse/global_mouse.rb +18 -0
- data/lib/rb_sdl2/mouse/mouse_button.rb +24 -0
- data/lib/rb_sdl2/mouse/mouse_class.rb +33 -0
- data/lib/rb_sdl2/mouse/mouse_wheel.rb +53 -0
- data/lib/rb_sdl2/mouse/relative_mouse.rb +12 -0
- data/lib/rb_sdl2/mouse/window_mouse.rb +17 -0
- data/lib/rb_sdl2/mouse.rb +74 -0
- data/lib/rb_sdl2/palette.rb +70 -0
- data/lib/rb_sdl2/pixel_format_enum.rb +73 -0
- data/lib/rb_sdl2/platform.rb +7 -0
- data/lib/rb_sdl2/power_info.rb +36 -0
- data/lib/rb_sdl2/rect.rb +14 -0
- data/lib/rb_sdl2/ref_count_pointer.rb +20 -0
- data/lib/rb_sdl2/rw_ops/rw_operator.rb +102 -0
- data/lib/rb_sdl2/rw_ops.rb +124 -0
- data/lib/rb_sdl2/screen_saver.rb +11 -0
- data/lib/rb_sdl2/sdl.rb +32 -0
- data/lib/rb_sdl2/surface/blend_mode.rb +41 -0
- data/lib/rb_sdl2/surface/pixel_format.rb +89 -0
- data/lib/rb_sdl2/surface.rb +244 -0
- data/lib/rb_sdl2/text_input.rb +15 -0
- data/lib/rb_sdl2/timer.rb +22 -0
- data/lib/rb_sdl2/version.rb +13 -0
- data/lib/rb_sdl2/video.rb +25 -0
- data/lib/rb_sdl2/window/dialog.rb +19 -0
- data/lib/rb_sdl2/window/display.rb +85 -0
- data/lib/rb_sdl2/window/grab.rb +23 -0
- data/lib/rb_sdl2/window/hit_test.rb +52 -0
- data/lib/rb_sdl2/window/position.rb +38 -0
- data/lib/rb_sdl2/window/shape.rb +76 -0
- data/lib/rb_sdl2/window/size.rb +59 -0
- data/lib/rb_sdl2/window/window_flags.rb +78 -0
- data/lib/rb_sdl2/window.rb +242 -0
- data/lib/rb_sdl2.rb +53 -0
- data/rb_sdl2.gemspec +19 -0
- 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,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
|
data/lib/rb_sdl2/rect.rb
ADDED
@@ -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
|
data/lib/rb_sdl2/sdl.rb
ADDED
@@ -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
|