Skip to content
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

Problem merging font awesome into default font #460

Open
JeffM2501 opened this issue Jan 20, 2024 · 8 comments
Open

Problem merging font awesome into default font #460

JeffM2501 opened this issue Jan 20, 2024 · 8 comments

Comments

@JeffM2501
Copy link

JeffM2501 commented Jan 20, 2024

Hello. I maintain an ImGui backend for the library Raylib (https://www.raylib.com/), for both C++ and C#.

One feature of the backend is that by default we add font awesome icons to the default font so that people can easily use them in ImGui.

I'm having a problem with the C# version of the code, no mater what I try I can't get the font to merge in anymore. This used to work a while ago, but there have been some library updates and refactors since I tested it last (changing over to events, etc..).
I'm in the process of updating the C# backend to the current ImGui.net 1.90.1.1, so I know I'm on current code.

This is my font loading code for C#
https://github.com/raylib-extras/rlImGui-cs/blob/23df04bc3ee07c2225594e2e378955fec57662c4/rlImGui/rlImGui.cs#L277

C#

unsafe
{
    ImFontConfig icons_config = new ImFontConfig();
    icons_config.MergeMode = 1;                      // merge the glyph ranges into the default font
    icons_config.PixelSnapH = 1;                     // don't try to render on partial pixels
    icons_config.FontDataOwnedByAtlas = 0;           // the font atlas does not own this font data

    icons_config.GlyphMaxAdvanceX = float.MaxValue;
    icons_config.RasterizerMultiply = 1.0f;
    icons_config.OversampleH = 2;
    icons_config.OversampleV = 1;

    ushort[] IconRanges = new ushort[3];
    IconRanges[0] = IconFonts.FontAwesome6.IconMin;
    IconRanges[1] = IconFonts.FontAwesome6.IconMax;
    IconRanges[2] = 0;

    fixed (ushort* range = &IconRanges[0])
    {
        // this unmanaged memory must remain allocated for the entire run of rlImgui
        IconFonts.FontAwesome6.IconFontRanges = Marshal.AllocHGlobal(6);
        Buffer.MemoryCopy(range, IconFonts.FontAwesome6.IconFontRanges.ToPointer(), 6, 6);
        icons_config.GlyphRanges = (ushort*)IconFonts.FontAwesome6.IconFontRanges.ToPointer();

        byte[] fontDataBuffer = Convert.FromBase64String(IconFonts.FontAwesome6.IconFontData);

        fixed (byte* buffer = fontDataBuffer)
        {
            var fontPtr = ImGui.GetIO().Fonts.AddFontFromMemoryTTF(new IntPtr(buffer), fontDataBuffer.Length, 11, &icons_config, IconFonts.FontAwesome6.IconFontRanges);
        }
    }
}

The font atlas that is generated does not have any of the merged characters in it.
image

It never seems to load the font. It does not mater if I use the font from memory or a file on disk, so I don't think it's a data issue.

The code very similar to what I do in the C++ version of the backend, and that code does work.
https://github.com/raylib-extras/rlImGui/blob/de2c361b5835e6c2075b4f314bc7d949869666f1/rlImGui.cpp#L252
C++

	ImFontConfig icons_config;
	icons_config.MergeMode = true;
	icons_config.PixelSnapH = true;
	icons_config.FontDataOwnedByAtlas = false;

	icons_config.GlyphRanges = icons_ranges;

    ImGuiIO& io = ImGui::GetIO();

	io.Fonts->AddFontFromMemoryCompressedTTF((void*)fa_solid_900_compressed_data, fa_solid_900_compressed_size, FONT_AWESOME_ICON_SIZE, &icons_config, icons_ranges);

With this code in C++, I do see the icon fonts as part of the font atlas.
image

I'm sure there is something I'm missing or doing wrong, C# hasn't been my primary language for a while. Anyone have any idea what more I can do to try and track this down? Any help would be appreciated.

@NoahStolk
Copy link
Contributor

I got this working a while ago, and I believe you must call ImGuiNative.ImFontConfig_ImFontConfig to properly create an ImFontConfig:

ImFontConfig* icons_config = ImGuiNative.ImFontConfig_ImFontConfig();
icons_config->MergeMode = 1;
// etc...

Just cloned rlImGui-cs and tried it myself. The font seems to show up correctly now in the Metrics/Debugger window. Will make a PR.

@zaafar
Copy link
Collaborator

zaafar commented Feb 11, 2024

Imgui constructors should be optional, looks like a imgui bug and you should report it to imgui repo.

@JeffM2501
Copy link
Author

Imgui constructors should be optional, looks like a imgui bug and you should report it to imgui repo.

The C++ version works just fine, so I don't think it's core ImGui issue. I think the main problem is that I was not allocating a native pointer, but a managed structure and it didn't marshal to the .net C# bindings correctly.

@zaafar
Copy link
Collaborator

zaafar commented Feb 11, 2024

I see, all good then, I was just pointing to “Constructors/destructors” documentation mentioned in https://github.com/dearimgui/dear_bindings repo.

@tingspain
Copy link

tingspain commented Aug 28, 2024

Hello @JeffM2501, by any chance, did you find the solution?

I am using the following code to load Font Icons to the Font Atlas and it works well with ImGui.NET 1.89.4. However, It doesn't work with ImGui.NET 1.90.0. I dont know why.

So I was wondering if you manage to make it work.

Thanks in advance.

            var io = ImGui.GetIO();
            
            // Add the default fonts for the App
            if(lSpace.SDK.Core.Utils.FileExists("Assets/Fonts/Manrope/Manrope-Regular.ttf"))
                io.Fonts.AddFontFromFileTTF("Assets/Fonts/Manrope/Manrope-Regular.ttf", 17.0f);

            // Add alternative bold style for the default font for the app
            if(Core.Utils.FileExists("Assets/Fonts/Manrope/Manrope-Bold.ttf"))
                io.Fonts.AddFontFromFileTTF("Assets/Fonts/Manrope/Manrope-Bold.ttf", 17.0f);

            // Add the App Icons
            if(Core.Utils.FileExists( "Assets/Fonts/appicons.ttf") ){

                    var ranges = new[] { '\ue800', '\uf2db' };

                    var rangesIntPtr = Marshal.UnsafeAddrOfPinnedArrayElement(ranges, 0);

                    ImFontConfig config = new ImFontConfig
                    {
                        MergeMode            = 1,
                        OversampleH          = 3,
                        OversampleV          = 3,
                        GlyphOffset          = System.Numerics.Vector2.Zero,
                        FontDataOwnedByAtlas = 1,
                        PixelSnapH           = 1,
                        GlyphMaxAdvanceX     = float.MaxValue,
                        RasterizerMultiply   = 1.0f
                    };
                    
                    var configHandle = GCHandle.Alloc(config, GCHandleType.Pinned);
                    ImGui.GetIO().Fonts.AddFontFromFileTTF("Assets/Fonts/appicons.ttf", 
                                                        12.5f, 
                                                        configHandle.AddrOfPinnedObject(), 
                                                        rangesIntPtr);
                    configHandle.Free();
                        
            }
  
            io.ConfigFlags  |= ImGuiConfigFlags.DockingEnable         | ImGuiConfigFlags.ViewportsEnable;
            io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset | ImGuiBackendFlags.PlatformHasViewports;
            io.Fonts.Build();

@NoahStolk
Copy link
Contributor

@tingspain Have you tried calling ImGuiNative.ImFontConfig_ImFontConfig() instead of the ImFontConfig constructor? See my comment and PR for details.

I don't know why this would break in 1.90.0 though.

@tingspain
Copy link

@NoahStolk, indeed. I am sorry to not post my solution earlier. At the end, I manage to make it works, as you suggested.

Here is my code.

public static void AddIconsFonts(float fontSize, char iconMin, char iconMax, string fontFilePath)
{
      unsafe {

            ushort[]  ranges = { iconMin, iconMax, 0 };

            var rangesIntPtr = Marshal.UnsafeAddrOfPinnedArrayElement(ranges, 0);

            ImFontConfigPtr fontConfig      = ImGuiNative.ImFontConfig_ImFontConfig();
            fontConfig.MergeMode            = true;
            fontConfig.OversampleH          = 3;
            fontConfig.OversampleV          = 3;
            fontConfig.GlyphOffset          = Vector2.Zero;
            fontConfig.FontDataOwnedByAtlas = false;
            fontConfig.PixelSnapH           = true;
            fontConfig.GlyphMaxAdvanceX     = float.MaxValue;
            fontConfig.RasterizerMultiply   = 2.0f;

            ImGui.GetIO().Fonts.AddFontFromFileTTF( fontFilePath, 
                                                      fontSize, 
                                                      fontConfig, 
                                                      rangesIntPtr);
                  
      }
}

(Just in case, it will be useful for someone)
And then I use it in my ImGuiController as follow:

var io = ImGui.GetIO();

unsafe {

      // Sanity Check
      if(!Core.Utils.FileExists("Assets/Fonts/Manrope/Manrope-Regular.ttf"))
            throw new System.NullReferenceException("The app can not find the default font");

      // Add the default fonts for the App
      io.Fonts.AddFontFromFileTTF("Assets/Fonts/Manrope/Manrope-Regular.ttf", 17.0f);

      // Add the App Icons
      if(Core.Utils.FileExists( ImGuiExt.AppIcons.FontFile ) )
            ImGuiExt.AddIconsFonts(14,  
                                   ImGuiExt.AppIcons.IconMin,  
                                   ImGuiExt.AppIcons.IconMax,  
                                   ImGuiExt.AppIcons.FontFile);  

}

io.ConfigFlags  |= ImGuiConfigFlags.DockingEnable         | ImGuiConfigFlags.ViewportsEnable | ImGuiConfigFlags.NavEnableKeyboard;
io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset | ImGuiBackendFlags.PlatformHasViewports;
io.Fonts.Build();

It will be more than welcome if anyone has any feedback/suggestion/recommendation. ^___^

Thanks in advance!!!

@blackholeearth
Copy link

blackholeearth commented Nov 26, 2024

holyy shit man genius...

forget font-awesome , i wasnt able to replace normal Font no matter what...

it works.

but i wish we can replace it while app is running. not just Controller definition.

at ImGUIController.cs -- modify like these.


 /// <summary>
 /// Constructs a new ImGuiController.
 /// </summary>
 public ImGuiController(GraphicsDevice gd, OutputDescription outputDescription, int width, int height)
 {
     _gd = gd;
     _windowWidth = width;
     _windowHeight = height;

     ImGui.CreateContext();
     var io = ImGui.GetIO();
     io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset;
     io.ConfigFlags |= ImGuiConfigFlags.NavEnableKeyboard |
         ImGuiConfigFlags.DockingEnable;
     io.Fonts.Flags |= ImFontAtlasFlags.NoBakedLines;

    //----------inject my font HERE---------
     string FontPath = @"C:\Windows\Fonts\arial.ttf";
     AddFont_viaGH460_build(FontPath, 22);


     CreateDeviceResources(gd, outputDescription);
     SetPerFrameImGuiData(1f / 60f);
     ImGui.NewFrame();
     _frameBegun = true;
 }

here the function GH460_build

    public static void AddFont_viaGH460_build(string fontFilePath, float fontSize)
        {
            var io = ImGui.GetIO();

            unsafe
            {

                // Add the default fonts for the App
                io.Fonts.AddFontFromFileTTF(fontFilePath, 22.0f);

            }

            io.ConfigFlags |= ImGuiConfigFlags.DockingEnable | ImGuiConfigFlags.ViewportsEnable | ImGuiConfigFlags.NavEnableKeyboard;
            io.BackendFlags |= ImGuiBackendFlags.RendererHasVtxOffset | ImGuiBackendFlags.PlatformHasViewports;
            io.Fonts.Build();
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants