diff --git a/src/hello_imgui/doc_params.md b/src/hello_imgui/doc_params.md index c89c4669..c6490bbe 100644 --- a/src/hello_imgui/doc_params.md +++ b/src/hello_imgui/doc_params.md @@ -313,11 +313,10 @@ struct RunnerCallbacks void EnqueuePostInit(const VoidFunction& callback); // `LoadAdditionalFonts`: default=_LoadDefaultFont_WithFontAwesome*. - // A function that is called once, when fonts are ready to be loaded. - // By default, _LoadDefaultFont_WithFontAwesome_ is called, - // but you can copy and customize it. - // (LoadDefaultFont_WithFontAwesome will load fonts from assets/fonts/ - // but reverts to the ImGui embedded font if not found) + // A function that is called in order to load fonts. + // `LoadAdditionalFonts` will be called once, then *set to nullptr*. + // If you want to load additional fonts, during the app execution, you can + // set LoadAdditionalFonts to a function that will load the additional fonts. VoidFunction LoadAdditionalFonts = (VoidFunction)ImGuiDefaultSettings::LoadDefaultFont_WithFontAwesomeIcons; // If LoadAdditionalFonts==LoadDefaultFont_WithFontAwesomeIcons, this parameter control // which icon font will be loaded by default. @@ -361,7 +360,7 @@ struct RunnerCallbacks // `PreNewFrame`: You can here add a function that will be called at each frame, // and before the call to ImGui::NewFrame(). - // It is a good place to dynamically add new fonts, or new dockable windows. + // It is a good place to add new dockable windows. VoidFunction PreNewFrame = EmptyVoidFunction(); // `BeforeImGuiRender`: You can here add a function that will be called at each frame, diff --git a/src/hello_imgui/internal/backend_impls/abstract_runner.cpp b/src/hello_imgui/internal/backend_impls/abstract_runner.cpp index f8571edf..730e188e 100644 --- a/src/hello_imgui/internal/backend_impls/abstract_runner.cpp +++ b/src/hello_imgui/internal/backend_impls/abstract_runner.cpp @@ -61,12 +61,18 @@ // + namespace HelloImGui { // Encapsulated inside hello_imgui_screenshot.cpp void setFinalAppWindowScreenshotRgbBuffer(const ImageBuffer& b); +// Only used with OpenGL if the font loading failed at first frame +// (used by ReloadFontIfFailed_OpenGL(), which should ideally by suppressed) +VoidFunction gInitialFontLoadingFunction = nullptr; + + AbstractRunner::AbstractRunner(RunnerParams ¶ms_) : params(params_) {} @@ -76,11 +82,11 @@ AbstractRunner::AbstractRunner(RunnerParams ¶ms_) // size for a crisper rendering) and try to reload the fonts. // This only works if the user provided callback LoadAdditionalFonts() uses DpiFontLoadingFactor() // to multiply its font size. -void AbstractRunner::ReloadFontIfFailed() const +void AbstractRunner::ReloadFontIfFailed_OpenGL() const { fprintf(stderr, "Detected a potential font loading error! You might try to reduce the number of loaded fonts and/or their size!\n"); #ifdef HELLOIMGUI_HAS_OPENGL - if (ImGui::GetIO().FontGlobalScale < 1.f) + if (ImGui::GetIO().FontGlobalScale < 1.f && gInitialFontLoadingFunction) { fprintf(stderr, "Trying to solve the font loading error by changing ImGui::GetIO().FontGlobalScale from %f to 1.f! Font rendering might be less crisp...\n", @@ -88,7 +94,7 @@ void AbstractRunner::ReloadFontIfFailed() const ); ImGui::GetIO().FontGlobalScale = 1.f; ImGui::GetIO().Fonts->Clear(); - params.callbacks.LoadAdditionalFonts(); + gInitialFontLoadingFunction(); ImGui::GetIO().Fonts->Build(); ImGui_ImplOpenGL3_CreateFontsTexture(); } @@ -662,10 +668,13 @@ void AbstractRunner::Setup() // // load fonts & set ImGui::GetIO().FontGlobalScale // - ImGui::GetIO().Fonts->Clear(); + // LoadAdditionalFonts will load fonts and resize them by 1./FontGlobalScale // (if and only if it uses HelloImGui::LoadFontTTF instead of ImGui's font loading functions) + ImGui::GetIO().Fonts->Clear(); + gInitialFontLoadingFunction = params.callbacks.LoadAdditionalFonts; params.callbacks.LoadAdditionalFonts(); + params.callbacks.LoadAdditionalFonts = nullptr; bool buildSuccess = ImGui::GetIO().Fonts->Build(); IM_ASSERT(buildSuccess && "ImGui::GetIO().Fonts->Build() failed!"); { @@ -905,6 +914,19 @@ void AbstractRunner::CreateFramesAndRender() #endif } // SCOPED_RELEASE_GIL_ON_MAIN_THREAD end + if (true_gil) // Load additional fonts during execution + { + if (params.callbacks.LoadAdditionalFonts != nullptr) + { + params.callbacks.LoadAdditionalFonts(); + ImGui::GetIO().Fonts->Build(); + // cf https://github.com/ocornut/imgui/issues/6547 + // We need to recreate the rendering backend device objects + mRenderingBackendCallbacks->Impl_DestroyFontTexture(); + mRenderingBackendCallbacks->Impl_CreateFontTexture(); + params.callbacks.LoadAdditionalFonts = nullptr; + } + } // // Rendering logic @@ -950,7 +972,10 @@ void AbstractRunner::CreateFramesAndRender() { auto error = glGetError(); if (error != 0) + { + fprintf(stderr, "OpenGL error detected on first frame: %d. Will try to reload font without scaling\n", error); foundPotentialFontLoadingError = true; + } } } #endif @@ -997,7 +1022,7 @@ void AbstractRunner::CreateFramesAndRender() #endif if (foundPotentialFontLoadingError) - ReloadFontIfFailed(); + ReloadFontIfFailed_OpenGL(); mIdxFrame += 1; } diff --git a/src/hello_imgui/internal/backend_impls/abstract_runner.h b/src/hello_imgui/internal/backend_impls/abstract_runner.h index aea7895e..c204964d 100644 --- a/src/hello_imgui/internal/backend_impls/abstract_runner.h +++ b/src/hello_imgui/internal/backend_impls/abstract_runner.h @@ -85,7 +85,7 @@ class AbstractRunner void SetupDpiAwareParams(); void PrepareWindowGeometry(); void HandleDpiOnSecondFrame(); - void ReloadFontIfFailed() const; + void ReloadFontIfFailed_OpenGL() const; void MakeWindowSizeRelativeTo96Ppi_IfRequired(); bool ShallSizeWindowRelativeTo96Ppi(); bool WantAutoSize(); diff --git a/src/hello_imgui/internal/backend_impls/rendering_callbacks.h b/src/hello_imgui/internal/backend_impls/rendering_callbacks.h index 51c1ae19..a71af02a 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_callbacks.h +++ b/src/hello_imgui/internal/backend_impls/rendering_callbacks.h @@ -98,6 +98,9 @@ namespace HelloImGui VoidFunction Impl_Shutdown_3D = [] { HIMG_ERROR("Empty function"); }; std::function Impl_ScreenshotRgb_3D = [] { return ImageBuffer{}; }; std::function Impl_GetFrameBufferSize; //= [] { return ScreenSize{0, 0}; }; + + VoidFunction Impl_DestroyFontTexture = [] { HIMG_ERROR("Empty function"); }; + VoidFunction Impl_CreateFontTexture = [] { HIMG_ERROR("Empty function"); }; }; using RenderingCallbacksPtr = std::shared_ptr; diff --git a/src/hello_imgui/internal/backend_impls/rendering_dx11.cpp b/src/hello_imgui/internal/backend_impls/rendering_dx11.cpp index acb19dbe..68eb9d06 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_dx11.cpp +++ b/src/hello_imgui/internal/backend_impls/rendering_dx11.cpp @@ -131,6 +131,9 @@ namespace HelloImGui // callbacks->Impl_GetFrameBufferSize; //= [] { return ScreenSize{0, 0}; }; + callbacks->Impl_CreateFontTexture = ImGui_ImplDX11_CreateFontsTexture; + callbacks->Impl_DestroyFontTexture = ImGui_ImplDX11_DestroyFontsTexture; + return callbacks; } diff --git a/src/hello_imgui/internal/backend_impls/rendering_dx12.cpp b/src/hello_imgui/internal/backend_impls/rendering_dx12.cpp index 275ba956..edd07af8 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_dx12.cpp +++ b/src/hello_imgui/internal/backend_impls/rendering_dx12.cpp @@ -312,6 +312,9 @@ namespace HelloImGui // callbacks->Impl_ScreenshotRgb_3D = [] { return ImageBuffer{}; }; // callbacks->Impl_GetFrameBufferSize; //= [] { return ScreenSize{0, 0}; }; + callbacks->Impl_CreateFontTexture = ImGui_ImplDX12_CreateFontsTexture; + callbacks->Impl_DestroyFontTexture = ImGui_ImplDX12_DestroyFontsTexture; + return callbacks; } diff --git a/src/hello_imgui/internal/backend_impls/rendering_metal.mm b/src/hello_imgui/internal/backend_impls/rendering_metal.mm index 04ab5f32..4af25c89 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_metal.mm +++ b/src/hello_imgui/internal/backend_impls/rendering_metal.mm @@ -102,6 +102,13 @@ RenderingCallbacksPtr PrepareBackendCallbacksCommon() ImGui_ImplMetal_Shutdown(); }; + callbacks->Impl_CreateFontTexture = [] + { + auto& gMetalGlobals = GetMetalGlobals(); + ImGui_ImplMetal_CreateFontsTexture(gMetalGlobals.mtlDevice); + }; + callbacks->Impl_DestroyFontTexture = ImGui_ImplMetal_DestroyFontsTexture; + return callbacks; } diff --git a/src/hello_imgui/internal/backend_impls/rendering_opengl3.cpp b/src/hello_imgui/internal/backend_impls/rendering_opengl3.cpp index 4e79443d..e2f84cc1 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_opengl3.cpp +++ b/src/hello_imgui/internal/backend_impls/rendering_opengl3.cpp @@ -34,6 +34,9 @@ namespace HelloImGui ImGui_ImplOpenGL3_Shutdown(); }; + callbacks->Impl_CreateFontTexture = ImGui_ImplOpenGL3_CreateFontsTexture; + callbacks->Impl_DestroyFontTexture = ImGui_ImplOpenGL3_DestroyFontsTexture; + return callbacks; } diff --git a/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp b/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp index 903143a5..91fade5a 100644 --- a/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp +++ b/src/hello_imgui/internal/backend_impls/rendering_vulkan.cpp @@ -102,6 +102,9 @@ namespace HelloImGui // callbacks->Impl_ScreenshotRgb_3D = [] { return ImageBuffer{}; }; // callbacks->Impl_GetFrameBufferSize; //= [] { return ScreenSize{0, 0}; }; + callbacks->Impl_CreateFontTexture = ImGui_ImplVulkan_CreateFontsTexture; + callbacks->Impl_DestroyFontTexture = ImGui_ImplVulkan_DestroyFontsTexture; + return callbacks; } diff --git a/src/hello_imgui/runner_callbacks.h b/src/hello_imgui/runner_callbacks.h index 43184eef..6738f633 100644 --- a/src/hello_imgui/runner_callbacks.h +++ b/src/hello_imgui/runner_callbacks.h @@ -183,11 +183,10 @@ struct RunnerCallbacks void EnqueuePostInit(const VoidFunction& callback); // `LoadAdditionalFonts`: default=_LoadDefaultFont_WithFontAwesome*. - // A function that is called once, when fonts are ready to be loaded. - // By default, _LoadDefaultFont_WithFontAwesome_ is called, - // but you can copy and customize it. - // (LoadDefaultFont_WithFontAwesome will load fonts from assets/fonts/ - // but reverts to the ImGui embedded font if not found) + // A function that is called in order to load fonts. + // `LoadAdditionalFonts` will be called once, then *set to nullptr*. + // If you want to load additional fonts, during the app execution, you can + // set LoadAdditionalFonts to a function that will load the additional fonts. VoidFunction LoadAdditionalFonts = (VoidFunction)ImGuiDefaultSettings::LoadDefaultFont_WithFontAwesomeIcons; // If LoadAdditionalFonts==LoadDefaultFont_WithFontAwesomeIcons, this parameter control // which icon font will be loaded by default. @@ -231,7 +230,7 @@ struct RunnerCallbacks // `PreNewFrame`: You can here add a function that will be called at each frame, // and before the call to ImGui::NewFrame(). - // It is a good place to dynamically add new fonts, or new dockable windows. + // It is a good place to add new dockable windows. VoidFunction PreNewFrame = EmptyVoidFunction(); // `BeforeImGuiRender`: You can here add a function that will be called at each frame,