ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
60.24k stars 10.2k forks source link

Touchscreen Patch for imgui on Nintendo Switch with GLFW and GLESv2 #6870

Closed DKingAlpha closed 1 year ago

DKingAlpha commented 1 year ago

Version/Branch of Dear ImGui:

Version: latest Branch: master

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp with macro IMGUI_IMPL_OPENGL_ES2 defined Compiler: devkitproA64 gcc 13.2.0 Operating System: Target: Nintendo Switch (Atomosphere). Host: Arch Linux Linked Libraries: glfw3;GLESv2;EGL;glapi;drm_nouveau

My Issue:

On Nintendo Switch, default imgui_impl_glfw.cpp with imgui_demo can render demo window correctly, but touching the window will instantly move it out of screen (Pos(-500, -600) for example).

By digging a few more deep into the glfw and imgui mouse event thing, I can confirm that glfw is sending correct MousePos event (by callback), but code in ImGui_ImplGlfw_UpdateMouseData will clear io.MousePos to (0,0), which moves window to ((0,0)-CurPos)

My guess is that glfwGetCursorPos(window, &mouse_x, &mouse_y); will write (0,0) to MousePos event queue.

            if (bd->MouseWindow == nullptr)
            {
                double mouse_x, mouse_y;
                glfwGetCursorPos(window, &mouse_x, &mouse_y);
                bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
                io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
            }

Possible Fix for this issue:

void ImGui_ImplGlfw_NewFrame()

#ifndef __SWITCH__
    ImGui_ImplGlfw_UpdateMouseData();
#endif

This fixed my issue. There can be better solutions.

ocornut commented 1 year ago

Have you installed the glfwSetCursorEnterCallback() ? which is calling ImGui_ImplGlfw_CursorEnterCallback() ? Or it is that your implement of GLFW for Switch never sends this callback?

I suppose we could call bd->MouseWindow = bd->Window in ImGui_ImplGlfw_Init() to cater for esoteric implemention of GLFW which are never honoring the cursor enter/leave callback. Can you test adding this?

DKingAlpha commented 1 year ago

Sorry for the delay. Took a while to upgrade the firmware.

  1. glfw CursorEnterCallback is NEVER called with any value. I don't even know if they have the cursor thing.
  2. setting bd->MouseWindow = bd->Window in ImGui_ImplGlfw_Init() works great!
ocornut commented 1 year ago

Which version of GLFW are you using? It seems like your implementation is not implementing cursor enter/leave callback nor implementing glfwGetCursorPos().

EDIT https://github.com/devkitPro/glfw/blob/switch/src/switch_window.c#L338

ocornut commented 1 year ago

This is a bit frustrating but it looks like some implementation out there are wholly silently incomplete: https://github.com/devkitPro/glfw/blob/switch/src/switch_window.c#L338

I'm suggesting this instead:

// (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
if (bd->MouseWindow == nullptr)
{
    double mouse_x = DBL_MAX, mouse_y = DBL_MAX;
    glfwGetCursorPos(window, &mouse_x, &mouse_y);
    if (mouse_x != DBL_MAX && mouse_y != DBL_MAX) // verify that value has been written to, as some implementation are empty.
    {
        bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
        io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
    }
}

Could you try this too?

DKingAlpha commented 1 year ago

I am using the same glfw library as you posted. switch-glfw package in devkitpro repo instead of official glfw.

Your code wont fix.

https://github.com/devkitPro/glfw/blob/switch/src/input.c#L681

GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
{
    _GLFWwindow* window = (_GLFWwindow*) handle;
    assert(window != NULL);

    if (xpos)
        *xpos = 0;
    if (ypos)
        *ypos = 0;

    _GLFW_REQUIRE_INIT();

    if (window->cursorMode == GLFW_CURSOR_DISABLED)
    {
        if (xpos)
            *xpos = window->virtualCursorPosX;
        if (ypos)
            *ypos = window->virtualCursorPosY;
    }
    else
        _glfwPlatformGetCursorPos(window, xpos, ypos);
}

This explains why we are getting 0 for mouse position.

DKingAlpha commented 1 year ago

glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

This fixed it.

EDIT: I think it's more about switch&glfw instead of imgui. Nothing need to be changed here. Maybe adding it to FAQ can help others.

Thanks for your effort.

ocornut commented 1 year ago

EDIT: I think it's more about switch&glfw instead of imgui. Nothing need to be changed here. Maybe adding it to FAQ can help others.

I think it would be worth pushing that fix to the GLFW fork of devkitpro, probably quite easy to do.

Hopefully this thread can serve as reference to others.