소스 검색

ENH: Add functions for pausing rendering to ctkVTKAbstractView

Calling pauseRender() increments and resumeRender() de-increments the pause render count.
While the pause render count is greater than 0, the invocation of forceRender() from scheduleRender() calls is prevented.
Useful for temporarily disabling rendering until all elements of the view have been correctly set.
Unpausing will invoke scheduleRender() if scheduleRender() was called while the view was paused.

Also adds a test for pauses and unpausing rendering using a ctkVTKSliceView.
Kyle Sunderland 6 년 전
부모
커밋
3508c05443

+ 2 - 0
Libs/Visualization/VTK/Widgets/Testing/Cpp/CMakeLists.txt

@@ -4,6 +4,7 @@ set(KIT ${PROJECT_NAME})
 # Tests
 #
 set(TEST_SOURCES
+  ctkVTKAbstractViewTest1.cpp
   ctkVTKColorTransferFunctionTest1.cpp
   ctkVTKDataSetArrayComboBoxTest1.cpp
   ctkVTKDataSetModelTest1.cpp
@@ -151,6 +152,7 @@ endif()
 # Add Tests
 #
 
+SIMPLE_TEST( ctkVTKAbstractViewTest1 )
 SIMPLE_TEST( ctkVTKColorTransferFunctionTest1 )
 SIMPLE_TEST( ctkVTKDataSetArrayComboBoxTest1 )
 SIMPLE_TEST( ctkVTKDataSetModelTest1 )

+ 136 - 0
Libs/Visualization/VTK/Widgets/Testing/Cpp/ctkVTKAbstractViewTest1.cpp

@@ -0,0 +1,136 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0.txt
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+// Qt includes
+#include <QApplication>
+#include <QDebug>
+#include <QTimer>
+
+// CTK includes
+#include "ctkCommandLineParser.h"
+#include "ctkVTKSliceView.h"
+#include "ctkVTKRenderView.h"
+#include "ctkCoreTestingMacros.h"
+
+// VTK includes
+#if CTK_USE_QVTKOPENGLWIDGET
+#include <QVTKOpenGLWidget.h>
+#endif
+#include <vtkRenderWindow.h>
+#include <vtkCallbackCommand.h>
+
+unsigned int RenderCount = 0;
+
+//-----------------------------------------------------------------------------
+void onRenderEvent(vtkObject *caller, unsigned long vtkNotUsed(eid), void *clientData, void *vtkNotUsed(callData))
+{
+  ++RenderCount;
+}
+
+//-----------------------------------------------------------------------------
+bool function2(ctkVTKAbstractView* view)
+{
+  view->pauseRender();
+  view->scheduleRender();
+  Sleep(100);
+  view->scheduleRender();
+  view->resumeRender();
+  if (RenderCount != 0)
+    {
+    std::cerr << "function2: Render count " << RenderCount
+              << " does not match expected value of " << 0 << std::endl;
+    }
+  return RenderCount == 0;
+}
+
+//-----------------------------------------------------------------------------
+bool function1(ctkVTKAbstractView* view)
+{
+  RenderCount = 0;
+  view->pauseRender();
+  bool success = function2(view);
+  view->resumeRender();
+  if (RenderCount == 0)
+    {
+    std::cerr << "function1: Render count " << RenderCount
+              << " should be greater than " << 0 << std::endl;
+    success = false;
+    }
+  return success;
+}
+
+//-----------------------------------------------------------------------------
+int ctkVTKAbstractViewTest1(int argc, char * argv [] )
+{
+#if CTK_USE_QVTKOPENGLWIDGET
+    QSurfaceFormat format = QVTKOpenGLWidget::defaultFormat();
+    format.setSamples(0);
+    QSurfaceFormat::setDefaultFormat(format);
+#endif
+
+  QApplication app(argc, argv);
+
+  // Command line parser
+  ctkCommandLineParser parser;
+  parser.addArgument("", "-I", QVariant::Bool);
+  QHash<QString, QVariant> parsedArgs = parser.parseArguments(app.arguments());
+  bool interactive = parsedArgs["-I"].toBool();
+
+  // Instantiate slice view
+  ctkVTKSliceView sliceView;
+  sliceView.setHighlightedBoxColor(QColor(Qt::yellow));
+  sliceView.setCornerAnnotationText("SliceView");
+
+  vtkNew<vtkCallbackCommand> renderEventCallback;
+  renderEventCallback->SetCallback(onRenderEvent);
+  sliceView.renderWindow()->AddObserver(vtkCommand::RenderEvent, renderEventCallback);
+  sliceView.setMaximumUpdateRate(INFINITE);
+  sliceView.show();
+
+  sliceView.scheduleRender();
+  Sleep(100);
+  sliceView.scheduleRender();
+
+  // We expect that the rendering has been triggered at least once
+  CHECK_BOOL(RenderCount == 0, false);
+
+  bool sliceViewWasPaused = sliceView.pauseRender();
+  RenderCount = 0;
+  sliceView.scheduleRender();
+  Sleep(100);
+  sliceView.scheduleRender();
+
+  // We expect that the rendering has not been triggered
+  CHECK_BOOL(RenderCount == 0, true);
+
+  sliceView.resumeRender();
+
+  // We expect that the rendering has been triggered at least once
+  CHECK_BOOL(RenderCount == 0, false);
+
+  // Nested functions that call pauseRender
+  CHECK_BOOL(function1(&sliceView), true);
+
+  if (!interactive)
+    {
+    QTimer::singleShot(200, &app, SLOT(quit()));
+    }
+  return app.exec();
+}

+ 68 - 3
Libs/Visualization/VTK/Widgets/ctkVTKAbstractView.cpp

@@ -60,6 +60,7 @@ ctkVTKAbstractViewPrivate::ctkVTKAbstractViewPrivate(ctkVTKAbstractView& object)
   this->FPSVisible = false;
   this->FPSTimer = 0;
   this->FPS = 0;
+  this->PauseRenderCount = 0;
 }
 
 // --------------------------------------------------------------------------
