<GeeXLab Rootard Guide/>
ImGui
Last update: 2018.12.10 by JeGX
>> Back <<
ImGui is a very popular library among graphic developers looking for an efficient way to draw widgets
(windows, sliders, checkboxes, etc.) on their 3D scenes. ImGui responds perfectly to this very specific need for all
3D APIs (OpenGL, Vulkan and Direct3D).
The ImGui functions are accessible in GeeXLab via the
gh_imgui library.
ImGui works in an immediate mode. All GUI widgets are completely rebuilt and rendered each and every frame.
Windows do not need to be created and initialized before being rendered as is the case with classic widget libraries.
Widgets exist only when they are rendered. Not before or after. The direct consequence is a totally dynamic graphical
interface that can evolve and transform from frame to frame.
The first thing to do to use ImGui is to initialize it (usually in an INIT script):
gh_imgui.init()
And the last thing to do (usually in a TERMINATE script) before leaving the demo:
gh_imgui.terminate()
Now all the rest of the code is about the FRAME script.
This is the general template for rendering ImGui: a call to
frame_begin() or
frame_begin_v2(), followed by
all renderings of widgets and ended with a call to
frame_end().
local win_w, win_h = gh_window.getsize(0)
local LEFT_BUTTON = 1
local mouse_left_button = gh_input.mouse_get_button_state(LEFT_BUTTON)
local RIGHT_BUTTON = 2
local mouse_right_button = gh_input.mouse_get_button_state(RIGHT_BUTTON)
local mouse_wheel = 0
local mouse_wheel_delta = gh_input.mouse_get_wheel_delta()
if (mouse_wheel_delta ~= 0) then
if (mouse_wheel_delta > 0) then
mouse_wheel = mouse_wheel + 1
elseif (mouse_wheel_delta < 0) then
mouse_wheel = mouse_wheel - 1
end
end
gh_input.mouse_reset_wheel_delta()
local dt = gh_utils.get_time_step()
gh_imgui.frame_begin_v2(win_w, win_h, mouse_x, mouse_y, mouse_left_button, mouse_right_button, mouse_wheel, dt)
...
...
gh_imgui.frame_end()
That's it, the template of a rendering ImGui is posed. Overall, this template will always be the same,
whatever the demo.
Now let's tackle the interesting things, the ones that produce the visual. The ImGui scripting API is very rich,
so I'll just give you some simple examples of widgets. There is an ImGui interface in virtually all recent GeeXLab demos,
just review them to get an idea of the possibilities.
Window + Text
ImGuiWindowFlags_Default = 0
ImGuiWindowFlags_NoTitleBar = 1 -- Disable title-bar
ImGuiWindowFlags_NoResize = 2 -- Disable user resizing with the lower-right grip
ImGuiWindowFlags_NoMove = 4 -- Disable user moving the window
ImGuiWindowFlags_NoScrollbar = 8 -- Disable scrollbars (window can still scroll with mouse or programatically)
ImGuiWindowFlags_NoScrollWithMouse = 16 -- Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will be forwarded to the parent unless NoScrollbar is also set.
ImGuiWindowFlags_NoCollapse = 32 -- Disable user collapsing window by double-clicking on it
ImGuiWindowFlags_AlwaysAutoResize = 64 -- Resize every window to its content every frame
ImGuiWindowFlags_NoBackground = 128 -- Disable drawing background color (WindowBg, etc.) and outside border. Similar as using SetNextWindowBgAlpha(0.0f).
ImGuiWindowFlags_NoSavedSettings = 256 -- Never load/save settings in .ini file
pos_size_flag_always = 1 -- Always set the pos and/or size
pos_size_flag_once = 2 -- Set the pos and/or size once per runtime session (only the first call with succeed)
pos_size_flag_first_use_ever = 4 -- Set the pos and/or size if the window has no saved data (if doesn't exist in the .ini file)
width = 300
height = 200
pos_x = 20
pos_y = 20
window_flags = ImGuiWindowFlags_Default
pos_flags = pos_size_flag_first_use_ever
size_flags = pos_size_flag_first_use_ever
local opened = gh_imgui.window_begin("Test Window", width, height, pos_x, pos_y, window_flags, pos_flags, size_flags)
if (opened == 1) then
gh_imgui.text("Hello (with default color)")
gh_imgui.text_rgba("Hello (yellow color)", 1.0, 1.0, 0.0, 1.0)
end
gh_imgui.window_end()
Button
if (gh_imgui.button("Click me") == 1) then
-- do something if pressed.
end
Progress Bar
fraction = 0.35
size_x = 0 -- for automatic width
size_y = 0 -- for automatic height
gh_imgui.progress_bar(fraction, size_x, size_y, "A progress bar set to 35 %")
Checkbox
initial_state = 0
if (gh_imgui.checkbox("Checkbox", initial_state) == 1) then
-- do something if checked.
end
1D Slider
initial_state = 0
local min_value = 0.0
local max_value = 1.0
local power = 1.0 -- Use power!=1.0 for logarithmic sliders.
local initial_value = 0.5
slider_value = gh_imgui.slider_1f("Slider 1f", initial_value, min_value, max_value, power)
TTF Font
It is possible to change the default font (or font) of ImGui by any other font available in TTF (True Type Font) format.
In reality, it is possible to have several fonts and activate them as soon as necessary (one font for titles, another for
subtitles, etc ...).
Adding additional fonts is done after gh_imgui.init () using
gh_imgui.add_font_from_file() (or
gh_imgui.add_font_from_zip_file()
or
gh_imgui.add_font_from_buffer()). Once all the fonts are loaded, you have to call
gh_imgui.rebuild_all_fonts().
Mandatory, that's all.
gh_imgui.init()
local demo_dir = gh_utils.get_demo_dir()
font_RobotoBlack = gh_imgui.add_font_from_file(demo_dir .. "data/Roboto-Black.ttf", 24)
font_RobotoRegular = gh_imgui.add_font_from_file(demo_dir .. "data/Roboto-Regular.ttf", 16)
gh_imgui.rebuild_all_fonts()
TTF fonts can also be loaded from a zip file. The following example shows how to use the
gh_imgui.add_font_from_zip_file() and
gh_utils.get_demo_zip_filename() functions.
gh_utils.get_demo_zip_filename() is useful for handling the case where the entire demo is archived in a zip file: do we want to load the font from the zip file of the demo (which can have any name)
or rather from a external file somewhere on the disk (a user TTF font)?
dofile(lib_dir .. "lua/imgui.lua")
imgui_init("dark")
font_HACKED = 0
font_RobotoRegular = 0
local demo_zip_filename = gh_utils.get_demo_zip_filename()
if (demo_zip_filename == "") then
font_HACKED = gh_imgui.add_font_from_file(demo_dir .. "data/HACKED.ttf", 26)
font_RobotoRegular = gh_imgui.add_font_from_file(demo_dir .. "data/Roboto-Regular.ttf", 20)
else
font_HACKED = gh_imgui.add_font_from_zip_file(demo_zip_filename, "data/HACKED.ttf", 26)
font_RobotoRegular = gh_imgui.add_font_from_zip_file(demo_zip_filename, "data/Roboto-Regular.ttf", 20)
end
gh_imgui.rebuild_all_fonts()
Now that we have several fonts, how to select the current font?
First there is the function
gh_imgui.set_default_font() which allows to change the default font:
gh_imgui.set_default_font(font_RobotoRegular)
Then punctually, as for a title, we can change the font with
gh_imgui.push_font() and
gh_imgui.pop_font():
gh_imgui.push_font(font_RobotoBlack)
gh_imgui.text("Font RobotoBlack!!!")
gh_imgui.pop_font()
Primitives
ImGui offers the possibility of drawing some very useful primitives: lines, quads, circles, disks as well as curves of Bezier.
The rendering functions of the primitives are:
add_line_to_drawlist() ,
add_quad_to_drawlist(),
add_circle_to_drawlist() and
add_bezier_curve_to_drawlist().
The following code shows the use of these primitives:
local wx, wy = gh_imgui.get_window_pos()
local mouse_x, mouse_y = gh_input.mouse_get_position()
local p0 = {x=wx+300, y=wy+50}
--local cp0 = {x=wx+200, y=wy+200}
local cp0 = {x=mouse_x, y=mouse_y}
local cp1 = {x=wx+460, y=wy+100}
local p1 = {x=wx+400, y=wy+200}
local color = {r=200, g=200, b=200, a=255}
local line_thickness = 2.0
local num_segments = 20
gh_imgui.add_quad_to_drawlist(wx+180, wy+35, wx+250, wy+35, wx+250, wy+45, wx+180, wy+45, 100,255,100,255, 2.0, 1)
gh_imgui.add_line_to_drawlist(p0.x, p0.y, cp0.x,cp0.y, 250,250,100,255, 1.0)
gh_imgui.add_line_to_drawlist(p1.x, p1.y, cp1.x,cp1.y, 250,250,100,255, 1.0)
gh_imgui.add_bezier_curve_to_drawlist(p0.x,p0.y, cp0.x,cp0.y, cp1.x,cp1.y, p1.x,p1.y, color.r, color.g, color.b, color.a, line_thickness, num_segments)
gh_imgui.add_circle_to_drawlist(p0.x, p0.y, 10, 200,200,200,255, 2.0, 20, 1)
gh_imgui.add_circle_to_drawlist(cp0.x, cp0.y, 10, 100,200,255,255, 2.0, 20, 1)
gh_imgui.add_circle_to_drawlist(cp1.x, cp1.y, 10, 100,200,255,255, 2.0, 20, 1)
gh_imgui.add_circle_to_drawlist(p1.x, p1.y, 10, 200,200,200,255, 2.0, 20, 1)