|
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