<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)


GeeXLab - ImGui, primitives: quad, bezier curves, lines and circles




GeeXLab Rootard Guide | Downloads | Contact | Newsletter