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

Multiple ImDrawLists HowTo? #114

Closed
BlizzCrafter opened this issue Mar 12, 2019 · 6 comments
Closed

Multiple ImDrawLists HowTo? #114

BlizzCrafter opened this issue Mar 12, 2019 · 6 comments

Comments

@BlizzCrafter
Copy link

BlizzCrafter commented Mar 12, 2019

I'm trying to create a custom ImDrawList to add game specific vertices and I am using the ImGui.NET.SampleProgram.XNA (which runs flawlessy).

I implemented an additional ImDrawData and ImDrawListPtr and the corresponding rendering logic (like the XNA sample).

But when I try to add something to the ImDrawListPtr (see below), I get a System.AccessViolationException.

ImGuiRenderer.CustomDrawListPtr.AddCircleFilled(
new Num.Vector2(200, 150), 100f, ImGui.ColorConvertFloat4ToU32(new Num.Vector4(0.9f, 0.7f, 0.7f, 0.8f)), 24);

It seems that I need to initialize ImDrawListPtr somehow, but I don't know how to do this correctly.

I want to use a custom DrawList to apply different transformations to the vertices.

Can someone point me to the right direction?
Any help is greatly appreciated!

@mellinoe
Copy link
Collaborator

I haven't used custom ImDrawLists myself, but according to the docs in the header, you can create one by calling GetDrawListSharedData and passing that to the constructor. Something like this in C#:

ImDrawListPtr = ImGuiNative.ImDrawList_ImDrawList(ImGuiNative.igGetDrawListSharedData));

@BlizzCrafter
Copy link
Author

BlizzCrafter commented Mar 12, 2019

Initialization is working now, thanks for your help.

But still getting System.AccessViolationException.

I tried a minimal standalone sample like in this post: ocornut/imgui#1878 (comment)

My code (directly in ImGuiLayout):

IntPtr shared = ImGui.GetDrawListSharedData();

ImDrawDataPtr CustomDrawData = new ImDrawDataPtr(shared);
CustomDrawData.DisplayPos = new Num.Vector2();
CustomDrawData.DisplaySize = new Num.Vector2(
Editor.graphics.PresentationParameters.BackBufferWidth,
Editor.graphics.PresentationParameters.BackBufferHeight);

ImDrawListPtr CustomDrawList = shared;
CustomDrawList.AddCircle(  // System.AccessViolationException
                  new Num.Vector2(200, 150), 100f,
                  ImGui.ColorConvertFloat4ToU32(new Num.Vector4(1f, 0.9f, 0.9f, 0.9f)), 24);

I think I can get around this by pre-multiplying transformations on the indices and then just use the built-in ImGui.GetWindowDrawList() with the updated Vectors.

Feel free to close this issue and thanks again for trying to help and for your fast reply.

But if someone stumbles upon this in the future I would still be interested to know how to successfully creating and using a seperate ImDrawList.

@mellinoe
Copy link
Collaborator

I don't think you can do this:

ImDrawListPtr CustomDrawList = shared;

You need to use something like the code I wrote above:

ImDrawListPtr CustomDrawList = ImGuiNative.ImDrawList_ImDrawList(shared));
// TODO: call ImDrawList_destroy(CustomDrawList) when finished.

@BlizzCrafter
Copy link
Author

Tried it again with both ImGuiNative.igGetDrawListSharedData() and ImGui.GetDrawListSharedData() like in your example, but still getting the System.AccessViolationException at the same line.

I created a gist so everyone who want can try it out:
https://gist.github.com/sqrMin1/8ecfecea2513d96c475fa42f3c67b0cb

@mellinoe
Copy link
Collaborator

mellinoe commented Mar 14, 2019

Again, your code doesn't do what I've suggested above (calling ImGuiNative.ImDrawList_ImDrawList(shared))).

I've tested the code below and it works, but it doesn't take care of cleaning up the native memory it allocates. If you want to do this in a real app, you need to be careful about all of the functions that allocate native memory and keep track of them somehow (and free the memory).

private static unsafe ImDrawDataPtr GenerateDrawData()
{
    ImDrawDataPtr drawData = ImDrawData_ImDrawData(); // Allocates native memory
    drawData.DisplayPos = new Vector2(0, 0);
    drawData.DisplaySize = new Vector2(_window.Width, _window.Height);

    IntPtr sharedData = igGetDrawListSharedData();
    ImDrawListPtr drawList = ImDrawList_ImDrawList(sharedData); // Allocates native memory
    IntPtr drawListArray = Marshal.AllocHGlobal(IntPtr.Size); // Allocates native memory
    *(IntPtr*)drawListArray = (IntPtr)drawList.NativePtr;

    if (drawList.CmdBuffer.Size == 0)
        drawList.AddDrawCmd();
    ImFontPtr defaultFont = ImGui.GetIO().Fonts.Fonts[0];
    drawList.PushClipRectFullScreen();
    drawList.PushTextureID(defaultFont.ContainerAtlas.TexID);
    drawList.AddText(defaultFont, 13, new Vector2(10, 200), 0xFFFFFFFF, "Test Standalone ImGui DrawList");
    drawList.PopTextureID();
    drawList.PopClipRect();
    drawList.AddCircle(new Vector2(100, 100), 100, 0xFFFFFFFF, 12, 1.0f);

    drawData.CmdLists = drawListArray;
    drawData.CmdListsCount = 1;
    drawData.TotalIdxCount = drawList.IdxBuffer.Size;
    drawData.TotalVtxCount = drawList.VtxBuffer.Size;
    drawData.Valid = true;

    return drawData;
}

I was able to take the result of that function, and feed it into the demo's existing ImGuiController.RenderDrawData method (after making it public).

@BlizzCrafter
Copy link
Author

Oops... I totally misreadImGuiNative.ImDrawList_ImDrawList(shared)); as ImGuiNative.igGetDrawListSharedData()... sorry!

Your code works perfectly, thanks for showing the correct way of handling a seperate ImDrawList.

I decided to go a different route, but your explanation solved my originally issue and it can be pretty helpful in the future. Maybe for other users as well.

So thanks again for your nice help!

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

2 participants