mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-18 04:23:20 +01:00
Port TTF_RenderUTF8_Shaded and TTF_drawLine_Shaded from SDL_ttf.
This commit is contained in:
committed by
Marijn van der Werf
parent
07cdc79bd7
commit
3357d32ec4
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user