Achievements: Include any codepoints above 0x100 in dynamic range
This commit is contained in:
parent
03181d1179
commit
b5925ab139
|
@ -445,20 +445,25 @@ void Achievements::UpdateGlyphRanges()
|
|||
// To avoid rasterizing all emoji fonts, we get the set of used glyphs in the emoji range for all strings in the
|
||||
// current game's achievement data.
|
||||
using CodepointSet = std::unordered_set<ImGuiManager::WCharType>;
|
||||
CodepointSet codepoints;
|
||||
CodepointSet codepoints, emoji_codepoints;
|
||||
|
||||
static constexpr auto add_string = [](const std::string_view str, CodepointSet& codepoints) {
|
||||
const auto add_string = [&codepoints, &emoji_codepoints](const std::string_view str) {
|
||||
char32_t codepoint;
|
||||
for (size_t offset = 0; offset < str.length();)
|
||||
{
|
||||
offset += StringUtil::DecodeUTF8(str, offset, &codepoint);
|
||||
|
||||
// Basic Latin + Latin Supplement always included.
|
||||
if (codepoint != StringUtil::UNICODE_REPLACEMENT_CHARACTER && codepoint >= 0x2000)
|
||||
codepoints.insert(static_cast<ImGuiManager::WCharType>(codepoint));
|
||||
if (codepoint != StringUtil::UNICODE_REPLACEMENT_CHARACTER && codepoint >= 0x100)
|
||||
{
|
||||
CodepointSet& dest = (codepoint >= 0x2000) ? emoji_codepoints : codepoints;
|
||||
dest.insert(static_cast<ImGuiManager::WCharType>(codepoint));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef __ANDROID__
|
||||
// We don't need to check rich presence on Android, because we're not displaying it with FullscreenUI.
|
||||
if (rc_client_has_rich_presence(s_state.client))
|
||||
{
|
||||
std::vector<const char*> rp_strings;
|
||||
|
@ -479,8 +484,9 @@ void Achievements::UpdateGlyphRanges()
|
|||
}
|
||||
|
||||
for (const char* str : rp_strings)
|
||||
add_string(str, codepoints);
|
||||
add_string(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rc_client_has_achievements(s_state.client))
|
||||
{
|
||||
|
@ -495,9 +501,9 @@ void Achievements::UpdateGlyphRanges()
|
|||
{
|
||||
const rc_client_achievement_t* achievement = bucket.achievements[j];
|
||||
if (achievement->title)
|
||||
add_string(achievement->title, codepoints);
|
||||
add_string(achievement->title);
|
||||
if (achievement->description)
|
||||
add_string(achievement->description, codepoints);
|
||||
add_string(achievement->description);
|
||||
}
|
||||
}
|
||||
rc_client_destroy_achievement_list(achievements);
|
||||
|
@ -517,24 +523,29 @@ void Achievements::UpdateGlyphRanges()
|
|||
{
|
||||
const rc_client_leaderboard_t* leaderboard = bucket.leaderboards[j];
|
||||
if (leaderboard->title)
|
||||
add_string(leaderboard->title, codepoints);
|
||||
add_string(leaderboard->title);
|
||||
if (leaderboard->description)
|
||||
add_string(leaderboard->description, codepoints);
|
||||
add_string(leaderboard->description);
|
||||
}
|
||||
}
|
||||
rc_client_destroy_leaderboard_list(leaderboards);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ImGuiManager::WCharType> sorted_codepoints;
|
||||
std::vector<ImGuiManager::WCharType> sorted_codepoints, sorted_emoji_codepoints;
|
||||
sorted_codepoints.reserve(codepoints.size());
|
||||
sorted_codepoints.insert(sorted_codepoints.begin(), codepoints.begin(), codepoints.end());
|
||||
std::sort(sorted_codepoints.begin(), sorted_codepoints.end());
|
||||
sorted_emoji_codepoints.reserve(codepoints.size());
|
||||
sorted_emoji_codepoints.insert(sorted_emoji_codepoints.begin(), emoji_codepoints.begin(), emoji_codepoints.end());
|
||||
std::sort(sorted_emoji_codepoints.begin(), sorted_emoji_codepoints.end());
|
||||
|
||||
// Compact codepoints to ranges.
|
||||
GPUThread::RunOnThread([sorted_codepoints = std::move(sorted_codepoints)]() {
|
||||
ImGuiManager::SetEmojiFontRange(ImGuiManager::CompactFontRange(sorted_codepoints));
|
||||
});
|
||||
GPUThread::RunOnThread(
|
||||
[sorted_codepoints = std::move(sorted_codepoints), sorted_emoji_codepoints = std::move(sorted_emoji_codepoints)]() {
|
||||
ImGuiManager::SetDynamicFontRange(ImGuiManager::CompactFontRange(sorted_codepoints),
|
||||
ImGuiManager::CompactFontRange(sorted_emoji_codepoints));
|
||||
});
|
||||
}
|
||||
|
||||
bool Achievements::IsActive()
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com> and contributors.
|
||||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "qthost.h"
|
||||
|
||||
#include "core/gpu_thread.h"
|
||||
#include "core/host.h"
|
||||
|
||||
#include "util/imgui_manager.h"
|
||||
|
@ -256,9 +257,10 @@ void QtHost::UpdateGlyphRangesAndClearCache(QWidget* dialog_parent, std::string_
|
|||
const char* imgui_font_url = nullptr;
|
||||
std::vector<ImWchar> glyph_ranges;
|
||||
glyph_ranges.clear();
|
||||
glyph_ranges.reserve(std::size(s_base_latin_range) + 2);
|
||||
|
||||
// Base Latin range is always included.
|
||||
glyph_ranges.insert(glyph_ranges.begin(), std::begin(s_base_latin_range), std::end(s_base_latin_range));
|
||||
glyph_ranges.insert(glyph_ranges.end(), std::begin(s_base_latin_range), std::end(s_base_latin_range));
|
||||
|
||||
if (gi)
|
||||
{
|
||||
|
@ -281,7 +283,7 @@ void QtHost::UpdateGlyphRangesAndClearCache(QWidget* dialog_parent, std::string_
|
|||
// If we don't have any specific glyph range, assume Central European, except if English, then keep the size down.
|
||||
if ((!gi || !gi->used_glyphs) && language != "en")
|
||||
{
|
||||
glyph_ranges.insert(glyph_ranges.begin(), std::begin(s_central_european_ranges),
|
||||
glyph_ranges.insert(glyph_ranges.end(), std::begin(s_central_european_ranges),
|
||||
std::end(s_central_european_ranges));
|
||||
}
|
||||
|
||||
|
@ -311,7 +313,9 @@ void QtHost::UpdateGlyphRangesAndClearCache(QWidget* dialog_parent, std::string_
|
|||
if (g_emu_thread)
|
||||
{
|
||||
Host::RunOnCPUThread([font_path = std::move(font_path), glyph_ranges = std::move(glyph_ranges)]() mutable {
|
||||
ImGuiManager::SetFontPathAndRange(std::move(font_path), std::move(glyph_ranges));
|
||||
GPUThread::RunOnThread([font_path = std::move(font_path), glyph_ranges = std::move(glyph_ranges)]() mutable {
|
||||
ImGuiManager::SetFontPathAndRange(std::move(font_path), std::move(glyph_ranges));
|
||||
});
|
||||
Host::ClearTranslationCache();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -132,9 +132,6 @@ bool RegTestHost::InitializeConfig()
|
|||
EmuFolders::LoadConfig(*s_base_settings_interface.get());
|
||||
EmuFolders::EnsureFoldersExist();
|
||||
|
||||
// imgui setup, make sure it doesn't bug out
|
||||
ImGuiManager::SetFontPathAndRange(std::string(), {0x0020, 0x00FF, 0x2022, 0x2022, 0, 0});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ static void SetKeyMap();
|
|||
static bool LoadFontData(Error* error);
|
||||
static void ReloadFontDataIfActive();
|
||||
static bool AddImGuiFonts(bool debug_font, bool fullscreen_fonts);
|
||||
static ImFont* AddTextFont(float size, bool full_glyph_range);
|
||||
static ImFont* AddTextFont(float size, const ImWchar* glyph_range);
|
||||
static ImFont* AddFixedFont(float size);
|
||||
static bool AddIconFonts(float size);
|
||||
static bool AddIconFonts(float size, const ImWchar* emoji_range);
|
||||
static void SetCommonIOOptions(ImGuiIO& io);
|
||||
static void SetImKeyState(ImGuiIO& io, ImGuiKey imkey, bool pressed);
|
||||
static const char* GetClipboardTextImpl(void* userdata);
|
||||
|
@ -94,7 +94,8 @@ static void DrawSoftwareCursor(const SoftwareCursor& sc, const std::pair<float,
|
|||
static constexpr float OSD_FADE_IN_TIME = 0.1f;
|
||||
static constexpr float OSD_FADE_OUT_TIME = 0.4f;
|
||||
|
||||
static constexpr std::array<ImWchar, 4> s_ascii_font_range = {{0x20, 0x7F, 0x00, 0x00}};
|
||||
static constexpr std::array<ImWchar, 4> ASCII_FONT_RANGE = {{0x20, 0x7F, 0x00, 0x00}};
|
||||
static constexpr std::array<ImWchar, 6> DEFAULT_FONT_RANGE = {{0x0020, 0x00FF, 0x2022, 0x2022, 0x0000, 0x0000}};
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -140,7 +141,8 @@ struct ALIGN_TO_CACHE_LINE State
|
|||
|
||||
std::string font_path;
|
||||
std::vector<WCharType> font_range;
|
||||
std::vector<WCharType> emoji_range;
|
||||
std::vector<WCharType> dynamic_font_range;
|
||||
std::vector<WCharType> dynamic_emoji_range;
|
||||
|
||||
DynamicHeapArray<u8> standard_font_data;
|
||||
DynamicHeapArray<u8> fixed_font_data;
|
||||
|
@ -166,32 +168,13 @@ void ImGuiManager::SetFontPathAndRange(std::string path, std::vector<WCharType>
|
|||
ReloadFontDataIfActive();
|
||||
}
|
||||
|
||||
void ImGuiManager::SetEmojiFontRange(std::vector<WCharType> range)
|
||||
void ImGuiManager::SetDynamicFontRange(std::vector<WCharType> font_range, std::vector<WCharType> emoji_range)
|
||||
{
|
||||
static constexpr size_t builtin_size = std::size(EMOJI_ICON_RANGE);
|
||||
const size_t runtime_size = range.size();
|
||||
|
||||
if (runtime_size == 0)
|
||||
{
|
||||
if (s_state.emoji_range.empty())
|
||||
return;
|
||||
|
||||
s_state.emoji_range = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!s_state.emoji_range.empty() && (s_state.emoji_range.size() - builtin_size) == range.size() &&
|
||||
std::memcmp(s_state.emoji_range.data(), range.data(), range.size() * sizeof(ImWchar)) == 0)
|
||||
{
|
||||
// no change
|
||||
return;
|
||||
}
|
||||
|
||||
s_state.emoji_range = std::move(range);
|
||||
s_state.emoji_range.resize(s_state.emoji_range.size() + builtin_size);
|
||||
std::memcpy(&s_state.emoji_range[runtime_size], EMOJI_ICON_RANGE, sizeof(EMOJI_ICON_RANGE));
|
||||
}
|
||||
if (s_state.dynamic_font_range == font_range && s_state.dynamic_emoji_range == emoji_range)
|
||||
return;
|
||||
|
||||
s_state.dynamic_font_range = std::move(font_range);
|
||||
s_state.dynamic_emoji_range = std::move(emoji_range);
|
||||
ReloadFontDataIfActive();
|
||||
}
|
||||
|
||||
|
@ -647,13 +630,12 @@ bool ImGuiManager::LoadFontData(Error* error)
|
|||
return true;
|
||||
}
|
||||
|
||||
ImFont* ImGuiManager::AddTextFont(float size, bool full_glyph_range)
|
||||
ImFont* ImGuiManager::AddTextFont(float size, const ImWchar* glyph_range)
|
||||
{
|
||||
ImFontConfig cfg;
|
||||
cfg.FontDataOwnedByAtlas = false;
|
||||
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
|
||||
s_state.standard_font_data.data(), static_cast<int>(s_state.standard_font_data.size()), size, &cfg,
|
||||
full_glyph_range ? s_state.font_range.data() : s_ascii_font_range.data());
|
||||
s_state.standard_font_data.data(), static_cast<int>(s_state.standard_font_data.size()), size, &cfg, glyph_range);
|
||||
}
|
||||
|
||||
ImFont* ImGuiManager::AddFixedFont(float size)
|
||||
|
@ -662,10 +644,10 @@ ImFont* ImGuiManager::AddFixedFont(float size)
|
|||
cfg.FontDataOwnedByAtlas = false;
|
||||
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_state.fixed_font_data.data(),
|
||||
static_cast<int>(s_state.fixed_font_data.size()), size, &cfg,
|
||||
s_ascii_font_range.data());
|
||||
ASCII_FONT_RANGE.data());
|
||||
}
|
||||
|
||||
bool ImGuiManager::AddIconFonts(float size)
|
||||
bool ImGuiManager::AddIconFonts(float size, const ImWchar* emoji_range)
|
||||
{
|
||||
{
|
||||
ImFontConfig cfg;
|
||||
|
@ -708,9 +690,9 @@ bool ImGuiManager::AddIconFonts(float size)
|
|||
cfg.FontDataOwnedByAtlas = false;
|
||||
cfg.FontBuilderFlags = ImGuiFreeTypeBuilderFlags_LoadColor | ImGuiFreeTypeBuilderFlags_Bitmap;
|
||||
|
||||
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
|
||||
s_state.emoji_font_data.data(), static_cast<int>(s_state.emoji_font_data.size()), size * 0.9f, &cfg,
|
||||
s_state.emoji_range.empty() ? EMOJI_ICON_RANGE : s_state.emoji_range.data())) [[unlikely]]
|
||||
if (!ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_state.emoji_font_data.data(),
|
||||
static_cast<int>(s_state.emoji_font_data.size()), size * 0.9f, &cfg,
|
||||
emoji_range)) [[unlikely]]
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -730,12 +712,43 @@ bool ImGuiManager::AddImGuiFonts(bool debug_font, bool fullscreen_fonts)
|
|||
INFO_LOG("Allocating fonts winscale={} globalscale={} debug={} fullscreen={}", window_scale, s_state.global_scale,
|
||||
debug_font, fullscreen_fonts);
|
||||
|
||||
// need to generate arrays if dynamic ranges are present
|
||||
const ImWchar* text_range = s_state.font_range.empty() ? DEFAULT_FONT_RANGE.data() : s_state.font_range.data();
|
||||
const ImWchar* emoji_range = EMOJI_ICON_RANGE;
|
||||
std::vector<ImWchar> full_text_range, full_emoji_range;
|
||||
if (!s_state.dynamic_font_range.empty())
|
||||
{
|
||||
// skip the zeros, we'll add them afterwards
|
||||
const size_t base_size = s_state.font_range.empty() ? DEFAULT_FONT_RANGE.size() : s_state.font_range.size();
|
||||
Assert(base_size > 2);
|
||||
full_text_range.reserve(base_size + s_state.dynamic_font_range.size());
|
||||
full_text_range.insert(full_text_range.end(), &text_range[0], &text_range[base_size - 2]);
|
||||
full_text_range.insert(full_text_range.end(), s_state.dynamic_font_range.begin(), s_state.dynamic_font_range.end());
|
||||
full_text_range.insert(full_text_range.end(), 2, 0);
|
||||
text_range = full_text_range.data();
|
||||
}
|
||||
if (!s_state.dynamic_emoji_range.empty())
|
||||
{
|
||||
// skip the zeros, we'll add them afterwards
|
||||
size_t base_size = 0;
|
||||
for (const ImWchar* c = EMOJI_ICON_RANGE; *c != 0; c++)
|
||||
base_size++;
|
||||
|
||||
Assert(base_size > 2);
|
||||
full_emoji_range.reserve(base_size + s_state.dynamic_emoji_range.size());
|
||||
full_emoji_range.insert(full_emoji_range.end(), &EMOJI_ICON_RANGE[0], &EMOJI_ICON_RANGE[base_size - 2]);
|
||||
full_emoji_range.insert(full_emoji_range.end(), s_state.dynamic_emoji_range.begin(),
|
||||
s_state.dynamic_emoji_range.end());
|
||||
full_emoji_range.insert(full_emoji_range.end(), 2, 0);
|
||||
emoji_range = full_emoji_range.data();
|
||||
}
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.Fonts->Clear();
|
||||
|
||||
if (debug_font)
|
||||
{
|
||||
s_state.debug_font = AddTextFont(debug_font_size, false);
|
||||
s_state.debug_font = AddTextFont(debug_font_size, ASCII_FONT_RANGE.data());
|
||||
if (!s_state.debug_font)
|
||||
return false;
|
||||
}
|
||||
|
@ -744,8 +757,8 @@ bool ImGuiManager::AddImGuiFonts(bool debug_font, bool fullscreen_fonts)
|
|||
if (!s_state.fixed_font)
|
||||
return false;
|
||||
|
||||
s_state.osd_font = AddTextFont(osd_font_size, true);
|
||||
if (!s_state.osd_font || !AddIconFonts(osd_font_size))
|
||||
s_state.osd_font = AddTextFont(osd_font_size, text_range);
|
||||
if (!s_state.osd_font || !AddIconFonts(osd_font_size, emoji_range))
|
||||
return false;
|
||||
if (!debug_font)
|
||||
s_state.debug_font = s_state.osd_font;
|
||||
|
@ -753,13 +766,13 @@ bool ImGuiManager::AddImGuiFonts(bool debug_font, bool fullscreen_fonts)
|
|||
if (fullscreen_fonts)
|
||||
{
|
||||
const float medium_font_size = ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_MEDIUM_FONT_SIZE);
|
||||
s_state.medium_font = AddTextFont(medium_font_size, true);
|
||||
if (!s_state.medium_font || !AddIconFonts(medium_font_size))
|
||||
s_state.medium_font = AddTextFont(medium_font_size, text_range);
|
||||
if (!s_state.medium_font || !AddIconFonts(medium_font_size, emoji_range))
|
||||
return false;
|
||||
|
||||
const float large_font_size = ImGuiFullscreen::LayoutScale(ImGuiFullscreen::LAYOUT_LARGE_FONT_SIZE);
|
||||
s_state.large_font = AddTextFont(large_font_size, true);
|
||||
if (!s_state.large_font || !AddIconFonts(large_font_size))
|
||||
s_state.large_font = AddTextFont(large_font_size, text_range);
|
||||
if (!s_state.large_font || !AddIconFonts(large_font_size, emoji_range))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -64,9 +64,9 @@ static constexpr float DEFAULT_SCREEN_MARGIN = 16.0f;
|
|||
/// Sets the path to the font to use. Empty string means to use the default.
|
||||
void SetFontPathAndRange(std::string path, std::vector<WCharType> range);
|
||||
|
||||
/// Sets the emoji font range to use. Empty means no glyphs will be rasterized.
|
||||
/// Sets the normal/emoji font range to use. Empty means no glyphs will be rasterized.
|
||||
/// Should NOT be terminated with zeros, unlike the font range above.
|
||||
void SetEmojiFontRange(std::vector<WCharType> range);
|
||||
void SetDynamicFontRange(std::vector<WCharType> font_range, std::vector<WCharType> emoji_range);
|
||||
|
||||
/// Returns a compacted font range, with adjacent glyphs merged into one pair.
|
||||
std::vector<WCharType> CompactFontRange(std::span<const WCharType> range);
|
||||
|
|
Loading…
Reference in New Issue