Bloat-Free Dear Imgui pro C++

Vytváření uživatelského rozhraní pro desktopové aplikace může být často komplikované a časově náročné. Naštěstí existují nástroje, které tento proces výrazně zjednodušují, a jedním z mých oblíbených je Dear Imgui. Tato jednoduchá knihovna umožňuje rychlé a efektivní vytváření působivých grafických uživatelských rozhraní bez zbytečné složitosti.

Dear Imgui lze snadno integrovat do C++ projektů, díky čemuž není potřeba se trápit s těžkopádným kódem. Pouze přilinkujete knihovnu a můžete začít vytvářet elegantní GUI s minimální námahou.

Příklad: Jednoduchá aplikace pro hádání čísel

Pro lepší ilustraci uvedu příklad jednoduché aplikace na hádání čísel, kterou lze v Dear Imgui snadno vytvořit. Hlavní smyčka aplikace obsahuje veškerou logiku pro dynamické vykreslování prvků uživatelského rozhraní, což je nejen intuitivní, ale i efektivní.

Rozhraní aplikace vytvořené v Dear Imgui

Veškerá "magie" se odehrává v hlavní smyčce, kde se jednotlivé grafické prvky dynamicky generují. Možnosti této knihovny jsou neuvěřitelně široké a poskytují vývojáři volnost při vytváření různých typů aplikací. Za zmínku stojí i demo aplikace, kterou si lze stáhnout přímo z webu projektu ImGui. Obsahuje předpřipravené vizuální prvky a komplexní návod, což umožňuje rychle pochopit, jak knihovnu používat.

Přehledný a efektivní kód

Není potřeba detailně rozebírat zdrojový kód – každý, kdo se již orientuje ve vývoji v C++, pochopí jednoduchost implementace aplikace do okna. Hlavní funkce může sice postupně narůstat, ale i tak zůstává kód přehledný a snadno udržovatelný. Tento přístup minimalizuje potřebu refaktorizace, což šetří čas i úsilí.

Rozhraní aplikace vytvořené v Dear Imgui

I přesto, že je soubor main.cpp trochu rozsáhlejší, pro základní ukázku, jak lze Dear Imgui využít, zcela postačuje.

#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#define GL_SILENCE_DEPRECATION
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h>
#endif
#include <GLFW/glfw3.h> // Will drag system OpenGL headers
#include <random>
#include <exception>
#include <stdexcept>
#include <iostream>
#include <filesystem>

#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
#endif

#ifdef __EMSCRIPTEN__
#include "../libs/emscripten/emscripten_mainloop_stub.h"
#endif

static void glfw_error_callback(int error, const char *description)
{
    fprintf(stderr, "GLFW Error %d: %s\n", error, description);
}

// Main code
int main(int, char **)
{

    glfwSetErrorCallback(glfw_error_callback);
    if (!glfwInit())
        return 1;

        // Decide GL+GLSL versions
#if defined(IMGUI_IMPL_OPENGL_ES2)
    // GL ES 2.0 + GLSL 100
    const char *glsl_version = "#version 100";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
#elif defined(__APPLE__)
    // GL 3.2 + GLSL 150
    const char *glsl_version = "#version 150";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);           // Required on Mac
#else
    // GL 3.0 + GLSL 130
    const char *glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    // glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);  // 3.2+ only
    // glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);            // 3.0+ only
#endif

    // Create window with graphics context
    GLFWwindow *window = glfwCreateWindow(1280, 720, "Game - Catch Number", nullptr, nullptr);
    if (window == nullptr)
        return 1;
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1); // Enable vsync

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO &io = ImGui::GetIO();
    (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;  // Enable Gamepad Controls

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();

    ImGuiStyle &style = ImGui::GetStyle();
    style.ScaleAllSizes(2.5f);

    // Setup Platform/Renderer backends
    ImGui_ImplGlfw_InitForOpenGL(window, true);
#ifdef __EMSCRIPTEN__
    ImGui_ImplGlfw_InstallEmscriptenCallbacks(window, "#canvas");
#endif
    ImGui_ImplOpenGL3_Init(glsl_version);

    // Load Fonts
    io.Fonts->AddFontFromFileTTF("../imgui/misc/fonts/Maximum Voltage Italic.ttf", 42.0f);

    // Our state
    bool show_demo_window = false;
    bool show_another_window = false;
    bool show_catch_number_window = true;
    bool show_message_window = true;

    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution dis(1, 1000);
    int randomNumber = dis(gen);
    std::string message_text = "";
    char input_buffer[256] = "";

    auto clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);

    // Main loop
#ifdef __EMSCRIPTEN__
    io.IniFilename = nullptr;
    EMSCRIPTEN_MAINLOOP_BEGIN
#else
    while (!glfwWindowShouldClose(window))
#endif
    {
        glfwPollEvents();

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        // 4. Show Catch Number Window
        if (show_catch_number_window)
        {
            ImGui::Begin("Catch NUMBER", &show_catch_number_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
            ImGui::Text("from 1 to 1000");
            ImGui::Text("Random number is %d", randomNumber);
            ImGui::InputText("Enter NUMBER", input_buffer, IM_ARRAYSIZE(input_buffer));

            if (ImGui::Button("Check NUMBER") || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
            {
                int input_number(0);

                try
                {
                    input_number = std::stoi(input_buffer);
                    if (input_number == randomNumber)
                    {
                        message_text = "Congratulation you catch the number " + std::to_string(randomNumber) + "!";
                        randomNumber = dis(gen);
                    }
                    else if (input_number < randomNumber)
                    {
                        show_message_window = true;
                        message_text = "Try bigger number!";
                    }
                    else
                    {
                        show_message_window = true;
                        message_text = "Try smaller number!";
                    }
                }
                catch (const std::invalid_argument &e)
                {
                    std::cerr << e.what() << '\n';
                    message_text = "Enter only NUMBER! Not a text!";
                }
            }
            if (show_message_window)
            {
                ImGui::Begin("Message", &show_message_window);
                ImGui::Text("%s", message_text.c_str());
                if (ImGui::Button("Hide this window"))
                    show_message_window = false;
                ImGui::End();
            }

            if (ImGui::Button("Exit Game"))
            {
                show_catch_number_window = false;
                return 0;
            }
            ImGui::End();
        }

        // Rendering
        ImGui::Render();
        int display_w;
        int display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        glfwSwapBuffers(window);
    }
#ifdef __EMSCRIPTEN__
    EMSCRIPTEN_MAINLOOP_END;
#endif

    // Cleanup
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(window);
    glfwTerminate();

    return 0;
}
VSCode IDE

Závěr

Dear Imgui je vynikající volbou pro každého vývojáře, který hledá jednoduchý a efektivní způsob, jak vytvářet grafická uživatelská rozhraní v C++. Tato knihovna se postará o všechny detaily, a přitom nabízí maximální flexibilitu a výkon.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *