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

Adding images #20

Closed
frknbhcl opened this issue Mar 13, 2023 · 5 comments
Closed

Adding images #20

frknbhcl opened this issue Mar 13, 2023 · 5 comments

Comments

@frknbhcl
Copy link

First of all, thank you for creating and sharing this with us.
I want to ask that if I can add images (imagebuttons) onto windows? I tried to create an IntPtr type of an image using Bitmap but I couldn't make it. I wonder if there is an easier way to do this?

@ds5678
Copy link

ds5678 commented Mar 13, 2023

I've done what you're describing, but I don't have any sample code on GitHub yet.

However, this might help you: ImGuiNET/ImGui.NET#141

@aybe
Copy link
Owner

aybe commented Mar 14, 2023

You welcome!

There is a section in the wiki entirely dedicated on how to load and display images using each 3D API:

Image Loading and Displaying Examples

@aybe
Copy link
Owner

aybe commented Mar 14, 2023

Woops, that was trickier than I thought! 😅

SampleApplication OpenTK_FWuU4ZmOdt

The code is the sample application, at the very bottom, how to draw a System.Drawing.Bitmap; don't forget to pick the bits in the constructor, Dispose, OnUpdateFrame.

I first thought that the controller needed an update but no, it's probably just an OpenGL error that you've encountered.

It seems that the changes made by @KCoen are a bit problematic because then OpenGL problems are simply swept under the carpet unless you watch for debug console.

Throwing at user's face is always better IMO.😁 I'll open an issue about that.

using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using DearImGui;
using DearImGui.OpenTK;
using DearImGui.OpenTK.Extensions;
using DearImPlot;
using OpenTK.Graphics.OpenGL;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using Vector2 = System.Numerics.Vector2;

namespace SampleApplication.OpenTK;

internal sealed class MyGameWindow : GameWindowBaseWithDebugContext
{
    private static readonly double[] SampleData1 = Enumerable.Range(0, 256).Select(s => Math.Cos(s / 2.0d / Math.PI)).ToArray();

    private static readonly double[] SampleData2 = Enumerable.Range(0, 256).Select(s => Math.Sin(s / 2.0d / Math.PI)).ToArray();

    private readonly ImGuiController Controller;

    private readonly ImPlotContext ImPlotContext;

    private Color4 Color1 = Color4.Crimson;

    private Color4 Color2 = Color4.DeepSkyBlue;

    private bool ShowDockingDemo = true;

    private bool ShowImGuiDemo = true;

    private bool ShowImPlotDemo = true;

    public MyGameWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
        : base(gameWindowSettings, nativeWindowSettings)
    {
        Controller = new ImGuiController(this, "Roboto-Regular.ttf", 10.0f);

        ImPlotContext = ImPlot.CreateContext();

        ImPlot.SetCurrentContext(ImPlotContext);

        ImPlot.SetImGuiContext(Controller.Context);

        SampleImageDemoData = SampleImageDemoInit();
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            Controller.Dispose();
            ImPlot.DestroyContext(ImPlotContext);
            SampleImageDemoFree();
        }

        base.Dispose(disposing);
    }

    protected override void OnUpdateFrame(FrameEventArgs args)
    {
        SampleExtraFontImpl();

        Controller.Update((float)args.Time);

        SampleImageDemo();
    }

    protected override void OnRenderFrame(FrameEventArgs args)
    {
        GL.ClearColor(Color.CornflowerBlue);
        GL.Clear(ClearBufferMask.ColorBufferBit);

        ImGui.SetNextWindowSize(new Vector2(800, 500), ImGuiCond.Once);

        if (ShowDockingDemo)
        {
            DrawDockSpaceOptionsBar(ref ShowDockingDemo);
        }


        if (ImGui.Begin("Hello, world!"))
        {
            if (ImPlot.BeginPlot("Sample plot"))
            {
                ImPlot.SetupAxes("X", "Y");

                ImPlot.SetNextLineStyle(Color1.ToVector4());
                ImPlot.PlotLine("Sample data 1", ref SampleData1[0], SampleData1.Length);

                ImPlot.SetNextLineStyle(Color2.ToVector4());
                ImPlot.PlotLine("Sample data 2", ref SampleData2[0], SampleData2.Length);

                ImPlot.EndPlot();
            }

            ImGui.ColorEdit4("Color 1", Color1.AsSpan(), ImGuiColorEditFlags.NoInputs);
            ImGui.ColorEdit4("Color 2", Color2.AsSpan(), ImGuiColorEditFlags.NoInputs);

            ImGui.Checkbox("Show ImGui Demo", ref ShowImGuiDemo);
            ImGui.Checkbox("Show ImPlot Demo", ref ShowImPlotDemo);
            ImGui.Checkbox("Show Docking Demo", ref ShowDockingDemo);
        }

        ImGui.End();

        SampleExtraFontDemo();

        if (ShowImGuiDemo)
        {
            ImGui.ShowDemoWindow(ref ShowImGuiDemo);
        }

        if (ShowImPlotDemo)
        {
            ImPlot.ShowDemoWindow(ref ShowImPlotDemo);
        }

        Controller.Render();

        SwapBuffers();
    }

    protected override void OnResize(ResizeEventArgs e)
    {
        base.OnResize(e);

        GL.Viewport(0, 0, e.Width, e.Height);
    }

    #region SampleDocking

    private ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags.None;

    private void DrawDockSpaceOptionsBar(ref bool p_open)
    {
        ImGui.DockSpaceOverViewport(ImGui.GetMainViewport(), dockspace_flags);

        if (ImGui.BeginMainMenuBar())
        {
            if (ImGui.BeginMenu("Options"))
            {
                if (ImGui.MenuItem("Enable Docking", "IO.ConfigFlags.DockingEnable", ImGui.GetIO().ConfigFlags.HasFlag(ImGuiConfigFlags.DockingEnable)))
                {
                    ImGui.GetIO().ConfigFlags ^= ImGuiConfigFlags.DockingEnable;
                }

                ImGui.Separator();

                if (ImGui.MenuItem("Require Shift For Docking", "IO.ConfigDockingWithShift",
                        ImGui.GetIO().ConfigDockingWithShift))
                {
                    ImGui.GetIO().ConfigDockingWithShift = !ImGui.GetIO().ConfigDockingWithShift;
                }

                ImGui.Separator();

                if (ImGui.MenuItem("Flag: NoSplit", "", (dockspace_flags & ImGuiDockNodeFlags.NoSplit) != 0))
                {
                    dockspace_flags ^= ImGuiDockNodeFlags.NoSplit;
                }

                if (ImGui.MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags.NoResize) != 0))
                {
                    dockspace_flags ^= ImGuiDockNodeFlags.NoResize;
                }

                if (ImGui.MenuItem("Flag: NoDockingInCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags.NoDockingInCentralNode) != 0))
                {
                    dockspace_flags ^= ImGuiDockNodeFlags.NoDockingInCentralNode;
                }

                if (ImGui.MenuItem("Flag: AutoHideTabBar", "", (dockspace_flags & ImGuiDockNodeFlags.AutoHideTabBar) != 0))
                {
                    dockspace_flags ^= ImGuiDockNodeFlags.AutoHideTabBar;
                }

                if (ImGui.MenuItem("Flag: PassthruCentralNode", "", (dockspace_flags & ImGuiDockNodeFlags.PassthruCentralNode) != 0))
                {
                    dockspace_flags ^= ImGuiDockNodeFlags.PassthruCentralNode;
                }

                ImGui.EndMenu();
            }

            HelpMarker(
                @"When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!
    
- Drag from window title bar or their tab to dock/undock.
    
- Drag from window menu button (upper-left button) to undock an entire node (all windows).
    
- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)
    
- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");

            ImGui.EndMainMenuBar();
        }

        static void HelpMarker(string desc)
        {
            ImGui.TextDisabled("(?)");

            if (ImGui.IsItemHovered())
            {
                ImGui.BeginTooltip();
                ImGui.PushTextWrapPos(ImGui.GetFontSize() * 35.0f);
                ImGui.TextUnformatted(desc);
                ImGui.PopTextWrapPos();
                ImGui.EndTooltip();
            }
        }
    }

    #endregion

    #region SampleExtraFont

    private bool? SampleExtraFontFlag;
    private readonly (int TextureId, int TextureWidth, int TextureHeight) SampleImageDemoData;

    private unsafe void SampleExtraFontImpl()
    {
        if (SampleExtraFontFlag is false)
            return;

        SampleExtraFontFlag = false;

        var io = ImGui.GetIO();

        var fonts = io.Fonts;

        var ranges = fonts.GlyphRangesDefault;

        var size = Controller.GetDpiScaledFontSize(12.0f);

        var font = fonts.AddFontFromFileTTF("Roboto-Regular.ttf", size, null, ref *ranges);

        Debug.WriteLine(font);

        fonts.Build();

        Controller.UpdateFontsTextureAtlas();
    }

    private void SampleExtraFontDemo()
    {
        ImGui.SetNextWindowSize(new Vector2(400, 100), ImGuiCond.Once);

        if (ImGui.Begin("Sample: extra font"))
        {
            if (SampleExtraFontFlag is false)
            {
                ImGui.Text("Change font from Tools/Style Editor.");
            }
            else
            {
                if (ImGui.Button("Click to add an extra font"))
                {
                    SampleExtraFontFlag = true;
                }
            }
        }

        ImGui.End();
    }

    #endregion

    #region SampleImageDemo

    private static (int TextureId, int TextureWidth, int TextureHeight) SampleImageDemoInit()
    {
        using var bitmap = new Bitmap(256, 256, PixelFormat.Format32bppArgb);

        var bits = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, bitmap.PixelFormat);

        var buffer = new byte[bitmap.Width * bitmap.Height * 4];

        Random.Shared.NextBytes(buffer);

        Marshal.Copy(buffer, 0, bits.Scan0, buffer.Length);

        bitmap.UnlockBits(bits);

        var texture = GL.GenTexture();

        GL.BindTexture(TextureTarget.Texture2D, texture);

        GL.TextureParameter(texture, TextureParameterName.TextureMinFilter, (int)All.Linear);
        GL.TextureParameter(texture, TextureParameterName.TextureMagFilter, (int)All.Linear);
        GL.TextureParameter(texture, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
        GL.TextureParameter(texture, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

        var rect = new Rectangle(Point.Empty, bitmap.Size);
        var data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);

        GL.TexImage2D(
            TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, bitmap.Width, bitmap.Height, 0,
            global::OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, data.Scan0);

        bitmap.UnlockBits(data);

        return (TextureId: texture, TextureWidth: bitmap.Width, TextureHeight: bitmap.Height);
    }

    private void SampleImageDemo()
    {
        if (ImGui.Begin("window"))
        {
            ImGui.Image((IntPtr)SampleImageDemoData.TextureId, new Vector2(SampleImageDemoData.TextureWidth, SampleImageDemoData.TextureHeight));
        }

        ImGui.End();
    }

    private void SampleImageDemoFree()
    {
        GL.DeleteTexture(SampleImageDemoData.TextureId);
    }

    #endregion
}

@frknbhcl
Copy link
Author

Yes! Thank you for the reply, it worked.

@aybe
Copy link
Owner

aybe commented Mar 17, 2023

Great! 😀

@aybe aybe closed this as completed Mar 17, 2023
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

3 participants