Skip to content

Commit

Permalink
ImGuiIntegration: use 4-channel font atlas texture format if it conta…
Browse files Browse the repository at this point in the history
…ins color.
  • Loading branch information
pezcode committed Nov 27, 2024
1 parent f9d9b9c commit cd92508
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 10 deletions.
26 changes: 16 additions & 10 deletions src/Magnum/ImGuiIntegration/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();

Expand Down
1 change: 1 addition & 0 deletions src/Magnum/ImGuiIntegration/Test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
76 changes: 76 additions & 0 deletions src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ struct ContextGLTest: GL::OpenGLTester {
void drawCallback();
void drawTexture();
void drawText();
void drawTextColorFont();
void drawScissor();
void drawVertexOffset();
void drawIndexOffset();
Expand Down Expand Up @@ -315,6 +316,7 @@ ContextGLTest::ContextGLTest() {
&ContextGLTest::drawCallback,
&ContextGLTest::drawTexture,
&ContextGLTest::drawText,
&ContextGLTest::drawTextColorFont,
&ContextGLTest::drawScissor,
&ContextGLTest::drawVertexOffset,
&ContextGLTest::drawIndexOffset},
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<Color4ub*>(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<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
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()};

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit cd92508

Please sign in to comment.