-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Help Wanted] Font Loading #33
Comments
It also might take a bit before I get to it because I'm pretty busy at the moment and working on this by myself lol. What you could try is during the first render call, load the font but with a config and enable Also keep this in mind: https://github.com/ocornut/imgui/blob/master/docs/FONTS.md#3-missing-glyph-ranges |
Yeah, no problem. Whatever time you need and remember to take breaks too!
This doesn't work either. Same result, all ImGui windows disappear. private ImFontPtr Font { get; set; }
private bool IsFontInitialized { get; set; } = false;
private unsafe CustomizationWindow InitFont()
{
IsFontInitialized = true;
var fonts = ImGui.GetIO().Fonts;
var fontConfig = new ImFontConfig();
fontConfig.MergeMode = 1;
var fontConfigPtr = new ImFontConfigPtr(&fontConfig);
// fonts.AddFontDefault(fontConfigPtr); // Uncommenting makes no difference
Font = fonts.AddFontFromFileTTF(Path.Combine(Constants.PLUGIN_DATA_PATH, "NotoSansKR-Bold.otf"), 26f, fontConfigPtr, fonts.GetGlyphRangesKorean());
fonts.Build();
// ImGui.SetCurrentFont(Font); // Uncommenting makes no difference
var loaded = Font.IsLoaded(); // True
Log.Info(loaded.ToString());
}
public void OnImGuiFreeRender()
{
if(!IsFontInitialized) InitFont();
ImGui.PushFont(Font);
...
ImGui.PopFont();
} |
I tried doing it inside SPL directly, in With the code below, in both cases, the windows don't disappear, thou default font is not actually updated, korean symbols don't work. Calling public static unsafe void InitFont()
{
IsFontInitialized = true;
var io = ImGui.GetIO();
var fonts = io.Fonts;
ImFontConfig* config = ImGuiNative.ImFontConfig_ImFontConfig();
config->MergeMode = 1;
Font = fonts.AddFontFromFileTTF(Path.Combine(Constants.PLUGIN_DATA_PATH, "NotoSansKR-Bold.otf"), 26f, config, fonts.GetGlyphRangesKorean());
// fonts.Build();
} There was a person on ImGui.NET discord who appears to have the same issue. So it's most likely ImGui.NET bug. Mine: |
Have you tried loading the font inside |
I haven't, I will take a look, thanks! |
Loading the font inside void D3DModule::imgui_load_fonts() {
const auto& io = *igGetIO();
ImFontAtlas_Clear(io.Fonts);
const auto& chunk_module = NativePluginFramework::get_module<ChunkModule>();
const auto& default_chunk = chunk_module->request_chunk("Default");
const auto& roboto = default_chunk->get_file("/Resources/Roboto-Medium.ttf");
const auto& noto_sans_jp = default_chunk->get_file("/Resources/NotoSansJP-Regular.ttf");
const auto& fa6 = default_chunk->get_file("/Resources/fa-solid-900.ttf");
ImFontConfig* font_cfg = ImFontConfig_ImFontConfig();
font_cfg->FontDataOwnedByAtlas = false;
font_cfg->MergeMode = false;
ImFontAtlas_AddFontFromMemoryTTF(io.Fonts, roboto->Contents.data(), (i32)roboto->size(), 16.0f, font_cfg, nullptr);
font_cfg->MergeMode = true;
ImFontAtlas_AddFontFromMemoryTTF(io.Fonts, noto_sans_jp->Contents.data(), (i32)noto_sans_jp->size(), 18.0f, font_cfg, s_japanese_glyph_ranges);
ImFontAtlas_AddFontFromMemoryTTF(io.Fonts, fa6->Contents.data(), (i32)fa6->size(), 16.0f, font_cfg, icons_ranges);
ImFontAtlas_AddFontFromFileTTF(io.Fonts, "D:/Programs/Steam/steamapps/common/Monster Hunter World/nativePC/plugins/CSharp/BetterMatchmaking/data/NotoSansKR-Bold.otf", 26.0f, font_cfg, ImFontAtlas_GetGlyphRangesKorean(io.Fonts));
ImFontAtlas_Build(io.Fonts);
ImFontConfig_destroy(font_cfg);
} |
Actually, this issue seems to be related: ocornut/imgui#2311. Have to recreate font atlas texture (call |
Okey, so. I don't know how to link ImGui to a Native Component, so I tried to modify existing SPL code. I assume I need to rebuild the texture and In private static ImFontPtr Font { get; set; }
private static bool IsFontInitialized { get; set; } = false;
private static unsafe void InitFont()
{
IsFontInitialized = true;
var io = ImGui.GetIO();
var fonts = io.Fonts;
ImFontConfig* config = ImGuiNative.ImFontConfig_ImFontConfig();
config->MergeMode = 0;
config->FontDataOwnedByAtlas = 0;
// Maybe I will need this, idk
// fonts.Clear();
fonts.AddFontDefault();
config->MergeMode = 1;
Font = fonts.AddFontFromFileTTF(@"D:\Programs\Steam\steamapps\common\Monster Hunter World\nativePC\plugins\CSharp\BetterMatchmaking\data\NotoSansKR-Bold.otf", 26f, config, fonts.GetGlyphRangesKorean());
// Only doing DX12 for now for simplicity
ImGuiExtensions.RecreateFontTextureDX12();
}
[UnmanagedCallersOnly]
internal static unsafe nint ImGuiRender()
{
if(Input.IsPressed(_menuKey))
_showMenu = !_showMenu;
if(Input.IsPressed(_demoKey))
_showDemo = !_showDemo;
if(!IsFontInitialized) InitFont();
...
ImGui.NewFrame();
...
} In public static void RecreateFontTextureDX12() => InternalCalls.RecreateFontTextureDX12(); In private:
static void recreate_font_texture_dx12(); In #include "imgui_impl_dx12.h"
void ImGuiModule::initialize(CoreClr* coreclr) {
coreclr->add_internal_call("RecreateFontTextureDX12", &ImGuiModule::recreate_font_texture_dx12);
...
}
void ImGuiModule::recreate_font_texture_dx12() {
// Line that produces the error:
ImGui_ImplDX12_CreateFontsTexture();
} This gives me this error:
Sorry, I am not very familiar with C++. I am extra allergic to declaration/implementation split and dependency hells. xd |
|
Realistically however you should not be calling that yourself. You should call |
Alternatively, this PR seems to be a more generic solution to this problem. I could potentially merge this into my fork of imgui. |
If merging the PR is feasible, go for it. All I want is to allow translators to define their own font in the localization file. Ideally, I want to load fonts on request at runtime, my plugins already support auto-updating localizations at runtime. But I will be fine if it was just at initialization on startup. Right now I am crashing and I am not even sure where. In private static ImFontPtr Font { get; set; }
private static bool IsFontInitialized { get; set; } = false;
private static unsafe void InitFont()
{
IsFontInitialized = true;
var io = ImGui.GetIO();
var fonts = io.Fonts;
ImFontConfig* config = ImGuiNative.ImFontConfig_ImFontConfig();
config->MergeMode = 0;
config->FontDataOwnedByAtlas = 0;
// Maybe I will need this, idk
// fonts.Clear();
fonts.AddFontDefault();
config->MergeMode = 1;
Font = fonts.AddFontFromFileTTF(@"D:\Programs\Steam\steamapps\common\Monster Hunter World\nativePC\plugins\CSharp\BetterMatchmaking\data\NotoSansKR-Bold.otf", 26f, config, fonts.GetGlyphRangesKorean());
fonts.Build();
// Only doing DX12 for now for simplicity
Log.Info("Pre-InvalidateDeviceObjectsDX12");
ImGuiExtensions.InvalidateDeviceObjectsDX12();
Log.Info("Post-InvalidateDeviceObjectsDX12");
}
[UnmanagedCallersOnly]
internal static unsafe nint ImGuiRender()
{
if(Input.IsPressed(_menuKey))
_showMenu = !_showMenu;
if(Input.IsPressed(_demoKey))
_showDemo = !_showDemo;
if(!IsFontInitialized) InitFont();
...
Log.Info("Pre-NewFrame");
ImGui.NewFrame();
Log.Info("Post-NewFrame");
...
Log.Info("Pre-EndFrame");
ImGui.EndFrame();
Log.Info("Post-EndFrame");
...
Log.Info("Pre-Render");
ImGui.Render();
Log.Info("Post-Render");
...
} In public static void InvalidateDeviceObjectsDX12() => InternalCalls.InvalidateDeviceObjectsDX12(); In public static delegate* unmanaged<void> InvalidateDeviceObjectsDX12Ptr;
public static void InvalidateDeviceObjectsDX12() => InvalidateDeviceObjectsDX12Ptr(); In #include "imgui_impl_dx12.h"
#include "Log.h"
void ImGuiModule::initialize(CoreClr* coreclr) {
coreclr->add_internal_call("InvalidateDeviceObjectsDX12", &ImGuiModule::invalidate_device_objects_dx12);
...
}
void ImGuiModule::invalidate_device_objects_dx12() {
dlog::info("ImGui_ImplDX12_InvalidateDeviceObjects");
ImGui_ImplDX12_InvalidateDeviceObjects();
} |
Ok I got it working by calling WICKED. Merging the PR or using this is up to you. All modified files: |
I ended up choosing a different approach entirely, which is implemented in cfb9e11. The new system lets you submit your own fonts inside public static unsafe void RegisterFont(string name, string path, float size, nint glyphRanges = 0,
bool merge = false, int oversampleV = 0, int oversampleH = 0) Example: // Inside OnLoad
Renderer.RegisterFont("My Font", @"C:\Windows\Fonts\times.ttf", 16f);
// Inside OnImGuiRender
ImGui.PushFont(Renderer.GetFont("My Font"));
ImGui.Text("Sample Text");
ImGui.PopFont(); Using a more unique name than "My Font" is recommended because it is using a dictionary behind the scenes, so try to avoid name collisions with other plugins. For specific glyph ranges do not use the |
Whoops, let me fix that Edit: f8f4132 |
I am having trouble merging fonts. public void OnLoad()
{
GlyphRange[] emojiRange = [(0x2122, 0x2B55), (0x0, 0x0)];
var emojiGlyphRangeAddress = GlyphRangeFactory.CreateGlyphRanges(emojiRange);
Renderer.RegisterFont("Default@@BetterMatchmaking", $"{Constants.PLUGIN_FONTS_PATH}NotoSans-Bold.ttf", 17f, 0, false, 2, 2);
Renderer.RegisterFont("Default@@BetterMatchmaking", $"{Constants.PLUGIN_FONTS_PATH}NotoEmoji-Bold.ttf", 17f, emojiGlyphRangeAddress, true, 2, 2);
GlyphRangeFactory.DestroyGlyphRanges(emojiGlyphRangeAddress);
} Individually, both fonts work correctly? (Idk what the hell are those circles thou, I don't even load ASCII range?). Just public void OnLoad()
{
Renderer.RegisterFont("Default@@BetterMatchmaking", $"{Constants.PLUGIN_FONTS_PATH}NotoSans-Bold.ttf", 17f, 0, false, 2, 2);
} Just public void OnLoad()
{
GlyphRange[] emojiRange = [(0x2122, 0x2B55), (0x0, 0x0)];
var emojiGlyphRangeAddress = GlyphRangeFactory.CreateGlyphRanges(emojiRange);
Renderer.RegisterFont("Default@@BetterMatchmaking", $"{Constants.PLUGIN_FONTS_PATH}NotoEmoji-Bold.ttf", 17f, emojiGlyphRangeAddress, false, 2, 2);
GlyphRangeFactory.DestroyGlyphRanges(emojiGlyphRangeAddress);
} |
Not sure if this is what's causing it and it might not be communicated properly, but you shouldn't free the glyph ranges until after the font was loaded (i.e. the first time In fact, I'm not sure if you should destroy them at all. If anything, do it inside Another thing, you don't need to manually add the (0, 0) entries for your glyph ranges, those are added automatically. |
Oopsies, you are right. I somehow thought that font is built on each RegisterFont, which is extremely silly of me. Probably, I got confused because I saw the method description saying to destroy the ranges, as well as saying to provide null terminator. |
I read it as if a null terminator should belong to the provided ranges. |
I will close this issue if there are no more problems. |
Ok, sorry for bumping. Encountered an issue. Didn't test properly in the beginning. The font initialization is called again when going back to main menu from a session, and if any plugin loads a font, it crashes. To reproduce:
|
This should now be fixed as of 734e9f8, haven't gotten around to fixing this until now. |
Describe The Problem
So for correct localization support in my plugins, I need to load arbitrary fonts. Working with fonts in ImGui is pain by itself, so no wonder I am having issues.
ImGui recommends to load fonts during initialization. I tried doing so in
IPlugin.OnLoad()
but that throws an exception on game launch.Ok, then I tried to do that during runtime inside
IPlugin.OnImGuiFreeRender()
(once). With exact same code as above it goes without crashes but all ImGui windows stop being rendered at all.loaded
printsTrue
thou.If I remove
ImGui.SetCurrentFont(font)
, the result is the same.I call
ImGui.PushFont(font)
andImGui.PopFont()
insideIPlugin.OnImGuiFreeRender()
. If I don't do that, the result is the same.Is there something that I am missing?
PC Specs
Show/Hide
Motherboard
: Asus ROG Strix Z390-H GamingCPU
: Intel Core i9-9900kRAM
: 32 GB 3200MHzGPU
: Nvidia GeForce RTX 3090 TiSystem and Game SSD
: Samsung SSD 970 EVO Plus NVMe M.2 1TBPlugin Repo SSD
: Western Digital Blue SATA M.2 2280 2TBEnvironment
Show/Hide
OS
: Window 10 Enterprise Version 22H2 (OS Build 19045.3996)Monster Hunter: World
: v15.21.00SharpPluginLoader
: v0.0.4.1Nvidia Drivers
: v551.76Game Display Settings
Show/Hide
DirectX 12 API
: OnScreen Mode
: Borderless WindowResolution Settings
: 2880x1620 (Supersampled down to 1920x1080)Aspect Ratio
: Wide (16:9)Nvidia DLSS
: OffFidelityFX CAS + Upscaling
: OffFrame Rate
: No LimitV-Sync
: OnGame Advanced Graphics Settings
Show/Hide
Image Quality
: HighTexture Quality
: High Resolution Texture PackAmbient Occlusion
: HighVolume Rendering Quality
: HighestShadow Quality
: HighCapsule AO
: OnContact Shadows
: OnAnti-Aliasing
: OffLOD Bias
: HighMax LOD Level
: No LimitFoliage Sway
: OnSubsurface Scattering
: OnScreen Space Reflection
: OnAnisotropic Filtering
: HighestWater Reflection
: OnSnow Quality
: HighSH Diffuse Quality
: HighDynamic Range
: 64-bitMotion Blur
: OnDOF (Depth of Field)
: OnVignette Effects
: NormalZ-Prepass
: OnMods and External Tools:
Show/Hide
Additional Context
Tea Overlay Repo
Better Matchmaking Repo
The text was updated successfully, but these errors were encountered: