mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-29 00:33:01 +00:00
overlays: Migrate to wide-char strings
This commit is contained in:
parent
6bb083a77c
commit
6178a0ab25
@ -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
|
||||
|
@ -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 <string>
|
||||
#include <vector>
|
||||
@ -24,10 +26,6 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
// STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally
|
||||
#include <stb_image.h>
|
||||
#include <stb_truetype.h>
|
||||
|
||||
// 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<stbtt_packedchar> pack_info;
|
||||
std::vector<u8> 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<vertex>& result, f32& x_advance, f32& y_advance, const char* text, u32 char_limit, u16 max_width, bool wrap);
|
||||
|
||||
std::vector<vertex> render_text(const char* text, u16 max_width = UINT16_MAX, bool wrap = false);
|
||||
|
||||
std::pair<f32, f32> 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<std::unique_ptr<font>> 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<font>(name, static_cast<f32>(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<vertex> render_text(const char *string, f32 x, f32 y)
|
||||
virtual std::vector<vertex> 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<f32>(renderer->size_px);
|
||||
v.values[1] += y + padding_top + static_cast<f32>(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<u16>(renderer->size_px);
|
||||
height = static_cast<u16>(renderer->get_size_px());
|
||||
|
||||
for (auto c : text)
|
||||
{
|
||||
if (c == '\n')
|
||||
{
|
||||
height += static_cast<u16>(renderer->size_px + 2);
|
||||
height += static_cast<u16>(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<u8>(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<u16>(renderer->size_px + 2);
|
||||
text_width -= (last_word + renderer->get_em_size());
|
||||
height += static_cast<u16>(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;
|
||||
|
@ -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<u16>(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;
|
||||
|
@ -6,7 +6,52 @@ namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
void codepage::initialize_glyphs(u16 codepage_id, f32 font_size, const std::vector<u8>& 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<u8> 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<codepage>();
|
||||
page->initialize_glyphs(codepage_id, size_px, bytes);
|
||||
page->sampler_z = static_cast<f32>(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<vertex>& 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<vertex>& 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<vertex> font::render_text(const char* text, u16 max_width, bool wrap)
|
||||
std::vector<vertex> font::render_text(const wchar_t* text, u16 max_width, bool wrap)
|
||||
{
|
||||
std::vector<vertex> result;
|
||||
f32 unused_x, unused_y;
|
||||
@ -280,7 +328,7 @@ namespace rsx
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<f32, f32> font::get_char_offset(const char* text, u16 max_length, u16 max_width, bool wrap)
|
||||
std::pair<f32, f32> font::get_char_offset(const wchar_t* text, u16 max_length, u16 max_width, bool wrap)
|
||||
{
|
||||
std::vector<vertex> 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<u8>& 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
|
116
rpcs3/Emu/RSX/Overlays/overlay_fonts.h
Normal file
116
rpcs3/Emu/RSX/Overlays/overlay_fonts.h
Normal file
@ -0,0 +1,116 @@
|
||||
#include "Utilities/types.h"
|
||||
#include "overlay_utils.h"
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
// STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally
|
||||
#include <stb_image.h>
|
||||
#include <stb_truetype.h>
|
||||
|
||||
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<stbtt_packedchar> pack_info;
|
||||
std::vector<u8> glyph_data;
|
||||
u16 glyph_base = 0;
|
||||
f32 sampler_z = 0.f;
|
||||
|
||||
void initialize_glyphs(u16 codepage_id, f32 font_size, const std::vector<u8>& 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<std::pair<u32, std::unique_ptr<codepage>>> 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<vertex>& result, f32& x_advance, f32& y_advance, const wchar_t* text, u32 char_limit, u16 max_width, bool wrap);
|
||||
|
||||
std::vector<vertex> render_text(const wchar_t* text, u16 max_width = UINT16_MAX, bool wrap = false);
|
||||
|
||||
std::pair<f32, f32> 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<int>(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<u8>& bytes) const;
|
||||
};
|
||||
|
||||
// TODO: Singletons are cancer
|
||||
class fontmgr
|
||||
{
|
||||
private:
|
||||
std::vector<std::unique_ptr<font>> 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<font>(name, static_cast<f32>(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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -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 {};
|
||||
|
@ -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);
|
||||
|
@ -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<u16>(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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
struct vertex
|
||||
{
|
||||
@ -146,3 +146,9 @@ void operator < (const vector3_base<T>& lhs, T rhs)
|
||||
|
||||
using vector3i = vector3_base<int>;
|
||||
using vector3f = vector3_base<float>;
|
||||
|
||||
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);
|
||||
|
@ -58,15 +58,13 @@ static auto s_ascii_lowering_map = []()
|
||||
return _map;
|
||||
}();
|
||||
|
||||
std::string utf8_to_ascii8(const std::string& utf8_string)
|
||||
template<typename F>
|
||||
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<u8>(utf8_string[index]);
|
||||
const u8 code = static_cast<u8>(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<u8>(u_code));
|
||||
continue;
|
||||
out.push_back(static_cast<u8>(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<wchar_t>(code));
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::u16string wstring_to_utf16(const std::wstring& w_string)
|
||||
{
|
||||
if constexpr (sizeof(wchar_t) == sizeof(char16_t))
|
||||
{
|
||||
return reinterpret_cast<const char16_t*>(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
|
||||
|
@ -20,9 +20,6 @@
|
||||
#include <list>
|
||||
|
||||
// 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
|
||||
|
@ -340,7 +340,7 @@
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlays.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_animation.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_edit_text.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_font.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_fonts.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_list_view.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_message_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_osk.cpp" />
|
||||
@ -417,6 +417,7 @@
|
||||
<ClInclude Include="Emu\Io\Keyboard.h" />
|
||||
<ClInclude Include="Emu\Io\pad_config.h" />
|
||||
<ClInclude Include="Emu\RSX\Common\texture_cache_helpers.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_fonts.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_perf_metrics.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_utils.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.h" />
|
||||
|
@ -836,9 +836,6 @@
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_trophy_notification.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_font.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_list_view.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
@ -883,7 +880,7 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\title.cpp">
|
||||
<Filter>Emu</Filter>
|
||||
</ClCompile>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\system_config.cpp">
|
||||
<Filter>Emu</Filter>
|
||||
</ClCompile>
|
||||
@ -895,6 +892,9 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\system_config_types.cpp">
|
||||
<Filter>Emu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_fonts.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@ -1689,7 +1689,7 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\title.h">
|
||||
<Filter>Emu</Filter>
|
||||
</ClInclude>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\system_config.h">
|
||||
<Filter>Emu</Filter>
|
||||
</ClInclude>
|
||||
@ -1698,6 +1698,9 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\system_config_types.h">
|
||||
<Filter>Emu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_fonts.h">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user