From cd925081b0ec3d07da2caddc1607f49a41825620 Mon Sep 17 00:00:00 2001 From: Pablo Escobar Date: Wed, 27 Nov 2024 13:32:08 +0700 Subject: [PATCH] ImGuiIntegration: use 4-channel font atlas texture format if it contains color. --- src/Magnum/ImGuiIntegration/Context.cpp | 26 +++--- .../ImGuiIntegration/Test/CMakeLists.txt | 1 + .../ImGuiIntegration/Test/ContextGLTest.cpp | 76 ++++++++++++++++++ .../ContextTestFiles/draw-text-color-font.png | Bin 0 -> 1208 bytes 4 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 src/Magnum/ImGuiIntegration/Test/ContextTestFiles/draw-text-color-font.png diff --git a/src/Magnum/ImGuiIntegration/Context.cpp b/src/Magnum/ImGuiIntegration/Context.cpp index 74e85053..c5eacf5b 100644 --- a/src/Magnum/ImGuiIntegration/Context.cpp +++ b/src/Magnum/ImGuiIntegration/Context.cpp @@ -197,18 +197,22 @@ void Context::relayout(const Vector2& size, const Vector2i& windowSize, const Ve /* Downscale back the upscaled font to achieve supersampling */ io.FontGlobalScale = 1.0f/nonZeroSupersamplingRatio; + PixelFormat format; unsigned char *pixels; int width, height; int pixelSize; - /* Texture atlas only requires alpha. Use a single-channel format and - swizzle, if available, to conserve memory. */ + /* If the texture atlas only requires alpha we can use a single-channel + format and swizzle, if available, to conserve memory */ #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - constexpr PixelFormat format = PixelFormat::R8Unorm; - io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &pixelSize); - #else - constexpr PixelFormat format = PixelFormat::RGBA8Unorm; - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &pixelSize); + if(!io.Fonts->TexPixelsUseColors) { + format = PixelFormat::R8Unorm; + io.Fonts->GetTexDataAsAlpha8(&pixels, &width, &height, &pixelSize); + } else #endif + { + format = PixelFormat::RGBA8Unorm; + io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &pixelSize); + } CORRADE_INTERNAL_ASSERT(width > 0 && height > 0 && std::size_t(pixelSize) == pixelFormatSize(format)); /* Atlas width is guaranteed to be a power-of-two, so the default @@ -225,11 +229,13 @@ void Context::relayout(const Vector2& size, const Vector2i& windowSize, const Ve #else .setImage(0, GL::textureFormat(format), image) #endif - #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) - .setSwizzle<'1', '1', '1', 'r'>() - #endif ; + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + if(!io.Fonts->TexPixelsUseColors) + _texture.setSwizzle<'1', '1', '1', 'r'>(); + #endif + /* Clear texture to save RAM, we have it on the GPU now */ io.Fonts->ClearTexData(); diff --git a/src/Magnum/ImGuiIntegration/Test/CMakeLists.txt b/src/Magnum/ImGuiIntegration/Test/CMakeLists.txt index 3058ec62..d0436e7c 100644 --- a/src/Magnum/ImGuiIntegration/Test/CMakeLists.txt +++ b/src/Magnum/ImGuiIntegration/Test/CMakeLists.txt @@ -64,6 +64,7 @@ if(MAGNUM_BUILD_GL_TESTS) ContextTestFiles/draw-scissor.png ContextTestFiles/draw-texture.png ContextTestFiles/draw-text.png + ContextTestFiles/draw-text-color-font.png ContextTestFiles/texture.png) target_include_directories(ImGuiContextGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) if(MAGNUM_IMGUIINTEGRATION_BUILD_STATIC) diff --git a/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp b/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp index 3dc034bd..48568eef 100644 --- a/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp +++ b/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp @@ -269,6 +269,7 @@ struct ContextGLTest: GL::OpenGLTester { void drawCallback(); void drawTexture(); void drawText(); + void drawTextColorFont(); void drawScissor(); void drawVertexOffset(); void drawIndexOffset(); @@ -315,6 +316,7 @@ ContextGLTest::ContextGLTest() { &ContextGLTest::drawCallback, &ContextGLTest::drawTexture, &ContextGLTest::drawText, + &ContextGLTest::drawTextColorFont, &ContextGLTest::drawScissor, &ContextGLTest::drawVertexOffset, &ContextGLTest::drawIndexOffset}, @@ -1409,6 +1411,8 @@ void ContextGLTest::drawText() { c.relayout({200, 200}, {70, 70}, _framebuffer.viewport().size()); + MAGNUM_VERIFY_NO_GL_ERROR(); + /* ImGui doesn't draw anything the first frame */ c.newFrame(); c.drawFrame(); @@ -1444,6 +1448,78 @@ void ContextGLTest::drawText() { (DebugTools::CompareImageToFile{_manager, 3.0f, 0.5f})); } +void ContextGLTest::drawTextColorFont() { + Context c{{200, 200}}; + + /* Scale up default font so large text output is not a complete blurry mess */ + ImGui::GetIO().Fonts->Clear(); + auto* font = ImGui::GetIO().Fonts->AddFontDefault(); + font->Scale = 8.0f; + + /* Add a custom glyph rect for Unicode black square (U+25A0) and color it */ + const float glyphSize = font->ConfigData->SizePixels; + const int rectIndex = ImGui::GetIO().Fonts->AddCustomRectFontGlyph(font, L'\u25A0', + glyphSize*0.5f, glyphSize*0.5f, glyphSize, {glyphSize*0.25f, glyphSize*0.25f}); + ImFontAtlasCustomRect* rect = ImGui::GetIO().Fonts->GetCustomRectByIndex(rectIndex); + /* Build the atlas manually so we get the offsets to draw to. drawText() + already checked that Build() is correctly called by relayout(). */ + ImGui::GetIO().Fonts->Build(); + + unsigned char* pixelData; + int width; + int height; + ImGui::GetIO().Fonts->GetTexDataAsRGBA32(&pixelData, &width, &height); + Color4ub* pixels = reinterpret_cast(pixelData); + for(UnsignedShort y = rect->Y; y < rect->Y + rect->Height; ++y) + for(UnsignedShort x = rect->X; x < rect->X + rect->Width; ++x) + pixels[(y*width) + x] = Color4ub{128, 255, 128, 128}; + + /* Tell the backend that the font atlas contains colored glyphs so it + always creates an RGBA texture */ + ImGui::GetIO().Fonts->TexPixelsUseColors = true; + + c.relayout({200, 200}, {70, 70}, _framebuffer.viewport().size()); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + /* ImGui doesn't draw anything the first frame */ + c.newFrame(); + c.drawFrame(); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + Utility::System::sleep(1); + + c.newFrame(); + + /* Last drawlist that gets rendered, covers the entire display */ + ImDrawList* drawList = ImGui::GetForegroundDrawList(); + const ImVec2& size = ImGui::GetIO().DisplaySize; + + drawList->AddRectFilled({size.x*0.1f, size.y*0.2f}, {size.x*0.9f, size.y*0.8f}, + IM_COL32(255, 128, 128, 255)); + /* White, gets multiplied with the glyph color */ + drawList->AddText(nullptr, font->FontSize*font->Scale, + {size.x*0.0f, size.y*0.0f}, IM_COL32(255, 255, 255, 255), u8"A\u25A0B"); + drawList->AddText(nullptr, font->FontSize*font->Scale, + {size.x*0.0f, size.y*0.5f}, IM_COL32(255, 255, 255, 255), u8"\u25A0\u25A0"); + + c.drawFrame(); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + /* Catch also ABI and interface mismatch errors */ + if(!(_manager.load("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.load("PngImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / PngImporter plugin can't be loaded."); + + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Path::join(IMGUIINTEGRATION_TEST_DIR, "ContextTestFiles/draw-text-color-font.png"), + (DebugTools::CompareImageToFile{_manager, 3.0f, 0.5f})); +} + void ContextGLTest::drawScissor() { Context c{{200, 200}, {70, 70}, _framebuffer.viewport().size()}; diff --git a/src/Magnum/ImGuiIntegration/Test/ContextTestFiles/draw-text-color-font.png b/src/Magnum/ImGuiIntegration/Test/ContextTestFiles/draw-text-color-font.png new file mode 100644 index 0000000000000000000000000000000000000000..72de85f5d2b6d02b38ba1662b76a110394c04dca GIT binary patch literal 1208 zcmV;p1V{UcP)000DkNkl{ zX!y@ClmQdN5C@|k80ZKbje*e^pfCi6d=g^83;-4u22D*65)y(+-nhYV{W`F zBPyzy_&I)~0=#vL;loXaf4_10;537ZG{aqDGBGCu ziz>qjA%+h`#8(Of1B(a4c@KtjjSN+2>QOwv!2!y<3_$0;c){@Q9irS35n%5D^jmgW`TZK5FLy&X2#o5mktim`^x48DwP{*x3zHGcmAqqH-qY zdGq5f7xgnS1JDD&G%O`$gqjC{sR5e@fWpAMtgH--GN@aCi3(UX;K{r&H*IyO7TB`LPdaS4VVN!e`Xjc0IUdr<>;L|=l|mN z0I&!G)(d}tx#ZI)kUN2VAcDIX=ow&T2&|=ng3QbeKsG%+1GF7je&4@;7o+?`Bq42W zP@sSO$iQ&^JWjU(D+nDOhS#qdu3lvr900`wzzPf4ZezH64!hd~1Q;|lKa}{7nBDS^qH;)tLLo#7K=Qo65x~@5g^?|9OdV81p{{ z?oWRyPlilbg<(hlNJYlTXoS&@98w+-6*a`u8U;3< zfw>o05aEmxU>*lnhrkL2*s7*yya8L5f1r)HFAPFxHe(qZt!HQ)w8^TGp&rd`qXSz5 z9a*C>Fd73ChQMeN8cjl@Nr+)+gW)(o0Ev;GqI_TYnEnwlK*IE&f#=gd_Sc`th{})h z0>4;^(#QSvKiBh*m`ZUrr-81&EAjO=6X8x1un(!sz|H=eoTT_f^ydf8pTy`?c+11} zoPh)nd=};S$@1wh<3D0d|3~gf)^|>Z-^>(Qfin+$73KWT#7OH5{)?SbD{y+?J0IIW zn!BIj4=c?)FjNZH;oBDCdjFG&_6u=Xe^F`&&KTf%{hjF_&3(Z3lV%>^eE*ZUB9x-c zLcFA4l8ha;NK@6ZU$urVoIX_OhCot z#RU6n8Fp4NV)Xw1%8gYSP7i!~&CUQsG)^HO9`aLY!)PWR=uA8s1EVo8nu!^PHUI#u W;Y8!T=mNU{0000