imgui-bindings 0.1.10-arm64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +361 -0
- data/LICENSE.txt +21 -0
- data/README.md +119 -0
- data/lib/imgui.arm64.dylib +0 -0
- data/lib/imgui.rb +5817 -0
- data/lib/imgui_impl_glfw.rb +511 -0
- data/lib/imgui_impl_opengl2.rb +212 -0
- data/lib/imgui_impl_opengl3.rb +509 -0
- data/lib/imgui_impl_raylib.rb +454 -0
- data/lib/imgui_impl_sdl2.rb +409 -0
- data/lib/imgui_impl_sdlrenderer.rb +200 -0
- data/lib/imgui_internal.rb +49 -0
- data/lib/imnodes.arm64.dylib +0 -0
- data/lib/imnodes.rb +161 -0
- metadata +87 -0
@@ -0,0 +1,409 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'sdl2'
|
3
|
+
require_relative 'imgui'
|
4
|
+
|
5
|
+
module ImGui
|
6
|
+
|
7
|
+
@@g_BackendPlatformName = FFI::MemoryPointer.from_string("imgui_impl_sdl")
|
8
|
+
|
9
|
+
# ImGui::GetCurrentContext().address => ImGui_ImplSDL2_Data
|
10
|
+
@@g_BackendData = Hash.new
|
11
|
+
|
12
|
+
# [INTERNAL]
|
13
|
+
class ImGui_ImplSDL2_Data
|
14
|
+
attr_accessor :window, :renderer, :time, :mouseButtonsDown, :mouseCursors, :clipboardTextData, :mouseCanUseGlobalState
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@window = nil # SDL_Window*
|
18
|
+
@renderer = nil # SDL_Renderer*
|
19
|
+
@time = 0.0 # Uint64
|
20
|
+
@mouseButtonsDown = 0 # int
|
21
|
+
@mouseCursors = Array.new(ImGuiMouseCursor_COUNT) { 0 } # SDL_Cursor*
|
22
|
+
@clipboardTextData = nil # char*
|
23
|
+
@mouseCanUseGlobalState = false # bool
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
|
28
|
+
# It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
|
29
|
+
# FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
|
30
|
+
# FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
|
31
|
+
# [INTERNAL]
|
32
|
+
def self.ImGui_ImplSDL2_GetBackendData()
|
33
|
+
if ImGui::GetCurrentContext() != nil
|
34
|
+
@@g_BackendData[ImGui::GetCurrentContext().address]
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# [TODO] Support ClipboardText
|
41
|
+
# g_ClipboardTextData
|
42
|
+
# ImplSDL2_GetClipboardText
|
43
|
+
# ImplSDL2_SetClipboardText
|
44
|
+
|
45
|
+
# [INTERNAL]
|
46
|
+
def self.ImGui_ImplSDL2_GetClipboardText(user_data)
|
47
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
48
|
+
SDL.free(bd.clipboardTextData) if bd.clipboardTextData
|
49
|
+
bd.clipboardTextData = SDL.GetClipboardText()
|
50
|
+
return bd.clipboardTextData
|
51
|
+
end
|
52
|
+
|
53
|
+
# [INTERNAL]
|
54
|
+
def self.ImGui_ImplSDL2_SetClipboardText(user_data, text)
|
55
|
+
SDL.SetClipboardText(text)
|
56
|
+
end
|
57
|
+
|
58
|
+
# [INTERNAL]
|
59
|
+
def self.ImGui_ImplSDL2_KeyToImGuiKey(key)
|
60
|
+
case key
|
61
|
+
when SDL::SDLK_TAB then ImGuiKey_Tab
|
62
|
+
when SDL::SDLK_LEFT then ImGuiKey_LeftArrow
|
63
|
+
when SDL::SDLK_RIGHT then ImGuiKey_RightArrow
|
64
|
+
when SDL::SDLK_UP then ImGuiKey_UpArrow
|
65
|
+
when SDL::SDLK_DOWN then ImGuiKey_DownArrow
|
66
|
+
when SDL::SDLK_PAGEUP then ImGuiKey_PageUp
|
67
|
+
when SDL::SDLK_PAGEDOWN then ImGuiKey_PageDown
|
68
|
+
when SDL::SDLK_HOME then ImGuiKey_Home
|
69
|
+
when SDL::SDLK_END then ImGuiKey_End
|
70
|
+
when SDL::SDLK_INSERT then ImGuiKey_Insert
|
71
|
+
when SDL::SDLK_DELETE then ImGuiKey_Delete
|
72
|
+
when SDL::SDLK_BACKSPACE then ImGuiKey_Backspace
|
73
|
+
when SDL::SDLK_SPACE then ImGuiKey_Space
|
74
|
+
when SDL::SDLK_RETURN then ImGuiKey_Enter
|
75
|
+
when SDL::SDLK_ESCAPE then ImGuiKey_Escape
|
76
|
+
when SDL::SDLK_QUOTE then ImGuiKey_Apostrophe
|
77
|
+
when SDL::SDLK_COMMA then ImGuiKey_Comma
|
78
|
+
when SDL::SDLK_MINUS then ImGuiKey_Minus
|
79
|
+
when SDL::SDLK_PERIOD then ImGuiKey_Period
|
80
|
+
when SDL::SDLK_SLASH then ImGuiKey_Slash
|
81
|
+
when SDL::SDLK_SEMICOLON then ImGuiKey_Semicolon
|
82
|
+
when SDL::SDLK_EQUALS then ImGuiKey_Equal
|
83
|
+
when SDL::SDLK_LEFTBRACKET then ImGuiKey_LeftBracket
|
84
|
+
when SDL::SDLK_BACKSLASH then ImGuiKey_Backslash
|
85
|
+
when SDL::SDLK_RIGHTBRACKET then ImGuiKey_RightBracket
|
86
|
+
when SDL::SDLK_BACKQUOTE then ImGuiKey_GraveAccent
|
87
|
+
when SDL::SDLK_CAPSLOCK then ImGuiKey_CapsLock
|
88
|
+
when SDL::SDLK_SCROLLLOCK then ImGuiKey_ScrollLock
|
89
|
+
when SDL::SDLK_NUMLOCKCLEAR then ImGuiKey_NumLock
|
90
|
+
when SDL::SDLK_PRINTSCREEN then ImGuiKey_PrintScreen
|
91
|
+
when SDL::SDLK_PAUSE then ImGuiKey_Pause
|
92
|
+
when SDL::SDLK_KP_0 then ImGuiKey_Keypad0
|
93
|
+
when SDL::SDLK_KP_1 then ImGuiKey_Keypad1
|
94
|
+
when SDL::SDLK_KP_2 then ImGuiKey_Keypad2
|
95
|
+
when SDL::SDLK_KP_3 then ImGuiKey_Keypad3
|
96
|
+
when SDL::SDLK_KP_4 then ImGuiKey_Keypad4
|
97
|
+
when SDL::SDLK_KP_5 then ImGuiKey_Keypad5
|
98
|
+
when SDL::SDLK_KP_6 then ImGuiKey_Keypad6
|
99
|
+
when SDL::SDLK_KP_7 then ImGuiKey_Keypad7
|
100
|
+
when SDL::SDLK_KP_8 then ImGuiKey_Keypad8
|
101
|
+
when SDL::SDLK_KP_9 then ImGuiKey_Keypad9
|
102
|
+
when SDL::SDLK_KP_PERIOD then ImGuiKey_KeypadDecimal
|
103
|
+
when SDL::SDLK_KP_DIVIDE then ImGuiKey_KeypadDivide
|
104
|
+
when SDL::SDLK_KP_MULTIPLY then ImGuiKey_KeypadMultiply
|
105
|
+
when SDL::SDLK_KP_MINUS then ImGuiKey_KeypadSubtract
|
106
|
+
when SDL::SDLK_KP_PLUS then ImGuiKey_KeypadAdd
|
107
|
+
when SDL::SDLK_KP_ENTER then ImGuiKey_KeypadEnter
|
108
|
+
when SDL::SDLK_KP_EQUALS then ImGuiKey_KeypadEqual
|
109
|
+
when SDL::SDLK_LCTRL then ImGuiKey_LeftCtrl
|
110
|
+
when SDL::SDLK_LSHIFT then ImGuiKey_LeftShift
|
111
|
+
when SDL::SDLK_LALT then ImGuiKey_LeftAlt
|
112
|
+
when SDL::SDLK_LGUI then ImGuiKey_LeftSuper
|
113
|
+
when SDL::SDLK_RCTRL then ImGuiKey_RightCtrl
|
114
|
+
when SDL::SDLK_RSHIFT then ImGuiKey_RightShift
|
115
|
+
when SDL::SDLK_RALT then ImGuiKey_RightAlt
|
116
|
+
when SDL::SDLK_RGUI then ImGuiKey_RightSuper
|
117
|
+
when SDL::SDLK_APPLICATION then ImGuiKey_Menu
|
118
|
+
when SDL::SDLK_0 then ImGuiKey_0
|
119
|
+
when SDL::SDLK_1 then ImGuiKey_1
|
120
|
+
when SDL::SDLK_2 then ImGuiKey_2
|
121
|
+
when SDL::SDLK_3 then ImGuiKey_3
|
122
|
+
when SDL::SDLK_4 then ImGuiKey_4
|
123
|
+
when SDL::SDLK_5 then ImGuiKey_5
|
124
|
+
when SDL::SDLK_6 then ImGuiKey_6
|
125
|
+
when SDL::SDLK_7 then ImGuiKey_7
|
126
|
+
when SDL::SDLK_8 then ImGuiKey_8
|
127
|
+
when SDL::SDLK_9 then ImGuiKey_9
|
128
|
+
when SDL::SDLK_a then ImGuiKey_A
|
129
|
+
when SDL::SDLK_b then ImGuiKey_B
|
130
|
+
when SDL::SDLK_c then ImGuiKey_C
|
131
|
+
when SDL::SDLK_d then ImGuiKey_D
|
132
|
+
when SDL::SDLK_e then ImGuiKey_E
|
133
|
+
when SDL::SDLK_f then ImGuiKey_F
|
134
|
+
when SDL::SDLK_g then ImGuiKey_G
|
135
|
+
when SDL::SDLK_h then ImGuiKey_H
|
136
|
+
when SDL::SDLK_i then ImGuiKey_I
|
137
|
+
when SDL::SDLK_j then ImGuiKey_J
|
138
|
+
when SDL::SDLK_k then ImGuiKey_K
|
139
|
+
when SDL::SDLK_l then ImGuiKey_L
|
140
|
+
when SDL::SDLK_m then ImGuiKey_M
|
141
|
+
when SDL::SDLK_n then ImGuiKey_N
|
142
|
+
when SDL::SDLK_o then ImGuiKey_O
|
143
|
+
when SDL::SDLK_p then ImGuiKey_P
|
144
|
+
when SDL::SDLK_q then ImGuiKey_Q
|
145
|
+
when SDL::SDLK_r then ImGuiKey_R
|
146
|
+
when SDL::SDLK_s then ImGuiKey_S
|
147
|
+
when SDL::SDLK_t then ImGuiKey_T
|
148
|
+
when SDL::SDLK_u then ImGuiKey_U
|
149
|
+
when SDL::SDLK_v then ImGuiKey_V
|
150
|
+
when SDL::SDLK_w then ImGuiKey_W
|
151
|
+
when SDL::SDLK_x then ImGuiKey_X
|
152
|
+
when SDL::SDLK_y then ImGuiKey_Y
|
153
|
+
when SDL::SDLK_z then ImGuiKey_Z
|
154
|
+
when SDL::SDLK_F1 then ImGuiKey_F1
|
155
|
+
when SDL::SDLK_F2 then ImGuiKey_F2
|
156
|
+
when SDL::SDLK_F3 then ImGuiKey_F3
|
157
|
+
when SDL::SDLK_F4 then ImGuiKey_F4
|
158
|
+
when SDL::SDLK_F5 then ImGuiKey_F5
|
159
|
+
when SDL::SDLK_F6 then ImGuiKey_F6
|
160
|
+
when SDL::SDLK_F7 then ImGuiKey_F7
|
161
|
+
when SDL::SDLK_F8 then ImGuiKey_F8
|
162
|
+
when SDL::SDLK_F9 then ImGuiKey_F9
|
163
|
+
when SDL::SDLK_F10 then ImGuiKey_F10
|
164
|
+
when SDL::SDLK_F11 then ImGuiKey_F11
|
165
|
+
when SDL::SDLK_F12 then ImGuiKey_F12
|
166
|
+
else ImGuiKey_None
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# [INTERNAL]
|
171
|
+
def self.ImGui_ImplSDL2_UpdateKeyModifiers(sdl_key_mods)
|
172
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
173
|
+
io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & SDL::KMOD_CTRL) != 0)
|
174
|
+
io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & SDL::KMOD_SHIFT) != 0)
|
175
|
+
io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & SDL::KMOD_ALT) != 0)
|
176
|
+
io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & SDL::KMOD_GUI) != 0)
|
177
|
+
end
|
178
|
+
|
179
|
+
# You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
|
180
|
+
# - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
|
181
|
+
# - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
|
182
|
+
# Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
|
183
|
+
# 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.
|
184
|
+
def self.ImplSDL2_ProcessEvent(event)
|
185
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
186
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
187
|
+
|
188
|
+
case event[:type]
|
189
|
+
|
190
|
+
when SDL::MOUSEMOTION
|
191
|
+
io.AddMousePosEvent(event[:motion][:x].to_f, event[:motion][:y].to_f)
|
192
|
+
return true
|
193
|
+
|
194
|
+
when SDL::MOUSEWHEEL
|
195
|
+
wheel_x = (event[:wheel][:x] > 0) ? 1.0 : (event[:wheel][:x] < 0) ? -1.0 : 0.0
|
196
|
+
wheel_y = (event[:wheel][:y] > 0) ? 1.0 : (event[:wheel][:y] < 0) ? -1.0 : 0.0
|
197
|
+
io.AddMouseWheelEvent(wheel_x, wheel_y)
|
198
|
+
return true
|
199
|
+
|
200
|
+
when SDL::MOUSEBUTTONDOWN, SDL::MOUSEBUTTONUP
|
201
|
+
mouse_button = -1
|
202
|
+
mouse_button = 0 if event[:button][:button] == SDL::BUTTON_LEFT
|
203
|
+
mouse_button = 1 if event[:button][:button] == SDL::BUTTON_RIGHT
|
204
|
+
mouse_button = 2 if event[:button][:button] == SDL::BUTTON_MIDDLE
|
205
|
+
if mouse_button != -1
|
206
|
+
io.AddMouseButtonEvent(mouse_button, event[:type] == SDL::MOUSEBUTTONDOWN)
|
207
|
+
bd.mouseButtonsDown = (event[:type] == SDL::MOUSEBUTTONDOWN) ? (bd.mouseButtonsDown | (1 << mouse_button)) : (bd.mouseButtonsDown & ~(1 << mouse_button))
|
208
|
+
return true
|
209
|
+
end
|
210
|
+
|
211
|
+
when SDL::TEXTINPUT
|
212
|
+
io.AddInputCharactersUTF8(event[:text][:text])
|
213
|
+
return true
|
214
|
+
|
215
|
+
when SDL::KEYDOWN, SDL::KEYUP
|
216
|
+
ImGui_ImplSDL2_UpdateKeyModifiers(event[:key][:keysym][:mod])
|
217
|
+
key = ImGui_ImplSDL2_KeyToImGuiKey(event[:key][:keysym][:sym])
|
218
|
+
io.AddKeyEvent(key, (event[:type] == SDL::KEYDOWN))
|
219
|
+
io.SetKeyEventNativeData(key, event[:key][:keysym][:sym], event[:key][:keysym][:scancode], event[:key][:keysym][:scancode]) # To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
|
220
|
+
return true
|
221
|
+
|
222
|
+
when SDL::WINDOWEVENT
|
223
|
+
io.AddMousePosEvent(-Float::MAX, -Float::MAX) if event[:window][:event] == SDL::WINDOWEVENT_LEAVE
|
224
|
+
|
225
|
+
if event[:window][:event] == SDL::WINDOWEVENT_FOCUS_GAINED
|
226
|
+
io.AddFocusEvent(true)
|
227
|
+
elsif event[:window][:event] == SDL::WINDOWEVENT_FOCUS_LOST
|
228
|
+
io.AddFocusEvent(false)
|
229
|
+
end
|
230
|
+
return true
|
231
|
+
|
232
|
+
end
|
233
|
+
|
234
|
+
return false
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.ImplSDL2_Init(window, renderer)
|
238
|
+
|
239
|
+
# Check and store if we are on a SDL backend that supports global mouse position
|
240
|
+
# ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
|
241
|
+
mouse_can_use_global_state = false
|
242
|
+
sdl_backend = SDL.GetCurrentVideoDriver().read_string
|
243
|
+
global_mouse_whitelist = ["windows", "cocoa", "x11", "DIVE", "VMAN"]
|
244
|
+
global_mouse_whitelist.each do |platform|
|
245
|
+
mouse_can_use_global_state = true if sdl_backend == platform
|
246
|
+
end
|
247
|
+
|
248
|
+
# Setup backend capabilities flags
|
249
|
+
bd = ImGui_ImplSDL2_Data.new
|
250
|
+
@@g_BackendData[ImGui::GetCurrentContext().address] = bd
|
251
|
+
|
252
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
253
|
+
io[:BackendPlatformName] = @@g_BackendPlatformName
|
254
|
+
io[:BackendFlags] |= ImGuiBackendFlags_HasMouseCursors # We can honor GetMouseCursor() values (optional)
|
255
|
+
io[:BackendFlags] |= ImGuiBackendFlags_HasSetMousePos # We can honor io.WantSetMousePos requests (optional, rarely used)
|
256
|
+
|
257
|
+
bd.window = window
|
258
|
+
bd.renderer = renderer
|
259
|
+
bd.mouseCanUseGlobalState = mouse_can_use_global_state
|
260
|
+
|
261
|
+
# [TODO] Support ClipboardText : pass callbacks as Proc or something
|
262
|
+
# io[:SetClipboardTextFn] = ImGui_ImplSDL2_SetClipboardText
|
263
|
+
# io[:GetClipboardTextFn] = ImGui_ImplSDL2_GetClipboardText
|
264
|
+
io[:ClipboardUserData] = nil
|
265
|
+
|
266
|
+
# Load mouse cursors
|
267
|
+
bd.mouseCursors[ImGuiMouseCursor_Arrow] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_ARROW)
|
268
|
+
bd.mouseCursors[ImGuiMouseCursor_TextInput] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_IBEAM)
|
269
|
+
bd.mouseCursors[ImGuiMouseCursor_ResizeAll] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZEALL)
|
270
|
+
bd.mouseCursors[ImGuiMouseCursor_ResizeNS] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZENS)
|
271
|
+
bd.mouseCursors[ImGuiMouseCursor_ResizeEW] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZEWE)
|
272
|
+
bd.mouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZENESW)
|
273
|
+
bd.mouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_SIZENWSE)
|
274
|
+
bd.mouseCursors[ImGuiMouseCursor_Hand] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_HAND)
|
275
|
+
bd.mouseCursors[ImGuiMouseCursor_NotAllowed] = SDL.CreateSystemCursor(SDL::SYSTEM_CURSOR_NO)
|
276
|
+
|
277
|
+
# Set platform dependent data in viewport
|
278
|
+
case RbConfig::CONFIG['host_os']
|
279
|
+
when /mswin|msys|mingw|cygwin/
|
280
|
+
info = SDL::SysWMinfo_win.new
|
281
|
+
SDL.GetVersion(info[:version])
|
282
|
+
if SDL.GetWindowWMInfo(window, info) == SDL::TRUE
|
283
|
+
viewport = ImGuiViewport.new(ImGui::GetMainViewport())
|
284
|
+
viewport[:PlatformHandleRaw] = info[:info][:win][:window]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
|
289
|
+
# Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
|
290
|
+
# (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
|
291
|
+
# It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
|
292
|
+
# you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
|
293
|
+
if defined?(SDL::HINT_MOUSE_FOCUS_CLICKTHROUGH)
|
294
|
+
SDL.SetHint(SDL::HINT_MOUSE_FOCUS_CLICKTHROUGH, "1")
|
295
|
+
end
|
296
|
+
|
297
|
+
return true
|
298
|
+
end
|
299
|
+
|
300
|
+
def self.ImplSDL2_Shutdown()
|
301
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
302
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
303
|
+
|
304
|
+
SDL.free(bd.clipboardTextData) if bd.clipboardTextData
|
305
|
+
|
306
|
+
ImGuiMouseCursor_COUNT.times do |cursor_n|
|
307
|
+
SDL.FreeCursor(bd.mouseCursors[cursor_n])
|
308
|
+
bd.mouseCursors[cursor_n] = nil
|
309
|
+
end
|
310
|
+
|
311
|
+
io[:BackendPlatformName] = nil
|
312
|
+
io[:BackendPlatformUserData] = nil
|
313
|
+
@@g_BackendData[ImGui::GetCurrentContext()] = nil
|
314
|
+
end
|
315
|
+
|
316
|
+
# [INTERNAL]
|
317
|
+
def self.ImplSDL2_UpdateMouseData()
|
318
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
319
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
320
|
+
|
321
|
+
SDL.CaptureMouse(bd.mouseButtonsDown != 0 ? SDL::TRUE : SDL::FALSE)
|
322
|
+
focused_window = SDL.GetKeyboardFocus()
|
323
|
+
is_app_focused = (bd.window == focused_window)
|
324
|
+
if is_app_focused
|
325
|
+
# (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
|
326
|
+
if io[:WantSetMousePos]
|
327
|
+
SDL.WarpMouseInWindow(bd.window, io[:MousePos][:x].to_i, io[:MousePos][:y].to_i)
|
328
|
+
end
|
329
|
+
|
330
|
+
# (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
|
331
|
+
if bd.mouseCanUseGlobalState && bd.mouseButtonsDown == 0
|
332
|
+
wx = FFI::MemoryPointer.new(:int)
|
333
|
+
wy = FFI::MemoryPointer.new(:int)
|
334
|
+
mx = FFI::MemoryPointer.new(:int)
|
335
|
+
my = FFI::MemoryPointer.new(:int)
|
336
|
+
SDL.GetGlobalMouseState(mx, my)
|
337
|
+
SDL.GetWindowPosition(bd.window, wx, wy)
|
338
|
+
io.AddMousePosEvent(mx.read(:int).to_f - wx.read(:int).to_f, my.read(:int).to_f - wy.read(:int).to_f)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# [INTERNAL]
|
344
|
+
def self.ImplSDL2_UpdateMouseCursor()
|
345
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
346
|
+
return if (io[:ConfigFlags] & ImGuiConfigFlags_NoMouseCursorChange)
|
347
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
348
|
+
|
349
|
+
imgui_cursor = ImGui::GetMouseCursor()
|
350
|
+
if io[:MouseDrawCursor] || imgui_cursor == ImGuiMouseCursor_None
|
351
|
+
# Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
|
352
|
+
SDL.ShowCursor(SDL::FALSE)
|
353
|
+
else
|
354
|
+
# Show OS mouse cursor
|
355
|
+
SDL.SetCursor(bd.mouseCursors[imgui_cursor] ? bd.mouseCursors[imgui_cursor] : bd.mouseCursors[ImGuiMouseCursor_Arrow])
|
356
|
+
SDL.ShowCursor(SDL::TRUE)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
#
|
361
|
+
# [TODO] Support ImplSDL2_UpdateGamepads
|
362
|
+
#
|
363
|
+
|
364
|
+
def self.ImplSDL2_NewFrame()
|
365
|
+
bd = ImGui_ImplSDL2_GetBackendData()
|
366
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
367
|
+
|
368
|
+
# Setup display size (every frame to accommodate for window resizing)
|
369
|
+
w = ' ' * 4
|
370
|
+
h = ' ' * 4
|
371
|
+
display_w = ' ' * 4
|
372
|
+
display_h = ' ' * 4
|
373
|
+
SDL.GetWindowSize(bd.window, w, h)
|
374
|
+
w = w.unpack1('L')
|
375
|
+
h = h.unpack1('L')
|
376
|
+
|
377
|
+
if (SDL.GetWindowFlags(bd.window) & SDL::WINDOW_MINIMIZED) != 0
|
378
|
+
w = h = 0
|
379
|
+
end
|
380
|
+
if bd.renderer != nil
|
381
|
+
SDL.GetRendererOutputSize(bd.renderer, display_w, display_h)
|
382
|
+
else
|
383
|
+
SDL.GL_GetDrawableSize(bd.window, display_w, display_h)
|
384
|
+
end
|
385
|
+
display_w = display_w.unpack1('L')
|
386
|
+
display_h = display_h.unpack1('L')
|
387
|
+
|
388
|
+
io[:DisplaySize] = ImVec2.create(w.to_f, h.to_f)
|
389
|
+
|
390
|
+
if w > 0 && h > 0
|
391
|
+
io[:DisplayFramebufferScale][:x] = display_w.to_f / w
|
392
|
+
io[:DisplayFramebufferScale][:y] = display_h.to_f / h
|
393
|
+
end
|
394
|
+
|
395
|
+
# Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
|
396
|
+
frequency = SDL.GetPerformanceFrequency()
|
397
|
+
current_time = SDL.GetPerformanceCounter()
|
398
|
+
|
399
|
+
io[:DeltaTime] = bd.time > 0 ? ((current_time - bd.time).to_f / frequency) : (1.0/60.0)
|
400
|
+
bd.time = current_time
|
401
|
+
|
402
|
+
ImplSDL2_UpdateMouseData()
|
403
|
+
ImplSDL2_UpdateMouseCursor()
|
404
|
+
|
405
|
+
# [TODO] update gamepads
|
406
|
+
# ImGui_ImplSDL2_UpdateGamepads()
|
407
|
+
end
|
408
|
+
|
409
|
+
end
|
@@ -0,0 +1,200 @@
|
|
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
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
64
|
+
ImGui::ImplSDLRenderer_CreateDeviceObjects() if bd[:FontTexture] == nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.ImplSDLRenderer_RenderDrawData(draw_data_raw)
|
68
|
+
draw_data = ImDrawData.new(draw_data_raw)
|
69
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
70
|
+
|
71
|
+
# If there's a scale factor set by the user, use that instead
|
72
|
+
# If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
|
73
|
+
# to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
|
74
|
+
rsx = FFI::MemoryPointer.new :float
|
75
|
+
rsy = FFI::MemoryPointer.new :float
|
76
|
+
SDL.RenderGetScale(bd[:SDLRenderer], rsx, rsy)
|
77
|
+
render_scale = ImVec2.create(0, 0)
|
78
|
+
render_scale[:x] = (rsx.read_float() == 1.0) ? draw_data[:FramebufferScale][:x] : 1.0
|
79
|
+
render_scale[:y] = (rsy.read_float() == 1.0) ? draw_data[:FramebufferScale][:y] : 1.0
|
80
|
+
|
81
|
+
# Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
|
82
|
+
fb_width = (draw_data[:DisplaySize][:x] * render_scale[:x]).to_i
|
83
|
+
fb_height = (draw_data[:DisplaySize][:y] * render_scale[:y]).to_i
|
84
|
+
return if fb_width == 0 || fb_height == 0
|
85
|
+
|
86
|
+
# Backup SDL_Renderer state that will be modified to restore it afterwards
|
87
|
+
oldViewport = SDL::Rect.new
|
88
|
+
oldClipEnabled = FFI::MemoryPointer.new :bool
|
89
|
+
oldClipRect = SDL::Rect.new
|
90
|
+
|
91
|
+
oldClipEnabled = (SDL.RenderIsClipEnabled(bd[:SDLRenderer]) == SDL::TRUE)
|
92
|
+
SDL.RenderGetViewport(bd[:SDLRenderer], oldViewport)
|
93
|
+
SDL.RenderGetClipRect(bd[:SDLRenderer], oldClipRect)
|
94
|
+
|
95
|
+
# Will project scissor/clipping rectangles into framebuffer space
|
96
|
+
clip_off = draw_data[:DisplayPos] # (0,0) unless using multi-viewports
|
97
|
+
clip_scale = render_scale
|
98
|
+
|
99
|
+
# Render command lists
|
100
|
+
ImplSDLRenderer_SetupRenderState()
|
101
|
+
draw_data[:CmdListsCount].times do |n|
|
102
|
+
cmd_list = ImDrawList.new((draw_data[:CmdLists][:Data] + FFI.type_size(:pointer) * n).read_pointer)
|
103
|
+
vtx_buffer = cmd_list[:VtxBuffer][:Data] # const ImDrawVert*
|
104
|
+
idx_buffer = cmd_list[:IdxBuffer][:Data] # const ImDrawIdx*
|
105
|
+
|
106
|
+
cmd_list[:CmdBuffer][:Size].times do |cmd_i|
|
107
|
+
pcmd = ImDrawCmd.new(cmd_list[:CmdBuffer][:Data] + ImDrawCmd.size * cmd_i) # const ImDrawCmd*
|
108
|
+
if pcmd[:UserCallback] != nil
|
109
|
+
# [TODO] Handle user callback (Ref.: https://github.com/ffi/ffi/wiki/Callbacks )
|
110
|
+
|
111
|
+
# User callback, registered via ImDrawList::AddCallback()
|
112
|
+
# (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
|
113
|
+
# if pcmd[:UserCallback] == :ImDrawCallback_ResetRenderState
|
114
|
+
ImGui_ImplSDLRenderer_SetupRenderState()
|
115
|
+
# else
|
116
|
+
# pcmd[:UserCallback](cmd_list, pcmd)
|
117
|
+
# end
|
118
|
+
else
|
119
|
+
clip_min = ImVec2.create((pcmd[:ClipRect][:x] - clip_off[:x]) * clip_scale[:x], (pcmd[:ClipRect][:y] - clip_off[:y]) * clip_scale[:y])
|
120
|
+
clip_max = ImVec2.create((pcmd[:ClipRect][:z] - clip_off[:x]) * clip_scale[:x], (pcmd[:ClipRect][:w] - clip_off[:y]) * clip_scale[:y])
|
121
|
+
|
122
|
+
clip_min[:x] = 0.0 if clip_min[:x] < 0.0
|
123
|
+
clip_min[:y] = 0.0 if clip_min[:y] < 0.0
|
124
|
+
clip_max[:x] = fb_width.to_f if clip_max[:x] > fb_width
|
125
|
+
clip_max[:y] = fb_height.to_f if clip_max[:y] > fb_height
|
126
|
+
next if (clip_max[:x] <= clip_min[:x] || clip_max[:y] <= clip_min[:y])
|
127
|
+
|
128
|
+
r = SDL::Rect.new
|
129
|
+
r[:x] = clip_min[:x].to_i
|
130
|
+
r[:y] = clip_min[:y].to_i
|
131
|
+
r[:w] = (clip_max[:x] - clip_min[:x]).to_i
|
132
|
+
r[:h] = (clip_max[:y] - clip_min[:y]).to_i
|
133
|
+
|
134
|
+
SDL.RenderSetClipRect(bd[:SDLRenderer], r.to_ptr)
|
135
|
+
|
136
|
+
xy = vtx_buffer + (pcmd[:VtxOffset] + ImDrawVert.offset_of(:pos))
|
137
|
+
uv = vtx_buffer + (pcmd[:VtxOffset] + ImDrawVert.offset_of(:uv))
|
138
|
+
color = vtx_buffer + (pcmd[:VtxOffset] + ImDrawVert.offset_of(:col))
|
139
|
+
|
140
|
+
SDL.RenderGeometryRaw(bd[:SDLRenderer], pcmd[:TextureId],
|
141
|
+
xy, ImDrawVert.size,
|
142
|
+
color, ImDrawVert.size,
|
143
|
+
uv, ImDrawVert.size,
|
144
|
+
cmd_list[:VtxBuffer][:Size] - pcmd[:VtxOffset],
|
145
|
+
idx_buffer + FFI.type_size(:ImDrawIdx) * pcmd[:IdxOffset], pcmd[:ElemCount], FFI.type_size(:ImDrawIdx)) # FFI.type_size(:ImDrawIdx) == FFI::Type::UINT16.size
|
146
|
+
|
147
|
+
# Restore modified SDL_Renderer state
|
148
|
+
SDL.RenderSetViewport(bd[:SDLRenderer], oldViewport)
|
149
|
+
SDL.RenderSetClipRect(bd[:SDLRenderer], oldClipEnabled ? oldClipRect : nil)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Called by Init/NewFrame/Shutdown
|
156
|
+
def self.ImplSDLRenderer_CreateFontsTexture()
|
157
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
158
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
159
|
+
|
160
|
+
# Build texture atlas
|
161
|
+
pixels = FFI::MemoryPointer.new :pointer
|
162
|
+
width = FFI::MemoryPointer.new :int
|
163
|
+
height = FFI::MemoryPointer.new :int
|
164
|
+
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.
|
165
|
+
|
166
|
+
# Upload texture to graphics system
|
167
|
+
bd[:FontTexture] = SDL.CreateTexture(bd[:SDLRenderer], SDL::PIXELFORMAT_ABGR8888, SDL::TEXTUREACCESS_STATIC, width.read_int, height.read_int)
|
168
|
+
if bd[:FontTexture] == nil
|
169
|
+
SDL.Log("error creating texture")
|
170
|
+
return false
|
171
|
+
end
|
172
|
+
|
173
|
+
SDL.UpdateTexture(bd[:FontTexture], nil, pixels.read_pointer, 4 * width.read_int)
|
174
|
+
SDL.SetTextureBlendMode(bd[:FontTexture], SDL::BLENDMODE_BLEND)
|
175
|
+
|
176
|
+
# Store our identifier
|
177
|
+
io[:Fonts].SetTexID(bd[:FontTexture])
|
178
|
+
|
179
|
+
return true
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.ImplSDLRenderer_DestroyFontsTexture()
|
183
|
+
io = ImGuiIO.new(ImGui::GetIO())
|
184
|
+
bd = ImGui_ImplSDLRenderer_GetBackendData()
|
185
|
+
if bd[:FontTexture] != nil
|
186
|
+
io[:Fonts].SetTexID(nil)
|
187
|
+
SDL.DestroyTexture(bd[:FontTexture])
|
188
|
+
bd[:FontTexture] = nil
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def self.ImplSDLRenderer_CreateDeviceObjects()
|
193
|
+
return ImGui::ImplSDLRenderer_CreateFontsTexture()
|
194
|
+
end
|
195
|
+
|
196
|
+
def self.ImplSDLRenderer_DestroyDeviceObjects()
|
197
|
+
ImGui::ImplSDLRenderer_DestroyFontsTexture()
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# imgui-bindings : Yet another ImGui wrapper for Ruby
|
2
|
+
#
|
3
|
+
# * https://github.com/vaiorabbit/ruby-imgui
|
4
|
+
|
5
|
+
require 'ffi'
|
6
|
+
|
7
|
+
module ImGui
|
8
|
+
|
9
|
+
extend FFI::Library
|
10
|
+
|
11
|
+
@@imgui_import_internal_done = false
|
12
|
+
|
13
|
+
def self.import_internal_symbols(output_error = false)
|
14
|
+
|
15
|
+
symbols = [
|
16
|
+
:igFocusWindow,
|
17
|
+
:igGetCurrentWindow,
|
18
|
+
]
|
19
|
+
|
20
|
+
args = {
|
21
|
+
:igFocusWindow => [:pointer],
|
22
|
+
:igGetCurrentWindow => [],
|
23
|
+
}
|
24
|
+
|
25
|
+
retvals = {
|
26
|
+
:igFocusWindow => :void,
|
27
|
+
:igGetCurrentWindow => :pointer,
|
28
|
+
}
|
29
|
+
|
30
|
+
symbols.each do |sym|
|
31
|
+
begin
|
32
|
+
attach_function sym, args[sym], retvals[sym]
|
33
|
+
rescue FFI::NotFoundError
|
34
|
+
$stderr.puts("[Warning] Failed to import #{sym}.\n") if output_error
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@@imgui_import_internal_done = true
|
39
|
+
end # self.import_internal_symbols
|
40
|
+
|
41
|
+
def self.GetCurrentWindow()
|
42
|
+
igGetCurrentWindow()
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.FocusWindow(window)
|
46
|
+
igFocusWindow(window)
|
47
|
+
end
|
48
|
+
|
49
|
+
end # module ImGui
|
Binary file
|