openMSX
imgui_impl_opengl3.cc
Go to the documentation of this file.
1// dear imgui: Renderer Backend for modern OpenGL with shaders / programmatic pipeline
2// - Desktop GL: 2.x 3.x 4.x
3// - Embedded GL: ES 2.0 (WebGL 1.0), ES 3.0 (WebGL 2.0)
4// This needs to be used along with a Platform Backend (e.g. GLFW, SDL, Win32, custom..)
5
6// Implemented features:
7// [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID!
8// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices (Desktop OpenGL only).
9// [X] Renderer: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
10
11// About WebGL/ES:
12// - You need to '#define IMGUI_IMPL_OPENGL_ES2' or '#define IMGUI_IMPL_OPENGL_ES3' to use WebGL or OpenGL ES.
13// - This is done automatically on iOS, Android and Emscripten targets.
14// - For other targets, the define needs to be visible from the imgui_impl_opengl3.cpp compilation unit. If unsure, define globally or in imconfig.h.
15
16// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
17// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
18// Learn about Dear ImGui:
19// - FAQ https://dearimgui.com/faq
20// - Getting Started https://dearimgui.com/getting-started
21// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
22// - Introduction, links and more at the top of imgui.cpp
23
24// CHANGELOG
25// (minor and older changes stripped away, please see git history for details)
26// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
27// 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap.
28// 2024-06-28: OpenGL: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748)
29// 2024-05-07: OpenGL: Update loader for Linux to support EGL/GLVND. (#7562)
30// 2024-04-16: OpenGL: Detect ES3 contexts on desktop based on version string, to e.g. avoid calling glPolygonMode() on them. (#7447)
31// 2024-01-09: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" and variants, fixing regression on distros missing a symlink.
32// 2023-11-08: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" instead of "libGL.so.1", accommodating for NetBSD systems having only "libGL.so.3" available. (#6983)
33// 2023-10-05: OpenGL: Rename symbols in our internal loader so that LTO compilation with another copy of gl3w is possible. (#6875, #6668, #4445)
34// 2023-06-20: OpenGL: Fixed erroneous use glGetIntegerv(GL_CONTEXT_PROFILE_MASK) on contexts lower than 3.2. (#6539, #6333)
35// 2023-05-09: OpenGL: Support for glBindSampler() backup/restore on ES3. (#6375)
36// 2023-04-18: OpenGL: Restore front and back polygon mode separately when supported by context. (#6333)
37// 2023-03-23: OpenGL: Properly restoring "no shader program bound" if it was the case prior to running the rendering function. (#6267, #6220, #6224)
38// 2023-03-15: OpenGL: Fixed GL loader crash when GL_VERSION returns NULL. (#6154, #4445, #3530)
39// 2023-03-06: OpenGL: Fixed restoration of a potentially deleted OpenGL program, by calling glIsProgram(). (#6220, #6224)
40// 2022-11-09: OpenGL: Reverted use of glBufferSubData(), too many corruptions issues + old issues seemingly can't be reproed with Intel drivers nowadays (revert 2021-12-15 and 2022-05-23 changes).
41// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
42// 2022-09-27: OpenGL: Added ability to '#define IMGUI_IMPL_OPENGL_DEBUG'.
43// 2022-05-23: OpenGL: Reworking 2021-12-15 "Using buffer orphaning" so it only happens on Intel GPU, seems to cause problems otherwise. (#4468, #4825, #4832, #5127).
44// 2022-05-13: OpenGL: Fixed state corruption on OpenGL ES 2.0 due to not preserving GL_ELEMENT_ARRAY_BUFFER_BINDING and vertex attribute states.
45// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
46// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
47// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
48// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
49// 2021-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
50// 2021-06-21: OpenGL: Destroy individual vertex/fragment shader objects right after they are linked into the main shader.
51// 2021-05-24: OpenGL: Access GL_CLIP_ORIGIN when "GL_ARB_clip_control" extension is detected, inside of just OpenGL 4.5 version.
52// 2021-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
53// 2021-04-06: OpenGL: Don't try to read GL_CLIP_ORIGIN unless we're OpenGL 4.5 or greater.
54// 2021-02-18: OpenGL: Change blending equation to preserve alpha in output buffer.
55// 2021-01-03: OpenGL: Backup, setup and restore GL_STENCIL_TEST state.
56// 2020-10-23: OpenGL: Backup, setup and restore GL_PRIMITIVE_RESTART state.
57// 2020-10-15: OpenGL: Use glGetString(GL_VERSION) instead of glGetIntegerv(GL_MAJOR_VERSION, ...) when the later returns zero (e.g. Desktop GL 2.x)
58// 2020-09-17: OpenGL: Fix to avoid compiling/calling glBindSampler() on ES or pre 3.3 context which have the defines set by a loader.
59// 2020-07-10: OpenGL: Added support for glad2 OpenGL loader.
60// 2020-05-08: OpenGL: Made default GLSL version 150 (instead of 130) on OSX.
61// 2020-04-21: OpenGL: Fixed handling of glClipControl(GL_UPPER_LEFT) by inverting projection matrix.
62// 2020-04-12: OpenGL: Fixed context version check mistakenly testing for 4.0+ instead of 3.2+ to enable ImGuiBackendFlags_RendererHasVtxOffset.
63// 2020-03-24: OpenGL: Added support for glbinding 2.x OpenGL loader.
64// 2020-01-07: OpenGL: Added support for glbinding 3.x OpenGL loader.
65// 2019-10-25: OpenGL: Using a combination of GL define and runtime GL version to decide whether to use glDrawElementsBaseVertex(). Fix building with pre-3.2 GL loaders.
66// 2019-09-22: OpenGL: Detect default GL loader using __has_include compiler facility.
67// 2019-09-16: OpenGL: Tweak initialization code to allow application calling ImGui_ImplOpenGL3_CreateFontsTexture() before the first NewFrame() call.
68// 2019-05-29: OpenGL: Desktop GL only: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
69// 2019-04-30: OpenGL: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
70// 2019-03-29: OpenGL: Not calling glBindBuffer more than necessary in the render loop.
71// 2019-03-15: OpenGL: Added a GL call + comments in ImGui_ImplOpenGL3_Init() to detect uninitialized GL function loaders early.
72// 2019-03-03: OpenGL: Fix support for ES 2.0 (WebGL 1.0).
73// 2019-02-20: OpenGL: Fix for OSX not supporting OpenGL 4.5, we don't try to read GL_CLIP_ORIGIN even if defined by the headers/loader.
74// 2019-02-11: OpenGL: Projecting clipping rectangles correctly using draw_data->FramebufferScale to allow multi-viewports for retina display.
75// 2019-02-01: OpenGL: Using GLSL 410 shaders for any version over 410 (e.g. 430, 450).
76// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
77// 2018-11-13: OpenGL: Support for GL 4.5's glClipControl(GL_UPPER_LEFT) / GL_CLIP_ORIGIN.
78// 2018-08-29: OpenGL: Added support for more OpenGL loaders: glew and glad, with comments indicative that any loader can be used.
79// 2018-08-09: OpenGL: Default to OpenGL ES 3 on iOS and Android. GLSL version default to "#version 300 ES".
80// 2018-07-30: OpenGL: Support for GLSL 300 ES and 410 core. Fixes for Emscripten compilation.
81// 2018-07-10: OpenGL: Support for more GLSL versions (based on the GLSL version string). Added error output when shaders fail to compile/link.
82// 2018-06-08: Misc: Extracted imgui_impl_opengl3.cpp/.h away from the old combined GLFW/SDL+OpenGL3 examples.
83// 2018-06-08: OpenGL: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
84// 2018-05-25: OpenGL: Removed unnecessary backup/restore of GL_ELEMENT_ARRAY_BUFFER_BINDING since this is part of the VAO state.
85// 2018-05-14: OpenGL: Making the call to glBindSampler() optional so 3.2 context won't fail if the function is a nullptr pointer.
86// 2018-03-06: OpenGL: Added const char* glsl_version parameter to ImGui_ImplOpenGL3_Init() so user can override the GLSL version e.g. "#version 150".
87// 2018-02-23: OpenGL: Create the VAO in the render function so the setup can more easily be used with multiple shared GL context.
88// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplSdlGL3_RenderDrawData() in the .h file so you can call it yourself.
89// 2018-01-07: OpenGL: Changed GLSL shader version from 330 to 150.
90// 2017-09-01: OpenGL: Save and restore current bound sampler. Save and restore current polygon mode.
91// 2017-05-01: OpenGL: Fixed save and restore of current blend func state.
92// 2017-05-01: OpenGL: Fixed save and restore of current GL_ACTIVE_TEXTURE.
93// 2016-09-05: OpenGL: Fixed save and restore of current scissor rectangle.
94// 2016-07-29: OpenGL: Explicitly setting GL_UNPACK_ROW_LENGTH to reduce issues because SDL changes it. (#752)
95
96//----------------------------------------
97// OpenGL GLSL GLSL
98// version version string
99//----------------------------------------
100// 2.0 110 "#version 110"
101// 2.1 120 "#version 120"
102// 3.0 130 "#version 130"
103// 3.1 140 "#version 140"
104// 3.2 150 "#version 150"
105// 3.3 330 "#version 330 core"
106// 4.0 400 "#version 400 core"
107// 4.1 410 "#version 410 core"
108// 4.2 420 "#version 410 core"
109// 4.3 430 "#version 430 core"
110// ES 2.0 100 "#version 100" = WebGL 1.0
111// ES 3.0 300 "#version 300 es" = WebGL 2.0
112//----------------------------------------
113
114#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
115#define _CRT_SECURE_NO_WARNINGS
116#endif
117
118#include "imgui.h"
119#ifndef IMGUI_DISABLE
120#include "imgui_impl_opengl3.h"
121#include <stdio.h>
122#include <stdint.h> // intptr_t
123#if defined(__APPLE__)
124#include <TargetConditionals.h>
125#endif
126
127// Clang/GCC warnings with -Weverything
128#if defined(__clang__)
129#pragma clang diagnostic push
130#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: ignore unknown flags
131#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
132#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
133#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used
134#pragma clang diagnostic ignored "-Wnonportable-system-include-path"
135#pragma clang diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
136#endif
137#if defined(__GNUC__)
138#pragma GCC diagnostic push
139#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
140#pragma GCC diagnostic ignored "-Wunknown-warning-option" // warning: unknown warning group 'xxx'
141#pragma GCC diagnostic ignored "-Wcast-function-type" // warning: cast between incompatible function types (for loader)
142#endif
143
144// GL includes
145#if defined(IMGUI_IMPL_OPENGL_ES2)
146#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
147#include <OpenGLES/ES2/gl.h> // Use GL ES 2
148#else
149#include <GLES2/gl2.h> // Use GL ES 2
150#endif
151#if defined(__EMSCRIPTEN__)
152#ifndef GL_GLEXT_PROTOTYPES
153#define GL_GLEXT_PROTOTYPES
154#endif
155#include <GLES2/gl2ext.h>
156#endif
157#elif defined(IMGUI_IMPL_OPENGL_ES3)
158#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
159#include <OpenGLES/ES3/gl.h> // Use GL ES 3
160#else
161#include <GLES3/gl3.h> // Use GL ES 3
162#endif
163#elif !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
164// Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
165// Helper libraries are often used for this purpose! Here we are using our own minimal custom loader based on gl3w.
166// In the rest of your app/engine, you can use another loader of your choice (gl3w, glew, glad, glbinding, glext, glLoadGen, etc.).
167// If you happen to be developing a new feature for this backend (imgui_impl_opengl3.cpp):
168// - You may need to regenerate imgui_impl_opengl3_loader.h to add new symbols. See https://github.com/dearimgui/gl3w_stripped
169// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
170// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
171#define IMGL3W_IMPL
172#include "imgui_impl_opengl3_loader.h"
173#endif
174
175// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension
176#ifndef IMGUI_IMPL_OPENGL_ES2
177#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
178#elif defined(__EMSCRIPTEN__)
179#define IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
180#define glBindVertexArray glBindVertexArrayOES
181#define glGenVertexArrays glGenVertexArraysOES
182#define glDeleteVertexArrays glDeleteVertexArraysOES
183#define GL_VERTEX_ARRAY_BINDING GL_VERTEX_ARRAY_BINDING_OES
184#endif
185
186// Desktop GL 2.0+ has extension and glPolygonMode() which GL ES and WebGL don't have..
187// A desktop ES context can technically compile fine with our loader, so we also perform a runtime checks
188#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3)
189#define IMGUI_IMPL_OPENGL_HAS_EXTENSIONS // has glGetIntegerv(GL_NUM_EXTENSIONS)
190#define IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE // may have glPolygonMode()
191#endif
192
193// Desktop GL 2.1+ and GL ES 3.0+ have glBindBuffer() with GL_PIXEL_UNPACK_BUFFER target.
194#if !defined(IMGUI_IMPL_OPENGL_ES2)
195#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK
196#endif
197
198// Desktop GL 3.1+ has GL_PRIMITIVE_RESTART state
199#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_1)
200#define IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
201#endif
202
203// Desktop GL 3.2+ has glDrawElementsBaseVertex() which GL ES and WebGL don't have.
204#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && defined(GL_VERSION_3_2)
205#define IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
206#endif
207
208// Desktop GL 3.3+ and GL ES 3.0+ have glBindSampler()
209#if !defined(IMGUI_IMPL_OPENGL_ES2) && (defined(IMGUI_IMPL_OPENGL_ES3) || defined(GL_VERSION_3_3))
210#define IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
211#endif
212
213// [Debugging]
214//#define IMGUI_IMPL_OPENGL_DEBUG
215#ifdef IMGUI_IMPL_OPENGL_DEBUG
216#include <stdio.h>
217#define GL_CALL(_CALL) do { _CALL; GLenum gl_err = glGetError(); if (gl_err != 0) fprintf(stderr, "GL error 0x%x returned from '%s'.\n", gl_err, #_CALL); } while (0) // Call with error check
218#else
219#define GL_CALL(_CALL) _CALL // Call without error check
220#endif
221
222// OpenGL Data
224{
225 GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
226 char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings.
233 GLint AttribLocationTex; // Uniforms location
235 GLuint AttribLocationVtxPos; // Vertex attributes location
240 GLsizeiptr IndexBufferSize;
244
245 ImGui_ImplOpenGL3_Data() { memset((void*)this, 0, sizeof(*this)); }
246};
247
248// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
249// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
250static ImGui_ImplOpenGL3_Data* ImGui_ImplOpenGL3_GetBackendData()
251{
252 return ImGui::GetCurrentContext() ? (ImGui_ImplOpenGL3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
253}
254
255// Forward Declarations
256static void ImGui_ImplOpenGL3_InitMultiViewportSupport();
257static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport();
258
259// OpenGL vertex attribute state (for ES 1.0 and ES 2.0 only)
260#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
261struct ImGui_ImplOpenGL3_VtxAttribState
262{
263 GLint Enabled, Size, Type, Normalized, Stride;
264 GLvoid* Ptr;
265
266 void GetState(GLint index)
267 {
268 glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &Enabled);
269 glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_SIZE, &Size);
270 glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_TYPE, &Type);
271 glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &Normalized);
272 glGetVertexAttribiv(index, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &Stride);
273 glGetVertexAttribPointerv(index, GL_VERTEX_ATTRIB_ARRAY_POINTER, &Ptr);
274 }
275 void SetState(GLint index)
276 {
277 glVertexAttribPointer(index, Size, Type, (GLboolean)Normalized, Stride, Ptr);
278 if (Enabled) glEnableVertexAttribArray(index); else glDisableVertexAttribArray(index);
279 }
280};
281#endif
282
283// Functions
284bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
285{
286 ImGuiIO& io = ImGui::GetIO();
287 IMGUI_CHECKVERSION();
288 IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
289
290 // Initialize our loader
291#if !defined(IMGUI_IMPL_OPENGL_ES2) && !defined(IMGUI_IMPL_OPENGL_ES3) && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM)
292 if (imgl3wInit() != 0)
293 {
294 fprintf(stderr, "Failed to initialize OpenGL loader!\n");
295 return false;
296 }
297#endif
298
299 // Setup backend capabilities flags
301 io.BackendRendererUserData = (void*)bd;
302 io.BackendRendererName = "imgui_impl_opengl3";
303
304 // Query for GL version (e.g. 320 for GL 3.2)
305#if defined(IMGUI_IMPL_OPENGL_ES2)
306 // GLES 2
307 bd->GlVersion = 200;
308 bd->GlProfileIsES2 = true;
309#else
310 // Desktop or GLES 3
311 const char* gl_version_str = (const char*)glGetString(GL_VERSION);
312 GLint major = 0;
313 GLint minor = 0;
314 glGetIntegerv(GL_MAJOR_VERSION, &major);
315 glGetIntegerv(GL_MINOR_VERSION, &minor);
316 if (major == 0 && minor == 0)
317 sscanf(gl_version_str, "%d.%d", &major, &minor); // Query GL_VERSION in desktop GL 2.x, the string will start with "<major>.<minor>"
318 bd->GlVersion = (GLuint)(major * 100 + minor * 10);
319#if defined(GL_CONTEXT_PROFILE_MASK)
320 if (bd->GlVersion >= 320)
321 glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &bd->GlProfileMask);
322 bd->GlProfileIsCompat = (bd->GlProfileMask & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT) != 0;
323#endif
324
325#if defined(IMGUI_IMPL_OPENGL_ES3)
326 bd->GlProfileIsES3 = true;
327#else
328 if (strncmp(gl_version_str, "OpenGL ES 3", 11) == 0)
329 bd->GlProfileIsES3 = true;
330#endif
331
332 bd->UseBufferSubData = false;
333 /*
334 // Query vendor to enable glBufferSubData kludge
335#ifdef _WIN32
336 if (const char* vendor = (const char*)glGetString(GL_VENDOR))
337 if (strncmp(vendor, "Intel", 5) == 0)
338 bd->UseBufferSubData = true;
339#endif
340 */
341#endif
342
343#ifdef IMGUI_IMPL_OPENGL_DEBUG
344 printf("GlVersion = %d, \"%s\"\nGlProfileIsCompat = %d\nGlProfileMask = 0x%X\nGlProfileIsES2 = %d, GlProfileIsES3 = %d\nGL_VENDOR = '%s'\nGL_RENDERER = '%s'\n", bd->GlVersion, gl_version_str, bd->GlProfileIsCompat, bd->GlProfileMask, bd->GlProfileIsES2, bd->GlProfileIsES3, (const char*)glGetString(GL_VENDOR), (const char*)glGetString(GL_RENDERER)); // [DEBUG]
345#endif
346
347#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
348 if (bd->GlVersion >= 320)
349 io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
350#endif
351 io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional)
352
353 // Store GLSL version string so we can refer to it later in case we recreate shaders.
354 // Note: GLSL version is NOT the same as GL version. Leave this to nullptr if unsure.
355 if (glsl_version == nullptr)
356 {
357#if defined(IMGUI_IMPL_OPENGL_ES2)
358 glsl_version = "#version 100";
359#elif defined(IMGUI_IMPL_OPENGL_ES3)
360 glsl_version = "#version 300 es";
361#elif defined(__APPLE__)
362 glsl_version = "#version 150";
363#else
364 glsl_version = "#version 130";
365#endif
366 }
367 IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(bd->GlslVersionString));
368 strcpy(bd->GlslVersionString, glsl_version);
369 strcat(bd->GlslVersionString, "\n");
370
371 // Make an arbitrary GL call (we don't actually need the result)
372 // IF YOU GET A CRASH HERE: it probably means the OpenGL function loader didn't do its job. Let us know!
373 GLint current_texture;
374 glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
375
376 // Detect extensions we support
377#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
378 bd->HasPolygonMode = (!bd->GlProfileIsES2 && !bd->GlProfileIsES3);
379#endif
380 bd->HasClipOrigin = (bd->GlVersion >= 450);
381#ifdef IMGUI_IMPL_OPENGL_HAS_EXTENSIONS
382 GLint num_extensions = 0;
383 glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
384 for (GLint i = 0; i < num_extensions; i++)
385 {
386 const char* extension = (const char*)glGetStringi(GL_EXTENSIONS, i);
387 if (extension != nullptr && strcmp(extension, "GL_ARB_clip_control") == 0)
388 bd->HasClipOrigin = true;
389 }
390#endif
391
392 ImGui_ImplOpenGL3_InitMultiViewportSupport();
393
394 return true;
395}
396
398{
399 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
400 IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
401 ImGuiIO& io = ImGui::GetIO();
402
403 ImGui_ImplOpenGL3_ShutdownMultiViewportSupport();
405 io.BackendRendererName = nullptr;
406 io.BackendRendererUserData = nullptr;
407 io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasViewports);
408 IM_DELETE(bd);
409}
410
412{
413 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
414 IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplOpenGL3_Init()?");
415
416 if (!bd->ShaderHandle)
418 if (!bd->FontTexture)
420}
421
422static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
423{
424 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
425
426 // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
427 glEnable(GL_BLEND);
428 glBlendEquation(GL_FUNC_ADD);
429 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
430 glDisable(GL_CULL_FACE);
431 glDisable(GL_DEPTH_TEST);
432 glDisable(GL_STENCIL_TEST);
433 glEnable(GL_SCISSOR_TEST);
434#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
435 if (bd->GlVersion >= 310)
436 glDisable(GL_PRIMITIVE_RESTART);
437#endif
438#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
439 if (bd->HasPolygonMode)
440 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
441#endif
442
443 // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
444#if defined(GL_CLIP_ORIGIN)
445 bool clip_origin_lower_left = true;
446 if (bd->HasClipOrigin)
447 {
448 GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)&current_clip_origin);
449 if (current_clip_origin == GL_UPPER_LEFT)
450 clip_origin_lower_left = false;
451 }
452#endif
453
454 // Setup viewport, orthographic projection matrix
455 // Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
456 GL_CALL(glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height));
457 float L = draw_data->DisplayPos.x;
458 float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x;
459 float T = draw_data->DisplayPos.y;
460 float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y;
461#if defined(GL_CLIP_ORIGIN)
462 if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
463#endif
464 const float ortho_projection[4][4] =
465 {
466 { 2.0f/(R-L), 0.0f, 0.0f, 0.0f },
467 { 0.0f, 2.0f/(T-B), 0.0f, 0.0f },
468 { 0.0f, 0.0f, -1.0f, 0.0f },
469 { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f },
470 };
471 glUseProgram(bd->ShaderHandle);
472 glUniform1i(bd->AttribLocationTex, 0);
473 glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
474
475#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
476 if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
477 glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 and GL ES 3.0 may set that otherwise.
478#endif
479
480 (void)vertex_array_object;
481#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
482 glBindVertexArray(vertex_array_object);
483#endif
484
485 // Bind vertex/index buffers and setup attributes for ImDrawVert
486 GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, bd->VboHandle));
487 GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bd->ElementsHandle));
488 GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxPos));
489 GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxUV));
490 GL_CALL(glEnableVertexAttribArray(bd->AttribLocationVtxColor));
491 GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, pos)));
492 GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, uv)));
493 GL_CALL(glVertexAttribPointer(bd->AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(ImDrawVert), (GLvoid*)offsetof(ImDrawVert, col)));
494}
495
496// OpenGL3 Render function.
497// Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly.
498// This is in order to be able to run within an OpenGL engine that doesn't do so.
499void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
500{
501 // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
502 int fb_width = (int)(draw_data->DisplaySize.x * draw_data->FramebufferScale.x);
503 int fb_height = (int)(draw_data->DisplaySize.y * draw_data->FramebufferScale.y);
504 if (fb_width <= 0 || fb_height <= 0)
505 return;
506
507 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
508
509 // Backup GL state
510 GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, (GLint*)&last_active_texture);
511 glActiveTexture(GL_TEXTURE0);
512 GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, (GLint*)&last_program);
513 GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint*)&last_texture);
514#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
515 GLuint last_sampler; if (bd->GlVersion >= 330 || bd->GlProfileIsES3) { glGetIntegerv(GL_SAMPLER_BINDING, (GLint*)&last_sampler); } else { last_sampler = 0; }
516#endif
517 GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, (GLint*)&last_array_buffer);
518#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
519 // This is part of VAO on OpenGL 3.0+ and OpenGL ES 3.0+.
520 GLint last_element_array_buffer; glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
521 ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_pos; last_vtx_attrib_state_pos.GetState(bd->AttribLocationVtxPos);
522 ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_uv; last_vtx_attrib_state_uv.GetState(bd->AttribLocationVtxUV);
523 ImGui_ImplOpenGL3_VtxAttribState last_vtx_attrib_state_color; last_vtx_attrib_state_color.GetState(bd->AttribLocationVtxColor);
524#endif
525#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
526 GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (GLint*)&last_vertex_array_object);
527#endif
528#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
529 GLint last_polygon_mode[2]; if (bd->HasPolygonMode) { glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); }
530#endif
531 GLint last_viewport[4]; glGetIntegerv(GL_VIEWPORT, last_viewport);
532 GLint last_scissor_box[4]; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box);
533 GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb);
534 GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb);
535 GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha);
536 GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha);
537 GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb);
538 GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha);
539 GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
540 GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
541 GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
542 GLboolean last_enable_stencil_test = glIsEnabled(GL_STENCIL_TEST);
543 GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
544#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
545 GLboolean last_enable_primitive_restart = (bd->GlVersion >= 310) ? glIsEnabled(GL_PRIMITIVE_RESTART) : GL_FALSE;
546#endif
547
548 // Setup desired GL state
549 // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
550 // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
551 GLuint vertex_array_object = 0;
552#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
553 GL_CALL(glGenVertexArrays(1, &vertex_array_object));
554#endif
555 ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
556
557 // Will project scissor/clipping rectangles into framebuffer space
558 ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
559 ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
560
561 // Render command lists
562 for (int n = 0; n < draw_data->CmdListsCount; n++)
563 {
564 const ImDrawList* draw_list = draw_data->CmdLists[n];
565
566 // Upload vertex/index buffers
567 // - OpenGL drivers are in a very sorry state nowadays....
568 // During 2021 we attempted to switch from glBufferData() to orphaning+glBufferSubData() following reports
569 // of leaks on Intel GPU when using multi-viewports on Windows.
570 // - After this we kept hearing of various display corruptions issues. We started disabling on non-Intel GPU, but issues still got reported on Intel.
571 // - We are now back to using exclusively glBufferData(). So bd->UseBufferSubData IS ALWAYS FALSE in this code.
572 // We are keeping the old code path for a while in case people finding new issues may want to test the bd->UseBufferSubData path.
573 // - See https://github.com/ocornut/imgui/issues/4468 and please report any corruption issues.
574 const GLsizeiptr vtx_buffer_size = (GLsizeiptr)draw_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
575 const GLsizeiptr idx_buffer_size = (GLsizeiptr)draw_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
576 if (bd->UseBufferSubData)
577 {
578 if (bd->VertexBufferSize < vtx_buffer_size)
579 {
580 bd->VertexBufferSize = vtx_buffer_size;
581 GL_CALL(glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, nullptr, GL_STREAM_DRAW));
582 }
583 if (bd->IndexBufferSize < idx_buffer_size)
584 {
585 bd->IndexBufferSize = idx_buffer_size;
586 GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, nullptr, GL_STREAM_DRAW));
587 }
588 GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)draw_list->VtxBuffer.Data));
589 GL_CALL(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)draw_list->IdxBuffer.Data));
590 }
591 else
592 {
593 GL_CALL(glBufferData(GL_ARRAY_BUFFER, vtx_buffer_size, (const GLvoid*)draw_list->VtxBuffer.Data, GL_STREAM_DRAW));
594 GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_buffer_size, (const GLvoid*)draw_list->IdxBuffer.Data, GL_STREAM_DRAW));
595 }
596
597 for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
598 {
599 const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
600 if (pcmd->UserCallback != nullptr)
601 {
602 // User callback, registered via ImDrawList::AddCallback()
603 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
604 if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
605 ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
606 else
607 pcmd->UserCallback(draw_list, pcmd);
608 }
609 else
610 {
611 // Project scissor/clipping rectangles into framebuffer space
612 ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
613 ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
614 if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
615 continue;
616
617 // Apply scissor/clipping rectangle (Y is inverted in OpenGL)
618 GL_CALL(glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
619
620 // Bind texture, Draw
621 GL_CALL(glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
622#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
623 if (bd->GlVersion >= 320)
624 GL_CALL(glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset));
625 else
626#endif
627 GL_CALL(glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
628 }
629 }
630 }
631
632 // Destroy the temporary VAO
633#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
634 GL_CALL(glDeleteVertexArrays(1, &vertex_array_object));
635#endif
636
637 // Restore modified GL state
638 // This "glIsProgram()" check is required because if the program is "pending deletion" at the time of binding backup, it will have been deleted by now and will cause an OpenGL error. See #6220.
639 if (last_program == 0 || glIsProgram(last_program)) glUseProgram(last_program);
640 glBindTexture(GL_TEXTURE_2D, last_texture);
641#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_SAMPLER
642 if (bd->GlVersion >= 330 || bd->GlProfileIsES3)
643 glBindSampler(0, last_sampler);
644#endif
645 glActiveTexture(last_active_texture);
646#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
647 glBindVertexArray(last_vertex_array_object);
648#endif
649 glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
650#ifndef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
651 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
652 last_vtx_attrib_state_pos.SetState(bd->AttribLocationVtxPos);
653 last_vtx_attrib_state_uv.SetState(bd->AttribLocationVtxUV);
654 last_vtx_attrib_state_color.SetState(bd->AttribLocationVtxColor);
655#endif
656 glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
657 glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
658 if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
659 if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
660 if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
661 if (last_enable_stencil_test) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST);
662 if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
663#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_PRIMITIVE_RESTART
664 if (bd->GlVersion >= 310) { if (last_enable_primitive_restart) glEnable(GL_PRIMITIVE_RESTART); else glDisable(GL_PRIMITIVE_RESTART); }
665#endif
666
667#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
668 // Desktop OpenGL 3.0 and OpenGL 3.1 had separate polygon draw modes for front-facing and back-facing faces of polygons
669 if (bd->HasPolygonMode) { if (bd->GlVersion <= 310 || bd->GlProfileIsCompat) { glPolygonMode(GL_FRONT, (GLenum)last_polygon_mode[0]); glPolygonMode(GL_BACK, (GLenum)last_polygon_mode[1]); } else { glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); } }
670#endif // IMGUI_IMPL_OPENGL_MAY_HAVE_POLYGON_MODE
671
672 glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]);
673 glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]);
674 (void)bd; // Not all compilation paths use this
675}
676
678{
679 ImGuiIO& io = ImGui::GetIO();
680 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
681
682 // Build texture atlas
683 unsigned char* pixels;
684 int width, height;
685 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
686
687 // Upload texture to graphics system
688 // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
689 GLint last_texture;
690 GL_CALL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture));
691 GL_CALL(glGenTextures(1, &bd->FontTexture));
692 GL_CALL(glBindTexture(GL_TEXTURE_2D, bd->FontTexture));
693 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
694 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
695 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
696 GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
697#ifdef GL_UNPACK_ROW_LENGTH // Not on WebGL/ES
698 GL_CALL(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0));
699#endif
700 GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
701
702 // Store our identifier
703 io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
704
705 // Restore state
706 GL_CALL(glBindTexture(GL_TEXTURE_2D, last_texture));
707
708 return true;
709}
710
712{
713 ImGuiIO& io = ImGui::GetIO();
714 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
715 if (bd->FontTexture)
716 {
717 glDeleteTextures(1, &bd->FontTexture);
718 io.Fonts->SetTexID(0);
719 bd->FontTexture = 0;
720 }
721}
722
723// If you get an error please report on github. You may try different GL context version or GLSL version. See GL<>GLSL version table at the top of this file.
724static bool CheckShader(GLuint handle, const char* desc)
725{
726 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
727 GLint status = 0, log_length = 0;
728 glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
729 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
730 if ((GLboolean)status == GL_FALSE)
731 fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s! With GLSL: %s\n", desc, bd->GlslVersionString);
732 if (log_length > 1)
733 {
734 ImVector<char> buf;
735 buf.resize((int)(log_length + 1));
736 glGetShaderInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
737 fprintf(stderr, "%s\n", buf.begin());
738 }
739 return (GLboolean)status == GL_TRUE;
740}
741
742// If you get an error please report on GitHub. You may try different GL context version or GLSL version.
743static bool CheckProgram(GLuint handle, const char* desc)
744{
745 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
746 GLint status = 0, log_length = 0;
747 glGetProgramiv(handle, GL_LINK_STATUS, &status);
748 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
749 if ((GLboolean)status == GL_FALSE)
750 fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! With GLSL %s\n", desc, bd->GlslVersionString);
751 if (log_length > 1)
752 {
753 ImVector<char> buf;
754 buf.resize((int)(log_length + 1));
755 glGetProgramInfoLog(handle, log_length, nullptr, (GLchar*)buf.begin());
756 fprintf(stderr, "%s\n", buf.begin());
757 }
758 return (GLboolean)status == GL_TRUE;
759}
760
762{
763 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
764
765 // Backup GL state
766 GLint last_texture, last_array_buffer;
767 glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
768 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
769#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK
770 GLint last_pixel_unpack_buffer = 0;
771 if (bd->GlVersion >= 210) { glGetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &last_pixel_unpack_buffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); }
772#endif
773#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
774 GLint last_vertex_array;
775 glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
776#endif
777
778 // Parse GLSL version string
779 int glsl_version = 130;
780 sscanf(bd->GlslVersionString, "#version %d", &glsl_version);
781
782 const GLchar* vertex_shader_glsl_120 =
783 "uniform mat4 ProjMtx;\n"
784 "attribute vec2 Position;\n"
785 "attribute vec2 UV;\n"
786 "attribute vec4 Color;\n"
787 "varying vec2 Frag_UV;\n"
788 "varying vec4 Frag_Color;\n"
789 "void main()\n"
790 "{\n"
791 " Frag_UV = UV;\n"
792 " Frag_Color = Color;\n"
793 " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
794 "}\n";
795
796 const GLchar* vertex_shader_glsl_130 =
797 "uniform mat4 ProjMtx;\n"
798 "in vec2 Position;\n"
799 "in vec2 UV;\n"
800 "in vec4 Color;\n"
801 "out vec2 Frag_UV;\n"
802 "out vec4 Frag_Color;\n"
803 "void main()\n"
804 "{\n"
805 " Frag_UV = UV;\n"
806 " Frag_Color = Color;\n"
807 " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
808 "}\n";
809
810 const GLchar* vertex_shader_glsl_300_es =
811 "precision highp float;\n"
812 "layout (location = 0) in vec2 Position;\n"
813 "layout (location = 1) in vec2 UV;\n"
814 "layout (location = 2) in vec4 Color;\n"
815 "uniform mat4 ProjMtx;\n"
816 "out vec2 Frag_UV;\n"
817 "out vec4 Frag_Color;\n"
818 "void main()\n"
819 "{\n"
820 " Frag_UV = UV;\n"
821 " Frag_Color = Color;\n"
822 " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
823 "}\n";
824
825 const GLchar* vertex_shader_glsl_410_core =
826 "layout (location = 0) in vec2 Position;\n"
827 "layout (location = 1) in vec2 UV;\n"
828 "layout (location = 2) in vec4 Color;\n"
829 "uniform mat4 ProjMtx;\n"
830 "out vec2 Frag_UV;\n"
831 "out vec4 Frag_Color;\n"
832 "void main()\n"
833 "{\n"
834 " Frag_UV = UV;\n"
835 " Frag_Color = Color;\n"
836 " gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
837 "}\n";
838
839 const GLchar* fragment_shader_glsl_120 =
840 "#ifdef GL_ES\n"
841 " precision mediump float;\n"
842 "#endif\n"
843 "uniform sampler2D Texture;\n"
844 "varying vec2 Frag_UV;\n"
845 "varying vec4 Frag_Color;\n"
846 "void main()\n"
847 "{\n"
848 " gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
849 "}\n";
850
851 const GLchar* fragment_shader_glsl_130 =
852 "uniform sampler2D Texture;\n"
853 "in vec2 Frag_UV;\n"
854 "in vec4 Frag_Color;\n"
855 "out vec4 Out_Color;\n"
856 "void main()\n"
857 "{\n"
858 " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
859 "}\n";
860
861 const GLchar* fragment_shader_glsl_300_es =
862 "precision mediump float;\n"
863 "uniform sampler2D Texture;\n"
864 "in vec2 Frag_UV;\n"
865 "in vec4 Frag_Color;\n"
866 "layout (location = 0) out vec4 Out_Color;\n"
867 "void main()\n"
868 "{\n"
869 " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
870 "}\n";
871
872 const GLchar* fragment_shader_glsl_410_core =
873 "in vec2 Frag_UV;\n"
874 "in vec4 Frag_Color;\n"
875 "uniform sampler2D Texture;\n"
876 "layout (location = 0) out vec4 Out_Color;\n"
877 "void main()\n"
878 "{\n"
879 " Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
880 "}\n";
881
882 // Select shaders matching our GLSL versions
883 const GLchar* vertex_shader = nullptr;
884 const GLchar* fragment_shader = nullptr;
885 if (glsl_version < 130)
886 {
887 vertex_shader = vertex_shader_glsl_120;
888 fragment_shader = fragment_shader_glsl_120;
889 }
890 else if (glsl_version >= 410)
891 {
892 vertex_shader = vertex_shader_glsl_410_core;
893 fragment_shader = fragment_shader_glsl_410_core;
894 }
895 else if (glsl_version == 300)
896 {
897 vertex_shader = vertex_shader_glsl_300_es;
898 fragment_shader = fragment_shader_glsl_300_es;
899 }
900 else
901 {
902 vertex_shader = vertex_shader_glsl_130;
903 fragment_shader = fragment_shader_glsl_130;
904 }
905
906 // Create shaders
907 const GLchar* vertex_shader_with_version[2] = { bd->GlslVersionString, vertex_shader };
908 GLuint vert_handle;
909 GL_CALL(vert_handle = glCreateShader(GL_VERTEX_SHADER));
910 glShaderSource(vert_handle, 2, vertex_shader_with_version, nullptr);
911 glCompileShader(vert_handle);
912 CheckShader(vert_handle, "vertex shader");
913
914 const GLchar* fragment_shader_with_version[2] = { bd->GlslVersionString, fragment_shader };
915 GLuint frag_handle;
916 GL_CALL(frag_handle = glCreateShader(GL_FRAGMENT_SHADER));
917 glShaderSource(frag_handle, 2, fragment_shader_with_version, nullptr);
918 glCompileShader(frag_handle);
919 CheckShader(frag_handle, "fragment shader");
920
921 // Link
922 bd->ShaderHandle = glCreateProgram();
923 glAttachShader(bd->ShaderHandle, vert_handle);
924 glAttachShader(bd->ShaderHandle, frag_handle);
925 glLinkProgram(bd->ShaderHandle);
926 CheckProgram(bd->ShaderHandle, "shader program");
927
928 glDetachShader(bd->ShaderHandle, vert_handle);
929 glDetachShader(bd->ShaderHandle, frag_handle);
930 glDeleteShader(vert_handle);
931 glDeleteShader(frag_handle);
932
933 bd->AttribLocationTex = glGetUniformLocation(bd->ShaderHandle, "Texture");
934 bd->AttribLocationProjMtx = glGetUniformLocation(bd->ShaderHandle, "ProjMtx");
935 bd->AttribLocationVtxPos = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Position");
936 bd->AttribLocationVtxUV = (GLuint)glGetAttribLocation(bd->ShaderHandle, "UV");
937 bd->AttribLocationVtxColor = (GLuint)glGetAttribLocation(bd->ShaderHandle, "Color");
938
939 // Create buffers
940 glGenBuffers(1, &bd->VboHandle);
941 glGenBuffers(1, &bd->ElementsHandle);
942
944
945 // Restore modified GL state
946 glBindTexture(GL_TEXTURE_2D, last_texture);
947 glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
948#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_BIND_BUFFER_PIXEL_UNPACK
949 if (bd->GlVersion >= 210) { glBindBuffer(GL_PIXEL_UNPACK_BUFFER, last_pixel_unpack_buffer); }
950#endif
951#ifdef IMGUI_IMPL_OPENGL_USE_VERTEX_ARRAY
952 glBindVertexArray(last_vertex_array);
953#endif
954
955 return true;
956}
957
959{
960 ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
961 if (bd->VboHandle) { glDeleteBuffers(1, &bd->VboHandle); bd->VboHandle = 0; }
962 if (bd->ElementsHandle) { glDeleteBuffers(1, &bd->ElementsHandle); bd->ElementsHandle = 0; }
963 if (bd->ShaderHandle) { glDeleteProgram(bd->ShaderHandle); bd->ShaderHandle = 0; }
965}
966
967//--------------------------------------------------------------------------------------------------------
968// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
969// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
970// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
971//--------------------------------------------------------------------------------------------------------
972
973static void ImGui_ImplOpenGL3_RenderWindow(ImGuiViewport* viewport, void*)
974{
975 if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear))
976 {
977 ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
978 glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
979 glClear(GL_COLOR_BUFFER_BIT);
980 }
981 ImGui_ImplOpenGL3_RenderDrawData(viewport->DrawData);
982}
983
984static void ImGui_ImplOpenGL3_InitMultiViewportSupport()
985{
986 ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
987 platform_io.Renderer_RenderWindow = ImGui_ImplOpenGL3_RenderWindow;
988}
989
990static void ImGui_ImplOpenGL3_ShutdownMultiViewportSupport()
991{
992 ImGui::DestroyPlatformWindows();
993}
994
995//-----------------------------------------------------------------------------
996
997#if defined(__GNUC__)
998#pragma GCC diagnostic pop
999#endif
1000#if defined(__clang__)
1001#pragma clang diagnostic pop
1002#endif
1003
1004#endif // #ifndef IMGUI_DISABLE
bool ImGui_ImplOpenGL3_Init(const char *glsl_version)
bool ImGui_ImplOpenGL3_CreateFontsTexture()
void ImGui_ImplOpenGL3_DestroyFontsTexture()
void ImGui_ImplOpenGL3_DestroyDeviceObjects()
void ImGui_ImplOpenGL3_NewFrame()
bool ImGui_ImplOpenGL3_CreateDeviceObjects()
void ImGui_ImplOpenGL3_Shutdown()
void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData *draw_data)
#define GL_CALL(_CALL)
RegFunction R