1 /* 2 Copyright © 2020, Inochi2D Project 3 Distributed under the 2-Clause BSD License, see LICENSE file. 4 5 Authors: Luna Nielsen 6 */ 7 module creator.core; 8 import creator.core.font; 9 import creator.panels; 10 import creator.windows; 11 import creator.utils.link; 12 import creator; 13 14 import std.exception; 15 16 import bindbc.sdl; 17 import bindbc.opengl; 18 import inochi2d; 19 import tinyfiledialogs; 20 import std.string; 21 import std.stdio; 22 import std.conv; 23 import std.range : repeat; 24 25 public import bindbc.imgui; 26 public import bindbc.imgui.ogl; 27 public import creator.core.settings; 28 public import creator.core.actionstack; 29 public import creator.core.taskstack; 30 public import creator.core.path; 31 public import creator.core.font; 32 33 private { 34 SDL_GLContext gl_context; 35 SDL_Window* window; 36 ImGuiIO* io; 37 bool done = false; 38 ImGuiID viewportDock; 39 40 Texture inLogo; 41 42 ImFont* mainFont; 43 ImFont* iconFont; 44 ImFont* biggerFont; 45 46 bool isDarkMode = true; 47 string[] files; 48 } 49 50 bool incShowStatsForNerds; 51 52 53 /** 54 Finalizes everything by freeing imgui resources, etc. 55 */ 56 void incFinalize() { 57 58 // This is important to prevent thread leakage 59 import creator.viewport.test : incViewportTestWithdraw; 60 incViewportTestWithdraw(); 61 62 // Save settings 63 igSaveIniSettingsToDisk(igGetIO().IniFilename); 64 65 // Cleanup 66 ImGuiOpenGLBackend.shutdown(); 67 ImGui_ImplSDL2_Shutdown(); 68 igDestroyContext(null); 69 70 SDL_GL_DeleteContext(gl_context); 71 SDL_DestroyWindow(window); 72 SDL_Quit(); 73 } 74 75 /** 76 Gets dockspace of the viewport 77 */ 78 ImGuiID incGetViewportDockSpace() { 79 return viewportDock; 80 } 81 82 /** 83 Initialize styling 84 */ 85 void incInitStyling() { 86 auto style = igGetStyle(); 87 //style.WindowBorderSize = 0; 88 style.ChildBorderSize = 1; 89 style.PopupBorderSize = 1; 90 style.FrameBorderSize = 1; 91 style.TabBorderSize = 1; 92 93 style.WindowRounding = 4; 94 style.ChildRounding = 0; 95 style.FrameRounding = 3; 96 style.PopupRounding = 6; 97 style.ScrollbarRounding = 18; 98 style.GrabRounding = 3; 99 style.LogSliderDeadzone = 6; 100 style.TabRounding = 6; 101 102 style.IndentSpacing = 10; 103 style.ItemSpacing.y = 3; 104 style.FramePadding.y = 4; 105 106 style.GrabMinSize = 13; 107 style.ScrollbarSize = 14; 108 style.ChildBorderSize = 1; 109 } 110 111 /** 112 Opens Window 113 */ 114 void incOpenWindow() { 115 116 import core.stdc.stdlib : exit; 117 118 auto sdlSupport = loadSDL(); 119 enforce(sdlSupport != SDLSupport.noLibrary, "SDL2 library not found!"); 120 enforce(sdlSupport != SDLSupport.badLibrary, "Bad SDL2 library found!"); 121 122 auto imSupport = loadImGui(); 123 enforce(imSupport != ImGuiSupport.noLibrary, "cimgui library not found!"); 124 125 // HACK: For some reason this check fails on some macOS and Linux installations 126 version(Windows) enforce(imSupport != ImGuiSupport.badLibrary, "Bad cimgui library found!"); 127 SDL_Init(SDL_INIT_EVERYTHING); 128 129 SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0); 130 version(OSX) { 131 pragma(msg, "Building in macOS support mode..."); 132 133 // macOS only supports up to GL 4.1 with some extra stuff 134 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GLcontextFlag.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); 135 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE); 136 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 137 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); 138 } else { 139 140 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GLcontextFlag.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); 141 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); 142 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); 143 } 144 debug SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GLcontextFlag.SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GLcontextFlag.SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); 145 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 146 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); 147 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); 148 149 SDL_WindowFlags flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; 150 151 if (incSettingsGet!bool("WinMax", false)) { 152 flags |= SDL_WINDOW_MAXIMIZED; 153 } 154 155 // Don't make KDE freak out when Inochi Creator opens 156 if (!incSettingsGet!bool("DisableCompositor")) SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0"); 157 158 window = SDL_CreateWindow( 159 "Inochi Creator", 160 SDL_WINDOWPOS_UNDEFINED, 161 SDL_WINDOWPOS_UNDEFINED, 162 cast(uint)incSettingsGet!int("WinW", 1280), 163 cast(uint)incSettingsGet!int("WinH", 800), 164 flags 165 ); 166 167 gl_context = SDL_GL_CreateContext(window); 168 SDL_GL_MakeCurrent(window, gl_context); 169 SDL_GL_SetSwapInterval(1); 170 171 // Load GL 3 172 GLSupport support = loadOpenGL(); 173 switch(support) { 174 case GLSupport.noLibrary: 175 throw new Exception("OpenGL library could not be loaded!"); 176 177 case GLSupport.noContext: 178 throw new Exception("No valid OpenGL 4.2 context was found!"); 179 180 default: break; 181 } 182 183 import std.string : fromStringz; 184 debug { 185 writefln("GLInfo:\n\t%s\n\t%s\n\t%s\n\t%s\n\tgls=%s", 186 glGetString(GL_VERSION).fromStringz, 187 glGetString(GL_VENDOR).fromStringz, 188 glGetString(GL_RENDERER).fromStringz, 189 glGetString(GL_SHADING_LANGUAGE_VERSION).fromStringz, 190 support 191 ); 192 193 glEnable(GL_DEBUG_OUTPUT); 194 version(Posix) { 195 glDebugMessageCallback(&incDebugCallback, null); 196 } 197 } 198 199 // Setup Inochi2D 200 inInit(() { return igGetTime(); }); 201 202 incCreateContext(); 203 204 205 // Load image resources 206 inLogo = new Texture(ShallowTexture(cast(ubyte[])import("logo.png"))); 207 208 // Load Settings 209 incShowStatsForNerds = incSettingsCanGet("NerdStats") ? incSettingsGet!bool("NerdStats") : false; 210 211 import creator.widgets.titlebar : incSetUseNativeTitlebar, incGetUseNativeTitlebar, incCanUseAppTitlebar; 212 incCanUseAppTitlebar = SDL_SetWindowHitTest(incGetWindowPtr(), null, null) != -1; 213 incSetUseNativeTitlebar(incSettingsGet("UseNativeTitleBar", false)); 214 215 } 216 217 void incCreateContext() { 218 219 // Setup IMGUI 220 igCreateContext(null); 221 io = igGetIO(); 222 223 // Setup font handling 224 incInitFonts(); 225 226 import std.file : exists; 227 if (!exists(incGetAppImguiConfigFile())) { 228 // TODO: Setup a base config 229 } 230 231 232 // Copy string out of GC memory to make sure it doesn't get yeeted before imgui exits. 233 import core.stdc.stdlib : malloc; 234 import core.stdc.string : memcpy; 235 io.IniFilename = cast(char*)malloc(incGetAppImguiConfigFile().length+1); 236 memcpy(cast(void*)io.IniFilename, toStringz(incGetAppImguiConfigFile), incGetAppImguiConfigFile().length+1); 237 igLoadIniSettingsFromDisk(io.IniFilename); 238 239 incSetDarkMode(incSettingsGet!bool("DarkMode", true)); 240 241 io.ConfigFlags |= ImGuiConfigFlags.DockingEnable; // Enable Docking 242 io.ConfigFlags |= ImGuiConfigFlags.ViewportsEnable; // Enable Viewports (causes freezes) 243 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Navigation 244 io.ConfigWindowsResizeFromEdges = true; // Enable Edge resizing 245 ImGui_ImplSDL2_InitForOpenGL(window, gl_context); 246 ImGuiOpenGLBackend.init(null); 247 248 incInitStyling(); 249 } 250 251 void incSetDarkMode(bool darkMode) { 252 auto style = igGetStyle(); 253 254 if (darkMode) { 255 style.Colors[ImGuiCol.Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); 256 style.Colors[ImGuiCol.TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 257 style.Colors[ImGuiCol.WindowBg] = ImVec4(0.17f, 0.17f, 0.17f, 1.00f); 258 style.Colors[ImGuiCol.ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 259 style.Colors[ImGuiCol.PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f); 260 style.Colors[ImGuiCol.Border] = ImVec4(0.00f, 0.00f, 0.00f, 0.16f); 261 style.Colors[ImGuiCol.BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.16f); 262 style.Colors[ImGuiCol.FrameBg] = ImVec4(0.12f, 0.12f, 0.12f, 1.00f); 263 style.Colors[ImGuiCol.FrameBgHovered] = ImVec4(0.15f, 0.15f, 0.15f, 0.40f); 264 style.Colors[ImGuiCol.FrameBgActive] = ImVec4(0.22f, 0.22f, 0.22f, 0.67f); 265 style.Colors[ImGuiCol.TitleBg] = ImVec4(0.04f, 0.04f, 0.04f, 1.00f); 266 style.Colors[ImGuiCol.TitleBgActive] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 267 style.Colors[ImGuiCol.TitleBgCollapsed] = ImVec4(0.00f, 0.00f, 0.00f, 0.51f); 268 style.Colors[ImGuiCol.MenuBarBg] = ImVec4(0.05f, 0.05f, 0.05f, 1.00f); 269 style.Colors[ImGuiCol.ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f); 270 style.Colors[ImGuiCol.ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f); 271 style.Colors[ImGuiCol.ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f); 272 style.Colors[ImGuiCol.ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f); 273 style.Colors[ImGuiCol.CheckMark] = ImVec4(0.76f, 0.76f, 0.76f, 1.00f); 274 style.Colors[ImGuiCol.SliderGrab] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); 275 style.Colors[ImGuiCol.SliderGrabActive] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); 276 style.Colors[ImGuiCol.Button] = ImVec4(0.39f, 0.39f, 0.39f, 0.40f); 277 style.Colors[ImGuiCol.ButtonHovered] = ImVec4(0.44f, 0.44f, 0.44f, 1.00f); 278 style.Colors[ImGuiCol.ButtonActive] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); 279 style.Colors[ImGuiCol.Header] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); 280 style.Colors[ImGuiCol.HeaderHovered] = ImVec4(0.28f, 0.28f, 0.28f, 0.80f); 281 style.Colors[ImGuiCol.HeaderActive] = ImVec4(0.44f, 0.44f, 0.44f, 1.00f); 282 style.Colors[ImGuiCol.Separator] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 283 style.Colors[ImGuiCol.SeparatorHovered] = ImVec4(0.29f, 0.29f, 0.29f, 0.78f); 284 style.Colors[ImGuiCol.SeparatorActive] = ImVec4(0.47f, 0.47f, 0.47f, 1.00f); 285 style.Colors[ImGuiCol.ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.00f); 286 style.Colors[ImGuiCol.ResizeGripHovered] = ImVec4(0.40f, 0.40f, 0.40f, 0.00f); 287 style.Colors[ImGuiCol.ResizeGripActive] = ImVec4(0.55f, 0.55f, 0.56f, 0.00f); 288 style.Colors[ImGuiCol.Tab] = ImVec4(0.00f, 0.00f, 0.00f, 1.00f); 289 style.Colors[ImGuiCol.TabHovered] = ImVec4(0.34f, 0.34f, 0.34f, 0.80f); 290 style.Colors[ImGuiCol.TabActive] = ImVec4(0.25f, 0.25f, 0.25f, 1.00f); 291 style.Colors[ImGuiCol.TabUnfocused] = ImVec4(0.14f, 0.14f, 0.14f, 0.97f); 292 style.Colors[ImGuiCol.TabUnfocusedActive] = ImVec4(0.17f, 0.17f, 0.17f, 1.00f); 293 style.Colors[ImGuiCol.DockingPreview] = ImVec4(0.62f, 0.68f, 0.75f, 0.70f); 294 style.Colors[ImGuiCol.DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f); 295 style.Colors[ImGuiCol.PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f); 296 style.Colors[ImGuiCol.PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f); 297 style.Colors[ImGuiCol.PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); 298 style.Colors[ImGuiCol.PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); 299 style.Colors[ImGuiCol.TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f); 300 style.Colors[ImGuiCol.TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f); 301 style.Colors[ImGuiCol.TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); 302 style.Colors[ImGuiCol.TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); 303 style.Colors[ImGuiCol.TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f); 304 style.Colors[ImGuiCol.TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f); 305 style.Colors[ImGuiCol.DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); 306 style.Colors[ImGuiCol.NavHighlight] = ImVec4(0.32f, 0.32f, 0.32f, 1.00f); 307 style.Colors[ImGuiCol.NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f); 308 style.Colors[ImGuiCol.NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); 309 style.Colors[ImGuiCol.ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); 310 311 style.FrameBorderSize = 1; 312 style.TabBorderSize = 1; 313 } else { 314 igStyleColorsLight(null); 315 style.Colors[ImGuiCol.Border] = ImVec4(0.8, 0.8, 0.8, 0.5); 316 style.Colors[ImGuiCol.BorderShadow] = ImVec4(0, 0, 0, 0.05); 317 318 style.FrameBorderSize = 1; 319 } 320 321 // Set Dark mode setting 322 incSettingsSet("DarkMode", darkMode); 323 isDarkMode = darkMode; 324 } 325 326 bool incGetDarkMode() { 327 return isDarkMode; 328 } 329 330 /** 331 Gets whether a frame should be processed 332 */ 333 bool incShouldProcess() { 334 return (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) == 0; 335 } 336 337 /** 338 Gets SDL Window Pointer 339 */ 340 SDL_Window* incGetWindowPtr() { 341 return window; 342 } 343 344 void incFinishFileDrag() { 345 files.length = 0; 346 } 347 348 void incBeginLoopNoEv() { 349 // Start the Dear ImGui frame 350 ImGuiOpenGLBackend.new_frame(); 351 ImGui_ImplSDL2_NewFrame(); 352 igNewFrame(); 353 354 if (files.length > 0) { 355 if (igBeginDragDropSource(ImGuiDragDropFlags.SourceExtern)) { 356 igSetDragDropPayload("__PARTS_DROP", &files, files.sizeof); 357 igBeginTooltip(); 358 foreach(file; files) { 359 igText(file.toStringz); 360 } 361 igEndTooltip(); 362 igEndDragDropSource(); 363 } 364 } 365 366 // Add docking space 367 viewportDock = igDockSpaceOverViewport(null, cast(ImGuiDockNodeFlags)0, null); 368 if (!incSettingsCanGet("firstrun_complete")) { 369 incSetDefaultLayout(); 370 incSettingsSet("firstrun_complete", true); 371 } 372 } 373 374 void incSetDefaultLayout() { 375 import creator.panels; 376 377 igDockBuilderRemoveNodeChildNodes(viewportDock); 378 ImGuiID 379 dockMainID, dockIDNodes, dockIDInspector, dockIDHistory, dockIDParams, 380 dockIDToolSettings, dockIDLoggerAndTextureSlots; 381 382 dockMainID = viewportDock; 383 dockIDNodes = igDockBuilderSplitNode(dockMainID, ImGuiDir.Left, 0.10f, null, &dockMainID); 384 dockIDInspector = igDockBuilderSplitNode(dockIDNodes, ImGuiDir.Down, 0.60f, null, &dockIDNodes); 385 dockIDToolSettings = igDockBuilderSplitNode(dockMainID, ImGuiDir.Right, 0.10f, null, &dockMainID); 386 dockIDHistory = igDockBuilderSplitNode(dockIDToolSettings, ImGuiDir.Down, 0.50f, null, &dockIDToolSettings); 387 dockIDParams = igDockBuilderSplitNode(dockMainID, ImGuiDir.Left, 0.15f, null, &dockMainID); 388 dockIDLoggerAndTextureSlots = igDockBuilderSplitNode(dockMainID, ImGuiDir.Down, 0.15f, null, &dockMainID); 389 390 igDockBuilderDockWindow("###Nodes", dockIDNodes); 391 igDockBuilderDockWindow("###Inspector", dockIDInspector); 392 igDockBuilderDockWindow("###Tool Settings", dockIDToolSettings); 393 igDockBuilderDockWindow("###History", dockIDHistory); 394 igDockBuilderDockWindow("###Tracking", dockIDHistory); 395 igDockBuilderDockWindow("###Parameters", dockIDParams); 396 igDockBuilderDockWindow("###Texture Slots", dockIDLoggerAndTextureSlots); 397 igDockBuilderDockWindow("###Logger", dockIDLoggerAndTextureSlots); 398 399 igDockBuilderFinish(viewportDock); 400 } 401 402 /** 403 Begins the Inochi Creator rendering loop 404 */ 405 void incBeginLoop() { 406 SDL_Event event; 407 408 while(SDL_PollEvent(&event)) { 409 switch(event.type) { 410 case SDL_QUIT: 411 incExit(); 412 break; 413 414 case SDL_DROPFILE: 415 files ~= cast(string)event.drop.file.fromStringz; 416 SDL_RaiseWindow(window); 417 break; 418 419 default: 420 ImGui_ImplSDL2_ProcessEvent(&event); 421 if ( 422 event.type == SDL_WINDOWEVENT && 423 event.window.event == SDL_WINDOWEVENT_CLOSE && 424 event.window.windowID == SDL_GetWindowID(window) 425 ) incExit(); 426 break; 427 } 428 } 429 430 incTaskUpdate(); 431 432 // Begin loop post-event 433 incBeginLoopNoEv(); 434 } 435 436 /** 437 Ends the Inochi Creator rendering loop 438 */ 439 void incEndLoop() { 440 441 // Rendering 442 igRender(); 443 glViewport(0, 0, cast(int)io.DisplaySize.x, cast(int)io.DisplaySize.y); 444 glClearColor(0.5, 0.5, 0.5, 1); 445 glClear(GL_COLOR_BUFFER_BIT); 446 ImGuiOpenGLBackend.render_draw_data(igGetDrawData()); 447 448 if (io.ConfigFlags & ImGuiConfigFlags.ViewportsEnable) { 449 SDL_Window* currentWindow = SDL_GL_GetCurrentWindow(); 450 SDL_GLContext currentCtx = SDL_GL_GetCurrentContext(); 451 igUpdatePlatformWindows(); 452 igRenderPlatformWindowsDefault(); 453 SDL_GL_MakeCurrent(currentWindow, currentCtx); 454 } 455 456 SDL_GL_SwapWindow(window); 457 } 458 459 /** 460 Prints ImGui debug info 461 */ 462 void incDebugImGuiState(string msg, int indent = 0) { 463 debug(imgui) { 464 static int currentIndent = 0; 465 466 string flag = " "; 467 if (indent > 0) { 468 currentIndent += indent; 469 flag = ">>"; 470 } else if (indent < 0) { 471 flag = "<<"; 472 } 473 474 //auto g = igGetCurrentContext(); 475 auto win = igGetCurrentWindow(); 476 writefln( 477 "%s%s%s [%s]", ' '.repeat(currentIndent * 2), flag, msg, 478 to!string(win.Name) 479 ); 480 481 if (indent < 0) { 482 currentIndent += indent; 483 if (currentIndent < 0) { 484 debug writeln("ERROR: dedented too far!"); 485 currentIndent = 0; 486 } 487 } 488 } 489 } 490 491 /** 492 Gets whether Inochi Creator has requested the app to close 493 */ 494 bool incIsCloseRequested() { 495 return done; 496 } 497 498 /** 499 Exit Inochi Creator 500 */ 501 void incExit() { 502 done = true; 503 504 int w, h; 505 SDL_WindowFlags flags; 506 flags = SDL_GetWindowFlags(window); 507 SDL_GetWindowSize(window, &w, &h); 508 incSettingsSet("WinW", w); 509 incSettingsSet("WinH", h); 510 incSettingsSet!bool("WinMax", (flags & SDL_WINDOW_MAXIMIZED) > 0); 511 } 512 513 /** 514 Main font 515 */ 516 ImFont* incMainFont() { 517 return mainFont; 518 } 519 520 /** 521 Bigger sized font 522 */ 523 ImFont* incBiggerFont() { 524 return biggerFont; 525 } 526 527 /** 528 Bigger sized font 529 */ 530 ImFont* incIconFont() { 531 return iconFont; 532 } 533 534 /** 535 Gets the Inochi2D Logo 536 */ 537 GLuint incGetLogo() { 538 return inLogo.getTextureId; 539 } 540 541 void incHandleShortcuts() { 542 auto io = igGetIO(); 543 544 if (io.KeyCtrl && io.KeyShift && igIsKeyPressed(igGetKeyIndex(ImGuiKey.Z), true)) { 545 incActionRedo(); 546 } else if (io.KeyCtrl && igIsKeyPressed(igGetKeyIndex(ImGuiKey.Z), true)) { 547 incActionUndo(); 548 } 549 } 550 551 552 debug { 553 extern(C) 554 void incDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const(char)* message, void* userParam) nothrow { 555 import core.stdc.stdio : fprintf, stderr; 556 if (type == 0x8251) return; 557 558 // HACK: I have no clue what causes this error 559 // but everything seems to work nontheless 560 // I'll just quietly ignore it. 561 if (type == 0x824c) return; 562 563 fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", 564 ( type == GL_DEBUG_TYPE_ERROR ? cast(char*)"** GL ERROR **" : cast(char*)"" ), 565 type, severity, message ); 566 567 } 568 }