diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index e65edf0591..fa01bfaff4 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -376,7 +376,7 @@ target_sources(rpcs3_emu PRIVATE RSX/Null/NullGSRender.cpp RSX/Overlays/overlay_animation.cpp RSX/Overlays/overlay_edit_text.cpp - RSX/Overlays/overlay_font.cpp + RSX/Overlays/overlay_fonts.cpp RSX/Overlays/overlay_list_view.cpp RSX/Overlays/overlay_message_dialog.cpp RSX/Overlays/overlay_osk.cpp diff --git a/rpcs3/Emu/RSX/Overlays/overlay_controls.h b/rpcs3/Emu/RSX/Overlays/overlay_controls.h index 93fc9487cf..c9e9bdd1c4 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_controls.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_controls.h @@ -3,6 +3,8 @@ #include "Utilities/geometry.h" #include "Utilities/File.h" #include "overlay_utils.h" +#include "overlay_fonts.h" +#include "Emu/System.h" #include #include @@ -24,10 +26,6 @@ #include #endif -// STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally -#include -#include - // Definitions for common UI controls and their routines namespace rsx { @@ -51,73 +49,6 @@ namespace rsx line_strip = 3 }; - struct font - { - const u32 width = 1024; - const u32 height = 1024; - const u32 oversample = 2; - const u32 char_count = 256; // 16x16 grid at max 48pt - - f32 size_pt = 12.f; - f32 size_px = 16.f; // Default font 12pt size - f32 em_size = 0.f; - std::string font_name; - std::vector pack_info; - std::vector glyph_data; - bool initialized = false; - - font(const char* ttf_name, f32 size); - - stbtt_aligned_quad get_char(char c, f32& x_advance, f32& y_advance); - - void render_text_ex(std::vector& result, f32& x_advance, f32& y_advance, const char* text, u32 char_limit, u16 max_width, bool wrap); - - std::vector render_text(const char* text, u16 max_width = UINT16_MAX, bool wrap = false); - - std::pair get_char_offset(const char* text, u16 max_length, u16 max_width = UINT16_MAX, bool wrap = false); - }; - - // TODO: Singletons are cancer - class fontmgr - { - private: - std::vector> fonts; - static fontmgr *m_instance; - - font* find(const char *name, int size) - { - for (auto &f : fonts) - { - if (f->font_name == name && - f->size_pt == size) - return f.get(); - } - - fonts.push_back(std::make_unique(name, static_cast(size))); - return fonts.back().get(); - } - - public: - - fontmgr() = default; - ~fontmgr() - { - if (m_instance) - { - delete m_instance; - m_instance = nullptr; - } - } - - static font* get(const char *name, int size) - { - if (m_instance == nullptr) - m_instance = new fontmgr; - - return m_instance->find(name, size); - } - }; - struct image_info { int w = 0, h = 0; @@ -400,7 +331,7 @@ namespace rsx u16 w = 0; u16 h = 0; - std::string text; + std::wstring text; font* font_ref = nullptr; text_align alignment = left; bool wrap_text = false; @@ -502,13 +433,13 @@ namespace rsx virtual void set_text(const std::string& text) { - this->text = text; + this->text = utf8_to_wstring(text); is_compiled = false; } virtual void set_text(const char* text) { - this->text = text; + this->text = utf8_to_wstring(text); is_compiled = false; } @@ -535,7 +466,7 @@ namespace rsx return font_ref ? font_ref : fontmgr::get("Arial", 12); } - virtual std::vector render_text(const char *string, f32 x, f32 y) + virtual std::vector render_text(const wchar_t *string, f32 x, f32 y) { auto renderer = get_font(); @@ -554,7 +485,7 @@ namespace rsx // Apply transform. // (0, 0) has text sitting one line off the top left corner (text is outside the rect) hence the offset by text height v.values[0] += x + padding_left; - v.values[1] += y + padding_top + static_cast(renderer->size_px); + v.values[1] += y + padding_top + static_cast(renderer->get_size_px()); } if (alignment == center) @@ -589,7 +520,7 @@ namespace rsx continue; const f32 line_length = result[p.second - 1].values[0] - result[p.first].values[0]; - const bool wrapped = std::fabs(result[p.second - 1].values[1] - result[p.first + 3].values[1]) >= (renderer->size_px * 0.5f); + const bool wrapped = std::fabs(result[p.second - 1].values[1] - result[p.first + 3].values[1]) >= (renderer->get_size_px() * 0.5f); if (wrapped) continue; @@ -665,13 +596,13 @@ namespace rsx f32 unused = 0.f; f32 max_w = 0.f; f32 last_word = 0.f; - height = static_cast(renderer->size_px); + height = static_cast(renderer->get_size_px()); for (auto c : text) { if (c == '\n') { - height += static_cast(renderer->size_px + 2); + height += static_cast(renderer->get_size_px() + 2); max_w = std::max(max_w, text_width); text_width = 0.f; last_word = 0.f; @@ -683,23 +614,15 @@ namespace rsx last_word = text_width; } - if (static_cast(c) > renderer->char_count) - { - // Non-existent glyph - text_width += renderer->em_size; - } - else - { - renderer->get_char(c, text_width, unused); - } + renderer->get_char(c, text_width, unused); if (!ignore_word_wrap && wrap_text && text_width >= w) { if ((text_width - last_word) < w) { max_w = std::max(max_w, last_word); - text_width -= (last_word + renderer->em_size); - height += static_cast(renderer->size_px + 2); + text_width -= (last_word + renderer->get_em_size()); + height += static_cast(renderer->get_size_px() + 2); } } } @@ -1033,7 +956,7 @@ namespace rsx label(const std::string& text) { - this->text = text; + set_text(text); } bool auto_resize(bool grow_only = false, u16 limit_w = UINT16_MAX, u16 limit_h = UINT16_MAX) @@ -1114,7 +1037,7 @@ namespace rsx int get_selected_index(); - std::string get_selected_item(); + std::wstring get_selected_item(); void set_cancel_only(bool cancel_only); void translate(s16 _x, s16 _y) override; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp b/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp index 1cbd84733e..6198ea4b66 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_edit_text.cpp @@ -39,17 +39,17 @@ namespace rsx if (caret_position == 0) { // Start - text = str + text; + text = utf8_to_wstring(str) + text; } else if (caret_position == text.length()) { // End - text += str; + text += utf8_to_wstring(str); } else { // Middle - text.insert(caret_position, str); + text.insert(caret_position, utf8_to_wstring(str)); } caret_position += ::narrow(str.length()); @@ -65,7 +65,7 @@ namespace rsx if (caret_position == 1) { - text = text.length() > 1 ? text.substr(1) : ""; + text = text.length() > 1 ? text.substr(1) : L""; } else if (caret_position == text.length()) { @@ -91,7 +91,7 @@ namespace rsx const auto caret_loc = renderer->get_char_offset(text.c_str(), caret_position, clip_text ? w : UINT16_MAX, wrap_text); caret.set_pos(u16(caret_loc.first + padding_left + x), u16(caret_loc.second + padding_top + y)); - caret.set_size(1, u16(renderer->size_px + 2)); + caret.set_size(1, u16(renderer->get_size_px() + 2)); caret.fore_color = fore_color; caret.back_color = fore_color; caret.pulse_effect_enabled = true; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_font.cpp b/rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp similarity index 67% rename from rpcs3/Emu/RSX/Overlays/overlay_font.cpp rename to rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp index 803c49634f..c649ef49f0 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_font.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_fonts.cpp @@ -6,7 +6,52 @@ namespace rsx { namespace overlays { + void codepage::initialize_glyphs(u16 codepage_id, f32 font_size, const std::vector& ttf_data) + { + glyph_base = (codepage_id * 256); + glyph_data.resize(bitmap_width * bitmap_height); + pack_info.resize(256); + + stbtt_pack_context context; + if (!stbtt_PackBegin(&context, glyph_data.data(), bitmap_width, bitmap_height, 0, 1, nullptr)) + { + rsx_log.error("Font packing failed"); + return; + } + + stbtt_PackSetOversampling(&context, oversample, oversample); + + if (!stbtt_PackFontRange(&context, ttf_data.data(), 0, font_size, (codepage_id * 256), 256, pack_info.data())) + { + rsx_log.error("Font packing failed"); + stbtt_PackEnd(&context); + return; + } + + stbtt_PackEnd(&context); + } + + stbtt_aligned_quad codepage::get_char(wchar_t c, f32& x_advance, f32& y_advance) + { + stbtt_aligned_quad quad; + stbtt_GetPackedQuad(pack_info.data(), bitmap_width, bitmap_height, (c - glyph_base), &x_advance, &y_advance, &quad, false); + + quad.t0 += sampler_z; + quad.t1 += sampler_z; + return quad; + } + font::font(const char* ttf_name, f32 size) + { + // Convert pt to px + size_px = ceilf(size * 96.f / 72.f); + size_pt = size; + + font_name = ttf_name; + initialized = true; + } + + codepage* font::initialize_codepage(u16 codepage_id) { // Init glyph std::vector bytes; @@ -41,7 +86,7 @@ namespace rsx bool font_found = false; for (auto& font_dir : font_dirs) { - std::string requested_file = font_dir + ttf_name; + std::string requested_file = font_dir + font_name; // Append ".ttf" if not present std::string font_lower(requested_file); @@ -66,10 +111,10 @@ namespace rsx { if (fs::is_file(fallback_font)) { - file_path = fallback_font; + file_path = fallback_font; font_found = true; - rsx_log.notice("Found font file '%s' as a replacement for '%s'", fallback_font.c_str(), ttf_name); + rsx_log.notice("Found font file '%s' as a replacement for '%s'", fallback_font, font_name); break; } } @@ -83,53 +128,62 @@ namespace rsx } else { - rsx_log.error("Failed to initialize font '%s.ttf'", ttf_name); - return; + rsx_log.error("Failed to initialize font '%s.ttf'", font_name); + return nullptr; } - glyph_data.resize(width * height); - pack_info.resize(256); + codepage_cache.page = nullptr; + auto page = std::make_unique(); + page->initialize_glyphs(codepage_id, size_px, bytes); + page->sampler_z = static_cast(m_glyph_map.size()); - stbtt_pack_context context; - if (!stbtt_PackBegin(&context, glyph_data.data(), width, height, 0, 1, nullptr)) + auto ret = page.get(); + m_glyph_map.emplace_back(codepage_id, std::move(page)); + + if (codepage_id == 0) { - rsx_log.error("Font packing failed"); - return; + // Latin-1 + f32 unused; + get_char('m', em_size, unused); } - stbtt_PackSetOversampling(&context, oversample, oversample); - - // Convert pt to px - size_px = ceilf(size * 96.f / 72.f); - size_pt = size; - - if (!stbtt_PackFontRange(&context, bytes.data(), 0, size_px, 0, 256, pack_info.data())) - { - rsx_log.error("Font packing failed"); - stbtt_PackEnd(&context); - return; - } - - stbtt_PackEnd(&context); - - font_name = ttf_name; - initialized = true; - - f32 unused; - get_char('m', em_size, unused); + return ret; } - stbtt_aligned_quad font::get_char(char c, f32& x_advance, f32& y_advance) + stbtt_aligned_quad font::get_char(wchar_t c, f32& x_advance, f32& y_advance) { if (!initialized) return {}; - stbtt_aligned_quad quad; - stbtt_GetPackedQuad(pack_info.data(), width, height, u8(c), &x_advance, &y_advance, &quad, false); - return quad; + const auto page_id = (c >> 8); + if (codepage_cache.codepage_id == page_id && codepage_cache.page) [[likely]] + { + return codepage_cache.page->get_char(c, x_advance, y_advance); + } + else + { + codepage_cache.codepage_id = page_id; + codepage_cache.page = nullptr; + + for (const auto& e : m_glyph_map) + { + if (e.first == unsigned(page_id)) + { + codepage_cache.page = e.second.get(); + break; + } + } + + if (!codepage_cache.page) [[unlikely]] + { + codepage_cache.page = initialize_codepage(page_id); + } + + return codepage_cache.page->get_char(c, x_advance, y_advance); + } } - void font::render_text_ex(std::vector& result, f32& x_advance, f32& y_advance, const char* text, u32 char_limit, u16 max_width, bool wrap) + void font::render_text_ex(std::vector& result, f32& x_advance, f32& y_advance, const wchar_t* text, u32 char_limit, u16 max_width, bool wrap) { x_advance = 0.f; y_advance = 0.f; @@ -145,14 +199,8 @@ namespace rsx while (true) { - if (char c = text[i++]; c && (i <= char_limit)) + if (auto c = text[i++]; c && (i <= char_limit)) { - if (u8(c) >= char_count) - { - // Unsupported glyph, render null for now - c = ' '; - } - switch (c) { case '\n': @@ -271,7 +319,7 @@ namespace rsx } } - std::vector font::render_text(const char* text, u16 max_width, bool wrap) + std::vector font::render_text(const wchar_t* text, u16 max_width, bool wrap) { std::vector result; f32 unused_x, unused_y; @@ -280,7 +328,7 @@ namespace rsx return result; } - std::pair font::get_char_offset(const char* text, u16 max_length, u16 max_width, bool wrap) + std::pair font::get_char_offset(const wchar_t* text, u16 max_length, u16 max_width, bool wrap) { std::vector unused; f32 loc_x, loc_y; @@ -288,5 +336,20 @@ namespace rsx render_text_ex(unused, loc_x, loc_y, text, max_length, max_width, wrap); return {loc_x, loc_y}; } + + void font::get_glyph_data(std::vector& bytes) const + { + const u32 page_size = codepage::bitmap_width * codepage::bitmap_height; + const auto size = page_size * m_glyph_map.size(); + + bytes.resize(size); + u8* data = bytes.data(); + + for (const auto& e : m_glyph_map) + { + std::memcpy(data, e.second->glyph_data.data(), page_size); + data += page_size; + } + } } // namespace overlays } // namespace rsx diff --git a/rpcs3/Emu/RSX/Overlays/overlay_fonts.h b/rpcs3/Emu/RSX/Overlays/overlay_fonts.h new file mode 100644 index 0000000000..63f7f624c3 --- /dev/null +++ b/rpcs3/Emu/RSX/Overlays/overlay_fonts.h @@ -0,0 +1,116 @@ +#include "Utilities/types.h" +#include "overlay_utils.h" + +#include +#include + +// STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally +#include +#include + +namespace rsx +{ + namespace overlays + { + // Each 'page' holds an indexed block of 256 code points + // The BMP (Basic Multilingual Plane) has 256 allocated pages but not all are necessary + // While there are supplementary planes, the BMP is the most important thing to support + struct codepage + { + static constexpr u32 bitmap_width = 1024; + static constexpr u32 bitmap_height = 1024; + static constexpr u32 char_count = 256; // 16x16 grid at max 48pt + static constexpr u32 oversample = 2; + + std::vector pack_info; + std::vector glyph_data; + u16 glyph_base = 0; + f32 sampler_z = 0.f; + + void initialize_glyphs(u16 codepage_id, f32 font_size, const std::vector& ttf_data); + stbtt_aligned_quad get_char(wchar_t c, f32& x_advance, f32& y_advance); + }; + + class font + { + private: + f32 size_pt = 12.f; + f32 size_px = 16.f; // Default font 12pt size + f32 em_size = 0.f; + std::string font_name; + + std::vector>> m_glyph_map; + bool initialized = false; + + struct + { + u16 codepage_id = 0; + codepage* page = nullptr; + } + codepage_cache; + + codepage* initialize_codepage(u16 page); + public: + + font(const char* ttf_name, f32 size); + + stbtt_aligned_quad get_char(wchar_t c, f32& x_advance, f32& y_advance); + + void render_text_ex(std::vector& result, f32& x_advance, f32& y_advance, const wchar_t* text, u32 char_limit, u16 max_width, bool wrap); + + std::vector render_text(const wchar_t* text, u16 max_width = UINT16_MAX, bool wrap = false); + + std::pair get_char_offset(const wchar_t* text, u16 max_length, u16 max_width = UINT16_MAX, bool wrap = false); + + bool matches(const char* name, int size) const { return font_name == name && static_cast(size_pt) == size; } + std::string_view get_name() const { return font_name; }; + f32 get_size_pt() const { return size_pt; } + f32 get_size_px() const { return size_px; } + f32 get_em_size() const { return em_size; } + + // Renderer info + size3u get_glyph_data_dimensions() const { return { codepage::bitmap_width, codepage::bitmap_height, ::size32(m_glyph_map) }; } + void get_glyph_data(std::vector& bytes) const; + }; + + // TODO: Singletons are cancer + class fontmgr + { + private: + std::vector> fonts; + static fontmgr* m_instance; + + font* find(const char* name, int size) + { + for (auto& f : fonts) + { + if (f->matches(name, size)) + return f.get(); + } + + fonts.push_back(std::make_unique(name, static_cast(size))); + return fonts.back().get(); + } + + public: + + fontmgr() = default; + ~fontmgr() + { + if (m_instance) + { + delete m_instance; + m_instance = nullptr; + } + } + + static font* get(const char* name, int size) + { + if (m_instance == nullptr) + m_instance = new fontmgr; + + return m_instance->find(name, size); + } + }; + } +} diff --git a/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp b/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp index accd474e35..4195f26faf 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_list_view.cpp @@ -150,7 +150,7 @@ namespace rsx return m_selected_entry; } - std::string list_view::get_selected_item() + std::wstring list_view::get_selected_item() { if (m_selected_entry < 0) return {}; diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp index b4220d2599..8556cd544c 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_message_dialog.cpp @@ -176,7 +176,7 @@ namespace rsx btn_cancel.translate(0, offset); } - text_display.set_text(utf8_to_ascii8(text)); + text_display.set_text(text); u16 text_w, text_h; text_display.measure_text(text_w, text_h); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp b/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp index 01de251372..fe9c16d98b 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_osk.cpp @@ -405,7 +405,7 @@ namespace rsx void osk_dialog::on_text_changed() { - const auto ws = ascii8_to_utf16(m_preview.text); + const auto ws = wstring_to_utf16(m_preview.text); const auto length = (ws.length() + 1) * sizeof(char16_t); memcpy(osk_text, ws.c_str(), length); @@ -420,7 +420,7 @@ namespace rsx void osk_dialog::on_default_callback(const std::string& str) { // Append to output text - if (m_preview.text == "[Enter Text]") + if (m_preview.text == L"[Enter Text]") { m_preview.caret_position = ::narrow(str.length()); m_preview.set_text(str); @@ -433,7 +433,7 @@ namespace rsx return; } - auto new_str = m_preview.text + str; + auto new_str = m_preview.text + utf8_to_wstring(str); if (new_str.length() <= char_limit) { m_preview.insert_text(str); diff --git a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp index 0321451302..ba189f74a9 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlay_perf_metrics.cpp @@ -186,9 +186,9 @@ namespace rsx switch (m_detail) { case detail_level::minimal: - case detail_level::low: m_titles.text = ""; break; - case detail_level::medium: m_titles.text = fmt::format("\n\n%s", title1_medium); break; - case detail_level::high: m_titles.text = fmt::format("\n\n%s\n\n\n\n\n\n%s", title1_high, title2); break; + case detail_level::low: m_titles.set_text(""); break; + case detail_level::medium: m_titles.set_text(fmt::format("\n\n%s", title1_medium)); break; + case detail_level::high: m_titles.set_text(fmt::format("\n\n%s\n\n\n\n\n\n%s", title1_high, title2)); break; } m_titles.auto_resize(); m_titles.refresh(); @@ -486,7 +486,7 @@ namespace rsx } } - m_body.text = perf_text; + m_body.set_text(perf_text); if (m_body.auto_resize()) { @@ -573,7 +573,7 @@ namespace rsx void graph::set_font_size(u16 font_size) { - const auto font_name = m_label.get_font()->font_name.c_str(); + const auto font_name = m_label.get_font()->get_name().data(); m_label.set_font(font_name, font_size); } diff --git a/rpcs3/Emu/RSX/Overlays/overlay_utils.h b/rpcs3/Emu/RSX/Overlays/overlay_utils.h index 9a64eb0128..304faf4251 100644 --- a/rpcs3/Emu/RSX/Overlays/overlay_utils.h +++ b/rpcs3/Emu/RSX/Overlays/overlay_utils.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once struct vertex { @@ -146,3 +146,9 @@ void operator < (const vector3_base& lhs, T rhs) using vector3i = vector3_base; using vector3f = vector3_base; + +std::string utf8_to_ascii8(const std::string& utf8_string); +std::string utf16_to_ascii8(const std::u16string& utf16_string); +std::u16string ascii8_to_utf16(const std::string& ascii_string); +std::wstring utf8_to_wstring(const std::string& utf8_string); +std::u16string wstring_to_utf16(const std::wstring& w_string); diff --git a/rpcs3/Emu/RSX/Overlays/overlays.cpp b/rpcs3/Emu/RSX/Overlays/overlays.cpp index 749fdbd0f4..dffa6ee7d9 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.cpp +++ b/rpcs3/Emu/RSX/Overlays/overlays.cpp @@ -58,15 +58,13 @@ static auto s_ascii_lowering_map = []() return _map; }(); -std::string utf8_to_ascii8(const std::string& utf8_string) +template +void process_multibyte(const std::string s, F&& func) { - std::string out; - out.reserve(utf8_string.length()); - - const auto end = utf8_string.length(); + const auto end = s.length(); for (u32 index = 0; index < end; ++index) { - const u8 code = static_cast(utf8_string[index]); + const u8 code = static_cast(s[index]); if (!code) { @@ -75,7 +73,7 @@ std::string utf8_to_ascii8(const std::string& utf8_string) if (code <= 0x7F) { - out.push_back(code); + std::invoke(func, code); continue; } @@ -83,7 +81,7 @@ std::string utf8_to_ascii8(const std::string& utf8_string) if ((index + extra_bytes) > end) { // Malformed string, abort - overlays.error("Failed to decode supossedly malformed utf8 string '%s'", utf8_string); + overlays.error("Failed to decode supossedly malformed utf8 string '%s'", s); break; } @@ -92,38 +90,46 @@ std::string utf8_to_ascii8(const std::string& utf8_string) { case 1: // 11 bits, 6 + 5 - u_code = (u32(code & 0x1F) << 6) | u32(utf8_string[index + 1] & 0x3F); + u_code = (u32(code & 0x1F) << 6) | u32(s[index + 1] & 0x3F); break; case 2: // 16 bits, 6 + 6 + 4 - u_code = (u32(code & 0xF) << 12) | (u32(utf8_string[index + 1] & 0x3F) << 6) | u32(utf8_string[index + 2] & 0x3F); + u_code = (u32(code & 0xF) << 12) | (u32(s[index + 1] & 0x3F) << 6) | u32(s[index + 2] & 0x3F); break; case 3: // 21 bits, 6 + 6 + 6 + 3 - u_code = (u32(code & 0x7) << 18) | (u32(utf8_string[index + 1] & 0x3F) << 12) | (u32(utf8_string[index + 2] & 0x3F) << 6) | u32(utf8_string[index + 3] & 0x3F); + u_code = (u32(code & 0x7) << 18) | (u32(s[index + 1] & 0x3F) << 12) | (u32(s[index + 2] & 0x3F) << 6) | u32(s[index + 3] & 0x3F); break; default: fmt::throw_exception("Unreachable" HERE); } index += extra_bytes; + std::invoke(func, u_code); + } +} - if (u_code <= 0xFF) +std::string utf8_to_ascii8(const std::string& utf8_string) +{ + std::string out; + out.reserve(utf8_string.length()); + + process_multibyte(utf8_string, [&out](u32 code) + { + if (code <= 0x7F) { - // Latin-1 supplement block - out.push_back(static_cast(u_code)); - continue; + out.push_back(static_cast(code)); } - - auto replace = s_ascii_lowering_map.find(u_code); - if (replace == s_ascii_lowering_map.end()) + else if (auto replace = s_ascii_lowering_map.find(code); + replace == s_ascii_lowering_map.end()) { out.push_back('#'); - continue; } - - out.push_back(replace->second); - } + else + { + out.push_back(replace->second); + } + }); return out; } @@ -161,6 +167,39 @@ std::u16string ascii8_to_utf16(const std::string& ascii_string) return out; } +std::wstring utf8_to_wstring(const std::string& utf8_string) +{ + std::wstring result; + result.reserve(utf8_string.size()); + + process_multibyte(utf8_string, [&result](u32 code) + { + result.push_back(static_cast(code)); + }); + + return result; +} + +std::u16string wstring_to_utf16(const std::wstring& w_string) +{ + if constexpr (sizeof(wchar_t) == sizeof(char16_t)) + { + return reinterpret_cast(w_string.data()); + } + else + { + std::u16string result; + result.reserve(w_string.size()); + + for (const auto& code : w_string) + { + result.push_back(code); + } + + return result; + } +} + namespace rsx { namespace overlays diff --git a/rpcs3/Emu/RSX/Overlays/overlays.h b/rpcs3/Emu/RSX/Overlays/overlays.h index e88f3d2131..efa4b8c71b 100644 --- a/rpcs3/Emu/RSX/Overlays/overlays.h +++ b/rpcs3/Emu/RSX/Overlays/overlays.h @@ -20,9 +20,6 @@ #include // Utils -std::string utf8_to_ascii8(const std::string& utf8_string); -std::string utf16_to_ascii8(const std::u16string& utf16_string); -std::u16string ascii8_to_utf16(const std::string& ascii_string); extern u64 get_system_time(); // Definition of user interface implementations diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 4d0d32bdc8..7d19ae7025 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -340,7 +340,7 @@ - + @@ -417,6 +417,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index bca5a1c828..cf5b78d574 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -836,9 +836,6 @@ Emu\GPU\RSX\Overlays - - Emu\GPU\RSX\Overlays - Emu\GPU\RSX\Overlays @@ -883,7 +880,7 @@ Emu - + Emu @@ -895,6 +892,9 @@ Emu + + + Emu\GPU\RSX\Overlays @@ -1689,7 +1689,7 @@ Emu - + Emu @@ -1698,6 +1698,9 @@ Emu + + + Emu\GPU\RSX\Overlays \ No newline at end of file