imgui-bindings 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|