ViewerTest_EventManager::handleViewRedraw() now starts ViewerTest_ContinuousRedrawer
working thread to workaround Tcl event loop invalidation issue.
ViewerTest_AutoUpdater.hxx
ViewerTest_CmdParser.cxx
ViewerTest_CmdParser.hxx
+ViewerTest_ContinuousRedrawer.cxx
+ViewerTest_ContinuousRedrawer.hxx
ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx
ViewerTest_DoubleMapOfInteractiveAndName.hxx
ViewerTest_EventManager.cxx
--- /dev/null
+// Copyright (c) 2019-2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <ViewerTest_ContinuousRedrawer.hxx>
+
+#include <Aspect_DisplayConnection.hxx>
+#include <Aspect_Window.hxx>
+#include <OSD.hxx>
+#include <OSD_Timer.hxx>
+
+// =======================================================================
+// function : Instance
+// purpose :
+// =======================================================================
+ViewerTest_ContinuousRedrawer& ViewerTest_ContinuousRedrawer::Instance()
+{
+ static ViewerTest_ContinuousRedrawer aRedrawer;
+ return aRedrawer;
+}
+
+// =======================================================================
+// function : ViewerTest_ContinuousRedrawer
+// purpose :
+// =======================================================================
+ViewerTest_ContinuousRedrawer::ViewerTest_ContinuousRedrawer()
+: myThread (doThreadWrapper),
+ myWakeEvent (false),
+ myTargetFps (0.0),
+ myToStop (false),
+ myToPause (false)
+{
+ //
+}
+
+// =======================================================================
+// function : ~ViewerTest_ContinuousRedrawer
+// purpose :
+// =======================================================================
+ViewerTest_ContinuousRedrawer::~ViewerTest_ContinuousRedrawer()
+{
+ Stop();
+}
+
+// =======================================================================
+// function : Start
+// purpose :
+// =======================================================================
+void ViewerTest_ContinuousRedrawer::Start (const Handle(Aspect_Window)& theWindow,
+ Standard_Real theTargetFps)
+{
+ if (myWindow != theWindow
+ || myTargetFps != theTargetFps)
+ {
+ Stop();
+ myWindow = theWindow;
+ myTargetFps = theTargetFps;
+ }
+
+ if (myThread.GetId() == 0)
+ {
+ myToStop = false;
+ myToPause = false;
+ myThread.Run (this);
+ }
+ else
+ {
+ {
+ Standard_Mutex::Sentry aLock (myMutex);
+ myToStop = false;
+ myToPause = false;
+ }
+ myWakeEvent.Set();
+ }
+}
+
+// =======================================================================
+// function : Start
+// purpose :
+// =======================================================================
+void ViewerTest_ContinuousRedrawer::Stop (const Handle(Aspect_Window)& theWindow)
+{
+ if (!theWindow.IsNull()
+ && myWindow != theWindow)
+ {
+ return;
+ }
+
+ {
+ Standard_Mutex::Sentry aLock (myMutex);
+ myToStop = true;
+ myToPause = false;
+ }
+ myWakeEvent.Set();
+ myThread.Wait();
+ myToStop = false;
+ myWindow.Nullify();
+}
+
+// =======================================================================
+// function : doThreadLoop
+// purpose :
+// =======================================================================
+void ViewerTest_ContinuousRedrawer::Pause()
+{
+ if (!myToPause)
+ {
+ Standard_Mutex::Sentry aLock (myMutex);
+ myToPause = true;
+ }
+}
+
+// =======================================================================
+// function : doThreadLoop
+// purpose :
+// =======================================================================
+void ViewerTest_ContinuousRedrawer::doThreadLoop()
+{
+ Handle(Aspect_DisplayConnection) aDisp = new Aspect_DisplayConnection();
+ OSD_Timer aTimer;
+ aTimer.Start();
+ Standard_Real aTimeOld = 0.0;
+ const Standard_Real aTargetDur = myTargetFps > 0.0 ? 1.0 / myTargetFps : -1.0;
+ for (;;)
+ {
+ bool toPause = false;
+ {
+ Standard_Mutex::Sentry aLock (myMutex);
+ if (myToStop)
+ {
+ return;
+ }
+ toPause = myToPause;
+ }
+ if (toPause)
+ {
+ myWakeEvent.Wait();
+ myWakeEvent.Reset();
+ }
+
+ if (myTargetFps > 0.0)
+ {
+ const Standard_Real aTimeNew = aTimer.ElapsedTime();
+ const Standard_Real aDuration = aTimeNew - aTimeOld;
+ if (aDuration >= aTargetDur)
+ {
+ myWindow->InvalidateContent (aDisp);
+ aTimeOld = aTimeNew;
+ }
+ }
+ else
+ {
+ myWindow->InvalidateContent (aDisp);
+ }
+
+ OSD::MilliSecSleep (1);
+ }
+}
--- /dev/null
+// Copyright (c) 2019-2020 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _ViewerTest_ContinuousRedrawer_HeaderFile
+#define _ViewerTest_ContinuousRedrawer_HeaderFile
+
+#include <OSD_Thread.hxx>
+#include <Standard_Condition.hxx>
+#include <Standard_Mutex.hxx>
+#include <Standard_Type.hxx>
+
+class Aspect_Window;
+
+//! Auxiliary tool performing continuous redraws of specified window.
+//! Tool creates an extra working thread pushing content invalidation messages to specific window using Aspect_Window::InvalidateContent() method.
+//! Normally, GUI application should done continuous rendering in simple fashion - just by drawing next frame without waiting for new events from windowing system;
+//! however, implementation of this approach is problematic in context of ViewerTest due to message loop binding mechanism implied by Tcl/Tk.
+class ViewerTest_ContinuousRedrawer
+{
+public:
+ //! Return global instance.
+ Standard_EXPORT static ViewerTest_ContinuousRedrawer& Instance();
+public:
+
+ //! Destructor.
+ Standard_EXPORT ~ViewerTest_ContinuousRedrawer();
+
+ //! Return TRUE if redrawer thread is started.
+ bool IsStarted() const { return myThread.GetId() != 0; }
+
+ //! Start thread.
+ Standard_EXPORT void Start (const Handle(Aspect_Window)& theWindow,
+ Standard_Real theTargetFps);
+
+ //! Stop thread.
+ Standard_EXPORT void Stop (const Handle(Aspect_Window)& theWindow = NULL);
+
+ //! Return TRUE if redrawer thread is in paused state.
+ bool IsPaused() const { return myToPause; }
+
+ //! Pause working thread, but does not terminate it.
+ Standard_EXPORT void Pause();
+
+private:
+
+ //! Thread loop.
+ void doThreadLoop();
+
+ //! Thread creation callback.
+ static Standard_Address doThreadWrapper (Standard_Address theData)
+ {
+ ViewerTest_ContinuousRedrawer* aThis = (ViewerTest_ContinuousRedrawer* )theData;
+ aThis->doThreadLoop();
+ return 0;
+ }
+
+ //! Empty constructor.
+ ViewerTest_ContinuousRedrawer();
+
+private:
+ Handle(Aspect_Window) myWindow; //!< window to invalidate
+ OSD_Thread myThread; //!< working thread
+ Standard_Mutex myMutex; //!< mutex for accessing common variables
+ Standard_Condition myWakeEvent; //!< event to wake up working thread
+ Standard_Real myTargetFps; //!< desired update framerate
+ volatile bool myToStop; //!< flag to stop working thread
+ volatile bool myToPause; //!< flag to put working thread asleep without stopping
+};
+
+#endif // _ViewerTest_ContinuousRedrawer_HeaderFile
#include <AIS_Shape.hxx>
#include <Aspect_Grid.hxx>
#include <Draw.hxx>
+#include <ViewerTest_ContinuousRedrawer.hxx>
#include <ViewerTest_V3dView.hxx>
Standard_IMPORT Standard_Boolean Draw_Interprete (const char* theCommand);
const Handle(AIS_InteractiveContext)& theCtx)
: myCtx (theCtx),
myView (theView),
- myToPickPnt (Standard_False)
+ myToPickPnt (Standard_False),
+ myIsTmpContRedraw (Standard_False)
{
myViewAnimation = GlobalViewAnimation();
}
}
}
+//==============================================================================
+//function : handleViewRedraw
+//purpose :
+//==============================================================================
+void ViewerTest_EventManager::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
+ const Handle(V3d_View)& theView)
+{
+ AIS_ViewController::handleViewRedraw (theCtx, theView);
+
+ // On non-Windows platforms Aspect_Window::InvalidateContent() from rendering thread does not work as expected
+ // as in Tcl event loop the new message might go to sleep with new event remaining in queue.
+ // As a workaround - use dedicated background thread to ping Tcl event loop.
+ if (myToAskNextFrame)
+ {
+ ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+ if (!myIsTmpContRedraw
+ && (!aRedrawer.IsStarted() || aRedrawer.IsPaused()))
+ {
+ myIsTmpContRedraw = true;
+ #ifndef _WIN32
+ aRedrawer.Start (theView->Window(), 60.0);
+ #endif
+ }
+ }
+ else if (myIsTmpContRedraw)
+ {
+ myIsTmpContRedraw = false;
+ #ifndef _WIN32
+ ViewerTest_ContinuousRedrawer& aRedrawer = ViewerTest_ContinuousRedrawer::Instance();
+ aRedrawer.Pause();
+ #endif
+ }
+}
+
//==============================================================================
//function : ProcessConfigure
//purpose :
//! Redraw the View on an Expose Event
Standard_EXPORT virtual void ProcessExpose();
+ //! Handle redraw.
+ Standard_EXPORT virtual void handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
+ const Handle(V3d_View)& theView) Standard_OVERRIDE;
+
//! Resize View.
Standard_EXPORT virtual void ProcessConfigure();
TCollection_AsciiString myPickPntArgVec[3];
Standard_Boolean myToPickPnt;
+ Standard_Boolean myIsTmpContRedraw;
};
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_MapOfAsciiString.hxx>
#include <ViewerTest_AutoUpdater.hxx>
+#include <ViewerTest_ContinuousRedrawer.hxx>
#include <ViewerTest_EventManager.hxx>
#include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
#include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
return ViewerTest_myViews.Find2( ViewerTest::CurrentView());
}
-//! Auxiliary tool performing continuous redraws of specified window.
-class ViewerTest_ContinuousRedrawer
-{
-public:
- //! Return global instance.
- static ViewerTest_ContinuousRedrawer& Instance()
- {
- static ViewerTest_ContinuousRedrawer aRedrawer;
- return aRedrawer;
- }
-public:
-
- //! Destructor.
- ~ViewerTest_ContinuousRedrawer()
- {
- Stop();
- }
-
- //! Start thread.
- void Start (const Handle(Aspect_Window)& theWindow,
- Standard_Real theTargetFps)
- {
- if (myWindow != theWindow
- || myTargetFps != theTargetFps)
- {
- Stop();
- myWindow = theWindow;
- myTargetFps = theTargetFps;
- }
- if (myThread.GetId() == 0)
- {
- myToStop = false;
- myThread.Run (this);
- }
- }
-
- //! Stop thread.
- void Stop (const Handle(Aspect_Window)& theWindow = NULL)
- {
- if (!theWindow.IsNull()
- && myWindow != theWindow)
- {
- return;
- }
-
- {
- Standard_Mutex::Sentry aLock (myMutex);
- myToStop = true;
- }
- myThread.Wait();
- myToStop = false;
- myWindow.Nullify();
- }
-
-private:
-
- //! Thread loop.
- void doThreadLoop()
- {
- Handle(Aspect_DisplayConnection) aDisp = new Aspect_DisplayConnection();
- OSD_Timer aTimer;
- aTimer.Start();
- Standard_Real aTimeOld = 0.0;
- const Standard_Real aTargetDur = myTargetFps > 0.0 ? 1.0 / myTargetFps : -1.0;
- for (;;)
- {
- {
- Standard_Mutex::Sentry aLock (myMutex);
- if (myToStop)
- {
- return;
- }
- }
- if (myTargetFps > 0.0)
- {
- const Standard_Real aTimeNew = aTimer.ElapsedTime();
- const Standard_Real aDuration = aTimeNew - aTimeOld;
- if (aDuration >= aTargetDur)
- {
- myWindow->InvalidateContent (aDisp);
- aTimeOld = aTimeNew;
- }
- }
- else
- {
- myWindow->InvalidateContent (aDisp);
- }
-
- OSD::MilliSecSleep (1);
- }
- }
-
- //! Thread creation callback.
- static Standard_Address doThreadWrapper (Standard_Address theData)
- {
- ViewerTest_ContinuousRedrawer* aThis = (ViewerTest_ContinuousRedrawer* )theData;
- aThis->doThreadLoop();
- return 0;
- }
-
- //! Empty constructor.
- ViewerTest_ContinuousRedrawer()
- : myThread (doThreadWrapper),
- myTargetFps (0.0),
- myToStop (false) {}
-
-private:
- Handle(Aspect_Window) myWindow;
- OSD_Thread myThread;
- Standard_Mutex myMutex;
- Standard_Real myTargetFps;
- volatile bool myToStop;
-};
-
//==============================================================================
//function : ViewerInit
//purpose : Create the window viewer and initialize all the global variable