yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
font_loader.cc
Go to the documentation of this file.
2
3#include <cstring>
4#include <filesystem>
5#include <string>
6#include <vector>
7
8#include "absl/status/status.h"
9#include "absl/strings/str_cat.h"
10#include "absl/strings/str_format.h"
11#include "app/gui/core/icons.h"
12#include "imgui/imgui.h"
13#include "util/file_util.h"
14#include "util/macro.h"
15
16namespace yaze {
17
18static const char* KARLA_REGULAR = "Karla-Regular.ttf";
19static const char* ROBOTO_MEDIUM = "Roboto-Medium.ttf";
20static const char* COUSINE_REGULAR = "Cousine-Regular.ttf";
21static const char* DROID_SANS = "DroidSans.ttf";
22static const char* NOTO_SANS_JP = "NotoSansJP.ttf";
23static const char* IBM_PLEX_JP = "IBMPlexSansJP-Bold.ttf";
24
25static const float FONT_SIZE_DEFAULT = 16.0F;
26static const float FONT_SIZE_DROID_SANS = 18.0F;
27static const float ICON_FONT_SIZE = 18.0F;
28
29namespace {
30
31std::string ResolveRepoFontPath(const std::string& font_path) {
32 const std::vector<std::filesystem::path> candidates = {
33 std::filesystem::path("assets/font") / font_path,
34 std::filesystem::path("../assets/font") / font_path,
35 std::filesystem::path("../../assets/font") / font_path,
36 std::filesystem::path("../../../assets/font") / font_path,
37 };
38 for (const auto& candidate : candidates) {
39 if (std::filesystem::exists(candidate)) {
40 return candidate.string();
41 }
42 }
43 return (std::filesystem::path("assets/font") / font_path).string();
44}
45
46std::string SetFontPath(const std::string& font_path) {
47#ifdef __APPLE__
48#if TARGET_OS_IOS == 1
49 const std::string bundle_root = util::GetBundleResourcePath();
50 std::string bundle_path =
51 absl::StrCat(bundle_root, "assets/font/", font_path);
52 if (std::filesystem::exists(bundle_path)) {
53 return bundle_path;
54 }
55 bundle_path = absl::StrCat(bundle_root, font_path);
56 if (std::filesystem::exists(bundle_path)) {
57 return bundle_path;
58 }
59 return ResolveRepoFontPath(font_path);
60#else
61 std::string bundle_path = absl::StrCat(util::GetBundleResourcePath(),
62 "Contents/Resources/font/", font_path);
63 if (std::filesystem::exists(bundle_path)) {
64 return bundle_path;
65 }
66 return ResolveRepoFontPath(font_path);
67#endif
68#else
69 return ResolveRepoFontPath(font_path);
70#endif
71}
72
73absl::Status LoadFont(const FontConfig& font_config) {
74 ImGuiIO& imgui_io = ImGui::GetIO();
75 std::string actual_font_path = SetFontPath(font_config.font_path);
76 // Check if the file exists with std library first, since ImGui IO will assert
77 // if the file does not exist
78 if (!std::filesystem::exists(actual_font_path)) {
79 return absl::InternalError(
80 absl::StrFormat("Font file %s does not exist", actual_font_path));
81 }
82
83 if (!imgui_io.Fonts->AddFontFromFileTTF(actual_font_path.data(),
84 font_config.font_size)) {
85 return absl::InternalError(
86 absl::StrFormat("Failed to load font from %s", actual_font_path));
87 }
88 return absl::OkStatus();
89}
90
91absl::Status AddIconFont(const FontConfig& /*config*/) {
92 static const ImWchar icons_ranges[] = {ICON_MIN_MD, 0xf900, 0};
93 ImFontConfig icons_config{};
94 icons_config.MergeMode = true;
95 icons_config.GlyphOffset.y = 5.0F;
96 icons_config.GlyphMinAdvanceX = 13.0F;
97 icons_config.PixelSnapH = true;
98 std::string icon_font_path = SetFontPath(FONT_ICON_FILE_NAME_MD);
99 ImGuiIO& imgui_io = ImGui::GetIO();
100 if (!imgui_io.Fonts->AddFontFromFileTTF(icon_font_path.c_str(),
101 ICON_FONT_SIZE, &icons_config,
102 icons_ranges)) {
103 return absl::InternalError("Failed to add icon fonts");
104 }
105 return absl::OkStatus();
106}
107
108absl::Status AddJapaneseFont(const FontConfig& /*config*/) {
109 ImFontConfig japanese_font_config{};
110 japanese_font_config.MergeMode = true;
111 japanese_font_config.GlyphOffset.y = 5.0F;
112 japanese_font_config.GlyphMinAdvanceX = 13.0F;
113 japanese_font_config.PixelSnapH = true;
114 std::string japanese_font_path = SetFontPath(NOTO_SANS_JP);
115 ImGuiIO& imgui_io = ImGui::GetIO();
116 if (!imgui_io.Fonts->AddFontFromFileTTF(
117 japanese_font_path.data(), ICON_FONT_SIZE, &japanese_font_config,
118 imgui_io.Fonts->GetGlyphRangesJapanese())) {
119 return absl::InternalError("Failed to add Japanese fonts");
120 }
121 return absl::OkStatus();
122}
123
124} // namespace
125
126absl::Status LoadPackageFonts() {
127 if (font_registry.fonts.empty()) {
128 // Initialize the font names and sizes with proper ImFontConfig
129 // initialization
131 FontConfig{KARLA_REGULAR, FONT_SIZE_DEFAULT, {}, {}},
132 FontConfig{ROBOTO_MEDIUM, FONT_SIZE_DEFAULT, {}, {}},
133 FontConfig{COUSINE_REGULAR, FONT_SIZE_DEFAULT, {}, {}},
134 FontConfig{IBM_PLEX_JP, FONT_SIZE_DEFAULT, {}, {}},
135 FontConfig{DROID_SANS, FONT_SIZE_DROID_SANS, {}, {}},
136 };
137 }
138
139 // Load fonts with associated icon and Japanese merges
140 for (const auto& font_config : font_registry.fonts) {
141 RETURN_IF_ERROR(LoadFont(font_config));
142 RETURN_IF_ERROR(AddIconFont(font_config));
143 RETURN_IF_ERROR(AddJapaneseFont(font_config));
144 }
145 return absl::OkStatus();
146}
147
148absl::Status ReloadPackageFont(const FontConfig& config) {
149 ImGuiIO& imgui_io = ImGui::GetIO();
150 std::string actual_font_path = SetFontPath(config.font_path);
151 if (!imgui_io.Fonts->AddFontFromFileTTF(actual_font_path.data(),
152 config.font_size)) {
153 return absl::InternalError(
154 absl::StrFormat("Failed to load font from %s", actual_font_path));
155 }
156 RETURN_IF_ERROR(AddIconFont(config));
157 RETURN_IF_ERROR(AddJapaneseFont(config));
158 return absl::OkStatus();
159}
160
161absl::Status LoadFontFromMemory(const std::string& name,
162 const std::string& data, float size_pixels) {
163 ImGuiIO& imgui_io = ImGui::GetIO();
164
165 // ImGui takes ownership of the data and will free it
166 void* font_data = ImGui::MemAlloc(data.size());
167 if (!font_data) {
168 return absl::InternalError("Failed to allocate memory for font data");
169 }
170 std::memcpy(font_data, data.data(), data.size());
171
172 ImFontConfig config;
173 std::strncpy(config.Name, name.c_str(), sizeof(config.Name) - 1);
174 config.Name[sizeof(config.Name) - 1] = 0;
175
176 if (!imgui_io.Fonts->AddFontFromMemoryTTF(
177 font_data, static_cast<int>(data.size()), size_pixels, &config)) {
178 ImGui::MemFree(font_data);
179 return absl::InternalError("Failed to load font from memory");
180 }
181
182 // We also need to add icons and Japanese characters to this new font
183 // Note: This is a simplified version of AddIconFont/AddJapaneseFont that
184 // works with the current font being added (since we can't easily merge into
185 // a font that's just been added without rebuilding atlas immediately)
186 // For now, we'll just load the base font. Merging requires more complex logic.
187
188 // Important: We must rebuild the font atlas!
189 // This is usually done by the backend, but since we changed fonts at runtime...
190 // Ideally, this should be done before NewFrame().
191 // If called during a frame, changes won't appear until texture is rebuilt.
192
193 return absl::OkStatus();
194}
195
196#ifdef __linux__
197void LoadSystemFonts() {
198 // Load Linux System Fonts into ImGui
199 // System font loading is now handled by NFD (Native File Dialog)
200 // This function is kept for compatibility but does nothing
201}
202#endif
203
204} // namespace yaze
#define ICON_MIN_MD
Definition icons.h:10
#define FONT_ICON_FILE_NAME_MD
Definition icons.h:8
absl::Status AddJapaneseFont(const FontConfig &)
std::string ResolveRepoFontPath(const std::string &font_path)
std::string SetFontPath(const std::string &font_path)
absl::Status LoadFont(const FontConfig &font_config)
absl::Status AddIconFont(const FontConfig &)
std::string GetBundleResourcePath()
GetBundleResourcePath returns the path to the bundle resource directory. Specific to MacOS.
absl::Status ReloadPackageFont(const FontConfig &config)
absl::Status LoadPackageFonts()
void LoadSystemFonts()
absl::Status LoadFontFromMemory(const std::string &name, const std::string &data, float size_pixels)
FontState font_registry
Definition font_loader.h:23
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
const char * font_path
Definition font_loader.h:13
std::vector< FontConfig > fonts
Definition font_loader.h:20