diff --git a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs index 9e148661..9b45c5fb 100644 --- a/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs +++ b/addons/imgui-godot/ImGuiGodot/ImGuiGD.cs @@ -58,9 +58,28 @@ public static void ResetFonts() _backend.ResetFonts(); } - public static void AddFont(FontFile fontData, int fontSize, bool merge = false) + public static void AddFont( + FontFile fontData, + int fontSize, + bool merge = false, + ushort[]? glyphRanges = null) { - _backend.AddFont(fontData, fontSize, merge); + _backend.AddFont(fontData, fontSize, merge, glyphRanges); + } + + /// + /// Add a font using glyph ranges from ImGui.GetIO().Fonts.GetGlyphRanges*() + /// + /// pointer to an array of ushorts terminated by 0 + public static unsafe void AddFont(FontFile fontData, int fontSize, bool merge, nint glyphRanges) + { + ushort* p = (ushort*)glyphRanges; + int len = 1; + while (p[len++] != 0) ; + ushort[] gr = new ushort[len]; + for (int i = 0; i < len; ++i) + gr[i] = p[i]; + _backend.AddFont(fontData, fontSize, merge, gr); } public static void AddFontDefault() diff --git a/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs b/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs index 79d6544f..1f581cd0 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/BackendNative.cs @@ -43,9 +43,19 @@ public bool Visible set => _gd.Set(PropertyName.Visible, value); } - public void AddFont(FontFile fontData, int fontSize, bool merge) + public void AddFont(FontFile fontData, int fontSize, bool merge, ushort[]? glyphRanges) { - _gd.Call(MethodName.AddFont, fontData, fontSize, merge); + if (glyphRanges != null) + { + int[] gr = new int[glyphRanges.Length]; + for (int i = 0; i < glyphRanges.Length; ++i) + gr[i] = glyphRanges[i]; + _gd.Call(MethodName.AddFont, fontData, fontSize, merge, gr); + } + else + { + _gd.Call(MethodName.AddFont, fontData, fontSize, merge); + } } public void AddFontDefault() diff --git a/addons/imgui-godot/ImGuiGodot/Internal/BackendNet.cs b/addons/imgui-godot/ImGuiGodot/Internal/BackendNet.cs index d1ebb4a1..14762afa 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/BackendNet.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/BackendNet.cs @@ -26,14 +26,14 @@ public bool Visible set => ImGuiLayer.Instance.Visible = value; } - public void AddFont(FontFile fontData, int fontSize, bool merge) + public void AddFont(FontFile fontData, int fontSize, bool merge, ushort[]? glyphRanges) { - State.Instance.Fonts.AddFont(fontData, fontSize, merge); + State.Instance.Fonts.AddFont(fontData, fontSize, merge, glyphRanges); } public void AddFontDefault() { - State.Instance.Fonts.AddFont(null, 13, false); + State.Instance.Fonts.AddFont(null, 13, false, null); } public void Connect(Callable callable) diff --git a/addons/imgui-godot/ImGuiGodot/Internal/Fonts.cs b/addons/imgui-godot/ImGuiGodot/Internal/Fonts.cs index a361541f..880c35ed 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/Fonts.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/Fonts.cs @@ -16,6 +16,7 @@ private sealed class FontParams public FontFile? Font { get; init; } public int FontSize { get; init; } public bool Merge { get; init; } + public ushort[]? Ranges { get; init; } } private readonly List _fontConfiguration = []; @@ -32,21 +33,30 @@ public void ResetFonts() _fontConfiguration.Clear(); } - public void AddFont(FontFile? fontData, int fontSize, bool merge) + public void AddFont(FontFile? fontData, int fontSize, bool merge, ushort[]? ranges) { _fontConfiguration.Add( - new FontParams { Font = fontData, FontSize = fontSize, Merge = merge }); + new FontParams + { + Font = fontData, + FontSize = fontSize, + Merge = merge, + Ranges = ranges + }); } - private static unsafe void AddFontToAtlas(FontFile? fontData, int fontSize, bool merge) + private static unsafe void AddFontToAtlas(FontParams fp, float scale) { + var io = ImGui.GetIO(); + int fontSize = (int)(fp.FontSize * scale); ImFontConfig* fc = ImGuiNative.ImFontConfig_ImFontConfig(); - if (merge) + + if (fp.Merge) { fc->MergeMode = 1; } - if (fontData == null) + if (fp.Font == null) { // default font var fcptr = new ImFontConfigPtr(fc) @@ -56,28 +66,37 @@ private static unsafe void AddFontToAtlas(FontFile? fontData, int fontSize, bool OversampleV = 1, PixelSnapH = true }; - ImGui.GetIO().Fonts.AddFontDefault(fc); + io.Fonts.AddFontDefault(fc); } else { - ImVector ranges = GetRanges(fontData); - string name = $"{System.IO.Path.GetFileName(fontData.ResourcePath)}, {fontSize}px"; + string name = $"{System.IO.Path.GetFileName(fp.Font.ResourcePath)}, {fontSize}px"; for (int i = 0; i < name.Length && i < 40; ++i) { fc->Name[i] = Convert.ToByte(name[i]); } - int len = fontData.Data.Length; + int len = fp.Font.Data.Length; // let ImGui manage this memory IntPtr p = ImGui.MemAlloc((uint)len); - Marshal.Copy(fontData.Data, 0, p, len); - ImGui.GetIO().Fonts.AddFontFromMemoryTTF(p, len, fontSize, fc, ranges.Data); + Marshal.Copy(fp.Font.Data, 0, p, len); + if (fp.Ranges == null) + { + ImVector ranges = GetRanges(fp.Font); + io.Fonts.AddFontFromMemoryTTF(p, len, fontSize, fc, ranges.Data); + } + else + { + fixed (ushort* pranges = fp.Ranges) + { + io.Fonts.AddFontFromMemoryTTF(p, len, fontSize, fc, (nint)pranges); + } + } } - if (merge) - { - ImGui.GetIO().Fonts.Build(); - } + if (fp.Merge) + io.Fonts.Build(); + ImGuiNative.ImFontConfig_destroy(fc); } @@ -129,6 +148,8 @@ public unsafe void RebuildFontAtlas(float scale) { var io = ImGui.GetIO(); int fontIndex = -1; + + // save current font index if (io.NativePtr->FontDefault != null) { for (int i = 0; i < io.Fonts.Fonts.Size; ++i) @@ -145,7 +166,7 @@ public unsafe void RebuildFontAtlas(float scale) foreach (var fontParams in _fontConfiguration) { - AddFontToAtlas(fontParams.Font, (int)(fontParams.FontSize * scale), fontParams.Merge); + AddFontToAtlas(fontParams, scale); } io.Fonts.GetTexDataAsRGBA32( @@ -163,6 +184,7 @@ public unsafe void RebuildFontAtlas(float scale) io.Fonts.SetTexID((IntPtr)_fontTexture.GetRid().Id); io.Fonts.ClearTexData(); + // maintain selected font when rescaling if (fontIndex != -1 && fontIndex < io.Fonts.Fonts.Size) { io.NativePtr->FontDefault = io.Fonts.Fonts[fontIndex].NativePtr; diff --git a/addons/imgui-godot/ImGuiGodot/Internal/IBackend.cs b/addons/imgui-godot/ImGuiGodot/Internal/IBackend.cs index 609e5b33..4cc47178 100644 --- a/addons/imgui-godot/ImGuiGodot/Internal/IBackend.cs +++ b/addons/imgui-godot/ImGuiGodot/Internal/IBackend.cs @@ -9,7 +9,7 @@ internal interface IBackend public float JoyAxisDeadZone { get; set; } public float Scale { get; set; } public void ResetFonts(); - public void AddFont(FontFile fontData, int fontSize, bool merge); + public void AddFont(FontFile fontData, int fontSize, bool merge, ushort[]? glyphRanges); public void AddFontDefault(); public void RebuildFontAtlas(float scale); public void Connect(Callable callable); diff --git a/gdext/include/imgui-godot.h b/gdext/include/imgui-godot.h index 9921f8b6..ad15d98e 100644 --- a/gdext/include/imgui-godot.h +++ b/gdext/include/imgui-godot.h @@ -31,6 +31,7 @@ using godot::InputEvent; using godot::JoyButton; using godot::Key; using godot::Object; +using godot::PackedInt32Array; using godot::Ref; using godot::Resource; using godot::RID; @@ -77,17 +78,26 @@ inline bool GET_IMGUIGD() inline static void GetAtlasUVs(AtlasTexture* tex, ImVec2& uv0, ImVec2& uv1) { + ERR_FAIL_COND(!tex); Vector2 atlasSize = tex->get_atlas()->get_size(); uv0 = tex->get_region().get_position() / atlasSize; uv1 = tex->get_region().get_end() / atlasSize; } } // namespace detail -inline void AddFont(const Ref& fontFile, int fontSize, bool merge = false) +inline void AddFont(const Ref& fontFile, int fontSize, bool merge = false, ImWchar* glyphRanges = nullptr) { ERR_FAIL_COND(!detail::GET_IMGUIGD()); static const StringName sn("AddFont"); - detail::ImGuiGD->call(sn, fontSize, merge); + PackedInt32Array gr; + if (glyphRanges) + { + do + { + gr.append(*glyphRanges); + } while (*++glyphRanges != 0); + } + detail::ImGuiGD->call(sn, fontSize, merge, gr); } inline void Connect(const Callable& callable) @@ -153,6 +163,7 @@ inline void SyncImGuiPtrs() inline ImTextureID BindTexture(Texture2D* tex) { + ERR_FAIL_COND_V(!tex, 0); return reinterpret_cast(tex->get_rid().get_id()); } #endif diff --git a/gdext/src/Context.cpp b/gdext/src/Context.cpp index da6eec18..2bb0452a 100644 --- a/gdext/src/Context.cpp +++ b/gdext/src/Context.cpp @@ -267,9 +267,9 @@ void ResetFonts() ctx->fonts->Reset(); } -void AddFont(const Ref& fontFile, int fontSize, bool merge) +void AddFont(const Ref& fontFile, int fontSize, bool merge, const ImVector& glyphRanges) { - ctx->fonts->Add(fontFile, fontSize, merge); + ctx->fonts->Add(fontFile, fontSize, merge, glyphRanges); } void AddFontDefault() diff --git a/gdext/src/Context.h b/gdext/src/Context.h index 47acff38..464688a4 100644 --- a/gdext/src/Context.h +++ b/gdext/src/Context.h @@ -72,7 +72,7 @@ void Render(); void Shutdown(); void Connect(const Callable& callable); void ResetFonts(); -void AddFont(const Ref& fontFile, int fontSize, bool merge = false); +void AddFont(const Ref& fontFile, int fontSize, bool merge = false, const ImVector& glyphRanges = {}); void AddFontDefault(); void RebuildFontAtlas(float scale = 1.0f); void SetIniFilename(const String& fn); diff --git a/gdext/src/Fonts.cpp b/gdext/src/Fonts.cpp index 959d6f60..8e1fc438 100644 --- a/gdext/src/Fonts.cpp +++ b/gdext/src/Fonts.cpp @@ -27,7 +27,7 @@ struct Fonts::Impl }; std::vector fontConfig; - void AddFontToAtlas(const Ref& font, int fontSize, bool merge, const ImVector& ranges); + void AddFontToAtlas(const FontParams& fp, float scale); static ImVector GetRanges(const Ref& font) { @@ -76,13 +76,16 @@ struct Fonts::Impl } }; -void Fonts::Impl::AddFontToAtlas(const Ref& font, int fontSize, bool merge, const ImVector& ranges) +void Fonts::Impl::AddFontToAtlas(const FontParams& fp, float scale) { + auto& io = ImGui::GetIO(); + int fontSize = fp.fontSize * scale; ImFontConfig fc; - if (merge) + + if (fp.merge) fc.MergeMode = 1; - if (font.is_null()) + if (fp.font.is_null()) { // default font fc = {}; @@ -90,29 +93,28 @@ void Fonts::Impl::AddFontToAtlas(const Ref& font, int fontSize, bool m fc.OversampleH = 1; fc.OversampleV = 1; fc.PixelSnapH = true; - ImGui::GetIO().Fonts->AddFontDefault(&fc); + io.Fonts->AddFontDefault(&fc); } else { - fs::path fontpath = (font->get_path().utf8().get_data()); + fs::path fontpath = (fp.font->get_path().utf8().get_data()); // no std::format in Clang 14 std::string fontdesc = fontpath.filename().string() + ", "s + std::to_string(fontSize) + "px"; if (fontdesc.length() > 39) fontdesc.resize(39); std::copy(fontdesc.begin(), fontdesc.end(), fc.Name); + fc.Name[fontdesc.length()] = '\0'; - int64_t len = font->get_data().size(); + int64_t len = fp.font->get_data().size(); // let ImGui manage this memory void* p = ImGui::MemAlloc(len); - memcpy(p, font->get_data().ptr(), len); - ImGui::GetIO().Fonts->AddFontFromMemoryTTF(p, len, fontSize, &fc, ranges.Data); + memcpy(p, fp.font->get_data().ptr(), len); + io.Fonts->AddFontFromMemoryTTF(p, len, fontSize, &fc, fp.ranges.Data); } - if (merge) - { - ImGui::GetIO().Fonts->Build(); - } + if (fp.merge) + io.Fonts->Build(); } Fonts::Fonts() : impl(std::make_unique()) @@ -131,9 +133,10 @@ void Fonts::Reset() impl->fontConfig.clear(); } -void Fonts::Add(Ref fontData, int fontSize, bool merge) +void Fonts::Add(Ref fontData, int fontSize, bool merge, const ImVector& glyphRanges) { - impl->fontConfig.push_back({fontData, fontSize, merge, Impl::GetRanges(fontData)}); + impl->fontConfig.push_back( + {fontData, fontSize, merge, glyphRanges.size() > 0 ? glyphRanges : Impl::GetRanges(fontData)}); } void Fonts::RebuildFontAtlas(float scale) @@ -156,7 +159,7 @@ void Fonts::RebuildFontAtlas(float scale) for (const auto& fp : impl->fontConfig) { - impl->AddFontToAtlas(fp.font, fp.fontSize * scale, fp.merge, fp.ranges); + impl->AddFontToAtlas(fp, scale); } uint8_t* pixelData; diff --git a/gdext/src/Fonts.h b/gdext/src/Fonts.h index e4121597..21772b0b 100644 --- a/gdext/src/Fonts.h +++ b/gdext/src/Fonts.h @@ -1,6 +1,6 @@ #pragma once #include - +#include #include using namespace godot; @@ -13,7 +13,7 @@ class Fonts ~Fonts(); void Reset(); - void Add(Ref fontData, int fontSize, bool merge = false); + void Add(Ref fontData, int fontSize, bool merge = false, const ImVector& glyphRanges = {}); void RebuildFontAtlas(float scale); private: diff --git a/gdext/src/ImGuiGD.cpp b/gdext/src/ImGuiGD.cpp index d82bcd35..2d469a24 100644 --- a/gdext/src/ImGuiGD.cpp +++ b/gdext/src/ImGuiGD.cpp @@ -25,7 +25,10 @@ void ImGuiGD::_bind_methods() ClassDB::bind_method(D_METHOD("_GetScale"), &ImGuiGD::_GetScale); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "Scale"), "_SetScale", "_GetScale"); - ClassDB::bind_method(D_METHOD("AddFont", "font_file", "font_size", "merge"), &ImGuiGD::AddFont, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("AddFont", "font_file", "font_size", "merge", "glyph_ranges"), + &ImGuiGD::AddFont, + DEFVAL(false), + DEFVAL(PackedInt32Array())); ClassDB::bind_method(D_METHOD("AddFontDefault"), &ImGuiGD::AddFontDefault); ClassDB::bind_method(D_METHOD("Connect", "callable"), &ImGuiGD::Connect); ClassDB::bind_method(D_METHOD("RebuildFontAtlas", "scale"), &ImGuiGD::RebuildFontAtlas, DEFVAL(1.0f)); @@ -87,9 +90,20 @@ void ImGuiGD::ResetFonts() ImGui::Godot::ResetFonts(); } -void ImGuiGD::AddFont(const Ref& fontFile, int fontSize, bool merge) +void ImGuiGD::AddFont(const Ref& fontFile, int fontSize, bool merge, const PackedInt32Array& glyphRanges) { - ImGui::Godot::AddFont(fontFile, fontSize, merge); + if (glyphRanges.size() > 0) + { + ImVector gr; + gr.resize(glyphRanges.size() + 1, 0); + for (int i = 0; i < glyphRanges.size(); ++i) + gr[i] = glyphRanges[i]; + ImGui::Godot::AddFont(fontFile, fontSize, merge, gr); + } + else + { + ImGui::Godot::AddFont(fontFile, fontSize, merge); + } } void ImGuiGD::AddFontDefault() diff --git a/gdext/src/ImGuiGD.h b/gdext/src/ImGuiGD.h index c61e0199..f62e2de3 100644 --- a/gdext/src/ImGuiGD.h +++ b/gdext/src/ImGuiGD.h @@ -27,7 +27,8 @@ class ImGuiGD : public Object void Connect(const Callable& cb); void ResetFonts(); - void AddFont(const Ref& fontFile, int fontSize, bool merge = false); + void AddFont(const Ref& fontFile, int fontSize, bool merge = false, + const PackedInt32Array& glyphRanges = {}); void AddFontDefault(); void RebuildFontAtlas(float scale); diff --git a/src/MySecondNode.cs b/src/MySecondNode.cs index fb84b4d9..ca1f3754 100644 --- a/src/MySecondNode.cs +++ b/src/MySecondNode.cs @@ -42,8 +42,9 @@ public override void _EnterTree() // use Hack for the default glyphs, M+2 for Japanese ImGuiGD.AddFont(GD.Load("res://data/Hack-Regular.ttf"), 18); - ImGuiGD.AddFont(GD.Load("res://data/MPLUS2-Regular.ttf"), 22, - merge: true); + ImGuiGD.AddFont(GD.Load("res://data/MPLUS2-Regular.ttf"), 24, + merge: true, + glyphRanges: ImGui.GetIO().Fonts.GetGlyphRangesJapanese()); ImGuiGD.AddFontDefault(); ImGuiGD.RebuildFontAtlas();