1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-24 00:03:11 +01:00

Start eradicating old format codes

This commit is contained in:
Ted John
2020-10-13 01:14:39 +01:00
parent eebababa90
commit 2f7c1aab14
12 changed files with 340 additions and 271 deletions

View File

@@ -42,7 +42,7 @@ namespace String
bool IsNullOrEmpty(const utf8* str);
int32_t Compare(const std::string& a, const std::string& b, bool ignoreCase = false);
int32_t Compare(const utf8* a, const utf8* b, bool ignoreCase = false);
bool Equals(const std::string_view& a, const std::string_view& b, bool ignoreCase);
bool Equals(const std::string_view& a, const std::string_view& b, bool ignoreCase = false);
bool Equals(const std::string& a, const std::string& b, bool ignoreCase = false);
bool Equals(const utf8* a, const utf8* b, bool ignoreCase = false);
bool StartsWith(const utf8* str, const utf8* match, bool ignoreCase = false);

View File

@@ -11,6 +11,7 @@
#include "../config/Config.h"
#include "../drawing/Drawing.h"
#include "../interface/Viewport.h"
#include "../localisation/Formatting.h"
#include "../localisation/Localisation.h"
#include "../localisation/LocalisationService.h"
#include "../platform/platform.h"
@@ -20,6 +21,83 @@
#include <algorithm>
using namespace OpenRCT2;
class CodepointView
{
private:
std::string_view _str;
public:
class iterator
{
private:
std::string_view _str;
size_t _index;
public:
iterator(std::string_view str, size_t index)
: _str(str)
, _index(index)
{
}
bool operator==(const iterator& rhs) const
{
return _index == rhs._index;
}
bool operator!=(const iterator& rhs) const
{
return _index != rhs._index;
}
const char32_t operator*() const
{
return utf8_get_next(&_str[_index], nullptr);
}
iterator& operator++()
{
if (_index < _str.size())
{
const utf8* nextch;
utf8_get_next(&_str[_index], &nextch);
_index = nextch - _str.data();
}
return *this;
}
iterator operator++(int)
{
auto result = *this;
if (_index < _str.size())
{
const utf8* nextch;
utf8_get_next(&_str[_index], &nextch);
_index = nextch - _str.data();
}
return result;
}
size_t GetIndex() const
{
return _index;
}
};
CodepointView(std::string_view str)
: _str(str)
{
}
iterator begin() const
{
return iterator(_str, 0);
}
iterator end() const
{
return iterator(_str, _str.size());
}
};
enum : uint32_t
{
TEXT_DRAW_FLAG_INSET = 1 << 0,
@@ -31,7 +109,7 @@ enum : uint32_t
TEXT_DRAW_FLAG_NO_DRAW = 1u << 31
};
static int32_t ttf_get_string_width(const utf8* text);
static int32_t ttf_get_string_width(std::string_view text);
/**
*
@@ -69,9 +147,9 @@ int32_t gfx_get_string_width_new_lined(utf8* text)
* rct2: 0x006C2321
* buffer (esi)
*/
int32_t gfx_get_string_width(const utf8* buffer)
int32_t gfx_get_string_width(std::string_view text)
{
return ttf_get_string_width(buffer);
return ttf_get_string_width(text);
}
/**
@@ -161,84 +239,84 @@ int32_t gfx_clip_string(utf8* text, int32_t width)
*/
int32_t gfx_wrap_string(utf8* text, int32_t width, int32_t* outNumLines, int32_t* outFontHeight)
{
int32_t lineWidth = 0;
constexpr size_t NULL_INDEX = std::numeric_limits<size_t>::max();
thread_local std::string buffer;
buffer.resize(0);
size_t currentLineIndex = 0;
size_t splitIndex = NULL_INDEX;
size_t numLines = 0;
int32_t maxWidth = 0;
*outNumLines = 0;
// Pointer to the start of the current word
utf8* currentWord = nullptr;
// Width of line up to current word
int32_t currentWidth = 0;
utf8* ch = text;
utf8* firstCh = text;
utf8* nextCh;
int32_t codepoint;
int32_t numCharactersOnLine = 0;
while ((codepoint = utf8_get_next(ch, const_cast<const utf8**>(&nextCh))) != 0)
FmtString fmt = text;
for (const auto& token : fmt)
{
if (codepoint == ' ')
if (token.IsLiteral())
{
currentWord = ch;
currentWidth = lineWidth;
numCharactersOnLine++;
}
else if (codepoint == FORMAT_NEWLINE)
{
*ch++ = 0;
maxWidth = std::max(maxWidth, lineWidth);
(*outNumLines)++;
lineWidth = 0;
currentWord = nullptr;
firstCh = ch;
numCharactersOnLine = 0;
continue;
}
else if (utf8_is_format_code(codepoint))
{
ch = nextCh;
ch += utf8_get_format_code_arg_length(codepoint);
continue;
}
CodepointView codepoints(token.text);
for (auto codepoint : codepoints)
{
buffer.push_back(codepoint);
uint8_t saveCh = *nextCh;
*nextCh = 0;
lineWidth = gfx_get_string_width(firstCh);
*nextCh = saveCh;
auto lineWidth = gfx_get_string_width(&buffer[currentLineIndex]);
if (lineWidth <= width || splitIndex == NULL_INDEX)
{
if (codepoint == ' ')
{
// Mark line split here
splitIndex = buffer.size() - 1;
}
else if (splitIndex == NULL_INDEX)
{
// Mark line split here (this is after first character of line)
splitIndex = buffer.size();
}
}
else
{
// Insert new line before current word
buffer.insert(buffer.begin() + splitIndex, '\0');
if (lineWidth <= width || numCharactersOnLine == 0)
{
ch = nextCh;
numCharactersOnLine++;
// Recalculate the line length after splitting
lineWidth = gfx_get_string_width(&buffer[currentLineIndex]);
maxWidth = std::max(maxWidth, lineWidth);
numLines++;
currentLineIndex = splitIndex + 1;
splitIndex = NULL_INDEX;
// Trim the beginning of the new line
while (buffer[currentLineIndex] == ' ')
{
buffer.erase(buffer.begin() + currentLineIndex);
}
}
}
}
else if (currentWord == nullptr)
else if (token.kind == FORMAT_NEWLINE)
{
// Single word is longer than line, insert null terminator
ch += utf8_insert_codepoint(ch, 0);
buffer.push_back('\0');
auto lineWidth = gfx_get_string_width(&buffer[currentLineIndex]);
maxWidth = std::max(maxWidth, lineWidth);
(*outNumLines)++;
lineWidth = 0;
currentWord = nullptr;
firstCh = ch;
numCharactersOnLine = 0;
numLines++;
splitIndex = buffer.size();
}
else
{
ch = currentWord;
*ch++ = 0;
maxWidth = std::max(maxWidth, currentWidth);
(*outNumLines)++;
lineWidth = 0;
currentWord = nullptr;
firstCh = ch;
numCharactersOnLine = 0;
buffer.append(token.text);
}
}
maxWidth = std::max(maxWidth, lineWidth);
{
// Final line width calculation
auto lineWidth = gfx_get_string_width(&buffer[currentLineIndex]);
maxWidth = std::max(maxWidth, lineWidth);
}
std::memcpy(text, buffer.data(), buffer.size() + 1);
*outNumLines = static_cast<int32_t>(numLines);
*outFontHeight = gCurrentFontSpriteBase;
return maxWidth == 0 ? lineWidth : maxWidth;
return maxWidth;
}
/**
@@ -509,20 +587,18 @@ static void ttf_draw_character_sprite(rct_drawpixelinfo* dpi, int32_t codepoint,
info->x += characterWidth;
}
static void ttf_draw_string_raw_sprite(rct_drawpixelinfo* dpi, const utf8* text, text_draw_info* info)
static void ttf_draw_string_raw_sprite(rct_drawpixelinfo* dpi, const std::string_view text, text_draw_info* info)
{
const utf8* ch = text;
int32_t codepoint;
while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &ch)))
CodepointView codepoints(text);
for (auto codepoint : codepoints)
{
ttf_draw_character_sprite(dpi, codepoint, info);
};
}
}
#ifndef NO_TTF
static void ttf_draw_string_raw_ttf(rct_drawpixelinfo* dpi, const utf8* text, text_draw_info* info)
static void ttf_draw_string_raw_ttf(rct_drawpixelinfo* dpi, std::string_view text, text_draw_info* info)
{
if (!ttf_initialise())
return;
@@ -670,58 +746,38 @@ static void ttf_draw_string_raw_ttf(rct_drawpixelinfo* dpi, const utf8* text, te
#endif // NO_TTF
static void ttf_draw_string_raw(rct_drawpixelinfo* dpi, const utf8* text, text_draw_info* info)
static void ttf_process_format_code(rct_drawpixelinfo* dpi, const FmtString::token& token, text_draw_info* info)
{
#ifndef NO_TTF
if (info->flags & TEXT_DRAW_FLAG_TTF)
{
ttf_draw_string_raw_ttf(dpi, text, info);
}
else
{
#endif // NO_TTF
ttf_draw_string_raw_sprite(dpi, text, info);
#ifndef NO_TTF
}
#endif // NO_TTF
}
static const utf8* ttf_process_format_code(rct_drawpixelinfo* dpi, const utf8* text, text_draw_info* info)
{
const utf8* nextCh;
int32_t codepoint;
codepoint = utf8_get_next(text, &nextCh);
switch (codepoint)
switch (token.kind)
{
case FORMAT_MOVE_X:
info->x = info->startX + static_cast<uint8_t>(*nextCh++);
// info->x = info->startX + static_cast<uint8_t>(*nextCh++);
break;
case FORMAT_ADJUST_PALETTE:
{
auto paletteMapId = static_cast<colour_t>(*nextCh++);
auto paletteMap = GetPaletteMapForColour(paletteMapId);
if (paletteMap)
{
uint32_t c = (*paletteMap)[249] + 256;
if (!(info->flags & TEXT_DRAW_FLAG_OUTLINE))
{
c &= 0xFF;
}
info->palette[1] = c & 0xFF;
info->palette[2] = (c >> 8) & 0xFF;
// Adjust the text palette
info->palette[3] = (*paletteMap)[247];
info->palette[4] = (*paletteMap)[248];
info->palette[5] = (*paletteMap)[250];
info->palette[6] = (*paletteMap)[251];
}
// auto paletteMapId = static_cast<colour_t>(*nextCh++);
// auto paletteMap = GetPaletteMapForColour(paletteMapId);
// if (paletteMap)
// {
// uint32_t c = (*paletteMap)[249] + 256;
// if (!(info->flags & TEXT_DRAW_FLAG_OUTLINE))
// {
// c &= 0xFF;
// }
// info->palette[1] = c & 0xFF;
// info->palette[2] = (c >> 8) & 0xFF;
//
// // Adjust the text palette
// info->palette[3] = (*paletteMap)[247];
// info->palette[4] = (*paletteMap)[248];
// info->palette[5] = (*paletteMap)[250];
// info->palette[6] = (*paletteMap)[251];
// }
break;
}
case FORMAT_3:
case FORMAT_4:
nextCh++;
// nextCh++;
break;
case FORMAT_NEWLINE:
info->x = info->startX;
@@ -766,102 +822,89 @@ static const utf8* ttf_process_format_code(rct_drawpixelinfo* dpi, const utf8* t
}
case FORMAT_16:
break;
case FORMAT_INLINE_SPRITE:
{
uint32_t imageId;
std::memcpy(&imageId, nextCh, sizeof(uint32_t));
const rct_g1_element* g1 = gfx_get_g1_element(imageId & 0x7FFFF);
if (g1 != nullptr)
{
if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW))
{
gfx_draw_sprite(dpi, imageId, { info->x, info->y }, 0);
}
info->x += g1->width;
}
nextCh += 4;
break;
}
// case FORMAT_INLINE_SPRITE:
// {
// uint32_t imageId;
// std::memcpy(&imageId, nextCh, sizeof(uint32_t));
// const rct_g1_element* g1 = gfx_get_g1_element(imageId & 0x7FFFF);
// if (g1 != nullptr)
// {
// if (!(info->flags & TEXT_DRAW_FLAG_NO_DRAW))
// {
// gfx_draw_sprite(dpi, imageId, { info->x, info->y }, 0);
// }
// info->x += g1->width;
// }
// nextCh += 4;
// break;
// }
default:
if (codepoint >= FORMAT_COLOUR_CODE_START && codepoint <= FORMAT_COLOUR_CODE_END)
if (token.kind >= FORMAT_COLOUR_CODE_START && token.kind <= FORMAT_COLOUR_CODE_END)
{
uint16_t flags = info->flags;
colour_char(codepoint - FORMAT_COLOUR_CODE_START, &flags, info->palette);
colour_char(token.kind - FORMAT_COLOUR_CODE_START, &flags, info->palette);
}
else if (codepoint <= 0x16)
else if (token.kind <= 0x16)
{ // case 0x11? FORMAT_NEW_LINE_X_Y
nextCh += 2;
// nextCh += 2;
}
else
{
nextCh += 4; // never happens?
// nextCh += 4; // never happens?
}
break;
}
return nextCh;
}
static const utf8* ttf_process_glyph_run(rct_drawpixelinfo* dpi, const utf8* text, text_draw_info* info)
static void ttf_process_string_literal(rct_drawpixelinfo* dpi, const std::string_view text, text_draw_info* info)
{
utf8 buffer[512];
const utf8* ch = text;
const utf8* lastCh;
int32_t codepoint;
#ifndef NO_TTF
bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF;
#else
bool isTTF = false;
#endif // NO_TTF
while (!utf8_is_format_code(codepoint = utf8_get_next(ch, &lastCh)))
if (!isTTF)
{
if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint))
{
break;
}
ch = lastCh;
}
if (codepoint == 0)
{
ttf_draw_string_raw(dpi, text, info);
return ch;
ttf_draw_string_raw_sprite(dpi, text, info);
}
else
{
size_t length = static_cast<size_t>(ch - text);
std::memcpy(buffer, text, length);
buffer[length] = 0;
ttf_draw_string_raw(dpi, buffer, info);
return ch;
CodepointView codepoints(text);
size_t ttfRunIndex = 0;
for (auto it = codepoints.begin(); it != codepoints.end(); it++)
{
auto codepoint = *it;
if (utf8_should_use_sprite_for_codepoint(codepoint))
{
auto index = it.GetIndex();
auto ttfLen = index - ttfRunIndex;
if (ttfLen > 0)
{
// Draw the TTF run
ttf_draw_string_raw_ttf(dpi, text.substr(ttfRunIndex, ttfLen), info);
}
ttfRunIndex = index;
// Draw the sprite font glyph
ttf_draw_character_sprite(dpi, codepoint, info);
}
}
}
}
static void ttf_process_string(rct_drawpixelinfo* dpi, const utf8* text, text_draw_info* info)
static void ttf_process_string(rct_drawpixelinfo* dpi, std::string_view text, text_draw_info* info)
{
const utf8* ch = text;
const utf8* nextCh;
int32_t codepoint;
#ifndef NO_TTF
bool isTTF = info->flags & TEXT_DRAW_FLAG_TTF;
#else
bool isTTF = false;
#endif // NO_TTF
while ((codepoint = utf8_get_next(ch, &nextCh)) != 0)
FmtString fmt(text);
for (const auto& token : fmt)
{
if (utf8_is_format_code(codepoint))
if (token.IsLiteral())
{
ch = ttf_process_format_code(dpi, ch, info);
}
else if (isTTF && utf8_should_use_sprite_for_codepoint(codepoint))
{
ttf_draw_character_sprite(dpi, codepoint, info);
ch = nextCh;
ttf_process_string_literal(dpi, token.text, info);
}
else
{
ch = ttf_process_glyph_run(dpi, ch, info);
ttf_process_format_code(dpi, token, info);
}
info->maxX = std::max(info->maxX, info->x);
info->maxY = std::max(info->maxY, info->y);
@@ -963,7 +1006,7 @@ void ttf_draw_string(rct_drawpixelinfo* dpi, const_utf8string text, int32_t colo
gLastDrawStringY = info.y;
}
static int32_t ttf_get_string_width(const utf8* text)
static int32_t ttf_get_string_width(std::string_view text)
{
text_draw_info info;
info.font_sprite_base = gCurrentFontSpriteBase;

View File

@@ -757,7 +757,7 @@ void gfx_draw_string_with_y_offsets(
bool forceSpriteFont);
int32_t gfx_wrap_string(char* buffer, int32_t width, int32_t* num_lines, int32_t* font_height);
int32_t gfx_get_string_width(const utf8* buffer);
int32_t gfx_get_string_width(std::string_view text);
int32_t gfx_get_string_width_new_lined(char* buffer);
int32_t string_get_height_raw(char* buffer);
int32_t gfx_clip_string(char* buffer, int32_t width);

View File

@@ -19,6 +19,7 @@
# include "../OpenRCT2.h"
# include "../config/Config.h"
# include "../core/String.hpp"
# include "../localisation/Localisation.h"
# include "../localisation/LocalisationService.h"
# include "../platform/platform.h"
@@ -63,9 +64,9 @@ static uint32_t 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 bool ttf_get_size(TTF_Font* font, const utf8* text, int32_t* width, int32_t* height);
static bool ttf_get_size(TTF_Font* font, std::string_view text, int32_t* outWidth, int32_t* outHeight);
static void ttf_toggle_hinting(bool);
static TTFSurface* ttf_render(TTF_Font* font, const utf8* text);
static TTFSurface* ttf_render(TTF_Font* font, std::string_view text);
template<typename T> class FontLockHelper
{
@@ -181,12 +182,12 @@ static void ttf_close_font(TTF_Font* font)
TTF_CloseFont(font);
}
static uint32_t ttf_surface_cache_hash(TTF_Font* font, const utf8* text)
static uint32_t ttf_surface_cache_hash(TTF_Font* font, std::string_view text)
{
uint32_t hash = static_cast<uint32_t>(((reinterpret_cast<uintptr_t>(font) * 23) ^ 0xAAAAAAAA) & 0xFFFFFFFF);
for (const utf8* ch = text; *ch != 0; ch++)
for (size_t i = 0; i < text.size(); i++)
{
hash = ror32(hash, 3) ^ (*ch * 13);
hash = ror32(hash, 3) ^ (text[i] * 13);
}
return hash;
}
@@ -219,7 +220,7 @@ void ttf_toggle_hinting()
ttf_toggle_hinting(true);
}
TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, const utf8* text)
TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, std::string_view text)
{
ttf_cache_entry* entry;
@@ -235,7 +236,7 @@ TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, const utf8* text)
// Check if entry is a hit
if (entry->surface == nullptr)
break;
if (entry->font == font && strcmp(entry->text, text) == 0)
if (entry->font == font && String::Equals(entry->text, text))
{
_ttfSurfaceCacheHitCount++;
entry->lastUseTick = gCurrentDrawCount;
@@ -269,7 +270,7 @@ TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, const utf8* text)
_ttfSurfaceCacheCount++;
entry->surface = surface;
entry->font = font;
entry->text = _strdup(text);
entry->text = strndup(text.data(), text.size());
entry->lastUseTick = gCurrentDrawCount;
return entry->surface;
}
@@ -295,7 +296,7 @@ static void ttf_getwidth_cache_dispose_all()
}
}
uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, const utf8* text)
uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, std::string_view text)
{
ttf_getwidth_cache_entry* entry;
@@ -311,7 +312,7 @@ uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, const utf8* text)
// Check if entry is a hit
if (entry->text == nullptr)
break;
if (entry->font == font && strcmp(entry->text, text) == 0)
if (entry->font == font && String::Equals(entry->text, text))
{
_ttfGetWidthCacheHitCount++;
entry->lastUseTick = gCurrentDrawCount;
@@ -341,7 +342,7 @@ uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, const utf8* text)
_ttfGetWidthCacheCount++;
entry->width = width;
entry->font = font;
entry->text = _strdup(text);
entry->text = strndup(text.data(), text.size());
entry->lastUseTick = gCurrentDrawCount;
return entry->width;
}
@@ -357,20 +358,24 @@ bool ttf_provides_glyph(const TTF_Font* font, codepoint_t codepoint)
return TTF_GlyphIsProvided(font, codepoint);
}
static bool ttf_get_size(TTF_Font* font, const utf8* text, int32_t* outWidth, int32_t* outHeight)
static bool ttf_get_size(TTF_Font* font, std::string_view text, int32_t* outWidth, int32_t* outHeight)
{
return TTF_SizeUTF8(font, text, outWidth, outHeight);
thread_local std::string buffer;
buffer.assign(text);
return TTF_SizeUTF8(font, buffer.c_str(), outWidth, outHeight);
}
static TTFSurface* ttf_render(TTF_Font* font, const utf8* text)
static TTFSurface* ttf_render(TTF_Font* font, std::string_view text)
{
thread_local std::string buffer;
buffer.assign(text);
if (TTF_GetFontHinting(font) != 0)
{
return TTF_RenderUTF8_Shaded(font, text, 0x000000FF, 0x000000FF);
return TTF_RenderUTF8_Shaded(font, buffer.c_str(), 0x000000FF, 0x000000FF);
}
else
{
return TTF_RenderUTF8_Solid(font, text, 0x000000FF);
return TTF_RenderUTF8_Solid(font, buffer.c_str(), 0x000000FF);
}
}

View File

@@ -11,6 +11,8 @@
#include "Font.h"
#include <string_view>
bool ttf_initialise();
void ttf_dispose();
@@ -26,8 +28,8 @@ struct TTFSurface
TTFFontDescriptor* ttf_get_font_from_sprite_base(uint16_t spriteBase);
void ttf_toggle_hinting();
TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, const utf8* text);
uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, const utf8* text);
TTFSurface* ttf_surface_cache_get_or_add(TTF_Font* font, std::string_view text);
uint32_t ttf_getwidth_cache_get_or_add(TTF_Font* font, std::string_view text);
bool ttf_provides_glyph(const TTF_Font* font, codepoint_t codepoint);
void ttf_free_surface(TTFSurface* surface);

View File

@@ -136,7 +136,7 @@ namespace OpenRCT2
}
FmtString::FmtString(const char* s)
: FmtString(std::string_view(s))
: FmtString(s == nullptr ? std::string_view() : std::string_view(s))
{
}
@@ -176,6 +176,18 @@ namespace OpenRCT2
return sz != nullptr ? sz : std::string_view();
}
void FormatRealName(std::stringstream& ss, rct_string_id id)
{
if (IsRealNameStringId(id))
{
auto realNameIndex = id - REAL_NAME_START;
ss << real_names[realNameIndex % std::size(real_names)];
ss << ' ';
ss << real_name_initials[(realNameIndex >> 10) % std::size(real_name_initials)];
ss << '.';
}
}
template<size_t TSize, typename TIndex> static void AppendSeperator(char (&buffer)[TSize], TIndex& i, std::string_view sep)
{
if (i < TSize)
@@ -468,13 +480,6 @@ namespace OpenRCT2
ss << arg.c_str();
}
break;
case FORMAT_STRINGID:
case FORMAT_STRINGID2:
if constexpr (std::is_integral<T>())
{
ss << language_get_string(arg);
}
break;
}
}
@@ -488,11 +493,15 @@ namespace OpenRCT2
return t == FORMAT_COMMA1DP16 || (t >= FORMAT_COMMA32 && t <= FORMAT_LENGTH);
}
bool IsRealNameStringId(rct_string_id id)
{
return id >= REAL_NAME_START && id <= REAL_NAME_END;
}
FmtString GetFmtStringById(rct_string_id id)
{
auto lang = language_get_string(id);
auto fmtc = language_convert_string_to_tokens(lang);
return FmtString(std::move(fmtc));
auto fmtc = language_get_string(id);
return FmtString(fmtc);
}
std::stringstream& GetThreadFormatStream()
@@ -547,8 +556,15 @@ namespace OpenRCT2
const auto& arg = args[argIndex++];
if (auto stringid = std::get_if<uint16_t>(&arg))
{
auto subfmt = GetFmtStringById(*stringid);
FormatStringAny(ss, subfmt, args, argIndex);
if (IsRealNameStringId(*stringid))
{
FormatRealName(ss, *stringid);
}
else
{
auto subfmt = GetFmtStringById(*stringid);
FormatStringAny(ss, subfmt, args, argIndex);
}
}
}
else
@@ -630,7 +646,6 @@ namespace OpenRCT2
{
auto sz = ReadFromArgs<const char*>(args);
anyArgs.push_back(sz);
BuildAnyArgListFromLegacyArgBuffer(sz, anyArgs, args);
break;
}
case FORMAT_POP16:
@@ -651,3 +666,8 @@ namespace OpenRCT2
return FormatStringAny(buffer, bufferLen, fmt, anyArgs);
}
} // namespace OpenRCT2
void format_string(utf8* dest, size_t size, rct_string_id format, const void* args)
{
OpenRCT2::FormatStringLegacy(dest, size, format, args);
}

View File

@@ -64,6 +64,7 @@ namespace OpenRCT2
bool eol() const;
};
FmtString() = default;
FmtString(std::string&& s);
FmtString(std::string_view s);
FmtString(const char* s);
@@ -76,6 +77,8 @@ namespace OpenRCT2
template<typename T> void FormatArgument(std::stringstream& ss, FormatToken token, T arg);
bool CanFormatToken(FormatToken t);
bool IsRealNameStringId(rct_string_id id);
void FormatRealName(std::stringstream& ss, rct_string_id id);
FmtString GetFmtStringById(rct_string_id id);
std::stringstream& GetThreadFormatStream();
size_t CopyStringStreamToBuffer(char* buffer, size_t bufferLen, std::stringstream& ss);
@@ -110,9 +113,17 @@ namespace OpenRCT2
{
if constexpr (std::is_integral<TArg0>())
{
auto subfmt = GetFmtStringById(static_cast<rct_string_id>(arg0));
auto subit = subfmt.begin();
stack.push(&subit);
auto stringId = static_cast<rct_string_id>(arg0);
if (IsRealNameStringId(stringId))
{
FormatRealName(ss, stringId);
}
else
{
auto subfmt = GetFmtStringById(stringId);
auto subit = subfmt.begin();
stack.push(&subit);
}
FormatString(ss, stack, argN...);
}
}
@@ -145,6 +156,14 @@ namespace OpenRCT2
return ss.str();
}
template<typename... TArgs>
size_t FormatStringToBuffer(char* buffer, size_t bufferLen, const FmtString& fmt, TArgs&&... argN)
{
auto& ss = GetThreadFormatStream();
FormatString(ss, fmt, argN...);
return CopyStringStreamToBuffer(buffer, bufferLen, ss);
}
template<typename... TArgs> static void FormatStringId(std::stringstream& ss, rct_string_id id, TArgs&&... argN)
{
auto fmt = GetFmtStringById(id);

View File

@@ -51,14 +51,6 @@ const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT] =
};
// clang-format on
// clang-format off
const utf8 BlackUpArrowString[] = { static_cast<utf8>(static_cast<uint8_t>(0xC2)), static_cast<utf8>(static_cast<uint8_t>(0x8E)), static_cast<utf8>(static_cast<uint8_t>(0xE2)), static_cast<utf8>(static_cast<uint8_t>(0x96)), static_cast<utf8>(static_cast<uint8_t>(0xB2)), static_cast<utf8>(static_cast<uint8_t>(0x00)) };
const utf8 BlackDownArrowString[] = { static_cast<utf8>(static_cast<uint8_t>(0xC2)), static_cast<utf8>(static_cast<uint8_t>(0x8E)), static_cast<utf8>(static_cast<uint8_t>(0xE2)), static_cast<utf8>(static_cast<uint8_t>(0x96)), static_cast<utf8>(static_cast<uint8_t>(0xBC)), static_cast<utf8>(static_cast<uint8_t>(0x00)) };
const utf8 BlackLeftArrowString[] = { static_cast<utf8>(static_cast<uint8_t>(0xC2)), static_cast<utf8>(static_cast<uint8_t>(0x8E)), static_cast<utf8>(static_cast<uint8_t>(0xE2)), static_cast<utf8>(static_cast<uint8_t>(0x97)), static_cast<utf8>(static_cast<uint8_t>(0x80)), static_cast<utf8>(static_cast<uint8_t>(0x00)) };
const utf8 BlackRightArrowString[] = { static_cast<utf8>(static_cast<uint8_t>(0xC2)), static_cast<utf8>(static_cast<uint8_t>(0x8E)), static_cast<utf8>(static_cast<uint8_t>(0xE2)), static_cast<utf8>(static_cast<uint8_t>(0x96)), static_cast<utf8>(static_cast<uint8_t>(0xB6)), static_cast<utf8>(static_cast<uint8_t>(0x00)) };
const utf8 CheckBoxMarkString[] = { static_cast<utf8>(static_cast<uint8_t>(0xE2)), static_cast<utf8>(static_cast<uint8_t>(0x9C)), static_cast<utf8>(static_cast<uint8_t>(0x93)), static_cast<utf8>(static_cast<uint8_t>(0x00)) };
// clang-format on
void utf8_remove_format_codes(utf8* text, bool allowcolours)
{
const utf8* ch = text;

View File

@@ -85,11 +85,11 @@ struct language_descriptor
extern const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT];
extern const utf8 BlackUpArrowString[];
extern const utf8 BlackDownArrowString[];
extern const utf8 BlackLeftArrowString[];
extern const utf8 BlackRightArrowString[];
extern const utf8 CheckBoxMarkString[];
constexpr const char* BlackUpArrowString = u8"{BLACK}▲";
constexpr const char* BlackDownArrowString = u8"{BLACK}▼";
constexpr const char* BlackLeftArrowString = u8"{BLACK}◀";
constexpr const char* BlackRightArrowString = u8"{BLACK}▶";
constexpr const char* CheckBoxMarkString = u8"";
uint8_t language_get_id_from_locale(const char* locale);
const char* language_get_string(rct_string_id id);

View File

@@ -539,28 +539,28 @@ private:
sb.Clear();
while (reader->TryPeek(&codepoint) && !IsNewLine(codepoint))
{
if (codepoint == '{')
{
uint32_t token;
bool isByte;
if (ParseToken(reader, &token, &isByte))
{
if (isByte)
{
sb.Append(reinterpret_cast<const utf8*>(&token), 1);
}
else
{
sb.Append(static_cast<int32_t>(token));
}
}
else
{
// Syntax error or unknown token, ignore line entirely
return;
}
}
else
// if (codepoint == '{')
// {
// uint32_t token;
// bool isByte;
// if (ParseToken(reader, &token, &isByte))
// {
// if (isByte)
// {
// sb.Append(reinterpret_cast<const utf8*>(&token), 1);
// }
// else
// {
// sb.Append(static_cast<int32_t>(token));
// }
// }
// else
// {
// // Syntax error or unknown token, ignore line entirely
// return;
// }
// }
// else
{
reader->Skip();
sb.Append(codepoint);

View File

@@ -1299,7 +1299,7 @@ std::string format_string(rct_string_id format, const void* args)
* format (ax)
* args (ecx)
*/
void format_string(utf8* dest, size_t size, rct_string_id format, const void* args)
void format_string_old(utf8* dest, size_t size, rct_string_id format, const void* args)
{
#ifdef DEBUG
if (gDebugStringFormatting)

View File

@@ -19,6 +19,7 @@
#include "../interface/Chat.h"
#include "../interface/InteractiveConsole.h"
#include "../localisation/FormatCodes.h"
#include "../localisation/Formatting.h"
#include "../localisation/Language.h"
#include "../paint/Paint.h"
#include "../title/TitleScreen.h"
@@ -83,16 +84,10 @@ void Painter::PaintReplayNotice(rct_drawpixelinfo* dpi, const char* text)
{
ScreenCoordsXY screenCoords(_uiContext->GetWidth() / 2, _uiContext->GetHeight() - 44);
// Format string
utf8 buffer[64] = { 0 };
utf8* ch = buffer;
ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
ch = utf8_write_codepoint(ch, FORMAT_OUTLINE);
ch = utf8_write_codepoint(ch, FORMAT_RED);
char buffer[64]{};
FormatStringToBuffer(buffer, sizeof(buffer), "{MEDIUMFONT}{OUTLINE}{RED}{STRING}", text);
snprintf(ch, 64 - (ch - buffer), "%s", text);
int32_t stringWidth = gfx_get_string_width(buffer);
auto stringWidth = gfx_get_string_width(buffer);
screenCoords.x = screenCoords.x - stringWidth;
if (((gCurrentTicks >> 1) & 0xF) > 4)
@@ -106,17 +101,10 @@ void Painter::PaintFPS(rct_drawpixelinfo* dpi)
{
ScreenCoordsXY screenCoords(_uiContext->GetWidth() / 2, 2);
// Measure FPS
MeasureFPS();
// Format string
utf8 buffer[64] = { 0 };
utf8* ch = buffer;
ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
ch = utf8_write_codepoint(ch, FORMAT_OUTLINE);
ch = utf8_write_codepoint(ch, FORMAT_WHITE);
snprintf(ch, 64 - (ch - buffer), "%d", _currentFPS);
char buffer[64]{};
FormatStringToBuffer(buffer, sizeof(buffer), "{MEDIUMFONT}{OUTLINE}{WHITE}{INT32}", _currentFPS);
// Draw Text
int32_t stringWidth = gfx_get_string_width(buffer);