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