From 2c07a556963022653b3147db8b941655b5e20476 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 13 Jun 2017 20:50:14 +0100 Subject: [PATCH 01/10] Refactor TTF into new source and remove SDL2_ttf --- openrct2.common.props | 2 +- src/openrct2-ui/CMakeLists.txt | 1 - src/openrct2/CMakeLists.txt | 14 +- src/openrct2/drawing/drawing.h | 9 - src/openrct2/drawing/font.c | 9 +- src/openrct2/drawing/font.h | 11 +- src/openrct2/drawing/scrolling_text.c | 15 +- src/openrct2/drawing/string.c | 276 ++------------------- src/openrct2/drawing/ttf.c | 329 ++++++++++++++++++++++++++ src/openrct2/drawing/ttf.h | 38 +++ src/openrct2/interface/Fonts.cpp | 11 +- 11 files changed, 406 insertions(+), 309 deletions(-) create mode 100644 src/openrct2/drawing/ttf.c create mode 100644 src/openrct2/drawing/ttf.h diff --git a/openrct2.common.props b/openrct2.common.props index 7c315c9315..b4046c449c 100644 --- a/openrct2.common.props +++ b/openrct2.common.props @@ -89,7 +89,7 @@ - $(SolutionDir)src;$(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(SolutionDir)lib\include\libzip;$(IncludePath) + $(SolutionDir)src;$(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\freetype;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(SolutionDir)lib\include\libzip;$(IncludePath) $(SolutionDir)lib;$(LibraryPath) diff --git a/src/openrct2-ui/CMakeLists.txt b/src/openrct2-ui/CMakeLists.txt index 2076650767..dfbc69b9ec 100644 --- a/src/openrct2-ui/CMakeLists.txt +++ b/src/openrct2-ui/CMakeLists.txt @@ -48,7 +48,6 @@ add_executable(${PROJECT} ${OPENRCT2_UI_SOURCES} ${OPENRCT2_UI_M_SOURCES} ${OPEN target_link_libraries(${PROJECT} "libopenrct2" ${SDL2_LIBRARIES} - ${SDL2_TTF_LIBRARIES} ${SPEEX_LIBRARIES}) if (APPLE) diff --git a/src/openrct2/CMakeLists.txt b/src/openrct2/CMakeLists.txt index 3b87b6fc7a..743dc1e61c 100644 --- a/src/openrct2/CMakeLists.txt +++ b/src/openrct2/CMakeLists.txt @@ -14,7 +14,7 @@ option(DISABLE_RCT2 "Build a standalone version, without using code and data seg option(DISABLE_HTTP_TWITCH "Disable HTTP and Twitch support.") option(DISABLE_NETWORK "Disable multiplayer functionality. Mainly for testing.") -option(DISABLE_TTF "Disable support for TTF provided by SDL2_ttf.") +option(DISABLE_TTF "Disable support for TTF provided by freetype2.") option(ENABLE_LIGHTFX "Enable lighting effects." ON) if (NOT DISABLE_RCT2) @@ -59,14 +59,10 @@ endif () PKG_CHECK_MODULES(SDL2 REQUIRED sdl2) PKG_CHECK_MODULES(SPEEX REQUIRED speexdsp) if (NOT DISABLE_TTF) - if (STATIC) - # FreeType is required by SDL2_ttf, but not wired up properly in package - PKG_CHECK_MODULES(FREETYPE REQUIRED freetype2) - endif () if (UNIX AND NOT APPLE) PKG_CHECK_MODULES(FONTCONFIG REQUIRED fontconfig) endif () - PKG_CHECK_MODULES(SDL2_TTF REQUIRED SDL2_ttf) + PKG_CHECK_MODULES(FREETYPE REQUIRED freetype2) endif () # Sources @@ -189,13 +185,12 @@ endif () if (NOT DISABLE_TTF) if (STATIC) - target_link_libraries(${PROJECT} ${FREETYPE_STATIC_LIBRARIES} - ${SDL2_TTF_STATIC_LIBRARIES}) + target_link_libraries(${PROJECT} ${FREETYPE_STATIC_LIBRARIES}) if (UNIX AND NOT APPLE) target_link_libraries(${PROJECT} ${FONTCONFIG_STATIC_LIBRARIES}) endif () else () - target_link_libraries(${PROJECT} ${SDL2_TTF_LIBRARIES}) + target_link_libraries(${PROJECT} ${FREETYPE_LIBRARIES}) if (UNIX AND NOT APPLE) target_link_libraries(${PROJECT} ${FONTCONFIG_LIBRARIES}) endif () @@ -210,6 +205,7 @@ endif() # Includes target_include_directories(${PROJECT} SYSTEM PRIVATE ${LIBZIP_INCLUDE_DIRS}) target_include_directories(${PROJECT} PRIVATE ${SDL2_INCLUDE_DIRS} + ${FREETYPE_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS} ${SPEEX_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS} diff --git a/src/openrct2/drawing/drawing.h b/src/openrct2/drawing/drawing.h index 981b6cd976..d764d1303a 100644 --- a/src/openrct2/drawing/drawing.h +++ b/src/openrct2/drawing/drawing.h @@ -21,8 +21,6 @@ #include "../interface/colour.h" #include "font.h" -typedef struct SDL_Surface SDL_Surface; - // For g1 only enable packing when still relying on vanilla #ifndef NO_RCT2 #pragma pack(push, 1) @@ -360,13 +358,6 @@ void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, sint32 x, s void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, sint32 colour, sint32 x, sint32 y, const sint8 *yOffsets, bool forceSpriteFont); sint32 gfx_clip_string(char* buffer, sint32 width); void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, sint32 availableWidth); -#ifndef NO_TTF -SDL_Surface *ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text); -TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase); -#endif // NO_TTF - -bool ttf_initialise(); -void ttf_dispose(); // scrolling text void scrolling_text_initialise_bitmaps(); diff --git a/src/openrct2/drawing/font.c b/src/openrct2/drawing/font.c index 34a7d89684..8077259ffb 100644 --- a/src/openrct2/drawing/font.c +++ b/src/openrct2/drawing/font.c @@ -14,15 +14,12 @@ *****************************************************************************/ #pragma endregion -#ifndef NO_TTF -#include "../common.h" -#include -#endif #include "../rct2/addresses.h" #include "../localisation/localisation.h" #include "../sprites.h" #include "drawing.h" #include "font.h" +#include "ttf.h" static const sint32 SpriteFontLineHeight[] = { 6, 10, 10, 18 }; @@ -202,14 +199,14 @@ bool font_supports_string_ttf(const utf8 *text, sint32 fontSize) { #ifndef NO_TTF const utf8 *src = text; - const TTF_Font *font = gCurrentTTFFontSet->size[fontSize].font; + const TTFFont *font = gCurrentTTFFontSet->size[fontSize].font; if (font == NULL) { return false; } uint32 codepoint; while ((codepoint = utf8_get_next(src, &src)) != 0) { - bool supported = TTF_GlyphIsProvided(font, (uint16)codepoint); + bool supported = ttf_provides_glyph(font, codepoint); if (!supported) { return false; } diff --git a/src/openrct2/drawing/font.h b/src/openrct2/drawing/font.h index a662431b45..f77ee4a1d9 100644 --- a/src/openrct2/drawing/font.h +++ b/src/openrct2/drawing/font.h @@ -17,10 +17,6 @@ #ifndef _DRAWING_FONT_H_ #define _DRAWING_FONT_H_ -#ifndef NO_TTF -typedef struct _TTF_Font TTF_Font; -#endif // NO_TTF - #include "../common.h" enum { @@ -43,6 +39,11 @@ enum { }; #ifndef NO_TTF +typedef struct FT_FaceRec_* FT_Face; +typedef struct TTFFont { + FT_Face face; +} TTFFont; + typedef struct TTFFontDescriptor { const utf8 *filename; const utf8 *font_name; @@ -50,7 +51,7 @@ typedef struct TTFFontDescriptor { sint32 offset_x; sint32 offset_y; sint32 line_height; - TTF_Font *font; + TTFFont * font; } TTFFontDescriptor; typedef struct TTFFontSetDescriptor { diff --git a/src/openrct2/drawing/scrolling_text.c b/src/openrct2/drawing/scrolling_text.c index 3b13286098..1585d962c0 100644 --- a/src/openrct2/drawing/scrolling_text.c +++ b/src/openrct2/drawing/scrolling_text.c @@ -14,16 +14,13 @@ *****************************************************************************/ #pragma endregion -#ifndef NO_TTF -#include "../common.h" -#include -#endif #include "../rct2/addresses.h" #include "../config/Config.h" #include "../interface/colour.h" #include "../localisation/localisation.h" #include "../sprites.h" #include "drawing.h" +#include "ttf.h" #pragma pack(push, 1) /* size: 0xA12 */ @@ -1543,19 +1540,15 @@ void scrolling_text_set_bitmap_for_ttf(utf8 *text, sint32 scroll, uint8 *bitmap, colour = g1Elements[SPR_TEXT_PALETTE].offset[(colour - FORMAT_COLOUR_CODE_START) * 4]; } - SDL_Surface *surface = ttf_surface_cache_get_or_add(fontDesc->font, text); + TTFSurface * surface = ttf_surface_cache_get_or_add(fontDesc->font, text); if (surface == NULL) { return; } - if (SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) == -1) { - return; - } - sint32 pitch = surface->pitch; sint32 width = surface->w; sint32 height = surface->h; - uint8 *src = surface->pixels; + const uint8 *src = surface->pixels; // Offset height -= 3; @@ -1586,7 +1579,5 @@ void scrolling_text_set_bitmap_for_ttf(utf8 *text, sint32 scroll, uint8 *bitmap, x++; if (x >= width) x = 0; } - - if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); #endif // NO_TTF } diff --git a/src/openrct2/drawing/string.c b/src/openrct2/drawing/string.c index 0304d13242..0ff2036830 100644 --- a/src/openrct2/drawing/string.c +++ b/src/openrct2/drawing/string.c @@ -14,16 +14,13 @@ *****************************************************************************/ #pragma endregion -#ifndef NO_TTF -#include "../common.h" -#include -#endif #include "../interface/colour.h" #include "../interface/viewport.h" #include "../localisation/localisation.h" #include "../platform/platform.h" #include "../sprites.h" #include "../util/util.h" +#include "ttf.h" enum { TEXT_DRAW_FLAG_INSET = 1 << 0, @@ -31,46 +28,13 @@ enum { TEXT_DRAW_FLAG_DARK = 1 << 2, TEXT_DRAW_FLAG_EXTRA_DARK = 1 << 3, TEXT_DRAW_FLAG_Y_OFFSET_EFFECT = 1 << 29, -#ifndef NO_TTF TEXT_DRAW_FLAG_TTF = 1 << 30, -#endif // NO_TTF TEXT_DRAW_FLAG_NO_DRAW = 1u << 31 }; static sint32 ttf_get_string_width(const utf8 *text); static void ttf_draw_string(rct_drawpixelinfo *dpi, char *buffer, sint32 colour, sint32 x, sint32 y); -#ifndef NO_TTF -static bool _ttfInitialised = false; - -#define TTF_SURFACE_CACHE_SIZE 256 -#define TTF_GETWIDTH_CACHE_SIZE 1024 - -typedef struct ttf_cache_entry { - SDL_Surface *surface; - TTF_Font *font; - utf8 *text; - uint32 lastUseTick; -} ttf_cache_entry; - -static ttf_cache_entry _ttfSurfaceCache[TTF_SURFACE_CACHE_SIZE] = { 0 }; -static sint32 _ttfSurfaceCacheCount = 0; -static sint32 _ttfSurfaceCacheHitCount = 0; -static sint32 _ttfSurfaceCacheMissCount = 0; - -typedef struct ttf_getwidth_cache_entry { - uint32 width; - TTF_Font *font; - utf8 *text; - uint32 lastUseTick; -} ttf_getwidth_cache_entry; - -static ttf_getwidth_cache_entry _ttfGetWidthCache[TTF_GETWIDTH_CACHE_SIZE] = { 0 }; -static sint32 _ttfGetWidthCacheCount = 0; -static sint32 _ttfGetWidthCacheHitCount = 0; -static sint32 _ttfGetWidthCacheMissCount = 0; -#endif // NO_TTF - /** * * rct2: 0x006C23B1 @@ -711,206 +675,6 @@ void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, sint32 x, s } } -#ifndef NO_TTF -static uint32 _ttf_surface_cache_hash(TTF_Font *font, const utf8 *text) -{ - uint32 hash = (uint32)((((uintptr_t)font * 23) ^ 0xAAAAAAAA) & 0xFFFFFFFF); - for (const utf8 *ch = text; *ch != 0; ch++) { - hash = ror32(hash, 3) ^ (*ch * 13); - } - return hash; -} - -static void _ttf_surface_cache_dispose(ttf_cache_entry *entry) -{ - if (entry->surface != NULL) { - SDL_FreeSurface(entry->surface); - free(entry->text); - - entry->surface = NULL; - entry->font = NULL; - entry->text = NULL; - } -} - -static void _ttf_surface_cache_dispose_all() -{ - for (sint32 i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) { - _ttf_surface_cache_dispose(&_ttfSurfaceCache[i]); - _ttfSurfaceCacheCount--; - } -} - -SDL_Surface *ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text) -{ - ttf_cache_entry *entry; - - uint32 hash = _ttf_surface_cache_hash(font, text); - sint32 index = hash % TTF_SURFACE_CACHE_SIZE; - for (sint32 i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) { - entry = &_ttfSurfaceCache[index]; - - // Check if entry is a hit - if (entry->surface == NULL) break; - if (entry->font == font && strcmp(entry->text, text) == 0) { - _ttfSurfaceCacheHitCount++; - entry->lastUseTick = gCurrentDrawCount; - return entry->surface; - } - - // If entry hasn't been used for a while, replace it - if (entry->lastUseTick < gCurrentDrawCount - 64) { - break; - } - - // Check if next entry is a hit - if (++index >= TTF_SURFACE_CACHE_SIZE) index = 0; - } - - // Cache miss, replace entry with new surface - entry = &_ttfSurfaceCache[index]; - _ttf_surface_cache_dispose(entry); - - SDL_Color c = { 0, 0, 0, 255 }; - SDL_Surface *surface = TTF_RenderUTF8_Solid(font, text, c); - if (surface == NULL) { - return NULL; - } - - _ttfSurfaceCacheMissCount++; - // printf("CACHE HITS: %d MISSES: %d)\n", _ttfSurfaceCacheHitCount, _ttfSurfaceCacheMissCount); - - _ttfSurfaceCacheCount++; - entry->surface = surface; - entry->font = font; - entry->text = _strdup(text); - entry->lastUseTick = gCurrentDrawCount; - return entry->surface; -} - -static void _ttf_getwidth_cache_dispose(ttf_getwidth_cache_entry *entry) -{ - if (entry->text != NULL) { - free(entry->text); - - entry->width = 0; - entry->font = NULL; - entry->text = NULL; - } -} - -static void _ttf_getwidth_cache_dispose_all() -{ - for (sint32 i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++) { - _ttf_getwidth_cache_dispose(&_ttfGetWidthCache[i]); - _ttfGetWidthCacheCount--; - } -} - -static uint32 _ttf_getwidth_cache_get_or_add(TTF_Font *font, const utf8 *text) -{ - ttf_getwidth_cache_entry *entry; - - uint32 hash = _ttf_surface_cache_hash(font, text); - sint32 index = hash % TTF_GETWIDTH_CACHE_SIZE; - for (sint32 i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++) { - entry = &_ttfGetWidthCache[index]; - - // Check if entry is a hit - if (entry->text == NULL) break; - if (entry->font == font && strcmp(entry->text, text) == 0) { - _ttfGetWidthCacheHitCount++; - entry->lastUseTick = gCurrentDrawCount; - return entry->width; - } - - // If entry hasn't been used for a while, replace it - if (entry->lastUseTick < gCurrentDrawCount - 64) { - break; - } - - // Check if next entry is a hit - if (++index >= TTF_GETWIDTH_CACHE_SIZE) index = 0; - } - - // Cache miss, replace entry with new width - entry = &_ttfGetWidthCache[index]; - _ttf_getwidth_cache_dispose(entry); - - sint32 width, height; - TTF_SizeUTF8(font, text, &width, &height); - - _ttfGetWidthCacheMissCount++; - - _ttfGetWidthCacheCount++; - entry->width = width; - entry->font = font; - entry->text = _strdup(text); - entry->lastUseTick = gCurrentDrawCount; - return entry->width; -} - -bool ttf_initialise() -{ - if (!_ttfInitialised) { - if (TTF_Init() != 0) { - return false; - } - - for (sint32 i = 0; i < 4; i++) { - TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); - - utf8 fontPath[MAX_PATH]; - if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath))) { - log_error("Unable to load font '%s'", fontDesc->font_name); - return false; - } - - fontDesc->font = TTF_OpenFont(fontPath, fontDesc->ptSize); - if (fontDesc->font == NULL) { - log_error("Unable to load '%s'", fontPath); - return false; - } - } - - _ttfInitialised = true; - } - return true; -} - -void ttf_dispose() -{ - if (!_ttfInitialised) - return; - - _ttf_surface_cache_dispose_all(); - _ttf_getwidth_cache_dispose_all(); - - for (sint32 i = 0; i < 4; i++) { - TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); - if (fontDesc->font != NULL) { - TTF_CloseFont(fontDesc->font); - fontDesc->font = NULL; - } - } - - TTF_Quit(); - _ttfInitialised = false; -} - -TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase) -{ - return &gCurrentTTFFontSet->size[font_get_size_from_sprite_base(spriteBase)]; -} -#else -bool ttf_initialise() -{ - return false; -} - -void ttf_dispose() {} -#endif // NO_TTF - typedef struct text_draw_info { sint32 startX; sint32 startY; @@ -924,6 +688,8 @@ typedef struct text_draw_info { const sint8 *y_offset; } text_draw_info; +#ifndef NO_TTF + static void ttf_draw_character_sprite(rct_drawpixelinfo *dpi, sint32 codepoint, text_draw_info *info) { sint32 characterWidth = font_sprite_get_codepoint_width(info->font_sprite_base, codepoint); @@ -953,10 +719,9 @@ static void ttf_draw_string_raw_sprite(rct_drawpixelinfo *dpi, const utf8 *text, }; } -#ifndef NO_TTF static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) { - if (!_ttfInitialised && !ttf_initialise()) + if (!ttf_initialise()) return; TTFFontDescriptor *fontDesc = ttf_get_font_from_sprite_base(info->font_sprite_base); @@ -966,20 +731,14 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te } if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) { - info->x += _ttf_getwidth_cache_get_or_add(fontDesc->font, text); + info->x += ttf_getwidth_cache_get_or_add(fontDesc->font, text); return; } else { uint8 colour = info->palette[1]; - SDL_Surface *surface = ttf_surface_cache_get_or_add(fontDesc->font, text); + TTFSurface * surface = ttf_surface_cache_get_or_add(fontDesc->font, text); if (surface == NULL) return; - if (SDL_MUSTLOCK(surface)) { - if (SDL_LockSurface(surface) != 0) { - return; - } - } - sint32 drawX = info->x + fontDesc->offset_x; sint32 drawY = info->y + fontDesc->offset_y; sint32 width = surface->w; @@ -993,7 +752,7 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te sint32 skipY = drawY - dpi->y; info->x += width; - uint8 *src = surface->pixels; + const uint8 *src = surface->pixels; uint8 *dst = dpi->bits; if (skipX < 0) { @@ -1013,7 +772,7 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te sint32 srcScanSkip = surface->pitch - width; sint32 dstScanSkip = dpi->width + dpi->pitch - width; uint8 *dst_orig = dst; - uint8 *src_orig = src; + const uint8 *src_orig = src; // Draw shadow/outline if (info->flags & TEXT_DRAW_FLAG_OUTLINE) { @@ -1051,12 +810,9 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te dst += dstScanSkip; } } - - if (SDL_MUSTLOCK(surface)) { - SDL_UnlockSurface(surface); - } } } + #endif // NO_TTF static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) @@ -1296,9 +1052,9 @@ static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, sint32 colour, s info.x = x; info.y = y; -#ifndef NO_TTF - if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF; -#endif // NO_TTF + if (gUseTrueTypeFont) { + info.flags |= TEXT_DRAW_FLAG_TTF; + } memcpy(info.palette, text_palette, sizeof(info.palette)); ttf_process_initial_colour(colour, &info); @@ -1325,9 +1081,9 @@ static sint32 ttf_get_string_width(const utf8 *text) info.maxY = 0; info.flags |= TEXT_DRAW_FLAG_NO_DRAW; -#ifndef NO_TTF - if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF; -#endif // NO_TTF + if (gUseTrueTypeFont) { + info.flags |= TEXT_DRAW_FLAG_TTF; + } ttf_process_string(NULL, text, &info); @@ -1351,11 +1107,9 @@ void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, si info.flags |= TEXT_DRAW_FLAG_Y_OFFSET_EFFECT; -#ifndef NO_TTF if (!forceSpriteFont && gUseTrueTypeFont) { info.flags |= TEXT_DRAW_FLAG_TTF; } -#endif // NO_TTF memcpy(info.palette, text_palette, sizeof(info.palette)); ttf_process_initial_colour(colour, &info); diff --git a/src/openrct2/drawing/ttf.c b/src/openrct2/drawing/ttf.c new file mode 100644 index 0000000000..3b1bbe614b --- /dev/null +++ b/src/openrct2/drawing/ttf.c @@ -0,0 +1,329 @@ +#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#ifndef NO_TTF + +#include +#include FT_FREETYPE_H + +#include "../platform/platform.h" +#include "../rct2.h" +#include "ttf.h" + +static bool _ttfInitialised = false; +static FT_Library _ftLibrary; + +#define TTF_SURFACE_CACHE_SIZE 256 +#define TTF_GETWIDTH_CACHE_SIZE 1024 + +typedef struct ttf_cache_entry +{ + TTFSurface * surface; + TTFFont * font; + utf8 * text; + uint32 lastUseTick; +} ttf_cache_entry; + +typedef struct ttf_getwidth_cache_entry +{ + uint32 width; + TTFFont * font; + utf8 * text; + uint32 lastUseTick; +} ttf_getwidth_cache_entry; + +static ttf_cache_entry _ttfSurfaceCache[TTF_SURFACE_CACHE_SIZE] = { 0 }; +static sint32 _ttfSurfaceCacheCount = 0; +static sint32 _ttfSurfaceCacheHitCount = 0; +static sint32 _ttfSurfaceCacheMissCount = 0; + +static ttf_getwidth_cache_entry _ttfGetWidthCache[TTF_GETWIDTH_CACHE_SIZE] = { 0 }; +static sint32 _ttfGetWidthCacheCount = 0; +static sint32 _ttfGetWidthCacheHitCount = 0; +static sint32 _ttfGetWidthCacheMissCount = 0; + +static TTFFont * ttf_open_font(const utf8 * fontPath, sint32 ptSize); +static void ttf_close_font(TTFFont * font); +static uint32 ttf_surface_cache_hash(TTFFont * font, const utf8 * text); +static void ttf_surface_cache_dispose(ttf_cache_entry * entry); +static void ttf_surface_cache_dispose_all(); +static void ttf_getwidth_cache_dispose_all(); +static void ttf_get_size(TTFFont * font, const utf8 * text, sint32 * width, sint32 * height); +static TTFSurface * ttf_render(TTFFont * font, const utf8 * text); +static void ttf_free_surface(TTFSurface * surface); + +bool ttf_initialise() +{ + if (!_ttfInitialised) { + FT_Error error = FT_Init_FreeType(&_ftLibrary); + if (error != 0) { + log_error("Couldn't initialise FreeType engine"); + return false; + } + + for (sint32 i = 0; i < 4; i++) { + TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); + + utf8 fontPath[MAX_PATH]; + if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath))) { + log_error("Unable to load font '%s'", fontDesc->font_name); + return false; + } + + fontDesc->font = ttf_open_font(fontPath, fontDesc->ptSize); + if (fontDesc->font == NULL) { + log_error("Unable to load '%s'", fontPath); + return false; + } + } + _ttfInitialised = true; + } + return true; +} + +void ttf_dispose() +{ + if (_ttfInitialised) + { + ttf_surface_cache_dispose_all(); + ttf_getwidth_cache_dispose_all(); + + for (sint32 i = 0; i < 4; i++) { + TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]); + if (fontDesc->font != NULL) { + ttf_close_font(fontDesc->font); + fontDesc->font = NULL; + } + } + + FT_Done_FreeType(_ftLibrary); + _ttfInitialised = false; + } +} + +static TTFFont * ttf_open_font(const utf8 * fontPath, sint32 ptSize) +{ + TTFFont * font = malloc(sizeof(TTFFont)); + if (font != NULL) { + FT_Error error = FT_New_Face(_ftLibrary, fontPath, 0, &font->face); + if (error != 0) { + ttf_close_font(font); + return NULL; + } + + error = FT_Set_Char_Size(font->face, 0, ptSize * 64, 0, 0); + if (error != 0) { + ttf_close_font(font); + return NULL; + } + } + return font; +} + +static void ttf_close_font(TTFFont * font) +{ + FT_Done_Face(font->face); + free(font); +} + +static uint32 ttf_surface_cache_hash(TTFFont *font, const utf8 *text) +{ + uint32 hash = (uint32)((((uintptr_t)font * 23) ^ 0xAAAAAAAA) & 0xFFFFFFFF); + for (const utf8 *ch = text; *ch != 0; ch++) { + hash = ror32(hash, 3) ^ (*ch * 13); + } + return hash; +} + +static void ttf_surface_cache_dispose(ttf_cache_entry *entry) +{ + if (entry->surface != NULL) { + ttf_free_surface(entry->surface); + free(entry->text); + + entry->surface = NULL; + entry->font = NULL; + entry->text = NULL; + } +} + +static void ttf_surface_cache_dispose_all() +{ + for (sint32 i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) { + ttf_surface_cache_dispose(&_ttfSurfaceCache[i]); + _ttfSurfaceCacheCount--; + } +} + +TTFSurface * ttf_surface_cache_get_or_add(TTFFont * font, const utf8 * text) +{ + ttf_cache_entry *entry; + + uint32 hash = ttf_surface_cache_hash(font, text); + sint32 index = hash % TTF_SURFACE_CACHE_SIZE; + for (sint32 i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) { + entry = &_ttfSurfaceCache[index]; + + // Check if entry is a hit + if (entry->surface == NULL) break; + if (entry->font == font && strcmp(entry->text, text) == 0) { + _ttfSurfaceCacheHitCount++; + entry->lastUseTick = gCurrentDrawCount; + return entry->surface; + } + + // If entry hasn't been used for a while, replace it + if (entry->lastUseTick < gCurrentDrawCount - 64) { + break; + } + + // Check if next entry is a hit + if (++index >= TTF_SURFACE_CACHE_SIZE) index = 0; + } + + // Cache miss, replace entry with new surface + entry = &_ttfSurfaceCache[index]; + ttf_surface_cache_dispose(entry); + + TTFSurface * surface = ttf_render(font, text); + if (surface == NULL) { + return NULL; + } + + _ttfSurfaceCacheMissCount++; + // printf("CACHE HITS: %d MISSES: %d)\n", _ttfSurfaceCacheHitCount, _ttfSurfaceCacheMissCount); + + _ttfSurfaceCacheCount++; + entry->surface = surface; + entry->font = font; + entry->text = _strdup(text); + entry->lastUseTick = gCurrentDrawCount; + return entry->surface; +} + +static void ttf_getwidth_cache_dispose(ttf_getwidth_cache_entry *entry) +{ + if (entry->text != NULL) { + free(entry->text); + + entry->width = 0; + entry->font = NULL; + entry->text = NULL; + } +} + +static void ttf_getwidth_cache_dispose_all() +{ + for (sint32 i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++) { + ttf_getwidth_cache_dispose(&_ttfGetWidthCache[i]); + _ttfGetWidthCacheCount--; + } +} + +uint32 ttf_getwidth_cache_get_or_add(TTFFont * font, const utf8 * text) +{ + ttf_getwidth_cache_entry *entry; + + uint32 hash = ttf_surface_cache_hash(font, text); + sint32 index = hash % TTF_GETWIDTH_CACHE_SIZE; + for (sint32 i = 0; i < TTF_GETWIDTH_CACHE_SIZE; i++) { + entry = &_ttfGetWidthCache[index]; + + // Check if entry is a hit + if (entry->text == NULL) break; + if (entry->font == font && strcmp(entry->text, text) == 0) { + _ttfGetWidthCacheHitCount++; + entry->lastUseTick = gCurrentDrawCount; + return entry->width; + } + + // If entry hasn't been used for a while, replace it + if (entry->lastUseTick < gCurrentDrawCount - 64) { + break; + } + + // Check if next entry is a hit + if (++index >= TTF_GETWIDTH_CACHE_SIZE) index = 0; + } + + // Cache miss, replace entry with new width + entry = &_ttfGetWidthCache[index]; + ttf_getwidth_cache_dispose(entry); + + sint32 width, height; + ttf_get_size(font, text, &width, &height); + + _ttfGetWidthCacheMissCount++; + + _ttfGetWidthCacheCount++; + entry->width = width; + entry->font = font; + entry->text = _strdup(text); + entry->lastUseTick = gCurrentDrawCount; + return entry->width; +} + +TTFFontDescriptor * ttf_get_font_from_sprite_base(uint16 spriteBase) +{ + return &gCurrentTTFFontSet->size[font_get_size_from_sprite_base(spriteBase)]; +} + +bool ttf_provides_glyph(const TTFFont * font, codepoint_t codepoint) +{ + return FT_Get_Char_Index(font->face, codepoint) != 0; +} + +static void ttf_get_size(TTFFont * font, const utf8 * text, sint32 * width, sint32 * height) +{ + *width = 128; + *height = 32; +} + +static TTFSurface * ttf_render(TTFFont * font, const utf8 * text) +{ + sint32 width = 128; + sint32 height = 32; + uint8 * pixels = (uint8 *)malloc(width * height); + memset(pixels, 0, width * height); + + TTFSurface * surface = (TTFSurface *)malloc(sizeof(TTFSurface)); + surface->w = width; + surface->h = height; + surface->pitch = width; + surface->pixels = pixels; + return NULL; +} + +static void ttf_free_surface(TTFSurface * surface) +{ + free((void *)surface->pixels); + free(surface); +} + +#else + +#include "ttf.h" + +bool ttf_initialise() +{ + return false; +} + +void ttf_dispose() +{ +} + +#endif // NO_TTF diff --git a/src/openrct2/drawing/ttf.h b/src/openrct2/drawing/ttf.h new file mode 100644 index 0000000000..9b6d505197 --- /dev/null +++ b/src/openrct2/drawing/ttf.h @@ -0,0 +1,38 @@ +#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#pragma once + +#include "font.h" + +bool ttf_initialise(); +void ttf_dispose(); + +#ifndef NO_TTF + +typedef struct TTFSurface { + const void * pixels; + sint32 w; + sint32 h; + sint32 pitch; +} TTFSurface; + +TTFFontDescriptor * ttf_get_font_from_sprite_base(uint16 spriteBase); +TTFSurface * ttf_surface_cache_get_or_add(TTFFont * font, const utf8 * text); +uint32 ttf_getwidth_cache_get_or_add(TTFFont * font, const utf8 * text); +bool ttf_provides_glyph(const TTFFont * font, codepoint_t codepoint); + +#endif // NO_TTF diff --git a/src/openrct2/interface/Fonts.cpp b/src/openrct2/interface/Fonts.cpp index f241bf89ac..151f04da41 100644 --- a/src/openrct2/interface/Fonts.cpp +++ b/src/openrct2/interface/Fonts.cpp @@ -14,16 +14,17 @@ *****************************************************************************/ #pragma endregion -#include "../common.h" +#include "../config/Config.h" #include "../core/Console.hpp" #include "../core/String.hpp" #include "../localisation/LanguagePack.h" #include "Fonts.h" -extern "C" { -#include "../config/Config.h" -#include "../drawing/drawing.h" -#include "../localisation/language.h" +extern "C" +{ + #include "../drawing/drawing.h" + #include "../drawing/ttf.h" + #include "../localisation/language.h" } #ifndef NO_TTF From 9ee1bbe4b5245906687168281b06280271ec3040 Mon Sep 17 00:00:00 2001 From: Ted John Date: Tue, 13 Jun 2017 22:20:04 +0100 Subject: [PATCH 02/10] Add some TTF code, poor --- src/openrct2/drawing/ttf.c | 90 +++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 7 deletions(-) diff --git a/src/openrct2/drawing/ttf.c b/src/openrct2/drawing/ttf.c index 3b1bbe614b..fc42c3a2d4 100644 --- a/src/openrct2/drawing/ttf.c +++ b/src/openrct2/drawing/ttf.c @@ -19,6 +19,7 @@ #include #include FT_FREETYPE_H +#include "../localisation/localisation.h" #include "../platform/platform.h" #include "../rct2.h" #include "ttf.h" @@ -286,25 +287,100 @@ bool ttf_provides_glyph(const TTFFont * font, codepoint_t codepoint) return FT_Get_Char_Index(font->face, codepoint) != 0; } -static void ttf_get_size(TTFFont * font, const utf8 * text, sint32 * width, sint32 * height) +static void ttf_get_size(TTFFont * font, const utf8 * text, sint32 * outWidth, sint32 * outHeight) { - *width = 128; - *height = 32; + sint32 width = 0; + sint32 height = 0; + + FT_GlyphSlot slot = font->face->glyph; + const utf8 * ch = text; + codepoint_t cp; + while ((cp = utf8_get_next(ch, &ch)) != 0) + { + FT_Error error = FT_Load_Char(font->face, cp, FT_LOAD_RENDER); + if (error == 0) + { + FT_Bitmap * bmp = &slot->bitmap; + width += slot->advance.x >> 6; + height = max(height, (sint32)bmp->rows); + } + } + + *outWidth = width; + *outHeight = height; +} + +static void ttf_render_char(void * dst, sint32 dstX, sint32 dstY, sint32 dstMaxWidth, sint32 dstMaxHeight, sint32 dstPitch, + const void * src, sint32 srcX, sint32 srcY, sint32 srcWidth, sint32 srcHeight, sint32 srcPitch) +{ + for (sint32 y = 0; y < srcHeight; y++) + { + for (sint32 x = 0; x < srcWidth; x++) + { + sint32 dstX2 = dstX + x; + sint32 dstY2 = dstY + y; + if (dstX2 >= 0 && dstY2 >= 0 && dstX2 < dstMaxWidth && dstY2 < dstMaxHeight) + { + uint8 * srcB = (uint8 *)((uintptr_t)src + x + (y * srcPitch)); + uint8 * dstB = (uint8 *)((uintptr_t)dst + dstX2 + (dstY2 * dstPitch)); + *dstB = *srcB; + } + } + } + + // sint32 cols = min(srcWidth, dstMaxWidth - srcX); + // sint32 rows = min(srcHeight, dstMaxHeight - dstY); + // for (sint32 y = 0; y < rows; y++) + // { + // uintptr_t srcI = (uintptr_t)src + (y * srcPitch); + // uintptr_t dstI = (uintptr_t)dst + ((dstY + y) * dstPitch) + dstX; + // + // assert(srcI >= (uintptr_t)src && srcI < ((uintptr_t)src + (srcWidth * srcHeight))); + // assert(dstI >= (uintptr_t)dst && dstI < ((uintptr_t)dst + (dstMaxWidth * dstMaxHeight))); + // memcpy((void *)dstI, (const void *)srcI, cols); + // } } static TTFSurface * ttf_render(TTFFont * font, const utf8 * text) { - sint32 width = 128; - sint32 height = 32; + // Calculate the size + sint32 width; + sint32 height; + ttf_get_size(font, text, &width, &height); + sint32 pitch = width; + + // Allocate pixels uint8 * pixels = (uint8 *)malloc(width * height); memset(pixels, 0, width * height); + // Draw to them + sint32 left = 0; + sint32 top = 0; + FT_GlyphSlot slot = font->face->glyph; + const utf8 * ch = text; + codepoint_t cp; + while ((cp = utf8_get_next(ch, &ch)) != 0) + { + FT_Error error = FT_Load_Char(font->face, cp, FT_LOAD_RENDER); + if (error == 0) + { + FT_Bitmap * bmp = &slot->bitmap; + + ttf_render_char(pixels, + left, + top, + width, height, pitch, + bmp->buffer, 0, 0, bmp->width, bmp->rows, bmp->pitch); + left += slot->advance.x >> 6; + } + } + TTFSurface * surface = (TTFSurface *)malloc(sizeof(TTFSurface)); surface->w = width; surface->h = height; - surface->pitch = width; + surface->pitch = pitch; surface->pixels = pixels; - return NULL; + return surface; } static void ttf_free_surface(TTFSurface * surface) From b7fd89361b24ff595b95c30f7ad60529bc3372fd Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 24 Jun 2017 23:13:07 +0100 Subject: [PATCH 03/10] Use complete SDL_ttf code --- src/openrct2/drawing/font.c | 2 +- src/openrct2/drawing/font.h | 7 +- src/openrct2/drawing/ttf.c | 150 +-- src/openrct2/drawing/ttf.h | 16 +- src/openrct2/drawing/ttf_sdlport.c | 1563 ++++++++++++++++++++++++++++ 5 files changed, 1602 insertions(+), 136 deletions(-) create mode 100644 src/openrct2/drawing/ttf_sdlport.c diff --git a/src/openrct2/drawing/font.c b/src/openrct2/drawing/font.c index 8077259ffb..52e58cd12e 100644 --- a/src/openrct2/drawing/font.c +++ b/src/openrct2/drawing/font.c @@ -199,7 +199,7 @@ bool font_supports_string_ttf(const utf8 *text, sint32 fontSize) { #ifndef NO_TTF const utf8 *src = text; - const TTFFont *font = gCurrentTTFFontSet->size[fontSize].font; + const TTF_Font *font = gCurrentTTFFontSet->size[fontSize].font; if (font == NULL) { return false; } diff --git a/src/openrct2/drawing/font.h b/src/openrct2/drawing/font.h index f77ee4a1d9..4b6180ab53 100644 --- a/src/openrct2/drawing/font.h +++ b/src/openrct2/drawing/font.h @@ -39,11 +39,8 @@ enum { }; #ifndef NO_TTF -typedef struct FT_FaceRec_* FT_Face; -typedef struct TTFFont { - FT_Face face; -} TTFFont; +typedef struct _TTF_Font TTF_Font; typedef struct TTFFontDescriptor { const utf8 *filename; const utf8 *font_name; @@ -51,7 +48,7 @@ typedef struct TTFFontDescriptor { sint32 offset_x; sint32 offset_y; sint32 line_height; - TTFFont * font; + TTF_Font * font; } TTFFontDescriptor; typedef struct TTFFontSetDescriptor { diff --git a/src/openrct2/drawing/ttf.c b/src/openrct2/drawing/ttf.c index fc42c3a2d4..4a2772d72f 100644 --- a/src/openrct2/drawing/ttf.c +++ b/src/openrct2/drawing/ttf.c @@ -25,7 +25,6 @@ #include "ttf.h" static bool _ttfInitialised = false; -static FT_Library _ftLibrary; #define TTF_SURFACE_CACHE_SIZE 256 #define TTF_GETWIDTH_CACHE_SIZE 1024 @@ -33,7 +32,7 @@ static FT_Library _ftLibrary; typedef struct ttf_cache_entry { TTFSurface * surface; - TTFFont * font; + TTF_Font * font; utf8 * text; uint32 lastUseTick; } ttf_cache_entry; @@ -41,7 +40,7 @@ typedef struct ttf_cache_entry typedef struct ttf_getwidth_cache_entry { uint32 width; - TTFFont * font; + TTF_Font * font; utf8 * text; uint32 lastUseTick; } ttf_getwidth_cache_entry; @@ -56,21 +55,19 @@ static sint32 _ttfGetWidthCacheCount = 0; static sint32 _ttfGetWidthCacheHitCount = 0; static sint32 _ttfGetWidthCacheMissCount = 0; -static TTFFont * ttf_open_font(const utf8 * fontPath, sint32 ptSize); -static void ttf_close_font(TTFFont * font); -static uint32 ttf_surface_cache_hash(TTFFont * font, const utf8 * text); +static TTF_Font * ttf_open_font(const utf8 * fontPath, sint32 ptSize); +static void ttf_close_font(TTF_Font * font); +static uint32 ttf_surface_cache_hash(TTF_Font * font, const utf8 * text); static void ttf_surface_cache_dispose(ttf_cache_entry * entry); static void ttf_surface_cache_dispose_all(); static void ttf_getwidth_cache_dispose_all(); -static void ttf_get_size(TTFFont * font, const utf8 * text, sint32 * width, sint32 * height); -static TTFSurface * ttf_render(TTFFont * font, const utf8 * text); -static void ttf_free_surface(TTFSurface * surface); +static bool ttf_get_size(TTF_Font * font, const utf8 * text, sint32 * width, sint32 * height); +static TTFSurface * ttf_render(TTF_Font * font, const utf8 * text); bool ttf_initialise() { if (!_ttfInitialised) { - FT_Error error = FT_Init_FreeType(&_ftLibrary); - if (error != 0) { + if (TTF_Init() != 0) { log_error("Couldn't initialise FreeType engine"); return false; } @@ -110,37 +107,22 @@ void ttf_dispose() } } - FT_Done_FreeType(_ftLibrary); + TTF_Quit(); _ttfInitialised = false; } } -static TTFFont * ttf_open_font(const utf8 * fontPath, sint32 ptSize) +static TTF_Font * ttf_open_font(const utf8 * fontPath, sint32 ptSize) { - TTFFont * font = malloc(sizeof(TTFFont)); - if (font != NULL) { - FT_Error error = FT_New_Face(_ftLibrary, fontPath, 0, &font->face); - if (error != 0) { - ttf_close_font(font); - return NULL; - } - - error = FT_Set_Char_Size(font->face, 0, ptSize * 64, 0, 0); - if (error != 0) { - ttf_close_font(font); - return NULL; - } - } - return font; + return TTF_OpenFont(fontPath, ptSize); } -static void ttf_close_font(TTFFont * font) +static void ttf_close_font(TTF_Font * font) { - FT_Done_Face(font->face); - free(font); + TTF_CloseFont(font); } -static uint32 ttf_surface_cache_hash(TTFFont *font, const utf8 *text) +static uint32 ttf_surface_cache_hash(TTF_Font *font, const utf8 *text) { uint32 hash = (uint32)((((uintptr_t)font * 23) ^ 0xAAAAAAAA) & 0xFFFFFFFF); for (const utf8 *ch = text; *ch != 0; ch++) { @@ -169,7 +151,7 @@ static void ttf_surface_cache_dispose_all() } } -TTFSurface * ttf_surface_cache_get_or_add(TTFFont * font, const utf8 * text) +TTFSurface * ttf_surface_cache_get_or_add(TTF_Font * font, const utf8 * text) { ttf_cache_entry *entry; @@ -234,7 +216,7 @@ static void ttf_getwidth_cache_dispose_all() } } -uint32 ttf_getwidth_cache_get_or_add(TTFFont * font, const utf8 * text) +uint32 ttf_getwidth_cache_get_or_add(TTF_Font * font, const utf8 * text) { ttf_getwidth_cache_entry *entry; @@ -282,108 +264,22 @@ TTFFontDescriptor * ttf_get_font_from_sprite_base(uint16 spriteBase) return &gCurrentTTFFontSet->size[font_get_size_from_sprite_base(spriteBase)]; } -bool ttf_provides_glyph(const TTFFont * font, codepoint_t codepoint) +bool ttf_provides_glyph(const TTF_Font * font, codepoint_t codepoint) { - return FT_Get_Char_Index(font->face, codepoint) != 0; + return TTF_GlyphIsProvided(font, codepoint); } -static void ttf_get_size(TTFFont * font, const utf8 * text, sint32 * outWidth, sint32 * outHeight) +static bool ttf_get_size(TTF_Font * font, const utf8 * text, sint32 * outWidth, sint32 * outHeight) { - sint32 width = 0; - sint32 height = 0; - - FT_GlyphSlot slot = font->face->glyph; - const utf8 * ch = text; - codepoint_t cp; - while ((cp = utf8_get_next(ch, &ch)) != 0) - { - FT_Error error = FT_Load_Char(font->face, cp, FT_LOAD_RENDER); - if (error == 0) - { - FT_Bitmap * bmp = &slot->bitmap; - width += slot->advance.x >> 6; - height = max(height, (sint32)bmp->rows); - } - } - - *outWidth = width; - *outHeight = height; + return TTF_SizeUTF8(font, text, outWidth, outHeight); } -static void ttf_render_char(void * dst, sint32 dstX, sint32 dstY, sint32 dstMaxWidth, sint32 dstMaxHeight, sint32 dstPitch, - const void * src, sint32 srcX, sint32 srcY, sint32 srcWidth, sint32 srcHeight, sint32 srcPitch) +static TTFSurface * ttf_render(TTF_Font * font, const utf8 * text) { - for (sint32 y = 0; y < srcHeight; y++) - { - for (sint32 x = 0; x < srcWidth; x++) - { - sint32 dstX2 = dstX + x; - sint32 dstY2 = dstY + y; - if (dstX2 >= 0 && dstY2 >= 0 && dstX2 < dstMaxWidth && dstY2 < dstMaxHeight) - { - uint8 * srcB = (uint8 *)((uintptr_t)src + x + (y * srcPitch)); - uint8 * dstB = (uint8 *)((uintptr_t)dst + dstX2 + (dstY2 * dstPitch)); - *dstB = *srcB; - } - } - } - - // sint32 cols = min(srcWidth, dstMaxWidth - srcX); - // sint32 rows = min(srcHeight, dstMaxHeight - dstY); - // for (sint32 y = 0; y < rows; y++) - // { - // uintptr_t srcI = (uintptr_t)src + (y * srcPitch); - // uintptr_t dstI = (uintptr_t)dst + ((dstY + y) * dstPitch) + dstX; - // - // assert(srcI >= (uintptr_t)src && srcI < ((uintptr_t)src + (srcWidth * srcHeight))); - // assert(dstI >= (uintptr_t)dst && dstI < ((uintptr_t)dst + (dstMaxWidth * dstMaxHeight))); - // memcpy((void *)dstI, (const void *)srcI, cols); - // } + return TTF_RenderUTF8_Solid(font, text, 0x000000FF); } -static TTFSurface * ttf_render(TTFFont * font, const utf8 * text) -{ - // Calculate the size - sint32 width; - sint32 height; - ttf_get_size(font, text, &width, &height); - sint32 pitch = width; - - // Allocate pixels - uint8 * pixels = (uint8 *)malloc(width * height); - memset(pixels, 0, width * height); - - // Draw to them - sint32 left = 0; - sint32 top = 0; - FT_GlyphSlot slot = font->face->glyph; - const utf8 * ch = text; - codepoint_t cp; - while ((cp = utf8_get_next(ch, &ch)) != 0) - { - FT_Error error = FT_Load_Char(font->face, cp, FT_LOAD_RENDER); - if (error == 0) - { - FT_Bitmap * bmp = &slot->bitmap; - - ttf_render_char(pixels, - left, - top, - width, height, pitch, - bmp->buffer, 0, 0, bmp->width, bmp->rows, bmp->pitch); - left += slot->advance.x >> 6; - } - } - - TTFSurface * surface = (TTFSurface *)malloc(sizeof(TTFSurface)); - surface->w = width; - surface->h = height; - surface->pitch = pitch; - surface->pixels = pixels; - return surface; -} - -static void ttf_free_surface(TTFSurface * surface) +void ttf_free_surface(TTFSurface * surface) { free((void *)surface->pixels); free(surface); diff --git a/src/openrct2/drawing/ttf.h b/src/openrct2/drawing/ttf.h index 9b6d505197..ea04cfe628 100644 --- a/src/openrct2/drawing/ttf.h +++ b/src/openrct2/drawing/ttf.h @@ -31,8 +31,18 @@ typedef struct TTFSurface { } TTFSurface; TTFFontDescriptor * ttf_get_font_from_sprite_base(uint16 spriteBase); -TTFSurface * ttf_surface_cache_get_or_add(TTFFont * font, const utf8 * text); -uint32 ttf_getwidth_cache_get_or_add(TTFFont * font, const utf8 * text); -bool ttf_provides_glyph(const TTFFont * font, codepoint_t codepoint); +TTFSurface * ttf_surface_cache_get_or_add(TTF_Font * font, const utf8 * text); +uint32 ttf_getwidth_cache_get_or_add(TTF_Font * font, const utf8 * text); +bool ttf_provides_glyph(const TTF_Font * font, codepoint_t codepoint); +void ttf_free_surface(TTFSurface * surface); + +// TTF_SDLPORT +int TTF_Init(void); +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); +void TTF_CloseFont(TTF_Font *font); +void TTF_Quit(void); #endif // NO_TTF diff --git a/src/openrct2/drawing/ttf_sdlport.c b/src/openrct2/drawing/ttf_sdlport.c new file mode 100644 index 0000000000..687af95ec7 --- /dev/null +++ b/src/openrct2/drawing/ttf_sdlport.c @@ -0,0 +1,1563 @@ +/* +SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts +Copyright (C) 2001-2017 Sam Lantinga + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +#include +#include +#include +#include + +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_STROKER_H +#include FT_GLYPH_H +#include FT_TRUETYPE_IDS_H + +#include "SDL.h" +#include "SDL_endian.h" + +#include "ttf.h" + +#pragma warning(disable : 4018) // '<': signed / unsigned mismatch + +/* ZERO WIDTH NO-BREAKSPACE (Unicode byte order mark) */ +#define UNICODE_BOM_NATIVE 0xFEFF +#define UNICODE_BOM_SWAPPED 0xFFFE + +/* Set and retrieve the font style */ +#define TTF_STYLE_NORMAL 0x00 +#define TTF_STYLE_BOLD 0x01 +#define TTF_STYLE_ITALIC 0x02 +#define TTF_STYLE_UNDERLINE 0x04 +#define TTF_STYLE_STRIKETHROUGH 0x08 + +/* Set and retrieve FreeType hinter settings */ +#define TTF_HINTING_NORMAL 0 +#define TTF_HINTING_LIGHT 1 +#define TTF_HINTING_MONO 2 +#define TTF_HINTING_NONE 3 + +/* FIXME: Right now we assume the gray-scale renderer Freetype is using +supports 256 shades of gray, but we should instead key off of num_grays +in the result FT_Bitmap after the FT_Render_Glyph() call. */ +#define NUM_GRAYS 256 + +/* Handy routines for converting from fixed point */ +#define FT_FLOOR(X) ((X & -64) / 64) +#define FT_CEIL(X) (((X + 63) & -64) / 64) + +#define CACHED_METRICS 0x10 +#define CACHED_BITMAP 0x01 +#define CACHED_PIXMAP 0x02 + +/* Cached glyph information */ +typedef struct cached_glyph { + int stored; + FT_UInt index; + FT_Bitmap bitmap; + FT_Bitmap pixmap; + int minx; + int maxx; + int miny; + int maxy; + int yoffset; + int advance; + Uint16 cached; +} c_glyph; + +/* The structure used to hold internal font information */ +struct _TTF_Font { + /* Freetype2 maintains all sorts of useful info itself */ + FT_Face face; + + /* We'll cache these ourselves */ + int height; + int ascent; + int descent; + int lineskip; + + /* The font style */ + int face_style; + int style; + int outline; + + /* Whether kerning is desired */ + int kerning; + + /* Extra width in glyph bounds for text styles */ + int glyph_overhang; + float glyph_italics; + + /* Information in the font for underlining */ + int underline_offset; + int underline_height; + + /* Cache for style-transformed glyphs */ + c_glyph *current; + c_glyph cache[257]; /* 257 is a prime */ + + /* We are responsible for closing the font stream */ + SDL_RWops *src; + int freesrc; + FT_Open_Args args; + + /* For non-scalable formats, we must remember which font index size */ + int font_size_family; + + /* really just flags passed into FT_Load_Glyph */ + int hinting; +}; + +/* Handle a style only if the font does not already handle it */ +#define TTF_HANDLE_STYLE_BOLD(font) (((font)->style & TTF_STYLE_BOLD) && \ + !((font)->face_style & TTF_STYLE_BOLD)) +#define TTF_HANDLE_STYLE_ITALIC(font) (((font)->style & TTF_STYLE_ITALIC) && \ + !((font)->face_style & TTF_STYLE_ITALIC)) +#define TTF_HANDLE_STYLE_UNDERLINE(font) ((font)->style & TTF_STYLE_UNDERLINE) +#define TTF_HANDLE_STYLE_STRIKETHROUGH(font) ((font)->style & TTF_STYLE_STRIKETHROUGH) + +/* Font styles that does not impact glyph drawing */ +#define TTF_STYLE_NO_GLYPH_CHANGE (TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH) + +/* The FreeType font engine/library */ +static FT_Library library; +static int TTF_initialized = 0; +static int TTF_byteswapped = 0; + +#define TTF_SetError SDL_SetError + +#define TTF_CHECKPOINTER(p, errval) \ + if ( !TTF_initialized ) { \ + TTF_SetError("Library not initialized"); \ + return errval; \ + } \ + if ( !p ) { \ + TTF_SetError("Passed a NULL pointer"); \ + return errval; \ + } + +/* Gets the top row of the underline. The outline +is taken into account. +*/ +static int TTF_underline_top_row(TTF_Font *font) +{ + /* With outline, the underline_offset is underline_offset+outline. */ + /* So, we don't have to remove the top part of the outline height. */ + return font->ascent - font->underline_offset - 1; +} + +/* Gets the top row of the underline. for a given glyph. The outline +is taken into account. +Need to update row according to height difference between font and glyph: +font_value - font->ascent + glyph->maxy +*/ +static int TTF_Glyph_underline_top_row(TTF_Font *font, c_glyph *glyph) +{ + return glyph->maxy - font->underline_offset - 1; +} + +/* Gets the bottom row of the underline. The outline +is taken into account. +*/ +static int TTF_underline_bottom_row(TTF_Font *font) +{ + int row = TTF_underline_top_row(font) + font->underline_height; + if (font->outline > 0) { + /* Add underline_offset outline offset and */ + /* the bottom part of the outline. */ + row += font->outline * 2; + } + return row; +} + +/* Gets the bottom row of the underline. for a given glyph. The outline +is taken into account. +Need to update row according to height difference between font and glyph: +font_value - font->ascent + glyph->maxy +*/ +static int TTF_Glyph_underline_bottom_row(TTF_Font *font, c_glyph *glyph) +{ + return TTF_underline_bottom_row(font) - font->ascent + glyph->maxy; +} + +/* Gets the top row of the strikethrough. The outline +is taken into account. +*/ +static int TTF_strikethrough_top_row(TTF_Font *font) +{ + /* With outline, the first text row is 'outline'. */ + /* So, we don't have to remove the top part of the outline height. */ + return font->height / 2; +} + +/* Gets the top row of the strikethrough for a given glyph. The outline +is taken into account. +Need to update row according to height difference between font and glyph: +font_value - font->ascent + glyph->maxy +*/ +static int TTF_Glyph_strikethrough_top_row(TTF_Font *font, c_glyph *glyph) +{ + return TTF_strikethrough_top_row(font) - font->ascent + glyph->maxy; +} + +static void TTF_initLineMectrics(const TTF_Font *font, const TTFSurface *textbuf, const int row, Uint8 **pdst, int *pheight) +{ + Uint8 *dst; + int height; + + dst = (Uint8 *)textbuf->pixels; + if (row > 0) { + dst += row * textbuf->pitch; + } + + height = font->underline_height; + /* Take outline into account */ + if (font->outline > 0) { + height += font->outline * 2; + } + *pdst = dst; + *pheight = height; +} + +/* Draw a solid line of underline_height (+ optional outline) +at the given row. The row value must take the +outline into account. +*/ +static void TTF_drawLine_Solid(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) { + /* 1 because 0 is the bg color */ + memset(dst, 1, textbuf->w); + dst += textbuf->pitch; + } +} + +/* This function tells the library whether UNICODE text is generally +byteswapped. A UNICODE BOM character at the beginning of a string +will override this setting for that string. +*/ +void TTF_ByteSwappedUNICODE(int swapped) +{ + TTF_byteswapped = swapped; +} + +static void TTF_SetFTError(const char *msg, FT_Error error) +{ +#ifdef USE_FREETYPE_ERRORS +#undef FTERRORS_H +#define FT_ERRORDEF( e, v, s ) { e, s }, + static const struct + { + int err_code; + const char* err_msg; + } ft_errors[] = { +#include + }; + int i; + const char *err_msg; + char buffer[1024]; + + err_msg = NULL; + for (i = 0; i<((sizeof ft_errors) / (sizeof ft_errors[0])); ++i) { + if (error == ft_errors[i].err_code) { + err_msg = ft_errors[i].err_msg; + break; + } + } + if (!err_msg) { + err_msg = "unknown FreeType error"; + } + TTF_SetError("%s: %s", msg, err_msg); +#else + TTF_SetError("%s", msg); +#endif /* USE_FREETYPE_ERRORS */ +} + +int TTF_Init(void) +{ + int status = 0; + + if (!TTF_initialized) { + FT_Error error = FT_Init_FreeType(&library); + if (error) { + TTF_SetFTError("Couldn't init FreeType engine", error); + status = -1; + } + } + if (status == 0) { + ++TTF_initialized; + } + return status; +} + +static unsigned long RWread( + FT_Stream stream, + unsigned long offset, + unsigned char* buffer, + unsigned long count +) +{ + SDL_RWops *src; + + src = (SDL_RWops *)stream->descriptor.pointer; + SDL_RWseek(src, (int)offset, RW_SEEK_SET); + if (count == 0) { + return 0; + } + return (unsigned long)SDL_RWread(src, buffer, 1, (int)count); +} + +TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index) +{ + TTF_Font* font; + FT_Error error; + FT_Face face; + FT_Fixed scale; + FT_Stream stream; + FT_CharMap found; + Sint64 position; + int i; + + if (!TTF_initialized) { + TTF_SetError("Library not initialized"); + if (src && freesrc) { + SDL_RWclose(src); + } + return NULL; + } + + if (!src) { + TTF_SetError("Passed a NULL font source"); + return NULL; + } + + /* Check to make sure we can seek in this stream */ + position = SDL_RWtell(src); + if (position < 0) { + TTF_SetError("Can't seek in stream"); + if (freesrc) { + SDL_RWclose(src); + } + return NULL; + } + + font = (TTF_Font*)SDL_malloc(sizeof *font); + if (font == NULL) { + TTF_SetError("Out of memory"); + if (freesrc) { + SDL_RWclose(src); + } + return NULL; + } + SDL_memset(font, 0, sizeof(*font)); + + font->src = src; + font->freesrc = freesrc; + + stream = (FT_Stream)SDL_malloc(sizeof(*stream)); + if (stream == NULL) { + TTF_SetError("Out of memory"); + TTF_CloseFont(font); + return NULL; + } + SDL_memset(stream, 0, sizeof(*stream)); + + stream->read = RWread; + stream->descriptor.pointer = src; + stream->pos = (unsigned long)position; + stream->size = (unsigned long)(SDL_RWsize(src) - position); + + font->args.flags = FT_OPEN_STREAM; + font->args.stream = stream; + + error = FT_Open_Face(library, &font->args, index, &font->face); + if (error) { + TTF_SetFTError("Couldn't load font file", error); + TTF_CloseFont(font); + return NULL; + } + face = font->face; + + /* Set charmap for loaded font */ + found = 0; + for (i = 0; i < face->num_charmaps; i++) { + FT_CharMap charmap = face->charmaps[i]; + if ((charmap->platform_id == 3 && charmap->encoding_id == 1) /* Windows Unicode */ + || (charmap->platform_id == 3 && charmap->encoding_id == 0) /* Windows Symbol */ + || (charmap->platform_id == 2 && charmap->encoding_id == 1) /* ISO Unicode */ + || (charmap->platform_id == 0)) { /* Apple Unicode */ + found = charmap; + break; + } + } + if (found) { + /* If this fails, continue using the default charmap */ + FT_Set_Charmap(face, found); + } + + /* Make sure that our font face is scalable (global metrics) */ + if (FT_IS_SCALABLE(face)) { + /* Set the character size and use default DPI (72) */ + error = FT_Set_Char_Size(font->face, 0, ptsize * 64, 0, 0); + if (error) { + TTF_SetFTError("Couldn't set font size", error); + TTF_CloseFont(font); + return NULL; + } + + /* Get the scalable font metrics for this font */ + scale = face->size->metrics.y_scale; + font->ascent = FT_CEIL(FT_MulFix(face->ascender, scale)); + font->descent = FT_CEIL(FT_MulFix(face->descender, scale)); + font->height = font->ascent - font->descent + /* baseline */ 1; + font->lineskip = FT_CEIL(FT_MulFix(face->height, scale)); + font->underline_offset = FT_FLOOR(FT_MulFix(face->underline_position, scale)); + font->underline_height = FT_FLOOR(FT_MulFix(face->underline_thickness, scale)); + + } + else { + /* Non-scalable font case. ptsize determines which family + * or series of fonts to grab from the non-scalable format. + * It is not the point size of the font. + * */ + if (ptsize >= font->face->num_fixed_sizes) + ptsize = font->face->num_fixed_sizes - 1; + font->font_size_family = ptsize; + error = FT_Set_Pixel_Sizes(face, + face->available_sizes[ptsize].width, + face->available_sizes[ptsize].height); + + /* With non-scalale fonts, Freetype2 likes to fill many of the + * font metrics with the value of 0. The size of the + * non-scalable fonts must be determined differently + * or sometimes cannot be determined. + * */ + font->ascent = face->available_sizes[ptsize].height; + font->descent = 0; + font->height = face->available_sizes[ptsize].height; + font->lineskip = FT_CEIL(font->ascent); + font->underline_offset = FT_FLOOR(face->underline_position); + font->underline_height = FT_FLOOR(face->underline_thickness); + } + + if (font->underline_height < 1) { + font->underline_height = 1; + } + +#ifdef DEBUG_FONTS + printf("Font metrics:\n"); + printf("\tascent = %d, descent = %d\n", + font->ascent, font->descent); + printf("\theight = %d, lineskip = %d\n", + font->height, font->lineskip); + printf("\tunderline_offset = %d, underline_height = %d\n", + font->underline_offset, font->underline_height); + printf("\tunderline_top_row = %d, strikethrough_top_row = %d\n", + TTF_underline_top_row(font), TTF_strikethrough_top_row(font)); +#endif + + /* Initialize the font face style */ + font->face_style = TTF_STYLE_NORMAL; + if (font->face->style_flags & FT_STYLE_FLAG_BOLD) { + font->face_style |= TTF_STYLE_BOLD; + } + if (font->face->style_flags & FT_STYLE_FLAG_ITALIC) { + font->face_style |= TTF_STYLE_ITALIC; + } + + /* Set the default font style */ + font->style = font->face_style; + font->outline = 0; + font->kerning = 1; + font->glyph_overhang = face->size->metrics.y_ppem / 10; + /* x offset = cos(((90.0-12)/360)*2*M_PI), or 12 degree angle */ + font->glyph_italics = 0.207f; + font->glyph_italics *= font->height; + + return font; +} + +TTF_Font* TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize) +{ + return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0); +} + +TTF_Font* TTF_OpenFontIndex(const char *file, int ptsize, long index) +{ + SDL_RWops *rw = SDL_RWFromFile(file, "rb"); + if (rw == NULL) { + return NULL; + } + return TTF_OpenFontIndexRW(rw, 1, ptsize, index); +} + +TTF_Font* TTF_OpenFont(const char *file, int ptsize) +{ + return TTF_OpenFontIndex(file, ptsize, 0); +} + +static void Flush_Glyph(c_glyph* glyph) +{ + glyph->stored = 0; + glyph->index = 0; + if (glyph->bitmap.buffer) { + SDL_free(glyph->bitmap.buffer); + glyph->bitmap.buffer = 0; + } + if (glyph->pixmap.buffer) { + SDL_free(glyph->pixmap.buffer); + glyph->pixmap.buffer = 0; + } + glyph->cached = 0; +} + +static void Flush_Cache(TTF_Font* font) +{ + int i; + int size = sizeof(font->cache) / sizeof(font->cache[0]); + + for (i = 0; i < size; ++i) { + if (font->cache[i].cached) { + Flush_Glyph(&font->cache[i]); + } + + } +} + +static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) +{ + FT_Face face; + FT_Error error; + FT_GlyphSlot glyph; + FT_Glyph_Metrics* metrics; + FT_Outline* outline; + + if (!font || !font->face) { + return FT_Err_Invalid_Handle; + } + + face = font->face; + + /* Load the glyph */ + if (!cached->index) { + cached->index = FT_Get_Char_Index(face, ch); + } + error = FT_Load_Glyph(face, cached->index, FT_LOAD_DEFAULT | font->hinting); + if (error) { + return error; + } + + /* Get our glyph shortcuts */ + glyph = face->glyph; + metrics = &glyph->metrics; + outline = &glyph->outline; + + /* Get the glyph metrics if desired */ + if ((want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS)) { + if (FT_IS_SCALABLE(face)) { + /* Get the bounding box */ + cached->minx = FT_FLOOR(metrics->horiBearingX); + cached->maxx = FT_CEIL(metrics->horiBearingX + metrics->width); + cached->maxy = FT_FLOOR(metrics->horiBearingY); + cached->miny = cached->maxy - FT_CEIL(metrics->height); + cached->yoffset = font->ascent - cached->maxy; + cached->advance = FT_CEIL(metrics->horiAdvance); + } + else { + /* Get the bounding box for non-scalable format. + * Again, freetype2 fills in many of the font metrics + * with the value of 0, so some of the values we + * need must be calculated differently with certain + * assumptions about non-scalable formats. + * */ + cached->minx = FT_FLOOR(metrics->horiBearingX); + cached->maxx = FT_CEIL(metrics->horiBearingX + metrics->width); + cached->maxy = FT_FLOOR(metrics->horiBearingY); + cached->miny = cached->maxy - FT_CEIL(face->available_sizes[font->font_size_family].height); + cached->yoffset = 0; + cached->advance = FT_CEIL(metrics->horiAdvance); + } + + /* Adjust for bold and italic text */ + if (TTF_HANDLE_STYLE_BOLD(font)) { + cached->maxx += font->glyph_overhang; + } + if (TTF_HANDLE_STYLE_ITALIC(font)) { + cached->maxx += (int)SDL_ceil(font->glyph_italics); + } + cached->stored |= CACHED_METRICS; + } + + if (((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) || + ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP))) { + int mono = (want & CACHED_BITMAP); + int i; + FT_Bitmap* src; + FT_Bitmap* dst; + FT_Glyph bitmap_glyph = NULL; + + /* Handle the italic style */ + if (TTF_HANDLE_STYLE_ITALIC(font)) { + FT_Matrix shear; + + shear.xx = 1 << 16; + shear.xy = (int)(font->glyph_italics * (1 << 16)) / font->height; + shear.yx = 0; + shear.yy = 1 << 16; + + FT_Outline_Transform(outline, &shear); + } + + /* Render as outline */ + if ((font->outline > 0) && glyph->format != FT_GLYPH_FORMAT_BITMAP) { + FT_Stroker stroker; + FT_Get_Glyph(glyph, &bitmap_glyph); + error = FT_Stroker_New(library, &stroker); + if (error) { + return error; + } + FT_Stroker_Set(stroker, font->outline * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); + FT_Glyph_Stroke(&bitmap_glyph, stroker, 1 /* delete the original glyph */); + FT_Stroker_Done(stroker); + /* Render the glyph */ + error = FT_Glyph_To_Bitmap(&bitmap_glyph, mono ? ft_render_mode_mono : ft_render_mode_normal, 0, 1); + if (error) { + FT_Done_Glyph(bitmap_glyph); + return error; + } + src = &((FT_BitmapGlyph)bitmap_glyph)->bitmap; + } + else { + /* Render the glyph */ + error = FT_Render_Glyph(glyph, mono ? ft_render_mode_mono : ft_render_mode_normal); + if (error) { + return error; + } + src = &glyph->bitmap; + } + /* Copy over information to cache */ + if (mono) { + dst = &cached->bitmap; + } + else { + dst = &cached->pixmap; + } + SDL_memcpy(dst, src, sizeof(*dst)); + + /* FT_Render_Glyph() and .fon fonts always generate a + * two-color (black and white) glyphslot surface, even + * when rendered in ft_render_mode_normal. */ + /* FT_IS_SCALABLE() means that the font is in outline format, + * but does not imply that outline is rendered as 8-bit + * grayscale, because embedded bitmap/graymap is preferred + * (see FT_LOAD_DEFAULT section of FreeType2 API Reference). + * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256- + * color graymap according to the format of embedded bitmap/ + * graymap. */ + if (src->pixel_mode == FT_PIXEL_MODE_MONO) { + dst->pitch *= 8; + } + else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) { + dst->pitch *= 4; + } + else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) { + dst->pitch *= 2; + } + + /* Adjust for bold and italic text */ + if (TTF_HANDLE_STYLE_BOLD(font)) { + int bump = font->glyph_overhang; + dst->pitch += bump; + dst->width += bump; + } + if (TTF_HANDLE_STYLE_ITALIC(font)) { + int bump = (int)SDL_ceil(font->glyph_italics); + dst->pitch += bump; + dst->width += bump; + } + + if (dst->rows != 0) { + dst->buffer = (unsigned char *)SDL_malloc(dst->pitch * dst->rows); + if (!dst->buffer) { + return FT_Err_Out_Of_Memory; + } + SDL_memset(dst->buffer, 0, dst->pitch * dst->rows); + + for (i = 0; i < src->rows; i++) { + int soffset = i * src->pitch; + int doffset = i * dst->pitch; + if (mono) { + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + int j; + if (src->pixel_mode == FT_PIXEL_MODE_MONO) { + for (j = 0; j < src->width; j += 8) { + unsigned char c = *srcp++; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + c <<= 1; + *dstp++ = (c & 0x80) >> 7; + } + } + else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) { + for (j = 0; j < src->width; j += 4) { + unsigned char c = *srcp++; + *dstp++ = (((c & 0xA0) >> 6) >= 0x2) ? 1 : 0; + c <<= 2; + *dstp++ = (((c & 0xA0) >> 6) >= 0x2) ? 1 : 0; + c <<= 2; + *dstp++ = (((c & 0xA0) >> 6) >= 0x2) ? 1 : 0; + c <<= 2; + *dstp++ = (((c & 0xA0) >> 6) >= 0x2) ? 1 : 0; + } + } + else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) { + for (j = 0; j < src->width; j += 2) { + unsigned char c = *srcp++; + *dstp++ = (((c & 0xF0) >> 4) >= 0x8) ? 1 : 0; + c <<= 4; + *dstp++ = (((c & 0xF0) >> 4) >= 0x8) ? 1 : 0; + } + } + else { + for (j = 0; j < src->width; j++) { + unsigned char c = *srcp++; + *dstp++ = (c >= 0x80) ? 1 : 0; + } + } + } + else if (src->pixel_mode == FT_PIXEL_MODE_MONO) { + /* This special case wouldn't + * be here if the FT_Render_Glyph() + * function wasn't buggy when it tried + * to render a .fon font with 256 + * shades of gray. Instead, it + * returns a black and white surface + * and we have to translate it back + * to a 256 gray shaded surface. + * */ + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + unsigned char c; + int j, k; + for (j = 0; j < src->width; j += 8) { + c = *srcp++; + for (k = 0; k < 8; ++k) { + if ((c & 0x80) >> 7) { + *dstp++ = NUM_GRAYS - 1; + } + else { + *dstp++ = 0x00; + } + c <<= 1; + } + } + } + else if (src->pixel_mode == FT_PIXEL_MODE_GRAY2) { + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + unsigned char c; + int j, k; + for (j = 0; j < src->width; j += 4) { + c = *srcp++; + for (k = 0; k < 4; ++k) { + if ((c & 0xA0) >> 6) { + *dstp++ = NUM_GRAYS * ((c & 0xA0) >> 6) / 3 - 1; + } + else { + *dstp++ = 0x00; + } + c <<= 2; + } + } + } + else if (src->pixel_mode == FT_PIXEL_MODE_GRAY4) { + unsigned char *srcp = src->buffer + soffset; + unsigned char *dstp = dst->buffer + doffset; + unsigned char c; + int j, k; + for (j = 0; j < src->width; j += 2) { + c = *srcp++; + for (k = 0; k < 2; ++k) { + if ((c & 0xF0) >> 4) { + *dstp++ = NUM_GRAYS * ((c & 0xF0) >> 4) / 15 - 1; + } + else { + *dstp++ = 0x00; + } + c <<= 4; + } + } + } + else { + SDL_memcpy(dst->buffer + doffset, + src->buffer + soffset, src->pitch); + } + } + } + + /* Handle the bold style */ + if (TTF_HANDLE_STYLE_BOLD(font)) { + int row; + int col; + int offset; + int pixel; + Uint8* pixmap; + + /* The pixmap is a little hard, we have to add and clamp */ + for (row = dst->rows - 1; row >= 0; --row) { + pixmap = (Uint8*)dst->buffer + row * dst->pitch; + for (offset = 1; offset <= font->glyph_overhang; ++offset) { + for (col = dst->width - 1; col > 0; --col) { + if (mono) { + pixmap[col] |= pixmap[col - 1]; + } + else { + pixel = (pixmap[col] + pixmap[col - 1]); + if (pixel > NUM_GRAYS - 1) { + pixel = NUM_GRAYS - 1; + } + pixmap[col] = (Uint8)pixel; + } + } + } + } + } + + /* Mark that we rendered this format */ + if (mono) { + cached->stored |= CACHED_BITMAP; + } + else { + cached->stored |= CACHED_PIXMAP; + } + + /* Free outlined glyph */ + if (bitmap_glyph) { + FT_Done_Glyph(bitmap_glyph); + } + } + + /* We're done, mark this glyph cached */ + cached->cached = ch; + + return 0; +} + +static FT_Error Find_Glyph(TTF_Font* font, Uint16 ch, int want) +{ + int retval = 0; + int hsize = sizeof(font->cache) / sizeof(font->cache[0]); + + int h = ch % hsize; + font->current = &font->cache[h]; + + if (font->current->cached != ch) + Flush_Glyph(font->current); + + if ((font->current->stored & want) != want) { + retval = Load_Glyph(font, ch, font->current, want); + } + return retval; +} + +void TTF_CloseFont(TTF_Font* font) +{ + if (font) { + Flush_Cache(font); + if (font->face) { + FT_Done_Face(font->face); + } + if (font->args.stream) { + SDL_free(font->args.stream); + } + if (font->freesrc) { + SDL_RWclose(font->src); + } + SDL_free(font); + } +} + +/* Gets the number of bytes used by a null terminated UCS2 string */ +static size_t UCS2_len(const Uint16 *text) +{ + size_t count = 0; + while (*text++) { + ++count; + } + return count * sizeof(*text); +} + +/* Convert a Latin-1 string to a UTF-8 string */ +static void LATIN1_to_UTF8(const char *src, Uint8 *dst) +{ + while (*src) { + Uint8 ch = *(Uint8*)src++; + if (ch <= 0x7F) { + *dst++ = ch; + } + else { + *dst++ = 0xC0 | ((ch >> 6) & 0x1F); + *dst++ = 0x80 | (ch & 0x3F); + } + } + *dst = '\0'; +} + +/* Convert a UCS-2 string to a UTF-8 string */ +static void UCS2_to_UTF8(const Uint16 *src, Uint8 *dst) +{ + int swapped = TTF_byteswapped; + + while (*src) { + Uint16 ch = *(Uint16*)src++; + if (ch == UNICODE_BOM_NATIVE) { + swapped = 0; + continue; + } + if (ch == UNICODE_BOM_SWAPPED) { + swapped = 1; + continue; + } + if (swapped) { + ch = SDL_Swap16(ch); + } + if (ch <= 0x7F) { + *dst++ = (Uint8)ch; + } + else if (ch <= 0x7FF) { + *dst++ = 0xC0 | (Uint8)((ch >> 6) & 0x1F); + *dst++ = 0x80 | (Uint8)(ch & 0x3F); + } + else { + *dst++ = 0xE0 | (Uint8)((ch >> 12) & 0x0F); + *dst++ = 0x80 | (Uint8)((ch >> 6) & 0x3F); + *dst++ = 0x80 | (Uint8)(ch & 0x3F); + } + } + *dst = '\0'; +} + +/* Gets a unicode value from a UTF-8 encoded string and advance the string */ +#define UNKNOWN_UNICODE 0xFFFD +static Uint32 UTF8_getch(const char **src, size_t *srclen) +{ + const Uint8 *p = *(const Uint8**)src; + size_t left = 0; + SDL_bool overlong = SDL_FALSE; + SDL_bool underflow = SDL_FALSE; + Uint32 ch = UNKNOWN_UNICODE; + + if (*srclen == 0) { + return UNKNOWN_UNICODE; + } + if (p[0] >= 0xFC) { + if ((p[0] & 0xFE) == 0xFC) { + if (p[0] == 0xFC && (p[1] & 0xFC) == 0x80) { + overlong = SDL_TRUE; + } + ch = (Uint32)(p[0] & 0x01); + left = 5; + } + } + else if (p[0] >= 0xF8) { + if ((p[0] & 0xFC) == 0xF8) { + if (p[0] == 0xF8 && (p[1] & 0xF8) == 0x80) { + overlong = SDL_TRUE; + } + ch = (Uint32)(p[0] & 0x03); + left = 4; + } + } + else if (p[0] >= 0xF0) { + if ((p[0] & 0xF8) == 0xF0) { + if (p[0] == 0xF0 && (p[1] & 0xF0) == 0x80) { + overlong = SDL_TRUE; + } + ch = (Uint32)(p[0] & 0x07); + left = 3; + } + } + else if (p[0] >= 0xE0) { + if ((p[0] & 0xF0) == 0xE0) { + if (p[0] == 0xE0 && (p[1] & 0xE0) == 0x80) { + overlong = SDL_TRUE; + } + ch = (Uint32)(p[0] & 0x0F); + left = 2; + } + } + else if (p[0] >= 0xC0) { + if ((p[0] & 0xE0) == 0xC0) { + if ((p[0] & 0xDE) == 0xC0) { + overlong = SDL_TRUE; + } + ch = (Uint32)(p[0] & 0x1F); + left = 1; + } + } + else { + if ((p[0] & 0x80) == 0x00) { + ch = (Uint32)p[0]; + } + } + ++*src; + --*srclen; + while (left > 0 && *srclen > 0) { + ++p; + if ((p[0] & 0xC0) != 0x80) { + ch = UNKNOWN_UNICODE; + break; + } + ch <<= 6; + ch |= (p[0] & 0x3F); + ++*src; + --*srclen; + --left; + } + if (left > 0) { + underflow = SDL_TRUE; + } + /* Technically overlong sequences are invalid and should not be interpreted. + However, it doesn't cause a security risk here and I don't see any harm in + displaying them. The application is responsible for any other side effects + of allowing overlong sequences (e.g. string compares failing, etc.) + See bug 1931 for sample input that triggers this. + */ + /*if (overlong) return UNKNOWN_UNICODE;*/ + if (underflow || + (ch >= 0xD800 && ch <= 0xDFFF) || + (ch == 0xFFFE || ch == 0xFFFF) || ch > 0x10FFFF) { + ch = UNKNOWN_UNICODE; + } + return ch; +} + +int TTF_FontHeight(const TTF_Font *font) +{ + return(font->height); +} + +int TTF_FontAscent(const TTF_Font *font) +{ + return(font->ascent); +} + +int TTF_FontDescent(const TTF_Font *font) +{ + return(font->descent); +} + +int TTF_FontLineSkip(const TTF_Font *font) +{ + return(font->lineskip); +} + +int TTF_GetFontKerning(const TTF_Font *font) +{ + return(font->kerning); +} + +void TTF_SetFontKerning(TTF_Font *font, int allowed) +{ + font->kerning = allowed; +} + +long TTF_FontFaces(const TTF_Font *font) +{ + return(font->face->num_faces); +} + +int TTF_FontFaceIsFixedWidth(const TTF_Font *font) +{ + return(FT_IS_FIXED_WIDTH(font->face)); +} + +char *TTF_FontFaceFamilyName(const TTF_Font *font) +{ + return(font->face->family_name); +} + +char *TTF_FontFaceStyleName(const TTF_Font *font) +{ + return(font->face->style_name); +} + +int TTF_GlyphIsProvided(const TTF_Font *font, codepoint_t ch) +{ + return(FT_Get_Char_Index(font->face, ch)); +} + +int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, + int* minx, int* maxx, int* miny, int* maxy, int* advance) +{ + FT_Error error; + + error = Find_Glyph(font, ch, CACHED_METRICS); + if (error) { + TTF_SetFTError("Couldn't find glyph", error); + return -1; + } + + if (minx) { + *minx = font->current->minx; + } + if (maxx) { + *maxx = font->current->maxx; + if (TTF_HANDLE_STYLE_BOLD(font)) { + *maxx += font->glyph_overhang; + } + } + if (miny) { + *miny = font->current->miny; + } + if (maxy) { + *maxy = font->current->maxy; + } + if (advance) { + *advance = font->current->advance; + if (TTF_HANDLE_STYLE_BOLD(font)) { + *advance += font->glyph_overhang; + } + } + return 0; +} + +int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h) +{ + int status = -1; + Uint8 *utf8; + + TTF_CHECKPOINTER(text, -1); + + utf8 = SDL_stack_alloc(Uint8, SDL_strlen(text) * 2 + 1); + if (utf8) { + LATIN1_to_UTF8(text, utf8); + status = TTF_SizeUTF8(font, (char *)utf8, w, h); + SDL_stack_free(utf8); + } + else { + SDL_OutOfMemory(); + } + return status; +} + +int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) +{ + int status; + int x, z; + int minx, maxx; + int miny, maxy; + c_glyph *glyph; + FT_Error error; + FT_Long use_kerning; + FT_UInt prev_index = 0; + int outline_delta = 0; + size_t textlen; + + TTF_CHECKPOINTER(text, -1); + + /* Initialize everything to 0 */ + status = 0; + minx = maxx = 0; + miny = maxy = 0; + + /* check kerning */ + use_kerning = FT_HAS_KERNING(font->face) && font->kerning; + + /* Init outline handling */ + if (font->outline > 0) { + outline_delta = font->outline * 2; + } + + /* Load each character and sum it's bounding box */ + textlen = SDL_strlen(text); + x = 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); + if (error) { + TTF_SetFTError("Couldn't find glyph", error); + return -1; + } + glyph = font->current; + + /* handle kerning */ + if (use_kerning && prev_index && glyph->index) { + FT_Vector delta; + FT_Get_Kerning(font->face, prev_index, glyph->index, ft_kerning_default, &delta); + x += delta.x >> 6; + } + +#if 0 + if ((ch == text) && (glyph->minx < 0)) { + /* Fixes the texture wrapping bug when the first letter + * has a negative minx value or horibearing value. The entire + * bounding box must be adjusted to be bigger so the entire + * letter can fit without any texture corruption or wrapping. + * + * Effects: First enlarges bounding box. + * Second, xstart has to start ahead of its normal spot in the + * negative direction of the negative minx value. + * (pushes everything to the right). + * + * This will make the memory copy of the glyph bitmap data + * work out correctly. + * */ + z -= glyph->minx; + } +#endif + + z = x + glyph->minx; + if (minx > z) { + minx = z; + } + if (TTF_HANDLE_STYLE_BOLD(font)) { + x += font->glyph_overhang; + } + if (glyph->advance > glyph->maxx) { + z = x + glyph->advance; + } + else { + z = x + glyph->maxx; + } + if (maxx < z) { + maxx = z; + } + x += glyph->advance; + + if (glyph->miny < miny) { + miny = glyph->miny; + } + if (glyph->maxy > maxy) { + maxy = glyph->maxy; + } + prev_index = glyph->index; + } + + /* Fill the bounds rectangle */ + if (w) { + /* Add outline extra width */ + *w = (maxx - minx) + outline_delta; + } + if (h) { + /* Some fonts descend below font height (FletcherGothicFLF) */ + /* Add outline extra height */ + *h = (font->ascent - miny) + outline_delta; + if (*h < font->height) { + *h = font->height; + } + /* Update height according to the needs of the underline style */ + if (TTF_HANDLE_STYLE_UNDERLINE(font)) { + int bottom_row = TTF_underline_bottom_row(font); + if (*h < bottom_row) { + *h = bottom_row; + } + } + } + return status; +} + +int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h) +{ + int status = -1; + Uint8 *utf8; + + TTF_CHECKPOINTER(text, -1); + + utf8 = SDL_stack_alloc(Uint8, UCS2_len(text) * 3 + 1); + if (utf8) { + UCS2_to_UTF8(text, utf8); + status = TTF_SizeUTF8(font, (char *)utf8, w, h); + SDL_stack_free(utf8); + } + else { + SDL_OutOfMemory(); + } + return status; +} + +TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, + const char *text, uint32 colour) +{ + SDL_bool first; + int xstart; + int width; + int height; + TTFSurface* textbuf; + Uint8* src; + Uint8* dst; + Uint8 *dst_check; + int row, col; + c_glyph *glyph; + + FT_Bitmap *current; + 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 = SDL_strlen(text); + first = SDL_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_BITMAP); + if (error) { + TTF_SetFTError("Couldn't find glyph", error); + ttf_free_surface(textbuf); + return NULL; + } + glyph = font->current; + current = &glyph->bitmap; + /* Ensure the width of the pixmap is correct. On some cases, + * freetype may report a larger pixmap than possible.*/ + width = current->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 wrap around bug with negative minx's */ + if (first && (glyph->minx < 0)) { + xstart -= glyph->minx; + } + first = SDL_FALSE; + + 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_Solid(font, textbuf, row); + } + + /* Handle the strikethrough style */ + if (TTF_HANDLE_STYLE_STRIKETHROUGH(font)) { + row = TTF_strikethrough_top_row(font); + TTF_drawLine_Solid(font, textbuf, row); + } + return textbuf; +} + +static SDL_bool CharacterIsDelimiter(char c, const char *delimiters) +{ + while (*delimiters) { + if (c == *delimiters) { + return SDL_TRUE; + } + ++delimiters; + } + return SDL_FALSE; +} + +void TTF_SetFontStyle(TTF_Font* font, int style) +{ + int prev_style = font->style; + font->style = style | font->face_style; + + /* Flush the cache if the style has changed. + * Ignore UNDERLINE which does not impact glyph drawning. + * */ + if ((font->style | TTF_STYLE_NO_GLYPH_CHANGE) != (prev_style | TTF_STYLE_NO_GLYPH_CHANGE)) { + Flush_Cache(font); + } +} + +int TTF_GetFontStyle(const TTF_Font* font) +{ + return font->style; +} + +void TTF_SetFontOutline(TTF_Font* font, int outline) +{ + font->outline = outline; + Flush_Cache(font); +} + +int TTF_GetFontOutline(const TTF_Font* font) +{ + return font->outline; +} + +void TTF_SetFontHinting(TTF_Font* font, int hinting) +{ + if (hinting == TTF_HINTING_LIGHT) + font->hinting = FT_LOAD_TARGET_LIGHT; + else if (hinting == TTF_HINTING_MONO) + font->hinting = FT_LOAD_TARGET_MONO; + else if (hinting == TTF_HINTING_NONE) + font->hinting = FT_LOAD_NO_HINTING; + else + font->hinting = 0; + + Flush_Cache(font); +} + +int TTF_GetFontHinting(const TTF_Font* font) +{ + if (font->hinting == FT_LOAD_TARGET_LIGHT) + return TTF_HINTING_LIGHT; + else if (font->hinting == FT_LOAD_TARGET_MONO) + return TTF_HINTING_MONO; + else if (font->hinting == FT_LOAD_NO_HINTING) + return TTF_HINTING_NONE; + return 0; +} + +void TTF_Quit(void) +{ + if (TTF_initialized) { + if (--TTF_initialized == 0) { + FT_Done_FreeType(library); + } + } +} + +int TTF_WasInit(void) +{ + return TTF_initialized; +} + +/* don't use this function. It's just here for binary compatibility. */ +int TTF_GetFontKerningSize(TTF_Font* font, int prev_index, int index) +{ + FT_Vector delta; + FT_Get_Kerning(font->face, prev_index, index, ft_kerning_default, &delta); + return (delta.x >> 6); +} + +int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint16 previous_ch, Uint16 ch) +{ + int error; + int glyph_index, prev_index; + FT_Vector delta; + + if (ch == UNICODE_BOM_NATIVE || ch == UNICODE_BOM_SWAPPED) { + return 0; + } + + if (previous_ch == UNICODE_BOM_NATIVE || previous_ch == UNICODE_BOM_SWAPPED) { + return 0; + } + + error = Find_Glyph(font, ch, CACHED_METRICS); + if (error) { + TTF_SetFTError("Couldn't find glyph", error); + return -1; + } + glyph_index = font->current->index; + + error = Find_Glyph(font, previous_ch, CACHED_METRICS); + if (error) { + TTF_SetFTError("Couldn't find glyph", error); + return -1; + } + prev_index = font->current->index; + + error = FT_Get_Kerning(font->face, prev_index, glyph_index, ft_kerning_default, &delta); + if (error) { + TTF_SetFTError("Couldn't get glyph kerning", error); + return -1; + } + return (delta.x >> 6); +} From 8046cbc70734ebc8a5074684f559a523bc0a4c09 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 24 Jun 2017 23:22:42 +0100 Subject: [PATCH 04/10] Replace SDL2 calls --- src/openrct2/drawing/ttf_sdlport.c | 231 +++++++++++++---------------- 1 file changed, 103 insertions(+), 128 deletions(-) diff --git a/src/openrct2/drawing/ttf_sdlport.c b/src/openrct2/drawing/ttf_sdlport.c index 687af95ec7..aa968840d9 100644 --- a/src/openrct2/drawing/ttf_sdlport.c +++ b/src/openrct2/drawing/ttf_sdlport.c @@ -1,3 +1,9 @@ +/** + * The following code is from SDL2_ttf (2 Jan 2017). + * Taking just what was needed for OpenRCT2 with all SDL2 calls + * removed. + */ + /* SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts Copyright (C) 2001-2017 Sam Lantinga @@ -31,9 +37,6 @@ misrepresented as being the original software. #include FT_GLYPH_H #include FT_TRUETYPE_IDS_H -#include "SDL.h" -#include "SDL_endian.h" - #include "ttf.h" #pragma warning(disable : 4018) // '<': signed / unsigned mismatch @@ -80,7 +83,7 @@ typedef struct cached_glyph { int maxy; int yoffset; int advance; - Uint16 cached; + uint16 cached; } c_glyph; /* The structure used to hold internal font information */ @@ -115,7 +118,7 @@ struct _TTF_Font { c_glyph cache[257]; /* 257 is a prime */ /* We are responsible for closing the font stream */ - SDL_RWops *src; + FILE *src; int freesrc; FT_Open_Args args; @@ -142,7 +145,7 @@ static FT_Library library; static int TTF_initialized = 0; static int TTF_byteswapped = 0; -#define TTF_SetError SDL_SetError +#define TTF_SetError log_error #define TTF_CHECKPOINTER(p, errval) \ if ( !TTF_initialized ) { \ @@ -218,12 +221,12 @@ static int TTF_Glyph_strikethrough_top_row(TTF_Font *font, c_glyph *glyph) return TTF_strikethrough_top_row(font) - font->ascent + glyph->maxy; } -static void TTF_initLineMectrics(const TTF_Font *font, const TTFSurface *textbuf, const int row, Uint8 **pdst, int *pheight) +static void TTF_initLineMectrics(const TTF_Font *font, const TTFSurface *textbuf, const int row, uint8 **pdst, int *pheight) { - Uint8 *dst; + uint8 *dst; int height; - dst = (Uint8 *)textbuf->pixels; + dst = (uint8 *)textbuf->pixels; if (row > 0) { dst += row * textbuf->pitch; } @@ -244,8 +247,8 @@ outline into account. static void TTF_drawLine_Solid(const TTF_Font *font, const TTFSurface *textbuf, const int row) { int line; - Uint8 *dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; - Uint8 *dst; + uint8 *dst_check = (uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; + uint8 *dst; int height; TTF_initLineMectrics(font, textbuf, row, &dst, &height); @@ -323,17 +326,26 @@ static unsigned long RWread( unsigned long count ) { - SDL_RWops *src; + FILE *src; - src = (SDL_RWops *)stream->descriptor.pointer; - SDL_RWseek(src, (int)offset, RW_SEEK_SET); + src = (FILE *)stream->descriptor.pointer; + fseek(src, (int)offset, SEEK_SET); if (count == 0) { return 0; } - return (unsigned long)SDL_RWread(src, buffer, 1, (int)count); + return (unsigned long)fread(buffer, 1, (int)count, src); } -TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index) +static size_t fsize(FILE * file) +{ + size_t origPos = ftell(file); + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + fseek(file, (long)origPos, SEEK_SET); + return size; +} + +TTF_Font* TTF_OpenFontIndexRW(FILE *src, int freesrc, int ptsize, long index) { TTF_Font* font; FT_Error error; @@ -341,13 +353,13 @@ TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long inde FT_Fixed scale; FT_Stream stream; FT_CharMap found; - Sint64 position; + sint64 position; int i; if (!TTF_initialized) { TTF_SetError("Library not initialized"); if (src && freesrc) { - SDL_RWclose(src); + fclose(src); } return NULL; } @@ -358,40 +370,40 @@ TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long inde } /* Check to make sure we can seek in this stream */ - position = SDL_RWtell(src); + position = ftell(src); if (position < 0) { TTF_SetError("Can't seek in stream"); if (freesrc) { - SDL_RWclose(src); + fclose(src); } return NULL; } - font = (TTF_Font*)SDL_malloc(sizeof *font); + font = (TTF_Font*)malloc(sizeof *font); if (font == NULL) { TTF_SetError("Out of memory"); if (freesrc) { - SDL_RWclose(src); + fclose(src); } return NULL; } - SDL_memset(font, 0, sizeof(*font)); + memset(font, 0, sizeof(*font)); font->src = src; font->freesrc = freesrc; - stream = (FT_Stream)SDL_malloc(sizeof(*stream)); + stream = (FT_Stream)malloc(sizeof(*stream)); if (stream == NULL) { TTF_SetError("Out of memory"); TTF_CloseFont(font); return NULL; } - SDL_memset(stream, 0, sizeof(*stream)); + memset(stream, 0, sizeof(*stream)); stream->read = RWread; stream->descriptor.pointer = src; stream->pos = (unsigned long)position; - stream->size = (unsigned long)(SDL_RWsize(src) - position); + stream->size = (unsigned long)(fsize(src) - position); font->args.flags = FT_OPEN_STREAM; font->args.stream = stream; @@ -503,14 +515,14 @@ TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long inde return font; } -TTF_Font* TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize) +TTF_Font* TTF_OpenFontRW(FILE *src, int freesrc, int ptsize) { return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0); } TTF_Font* TTF_OpenFontIndex(const char *file, int ptsize, long index) { - SDL_RWops *rw = SDL_RWFromFile(file, "rb"); + FILE *rw = fopen(file, "rb"); if (rw == NULL) { return NULL; } @@ -527,11 +539,11 @@ static void Flush_Glyph(c_glyph* glyph) glyph->stored = 0; glyph->index = 0; if (glyph->bitmap.buffer) { - SDL_free(glyph->bitmap.buffer); + free(glyph->bitmap.buffer); glyph->bitmap.buffer = 0; } if (glyph->pixmap.buffer) { - SDL_free(glyph->pixmap.buffer); + free(glyph->pixmap.buffer); glyph->pixmap.buffer = 0; } glyph->cached = 0; @@ -550,7 +562,7 @@ static void Flush_Cache(TTF_Font* font) } } -static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) +static FT_Error Load_Glyph(TTF_Font* font, uint16 ch, c_glyph* cached, int want) { FT_Face face; FT_Error error; @@ -609,7 +621,7 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) cached->maxx += font->glyph_overhang; } if (TTF_HANDLE_STYLE_ITALIC(font)) { - cached->maxx += (int)SDL_ceil(font->glyph_italics); + cached->maxx += (int)ceil(font->glyph_italics); } cached->stored |= CACHED_METRICS; } @@ -668,7 +680,7 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) else { dst = &cached->pixmap; } - SDL_memcpy(dst, src, sizeof(*dst)); + memcpy(dst, src, sizeof(*dst)); /* FT_Render_Glyph() and .fon fonts always generate a * two-color (black and white) glyphslot surface, even @@ -697,17 +709,17 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) dst->width += bump; } if (TTF_HANDLE_STYLE_ITALIC(font)) { - int bump = (int)SDL_ceil(font->glyph_italics); + int bump = (int)ceil(font->glyph_italics); dst->pitch += bump; dst->width += bump; } if (dst->rows != 0) { - dst->buffer = (unsigned char *)SDL_malloc(dst->pitch * dst->rows); + dst->buffer = (unsigned char *)malloc(dst->pitch * dst->rows); if (!dst->buffer) { return FT_Err_Out_Of_Memory; } - SDL_memset(dst->buffer, 0, dst->pitch * dst->rows); + memset(dst->buffer, 0, dst->pitch * dst->rows); for (i = 0; i < src->rows; i++) { int soffset = i * src->pitch; @@ -827,7 +839,7 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) } } else { - SDL_memcpy(dst->buffer + doffset, + memcpy(dst->buffer + doffset, src->buffer + soffset, src->pitch); } } @@ -839,11 +851,11 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) int col; int offset; int pixel; - Uint8* pixmap; + uint8* pixmap; /* The pixmap is a little hard, we have to add and clamp */ for (row = dst->rows - 1; row >= 0; --row) { - pixmap = (Uint8*)dst->buffer + row * dst->pitch; + pixmap = (uint8*)dst->buffer + row * dst->pitch; for (offset = 1; offset <= font->glyph_overhang; ++offset) { for (col = dst->width - 1; col > 0; --col) { if (mono) { @@ -854,7 +866,7 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) if (pixel > NUM_GRAYS - 1) { pixel = NUM_GRAYS - 1; } - pixmap[col] = (Uint8)pixel; + pixmap[col] = (uint8)pixel; } } } @@ -881,7 +893,7 @@ static FT_Error Load_Glyph(TTF_Font* font, Uint16 ch, c_glyph* cached, int want) return 0; } -static FT_Error Find_Glyph(TTF_Font* font, Uint16 ch, int want) +static FT_Error Find_Glyph(TTF_Font* font, uint16 ch, int want) { int retval = 0; int hsize = sizeof(font->cache) / sizeof(font->cache[0]); @@ -906,17 +918,17 @@ void TTF_CloseFont(TTF_Font* font) FT_Done_Face(font->face); } if (font->args.stream) { - SDL_free(font->args.stream); + free(font->args.stream); } if (font->freesrc) { - SDL_RWclose(font->src); + fclose(font->src); } - SDL_free(font); + free(font); } } /* Gets the number of bytes used by a null terminated UCS2 string */ -static size_t UCS2_len(const Uint16 *text) +static size_t UCS2_len(const uint16 *text) { size_t count = 0; while (*text++) { @@ -926,10 +938,10 @@ static size_t UCS2_len(const Uint16 *text) } /* Convert a Latin-1 string to a UTF-8 string */ -static void LATIN1_to_UTF8(const char *src, Uint8 *dst) +static void LATIN1_to_UTF8(const char *src, uint8 *dst) { while (*src) { - Uint8 ch = *(Uint8*)src++; + uint8 ch = *(uint8*)src++; if (ch <= 0x7F) { *dst++ = ch; } @@ -942,12 +954,12 @@ static void LATIN1_to_UTF8(const char *src, Uint8 *dst) } /* Convert a UCS-2 string to a UTF-8 string */ -static void UCS2_to_UTF8(const Uint16 *src, Uint8 *dst) +static void UCS2_to_UTF8(const uint16 *src, uint8 *dst) { int swapped = TTF_byteswapped; while (*src) { - Uint16 ch = *(Uint16*)src++; + uint16 ch = *(uint16*)src++; if (ch == UNICODE_BOM_NATIVE) { swapped = 0; continue; @@ -957,19 +969,20 @@ static void UCS2_to_UTF8(const Uint16 *src, Uint8 *dst) continue; } if (swapped) { - ch = SDL_Swap16(ch); + ch = (ch & 0xFF) << 8 || + ((ch & 0xFF00) >> 8); } if (ch <= 0x7F) { - *dst++ = (Uint8)ch; + *dst++ = (uint8)ch; } else if (ch <= 0x7FF) { - *dst++ = 0xC0 | (Uint8)((ch >> 6) & 0x1F); - *dst++ = 0x80 | (Uint8)(ch & 0x3F); + *dst++ = 0xC0 | (uint8)((ch >> 6) & 0x1F); + *dst++ = 0x80 | (uint8)(ch & 0x3F); } else { - *dst++ = 0xE0 | (Uint8)((ch >> 12) & 0x0F); - *dst++ = 0x80 | (Uint8)((ch >> 6) & 0x3F); - *dst++ = 0x80 | (Uint8)(ch & 0x3F); + *dst++ = 0xE0 | (uint8)((ch >> 12) & 0x0F); + *dst++ = 0x80 | (uint8)((ch >> 6) & 0x3F); + *dst++ = 0x80 | (uint8)(ch & 0x3F); } } *dst = '\0'; @@ -977,13 +990,13 @@ static void UCS2_to_UTF8(const Uint16 *src, Uint8 *dst) /* Gets a unicode value from a UTF-8 encoded string and advance the string */ #define UNKNOWN_UNICODE 0xFFFD -static Uint32 UTF8_getch(const char **src, size_t *srclen) +static uint32 UTF8_getch(const char **src, size_t *srclen) { - const Uint8 *p = *(const Uint8**)src; + const uint8 *p = *(const uint8**)src; size_t left = 0; - SDL_bool overlong = SDL_FALSE; - SDL_bool underflow = SDL_FALSE; - Uint32 ch = UNKNOWN_UNICODE; + bool overlong = false; + bool underflow = false; + uint32 ch = UNKNOWN_UNICODE; if (*srclen == 0) { return UNKNOWN_UNICODE; @@ -991,51 +1004,51 @@ static Uint32 UTF8_getch(const char **src, size_t *srclen) if (p[0] >= 0xFC) { if ((p[0] & 0xFE) == 0xFC) { if (p[0] == 0xFC && (p[1] & 0xFC) == 0x80) { - overlong = SDL_TRUE; + overlong = true; } - ch = (Uint32)(p[0] & 0x01); + ch = (uint32)(p[0] & 0x01); left = 5; } } else if (p[0] >= 0xF8) { if ((p[0] & 0xFC) == 0xF8) { if (p[0] == 0xF8 && (p[1] & 0xF8) == 0x80) { - overlong = SDL_TRUE; + overlong = true; } - ch = (Uint32)(p[0] & 0x03); + ch = (uint32)(p[0] & 0x03); left = 4; } } else if (p[0] >= 0xF0) { if ((p[0] & 0xF8) == 0xF0) { if (p[0] == 0xF0 && (p[1] & 0xF0) == 0x80) { - overlong = SDL_TRUE; + overlong = true; } - ch = (Uint32)(p[0] & 0x07); + ch = (uint32)(p[0] & 0x07); left = 3; } } else if (p[0] >= 0xE0) { if ((p[0] & 0xF0) == 0xE0) { if (p[0] == 0xE0 && (p[1] & 0xE0) == 0x80) { - overlong = SDL_TRUE; + overlong = true; } - ch = (Uint32)(p[0] & 0x0F); + ch = (uint32)(p[0] & 0x0F); left = 2; } } else if (p[0] >= 0xC0) { if ((p[0] & 0xE0) == 0xC0) { if ((p[0] & 0xDE) == 0xC0) { - overlong = SDL_TRUE; + overlong = true; } - ch = (Uint32)(p[0] & 0x1F); + ch = (uint32)(p[0] & 0x1F); left = 1; } } else { if ((p[0] & 0x80) == 0x00) { - ch = (Uint32)p[0]; + ch = (uint32)p[0]; } } ++*src; @@ -1053,7 +1066,7 @@ static Uint32 UTF8_getch(const char **src, size_t *srclen) --left; } if (left > 0) { - underflow = SDL_TRUE; + underflow = true; } /* Technically overlong sequences are invalid and should not be interpreted. However, it doesn't cause a security risk here and I don't see any harm in @@ -1125,7 +1138,7 @@ int TTF_GlyphIsProvided(const TTF_Font *font, codepoint_t ch) return(FT_Get_Char_Index(font->face, ch)); } -int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, +int TTF_GlyphMetrics(TTF_Font *font, uint16 ch, int* minx, int* maxx, int* miny, int* maxy, int* advance) { FT_Error error; @@ -1160,25 +1173,6 @@ int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, return 0; } -int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h) -{ - int status = -1; - Uint8 *utf8; - - TTF_CHECKPOINTER(text, -1); - - utf8 = SDL_stack_alloc(Uint8, SDL_strlen(text) * 2 + 1); - if (utf8) { - LATIN1_to_UTF8(text, utf8); - status = TTF_SizeUTF8(font, (char *)utf8, w, h); - SDL_stack_free(utf8); - } - else { - SDL_OutOfMemory(); - } - return status; -} - int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) { int status; @@ -1208,10 +1202,10 @@ int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) } /* Load each character and sum it's bounding box */ - textlen = SDL_strlen(text); + textlen = strlen(text); x = 0; while (textlen > 0) { - Uint16 c = UTF8_getch(&text, &textlen); + uint16 c = UTF8_getch(&text, &textlen); if (c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED) { continue; } @@ -1299,36 +1293,17 @@ int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) return status; } -int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h) -{ - int status = -1; - Uint8 *utf8; - - TTF_CHECKPOINTER(text, -1); - - utf8 = SDL_stack_alloc(Uint8, UCS2_len(text) * 3 + 1); - if (utf8) { - UCS2_to_UTF8(text, utf8); - status = TTF_SizeUTF8(font, (char *)utf8, w, h); - SDL_stack_free(utf8); - } - else { - SDL_OutOfMemory(); - } - return status; -} - TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, const char *text, uint32 colour) { - SDL_bool first; + bool first; int xstart; int width; int height; TTFSurface* textbuf; - Uint8* src; - Uint8* dst; - Uint8 *dst_check; + uint8* src; + uint8* dst; + uint8 *dst_check; int row, col; c_glyph *glyph; @@ -1358,17 +1333,17 @@ TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, /* Adding bound checking to avoid all kinds of memory corruption errors that may occur. */ - dst_check = (Uint8*)textbuf->pixels + textbuf->pitch * textbuf->h; + 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 = SDL_strlen(text); - first = SDL_TRUE; + textlen = strlen(text); + first = true; xstart = 0; while (textlen > 0) { - Uint16 c = UTF8_getch(&text, &textlen); + uint16 c = UTF8_getch(&text, &textlen); if (c == UNICODE_BOM_NATIVE || c == UNICODE_BOM_SWAPPED) { continue; } @@ -1397,7 +1372,7 @@ TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, if (first && (glyph->minx < 0)) { xstart -= glyph->minx; } - first = SDL_FALSE; + first = false; for (row = 0; row < current->rows; ++row) { /* Make sure we don't go either over, or under the @@ -1408,7 +1383,7 @@ TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, if (row + glyph->yoffset >= textbuf->h) { continue; } - dst = (Uint8*)textbuf->pixels + + dst = (uint8*)textbuf->pixels + (row + glyph->yoffset) * textbuf->pitch + xstart + glyph->minx; src = current->buffer + row * current->pitch; @@ -1439,15 +1414,15 @@ TTFSurface *TTF_RenderUTF8_Solid(TTF_Font *font, return textbuf; } -static SDL_bool CharacterIsDelimiter(char c, const char *delimiters) +static bool CharacterIsDelimiter(char c, const char *delimiters) { while (*delimiters) { if (c == *delimiters) { - return SDL_TRUE; + return true; } ++delimiters; } - return SDL_FALSE; + return false; } void TTF_SetFontStyle(TTF_Font* font, int style) @@ -1526,7 +1501,7 @@ int TTF_GetFontKerningSize(TTF_Font* font, int prev_index, int index) return (delta.x >> 6); } -int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint16 previous_ch, Uint16 ch) +int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, uint16 previous_ch, uint16 ch) { int error; int glyph_index, prev_index; From 16d6ddd22b78547c7672a1f9835a4f1128611dd4 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 24 Jun 2017 23:40:46 +0100 Subject: [PATCH 05/10] Remove unused code from SDL_ttf --- src/openrct2/drawing/ttf_sdlport.c | 266 +---------------------------- 1 file changed, 4 insertions(+), 262 deletions(-) diff --git a/src/openrct2/drawing/ttf_sdlport.c b/src/openrct2/drawing/ttf_sdlport.c index aa968840d9..e070bd95a4 100644 --- a/src/openrct2/drawing/ttf_sdlport.c +++ b/src/openrct2/drawing/ttf_sdlport.c @@ -143,7 +143,6 @@ struct _TTF_Font { /* The FreeType font engine/library */ static FT_Library library; static int TTF_initialized = 0; -static int TTF_byteswapped = 0; #define TTF_SetError log_error @@ -261,15 +260,6 @@ static void TTF_drawLine_Solid(const TTF_Font *font, const TTFSurface *textbuf, } } -/* This function tells the library whether UNICODE text is generally -byteswapped. A UNICODE BOM character at the beginning of a string -will override this setting for that string. -*/ -void TTF_ByteSwappedUNICODE(int swapped) -{ - TTF_byteswapped = swapped; -} - static void TTF_SetFTError(const char *msg, FT_Error error) { #ifdef USE_FREETYPE_ERRORS @@ -345,7 +335,7 @@ static size_t fsize(FILE * file) return size; } -TTF_Font* TTF_OpenFontIndexRW(FILE *src, int freesrc, int ptsize, long index) +static TTF_Font* TTF_OpenFontIndexRW(FILE *src, int freesrc, int ptsize, long index) { TTF_Font* font; FT_Error error; @@ -515,12 +505,12 @@ TTF_Font* TTF_OpenFontIndexRW(FILE *src, int freesrc, int ptsize, long index) return font; } -TTF_Font* TTF_OpenFontRW(FILE *src, int freesrc, int ptsize) +static TTF_Font* TTF_OpenFontRW(FILE *src, int freesrc, int ptsize) { return TTF_OpenFontIndexRW(src, freesrc, ptsize, 0); } -TTF_Font* TTF_OpenFontIndex(const char *file, int ptsize, long index) +static TTF_Font* TTF_OpenFontIndex(const char *file, int ptsize, long index) { FILE *rw = fopen(file, "rb"); if (rw == NULL) { @@ -927,67 +917,6 @@ void TTF_CloseFont(TTF_Font* font) } } -/* Gets the number of bytes used by a null terminated UCS2 string */ -static size_t UCS2_len(const uint16 *text) -{ - size_t count = 0; - while (*text++) { - ++count; - } - return count * sizeof(*text); -} - -/* Convert a Latin-1 string to a UTF-8 string */ -static void LATIN1_to_UTF8(const char *src, uint8 *dst) -{ - while (*src) { - uint8 ch = *(uint8*)src++; - if (ch <= 0x7F) { - *dst++ = ch; - } - else { - *dst++ = 0xC0 | ((ch >> 6) & 0x1F); - *dst++ = 0x80 | (ch & 0x3F); - } - } - *dst = '\0'; -} - -/* Convert a UCS-2 string to a UTF-8 string */ -static void UCS2_to_UTF8(const uint16 *src, uint8 *dst) -{ - int swapped = TTF_byteswapped; - - while (*src) { - uint16 ch = *(uint16*)src++; - if (ch == UNICODE_BOM_NATIVE) { - swapped = 0; - continue; - } - if (ch == UNICODE_BOM_SWAPPED) { - swapped = 1; - continue; - } - if (swapped) { - ch = (ch & 0xFF) << 8 || - ((ch & 0xFF00) >> 8); - } - if (ch <= 0x7F) { - *dst++ = (uint8)ch; - } - else if (ch <= 0x7FF) { - *dst++ = 0xC0 | (uint8)((ch >> 6) & 0x1F); - *dst++ = 0x80 | (uint8)(ch & 0x3F); - } - else { - *dst++ = 0xE0 | (uint8)((ch >> 12) & 0x0F); - *dst++ = 0x80 | (uint8)((ch >> 6) & 0x3F); - *dst++ = 0x80 | (uint8)(ch & 0x3F); - } - } - *dst = '\0'; -} - /* Gets a unicode value from a UTF-8 encoded string and advance the string */ #define UNKNOWN_UNICODE 0xFFFD static uint32 UTF8_getch(const char **src, size_t *srclen) @@ -995,6 +924,7 @@ static uint32 UTF8_getch(const char **src, size_t *srclen) const uint8 *p = *(const uint8**)src; size_t left = 0; bool overlong = false; + UNUSED(overlong); bool underflow = false; uint32 ch = UNKNOWN_UNICODE; @@ -1083,96 +1013,11 @@ static uint32 UTF8_getch(const char **src, size_t *srclen) return ch; } -int TTF_FontHeight(const TTF_Font *font) -{ - return(font->height); -} - -int TTF_FontAscent(const TTF_Font *font) -{ - return(font->ascent); -} - -int TTF_FontDescent(const TTF_Font *font) -{ - return(font->descent); -} - -int TTF_FontLineSkip(const TTF_Font *font) -{ - return(font->lineskip); -} - -int TTF_GetFontKerning(const TTF_Font *font) -{ - return(font->kerning); -} - -void TTF_SetFontKerning(TTF_Font *font, int allowed) -{ - font->kerning = allowed; -} - -long TTF_FontFaces(const TTF_Font *font) -{ - return(font->face->num_faces); -} - -int TTF_FontFaceIsFixedWidth(const TTF_Font *font) -{ - return(FT_IS_FIXED_WIDTH(font->face)); -} - -char *TTF_FontFaceFamilyName(const TTF_Font *font) -{ - return(font->face->family_name); -} - -char *TTF_FontFaceStyleName(const TTF_Font *font) -{ - return(font->face->style_name); -} - int TTF_GlyphIsProvided(const TTF_Font *font, codepoint_t ch) { return(FT_Get_Char_Index(font->face, ch)); } -int TTF_GlyphMetrics(TTF_Font *font, uint16 ch, - int* minx, int* maxx, int* miny, int* maxy, int* advance) -{ - FT_Error error; - - error = Find_Glyph(font, ch, CACHED_METRICS); - if (error) { - TTF_SetFTError("Couldn't find glyph", error); - return -1; - } - - if (minx) { - *minx = font->current->minx; - } - if (maxx) { - *maxx = font->current->maxx; - if (TTF_HANDLE_STYLE_BOLD(font)) { - *maxx += font->glyph_overhang; - } - } - if (miny) { - *miny = font->current->miny; - } - if (maxy) { - *maxy = font->current->maxy; - } - if (advance) { - *advance = font->current->advance; - if (TTF_HANDLE_STYLE_BOLD(font)) { - *advance += font->glyph_overhang; - } - } - return 0; -} - int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h) { int status; @@ -1425,60 +1270,6 @@ static bool CharacterIsDelimiter(char c, const char *delimiters) return false; } -void TTF_SetFontStyle(TTF_Font* font, int style) -{ - int prev_style = font->style; - font->style = style | font->face_style; - - /* Flush the cache if the style has changed. - * Ignore UNDERLINE which does not impact glyph drawning. - * */ - if ((font->style | TTF_STYLE_NO_GLYPH_CHANGE) != (prev_style | TTF_STYLE_NO_GLYPH_CHANGE)) { - Flush_Cache(font); - } -} - -int TTF_GetFontStyle(const TTF_Font* font) -{ - return font->style; -} - -void TTF_SetFontOutline(TTF_Font* font, int outline) -{ - font->outline = outline; - Flush_Cache(font); -} - -int TTF_GetFontOutline(const TTF_Font* font) -{ - return font->outline; -} - -void TTF_SetFontHinting(TTF_Font* font, int hinting) -{ - if (hinting == TTF_HINTING_LIGHT) - font->hinting = FT_LOAD_TARGET_LIGHT; - else if (hinting == TTF_HINTING_MONO) - font->hinting = FT_LOAD_TARGET_MONO; - else if (hinting == TTF_HINTING_NONE) - font->hinting = FT_LOAD_NO_HINTING; - else - font->hinting = 0; - - Flush_Cache(font); -} - -int TTF_GetFontHinting(const TTF_Font* font) -{ - if (font->hinting == FT_LOAD_TARGET_LIGHT) - return TTF_HINTING_LIGHT; - else if (font->hinting == FT_LOAD_TARGET_MONO) - return TTF_HINTING_MONO; - else if (font->hinting == FT_LOAD_NO_HINTING) - return TTF_HINTING_NONE; - return 0; -} - void TTF_Quit(void) { if (TTF_initialized) { @@ -1487,52 +1278,3 @@ void TTF_Quit(void) } } } - -int TTF_WasInit(void) -{ - return TTF_initialized; -} - -/* don't use this function. It's just here for binary compatibility. */ -int TTF_GetFontKerningSize(TTF_Font* font, int prev_index, int index) -{ - FT_Vector delta; - FT_Get_Kerning(font->face, prev_index, index, ft_kerning_default, &delta); - return (delta.x >> 6); -} - -int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, uint16 previous_ch, uint16 ch) -{ - int error; - int glyph_index, prev_index; - FT_Vector delta; - - if (ch == UNICODE_BOM_NATIVE || ch == UNICODE_BOM_SWAPPED) { - return 0; - } - - if (previous_ch == UNICODE_BOM_NATIVE || previous_ch == UNICODE_BOM_SWAPPED) { - return 0; - } - - error = Find_Glyph(font, ch, CACHED_METRICS); - if (error) { - TTF_SetFTError("Couldn't find glyph", error); - return -1; - } - glyph_index = font->current->index; - - error = Find_Glyph(font, previous_ch, CACHED_METRICS); - if (error) { - TTF_SetFTError("Couldn't find glyph", error); - return -1; - } - prev_index = font->current->index; - - error = FT_Get_Kerning(font->face, prev_index, glyph_index, ft_kerning_default, &delta); - if (error) { - TTF_SetFTError("Couldn't get glyph kerning", error); - return -1; - } - return (delta.x >> 6); -} From 6368a29d398df2417984f40833bb8ab5015516ee Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 25 Jun 2017 00:18:08 +0100 Subject: [PATCH 06/10] Fix NO_TTF builds --- src/openrct2/drawing/string.c | 4 ++-- src/openrct2/drawing/ttf_sdlport.c | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/openrct2/drawing/string.c b/src/openrct2/drawing/string.c index 0ff2036830..bf2dc72051 100644 --- a/src/openrct2/drawing/string.c +++ b/src/openrct2/drawing/string.c @@ -688,8 +688,6 @@ typedef struct text_draw_info { const sint8 *y_offset; } text_draw_info; -#ifndef NO_TTF - static void ttf_draw_character_sprite(rct_drawpixelinfo *dpi, sint32 codepoint, text_draw_info *info) { sint32 characterWidth = font_sprite_get_codepoint_width(info->font_sprite_base, codepoint); @@ -719,6 +717,8 @@ static void ttf_draw_string_raw_sprite(rct_drawpixelinfo *dpi, const utf8 *text, }; } +#ifndef NO_TTF + static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info) { if (!ttf_initialise()) diff --git a/src/openrct2/drawing/ttf_sdlport.c b/src/openrct2/drawing/ttf_sdlport.c index e070bd95a4..5dc5c8f7e1 100644 --- a/src/openrct2/drawing/ttf_sdlport.c +++ b/src/openrct2/drawing/ttf_sdlport.c @@ -4,6 +4,8 @@ * removed. */ +#ifndef NO_TTF + /* SDL_ttf: A companion library to SDL for working with TrueType (tm) fonts Copyright (C) 2001-2017 Sam Lantinga @@ -1278,3 +1280,5 @@ void TTF_Quit(void) } } } + +#endif From 57ed3a8506d51b583a19f09943a95ef8be4679df Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 25 Jun 2017 01:25:28 +0100 Subject: [PATCH 07/10] Update VS dependencies to 12 which includes freetype headers --- openrct2.common.props | 2 +- openrct2.proj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openrct2.common.props b/openrct2.common.props index b4046c449c..7c315c9315 100644 --- a/openrct2.common.props +++ b/openrct2.common.props @@ -89,7 +89,7 @@ - $(SolutionDir)src;$(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\freetype;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(SolutionDir)lib\include\libzip;$(IncludePath) + $(SolutionDir)src;$(SolutionDir)lib\include;$(SolutionDir)lib\include\breakpad;$(SolutionDir)lib\include\libspeex;$(SolutionDir)lib\include\sdl;$(SolutionDir)lib\include\jansson;$(SolutionDir)lib\include\sdl_ttf;$(SolutionDir)lib\include\libpng;$(SolutionDir)lib\include\zlib;$(SolutionDir)lib\include\libzip;$(IncludePath) $(SolutionDir)lib;$(LibraryPath) diff --git a/openrct2.proj b/openrct2.proj index e240ae0756..21f0b7c118 100644 --- a/openrct2.proj +++ b/openrct2.proj @@ -21,7 +21,7 @@ 0.0.8 -$(GIT_BRANCH)-$(GIT_COMMIT_SHA1_SHORT) - 11 + 12 /D "OPENRCT2_BUILD_SERVER=\"$(BUILD_SERVER)\"" $(OPENRCT2_CL_ADDITIONALOPTIONS) @@ -64,7 +64,7 @@ $(RootDir).dependencies https://github.com/OpenRCT2/Dependencies/releases/download/v$(TargetLibsVersion)/openrct2-libs-vs2015.zip - f088adcd12450c2672f78679ea5d1fbffc28fd22 + f845fe2fad0a1dece905c42ac4cfc1234ec447a7 1.8.0 https://github.com/google/googletest/archive/release-1.8.0.zip 667f873ab7a4d246062565fad32fb6d8e203ee73 From 1836515e3e4f827a58c220d552e9071770cf629f Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Sun, 25 Jun 2017 11:25:27 +0200 Subject: [PATCH 08/10] Add files to Xcode project --- OpenRCT2.xcodeproj/project.pbxproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index e45581d698..28f69a2c9f 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -26,6 +26,8 @@ 4C8B42721EEB1AE400F015CA /* HardwareDisplayDrawingEngine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B42711EEB1AE400F015CA /* HardwareDisplayDrawingEngine.cpp */; }; 4C8B42741EEB1B6F00F015CA /* Screenshot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C8B42731EEB1B6F00F015CA /* Screenshot.cpp */; }; 4CB832A71EFBDCCE00B88761 /* land_tool.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CB832A51EFBDCCE00B88761 /* land_tool.c */; }; + 4CB832AB1EFFB8D100B88761 /* ttf_sdlport.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CB832A81EFFB8D100B88761 /* ttf_sdlport.c */; }; + 4CB832AC1EFFB8D100B88761 /* ttf.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CB832A91EFFB8D100B88761 /* ttf.c */; }; C606CCBE1DB4054000FE4015 /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAB1DB4054000FE4015 /* compat.c */; }; C606CCBF1DB4054000FE4015 /* data.c in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAC1DB4054000FE4015 /* data.c */; }; C606CCC01DB4054000FE4015 /* FunctionCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C606CCAE1DB4054000FE4015 /* FunctionCall.cpp */; }; @@ -573,6 +575,9 @@ 4C8B42731EEB1B6F00F015CA /* Screenshot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Screenshot.cpp; sourceTree = ""; }; 4CB832A51EFBDCCE00B88761 /* land_tool.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = land_tool.c; sourceTree = ""; }; 4CB832A61EFBDCCE00B88761 /* land_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = land_tool.h; sourceTree = ""; }; + 4CB832A81EFFB8D100B88761 /* ttf_sdlport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ttf_sdlport.c; sourceTree = ""; }; + 4CB832A91EFFB8D100B88761 /* ttf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ttf.c; sourceTree = ""; }; + 4CB832AA1EFFB8D100B88761 /* ttf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ttf.h; sourceTree = ""; }; C606CCAB1DB4054000FE4015 /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = compat.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; C606CCAC1DB4054000FE4015 /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = data.c; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.c; }; C606CCAD1DB4054000FE4015 /* data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = data.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; @@ -1899,6 +1904,9 @@ F76C83AE1EC4E7CC00FA49E2 /* scrolling_text.c */, F76C83AF1EC4E7CC00FA49E2 /* sprite.cpp */, F76C83B01EC4E7CC00FA49E2 /* string.c */, + 4CB832A91EFFB8D100B88761 /* ttf.c */, + 4CB832AA1EFFB8D100B88761 /* ttf.h */, + 4CB832A81EFFB8D100B88761 /* ttf_sdlport.c */, 4C8B426E1EEB1ABD00F015CA /* X8DrawingEngine.cpp */, 4C8B426F1EEB1ABD00F015CA /* X8DrawingEngine.h */, ); @@ -2974,11 +2982,13 @@ 4C8B42741EEB1B6F00F015CA /* Screenshot.cpp in Sources */, F76C88781EC5324E00FA49E2 /* AudioChannel.cpp in Sources */, F76C88791EC5324E00FA49E2 /* AudioContext.cpp in Sources */, + 4CB832AC1EFFB8D100B88761 /* ttf.c in Sources */, 4C8B42721EEB1AE400F015CA /* HardwareDisplayDrawingEngine.cpp in Sources */, F76C887A1EC5324E00FA49E2 /* AudioMixer.cpp in Sources */, F76C887B1EC5324E00FA49E2 /* FileAudioSource.cpp in Sources */, F7CB864D1EEDA1A80030C877 /* DummyWindowManager.cpp in Sources */, F76C887C1EC5324E00FA49E2 /* MemoryAudioSource.cpp in Sources */, + 4CB832AB1EFFB8D100B88761 /* ttf_sdlport.c in Sources */, F76C887D1EC5324E00FA49E2 /* CursorData.cpp in Sources */, 4CB832A71EFBDCCE00B88761 /* land_tool.c in Sources */, F7D7747F1EC61E5100BE6EBC /* UiContext.macOS.mm in Sources */, From be71553a1497bb75f6531a9632b6197461cce82e Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 25 Jun 2017 10:30:55 +0100 Subject: [PATCH 09/10] Update xcode dependencies --- OpenRCT2.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 28f69a2c9f..c13d95db2f 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -2823,7 +2823,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "version=\"11\"\nzipname=\"openrct2-libs-macos.zip\"\nliburl=\"https://github.com/OpenRCT2/Dependencies/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/libxc\" || ! -e \"${SRCROOT}/libversion\" || $(head -n 1 \"${SRCROOT}/libversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/libxc\" ]]; then rm -r \"${SRCROOT}/libxc\"; fi\nmkdir \"${SRCROOT}/libxc\"\n\ncurl -L -o \"${SRCROOT}/libxc/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/libxc\" \"${SRCROOT}/libxc/$zipname\"\nrm \"${SRCROOT}/libxc/$zipname\"\n\necho $version > \"${SRCROOT}/libversion\"\nfi"; + shellScript = "version=\"12\"\nzipname=\"openrct2-libs-macos.zip\"\nliburl=\"https://github.com/OpenRCT2/Dependencies/releases/download/v$version/$zipname\"\n\n[[ ! -d \"${SRCROOT}/libxc\" || ! -e \"${SRCROOT}/libversion\" || $(head -n 1 \"${SRCROOT}/libversion\") != $version ]]\noutdated=$?\n\nif [[ $outdated -eq 0 ]]; then\nif [[ -d \"${SRCROOT}/libxc\" ]]; then rm -r \"${SRCROOT}/libxc\"; fi\nmkdir \"${SRCROOT}/libxc\"\n\ncurl -L -o \"${SRCROOT}/libxc/$zipname\" \"$liburl\"\nunzip -uaq -d \"${SRCROOT}/libxc\" \"${SRCROOT}/libxc/$zipname\"\nrm \"${SRCROOT}/libxc/$zipname\"\n\necho $version > \"${SRCROOT}/libversion\"\nfi"; }; D42C09D21C254F4E00309751 /* Build g2.dat */ = { isa = PBXShellScriptBuildPhase; From 87e73d160e6e25ef09cdc6314c32f334da25c144 Mon Sep 17 00:00:00 2001 From: Marijn van der Werf Date: Sun, 25 Jun 2017 11:56:17 +0200 Subject: [PATCH 10/10] Update Xcode project --- OpenRCT2.xcodeproj/project.pbxproj | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index c13d95db2f..2b5311724e 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -58,6 +58,7 @@ C64FDAA71D6D9A2100F259B9 /* boat_ride.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9031CDBC3B7009F9BFC /* boat_ride.c */; }; C64FDAA81D6D9A2100F259B9 /* dingy_slide.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9041CDBC3B7009F9BFC /* dingy_slide.c */; }; C64FDAA91D6D9A2100F259B9 /* log_flume.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9051CDBC3B7009F9BFC /* log_flume.c */; }; + C6CB94F21EFFBF860065888F /* libfreetype.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B41CF3006400659A24 /* libfreetype.dylib */; }; C6E96E361E0408B40076A04F /* libzip.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C6E96E351E0408B40076A04F /* libzip.dylib */; }; C6E96E371E040E040076A04F /* libzip.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C6E96E351E0408B40076A04F /* libzip.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; D41B73EF1C2101890080A7B9 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73EE1C2101890080A7B9 /* libcurl.tbd */; }; @@ -66,7 +67,6 @@ D43407E21D0E14CE00C2B3D4 /* shaders in Resources */ = {isa = PBXBuildFile; fileRef = D43407E11D0E14CE00C2B3D4 /* shaders */; }; D45A38BC1CF3006400659A24 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B31CF3006400659A24 /* libcrypto.dylib */; }; D45A38BE1CF3006400659A24 /* libjansson.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B51CF3006400659A24 /* libjansson.dylib */; }; - D45A38C01CF3006400659A24 /* libSDL2_ttf.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B71CF3006400659A24 /* libSDL2_ttf.dylib */; }; D45A38C11CF3006400659A24 /* libSDL2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B81CF3006400659A24 /* libSDL2.dylib */; }; D45A38C21CF3006400659A24 /* libspeexdsp.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B91CF3006400659A24 /* libspeexdsp.dylib */; }; D45A39591CF300AF00659A24 /* libcrypto.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B31CF3006400659A24 /* libcrypto.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -466,8 +466,6 @@ F7D7749B1EC6705F00BE6EBC /* libspeexdsp.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B91CF3006400659A24 /* libspeexdsp.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; F7D7749C1EC6705F00BE6EBC /* libzip.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C6E96E351E0408B40076A04F /* libzip.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; F7D7749E1EC6713200BE6EBC /* Cli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F76C857D1EC4E80E00FA49E2 /* Cli.cpp */; }; - F7D7749F1EC6714C00BE6EBC /* libSDL2_ttf.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B71CF3006400659A24 /* libSDL2_ttf.dylib */; }; - F7D774A01EC6714C00BE6EBC /* libSDL2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B81CF3006400659A24 /* libSDL2.dylib */; }; F7D774A11EC6715C00BE6EBC /* libSDL2_ttf.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B71CF3006400659A24 /* libSDL2_ttf.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; F7D774A21EC6715C00BE6EBC /* libSDL2.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D45A38B81CF3006400659A24 /* libSDL2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; F7D774AC1EC6741D00BE6EBC /* language in CopyFiles */ = {isa = PBXBuildFile; fileRef = D4EC48E41C2637710024B507 /* language */; }; @@ -1378,7 +1376,7 @@ D45A38BE1CF3006400659A24 /* libjansson.dylib in Frameworks */, D4A8B4B41DB41873007A2F29 /* libpng16.dylib in Frameworks */, D45A38C11CF3006400659A24 /* libSDL2.dylib in Frameworks */, - D45A38C01CF3006400659A24 /* libSDL2_ttf.dylib in Frameworks */, + C6CB94F21EFFBF860065888F /* libfreetype.dylib in Frameworks */, D45A38C21CF3006400659A24 /* libspeexdsp.dylib in Frameworks */, C6E96E361E0408B40076A04F /* libzip.dylib in Frameworks */, ); @@ -1396,8 +1394,6 @@ F7D774921EC66FBA00BE6EBC /* libfreetype.dylib in Frameworks */, F7D774931EC66FBA00BE6EBC /* libjansson.dylib in Frameworks */, F7D774941EC66FBA00BE6EBC /* libpng16.dylib in Frameworks */, - F7D774A01EC6714C00BE6EBC /* libSDL2.dylib in Frameworks */, - F7D7749F1EC6714C00BE6EBC /* libSDL2_ttf.dylib in Frameworks */, F7D774951EC66FBA00BE6EBC /* libspeexdsp.dylib in Frameworks */, F7D774961EC66FBA00BE6EBC /* libzip.dylib in Frameworks */, );