296 lines
9.4 KiB
C
296 lines
9.4 KiB
C
|
|
/*=========================================================================
|
||
|
|
|
||
|
|
Program: Visualization Toolkit
|
||
|
|
Module: QQuickVTKRenderWindow.h
|
||
|
|
|
||
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
||
|
|
All rights reserved.
|
||
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
||
|
|
|
||
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
||
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||
|
|
PURPOSE. See the above copyright notice for more information.
|
||
|
|
|
||
|
|
=========================================================================*/
|
||
|
|
/**
|
||
|
|
* @class QQuickVTKRenderWindow
|
||
|
|
* @brief [QQuickItem] subclass that manages the vtkRenderWindow and, in
|
||
|
|
* turn, the OpenGL context of the QML application
|
||
|
|
*
|
||
|
|
* QQuickVTKRenderWindow extends [QQuickItem] in a way that allows for VTK to get a handle to, and
|
||
|
|
* draw inside of the QtQuick scenegraph, using OpenGL draw calls.
|
||
|
|
*
|
||
|
|
* This item is exported to the QML layer via the QQmlVTKPlugin under the module VTK. It is
|
||
|
|
* registered as a type \b VTKRenderWindow. Since, this class is intended to manage an OpenGL
|
||
|
|
* context in the window, a single instance would be needed for most QML applications.
|
||
|
|
*
|
||
|
|
* Typical usage for QQuickVTKRenderWindow in a Qml application is as follows:
|
||
|
|
*
|
||
|
|
* @code
|
||
|
|
* // import related modules
|
||
|
|
* import QtQuick 2.15
|
||
|
|
* import QtQuick.Controls 2.15
|
||
|
|
* import QtQuick.Window 2.15
|
||
|
|
*
|
||
|
|
* // import the VTK module
|
||
|
|
* import VTK 9.0
|
||
|
|
*
|
||
|
|
* // window containing the application
|
||
|
|
* ApplicationWindow {
|
||
|
|
* // title of the application
|
||
|
|
* title: qsTr("VTK QtQuick App")
|
||
|
|
* width: 400
|
||
|
|
* height: 400
|
||
|
|
* color: palette.window
|
||
|
|
*
|
||
|
|
* SystemPalette {
|
||
|
|
* id: palette
|
||
|
|
* colorGroup: SystemPalette.Active
|
||
|
|
* }
|
||
|
|
*
|
||
|
|
* // Instantiate the vtk render window
|
||
|
|
* VTKRenderWindow {
|
||
|
|
* id: vtkwindow
|
||
|
|
* width: 400
|
||
|
|
* height: 400
|
||
|
|
* }
|
||
|
|
*
|
||
|
|
* // add one or more vtk render items
|
||
|
|
* VTKRenderItem {
|
||
|
|
* objectName: "ConeView"
|
||
|
|
* x: 200
|
||
|
|
* y: 200
|
||
|
|
* width: 200
|
||
|
|
* height: 200
|
||
|
|
* // Provide the handle to the render window
|
||
|
|
* renderWindow: vtkwindow
|
||
|
|
* }
|
||
|
|
* VTKRenderItem {
|
||
|
|
* objectName: "VolumeView"
|
||
|
|
* x: 0
|
||
|
|
* y: 0
|
||
|
|
* width: 200
|
||
|
|
* height: 200
|
||
|
|
* // Provide the handle to the render window
|
||
|
|
* renderWindow: vtkwindow
|
||
|
|
* }
|
||
|
|
* }
|
||
|
|
* @endcode
|
||
|
|
*
|
||
|
|
* To ensure that the graphics backend set up by QtQuick matches that expected by VTK, use the
|
||
|
|
* method QQuickVTKRenderWindow::setupGraphicsBackend() before a QApplication/QGuiApplication is
|
||
|
|
* instantiated in the main method of the application.
|
||
|
|
*
|
||
|
|
* @code
|
||
|
|
* int main(int argc, char* argv[])
|
||
|
|
* {
|
||
|
|
* // Setup the graphics backend
|
||
|
|
* QQuickVTKRenderWindow::setupGraphicsBackend();
|
||
|
|
* QGuiApplication app(argc, argv);
|
||
|
|
* ...
|
||
|
|
* return EXIT_SUCCESS;
|
||
|
|
* }
|
||
|
|
* @endcode
|
||
|
|
*
|
||
|
|
* The VTK pipeline can be then set up for each \b VTKRenderItem in the C++ code.
|
||
|
|
*
|
||
|
|
* ## QtQuick scenegraph and threaded render loop
|
||
|
|
*
|
||
|
|
* QtQuick/QML scenegraph rendering is done via private API inside the [QQuickWindow] class. For
|
||
|
|
* details on QtQuick's render loop, see [QtQuick Scenegraph Rendering](
|
||
|
|
* https://doc.qt.io/qt-6/qtquick-visualcanvas-scenegraph.html#scene-graph-and-rendering).
|
||
|
|
* Qt automatically decides between a threaded and basic render loop for most applications.
|
||
|
|
* QQuickVTKRenderWindow and QQuickVTKRenderItem support both these variants of the QtQuick render
|
||
|
|
* loop.
|
||
|
|
*
|
||
|
|
* When the scenegraph render loop is threaded, i.e. there is a dedicated rendering thread, vtk
|
||
|
|
* sticks to doing all rendering on this render thread. This means that all the vtk classes,
|
||
|
|
* pipelines etc. can be set up on the main thread but vtkRenderWindow::Render should only be
|
||
|
|
* invoked on the render thread. Care must be taken not to call Render on the main thread because
|
||
|
|
* the OpenGL context would not be valid on the main thread.
|
||
|
|
*
|
||
|
|
* [QQuickItem]: https://doc.qt.io/qt-5/qquickitem.html
|
||
|
|
* [QQuickWindow]: https://doc.qt.io/qt-5/qquickwindow.html
|
||
|
|
*/
|
||
|
|
|
||
|
|
#ifndef QQuickVTKRenderWindow_h
|
||
|
|
#define QQuickVTKRenderWindow_h
|
||
|
|
|
||
|
|
// vtk includes
|
||
|
|
#include "vtkSmartPointer.h" // For vtkSmartPointer
|
||
|
|
|
||
|
|
// Qt includes
|
||
|
|
#include <QOpenGLFunctions> // For QOpenGLFunctions
|
||
|
|
#include <QPointer> // For QPointer
|
||
|
|
#include <QQuickItem>
|
||
|
|
|
||
|
|
#include "vtkGUISupportQtQuickModule.h" // for export macro
|
||
|
|
|
||
|
|
// Forward declarations
|
||
|
|
class QEvent;
|
||
|
|
class QQuickVTKInteractorAdapter;
|
||
|
|
class QQuickWindow;
|
||
|
|
class QWheelEvent;
|
||
|
|
class vtkGenericOpenGLRenderWindow;
|
||
|
|
class vtkImageData;
|
||
|
|
class vtkRenderWindow;
|
||
|
|
class vtkRenderer;
|
||
|
|
class vtkWindowToImageFilter;
|
||
|
|
|
||
|
|
class VTKGUISUPPORTQTQUICK_EXPORT QQuickVTKRenderWindow
|
||
|
|
: public QQuickItem
|
||
|
|
, protected QOpenGLFunctions
|
||
|
|
{
|
||
|
|
Q_OBJECT
|
||
|
|
typedef QQuickItem Superclass;
|
||
|
|
|
||
|
|
public:
|
||
|
|
/**
|
||
|
|
* Constructor
|
||
|
|
* Creates a QQuickVTKRenderWindow with:
|
||
|
|
* - a vtkGenericOpenGLRenderWindow to manage the OpenGL context
|
||
|
|
* - an interactor adapter to forward Qt events to vtk's interactor
|
||
|
|
*/
|
||
|
|
QQuickVTKRenderWindow(QQuickItem* parent = nullptr);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Destructor
|
||
|
|
*/
|
||
|
|
~QQuickVTKRenderWindow();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set up the graphics surface format and api.
|
||
|
|
*
|
||
|
|
* This method sets the graphics API to OpenGLRhi and sets up the surface format for intermixed
|
||
|
|
* VTK and QtQuick rendering.
|
||
|
|
* Use this method before instantiating a QApplication/QGuiApplication in a QtQuick/QML app with
|
||
|
|
* a VTK render view like QQuickVTKRenderItem.
|
||
|
|
*/
|
||
|
|
static void setupGraphicsBackend();
|
||
|
|
|
||
|
|
///@{
|
||
|
|
/**
|
||
|
|
* Set/Get the vtkRenderWindow for the view.
|
||
|
|
* Note that this render window should be of type vtkGenericOpenGLRenderWindow. This is necessary
|
||
|
|
* since that would allow vtk's opengl draw calls to work seamlessly inside the QtQuick created
|
||
|
|
* scenegraph and OpenGL context.
|
||
|
|
*
|
||
|
|
* By default, a vtkGenericOpenGLRenderWindow is created and set on this item at construction
|
||
|
|
* time.
|
||
|
|
*/
|
||
|
|
virtual void setRenderWindow(vtkRenderWindow* renWin);
|
||
|
|
virtual void setRenderWindow(vtkGenericOpenGLRenderWindow* renWin);
|
||
|
|
vtkRenderWindow* renderWindow() const;
|
||
|
|
///@}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Map a Qt item rect to viewport coordinates
|
||
|
|
*/
|
||
|
|
virtual void mapToViewport(const QRectF& rect, double viewport[4]);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get access to the interactor adapter
|
||
|
|
*/
|
||
|
|
QPointer<QQuickVTKInteractorAdapter> interactorAdapter() const;
|
||
|
|
|
||
|
|
///@{
|
||
|
|
/**
|
||
|
|
* Capture a screenshot of the window
|
||
|
|
*
|
||
|
|
* \param viewport area to capture.
|
||
|
|
* \returns Image data containing the window capture.
|
||
|
|
* \note This triggers a scenegraph update to capture the render window view.
|
||
|
|
*/
|
||
|
|
virtual vtkSmartPointer<vtkImageData> captureScreenshot();
|
||
|
|
virtual vtkSmartPointer<vtkImageData> captureScreenshot(double* viewport);
|
||
|
|
///@}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get whether the render window is initialized
|
||
|
|
* Used internally to determine if the OpenGL context, QQuickWindow, children items and viewports
|
||
|
|
* have been initialized.
|
||
|
|
*/
|
||
|
|
virtual bool isInitialized() const;
|
||
|
|
|
||
|
|
public Q_SLOTS:
|
||
|
|
/**
|
||
|
|
* This is the function called on the QtQuick render thread before the scenegraph state
|
||
|
|
* is synchronized. This is where most of the pipeline updates, camera manipulations, etc. and
|
||
|
|
* other pre-render steps can be performed.
|
||
|
|
*
|
||
|
|
* \note At the time of this method execution, the GUI thread is blocked. Hence, it is safe to
|
||
|
|
* perform state synchronization between the GUI elements and the VTK classes here.
|
||
|
|
*/
|
||
|
|
virtual void sync();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Initialize the VTK render window for OpenGL based on the context created by QtQuick
|
||
|
|
*
|
||
|
|
* \note This method is called at the beforeRenderPassRecording stage of the QtQuick scenegraph.
|
||
|
|
* All the QtQuick element rendering is stacked visually above the vtk rendering.
|
||
|
|
*/
|
||
|
|
virtual void init();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This is the function called on the QtQuick render thread right before the scenegraph is
|
||
|
|
* rendered. This is the stage where all the vtk rendering is performed. Applications would rarely
|
||
|
|
* need to override this method.
|
||
|
|
*
|
||
|
|
* \note This method is called at the beforeRenderPassRecording stage of the QtQuick scenegraph.
|
||
|
|
* All the QtQuick element rendering is stacked visually above the vtk rendering.
|
||
|
|
*/
|
||
|
|
virtual void paint();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This is the function called on the QtQuick render thread when the scenegraph is invalidated.
|
||
|
|
* This is where all graphics resources allocated by vtk are released.
|
||
|
|
*/
|
||
|
|
virtual void cleanup();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convenience method that schedules a scenegraph update and waits for the update.
|
||
|
|
* \sa render()
|
||
|
|
*/
|
||
|
|
virtual void renderNow();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Schedule a scenegraph update
|
||
|
|
*
|
||
|
|
* \note Since this schedules a scenegraph update, it does not guarantee that the scene will be
|
||
|
|
* updated after this call.
|
||
|
|
* \sa renderNow()
|
||
|
|
*/
|
||
|
|
virtual void render();
|
||
|
|
|
||
|
|
protected Q_SLOTS:
|
||
|
|
virtual void handleWindowChanged(QQuickWindow* w);
|
||
|
|
|
||
|
|
protected:
|
||
|
|
QPointer<QQuickVTKInteractorAdapter> m_interactorAdapter;
|
||
|
|
vtkSmartPointer<vtkGenericOpenGLRenderWindow> m_renderWindow;
|
||
|
|
bool m_initialized = false;
|
||
|
|
|
||
|
|
// Screenshot stuff
|
||
|
|
bool m_screenshotScheduled = false;
|
||
|
|
vtkNew<vtkWindowToImageFilter> m_screenshotFilter;
|
||
|
|
vtkNew<vtkRenderer> m_dummyRenderer;
|
||
|
|
|
||
|
|
// Event handlers
|
||
|
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||
|
|
void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry) override;
|
||
|
|
#else
|
||
|
|
void geometryChange(const QRectF& newGeometry, const QRectF& oldGeometry) override;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check the scenegraph backend and graphics API being used.
|
||
|
|
*/
|
||
|
|
bool checkGraphicsBackend();
|
||
|
|
|
||
|
|
private:
|
||
|
|
QQuickVTKRenderWindow(const QQuickVTKRenderWindow&) = delete;
|
||
|
|
void operator=(const QQuickVTKRenderWindow) = delete;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // QQuickVTKRenderWindow_h
|