How to Integrate ImGui with OpenGL: Backend Setup for Modern Core Profiles

TLDR: To integrate ImGui with OpenGL, create a core-profile OpenGL context, include imgui_impl_opengl3.cpp from the backends/ folder, and call ImGui_ImplOpenGL3_Init with a matching GLSL version string before driving the frame loop with ImGui_ImplOpenGL3_NewFrame and ImGui_ImplOpenGL3_RenderDrawData.

Dear ImGui is a renderer-agnostic UI library that ships its OpenGL support as a standalone backend in the ocornut/imgui repository. To integrate ImGui with OpenGL, you only need the imgui_impl_opengl3.* renderer backend paired with a platform backend such as GLFW, SDL, or Win32. The same backend works across OpenGL 2.0 through 4.6+ by automatically detecting and enabling modern features at runtime.

Where the OpenGL Backend Lives in ImGui

All OpenGL rendering logic lives in backends/imgui_impl_opengl3.cpp and backends/imgui_impl_opengl3.h. Because Dear ImGui itself is renderer-agnostic, these files handle shader compilation, vertex buffer management, and state restoration without touching the core imgui.cpp or imgui.h API. The repository's reference application in examples/example_glfw_opengl3/main.cpp demonstrates the standard integration pattern; for OpenGL 4.x you only need to adjust the context-creation window hints and the GLSL version string passed to the backend.

Creating an OpenGL 4.x Rendering Context

Request a core profile from your windowing library before initializing ImGui. The following GLFW hints configure an OpenGL 4.5 core context:

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // macOS
GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui + OpenGL 4.5", nullptr, nullptr);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);

You can substitute 4.1 or 4.6 by changing the major and minor hints. The ImGui OpenGL backend does not require a specific context version beyond what your own renderer needs.

Initializing the OpenGL Backend for ImGui

Call the platform backend first, then the renderer backend, and finally create the ImGui context.

Linking the Platform Backend

Link imgui_impl_glfw.cpp (or your platform equivalent) and initialize it for OpenGL:

IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;

ImGui_ImplGlfw_InitForOpenGL(window, true);

Passing the GLSL Version String

Pass a GLSL version string matching your context to ImGui_ImplOpenGL3_Init. For OpenGL 4.5, use "#version 450 core":

const char* glsl_version = "#version 450 core";
ImGui_ImplOpenGL3_Init(glsl_version);

If you pass nullptr, the backend attempts to infer a compatible shader version automatically. Explicit strings are recommended for OpenGL 4.x core profiles because they guarantee modern syntax such as layout(location = ...) inside the generated shaders. According to the ocornut/imgui source code, the function ImGui_ImplOpenGL3_CreateDeviceObjects prepends this GLSL string when assembling shader source (imgui_impl_opengl3.cpp, lines 104-126).

Implementing the Frame Render Loop

Each frame follows a strict sequence: platform new-frame, renderer new-frame, ImGui new-frame, UI construction, and finally drawing submission.

while (!glfwWindowShouldClose(window))
{
    glfwPollEvents();

    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    // --- Your UI code ---
    ImGui::Begin("OpenGL 4.5 Demo");
    ImGui::Text("Running with OpenGL %s", glGetString(GL_VERSION));
    ImGui::End();
    // --------------------

    ImGui::Render();
    int fb_w, fb_h;
    glfwGetFramebufferSize(window, &fb_w, &fb_h);
    glViewport(0, 0, fb_w, fb_h);
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
    glfwSwapBuffers(window);
}

ImGui_ImplOpenGL3_RenderDrawData consumes the draw lists produced by ImGui::Render and issues the actual OpenGL draw calls on your behalf.

Automatic OpenGL 4.x Feature Detection

The same imgui_impl_opengl3.cpp backend enables several advanced capabilities when the driver reports support, so you do not need conditional code in your application:

  • Upper-left clip origin via glClipControl — When the runtime flag HasClipOrigin is true, ImGui_ImplOpenGL3_SetupRenderState automatically toggles GL_UPPER_LEFT clip origin behavior (imgui_impl_opengl3.cpp, lines 55-63).
  • Sampler objects with glBindSampler — If IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER is defined and HasBindSampler is set at runtime, the backend uses ImGui_ImplOpenGL3_DrawCallback_SetSamplerLinear and ImGui_ImplOpenGL3_DrawCallback_SetSamplerNearest for filtering (imgui_impl_opengl3.cpp, lines 13-33).
  • Vertex-offset rendering via glDrawElementsBaseVertex — For meshes exceeding 64k vertices, the path guarded by IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET is activated inside ImGui_ImplOpenGL3_RenderDrawData (imgui_impl_opengl3.cpp, lines 200-207).
  • State preservation — The backend saves and restores every piece of OpenGL state it touches, including the current VAO, VBO, shader program, blend parameters, and viewport. This makes it safe to inject into an existing OpenGL 4.x rendering pipeline without side effects.

