2016-05-04 19:24:41 +02:00
|
|
|
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
2014-10-06 18:36:58 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
|
|
|
*
|
2016-05-04 19:24:41 +02:00
|
|
|
* 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
|
2014-10-06 18:36:58 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2016-05-04 19:24:41 +02:00
|
|
|
*
|
|
|
|
* A full copy of the GNU General Public License can be found in licence.txt
|
2014-10-06 18:36:58 +02:00
|
|
|
*****************************************************************************/
|
2016-05-04 19:24:41 +02:00
|
|
|
#pragma endregion
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-11-08 19:55:32 +01:00
|
|
|
#include "../interface/colour.h"
|
2016-09-14 19:29:56 +02:00
|
|
|
#include "../interface/viewport.h"
|
2014-10-06 18:36:58 +02:00
|
|
|
#include "../localisation/localisation.h"
|
|
|
|
#include "../sprites.h"
|
2016-01-02 23:41:35 +01:00
|
|
|
#include "../util/util.h"
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-11-16 14:24:39 +01:00
|
|
|
enum {
|
|
|
|
TEXT_DRAW_FLAG_INSET = 1 << 0,
|
|
|
|
TEXT_DRAW_FLAG_OUTLINE = 1 << 1,
|
|
|
|
TEXT_DRAW_FLAG_DARK = 1 << 2,
|
|
|
|
TEXT_DRAW_FLAG_EXTRA_DARK = 1 << 3,
|
|
|
|
TEXT_DRAW_FLAG_Y_OFFSET_EFFECT = 1 << 29,
|
|
|
|
TEXT_DRAW_FLAG_TTF = 1 << 30,
|
|
|
|
TEXT_DRAW_FLAG_NO_DRAW = 1u << 31
|
|
|
|
};
|
|
|
|
|
2015-07-26 01:55:17 +02:00
|
|
|
static int ttf_get_string_width(const utf8 *text);
|
|
|
|
static void ttf_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y);
|
|
|
|
|
|
|
|
static bool _ttfInitialised = false;
|
2015-07-26 18:50:01 +02:00
|
|
|
|
2015-07-29 04:06:51 +02:00
|
|
|
#define TTF_SURFACE_CACHE_SIZE 256
|
|
|
|
#define TTF_GETWIDTH_CACHE_SIZE 1024
|
|
|
|
|
2016-05-12 23:57:40 +02:00
|
|
|
typedef struct ttf_cache_entry {
|
2015-07-29 04:06:51 +02:00
|
|
|
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;
|
|
|
|
|
2016-05-12 23:57:40 +02:00
|
|
|
typedef struct ttf_getwidth_cache_entry {
|
2015-07-29 04:06:51 +02:00
|
|
|
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;
|
|
|
|
|
2015-07-27 19:58:12 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x006C23B1
|
|
|
|
*/
|
|
|
|
int gfx_get_string_width_new_lined(utf8 *text)
|
|
|
|
{
|
|
|
|
utf8 *ch = text;
|
|
|
|
utf8 *firstCh = text;
|
|
|
|
utf8 *nextCh;
|
|
|
|
utf8 backup;
|
|
|
|
int codepoint;
|
2014-11-01 14:10:14 +01:00
|
|
|
|
2015-07-27 19:58:12 +02:00
|
|
|
int maxWidth = 0;
|
2015-09-07 14:57:39 +02:00
|
|
|
while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) {
|
2015-07-27 19:58:12 +02:00
|
|
|
if (codepoint == FORMAT_NEWLINE || codepoint == FORMAT_NEWLINE_SMALLER) {
|
|
|
|
backup = *nextCh;
|
|
|
|
*nextCh = 0;
|
|
|
|
maxWidth = max(maxWidth, gfx_get_string_width(firstCh));
|
|
|
|
*nextCh = backup;
|
|
|
|
firstCh = nextCh;
|
2014-11-01 14:10:14 +01:00
|
|
|
}
|
2015-07-27 19:58:12 +02:00
|
|
|
ch = nextCh;
|
2014-11-01 14:10:14 +01:00
|
|
|
}
|
2015-07-27 19:58:12 +02:00
|
|
|
maxWidth = max(maxWidth, gfx_get_string_width(firstCh));
|
2014-11-01 14:10:14 +01:00
|
|
|
|
2015-07-27 19:58:12 +02:00
|
|
|
return maxWidth;
|
2014-11-01 14:10:14 +01:00
|
|
|
}
|
|
|
|
|
2014-10-06 18:36:58 +02:00
|
|
|
/**
|
2015-12-11 16:38:37 +01:00
|
|
|
* Return the width of the string in buffer
|
2014-10-06 18:36:58 +02:00
|
|
|
*
|
|
|
|
* rct2: 0x006C2321
|
|
|
|
* buffer (esi)
|
|
|
|
*/
|
|
|
|
int gfx_get_string_width(char* buffer)
|
|
|
|
{
|
2015-07-26 18:50:01 +02:00
|
|
|
return ttf_get_string_width(buffer);
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-12-11 16:38:37 +01:00
|
|
|
* Clip the text in buffer to width, add ellipsis and return the new width of the clipped string
|
2014-10-06 18:36:58 +02:00
|
|
|
*
|
|
|
|
* rct2: 0x006C2460
|
|
|
|
* buffer (esi)
|
|
|
|
* width (edi)
|
|
|
|
*/
|
2015-07-26 18:50:01 +02:00
|
|
|
int gfx_clip_string(utf8 *text, int width)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2015-07-27 18:21:21 +02:00
|
|
|
int clippedWidth;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
if (width < 6) {
|
2015-07-26 18:50:01 +02:00
|
|
|
*text = 0;
|
2014-10-06 18:36:58 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-27 18:21:21 +02:00
|
|
|
clippedWidth = gfx_get_string_width(text);
|
|
|
|
if (clippedWidth <= width) {
|
|
|
|
return clippedWidth;
|
|
|
|
}
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-07-27 18:21:21 +02:00
|
|
|
utf8 backup[4];
|
2015-07-26 18:50:01 +02:00
|
|
|
utf8 *ch = text;
|
2015-07-27 18:21:21 +02:00
|
|
|
utf8 *nextCh = text;
|
|
|
|
utf8 *clipCh = text;
|
2015-07-26 18:50:01 +02:00
|
|
|
int codepoint;
|
2015-09-07 14:57:39 +02:00
|
|
|
while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) {
|
2015-07-30 02:09:23 +02:00
|
|
|
if (utf8_is_format_code(codepoint)) {
|
|
|
|
ch = nextCh;
|
|
|
|
ch += utf8_get_format_code_arg_length(codepoint);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-07-27 18:21:21 +02:00
|
|
|
for (int i = 0; i < 4; i++) { backup[i] = nextCh[i]; };
|
|
|
|
for (int i = 0; i < 3; i++) { nextCh[i] = '.'; }
|
|
|
|
nextCh[3] = 0;
|
|
|
|
|
|
|
|
int queryWidth = gfx_get_string_width(text);
|
|
|
|
if (queryWidth < width) {
|
|
|
|
clipCh = nextCh;
|
|
|
|
clippedWidth = queryWidth;
|
2015-07-26 18:50:01 +02:00
|
|
|
} else {
|
2015-07-27 18:21:21 +02:00
|
|
|
for (int i = 0; i < 3; i++) { clipCh[i] = '.'; }
|
|
|
|
clipCh[3] = 0;
|
|
|
|
return clippedWidth;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
2015-07-27 18:21:21 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < 4; i++) { nextCh[i] = backup[i]; };
|
|
|
|
ch = nextCh;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
2015-07-27 18:21:21 +02:00
|
|
|
return gfx_get_string_width(text);
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-12-11 16:38:37 +01:00
|
|
|
* Wrap the text in buffer to width, returns width of longest line.
|
2014-10-06 18:36:58 +02:00
|
|
|
*
|
2015-12-11 16:38:37 +01:00
|
|
|
* Inserts NULL where line should break (as \n is used for something else),
|
|
|
|
* so the number of lines is returned in num_lines. font_height seems to be
|
|
|
|
* a control character for line height.
|
2014-10-06 18:36:58 +02:00
|
|
|
*
|
|
|
|
* rct2: 0x006C21E2
|
|
|
|
* buffer (esi)
|
|
|
|
* width (edi) - in
|
|
|
|
* num_lines (edi) - out
|
|
|
|
* font_height (ebx) - out
|
|
|
|
*/
|
2015-07-27 18:21:21 +02:00
|
|
|
int gfx_wrap_string(utf8 *text, int width, int *outNumLines, int *outFontHeight)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2015-07-27 15:26:22 +02:00
|
|
|
int lineWidth = 0;
|
|
|
|
int maxWidth = 0;
|
2015-07-27 18:21:21 +02:00
|
|
|
*outNumLines = 0;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
// Pointer to the start of the current word
|
2015-07-27 15:26:22 +02:00
|
|
|
utf8 *currentWord = NULL;
|
2015-07-27 18:21:21 +02:00
|
|
|
|
2014-10-06 18:36:58 +02:00
|
|
|
// Width of line up to current word
|
2015-07-27 15:26:22 +02:00
|
|
|
int currentWidth;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-07-27 15:26:22 +02:00
|
|
|
utf8 *ch = text;
|
2015-07-27 18:21:21 +02:00
|
|
|
utf8 *firstCh = text;
|
2015-07-30 02:09:23 +02:00
|
|
|
utf8 *nextCh;
|
2015-07-27 15:26:22 +02:00
|
|
|
int codepoint;
|
2015-07-31 20:05:00 +02:00
|
|
|
int numCharactersOnLine = 0;
|
2015-09-07 14:57:39 +02:00
|
|
|
while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) {
|
2015-07-27 15:26:22 +02:00
|
|
|
if (codepoint == ' ') {
|
|
|
|
currentWord = ch;
|
|
|
|
currentWidth = lineWidth;
|
2015-07-31 20:05:00 +02:00
|
|
|
numCharactersOnLine++;
|
2015-07-27 19:58:12 +02:00
|
|
|
} else if (codepoint == FORMAT_NEWLINE) {
|
|
|
|
*ch++ = 0;
|
|
|
|
maxWidth = max(maxWidth, lineWidth);
|
|
|
|
(*outNumLines)++;
|
|
|
|
lineWidth = 0;
|
|
|
|
currentWord = NULL;
|
|
|
|
firstCh = ch;
|
2015-07-31 20:05:00 +02:00
|
|
|
numCharactersOnLine = 0;
|
2015-07-27 19:58:12 +02:00
|
|
|
continue;
|
2015-07-30 02:09:23 +02:00
|
|
|
} else if (utf8_is_format_code(codepoint)) {
|
|
|
|
ch = nextCh;
|
|
|
|
ch += utf8_get_format_code_arg_length(codepoint);
|
|
|
|
continue;
|
2015-07-27 15:26:22 +02:00
|
|
|
}
|
|
|
|
|
2015-07-30 02:09:23 +02:00
|
|
|
uint8 saveCh = *nextCh;
|
|
|
|
*nextCh = 0;
|
2015-07-27 18:21:21 +02:00
|
|
|
lineWidth = gfx_get_string_width(firstCh);
|
2015-07-30 02:09:23 +02:00
|
|
|
*nextCh = saveCh;
|
2015-07-27 18:21:21 +02:00
|
|
|
|
2015-07-31 20:05:00 +02:00
|
|
|
if (lineWidth <= width || numCharactersOnLine == 0) {
|
2015-07-30 02:09:23 +02:00
|
|
|
ch = nextCh;
|
2015-07-31 20:05:00 +02:00
|
|
|
numCharactersOnLine++;
|
2015-07-27 18:21:21 +02:00
|
|
|
} else if (currentWord == NULL) {
|
|
|
|
// Single word is longer than line, insert null terminator
|
2015-07-29 19:16:15 +02:00
|
|
|
ch += utf8_insert_codepoint(ch, 0);
|
2015-07-27 18:21:21 +02:00
|
|
|
maxWidth = max(maxWidth, lineWidth);
|
|
|
|
(*outNumLines)++;
|
|
|
|
lineWidth = 0;
|
|
|
|
currentWord = NULL;
|
|
|
|
firstCh = ch;
|
2015-07-31 20:05:00 +02:00
|
|
|
numCharactersOnLine = 0;
|
2015-07-27 15:26:22 +02:00
|
|
|
} else {
|
2015-07-27 18:21:21 +02:00
|
|
|
ch = currentWord;
|
|
|
|
*ch++ = 0;
|
|
|
|
|
|
|
|
maxWidth = max(maxWidth, currentWidth);
|
|
|
|
(*outNumLines)++;
|
|
|
|
lineWidth = 0;
|
|
|
|
currentWord = NULL;
|
|
|
|
firstCh = ch;
|
2015-07-31 20:05:00 +02:00
|
|
|
numCharactersOnLine = 0;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
}
|
2015-08-01 17:40:15 +02:00
|
|
|
maxWidth = max(maxWidth, lineWidth);
|
2016-04-26 00:00:58 +02:00
|
|
|
*outFontHeight = gCurrentFontSpriteBase;
|
2015-07-27 15:26:22 +02:00
|
|
|
return maxWidth == 0 ? lineWidth : maxWidth;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws i formatted text string left aligned at i specified position but clips
|
|
|
|
* the text with an elipsis if the text width exceeds the specified width.
|
|
|
|
* rct2: 0x006C1B83
|
|
|
|
* dpi (edi)
|
|
|
|
* format (bx)
|
|
|
|
* args (esi)
|
|
|
|
* colour (al)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
* width (bp)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
void gfx_draw_string_left_clipped(rct_drawpixelinfo* dpi, rct_string_id format, void* args, int colour, int x, int y, int width)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2016-09-04 16:55:37 +02:00
|
|
|
char* buffer = gCommonStringFormatBuffer;
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
// Clip text - return value is not needed
|
|
|
|
gfx_clip_string(buffer, width);
|
|
|
|
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws i formatted text string centred at i specified position but clips the
|
|
|
|
* text with an elipsis if the text width exceeds the specified width.
|
|
|
|
* rct2: 0x006C1BBA
|
|
|
|
* dpi (edi)
|
|
|
|
* format (bx)
|
|
|
|
* args (esi)
|
|
|
|
* colour (al)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
* width (bp)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
void gfx_draw_string_centred_clipped(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y, int width)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2016-09-04 16:55:37 +02:00
|
|
|
char* buffer = gCommonStringFormatBuffer;
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
// Clip text
|
2016-05-15 11:25:24 +02:00
|
|
|
int text_width = gfx_clip_string(buffer, width);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
// Draw the text centred
|
2015-09-07 00:46:54 +02:00
|
|
|
if (text_width <= 0xFFFF && text_width >= 0) {
|
2014-10-06 18:36:58 +02:00
|
|
|
x -= (text_width - 1) / 2;
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
2015-09-07 00:46:54 +02:00
|
|
|
} else {
|
|
|
|
log_warning("improper text width %d for string %s", text_width, buffer);
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws i formatted text string right aligned.
|
|
|
|
* rct2: 0x006C1BFC
|
|
|
|
* dpi (edi)
|
|
|
|
* format (bx)
|
|
|
|
* args (esi)
|
|
|
|
* colour (al)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
void gfx_draw_string_right(rct_drawpixelinfo* dpi, rct_string_id format, void* args, int colour, int x, int y)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2016-09-04 16:55:37 +02:00
|
|
|
char* buffer = gCommonStringFormatBuffer;
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
// Measure text width
|
2016-05-15 11:25:24 +02:00
|
|
|
short text_width = gfx_get_string_width(buffer);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
// Draw the text right aligned
|
|
|
|
x -= text_width;
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
|
|
|
}
|
|
|
|
|
2014-10-07 20:53:21 +02:00
|
|
|
/**
|
|
|
|
* Draws i formatted text string centred at i specified position.
|
|
|
|
* rct2: 0x006C1D6C
|
|
|
|
* dpi (edi)
|
|
|
|
* format (bx)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
* colour (al)
|
|
|
|
* args (esi)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
void gfx_draw_string_centred(rct_drawpixelinfo *dpi, rct_string_id format, int x, int y, int colour, void *args)
|
2014-10-07 20:53:21 +02:00
|
|
|
{
|
2016-01-23 01:23:40 +01:00
|
|
|
gfx_draw_string_centred_wrapped(dpi, args, x, y, INT32_MAX, format, colour);
|
2014-10-07 20:53:21 +02:00
|
|
|
}
|
|
|
|
|
2014-10-06 18:36:58 +02:00
|
|
|
/**
|
2015-08-04 22:39:44 +02:00
|
|
|
*
|
2014-10-06 18:36:58 +02:00
|
|
|
* rct2: 0x006C1E53
|
|
|
|
* dpi (edi)
|
|
|
|
* args (esi)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
* width (bp)
|
|
|
|
* colour (al)
|
|
|
|
* format (ebx)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
int gfx_draw_string_centred_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, rct_string_id format, int colour)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2016-09-07 14:39:29 +02:00
|
|
|
int font_height, line_height, line_y, num_lines;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
if (gCurrentFontSpriteBase >= 0) {
|
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
|
|
|
}
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-09-11 00:48:29 +02:00
|
|
|
char *buffer = gCommonStringFormatBuffer;
|
|
|
|
gfx_draw_string(dpi, "", colour, dpi->x, dpi->y);
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-09-07 14:39:29 +02:00
|
|
|
gfx_wrap_string(buffer, width, &num_lines, &font_height);
|
2015-07-31 02:15:35 +02:00
|
|
|
line_height = font_get_line_height(font_height);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-07-31 02:15:35 +02:00
|
|
|
if (*buffer == FORMAT_OUTLINE) {
|
2014-10-06 18:36:58 +02:00
|
|
|
line_height = line_height + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
font_height = (line_height / 2) * num_lines;
|
|
|
|
line_y = y - font_height;
|
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontFlags = 0;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
for (int line = 0; line <= num_lines; ++line) {
|
|
|
|
int half_width = gfx_get_string_width(buffer) / 2;
|
2016-11-16 14:24:39 +01:00
|
|
|
gfx_draw_string(dpi, buffer, TEXT_COLOUR_254, x - half_width, line_y);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-07-27 19:58:12 +02:00
|
|
|
buffer = get_string_end(buffer) + 1;
|
|
|
|
line_y += line_height;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return line_y - y;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-08-04 22:39:44 +02:00
|
|
|
*
|
2014-10-06 18:36:58 +02:00
|
|
|
* rct2: 0x006C2105
|
|
|
|
* dpi (edi)
|
|
|
|
* args (esi)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
* width (bp)
|
|
|
|
* format (bx)
|
|
|
|
* colour (al)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
int gfx_draw_string_left_wrapped(rct_drawpixelinfo *dpi, void *args, int x, int y, int width, rct_string_id format, int colour)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
|
|
|
// font height might actually be something else
|
2015-07-27 19:58:12 +02:00
|
|
|
int fontSpriteBase, lineHeight, lineY, numLines;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-09-11 00:48:29 +02:00
|
|
|
char *buffer = gCommonStringFormatBuffer;
|
|
|
|
gfx_draw_string(dpi, "", colour, dpi->x, dpi->y);
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2015-07-27 19:58:12 +02:00
|
|
|
gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase);
|
2015-07-31 02:15:35 +02:00
|
|
|
lineHeight = font_get_line_height(fontSpriteBase);
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontFlags = 0;
|
2015-07-27 19:58:12 +02:00
|
|
|
lineY = y;
|
|
|
|
for (int line = 0; line <= numLines; ++line) {
|
2016-11-16 14:24:39 +01:00
|
|
|
gfx_draw_string(dpi, buffer, TEXT_COLOUR_254, x, lineY);
|
2015-07-27 19:58:12 +02:00
|
|
|
buffer = get_string_end(buffer) + 1;
|
|
|
|
lineY += lineHeight;
|
2015-08-04 22:39:44 +02:00
|
|
|
}
|
2015-07-27 19:58:12 +02:00
|
|
|
return lineY - y;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws i formatted text string.
|
|
|
|
* rct2: 0x006C1B2F
|
|
|
|
* dpi (edi)
|
|
|
|
* format (bx)
|
|
|
|
* args (esi)
|
|
|
|
* colour (al)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
*/
|
2016-07-14 14:07:49 +02:00
|
|
|
void gfx_draw_string_left(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
2016-09-04 16:55:37 +02:00
|
|
|
char* buffer = gCommonStringFormatBuffer;
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
|
|
|
}
|
|
|
|
|
2015-06-17 17:21:50 +02:00
|
|
|
/**
|
|
|
|
* Draws text that is left aligned and vertically centred.
|
|
|
|
*/
|
|
|
|
void gfx_draw_string_left_centred(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y)
|
|
|
|
{
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2016-09-04 16:55:37 +02:00
|
|
|
char *buffer = gCommonStringFormatBuffer;
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2015-06-17 17:21:50 +02:00
|
|
|
int height = string_get_height_raw(buffer);
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y - (height / 2));
|
|
|
|
}
|
|
|
|
|
2014-10-06 18:36:58 +02:00
|
|
|
/**
|
|
|
|
* Changes the palette so that the next character changes colour
|
|
|
|
*/
|
2016-07-13 00:46:51 +02:00
|
|
|
static void colour_char(uint8 colour, uint16* current_font_flags, uint8* palette_pointer) {
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
int eax;
|
|
|
|
|
2016-07-14 14:07:49 +02:00
|
|
|
rct_g1_element g1_element = g1Elements[SPR_TEXT_PALETTE];
|
2014-10-06 18:36:58 +02:00
|
|
|
eax = ((uint32*)g1_element.offset)[colour & 0xFF];
|
|
|
|
|
|
|
|
if (!(*current_font_flags & 2)) {
|
|
|
|
eax = eax & 0x0FF0000FF;
|
|
|
|
}
|
2015-08-04 22:39:44 +02:00
|
|
|
// Adjust text palette. Store current colour?
|
2014-10-06 18:36:58 +02:00
|
|
|
palette_pointer[1] = eax & 0xFF;
|
|
|
|
palette_pointer[2] = (eax >> 8) & 0xFF;
|
|
|
|
palette_pointer[3] = (eax >> 16) & 0xFF;
|
|
|
|
palette_pointer[4] = (eax >> 24) & 0xFF;
|
2016-04-24 13:31:13 +02:00
|
|
|
unk_9ABDA4 = palette_pointer;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Changes the palette so that the next character changes colour
|
2015-12-11 16:38:37 +01:00
|
|
|
* This is specific to changing to a predefined window related colour
|
2014-10-06 18:36:58 +02:00
|
|
|
*/
|
2016-07-13 00:46:51 +02:00
|
|
|
static void colour_char_window(uint8 colour, uint16* current_font_flags,uint8* palette_pointer) {
|
2014-10-06 18:36:58 +02:00
|
|
|
|
|
|
|
int eax;
|
|
|
|
|
2016-11-06 20:49:03 +01:00
|
|
|
colour = NOT_TRANSLUCENT(colour);
|
2016-11-11 09:46:14 +01:00
|
|
|
eax = ColourMapA[colour].colour_11;
|
2016-11-16 14:24:39 +01:00
|
|
|
if (*current_font_flags & TEXT_DRAW_FLAG_OUTLINE) {
|
2014-10-06 18:36:58 +02:00
|
|
|
eax |= 0x0A0A00;
|
|
|
|
}
|
2015-08-04 22:39:44 +02:00
|
|
|
//Adjust text palette. Store current colour?
|
2014-10-06 18:36:58 +02:00
|
|
|
palette_pointer[1] = eax & 0xFF;
|
|
|
|
palette_pointer[2] = (eax >> 8) & 0xFF;
|
|
|
|
palette_pointer[3] = (eax >> 16) & 0xFF;
|
|
|
|
palette_pointer[4] = (eax >> 24) & 0xFF;
|
2016-04-24 13:31:13 +02:00
|
|
|
unk_9ABDA4 = palette_pointer;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2015-08-04 22:39:44 +02:00
|
|
|
*
|
2014-10-06 18:36:58 +02:00
|
|
|
* rct2: 0x00682702
|
|
|
|
* dpi (edi)
|
|
|
|
* buffer (esi)
|
|
|
|
* colour (al)
|
|
|
|
* x (cx)
|
|
|
|
* y (dx)
|
|
|
|
*/
|
|
|
|
void gfx_draw_string(rct_drawpixelinfo *dpi, char *buffer, int colour, int x, int y)
|
|
|
|
{
|
2015-07-26 18:50:01 +02:00
|
|
|
ttf_draw_string(dpi, buffer, colour, x, y);
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
2016-07-14 14:07:49 +02:00
|
|
|
void draw_string_left_underline(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
|
|
|
char buffer[128];
|
|
|
|
int width;
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 128, format, args);
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
width = gfx_get_string_width(buffer);
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
|
|
|
gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]);
|
|
|
|
if (text_palette[2] != 0)
|
|
|
|
gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]);
|
|
|
|
}
|
|
|
|
|
2016-07-14 14:07:49 +02:00
|
|
|
void draw_string_right_underline(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
|
|
|
char buffer[128];
|
|
|
|
int width;
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 128, format, args);
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
width = gfx_get_string_width(buffer);
|
|
|
|
x -= width;
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
|
|
|
gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]);
|
|
|
|
if (text_palette[2] != 0)
|
|
|
|
gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]);
|
|
|
|
}
|
|
|
|
|
2016-07-14 14:07:49 +02:00
|
|
|
void draw_string_centred_underline(rct_drawpixelinfo *dpi, rct_string_id format, void *args, int colour, int x, int y)
|
2014-10-06 18:36:58 +02:00
|
|
|
{
|
|
|
|
char buffer[128];
|
|
|
|
int width;
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 128, format, args);
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2014-10-06 18:36:58 +02:00
|
|
|
width = gfx_get_string_width(buffer);
|
|
|
|
x -= width / 2;
|
|
|
|
gfx_draw_string(dpi, buffer, colour, x, y);
|
|
|
|
gfx_fill_rect(dpi, x, y + 11, x + width, y + 11, text_palette[1]);
|
|
|
|
if (text_palette[2] != 0)
|
|
|
|
gfx_fill_rect(dpi, x + 1, y + 12, x + width + 1, y + 12, text_palette[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2015-12-11 16:38:37 +01:00
|
|
|
* rct2: 0x006C1DB7
|
2014-10-06 18:36:58 +02:00
|
|
|
*
|
|
|
|
* left : cx
|
|
|
|
* top : dx
|
|
|
|
* numLines : bp
|
|
|
|
* text : esi
|
|
|
|
* dpi : edi
|
|
|
|
*/
|
|
|
|
void draw_string_centred_raw(rct_drawpixelinfo *dpi, int x, int y, int numLines, char *text)
|
|
|
|
{
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2016-11-13 18:20:30 +01:00
|
|
|
gfx_draw_string(dpi, "", COLOUR_BLACK, dpi->x, dpi->y);
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontFlags = 0;
|
2015-06-09 16:42:25 +02:00
|
|
|
|
|
|
|
for (int i = 0; i <= numLines; i++) {
|
|
|
|
int width = gfx_get_string_width(text);
|
2016-11-16 14:24:39 +01:00
|
|
|
gfx_draw_string(dpi, text, TEXT_COLOUR_254, x - (width / 2), y);
|
2015-06-09 16:42:25 +02:00
|
|
|
|
2016-03-01 12:23:48 +01:00
|
|
|
const utf8 *ch = text;
|
|
|
|
const utf8 *nextCh = 0;
|
|
|
|
int codepoint = 0;
|
|
|
|
|
|
|
|
while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) {
|
|
|
|
ch = nextCh;
|
2015-06-09 16:42:25 +02:00
|
|
|
}
|
2016-03-05 00:12:52 +01:00
|
|
|
text = (char*)(ch + 1);
|
2015-06-09 16:42:25 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
y += font_get_line_height(gCurrentFontSpriteBase);
|
2015-06-09 16:42:25 +02:00
|
|
|
}
|
2015-06-16 23:56:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int string_get_height_raw(char *buffer)
|
|
|
|
{
|
2016-04-26 00:00:58 +02:00
|
|
|
uint16 fontBase = gCurrentFontSpriteBase;
|
2015-06-16 23:56:08 +02:00
|
|
|
|
|
|
|
int height = 0;
|
2016-04-26 00:20:54 +02:00
|
|
|
if (fontBase <= FONT_SPRITE_BASE_MEDIUM)
|
2015-06-16 23:56:08 +02:00
|
|
|
height += 10;
|
2016-04-26 00:00:58 +02:00
|
|
|
else if (fontBase == FONT_SPRITE_BASE_TINY)
|
2015-06-16 23:56:08 +02:00
|
|
|
height += 6;
|
|
|
|
|
|
|
|
char *ch = buffer;
|
|
|
|
while (*ch != 0) {
|
|
|
|
char c = *ch++;
|
|
|
|
switch (c) {
|
|
|
|
case FORMAT_NEWLINE:
|
|
|
|
if (fontBase <= 224) {
|
|
|
|
height += 10;
|
|
|
|
break;
|
|
|
|
} else if (fontBase == 448) {
|
|
|
|
height += 6;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
height += 18;
|
|
|
|
break;
|
|
|
|
case FORMAT_NEWLINE_SMALLER:
|
|
|
|
if (fontBase <= 224) {
|
|
|
|
height += 5;
|
|
|
|
break;
|
|
|
|
} else if (fontBase == 448) {
|
|
|
|
height += 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
height += 9;
|
|
|
|
break;
|
|
|
|
case FORMAT_TINYFONT:
|
|
|
|
fontBase = 448;
|
|
|
|
break;
|
|
|
|
case FORMAT_BIGFONT:
|
|
|
|
fontBase = 672;
|
|
|
|
break;
|
|
|
|
case FORMAT_MEDIUMFONT:
|
|
|
|
fontBase = 224;
|
|
|
|
break;
|
|
|
|
case FORMAT_SMALLFONT:
|
|
|
|
fontBase = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (c >= 32) continue;
|
|
|
|
if (c <= 4) {
|
|
|
|
ch++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c <= 16) continue;
|
|
|
|
ch += 2;
|
|
|
|
if (c <= 22) continue;
|
|
|
|
ch += 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return height;
|
2015-06-28 02:57:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
2015-12-11 16:38:37 +01:00
|
|
|
* rct2: 0x006C1F57
|
2015-06-28 02:57:50 +02:00
|
|
|
*
|
|
|
|
* colour : al
|
|
|
|
* format : bx
|
|
|
|
* x : cx
|
|
|
|
* y : dx
|
|
|
|
* text : esi
|
|
|
|
* dpi : edi
|
|
|
|
* width : bp
|
|
|
|
* ticks : ebp >> 16
|
|
|
|
*/
|
2015-07-29 17:34:13 +02:00
|
|
|
void gfx_draw_string_centred_wrapped_partial(rct_drawpixelinfo *dpi, int x, int y, int width, int colour, rct_string_id format, void *args, int ticks)
|
2015-06-28 02:57:50 +02:00
|
|
|
{
|
2015-07-29 17:34:13 +02:00
|
|
|
int numLines, fontSpriteBase, lineHeight, lineY;
|
2016-09-04 16:55:37 +02:00
|
|
|
utf8 *buffer = gCommonStringFormatBuffer;
|
2015-07-29 17:34:13 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2016-09-11 00:48:29 +02:00
|
|
|
gfx_draw_string(dpi, "", colour, dpi->x, dpi->y);
|
2016-09-26 04:24:29 +02:00
|
|
|
format_string(buffer, 256, format, args);
|
2015-07-29 17:34:13 +02:00
|
|
|
|
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = FONT_SPRITE_BASE_MEDIUM;
|
2015-07-29 17:34:13 +02:00
|
|
|
gfx_wrap_string(buffer, width, &numLines, &fontSpriteBase);
|
2015-07-31 02:15:35 +02:00
|
|
|
lineHeight = font_get_line_height(fontSpriteBase);
|
2015-07-29 17:34:13 +02:00
|
|
|
|
|
|
|
int numCharactersDrawn = 0;
|
|
|
|
int numCharactersToDraw = ticks;
|
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontFlags = 0;
|
2015-07-31 02:15:35 +02:00
|
|
|
lineY = y - ((numLines * lineHeight) / 2);
|
2015-07-29 17:34:13 +02:00
|
|
|
for (int line = 0; line <= numLines; line++) {
|
|
|
|
int halfWidth = gfx_get_string_width(buffer) / 2;
|
2015-08-04 22:39:44 +02:00
|
|
|
|
2015-07-29 17:34:13 +02:00
|
|
|
utf8 *ch = buffer;
|
|
|
|
utf8 *nextCh;
|
|
|
|
int codepoint;
|
2015-09-07 14:57:39 +02:00
|
|
|
while ((codepoint = utf8_get_next(ch, (const utf8**)&nextCh)) != 0) {
|
2015-07-29 17:34:13 +02:00
|
|
|
if (!utf8_is_format_code(codepoint)) {
|
|
|
|
numCharactersDrawn++;
|
|
|
|
if (numCharactersDrawn > numCharactersToDraw) {
|
|
|
|
*ch = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ch = nextCh;
|
|
|
|
}
|
|
|
|
|
2016-11-16 14:24:39 +01:00
|
|
|
gfx_draw_string(dpi, buffer, TEXT_COLOUR_254, x - halfWidth, lineY);
|
2015-07-29 17:34:13 +02:00
|
|
|
|
|
|
|
if (numCharactersDrawn > numCharactersToDraw) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = get_string_end(buffer) + 1;
|
|
|
|
lineY += lineHeight;
|
2015-08-04 22:39:44 +02:00
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
|
2015-07-29 04:06:51 +02:00
|
|
|
static uint32 _ttf_surface_cache_hash(TTF_Font *font, const utf8 *text)
|
|
|
|
{
|
2016-08-28 00:32:15 +02:00
|
|
|
uint32 hash = (uint32)((((uintptr_t)font * 23) ^ 0xAAAAAAAA) & 0xFFFFFFFF);
|
2015-10-20 01:18:59 +02:00
|
|
|
for (const utf8 *ch = text; *ch != 0; ch++) {
|
2015-07-29 04:06:51 +02:00
|
|
|
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--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-13 00:46:51 +02:00
|
|
|
SDL_Surface *ttf_surface_cache_get_or_add(TTF_Font *font, const utf8 *text)
|
2015-07-29 04:06:51 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-07-26 01:55:17 +02:00
|
|
|
bool ttf_initialise()
|
|
|
|
{
|
|
|
|
if (!_ttfInitialised) {
|
2015-11-26 19:28:52 +01:00
|
|
|
if (TTF_Init() != 0) {
|
2015-07-26 01:55:17 +02:00
|
|
|
return false;
|
2015-11-26 19:28:52 +01:00
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
|
2015-07-26 18:50:01 +02:00
|
|
|
for (int i = 0; i < 4; i++) {
|
2015-07-31 02:15:35 +02:00
|
|
|
TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]);
|
2015-08-04 22:39:44 +02:00
|
|
|
|
2015-12-22 18:56:47 +01:00
|
|
|
utf8 fontPath[MAX_PATH];
|
2016-09-26 04:24:29 +02:00
|
|
|
if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath))) {
|
2015-12-22 18:56:47 +01:00
|
|
|
log_error("Unable to load font '%s'", fontDesc->font_name);
|
|
|
|
return false;
|
|
|
|
}
|
2015-07-31 02:15:35 +02:00
|
|
|
|
|
|
|
fontDesc->font = TTF_OpenFont(fontPath, fontDesc->ptSize);
|
|
|
|
if (fontDesc->font == NULL) {
|
2015-07-31 20:05:00 +02:00
|
|
|
log_error("Unable to load '%s'", fontPath);
|
2015-11-26 19:28:52 +01:00
|
|
|
return false;
|
2015-07-26 18:50:01 +02:00
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_ttfInitialised = true;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ttf_dispose()
|
|
|
|
{
|
|
|
|
if (!_ttfInitialised)
|
|
|
|
return;
|
|
|
|
|
2015-07-29 04:06:51 +02:00
|
|
|
_ttf_surface_cache_dispose_all();
|
|
|
|
_ttf_getwidth_cache_dispose_all();
|
|
|
|
|
2015-07-31 02:15:35 +02:00
|
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
TTFFontDescriptor *fontDesc = &(gCurrentTTFFontSet->size[i]);
|
|
|
|
if (fontDesc->font != NULL) {
|
|
|
|
TTF_CloseFont(fontDesc->font);
|
|
|
|
fontDesc->font = NULL;
|
2015-07-26 18:50:01 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
|
|
|
|
TTF_Quit();
|
2015-07-26 18:50:01 +02:00
|
|
|
_ttfInitialised = false;
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
|
2015-07-31 02:15:35 +02:00
|
|
|
TTFFontDescriptor *ttf_get_font_from_sprite_base(uint16 spriteBase)
|
2015-07-30 09:20:27 +02:00
|
|
|
{
|
2015-07-31 02:15:35 +02:00
|
|
|
return &gCurrentTTFFontSet->size[font_get_size_from_sprite_base(spriteBase)];
|
2015-07-30 09:20:27 +02:00
|
|
|
}
|
|
|
|
|
2016-05-12 23:57:40 +02:00
|
|
|
typedef struct text_draw_info {
|
2015-07-26 18:50:01 +02:00
|
|
|
int startX;
|
|
|
|
int startY;
|
2015-07-26 01:55:17 +02:00
|
|
|
int x;
|
|
|
|
int y;
|
2015-07-31 20:05:00 +02:00
|
|
|
int maxX;
|
|
|
|
int maxY;
|
2015-07-26 01:55:17 +02:00
|
|
|
int flags;
|
2015-07-26 14:58:53 +02:00
|
|
|
uint8 palette[8];
|
|
|
|
uint16 font_sprite_base;
|
2015-08-03 19:06:54 +02:00
|
|
|
const sint8 *y_offset;
|
2015-07-26 01:55:17 +02:00
|
|
|
} text_draw_info;
|
|
|
|
|
2015-07-27 02:09:24 +02:00
|
|
|
static void ttf_draw_character_sprite(rct_drawpixelinfo *dpi, int codepoint, text_draw_info *info)
|
|
|
|
{
|
2015-07-29 15:36:21 +02:00
|
|
|
int characterWidth = font_sprite_get_codepoint_width(info->font_sprite_base, codepoint);
|
|
|
|
int sprite = font_sprite_get_codepoint_sprite(info->font_sprite_base, codepoint);
|
2015-07-27 02:09:24 +02:00
|
|
|
|
|
|
|
if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) {
|
2016-04-24 13:31:13 +02:00
|
|
|
unk_9ABDA4 = &info->palette;
|
2015-08-03 19:06:54 +02:00
|
|
|
|
|
|
|
int x = info->x;
|
|
|
|
int y = info->y;
|
|
|
|
if (info->flags & TEXT_DRAW_FLAG_Y_OFFSET_EFFECT) {
|
|
|
|
y += *info->y_offset++;
|
|
|
|
}
|
2016-06-12 00:14:22 +02:00
|
|
|
gfx_draw_glpyh(dpi, sprite, x, y, info->palette);
|
2015-07-27 02:09:24 +02:00
|
|
|
}
|
|
|
|
|
2015-07-29 15:36:21 +02:00
|
|
|
info->x += characterWidth;
|
2015-07-27 02:09:24 +02:00
|
|
|
}
|
|
|
|
|
2015-07-26 14:58:53 +02:00
|
|
|
static void ttf_draw_string_raw_sprite(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info)
|
|
|
|
{
|
|
|
|
const utf8 *ch = text;
|
|
|
|
int codepoint;
|
|
|
|
|
|
|
|
while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &ch))) {
|
2015-07-27 02:09:24 +02:00
|
|
|
ttf_draw_character_sprite(dpi, codepoint, info);
|
2015-07-26 14:58:53 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ttf_draw_string_raw_ttf(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info)
|
2015-07-26 01:55:17 +02:00
|
|
|
{
|
|
|
|
if (!_ttfInitialised && !ttf_initialise())
|
|
|
|
return;
|
|
|
|
|
2015-07-31 02:15:35 +02:00
|
|
|
TTFFontDescriptor *fontDesc = ttf_get_font_from_sprite_base(info->font_sprite_base);
|
2015-07-31 20:05:00 +02:00
|
|
|
if (fontDesc->font == NULL) {
|
2015-08-02 12:25:26 +02:00
|
|
|
ttf_draw_string_raw_sprite(dpi, text, info);
|
2015-08-03 19:06:54 +02:00
|
|
|
return;
|
2015-07-31 20:05:00 +02:00
|
|
|
}
|
|
|
|
|
2015-07-26 01:55:17 +02:00
|
|
|
if (info->flags & TEXT_DRAW_FLAG_NO_DRAW) {
|
2015-07-31 02:15:35 +02:00
|
|
|
info->x += _ttf_getwidth_cache_get_or_add(fontDesc->font, text);
|
2015-07-26 01:55:17 +02:00
|
|
|
return;
|
|
|
|
} else {
|
2015-07-26 14:58:53 +02:00
|
|
|
uint8 colour = info->palette[1];
|
2016-07-13 00:46:51 +02:00
|
|
|
SDL_Surface *surface = ttf_surface_cache_get_or_add(fontDesc->font, text);
|
2015-07-26 01:55:17 +02:00
|
|
|
if (surface == NULL)
|
|
|
|
return;
|
|
|
|
|
2015-07-29 04:06:51 +02:00
|
|
|
if (SDL_MUSTLOCK(surface)) {
|
|
|
|
if (SDL_LockSurface(surface) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
2015-08-04 22:39:44 +02:00
|
|
|
|
2015-07-31 02:15:35 +02:00
|
|
|
int drawX = info->x + fontDesc->offset_x;
|
|
|
|
int drawY = info->y + fontDesc->offset_y;
|
2015-07-26 01:55:17 +02:00
|
|
|
int width = surface->w;
|
|
|
|
int height = surface->h;
|
2015-07-26 14:58:53 +02:00
|
|
|
|
|
|
|
int overflowX = (dpi->x + dpi->width) - (drawX + width);
|
|
|
|
int overflowY = (dpi->y + dpi->height) - (drawY + height);
|
|
|
|
if (overflowX < 0) width += overflowX;
|
|
|
|
if (overflowY < 0) height += overflowY;
|
|
|
|
int skipX = drawX - dpi->x;
|
|
|
|
int skipY = drawY - dpi->y;
|
2015-07-26 01:55:17 +02:00
|
|
|
info->x += width;
|
|
|
|
|
|
|
|
uint8 *src = surface->pixels;
|
|
|
|
uint8 *dst = dpi->bits;
|
|
|
|
|
|
|
|
if (skipX < 0) {
|
|
|
|
width += skipX;
|
|
|
|
src += -skipX;
|
2015-07-26 14:58:53 +02:00
|
|
|
skipX = 0;
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
if (skipY < 0) {
|
|
|
|
height += skipY;
|
|
|
|
src += (-skipY * surface->pitch);
|
2015-07-26 14:58:53 +02:00
|
|
|
skipY = 0;
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
2015-07-26 14:58:53 +02:00
|
|
|
|
2015-07-26 01:55:17 +02:00
|
|
|
dst += skipX;
|
|
|
|
dst += skipY * (dpi->width + dpi->pitch);
|
|
|
|
|
|
|
|
int srcScanSkip = surface->pitch - width;
|
|
|
|
int dstScanSkip = dpi->width + dpi->pitch - width;
|
2016-01-07 15:06:09 +01:00
|
|
|
uint8 *dst_orig = dst;
|
|
|
|
uint8 *src_orig = src;
|
|
|
|
|
|
|
|
// Draw shadow/outline
|
|
|
|
if (info->flags & TEXT_DRAW_FLAG_OUTLINE) {
|
|
|
|
for (int yy = 0; yy < height - 0; yy++) {
|
|
|
|
for (int xx = 0; xx < width - 0; xx++) {
|
|
|
|
if (*src != 0) {
|
|
|
|
*(dst + 1) = info->palette[3]; // right
|
|
|
|
*(dst - 1) = info->palette[3]; // left
|
|
|
|
*(dst - width - dstScanSkip) = info->palette[3]; // top
|
|
|
|
*(dst + width + dstScanSkip) = info->palette[3]; // bottom
|
2015-07-27 15:26:22 +02:00
|
|
|
}
|
2016-01-07 15:06:09 +01:00
|
|
|
src++;
|
|
|
|
dst++;
|
2015-07-27 15:26:22 +02:00
|
|
|
}
|
2016-01-07 15:06:09 +01:00
|
|
|
// Skip any remaining bits
|
|
|
|
src += srcScanSkip;
|
|
|
|
dst += dstScanSkip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{
|
|
|
|
dst = dst_orig;
|
|
|
|
src = src_orig;
|
|
|
|
for (int yy = 0; yy < height; yy++) {
|
|
|
|
for (int xx = 0; xx < width; xx++) {
|
|
|
|
if (*src != 0) {
|
|
|
|
if (info->flags & TEXT_DRAW_FLAG_INSET) {
|
|
|
|
*(dst + width + dstScanSkip + 1) = info->palette[3];
|
|
|
|
}
|
|
|
|
*dst = colour;
|
|
|
|
}
|
|
|
|
src++;
|
|
|
|
dst++;
|
|
|
|
}
|
|
|
|
src += srcScanSkip;
|
|
|
|
dst += dstScanSkip;
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-29 04:06:51 +02:00
|
|
|
if (SDL_MUSTLOCK(surface)) {
|
|
|
|
SDL_UnlockSurface(surface);
|
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-26 14:58:53 +02:00
|
|
|
static void ttf_draw_string_raw(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info)
|
2015-07-26 01:55:17 +02:00
|
|
|
{
|
2015-07-26 14:58:53 +02:00
|
|
|
if (info->flags & TEXT_DRAW_FLAG_TTF) {
|
|
|
|
ttf_draw_string_raw_ttf(dpi, text, info);
|
|
|
|
} else {
|
|
|
|
ttf_draw_string_raw_sprite(dpi, text, info);
|
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const utf8 *ttf_process_format_code(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info)
|
|
|
|
{
|
|
|
|
const utf8 *nextCh;
|
|
|
|
int codepoint;
|
|
|
|
|
|
|
|
codepoint = utf8_get_next(text, &nextCh);
|
|
|
|
switch (codepoint) {
|
|
|
|
case FORMAT_MOVE_X:
|
2015-07-29 03:03:34 +02:00
|
|
|
info->x = info->startX + (uint8)(*nextCh++);
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
case FORMAT_ADJUST_PALETTE:
|
2015-07-26 14:58:53 +02:00
|
|
|
{
|
2016-02-26 12:54:00 +01:00
|
|
|
uint16 eax = palette_to_g1_offset[(uint8)*nextCh++];
|
2015-07-26 14:58:53 +02:00
|
|
|
rct_g1_element *g1Element = &g1Elements[eax];
|
|
|
|
uint32 ebx = g1Element->offset[249] + 256;
|
|
|
|
if (!(info->flags & TEXT_DRAW_FLAG_OUTLINE)) {
|
|
|
|
ebx = ebx & 0xFF;
|
|
|
|
}
|
|
|
|
info->palette[1] = ebx & 0xFF;
|
|
|
|
info->palette[2] = (ebx >> 8) & 0xFF;
|
|
|
|
|
|
|
|
// Adjust the text palette
|
|
|
|
memcpy(info->palette + 3, &(g1Element->offset[247]), 2);
|
|
|
|
memcpy(info->palette + 5, &(g1Element->offset[250]), 2);
|
|
|
|
|
|
|
|
// Set the palette pointer
|
2016-04-24 13:31:13 +02:00
|
|
|
unk_9ABDA4 = &info->palette;
|
2015-07-26 14:58:53 +02:00
|
|
|
break;
|
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
nextCh++;
|
|
|
|
break;
|
|
|
|
case FORMAT_NEWLINE:
|
2015-07-31 02:15:35 +02:00
|
|
|
info->x = info->startX;
|
|
|
|
info->y += font_get_line_height(info->font_sprite_base);
|
2015-07-26 14:58:53 +02:00
|
|
|
break;
|
2015-07-26 01:55:17 +02:00
|
|
|
case FORMAT_NEWLINE_SMALLER:
|
2015-07-31 02:15:35 +02:00
|
|
|
info->x = info->startX;
|
|
|
|
info->y += font_get_line_height_small(info->font_sprite_base);
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
case FORMAT_TINYFONT:
|
2015-07-26 14:58:53 +02:00
|
|
|
info->font_sprite_base = 448;
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
2015-07-26 18:50:01 +02:00
|
|
|
case FORMAT_SMALLFONT:
|
|
|
|
info->font_sprite_base = 0;
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
case FORMAT_MEDIUMFONT:
|
2015-07-26 14:58:53 +02:00
|
|
|
info->font_sprite_base = 224;
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
2015-07-26 18:50:01 +02:00
|
|
|
case FORMAT_BIGFONT:
|
|
|
|
info->font_sprite_base = 672;
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
case FORMAT_OUTLINE:
|
2015-07-26 14:58:53 +02:00
|
|
|
info->flags |= TEXT_DRAW_FLAG_OUTLINE;
|
|
|
|
break;
|
2015-07-26 01:55:17 +02:00
|
|
|
case FORMAT_OUTLINE_OFF:
|
2015-07-26 14:58:53 +02:00
|
|
|
info->flags &= ~TEXT_DRAW_FLAG_OUTLINE;
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
case FORMAT_WINDOW_COLOUR_1:
|
|
|
|
{
|
|
|
|
uint16 flags = info->flags;
|
2016-08-06 02:32:40 +02:00
|
|
|
colour_char_window(gCurrentWindowColours[0], &flags, info->palette);
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FORMAT_WINDOW_COLOUR_2:
|
|
|
|
{
|
|
|
|
uint16 flags = info->flags;
|
2016-08-06 02:32:40 +02:00
|
|
|
colour_char_window(gCurrentWindowColours[1], &flags, info->palette);
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case FORMAT_WINDOW_COLOUR_3:
|
|
|
|
{
|
|
|
|
uint16 flags = info->flags;
|
2016-08-06 02:32:40 +02:00
|
|
|
colour_char_window(gCurrentWindowColours[2], &flags, info->palette);
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 0x10:
|
|
|
|
break;
|
|
|
|
case FORMAT_INLINE_SPRITE:
|
2015-07-26 14:58:53 +02:00
|
|
|
{
|
2015-07-26 18:50:01 +02:00
|
|
|
uint32 imageId = *((uint32*)(nextCh));
|
2015-07-26 14:58:53 +02:00
|
|
|
rct_g1_element *g1Element = &g1Elements[imageId & 0x7FFFF];
|
|
|
|
if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW)) {
|
|
|
|
gfx_draw_sprite(dpi, imageId, info->x, info->y, 0);
|
|
|
|
}
|
|
|
|
info->x += g1Element->width;
|
2015-07-26 18:50:01 +02:00
|
|
|
nextCh += 4;
|
2015-07-26 01:55:17 +02:00
|
|
|
break;
|
2015-07-26 14:58:53 +02:00
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
default:
|
|
|
|
if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END) {
|
|
|
|
uint16 flags = info->flags;
|
2015-07-26 14:58:53 +02:00
|
|
|
colour_char(codepoint - FORMAT_COLOUR_CODE_START, &flags, info->palette);
|
2015-07-26 01:55:17 +02:00
|
|
|
} else if (codepoint <= 0x16) { //case 0x11? FORMAT_NEW_LINE_X_Y
|
|
|
|
nextCh += 2;
|
|
|
|
} else {
|
|
|
|
nextCh += 4;//never happens?
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return nextCh;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const utf8 *ttf_process_glyph_run(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info)
|
|
|
|
{
|
|
|
|
utf8 buffer[512];
|
|
|
|
const utf8 *ch = text;
|
2015-07-26 18:50:01 +02:00
|
|
|
const utf8 *lastCh;
|
2015-07-26 01:55:17 +02:00
|
|
|
int codepoint;
|
|
|
|
|
2015-07-27 02:09:24 +02:00
|
|
|
bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF;
|
2015-07-26 18:50:01 +02:00
|
|
|
while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &lastCh))) {
|
2015-07-27 02:09:24 +02:00
|
|
|
if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint)) {
|
|
|
|
break;
|
|
|
|
}
|
2015-07-26 18:50:01 +02:00
|
|
|
ch = lastCh;
|
|
|
|
}
|
2015-07-26 01:55:17 +02:00
|
|
|
if (codepoint == 0) {
|
|
|
|
ttf_draw_string_raw(dpi, text, info);
|
2015-07-26 18:50:01 +02:00
|
|
|
return ch;
|
2015-07-26 01:55:17 +02:00
|
|
|
} else {
|
2016-08-28 00:32:15 +02:00
|
|
|
size_t length = (size_t)(ch - text);
|
2015-07-26 01:55:17 +02:00
|
|
|
memcpy(buffer, text, length);
|
|
|
|
buffer[length] = 0;
|
|
|
|
ttf_draw_string_raw(dpi, buffer, info);
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-26 14:58:53 +02:00
|
|
|
static void ttf_process_string(rct_drawpixelinfo *dpi, const utf8 *text, text_draw_info *info)
|
2015-07-26 01:55:17 +02:00
|
|
|
{
|
|
|
|
const utf8 *ch = text;
|
|
|
|
const utf8 *nextCh;
|
|
|
|
int codepoint;
|
2015-07-26 18:50:01 +02:00
|
|
|
|
|
|
|
bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF;
|
|
|
|
|
2015-07-26 01:55:17 +02:00
|
|
|
while ((codepoint = utf8_get_next(ch, &nextCh)) != 0) {
|
|
|
|
if (utf8_is_format_code(codepoint)) {
|
2015-07-26 14:58:53 +02:00
|
|
|
ch = ttf_process_format_code(dpi, ch, info);
|
2015-07-26 18:50:01 +02:00
|
|
|
} else if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint)) {
|
2015-07-27 02:09:24 +02:00
|
|
|
ttf_draw_character_sprite(dpi, codepoint, info);
|
|
|
|
ch = nextCh;
|
2015-07-26 01:55:17 +02:00
|
|
|
} else {
|
2015-07-26 14:58:53 +02:00
|
|
|
ch = ttf_process_glyph_run(dpi, ch, info);
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
2015-07-31 20:05:00 +02:00
|
|
|
info->maxX = max(info->maxX, info->x);
|
|
|
|
info->maxY = max(info->maxY, info->y);
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
2015-07-26 14:58:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ttf_process_initial_colour(int colour, text_draw_info *info)
|
|
|
|
{
|
2016-11-16 14:24:39 +01:00
|
|
|
if (colour != TEXT_COLOUR_254 && colour != TEXT_COLOUR_255) {
|
|
|
|
info->flags &= ~(TEXT_DRAW_FLAG_INSET | TEXT_DRAW_FLAG_OUTLINE | TEXT_DRAW_FLAG_DARK | TEXT_DRAW_FLAG_EXTRA_DARK);
|
2015-07-27 02:09:24 +02:00
|
|
|
if ((sint16)info->font_sprite_base < 0) {
|
2016-11-16 14:24:39 +01:00
|
|
|
info->flags |= TEXT_DRAW_FLAG_DARK;
|
|
|
|
if ((sint16)info->font_sprite_base == FONT_SPRITE_BASE_MEDIUM_EXTRA_DARK) {
|
|
|
|
info->flags |= TEXT_DRAW_FLAG_EXTRA_DARK;
|
2015-07-26 14:58:53 +02:00
|
|
|
}
|
2016-11-16 14:24:39 +01:00
|
|
|
info->font_sprite_base = FONT_SPRITE_BASE_MEDIUM;
|
2015-07-26 14:58:53 +02:00
|
|
|
}
|
2016-08-06 19:47:55 +02:00
|
|
|
if (colour & COLOUR_FLAG_OUTLINE) {
|
2015-07-26 14:58:53 +02:00
|
|
|
info->flags |= TEXT_DRAW_FLAG_OUTLINE;
|
|
|
|
}
|
2016-08-06 19:47:55 +02:00
|
|
|
colour &= ~COLOUR_FLAG_OUTLINE;
|
|
|
|
if (!(colour & COLOUR_FLAG_INSET)) {
|
|
|
|
if (!(info->flags & TEXT_DRAW_FLAG_INSET)) {
|
2015-07-26 14:58:53 +02:00
|
|
|
uint16 flags = info->flags;
|
|
|
|
colour_char_window(colour, &flags, (uint8*)&info->palette);
|
|
|
|
}
|
|
|
|
} else {
|
2016-08-06 19:47:55 +02:00
|
|
|
info->flags |= TEXT_DRAW_FLAG_INSET;
|
|
|
|
colour &= ~COLOUR_FLAG_INSET;
|
2015-07-26 14:58:53 +02:00
|
|
|
|
|
|
|
uint32 eax;
|
2016-11-16 14:24:39 +01:00
|
|
|
if (info->flags & TEXT_DRAW_FLAG_DARK) {
|
|
|
|
if (info->flags & TEXT_DRAW_FLAG_EXTRA_DARK) {
|
2015-11-08 19:55:32 +01:00
|
|
|
eax = ColourMapA[colour].mid_light;
|
2015-07-26 14:58:53 +02:00
|
|
|
eax = eax << 16;
|
2015-11-08 19:55:32 +01:00
|
|
|
eax = eax | ColourMapA[colour].dark;
|
2015-07-26 14:58:53 +02:00
|
|
|
} else {
|
2015-11-08 19:55:32 +01:00
|
|
|
eax = ColourMapA[colour].light;
|
2015-07-26 14:58:53 +02:00
|
|
|
eax = eax << 16;
|
2015-11-08 19:55:32 +01:00
|
|
|
eax = eax | ColourMapA[colour].mid_dark;
|
2015-07-26 14:58:53 +02:00
|
|
|
}
|
|
|
|
} else {
|
2015-11-08 19:55:32 +01:00
|
|
|
eax = ColourMapA[colour].lighter;
|
2015-07-26 14:58:53 +02:00
|
|
|
eax = eax << 16;
|
2015-11-08 19:55:32 +01:00
|
|
|
eax = eax | ColourMapA[colour].mid_light;
|
2015-07-26 14:58:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust text palette. Store current colour? ;
|
|
|
|
info->palette[1] = eax & 0xFF;
|
|
|
|
info->palette[2] = (eax >> 8) & 0xFF;
|
|
|
|
info->palette[3] = (eax >> 16) & 0xFF;
|
|
|
|
info->palette[4] = (eax >> 24) & 0xFF;
|
2016-04-24 13:31:13 +02:00
|
|
|
unk_9ABDA4 = &info->palette;
|
2015-07-26 14:58:53 +02:00
|
|
|
eax = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int x, int y)
|
|
|
|
{
|
2015-08-16 17:36:57 +02:00
|
|
|
if (text == NULL) return;
|
|
|
|
|
2015-07-26 14:58:53 +02:00
|
|
|
text_draw_info info;
|
2016-04-26 00:00:58 +02:00
|
|
|
info.font_sprite_base = gCurrentFontSpriteBase;
|
|
|
|
info.flags = gCurrentFontFlags;
|
2015-07-26 18:50:01 +02:00
|
|
|
info.startX = x;
|
|
|
|
info.startY = x;
|
2015-07-26 14:58:53 +02:00
|
|
|
info.x = x;
|
|
|
|
info.y = y;
|
|
|
|
|
2015-07-26 18:50:01 +02:00
|
|
|
if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF;
|
2015-07-26 14:58:53 +02:00
|
|
|
|
2015-07-26 18:50:01 +02:00
|
|
|
memcpy(info.palette, text_palette, sizeof(info.palette));
|
2015-07-26 14:58:53 +02:00
|
|
|
ttf_process_initial_colour(colour, &info);
|
|
|
|
ttf_process_string(dpi, text, &info);
|
2015-07-26 18:50:01 +02:00
|
|
|
memcpy(text_palette, info.palette, sizeof(info.palette));
|
2015-07-26 01:55:17 +02:00
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = info.font_sprite_base;
|
|
|
|
gCurrentFontFlags = info.flags;
|
2015-07-26 19:47:26 +02:00
|
|
|
|
2015-07-26 01:55:17 +02:00
|
|
|
gLastDrawStringX = info.x;
|
|
|
|
gLastDrawStringY = info.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ttf_get_string_width(const utf8 *text)
|
|
|
|
{
|
|
|
|
text_draw_info info;
|
2016-04-26 00:00:58 +02:00
|
|
|
info.font_sprite_base = gCurrentFontSpriteBase;
|
|
|
|
info.flags = gCurrentFontFlags;
|
2015-07-26 18:50:01 +02:00
|
|
|
info.startX = 0;
|
|
|
|
info.startY = 0;
|
2015-07-26 01:55:17 +02:00
|
|
|
info.x = 0;
|
|
|
|
info.y = 0;
|
2015-07-31 20:05:00 +02:00
|
|
|
info.maxX = 0;
|
|
|
|
info.maxY = 0;
|
2015-07-26 01:55:17 +02:00
|
|
|
|
|
|
|
info.flags |= TEXT_DRAW_FLAG_NO_DRAW;
|
2015-07-26 18:50:01 +02:00
|
|
|
if (gUseTrueTypeFont) info.flags |= TEXT_DRAW_FLAG_TTF;
|
2015-07-26 01:55:17 +02:00
|
|
|
|
2015-07-26 14:58:53 +02:00
|
|
|
ttf_process_string(NULL, text, &info);
|
2015-07-26 01:55:17 +02:00
|
|
|
|
2015-07-31 20:05:00 +02:00
|
|
|
return info.maxX;
|
2015-07-26 01:55:17 +02:00
|
|
|
}
|
2015-08-03 19:06:54 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* rct2: 0x00682F28
|
|
|
|
*/
|
2015-11-28 13:10:17 +01:00
|
|
|
void gfx_draw_string_with_y_offsets(rct_drawpixelinfo *dpi, const utf8 *text, int colour, int x, int y, const sint8 *yOffsets, bool forceSpriteFont)
|
2015-08-03 19:06:54 +02:00
|
|
|
{
|
|
|
|
text_draw_info info;
|
2016-04-26 00:00:58 +02:00
|
|
|
info.font_sprite_base = gCurrentFontSpriteBase;
|
|
|
|
info.flags = gCurrentFontFlags;
|
2015-08-03 19:06:54 +02:00
|
|
|
info.startX = x;
|
|
|
|
info.startY = x;
|
|
|
|
info.x = x;
|
|
|
|
info.y = y;
|
|
|
|
info.y_offset = yOffsets;
|
|
|
|
|
|
|
|
info.flags |= TEXT_DRAW_FLAG_Y_OFFSET_EFFECT;
|
|
|
|
|
2015-11-28 13:10:17 +01:00
|
|
|
if (!forceSpriteFont && gUseTrueTypeFont) {
|
|
|
|
info.flags |= TEXT_DRAW_FLAG_TTF;
|
|
|
|
}
|
2015-08-03 19:06:54 +02:00
|
|
|
|
|
|
|
memcpy(info.palette, text_palette, sizeof(info.palette));
|
|
|
|
ttf_process_initial_colour(colour, &info);
|
|
|
|
ttf_process_string(dpi, text, &info);
|
|
|
|
memcpy(text_palette, info.palette, sizeof(info.palette));
|
|
|
|
|
2016-04-26 00:00:58 +02:00
|
|
|
gCurrentFontSpriteBase = info.font_sprite_base;
|
|
|
|
gCurrentFontFlags = info.flags;
|
2015-08-03 19:06:54 +02:00
|
|
|
|
|
|
|
gLastDrawStringX = info.x;
|
|
|
|
gLastDrawStringY = info.y;
|
|
|
|
}
|
2016-01-02 23:41:35 +01:00
|
|
|
|
|
|
|
void shorten_path(utf8 *buffer, size_t bufferSize, const utf8 *path, int availableWidth)
|
|
|
|
{
|
2016-08-28 00:32:15 +02:00
|
|
|
size_t length = strlen(path);
|
2016-01-02 23:41:35 +01:00
|
|
|
|
|
|
|
// Return full string if it fits
|
|
|
|
if (gfx_get_string_width((char*)path) <= availableWidth) {
|
2016-01-18 20:49:52 +01:00
|
|
|
safe_strcpy(buffer, path, bufferSize);
|
2016-01-02 23:41:35 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Count path separators
|
|
|
|
int path_separators = 0;
|
2016-08-28 00:32:15 +02:00
|
|
|
for (size_t x = 0; x < length; x++) {
|
2016-09-26 04:24:29 +02:00
|
|
|
if (path[x] == *PATH_SEPARATOR) {
|
2016-01-02 23:41:35 +01:00
|
|
|
path_separators++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Replace with unicode ellipsis when supported
|
2016-01-18 20:49:52 +01:00
|
|
|
safe_strcpy(buffer, "...", bufferSize);
|
2016-01-02 23:41:35 +01:00
|
|
|
|
|
|
|
// Abreviate beginning with xth separator
|
|
|
|
int begin = -1;
|
|
|
|
for (int x = 0; x < path_separators; x++){
|
|
|
|
do {
|
|
|
|
begin++;
|
2016-09-26 04:24:29 +02:00
|
|
|
} while (path[begin] != *PATH_SEPARATOR);
|
2016-01-02 23:41:35 +01:00
|
|
|
|
2016-01-18 20:49:52 +01:00
|
|
|
safe_strcpy(buffer + 3, path + begin, bufferSize - 3);
|
2016-01-02 23:41:35 +01:00
|
|
|
if (gfx_get_string_width(buffer) <= availableWidth) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-01-18 20:49:52 +01:00
|
|
|
safe_strcpy(buffer, path, bufferSize);
|
2016-01-02 23:41:35 +01:00
|
|
|
}
|