diff --git a/CMakeLists.txt b/CMakeLists.txt index 68f3c39fb..6524222aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1102,6 +1102,10 @@ set(IMGUI src/imgui/imgui_config.h src/imgui/renderer/imgui_impl_sdlrenderer3.h src/imgui/renderer/imgui_impl_vulkan.cpp src/imgui/renderer/imgui_impl_vulkan.h + src/imgui/renderer/font_data.cpp + src/imgui/renderer/font_data.h + src/imgui/renderer/font_stack.cpp + src/imgui/renderer/font_stack.h src/imgui/renderer/texture_manager.cpp src/imgui/renderer/texture_manager.h src/imgui/big_picture.cpp diff --git a/REUSE.toml b/REUSE.toml index 1f6aa1b05..c59a358c7 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -116,9 +116,33 @@ SPDX-FileCopyrightText = "2017-2024 Bartosz Taudul " SPDX-License-Identifier = "BSD-3-Clause" [[annotations]] -path = "src/imgui/renderer/fonts/NotoSansJP-Regular.ttf" +path = "src/imgui/renderer/fonts/NotoSans-Regular.ttf" precedence = "aggregate" -SPDX-FileCopyrightText = "2012 Google Inc. All Rights Reserved." +SPDX-FileCopyrightText = "Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)" +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = "src/imgui/renderer/fonts/NotoSansArabic-Regular.ttf" +precedence = "aggregate" +SPDX-FileCopyrightText = "Copyright 2015-2021 Google LLC. All Rights Reserved." +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = "src/imgui/renderer/fonts/NotoSansThai-Regular.ttf" +precedence = "aggregate" +SPDX-FileCopyrightText = "Copyright 2016 Google Inc. All Rights Reserved." +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = "src/imgui/renderer/fonts/NotoSansSymbols2-Regular.ttf" +precedence = "aggregate" +SPDX-FileCopyrightText = "Copyright 2017 Google Inc. All Rights Reserved." +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = "src/imgui/renderer/fonts/NotoSansCJK-Regular.ttc" +precedence = "aggregate" +SPDX-FileCopyrightText = "Copyright 2014-2021 Adobe (http://www.adobe.com/)." SPDX-License-Identifier = "OFL-1.1" [[annotations]] diff --git a/src/imgui/big_picture.cpp b/src/imgui/big_picture.cpp index 61ea53ac4..3ac1c7039 100644 --- a/src/imgui/big_picture.cpp +++ b/src/imgui/big_picture.cpp @@ -9,16 +9,15 @@ #include "big_picture.h" #include "common/logging/log.h" #include "core/devtools/layer.h" +#include "core/emulator_settings.h" #include "core/file_format/psf.h" #include "emulator.h" #include "imgui/imgui_std.h" +#include "imgui/renderer/font_stack.h" #include "imgui/renderer/imgui_impl_sdl3_bpm.h" #include "imgui/renderer/imgui_impl_sdlrenderer3.h" #include "settings_dialog_imgui.h" -#include "imgui_fonts/notosansjp_regular.ttf.g.cpp" -#include "imgui_fonts/proggyvector_regular.ttf.g.cpp" - CMRC_DECLARE(res); namespace BigPictureMode { @@ -67,24 +66,12 @@ void Launch() { io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; io.ConfigNavCursorVisibleAlways = true; - ImFontConfig configBase; - configBase.OversampleH = 3; - configBase.OversampleV = 3; - - ImFontConfig configMerge; - configMerge.OversampleH = 3; - configMerge.OversampleV = 3; - configMerge.MergeMode = true; - - // tm symbol - const ImWchar icon_ranges[] = {0x2122, 0x2122, 0}; - ImFont* myFont = io.Fonts->AddFontFromMemoryCompressedTTF( - imgui_font_notosansjp_regular_compressed_data, - imgui_font_notosansjp_regular_compressed_size, 32.0f, &configBase, icon_ranges); - - io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_notosansjp_regular_compressed_data, - imgui_font_notosansjp_regular_compressed_size, 32.0f, - &configMerge, io.Fonts->GetGlyphRangesDefault()); + ImFontConfig font_cfg; + font_cfg.OversampleH = 2; + font_cfg.OversampleV = 1; + ImFont* myFont = ImGui::FontStack::AddPrimaryUiFont( + io.Fonts, 32.0f, EmulatorSettings.GetConsoleLanguage(), font_cfg, true); + io.FontDefault = myFont; io.Fonts->Build(); diff --git a/src/imgui/renderer/CMakeLists.txt b/src/imgui/renderer/CMakeLists.txt index 5d74632f9..dee8e2407 100644 --- a/src/imgui/renderer/CMakeLists.txt +++ b/src/imgui/renderer/CMakeLists.txt @@ -6,7 +6,11 @@ project(ImGui_Resources) add_executable(Dear_ImGui_FontEmbed ${CMAKE_SOURCE_DIR}/externals/dear_imgui/misc/fonts/binary_to_compressed_c.cpp) set(FONT_LIST - NotoSansJP-Regular.ttf + NotoSansArabic-Regular.ttf + NotoSansCJK-Regular.ttc + NotoSans-Regular.ttf + NotoSansSymbols2-Regular.ttf + NotoSansThai-Regular.ttf ProggyVector-Regular.ttf ) @@ -14,7 +18,7 @@ set(OutputList "") FOREACH (FONT_FILE ${FONT_LIST}) string(REGEX REPLACE "-" "_" fontname ${FONT_FILE}) string(TOLOWER ${fontname} fontname) - string(REGEX REPLACE ".ttf" "" fontname_cpp ${fontname}) + string(REGEX REPLACE "\\.(ttf|otf|ttc)$" "" fontname_cpp ${fontname}) set(fontname_cpp "imgui_font_${fontname_cpp}") MESSAGE(STATUS "Embedding font ${FONT_FILE}") diff --git a/src/imgui/renderer/font_data.cpp b/src/imgui/renderer/font_data.cpp new file mode 100644 index 000000000..d0bdd53e6 --- /dev/null +++ b/src/imgui/renderer/font_data.cpp @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "font_data.h" + +#include "imgui_fonts/notosans_regular.ttf.g.cpp" +#include "imgui_fonts/notosansarabic_regular.ttf.g.cpp" +#include "imgui_fonts/notosanscjk_regular.ttc.g.cpp" +#include "imgui_fonts/notosanssymbols2_regular.ttf.g.cpp" +#include "imgui_fonts/notosansthai_regular.ttf.g.cpp" +#include "imgui_fonts/proggyvector_regular.ttf.g.cpp" diff --git a/src/imgui/renderer/font_data.h b/src/imgui/renderer/font_data.h new file mode 100644 index 000000000..62241fbcc --- /dev/null +++ b/src/imgui/renderer/font_data.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +extern const unsigned int imgui_font_notosans_regular_compressed_size; +extern const unsigned char imgui_font_notosans_regular_compressed_data[]; + +extern const unsigned int imgui_font_notosansarabic_regular_compressed_size; +extern const unsigned char imgui_font_notosansarabic_regular_compressed_data[]; + +extern const unsigned int imgui_font_notosansthai_regular_compressed_size; +extern const unsigned char imgui_font_notosansthai_regular_compressed_data[]; + +extern const unsigned int imgui_font_notosanssymbols2_regular_compressed_size; +extern const unsigned char imgui_font_notosanssymbols2_regular_compressed_data[]; + +extern const unsigned int imgui_font_notosanscjk_regular_compressed_size; +extern const unsigned char imgui_font_notosanscjk_regular_compressed_data[]; + +extern const unsigned int imgui_font_proggyvector_regular_compressed_size; +extern const unsigned char imgui_font_proggyvector_regular_compressed_data[]; diff --git a/src/imgui/renderer/font_stack.cpp b/src/imgui/renderer/font_stack.cpp new file mode 100644 index 000000000..79e9db744 --- /dev/null +++ b/src/imgui/renderer/font_stack.cpp @@ -0,0 +1,147 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "font_stack.h" + +#include "font_data.h" + +namespace { + +struct CompressedFontBlob { + const unsigned char* data; + int size; +}; + +constexpr int kConsoleLanguageJapanese = 0; +constexpr int kConsoleLanguageKorean = 9; +constexpr int kConsoleLanguageTraditionalChinese = 10; +constexpr int kConsoleLanguageSimplifiedChinese = 11; + +constexpr int kNotoSansCjkFontIndexJp = 0; +constexpr int kNotoSansCjkFontIndexKr = 1; +constexpr int kNotoSansCjkFontIndexSc = 2; +constexpr int kNotoSansCjkFontIndexTc = 3; + +constexpr ImWchar kLatinExtendedRanges[] = { + 0x0100, 0x024F, // Latin Extended-A + Latin Extended-B + 0x1E00, 0x1EFF, // Latin Extended Additional + 0, +}; + +constexpr ImWchar kArabicRanges[] = { + 0x0600, 0x06FF, // Arabic + 0x0750, 0x077F, // Arabic Supplement + 0x08A0, 0x08FF, // Arabic Extended-A + 0xFB50, 0xFDFF, // Arabic Presentation Forms-A + 0xFE70, 0xFEFF, // Arabic Presentation Forms-B + 0, +}; + +constexpr ImWchar kSymbolsRanges[] = { + 0x20A0, 0x20CF, // Currency symbols + 0x2100, 0x214F, // Letterlike symbols + 0x2190, 0x21FF, // Arrows + 0x2200, 0x22FF, // Math operators + 0x2460, 0x24FF, // Enclosed alphanumerics + 0x25A0, 0x25FF, // Geometric shapes + 0x2600, 0x26FF, // Misc symbols + 0x2700, 0x27BF, // Dingbats + 0x2B00, 0x2BFF, // Misc symbols and arrows + 0, +}; + +const CompressedFontBlob kNotoSansBlob{ + imgui_font_notosans_regular_compressed_data, + static_cast(imgui_font_notosans_regular_compressed_size), +}; +const CompressedFontBlob kNotoSansArabicBlob{ + imgui_font_notosansarabic_regular_compressed_data, + static_cast(imgui_font_notosansarabic_regular_compressed_size), +}; +const CompressedFontBlob kNotoSansThaiBlob{ + imgui_font_notosansthai_regular_compressed_data, + static_cast(imgui_font_notosansthai_regular_compressed_size), +}; +const CompressedFontBlob kNotoSansSymbols2Blob{ + imgui_font_notosanssymbols2_regular_compressed_data, + static_cast(imgui_font_notosanssymbols2_regular_compressed_size), +}; +const CompressedFontBlob kNotoSansCjkBlob{ + imgui_font_notosanscjk_regular_compressed_data, + static_cast(imgui_font_notosanscjk_regular_compressed_size), +}; + +int GetCjkFontIndex(const int console_language) { + switch (console_language) { + case kConsoleLanguageJapanese: + return kNotoSansCjkFontIndexJp; + case kConsoleLanguageKorean: + return kNotoSansCjkFontIndexKr; + case kConsoleLanguageTraditionalChinese: + return kNotoSansCjkFontIndexTc; + case kConsoleLanguageSimplifiedChinese: + return kNotoSansCjkFontIndexSc; + default: + return kNotoSansCjkFontIndexJp; + } +} + +const ImWchar* GetPrimaryTextRanges(ImFontAtlas* atlas) { + static ImVector ranges{}; + if (ranges.empty()) { + ImFontGlyphRangesBuilder rb{}; + rb.AddRanges(atlas->GetGlyphRangesDefault()); + rb.AddRanges(atlas->GetGlyphRangesGreek()); + rb.AddRanges(atlas->GetGlyphRangesCyrillic()); + rb.AddRanges(atlas->GetGlyphRangesVietnamese()); + rb.AddRanges(kLatinExtendedRanges); + rb.BuildRanges(&ranges); + } + return ranges.Data; +} + +const ImWchar* GetCjkCoverageRanges(ImFontAtlas* atlas) { + static ImVector ranges{}; + if (ranges.empty()) { + ImFontGlyphRangesBuilder rb{}; + rb.AddRanges(atlas->GetGlyphRangesJapanese()); + rb.AddRanges(atlas->GetGlyphRangesKorean()); + rb.AddRanges(atlas->GetGlyphRangesChineseFull()); + rb.BuildRanges(&ranges); + } + return ranges.Data; +} + +void AddMergedFont(ImFontAtlas* atlas, const CompressedFontBlob blob, const float font_size, + const ImWchar* glyph_ranges, const ImFontConfig& base_cfg, + const int font_no = 0) { + ImFontConfig cfg = base_cfg; + cfg.MergeMode = true; + cfg.FontNo = font_no; + atlas->AddFontFromMemoryCompressedTTF(blob.data, blob.size, font_size, &cfg, glyph_ranges); +} + +} // namespace + +namespace ImGui::FontStack { + +ImFont* AddPrimaryUiFont(ImFontAtlas* atlas, const float font_size, const int console_language, + const ImFontConfig& base_cfg, const bool include_cjk_fallback) { + const ImWchar* primary_ranges = GetPrimaryTextRanges(atlas); + ImFont* font = atlas->AddFontFromMemoryCompressedTTF(kNotoSansBlob.data, kNotoSansBlob.size, + font_size, &base_cfg, primary_ranges); + + AddMergedFont(atlas, kNotoSansArabicBlob, font_size, kArabicRanges, base_cfg); + AddMergedFont(atlas, kNotoSansThaiBlob, font_size, atlas->GetGlyphRangesThai(), base_cfg); + AddMergedFont(atlas, kNotoSansSymbols2Blob, font_size, kSymbolsRanges, base_cfg); + + if (include_cjk_fallback) { + const ImWchar* cjk_ranges = GetCjkCoverageRanges(atlas); + AddMergedFont(atlas, kNotoSansCjkBlob, font_size, cjk_ranges, base_cfg, + GetCjkFontIndex(console_language)); + } + + return font; +} + +} // namespace ImGui::FontStack diff --git a/src/imgui/renderer/font_stack.h b/src/imgui/renderer/font_stack.h new file mode 100644 index 000000000..071e07269 --- /dev/null +++ b/src/imgui/renderer/font_stack.h @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +namespace ImGui::FontStack { + +ImFont* AddPrimaryUiFont(ImFontAtlas* atlas, float font_size, int console_language, + const ImFontConfig& base_cfg, bool include_cjk_fallback); + +} // namespace ImGui::FontStack diff --git a/src/imgui/renderer/fonts/NotoSans-Regular.ttf b/src/imgui/renderer/fonts/NotoSans-Regular.ttf new file mode 100644 index 000000000..b48f1f22e Binary files /dev/null and b/src/imgui/renderer/fonts/NotoSans-Regular.ttf differ diff --git a/src/imgui/renderer/fonts/NotoSansArabic-Regular.ttf b/src/imgui/renderer/fonts/NotoSansArabic-Regular.ttf new file mode 100644 index 000000000..ce21d4f5a Binary files /dev/null and b/src/imgui/renderer/fonts/NotoSansArabic-Regular.ttf differ diff --git a/src/imgui/renderer/fonts/NotoSansCJK-Regular.ttc b/src/imgui/renderer/fonts/NotoSansCJK-Regular.ttc new file mode 100644 index 000000000..a2033d0e4 Binary files /dev/null and b/src/imgui/renderer/fonts/NotoSansCJK-Regular.ttc differ diff --git a/src/imgui/renderer/fonts/NotoSansJP-Regular.ttf b/src/imgui/renderer/fonts/NotoSansJP-Regular.ttf deleted file mode 100644 index b2dad730d..000000000 Binary files a/src/imgui/renderer/fonts/NotoSansJP-Regular.ttf and /dev/null differ diff --git a/src/imgui/renderer/fonts/NotoSansSymbols2-Regular.ttf b/src/imgui/renderer/fonts/NotoSansSymbols2-Regular.ttf new file mode 100644 index 000000000..d786ee8fd Binary files /dev/null and b/src/imgui/renderer/fonts/NotoSansSymbols2-Regular.ttf differ diff --git a/src/imgui/renderer/fonts/NotoSansThai-Regular.ttf b/src/imgui/renderer/fonts/NotoSansThai-Regular.ttf new file mode 100644 index 000000000..47c3fa8d5 Binary files /dev/null and b/src/imgui/renderer/fonts/NotoSansThai-Regular.ttf differ diff --git a/src/imgui/renderer/imgui_core.cpp b/src/imgui/renderer/imgui_core.cpp index b52a68d22..b2e39f268 100644 --- a/src/imgui/renderer/imgui_core.cpp +++ b/src/imgui/renderer/imgui_core.cpp @@ -8,6 +8,8 @@ #include "core/debug_state.h" #include "core/devtools/layer.h" #include "core/emulator_settings.h" +#include "font_data.h" +#include "font_stack.h" #include "imgui/imgui_layer.h" #include "imgui_core.h" #include "imgui_impl_sdl3.h" @@ -17,9 +19,6 @@ #include "texture_manager.h" #include "video_core/renderer_vulkan/vk_presenter.h" -#include "imgui_fonts/notosansjp_regular.ttf.g.cpp" -#include "imgui_fonts/proggyvector_regular.ttf.g.cpp" - static void CheckVkResult(const vk::Result err) { LOG_ERROR(ImGui, "Vulkan error {}", vk::to_string(err)); } @@ -63,26 +62,18 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w std::memcpy(log_file_buf, path.c_str(), path.size()); io.LogFilename = log_file_buf; - ImFontGlyphRangesBuilder rb{}; - rb.AddRanges(io.Fonts->GetGlyphRangesDefault()); - rb.AddRanges(io.Fonts->GetGlyphRangesGreek()); - rb.AddRanges(io.Fonts->GetGlyphRangesKorean()); - rb.AddRanges(io.Fonts->GetGlyphRangesJapanese()); - rb.AddRanges(io.Fonts->GetGlyphRangesCyrillic()); - ImVector ranges{}; - rb.BuildRanges(&ranges); ImFontConfig font_cfg{}; font_cfg.OversampleH = 2; font_cfg.OversampleV = 1; - io.FontDefault = io.Fonts->AddFontFromMemoryCompressedTTF( - imgui_font_notosansjp_regular_compressed_data, - imgui_font_notosansjp_regular_compressed_size, 32.0f, &font_cfg, ranges.Data); + const int console_language = EmulatorSettings.GetConsoleLanguage(); + io.FontDefault = FontStack::AddPrimaryUiFont(io.Fonts, 32.0f, console_language, font_cfg, true); + io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_proggyvector_regular_compressed_data, imgui_font_proggyvector_regular_compressed_size, 32.0f); - io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_notosansjp_regular_compressed_data, - imgui_font_notosansjp_regular_compressed_size, 128.0f, - &font_cfg, ranges.Data); + + FontStack::AddPrimaryUiFont(io.Fonts, 128.0f, console_language, font_cfg, true); + io.Fonts->Build(); io.FontGlobalScale = 0.5f;