ocornut / imgui

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

How to properly render dearimgui editors on multi viewports/render textures with input. #6729

Open DeltaXero opened 1 year ago

DeltaXero commented 1 year ago

Version/Branch of Dear ImGui:

Version: 1.89.8 Branch: (docking)

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp Compiler: MSVC Operating System: Windows

How to properly render dearimgui editors on multi viewports/render textures with input?

Hello, I'm trying to integrate dearimgui into my multi appwindow setup. i use the first window that i instantiate as my openGL context for drawing for each camera view. and for every camera view the scene is rendered into a fbo render texture. and these view textures are then displayed on multiple windows as required on their window openGL contexts. now i want to render editors in this setup with dearimgui for each camera there'd be different editors attached and they'd be rendered right along with the camera's scene capture. and onto that camera's fbo texture. and i do have this working visually but none of the editors respond to my mouse input if i have different editors and some shared editors on each camera. and also even if the input works, it only works on my first window. i can only interact with the editors on one window. and i've tried setting the Input for the imgui context during each camera pass with the corresponding window's input. but they're not working out. can someone please point me in the right direction as to how i can get this working? also i think we can use RenderTextures on dearimgui windows instead of rendering dearimgui as part of each RenderTexture. but my current approach is a bit more general setup i think and i'd like to proceed in this direction. here's a code example below of what im doing and trying to have.

ProxyWindow window[2];
window[0] = ProxyCreateWindow("main",glfw);
window[1] = ProxyCreateWindow("other",glfw);

Camera camera[2];
camera[0].SetPos(3,3,3);
camera[0].LookAt(0);
camera[1].SetPos(-3,-3,-3);
camera[1].LookAt(0);

FBO fbo[2];
for(auto i=0;i<2;i++){
    fbo[i].SetupTexture();
    fbo[i].Setup();
}

while(App::run){
    window[0].SetContext();
    for(auto i=0;i<2;i++){
        ProxyWindow::running = &window[i];
        RenderContext::renderDimensions = window[i].GetDimensions();
        InputSystem::input = &window[i].input;
        fbo[i].renderSize = window[i].size;
        fbo[i].Bind();//binds rt texture.
        camera[i].UseCurrentCamera();
        camera[i].RenderView(scene);
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        InterceptAttempt();
        //how to tell ImGui to use Window[index] input and dimentions?
        ImGui::NewFrame();
        camera[i].RenderAttachedEditors();
        ImGui::ShowDemoWindow();
        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
        camera[i].DiscardCurrentCamera();
        fbo[i].UnBind();
    }
    for(auto i=0;i<2;i++){
        ProxyWindow::running = &window[i];
        window[i].SetContext();
        DisplayTextureInWindow(fbo[i].texture);
        window[i].poolEvents();
    }
}
void InterceptAttempt(){
    ImGuiIO& io = ImGui::GetIO();
    auto& window = ProxyWindow::running.As<GLFWindow>();
    double mouse_x=0,mouse_y=0;
    glfwGetCursorPos(window.handle,&mouse_x,&mouse_y);
    int window_x,window_y;
    glfwGetWindowPos(window.handle,&window_x,&window_y);
    int display_w,display_h;
    glfwGetFramebufferSize(window.handle,&display_w,&display_h);
    auto windowSize = window.GetSize();
    const bool focused = glfwGetWindowAttrib(window.handle,GLFW_FOCUSED) != 0;
    //const ImVec2 mouse_pos_prev = io.MousePos;
    io.DisplaySize = ImVec2(windowSize.x(),windowSize.y());
    io.DisplayFramebufferScale = ImVec2((float)display_w/windowSize.x(),(float)display_h/windowSize.y());
    ///io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX);
    //io.MouseHoveredViewport = 0;
    //if(focused){
        for(int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++){
            io.MouseDown[i] = glfwGetMouseButton(window.handle,i) != 0;
            //io.MouseDown[i] = Input::GetCurrent().OnKeyEnter(i);//my API
            //io.MouseClicked[i] = GetCurrent().OnKeyEnter(i);//my API
        }
        //if(io.WantSetMousePos){glfwSetCursorPos(glfWindow.handle,(double)(mouse_pos_prev.x - glfWindow.GetPosition().x()), (double)(mouse_pos_prev.y - glfWindow.GetPosition().y()));}
    //}
    //io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y);
    io.MousePos = ImVec2((float)mouse_x,(float)mouse_y);
/*#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
        const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
#if GLFW_HAS_MOUSE_PASSTHROUGH
        glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
#endif
        if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input)
            io.MouseHoveredViewport = viewport->ID;
#endif
}
DeltaXero commented 1 year ago

also after some more tests input fully stops working if i have different editors for each camera in the mix. but if i render the same editors(imgui windows with some buttons etc) for every camera. i can control these editors with input on any window, with some window drag offset issues. but still i really need different editors on different app windows.