Skip to content

Commit 4ba2111

Browse files
ABSitfGrantim
andauthored
I6839 fix multi viewport window position (#5448)
* fix search free position for window * fix blink window position * fix and test * update * update * fixes * small fixes, added comments --------- Co-authored-by: Grant Karapetyan <grant.karapetyan@meshinspector.com>
1 parent dd50d73 commit 4ba2111

File tree

4 files changed

+97
-15
lines changed

4 files changed

+97
-15
lines changed

source/MRViewer/ImGuiMenu.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,28 @@ void ImGuiMenu::startFrame()
293293
style.Colors[ImGuiCol_ModalWindowDimBg] = ImVec4( 0.9f, 0.9f, 0.9f, 0.5f );
294294

295295
}
296+
297+
// checking for mouse or keyboard events
298+
// this will start drawing multiple frames without a swapping to render the interface elements without flickering
299+
bool needIncrement = false;
300+
if ( ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable && context_ )
301+
{
302+
if ( !context_->InputEventsQueue.empty() )
303+
{
304+
needIncrement = context_->InputEventsQueue.back().Type == ImGuiInputEventType_MouseButton ||
305+
context_->InputEventsQueue.back().Type == ImGuiInputEventType_MouseWheel ||
306+
context_->InputEventsQueue.back().Type == ImGuiInputEventType_Key;
307+
}
308+
}
309+
296310
ImGui::NewFrame();
297311
UI::getDefaultWindowRectAllocator().invalidateClosedWindows();
312+
313+
if ( needIncrement && context_->MouseViewport != ImGui::GetMainViewport() ) // needIncrement can be true only if ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable && context_
314+
{
315+
// drawing multiple frames without a swapping to render the interface elements without flickering
316+
viewer->incrementForceRedrawFrames( viewer->forceRedrawMinimumIncrementAfterEvents, true );
317+
}
298318
}
299319

300320
void ImGuiMenu::finishFrame()
@@ -323,7 +343,33 @@ void ImGuiMenu::finishFrame()
323343
{
324344
GLFWwindow* backup_current_context = glfwGetCurrentContext();
325345
ImGui::UpdatePlatformWindows();
326-
ImGui::RenderPlatformWindowsDefault();
346+
347+
if ( context_ )
348+
{
349+
for ( int i = 1; i < context_->Viewports.Size; ++i )
350+
{
351+
const auto* vp = context_->Viewports[i];
352+
// if non-main viewport will be deleted in following frames we force redraw of main frame
353+
// to ensure that there is at least one frame when both removed viewport and main viewport renders the window
354+
if ( vp->LastFrameActive < context_->FrameCount )
355+
{
356+
viewer->forceSwapOnFrame();
357+
break;
358+
}
359+
}
360+
361+
if ( viewer->isCurrentFrameSwapping() )
362+
{
363+
ImGui::RenderPlatformWindowsDefault();
364+
365+
// if in swapping frame new viewport appears deffer swapping for main viewport for one frame
366+
// to ensure that there is at least one frame when both new viewport and main viewport renders the window
367+
static int prevViewports = context_->Viewports.Size;
368+
if ( context_->Viewports.Size > prevViewports )
369+
viewer->incrementForceRedrawFrames( 1, true );
370+
prevViewports = context_->Viewports.Size;
371+
}
372+
}
327373
glfwMakeContextCurrent( backup_current_context );
328374
}
329375
}

