ImGui

Dear ImGui is a popular C++ GUI library. It can be used as an alternative for Scene2D. Since it is written in C++, you need to choose one of its Java bindings for using it with libGDX: kotlin-graphics/imgui, ice1000/jimgui, SpaiR/imgui-java and xpenatan/gdx-imgui.

General Information

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.

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


Option 1: kotlin-graphics’ Bindings

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

var f = 0f
with(ImGui) {
    text("Hello, world %d", 123)
    button("OK"){
        // react
    }
    inputText("string", buf)
    sliderFloat("float", ::f, 0f, 1f)
}

Java

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

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

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

Option 2: SpaiR’s Bindings

Required Dependencies for the LWJGL 3 Subproject

api "io.github.spair:imgui-java-binding:<version>"
api "io.github.spair:imgui-java-lwjgl3:<version>"
api "io.github.spair:imgui-java-natives-linux:<version>"
api "io.github.spair:imgui-java-natives-macos:<version>"
api "io.github.spair:imgui-java-natives-windows:<version>"

Replace <version> with the latest version found at the top of the README file here.

Example Minimal Usage

The following instructions detail how ImGui can be used in a libGDX game. For easier use, you can put most of the methods in a specialised class, e.g. ImGuiRenderer.

  1. Initialize ImGui. This has to be done once for your application, for example in Game#create():

    private static ImGuiImplGlfw imGuiGlfw;
    private static ImGuiImplGl3 imGuiGl3;
    
    public static void init() {
       imGuiGlfw = new ImGuiImplGlfw();
       imGuiGl3 = new ImGuiImplGl3();
       long windowHandle = ((Lwjgl3Graphics) Gdx.graphics).getWindow().getWindowHandle();
       ImGui.createContext();
       ImGuiIO io = ImGui.getIO();
       io.setIniFilename(null);
       io.getFonts().addFontDefault();
       io.getFonts().build();
       imGuiGlfw.init(windowHandle, true);
       imGuiGl3.init("#version 150");
    }
    
  2. Before you start using any of the ImGui methods in the render() method of your screens, you need to start a new frame:

    private static InputProcessor tmpProcessor;
    
    public static void start() {
       if (tmpProcessor != null) { // Restore the input processor after ImGui caught all inputs, see #end()
          Gdx.input.setInputProcessor(tmpProcessor);
          tmpProcessor = null;
       }
    
       imGuiGlfw.newFrame();
       ImGui.newFrame();
    }
    
  3. Then you can render any UI stuff you want, e.g.:

    ImGui.button("I'm a Button!");
    
  4. Afterwards, you need to actually render the ImGui frame:

    public static void end() {
       ImGui.render();
       imGuiGl3.renderDrawData(ImGui.getDrawData());
    
       // If ImGui wants to capture the input, disable libGDX's input processor
       if (ImGui.getIO().getWantCaptureKeyboard() || ImGui.getIO().getWantCaptureMouse()) {
          tmpProcessor = Gdx.input.getInputProcessor();
          Gdx.input.setInputProcessor(null);
       }
    }
    
  5. Be sure to dispose ImGui if you no longer need it:

    public static void dispose() {
       imGuiGl3.dispose();
       imGuiGl3 = null;
       imGuiGlfw.dispose();
       imGuiGlfw = null;
       ImGui.destroyContext();
    }
    
  6. The result can look like this:

    Screenshot of ImGui in libGDX