mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-17 20:13:07 +01:00
implement utf8, part 13
This commit is contained in:
@@ -34,6 +34,33 @@ static int _ttfFontOffsetY = 0;
|
||||
|
||||
static const int TTFFontSizes[] = { 7, 9, 11, 13 };
|
||||
|
||||
#define TTF_SURFACE_CACHE_SIZE 256
|
||||
#define TTF_GETWIDTH_CACHE_SIZE 1024
|
||||
|
||||
typedef struct {
|
||||
SDL_Surface *surface;
|
||||
TTF_Font *font;
|
||||
utf8 *text;
|
||||
uint32 lastUseTick;
|
||||
} ttf_cache_entry;
|
||||
|
||||
static ttf_cache_entry _ttfSurfaceCache[TTF_SURFACE_CACHE_SIZE] = { 0 };
|
||||
static int _ttfSurfaceCacheCount = 0;
|
||||
static int _ttfSurfaceCacheHitCount = 0;
|
||||
static int _ttfSurfaceCacheMissCount = 0;
|
||||
|
||||
typedef struct {
|
||||
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 int _ttfGetWidthCacheCount = 0;
|
||||
static int _ttfGetWidthCacheHitCount = 0;
|
||||
static int _ttfGetWidthCacheMissCount = 0;
|
||||
|
||||
enum {
|
||||
FONT_SIZE_TINY = 2,
|
||||
FONT_SIZE_SMALL = 0,
|
||||
@@ -746,6 +773,144 @@ void sub_6C1F57(rct_drawpixelinfo *dpi, int x, int y, int width, int colour, rct
|
||||
);
|
||||
}
|
||||
|
||||
static uint32 _ttf_surface_cache_hash(TTF_Font *font, const utf8 *text)
|
||||
{
|
||||
uint32 hash = ((uint32)font * 23) ^ 0xAAAAAAAA;
|
||||
for (const uint8 *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 (int i = 0; i < TTF_SURFACE_CACHE_SIZE; i++) {
|
||||
_ttf_surface_cache_dispose(&_ttfSurfaceCache[i]);
|
||||
_ttfSurfaceCacheCount--;
|
||||
}
|
||||
}
|
||||
|
||||
static 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);
|
||||
int index = hash % TTF_SURFACE_CACHE_SIZE;
|
||||
for (int 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 (int 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);
|
||||
int index = hash % TTF_GETWIDTH_CACHE_SIZE;
|
||||
for (int 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);
|
||||
|
||||
int 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) {
|
||||
@@ -774,6 +939,9 @@ void ttf_dispose()
|
||||
if (!_ttfInitialised)
|
||||
return;
|
||||
|
||||
_ttf_surface_cache_dispose_all();
|
||||
_ttf_getwidth_cache_dispose_all();
|
||||
|
||||
if (_ttfFont != NULL) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
TTF_CloseFont(_ttfFont[i]);
|
||||
@@ -785,6 +953,21 @@ void ttf_dispose()
|
||||
_ttfInitialised = false;
|
||||
}
|
||||
|
||||
TTF_Font *ttf_get_font_from_sprite_base(uint16 spriteBase)
|
||||
{
|
||||
switch (spriteBase) {
|
||||
case FONT_SPRITE_BASE_TINY:
|
||||
return _ttfFont[0];
|
||||
case FONT_SPRITE_BASE_SMALL:
|
||||
return _ttfFont[1];
|
||||
default:
|
||||
case FONT_SPRITE_BASE_MEDIUM:
|
||||
return _ttfFont[2];
|
||||
case FONT_SPRITE_BASE_BIG:
|
||||
return _ttfFont[3];
|
||||
}
|
||||
}
|
||||
|
||||
enum {
|
||||
TEXT_DRAW_FLAG_INSET = 1 << 0,
|
||||
TEXT_DRAW_FLAG_OUTLINE = 1 << 1,
|
||||
@@ -831,39 +1014,20 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te
|
||||
if (!_ttfInitialised && !ttf_initialise())
|
||||
return;
|
||||
|
||||
TTF_Font *font;
|
||||
switch (info->font_sprite_base) {
|
||||
case FONT_SPRITE_BASE_TINY:
|
||||
font = _ttfFont[0];
|
||||
break;
|
||||
case FONT_SPRITE_BASE_SMALL:
|
||||
font = _ttfFont[1];
|
||||
break;
|
||||
default:
|
||||
case FONT_SPRITE_BASE_MEDIUM:
|
||||
font = _ttfFont[2];
|
||||
break;
|
||||
case FONT_SPRITE_BASE_BIG:
|
||||
font = _ttfFont[3];
|
||||
break;
|
||||
}
|
||||
|
||||
TTF_Font *font = ttf_get_font_from_sprite_base(info->font_sprite_base);
|
||||
if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) {
|
||||
int width, height;
|
||||
|
||||
TTF_SizeUTF8(font, text, &width, &height);
|
||||
info->x += width;
|
||||
info->x += _ttf_getwidth_cache_get_or_add(font, text);
|
||||
return;
|
||||
} else {
|
||||
uint8 colour = info->palette[1];
|
||||
SDL_Color c = { 0, 0, 0, 255 };
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Solid(font, text, c);
|
||||
SDL_Surface *surface = _ttf_surface_cache_get_or_add(font, text);
|
||||
if (surface == NULL)
|
||||
return;
|
||||
|
||||
if (SDL_LockSurface(surface) != 0) {
|
||||
SDL_FreeSurface(surface);
|
||||
return;
|
||||
if (SDL_MUSTLOCK(surface)) {
|
||||
if (SDL_LockSurface(surface) != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int drawX = info->x + _ttfFontOffsetX;
|
||||
@@ -914,9 +1078,10 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, te
|
||||
src += srcScanSkip;
|
||||
dst += dstScanSkip;
|
||||
}
|
||||
SDL_UnlockSurface(surface);
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
if (SDL_MUSTLOCK(surface)) {
|
||||
SDL_UnlockSurface(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
#include "world/scenery.h"
|
||||
#include "world/sprite.h"
|
||||
|
||||
uint32 gCurrentDrawCount = 0;
|
||||
|
||||
typedef struct tm tm_t;
|
||||
|
||||
void print_launch_information();
|
||||
@@ -236,6 +238,8 @@ void rct2_draw()
|
||||
} else {
|
||||
//game
|
||||
}
|
||||
|
||||
gCurrentDrawCount++;
|
||||
}
|
||||
|
||||
int rct2_open_file(const char *path)
|
||||
|
||||
@@ -286,6 +286,8 @@ static const struct file_to_check
|
||||
{ PATH_ID_END, 0 }
|
||||
};
|
||||
|
||||
extern uint32 gCurrentDrawCount;
|
||||
|
||||
int rct2_init();
|
||||
void rct2_update();
|
||||
void rct2_draw();
|
||||
|
||||
Reference in New Issue
Block a user