From bd680b34b58c8bf6dee8e7e1895108764f5a49a5 Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 7 Oct 2024 18:49:01 +0100 Subject: [PATCH] Win32 interactive resizing proof-of-concept Basically works by setting up a callback to draw a new frame which we do when the WM_PAINT event arrives, which is how Windows tries to tell us it's time to redraw the window due to a resize etc. Unlike the WM_SIZE event, it only happens when we've consumed the whole message queue, so it should be pretty similar to the regular situation where a frame happens after `pollEvents` is called. This approach is necessary in the first place because Win32 window messages can be reentrant, so the handler for one event, like a click on the corner of a window, can in turn fire a series of extra messages for the drag and resizes and release, without first returning. --- include/vsg/app/Viewer.h | 3 +++ include/vsg/app/Window.h | 2 ++ src/vsg/app/Viewer.cpp | 25 +++++++++++++++++++++++++ src/vsg/platform/win32/Win32_Window.cpp | 2 ++ 4 files changed, 32 insertions(+) diff --git a/include/vsg/app/Viewer.h b/include/vsg/app/Viewer.h index 880f0ee5c6..145e6e074f 100644 --- a/include/vsg/app/Viewer.h +++ b/include/vsg/app/Viewer.h @@ -101,6 +101,9 @@ namespace vsg /// If still active, poll for pending events and place them in the Events list and advance to the next frame, generate updated FrameStamp to signify the advancement to a new frame and return true. virtual bool advanceToNextFrame(double simulationTime = UseTimeSinceStartPoint); + virtual bool advanceToNextFramePhaseOne(); + virtual bool advanceToNextFramePhaseTwo(double simulationTime = UseTimeSinceStartPoint); + /// pass the Events into any registered EventHandlers virtual void handleEvents(); diff --git a/include/vsg/app/Window.h b/include/vsg/app/Window.h index d1b475d251..e89f478c17 100644 --- a/include/vsg/app/Window.h +++ b/include/vsg/app/Window.h @@ -58,6 +58,8 @@ namespace vsg virtual void resize() {} + std::function resizeCallback = {}; + ref_ptr traits() { return _traits; } const ref_ptr traits() const { return _traits; } diff --git a/src/vsg/app/Viewer.cpp b/src/vsg/app/Viewer.cpp index d15ce5dba1..3dceb0e239 100644 --- a/src/vsg/app/Viewer.cpp +++ b/src/vsg/app/Viewer.cpp @@ -79,6 +79,14 @@ void Viewer::addWindow(ref_ptr window) if (itr != _windows.end()) return; _windows.push_back(window); + + window->resizeCallback = [this]() { + advanceToNextFramePhaseTwo(); + handleEvents(); + update(); + recordAndSubmit(); + present(); + }; } void Viewer::removeWindow(ref_ptr window) @@ -88,6 +96,8 @@ void Viewer::removeWindow(ref_ptr window) _windows.erase(itr); + window->resizeCallback = nullptr; + // create a new list of CommandGraphs not associated with removed window CommandGraphs commandGraphs; for (const auto& task : recordAndSubmitTasks) @@ -153,6 +163,14 @@ bool Viewer::pollEvents(bool discardPreviousEvents) } bool Viewer::advanceToNextFrame(double simulationTime) +{ + if (!advanceToNextFramePhaseOne()) + return false; + + return advanceToNextFramePhaseTwo(simulationTime); +} + +bool vsg::Viewer::advanceToNextFramePhaseOne() { static constexpr SourceLocation s_frame_source_location{"Viewer advanceToNextFrame", VsgFunctionName, __FILE__, __LINE__, COLOR_VIEWER, 1}; @@ -167,6 +185,13 @@ bool Viewer::advanceToNextFrame(double simulationTime) // poll all the windows for events. pollEvents(true); + return true; +} + +bool vsg::Viewer::advanceToNextFramePhaseTwo(double simulationTime) +{ + static constexpr SourceLocation s_frame_source_location{"Viewer advanceToNextFrame", VsgFunctionName, __FILE__, __LINE__, COLOR_VIEWER, 1}; + if (!acquireNextFrame()) return false; // create FrameStamp for frame diff --git a/src/vsg/platform/win32/Win32_Window.cpp b/src/vsg/platform/win32/Win32_Window.cpp index fe1a05248e..4a7081c3f3 100644 --- a/src/vsg/platform/win32/Win32_Window.cpp +++ b/src/vsg/platform/win32/Win32_Window.cpp @@ -610,6 +610,8 @@ bool Win32_Window::handleWin32Messages(UINT msg, WPARAM wParam, LPARAM lParam) _windowMapped = false; return true; case WM_PAINT: + if (resizeCallback) + resizeCallback(); ValidateRect(_window, NULL); return true; case WM_MOUSEMOVE: {