ctkVTKAbstractView.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. =========================================================================*/
  14. // Qt includes
  15. #include <QTimer>
  16. #include <QVBoxLayout>
  17. #include <QDebug>
  18. // CTK includes
  19. #include "ctkVTKAbstractView.h"
  20. #include "ctkVTKAbstractView_p.h"
  21. #include "ctkLogger.h"
  22. // VTK includes
  23. #include <vtkGenericOpenGLRenderWindow.h>
  24. #include <vtkOpenGLRenderWindow.h>
  25. #include <vtkRendererCollection.h>
  26. #include <vtkRenderWindowInteractor.h>
  27. #include <vtkTextProperty.h>
  28. //--------------------------------------------------------------------------
  29. static ctkLogger logger("org.commontk.visualization.vtk.widgets.ctkVTKAbstractView");
  30. //--------------------------------------------------------------------------
  31. int ctkVTKAbstractViewPrivate::MultiSamples = 0; // Default for static var
  32. //--------------------------------------------------------------------------
  33. // --------------------------------------------------------------------------
  34. // ctkVTKAbstractViewPrivate methods
  35. // --------------------------------------------------------------------------
  36. ctkVTKAbstractViewPrivate::ctkVTKAbstractViewPrivate(ctkVTKAbstractView& object)
  37. : q_ptr(&object)
  38. {
  39. #ifdef CTK_USE_QVTKOPENGLWIDGET
  40. this->RenderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  41. #else
  42. this->RenderWindow = vtkSmartPointer<vtkRenderWindow>::New();
  43. #endif
  44. this->CornerAnnotation = vtkSmartPointer<vtkCornerAnnotation>::New();
  45. this->RequestTimer = 0;
  46. this->RenderEnabled = true;
  47. this->MaximumUpdateRate = 60.0;
  48. this->FPSVisible = false;
  49. this->FPSTimer = 0;
  50. this->FPS = 0;
  51. this->PauseRenderCount = 0;
  52. }
  53. // --------------------------------------------------------------------------
  54. void ctkVTKAbstractViewPrivate::init()
  55. {
  56. Q_Q(ctkVTKAbstractView);
  57. this->setParent(q);
  58. this->VTKWidget = new ctkVTKOpenGLNativeWidget;
  59. #ifdef CTK_USE_QVTKOPENGLWIDGET
  60. this->VTKWidget->setEnableHiDPI(true);
  61. QObject::connect(this->VTKWidget, SIGNAL(resized()),
  62. q, SLOT(forceRender()));
  63. #endif
  64. q->setLayout(new QVBoxLayout);
  65. q->layout()->setMargin(0);
  66. q->layout()->setSpacing(0);
  67. q->layout()->addWidget(this->VTKWidget);
  68. this->RequestTimer = new QTimer(q);
  69. this->RequestTimer->setSingleShot(true);
  70. QObject::connect(this->RequestTimer, SIGNAL(timeout()),
  71. q, SLOT(requestRender()));
  72. this->FPSTimer = new QTimer(q);
  73. this->FPSTimer->setInterval(1000);
  74. QObject::connect(this->FPSTimer, SIGNAL(timeout()),
  75. q, SLOT(updateFPS()));
  76. this->setupCornerAnnotation();
  77. this->setupRendering();
  78. // block renders and observe interactor to enforce framerate
  79. q->setInteractor(this->RenderWindow->GetInteractor());
  80. }
  81. // --------------------------------------------------------------------------
  82. void ctkVTKAbstractViewPrivate::setupCornerAnnotation()
  83. {
  84. this->CornerAnnotation->SetMaximumLineHeight(0.07);
  85. vtkTextProperty *tprop = this->CornerAnnotation->GetTextProperty();
  86. tprop->ShadowOn();
  87. this->CornerAnnotation->ClearAllTexts();
  88. }
  89. //---------------------------------------------------------------------------
  90. void ctkVTKAbstractViewPrivate::setupRendering()
  91. {
  92. Q_ASSERT(this->RenderWindow);
  93. this->RenderWindow->SetAlphaBitPlanes(1);
  94. int nSamples = ctkVTKAbstractView::multiSamples();
  95. if (nSamples < 0)
  96. {
  97. nSamples = vtkOpenGLRenderWindow::GetGlobalMaximumNumberOfMultiSamples();
  98. }
  99. this->RenderWindow->SetMultiSamples(nSamples);
  100. this->RenderWindow->StereoCapableWindowOn();
  101. this->VTKWidget->SetRenderWindow(this->RenderWindow);
  102. }
  103. //---------------------------------------------------------------------------
  104. QList<vtkRenderer*> ctkVTKAbstractViewPrivate::renderers()const
  105. {
  106. QList<vtkRenderer*> rendererList;
  107. vtkRendererCollection* rendererCollection = this->RenderWindow->GetRenderers();
  108. vtkCollectionSimpleIterator rendererIterator;
  109. rendererCollection->InitTraversal(rendererIterator);
  110. vtkRenderer *renderer;
  111. while ( (renderer= rendererCollection->GetNextRenderer(rendererIterator)) )
  112. {
  113. rendererList << renderer;
  114. }
  115. return rendererList;
  116. }
  117. //---------------------------------------------------------------------------
  118. vtkRenderer* ctkVTKAbstractViewPrivate::firstRenderer()const
  119. {
  120. return static_cast<vtkRenderer*>(this->RenderWindow->GetRenderers()
  121. ->GetItemAsObject(0));
  122. }
  123. //---------------------------------------------------------------------------
  124. // ctkVTKAbstractView methods
  125. // --------------------------------------------------------------------------
  126. ctkVTKAbstractView::ctkVTKAbstractView(QWidget* parentWidget)
  127. : Superclass(parentWidget)
  128. , d_ptr(new ctkVTKAbstractViewPrivate(*this))
  129. {
  130. Q_D(ctkVTKAbstractView);
  131. d->init();
  132. }
  133. // --------------------------------------------------------------------------
  134. ctkVTKAbstractView::ctkVTKAbstractView(ctkVTKAbstractViewPrivate* pimpl, QWidget* parentWidget)
  135. : Superclass(parentWidget)
  136. , d_ptr(pimpl)
  137. {
  138. // derived classes must call init manually. Calling init() here may results in
  139. // actions on a derived public class not yet finished to be created
  140. }
  141. //----------------------------------------------------------------------------
  142. ctkVTKAbstractView::~ctkVTKAbstractView()
  143. {
  144. }
  145. //----------------------------------------------------------------------------
  146. void ctkVTKAbstractView::scheduleRender()
  147. {
  148. Q_D(ctkVTKAbstractView);
  149. //logger.trace(QString("scheduleRender - RenderEnabled: %1 - Request render elapsed: %2ms").
  150. // arg(d->RenderEnabled ? "true" : "false")
  151. // .arg(d->RequestTime.elapsed()));
  152. if (!d->RenderEnabled)
  153. {
  154. return;
  155. }
  156. double msecsBeforeRender = 0;
  157. // If the MaximumUpdateRate is set to 0 then it indicates that rendering is done next time
  158. // the application is idle.
  159. if (d->MaximumUpdateRate > 0.0)
  160. {
  161. msecsBeforeRender = 1000. / d->MaximumUpdateRate;
  162. }
  163. if(d->VTKWidget->testAttribute(Qt::WA_WState_InPaintEvent))
  164. {
  165. // If the request comes from the system (widget exposed, resized...), the
  166. // render must be done immediately.
  167. this->requestRender();
  168. }
  169. else if (!d->RequestTime.isValid())
  170. {
  171. d->RequestTime.start();
  172. d->RequestTimer->start(static_cast<int>(msecsBeforeRender));
  173. }
  174. else if (d->RequestTime.elapsed() > msecsBeforeRender)
  175. {
  176. // The rendering hasn't still be done, but msecsBeforeRender milliseconds
  177. // have already been elapsed, it is likely that RequestTimer has already
  178. // timed out, but the event queue hasn't been processed yet, rendering is
  179. // done now to ensure the desired framerate is respected.
  180. this->requestRender();
  181. }
  182. }
  183. //----------------------------------------------------------------------------
  184. void ctkVTKAbstractView::requestRender()
  185. {
  186. Q_D(const ctkVTKAbstractView);
  187. if (this->isRenderPaused())
  188. {
  189. return;
  190. }
  191. this->forceRender();
  192. }
  193. //----------------------------------------------------------------------------
  194. void ctkVTKAbstractView::forceRender()
  195. {
  196. Q_D(ctkVTKAbstractView);
  197. if (this->sender() == d->RequestTimer &&
  198. !d->RequestTime.isValid())
  199. {
  200. // The slot associated to the timeout signal is now called, however the
  201. // render has already been executed meanwhile. There is no need to do it
  202. // again.
  203. return;
  204. }
  205. // The timer can be stopped if it hasn't timed out yet.
  206. d->RequestTimer->stop();
  207. d->RequestTime = QTime();
  208. //logger.trace(QString("forceRender - RenderEnabled: %1")
  209. // .arg(d->RenderEnabled ? "true" : "false"));
  210. if (!d->RenderEnabled || !this->isVisible())
  211. {
  212. return;
  213. }
  214. d->RenderWindow->Render();
  215. }
  216. //----------------------------------------------------------------------------
  217. bool ctkVTKAbstractView::isRenderPaused()const
  218. {
  219. Q_D(const ctkVTKAbstractView);
  220. return d->PauseRenderCount > 0;
  221. }
  222. //----------------------------------------------------------------------------
  223. int ctkVTKAbstractView::pauseRender()
  224. {
  225. Q_D(ctkVTKAbstractView);
  226. ++d->PauseRenderCount;
  227. return d->PauseRenderCount;
  228. }
  229. //----------------------------------------------------------------------------
  230. int ctkVTKAbstractView::resumeRender()
  231. {
  232. Q_D(ctkVTKAbstractView);
  233. if (d->PauseRenderCount > 0)
  234. {
  235. --d->PauseRenderCount;
  236. }
  237. else
  238. {
  239. qWarning() << Q_FUNC_INFO << "Cannot resume rendering, pause render count is already 0!";
  240. }
  241. // If the rendering is not paused and has been scheduled, call scheduleRender
  242. if (!this->isRenderPaused() && d->RequestTimer && d->RequestTime.isValid())
  243. {
  244. this->scheduleRender();
  245. }
  246. return d->PauseRenderCount;
  247. }
  248. //----------------------------------------------------------------------------
  249. int ctkVTKAbstractView::setRenderPaused(bool pause)
  250. {
  251. Q_D(const ctkVTKAbstractView);
  252. if (pause)
  253. {
  254. this->pauseRender();
  255. }
  256. else
  257. {
  258. this->resumeRender();
  259. }
  260. return d->PauseRenderCount;
  261. }
  262. //----------------------------------------------------------------------------
  263. CTK_GET_CPP(ctkVTKAbstractView, vtkRenderWindow*, renderWindow, RenderWindow);
  264. //----------------------------------------------------------------------------
  265. void ctkVTKAbstractView::setInteractor(vtkRenderWindowInteractor* newInteractor)
  266. {
  267. Q_D(ctkVTKAbstractView);
  268. d->RenderWindow->SetInteractor(newInteractor);
  269. // Prevent the interactor to call Render() on the render window; only
  270. // scheduleRender() and forceRender() can Render() the window.
  271. // This is done to ensure the desired framerate is respected.
  272. newInteractor->SetEnableRender(false);
  273. qvtkReconnect(d->RenderWindow->GetInteractor(), newInteractor,
  274. vtkCommand::RenderEvent, this, SLOT(scheduleRender()));
  275. }
  276. //----------------------------------------------------------------------------
  277. vtkRenderWindowInteractor* ctkVTKAbstractView::interactor()const
  278. {
  279. Q_D(const ctkVTKAbstractView);
  280. return d->RenderWindow->GetInteractor();
  281. }
  282. //----------------------------------------------------------------------------
  283. vtkInteractorObserver* ctkVTKAbstractView::interactorStyle()const
  284. {
  285. return this->interactor() ?
  286. this->interactor()->GetInteractorStyle() : 0;
  287. }
  288. //----------------------------------------------------------------------------
  289. void ctkVTKAbstractView::setCornerAnnotationText(const QString& text)
  290. {
  291. Q_D(ctkVTKAbstractView);
  292. d->CornerAnnotation->ClearAllTexts();
  293. d->CornerAnnotation->SetText(2, text.toLatin1());
  294. }
  295. //----------------------------------------------------------------------------
  296. QString ctkVTKAbstractView::cornerAnnotationText() const
  297. {
  298. Q_D(const ctkVTKAbstractView);
  299. return QLatin1String(d->CornerAnnotation->GetText(2));
  300. }
  301. //----------------------------------------------------------------------------
  302. vtkCornerAnnotation* ctkVTKAbstractView::cornerAnnotation() const
  303. {
  304. Q_D(const ctkVTKAbstractView);
  305. return d->CornerAnnotation;
  306. }
  307. //----------------------------------------------------------------------------
  308. ctkVTKOpenGLNativeWidget * ctkVTKAbstractView::VTKWidget() const
  309. {
  310. Q_D(const ctkVTKAbstractView);
  311. return d->VTKWidget;
  312. }
  313. //----------------------------------------------------------------------------
  314. CTK_SET_CPP(ctkVTKAbstractView, bool, setRenderEnabled, RenderEnabled);
  315. CTK_GET_CPP(ctkVTKAbstractView, bool, renderEnabled, RenderEnabled);
  316. //----------------------------------------------------------------------------
  317. QSize ctkVTKAbstractView::minimumSizeHint()const
  318. {
  319. // Arbitrary size. 50x50 because smaller seems too small.
  320. return QSize(50, 50);
  321. }
  322. //----------------------------------------------------------------------------
  323. QSize ctkVTKAbstractView::sizeHint()const
  324. {
  325. // Arbitrary size. 300x300 is the default vtkRenderWindow size.
  326. return QSize(300, 300);
  327. }
  328. //----------------------------------------------------------------------------
  329. bool ctkVTKAbstractView::hasHeightForWidth()const
  330. {
  331. return true;
  332. }
  333. //----------------------------------------------------------------------------
  334. int ctkVTKAbstractView::heightForWidth(int width)const
  335. {
  336. // typically VTK render window tend to be square...
  337. return width;
  338. }
  339. //----------------------------------------------------------------------------
  340. void ctkVTKAbstractView::setBackgroundColor(const QColor& newBackgroundColor)
  341. {
  342. Q_D(ctkVTKAbstractView);
  343. double color[3];
  344. color[0] = newBackgroundColor.redF();
  345. color[1] = newBackgroundColor.greenF();
  346. color[2] = newBackgroundColor.blueF();
  347. foreach(vtkRenderer* renderer, d->renderers())
  348. {
  349. renderer->SetBackground(color);
  350. }
  351. }
  352. //----------------------------------------------------------------------------
  353. QColor ctkVTKAbstractView::backgroundColor()const
  354. {
  355. Q_D(const ctkVTKAbstractView);
  356. vtkRenderer* firstRenderer = d->firstRenderer();
  357. return firstRenderer ? QColor::fromRgbF(firstRenderer->GetBackground()[0],
  358. firstRenderer->GetBackground()[1],
  359. firstRenderer->GetBackground()[2])
  360. : QColor();
  361. }
  362. //----------------------------------------------------------------------------
  363. void ctkVTKAbstractView::setBackgroundColor2(const QColor& newBackgroundColor)
  364. {
  365. Q_D(ctkVTKAbstractView);
  366. double color[3];
  367. color[0] = newBackgroundColor.redF();
  368. color[1] = newBackgroundColor.greenF();
  369. color[2] = newBackgroundColor.blueF();
  370. foreach(vtkRenderer* renderer, d->renderers())
  371. {
  372. renderer->SetBackground2(color);
  373. }
  374. }
  375. //----------------------------------------------------------------------------
  376. QColor ctkVTKAbstractView::backgroundColor2()const
  377. {
  378. Q_D(const ctkVTKAbstractView);
  379. vtkRenderer* firstRenderer = d->firstRenderer();
  380. return firstRenderer ? QColor::fromRgbF(firstRenderer->GetBackground2()[0],
  381. firstRenderer->GetBackground2()[1],
  382. firstRenderer->GetBackground2()[2])
  383. : QColor();
  384. }
  385. //----------------------------------------------------------------------------
  386. void ctkVTKAbstractView::setGradientBackground(bool enable)
  387. {
  388. Q_D(ctkVTKAbstractView);
  389. foreach(vtkRenderer* renderer, d->renderers())
  390. {
  391. renderer->SetGradientBackground(enable);
  392. }
  393. }
  394. //----------------------------------------------------------------------------
  395. bool ctkVTKAbstractView::gradientBackground()const
  396. {
  397. Q_D(const ctkVTKAbstractView);
  398. vtkRenderer* firstRenderer = d->firstRenderer();
  399. return firstRenderer ? firstRenderer->GetGradientBackground() : false;
  400. }
  401. //----------------------------------------------------------------------------
  402. void ctkVTKAbstractView::setFPSVisible(bool show)
  403. {
  404. Q_D(ctkVTKAbstractView);
  405. if (d->FPSVisible == show)
  406. {
  407. return;
  408. }
  409. d->FPSVisible = show;
  410. vtkRenderer* renderer = d->firstRenderer();
  411. if (d->FPSVisible)
  412. {
  413. d->FPSTimer->start();
  414. qvtkConnect(renderer,
  415. vtkCommand::EndEvent, this, SLOT(onRender()));
  416. }
  417. else
  418. {
  419. d->FPSTimer->stop();
  420. qvtkDisconnect(renderer,
  421. vtkCommand::EndEvent, this, SLOT(onRender()));
  422. d->CornerAnnotation->SetText(1, "");
  423. }
  424. }
  425. //----------------------------------------------------------------------------
  426. bool ctkVTKAbstractView::isFPSVisible()const
  427. {
  428. Q_D(const ctkVTKAbstractView);
  429. return d->FPSVisible;
  430. }
  431. //----------------------------------------------------------------------------
  432. void ctkVTKAbstractView::onRender()
  433. {
  434. Q_D(ctkVTKAbstractView);
  435. ++d->FPS;
  436. }
  437. //----------------------------------------------------------------------------
  438. void ctkVTKAbstractView::updateFPS()
  439. {
  440. Q_D(ctkVTKAbstractView);
  441. vtkRenderer* renderer = d->firstRenderer();
  442. double lastRenderTime = renderer ? renderer->GetLastRenderTimeInSeconds() : 0.;
  443. QString fpsString = tr("FPS: %1(%2s)").arg(d->FPS).arg(lastRenderTime);
  444. d->FPS = 0;
  445. d->CornerAnnotation->SetText(1, fpsString.toLatin1());
  446. }
  447. //----------------------------------------------------------------------------
  448. bool ctkVTKAbstractView::useDepthPeeling()const
  449. {
  450. Q_D(const ctkVTKAbstractView);
  451. vtkRenderer* renderer = d->firstRenderer();
  452. return renderer ? static_cast<bool>(renderer->GetUseDepthPeeling()):0;
  453. }
  454. //----------------------------------------------------------------------------
  455. void ctkVTKAbstractView::setUseDepthPeeling(bool useDepthPeeling)
  456. {
  457. Q_D(ctkVTKAbstractView);
  458. vtkRenderer* renderer = d->firstRenderer();
  459. if (!renderer)
  460. {
  461. return;
  462. }
  463. this->renderWindow()->SetAlphaBitPlanes( useDepthPeeling ? 1 : 0);
  464. int nSamples = ctkVTKAbstractView::multiSamples();
  465. if (nSamples < 0)
  466. {
  467. nSamples = vtkOpenGLRenderWindow::GetGlobalMaximumNumberOfMultiSamples();
  468. }
  469. this->renderWindow()->SetMultiSamples(useDepthPeeling ? 0 : nSamples);
  470. renderer->SetUseDepthPeeling(useDepthPeeling ? 1 : 0);
  471. #ifdef CTK_USE_QVTKOPENGLWIDGET
  472. renderer->SetUseDepthPeelingForVolumes(useDepthPeeling);
  473. #endif
  474. }
  475. //----------------------------------------------------------------------------
  476. int ctkVTKAbstractView::multiSamples()
  477. {
  478. return ctkVTKAbstractViewPrivate::MultiSamples;
  479. }
  480. //----------------------------------------------------------------------------
  481. void ctkVTKAbstractView::setMultiSamples(int number)
  482. {
  483. ctkVTKAbstractViewPrivate::MultiSamples = number;
  484. }
  485. //----------------------------------------------------------------------------
  486. double ctkVTKAbstractView::maximumUpdateRate()const
  487. {
  488. Q_D(const ctkVTKAbstractView);
  489. return d->MaximumUpdateRate;
  490. }
  491. //----------------------------------------------------------------------------
  492. void ctkVTKAbstractView::setMaximumUpdateRate(double fps)
  493. {
  494. Q_D(ctkVTKAbstractView);
  495. d->MaximumUpdateRate = fps;
  496. }