<Guide du Rootard GeeXLab/>
ImGui
Dernière mise à jour: 2018.12.10 par JeGX
>> Retour <<
ImGui est une librairie très populaire parmi les développeurs graphiques à la recherche d'une façon efficace de dessiner des
widgets (fenêtres, sliders, checkboxes, etc.) sur leurs scènes 3D. ImGui répond à merveille à ce besoin très précis et ce pour toutes
les APIs 3D (OpenGL, Vulkan et Direct3D).
Les fonctions d'ImGui sont accessibles dans GeeXLab via la librairie
gh_imgui.
ImGui fonctionne selon un mode immédiat. Tous les widgets de l'interface graphique sont totalement reconstruits et rendus
à chaque frame. Les fenêtres n'ont pas besoin d'être créées et initialisées avant d'être rendue comme c'est le cas avec les librairies
de widgets classiques. Les widgets existent uniquement au moment où ils sont rendus. Pas avant ni après. La conséquence directe
est une interface graphhique totalement dynamique qui peut évoluer et se métamorphoser de frame en frame.
La première chose à faire pour utiliser ImGui est de l'initialiser (en général dans un script INIT):
gh_imgui.init()
Et la dernière chose à faire (en général dans un script TERMINATE) avant de quitter la demo:
gh_imgui.terminate()
Maintenant, tout le reste du code concerne le script FRAME.
Voilà le gabarit général pour un rendu ImGui: un appel à
frame_begin() ou
frame_begin_v2(), suivi de tous les rendus des widgets
et terminé par un appel à
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()
Voilà, le template d'un rendu ImGui est posé. Globalement, ce template sera toujours le même, quelque soit la démo.
Attaquons maintenant les choses intéressantes, celles qui produisent du visuel. L'API de scripting ImGui est très riche, aussi
je vais me contenter de vous donner quelques examples simples de widgets. Il y a une interface ImGui dans pratiquement toutes les démos
GeeXLab récentes, il suffit de les passer en revue pour avoir une idée des possibilités.
Fenêtre + Texte
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()
Bouton
if (gh_imgui.button("Click me") == 1) then
-- do something if pressed.
end
Barre de Progression
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)
Police TTF
Il est possible de changer la police (ou font) par défaut d'ImGui par n'imnporte quelle autre police disponible au format
TTF (True Type Font). En réalité, il est possible d'avoir plusieurs polices et de les activer dès que nécessaire (une police
pour les titres, une autre pour les sous titres, etc...).
L'ajout de polices additionnelles se fait après gh_imgui.init() en utilisant la fonction
gh_imgui.add_font_from_file()
(ou
gh_imgui.add_font_from_zip_file() ou
gh_imgui.add_font_from_buffer()). Une fois toutes les polices chargées,
il faut appeller
gh_imgui.rebuild_all_fonts(). Obligatoire, c'est tout.
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()
Les polices TTF peuvent aussi être chargées depuis un fichier zip. L'exemple suivant nous montre comment utiliser les fonctions
gh_imgui.add_font_from_zip_file() et
gh_utils.get_demo_zip_filename().
gh_utils.get_demo_zip_filename() est utile pour gérer le cas où toute la démo est archivé dans un fichier zip:
souhaite t'on charger la police depuis le fichier zip de la demo (qui peut avoir n'importe quel nom) ou plutot depuis un fichier
externe situé quelque part sur le disque (une police TTF utilisateur)?
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()
Maintenant que nous avons plusieurs polices, comment sélectionner la police courante?
D'abord il y a la fonction
gh_imgui.set_default_font() qui permet de changer la police par défaut:
gh_imgui.set_default_font(font_RobotoRegular)
Ensuite ponctuellement, comme pour un titre, on peut changer de police avec
gh_imgui.push_font() et
gh_imgui.pop_font():
gh_imgui.push_font(font_RobotoBlack)
gh_imgui.text("Font RobotoBlack!!!")
gh_imgui.pop_font()
Primitives
ImGui offre la possibilité de dessiner, dans les fenêtres, quelques primitives très utiles: des lignes, des quads, cercles, disques ainsi que des
courbes de Bezier. Les fonctions de rendu des primitives sont:
add_line_to_drawlist(),
add_quad_to_drawlist(),
add_circle_to_drawlist() et
add_bezier_curve_to_drawlist().
Le code suivant montre l'utilisation de ces 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)