@@ -82,7 +83,7 @@ void ctkVTKAbstractViewPrivate::init()
   this->RequestTimer = new QTimer(q);
   this->RequestTimer->setSingleShot(true);
   QObject::connect(this->RequestTimer, SIGNAL(timeout()),
-                   q, SLOT(forceRender()));
+                   q, SLOT(requestRender()));
 
   this->FPSTimer = new QTimer(q);
   this->FPSTimer->setInterval(1000);
@@ -194,7 +195,7 @@ void ctkVTKAbstractView::scheduleRender()
     {
     // If the request comes from the system (widget exposed, resized...), the
     // render must be done immediately.
-    this->forceRender();
+    this->requestRender();
     }
   else if (!d->RequestTime.isValid())
     {
@@ -207,11 +208,23 @@ void ctkVTKAbstractView::scheduleRender()
     // have already been elapsed, it is likely that RequestTimer has already
     // timed out, but the event queue hasn't been processed yet, rendering is
     // done now to ensure the desired framerate is respected.
-    this->forceRender();
+    this->requestRender();
     }
 }
 
 //----------------------------------------------------------------------------
+void ctkVTKAbstractView::requestRender()
+{
+  Q_D(const ctkVTKAbstractView);
+
+  if (this->isRenderPaused())
+    {
+    return;
+    }
+  this->forceRender();
+}
+
+//----------------------------------------------------------------------------
 void ctkVTKAbstractView::forceRender()
 {
   Q_D(ctkVTKAbstractView);
@@ -240,6 +253,58 @@ void ctkVTKAbstractView::forceRender()
 }
 
 //----------------------------------------------------------------------------
