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