From 3357d32ec4b39d4cee88b0f46157c01bd39f61aa Mon Sep 17 00:00:00 2001 From: Aaron van Geffen Date: Fri, 22 Sep 2017 12:41:46 +0200 Subject: [PATCH] Port TTF_RenderUTF8_Shaded and TTF_drawLine_Shaded from SDL_ttf. --- src/openrct2/drawing/ttf.h | 1 + src/openrct2/drawing/ttf_sdlport.c | 161 +++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/src/openrct2/drawing/ttf.h b/src/openrct2/drawing/ttf.h index adc3046134..46c39a8634 100644 --- a/src/openrct2/drawing/ttf.h +++ b/src/openrct2/drawing/ttf.h @@ -54,6 +54,7 @@ TTF_Font * TTF_OpenFont(const char *file, int ptsize); int TTF_GlyphIsProvided(const TTF_Font *font, codepoint_t ch); int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h); TTFSurface * TTF_RenderUTF8_Solid(TTF_Font *font, const char *text, uint32 colour); +TTFSurface * TTF_RenderUTF8_Shaded(TTF_Font *font, const char *text, uint32 fg, uint32 bg); void TTF_CloseFont(TTF_Font *font); void TTF_Quit(void); diff --git a/src/openrct2/drawing/ttf_sdlport.c b/src/openrct2/drawing/ttf_sdlport.c index 5dc5c8f7e1..1ad66919b8 100644 --- a/src/openrct2/drawing/ttf_sdlport.c +++ b/src/openrct2/drawing/ttf_sdlport.c @@ -262,6 +262,27 @@ static void TTF_drawLine_Solid(const TTF_Font *font, const TTFSurface *textbuf, } } +/* Draw a shaded line of underline_height (+ optional outline) + at the given row. The row value must take the + outline into account. +*/ +static void TTF_drawLine_Shaded(const TTF_Font *font, const TTFSurface *textbuf, const int row) +{ + int line; + uint8 *dst_check = (uint8*) textbuf->pixels + textbuf->pitch * textbuf->h; + uint8 *dst; + int height; + + TTF_initLineMectrics(font, textbuf, row, &dst, &height); + + /* Draw line */ + for (line=height; line>0 && dst < dst_check; --line) + { + memset(dst, NUM_GRAYS - 1, textbuf->w); + dst += textbuf->pitch; + } +} + static void TTF_SetFTError(const char *msg, FT_Error error) { #ifdef USE_FREETYPE_ERRORS @@ -1261,6 +1282,146 @@ TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, return textbuf; } +TTFSurface *TTF_RenderUTF8_Shaded(TTF_Font *font, + const char *text, uint32 fg, uint32 bg) +{ + bool first; + int xstart; + int width; + int height; + TTFSurface* textbuf; + uint8* src; + uint8* dst; + uint8* dst_check; + int row, col; + FT_Bitmap* current; + c_glyph *glyph; + FT_Error error; + FT_Long use_kerning; + FT_UInt prev_index = 0; + size_t textlen; + + TTF_CHECKPOINTER(text, NULL); + + /* Get the dimensions of the text surface */ + if ((TTF_SizeUTF8(font, text, &width, &height) < 0 ) || !width) + { + TTF_SetError("Text has zero width"); + return NULL; + } + + /* Create the target surface */ + textbuf = calloc(1, sizeof(TTFSurface)); + if (textbuf == NULL) + { + return NULL; + } + 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 = (uint8*) textbuf->pixels + textbuf->pitch * textbuf->h; + + /* check kerning */ + use_kerning = FT_HAS_KERNING(font->face) && font->kerning; + + /* Load and render each character */ + textlen = strlen(text); + first = true; + xstart = 0; + while (textlen > 0) + { + uint16 c = UTF8_getch(&text, &textlen); + if (c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED) + { + continue; + } + + error = Find_Glyph(font, c, CACHED_METRICS|CACHED_PIXMAP); + if (error) + { + TTF_SetFTError("Couldn't find glyph", error); + ttf_free_surface(textbuf); + return NULL; + } + + glyph = font->current; + + /* Ensure the width of the pixmap is correct. On some cases, + * freetype may report a larger pixmap than possible.*/ + width = glyph->pixmap.width; + if (font->outline <= 0 && width > glyph->maxx - glyph->minx) + { + width = glyph->maxx - glyph->minx; + } + + /* do kerning, if possible AC-Patch */ + if (use_kerning && prev_index && glyph->index) + { + FT_Vector delta; + FT_Get_Kerning(font->face, prev_index, glyph->index, ft_kerning_default, &delta); + xstart += delta.x >> 6; + } + + /* Compensate for the wrap around with negative minx's */ + if (first && (glyph->minx < 0)) + { + xstart -= glyph->minx; + } + first = false; + + current = &glyph->pixmap; + for (row = 0; row < current->rows; ++row) + { + /* Make sure we don't go either over, or under the + * limit */ + if (row + glyph->yoffset < 0) + { + continue; + } + if (row + glyph->yoffset >= textbuf->h) + { + continue; + } + + dst = (uint8*) textbuf->pixels + + (row+glyph->yoffset) * textbuf->pitch + + xstart + glyph->minx; + src = current->buffer + row * current->pitch; + + for (col=width; col>0 && dst < dst_check; --col) + { + *dst++ |= *src++; + } + } + + xstart += glyph->advance; + if (TTF_HANDLE_STYLE_BOLD(font)) + { + xstart += font->glyph_overhang; + } + prev_index = glyph->index; + } + + /* Handle the underline style */ + if (TTF_HANDLE_STYLE_UNDERLINE(font)) + { + row = TTF_underline_top_row(font); + TTF_drawLine_Shaded(font, textbuf, row); + } + + /* Handle the strikethrough style */ + if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) + { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Shaded(font, textbuf, row); + } + return textbuf; +} + static bool CharacterIsDelimiter(char c, const char *delimiters) { while (*delimiters) {