Build and Run a Complete GLFW Example

Here is a self-contained program that creates an OpenGL 4.5 context, initializes Dear ImGui, and runs the frame loop:

#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"
#include <GLFW/glfw3.h>

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    GLFWwindow* win = glfwCreateWindow(1280, 720, "ImGui + OpenGL 4.5", nullptr, nullptr);
    glfwMakeContextCurrent(win);
    glfwSwapInterval(1);

    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    ImGui::StyleColorsDark();

    ImGui_ImplGlfw_InitForOpenGL(win, true);
    const char* glsl = "#version 450 core";
    ImGui_ImplOpenGL3_Init(glsl);

    while (!glfwWindowShouldClose(win))
    {
        glfwPollEvents();

        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();

        ImGui::Begin("Hello GL 4.5");
        ImGui::Text("OpenGL version: %s", glGetString(GL_VERSION));
        ImGui::End();

        ImGui::Render();
        int w, h;
        glfwGetFramebufferSize(win, &w, &h);
        glViewport(0, 0, w, h);
        glClearColor(0.12f, 0.13f, 0.15f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        glfwSwapBuffers(win);
    }

    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
    glfwDestroyWindow(win);
    glfwTerminate();

    return 0;
}

Compile the example by linking GLFW and OpenGL. On Linux, the typical command is:

g++ -std=c++17 main.cpp -Ipath/to/imgui -Ipath/to/imgui/backends \
    -lglfw -lGL -ldl -pthread -o imgui_gl45

Proper Cleanup Sequence

Shutdown in the reverse order of initialization:

ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
glfwTerminate();

Summary

  • Integrate ImGui with OpenGL by adding imgui_impl_opengl3.cpp and a platform backend from the ocornut/imgui backends/ folder.
  • Create an OpenGL core context with windowing hints for version 4.x, then pass a matching GLSL string such as "#version 450 core" to ImGui_ImplOpenGL3_Init.
  • Drive each frame with ImGui_ImplOpenGL3_NewFrame, your platform NewFrame, ImGui::NewFrame, and finalize with ImGui_ImplOpenGL3_RenderDrawData.
  • The backend automatically leverages OpenGL 4.x capabilities—including glClipControl, sampler objects, and glDrawElementsBaseVertex—when the driver supports them.
  • State restoration in imgui_impl_opengl3.cpp ensures the backend does not corrupt your existing renderer state.

Frequently Asked Questions

Do I need a separate backend for OpenGL 4.x?

No. The same imgui_impl_opengl3 backend works with any OpenGL version from 2.0 through 4.6 and newer. It detects runtime capabilities such as HasBindSampler and HasClipOrigin, and selects appropriate shader paths inside ImGui_ImplOpenGL3_CreateDeviceObjects, so a single codebase covers all versions.

What GLSL version should I pass to ImGui_ImplOpenGL3_Init?

Pass a string that matches your context, for example "#version 450 core" for OpenGL 4.5. If you pass nullptr, the backend attempts to infer a compatible version, but explicit strings are safer for core profiles because they guarantee modern syntax like explicit layout(location) qualifiers.

Will the ImGui backend interfere with my custom OpenGL state?

No. According to the ocornut/imgui source code, imgui_impl_opengl3.cpp saves and restores every state object it touches, including the current VAO, VBO, shader program, blend parameters, and viewport. This makes it safe to call ImGui_ImplOpenGL3_RenderDrawData inside an existing OpenGL 4.x rendering pipeline.

Can I use this backend with OpenGL ES or older OpenGL 2.0?

Yes. The backend is not limited to OpenGL 4.x; it supports OpenGL ES 2.0/3.0 and desktop OpenGL 2.0+. Feature flags such as IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET and IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER are enabled only when the driver version or extensions indicate support, allowing the same code to run across hardware generations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →