imgui-bindings 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,409 +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
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