sdl3 1.0.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 (88) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/LICENSE +21 -0
  4. data/README.md +188 -0
  5. data/Rakefile +12 -0
  6. data/examples/01_hello_window.rb +24 -0
  7. data/examples/02_basic_rendering.rb +45 -0
  8. data/examples/03_keyboard_input.rb +52 -0
  9. data/examples/04_mouse_input.rb +56 -0
  10. data/examples/05_simple_game.rb +107 -0
  11. data/lib/sdl3/high_level/audio_device.rb +202 -0
  12. data/lib/sdl3/high_level/camera.rb +118 -0
  13. data/lib/sdl3/high_level/clipboard.rb +59 -0
  14. data/lib/sdl3/high_level/event.rb +240 -0
  15. data/lib/sdl3/high_level/gamepad.rb +190 -0
  16. data/lib/sdl3/high_level/gpu.rb +194 -0
  17. data/lib/sdl3/high_level/haptic.rb +213 -0
  18. data/lib/sdl3/high_level/joystick.rb +165 -0
  19. data/lib/sdl3/high_level/renderer.rb +163 -0
  20. data/lib/sdl3/high_level/sensor.rb +105 -0
  21. data/lib/sdl3/high_level/surface.rb +143 -0
  22. data/lib/sdl3/high_level/texture.rb +111 -0
  23. data/lib/sdl3/high_level/timer.rb +88 -0
  24. data/lib/sdl3/high_level/window.rb +151 -0
  25. data/lib/sdl3/library_loader.rb +63 -0
  26. data/lib/sdl3/raw/assert.rb +32 -0
  27. data/lib/sdl3/raw/asyncio.rb +36 -0
  28. data/lib/sdl3/raw/atomic.rb +40 -0
  29. data/lib/sdl3/raw/audio.rb +95 -0
  30. data/lib/sdl3/raw/base.rb +12 -0
  31. data/lib/sdl3/raw/bits.rb +17 -0
  32. data/lib/sdl3/raw/blendmode.rb +36 -0
  33. data/lib/sdl3/raw/camera.rb +38 -0
  34. data/lib/sdl3/raw/clipboard.rb +20 -0
  35. data/lib/sdl3/raw/cpuinfo.rb +29 -0
  36. data/lib/sdl3/raw/dialog.rb +33 -0
  37. data/lib/sdl3/raw/endian.rb +8 -0
  38. data/lib/sdl3/raw/error.rb +15 -0
  39. data/lib/sdl3/raw/events.rb +563 -0
  40. data/lib/sdl3/raw/filesystem.rb +47 -0
  41. data/lib/sdl3/raw/gamepad.rb +135 -0
  42. data/lib/sdl3/raw/gpu.rb +734 -0
  43. data/lib/sdl3/raw/guid.rb +12 -0
  44. data/lib/sdl3/raw/haptic.rb +167 -0
  45. data/lib/sdl3/raw/hidapi.rb +57 -0
  46. data/lib/sdl3/raw/hints.rb +20 -0
  47. data/lib/sdl3/raw/init.rb +27 -0
  48. data/lib/sdl3/raw/iostream.rb +88 -0
  49. data/lib/sdl3/raw/joystick.rb +101 -0
  50. data/lib/sdl3/raw/keyboard.rb +30 -0
  51. data/lib/sdl3/raw/keycode.rb +132 -0
  52. data/lib/sdl3/raw/loadso.rb +9 -0
  53. data/lib/sdl3/raw/locale.rb +12 -0
  54. data/lib/sdl3/raw/log.rb +61 -0
  55. data/lib/sdl3/raw/main.rb +23 -0
  56. data/lib/sdl3/raw/messagebox.rb +50 -0
  57. data/lib/sdl3/raw/metal.rb +9 -0
  58. data/lib/sdl3/raw/misc.rb +7 -0
  59. data/lib/sdl3/raw/mouse.rb +82 -0
  60. data/lib/sdl3/raw/mutex.rb +48 -0
  61. data/lib/sdl3/raw/openxr.rb +21 -0
  62. data/lib/sdl3/raw/pen.rb +38 -0
  63. data/lib/sdl3/raw/pixels.rb +180 -0
  64. data/lib/sdl3/raw/platform.rb +7 -0
  65. data/lib/sdl3/raw/power.rb +14 -0
  66. data/lib/sdl3/raw/process.rb +15 -0
  67. data/lib/sdl3/raw/properties.rb +39 -0
  68. data/lib/sdl3/raw/rect.rb +41 -0
  69. data/lib/sdl3/raw/render.rb +153 -0
  70. data/lib/sdl3/raw/scancode.rb +112 -0
  71. data/lib/sdl3/raw/sensor.rb +31 -0
  72. data/lib/sdl3/raw/stdinc.rb +209 -0
  73. data/lib/sdl3/raw/storage.rb +50 -0
  74. data/lib/sdl3/raw/surface.rb +106 -0
  75. data/lib/sdl3/raw/system.rb +77 -0
  76. data/lib/sdl3/raw/thread.rb +40 -0
  77. data/lib/sdl3/raw/time.rb +36 -0
  78. data/lib/sdl3/raw/timer.rb +19 -0
  79. data/lib/sdl3/raw/touch.rb +22 -0
  80. data/lib/sdl3/raw/tray.rb +42 -0
  81. data/lib/sdl3/raw/types.rb +21 -0
  82. data/lib/sdl3/raw/version.rb +8 -0
  83. data/lib/sdl3/raw/video.rb +208 -0
  84. data/lib/sdl3/raw/vulkan.rb +13 -0
  85. data/lib/sdl3/version.rb +5 -0
  86. data/lib/sdl3.rb +128 -0
  87. data/sdl3.gemspec +30 -0
  88. metadata +143 -0
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SDL3
4
+ class Joystick
5
+ attr_reader :ptr
6
+
7
+ HAT_CENTERED = Raw::SDL_HAT_CENTERED
8
+ HAT_UP = Raw::SDL_HAT_UP
9
+ HAT_RIGHT = Raw::SDL_HAT_RIGHT
10
+ HAT_DOWN = Raw::SDL_HAT_DOWN
11
+ HAT_LEFT = Raw::SDL_HAT_LEFT
12
+
13
+ def initialize(instance_id)
14
+ @ptr = Raw.SDL_OpenJoystick(instance_id)
15
+ raise Error, Raw.SDL_GetError if @ptr.null?
16
+
17
+ ObjectSpace.define_finalizer(self, self.class.releasing(@ptr))
18
+ end
19
+
20
+ def self.releasing(ptr)
21
+ prevented_ptr = ptr
22
+ proc { Raw.SDL_CloseJoystick(prevented_ptr) unless prevented_ptr.null? }
23
+ end
24
+
25
+ def self.open(instance_id)
26
+ joystick = new(instance_id)
27
+ return joystick unless block_given?
28
+
29
+ begin
30
+ yield joystick
31
+ ensure
32
+ joystick.close
33
+ end
34
+ end
35
+
36
+ def self.available?
37
+ Raw.SDL_HasJoystick
38
+ end
39
+
40
+ def self.list
41
+ count_ptr = FFI::MemoryPointer.new(:int)
42
+ joysticks_ptr = Raw.SDL_GetJoysticks(count_ptr)
43
+ return [] if joysticks_ptr.null?
44
+
45
+ count = count_ptr.read_int
46
+ joysticks_ptr.read_array_of_uint32(count)
47
+ end
48
+
49
+ def self.name_for_id(instance_id)
50
+ Raw.SDL_GetJoystickNameForID(instance_id)
51
+ end
52
+
53
+ def self.type_for_id(instance_id)
54
+ Raw.SDL_GetJoystickTypeForID(instance_id)
55
+ end
56
+
57
+ def close
58
+ return if @ptr.null?
59
+
60
+ ObjectSpace.undefine_finalizer(self)
61
+ Raw.SDL_CloseJoystick(@ptr)
62
+ @ptr = FFI::Pointer::NULL
63
+ end
64
+
65
+ def id
66
+ Raw.SDL_GetJoystickID(@ptr)
67
+ end
68
+
69
+ def name
70
+ Raw.SDL_GetJoystickName(@ptr)
71
+ end
72
+
73
+ def path
74
+ Raw.SDL_GetJoystickPath(@ptr)
75
+ end
76
+
77
+ def type
78
+ Raw.SDL_GetJoystickType(@ptr)
79
+ end
80
+
81
+ def vendor
82
+ Raw.SDL_GetJoystickVendor(@ptr)
83
+ end
84
+
85
+ def product
86
+ Raw.SDL_GetJoystickProduct(@ptr)
87
+ end
88
+
89
+ def product_version
90
+ Raw.SDL_GetJoystickProductVersion(@ptr)
91
+ end
92
+
93
+ def firmware_version
94
+ Raw.SDL_GetJoystickFirmwareVersion(@ptr)
95
+ end
96
+
97
+ def serial
98
+ Raw.SDL_GetJoystickSerial(@ptr)
99
+ end
100
+
101
+ def connected?
102
+ Raw.SDL_JoystickConnected(@ptr)
103
+ end
104
+
105
+ def num_axes
106
+ Raw.SDL_GetNumJoystickAxes(@ptr)
107
+ end
108
+
109
+ def num_balls
110
+ Raw.SDL_GetNumJoystickBalls(@ptr)
111
+ end
112
+
113
+ def num_hats
114
+ Raw.SDL_GetNumJoystickHats(@ptr)
115
+ end
116
+
117
+ def num_buttons
118
+ Raw.SDL_GetNumJoystickButtons(@ptr)
119
+ end
120
+
121
+ def axis(index)
122
+ Raw.SDL_GetJoystickAxis(@ptr, index)
123
+ end
124
+
125
+ def hat(index)
126
+ Raw.SDL_GetJoystickHat(@ptr, index)
127
+ end
128
+
129
+ def button(index)
130
+ Raw.SDL_GetJoystickButton(@ptr, index)
131
+ end
132
+
133
+ def button?(index)
134
+ Raw.SDL_GetJoystickButton(@ptr, index)
135
+ end
136
+
137
+ def rumble(low_frequency, high_frequency, duration_ms)
138
+ Raw.SDL_RumbleJoystick(@ptr, low_frequency, high_frequency, duration_ms)
139
+ end
140
+
141
+ def rumble_triggers(left, right, duration_ms)
142
+ Raw.SDL_RumbleJoystickTriggers(@ptr, left, right, duration_ms)
143
+ end
144
+
145
+ def set_led(red, green, blue)
146
+ Raw.SDL_SetJoystickLED(@ptr, red, green, blue)
147
+ end
148
+
149
+ def player_index
150
+ Raw.SDL_GetJoystickPlayerIndex(@ptr)
151
+ end
152
+
153
+ def player_index=(index)
154
+ Raw.SDL_SetJoystickPlayerIndex(@ptr, index)
155
+ end
156
+
157
+ def connection_state
158
+ Raw.SDL_GetJoystickConnectionState(@ptr)
159
+ end
160
+
161
+ def to_ptr
162
+ @ptr
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SDL3
4
+ class Renderer
5
+ attr_reader :ptr
6
+
7
+ def initialize(window, driver_name = nil)
8
+ @ptr = Raw.SDL_CreateRenderer(window.to_ptr, driver_name)
9
+ raise Error, Raw.SDL_GetError if @ptr.null?
10
+
11
+ ObjectSpace.define_finalizer(self, self.class.releasing(@ptr))
12
+ end
13
+
14
+ def self.releasing(ptr)
15
+ prevented_ptr = ptr
16
+ proc { Raw.SDL_DestroyRenderer(prevented_ptr) unless prevented_ptr.null? }
17
+ end
18
+
19
+ def self.create(window, driver_name = nil)
20
+ renderer = new(window, driver_name)
21
+ return renderer unless block_given?
22
+
23
+ begin
24
+ yield renderer
25
+ ensure
26
+ renderer.destroy
27
+ end
28
+ end
29
+
30
+ def destroy
31
+ return if @ptr.null?
32
+
33
+ ObjectSpace.undefine_finalizer(self)
34
+ Raw.SDL_DestroyRenderer(@ptr)
35
+ @ptr = FFI::Pointer::NULL
36
+ end
37
+
38
+ def draw_color
39
+ r = FFI::MemoryPointer.new(:uint8)
40
+ g = FFI::MemoryPointer.new(:uint8)
41
+ b = FFI::MemoryPointer.new(:uint8)
42
+ a = FFI::MemoryPointer.new(:uint8)
43
+ Raw.SDL_GetRenderDrawColor(@ptr, r, g, b, a)
44
+ [r.read_uint8, g.read_uint8, b.read_uint8, a.read_uint8]
45
+ end
46
+
47
+ def draw_color=(color)
48
+ r, g, b, a = color
49
+ a ||= 255
50
+ Raw.SDL_SetRenderDrawColor(@ptr, r, g, b, a)
51
+ end
52
+
53
+ def clear
54
+ raise Error, Raw.SDL_GetError unless Raw.SDL_RenderClear(@ptr)
55
+
56
+ true
57
+ end
58
+
59
+ def present
60
+ raise Error, Raw.SDL_GetError unless Raw.SDL_RenderPresent(@ptr)
61
+
62
+ true
63
+ end
64
+
65
+ def draw_point(x, y)
66
+ Raw.SDL_RenderPoint(@ptr, x.to_f, y.to_f)
67
+ end
68
+
69
+ def draw_line(x1, y1, x2, y2)
70
+ Raw.SDL_RenderLine(@ptr, x1.to_f, y1.to_f, x2.to_f, y2.to_f)
71
+ end
72
+
73
+ def draw_rect(x, y, w, h)
74
+ rect = Raw::SDL_FRect.new
75
+ rect[:x] = x.to_f
76
+ rect[:y] = y.to_f
77
+ rect[:w] = w.to_f
78
+ rect[:h] = h.to_f
79
+ Raw.SDL_RenderRect(@ptr, rect)
80
+ end
81
+
82
+ def fill_rect(x, y, w, h)
83
+ rect = Raw::SDL_FRect.new
84
+ rect[:x] = x.to_f
85
+ rect[:y] = y.to_f
86
+ rect[:w] = w.to_f
87
+ rect[:h] = h.to_f
88
+ Raw.SDL_RenderFillRect(@ptr, rect)
89
+ end
90
+
91
+ def copy(texture, src_rect = nil, dst_rect = nil)
92
+ src = rect_to_frect(src_rect)
93
+ dst = rect_to_frect(dst_rect)
94
+ Raw.SDL_RenderTexture(@ptr, texture.to_ptr, src, dst)
95
+ end
96
+
97
+ def copy_ex(texture, src_rect, dst_rect, angle, center = nil, flip = :SDL_FLIP_NONE)
98
+ src = rect_to_frect(src_rect)
99
+ dst = rect_to_frect(dst_rect)
100
+ center_ptr = nil
101
+ if center
102
+ center_ptr = Raw::SDL_FPoint.new
103
+ center_ptr[:x] = center[0].to_f
104
+ center_ptr[:y] = center[1].to_f
105
+ end
106
+ Raw.SDL_RenderTextureRotated(@ptr, texture.to_ptr, src, dst, angle.to_f, center_ptr, flip)
107
+ end
108
+
109
+ def target=(texture)
110
+ ptr = texture ? texture.to_ptr : nil
111
+ Raw.SDL_SetRenderTarget(@ptr, ptr)
112
+ end
113
+
114
+ def logical_size=(dimensions)
115
+ Raw.SDL_SetRenderLogicalPresentation(@ptr, dimensions[0], dimensions[1],
116
+ :SDL_LOGICAL_PRESENTATION_LETTERBOX,
117
+ :SDL_SCALEMODE_LINEAR)
118
+ end
119
+
120
+ def scale=(factors)
121
+ Raw.SDL_SetRenderScale(@ptr, factors[0].to_f, factors[1].to_f)
122
+ end
123
+
124
+ def scale
125
+ x = FFI::MemoryPointer.new(:float)
126
+ y = FFI::MemoryPointer.new(:float)
127
+ Raw.SDL_GetRenderScale(@ptr, x, y)
128
+ [x.read_float, y.read_float]
129
+ end
130
+
131
+ def create_texture(format, access, width, height)
132
+ Texture.new(self, format, access, width, height)
133
+ end
134
+
135
+ def create_texture_from_surface(surface)
136
+ Texture.from_surface(self, surface)
137
+ end
138
+
139
+ def to_ptr
140
+ @ptr
141
+ end
142
+
143
+ private
144
+
145
+ def rect_to_frect(rect)
146
+ return nil unless rect
147
+
148
+ frect = Raw::SDL_FRect.new
149
+ if rect.is_a?(Hash)
150
+ frect[:x] = rect[:x].to_f
151
+ frect[:y] = rect[:y].to_f
152
+ frect[:w] = rect[:w].to_f
153
+ frect[:h] = rect[:h].to_f
154
+ else
155
+ frect[:x] = rect[0].to_f
156
+ frect[:y] = rect[1].to_f
157
+ frect[:w] = rect[2].to_f
158
+ frect[:h] = rect[3].to_f
159
+ end
160
+ frect
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SDL3
4
+ class Sensor
5
+ attr_reader :ptr
6
+
7
+ STANDARD_GRAVITY = Raw::SDL_STANDARD_GRAVITY
8
+
9
+ TYPE_INVALID = :SDL_SENSOR_INVALID
10
+ TYPE_UNKNOWN = :SDL_SENSOR_UNKNOWN
11
+ TYPE_ACCEL = :SDL_SENSOR_ACCEL
12
+ TYPE_GYRO = :SDL_SENSOR_GYRO
13
+ TYPE_ACCEL_L = :SDL_SENSOR_ACCEL_L
14
+ TYPE_GYRO_L = :SDL_SENSOR_GYRO_L
15
+ TYPE_ACCEL_R = :SDL_SENSOR_ACCEL_R
16
+ TYPE_GYRO_R = :SDL_SENSOR_GYRO_R
17
+
18
+ def initialize(sensor_id)
19
+ @ptr = Raw.SDL_OpenSensor(sensor_id)
20
+ raise Error, Raw.SDL_GetError if @ptr.null?
21
+
22
+ ObjectSpace.define_finalizer(self, self.class.releasing(@ptr))
23
+ end
24
+
25
+ def self.releasing(ptr)
26
+ prevented_ptr = ptr
27
+ proc { Raw.SDL_CloseSensor(prevented_ptr) unless prevented_ptr.null? }
28
+ end
29
+
30
+ def self.open(sensor_id)
31
+ sensor = new(sensor_id)
32
+ return sensor unless block_given?
33
+
34
+ begin
35
+ yield sensor
36
+ ensure
37
+ sensor.close
38
+ end
39
+ end
40
+
41
+ def self.list
42
+ count_ptr = FFI::MemoryPointer.new(:int)
43
+ sensors_ptr = Raw.SDL_GetSensors(count_ptr)
44
+ return [] if sensors_ptr.null?
45
+
46
+ count = count_ptr.read_int
47
+ sensors_ptr.read_array_of_uint32(count)
48
+ end
49
+
50
+ def self.name_for_id(sensor_id)
51
+ Raw.SDL_GetSensorNameForID(sensor_id)
52
+ end
53
+
54
+ def self.type_for_id(sensor_id)
55
+ Raw.SDL_GetSensorTypeForID(sensor_id)
56
+ end
57
+
58
+ def self.non_portable_type_for_id(sensor_id)
59
+ Raw.SDL_GetSensorNonPortableTypeForID(sensor_id)
60
+ end
61
+
62
+ def self.update_all
63
+ Raw.SDL_UpdateSensors
64
+ end
65
+
66
+ def close
67
+ return if @ptr.null?
68
+
69
+ ObjectSpace.undefine_finalizer(self)
70
+ Raw.SDL_CloseSensor(@ptr)
71
+ @ptr = FFI::Pointer::NULL
72
+ end
73
+
74
+ def id
75
+ Raw.SDL_GetSensorID(@ptr)
76
+ end
77
+
78
+ def name
79
+ Raw.SDL_GetSensorName(@ptr)
80
+ end
81
+
82
+ def type
83
+ Raw.SDL_GetSensorType(@ptr)
84
+ end
85
+
86
+ def non_portable_type
87
+ Raw.SDL_GetSensorNonPortableType(@ptr)
88
+ end
89
+
90
+ def properties
91
+ Raw.SDL_GetSensorProperties(@ptr)
92
+ end
93
+
94
+ def data(num_values = 3)
95
+ data_ptr = FFI::MemoryPointer.new(:float, num_values)
96
+ return nil unless Raw.SDL_GetSensorData(@ptr, data_ptr, num_values)
97
+
98
+ data_ptr.read_array_of_float(num_values)
99
+ end
100
+
101
+ def to_ptr
102
+ @ptr
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SDL3
4
+ class Surface
5
+ attr_reader :ptr
6
+
7
+ def initialize(width, height, format = Raw::SDL_PIXELFORMAT_RGBA8888)
8
+ @ptr = Raw.SDL_CreateSurface(width, height, format)
9
+ raise Error, Raw.SDL_GetError if @ptr.null?
10
+
11
+ @owned = true
12
+ ObjectSpace.define_finalizer(self, self.class.releasing(@ptr))
13
+ end
14
+
15
+ def self.releasing(ptr)
16
+ prevented_ptr = ptr
17
+ proc do
18
+ Raw.SDL_DestroySurface(prevented_ptr) unless prevented_ptr.null?
19
+ end
20
+ end
21
+
22
+ def self.from_ptr(ptr, owned: true)
23
+ surface = allocate
24
+ surface.instance_variable_set(:@ptr, ptr)
25
+ surface.instance_variable_set(:@owned, owned)
26
+ ObjectSpace.define_finalizer(surface, releasing(ptr)) if owned
27
+ surface
28
+ end
29
+
30
+ def self.load_bmp(file)
31
+ ptr = Raw.SDL_LoadBMP(file)
32
+ raise Error, Raw.SDL_GetError if ptr.null?
33
+
34
+ from_ptr(ptr, owned: true)
35
+ end
36
+
37
+ def destroy
38
+ return if @ptr.null?
39
+ return unless @owned
40
+
41
+ ObjectSpace.undefine_finalizer(self)
42
+ Raw.SDL_DestroySurface(@ptr)
43
+ @ptr = FFI::Pointer::NULL
44
+ end
45
+
46
+ def width
47
+ struct[:w]
48
+ end
49
+
50
+ def height
51
+ struct[:h]
52
+ end
53
+
54
+ def size
55
+ [width, height]
56
+ end
57
+
58
+ def pitch
59
+ struct[:pitch]
60
+ end
61
+
62
+ def format
63
+ struct[:format]
64
+ end
65
+
66
+ def pixels
67
+ struct[:pixels]
68
+ end
69
+
70
+ def lock
71
+ raise Error, Raw.SDL_GetError unless Raw.SDL_LockSurface(@ptr)
72
+
73
+ true
74
+ end
75
+
76
+ def unlock
77
+ Raw.SDL_UnlockSurface(@ptr)
78
+ end
79
+
80
+ def fill_rect(rect, color)
81
+ rect_ptr = nil
82
+ if rect
83
+ rect_ptr = Raw::SDL_Rect.new
84
+ rect_ptr[:x] = rect[0]
85
+ rect_ptr[:y] = rect[1]
86
+ rect_ptr[:w] = rect[2]
87
+ rect_ptr[:h] = rect[3]
88
+ end
89
+ Raw.SDL_FillSurfaceRect(@ptr, rect_ptr, color)
90
+ end
91
+
92
+ def blit(src_surface, src_rect = nil, dst_rect = nil)
93
+ src_rect_ptr = nil
94
+ dst_rect_ptr = nil
95
+
96
+ if src_rect
97
+ src_rect_ptr = Raw::SDL_Rect.new
98
+ src_rect_ptr[:x] = src_rect[0]
99
+ src_rect_ptr[:y] = src_rect[1]
100
+ src_rect_ptr[:w] = src_rect[2]
101
+ src_rect_ptr[:h] = src_rect[3]
102
+ end
103
+
104
+ if dst_rect
105
+ dst_rect_ptr = Raw::SDL_Rect.new
106
+ dst_rect_ptr[:x] = dst_rect[0]
107
+ dst_rect_ptr[:y] = dst_rect[1]
108
+ dst_rect_ptr[:w] = dst_rect[2]
109
+ dst_rect_ptr[:h] = dst_rect[3]
110
+ end
111
+
112
+ Raw.SDL_BlitSurface(src_surface.to_ptr, src_rect_ptr, @ptr, dst_rect_ptr)
113
+ end
114
+
115
+ def convert(format)
116
+ ptr = Raw.SDL_ConvertSurface(@ptr, format)
117
+ raise Error, Raw.SDL_GetError if ptr.null?
118
+
119
+ Surface.from_ptr(ptr, owned: true)
120
+ end
121
+
122
+ def flip(mode)
123
+ Raw.SDL_FlipSurface(@ptr, mode)
124
+ end
125
+
126
+ def duplicate
127
+ ptr = Raw.SDL_DuplicateSurface(@ptr)
128
+ raise Error, Raw.SDL_GetError if ptr.null?
129
+
130
+ Surface.from_ptr(ptr, owned: true)
131
+ end
132
+
133
+ def to_ptr
134
+ @ptr
135
+ end
136
+
137
+ private
138
+
139
+ def struct
140
+ @struct ||= Raw::SDL_Surface.new(@ptr)
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SDL3
4
+ class Texture
5
+ attr_reader :ptr
6
+
7
+ ACCESS_STATIC = :SDL_TEXTUREACCESS_STATIC
8
+ ACCESS_STREAMING = :SDL_TEXTUREACCESS_STREAMING
9
+ ACCESS_TARGET = :SDL_TEXTUREACCESS_TARGET
10
+
11
+ def initialize(renderer, format, access, width, height)
12
+ access_value = case access
13
+ when Symbol then Raw::SDL_TextureAccess[access]
14
+ when Integer then access
15
+ else access
16
+ end
17
+ @ptr = Raw.SDL_CreateTexture(renderer.to_ptr, format, access_value, width, height)
18
+ raise Error, Raw.SDL_GetError if @ptr.null?
19
+
20
+ @owned = true
21
+ ObjectSpace.define_finalizer(self, self.class.releasing(@ptr))
22
+ end
23
+
24
+ def self.releasing(ptr)
25
+ prevented_ptr = ptr
26
+ proc { Raw.SDL_DestroyTexture(prevented_ptr) unless prevented_ptr.null? }
27
+ end
28
+
29
+ def self.from_surface(renderer, surface)
30
+ ptr = Raw.SDL_CreateTextureFromSurface(renderer.to_ptr, surface.to_ptr)
31
+ raise Error, Raw.SDL_GetError if ptr.null?
32
+
33
+ texture = allocate
34
+ texture.instance_variable_set(:@ptr, ptr)
35
+ texture.instance_variable_set(:@owned, true)
36
+ ObjectSpace.define_finalizer(texture, releasing(ptr))
37
+ texture
38
+ end
39
+
40
+ def destroy
41
+ return if @ptr.null?
42
+
43
+ ObjectSpace.undefine_finalizer(self)
44
+ Raw.SDL_DestroyTexture(@ptr)
45
+ @ptr = FFI::Pointer::NULL
46
+ end
47
+
48
+ def size
49
+ w = FFI::MemoryPointer.new(:float)
50
+ h = FFI::MemoryPointer.new(:float)
51
+ Raw.SDL_GetTextureSize(@ptr, w, h)
52
+ [w.read_float.to_i, h.read_float.to_i]
53
+ end
54
+
55
+ def width
56
+ size[0]
57
+ end
58
+
59
+ def height
60
+ size[1]
61
+ end
62
+
63
+ def color_mod=(rgb)
64
+ Raw.SDL_SetTextureColorMod(@ptr, rgb[0], rgb[1], rgb[2])
65
+ end
66
+
67
+ def color_mod
68
+ r = FFI::MemoryPointer.new(:uint8)
69
+ g = FFI::MemoryPointer.new(:uint8)
70
+ b = FFI::MemoryPointer.new(:uint8)
71
+ Raw.SDL_GetTextureColorMod(@ptr, r, g, b)
72
+ [r.read_uint8, g.read_uint8, b.read_uint8]
73
+ end
74
+
75
+ def alpha_mod=(alpha)
76
+ Raw.SDL_SetTextureAlphaMod(@ptr, alpha)
77
+ end
78
+
79
+ def alpha_mod
80
+ a = FFI::MemoryPointer.new(:uint8)
81
+ Raw.SDL_GetTextureAlphaMod(@ptr, a)
82
+ a.read_uint8
83
+ end
84
+
85
+ def blend_mode=(mode)
86
+ Raw.SDL_SetTextureBlendMode(@ptr, mode)
87
+ end
88
+
89
+ def blend_mode
90
+ mode = FFI::MemoryPointer.new(:uint32)
91
+ Raw.SDL_GetTextureBlendMode(@ptr, mode)
92
+ mode.read_uint32
93
+ end
94
+
95
+ def update(rect, pixels, pitch)
96
+ rect_ptr = nil
97
+ if rect
98
+ rect_ptr = Raw::SDL_Rect.new
99
+ rect_ptr[:x] = rect[0]
100
+ rect_ptr[:y] = rect[1]
101
+ rect_ptr[:w] = rect[2]
102
+ rect_ptr[:h] = rect[3]
103
+ end
104
+ Raw.SDL_UpdateTexture(@ptr, rect_ptr, pixels, pitch)
105
+ end
106
+
107
+ def to_ptr
108
+ @ptr
109
+ end
110
+ end
111
+ end