Thu, 12/08/2022 - 21:46
I am expanding a GLFW example with some code to work with Dear ImGui.
My main subroutine looks like this:
void GlfwOcctView::run() { initWindow (800, 600, "glfw occt"); initViewer(); initDemoScene(); if (myView.IsNull()) { return; } myView->MustBeResized(); myOcctWindow->Map(); initUI(); mainloop(); cleanupUI(); cleanup(); }
cleanupUI() was taken from Dear ImGui repo
Here are ImGUI-related routines:
void GlfwOcctView::initUI() { // Setup Dear ImGui context const char* glsl_version = "#version 330"; IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); // Setup Platform/Renderer bindings ImGui_ImplGlfw_InitForOpenGL(myOcctWindow->getGlfwWindow(), true); ImGui_ImplOpenGL3_Init(glsl_version); // Setup Dear ImGui style ImGui::StyleColorsDark(); } void GlfwOcctView::processUI() { // feed inputs to dear imgui, start new frame ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ImGui::Begin("STEP files"); ImGui::Button("Add File"); ImGui::SameLine(); ImGui::Button("Clear List"); //ImGui::ListBox("Files",¤tItem,listboxItems,currentItemsCount,10); ImGui::End(); // Rendering ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } void GlfwOcctView::cleanupUI() { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); }
GlfwOcctView::processUI() is called from mainloop(). Now here is the problem:
I define mainloop() like this:
void GlfwOcctView::mainloop() { while (!glfwWindowShouldClose (myOcctWindow->getGlfwWindow())) { // glfwPollEvents() for continuous rendering (immediate return if there are no new events) // and glfwWaitEvents() for rendering on demand (something actually happened in the viewer) //glfwPollEvents(); glfwWaitEvents(); if (!myView.IsNull()) { processUI(); glfwSwapBuffers(myOcctWindow->getGlfwWindow()); //FlushViewEvents(myContext, myView, true); } } }
I mean, if I use glfwSwapBuffers(myOcctWindow->getGlfwWindow());
, then my scene becomes unresponsible, but my Dear Imgui window shows and can be controlled
If I use FlushViewEvents(myContext, myView, true);
then my Dear Imgui window is not showing at all, but scene is responsible.
If I have both these lines, glfwSwapBuffers and FlushViewEvents then my Dear ImGui window and scene shows, but with graphical artifacts - flickering heavily, Dear ImGui window not redrawing properly when it covers a scene.
So, the question is: How do I use Dear Imgui with Opencascade, in glfw window? I'd like to base my code on an example, since it has good design
Fri, 12/09/2022 - 17:51
Let's start from architectural point of view:
Here you may notice that as OCCT takes responsibility to wrap graphic driver, logically it is expected that somebody should write ImGUI renderer plugin on top of OCCT abstraction layer (e.g. creating Graphic3d primitive arrays, AIS objects and so on instead of using OpenGL directly). In this way, one could use such plugin for ImGUI naturally on different platforms supported by OCCT (and potentially using new Graphic3d_GraphicDriver implementations using other graphic APIs). The same might be considered for wrapping window events through OCCT as well (e.g. implementing some ImGUI driver for AIS_ViewController / Aspect_WindowInputListener instead of ImGui_ImplGlfw_InitForOpenGL).
That is what one would expect taking a look at ImGUI and OCCT design... But from the other point of view, that would require a plenty of work (probably several weeks). To avoid this, we may consider more limited alternative approaches - like using existing OpenGL3 renderer implementation coming with ImGUI. For that, however, one should understand basics how to embed another OpenGL into OCCT renderer. There are two basic approaches:
In both cases you might need to carefully prepare / restore global OpenGL state before / after ImGUI OpenGL renderer to not corrupt OCCT rendering / ensure ImGUI rendering.
Less intrusive approach could be achieved by hacks like OpenGl_Caps::buffersNoSwap=true so that you could call glfwSwapBuffers() manually after FlushViewEvents() (or probably better - within overridden AIS_ViewController::handleViewRedraw()) and before ImGUI rendering code.
Sun, 12/11/2022 - 17:33
Thanks a lot, it worked.
In initViewer() I added this call:
And then I changed mainloop() as advised:
There is a little problem though: when moving ImGui window, my scene reacts too on moves. It's worth investigating too
Mon, 12/12/2022 - 18:58
This link may be useful:
https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear-imgui-or-my-application
It is handled by Dear ImGui
I changed event handlers in GlfwOcctView.h
Note the statement toView(theWin)->myView->Redraw(); It is needed to manually redraw View if we do something with ImGui window
Tue, 12/13/2022 - 23:51
I was going to suggest using Imgui::IsItemHovered() to detect if the mouse was interacting with the ui but this is a much better solution
Wed, 12/14/2022 - 06:44
I noticed that due to the buffer swapping hack, the screen starts flickering after zooming with the mouse scroll. Are you experiencing this in your program too
Mon, 07/10/2023 - 17:49
Yes, it’s the same on my side. After the rotation, it shakes and the cursor moves just fine. I’m trying to solve it. Did you solve the problem?
Mon, 07/10/2023 - 17:50
Yes, it’s the same on my side. After the rotation, it shakes and the cursor moves just fine. I’m trying to solve it. Did you solve the problem?
Tue, 07/11/2023 - 17:10
When you use glfwWaitEvents(), there is no problem.
Thu, 01/04/2024 - 11:21
I notice onece remove viewer gird code, the screen will flickering,
aViewer->ActivateGrid(Aspect_GT_Rectangular, Aspect_GDM_Lines);
Has anyone encountered the same problem?