+bool ctkVTKAbstractView::isRenderPaused()const
+{
+  Q_D(const ctkVTKAbstractView);
+  return d->PauseRenderCount > 0;
+}
+
+//----------------------------------------------------------------------------
+int ctkVTKAbstractView::pauseRender()
+{
+  Q_D(ctkVTKAbstractView);
+  ++d->PauseRenderCount;
+  return d->PauseRenderCount;
+}
+
+//----------------------------------------------------------------------------
+int ctkVTKAbstractView::resumeRender()
+{
+  Q_D(ctkVTKAbstractView);
+  if (d->PauseRenderCount > 0)
+    {
+    --d->PauseRenderCount;
+    }
+  else
+    {
+    qWarning() << Q_FUNC_INFO << "Cannot resume rendering, pause render count is already 0!";
+    }
+
+  // If the rendering is not paused and has been scheduled, call scheduleRender
+  if (!this->isRenderPaused() && d->RequestTimer && d->RequestTime.isValid())
+    {
+    this->scheduleRender();
+    }
+  return d->PauseRenderCount;
+}
+
+//----------------------------------------------------------------------------
+int ctkVTKAbstractView::setRenderPaused(bool pause)
+{
+  Q_D(const ctkVTKAbstractView);
+
+  if (pause)
+    {
+    this->pauseRender();
+    }
+  else
+    {
+    this->resumeRender();
+    }
+  return d->PauseRenderCount;
+}
+
+//----------------------------------------------------------------------------
 CTK_GET_CPP(ctkVTKAbstractView, vtkRenderWindow*, renderWindow, RenderWindow);
 
 //----------------------------------------------------------------------------

+ 35 - 0
Libs/Visualization/VTK/Widgets/ctkVTKAbstractView.h

@@ -76,6 +76,37 @@ public Q_SLOTS:
   /// \sa scheduleRender
   virtual void forceRender();
 
+  /// Calls pauseRender() if pause is true or resumeRender() if pause is false
+  /// When pause render count is greater than 0, prevents requestRender() from calling forceRender()
+  /// Callers are responsible for calling both setPauseRender(true) and setPauseRender(false)
+  /// Ex.
+  /// \code{.cpp}
+  ///  view->pauseRender() // Or setPauseRender(true)
+  /// // Perform operations that may call view->scheduleRender().
+  /// view->resumeRender(); // Or setPauseRender(false)
+  /// \endcode
+  ///
+  /// If the pause render count reaches zero when calling resumeRender(), scheduleRender() will be
+  /// called if a scheduleRender() was invoked while rendering was paused.
+  /// Rendering can still be triggered while the paused with forceRender()
+  /// 
+  /// This behaviour is different from renderEnabled(), which will prevent all rendering calls
+  /// from both scheduleRender() and forceRender(), and will not invoke either when re-enabled.
+  /// \sa renderEnabled
+  virtual int setRenderPaused(bool pause);
+
+  /// Increments the pause render count
+  /// \sa setPauseRender
+  virtual int pauseRender();
+
+  /// De-increments the pause render count and calls scheduleRender() if one is currently pending
+  /// \sa setPauseRender  
+  virtual int resumeRender();
+
+  /// Returns true if the current pause render count is greater than 0
+  /// \sa setPauseRender
+  virtual bool isRenderPaused()const;
+
   /// Set maximum rate for rendering (in frames per second).
   /// If rendering is requested more frequently than this rate using scheduleRender,
   /// actual rendering will happen at this rate.
@@ -195,6 +226,10 @@ protected Q_SLOTS:
   void onRender();
   void updateFPS();
 
+  /// Calls forceRender if the rendering has not been paused from pauseRender()
+  /// \sa pauseRender
+  virtual void requestRender();
+
 protected:
   QScopedPointer<ctkVTKAbstractViewPrivate> d_ptr;
   ctkVTKAbstractView(ctkVTKAbstractViewPrivate* pimpl, QWidget* parent);

+ 1 - 0
Libs/Visualization/VTK/Widgets/ctkVTKAbstractView_p.h

@@ -71,6 +71,7 @@ public:
   QTimer*                                       FPSTimer;
   int                                           FPS;
   static int                                    MultiSamples;
+  int                                           PauseRenderCount;
 
   vtkSmartPointer<vtkCornerAnnotation>          CornerAnnotation;
 };