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