imgui-bindings 0.0.1

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