1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: QQuickVTKRenderItem.h 5 6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 7 All rights reserved. 8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details. 9 10 This software is distributed WITHOUT ANY WARRANTY; without even 11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 12 PURPOSE. See the above copyright notice for more information. 13 14 =========================================================================*/ 15 /** 16 * @class QQuickVTKRenderItem 17 * @brief [QQuickItem] subclass to render a VTK scene in a QtQuick/QML application. 18 * 19 * QQuickVTKRenderItem extends [QQuickItem] so that a VTK visualization pipeline can be rendererd 20 * within the rect of the item. 21 * 22 * This item is exported to the QML layer via the QQmlVTKPlugin under the module VTK. It is 23 * registered as a type \b VTKRenderItem. The QQuickVTKRenderItem manages a vtkRenderer internally 24 * that is rendered as a viewport inside the render window provided by QQuickVTKRenderWindow. 25 * 26 * Typical usage for QQuickVTKRenderItem in a Qml application is as follows: 27 * 28 * @code 29 * // import related modules 30 * import QtQuick 2.15 31 * import QtQuick.Controls 2.15 32 * import QtQuick.Window 2.15 33 * 34 * // import the VTK module 35 * import VTK 9.0 36 * 37 * // window containing the application 38 * ApplicationWindow { 39 * // title of the application 40 * title: qsTr("VTK QtQuick App") 41 * width: 400 42 * height: 400 43 * color: palette.window 44 * 45 * SystemPalette { 46 * id: palette 47 * colorGroup: SystemPalette.Active 48 * } 49 * 50 * // Instantiate the vtk render window 51 * VTKRenderWindow { 52 * id: vtkwindow 53 * width: 400 54 * height: 400 55 * } 56 * 57 * // add one or more vtk render items 58 * VTKRenderItem { 59 * objectName: "ConeView" 60 * x: 200 61 * y: 200 62 * width: 200 63 * height: 200 64 * // Provide the handle to the render window 65 * renderWindow: vtkwindow 66 * } 67 * } 68 * @endcode 69 * 70 * The corresponding C++ code that sets up the VTK pipeline would look like the following: 71 * 72 * @code 73 * int main(int argc, char* argv[]) 74 * { 75 * QQuickVTKRenderWindow::setupGraphicsBackend(); 76 * QGuiApplication app(argc, argv); 77 * 78 * QQmlApplicaQtionEngine engine; 79 * engine.load(QUrl("qrc:///<qmlfile>.qml")); 80 * 81 * QObject* topLevel = engine.rootObjects().value(0); 82 * QQuickWindow* window = qobject_cast<QQuickWindow*>(topLevel); 83 * 84 * window->show(); 85 * 86 * // Fetch the QQuick window using the standard object name set up in the constructor 87 * QQuickVTKRenderItem* qquickvtkItem = topLevel->findChild<QQuickVTKRenderItem*>("ConeView"); 88 * 89 * // Create a cone pipeline and add it to the view 90 * vtkNew<vtkActor> actor; 91 * vtkNew<vtkPolyDataMapper> mapper; 92 * vtkNew<vtkConeSource> cone; 93 * mapper->SetInputConnection(cone->GetOutputPort()); 94 * actor->SetMapper(mapper); 95 * qquickvtkItem->renderer()->AddActor(actor); 96 * qquickvtkItem->renderer()->ResetCamera(); 97 * qquickvtkItem->renderer()->SetBackground(0.5, 0.5, 0.7); 98 * qquickvtkItem->renderer()->SetBackground2(0.7, 0.7, 0.7); 99 * qquickvtkItem->renderer()->SetGradientBackground(true); 100 * qquickvtkItem->update(); 101 * app.exec(); 102 * } 103 * @endcode 104 * 105 * ## QtQuick scenegraph and threaded render loop 106 * 107 * QtQuick/QML scenegraph rendering is done via private API inside the [QQuickWindow] class. For 108 * details on QtQuick's render loop, see [QtQuick Scenegraph Rendering]( 109 * https://doc.qt.io/qt-6/qtquick-visualcanvas-scenegraph.html#scene-graph-and-rendering). 110 * Qt automatically decides between a threaded and basic render loop for most applications. 111 * QQuickVTKRenderWindow and QQuickVTKRenderItem support both these variants of the QtQuick render 112 * loop. 113 * 114 * When the scenegraph render loop is threaded, i.e. there is a dedicated rendering thread, vtk 115 * sticks to doing all rendering on this render thread. This means that all the vtk classes, 116 * pipelines etc. can be set up on the main thread but vtkRenderWindow::Render should only be 117 * invoked on the render thread. Care must be taken not to call Render on the main thread because 118 * the OpenGL context would not be valid on the main thread. 119 * 120 * ## Interactive vtk widgets 121 * 122 * QQuickVTKRenderItem also supports interactive vtk widgets with QtQuick's threaded render loop via 123 * the QQuickVTKInteractiveWidget class. 124 * 125 * [QQuickItem]: https://doc.qt.io/qt-5/qquickitem.html 126 * [QQuickWindow]: https://doc.qt.io/qt-5/qquickwindow.html 127 */ 128 129 #ifndef QQuickVTKRenderItem_h 130 #define QQuickVTKRenderItem_h 131 132 // Qt includes 133 #include <QOpenGLFunctions> // For QOpenGLFunctions 134 #include <QQuickItem> 135 136 // vtk includes 137 #include "QQuickVTKRenderWindow.h" // For QQuickVTKRenderWindow 138 #include "vtkNew.h" // For vtkNew 139 #include "vtkRenderer.h" // For vtkRenderer 140 141 #include "vtkGUISupportQtQuickModule.h" // for export macro 142 143 // Forward declarations 144 class QHoverEvent; 145 class QKeyEvent; 146 class QMouseEvent; 147 class QQuickVTKInteractiveWidget; 148 class vtkImageData; 149 150 class VTKGUISUPPORTQTQUICK_EXPORT QQuickVTKRenderItem 151 : public QQuickItem 152 , protected QOpenGLFunctions 153 { 154 Q_OBJECT 155 typedef QQuickItem Superclass; 156 157 Q_PROPERTY(QQuickVTKRenderWindow* renderWindow READ renderWindow WRITE setRenderWindow) 158 159 public: 160 QQuickVTKRenderItem(QQuickItem* parent = nullptr); 161 ~QQuickVTKRenderItem() = default; 162 163 ///@{ 164 /** 165 * Set/Get the render window for the item 166 */ 167 QQuickVTKRenderWindow* renderWindow() const; 168 virtual void setRenderWindow(QQuickVTKRenderWindow* w); 169 ///@} 170 171 /** 172 * Get access to the renderer 173 */ 174 vtkRenderer* renderer() const; 175 176 /** 177 * Capture a screenshot of the view 178 * 179 * \returns Image data containing the view capture. 180 * \sa QQuickVTKRenderWindow::captureScreenshot 181 */ 182 virtual vtkSmartPointer<vtkImageData> captureScreenshot(); 183 184 ///@{ 185 /** 186 * Add/Remove widgets to/from the view 187 */ 188 virtual void addWidget(QQuickVTKInteractiveWidget* w); 189 virtual void removeWidget(QQuickVTKInteractiveWidget* w); 190 ///@} 191 192 ///@{ 193 /** 194 * Get/Remove widgets from the view by their object name 195 */ 196 virtual QQuickVTKInteractiveWidget* widgetByName(QString name) const; 197 virtual void removeWidgetByName(QString name); 198 ///@} 199 200 public Q_SLOTS: 201 /** 202 * This is the function called on the QtQuick render thread before the scenegraph state 203 * is synchronized. This is where most of the pipeline updates, camera manipulations, etc. and 204 * other pre-render steps can be performed. 205 * 206 * \note At the time of this method execution, the GUI thread is blocked. Hence, it is safe to 207 * perform state synchronization between the GUI elements and the VTK classes here. 208 */ 209 virtual void sync(); 210 211 /** 212 * Initialize the graphics resources required for this render item. 213 * 214 * This method is called on the QtQuick render thread at the beforeRenderPassRecording stage of 215 * the scenegraph render loop. 216 */ 217 virtual void init(); 218 219 /** 220 * This is the function called on the QtQuick render thread right before the scenegraph is 221 * rendered. This is the stage where all the vtk rendering is performed. Applications would rarely 222 * need to override this method. 223 * 224 * \note This method is called at the beforeRendering stage of the QtQuick scenegraph. All the 225 * QtQuick element rendering is stacked visually above the vtk rendering. 226 */ 227 virtual void paint(); 228 229 /** 230 * This is the function called on the QtQuick render thread when the scenegraph is invalidated. 231 * This is where all graphics resources allocated by vtk are released. 232 */ 233 virtual void cleanup(); 234 235 protected Q_SLOTS: 236 virtual void handleWindowChanged(QQuickWindow* w); 237 238 protected: 239 // Helper members 240 QQuickVTKRenderWindow* m_renderWindow = nullptr; 241 vtkNew<vtkRenderer> m_renderer; 242 243 QVector<QQuickVTKInteractiveWidget*> m_widgets; 244 245 /** 246 * Set the viewport for this item 247 */ 248 virtual void setViewport(const QRectF& rect); 249 250 // Event handlers 251 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 252 void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) override; 253 #else 254 void geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) override; 255 #endif 256 bool event(QEvent* ev) override; 257 258 private: 259 QQuickVTKRenderItem(const QQuickVTKRenderItem&) = delete; 260 void operator=(const QQuickVTKRenderItem) = delete; 261 }; 262 263 #endif // QQuickVTKRenderItem_h 264