What’s Dear ImGui
Dear ImGui is a C++ library (that has been ported to a lot of other languages) used to quickly render debug UI for easily rendering text, making buttons etc
For ImGui we need to set the UI elements each frame. To change a text or any different attribute all we need to do is to send a different value to the ImGui function that frame. A call to the ImGui function may look like ImGui::Text("Favorite number: %d", favoriteNumber);
Including it in our project
First we need to put the new library into the vcpkg.json. This can be done just by adding it to the list of dependencies. As ImGui is build for many rendering engines like SDL2, OpenGL, Vulkan,… we need to specify how are we planning to use ImGui
...
"dependencies": [
"glfw3",
"glm",
"other packages...",
{
"name": "imgui",
"features": ["glfw-binding", "opengl3-binding"]
}
]
...Then we need to modify the CMakeLists.txt to put Dear ImGui into our project with
find_package(imgui CONFIG REQUIRED)and modify the project link libraries command as
target_link_libraries(PlanetGenerator
PRIVATE
glad
glm::glm
glfw
OpenGL::GL
...other libraries
imgui::imgui
)C++ part of the code
After Adding the Dear ImGui in the project we can now use the ImGui includes with
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>Then at the start of our program we initialize ImGui
// GLFWwindow* window = ...;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
// we can use `io` for ImGui configuration
// ImGui::StyleColorsDark(); // <- optional dark mode
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 330");Remember that at the end of our application we need to delete the ImGui context
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();Rendering loop
As a final rendering step in our rendering pipeline, just before swapping frame buffers with glfwSwapBuffers(window); we should render our ImGui UI
Before we start doing anything with ImGui elements we need to set a new ImGui frame
ImGui_ImplGlfw_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
ImGui::NewFrame();Now we can create an ImGui window. This is the box holding all its buttons, texts and other elements. Inside the window we can add any elements we want. ImGui supports basic buttons, texts and sliders but also more advanced stuff like texture renderers, graph elements and much more
ImGui::Begin("My Window");
ImGui::Text("FPS: %.1f", FPS);
ImGui::Text("Camera Position: (%.1f, %.1f, %.1f)", cameraPos.x, cameraPos.y, cameraPos.z);
// Button returns true if pressed
if(ImGui::Button("Do stuff")) Stuff();
if(ImGui::DragFloat("How much stuff", &numOfStuff, 0.1f, 0.1f, 10.0f))
std::cout << "Stuff changed with ImGui to: " << numOfStuff << std::endl;
ImGui::Checkbox("Allow doing stuff", &isDoingStuffAllowed);
ImGui::End();With ImGui::Begin("...") and ImGui::End() we can create as many ImGui windows as we want
When we stop inputting any new UI elements into our ImGui that frame we have to render it with
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());Input loop
During our input setup we have overridden the mouse position, mouse button and scroll callbacks. Since ImGui is no longer registered for those callbacks we need to fix it by calling the ImGui callback inside our own callback. The code should look something like this
void cursorPositionCallback(GLFWwindow* window, double xpos, double ypos){
ImGui_ImplGlfw_CursorPosCallback(window, xpos, ypos);
// ...
}
void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods){
ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods);
// ...
}
void scrollCallback(GLFWwindow* window, double xoffset, double yoffset){
ImGui_ImplGlfw_ScrollCallback(window, xoffset, yoffset);
// ...
}
// + any other callbacks written by us and registered with GLFWSomething we will most likely want to use is the io.WantCaptureMouse and io.WantCaptureKeyboard. When we click on an ImGui element we most likely do not want to also register a click on anything behind the ImGui panel. The same thing for when writing in an ImGui text field and registering keyboard inputs for walking etc.
We can put an if statement in our callbacks asking ImGui if ImGui wanted to capture our mouse or keyboard that frame and if it did we skip our callback
void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods){
ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods);
if(ImGui::GetIO().WantCaptureMouse) return;
// ...
}