1 module ecs_utils.imgui_bind; 2 3 import bindbc.sdl; 4 import cimgui.cimgui; 5 6 version(WebAssembly) 7 { 8 extern(C): 9 bool ImGui_ImplOpenGL3_Init(const char* glsl_version = null); 10 void ImGui_ImplOpenGL3_Shutdown(); 11 void ImGui_ImplOpenGL3_NewFrame(); 12 void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 13 14 bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context); 15 bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window); 16 bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); 17 void ImGui_ImplSDL2_Shutdown(); 18 void ImGui_ImplSDL2_NewFrame(SDL_Window* window); 19 bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); 20 } 21 else : 22 23 import bindbc.sdl; 24 25 version(WebAssembly)import glad.gl.gles2; 26 else version(Android)import glad.gl.gles2; 27 else import glad.gl.gl; 28 29 import cimgui.cimgui; 30 31 extern(C): 32 33 __gshared SDL_Window* g_Window; 34 __gshared ulong g_Time; 35 __gshared bool[3] g_MousePressed; 36 __gshared SDL_Cursor*[ImGuiMouseCursor_COUNT] g_MouseCursors; 37 __gshared char* g_ClipboardTextData; 38 __gshared GLuint g_FontTexture = 0; 39 40 const (char)* ImGuiImplSDL2GetClipboardText(void*) 41 { 42 if (g_ClipboardTextData) 43 SDL_free(g_ClipboardTextData); 44 g_ClipboardTextData = SDL_GetClipboardText(); 45 return g_ClipboardTextData; 46 } 47 48 void ImGuiImplSDL2SetClipboardText(void*, const char* text) 49 { 50 SDL_SetClipboardText(text); 51 } 52 53 bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event) 54 { 55 ImGuiIO* io = igGetIO(); 56 switch (event.type) 57 { 58 case SDL_MOUSEWHEEL: 59 { 60 if (event.wheel.x > 0) io.MouseWheelH += 1; 61 if (event.wheel.x < 0) io.MouseWheelH -= 1; 62 if (event.wheel.y > 0) io.MouseWheel += 1; 63 if (event.wheel.y < 0) io.MouseWheel -= 1; 64 return true; 65 } 66 case SDL_MOUSEBUTTONDOWN: 67 { 68 if (event.button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true; 69 if (event.button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true; 70 if (event.button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true; 71 return true; 72 } 73 case SDL_TEXTINPUT: 74 { 75 ImGuiIO_AddInputCharactersUTF8(io,event.text.text.ptr); 76 return true; 77 } 78 case SDL_KEYDOWN: 79 case SDL_KEYUP: 80 { 81 int key = event.key.keysym.scancode; 82 //IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown)); 83 io.KeysDown[key] = (event.type == SDL_KEYDOWN); 84 io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0); 85 io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0); 86 io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0); 87 io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0); 88 return true; 89 } 90 default:break; 91 } 92 return false; 93 } 94 95 bool ImGuiImplSDL2Init(SDL_Window* window) 96 { 97 g_Window = window; 98 99 // Setup back-end capabilities flags 100 ImGuiIO* io = igGetIO(); 101 io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) 102 io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) 103 io.BackendPlatformName = "imgui_impl_sdl"; 104 105 // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. 106 io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB; 107 io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT; 108 io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT; 109 io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP; 110 io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN; 111 io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP; 112 io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN; 113 io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME; 114 io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END; 115 io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT; 116 io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE; 117 io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE; 118 io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE; 119 io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN; 120 io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE; 121 io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_RETURN2; 122 io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A; 123 io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C; 124 io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V; 125 io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X; 126 io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y; 127 io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z; 128 129 io.SetClipboardTextFn = &ImGuiImplSDL2SetClipboardText; 130 io.GetClipboardTextFn = &ImGuiImplSDL2GetClipboardText; 131 io.ClipboardUserData = null; 132 133 g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); 134 g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); 135 g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); 136 g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); 137 g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); 138 g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); 139 g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); 140 g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); 141 142 //#ifdef _WIN32 143 version(WebAssembly) 144 { 145 146 } 147 else version(Windows) 148 { 149 SDL_SysWMinfo wmInfo; 150 SDL_VERSION(&wmInfo.version_); 151 SDL_GetWindowWMInfo(window, &wmInfo); 152 io.ImeWindowHandle = wmInfo.info.win.window; 153 } 154 //#else 155 //(void)window; 156 //#endif 157 158 return true; 159 } 160 161 bool ImGuiImplSDL2InitForOpenGL(SDL_Window* window, void* sdl_gl_context) 162 { 163 //(void)sdl_gl_context; // Viewport branch will need this. 164 return ImGuiImplSDL2Init(window); 165 } 166 167 void ImGuiImplSDL2Shutdown() 168 { 169 g_Window = null; 170 171 // Destroy last known clipboard data 172 if (g_ClipboardTextData) 173 SDL_free(g_ClipboardTextData); 174 g_ClipboardTextData = null; 175 176 // Destroy SDL mouse cursors 177 for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) 178 SDL_FreeCursor(g_MouseCursors[cursor_n]); 179 //memset(g_MouseCursors, 0, sizeof(g_MouseCursors)); 180 } 181 182 static void ImGui_ImplSDL2_UpdateMousePosAndButtons() 183 { 184 ImGuiIO* io = igGetIO(); 185 186 // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) 187 if (io.WantSetMousePos) 188 SDL_WarpMouseInWindow(g_Window, cast(int)io.MousePos.x, cast(int)io.MousePos.y); 189 else 190 io.MousePos = ImVec2(-float.max, -float.max); 191 192 int mx, my; 193 Uint32 mouse_buttons = SDL_GetMouseState(&mx, &my); 194 io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & (SDL_PRESSED<<(SDL_BUTTON_LEFT-1))) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. 195 io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & (SDL_PRESSED<<(SDL_BUTTON_RIGHT-1))) != 0; 196 io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & (SDL_PRESSED<<(SDL_BUTTON_MIDDLE-1))) != 0; 197 g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false; 198 199 //#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) 200 /*SDL_Window* focused_window = SDL_GetKeyboardFocus(); 201 if (g_Window == focused_window) 202 { 203 // SDL_GetMouseState() gives mouse position seemingly based on the last window entered/focused(?) 204 // The creation of a new windows at runtime and SDL_CaptureMouse both seems to severely mess up with that, so we retrieve that position globally. 205 int wx, wy; 206 SDL_GetWindowPosition(focused_window, &wx, &wy); 207 SDL_GetGlobalMouseState(&mx, &my); 208 mx -= wx; 209 my -= wy; 210 io.MousePos = ImVec2((float)mx, (float)my); 211 } 212 213 // SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger the OS window resize cursor. 214 // The function is only supported from SDL 2.0.4 (released Jan 2016) 215 bool any_mouse_button_down = ImGui.IsAnyMouseDown(); 216 SDL_CaptureMouse(any_mouse_button_down ? SDL_TRUE : SDL_FALSE); 217 //#else*/ 218 if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS) 219 io.MousePos = ImVec2(cast(float)mx, cast(float)my); 220 //#endif 221 } 222 223 static void ImGui_ImplSDL2_UpdateMouseCursor() 224 { 225 ImGuiIO* io = igGetIO(); 226 if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) 227 return; 228 229 ImGuiMouseCursor imgui_cursor = igGetMouseCursor(); 230 if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) 231 { 232 // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor 233 SDL_ShowCursor(SDL_FALSE); 234 } 235 else 236 { 237 // Show OS mouse cursor 238 SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); 239 SDL_ShowCursor(SDL_TRUE); 240 } 241 } 242 243 static void ImGui_ImplSDL2_UpdateGamepads() 244 { 245 ImGuiIO* io = igGetIO(); 246 //memset(io.NavInputs, 0, sizeof(io.NavInputs)); 247 if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) 248 return; 249 250 // Get gamepad 251 SDL_GameController* game_controller = SDL_GameControllerOpen(0); 252 if (!game_controller) 253 { 254 io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; 255 return; 256 } 257 258 // Update gamepad inputs 259 /*#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; } 260 #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; } 261 const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value. 262 MAP_BUTTON(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A 263 MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B 264 MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X 265 MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y 266 MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left 267 MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right 268 MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up 269 MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down 270 MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB 271 MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB 272 MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB 273 MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB 274 MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768); 275 MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767); 276 MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767); 277 MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767); 278 279 io.BackendFlags |= ImGuiBackendFlags_HasGamepad; 280 #undef MAP_BUTTON 281 #undef MAP_ANALOG*/ 282 } 283 284 285 __gshared private long frequency; 286 287 void ImGuiImplSDL2NewFrame(SDL_Window* window) 288 { 289 ImGuiIO* io = igGetIO(); 290 assert(ImFontAtlas_IsBuilt(io.Fonts), "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); 291 292 // Setup display size (every frame to accommodate for window resizing) 293 int w, h; 294 int display_w, display_h; 295 SDL_GetWindowSize(window, &w, &h); 296 // SDL_GL_GetDrawableSize(window, &display_w, &display_h); FIXME: you see 297 io.DisplaySize = ImVec2(cast(float)w, cast(float)h); 298 // if (w > 0 && h > 0) 299 // io.DisplayFramebufferScale = ImVec2(cast(float)display_w / w, cast(float)display_h / h); 300 io.DisplayFramebufferScale = ImVec2(1,1); 301 302 // Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution) 303 frequency = SDL_GetPerformanceFrequency(); 304 long current_time = SDL_GetPerformanceCounter(); 305 io.DeltaTime = g_Time > 0 ? cast(float)(cast(double)(current_time - g_Time) / frequency) : cast(float)(1.0f / 60.0f); 306 g_Time = current_time; 307 308 ImGui_ImplSDL2_UpdateMousePosAndButtons(); 309 ImGui_ImplSDL2_UpdateMouseCursor(); 310 311 // Update game controllers (if enabled and available) 312 ImGui_ImplSDL2_UpdateGamepads(); 313 } 314 315 316 __gshared GLuint g_GlVersion = 0; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) 317 __gshared char[32] g_GlslVersionString = ""; // Specified by user or detected based on compile time GL settings. 318 //__gshared GLuint g_FontTexture = 0; 319 __gshared GLuint g_ShaderHandle = 0, g_VertHandle = 0, g_FragHandle = 0; 320 __gshared int g_AttribLocationTex = 0, g_AttribLocationProjMtx = 0; // Uniforms location 321 __gshared int g_AttribLocationVtxPos = 0, g_AttribLocationVtxUV = 0, g_AttribLocationVtxColor = 0; // Vertex attributes location 322 __gshared uint g_VboHandle = 0, g_ElementsHandle = 0; 323 324 bool ImGui_ImplOpenGL3_Init(const char* glsl_version) 325 { 326 // Setup back-end capabilities flags 327 ImGuiIO* io = igGetIO(); 328 io.BackendRendererName = "imgui_impl_opengl3"; 329 330 331 // Store GLSL version string so we can refer to it later in case we recreate shaders. 332 // Note: GLSL version is NOT the same as GL version. Leave this to null if unsure. 333 /*#if defined(IMGUI_IMPL_OPENGL_ES2) 334 if (glsl_version == null) 335 glsl_version = "#version 100"; 336 #elif defined(IMGUI_IMPL_OPENGL_ES3) 337 if (glsl_version == null) 338 glsl_version = "#version 300 es"; 339 #elif defined(__APPLE__) 340 if (glsl_version == null) 341 glsl_version = "#version 150"; 342 #else 343 if (glsl_version == null) 344 glsl_version = "#version 130"; 345 #endif 346 IM_ASSERT((int)strlen(glsl_version) + 2 < IM_ARRAYSIZE(g_GlslVersionString));*/ 347 //const (char)*glsl_version = "#version 100"; 348 import core.stdc.string; 349 strcpy(g_GlslVersionString.ptr, glsl_version); 350 strcat(g_GlslVersionString.ptr, "\n"); 351 352 // Dummy construct to make it easily visible in the IDE and debugger which GL loader has been selected. 353 // The code actually never uses the 'gl_loader' variable! It is only here so you can read it! 354 // If auto-detection fails or doesn't select the same GL loader file as used by your application, 355 // you are likely to get a crash below. 356 // You can explicitly select a loader by using '#define IMGUI_IMPL_OPENGL_LOADER_XXX' in imconfig.h or compiler command-line. 357 /*const char* gl_loader = "Unknown"; 358 IM_UNUSED(gl_loader); 359 #if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) 360 gl_loader = "GL3W"; 361 #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) 362 gl_loader = "GLEW"; 363 #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) 364 gl_loader = "GLAD"; 365 #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2) 366 gl_loader = "glbinding2"; 367 #elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3) 368 gl_loader = "glbinding3"; 369 #elif defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) 370 gl_loader = "custom"; 371 #else 372 gl_loader = "none"; 373 #endif*/ 374 375 // Make a dummy GL call (we don't actually need the result) 376 // IF YOU GET A CRASH HERE: it probably means that you haven't initialized the OpenGL function loader used by this code. 377 // Desktop OpenGL 3/4 need a function loader. See the IMGUI_IMPL_OPENGL_LOADER_xxx explanation above. 378 /*GLint current_texture; 379 glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);*/ 380 381 return true; 382 } 383 384 static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object) 385 { 386 // Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill 387 glEnable(GL_BLEND); 388 glBlendEquation(GL_FUNC_ADD); 389 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 390 glDisable(GL_CULL_FACE); 391 glDisable(GL_DEPTH_TEST); 392 glEnable(GL_SCISSOR_TEST); 393 // #ifdef GL_POLYGON_MODE 394 // glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 395 // #endif 396 397 // Support for GL 4.5 rarely used glClipControl(GL_UPPER_LEFT) 398 bool clip_origin_lower_left = true; 399 // #if defined(GL_CLIP_ORIGIN) && !defined(__APPLE__) 400 // GLenum current_clip_origin = 0; glGetIntegerv(GL_CLIP_ORIGIN, (GLint*)¤t_clip_origin); 401 // if (current_clip_origin == GL_UPPER_LEFT) 402 // clip_origin_lower_left = false; 403 // #endif 404 405 // Setup viewport, orthographic projection matrix 406 // 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. 407 glViewport(0, 0, cast(GLsizei)fb_width, cast(GLsizei)fb_height); 408 float L = draw_data.DisplayPos.x; 409 float R = draw_data.DisplayPos.x + draw_data.DisplaySize.x; 410 float T = draw_data.DisplayPos.y; 411 float B = draw_data.DisplayPos.y + draw_data.DisplaySize.y; 412 if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left 413 const float[4][4] ortho_projection = 414 [ 415 [ 2.0f/(R-L), 0.0f, 0.0f, 0.0f ], 416 [ 0.0f, 2.0f/(T-B), 0.0f, 0.0f ], 417 [ 0.0f, 0.0f, -1.0f, 0.0f ], 418 [ (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f ], 419 ]; 420 glUseProgram(g_ShaderHandle); 421 glUniform1i(g_AttribLocationTex, 0); 422 glUniformMatrix4fv(g_AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); 423 // #ifdef GL_SAMPLER_BINDING 424 // glBindSampler(0, 0); // We use combined texture/sampler state. Applications using GL 3.3 may set that otherwise. 425 // #endif 426 427 // (void)vertex_array_object; 428 // #ifndef IMGUI_IMPL_OPENGL_ES2 429 // glBindVertexArray(vertex_array_object); 430 // #endif 431 432 // Bind vertex/index buffers and setup attributes for ImDrawVert 433 glBindBuffer(GL_ARRAY_BUFFER, g_VboHandle); 434 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_ElementsHandle); 435 glEnableVertexAttribArray(g_AttribLocationVtxPos); 436 glEnableVertexAttribArray(g_AttribLocationVtxUV); 437 glEnableVertexAttribArray(g_AttribLocationVtxColor); 438 glVertexAttribPointer(g_AttribLocationVtxPos, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.pos.offsetof); 439 glVertexAttribPointer(g_AttribLocationVtxUV, 2, GL_FLOAT, GL_FALSE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.uv.offsetof); 440 glVertexAttribPointer(g_AttribLocationVtxColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, ImDrawVert.sizeof, cast(GLvoid*)ImDrawVert.col.offsetof); 441 } 442 443 444 void ImGui_ImplOpenGL3_Shutdown() 445 { 446 ImGui_ImplOpenGL3_DestroyDeviceObjects(); 447 } 448 449 void ImGui_ImplOpenGL3_NewFrame() 450 { 451 if (!g_ShaderHandle) 452 ImGui_ImplOpenGL3_CreateDeviceObjects(); 453 } 454 455 bool ImGui_ImplOpenGL3_CreateDeviceObjects() 456 { 457 // Backup GL state 458 GLint last_texture, last_array_buffer; 459 glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 460 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 461 // #ifndef IMGUI_IMPL_OPENGL_ES2 462 // GLint last_vertex_array; 463 // glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 464 // #endif 465 466 // Parse GLSL version string 467 import core.stdc.stdio; 468 int glsl_version = 130; 469 sscanf(g_GlslVersionString.ptr, "#version %d", &glsl_version); 470 471 const GLchar* vertex_shader_glsl_120 = 472 "uniform mat4 ProjMtx;\n 473 attribute vec2 Position;\n 474 attribute vec2 UV;\n 475 attribute vec4 Color;\n 476 varying vec2 Frag_UV;\n 477 varying vec4 Frag_Color;\n 478 void main()\n 479 {\n 480 Frag_UV = UV;\n 481 Frag_Color = Color;\n 482 gl_Position = ProjMtx * vec4(Position.xy,0,1);\n 483 }\n"; 484 485 const GLchar* vertex_shader_glsl_130 = 486 "uniform mat4 ProjMtx;\n 487 in vec2 Position;\n 488 in vec2 UV;\n 489 in vec4 Color;\n 490 out vec2 Frag_UV;\n 491 out vec4 Frag_Color;\n 492 void main()\n 493 {\n 494 Frag_UV = UV;\n 495 Frag_Color = Color;\n 496 gl_Position = ProjMtx * vec4(Position.xy,0,1);\n 497 }\n"; 498 499 const GLchar* vertex_shader_glsl_300_es = 500 "precision mediump float;\n 501 layout (location = 0) in vec2 Position;\n 502 layout (location = 1) in vec2 UV;\n 503 layout (location = 2) in vec4 Color;\n 504 uniform mat4 ProjMtx;\n 505 out vec2 Frag_UV;\n 506 out vec4 Frag_Color;\n 507 void main()\n 508 {\n 509 Frag_UV = UV;\n 510 Frag_Color = Color;\n 511 gl_Position = ProjMtx * vec4(Position.xy,0,1);\n 512 }\n"; 513 514 const GLchar* vertex_shader_glsl_410_core = 515 "layout (location = 0) in vec2 Position;\n 516 layout (location = 1) in vec2 UV;\n 517 layout (location = 2) in vec4 Color;\n 518 uniform mat4 ProjMtx;\n 519 out vec2 Frag_UV;\n 520 out vec4 Frag_Color;\n 521 void main()\n 522 {\n 523 Frag_UV = UV;\n 524 Frag_Color = Color;\n 525 gl_Position = ProjMtx * vec4(Position.xy,0,1);\n 526 }\n"; 527 528 const GLchar* fragment_shader_glsl_120 = 529 "#ifdef GL_ES\n 530 precision mediump float;\n 531 #endif\n 532 uniform sampler2D Texture;\n 533 varying vec2 Frag_UV;\n 534 varying vec4 Frag_Color;\n 535 void main()\n 536 {\n 537 gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV.st);\n 538 }\n"; 539 540 const GLchar* fragment_shader_glsl_130 = 541 "uniform sampler2D Texture;\n 542 in vec2 Frag_UV;\n 543 in vec4 Frag_Color;\n 544 out vec4 Out_Color;\n 545 void main()\n 546 {\n 547 Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n 548 }\n"; 549 550 const GLchar* fragment_shader_glsl_300_es = 551 "precision mediump float;\n 552 uniform sampler2D Texture;\n 553 in vec2 Frag_UV;\n 554 in vec4 Frag_Color;\n 555 layout (location = 0) out vec4 Out_Color;\n 556 void main()\n 557 {\n 558 Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n 559 }\n"; 560 561 const GLchar* fragment_shader_glsl_410_core = 562 "in vec2 Frag_UV;\n 563 in vec4 Frag_Color;\n 564 uniform sampler2D Texture;\n 565 layout (location = 0) out vec4 Out_Color;\n 566 void main()\n 567 {\n 568 Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\n 569 }\n"; 570 571 // Select shaders matching our GLSL versions 572 const (char)* vertex_shader = null; 573 const (char)* fragment_shader = null; 574 if (glsl_version < 130) 575 { 576 vertex_shader = vertex_shader_glsl_120; 577 fragment_shader = fragment_shader_glsl_120; 578 } 579 else if (glsl_version >= 410) 580 { 581 vertex_shader = vertex_shader_glsl_410_core; 582 fragment_shader = fragment_shader_glsl_410_core; 583 } 584 else if (glsl_version == 300) 585 { 586 vertex_shader = vertex_shader_glsl_300_es; 587 fragment_shader = fragment_shader_glsl_300_es; 588 } 589 else 590 { 591 vertex_shader = vertex_shader_glsl_130; 592 fragment_shader = fragment_shader_glsl_130; 593 } 594 595 // Create shaders 596 const (char)*[2] vertex_shader_with_version = [ g_GlslVersionString.ptr, vertex_shader ]; 597 g_VertHandle = glCreateShader(GL_VERTEX_SHADER); 598 glShaderSource(g_VertHandle, 2, vertex_shader_with_version.ptr, null); 599 glCompileShader(g_VertHandle); 600 CheckShader(g_VertHandle, "vertex shader"); 601 602 const (char)*[2] fragment_shader_with_version = [ g_GlslVersionString.ptr, fragment_shader ]; 603 g_FragHandle = glCreateShader(GL_FRAGMENT_SHADER); 604 glShaderSource(g_FragHandle, 2, fragment_shader_with_version.ptr, null); 605 glCompileShader(g_FragHandle); 606 CheckShader(g_FragHandle, "fragment shader"); 607 608 g_ShaderHandle = glCreateProgram(); 609 glAttachShader(g_ShaderHandle, g_VertHandle); 610 glAttachShader(g_ShaderHandle, g_FragHandle); 611 glLinkProgram(g_ShaderHandle); 612 CheckProgram(g_ShaderHandle, "shader program"); 613 614 g_AttribLocationTex = glGetUniformLocation(g_ShaderHandle, "Texture"); 615 g_AttribLocationProjMtx = glGetUniformLocation(g_ShaderHandle, "ProjMtx"); 616 g_AttribLocationVtxPos = glGetAttribLocation(g_ShaderHandle, "Position"); 617 g_AttribLocationVtxUV = glGetAttribLocation(g_ShaderHandle, "UV"); 618 g_AttribLocationVtxColor = glGetAttribLocation(g_ShaderHandle, "Color"); 619 620 // Create buffers 621 glGenBuffers(1, &g_VboHandle); 622 glGenBuffers(1, &g_ElementsHandle); 623 624 ImGui_ImplOpenGL3_CreateFontsTexture(); 625 626 // Restore modified GL state 627 glBindTexture(GL_TEXTURE_2D, last_texture); 628 glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 629 // #ifndef IMGUI_IMPL_OPENGL_ES2 630 // glBindVertexArray(last_vertex_array); 631 // #endif 632 633 return true; 634 } 635 636 void ImGui_ImplOpenGL3_DestroyDeviceObjects() 637 { 638 if (g_VboHandle) { glDeleteBuffers(1, &g_VboHandle); g_VboHandle = 0; } 639 if (g_ElementsHandle) { glDeleteBuffers(1, &g_ElementsHandle); g_ElementsHandle = 0; } 640 if (g_ShaderHandle && g_VertHandle) { glDetachShader(g_ShaderHandle, g_VertHandle); } 641 if (g_ShaderHandle && g_FragHandle) { glDetachShader(g_ShaderHandle, g_FragHandle); } 642 if (g_VertHandle) { glDeleteShader(g_VertHandle); g_VertHandle = 0; } 643 if (g_FragHandle) { glDeleteShader(g_FragHandle); g_FragHandle = 0; } 644 if (g_ShaderHandle) { glDeleteProgram(g_ShaderHandle); g_ShaderHandle = 0; } 645 646 ImGui_ImplOpenGL3_DestroyFontsTexture(); 647 } 648 649 static bool CheckShader(GLuint handle, const char* desc) 650 { 651 GLint status = 0, log_length = 0; 652 glGetShaderiv(handle, GL_COMPILE_STATUS, &status); 653 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length); 654 /*if (cast(GLboolean)status == GL_FALSE) 655 fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to compile %s!\n", desc); 656 if (log_length > 1) 657 { 658 ImVector<char> buf; 659 buf.resize(cast(int)(log_length + 1)); 660 glGetShaderInfoLog(handle, log_length, null, cast(GLchar*)buf.begin()); 661 fprintf(stderr, "%s\n", buf.begin()); 662 }*/ 663 return cast(GLboolean)status == GL_TRUE; 664 } 665 666 // If you get an error please report on GitHub. You may try different GL context version or GLSL version. 667 static bool CheckProgram(GLuint handle, const char* desc) 668 { 669 GLint status = 0, log_length = 0; 670 glGetProgramiv(handle, GL_LINK_STATUS, &status); 671 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length); 672 /*if (cast(GLboolean)status == GL_FALSE) 673 fprintf(stderr, "ERROR: ImGui_ImplOpenGL3_CreateDeviceObjects: failed to link %s! (with GLSL '%s')\n", desc, g_GlslVersionString); 674 if (log_length > 1) 675 { 676 ImVector<char> buf; 677 buf.resize(cast(int)(log_length + 1)); 678 glGetProgramInfoLog(handle, log_length, null, cast(GLchar*)buf.begin()); 679 fprintf(stderr, "%s\n", buf.begin()); 680 }*/ 681 return cast(GLboolean)status == GL_TRUE; 682 } 683 684 bool ImGui_ImplOpenGL3_CreateFontsTexture() 685 { 686 // Build texture atlas 687 ImGuiIO* io = igGetIO(); 688 ubyte* pixels; 689 int width, height, bpp; 690 691 ImFontAtlas_GetTexDataAsRGBA32(io.Fonts,&pixels, &width, &height, &bpp); 692 //io.Fonts.GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory. 693 694 // Upload texture to graphics system 695 GLint last_texture; 696 glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 697 glGenTextures(1, &g_FontTexture); 698 glBindTexture(GL_TEXTURE_2D, g_FontTexture); 699 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 700 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 701 // #ifdef GL_UNPACK_ROW_LENGTH 702 // glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 703 // #endif 704 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 705 706 // Store our identifier 707 io.Fonts.TexID = cast(ImTextureID)cast(sizediff_t)g_FontTexture; 708 709 // Restore state 710 glBindTexture(GL_TEXTURE_2D, last_texture); 711 712 return true; 713 } 714 715 void ImGui_ImplOpenGL3_DestroyFontsTexture() 716 { 717 if (g_FontTexture) 718 { 719 ImGuiIO* io = igGetIO(); 720 glDeleteTextures(1, &g_FontTexture); 721 io.Fonts.TexID = null; 722 g_FontTexture = 0; 723 } 724 } 725 726 void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data) 727 { 728 // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) 729 int fb_width = cast(int)(draw_data.DisplaySize.x * draw_data.FramebufferScale.x); 730 int fb_height = cast(int)(draw_data.DisplaySize.y * draw_data.FramebufferScale.y); 731 if (fb_width <= 0 || fb_height <= 0) 732 return; 733 734 // Backup GL state 735 GLenum last_active_texture; glGetIntegerv(GL_ACTIVE_TEXTURE, cast(GLint*)&last_active_texture); 736 glActiveTexture(GL_TEXTURE0); 737 GLint last_program; glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); 738 GLint last_texture; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); 739 // #ifdef GL_SAMPLER_BINDING 740 // GLint last_sampler; glGetIntegerv(GL_SAMPLER_BINDING, &last_sampler); 741 // #endif 742 GLint last_array_buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 743 // #ifndef IMGUI_IMPL_OPENGL_ES2 744 // GLint last_vertex_array_object; glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array_object); 745 // #endif 746 // #ifdef GL_POLYGON_MODE 747 // GLint last_polygon_mode[2]; glGetIntegerv(GL_POLYGON_MODE, last_polygon_mode); 748 // #endif 749 GLint[4] last_viewport; glGetIntegerv(GL_VIEWPORT, last_viewport.ptr); 750 GLint[4] last_scissor_box; glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box.ptr); 751 GLenum last_blend_src_rgb; glGetIntegerv(GL_BLEND_SRC_RGB, cast(GLint*)&last_blend_src_rgb); 752 GLenum last_blend_dst_rgb; glGetIntegerv(GL_BLEND_DST_RGB, cast(GLint*)&last_blend_dst_rgb); 753 GLenum last_blend_src_alpha; glGetIntegerv(GL_BLEND_SRC_ALPHA, cast(GLint*)&last_blend_src_alpha); 754 GLenum last_blend_dst_alpha; glGetIntegerv(GL_BLEND_DST_ALPHA, cast(GLint*)&last_blend_dst_alpha); 755 GLenum last_blend_equation_rgb; glGetIntegerv(GL_BLEND_EQUATION_RGB, cast(GLint*)&last_blend_equation_rgb); 756 GLenum last_blend_equation_alpha; glGetIntegerv(GL_BLEND_EQUATION_ALPHA, cast(GLint*)&last_blend_equation_alpha); 757 GLboolean last_enable_blend = glIsEnabled(GL_BLEND); 758 GLboolean last_enable_cull_face = glIsEnabled(GL_CULL_FACE); 759 GLboolean last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); 760 GLboolean last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); 761 762 // Setup desired GL state 763 // Recreate the VAO every time (this is to easily allow multiple GL contexts to be rendered to. VAO are not shared among GL contexts) 764 // The renderer would actually work without any VAO bound, but then our VertexAttrib calls would overwrite the default one currently bound. 765 GLuint vertex_array_object = 0; 766 // #ifndef IMGUI_IMPL_OPENGL_ES2 767 // glGenVertexArrays(1, &vertex_array_object); 768 // #endif 769 ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); 770 771 // Will project scissor/clipping rectangles into framebuffer space 772 ImVec2 clip_off = draw_data.DisplayPos; // (0,0) unless using multi-viewports 773 ImVec2 clip_scale = draw_data.FramebufferScale; // (1,1) unless using retina display which are often (2,2) 774 775 // Render command lists 776 for (int n = 0; n < draw_data.CmdListsCount; n++) 777 { 778 const ImDrawList* cmd_list = draw_data.CmdLists[n]; 779 780 // Upload vertex/index buffers 781 glBufferData(GL_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.VtxBuffer.Size * ImDrawVert.sizeof, cast(const GLvoid*)cmd_list.VtxBuffer.Data, GL_STREAM_DRAW); 782 glBufferData(GL_ELEMENT_ARRAY_BUFFER, cast(GLsizeiptr)cmd_list.IdxBuffer.Size * ImDrawIdx.sizeof, cast(const GLvoid*)cmd_list.IdxBuffer.Data, GL_STREAM_DRAW); 783 784 for (int cmd_i = 0; cmd_i < cmd_list.CmdBuffer.Size; cmd_i++) 785 { 786 const ImDrawCmd* pcmd = &cmd_list.CmdBuffer.Data[cmd_i]; 787 if (pcmd.UserCallback != null) 788 { 789 // User callback, registered via ImDrawList::AddCallback() 790 // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.) 791 // if (pcmd.UserCallback == ImDrawCallback_ResetRenderState) 792 // ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object); 793 // else 794 pcmd.UserCallback(cmd_list, pcmd); 795 } 796 else 797 { 798 // Project scissor/clipping rectangles into framebuffer space 799 ImVec4 clip_rect = ImVec4(0,0,0,0); 800 clip_rect.x = (pcmd.ClipRect.x - clip_off.x) * clip_scale.x; 801 clip_rect.y = (pcmd.ClipRect.y - clip_off.y) * clip_scale.y; 802 clip_rect.z = (pcmd.ClipRect.z - clip_off.x) * clip_scale.x; 803 clip_rect.w = (pcmd.ClipRect.w - clip_off.y) * clip_scale.y; 804 805 if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f) 806 { 807 // Apply scissor/clipping rectangle 808 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)); 809 810 // Bind texture, Draw 811 glBindTexture(GL_TEXTURE_2D, cast(GLuint)cast(sizediff_t)pcmd.TextureId); 812 // #if IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET 813 // if (g_GlVersion >= 320) 814 // glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd.ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd.IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd.VtxOffset); 815 // else 816 // #endif 817 glDrawElements(GL_TRIANGLES, cast(GLsizei)pcmd.ElemCount, ImDrawIdx.sizeof == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, cast(void*)cast(sizediff_t)(pcmd.IdxOffset * ImDrawIdx.sizeof)); 818 } 819 } 820 } 821 } 822 823 // Destroy the temporary VAO 824 // #ifndef IMGUI_IMPL_OPENGL_ES2 825 // glDeleteVertexArrays(1, &vertex_array_object); 826 // #endif 827 828 // Restore modified GL state 829 glUseProgram(last_program); 830 glBindTexture(GL_TEXTURE_2D, last_texture); 831 // #ifdef GL_SAMPLER_BINDING 832 // glBindSampler(0, last_sampler); 833 // #endif 834 glActiveTexture(last_active_texture); 835 // #ifndef IMGUI_IMPL_OPENGL_ES2 836 // glBindVertexArray(last_vertex_array_object); 837 // #endif 838 glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 839 glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); 840 glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); 841 if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); 842 if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); 843 if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); 844 if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); 845 // #ifdef GL_POLYGON_MODE 846 // glPolygonMode(GL_FRONT_AND_BACK, (GLenum)last_polygon_mode[0]); 847 // #endif 848 glViewport(last_viewport[0], last_viewport[1], cast(GLsizei)last_viewport[2], cast(GLsizei)last_viewport[3]); 849 glScissor(last_scissor_box[0], last_scissor_box[1], cast(GLsizei)last_scissor_box[2], cast(GLsizei)last_scissor_box[3]); 850 }