Skip to content

Commit

Permalink
[UI] Allow loading custom font & changed default font on Windows
Browse files Browse the repository at this point in the history
- 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)
  • Loading branch information
Gliniak committed Mar 22, 2023
1 parent f357f26 commit beb7dd9
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 32 deletions.
166 changes: 134 additions & 32 deletions src/xenia/ui/imgui_drawer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@
#include "xenia/ui/ui_event.h"
#include "xenia/ui/window.h"

#if XE_PLATFORM_WIN32
#include <ShlObj_core.h>
#endif

DEFINE_path(
custom_font_path, "",
"Allows user to load custom font and use it instead of default one.", "UI");
DEFINE_uint32(font_size, 12, "Allows user to set custom font size.", "UI");

namespace xe {
namespace ui {

Expand Down Expand Up @@ -98,38 +107,7 @@ void ImGuiDrawer::Initialize() {
internal_state_ = ImGui::CreateContext();
ImGui::SetCurrentContext(internal_state_);

auto& io = ImGui::GetIO();

// TODO(gibbed): disable imgui.ini saving for now,
// imgui assumes paths are char* so we can't throw a good path at it on
// Windows.
io.IniFilename = nullptr;

// Setup the font glyphs.
ImFontConfig font_config;
font_config.OversampleH = font_config.OversampleV = 1;
font_config.PixelSnapH = true;
static const ImWchar font_glyph_ranges[] = {
0x0020,
0x00FF, // Basic Latin + Latin Supplement
0,
};
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
kProggyTinyCompressedDataBase85, 10.0f, &font_config, font_glyph_ranges);
// TODO(benvanik): jp font on other platforms?
// https://github.com/Koruri/kibitaki looks really good, but is 1.5MiB.
const char* jp_font_path = "C:\\Windows\\Fonts\\msgothic.ttc";
if (std::filesystem::exists(jp_font_path)) {
ImFontConfig jp_font_config;
jp_font_config.MergeMode = true;
jp_font_config.OversampleH = jp_font_config.OversampleV = 1;
jp_font_config.PixelSnapH = true;
jp_font_config.FontNo = 0;
io.Fonts->AddFontFromFileTTF(jp_font_path, 12.0f, &jp_font_config,
io.Fonts->GetGlyphRangesJapanese());
} else {
XELOGW("Unable to load Japanese font; JP characters will be boxes");
}
InitializeFonts();

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

static const ImWchar font_glyph_ranges[] = {
0x0020, 0x00FF, // Basic Latin + Latin Supplement
0x0370, 0x03FF, // Greek
0x0400, 0x044F, // Cyrillic
0x2000, 0x206F, // General Punctuation
0,
};

const std::filesystem::path ImGuiDrawer::GetWindowsFont(std::string font_name) {
std::filesystem::path font_path = "";

#if XE_PLATFORM_WIN32
PWSTR fonts_dir;
HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir);
if (FAILED(result)) {
CoTaskMemFree(static_cast<void*>(fonts_dir));
return "";
}

font_path = std::wstring(fonts_dir);
CoTaskMemFree(static_cast<void*>(fonts_dir));
#endif
font_path.append(font_name);
if (!std::filesystem::exists(font_path)) {
return "";
}

return font_path;
}

bool ImGuiDrawer::LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config,
const float font_size) {
if (cvars::custom_font_path.empty()) {
return false;
}

if (!std::filesystem::exists(cvars::custom_font_path)) {
return false;
}

const std::string font_path = xe::path_to_utf8(cvars::custom_font_path);
ImFont* font = io.Fonts->AddFontFromFileTTF(font_path.c_str(), font_size,
&font_config, font_glyph_ranges);

io.Fonts->Build();

if (!font->IsLoaded()) {
XELOGE("Failed to load custom font: {}", font_path);
io.Fonts->Clear();
return false;
}
return true;
}

bool ImGuiDrawer::LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config,
const float font_size) {
const std::filesystem::path font_path = GetWindowsFont("tahoma.ttf");
if (!std::filesystem::exists(font_path)) {
XELOGW(
"Unable to find tahoma font in Windows fonts directory. Switching to "
"embedded Xenia font");
return false;
}

ImFont* font =
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(),
font_size, &font_config, font_glyph_ranges);

io.Fonts->Build();
// Something went wrong while loading custom font. Probably corrupted.
if (!font->IsLoaded()) {
XELOGE("Failed to load custom font: {}", xe::path_to_utf8(font_path));
io.Fonts->Clear();
}
return true;
}

bool ImGuiDrawer::LoadJapaneseFont(ImGuiIO& io, const float font_size) {
// TODO(benvanik): jp font on other platforms?
const std::filesystem::path font_path = GetWindowsFont("msgothic.ttc");

if (!std::filesystem::exists(font_path)) {
XELOGW("Unable to load Japanese font; JP characters will be boxes");
return false;
}

ImFontConfig jp_font_config;
jp_font_config.MergeMode = true;
jp_font_config.OversampleH = jp_font_config.OversampleV = 2;
jp_font_config.PixelSnapH = true;
jp_font_config.FontNo = 0;
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(), font_size,
&jp_font_config,
io.Fonts->GetGlyphRangesJapanese());
return true;
};

void ImGuiDrawer::InitializeFonts() {
auto& io = ImGui::GetIO();

const float font_size = std::max((float)cvars::font_size, 8.f);
// TODO(gibbed): disable imgui.ini saving for now,
// imgui assumes paths are char* so we can't throw a good path at it on
// Windows.
io.IniFilename = nullptr;

ImFontConfig font_config;
font_config.OversampleH = font_config.OversampleV = 2;
font_config.PixelSnapH = true;

bool is_font_loaded = LoadCustomFont(io, font_config, font_size);
if (!is_font_loaded) {
is_font_loaded = LoadWindowsFont(io, font_config, font_size);
}

if (io.Fonts->Fonts.empty()) {
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
kProggyTinyCompressedDataBase85, font_size, &font_config,
io.Fonts->GetGlyphRangesDefault());
}

LoadJapaneseFont(io, font_size);
}

void ImGuiDrawer::SetupFontTexture() {
if (font_texture_ || !immediate_drawer_) {
return;
Expand Down
8 changes: 8 additions & 0 deletions src/xenia/ui/imgui_drawer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <optional>
#include <vector>

#include "third_party/imgui/imgui.h"
#include "xenia/ui/immediate_drawer.h"
#include "xenia/ui/presenter.h"
#include "xenia/ui/window.h"
Expand Down Expand Up @@ -66,6 +67,13 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {

private:
void Initialize();
void InitializeFonts();
bool LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config, const float font_size);
bool LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config,
const float font_size);
bool LoadJapaneseFont(ImGuiIO& io, const float font_size);

const std::filesystem::path GetWindowsFont(std::string font_name);

void SetupFontTexture();

Expand Down

0 comments on commit beb7dd9

Please sign in to comment.