source/MRViewer/MRUIRectAllocator.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -158,22 +158,50 @@ void WindowRectAllocator::setFreeNextWindowPos( const char* expectedWindowName,
158158

159159
if ( findLocation )
160160
{
161-
// push into application window if it is out
162-
const Vector2f appWindowSize = Vector2f( getViewerInstance().framebufferSize );
163-
const Box2f appWindowBox = Box2f::fromMinAndSize( ImGuiMV::GetMainViewportShift(), appWindowSize );
164161
auto windowBox = Box2f::fromMinAndSize( defaultPos, window->Size );
165-
defaultPos.x = std::clamp( windowBox.min.x, appWindowBox.min.x, std::max( 0.0f, windowBox.min.x + appWindowBox.min.x - ( windowBox.max.x - appWindowBox.max.x ) ) );
166-
defaultPos.y = std::clamp( windowBox.min.y, appWindowBox.min.y, std::max( 0.0f, windowBox.min.y + appWindowBox.min.y - ( windowBox.max.y - appWindowBox.max.y ) ) );
162+
Box2f boundsFixed;
163+
164+
Box2f workBox;
165+
166+
if ( ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
167+
{
168+
const auto& monitors = ImGui::GetPlatformIO().Monitors;
169+
for ( const auto& m : monitors )
170+
{
171+
Box2f mBox = Box2f::fromMinAndSize( m.WorkPos, m.WorkSize );
172+
if ( mBox.intersects( windowBox ) ) // alternative way: calculate window area in current monitor
173+
{
174+
workBox = mBox;
175+
break;
176+
}
177+
}
178+
}
179+
else
180+
{
181+
const Vector2f appWindowSize = Vector2f( getViewerInstance().framebufferSize );
182+
workBox = Box2f::fromMinAndSize( ImGuiMV::GetMainViewportShift(), appWindowSize );
183+
}
184+
defaultPos.x = std::clamp( windowBox.min.x, workBox.min.x, std::max( 0.0f, workBox.max.x - windowBox.size().x ) );
185+
defaultPos.y = std::clamp( windowBox.min.y, workBox.min.y, std::max( 0.0f, workBox.max.y - windowBox.size().y ) );
167186
windowBox = Box2f::fromMinAndSize( defaultPos, window->Size );
168187

169-
// convert viewport bounds from local to window space
170-
Box2f viewportBounds = getViewerInstance().getViewportsBounds();
171-
Box2f boundsFixed = viewportBounds;
172-
boundsFixed.min.y = ImGui::GetIO().DisplaySize.y - boundsFixed.max.y;
173-
boundsFixed.max.y = boundsFixed.min.y + viewportBounds.size().y;
174-
// convert viewport bounds from window to screen space
175-
boundsFixed.min = ImGuiMV::Window2ScreenSpaceVector2f( boundsFixed.min );
176-
boundsFixed.max = ImGuiMV::Window2ScreenSpaceVector2f( boundsFixed.max );
188+
189+
if ( ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
190+
{
191+
boundsFixed = workBox;
192+
}
193+
else
194+
{
195+
// convert viewport bounds from local to window space
196+
Box2f viewportBounds = getViewerInstance().getViewportsBounds();
197+
boundsFixed = viewportBounds;
198+
boundsFixed.min.y = ImGui::GetIO().DisplaySize.y - boundsFixed.max.y;
199+
boundsFixed.max.y = boundsFixed.min.y + viewportBounds.size().y;
200+
// convert viewport bounds from window to screen space
201+
boundsFixed.min = ImGuiMV::Window2ScreenSpaceVector2f( boundsFixed.min );
202+
boundsFixed.max = ImGuiMV::Window2ScreenSpaceVector2f( boundsFixed.max );
203+
}
204+
// push into application window if it is out
177205

178206
auto result = findFreeRect( windowBox, boundsFixed, [&]( Box2f rect, std::function<void( const char*, Box2f )> func )
179207
{

source/MRViewer/MRViewer.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2419,9 +2419,14 @@ void Viewer::incrementForceRedrawFrames( int i /*= 1 */, bool swapOnLastOnly /*=
24192419
forceRedrawFramesWithoutSwap_ = std::max( i, forceRedrawFramesWithoutSwap_ );
24202420
}
24212421

2422+
void Viewer::forceSwapOnFrame( int i /*= 0*/ )
2423+
{
2424+
forceRedrawFramesWithoutSwap_ = std::min( i, forceRedrawFramesWithoutSwap_ );
2425+
}
2426+
24222427
bool Viewer::isCurrentFrameSwapping() const
24232428
{
2424-
return forceRedrawFramesWithoutSwap_ == 0;
2429+
return forceRedrawFramesWithoutSwap_ <= 1;
24252430
}
24262431

24272432
size_t Viewer::getEventsCount( EventType type ) const

source/MRViewer/MRViewer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ class MRVIEWER_CLASS Viewer
266266
// if `swapOnLastOnly` only last forced frame will be present on screen and all previous will not
267267
MRVIEWER_API void incrementForceRedrawFrames( int i = 1, bool swapOnLastOnly = false );
268268

269+
// Forces redraw no later than the specified number of frames
270+
MRVIEWER_API void forceSwapOnFrame( int i = 0 );
271+
269272
// Returns true if current frame will be shown on display
270273
MRVIEWER_API bool isCurrentFrameSwapping() const;
271274

0 commit comments

Comments
 (0)