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