From d48b75fb86445bfb171eda46b4ae70b34ebffdfa Mon Sep 17 00:00:00 2001 From: mrmbernardi Date: Thu, 28 Mar 2024 23:28:54 +0100 Subject: [PATCH] Refactor TTF drawing (#21621) --- .../engines/opengl/OpenGLDrawingEngine.cpp | 29 ++-- src/openrct2/drawing/Drawing.String.cpp | 133 ++---------------- src/openrct2/drawing/IDrawingContext.h | 5 +- src/openrct2/drawing/ScrollingText.cpp | 5 +- src/openrct2/drawing/TTF.cpp | 9 -- src/openrct2/drawing/TTF.h | 3 +- src/openrct2/drawing/TTFSDLPort.cpp | 15 +- src/openrct2/drawing/X8DrawingEngine.cpp | 99 ++++++++++++- src/openrct2/drawing/X8DrawingEngine.h | 7 +- 9 files changed, 139 insertions(+), 166 deletions(-) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index 81ef8d588f..a06afd3ef2 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -37,7 +37,6 @@ # include # include # include -# include using namespace OpenRCT2; using namespace OpenRCT2::Drawing; @@ -74,6 +73,8 @@ private: int32_t _drawCount = 0; + uint32_t _ttfGlId = 0; + struct { LineCommandBatch lines; @@ -110,8 +111,7 @@ public: void DrawSpriteSolid(DrawPixelInfo& dpi, const ImageId image, int32_t x, int32_t y, uint8_t colour) override; void DrawGlyph(DrawPixelInfo& dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& palette) override; void DrawTTFBitmap( - DrawPixelInfo& dpi, TextDrawInfo* info, ImageIndex image, const void* pixels, int32_t width, int32_t height, int32_t x, - int32_t y, uint8_t hinting_threshold) override; + DrawPixelInfo& dpi, TextDrawInfo* info, TTFSurface* surface, int32_t x, int32_t y, uint8_t hintingThreshold) override; void FlushCommandBuffers(); @@ -908,17 +908,25 @@ void OpenGLDrawingContext::DrawGlyph(DrawPixelInfo& dpi, const ImageId image, in } void OpenGLDrawingContext::DrawTTFBitmap( - DrawPixelInfo& dpi, TextDrawInfo* info, ImageIndex image, const void* pixels, int32_t width, int32_t height, int32_t x, - int32_t y, uint8_t hinting_threshold) + DrawPixelInfo& dpi, TextDrawInfo* info, TTFSurface* surface, int32_t x, int32_t y, uint8_t hintingThreshold) { +# ifndef NO_TTF CalculcateClipping(dpi); - const auto texture = _textureCache->GetOrLoadBitmapTexture(image, pixels, width, height); + auto baseId = uint32_t(0x7FFFF) - 1024; + auto imageId = baseId + _ttfGlId; + _engine.InvalidateImage(imageId); + const auto texture = _textureCache->GetOrLoadBitmapTexture(imageId, surface->pixels, surface->w, surface->h); + _ttfGlId++; + if (_ttfGlId >= 1023) + { + _ttfGlId = 0; + } int32_t drawOffsetX = 0; int32_t drawOffsetY = 0; - int32_t drawWidth = static_cast(width); - int32_t drawHeight = static_cast(height); + int32_t drawWidth = static_cast(surface->w); + int32_t drawHeight = static_cast(surface->h); int32_t left = x + drawOffsetX; int32_t top = y + drawOffsetY; @@ -976,7 +984,7 @@ void OpenGLDrawingContext::DrawTTFBitmap( command.bounds = { left + 1, top + 1, right + 1, bottom + 1 }; command.depth = _drawCount++; } - auto& cmdBuf = hinting_threshold > 0 ? _commandBuffers.transparent : _commandBuffers.rects; + auto& cmdBuf = hintingThreshold > 0 ? _commandBuffers.transparent : _commandBuffers.rects; DrawRectCommand& command = cmdBuf.allocate(); command.clip = { _clipLeft, _clipTop, _clipRight, _clipBottom }; command.texColourAtlas = texture.index; @@ -984,10 +992,11 @@ void OpenGLDrawingContext::DrawTTFBitmap( command.texMaskAtlas = 0; command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f }; command.palettes = { 0, 0, 0 }; - command.flags = DrawRectCommand::FLAG_TTF_TEXT | (hinting_threshold << 8); + command.flags = DrawRectCommand::FLAG_TTF_TEXT | (hintingThreshold << 8); command.colour = info->palette[1]; command.bounds = { left, top, right, bottom }; command.depth = _drawCount++; +# endif // NO_TTF } void OpenGLDrawingContext::FlushCommandBuffers() diff --git a/src/openrct2/drawing/Drawing.String.cpp b/src/openrct2/drawing/Drawing.String.cpp index 8d6ac1fd11..e8c484da69 100644 --- a/src/openrct2/drawing/Drawing.String.cpp +++ b/src/openrct2/drawing/Drawing.String.cpp @@ -21,7 +21,6 @@ #include "../localisation/LocalisationService.h" #include "../platform/Platform.h" #include "../sprites.h" -#include "../util/Util.h" #include "TTF.h" #include @@ -509,7 +508,6 @@ static void TTFDrawStringRawSprite(DrawPixelInfo& dpi, std::string_view text, Te #ifndef NO_TTF -static int _ttfGlId = 0; static void TTFDrawStringRawTTF(DrawPixelInfo& dpi, std::string_view text, TextDrawInfo* info) { if (!TTFInitialise()) @@ -528,135 +526,20 @@ static void TTFDrawStringRawTTF(DrawPixelInfo& dpi, std::string_view text, TextD return; } - uint8_t colour = info->palette[1]; TTFSurface* surface = TTFSurfaceCacheGetOrAdd(fontDesc->font, text); if (surface == nullptr) return; - int32_t drawX = info->x + fontDesc->offset_x; - int32_t drawY = info->y + fontDesc->offset_y; - int32_t width = surface->w; - int32_t height = surface->h; - bool use_hinting = gConfigFonts.EnableHinting && fontDesc->hinting_threshold > 0; - - if (OpenRCT2::GetContext()->GetDrawingEngineType() == DrawingEngine::OpenGL) + auto drawingEngine = dpi.DrawingEngine; + if (drawingEngine != nullptr) { - auto baseId = uint32_t(0x7FFFF) - 1024; - auto imageId = baseId + _ttfGlId; - auto drawingEngine = dpi.DrawingEngine; - auto drawingContext = drawingEngine->GetDrawingContext(); - uint8_t hint_thresh = use_hinting ? fontDesc->hinting_threshold : 0; - drawingEngine->InvalidateImage(imageId); - drawingContext->DrawTTFBitmap( - dpi, info, imageId, surface->pixels, surface->pitch, surface->h, drawX, drawY, hint_thresh); - - _ttfGlId++; - if (_ttfGlId >= 1023) - { - _ttfGlId = 0; - } - info->x += width; - return; - } - - int32_t overflowX = (dpi.x + dpi.width) - (drawX + width); - int32_t overflowY = (dpi.y + dpi.height) - (drawY + height); - if (overflowX < 0) - width += overflowX; - if (overflowY < 0) - height += overflowY; - int32_t skipX = drawX - dpi.x; - int32_t skipY = drawY - dpi.y; - info->x += width; - - auto src = static_cast(surface->pixels); - uint8_t* dst = dpi.bits; - - int32_t srcXStart = 0; - int32_t srcYStart = 0; - if (skipX < 0) - { - width += skipX; - src += -skipX; - srcXStart += -skipX; - skipX = 0; - } - if (skipY < 0) - { - height += skipY; - src += (-skipY * surface->pitch); - srcYStart += -skipY; - skipY = 0; - } - - dst += skipX; - dst += skipY * (dpi.width + dpi.pitch); - - int32_t srcScanSkip = surface->pitch - width; - int32_t dstScanSkip = dpi.width + dpi.pitch - width; - uint8_t* dst_orig = dst; - - // Draw shadow/outline - if (info->flags & (TEXT_DRAW_FLAG_OUTLINE | TEXT_DRAW_FLAG_INSET)) - { - for (int32_t yy = 0; yy < height; yy++) - { - for (int32_t xx = 0; xx < width; xx++) - { - if (info->flags & TEXT_DRAW_FLAG_OUTLINE) - { - if (GetPixel(*surface, xx + srcXStart + 1, yy + srcYStart) - || GetPixel(*surface, xx + srcXStart - 1, yy + srcYStart) - || GetPixel(*surface, xx + srcXStart, yy + srcYStart + 1) - || GetPixel(*surface, xx + srcXStart, yy + srcYStart - 1)) - { - *dst = info->palette[3]; - } - } - if (info->flags & TEXT_DRAW_FLAG_INSET) - { - if (GetPixel(*surface, xx + srcXStart - 1, yy + srcYStart - 1)) - { - *dst = info->palette[3]; - } - } - dst++; - } - // Skip any remaining bits - dst += dstScanSkip; - } - } - dst = dst_orig; - for (int32_t yy = 0; yy < height; yy++) - { - for (int32_t xx = 0; xx < width; xx++) - { - if (*src != 0) - { - if (*src > 180 || !use_hinting) - { - // Centre of the glyph: use full colour. - *dst = colour; - } - else if (use_hinting && *src > fontDesc->hinting_threshold) - { - // Simulate font hinting by shading the background colour instead. - if (info->flags & TEXT_DRAW_FLAG_OUTLINE) - { - *dst = BlendColours(colour, info->palette[3]); - } - else - { - *dst = BlendColours(colour, *dst); - } - } - } - src++; - dst++; - } - src += srcScanSkip; - dst += dstScanSkip; + int32_t drawX = info->x + fontDesc->offset_x; + int32_t drawY = info->y + fontDesc->offset_y; + uint8_t hintThresh = gConfigFonts.EnableHinting ? fontDesc->hinting_threshold : 0; + OpenRCT2::Drawing::IDrawingContext* dc = drawingEngine->GetDrawingContext(); + dc->DrawTTFBitmap(dpi, info, surface, drawX, drawY, hintThresh); } + info->x += surface->w; } #endif // NO_TTF diff --git a/src/openrct2/drawing/IDrawingContext.h b/src/openrct2/drawing/IDrawingContext.h index 9bff8c72fb..6ea2938bac 100644 --- a/src/openrct2/drawing/IDrawingContext.h +++ b/src/openrct2/drawing/IDrawingContext.h @@ -11,6 +11,7 @@ #include "../common.h" #include "Drawing.h" +#include "TTF.h" namespace OpenRCT2::Drawing { @@ -33,8 +34,8 @@ namespace OpenRCT2::Drawing virtual void DrawGlyph( DrawPixelInfo& dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& palette) abstract; virtual void DrawTTFBitmap( - DrawPixelInfo& dpi, TextDrawInfo* info, ImageIndex image, const void* pixels, int32_t width, int32_t height, - int32_t x, int32_t y, uint8_t hinting_threshold) abstract; + DrawPixelInfo& dpi, TextDrawInfo* info, TTFSurface* surface, int32_t x, int32_t y, + uint8_t hintingThreshold) abstract; }; } // namespace OpenRCT2::Drawing diff --git a/src/openrct2/drawing/ScrollingText.cpp b/src/openrct2/drawing/ScrollingText.cpp index 4a1f76791b..a6d3604630 100644 --- a/src/openrct2/drawing/ScrollingText.cpp +++ b/src/openrct2/drawing/ScrollingText.cpp @@ -1577,12 +1577,11 @@ static void ScrollingTextSetBitmapForTTF( return; } - int32_t pitch = surface->pitch; int32_t width = surface->w; auto src = static_cast(surface->pixels); // Pitch offset - src += 2 * pitch; + src += 2 * width; // Line height offset int32_t min_vpos = -fontDesc->offset_y; @@ -1608,7 +1607,7 @@ static void ScrollingTextSetBitmapForTTF( for (int32_t y = min_vpos; y < max_vpos; y++) { - uint8_t src_pixel = src[y * pitch + x]; + uint8_t src_pixel = src[y * width + x]; if ((!use_hinting && src_pixel != 0) || src_pixel > 140) { // Centre of the glyph: use full colour. diff --git a/src/openrct2/drawing/TTF.cpp b/src/openrct2/drawing/TTF.cpp index 7c48db277a..ce61a0a273 100644 --- a/src/openrct2/drawing/TTF.cpp +++ b/src/openrct2/drawing/TTF.cpp @@ -9,7 +9,6 @@ #ifndef NO_TTF -# include # include # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdocumentation" @@ -21,7 +20,6 @@ # include "../config/Config.h" # include "../core/Numerics.hpp" # include "../core/String.hpp" -# include "../localisation/Localisation.h" # include "../localisation/LocalisationService.h" # include "../platform/Platform.h" # include "TTF.h" @@ -374,13 +372,6 @@ void TTFFreeSurface(TTFSurface* surface) free(surface); } -uint8_t GetPixel(const TTFSurface& surface, int32_t x, int32_t y) -{ - if (x < 0 || y < 0 || x >= surface.w || y >= surface.h) - return 0; - return static_cast(surface.pixels)[y * surface.pitch + x]; -} - #else # include "TTF.h" diff --git a/src/openrct2/drawing/TTF.h b/src/openrct2/drawing/TTF.h index 273fb48f90..8c9cdce7e1 100644 --- a/src/openrct2/drawing/TTF.h +++ b/src/openrct2/drawing/TTF.h @@ -15,6 +15,7 @@ bool TTFInitialise(); void TTFDispose(); +struct TTFSurface; #ifndef NO_TTF @@ -23,7 +24,6 @@ struct TTFSurface const void* pixels; int32_t w; int32_t h; - int32_t pitch; }; TTFFontDescriptor* TTFGetFontFromSpriteBase(FontStyle fontStyle); @@ -43,6 +43,5 @@ void TTF_CloseFont(TTF_Font* font); void TTF_SetFontHinting(TTF_Font* font, int hinting); int TTF_GetFontHinting(const TTF_Font* font); void TTF_Quit(void); -uint8_t GetPixel(const TTFSurface& surface, int32_t x, int32_t y); #endif // NO_TTF diff --git a/src/openrct2/drawing/TTFSDLPort.cpp b/src/openrct2/drawing/TTFSDLPort.cpp index f26b35b86c..1bc216c0ea 100644 --- a/src/openrct2/drawing/TTFSDLPort.cpp +++ b/src/openrct2/drawing/TTFSDLPort.cpp @@ -216,7 +216,7 @@ static void TTF_initLineMectrics(const TTF_Font* font, const TTFSurface* textbuf dst = const_cast(static_cast(textbuf->pixels)); if (row > 0) { - dst += row * textbuf->pitch; + dst += row * textbuf->w; } height = font->underline_height; @@ -236,7 +236,7 @@ outline into account. static void TTF_drawLine_Solid(const TTF_Font* font, const TTFSurface* textbuf, const int row) { int line; - uint8_t* dst_check = const_cast(static_cast(textbuf->pixels)) + textbuf->pitch * textbuf->h; + uint8_t* dst_check = const_cast(static_cast(textbuf->pixels)) + textbuf->w * textbuf->h; uint8_t* dst; int height; @@ -247,7 +247,7 @@ static void TTF_drawLine_Solid(const TTF_Font* font, const TTFSurface* textbuf, { /* 1 because 0 is the bg color */ std::fill_n(dst, textbuf->w, 0x01); - dst += textbuf->pitch; + dst += textbuf->w; } } @@ -258,7 +258,7 @@ static void TTF_drawLine_Solid(const TTF_Font* font, const TTFSurface* textbuf, static void TTF_drawLine_Shaded(const TTF_Font* font, const TTFSurface* textbuf, const int row) { int line; - uint8_t* dst_check = const_cast(static_cast(textbuf->pixels)) + textbuf->pitch * textbuf->h; + uint8_t* dst_check = const_cast(static_cast(textbuf->pixels)) + textbuf->w * textbuf->h; uint8_t* dst; int height; @@ -268,7 +268,7 @@ static void TTF_drawLine_Shaded(const TTF_Font* font, const TTFSurface* textbuf, for (line = height; line > 0 && dst < dst_check; --line) { std::fill_n(dst, textbuf->w, NUM_GRAYS - 1); - dst += textbuf->pitch; + dst += textbuf->w; } } @@ -1299,12 +1299,11 @@ TTFSurface* TTF_RenderUTF8(TTF_Font* font, const char* text, bool shaded) } textbuf->w = width; textbuf->h = height; - textbuf->pitch = width; textbuf->pixels = calloc(1, width * height); /* Adding bound checking to avoid all kinds of memory corruption errors that may occur. */ - dst_check = const_cast(static_cast(textbuf->pixels)) + textbuf->pitch * textbuf->h; + dst_check = const_cast(static_cast(textbuf->pixels)) + textbuf->w * textbuf->h; /* check kerning */ use_kerning = FT_HAS_KERNING(font->face) && font->kerning; @@ -1363,7 +1362,7 @@ TTFSurface* TTF_RenderUTF8(TTF_Font* font, const char* text, bool shaded) { continue; } - dst = const_cast(static_cast(textbuf->pixels)) + (row + glyph->yoffset) * textbuf->pitch + dst = const_cast(static_cast(textbuf->pixels)) + (row + glyph->yoffset) * textbuf->w + xstart + glyph->minx; src = current->buffer + row * current->pitch; diff --git a/src/openrct2/drawing/X8DrawingEngine.cpp b/src/openrct2/drawing/X8DrawingEngine.cpp index c7f54ec56f..5af091d8ab 100644 --- a/src/openrct2/drawing/X8DrawingEngine.cpp +++ b/src/openrct2/drawing/X8DrawingEngine.cpp @@ -10,7 +10,6 @@ #include "X8DrawingEngine.h" #include "../Context.h" -#include "../Game.h" #include "../Intro.h" #include "../config/Config.h" #include "../core/Numerics.hpp" @@ -19,7 +18,6 @@ #include "../interface/Window.h" #include "../ui/UiContext.h" #include "../util/Util.h" -#include "../world/Climate.h" #include "Drawing.h" #include "IDrawingContext.h" #include "IDrawingEngine.h" @@ -743,3 +741,100 @@ void X8DrawingContext::DrawGlyph(DrawPixelInfo& dpi, const ImageId image, int32_ { GfxDrawSpritePaletteSetSoftware(dpi, image, { x, y }, paletteMap); } + +#ifndef NO_TTF +template +static void DrawTTFBitmapInternal( + DrawPixelInfo& dpi, uint8_t colour, TTFSurface* surface, int32_t x, int32_t y, uint8_t hintingThreshold) +{ + const int32_t surfaceWidth = surface->w; + int32_t width = surfaceWidth; + int32_t height = surface->h; + + const int32_t overflowX = (dpi.x + dpi.width) - (x + width); + const int32_t overflowY = (dpi.y + dpi.height) - (y + height); + if (overflowX < 0) + width += overflowX; + if (overflowY < 0) + height += overflowY; + int32_t skipX = x - dpi.x; + int32_t skipY = y - dpi.y; + + auto src = static_cast(surface->pixels); + uint8_t* dst = dpi.bits; + + if (skipX < 0) + { + width += skipX; + src += -skipX; + skipX = 0; + } + if (skipY < 0) + { + height += skipY; + src += (-skipY * surfaceWidth); + skipY = 0; + } + + dst += skipX; + dst += skipY * (dpi.width + dpi.pitch); + + const int32_t srcScanSkip = surfaceWidth - width; + const int32_t dstScanSkip = dpi.width + dpi.pitch - width; + for (int32_t yy = 0; yy < height; yy++) + { + for (int32_t xx = 0; xx < width; xx++) + { + if (*src != 0) + { + if constexpr (TUseHinting) + { + if (*src > 180) + { + // Centre of the glyph: use full colour. + *dst = colour; + } + else if (*src > hintingThreshold) + { + *dst = BlendColours(colour, *dst); + } + } + else + { + *dst = colour; + } + } + src++; + dst++; + } + src += srcScanSkip; + dst += dstScanSkip; + } +} +#endif // NO_TTF + +void X8DrawingContext::DrawTTFBitmap( + DrawPixelInfo& dpi, TextDrawInfo* info, TTFSurface* surface, int32_t x, int32_t y, uint8_t hintingThreshold) +{ +#ifndef NO_TTF + const uint8_t fgColor = info->palette[1]; + const uint8_t bgColor = info->palette[3]; + + if (info->flags & TEXT_DRAW_FLAG_OUTLINE) + { + DrawTTFBitmapInternal(dpi, bgColor, surface, x + 1, y, 0); + DrawTTFBitmapInternal(dpi, bgColor, surface, x - 1, y, 0); + DrawTTFBitmapInternal(dpi, bgColor, surface, x, y + 1, 0); + DrawTTFBitmapInternal(dpi, bgColor, surface, x, y - 1, 0); + } + if (info->flags & TEXT_DRAW_FLAG_INSET) + { + DrawTTFBitmapInternal(dpi, bgColor, surface, x + 1, y + 1, 0); + } + + if (hintingThreshold > 0) + DrawTTFBitmapInternal(dpi, fgColor, surface, x, y, hintingThreshold); + else + DrawTTFBitmapInternal(dpi, fgColor, surface, x, y, 0); +#endif // NO_TTF +} \ No newline at end of file diff --git a/src/openrct2/drawing/X8DrawingEngine.h b/src/openrct2/drawing/X8DrawingEngine.h index 97bc0b93bc..4a3ea69ee3 100644 --- a/src/openrct2/drawing/X8DrawingEngine.h +++ b/src/openrct2/drawing/X8DrawingEngine.h @@ -9,7 +9,6 @@ #pragma once -#include "../common.h" #include "IDrawingContext.h" #include "IDrawingEngine.h" @@ -148,10 +147,8 @@ namespace OpenRCT2 void DrawGlyph( DrawPixelInfo& dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& paletteMap) override; void DrawTTFBitmap( - DrawPixelInfo& dpi, TextDrawInfo* info, uint32_t image, const void* pixels, int32_t width, int32_t height, - int32_t x, int32_t y, uint8_t hinting_threshold) override - { - } + DrawPixelInfo& dpi, TextDrawInfo* info, TTFSurface* surface, int32_t x, int32_t y, + uint8_t hintingThreshold) override; }; } // namespace Drawing } // namespace OpenRCT2