go-to-noto-again (#4309)

* renderer: update font handling and add new font support
- Added support for multiple NotoSans fonts including Arabic, Thai, and CJK.
- Refactored font loading logic to use FontStack for better management.
- Removed deprecated NotoSansJP font and updated font paths in CMake.

* optimize atlas size

---------

Co-authored-by: w1naenator <valdis.bogdans@hotmail.com>
This commit is contained in:
Valdis Bogdāns 2026-04-23 18:52:04 +03:00 committed by GitHub
parent f24ad8568e
commit e455a2f41a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 253 additions and 42 deletions

View File

@ -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

View File

@ -116,9 +116,33 @@ SPDX-FileCopyrightText = "2017-2024 Bartosz Taudul <wolf@nereid.pl>"
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]]

View File

@ -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();

View File

@ -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}")

View File

@ -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"

View File

@ -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[];

View File

@ -0,0 +1,153 @@
// 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<int>(imgui_font_notosans_regular_compressed_size),
};
const CompressedFontBlob kNotoSansArabicBlob{
imgui_font_notosansarabic_regular_compressed_data,
static_cast<int>(imgui_font_notosansarabic_regular_compressed_size),
};
const CompressedFontBlob kNotoSansThaiBlob{
imgui_font_notosansthai_regular_compressed_data,
static_cast<int>(imgui_font_notosansthai_regular_compressed_size),
};
const CompressedFontBlob kNotoSansSymbols2Blob{
imgui_font_notosanssymbols2_regular_compressed_data,
static_cast<int>(imgui_font_notosanssymbols2_regular_compressed_size),
};
const CompressedFontBlob kNotoSansCjkBlob{
imgui_font_notosanscjk_regular_compressed_data,
static_cast<int>(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<ImWchar> 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, const int console_language) {
switch (console_language) {
case kConsoleLanguageJapanese:
return atlas->GetGlyphRangesJapanese();
case kConsoleLanguageKorean:
return atlas->GetGlyphRangesKorean();
case kConsoleLanguageSimplifiedChinese:
return atlas->GetGlyphRangesChineseSimplifiedCommon();
case kConsoleLanguageTraditionalChinese:
return atlas->GetGlyphRangesChineseFull();
default:
return nullptr;
}
}
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) {
// Keep the atlas lean by only merging CJK ranges for active CJK console locales.
const ImWchar* cjk_ranges = GetCjkCoverageRanges(atlas, console_language);
if (cjk_ranges != nullptr) {
AddMergedFont(atlas, kNotoSansCjkBlob, font_size, cjk_ranges, base_cfg,
GetCjkFontIndex(console_language));
}
}
return font;
}
} // namespace ImGui::FontStack

View File

@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <imgui.h>
namespace ImGui::FontStack {
ImFont* AddPrimaryUiFont(ImFontAtlas* atlas, float font_size, int console_language,
const ImFontConfig& base_cfg, bool include_cjk_fallback);
} // namespace ImGui::FontStack

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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,20 @@ 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<ImWchar> 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);
io.Fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
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);
// Avoid exploding atlas size on Metal/MoltenVK when CJK fallback is enabled.
FontStack::AddPrimaryUiFont(io.Fonts, 128.0f, console_language, font_cfg, false);
io.Fonts->Build();
io.FontGlobalScale = 0.5f;