glfw-ruby 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.
@@ -0,0 +1,435 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GLFW
4
+ class Window
5
+ HINT_MAP = {
6
+ resizable: GLFW_RESIZABLE,
7
+ visible: GLFW_VISIBLE,
8
+ decorated: GLFW_DECORATED,
9
+ focused: GLFW_FOCUSED,
10
+ auto_iconify: GLFW_AUTO_ICONIFY,
11
+ floating: GLFW_FLOATING,
12
+ maximized: GLFW_MAXIMIZED,
13
+ center_cursor: GLFW_CENTER_CURSOR,
14
+ transparent_framebuffer: GLFW_TRANSPARENT_FRAMEBUFFER,
15
+ focus_on_show: GLFW_FOCUS_ON_SHOW,
16
+ scale_to_monitor: GLFW_SCALE_TO_MONITOR,
17
+ mouse_passthrough: GLFW_MOUSE_PASSTHROUGH,
18
+ samples: GLFW_SAMPLES,
19
+ refresh_rate: GLFW_REFRESH_RATE,
20
+ stereo: GLFW_STEREO,
21
+ srgb_capable: GLFW_SRGB_CAPABLE,
22
+ doublebuffer: GLFW_DOUBLEBUFFER,
23
+ client_api: GLFW_CLIENT_API,
24
+ context_version_major: GLFW_CONTEXT_VERSION_MAJOR,
25
+ context_version_minor: GLFW_CONTEXT_VERSION_MINOR,
26
+ context_robustness: GLFW_CONTEXT_ROBUSTNESS,
27
+ opengl_forward_compat: GLFW_OPENGL_FORWARD_COMPAT,
28
+ opengl_debug_context: GLFW_OPENGL_DEBUG_CONTEXT,
29
+ context_release_behavior: GLFW_CONTEXT_RELEASE_BEHAVIOR,
30
+ context_no_error: GLFW_CONTEXT_NO_ERROR,
31
+ context_creation_api: GLFW_CONTEXT_CREATION_API,
32
+ red_bits: GLFW_RED_BITS,
33
+ green_bits: GLFW_GREEN_BITS,
34
+ blue_bits: GLFW_BLUE_BITS,
35
+ alpha_bits: GLFW_ALPHA_BITS,
36
+ depth_bits: GLFW_DEPTH_BITS,
37
+ stencil_bits: GLFW_STENCIL_BITS,
38
+ opengl_profile: GLFW_OPENGL_PROFILE
39
+ }.freeze
40
+
41
+ PROFILE_MAP = {
42
+ any: GLFW_OPENGL_ANY_PROFILE,
43
+ core: GLFW_OPENGL_CORE_PROFILE,
44
+ compat: GLFW_OPENGL_COMPAT_PROFILE
45
+ }.freeze
46
+
47
+ attr_reader :handle
48
+
49
+ def initialize(width, height, title, monitor: nil, share: nil, **hints)
50
+ API.glfwDefaultWindowHints
51
+
52
+ hints.each do |key, value|
53
+ hint_const = HINT_MAP[key]
54
+ raise ArgumentError, "Unknown hint: #{key}" unless hint_const
55
+
56
+ if key == :opengl_profile && value.is_a?(Symbol)
57
+ value = PROFILE_MAP[value] || raise(ArgumentError, "Unknown profile: #{value}")
58
+ elsif value == true
59
+ value = GLFW_TRUE
60
+ elsif value == false
61
+ value = GLFW_FALSE
62
+ end
63
+
64
+ API.glfwWindowHint(hint_const, value)
65
+ end
66
+
67
+ monitor_handle = monitor&.handle
68
+ share_handle = share&.handle
69
+
70
+ @handle = API.glfwCreateWindow(width, height, title, monitor_handle, share_handle)
71
+ raise GLFW::Error, "Failed to create GLFW window" if @handle.null?
72
+
73
+ @title = title
74
+ @callbacks = {}
75
+ GLFW.register_window(self)
76
+ end
77
+
78
+ def destroy
79
+ GLFW.unregister_callbacks(@handle)
80
+ GLFW.unregister_window(self)
81
+ API.glfwDestroyWindow(@handle)
82
+ @handle = nil
83
+ end
84
+
85
+ def title
86
+ if GLFW.version_at_least?(3, 4)
87
+ API.glfwGetWindowTitle(@handle)
88
+ else
89
+ @title
90
+ end
91
+ end
92
+
93
+ def title=(t)
94
+ @title = t
95
+ API.glfwSetWindowTitle(@handle, t)
96
+ end
97
+
98
+ def size
99
+ w = FFI::MemoryPointer.new(:int)
100
+ h = FFI::MemoryPointer.new(:int)
101
+ API.glfwGetWindowSize(@handle, w, h)
102
+ [w.read_int, h.read_int]
103
+ end
104
+
105
+ def size=(wh)
106
+ API.glfwSetWindowSize(@handle, wh[0], wh[1])
107
+ end
108
+
109
+ def position
110
+ x = FFI::MemoryPointer.new(:int)
111
+ y = FFI::MemoryPointer.new(:int)
112
+ API.glfwGetWindowPos(@handle, x, y)
113
+ [x.read_int, y.read_int]
114
+ end
115
+
116
+ def position=(xy)
117
+ API.glfwSetWindowPos(@handle, xy[0], xy[1])
118
+ end
119
+
120
+ def framebuffer_size
121
+ w = FFI::MemoryPointer.new(:int)
122
+ h = FFI::MemoryPointer.new(:int)
123
+ API.glfwGetFramebufferSize(@handle, w, h)
124
+ [w.read_int, h.read_int]
125
+ end
126
+
127
+ def content_scale
128
+ x = FFI::MemoryPointer.new(:float)
129
+ y = FFI::MemoryPointer.new(:float)
130
+ API.glfwGetWindowContentScale(@handle, x, y)
131
+ [x.read_float, y.read_float]
132
+ end
133
+
134
+ def frame_size
135
+ l = FFI::MemoryPointer.new(:int)
136
+ t = FFI::MemoryPointer.new(:int)
137
+ r = FFI::MemoryPointer.new(:int)
138
+ b = FFI::MemoryPointer.new(:int)
139
+ API.glfwGetWindowFrameSize(@handle, l, t, r, b)
140
+ { left: l.read_int, top: t.read_int, right: r.read_int, bottom: b.read_int }
141
+ end
142
+
143
+ def opacity
144
+ API.glfwGetWindowOpacity(@handle)
145
+ end
146
+
147
+ def opacity=(val)
148
+ API.glfwSetWindowOpacity(@handle, val.to_f)
149
+ end
150
+
151
+ def should_close?
152
+ API.glfwWindowShouldClose(@handle) == GLFW_TRUE
153
+ end
154
+
155
+ def should_close=(val)
156
+ API.glfwSetWindowShouldClose(@handle, val ? GLFW_TRUE : GLFW_FALSE)
157
+ end
158
+
159
+ def focused?
160
+ API.glfwGetWindowAttrib(@handle, GLFW_FOCUSED) == GLFW_TRUE
161
+ end
162
+
163
+ def iconified?
164
+ API.glfwGetWindowAttrib(@handle, GLFW_ICONIFIED) == GLFW_TRUE
165
+ end
166
+
167
+ def maximized?
168
+ API.glfwGetWindowAttrib(@handle, GLFW_MAXIMIZED) == GLFW_TRUE
169
+ end
170
+
171
+ def visible?
172
+ API.glfwGetWindowAttrib(@handle, GLFW_VISIBLE) == GLFW_TRUE
173
+ end
174
+
175
+ def hovered?
176
+ API.glfwGetWindowAttrib(@handle, GLFW_HOVERED) == GLFW_TRUE
177
+ end
178
+
179
+ def transparent_framebuffer?
180
+ API.glfwGetWindowAttrib(@handle, GLFW_TRANSPARENT_FRAMEBUFFER) == GLFW_TRUE
181
+ end
182
+
183
+ def iconify
184
+ API.glfwIconifyWindow(@handle)
185
+ end
186
+
187
+ def restore
188
+ API.glfwRestoreWindow(@handle)
189
+ end
190
+
191
+ def maximize
192
+ API.glfwMaximizeWindow(@handle)
193
+ end
194
+
195
+ def show
196
+ API.glfwShowWindow(@handle)
197
+ end
198
+
199
+ def hide
200
+ API.glfwHideWindow(@handle)
201
+ end
202
+
203
+ def focus
204
+ API.glfwFocusWindow(@handle)
205
+ end
206
+
207
+ def request_attention
208
+ API.glfwRequestWindowAttention(@handle)
209
+ end
210
+
211
+ def swap_buffers
212
+ API.glfwSwapBuffers(@handle)
213
+ end
214
+
215
+ def make_context_current
216
+ API.glfwMakeContextCurrent(@handle)
217
+ end
218
+
219
+ def set_size_limits(min_w, min_h, max_w, max_h)
220
+ API.glfwSetWindowSizeLimits(@handle, min_w, min_h, max_w, max_h)
221
+ end
222
+
223
+ def set_aspect_ratio(numer, denom)
224
+ API.glfwSetWindowAspectRatio(@handle, numer, denom)
225
+ end
226
+
227
+ def monitor
228
+ ptr = API.glfwGetWindowMonitor(@handle)
229
+ return nil if ptr.null?
230
+
231
+ Monitor.new(ptr)
232
+ end
233
+
234
+ def set_fullscreen(monitor, width, height, refresh_rate: GLFW_DONT_CARE)
235
+ API.glfwSetWindowMonitor(@handle, monitor.handle, 0, 0, width, height, refresh_rate)
236
+ end
237
+
238
+ def set_windowed(x, y, width, height)
239
+ API.glfwSetWindowMonitor(@handle, nil, x, y, width, height, GLFW_DONT_CARE)
240
+ end
241
+
242
+ def get_attrib(attrib)
243
+ API.glfwGetWindowAttrib(@handle, attrib)
244
+ end
245
+
246
+ def set_attrib(attrib, value)
247
+ API.glfwSetWindowAttrib(@handle, attrib, value)
248
+ end
249
+
250
+ def decorated?
251
+ get_attrib(GLFW_DECORATED) == GLFW_TRUE
252
+ end
253
+
254
+ def resizable?
255
+ get_attrib(GLFW_RESIZABLE) == GLFW_TRUE
256
+ end
257
+
258
+ def floating?
259
+ get_attrib(GLFW_FLOATING) == GLFW_TRUE
260
+ end
261
+
262
+ def auto_iconify?
263
+ get_attrib(GLFW_AUTO_ICONIFY) == GLFW_TRUE
264
+ end
265
+
266
+ def focus_on_show?
267
+ get_attrib(GLFW_FOCUS_ON_SHOW) == GLFW_TRUE
268
+ end
269
+
270
+ def mouse_passthrough?
271
+ get_attrib(GLFW_MOUSE_PASSTHROUGH) == GLFW_TRUE
272
+ end
273
+
274
+ def set_icon(images)
275
+ count = images.size
276
+ structs_ptr = FFI::MemoryPointer.new(API::GLFWimage, count)
277
+ images.each_with_index do |img, i|
278
+ s = img.to_struct
279
+ structs_ptr.put_bytes(i * API::GLFWimage.size, s.pointer.read_bytes(API::GLFWimage.size))
280
+ end
281
+ API.glfwSetWindowIcon(@handle, count, structs_ptr)
282
+ end
283
+
284
+ def clear_icon
285
+ API.glfwSetWindowIcon(@handle, 0, nil)
286
+ end
287
+
288
+ def cursor=(cursor)
289
+ API.glfwSetCursor(@handle, cursor&.handle)
290
+ end
291
+
292
+ def cursor_pos
293
+ x = FFI::MemoryPointer.new(:double)
294
+ y = FFI::MemoryPointer.new(:double)
295
+ API.glfwGetCursorPos(@handle, x, y)
296
+ [x.read_double, y.read_double]
297
+ end
298
+
299
+ def cursor_pos=(xy)
300
+ API.glfwSetCursorPos(@handle, xy[0].to_f, xy[1].to_f)
301
+ end
302
+
303
+ def key(key_code)
304
+ val = API.glfwGetKey(@handle, key_code)
305
+ ACTION_MAP[val] || val
306
+ end
307
+
308
+ def mouse_button(button)
309
+ val = API.glfwGetMouseButton(@handle, button)
310
+ ACTION_MAP[val] || val
311
+ end
312
+
313
+ def input_mode(mode)
314
+ API.glfwGetInputMode(@handle, mode)
315
+ end
316
+
317
+ def set_input_mode(mode, value)
318
+ API.glfwSetInputMode(@handle, mode, value)
319
+ end
320
+
321
+ # Callbacks
322
+ def on_key(&block)
323
+ cb = proc { |_win_ptr, key, scancode, action, mods|
324
+ block.call(self, key, scancode, ACTION_MAP[action] || action, mods)
325
+ }
326
+ register_and_set(:key, cb) { |c| API.glfwSetKeyCallback(@handle, c) }
327
+ end
328
+
329
+ def on_char(&block)
330
+ cb = proc { |_win_ptr, codepoint|
331
+ block.call(self, codepoint)
332
+ }
333
+ register_and_set(:char, cb) { |c| API.glfwSetCharCallback(@handle, c) }
334
+ end
335
+
336
+ def on_mouse_button(&block)
337
+ cb = proc { |_win_ptr, button, action, mods|
338
+ block.call(self, button, ACTION_MAP[action] || action, mods)
339
+ }
340
+ register_and_set(:mouse_button, cb) { |c| API.glfwSetMouseButtonCallback(@handle, c) }
341
+ end
342
+
343
+ def on_cursor_pos(&block)
344
+ cb = proc { |_win_ptr, x, y|
345
+ block.call(self, x, y)
346
+ }
347
+ register_and_set(:cursor_pos, cb) { |c| API.glfwSetCursorPosCallback(@handle, c) }
348
+ end
349
+
350
+ def on_cursor_enter(&block)
351
+ cb = proc { |_win_ptr, entered|
352
+ block.call(self, entered == GLFW_TRUE)
353
+ }
354
+ register_and_set(:cursor_enter, cb) { |c| API.glfwSetCursorEnterCallback(@handle, c) }
355
+ end
356
+
357
+ def on_scroll(&block)
358
+ cb = proc { |_win_ptr, xoffset, yoffset|
359
+ block.call(self, xoffset, yoffset)
360
+ }
361
+ register_and_set(:scroll, cb) { |c| API.glfwSetScrollCallback(@handle, c) }
362
+ end
363
+
364
+ def on_drop(&block)
365
+ cb = proc { |_win_ptr, count, paths_ptr|
366
+ paths = count.times.map { |i| paths_ptr.get_pointer(i * FFI::Pointer.size).read_string }
367
+ block.call(self, paths)
368
+ }
369
+ register_and_set(:drop, cb) { |c| API.glfwSetDropCallback(@handle, c) }
370
+ end
371
+
372
+ def on_resize(&block)
373
+ cb = proc { |_win_ptr, width, height|
374
+ block.call(self, width, height)
375
+ }
376
+ register_and_set(:resize, cb) { |c| API.glfwSetWindowSizeCallback(@handle, c) }
377
+ end
378
+
379
+ def on_close(&block)
380
+ cb = proc { |_win_ptr|
381
+ block.call(self)
382
+ }
383
+ register_and_set(:close, cb) { |c| API.glfwSetWindowCloseCallback(@handle, c) }
384
+ end
385
+
386
+ def on_refresh(&block)
387
+ cb = proc { |_win_ptr|
388
+ block.call(self)
389
+ }
390
+ register_and_set(:refresh, cb) { |c| API.glfwSetWindowRefreshCallback(@handle, c) }
391
+ end
392
+
393
+ def on_focus(&block)
394
+ cb = proc { |_win_ptr, focused|
395
+ block.call(self, focused == GLFW_TRUE)
396
+ }
397
+ register_and_set(:focus, cb) { |c| API.glfwSetWindowFocusCallback(@handle, c) }
398
+ end
399
+
400
+ def on_iconify(&block)
401
+ cb = proc { |_win_ptr, iconified|
402
+ block.call(self, iconified == GLFW_TRUE)
403
+ }
404
+ register_and_set(:iconify, cb) { |c| API.glfwSetWindowIconifyCallback(@handle, c) }
405
+ end
406
+
407
+ def on_maximize(&block)
408
+ cb = proc { |_win_ptr, maximized|
409
+ block.call(self, maximized == GLFW_TRUE)
410
+ }
411
+ register_and_set(:maximize, cb) { |c| API.glfwSetWindowMaximizeCallback(@handle, c) }
412
+ end
413
+
414
+ def on_framebuffer_resize(&block)
415
+ cb = proc { |_win_ptr, width, height|
416
+ block.call(self, width, height)
417
+ }
418
+ register_and_set(:framebuffer_resize, cb) { |c| API.glfwSetFramebufferSizeCallback(@handle, c) }
419
+ end
420
+
421
+ def on_content_scale(&block)
422
+ cb = proc { |_win_ptr, xscale, yscale|
423
+ block.call(self, xscale, yscale)
424
+ }
425
+ register_and_set(:content_scale, cb) { |c| API.glfwSetWindowContentScaleCallback(@handle, c) }
426
+ end
427
+
428
+ private
429
+
430
+ def register_and_set(type, cb)
431
+ GLFW.register_callback(type, @handle, cb)
432
+ yield cb
433
+ end
434
+ end
435
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rbconfig"
4
+
5
+ module GLFW
6
+ module Loader
7
+ SEARCH_PATHS = {
8
+ linux: %w[libglfw.so.3 libglfw.so],
9
+ darwin: %w[libglfw.3.dylib libglfw.dylib /opt/homebrew/lib/libglfw.3.dylib
10
+ /usr/local/lib/libglfw.3.dylib],
11
+ windows: %w[glfw3.dll glfw3_64.dll]
12
+ }.freeze
13
+
14
+ def self.load!
15
+ platform = detect_platform
16
+ paths = SEARCH_PATHS[platform].dup
17
+
18
+ if ENV["GLFW_LIB_PATH"]
19
+ paths.unshift(ENV["GLFW_LIB_PATH"])
20
+ end
21
+
22
+ lib_path = paths.find { |p| loadable?(p) }
23
+ raise GLFW::LibraryNotFoundError, <<~MSG unless lib_path
24
+ GLFW shared library not found.
25
+ Searched: #{paths.join(", ")}
26
+ Set GLFW_LIB_PATH environment variable to specify the library location.
27
+ MSG
28
+
29
+ lib_path
30
+ end
31
+
32
+ def self.detect_platform
33
+ case RbConfig::CONFIG["host_os"]
34
+ when /linux/i then :linux
35
+ when /darwin/i then :darwin
36
+ when /mswin|mingw|cygwin/i then :windows
37
+ else raise GLFW::Error, "Unsupported platform: #{RbConfig::CONFIG["host_os"]}"
38
+ end
39
+ end
40
+
41
+ def self.loadable?(path)
42
+ FFI::DynamicLibrary.open(path, FFI::DynamicLibrary::RTLD_LAZY)
43
+ true
44
+ rescue LoadError
45
+ false
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GLFW
4
+ VERSION = "0.1.0"
5
+ end
data/lib/glfw.rb ADDED
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ require_relative "glfw/version"
6
+ require_relative "glfw/errors"
7
+ require_relative "glfw/api/constants"
8
+ require_relative "glfw/loader"
9
+ require_relative "glfw/api/types"
10
+
11
+ module GLFW
12
+ module API
13
+ ffi_lib Loader.load!
14
+ end
15
+ end
16
+
17
+ require_relative "glfw/api/init"
18
+ require_relative "glfw/api/window"
19
+ require_relative "glfw/api/monitor"
20
+ require_relative "glfw/api/input"
21
+ require_relative "glfw/api/context"
22
+ require_relative "glfw/api/vulkan"
23
+ require_relative "glfw/api/v34"
24
+
25
+ GLFW::API.bind_v34_functions!
26
+
27
+ require_relative "glfw/high_level/video_mode"
28
+ require_relative "glfw/high_level/gamma_ramp"
29
+ require_relative "glfw/high_level/image"
30
+ require_relative "glfw/high_level/gamepad"
31
+ require_relative "glfw/high_level/cursor"
32
+ require_relative "glfw/high_level/joystick"
33
+ require_relative "glfw/high_level/monitor"
34
+ require_relative "glfw/high_level/window"
35
+
36
+ module GLFW
37
+ @callback_registry = {}
38
+ @window_map = {}
39
+ @user_error_callback = nil
40
+ @error_callback = nil
41
+
42
+ def self.init
43
+ result = API.glfwInit
44
+ raise InitError, "Failed to initialize GLFW" if result == GLFW_FALSE
45
+
46
+ @error_callback = proc { |code, desc|
47
+ if @user_error_callback
48
+ @user_error_callback.call(code, desc)
49
+ else
50
+ warn "[GLFW Error 0x#{code.to_s(16)}]: #{desc}"
51
+ end
52
+ }
53
+ API.glfwSetErrorCallback(@error_callback)
54
+ true
55
+ end
56
+
57
+ def self.terminate
58
+ @window_map.values.each do |win|
59
+ warn "[GLFW] Window '#{win.title}' was not destroyed before terminate"
60
+ end
61
+ @window_map.clear
62
+ @callback_registry.clear
63
+ API.glfwTerminate
64
+ end
65
+
66
+ def self.version
67
+ major = FFI::MemoryPointer.new(:int)
68
+ minor = FFI::MemoryPointer.new(:int)
69
+ rev = FFI::MemoryPointer.new(:int)
70
+ API.glfwGetVersion(major, minor, rev)
71
+ [major.read_int, minor.read_int, rev.read_int]
72
+ end
73
+
74
+ def self.version_at_least?(maj, min)
75
+ v = version
76
+ v[0] > maj || (v[0] == maj && v[1] >= min)
77
+ end
78
+
79
+ def self.poll_events
80
+ API.glfwPollEvents
81
+ end
82
+
83
+ def self.wait_events(timeout: nil)
84
+ if timeout
85
+ API.glfwWaitEventsTimeout(timeout.to_f)
86
+ else
87
+ API.glfwWaitEvents
88
+ end
89
+ end
90
+
91
+ def self.post_empty_event
92
+ API.glfwPostEmptyEvent
93
+ end
94
+
95
+ def self.time
96
+ API.glfwGetTime
97
+ end
98
+
99
+ def self.time=(t)
100
+ API.glfwSetTime(t.to_f)
101
+ end
102
+
103
+ def self.clipboard
104
+ API.glfwGetClipboardString(nil)
105
+ end
106
+
107
+ def self.clipboard=(text)
108
+ API.glfwSetClipboardString(nil, text)
109
+ end
110
+
111
+ def self.on_error(&block)
112
+ @user_error_callback = block
113
+ end
114
+
115
+ def self.platform
116
+ PLATFORM_MAP[API.glfwGetPlatform]
117
+ end
118
+
119
+ def self.platform_supported?(platform_id)
120
+ API.glfwPlatformSupported(platform_id) == GLFW_TRUE
121
+ end
122
+
123
+ def self.register_callback(type, handle, proc_obj)
124
+ key = handle ? [type, handle.address] : [type, nil]
125
+ @callback_registry[key] = proc_obj
126
+ end
127
+
128
+ def self.unregister_callbacks(handle)
129
+ @callback_registry.delete_if { |k, _| k[1] == handle.address }
130
+ end
131
+
132
+ def self.register_window(window)
133
+ @window_map[window.handle.address] = window
134
+ end
135
+
136
+ def self.unregister_window(window)
137
+ @window_map.delete(window.handle.address)
138
+ end
139
+
140
+ def self.window_for(handle)
141
+ @window_map[handle.address]
142
+ end
143
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: glfw-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yudai Takada
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: ffi
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.15'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.15'
26
+ description: Pure Ruby FFI bindings for the GLFW library, providing both low-level
27
+ C API access and high-level Ruby OOP interface for OpenGL/Vulkan window, context,
28
+ and input management.
29
+ email:
30
+ - t.yudai92@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - examples/01_minimal_window.rb
39
+ - examples/02_input_callbacks.rb
40
+ - examples/03_window_attributes.rb
41
+ - examples/04_monitor_info.rb
42
+ - examples/05_custom_cursor_and_icon.rb
43
+ - examples/06_gamepad_inspector.rb
44
+ - examples/07_glfw_34_features.rb
45
+ - examples/example_runtime.rb
46
+ - lib/glfw.rb
47
+ - lib/glfw/api/constants.rb
48
+ - lib/glfw/api/context.rb
49
+ - lib/glfw/api/init.rb
50
+ - lib/glfw/api/input.rb
51
+ - lib/glfw/api/monitor.rb
52
+ - lib/glfw/api/types.rb
53
+ - lib/glfw/api/v34.rb
54
+ - lib/glfw/api/vulkan.rb
55
+ - lib/glfw/api/window.rb
56
+ - lib/glfw/errors.rb
57
+ - lib/glfw/high_level/cursor.rb
58
+ - lib/glfw/high_level/gamepad.rb
59
+ - lib/glfw/high_level/gamma_ramp.rb
60
+ - lib/glfw/high_level/image.rb
61
+ - lib/glfw/high_level/joystick.rb
62
+ - lib/glfw/high_level/monitor.rb
63
+ - lib/glfw/high_level/video_mode.rb
64
+ - lib/glfw/high_level/window.rb
65
+ - lib/glfw/loader.rb
66
+ - lib/glfw/version.rb
67
+ homepage: https://github.com/ydah/glfw-ruby
68
+ licenses:
69
+ - MIT
70
+ metadata:
71
+ homepage_uri: https://github.com/ydah/glfw-ruby
72
+ source_code_uri: https://github.com/ydah/glfw-ruby
73
+ changelog_uri: https://github.com/ydah/glfw-ruby/blob/main/CHANGELOG.md
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 3.1.0
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 4.0.6
89
+ specification_version: 4
90
+ summary: Complete Ruby FFI bindings for GLFW 3.3/3.4
91
+ test_files: []