Skip to content

Commit 6c0d1f9

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 c5e6352 commit 6c0d1f9

File tree

6 files changed

+145
-32
lines changed

6 files changed

+145
-32
lines changed

src/xenia/base/system.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ enum class SimpleMessageBoxType {
3636
// This is expected to block the caller until the message box is closed.
3737
void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message);
3838

39+
const std::filesystem::path GetFontPath(const std::string font_name);
3940
} // namespace xe
4041

4142
#endif // XENIA_BASE_SYSTEM_H_

src/xenia/base/system_android.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,8 @@ void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) {
294294
// Java VM for the calling thread is needed.
295295
}
296296

297+
const std::filesystem::path GetFontPath(const std::string font_name) {
298+
return "";
299+
}
300+
297301
} // namespace xe

src/xenia/base/system_gnulinux.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,8 @@ void ShowSimpleMessageBox(SimpleMessageBoxType type, std::string_view message) {
6767
}
6868
}
6969

70+
const std::filesystem::path GetFontPath(const std::string font_name) {
71+
return "";
72+
}
73+
7074
} // namespace xe

src/xenia/base/system_win.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
******************************************************************************
88
*/
99

10+
#include <ShlObj_core.h>
11+
1012
#include "xenia/base/platform_win.h"
1113
#include "xenia/base/string.h"
1214
#include "xenia/base/system.h"
@@ -48,4 +50,25 @@ void ShowSimpleMessageBox(SimpleMessageBoxType type,
4850
type_flags);
4951
}
5052

53+
const std::filesystem::path GetFontPath(const std::string font_name) {
54+
std::filesystem::path font_path = "";
55+
56+
PWSTR fonts_dir;
57+
HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir);
58+
if (FAILED(result)) {
59+
CoTaskMemFree(static_cast<void*>(fonts_dir));
60+
return "";
61+
}
62+
font_path = std::wstring(fonts_dir);
63+
font_path.append(font_name);
64+
65+
CoTaskMemFree(static_cast<void*>(fonts_dir));
66+
67+
if (!std::filesystem::exists(font_path)) {
68+
return "";
69+
}
70+
71+
return font_path;
72+
}
73+
5174
} // namespace xe

src/xenia/ui/imgui_drawer.cc

Lines changed: 106 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <cstring>
1414

1515
#include "third_party/imgui/imgui.h"
16+
#include "xenia/base/system.h"
1617
#include "xenia/base/assert.h"
1718
#include "xenia/base/clock.h"
1819
#include "xenia/base/logging.h"
@@ -21,6 +22,11 @@
2122
#include "xenia/ui/ui_event.h"
2223
#include "xenia/ui/window.h"
2324

