From 6ffa228df55a2298ce82df2931d8a78e90a863c3 Mon Sep 17 00:00:00 2001 From: Casey Muratori Date: Sun, 11 Jul 2021 19:58:44 -0700 Subject: [PATCH] Fixed rounding error in glyph size code that was truncating descenders. --- refterm_example_dwrite.cpp | 103 ++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/refterm_example_dwrite.cpp b/refterm_example_dwrite.cpp index daf5e67..db25b33 100644 --- a/refterm_example_dwrite.cpp +++ b/refterm_example_dwrite.cpp @@ -14,14 +14,14 @@ extern "C" int D2DAcquire(IDXGISurface *GlyphTransferSurface, struct ID2D1SolidColorBrush **DWriteFillBrush) { int Result = 0; - + // TODO(casey): Obey "ClearType" here. - + // TODO(casey): Not sure about these props... D2D1_RENDER_TARGET_PROPERTIES Props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED), 0, 0); - + ID2D1Factory *Factory = 0; D2D1_FACTORY_OPTIONS Options = {}; Options.debugLevel = D2D1_DEBUG_LEVEL_ERROR; @@ -34,10 +34,10 @@ extern "C" int D2DAcquire(IDXGISurface *GlyphTransferSurface, (*DWriteRenderTarget)->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), DWriteFillBrush); Result = (*DWriteFillBrush != 0); } - + Factory->Release(); } - + return Result; } @@ -49,7 +49,7 @@ extern "C" void D2DRelease(struct ID2D1RenderTarget **DWriteRenderTarget, (*DWriteFillBrush)->Release(); *DWriteFillBrush = 0; } - + if(*DWriteRenderTarget) { (*DWriteRenderTarget)->Release(); @@ -60,20 +60,20 @@ extern "C" void D2DRelease(struct ID2D1RenderTarget **DWriteRenderTarget, extern "C" int DWriteInit(glyph_generator *GlyphGen, IDXGISurface *GlyphTransferSurface) { int Result = 0; - + DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown**)&GlyphGen->DWriteFactory); if(GlyphGen->DWriteFactory) { Result = 1; } - + return Result; } extern "C" SIZE DWriteGetTextExtent(glyph_generator *GlyphGen, int StringLen, wchar_t *String) { SIZE Result = {0}; - + IDWriteTextLayout *Layout = 0; GlyphGen->DWriteFactory->CreateTextLayout(String, StringLen, GlyphGen->TextFormat, (float)GlyphGen->TransferWidth, (float)GlyphGen->TransferHeight, &Layout); @@ -81,12 +81,14 @@ extern "C" SIZE DWriteGetTextExtent(glyph_generator *GlyphGen, int StringLen, wc { DWRITE_TEXT_METRICS Metrics = {0}; Layout->GetMetrics(&Metrics); - Result.cx = (uint32_t)Metrics.width; - Result.cy = (uint32_t)Metrics.height; - + Assert(Metrics.left == 0); + Assert(Metrics.top == 0); + Result.cx = (uint32_t)(Metrics.width + 0.5f); + Result.cy = (uint32_t)(Metrics.height + 0.5f); + Layout->Release(); } - + return Result; } @@ -97,14 +99,48 @@ void DWriteReleaseFont(glyph_generator *GlyphGen) GlyphGen->FontFace->Release(); GlyphGen->FontFace = 0; } +} + +void IncludeLetterBounds(glyph_generator *GlyphGen, wchar_t Letter) +{ + IDWriteTextLayout *Layout = 0; + GlyphGen->DWriteFactory->CreateTextLayout(&Letter, 1, GlyphGen->TextFormat, + (float)GlyphGen->TransferWidth, (float)GlyphGen->TransferHeight, &Layout); + if(Layout) + { + // TODO(casey): Real cell size determination would go here - probably with input from the user? + DWRITE_TEXT_METRICS CharMetrics = {0}; + Layout->GetMetrics(&CharMetrics); + + DWRITE_LINE_METRICS LineMetrics = {0}; + UINT32 Ignored; + Layout->GetLineMetrics(&LineMetrics, 1, &Ignored); + + if(GlyphGen->FontHeight < (uint32_t)(LineMetrics.height + 0.5f)) + { + GlyphGen->FontHeight = (uint32_t)(LineMetrics.height + 0.5f); + } + + if(GlyphGen->FontHeight < (uint32_t)(CharMetrics.height + 0.5f)) + { + GlyphGen->FontHeight = (uint32_t)(CharMetrics.height + 0.5f); + } + + if(GlyphGen->FontWidth < (uint32_t)(CharMetrics.width + 0.5f)) + { + GlyphGen->FontWidth = (uint32_t)(CharMetrics.width + 0.5f); + } + + Layout->Release(); } +} extern "C" int DWriteSetFont(glyph_generator *GlyphGen, wchar_t *FontName, uint32_t FontHeight) { int Result = 0; - + DWriteReleaseFont(GlyphGen); - + if(GlyphGen->DWriteFactory) { GlyphGen->DWriteFactory->CreateTextFormat(FontName, @@ -119,31 +155,16 @@ extern "C" int DWriteSetFont(glyph_generator *GlyphGen, wchar_t *FontName, uint3 { GlyphGen->TextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR); GlyphGen->TextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING); - - wchar_t M = L'M'; - IDWriteTextLayout *Layout = 0; - GlyphGen->DWriteFactory->CreateTextLayout(&M, 1, GlyphGen->TextFormat, - (float)GlyphGen->TransferWidth, (float)GlyphGen->TransferHeight, &Layout); - if(Layout) - { - // TODO(casey): Real cell size determination would go here - probably with input from the user? - DWRITE_TEXT_METRICS CharMetrics = {0}; - Layout->GetMetrics(&CharMetrics); - - DWRITE_LINE_METRICS LineMetrics = {0}; - UINT32 Ignored; - Layout->GetLineMetrics(&LineMetrics, 1, &Ignored); - - GlyphGen->FontHeight = (uint32_t)LineMetrics.height; - GlyphGen->FontWidth = (uint32_t)CharMetrics.width; - - Layout->Release(); - - Result = 1; - } + + GlyphGen->FontWidth = 0; + GlyphGen->FontHeight = 0; + IncludeLetterBounds(GlyphGen, L'M'); + IncludeLetterBounds(GlyphGen, L'g'); + + Result = 1; } } - + return Result; } @@ -154,7 +175,7 @@ extern "C" void DWriteDrawText(glyph_generator *GlyphGen, int StringLen, WCHAR * float XScale, float YScale) { D2D1_RECT_F Rect; - + Rect.left = (float)Left; Rect.top = (float)Top; Rect.right = (float)Right; @@ -176,12 +197,12 @@ extern "C" void DWriteDrawText(glyph_generator *GlyphGen, int StringLen, WCHAR * extern "C" void DWriteRelease(glyph_generator *GlyphGen) { /* NOTE(casey): There is literally no point to this function - whatsoever except to stop the D3D debug runtime from + whatsoever except to stop the D3D debug runtime from complaining about unreleased resources when the program exits. EVEN THOUGH THEY WOULD BE AUTOMATICALLY RELEASED AT THAT TIME. So now here I am manually releasing them, which wastes the user's time, for no reason at all. */ - + DWriteReleaseFont(GlyphGen); if(GlyphGen->DWriteFactory) GlyphGen->DWriteFactory->Release(); }