1 // This is essentially a straight port of the ImGui OpenGL3 backend, removing most code that optimized for version for non-3_3.
2 // Certainly willing to revisit adding that code back in the future. It's just slimmed down for the Inochi needs for right now.
3 
4 module dagon.ext.imgui;
5 
6 import core.stdc.stdio;
7 
8 import bindbc.opengl;
9 public import bindbc.imgui;
10 public import bindbc.imgui.bind.imgui;
11 
12 // OpenGL Data
13 static GLuint       g_GlVersion = 0;                // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2)
14 
15 version(OSX) static char[32]     g_GlslVersionString = "#version 330";   // Specified by user or detected based on compile time GL settings.
16 else static char[32]     g_GlslVersionString = "#version 130";   // Specified by user or detected based on compile time GL settings.
17 static GLuint       g_FontTexture = 0;
18 static GLuint       g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0;
19 static GLint        g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0;                                // Uniforms location
20 static GLuint       g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location
21 static uint g_VboHandle = 0, g_ElementsHandle = 0;
22 
23 class ImGuiOpenGLBackend {
24 static: 
25     // Functions
26     bool init()
27     {
28         // Query for GL version (e.g. 320 for GL 3.2)
29         const GLint major = 4, minor = 2;
30         //glGetIntegerv(GL_MAJOR_VERSION, &major);
31         //glGetIntegerv(GL_MINOR_VERSION, &minor);
32         g_GlVersion = cast(GLuint)(major * 100 + minor * 10);
33 
34         // Setup back-end capabilities flags
35         ImGuiIO* io = igGetIO();
36         //io.BackendRendererName = "imgui_impl_opengl3";
37 
38         if (g_GlVersion >= 320)
39         {
40             io.BackendFlags |= cast(int)ImGuiBackendFlags.RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
41         }
42         
43         io.BackendFlags |= cast(int)ImGuiBackendFlags.RendererHasViewports;  // We can create multi-viewports on the Renderer side (optional)
44 
45         // Make an arbitrary GL call (we don't actually need the result)
46         // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code.
47         // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above.
48         GLint current_texture;
49         glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture);
50 
51         if (io.ConfigFlags & ImGuiConfigFlags.ViewportsEnable)
52             init_platform_interface();
53 
54         return true;
55     }
56 
57     void shutdown()
58     {
59         shutdown_platform_interface();
60         destroy_device_objects();
61     }
62 
63     void new_frame()
64     {
65         if (!g_ShaderHandle)
66             create_device_objects();
67     }
68 
69     static void setup_render_state(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
70     {
71         // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
72         glEnable(GL_BLEND);
73         glBlendEquation(GL_FUNC_ADD);
74         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
75         glDisable(GL_CULL_FACE);
76         glDisable(GL_DEPTH_TEST);
77         glEnable(GL_SCISSOR_TEST);
78 
79         // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT)
80         bool clip_origin_lower_left = true;
81 
82         // Setup viewport, orthographic projection matrix
83         // 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.
84         glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height);
85         float L = draw_data.DisplayPos.x;
86         float R = draw_data.DisplayPos.x + draw_data.DisplaySize.x;
87         float T = draw_data.DisplayPos.y;
88         float B = draw_data.DisplayPos.y + draw_data.DisplaySize.y;
89         if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
90         const float[4][4] ortho_projection =
91         [
92             [ 2.0f/(R-L),   0.0f,         0.0f,   0.0f ],
93             [ 0.0f,         2.0f/(T-B),   0.0f,   0.0f ],
94             [ 0.0f,         0.0f,        -1.0f,   0.0f ],
95             [ (R+L)/(L-R),  (T+B)/(B-T),  0.0f,   1.0f ],
96         ];
97         glUseProgram(g_ShaderHandle);
98         glUniform1i(g_AttribLocationTex, 0);
99         glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]);
100         
101         if (g_GlVersion >= 330)
102             glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise.
103         
104         glBindVertexArray(vertex_array_object);
105 
106         // Bind vertex/index buffers and setup attributes for ImDrawVert
107         glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle);
108         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle);
109         glEnableVertexAttribArray(g_AttribLocationVtxPos);
110         glEnableVertexAttribArray(g_AttribLocationVtxUV);
111         glEnableVertexAttribArray(g_AttribLocationVtxColor);
112         glVertexAttribPointer(g_AttribLocationVtxPos,   2, GL_FLOAT,         GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.pos.offsetof);
113         glVertexAttribPointer(g_AttribLocationVtxUV,    2, GL_FLOAT,         GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.uv.offsetof);
114         glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE,  ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.col.offsetof);
115     }
116 
117     // OpenGL3 Render function.
118     // (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
119     // Note that this implementation is little overcomplicated because we are saving/setting up/restoring every OpenGL state explicitly, in order to be able to run within any OpenGL engine that doesn't do so.
120     void render_draw_data(ImDrawData* draw_data)
121     {
122         // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
123         int fb_width = cast(int)(draw_data.DisplaySize.x * draw_data.FramebufferScale.x);
124         int fb_height = cast(int)(draw_data.DisplaySize.y * draw_data.FramebufferScale.y);
125         if (fb_width <= 0 || fb_height <= 0)
126             return;
127 
128         // Backup GL state
129         GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, cast(GLint*)&last_active_texture);
130         glActiveTexture(GL_TEXTURE0);
131         GLuint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, cast(GLint*)&last_program);
132         GLuint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, cast(GLint*)&last_texture);
133         GLuint last_sampler; if (g_GlVersion >= 330) { glGetIntegerv(GL_SAMPLER_BINDING, cast(GLint*)&last_sampler); } else { last_sampler = 0; }
134         GLuint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, cast(GLint*)&last_array_buffer);
135         GLuint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, cast(GLint*)&last_vertex_array_object);
136         GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr);
137         GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr);
138         GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, cast(GLint*)&last_blend_src_rgb);
139         GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, cast(GLint*)&last_blend_dst_rgb);
140         GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, cast(GLint*)&last_blend_src_alpha);
141         GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, cast(GLint*)&last_blend_dst_alpha);
142         GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, cast(GLint*)&last_blend_equation_rgb);
143         GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, cast(GLint*)&last_blend_equation_alpha);
144         const GLboolean last_enable_blend = glIsEnabled(GL_BLEND);
145         const GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE);
146         const GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST);
147         const GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
148 
149         // Setup desired GL state
150         // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts)
151         // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound.
152         GLuint vertex_array_object = 0;
153         glGenVertexArrays(1, &vertex_array_object);
154         setup_render_state(draw_data, fb_width, fb_height, vertex_array_object);
155 
156         // Will project scissor/clipping rectangles into framebuffer space
157         ImVec2 clip_off = draw_data.DisplayPos;         // (0,0) unless using multi-viewports
158         ImVec2 clip_scale = draw_data.FramebufferScale; // (1,1) unless using retina display which are often (2,2)
159 
160         // Render command lists
161         for (int n = 0; n < draw_data.CmdListsCount; n++)
162         {
163             const ImDrawList* cmd_list = draw_data.CmdLists[n];
164 
165             // Upload vertex/index buffers
166             glBufferData(GL_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.VtxBuffer.Size * cast(int)(ImDrawVert.sizeof), cast(const GLvoid*)cmd_list.VtxBuffer.Data, GL_STREAM_DRAW);
167             glBufferData(GL_ELEMENT_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.IdxBuffer.Size * cast(int)(ImDrawIdx.sizeof), cast(const GLvoid*)cmd_list.IdxBuffer.Data, GL_STREAM_DRAW);
168 
169             for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++)
170             {
171                 const (ImDrawCmd)* pcmd = &cmd_list.CmdBuffer.Data[cmd_i];
172                 if (pcmd.UserCallback != null)
173                 {
174                     // User callback, registered via ImDrawList::AddCallback()
175                     // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
176                     if (pcmd.UserCallback == cast(ImDrawCallback)(-1))
177                         setup_render_state(draw_data, fb_width, fb_height, vertex_array_object);
178                     else
179                         pcmd.UserCallback(cmd_list, pcmd);
180                 }
181                 else
182                 {
183                     // Project scissor/clipping rectangles into framebuffer space
184                     ImVec4 clip_rect;
185                     clip_rect.x = (pcmd.ClipRect.x - clip_off.x) * clip_scale.x;
186                     clip_rect.y = (pcmd.ClipRect.y - clip_off.y) * clip_scale.y;
187                     clip_rect.z = (pcmd.ClipRect.z - clip_off.x) * clip_scale.x;
188                     clip_rect.w = (pcmd.ClipRect.w - clip_off.y) * clip_scale.y;
189 
190                     if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
191                     {
192                         // Apply scissor/clipping rectangle
193                         glScissor(cast(int)clip_rect.x, cast(int)(fb_height - clip_rect.w), cast(int)(clip_rect.z - clip_rect.x), cast(int)(clip_rect.w - clip_rect.y));
194 
195                         // Bind texture, Draw
196                         glBindTexture(GL_TEXTURE_2D, cast(GLuint)(cast(int*)(pcmd.TextureId)));
197                         if (g_GlVersion >= 320)
198                             glDrawElementsBaseVertex(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, (ImDrawIdx.sizeof) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, cast(void*)cast(int*)(pcmd.IdxOffset * (ImDrawIdx.sizeof)), cast(GLint)pcmd.VtxOffset);
199                         else
200                             glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, (ImDrawIdx.sizeof) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, cast(void*)cast(int*)(pcmd.IdxOffset * (ImDrawIdx.sizeof)));
201                     }
202                 }
203             }
204         }
205 
206         // Destroy the temporary VAO
207         glDeleteVertexArrays(1, &vertex_array_object);
208 
209         // Restore modified GL state
210         glUseProgram(last_program);
211         glBindTexture(GL_TEXTURE_2D, last_texture);
212         if (g_GlVersion >= 330)
213             glBindSampler(0, last_sampler);
214         glActiveTexture(last_active_texture);
215         glBindVertexArray(last_vertex_array_object);
216         glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
217         glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha);
218         glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha);
219         if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND);
220         if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE);
221         if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST);
222         if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST);
223         glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)(last_viewport[2]), cast(GLsizei)(last_viewport[3]));
224         glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)(last_scissor_box[2]), cast(GLsizei)(last_scissor_box[3]));
225     }
226 
227     bool create_fonts_texture()
228     {
229         // Build texture atlas
230         ImGuiIO* io = igGetIO();
231         char* pixels;
232         int width, height;
233 
234         ImFontAtlas_GetTexDataAsRGBA32(io.Fonts, &pixels, &width, &height, null); // 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.
235 
236         // Upload texture to graphics system
237         GLint last_texture;
238         glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
239         glGenTextures(1, &g_FontTexture);
240         glBindTexture(GL_TEXTURE_2D, g_FontTexture);
241         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
242         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
243         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
244 
245         // Store our identifier
246         io.Fonts.TexID = cast(ImTextureID)cast(int*)g_FontTexture;
247 
248         // Restore state
249         glBindTexture(GL_TEXTURE_2D, last_texture);
250 
251         return true;
252     }
253 
254     void destroy_fonts_texture()
255     {
256         if (g_FontTexture)
257         {
258             ImGuiIO* io = igGetIO();
259             glDeleteTextures(1, &g_FontTexture);
260             io.Fonts.TexID = cast(ImTextureID)0;
261             g_FontTexture = 0;
262         }
263     }
264 
265     // 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.
266     static bool check_shader(GLuint handle, const (char)* desc)
267     {
268         GLint status = 0, log_length = 0;
269         glGetShaderiv(handle, GL_COMPILE_STATUS, &status);
270         glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length);
271         if (cast(GLboolean)status == GL_FALSE)
272             fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc);
273         if (log_length > 1)
274         {
275             char[] buf;
276             buf.length = log_length + 1;
277             glGetShaderInfoLog(handle, log_length, null, cast(GLchar*)buf.ptr);
278             fprintf(stderr, "%s\n", buf.ptr);
279         }
280         return cast(GLboolean)status == GL_TRUE;
281     }
282 
283     // If you get an error please report on GitHub. You may try different GL context version or GLSL version.
284     static bool check_program(GLuint handle, const char* desc)
285     {
286         GLint status = 0, log_length = 0;
287         glGetProgramiv(handle, GL_LINK_STATUS, &status);
288         glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length);
289         if (cast(GLboolean)status == GL_FALSE)
290             fprintf(stderr, "ERROR: create_device_objects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString.ptr);
291         if (log_length > 1)
292         {
293             char[] buf;
294             buf.length = log_length + 1;
295             glGetProgramInfoLog(handle, log_length, null, cast(GLchar*)buf.ptr);
296             fprintf(stderr, "%s\n", buf.ptr);
297         }
298         return cast(GLboolean)status == GL_TRUE;
299     }
300 
301     bool create_device_objects()
302     {
303         // Backup GL state
304         GLint last_texture, last_array_buffer;
305         glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
306         glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
307         GLint last_vertex_array;
308         glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array);
309 
310         // Parse GLSL version string
311         int glsl_version = 130;
312         sscanf(g_GlslVersionString.ptr, "#version %d", &glsl_version);
313 
314         const GLchar* vertex_shader_glsl_120 =
315             "uniform mat4 ProjMtx;\n"
316         ~ "attribute vec2 Position;\n"
317         ~ "attribute vec2 UV;\n"
318         ~ "attribute vec4 Color;\n"
319         ~ "varying vec2 Frag_UV;\n"
320         ~ "varying vec4 Frag_Color;\n"
321         ~ "void main()\n"
322         ~ "{\n"
323         ~ "    Frag_UV = UV;\n"
324         ~ "    Frag_Color = Color;\n"
325         ~ "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
326         ~ "}\n";
327 
328         const GLchar* vertex_shader_glsl_130 = `
329         uniform mat4 ProjMtx;
330         in vec2 Position;
331         in vec2 UV;
332         in vec4 Color;
333         out vec2 Frag_UV;
334         out vec4 Frag_Color;
335         void main()
336         {
337             Frag_UV = UV;
338             Frag_Color = Color;
339             gl_Position = ProjMtx * vec4(Position.xy,0,1);
340         }
341         `;
342 
343         const GLchar* vertex_shader_glsl_300_es =
344             "precision mediump float;\n"
345         ~ "layout (location = 0) in vec2 Position;\n"
346         ~ "layout (location = 1) in vec2 UV;\n"
347         ~ "layout (location = 2) in vec4 Color;\n"
348         ~ "uniform mat4 ProjMtx;\n"
349         ~ "out vec2 Frag_UV;\n"
350         ~ "out vec4 Frag_Color;\n"
351         ~ "void main()\n"
352         ~ "{\n"
353         ~ "    Frag_UV = UV;\n"
354         ~ "    Frag_Color = Color;\n"
355         ~ "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
356         ~ "}\n";
357 
358         const GLchar* vertex_shader_glsl_410_core =
359             "layout (location = 0) in vec2 Position;\n"
360         ~ "layout (location = 1) in vec2 UV;\n"
361         ~ "layout (location = 2) in vec4 Color;\n"
362         ~ "uniform mat4 ProjMtx;\n"
363         ~ "out vec2 Frag_UV;\n"
364         ~ "out vec4 Frag_Color;\n"
365         ~ "void main()\n"
366         ~ "{\n"
367         ~ "    Frag_UV = UV;\n"
368         ~ "    Frag_Color = Color;\n"
369         ~ "    gl_Position = ProjMtx * vec4(Position.xy,0,1);\n"
370         ~ "}\n";
371 
372         const GLchar* fragment_shader_glsl_120 =
373             "#ifdef GL_ES\n"
374         ~ "    precision mediump float;\n"
375         ~ "#endif\n"
376         ~ "uniform sampler2D Texture;\n"
377         ~ "varying vec2 Frag_UV;\n"
378         ~ "varying vec4 Frag_Color;\n"
379         ~ "void main()\n"
380         ~ "{\n"
381         ~ "    gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n"
382         ~ "}\n";
383 
384         const GLchar* fragment_shader_glsl_130 = `
385         uniform sampler2D Texture;
386         in vec2 Frag_UV;
387         in vec4 Frag_Color;
388         out vec4 Out_Color;
389         void main()
390         {
391             Out_Color = Frag_Color * texture(Texture, Frag_UV.st);
392         }
393         `;
394 
395         const GLchar* fragment_shader_glsl_300_es =
396             "precision mediump float;\n"
397         ~ "uniform sampler2D Texture;\n"
398         ~ "in vec2 Frag_UV;\n"
399         ~ "in vec4 Frag_Color;\n"
400         ~ "layout (location = 0) out vec4 Out_Color;\n"
401         ~ "void main()\n"
402         ~ "{\n"
403         ~ "    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
404         ~ "}\n";
405 
406         const GLchar* fragment_shader_glsl_410_core =
407             "in vec2 Frag_UV;\n"
408         ~ "in vec4 Frag_Color;\n"
409         ~ "uniform sampler2D Texture;\n"
410         ~ "layout (location = 0) out vec4 Out_Color;\n"
411         ~ "void main()\n"
412         ~ "{\n"
413         ~ "    Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n"
414         ~ "}\n";
415 
416         // Select shaders matching our GLSL versions
417         const (GLchar)* vertex_shader = null;
418         const (GLchar)* fragment_shader = null;
419         if (glsl_version < 130)
420         {
421             vertex_shader = vertex_shader_glsl_120;
422             fragment_shader = fragment_shader_glsl_120;
423         }
424         else if (glsl_version >= 410)
425         {
426             vertex_shader = vertex_shader_glsl_410_core;
427             fragment_shader = fragment_shader_glsl_410_core;
428         }
429         else if (glsl_version == 300)
430         {
431             vertex_shader = vertex_shader_glsl_300_es;
432             fragment_shader = fragment_shader_glsl_300_es;
433         }
434         else
435         {
436             vertex_shader = vertex_shader_glsl_130;
437             fragment_shader = fragment_shader_glsl_130;
438         }
439 
440         // Create shaders
441         const (GLchar)*[2] vertex_shader_with_version = [ g_GlslVersionString.ptr, vertex_shader ];
442         g_VertHandle = glCreateShader(GL_VERTEX_SHADER);
443         glShaderSource(g_VertHandle, 2, vertex_shader_with_version.ptr, null);
444         glCompileShader(g_VertHandle);
445         check_shader(g_VertHandle, "vertex shader");
446 
447         const (GLchar)*[2] fragment_shader_with_version = [ g_GlslVersionString.ptr, fragment_shader ];
448         g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER);
449         glShaderSource(g_FragHandle, 2, fragment_shader_with_version.ptr, null);
450         glCompileShader(g_FragHandle);
451         check_shader(g_FragHandle, "fragment shader");
452 
453         g_ShaderHandle = glCreateProgram();
454         glAttachShader(g_ShaderHandle, g_VertHandle);
455         glAttachShader(g_ShaderHandle, g_FragHandle);
456         glLinkProgram(g_ShaderHandle);
457         check_program(g_ShaderHandle, "shader program");
458 
459         g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture");
460         g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx");
461         g_AttribLocationVtxPos = cast(GLuint)glGetAttribLocation(g_ShaderHandle, "Position");
462         g_AttribLocationVtxUV = cast(GLuint)glGetAttribLocation(g_ShaderHandle, "UV");
463         g_AttribLocationVtxColor = cast(GLuint)glGetAttribLocation(g_ShaderHandle, "Color");
464 
465         // Create buffers
466         glGenBuffers(1, &g_VboHandle);
467         glGenBuffers(1, &g_ElementsHandle);
468 
469         create_fonts_texture();
470 
471         // Restore modified GL state
472         glBindTexture(GL_TEXTURE_2D, last_texture);
473         glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
474         glBindVertexArray(last_vertex_array);
475 
476         return true;
477     }
478 
479     void destroy_device_objects()
480     {
481         if (g_VboHandle)        { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; }
482         if (g_ElementsHandle)   { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; }
483         if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); }
484         if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); }
485         if (g_VertHandle)       { glDeleteShader(g_VertHandle); g_VertHandle = 0; }
486         if (g_FragHandle)       { glDeleteShader(g_FragHandle); g_FragHandle = 0; }
487         if (g_ShaderHandle)     { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; }
488 
489         destroy_fonts_texture();
490     }
491 
492     //--------------------------------------------------------------------------------------------------------
493     // MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
494     // This is an _advanced_ and _optional_ feature, allowing the back-end to create and handle multiple viewports simultaneously.
495     // 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..
496     //--------------------------------------------------------------------------------------------------------
497     extern (C)
498     {
499         static void render_window(ImGuiViewport* viewport, void*)
500         {
501             if (!(viewport.Flags & ImGuiViewportFlags.NoRendererClear))
502             {
503                 ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
504                 glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
505                 glClear(GL_COLOR_BUFFER_BIT);
506             }
507             render_draw_data(viewport.DrawData);
508         }
509     }
510 
511     static void init_platform_interface()
512     {
513         ImGuiPlatformIO* platform_io = igGetPlatformIO();
514         platform_io.Renderer_RenderWindow = &render_window;
515     }
516 
517     static void shutdown_platform_interface()
518     {
519         igDestroyPlatformWindows();
520     }
521 }