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, ¤t_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 }