Skip to content

Commit beb7dd9

Browse files
committed
[UI] Allow loading custom font & changed default font on Windows
- Unified font size to 12. This causes default UI to look a bit bigger - Set oversample to 2 to make font more readable (especially custom fonts)
1 parent f357f26 commit beb7dd9

File tree

2 files changed

+142
-32
lines changed

2 files changed

+142
-32
lines changed

src/xenia/ui/imgui_drawer.cc

Lines changed: 134 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@
2121
#include "xenia/ui/ui_event.h"
2222
#include "xenia/ui/window.h"
2323

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+
2433
namespace xe {
2534
namespace ui {
2635

@@ -98,38 +107,7 @@ void ImGuiDrawer::Initialize() {
98107
internal_state_ = ImGui::CreateContext();
99108
ImGui::SetCurrentContext(internal_state_);
100109

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

134112
auto& style = ImGui::GetStyle();
135113
style.ScrollbarRounding = 0;
@@ -218,6 +196,130 @@ std::optional<ImGuiKey> ImGuiDrawer::VirtualKeyToImGuiKey(VirtualKey vkey) {
218196
}
219197
}
220198

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+
221323
void ImGuiDrawer::SetupFontTexture() {
222324
if (font_texture_ || !immediate_drawer_) {
223325
return;

src/xenia/ui/imgui_drawer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <optional>
1717
#include <vector>
1818

19+
#include "third_party/imgui/imgui.h"
1920
#include "xenia/ui/immediate_drawer.h"
2021
#include "xenia/ui/presenter.h"
2122
#include "xenia/ui/window.h"
@@ -66,6 +67,13 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {
6667

6768
private:
6869
void Initialize();
70+
void InitializeFonts();
71+
bool LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config, const float font_size);
72+
bool LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config,
73+
const float font_size);
74+
bool LoadJapaneseFont(ImGuiIO& io, const float font_size);
75+
76+
const std::filesystem::path GetWindowsFont(std::string font_name);
6977

7078
void SetupFontTexture();
7179

0 commit comments

Comments
 (0)