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.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +243 -0
- data/Rakefile +8 -0
- data/examples/01_minimal_window.rb +35 -0
- data/examples/02_input_callbacks.rb +56 -0
- data/examples/03_window_attributes.rb +116 -0
- data/examples/04_monitor_info.rb +52 -0
- data/examples/05_custom_cursor_and_icon.rb +93 -0
- data/examples/06_gamepad_inspector.rb +81 -0
- data/examples/07_glfw_34_features.rb +46 -0
- data/examples/example_runtime.rb +66 -0
- data/lib/glfw/api/constants.rb +403 -0
- data/lib/glfw/api/context.rb +11 -0
- data/lib/glfw/api/init.rb +13 -0
- data/lib/glfw/api/input.rb +46 -0
- data/lib/glfw/api/monitor.rb +21 -0
- data/lib/glfw/api/types.rb +96 -0
- data/lib/glfw/api/v34.rb +21 -0
- data/lib/glfw/api/vulkan.rb +11 -0
- data/lib/glfw/api/window.rb +53 -0
- data/lib/glfw/errors.rb +72 -0
- data/lib/glfw/high_level/cursor.rb +31 -0
- data/lib/glfw/high_level/gamepad.rb +43 -0
- data/lib/glfw/high_level/gamma_ramp.rb +32 -0
- data/lib/glfw/high_level/image.rb +27 -0
- data/lib/glfw/high_level/joystick.rb +69 -0
- data/lib/glfw/high_level/monitor.rb +104 -0
- data/lib/glfw/high_level/video_mode.rb +32 -0
- data/lib/glfw/high_level/window.rb +435 -0
- data/lib/glfw/loader.rb +48 -0
- data/lib/glfw/version.rb +5 -0
- data/lib/glfw.rb +143 -0
- metadata +91 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
module API
|
|
5
|
+
extend FFI::Library
|
|
6
|
+
|
|
7
|
+
typedef :pointer, :GLFWwindow
|
|
8
|
+
typedef :pointer, :GLFWmonitor
|
|
9
|
+
typedef :pointer, :GLFWcursor
|
|
10
|
+
typedef :pointer, :GLFWglproc
|
|
11
|
+
typedef :pointer, :GLFWvkproc
|
|
12
|
+
|
|
13
|
+
callback :GLFWallocatefun, [:size_t, :pointer], :pointer
|
|
14
|
+
callback :GLFWreallocatefun, [:pointer, :size_t, :pointer], :pointer
|
|
15
|
+
callback :GLFWdeallocatefun, [:pointer, :pointer], :void
|
|
16
|
+
|
|
17
|
+
class GLFWvidmode < FFI::Struct
|
|
18
|
+
layout :width, :int,
|
|
19
|
+
:height, :int,
|
|
20
|
+
:redBits, :int,
|
|
21
|
+
:greenBits, :int,
|
|
22
|
+
:blueBits, :int,
|
|
23
|
+
:refreshRate, :int
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class GLFWgammaramp < FFI::Struct
|
|
27
|
+
layout :red, :pointer,
|
|
28
|
+
:green, :pointer,
|
|
29
|
+
:blue, :pointer,
|
|
30
|
+
:size, :uint
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class GLFWimage < FFI::Struct
|
|
34
|
+
layout :width, :int,
|
|
35
|
+
:height, :int,
|
|
36
|
+
:pixels, :pointer
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class GLFWgamepadstate < FFI::Struct
|
|
40
|
+
layout :buttons, [:uchar, 15],
|
|
41
|
+
:axes, [:float, 6]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class GLFWallocator < FFI::Struct
|
|
45
|
+
layout :allocate, :GLFWallocatefun,
|
|
46
|
+
:reallocate, :GLFWreallocatefun,
|
|
47
|
+
:deallocate, :GLFWdeallocatefun,
|
|
48
|
+
:user, :pointer
|
|
49
|
+
|
|
50
|
+
def self.build(allocate:, reallocate:, deallocate:, user: nil)
|
|
51
|
+
allocator = new
|
|
52
|
+
allocator.allocate = allocate
|
|
53
|
+
allocator.reallocate = reallocate
|
|
54
|
+
allocator.deallocate = deallocate
|
|
55
|
+
allocator[:user] = user
|
|
56
|
+
allocator
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def allocate=(callback)
|
|
60
|
+
@allocate_callback = callback
|
|
61
|
+
self[:allocate] = callback
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def reallocate=(callback)
|
|
65
|
+
@reallocate_callback = callback
|
|
66
|
+
self[:reallocate] = callback
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def deallocate=(callback)
|
|
70
|
+
@deallocate_callback = callback
|
|
71
|
+
self[:deallocate] = callback
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
callback :GLFWerrorfun, [:int, :string], :void
|
|
76
|
+
callback :GLFWwindowposfun, [:GLFWwindow, :int, :int], :void
|
|
77
|
+
callback :GLFWwindowsizefun, [:GLFWwindow, :int, :int], :void
|
|
78
|
+
callback :GLFWwindowclosefun, [:GLFWwindow], :void
|
|
79
|
+
callback :GLFWwindowrefreshfun, [:GLFWwindow], :void
|
|
80
|
+
callback :GLFWwindowfocusfun, [:GLFWwindow, :int], :void
|
|
81
|
+
callback :GLFWwindowiconifyfun, [:GLFWwindow, :int], :void
|
|
82
|
+
callback :GLFWwindowmaximizefun, [:GLFWwindow, :int], :void
|
|
83
|
+
callback :GLFWframebuffersizefun, [:GLFWwindow, :int, :int], :void
|
|
84
|
+
callback :GLFWwindowcontentscalefun, [:GLFWwindow, :float, :float], :void
|
|
85
|
+
callback :GLFWmousebuttonfun, [:GLFWwindow, :int, :int, :int], :void
|
|
86
|
+
callback :GLFWcursorposfun, [:GLFWwindow, :double, :double], :void
|
|
87
|
+
callback :GLFWcursorenterfun, [:GLFWwindow, :int], :void
|
|
88
|
+
callback :GLFWscrollfun, [:GLFWwindow, :double, :double], :void
|
|
89
|
+
callback :GLFWkeyfun, [:GLFWwindow, :int, :int, :int, :int], :void
|
|
90
|
+
callback :GLFWcharfun, [:GLFWwindow, :uint], :void
|
|
91
|
+
callback :GLFWcharmodsfun, [:GLFWwindow, :uint, :int], :void
|
|
92
|
+
callback :GLFWdropfun, [:GLFWwindow, :int, :pointer], :void
|
|
93
|
+
callback :GLFWmonitorfun, [:GLFWmonitor, :int], :void
|
|
94
|
+
callback :GLFWjoystickfun, [:int, :int], :void
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/glfw/api/v34.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
module API
|
|
5
|
+
V34_FUNCTIONS = {
|
|
6
|
+
glfwGetPlatform: [[], :int],
|
|
7
|
+
glfwPlatformSupported: [[:int], :int],
|
|
8
|
+
glfwGetWindowTitle: [[:GLFWwindow], :string],
|
|
9
|
+
glfwInitAllocator: [[:pointer], :void],
|
|
10
|
+
glfwInitVulkanLoader: [[:GLFWvkproc], :void]
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
def self.bind_v34_functions!
|
|
14
|
+
V34_FUNCTIONS.each do |name, (args, ret)|
|
|
15
|
+
attach_function name, args, ret
|
|
16
|
+
rescue FFI::NotFoundError
|
|
17
|
+
define_singleton_method(name) { |*_| raise GLFW::NotSupportedError, "#{name} requires GLFW 3.4+" }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
module API
|
|
5
|
+
attach_function :glfwVulkanSupported, [], :int
|
|
6
|
+
attach_function :glfwGetRequiredInstanceExtensions, [:pointer], :pointer
|
|
7
|
+
attach_function :glfwGetInstanceProcAddress, [:pointer, :string], :GLFWvkproc
|
|
8
|
+
attach_function :glfwGetPhysicalDevicePresentationSupport, [:pointer, :pointer, :uint32], :int
|
|
9
|
+
attach_function :glfwCreateWindowSurface, [:pointer, :GLFWwindow, :pointer, :pointer], :int
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
module API
|
|
5
|
+
attach_function :glfwDefaultWindowHints, [], :void
|
|
6
|
+
attach_function :glfwWindowHint, [:int, :int], :void
|
|
7
|
+
attach_function :glfwWindowHintString, [:int, :string], :void
|
|
8
|
+
attach_function :glfwCreateWindow, [:int, :int, :string, :GLFWmonitor, :GLFWwindow], :GLFWwindow
|
|
9
|
+
attach_function :glfwDestroyWindow, [:GLFWwindow], :void
|
|
10
|
+
attach_function :glfwWindowShouldClose, [:GLFWwindow], :int
|
|
11
|
+
attach_function :glfwSetWindowShouldClose, [:GLFWwindow, :int], :void
|
|
12
|
+
attach_function :glfwSetWindowTitle, [:GLFWwindow, :string], :void
|
|
13
|
+
attach_function :glfwSetWindowIcon, [:GLFWwindow, :int, :pointer], :void
|
|
14
|
+
attach_function :glfwGetWindowPos, [:GLFWwindow, :pointer, :pointer], :void
|
|
15
|
+
attach_function :glfwSetWindowPos, [:GLFWwindow, :int, :int], :void
|
|
16
|
+
attach_function :glfwGetWindowSize, [:GLFWwindow, :pointer, :pointer], :void
|
|
17
|
+
attach_function :glfwSetWindowSize, [:GLFWwindow, :int, :int], :void
|
|
18
|
+
attach_function :glfwSetWindowSizeLimits, [:GLFWwindow, :int, :int, :int, :int], :void
|
|
19
|
+
attach_function :glfwSetWindowAspectRatio, [:GLFWwindow, :int, :int], :void
|
|
20
|
+
attach_function :glfwGetFramebufferSize, [:GLFWwindow, :pointer, :pointer], :void
|
|
21
|
+
attach_function :glfwGetWindowFrameSize, [:GLFWwindow, :pointer, :pointer, :pointer, :pointer], :void
|
|
22
|
+
attach_function :glfwGetWindowContentScale, [:GLFWwindow, :pointer, :pointer], :void
|
|
23
|
+
attach_function :glfwGetWindowOpacity, [:GLFWwindow], :float
|
|
24
|
+
attach_function :glfwSetWindowOpacity, [:GLFWwindow, :float], :void
|
|
25
|
+
attach_function :glfwIconifyWindow, [:GLFWwindow], :void
|
|
26
|
+
attach_function :glfwRestoreWindow, [:GLFWwindow], :void
|
|
27
|
+
attach_function :glfwMaximizeWindow, [:GLFWwindow], :void
|
|
28
|
+
attach_function :glfwShowWindow, [:GLFWwindow], :void
|
|
29
|
+
attach_function :glfwHideWindow, [:GLFWwindow], :void
|
|
30
|
+
attach_function :glfwFocusWindow, [:GLFWwindow], :void
|
|
31
|
+
attach_function :glfwRequestWindowAttention, [:GLFWwindow], :void
|
|
32
|
+
attach_function :glfwGetWindowMonitor, [:GLFWwindow], :GLFWmonitor
|
|
33
|
+
attach_function :glfwSetWindowMonitor, [:GLFWwindow, :GLFWmonitor, :int, :int, :int, :int, :int], :void
|
|
34
|
+
attach_function :glfwGetWindowAttrib, [:GLFWwindow, :int], :int
|
|
35
|
+
attach_function :glfwSetWindowAttrib, [:GLFWwindow, :int, :int], :void
|
|
36
|
+
attach_function :glfwSetWindowUserPointer, [:GLFWwindow, :pointer], :void
|
|
37
|
+
attach_function :glfwGetWindowUserPointer, [:GLFWwindow], :pointer
|
|
38
|
+
attach_function :glfwSetWindowPosCallback, [:GLFWwindow, :GLFWwindowposfun], :pointer
|
|
39
|
+
attach_function :glfwSetWindowSizeCallback, [:GLFWwindow, :GLFWwindowsizefun], :pointer
|
|
40
|
+
attach_function :glfwSetWindowCloseCallback, [:GLFWwindow, :GLFWwindowclosefun], :pointer
|
|
41
|
+
attach_function :glfwSetWindowRefreshCallback, [:GLFWwindow, :GLFWwindowrefreshfun], :pointer
|
|
42
|
+
attach_function :glfwSetWindowFocusCallback, [:GLFWwindow, :GLFWwindowfocusfun], :pointer
|
|
43
|
+
attach_function :glfwSetWindowIconifyCallback, [:GLFWwindow, :GLFWwindowiconifyfun], :pointer
|
|
44
|
+
attach_function :glfwSetWindowMaximizeCallback, [:GLFWwindow, :GLFWwindowmaximizefun], :pointer
|
|
45
|
+
attach_function :glfwSetFramebufferSizeCallback, [:GLFWwindow, :GLFWframebuffersizefun], :pointer
|
|
46
|
+
attach_function :glfwSetWindowContentScaleCallback, [:GLFWwindow, :GLFWwindowcontentscalefun], :pointer
|
|
47
|
+
attach_function :glfwPollEvents, [], :void
|
|
48
|
+
attach_function :glfwWaitEvents, [], :void
|
|
49
|
+
attach_function :glfwWaitEventsTimeout, [:double], :void
|
|
50
|
+
attach_function :glfwPostEmptyEvent, [], :void
|
|
51
|
+
attach_function :glfwSwapBuffers, [:GLFWwindow], :void
|
|
52
|
+
end
|
|
53
|
+
end
|
data/lib/glfw/errors.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
class LibraryNotFoundError < Error; end
|
|
6
|
+
class InitError < Error; end
|
|
7
|
+
class NotSupportedError < Error; end
|
|
8
|
+
|
|
9
|
+
class APIError < Error
|
|
10
|
+
attr_reader :code
|
|
11
|
+
|
|
12
|
+
def initialize(code, message)
|
|
13
|
+
@code = code
|
|
14
|
+
super("[GLFW #{error_name(code)}] #{message}")
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def error_name(code)
|
|
20
|
+
ERROR_CODE_NAMES[code] || "0x#{code.to_s(16).rjust(8, '0')}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
ERROR_CODE_NAMES = {
|
|
25
|
+
0x00010001 => "NOT_INITIALIZED",
|
|
26
|
+
0x00010002 => "NO_CURRENT_CONTEXT",
|
|
27
|
+
0x00010003 => "INVALID_ENUM",
|
|
28
|
+
0x00010004 => "INVALID_VALUE",
|
|
29
|
+
0x00010005 => "OUT_OF_MEMORY",
|
|
30
|
+
0x00010006 => "API_UNAVAILABLE",
|
|
31
|
+
0x00010007 => "VERSION_UNAVAILABLE",
|
|
32
|
+
0x00010008 => "PLATFORM_ERROR",
|
|
33
|
+
0x00010009 => "FORMAT_UNAVAILABLE",
|
|
34
|
+
0x0001000A => "NO_WINDOW_CONTEXT",
|
|
35
|
+
0x0001000B => "CURSOR_UNAVAILABLE",
|
|
36
|
+
0x0001000C => "FEATURE_UNAVAILABLE",
|
|
37
|
+
0x0001000D => "FEATURE_UNIMPLEMENTED",
|
|
38
|
+
0x0001000E => "PLATFORM_UNAVAILABLE"
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
class NotInitializedError < APIError; end
|
|
42
|
+
class NoCurrentContextError < APIError; end
|
|
43
|
+
class InvalidEnumError < APIError; end
|
|
44
|
+
class InvalidValueError < APIError; end
|
|
45
|
+
class OutOfMemoryError < APIError; end
|
|
46
|
+
class APIUnavailableError < APIError; end
|
|
47
|
+
class VersionUnavailableError < APIError; end
|
|
48
|
+
class PlatformError < APIError; end
|
|
49
|
+
class FormatUnavailableError < APIError; end
|
|
50
|
+
class NoWindowContextError < APIError; end
|
|
51
|
+
class CursorUnavailableError < APIError; end
|
|
52
|
+
class FeatureUnavailableError < APIError; end
|
|
53
|
+
class FeatureUnimplementedError < APIError; end
|
|
54
|
+
class PlatformUnavailableError < APIError; end
|
|
55
|
+
|
|
56
|
+
ERROR_CLASS_MAP = {
|
|
57
|
+
0x00010001 => NotInitializedError,
|
|
58
|
+
0x00010002 => NoCurrentContextError,
|
|
59
|
+
0x00010003 => InvalidEnumError,
|
|
60
|
+
0x00010004 => InvalidValueError,
|
|
61
|
+
0x00010005 => OutOfMemoryError,
|
|
62
|
+
0x00010006 => APIUnavailableError,
|
|
63
|
+
0x00010007 => VersionUnavailableError,
|
|
64
|
+
0x00010008 => PlatformError,
|
|
65
|
+
0x00010009 => FormatUnavailableError,
|
|
66
|
+
0x0001000A => NoWindowContextError,
|
|
67
|
+
0x0001000B => CursorUnavailableError,
|
|
68
|
+
0x0001000C => FeatureUnavailableError,
|
|
69
|
+
0x0001000D => FeatureUnimplementedError,
|
|
70
|
+
0x0001000E => PlatformUnavailableError
|
|
71
|
+
}.freeze
|
|
72
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class Cursor
|
|
5
|
+
attr_reader :handle
|
|
6
|
+
|
|
7
|
+
def initialize(handle)
|
|
8
|
+
@handle = handle
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.create(image, xhot, yhot)
|
|
12
|
+
img_struct = image.to_struct
|
|
13
|
+
handle = API.glfwCreateCursor(img_struct, xhot, yhot)
|
|
14
|
+
raise GLFW::Error, "Failed to create cursor" if handle.null?
|
|
15
|
+
|
|
16
|
+
new(handle)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.standard(shape)
|
|
20
|
+
handle = API.glfwCreateStandardCursor(shape)
|
|
21
|
+
raise GLFW::Error, "Failed to create standard cursor" if handle.null?
|
|
22
|
+
|
|
23
|
+
new(handle)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def destroy
|
|
27
|
+
API.glfwDestroyCursor(@handle)
|
|
28
|
+
@handle = nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class GamepadState
|
|
5
|
+
attr_reader :buttons, :axes
|
|
6
|
+
|
|
7
|
+
def initialize(buttons, axes)
|
|
8
|
+
@buttons = buttons
|
|
9
|
+
@axes = axes
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def button_pressed?(button)
|
|
13
|
+
@buttons[button] == GLFW_PRESS
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def axis_value(axis)
|
|
17
|
+
@axes[axis]
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Gamepad
|
|
22
|
+
def initialize(jid)
|
|
23
|
+
@jid = jid
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def name
|
|
27
|
+
API.glfwGetGamepadName(@jid)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def state
|
|
31
|
+
gs = API::GLFWgamepadstate.new
|
|
32
|
+
return nil unless API.glfwGetGamepadState(@jid, gs) == GLFW_TRUE
|
|
33
|
+
|
|
34
|
+
buttons = gs[:buttons].to_a
|
|
35
|
+
axes = gs[:axes].to_a
|
|
36
|
+
GamepadState.new(buttons, axes)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.update_mappings(string)
|
|
40
|
+
API.glfwUpdateGamepadMappings(string) == GLFW_TRUE
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class GammaRamp
|
|
5
|
+
attr_reader :red, :green, :blue, :size
|
|
6
|
+
|
|
7
|
+
def initialize(red, green, blue, size)
|
|
8
|
+
@red = red
|
|
9
|
+
@green = green
|
|
10
|
+
@blue = blue
|
|
11
|
+
@size = size
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.from_struct(ptr)
|
|
15
|
+
struct = API::GLFWgammaramp.new(ptr)
|
|
16
|
+
size = struct[:size]
|
|
17
|
+
red = struct[:red].read_array_of_uint16(size)
|
|
18
|
+
green = struct[:green].read_array_of_uint16(size)
|
|
19
|
+
blue = struct[:blue].read_array_of_uint16(size)
|
|
20
|
+
new(red, green, blue, size)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_struct
|
|
24
|
+
ramp = API::GLFWgammaramp.new
|
|
25
|
+
ramp[:size] = @size
|
|
26
|
+
ramp[:red] = FFI::MemoryPointer.new(:uint16, @size).tap { |p| p.write_array_of_uint16(@red) }
|
|
27
|
+
ramp[:green] = FFI::MemoryPointer.new(:uint16, @size).tap { |p| p.write_array_of_uint16(@green) }
|
|
28
|
+
ramp[:blue] = FFI::MemoryPointer.new(:uint16, @size).tap { |p| p.write_array_of_uint16(@blue) }
|
|
29
|
+
ramp
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class Image
|
|
5
|
+
attr_reader :width, :height, :pixels
|
|
6
|
+
|
|
7
|
+
def initialize(width, height, pixels)
|
|
8
|
+
@width = width
|
|
9
|
+
@height = height
|
|
10
|
+
@pixels = pixels
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.from_rgba(width, height, data)
|
|
14
|
+
pixels = FFI::MemoryPointer.new(:uchar, data.bytesize)
|
|
15
|
+
pixels.put_bytes(0, data)
|
|
16
|
+
new(width, height, pixels)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_struct
|
|
20
|
+
img = API::GLFWimage.new
|
|
21
|
+
img[:width] = @width
|
|
22
|
+
img[:height] = @height
|
|
23
|
+
img[:pixels] = @pixels
|
|
24
|
+
img
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class Joystick
|
|
5
|
+
attr_reader :jid
|
|
6
|
+
|
|
7
|
+
def initialize(jid)
|
|
8
|
+
@jid = jid
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.[](jid)
|
|
12
|
+
new(jid)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def present?
|
|
16
|
+
API.glfwJoystickPresent(@jid) == GLFW_TRUE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def name
|
|
20
|
+
API.glfwGetJoystickName(@jid)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def guid
|
|
24
|
+
API.glfwGetJoystickGUID(@jid)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def axes
|
|
28
|
+
count = FFI::MemoryPointer.new(:int)
|
|
29
|
+
ptr = API.glfwGetJoystickAxes(@jid, count)
|
|
30
|
+
return [] if ptr.null?
|
|
31
|
+
|
|
32
|
+
ptr.read_array_of_float(count.read_int)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def buttons
|
|
36
|
+
count = FFI::MemoryPointer.new(:int)
|
|
37
|
+
ptr = API.glfwGetJoystickButtons(@jid, count)
|
|
38
|
+
return [] if ptr.null?
|
|
39
|
+
|
|
40
|
+
ptr.read_array_of_uchar(count.read_int).map { |b| ACTION_MAP[b] || b }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def hats
|
|
44
|
+
count = FFI::MemoryPointer.new(:int)
|
|
45
|
+
ptr = API.glfwGetJoystickHats(@jid, count)
|
|
46
|
+
return [] if ptr.null?
|
|
47
|
+
|
|
48
|
+
ptr.read_array_of_uchar(count.read_int)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def gamepad?
|
|
52
|
+
API.glfwJoystickIsGamepad(@jid) == GLFW_TRUE
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def gamepad
|
|
56
|
+
return nil unless gamepad?
|
|
57
|
+
|
|
58
|
+
Gamepad.new(@jid)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.on_connect(&block)
|
|
62
|
+
cb = proc { |jid, event|
|
|
63
|
+
block.call(new(jid), event == GLFW_CONNECTED ? :connected : :disconnected)
|
|
64
|
+
}
|
|
65
|
+
GLFW.register_callback(:joystick, nil, cb)
|
|
66
|
+
API.glfwSetJoystickCallback(cb)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class Monitor
|
|
5
|
+
attr_reader :handle
|
|
6
|
+
|
|
7
|
+
def initialize(handle)
|
|
8
|
+
@handle = handle
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.all
|
|
12
|
+
count = FFI::MemoryPointer.new(:int)
|
|
13
|
+
ptr = API.glfwGetMonitors(count)
|
|
14
|
+
return [] if ptr.null?
|
|
15
|
+
|
|
16
|
+
n = count.read_int
|
|
17
|
+
ptr.read_array_of_pointer(n).map { |p| new(p) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.primary
|
|
21
|
+
handle = API.glfwGetPrimaryMonitor
|
|
22
|
+
return nil if handle.null?
|
|
23
|
+
|
|
24
|
+
new(handle)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def name
|
|
28
|
+
API.glfwGetMonitorName(@handle)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def position
|
|
32
|
+
x = FFI::MemoryPointer.new(:int)
|
|
33
|
+
y = FFI::MemoryPointer.new(:int)
|
|
34
|
+
API.glfwGetMonitorPos(@handle, x, y)
|
|
35
|
+
[x.read_int, y.read_int]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def workarea
|
|
39
|
+
x = FFI::MemoryPointer.new(:int)
|
|
40
|
+
y = FFI::MemoryPointer.new(:int)
|
|
41
|
+
w = FFI::MemoryPointer.new(:int)
|
|
42
|
+
h = FFI::MemoryPointer.new(:int)
|
|
43
|
+
API.glfwGetMonitorWorkarea(@handle, x, y, w, h)
|
|
44
|
+
{ x: x.read_int, y: y.read_int, width: w.read_int, height: h.read_int }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def physical_size
|
|
48
|
+
w = FFI::MemoryPointer.new(:int)
|
|
49
|
+
h = FFI::MemoryPointer.new(:int)
|
|
50
|
+
API.glfwGetMonitorPhysicalSize(@handle, w, h)
|
|
51
|
+
[w.read_int, h.read_int]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def content_scale
|
|
55
|
+
x = FFI::MemoryPointer.new(:float)
|
|
56
|
+
y = FFI::MemoryPointer.new(:float)
|
|
57
|
+
API.glfwGetMonitorContentScale(@handle, x, y)
|
|
58
|
+
[x.read_float, y.read_float]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def video_modes
|
|
62
|
+
count = FFI::MemoryPointer.new(:int)
|
|
63
|
+
ptr = API.glfwGetVideoModes(@handle, count)
|
|
64
|
+
return [] if ptr.null?
|
|
65
|
+
|
|
66
|
+
n = count.read_int
|
|
67
|
+
n.times.map do |i|
|
|
68
|
+
struct = API::GLFWvidmode.new(ptr + i * API::GLFWvidmode.size)
|
|
69
|
+
VideoMode.from_struct(struct)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def current_video_mode
|
|
74
|
+
ptr = API.glfwGetVideoMode(@handle)
|
|
75
|
+
return nil if ptr.null?
|
|
76
|
+
|
|
77
|
+
VideoMode.from_struct(API::GLFWvidmode.new(ptr))
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def gamma=(val)
|
|
81
|
+
API.glfwSetGamma(@handle, val.to_f)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def gamma_ramp
|
|
85
|
+
ptr = API.glfwGetGammaRamp(@handle)
|
|
86
|
+
return nil if ptr.null?
|
|
87
|
+
|
|
88
|
+
GammaRamp.from_struct(ptr)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def gamma_ramp=(ramp)
|
|
92
|
+
struct = ramp.to_struct
|
|
93
|
+
API.glfwSetGammaRamp(@handle, struct)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.on_connect(&block)
|
|
97
|
+
cb = proc { |monitor_ptr, event|
|
|
98
|
+
block.call(new(monitor_ptr), event == GLFW_CONNECTED ? :connected : :disconnected)
|
|
99
|
+
}
|
|
100
|
+
GLFW.register_callback(:monitor, nil, cb)
|
|
101
|
+
API.glfwSetMonitorCallback(cb)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module GLFW
|
|
4
|
+
class VideoMode
|
|
5
|
+
attr_reader :width, :height, :red_bits, :green_bits, :blue_bits, :refresh_rate
|
|
6
|
+
|
|
7
|
+
def initialize(width, height, red_bits, green_bits, blue_bits, refresh_rate)
|
|
8
|
+
@width = width
|
|
9
|
+
@height = height
|
|
10
|
+
@red_bits = red_bits
|
|
11
|
+
@green_bits = green_bits
|
|
12
|
+
@blue_bits = blue_bits
|
|
13
|
+
@refresh_rate = refresh_rate
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.from_struct(struct)
|
|
17
|
+
new(struct[:width], struct[:height], struct[:redBits],
|
|
18
|
+
struct[:greenBits], struct[:blueBits], struct[:refreshRate])
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def ==(other)
|
|
22
|
+
other.is_a?(VideoMode) &&
|
|
23
|
+
width == other.width && height == other.height &&
|
|
24
|
+
red_bits == other.red_bits && green_bits == other.green_bits &&
|
|
25
|
+
blue_bits == other.blue_bits && refresh_rate == other.refresh_rate
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
"#{width}x#{height}@#{refresh_rate}Hz (#{red_bits}/#{green_bits}/#{blue_bits})"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|