1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    QVTKOpenGLWindow.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 QVTKOpenGLWindow
17  * @brief display a vtkGenericOpenGLRenderWindow in a Qt QOpenGLWindow.
18  *
19  * QVTKOpenGLWindow is one of the mechanisms for displaying VTK rendering
20  * results in a Qt application. QVTKOpenGLWindow extends QOpenGLWindow to
21  * display the rendering results of a vtkGenericOpenGLRenderWindow.
22  *
23  * Since QVTKOpenGLWindow is based on QOpenGLWindow it is intended for
24  * rendering in a top-level window. QVTKOpenGLWindow can be embedded in a
25  * another QWidget using `QWidget::createWindowContainer` or by using
26  * QVTKOpenGLStereoWidget instead. However, developers are encouraged to check
27  * Qt documentation for `QWidget::createWindowContainer` idiosyncrasies.
28  * Using QVTKOpenGLNativeWidget instead is generally a better choice for causes
29  * where you want to embed VTK rendering results in a QWidget. QVTKOpenGLWindow
30  * or QVTKOpenGLStereoWidget is still preferred for applications that want to support
31  * quad-buffer based stereo rendering.
32  *
33  * To request a specific configuration for the context, use
34  * `QWindow::setFormat()` like for any other QWindow. This allows, among others,
35  * requesting a given OpenGL version and profile. Use
36  * `QOpenGLWindow::defaultFormat()` to obtain a QSurfaceFormat with appropriate
37  * OpenGL version configuration. To enable quad-buffer stereo, you'll need to
38  * call `QSurfaceFormat::setStereo(true)`.
39  *
40  * VTK Rendering features like multi-sampling, double buffering etc.
41  * are enabled/disabled by directly setting the corresponding attributes on
42  * vtkGenericOpenGLRenderWindow and not when specifying the OpenGL context
43  * format in `setFormat`. If not specified, then `QSurfaceFormat::defaultFormat`
44  * will be used.
45  *
46  * @note QVTKOpenGLWindow requires Qt version 5.9 and above.
47  * @sa QVTKOpenGLStereoWidget QVTKOpenGLNativeWidget
48  */
49 #ifndef QVTKOpenGLWindow_h
50 #define QVTKOpenGLWindow_h
51 
52 #include <QOpenGLWindow>
53 #include <QScopedPointer> // for QScopedPointer.
54 
55 #include "QVTKInteractor.h"        // needed for QVTKInteractor
56 #include "vtkDeprecation.h"        // For VTK_DEPRECATED_IN_9_0_0
57 #include "vtkGUISupportQtModule.h" // for export macro
58 #include "vtkNew.h"                // needed for vtkNew
59 #include "vtkSmartPointer.h"       // needed for vtkSmartPointer
60 
61 class QVTKInteractor;
62 class QVTKInteractorAdapter;
63 class QVTKRenderWindowAdapter;
64 class vtkGenericOpenGLRenderWindow;
65 
66 class VTKGUISUPPORTQT_EXPORT QVTKOpenGLWindow : public QOpenGLWindow
67 {
68   Q_OBJECT
69   typedef QOpenGLWindow Superclass;
70 
71 public:
72   QVTKOpenGLWindow(
73     QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow* parent = nullptr);
74   QVTKOpenGLWindow(QOpenGLContext* shareContext,
75     QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow* parent = nullptr);
76   QVTKOpenGLWindow(vtkGenericOpenGLRenderWindow* renderWindow,
77     QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow* parent = nullptr);
78   QVTKOpenGLWindow(vtkGenericOpenGLRenderWindow* renderWindow, QOpenGLContext* shareContext,
79     QOpenGLWindow::UpdateBehavior updateBehavior = NoPartialUpdate, QWindow* parent = nullptr);
80   ~QVTKOpenGLWindow() override;
81 
82   ///@{
83   /**
84    * Set a render window to use. It a render window was already set, it will be
85    * finalized and all of its OpenGL resource released. If the \c win is
86    * non-null and it has no interactor set, then a QVTKInteractor instance will
87    * be created as set on the render window as the interactor.
88    */
89   void setRenderWindow(vtkGenericOpenGLRenderWindow* win);
90   void setRenderWindow(vtkRenderWindow* win);
91   ///@}
92 
93   /**
94    * Returns the render window that is being shown in this widget.
95    */
96   vtkRenderWindow* renderWindow() const;
97 
98   /**
99    * Get the QVTKInteractor that was either created by default or set by the user.
100    */
101   QVTKInteractor* interactor() const;
102 
103   /**
104    * @copydoc QVTKRenderWindowAdapter::defaultFormat(bool)
105    */
106   static QSurfaceFormat defaultFormat(bool stereo_capable = false);
107 
108   ///@{
109   /**
110    * Enable or disable support for HiDPI displays. When enabled, this enabled
111    * DPI scaling i.e. `vtkWindow::SetDPI` will be called with a DPI value scaled
112    * by the device pixel ratio every time the widget is resized. The unscaled
113    * DPI value can be specified by using `setUnscaledDPI`.
114    */
115   void setEnableHiDPI(bool enable);
enableHiDPI()116   bool enableHiDPI() const { return this->EnableHiDPI; }
117   ///@}
118 
119   ///@{
120   /**
121    * Set/Get unscaled DPI value. Defaults to 72, which is also the default value
122    * in vtkWindow.
123    */
124   void setUnscaledDPI(int);
unscaledDPI()125   int unscaledDPI() const { return this->UnscaledDPI; }
126   ///@}
127 
128   ///@{
129   /**
130    * Set/Get a custom device pixel ratio to use to map Qt sizes to VTK (or
131    * OpenGL) sizes. Thus, when the QWidget is resized, it called
132    * `vtkRenderWindow::SetSize` on the internal vtkRenderWindow after
133    * multiplying the QWidget's size by this scale factor.
134    *
135    * By default, this is set to 0. Which means that `devicePixelRatio` obtained
136    * from Qt will be used. Set this to a number greater than 0 to override this
137    * behaviour and use the custom scale factor instead.
138    *
139    * `effectiveDevicePixelRatio` can be used to obtain the device-pixel-ratio
140    * that will be used given the value for customDevicePixelRatio.
141    */
142   void setCustomDevicePixelRatio(double cdpr);
customDevicePixelRatio()143   double customDevicePixelRatio() const { return this->CustomDevicePixelRatio; }
144   double effectiveDevicePixelRatio() const;
145   ///@}
146 
147   ///@{
148   /**
149    * Set/get the default cursor to use for this widget.
150    */
151   void setDefaultCursor(const QCursor& cursor);
defaultCursor()152   const QCursor& defaultCursor() const { return this->DefaultCursor; }
153   ///@}
154 
155   ///@{
156   /**
157    * @deprecated in VTK 9.0. Use `setRenderWindow` instead.
158    */
159   VTK_DEPRECATED_IN_9_0_0("Use QVTKOpenGLWindow::setRenderWindow")
160   void SetRenderWindow(vtkGenericOpenGLRenderWindow* win);
161   VTK_DEPRECATED_IN_9_0_0("Use QVTKOpenGLWindow::setRenderWindow")
162   void SetRenderWindow(vtkRenderWindow* win);
163   ///@}
164 
165   ///@{
166   /**
167    * These methods have be deprecated to fix naming style. Since
168    * QVTKOpenGLWindow is QObject subclass, we follow Qt naming conventions
169    * rather than VTK's.
170    */
171   VTK_DEPRECATED_IN_9_0_0("Use QVTKOpenGLWindow::renderWindow")
172   vtkRenderWindow* GetRenderWindow();
173   VTK_DEPRECATED_IN_9_0_0("Use QVTKOpenGLWindow::interactor")
174   QVTKInteractor* GetInteractor();
175   ///@}
176 
177   /**
178    * @deprecated in VTK 9.0
179    * QVTKInteractorAdapter is an internal helper. Hence the API was removed.
180    */
181   VTK_DEPRECATED_IN_9_0_0("Removed in 9.0.0 (internal)")
182   QVTKInteractorAdapter* GetInteractorAdapter();
183 
184   /**
185    * @deprecated in VTK 9.0. Simply use `QWidget::setCursor` API to change
186    * cursor.
187    */
188   VTK_DEPRECATED_IN_9_0_0("Use QWidget::setCursor")
189   void setQVTKCursor(const QCursor& cursor);
190 
191   /**
192    * @deprecated in VTK 9.0. Use `setDefaultCursor` instead.
193    */
194   VTK_DEPRECATED_IN_9_0_0("Use QWidget::setDefaultCursor")
195   void setDefaultQVTKCursor(const QCursor& cursor);
196 
197 Q_SIGNALS:
198   /**
199    * Signal emitted when any event has been receive, with the corresponding
200    * event as argument.
201    */
202   void windowEvent(QEvent* e);
203 
204 protected Q_SLOTS:
205   /**
206    * Called as a response to `QOpenGLContext::aboutToBeDestroyed`. This may be
207    * called anytime during the widget lifecycle. We need to release any OpenGL
208    * resources allocated in VTK work in this method.
209    */
210   void cleanupContext();
211 
212   void updateSize();
213 
214   /**
215    * QVTKOpenGLStereoWidget is given friendship so it can call `cleanupContext` in its
216    * destructor to ensure that OpenGL state is proporly cleaned up before the
217    * widget goes away.
218    */
219   friend class QVTKOpenGLStereoWidget;
220 
221 protected:
222   bool event(QEvent* evt) override;
223   void initializeGL() override;
224   void paintGL() override;
225   void resizeGL(int w, int h) override;
226 
227 protected:
228   vtkSmartPointer<vtkGenericOpenGLRenderWindow> RenderWindow;
229   QScopedPointer<QVTKRenderWindowAdapter> RenderWindowAdapter;
230 
231 private:
232   Q_DISABLE_COPY(QVTKOpenGLWindow);
233   bool EnableHiDPI;
234   int UnscaledDPI;
235   double CustomDevicePixelRatio;
236   QCursor DefaultCursor;
237 };
238 
239 #endif
240