imgui-bindings 0.0.1
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 +256 -0
- data/LICENSE.txt +21 -0
- data/README.md +90 -0
- data/lib/imgui.dll +0 -0
- data/lib/imgui.dylib +0 -0
- data/lib/imgui.rb +5414 -0
- data/lib/imgui_debug.dll +0 -0
- data/lib/imgui_debug.dylib +0 -0
- data/lib/imgui_impl_glfw.rb +240 -0
- data/lib/imgui_impl_opengl2.rb +213 -0
- data/lib/imgui_impl_opengl3.rb +513 -0
- data/lib/imgui_impl_sdl2.rb +296 -0
- data/lib/imgui_impl_sdlrenderer.rb +201 -0
- metadata +58 -0
@@ -0,0 +1,296 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'sdl2'
|
3
|
+
require_relative 'imgui'
|
4
|
+
|
5
|
+
module ImGui
|
6
|
+
|
7
|
+
class ImGui_ImplSDL2_Data < FFI::Struct
|
8
|
+
layout(
|
9
|
+
:Window, :pointer,
|
10
|
+
:Time, :uint64,
|
11
|
+
:MousePressed, [:bool, 3],
|
12
|
+
:MouseCursors, [:pointer, ImGuiMouseCursor_COUNT],
|
13
|
+
:ClipboardTextData, :pointer,
|
14
|
+
:MouseCanUseGlobalState, :bool
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.ImGui_ImplSDL2_GetBackendData()
|
19
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
20
|
+
return ImGui_ImplSDL2_Data.new(io[:BackendPlatformUserData])
|
21
|
+
end
|
22
|
+
|
23
|
+
@@g_Window = nil # SDL_Window*
|
24
|
+
@@g_Time = 0.0 # UInt64
|
25
|
+
@@g_BackendPlatformName = FFI::MemoryPointer.from_string("imgui_impl_sdl")
|
26
|
+
@@g_BackendPlatformUserData = nil
|
27
|
+
|
28
|
+
# [TODO] Support ClipboardText
|
29
|
+
# g_ClipboardTextData
|
30
|
+
# ImplSDL2_GetClipboardText
|
31
|
+
# ImplSDL2_SetClipboardText
|
32
|
+
|
33
|
+
# [TODO] SDL_MOUSE
|
34
|
+
def self.get_sdl2_mousebit(x); return (1 << ((x)-1)); end
|
35
|
+
|
36
|
+
# [TODO] #define KMOD_CTRL, #define KMOD_SHIFT, #define KMOD_ALT and #define KMOD_GUI
|
37
|
+
KMOD_CTRL = SDL2::KMOD_LCTRL|SDL2::KMOD_RCTRL
|
38
|
+
KMOD_SHIFT = SDL2::KMOD_LSHIFT|SDL2::KMOD_RSHIFT
|
39
|
+
KMOD_ALT = SDL2::KMOD_LALT|SDL2::KMOD_RALT
|
40
|
+
KMOD_GUI = SDL2::KMOD_LGUI|SDL2::KMOD_RGUI
|
41
|
+
|
42
|
+
# [INTERNAL]
|
43
|
+
def self.ImplSDL2_UpdateMousePosAndButtons()
|
44
|
+
# Update buttons
|
45
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
46
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
47
|
+
window = bd[:Window]
|
48
|
+
|
49
|
+
# Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
50
|
+
if io[:WantSetMousePos]
|
51
|
+
SDL2::SDL_WarpMouseInWindow(window, io[:MousePos][:x].to_i, io[:MousePos][:y].to_i)
|
52
|
+
else
|
53
|
+
io[:MousePos][:x] = -Float::MAX
|
54
|
+
io[:MousePos][:y] = -Float::MAX
|
55
|
+
end
|
56
|
+
|
57
|
+
mx = FFI::MemoryPointer.new(:int)
|
58
|
+
my = FFI::MemoryPointer.new(:int)
|
59
|
+
mouse_buttons = SDL2::SDL_GetMouseState(mx, my)
|
60
|
+
io[:MouseDown][0] = bd[:MousePressed][0] || (mouse_buttons & get_sdl2_mousebit(SDL2::SDL_BUTTON_LEFT)) != 0 # If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
|
61
|
+
io[:MouseDown][1] = bd[:MousePressed][1] || (mouse_buttons & get_sdl2_mousebit(SDL2::SDL_BUTTON_RIGHT)) != 0
|
62
|
+
io[:MouseDown][2] = bd[:MousePressed][2] || (mouse_buttons & get_sdl2_mousebit(SDL2::SDL_BUTTON_MIDDLE)) != 0
|
63
|
+
bd[:MousePressed][0] = bd[:MousePressed][1] = bd[:MousePressed][2] = false
|
64
|
+
|
65
|
+
focused_window = SDL2::SDL_GetKeyboardFocus()
|
66
|
+
hover_window = nil
|
67
|
+
mouse_window = nil
|
68
|
+
if defined?(SDL2::SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)
|
69
|
+
hovered_window = SDL_GetMouseFocus() # This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH enabled.
|
70
|
+
mouse_window = (window == focused_window || window == hovered_window) ? window : nil
|
71
|
+
else
|
72
|
+
mouse_window = (window == focused_window) ? window : nil
|
73
|
+
end
|
74
|
+
if mouse_window != nil
|
75
|
+
if bd[:MouseCanUseGlobalState]
|
76
|
+
# SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?)
|
77
|
+
# The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally.
|
78
|
+
# Won't use this workaround on SDL backends that have no global mouse position, like Wayland or RPI
|
79
|
+
wx = FFI::MemoryPointer.new(:int)
|
80
|
+
wy = FFI::MemoryPointer.new(:int)
|
81
|
+
SDL2::SDL_GetWindowPosition(focused_window, wx, wy)
|
82
|
+
SDL2::SDL_GetGlobalMouseState(mx, my)
|
83
|
+
io[:MousePos][:x] = mx.read(:int).to_f - wx.read(:int).to_f
|
84
|
+
io[:MousePos][:y] = my.read(:int).to_f - wy.read(:int).to_f
|
85
|
+
else
|
86
|
+
io[:MousePos][:x] = mx.read(:int).to_f
|
87
|
+
io[:MousePos][:y] = my.read(:int).to_f
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor.
|
92
|
+
# The function is only supported from SDL 2.0.4 (released Jan 2016)
|
93
|
+
any_mouse_button_down = ImGui::IsAnyMouseDown()
|
94
|
+
SDL2::SDL_CaptureMouse(any_mouse_button_down ? SDL2::SDL_TRUE : SDL2::SDL_FALSE)
|
95
|
+
|
96
|
+
# [TODO]
|
97
|
+
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.ImplSDL2_UpdateMouseCursor()
|
101
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
102
|
+
return if (io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange)
|
103
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
104
|
+
|
105
|
+
imgui_cursor = ImGui::GetMouseCursor()
|
106
|
+
if io[:MouseDrawCursor] || imgui_cursor == ImGuiMouseCursor_None
|
107
|
+
# Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
108
|
+
SDL2::SDL_ShowCursor(SDL2::SDL_FALSE)
|
109
|
+
else
|
110
|
+
# Show OS mouse cursor
|
111
|
+
SDL2::SDL_SetCursor(bd[:MouseCursors][imgui_cursor] ? bd[:MouseCursors][imgui_cursor] : bd[:MouseCursors][ImGuiMouseCursor_Arrow])
|
112
|
+
SDL2::SDL_ShowCursor(SDL2::SDL_TRUE)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
#
|
117
|
+
# [TODO] Support ImplSDL2_UpdateGamepads
|
118
|
+
#
|
119
|
+
|
120
|
+
def self.ImplSDL2_Shutdown()
|
121
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
122
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
123
|
+
|
124
|
+
# [TODO] Destroy last known clipboard data
|
125
|
+
|
126
|
+
@@g_Window = nil
|
127
|
+
ImGuiMouseCursor_COUNT.times do |cursor_n|
|
128
|
+
SDL2::SDL_FreeCursor(bd[:MouseCursors][cursor_n])
|
129
|
+
bd[:MouseCursors][cursor_n] = nil
|
130
|
+
end
|
131
|
+
@@g_BackendPlatformUserData = nil
|
132
|
+
end
|
133
|
+
|
134
|
+
def self.ImplSDL2_NewFrame()
|
135
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
136
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
137
|
+
|
138
|
+
unless io[:Fonts].IsBuilt()
|
139
|
+
puts "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."
|
140
|
+
end
|
141
|
+
|
142
|
+
# Setup display size (every frame to accommodate for window resizing)
|
143
|
+
w = ' ' * 4
|
144
|
+
h = ' ' * 4
|
145
|
+
display_w = ' ' * 4
|
146
|
+
display_h = ' ' * 4
|
147
|
+
SDL2::SDL_GetWindowSize(bd[:Window], w, h)
|
148
|
+
SDL2::SDL_GL_GetDrawableSize(bd[:Window], display_w, display_h)
|
149
|
+
|
150
|
+
w = w.unpack1('L')
|
151
|
+
h = h.unpack1('L')
|
152
|
+
display_size = ImVec2.new
|
153
|
+
display_size[:x] = w.to_f
|
154
|
+
display_size[:y] = h.to_f
|
155
|
+
io[:DisplaySize] = display_size
|
156
|
+
|
157
|
+
if w > 0 && h > 0
|
158
|
+
fb_scale = ImVec2.new
|
159
|
+
fb_scale[:x] = display_w.unpack1('L').to_f / w
|
160
|
+
fb_scale[:y] = display_h.unpack1('L').to_f / h
|
161
|
+
io[:DisplayFramebufferScale] = fb_scale
|
162
|
+
end
|
163
|
+
|
164
|
+
# Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
165
|
+
frequency = SDL2::SDL_GetPerformanceFrequency()
|
166
|
+
current_time = SDL2::SDL_GetPerformanceCounter()
|
167
|
+
|
168
|
+
io[:DeltaTime] = @@g_Time > 0 ? ((current_time - @@g_Time).to_f / frequency) : (1.0/60.0)
|
169
|
+
@@g_Time = current_time
|
170
|
+
|
171
|
+
ImplSDL2_UpdateMousePosAndButtons()
|
172
|
+
ImplSDL2_UpdateMouseCursor()
|
173
|
+
|
174
|
+
# [TODO] update gamepads
|
175
|
+
end
|
176
|
+
|
177
|
+
# You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
178
|
+
# - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
179
|
+
# - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
180
|
+
# Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
181
|
+
# If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
|
182
|
+
def self.ImplSDL2_ProcessEvent(event)
|
183
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
184
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
185
|
+
|
186
|
+
case event[:type]
|
187
|
+
|
188
|
+
when SDL2::SDL_MOUSEWHEEL
|
189
|
+
io[:MouseWheelH] += 1 if (event[:wheel][:x] > 0)
|
190
|
+
io[:MouseWheelH] -= 1 if (event[:wheel][:x] < 0)
|
191
|
+
io[:MouseWheel] += 1 if (event[:wheel][:y] > 0)
|
192
|
+
io[:MouseWheel] -= 1 if (event[:wheel][:y] < 0)
|
193
|
+
return true
|
194
|
+
|
195
|
+
when SDL2::SDL_MOUSEBUTTONDOWN
|
196
|
+
bd[:MousePressed][0] = true if event[:button][:button] == SDL2::SDL_BUTTON_LEFT
|
197
|
+
bd[:MousePressed][1] = true if event[:button][:button] == SDL2::SDL_BUTTON_RIGHT
|
198
|
+
bd[:MousePressed][2] = true if event[:button][:button] == SDL2::SDL_BUTTON_MIDDLE
|
199
|
+
return true
|
200
|
+
|
201
|
+
when SDL2::SDL_TEXTINPUT
|
202
|
+
io.AddInputCharactersUTF8(event[:text][:text])
|
203
|
+
return true
|
204
|
+
|
205
|
+
when SDL2::SDL_KEYDOWN, SDL2::SDL_KEYUP
|
206
|
+
key = event[:key][:keysym][:scancode]
|
207
|
+
# IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
|
208
|
+
io[:KeysDown][key] = (event[:type] == SDL2::SDL_KEYDOWN)
|
209
|
+
io[:KeyShift] = ((SDL2::SDL_GetModState() & KMOD_SHIFT) != 0)
|
210
|
+
io[:KeyCtrl] = ((SDL2::SDL_GetModState() & KMOD_CTRL) != 0)
|
211
|
+
io[:KeyAlt] = ((SDL2::SDL_GetModState() & KMOD_ALT) != 0)
|
212
|
+
io[:KeySuper] = ((SDL2::SDL_GetModState() & KMOD_GUI) != 0) # [TODO] io.KeySuper = false on _WIN32
|
213
|
+
return true
|
214
|
+
end
|
215
|
+
|
216
|
+
return false
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.ImplSDL2_Init(window)
|
220
|
+
|
221
|
+
@@g_Window = window
|
222
|
+
@@g_Time = 0
|
223
|
+
|
224
|
+
@@g_BackendPlatformUserData = ImGui_ImplSDL2_Data.new
|
225
|
+
@@g_BackendPlatformUserData[:Window] = window
|
226
|
+
|
227
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
228
|
+
|
229
|
+
io[:BackendPlatformUserData] = @@g_BackendPlatformUserData
|
230
|
+
io[:BackendPlatformName] = @@g_BackendPlatformName
|
231
|
+
io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors # We can honor GetMouseCursor() values (optional)
|
232
|
+
io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos # We can honor io.WantSetMousePos requests (optional, rarely used)
|
233
|
+
|
234
|
+
# Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
|
235
|
+
io[:KeyMap][ImGuiKey_Tab] = SDL2::SDL_SCANCODE_TAB
|
236
|
+
io[:KeyMap][ImGuiKey_LeftArrow] = SDL2::SDL_SCANCODE_LEFT
|
237
|
+
io[:KeyMap][ImGuiKey_RightArrow] = SDL2::SDL_SCANCODE_RIGHT
|
238
|
+
io[:KeyMap][ImGuiKey_UpArrow] = SDL2::SDL_SCANCODE_UP
|
239
|
+
io[:KeyMap][ImGuiKey_DownArrow] = SDL2::SDL_SCANCODE_DOWN
|
240
|
+
io[:KeyMap][ImGuiKey_PageUp] = SDL2::SDL_SCANCODE_PAGEUP
|
241
|
+
io[:KeyMap][ImGuiKey_PageDown] = SDL2::SDL_SCANCODE_PAGEDOWN
|
242
|
+
io[:KeyMap][ImGuiKey_Home] = SDL2::SDL_SCANCODE_HOME
|
243
|
+
io[:KeyMap][ImGuiKey_End] = SDL2::SDL_SCANCODE_END
|
244
|
+
io[:KeyMap][ImGuiKey_Insert] = SDL2::SDL_SCANCODE_INSERT
|
245
|
+
io[:KeyMap][ImGuiKey_Delete] = SDL2::SDL_SCANCODE_DELETE
|
246
|
+
io[:KeyMap][ImGuiKey_Backspace] = SDL2::SDL_SCANCODE_BACKSPACE
|
247
|
+
io[:KeyMap][ImGuiKey_Space] = SDL2::SDL_SCANCODE_SPACE
|
248
|
+
io[:KeyMap][ImGuiKey_Enter] = SDL2::SDL_SCANCODE_RETURN
|
249
|
+
io[:KeyMap][ImGuiKey_Escape] = SDL2::SDL_SCANCODE_ESCAPE
|
250
|
+
io[:KeyMap][ImGuiKey_KeyPadEnter] = SDL2::SDL_SCANCODE_RETURN2
|
251
|
+
io[:KeyMap][ImGuiKey_A] = SDL2::SDL_SCANCODE_A
|
252
|
+
io[:KeyMap][ImGuiKey_C] = SDL2::SDL_SCANCODE_C
|
253
|
+
io[:KeyMap][ImGuiKey_V] = SDL2::SDL_SCANCODE_V
|
254
|
+
io[:KeyMap][ImGuiKey_X] = SDL2::SDL_SCANCODE_X
|
255
|
+
io[:KeyMap][ImGuiKey_Y] = SDL2::SDL_SCANCODE_Y
|
256
|
+
io[:KeyMap][ImGuiKey_Z] = SDL2::SDL_SCANCODE_Z
|
257
|
+
|
258
|
+
# [TODO] Support ClipboardText
|
259
|
+
|
260
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
261
|
+
|
262
|
+
bd[:MouseCursors][ImGuiMouseCursor_Arrow] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_ARROW)
|
263
|
+
bd[:MouseCursors][ImGuiMouseCursor_TextInput] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_IBEAM)
|
264
|
+
bd[:MouseCursors][ImGuiMouseCursor_ResizeAll] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZEALL)
|
265
|
+
bd[:MouseCursors][ImGuiMouseCursor_ResizeNS] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZENS)
|
266
|
+
bd[:MouseCursors][ImGuiMouseCursor_ResizeEW] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZEWE)
|
267
|
+
bd[:MouseCursors][ImGuiMouseCursor_ResizeNESW] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZENESW)
|
268
|
+
bd[:MouseCursors][ImGuiMouseCursor_ResizeNWSE] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_SIZENWSE)
|
269
|
+
bd[:MouseCursors][ImGuiMouseCursor_Hand] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_HAND)
|
270
|
+
bd[:MouseCursors][ImGuiMouseCursor_NotAllowed] = SDL2::SDL_CreateSystemCursor(SDL2::SDL_SYSTEM_CURSOR_NO)
|
271
|
+
|
272
|
+
=begin
|
273
|
+
#ifdef _WIN32
|
274
|
+
SDL_SysWMinfo info;
|
275
|
+
SDL_VERSION(&info.version);
|
276
|
+
if (SDL_GetWindowWMInfo(window, &info))
|
277
|
+
io.ImeWindowHandle = info.info.win.window;
|
278
|
+
#else
|
279
|
+
=end
|
280
|
+
|
281
|
+
=begin
|
282
|
+
sdl_backend = SDL_GetCurrentVideoDriver().read_string
|
283
|
+
global_mouse_whitelist = [ "windows", "cocoa", "x11", "DIVE", "VMAN" ]
|
284
|
+
bd[:MouseCanUseGlobalState] = false
|
285
|
+
global_mouse_whitelist.each do |elem|
|
286
|
+
bd[:MouseCanUseGlobalState] = true if sdl_backend == elem
|
287
|
+
end
|
288
|
+
=end
|
289
|
+
if defined?(SDL2::SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH)
|
290
|
+
SDL_SetHint(SDL2::SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")
|
291
|
+
end
|
292
|
+
|
293
|
+
return true
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'sdl2'
|
3
|
+
require_relative 'imgui'
|
4
|
+
|
5
|
+
module ImGui
|
6
|
+
|
7
|
+
class ImGui_ImplSDLRenderer_Data < FFI::Struct
|
8
|
+
layout(
|
9
|
+
:SDLRenderer, :pointer,
|
10
|
+
:FontTexture, :pointer
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.ImGui_ImplSDLRenderer_GetBackendData()
|
15
|
+
if ImGui::GetCurrentContext() != nil
|
16
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
17
|
+
instance = ImGui_ImplSDLRenderer_Data.new(io[:BackendRendererUserData])
|
18
|
+
return instance
|
19
|
+
else
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@@g_BackendRendererName = FFI::MemoryPointer.from_string("imgui_impl_sdlrenderer")
|
25
|
+
@@g_BackendRendererUserData = nil
|
26
|
+
|
27
|
+
def self.ImplSDLRenderer_Init(renderer)
|
28
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
29
|
+
|
30
|
+
# Setup backend capabilities flags
|
31
|
+
|
32
|
+
io[:BackendRendererName] = @@g_BackendRendererName
|
33
|
+
|
34
|
+
@@g_BackendRendererUserData = ImGui_ImplSDLRenderer_Data.new
|
35
|
+
@@g_BackendRendererUserData[:SDLRenderer] = renderer
|
36
|
+
@@g_BackendRendererUserData[:FontTexture] = nil
|
37
|
+
io[:BackendRendererUserData] = @@g_BackendRendererUserData
|
38
|
+
|
39
|
+
io[:BackendFlags] |= ImGuiBackendFlags_RendererHasVtxOffset # We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
40
|
+
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.ImplSDLRenderer_Shutdown()
|
45
|
+
ImplSDLRenderer_DestroyDeviceObjects()
|
46
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
47
|
+
io[:BackendRendererName] = nil
|
48
|
+
io[:BackendRendererUserData] = nil
|
49
|
+
@@g_BackendRendererUserData = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# [Internal]
|
53
|
+
def self.ImplSDLRenderer_SetupRenderState()
|
54
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
55
|
+
|
56
|
+
# Clear out any viewports and cliprect set by the user
|
57
|
+
# FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
|
58
|
+
SDL_RenderSetViewport(bd[:SDLRenderer], nil)
|
59
|
+
SDL_RenderSetClipRect(bd[:SDLRenderer], nil)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.ImplSDLRenderer_NewFrame()
|
63
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
64
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
65
|
+
ImGui::ImplSDLRenderer_CreateDeviceObjects() if bd[:FontTexture] == nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.ImplSDLRenderer_RenderDrawData(draw_data_raw)
|
69
|
+
draw_data = ImDrawData.new(draw_data_raw)
|
70
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
71
|
+
|
72
|
+
# If there's a scale factor set by the user, use that instead
|
73
|
+
# If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
74
|
+
# to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
75
|
+
rsx = FFI::MemoryPointer.new :float
|
76
|
+
rsy = FFI::MemoryPointer.new :float
|
77
|
+
SDL_RenderGetScale(bd[:SDLRenderer], rsx, rsy)
|
78
|
+
render_scale = ImVec2.create(0, 0)
|
79
|
+
render_scale[:x] = (rsx.read_float() == 1.0) ? draw_data[:FramebufferScale][:x] : 1.0
|
80
|
+
render_scale[:y] = (rsy.read_float() == 1.0) ? draw_data[:FramebufferScale][:y] : 1.0
|
81
|
+
|
82
|
+
# Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
83
|
+
fb_width = (draw_data[:DisplaySize][:x] * render_scale[:x]).to_i
|
84
|
+
fb_height = (draw_data[:DisplaySize][:y] * render_scale[:y]).to_i
|
85
|
+
return if fb_width == 0 || fb_height == 0
|
86
|
+
|
87
|
+
# Backup SDL_Renderer state that will be modified to restore it afterwards
|
88
|
+
oldViewport = SDL_Rect.new
|
89
|
+
oldClipEnabled = FFI::MemoryPointer.new :bool
|
90
|
+
oldClipRect = SDL_Rect.new
|
91
|
+
|
92
|
+
oldClipEnabled = (SDL_RenderIsClipEnabled(bd[:SDLRenderer]) == SDL_TRUE)
|
93
|
+
SDL_RenderGetViewport(bd[:SDLRenderer], oldViewport)
|
94
|
+
SDL_RenderGetClipRect(bd[:SDLRenderer], oldClipRect)
|
95
|
+
|
96
|
+
# Will project scissor/clipping rectangles into framebuffer space
|
97
|
+
clip_off = draw_data[:DisplayPos] # (0,0) unless using multi-viewports
|
98
|
+
clip_scale = render_scale
|
99
|
+
|
100
|
+
# Render command lists
|
101
|
+
ImplSDLRenderer_SetupRenderState()
|
102
|
+
draw_data[:CmdListsCount].times do |n|
|
103
|
+
cmd_list = ImDrawList.new((draw_data[:CmdLists].pointer + FFI.type_size(:pointer) * n).read_pointer)
|
104
|
+
vtx_buffer = cmd_list[:VtxBuffer][:Data] # const ImDrawVert*
|
105
|
+
idx_buffer = cmd_list[:IdxBuffer][:Data] # const ImDrawIdx*
|
106
|
+
|
107
|
+
cmd_list[:CmdBuffer][:Size].times do |cmd_i|
|
108
|
+
pcmd = ImDrawCmd.new(cmd_list[:CmdBuffer][:Data] + ImDrawCmd.size * cmd_i) # const ImDrawCmd*
|
109
|
+
if pcmd[:UserCallback] != nil
|
110
|
+
# [TODO] Handle user callback (Ref.: https://github.com/ffi/ffi/wiki/Callbacks )
|
111
|
+
|
112
|
+
# User callback, registered via ImDrawList::AddCallback()
|
113
|
+
# (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
114
|
+
# if pcmd[:UserCallback] == :ImDrawCallback_ResetRenderState
|
115
|
+
ImGui_ImplSDLRenderer_SetupRenderState()
|
116
|
+
# else
|
117
|
+
# pcmd[:UserCallback](cmd_list, pcmd)
|
118
|
+
# end
|
119
|
+
else
|
120
|
+
clip_min = ImVec2.create((pcmd[:ClipRect][:x] - clip_off[:x]) * clip_scale[:x], (pcmd[:ClipRect][:y] - clip_off[:y]) * clip_scale[:y])
|
121
|
+
clip_max = ImVec2.create((pcmd[:ClipRect][:z] - clip_off[:x]) * clip_scale[:x], (pcmd[:ClipRect][:w] - clip_off[:y]) * clip_scale[:y])
|
122
|
+
|
123
|
+
clip_min[:x] = 0.0 if clip_min[:x] < 0.0
|
124
|
+
clip_min[:y] = 0.0 if clip_min[:y] < 0.0
|
125
|
+
clip_max[:x] = fb_width.to_f if clip_max[:x] > fb_width
|
126
|
+
clip_max[:y] = fb_height.to_f if clip_max[:y] > fb_height
|
127
|
+
next if (clip_max[:x] <= clip_min[:x] || clip_max[:y] <= clip_min[:y])
|
128
|
+
|
129
|
+
r = SDL_Rect.new
|
130
|
+
r[:x] = clip_min[:x].to_i
|
131
|
+
r[:y] = clip_min[:y].to_i
|
132
|
+
r[:w] = (clip_max[:x] - clip_min[:x]).to_i
|
133
|
+
r[:h] = (clip_max[:y] - clip_min[:y]).to_i
|
134
|
+
|
135
|
+
SDL_RenderSetClipRect(bd[:SDLRenderer], r.to_ptr)
|
136
|
+
|
137
|
+
xy = vtx_buffer + (pcmd[:VtxOffset] + ImDrawVert.offset_of(:pos))
|
138
|
+
uv = vtx_buffer + (pcmd[:VtxOffset] + ImDrawVert.offset_of(:uv))
|
139
|
+
color = vtx_buffer + (pcmd[:VtxOffset] + ImDrawVert.offset_of(:col))
|
140
|
+
|
141
|
+
SDL_RenderGeometryRaw(bd[:SDLRenderer], pcmd[:TextureId],
|
142
|
+
xy, ImDrawVert.size,
|
143
|
+
color, ImDrawVert.size,
|
144
|
+
uv, ImDrawVert.size,
|
145
|
+
cmd_list[:VtxBuffer][:Size] - pcmd[:VtxOffset],
|
146
|
+
idx_buffer + FFI.type_size(:ImDrawIdx) * pcmd[:IdxOffset], pcmd[:ElemCount], FFI.type_size(:ImDrawIdx)) # FFI.type_size(:ImDrawIdx) == FFI::Type::UINT16.size
|
147
|
+
|
148
|
+
# Restore modified SDL_Renderer state
|
149
|
+
SDL_RenderSetViewport(bd[:SDLRenderer], oldViewport)
|
150
|
+
SDL_RenderSetClipRect(bd[:SDLRenderer], oldClipEnabled ? oldClipRect : nil)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Called by Init/NewFrame/Shutdown
|
157
|
+
def self.ImplSDLRenderer_CreateFontsTexture()
|
158
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
159
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
160
|
+
|
161
|
+
# Build texture atlas
|
162
|
+
pixels = FFI::MemoryPointer.new :pointer
|
163
|
+
width = FFI::MemoryPointer.new :int
|
164
|
+
height = FFI::MemoryPointer.new :int
|
165
|
+
io[:Fonts].GetTexDataAsRGBA32(pixels, width, height, nil) # Load as RGBA 32-bits (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
166
|
+
|
167
|
+
# Upload texture to graphics system
|
168
|
+
bd[:FontTexture] = SDL_CreateTexture(bd[:SDLRenderer], SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width.read_int, height.read_int)
|
169
|
+
if bd[:FontTexture] == nil
|
170
|
+
SDL_Log("error creating texture")
|
171
|
+
return false
|
172
|
+
end
|
173
|
+
|
174
|
+
SDL_UpdateTexture(bd[:FontTexture], nil, pixels.read_pointer, 4 * width.read_int)
|
175
|
+
SDL_SetTextureBlendMode(bd[:FontTexture], SDL_BLENDMODE_BLEND)
|
176
|
+
|
177
|
+
# Store our identifier
|
178
|
+
io[:Fonts].SetTexID(bd[:FontTexture])
|
179
|
+
|
180
|
+
return true
|
181
|
+
end
|
182
|
+
|
183
|
+
def self.ImplSDLRenderer_DestroyFontsTexture()
|
184
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
185
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
186
|
+
if bd[:FontTexture] != nil
|
187
|
+
io[:Fonts].SetTexID(nil)
|
188
|
+
SDL_DestroyTexture(bd[:FontTexture])
|
189
|
+
bd[:FontTexture] = nil
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def self.ImplSDLRenderer_CreateDeviceObjects()
|
194
|
+
return ImGui::ImplSDLRenderer_CreateFontsTexture()
|
195
|
+
end
|
196
|
+
|
197
|
+
def self.ImplSDLRenderer_DestroyDeviceObjects()
|
198
|
+
ImGui::ImplSDLRenderer_DestroyFontsTexture()
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: imgui-bindings
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- vaiorabbit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-12-31 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: 'Ruby bindings for Dear ImGui.
|
14
|
+
|
15
|
+
'
|
16
|
+
email:
|
17
|
+
- vaiorabbit@gmail.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- ChangeLog
|
23
|
+
- LICENSE.txt
|
24
|
+
- README.md
|
25
|
+
- lib/imgui.dll
|
26
|
+
- lib/imgui.dylib
|
27
|
+
- lib/imgui.rb
|
28
|
+
- lib/imgui_debug.dll
|
29
|
+
- lib/imgui_debug.dylib
|
30
|
+
- lib/imgui_impl_glfw.rb
|
31
|
+
- lib/imgui_impl_opengl2.rb
|
32
|
+
- lib/imgui_impl_opengl3.rb
|
33
|
+
- lib/imgui_impl_sdl2.rb
|
34
|
+
- lib/imgui_impl_sdlrenderer.rb
|
35
|
+
homepage: https://github.com/vaiorabbit/ruby-imgui
|
36
|
+
licenses:
|
37
|
+
- Zlib
|
38
|
+
metadata: {}
|
39
|
+
post_install_message:
|
40
|
+
rdoc_options: []
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.6.0
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubygems_version: 3.3.3
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: Bindings for Dear ImGui
|
58
|
+
test_files: []
|