pkdawson / imgui-godot

Dear ImGui plugin for Godot 4
MIT License
322 stars 19 forks source link

Add widget for Godot viewports #11

Closed BrandonGillis closed 1 year ago

BrandonGillis commented 1 year ago

Hello,

I'm currently using your plugin to create a level editor and I'm currently facing an issue with input processing.

I created a godot viewport to bind the texture to an imgui window, and it works perfectly fine.

Inside that godot viewport I have a meshInstance, with an Area node and a collisionshape, that allow to select the mesh with my mouse by using the signal input_event from godot.

The issue I'm facing is that your imguinode is stopping the input event propagation, to handle it directly with imgui.

I tried to recreate a new custom event that I forward to my viewport (after handling it through imgui), but that input event doesn't get to the collisionshape input_event.

Do you know how I could forward an input from imgui back to the collisionshape input_event?

Thanks in advance for your help.

pkdawson commented 1 year ago

I think I understand the problem, though I don't know what the proper solution is.

Just to confirm, change the line in ImGuiGD.cs here from return consumed; to return false;, and it should just pass through every input event. https://github.com/pkdawson/imgui-godot/blob/master/addons/imgui-godot/ImGuiGD.cs#L260

Is that enough for the viewport to receive the input events you want it to? If not, I probably need some special handling for viewports.

pkdawson commented 1 year ago

Or alternatively, just comment out this line: https://github.com/pkdawson/imgui-godot/blob/22ec3fbe597e278cac49f3baf213fc0cbf49cea2/addons/imgui-godot/ImGuiNode.cs#L54

// GetViewport().SetInputAsHandled();

BrandonGillis commented 1 year ago

Thanks for you fast answer! I already did the change on commenting the line setinputashandled().

Input are propagated correctly by commenting that and if the viewport is inside a viewportContainer. Anyway there's another issue coming up with that. When the viewportContainer receive an input event, it forward it to child node, but for a mouse position it changes it based on the coordinate inside that viewportContainer.

The issue with imgui is that window can be moved around, so the coordinate of the input event are not "recalculated" correctly (it should be relative to the imgui window).

If needed I can provide a test project reproducing the issue to better explain it

pkdawson commented 1 year ago

Yeah it sounds like I need to add something for viewports.

Could you send me a simple project to reproduce this issue? I think you can make a .zip and just attach it to a comment here. That would help me get this done faster.

BrandonGillis commented 1 year ago

Here the example project. ImguiViewportIssue.zip

I created two scenes :

There's some little changed option inside the viewport to make it work :

I already commented the GetViewport().SetInputAsHandled(); to make the "ImguiExample" kinda work.

BrandonGillis commented 1 year ago

Just noticed that I'm using an older version of your plugin as I use godot 3.5. Anyway, the issue should be still present in the latest version

pkdawson commented 1 year ago

I'm focused on Godot 4, so unfortunately I won't be able to work on anything for Godot 3. But I definitely want to support interactive viewports, so thanks for filing the issue.

BrandonGillis commented 1 year ago

So, I finally moved to Godot4 and did some trial and error to finally find a way to forward InputEvent to a viewport. I guess my implementation is not the optimal one and could be improved though.

Inside imGuiGD.cs I added a GetLastInputEvent() method, that allow to recover the latest inputEvent thas has been processed with the ProcessInput method. it looks like this :

    public static InputEvent GetLastInputEvent()
    {
        if (_lastInputEvent != null) {
            InputEvent evt = (InputEvent)_lastInputEvent.Duplicate();
            _lastInputEvent = null;

            return evt;
        }

        return null;
    }

Then, in my editor code I forward the input like this :

    private void onInput()
    {
        Vector2 size = ImGui.GetContentRegionAvail();
        SubViewport viewport = GetNode<SubViewport>("SubViewportContainer/SubViewport");
        SubViewportContainer viewportContainer = GetNode<SubViewportContainer>("SubViewportContainer");
        viewport.Size = new Godot.Vector2i((int)size.X, (int)size.Y);

        InputEvent ev = ImGuiGD.GetLastInputEvent();

        if (ImGui.IsWindowHovered() && ev != null) {
            // forward mouse position down.
            if (ev is InputEventMouseMotion) {
                InputEventMouseMotion mouseMotion = (InputEventMouseMotion)ev;

                Vector2 pos = ImGui.GetCursorScreenPos();
                mouseMotion.Position = new Godot.Vector2(mouseMotion.Position.x - pos.X, mouseMotion.Position.y - pos.Y);
                GD.Print("send relative mousepos : " + mouseMotion.Position);

                // this is how the magic happen, it should be sent like that :')
                viewportContainer.GetViewport().PushUnhandledInput(mouseMotion, true);
            } else {
                viewportContainer.GetViewport().PushUnhandledInput(ev);
            }
        }
    }

Here's a test project with the needed modifications in ÌmguiGD to make it work mapEditor4.zip

pkdawson commented 1 year ago

Thanks for your help! Released in v3.0.0