1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-03 09:09:47 +02:00

rwengine+rwgame: convert utf8 to GameString depending on used font

This commit is contained in:
Anonymous Maarten 2017-09-07 19:00:16 +02:00
parent 12afe81a35
commit 640af372ba
17 changed files with 122 additions and 94 deletions

View File

@ -86,7 +86,7 @@ void Payphone::tick(float dt) {
if (!message.empty()) {
const auto& text =
ScreenText::format(engine->data->texts.text(message));
ScreenText::format(engine->data->texts.text(message), FONT_ARIAL);
engine->state->text.clear<ScreenTextType::HighPriority>();
engine->state->text.addText<ScreenTextType::HighPriority>(
@ -124,4 +124,4 @@ void Payphone::tick(float dt) {
default: { break; }
}
}
}

View File

@ -2,6 +2,8 @@
#include <rw/debug.hpp>
#include "fonts/FontMapGta3.hpp"
void ScreenText::tick(float dt) {
int millis = dt * 1000;
@ -35,7 +37,7 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
case 1:
return {str,
{320.f, 252.f},
1,
FONT_PRICEDOWN,
50,
{2, 0, 0, 0},
{58, 119, 133},
@ -54,7 +56,7 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
case 2:
return {str,
{620.f, 380.f},
1,
FONT_PRICEDOWN,
30,
{2, 3, 0, 0},
{214, 171, 9},
@ -73,7 +75,7 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
case 3:
return {str,
{320.f, 400.f},
1,
FONT_PRICEDOWN,
50,
{5, 5, 0, 0},
{169, 123, 88}, /// @todo verify
@ -93,7 +95,7 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
case 5:
return {str,
{320.f, 176.f},
2,
FONT_ARIAL,
50,
((style == 4) ? glm::u8vec4({2, 2, 0, 0})
: glm::u8vec4({-2, -2, 0, 0})),
@ -113,7 +115,7 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
case 6:
return {str,
{320.f, 240.f},
2,
FONT_ARIAL,
50,
{2, 2, 0, 0},
{152, 89, 39},
@ -128,9 +130,9 @@ ScreenTextEntry ScreenTextEntry::makeBig(const GameStringKey& id,
break;
}
return {GameStringUtil::fromString("Error, style " + std::to_string(style)),
return {GameStringUtil::fromString("Error, style " + std::to_string(style), FONT_PRICEDOWN),
{320.f, 400.f},
2,
FONT_ARIAL,
50,
{20, 20, 0, 0},
{20, 20, 200},
@ -152,7 +154,7 @@ ScreenTextEntry ScreenTextEntry::makeHighPriority(const GameStringKey& id,
// @todo verify: Size: 15 Pixel high letters ('S', 'l')
return {str,
{320.f, 420.f},
2,
FONT_ARIAL,
18,
{1, 0, 0, 0},
{255, 255, 255},
@ -165,7 +167,7 @@ ScreenTextEntry ScreenTextEntry::makeHighPriority(const GameStringKey& id,
ScreenTextEntry ScreenTextEntry::makeHelp(const GameStringKey& id,
const GameString& str) {
return {str, {20.f, 20.f}, 2, 18, {0, 0, 0, 255}, {255, 255, 255}, 0, 5000,
return {str, {20.f, 20.f}, FONT_ARIAL, 18, {0, 0, 0, 255}, {255, 255, 255}, 0, 5000,
0, 35, id};
}
@ -173,7 +175,7 @@ ScreenTextEntry ScreenTextEntry::makeHiddenPackageText(const GameStringKey& id,
const GameString& str) {
return {str,
{318.f, 138.f},
2,
FONT_ARIAL,
33,
{2, 2, 0, 0},
{0x59, 0x73, 0x96},

View File

@ -143,8 +143,8 @@ public:
}
template <class... Args>
static GameString format(GameString format, Args&&... args) {
static auto kReplacementMarker = GameStringUtil::fromString("~1~");
static GameString format(GameString format, font_t font, Args&&... args) {
static auto kReplacementMarker = GameStringUtil::fromString("~1~", font);
const std::array<GameString, sizeof...(args)> vals = {{args...}};
size_t x = 0, val = 0;
// We're only looking for numerical replacement markers

View File

@ -404,10 +404,11 @@ bool CollectablePickup::onPlayerTouch() {
auto text = ScreenText::format(
engine->data->texts.text(gxtEntry),
FONT_PRICEDOWN,
GameStringUtil::fromString(
std::to_string(state->playerInfo.hiddenPackagesCollected)),
std::to_string(state->playerInfo.hiddenPackagesCollected), FONT_PRICEDOWN),
GameStringUtil::fromString(
std::to_string(state->playerInfo.hiddenPackageCount)));
std::to_string(state->playerInfo.hiddenPackageCount), FONT_PRICEDOWN));
state->text.addText<ScreenTextType::HiddenPackageText>(
ScreenTextEntry::makeHiddenPackageText(gxtEntry, text));
@ -448,4 +449,4 @@ bool BigNVeinyPickup::onPlayerVehicleTouch() {
engine->state->bigNVeinyPickupsCollected++;
return true;
}
}

View File

@ -76,7 +76,7 @@ public:
* should be controlled via a different mechanism.
*/
struct DrawParameters {
/// Number of indicies
/// Number of indices
size_t count{};
/// Start index.
unsigned int start{};

View File

@ -18,10 +18,10 @@ int charToIndex(uint16_t g) {
return g - 32;
}
glm::vec4 indexToCoord(int font, int index) {
glm::vec4 indexToCoord(font_t font, int index) {
float x = static_cast<int>(index % 16);
float y = static_cast<int>(index / 16) + 0.01f;
float fontHeight = ((font == 0) ? 16.f : 13.f);
float fontHeight = ((font == FONT_PAGER) ? 16.f : 13.f);
glm::vec2 gsize(1.f / 16.f, 1.f / fontHeight);
return glm::vec4(x, y, x + 1, y + 0.98f) * glm::vec4(gsize, gsize);
}
@ -100,31 +100,25 @@ TextRenderer::TextRenderer(GameRenderer* renderer) : renderer(renderer) {
glyphData[charToIndex(g)].widthFrac = 0.65f;
}
// Assumes contigious a-z character encoding
// Assumes contiguous a-z character encoding
for (char g = 0; g <= ('z' - 'a'); g++) {
switch (('a' + g)) {
case 'i':
glyphData[charToIndex('a' + g)].widthFrac = 0.4f;
glyphData[charToIndex('A' + g)].widthFrac = 0.4f;
break;
case 'l':
glyphData[charToIndex('a' + g)].widthFrac = 0.5f;
glyphData[charToIndex('A' + g)].widthFrac = 0.5f;
break;
case 'm':
glyphData[charToIndex('a' + g)].widthFrac = 1.0f;
glyphData[charToIndex('A' + g)].widthFrac = 1.0f;
break;
case 'w':
glyphData[charToIndex('a' + g)].widthFrac = 1.0f;
glyphData[charToIndex('A' + g)].widthFrac = 1.0f;
break;
default:
glyphData[charToIndex('a' + g)].widthFrac = 0.7f;
glyphData[charToIndex('A' + g)].widthFrac = 0.7f;
break;
}
glyphData[charToIndex('a' + g)].widthFrac = 0.7f;
glyphData[charToIndex('A' + g)].widthFrac = 0.7f;
}
// case 'i':
glyphData[charToIndex('i')].widthFrac = 0.4f;
glyphData[charToIndex('I')].widthFrac = 0.4f;
// case 'l':
glyphData[charToIndex('l')].widthFrac = 0.5f;
glyphData[charToIndex('L')].widthFrac = 0.5f;
// case 'm':
glyphData[charToIndex('m')].widthFrac = 1.0f;
glyphData[charToIndex('M')].widthFrac = 1.0f;
// case 'w':
glyphData[charToIndex('w')].widthFrac = 1.0f;
glyphData[charToIndex('W')].widthFrac = 1.0f;
// case 'accent aigu'
glyphData[0x91].widthFrac = 0.6f;
}
void TextRenderer::setFontTexture(int index, const std::string& texture) {

View File

@ -33,7 +33,7 @@ public:
enum TextAlignment { Left = 0, Right = 1, Center = 2 };
/// Font index @see TextRenderer::setFontTexture
int font{0};
font_t font{FONT_PAGER};
/// Message to be displayed (including markup)
GameString text;
/// On screen position

View File

@ -5376,13 +5376,13 @@ void opcode_01e2(const ScriptArguments& args, const ScriptInt arg1, const Script
*/
void opcode_01e3(const ScriptArguments& args, const ScriptString gxtEntry, const ScriptInt arg2, const ScriptInt time, const ScriptInt style) {
auto str =
ScreenText::format(
script::gxt(args, gxtEntry),
GameStringUtil::fromString(std::to_string(arg2)));
ScreenText::format(
script::gxt(args, gxtEntry),
FONT_PRICEDOWN,
GameStringUtil::fromString(std::to_string(arg2), FONT_PRICEDOWN));
args.getState()->text.addText<ScreenTextType::Big>(
ScreenTextEntry::makeBig(
gxtEntry, str, style, time
));
ScreenTextEntry::makeBig(
gxtEntry, str, style, time));
}
/**
@ -9763,8 +9763,9 @@ void opcode_036d(const ScriptArguments& args, const ScriptString gxtEntry, const
auto str =
ScreenText::format(script::gxt(args, gxtEntry),
GameStringUtil::fromString(std::to_string(arg2)),
GameStringUtil::fromString(std::to_string(arg3)));
FONT_PRICEDOWN,
GameStringUtil::fromString(std::to_string(arg2), FONT_PRICEDOWN),
GameStringUtil::fromString(std::to_string(arg3), FONT_PRICEDOWN));
auto textEntry = ScreenTextEntry::makeBig(gxtEntry, str, style, time);
world->state->text.addText<ScreenTextType::Big>(textEntry);

View File

@ -42,7 +42,7 @@ void drawScriptTimer(GameWorld* world, GameRenderer* render) {
float scriptTimerTextY = ui_scriptTimerHeight;
TextRenderer::TextInfo ti;
ti.font = 1;
ti.font = FONT_PRICEDOWN;
ti.size = ui_textSize;
ti.align = TextRenderer::TextInfo::Right;
@ -52,7 +52,7 @@ void drawScriptTimer(GameWorld* world, GameRenderer* render) {
ss << std::setw(2) << std::setfill('0') << seconds / 60
<< std::setw(0) << ":" << std::setw(2) << seconds % 60;
ti.text = GameStringUtil::fromString(ss.str());
ti.text = GameStringUtil::fromString(ss.str(), ti.font);
}
ti.baseColour = ui_shadowColour;
@ -107,7 +107,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
float wantedY = ui_wantedLevelHeight;
TextRenderer::TextInfo ti;
ti.font = 1;
ti.font = FONT_PRICEDOWN;
ti.size = ui_textSize;
ti.align = TextRenderer::TextInfo::Right;
@ -116,7 +116,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
ss << std::setw(2) << std::setfill('0') << world->getHour()
<< std::setw(0) << ":" << std::setw(2) << world->getMinute();
ti.text = GameStringUtil::fromString(ss.str());
ti.text = GameStringUtil::fromString(ss.str(), ti.font);
}
ti.baseColour = ui_shadowColour;
@ -135,7 +135,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
ss << std::setw(8) << std::setfill('0')
<< world->state->playerInfo.displayedMoney;
ti.text = GameSymbols::Money + GameStringUtil::fromString(ss.str());
ti.text = GameSymbols::Money + GameStringUtil::fromString(ss.str(), ti.font);
}
ti.baseColour = ui_shadowColour;
@ -157,7 +157,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
ss << std::setw(3) << std::setfill('0')
<< static_cast<int>(
player->getCharacter()->getCurrentState().health);
ti.text = GameSymbols::Heart + GameStringUtil::fromString(ss.str());
ti.text = GameSymbols::Heart + GameStringUtil::fromString(ss.str(), ti.font);
ti.baseColour = ui_shadowColour;
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);
@ -174,7 +174,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
ss << std::setw(3) << std::setfill('0')
<< static_cast<int>(
player->getCharacter()->getCurrentState().armour);
ti.text = GameSymbols::Armour + GameStringUtil::fromString(ss.str());
ti.text = GameSymbols::Armour + GameStringUtil::fromString(ss.str(), ti.font);
ti.baseColour = ui_shadowColour;
ti.screenPosition =
@ -249,7 +249,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
displayBulletsTotal += slotInfo.bulletsClip;
ti.text =
GameStringUtil::fromString(std::to_string(displayBulletsTotal));
GameStringUtil::fromString(std::to_string(displayBulletsTotal), ti.font);
} else {
// Limit the maximal displayed length for the total bullet count
if (slotInfo.bulletsTotal > 9999) {
@ -258,11 +258,11 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
ti.text = GameStringUtil::fromString(
std::to_string(displayBulletsTotal) + "-" +
std::to_string(slotInfo.bulletsClip));
std::to_string(slotInfo.bulletsClip), ti.font);
}
ti.baseColour = ui_shadowColour;
ti.font = 2;
ti.font = FONT_ARIAL;
ti.size = ui_ammoSize;
ti.align = TextRenderer::TextInfo::Center;
ti.screenPosition = glm::vec2(iconX + ui_weaponSize / 2.f,
@ -284,7 +284,7 @@ void drawOnScreenText(GameWorld* world, GameRenderer* renderer) {
const auto vp = glm::vec2(renderer->getRenderer()->getViewport());
TextRenderer::TextInfo ti;
ti.font = 2;
ti.font = FONT_ARIAL;
ti.screenPosition = glm::vec2(10.f, 10.f);
ti.size = 20.f;

View File

@ -40,13 +40,13 @@ public:
public:
MenuEntry(const std::string& n, const std::function<void(void)>& cb)
: text(GameStringUtil::fromString(n)), callback(cb) {
: text(GameStringUtil::fromString(n, FONT_PRICEDOWN)), callback(cb) {
}
MenuEntry(const GameString& n, const std::function<void(void)>& cb)
: text(n), callback(cb) {
}
void draw(int font, float size, bool active, GameRenderer* r,
void draw(font_t font, float size, bool active, GameRenderer* r,
glm::vec2& basis) {
TextRenderer::TextInfo ti;
ti.font = font;
@ -90,7 +90,7 @@ public:
}
Menu& lambda(const std::string& n, std::function<void(void)> callback) {
entries.emplace_back(GameStringUtil::fromString(n), callback);
entries.emplace_back(GameStringUtil::fromString(n, FONT_PRICEDOWN), callback);
return *this;
}

View File

@ -663,8 +663,8 @@ void RWGame::renderDebugStats(float time) {
<< "Timescale: " << world->state->basic.timeScale;
TextRenderer::TextInfo ti;
ti.text = GameStringUtil::fromString(ss.str());
ti.font = 2;
ti.font = FONT_ARIAL;
ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
ti.screenPosition = glm::vec2(10.f, 10.f);
ti.size = 15.f;
ti.baseColour = glm::u8vec3(255);
@ -786,8 +786,8 @@ void RWGame::renderDebugObjects(float time, ViewCamera& camera) {
<< " Peds: " << world->pedestrianPool.objects.size() << "\n";
TextRenderer::TextInfo ti;
ti.text = GameStringUtil::fromString(ss.str());
ti.font = 2;
ti.font = FONT_ARIAL;
ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
ti.screenPosition = glm::vec2(10.f, 10.f);
ti.size = 15.f;
ti.baseColour = glm::u8vec3(255);
@ -809,7 +809,7 @@ void RWGame::renderDebugObjects(float time, ViewCamera& camera) {
if (screen.z >= 1.f) {
return;
}
ti.text = GameStringUtil::fromString(ss.str());
ti.text = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
screen.y = viewport.w - screen.y;
ti.screenPosition = glm::vec2(screen);
ti.size = 10.f;
@ -863,7 +863,7 @@ void RWGame::renderProfile() {
float xscale = renderer.getRenderer()->getViewport().x / upperlimit;
TextRenderer::TextInfo ti;
ti.align = TextRenderer::TextInfo::Left;
ti.font = 2;
ti.font = FONT_ARIAL;
ti.size = lineHeight - 2.f;
ti.baseColour = glm::u8vec3(255);
std::function<void(const perf::ProfileEntry&, int)> renderEntry =
@ -880,14 +880,14 @@ void RWGame::renderProfile() {
ti.screenPosition.x = xscale * (event.start);
ti.screenPosition.y = y + 2.f;
ti.text = GameStringUtil::fromString(
event.label + " " + std::to_string(duration) + " us ");
event.label + " " + std::to_string(duration) + " us ", ti.font);
renderer.text.renderText(ti);
renderEntry(event, depth + 1);
}
};
renderEntry(frame, 0);
ti.screenPosition = glm::vec2(xscale * (16000), 40.f);
ti.text = GameStringUtil::fromString(".16 ms");
ti.text = GameStringUtil::fromString(".16 ms", ti.font);
renderer.text.renderText(ti);
#endif
}

View File

@ -375,8 +375,8 @@ void DebugState::draw(GameRenderer* r) {
ss << (zone ? zone->name : "No Zone") << "\n";
TextRenderer::TextInfo ti;
ti.text = GameStringUtil::fromString(ss.str());
ti.font = 2;
ti.font = FONT_ARIAL;
ti.text = GameStringUtil::fromString(ss.str(), ti.font);
ti.screenPosition = glm::vec2(10.f, 10.f);
ti.size = 15.f;
ti.baseColour = glm::u8vec3(255);

View File

@ -28,14 +28,14 @@ void LoadingState::handleEvent(const SDL_Event& e) {
}
void LoadingState::draw(GameRenderer* r) {
static auto kLoadingString = GameStringUtil::fromString("Loading...");
static auto kLoadingString = GameStringUtil::fromString("Loading...", FONT_ARIAL);
// Display some manner of loading screen.
TextRenderer::TextInfo ti;
ti.text = kLoadingString;
auto size = r->getRenderer()->getViewport();
ti.size = 25.f;
ti.screenPosition = glm::vec2(50.f, size.y - ti.size - 50.f);
ti.font = 2;
ti.font = FONT_PRICEDOWN;
ti.baseColour = glm::u8vec3(255);
r->text.renderText(ti);
}

View File

@ -40,7 +40,7 @@ void MenuState::enterLoadMenu() {
<< save.basicState.saveTime.day << " "
<< save.basicState.saveTime.hour << ":"
<< save.basicState.saveTime.minute << " ";
auto name = GameStringUtil::fromString(ss.str());
auto name = GameStringUtil::fromString(ss.str(), FONT_ARIAL);
name += save.basicState.saveName;
auto loadsave = [=] {
StateManager::get().enter<IngameState>(game, false);

View File

@ -1,9 +1,15 @@
#include "GameTexts.hpp"
GameString GameStringUtil::fromString(const std::string& str) {
GameString s;
for (const char &i : str) {
s += i;
}
return s;
// FIXME: Update for GTA VC
#include "FontMapGta3.hpp"
#include "rw/debug.hpp"
GameString GameStringUtil::fromString(const std::string& str, font_t font) {
RW_ASSERT(font < FONTS_COUNT);
return maps_gta3_font[font].to_GameString(str);
}
std::string GameStringUtil::toString(const GameString& str, font_t font) {
return maps_gta3_font[font].to_string(str);
}

View File

@ -4,6 +4,8 @@
#include <cstdint>
#include <string>
#include <unordered_map>
#include <sstream>
#include <string>
/**
* Each GXT char is just a 16-bit index into the font map.
@ -12,7 +14,7 @@ using GameStringChar = std::uint16_t;
/**
* The game stores strings as 16-bit indexes into the font
* texture, which is something simllar to ASCII.
* texture, which is something similar to ASCII.
*/
using GameString = std::basic_string<GameStringChar>;
@ -22,6 +24,16 @@ using GameString = std::basic_string<GameStringChar>;
*/
using GameStringKey = std::string;
/**
* Index to used font.
*/
using font_t = size_t;
static const font_t FONT_PAGER = 0;
static const font_t FONT_PRICEDOWN = 1;
static const font_t FONT_ARIAL = 2;
static const font_t FONTS_COUNT = 3;
namespace GameStringUtil {
/**
* @brief fromString Converts a string to a GameString
@ -29,7 +41,15 @@ namespace GameStringUtil {
* Encoding of GameStrings depends on the font, only simple ASCII chars will map
* well
*/
GameString fromString(const std::string& str);
GameString fromString(const std::string& str, font_t font);
/**
* @brief fromString Converts a string to a GameString
*
* Encoding of GameStrings depends on the font, only simple ASCII chars will map
* well
*/
std::string toString(const GameString& str, font_t font);
}
/**
@ -58,7 +78,11 @@ public:
if (a != m_strings.end()) {
return a->second;
}
return GameStringUtil::fromString("MISSING: " + id);
return GameStringUtil::fromString("MISSING: " + id, FONT_ARIAL);
}
const StringTable &getStringTable() const {
return m_strings;
}
};

View File

@ -4,7 +4,7 @@
#include <loaders/LoaderGXT.hpp>
#include "test_Globals.hpp"
#define T(x) GameStringUtil::fromString(x)
#define T(x) GameStringUtil::fromString(x, FONT_PRICEDOWN)
BOOST_AUTO_TEST_SUITE(TextTests)
@ -22,6 +22,7 @@ BOOST_AUTO_TEST_CASE(load_test) {
BOOST_CHECK_EQUAL(texts.text("1008"), T("BUSTED"));
}
}
#endif
BOOST_AUTO_TEST_CASE(special_chars) {
{
@ -108,16 +109,16 @@ BOOST_AUTO_TEST_CASE(format_test) {
const auto codeStr2 = T("~1~Hello ~1~ world~1~");
const auto codeStr3 = T("Hello world~1~");
auto f1 = ScreenText::format(codeStr1, T("r"));
auto f1 = ScreenText::format(codeStr1, FONT_PRICEDOWN, T("r"));
BOOST_CHECK_EQUAL(f1, T("Hello r world"));
auto f2 = ScreenText::format(codeStr2, T("k"), T("h"));
auto f2 = ScreenText::format(codeStr2, FONT_PRICEDOWN, T("k"), T("h"));
BOOST_CHECK_EQUAL(f2, T("kHello h world~1~"));
auto f3 = ScreenText::format(codeStr3, T("x"));
auto f3 = ScreenText::format(codeStr3, FONT_PRICEDOWN, T("x"));
BOOST_CHECK_EQUAL(f3, T("Hello worldx"));
auto f4 = ScreenText::format(codeStr3, T("x"), T("k"));
auto f4 = ScreenText::format(codeStr3, FONT_PRICEDOWN, T("x"), T("k"));
BOOST_CHECK_EQUAL(f4, T("Hello worldx"));
}
@ -140,6 +141,5 @@ BOOST_AUTO_TEST_CASE(format_remove) {
BOOST_CHECK_EQUAL(1, st.getText<ScreenTextType::Big>().size());
}
#endif
BOOST_AUTO_TEST_SUITE_END()