25+
DEFINE_path(
26+
custom_font_path, "",
27+
"Allows user to load custom font and use it instead of default one.", "UI");
28+
DEFINE_uint32(font_size, 12, "Allows user to set custom font size.", "UI");
29+
2430
namespace xe {
2531
namespace ui {
2632

@@ -98,38 +104,7 @@ void ImGuiDrawer::Initialize() {
98104
internal_state_ = ImGui::CreateContext();
99105
ImGui::SetCurrentContext(internal_state_);
100106

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-
}
107+
InitializeFonts();
133108

134109
auto& style = ImGui::GetStyle();
135110
style.ScrollbarRounding = 0;
@@ -218,6 +193,105 @@ std::optional<ImGuiKey> ImGuiDrawer::VirtualKeyToImGuiKey(VirtualKey vkey) {
218193
}
219194
}
220195

196+
static const ImWchar font_glyph_ranges[] = {
197+
0x0020, 0x00FF, // Basic Latin + Latin Supplement
198+
0x0370, 0x03FF, // Greek
199+
0x0400, 0x044F, // Cyrillic
200+
0x2000, 0x206F, // General Punctuation
201+
0,
202+
};
203+
204+
void ImGuiDrawer::LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config,
205+
const float font_size) {
206+
if (cvars::custom_font_path.empty()) {
207+
return;
208+
}
209+
210+
if (!std::filesystem::exists(cvars::custom_font_path)) {
211+
return;
212+
}
213+
214+
const std::string font_path = xe::path_to_utf8(cvars::custom_font_path);
215+
ImFont* font = io.Fonts->AddFontFromFileTTF(font_path.c_str(), font_size,
216+
&font_config, font_glyph_ranges);
217+
218+
io.Fonts->Build();
219+
220+
if (!font->IsLoaded()) {
221+
XELOGE("Failed to load custom font: {}", font_path);
222+
io.Fonts->Clear();
223+
}
224+
}
225+
226+
void ImGuiDrawer::LoadSystemFont(ImGuiIO& io, ImFontConfig& font_config,
227+
const float font_size) {
228+
const std::filesystem::path font_path = xe::GetFontPath("tahoma.ttf");
229+
if (!std::filesystem::exists(font_path)) {
230+
XELOGW(
231+
"Unable to find Tahoma font in OS fonts directory. Switching to "
232+
"embedded Xenia font");
233+
return;
234+
}
235+
236+
ImFont* font =
237+
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(),
238+
font_size, &font_config, font_glyph_ranges);
239+
240+
io.Fonts->Build();
241+
// Something went wrong while loading custom font. Probably corrupted.
242+
if (!font->IsLoaded()) {
243+
XELOGE("Failed to load custom font: {}", xe::path_to_utf8(font_path));
244+
io.Fonts->Clear();
245+
}
246+
}
247+
248+
void ImGuiDrawer::LoadJapaneseFont(ImGuiIO& io, const float font_size) {
249+
// TODO(benvanik): jp font on other platforms?
250+
const std::filesystem::path font_path = xe::GetFontPath("msgothic.ttc");
251+
252+
if (!std::filesystem::exists(font_path)) {
253+
XELOGW("Unable to load Japanese font; JP characters will be boxes");
254+
return;
255+
}
256+
257+
ImFontConfig jp_font_config;
258+
jp_font_config.MergeMode = true;
259+
jp_font_config.OversampleH = jp_font_config.OversampleV = 2;
260+
jp_font_config.PixelSnapH = true;
261+
jp_font_config.FontNo = 0;
262+
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(), font_size,
263+
&jp_font_config,
264+
io.Fonts->GetGlyphRangesJapanese());
265+
};
266+
267+
void ImGuiDrawer::InitializeFonts() {
268+
auto& io = ImGui::GetIO();
269+
270+
const float font_size = std::max((float)cvars::font_size, 8.f);
271+
// TODO(gibbed): disable imgui.ini saving for now,
272+
// imgui assumes paths are char* so we can't throw a good path at it on
273+
// Windows.
274+
io.IniFilename = nullptr;
275+
276+
ImFontConfig font_config;
277+
font_config.OversampleH = font_config.OversampleV = 2;
278+
font_config.PixelSnapH = true;
279+
280+
LoadCustomFont(io, font_config, font_size);
281+
// Failed to load custom font. Trying to load one of OS fonts.
282+
if (io.Fonts->Fonts.empty()) {
283+
LoadSystemFont(io, font_config, font_size);
284+
}
285+
// Failed to load OS font. Loading Xenia embedded font.
286+
if (io.Fonts->Fonts.empty()) {
287+
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
288+
kProggyTinyCompressedDataBase85, font_size, &font_config,
289+
io.Fonts->GetGlyphRangesDefault());
290+
}
291+
292+
LoadJapaneseFont(io, font_size);
293+
}
294+
221295
void ImGuiDrawer::SetupFontTexture() {
222296
if (font_texture_ || !immediate_drawer_) {
223297
return;

src/xenia/ui/imgui_drawer.h

Lines changed: 7 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,12 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {
6667

6768
private:
6869
void Initialize();
70+
void InitializeFonts();
71+
void LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config,
72+
const float font_size);
73+
void LoadSystemFont(ImGuiIO& io, ImFontConfig& font_config,
74+
const float font_size);
75+
void LoadJapaneseFont(ImGuiIO& io, const float font_size);
6976

7077
void SetupFontTexture();
7178

0 commit comments

Comments
 (0)