From b20e73c9861b11e4d764f281300bbca82a9d1e94 Mon Sep 17 00:00:00 2001 From: Peter Gaal Date: Mon, 22 Jun 2020 22:20:24 +0200 Subject: [PATCH] Implement get_string_width function (#509) * Implement get_string_width function uint16_t get_string_width(const char* buffer); * Use readCodePoint to parse the string * Fix formatting issue * reverting back changes with readCodePoint * Remove unicode.h * Addressed review comments * Added const definition Co-authored-by: Duncan --- src/openloco/graphics/gfx.cpp | 85 +++++++++++++++++++++++++-- src/openloco/graphics/gfx.h | 2 +- src/openloco/ui/WindowManager.cpp | 12 ++++ src/openloco/windows/textinputwnd.cpp | 8 +-- 4 files changed, 97 insertions(+), 10 deletions(-) diff --git a/src/openloco/graphics/gfx.cpp b/src/openloco/graphics/gfx.cpp index 19c54718..d56fb7a8 100644 --- a/src/openloco/graphics/gfx.cpp +++ b/src/openloco/graphics/gfx.cpp @@ -182,12 +182,87 @@ namespace openloco::gfx * @param buffer @ * @return width @ */ - uint16_t get_string_width(const char* buffer) + uint16_t getStringWidth(const char* buffer) { - registers regs; - regs.esi = (uintptr_t)buffer; - call(0x495685, regs); - return regs.cx; + uint16_t width = 0; + const uint8_t* str = reinterpret_cast(buffer); + int16_t fontSpriteBase = _currentFontSpriteBase; + + while (*str != (uint8_t)0) + { + const uint8_t chr = *str; + str++; + + if (chr >= 32) + { + width += _characterWidths[chr - 32 + fontSpriteBase]; + continue; + } + + switch (chr) + { + case control_codes::move_x: + width = *str; + str++; + break; + + case control_codes::adjust_palette: + case 3: + case 4: + str++; + break; + + case control_codes::newline: + case control_codes::newline_smaller: + continue; + + case control_codes::font_small: + fontSpriteBase = font::small; + break; + + case control_codes::font_large: + fontSpriteBase = font::large; + break; + + case control_codes::font_bold: + fontSpriteBase = font::medium_bold; + break; + + case control_codes::font_regular: + fontSpriteBase = font::medium_normal; + break; + + case control_codes::outline: + case control_codes::outline_off: + case control_codes::window_colour_1: + case control_codes::window_colour_2: + case control_codes::window_colour_3: + case 0x10: + break; + + case control_codes::inline_sprite_str: + { + const uint32_t image = reinterpret_cast(str)[0]; + const uint32_t imageId = image & 0x7FFFF; + str += 4; + width += _g1Elements[imageId].width; + break; + } + + default: + if (chr <= 0x16) + { + str += 2; + } + else + { + str += 4; + } + break; + } + } + + return width; } static void setTextColours(palette_index_t pal1, palette_index_t pal2, palette_index_t pal3) diff --git a/src/openloco/graphics/gfx.h b/src/openloco/graphics/gfx.h index 677d9394..dacb8e89 100644 --- a/src/openloco/graphics/gfx.h +++ b/src/openloco/graphics/gfx.h @@ -74,7 +74,7 @@ namespace openloco::gfx void clear_single(drawpixelinfo_t& dpi, uint8_t paletteId); int16_t clip_string(int16_t width, char* string); - uint16_t get_string_width(const char* buffer); + uint16_t getStringWidth(const char* buffer); gfx::point_t draw_string(drawpixelinfo_t* context, int16_t x, int16_t y, uint8_t colour, void* str); diff --git a/src/openloco/ui/WindowManager.cpp b/src/openloco/ui/WindowManager.cpp index 5706c5a3..0d21360c 100644 --- a/src/openloco/ui/WindowManager.cpp +++ b/src/openloco/ui/WindowManager.cpp @@ -200,6 +200,18 @@ namespace openloco::ui::WindowManager return 0; }); + register_hook( + 0x00495685, + [](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t { + registers backup = regs; + const char* buffer = (const char*)regs.esi; + uint16_t width = gfx::getStringWidth(buffer); + regs = backup; + regs.cx = width; + + return 0; + }); + register_hook( 0x00499B7E, [](registers& regs) FORCE_ALIGN_ARG_POINTER -> uint8_t { diff --git a/src/openloco/windows/textinputwnd.cpp b/src/openloco/windows/textinputwnd.cpp index 976f8819..db8dd6fc 100644 --- a/src/openloco/windows/textinputwnd.cpp +++ b/src/openloco/windows/textinputwnd.cpp @@ -413,8 +413,8 @@ namespace openloco::ui::textinput std::string cursorStr = _buffer.substr(0, cursor_position); _currentFontSpriteBase = font::medium_bold; - auto stringWidth = gfx::get_string_width(_buffer.data()); - auto cursorX = gfx::get_string_width(cursorStr.data()); + auto stringWidth = gfx::getStringWidth(_buffer.data()); + auto cursorX = gfx::getStringWidth(cursorStr.data()); int x = _xOffset + cursorX; @@ -440,8 +440,8 @@ namespace openloco::ui::textinput std::string cursorStr = _buffer.substr(0, cursor_position); _currentFontSpriteBase = font::medium_bold; - auto stringWidth = gfx::get_string_width(_buffer.data()); - auto cursorX = gfx::get_string_width(cursorStr.data()); + auto stringWidth = gfx::getStringWidth(_buffer.data()); + auto cursorX = gfx::getStringWidth(cursorStr.data()); auto midX = containerWidth / 2;