|
21 | 21 | #include "xenia/ui/ui_event.h"
|
22 | 22 | #include "xenia/ui/window.h"
|
23 | 23 |
|
| 24 | +#if XE_PLATFORM_WIN32 |
| 25 | +#include <ShlObj_core.h> |
| 26 | +#endif |
| 27 | + |
| 28 | +DEFINE_path( |
| 29 | + custom_font_path, "", |
| 30 | + "Allows user to load custom font and use it instead of default one.", "UI"); |
| 31 | +DEFINE_uint32(font_size, 12, "Allows user to set custom font size.", "UI"); |
| 32 | + |
24 | 33 | namespace xe {
|
25 | 34 | namespace ui {
|
26 | 35 |
|
@@ -98,38 +107,7 @@ void ImGuiDrawer::Initialize() {
|
98 | 107 | internal_state_ = ImGui::CreateContext();
|
99 | 108 | ImGui::SetCurrentContext(internal_state_);
|
100 | 109 |
|
101 |
| - auto& io = ImGui::GetIO(); |
102 |
| - |
103 |
| - // TODO(gibbed): disable imgui.ini saving for now, |
104 |
| - // imgui assumes paths are char* so we can't throw a good path at it on |
105 |
| - // Windows. |
106 |
| - io.IniFilename = nullptr; |
107 |
| - |
108 |
| - // Setup the font glyphs. |
109 |
| - ImFontConfig font_config; |
110 |
| - font_config.OversampleH = font_config.OversampleV = 1; |
111 |
| - font_config.PixelSnapH = true; |
112 |
| - static const ImWchar font_glyph_ranges[] = { |
113 |
| - 0x0020, |
114 |
| - 0x00FF, // Basic Latin + Latin Supplement |
115 |
| - 0, |
116 |
| - }; |
117 |
| - io.Fonts->AddFontFromMemoryCompressedBase85TTF( |
118 |
| - kProggyTinyCompressedDataBase85, 10.0f, &font_config, font_glyph_ranges); |
119 |
| - // TODO(benvanik): jp font on other platforms? |
120 |
| - // https://github.com/Koruri/kibitaki looks really good, but is 1.5MiB. |
121 |
| - const char* jp_font_path = "C:\\Windows\\Fonts\\msgothic.ttc"; |
122 |
| - if (std::filesystem::exists(jp_font_path)) { |
123 |
| - ImFontConfig jp_font_config; |
124 |
| - jp_font_config.MergeMode = true; |
125 |
| - jp_font_config.OversampleH = jp_font_config.OversampleV = 1; |
126 |
| - jp_font_config.PixelSnapH = true; |
127 |
| - jp_font_config.FontNo = 0; |
128 |
| - io.Fonts->AddFontFromFileTTF(jp_font_path, 12.0f, &jp_font_config, |
129 |
| - io.Fonts->GetGlyphRangesJapanese()); |
130 |
| - } else { |
131 |
| - XELOGW("Unable to load Japanese font; JP characters will be boxes"); |
132 |
| - } |
| 110 | + InitializeFonts(); |
133 | 111 |
|
134 | 112 | auto& style = ImGui::GetStyle();
|
135 | 113 | style.ScrollbarRounding = 0;
|
@@ -218,6 +196,130 @@ std::optional<ImGuiKey> ImGuiDrawer::VirtualKeyToImGuiKey(VirtualKey vkey) {
|
218 | 196 | }
|
219 | 197 | }
|
220 | 198 |
|
| 199 | +static const ImWchar font_glyph_ranges[] = { |
| 200 | + 0x0020, 0x00FF, // Basic Latin + Latin Supplement |
| 201 | + 0x0370, 0x03FF, // Greek |
| 202 | + 0x0400, 0x044F, // Cyrillic |
| 203 | + 0x2000, 0x206F, // General Punctuation |
| 204 | + 0, |
| 205 | +}; |
| 206 | + |
| 207 | +const std::filesystem::path ImGuiDrawer::GetWindowsFont(std::string font_name) { |
| 208 | + std::filesystem::path font_path = ""; |
| 209 | + |
| 210 | +#if XE_PLATFORM_WIN32 |
| 211 | + PWSTR fonts_dir; |
| 212 | + HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir); |
| 213 | + if (FAILED(result)) { |
| 214 | + CoTaskMemFree(static_cast<void*>(fonts_dir)); |
| 215 | + return ""; |
| 216 | + } |
| 217 | + |
| 218 | + font_path = std::wstring(fonts_dir); |
| 219 | + CoTaskMemFree(static_cast<void*>(fonts_dir)); |
| 220 | +#endif |
| 221 | + font_path.append(font_name); |
| 222 | + if (!std::filesystem::exists(font_path)) { |
| 223 | + return ""; |
| 224 | + } |
| 225 | + |
| 226 | + return font_path; |
| 227 | +} |
| 228 | + |
| 229 | +bool ImGuiDrawer::LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config, |
| 230 | + const float font_size) { |
| 231 | + if (cvars::custom_font_path.empty()) { |
| 232 | + return false; |
| 233 | + } |
| 234 | + |
| 235 | + if (!std::filesystem::exists(cvars::custom_font_path)) { |
| 236 | + return false; |
| 237 | + } |
| 238 | + |
| 239 | + const std::string font_path = xe::path_to_utf8(cvars::custom_font_path); |
| 240 | + ImFont* font = io.Fonts->AddFontFromFileTTF(font_path.c_str(), font_size, |
| 241 | + &font_config, font_glyph_ranges); |
| 242 | + |
| 243 | + io.Fonts->Build(); |
| 244 | + |
| 245 | + if (!font->IsLoaded()) { |
| 246 | + XELOGE("Failed to load custom font: {}", font_path); |
| 247 | + io.Fonts->Clear(); |
| 248 | + return false; |
| 249 | + } |
| 250 | + return true; |
| 251 | +} |
| 252 | + |
| 253 | +bool ImGuiDrawer::LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config, |
| 254 | + const float font_size) { |
| 255 | + const std::filesystem::path font_path = GetWindowsFont("tahoma.ttf"); |
| 256 | + if (!std::filesystem::exists(font_path)) { |
| 257 | + XELOGW( |
| 258 | + "Unable to find tahoma font in Windows fonts directory. Switching to " |
| 259 | + "embedded Xenia font"); |
| 260 | + return false; |
| 261 | + } |
| 262 | + |
| 263 | + ImFont* font = |
| 264 | + io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(), |
| 265 | + font_size, &font_config, font_glyph_ranges); |
| 266 | + |
| 267 | + io.Fonts->Build(); |
| 268 | + // Something went wrong while loading custom font. Probably corrupted. |
| 269 | + if (!font->IsLoaded()) { |
| 270 | + XELOGE("Failed to load custom font: {}", xe::path_to_utf8(font_path)); |
| 271 | + io.Fonts->Clear(); |
| 272 | + } |
| 273 | + return true; |
| 274 | +} |
| 275 | + |
| 276 | +bool ImGuiDrawer::LoadJapaneseFont(ImGuiIO& io, const float font_size) { |
| 277 | + // TODO(benvanik): jp font on other platforms? |
| 278 | + const std::filesystem::path font_path = GetWindowsFont("msgothic.ttc"); |
| 279 | + |
| 280 | + if (!std::filesystem::exists(font_path)) { |
| 281 | + XELOGW("Unable to load Japanese font; JP characters will be boxes"); |
| 282 | + return false; |
| 283 | + } |
| 284 | + |
| 285 | + ImFontConfig jp_font_config; |
| 286 | + jp_font_config.MergeMode = true; |
| 287 | + jp_font_config.OversampleH = jp_font_config.OversampleV = 2; |
| 288 | + jp_font_config.PixelSnapH = true; |
| 289 | + jp_font_config.FontNo = 0; |
| 290 | + io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(), font_size, |
| 291 | + &jp_font_config, |
| 292 | + io.Fonts->GetGlyphRangesJapanese()); |
| 293 | + return true; |
| 294 | +}; |
| 295 | + |
| 296 | +void ImGuiDrawer::InitializeFonts() { |
| 297 | + auto& io = ImGui::GetIO(); |
| 298 | + |
| 299 | + const float font_size = std::max((float)cvars::font_size, 8.f); |
| 300 | + // TODO(gibbed): disable imgui.ini saving for now, |
| 301 | + // imgui assumes paths are char* so we can't throw a good path at it on |
| 302 | + // Windows. |
| 303 | + io.IniFilename = nullptr; |
| 304 | + |
| 305 | + ImFontConfig font_config; |
| 306 | + font_config.OversampleH = font_config.OversampleV = 2; |
| 307 | + font_config.PixelSnapH = true; |
| 308 | + |
| 309 | + bool is_font_loaded = LoadCustomFont(io, font_config, font_size); |
| 310 | + if (!is_font_loaded) { |
| 311 | + is_font_loaded = LoadWindowsFont(io, font_config, font_size); |
| 312 | + } |
| 313 | + |
| 314 | + if (io.Fonts->Fonts.empty()) { |
| 315 | + io.Fonts->AddFontFromMemoryCompressedBase85TTF( |
| 316 | + kProggyTinyCompressedDataBase85, font_size, &font_config, |
| 317 | + io.Fonts->GetGlyphRangesDefault()); |
| 318 | + } |
| 319 | + |
| 320 | + LoadJapaneseFont(io, font_size); |
| 321 | +} |
| 322 | + |
221 | 323 | void ImGuiDrawer::SetupFontTexture() {
|
222 | 324 | if (font_texture_ || !immediate_drawer_) {
|
223 | 325 | return;
|
|
0 commit comments