An alternative GUI for libGDX is Dear ImGui, a bloat-free graphical user interface library in C++. It outputs optimized vertex buffers that you can render anytime in your 3D-pipeline enabled application. It is fast, portable, renderer agnostic and self-contained (few dependencies).

There are a couple of different JVM bindings you can choose from: kotlin-graphics/imgui, ice1000/jimgui and SpaiR/imgui-java.

Dear ImGui is designed to enable fast iteration and empower programmers to create content creation tools and visualization/ debug tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries.

A common misunderstanding is to think that immediate mode gui == immediate mode rendering, which usually implies hammering your driver/GPU with a bunch of inefficient draw calls and state changes, as the gui functions are called by the user. This is NOT what Dear ImGui does. Dear ImGui outputs vertex buffers and a small list of draw calls batches. It never touches your GPU directly. The draw call batches are decently optimal and you can render them later, in your app or even remotely.

Dear ImGui is particularly suited to integration in realtime 3D applications, fullscreen applications, embedded applications, games, or any applications on consoles platforms where operating system features are non-standard.

This is an example demonstrating what ImGui is capable of: Sample

First steps using kotlin-graphics’ binding)

There is an elaborate wiki entry over in the Kotlin-graphics’s repo, detailing how ImGui can be used together with libGDX: https://github.com/kotlin-graphics/imgui/wiki/Using-libGDX

These are some very simple examples, how its usage may look like:

Kotlin

  1. var f = 0f
  2. with(ImGui) {
  3. text("Hello, world %d", 123)
  4. button("OK"){
  5. // react
  6. }
  7. inputText("string", buf)
  8. sliderFloat("float", ::f, 0f, 1f)
  9. }

Java

  1. ImGui imgui = ImGui.INSTANCE;
  2. float[] f = {0f};
  3. imgui.text("Hello, world %d", 123);
  4. if(imgui.button("OK")) {
  5. // react
  6. }
  7. imgui.inputText("string", buf);
  8. imgui.sliderFloat("float", f, 0f, 1f);

screenshot of sample code alongside its output with ImGui

ImGui supports also other languages, such as japanese, initiliazed here as:

  1. IO.fonts.addFontFromFileTTF("extraFonts/ArialUni.ttf", 18f, glyphRanges = IO.fonts.glyphRangesJapanese)!!

First steps using SpaiR’s bindings

Required Dependencies

  1. "io.github.spair:imgui-java-binding:<version>"
  2. "io.github.spair:imgui-java-lwjgl3:<version>"
  3. "io.github.spair:imgui-java-natives-linux:<version>"
  4. "io.github.spair:imgui-java-natives-macos:<version>"
  5. "io.github.spair:imgui-java-natives-windows:<version>"

Example Minimal Usage

The following instructions detail how ImGui can be used on top of a 3D scene in libGDX.

  1. Initialize ImGui at the beginning of the program:
  1. ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
  2. ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
  1. In create():
  1. // create 3D scene
  2. GLFWErrorCallback.createPrint(System.err).set();
  3. if (!glfwInit())
  4. {
  5. throw new IllegalStateException("Unable to initialize GLFW");
  6. }
  7. ImGui.createContext();
  8. final ImGuiIO io = ImGui.getIO();
  9. io.setIniFilename(null);
  10. ImGuiTools.setupFonts(io);
  11. windowHandle = ((Lwjgl3Graphics) Gdx.graphics).getWindow().getWindowHandle();
  12. imGuiGlfw.init(windowHandle, true);
  13. imGuiGl3.init(glslVersion);
  1. In render():
  1. // render 3D scene
  2. imGuiGlfw.newFrame();
  3. ImGui.newFrame();
  4. ImGui.button("I'm a Button!");
  5. ImGui.render();
  6. imGuiGl3.renderDrawData(ImGui.getDrawData());
  7. glfwSwapBuffers(windowHandle);
  8. glfwPollEvents();
  1. In dispose():
  1. imGuiGl3.dispose();
  2. imGuiGlfw.dispose();
  3. ImGui.destroyContext();
  1. The result:

Screenshot of ImGui in libGDX