Remove myQVTKOpenGLNativeWidget
This commit is contained in:
@@ -66,6 +66,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
void OnLeftButtonUp() override;
|
void OnLeftButtonUp() override;
|
||||||
|
|
||||||
|
void OnMouseWheelForward() override{}
|
||||||
|
void OnMouseWheelBackward() override{}
|
||||||
|
|
||||||
void OnChar() override;
|
void OnChar() override;
|
||||||
void EndDolly() override;
|
void EndDolly() override;
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
void ShowMetaData();
|
void ShowMetaData();
|
||||||
myQVTKOpenGLNativeWidget* getGLWidget()
|
QVTKOpenGLNativeWidget* getGLWidget()
|
||||||
{
|
{
|
||||||
return _glWidt;
|
return _glWidt;
|
||||||
}
|
}
|
||||||
@@ -216,7 +216,7 @@ private:
|
|||||||
SeriesInstance* _Series =nullptr;
|
SeriesInstance* _Series =nullptr;
|
||||||
QScrollBar* _scrollBar =nullptr;
|
QScrollBar* _scrollBar =nullptr;
|
||||||
MyTitleBar *_titleBar =nullptr;
|
MyTitleBar *_titleBar =nullptr;
|
||||||
myQVTKOpenGLNativeWidget* _glWidt = nullptr;
|
QVTKOpenGLNativeWidget* _glWidt = nullptr;
|
||||||
pqVCRToolbar* _vcr_toolbar = nullptr;
|
pqVCRToolbar* _vcr_toolbar = nullptr;
|
||||||
pqVCRController *_vcr_ctrl = nullptr;
|
pqVCRController *_vcr_ctrl = nullptr;
|
||||||
QThread _thread;
|
QThread _thread;
|
||||||
|
|||||||
@@ -1,289 +0,0 @@
|
|||||||
/*=========================================================================
|
|
||||||
|
|
||||||
Program: Visualization Toolkit
|
|
||||||
Module: myQVTKOpenGLNativeWidget.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 myQVTKOpenGLNativeWidget
|
|
||||||
* @brief QOpenGLWidget subclass to house a vtkGenericOpenGLRenderWindow in a Qt
|
|
||||||
* application.
|
|
||||||
*
|
|
||||||
* myQVTKOpenGLNativeWidget extends QOpenGLWidget to make it work with a
|
|
||||||
* vtkGenericOpenGLRenderWindow. This is akin to QVTKWidget except it uses Qt to create and
|
|
||||||
* manage the OpenGL context using QOpenGLWidget (added in Qt 5.4).
|
|
||||||
*
|
|
||||||
* While myQVTKOpenGLNativeWidget is intended to be a replacement for QVTKWidget when
|
|
||||||
* using Qt 5, there are a few difference between myQVTKOpenGLNativeWidget and
|
|
||||||
* QVTKWidget.
|
|
||||||
*
|
|
||||||
* Unlike QVTKWidget, myQVTKOpenGLNativeWidget only works with vtkGenericOpenGLRenderWindow.
|
|
||||||
* This is necessary since QOpenGLWidget wants to take over the window management as
|
|
||||||
* well as the OpenGL context creation. Getting that to work reliably with
|
|
||||||
* vtkXRenderWindow or vtkWin32RenderWindow (and other platform specific
|
|
||||||
* vtkRenderWindow subclasses) was tricky and fraught with issues.
|
|
||||||
*
|
|
||||||
* Since myQVTKOpenGLNativeWidget uses QOpenGLWidget to create the OpenGL context,
|
|
||||||
* it uses QSurfaceFormat (set using `QOpenGLWidget::setFormat` or
|
|
||||||
* `QSurfaceFormat::setDefaultFormat`) to create appropriate window and context.
|
|
||||||
* You can use `myQVTKOpenGLNativeWidget::copyToFormat` to obtain a QSurfaceFormat
|
|
||||||
* appropriate for a vtkRenderWindow.
|
|
||||||
*
|
|
||||||
* A typical usage for myQVTKOpenGLNativeWidget is as follows:
|
|
||||||
* @code{.cpp}
|
|
||||||
*
|
|
||||||
* // before initializing QApplication, set the default surface format.
|
|
||||||
* QSurfaceFormat::setDefaultFormat(myQVTKOpenGLNativeWidget::defaultFormat());
|
|
||||||
*
|
|
||||||
* vtkNew<vtkGenericOpenGLRenderWindow> window;
|
|
||||||
* QPointer<myQVTKOpenGLNativeWidget> widget = new myQVTKOpenGLNativeWidget(...);
|
|
||||||
* widget->SetRenderWindow(window.Get());
|
|
||||||
*
|
|
||||||
* // If using any of the standard view e.g. vtkContextView, then
|
|
||||||
* // you can do the following.
|
|
||||||
* vtkNew<vtkContextView> view;
|
|
||||||
* view->SetRenderWindow(window.Get());
|
|
||||||
*
|
|
||||||
* // You can continue to use `window` as a regular vtkRenderWindow
|
|
||||||
* // including adding renderers, actors etc.
|
|
||||||
*
|
|
||||||
* @endcode
|
|
||||||
*
|
|
||||||
* @section OpenGLContext OpenGL Context
|
|
||||||
*
|
|
||||||
* In QOpenGLWidget (superclass for myQVTKOpenGLNativeWidget), all rendering happens in a
|
|
||||||
* framebuffer object. Thus, care must be taken in the rendering code to never
|
|
||||||
* directly re-bind the default framebuffer i.e. ID 0.
|
|
||||||
*
|
|
||||||
* myQVTKOpenGLNativeWidget creates an internal QOpenGLFramebufferObject, independent of the
|
|
||||||
* one created by superclass, for vtkRenderWindow to do the rendering in. This
|
|
||||||
* explicit double-buffering is useful in avoiding temporary back-buffer only
|
|
||||||
* renders done in VTK (e.g. when making selections) from destroying the results
|
|
||||||
* composed on screen.
|
|
||||||
*
|
|
||||||
* @section RenderAndPaint Handling Render and Paint.
|
|
||||||
*
|
|
||||||
* QWidget subclasses (including `QOpenGLWidget` and `myQVTKOpenGLNativeWidget`) display
|
|
||||||
* their contents on the screen in `QWidget::paint` in response to a paint event.
|
|
||||||
* `QOpenGLWidget` subclasses are expected to do OpenGL rendering in
|
|
||||||
* `QOpenGLWidget::paintGL`. QWidget can receive paint events for various
|
|
||||||
* reasons including widget getting focus/losing focus, some other widget on
|
|
||||||
* the UI e.g. QProgressBar in status bar updating, etc.
|
|
||||||
*
|
|
||||||
* In VTK applications, any time the vtkRenderWindow needs to be updated to
|
|
||||||
* render a new result, one call `vtkRenderWindow::Render` on it.
|
|
||||||
* vtkRenderWindowInteractor set on the render window ensures that as
|
|
||||||
* interactions happen that affect the rendered result, it calls `Render` on the
|
|
||||||
* render window.
|
|
||||||
*
|
|
||||||
* Since paint in Qt can be called more often then needed, we avoid potentially
|
|
||||||
* expensive `vtkRenderWindow::Render` calls each time that happens. Instead,
|
|
||||||
* myQVTKOpenGLNativeWidget relies on the VTK application calling
|
|
||||||
* `vtkRenderWindow::Render` on the render window when it needs to update the
|
|
||||||
* rendering. `paintGL` simply passes on the result rendered by the most render
|
|
||||||
* vtkRenderWindow::Render to Qt windowing system for composing on-screen.
|
|
||||||
*
|
|
||||||
* There may still be occasions when we may have to render in `paint` for
|
|
||||||
* example if the window was resized or Qt had to recreate the OpenGL context.
|
|
||||||
* In those cases, `myQVTKOpenGLNativeWidget::paintGL` can request a render by calling
|
|
||||||
* `myQVTKOpenGLNativeWidget::renderVTK`.
|
|
||||||
*
|
|
||||||
* @section Caveats
|
|
||||||
* myQVTKOpenGLNativeWidget only supports **OpenGL2** rendering backend.
|
|
||||||
* myQVTKOpenGLNativeWidget does not support stereo,
|
|
||||||
* please use QVTKOpenGLWidget if you need support for stereo rendering
|
|
||||||
*
|
|
||||||
* myQVTKOpenGLNativeWidget is targeted for Qt version 5.5 and above.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef myQVTKOpenGLNativeWidget_h
|
|
||||||
#define myQVTKOpenGLNativeWidget_h
|
|
||||||
|
|
||||||
#include <QOpenGLWidget>
|
|
||||||
|
|
||||||
#include "QVTKInteractor.h" // needed for QVTKInteractor
|
|
||||||
#include "vtkGUISupportQtModule.h" // for export macro
|
|
||||||
#include "vtkNew.h" // needed for vtkNew
|
|
||||||
#include "vtkSmartPointer.h" // needed for vtkSmartPointer
|
|
||||||
|
|
||||||
class QOpenGLDebugLogger;
|
|
||||||
class QOpenGLFramebufferObject;
|
|
||||||
class QVTKInteractor;
|
|
||||||
class QVTKInteractorAdapter;
|
|
||||||
class QVTKOpenGLNativeWidgetObserver;
|
|
||||||
class vtkGenericOpenGLRenderWindow;
|
|
||||||
class DicomImageView;
|
|
||||||
|
|
||||||
//class VTKGUISUPPORTQT_EXPORT myQVTKOpenGLNativeWidget : public QOpenGLWidget
|
|
||||||
class myQVTKOpenGLNativeWidget : public QOpenGLWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
typedef QOpenGLWidget Superclass;
|
|
||||||
public:
|
|
||||||
myQVTKOpenGLNativeWidget(QWidget* parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
|
||||||
~myQVTKOpenGLNativeWidget() override;
|
|
||||||
|
|
||||||
//@{
|
|
||||||
/**
|
|
||||||
* Get/Set the currently used vtkGenericOpenGLRenderWindow.
|
|
||||||
* GetRenderWindow() creates and returns a new vtkGenericOpenGLRenderWindow
|
|
||||||
* if it is not already provided.
|
|
||||||
*/
|
|
||||||
void SetImageView(DicomImageView *v);
|
|
||||||
DicomImageView* GetImageView();
|
|
||||||
|
|
||||||
void SetRenderWindow(vtkGenericOpenGLRenderWindow* win);
|
|
||||||
void SetRenderWindow(vtkRenderWindow* win);
|
|
||||||
virtual vtkRenderWindow* GetRenderWindow();
|
|
||||||
//@}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the QEvent to VTK events translator.
|
|
||||||
*/
|
|
||||||
virtual QVTKInteractorAdapter* GetInteractorAdapter() { return this->InteractorAdapter; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the QVTKInteractor that was either created by default or set by the user.
|
|
||||||
*/
|
|
||||||
virtual QVTKInteractor* GetInteractor();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up vtkRenderWindow ivars using QSurfaceFormat.
|
|
||||||
*/
|
|
||||||
static void copyFromFormat(const QSurfaceFormat& format, vtkRenderWindow* win);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Using the vtkRenderWindow, setup QSurfaceFormat.
|
|
||||||
*/
|
|
||||||
static void copyToFormat(vtkRenderWindow* win, QSurfaceFormat& format);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a typical QSurfaceFormat suitable for most applications using
|
|
||||||
* myQVTKOpenGLNativeWidget. Note that this is not the QSurfaceFormat that gets used
|
|
||||||
* if none is specified. That is set using `QSurfaceFormat::setDefaultFormat`.
|
|
||||||
*/
|
|
||||||
static QSurfaceFormat defaultFormat();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable support for HiDPI displays.
|
|
||||||
*/
|
|
||||||
virtual void setEnableHiDPI(bool enable);
|
|
||||||
virtual bool enableHiDPI() { return this->EnableHiDPI; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the cursor on this widget.
|
|
||||||
*/
|
|
||||||
void setQVTKCursor(const QCursor &cursor);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
/**
|
|
||||||
* This signal will be emitted whenever a mouse event occurs within the QVTK window.
|
|
||||||
*/
|
|
||||||
void mouseEvent(QMouseEvent* event);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
/**
|
|
||||||
* Called as a response to `QOpenGLContext::aboutToBeDestroyed`. This may be
|
|
||||||
* called anytime during the widget lifecycle. We need to release any OpenGL
|
|
||||||
* resources allocated in VTK work in this method.
|
|
||||||
*/
|
|
||||||
virtual void cleanupContext();
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
/**
|
|
||||||
* recreates the FBO used for VTK rendering.
|
|
||||||
*/
|
|
||||||
void recreateFBO();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* called before the render window starts to render. We ensure that this->FBO
|
|
||||||
* is bound and ready to use.
|
|
||||||
*/
|
|
||||||
void startEventCallback();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* callback for changing the cursor. Called when vtkGenericOpenGLRenderWindow
|
|
||||||
* fires the CursorChangedEvent.
|
|
||||||
*/
|
|
||||||
void cursorChangedCallback(vtkObject* caller, unsigned long vtk_event,
|
|
||||||
void* client_data, void* call_data);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//virtual void wheelEvent(QWheelEvent *event);
|
|
||||||
|
|
||||||
bool event(QEvent* evt) Q_DECL_OVERRIDE;
|
|
||||||
void initializeGL() Q_DECL_OVERRIDE;
|
|
||||||
void resizeGL(int w, int h) Q_DECL_OVERRIDE;
|
|
||||||
void paintGL() Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
//void mousePressEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
|
||||||
//void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
|
||||||
//void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
|
||||||
//void mouseDoubleClickEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method is called to indicate that vtkRenderWindow needs to reinitialize
|
|
||||||
* itself before the next render (done in myQVTKOpenGLNativeWidget::paintGL).
|
|
||||||
* This is needed when the context gets recreated
|
|
||||||
* or the default FrameBufferObject gets recreated, for example.
|
|
||||||
*/
|
|
||||||
void requireRenderWindowInitialization();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method may be called in `paintGL` to request VTK to do a render i.e.
|
|
||||||
* trigger render on the render window via its interactor.
|
|
||||||
*
|
|
||||||
* It will return true if render (or an equivalent action) was performed to
|
|
||||||
* update the frame buffer made available to VTK for rendering with latest
|
|
||||||
* rendering.
|
|
||||||
*
|
|
||||||
* Default implementation never returns false. However, subclasses can return
|
|
||||||
* false to indicate to myQVTKOpenGLNativeWidget that it cannot generate a reasonable
|
|
||||||
* image to be displayed in myQVTKOpenGLNativeWidget. In which case, the `paintGL`
|
|
||||||
* call will return leaving the `defaultFramebufferObject` untouched.
|
|
||||||
*
|
|
||||||
* Since by default `QOpenGLWidget::UpdateBehavior` is set to
|
|
||||||
* QOpenGLWidget::PartialUpdate, this means whatever was rendered in the frame
|
|
||||||
* buffer in most recent successful call will be preserved, unless the widget
|
|
||||||
* was forced to recreate the FBO as a result of resize or screen change.
|
|
||||||
*
|
|
||||||
* @sa Section @ref RenderAndPaint.
|
|
||||||
*/
|
|
||||||
virtual bool renderVTK();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
vtkSmartPointer<vtkGenericOpenGLRenderWindow> RenderWindow;
|
|
||||||
QVTKInteractorAdapter* InteractorAdapter;
|
|
||||||
|
|
||||||
bool EnableHiDPI;
|
|
||||||
int OriginalDPI;
|
|
||||||
|
|
||||||
static const double DevicePixelRatioTolerance;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Q_DISABLE_COPY(myQVTKOpenGLNativeWidget);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when vtkCommand::WindowFrameEvent is fired by the
|
|
||||||
* vtkGenericOpenGLRenderWindow.
|
|
||||||
*/
|
|
||||||
void windowFrameEventCallback();
|
|
||||||
|
|
||||||
QOpenGLFramebufferObject* FBO;
|
|
||||||
bool InPaintGL;
|
|
||||||
bool DoVTKRenderInPaintGL;
|
|
||||||
vtkNew<QVTKOpenGLNativeWidgetObserver> Observer;
|
|
||||||
friend class QVTKOpenGLNativeWidgetObserver;
|
|
||||||
QOpenGLDebugLogger* Logger;
|
|
||||||
DicomImageView *view;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -36,13 +36,13 @@ DicomImageView::DicomImageView(QWidget* parent)
|
|||||||
|
|
||||||
QGridLayout* controlLayout = new QGridLayout(wrapper);
|
QGridLayout* controlLayout = new QGridLayout(wrapper);
|
||||||
|
|
||||||
_glWidt = new myQVTKOpenGLNativeWidget(wrapper);
|
_glWidt = new QVTKOpenGLNativeWidget(wrapper);
|
||||||
|
|
||||||
m_glrenWin = vtkSmartPointer <vtkGenericOpenGLRenderWindow>::New();
|
m_glrenWin = vtkSmartPointer <vtkGenericOpenGLRenderWindow>::New();
|
||||||
//m_glrenWin->SetOffScreenRendering(1); //for offscreen rendering
|
//m_glrenWin->SetOffScreenRendering(1); //for offscreen rendering
|
||||||
_glWidt->SetRenderWindow(m_glrenWin);//set up interacte
|
_glWidt->SetRenderWindow(m_glrenWin);//set up interacte
|
||||||
//in order to visit in both way!
|
//in order to visit in both way!
|
||||||
_glWidt->SetImageView(this);
|
// _glWidt->SetImageView(this);
|
||||||
|
|
||||||
controlLayout->addWidget(_glWidt, 0, 0);
|
controlLayout->addWidget(_glWidt, 0, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -1,821 +0,0 @@
|
|||||||
/*=========================================================================
|
|
||||||
|
|
||||||
Program: Visualization Toolkit
|
|
||||||
Module: myQVTKOpenGLNativeWidget.cxx
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
=========================================================================*/
|
|
||||||
#include "view/myQVTKOpenGLNativeWidget.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QDesktopWidget>
|
|
||||||
#include <QMouseEvent>
|
|
||||||
#include <QOpenGLContext>
|
|
||||||
#include <QOpenGLDebugLogger>
|
|
||||||
#include <QOpenGLFramebufferObject>
|
|
||||||
#include <QOpenGLFunctions>
|
|
||||||
#include <QOpenGLFunctions_3_2_Core>
|
|
||||||
#include <QOpenGLTexture>
|
|
||||||
#include <QPointer>
|
|
||||||
#include <QScopedValueRollback>
|
|
||||||
#include <QtDebug>
|
|
||||||
|
|
||||||
#include "QVTKInteractor.h"
|
|
||||||
#include "QVTKInteractorAdapter.h"
|
|
||||||
#include "vtkCommand.h"
|
|
||||||
#include "vtkGenericOpenGLRenderWindow.h"
|
|
||||||
#include "vtkInteractorStyleTrackballCamera.h"
|
|
||||||
#include "vtkNew.h"
|
|
||||||
#include "vtkObjectFactory.h"
|
|
||||||
#include "vtkOpenGLState.h"
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include "QVTKOpenGLWidget.h"
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unused except on MacOS.
|
|
||||||
* In an application using both QVTKOpenGLWidget
|
|
||||||
* and myQVTKOpenGLNativeWidget, this bug can appear:
|
|
||||||
* https://bugreports.qt.io/browse/QTBUG-69644
|
|
||||||
*/
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* It is needed to switch the visibility of currently visible QVTKOpenGLWidget
|
|
||||||
* back and forth (ie hide then show). Just after initialization of myQVTKOpenGLNativeWidget
|
|
||||||
* (ie when we receive WindowActivate event, or PolishRequest event)
|
|
||||||
* This method takes care of it.
|
|
||||||
*/
|
|
||||||
void QVTKOpenGLWidgetMacOSCheck(QWidget* window)
|
|
||||||
{
|
|
||||||
// Used a static to ensure the fix is done only once
|
|
||||||
static bool QVTKOpenGLWidgetMacOSFixed = false;
|
|
||||||
|
|
||||||
if (QVTKOpenGLWidgetMacOSFixed || !window)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch visibility back and forth of visible QVTKOpenGLWidgets
|
|
||||||
// that share the same window as this myQVTKOpenGLNativeWidget.
|
|
||||||
// This ensures they come back on the front after the Qt bug happens.
|
|
||||||
auto widgets = window->findChildren<QVTKOpenGLWidget*>();
|
|
||||||
for (auto qvglWidget : widgets)
|
|
||||||
{
|
|
||||||
if (qvglWidget->isVisible())
|
|
||||||
{
|
|
||||||
qvglWidget->hide();
|
|
||||||
qvglWidget->show();
|
|
||||||
QVTKOpenGLWidgetMacOSFixed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // __APPLE__
|
|
||||||
|
|
||||||
// #define DEBUG_QVTKOPENGL_WIDGET
|
|
||||||
#ifdef DEBUG_QVTKOPENGL_WIDGET
|
|
||||||
#define vtkmyQVTKOpenGLNativeWidgetDebugMacro(msg) \
|
|
||||||
cout << this << ": " msg << endl; \
|
|
||||||
if (this->Logger) \
|
|
||||||
{ \
|
|
||||||
this->Logger->logMessage( \
|
|
||||||
QOpenGLDebugMessage::createApplicationMessage(QStringLiteral("myQVTKOpenGLNativeWidget::" msg))); \
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define vtkmyQVTKOpenGLNativeWidgetDebugMacro(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class QVTKOpenGLNativeWidgetObserver : public vtkCommand
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static QVTKOpenGLNativeWidgetObserver* New() { return new QVTKOpenGLNativeWidgetObserver(); }
|
|
||||||
vtkTypeMacro(QVTKOpenGLNativeWidgetObserver, vtkCommand);
|
|
||||||
|
|
||||||
void SetTarget(myQVTKOpenGLNativeWidget* target) { this->Target = target; }
|
|
||||||
|
|
||||||
void Execute(vtkObject* object, unsigned long eventId, void* callData) override
|
|
||||||
{
|
|
||||||
if (this->Target)
|
|
||||||
{
|
|
||||||
switch (eventId)
|
|
||||||
{
|
|
||||||
case vtkCommand::WindowMakeCurrentEvent:
|
|
||||||
{
|
|
||||||
// We do not call QOpenGLWidget::makeCurrent() as that also makes the
|
|
||||||
// frame buffer object used by QOpenGLWidget active. This can have
|
|
||||||
// unintended side effects when MakeCurrent gets called in a
|
|
||||||
// render-pass, for example. We should only be making the context
|
|
||||||
// active. To do that, we use this trick. We rely on the
|
|
||||||
// QOpenGLContext have been called makeCurrent() previously so we
|
|
||||||
// can get to the surface that was used to do that. We simply
|
|
||||||
// reactivate on that surface.
|
|
||||||
QOpenGLContext* ctxt = this->Target->context();
|
|
||||||
QSurface* surface = ctxt ? ctxt->surface() : nullptr;
|
|
||||||
if (surface)
|
|
||||||
{
|
|
||||||
ctxt->makeCurrent(surface);
|
|
||||||
}
|
|
||||||
Q_ASSERT(ctxt == nullptr || surface != nullptr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case vtkCommand::WindowIsCurrentEvent:
|
|
||||||
{
|
|
||||||
bool& cstatus = *reinterpret_cast<bool*>(callData);
|
|
||||||
cstatus = (QOpenGLContext::currentContext() == this->Target->context());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case vtkCommand::WindowFrameEvent:
|
|
||||||
this->Target->windowFrameEventCallback();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case vtkCommand::StartEvent:
|
|
||||||
VTK_FALLTHROUGH;
|
|
||||||
case vtkCommand::StartPickEvent:
|
|
||||||
this->Target->startEventCallback();
|
|
||||||
break;
|
|
||||||
case vtkCommand::CursorChangedEvent:
|
|
||||||
this->Target->cursorChangedCallback(object, eventId, nullptr, callData);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QVTKOpenGLNativeWidgetObserver() {}
|
|
||||||
~QVTKOpenGLNativeWidgetObserver() override {}
|
|
||||||
QPointer<myQVTKOpenGLNativeWidget> Target;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Tolerance used when truncating the device pixel ratio scaled
|
|
||||||
// window size in calls to SetSize / SetPosition.
|
|
||||||
const double myQVTKOpenGLNativeWidget::DevicePixelRatioTolerance = 1e-5;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
myQVTKOpenGLNativeWidget::myQVTKOpenGLNativeWidget(QWidget* parentWdg, Qt::WindowFlags f)
|
|
||||||
: Superclass(parentWdg, f)
|
|
||||||
, InteractorAdapter(nullptr)
|
|
||||||
, EnableHiDPI(false)
|
|
||||||
, OriginalDPI(0)
|
|
||||||
, FBO(nullptr)
|
|
||||||
, InPaintGL(false)
|
|
||||||
, DoVTKRenderInPaintGL(false)
|
|
||||||
, Logger(nullptr)
|
|
||||||
{
|
|
||||||
this->Observer->SetTarget(this);
|
|
||||||
|
|
||||||
// default to strong focus
|
|
||||||
this->setFocusPolicy(Qt::StrongFocus);
|
|
||||||
|
|
||||||
this->setUpdateBehavior(QOpenGLWidget::PartialUpdate);
|
|
||||||
|
|
||||||
this->InteractorAdapter = new QVTKInteractorAdapter(this);
|
|
||||||
this->InteractorAdapter->SetDevicePixelRatio(this->devicePixelRatio());
|
|
||||||
|
|
||||||
this->setMouseTracking(true);
|
|
||||||
|
|
||||||
// QOpenGLWidget::resized() is triggered when the default FBO in QOpenGLWidget is recreated.
|
|
||||||
// We use the same signal to recreate our FBO.
|
|
||||||
this->connect(this, SIGNAL(resized()), SLOT(recreateFBO()));
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
myQVTKOpenGLNativeWidget::~myQVTKOpenGLNativeWidget()
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("~myQVTKOpenGLNativeWidget");
|
|
||||||
// essential to cleanup context so that the render window finalizes and
|
|
||||||
// releases any graphics resources it may have allocated.
|
|
||||||
this->cleanupContext();
|
|
||||||
this->SetRenderWindow(static_cast<vtkGenericOpenGLRenderWindow*>(nullptr));
|
|
||||||
this->Observer->SetTarget(nullptr);
|
|
||||||
delete this->InteractorAdapter;
|
|
||||||
delete this->Logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
void myQVTKOpenGLNativeWidget::SetImageView(DicomImageView *v)
|
|
||||||
{
|
|
||||||
this->view = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
DicomImageView* myQVTKOpenGLNativeWidget::GetImageView()
|
|
||||||
{
|
|
||||||
return this->view;
|
|
||||||
}
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::SetRenderWindow(vtkRenderWindow* win)
|
|
||||||
{
|
|
||||||
vtkGenericOpenGLRenderWindow* gwin = vtkGenericOpenGLRenderWindow::SafeDownCast(win);
|
|
||||||
this->SetRenderWindow(gwin);
|
|
||||||
if (gwin == nullptr && win != nullptr)
|
|
||||||
{
|
|
||||||
qDebug() << "myQVTKOpenGLNativeWidget requires a `vtkGenericOpenGLRenderWindow`. `"
|
|
||||||
<< win->GetClassName() << "` is not supported.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::SetRenderWindow(vtkGenericOpenGLRenderWindow* win)
|
|
||||||
{
|
|
||||||
if (this->RenderWindow == win)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
this->RenderWindow->RemoveObserver(this->Observer);
|
|
||||||
this->RenderWindow->SetReadyForRendering(false);
|
|
||||||
}
|
|
||||||
this->RenderWindow = win;
|
|
||||||
this->requireRenderWindowInitialization();
|
|
||||||
if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
// set this to 0 to reinitialize it before setting the RenderWindow DPI
|
|
||||||
this->OriginalDPI = 0;
|
|
||||||
|
|
||||||
// if an interactor wasn't provided, we'll make one by default
|
|
||||||
if (!this->RenderWindow->GetInteractor())
|
|
||||||
{
|
|
||||||
// create a default interactor
|
|
||||||
vtkNew<QVTKInteractor> iren;
|
|
||||||
// iren->SetUseTDx(this->UseTDx);
|
|
||||||
this->RenderWindow->SetInteractor(iren);
|
|
||||||
iren->Initialize();
|
|
||||||
|
|
||||||
// now set the default style
|
|
||||||
vtkNew<vtkInteractorStyleTrackballCamera> style;
|
|
||||||
iren->SetInteractorStyle(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::WindowMakeCurrentEvent, this->Observer);
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::WindowIsCurrentEvent, this->Observer);
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::WindowFrameEvent, this->Observer);
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::StartEvent, this->Observer);
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::StartPickEvent, this->Observer);
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::StartPickEvent, this->Observer);
|
|
||||||
this->RenderWindow->AddObserver(vtkCommand::CursorChangedEvent, this->Observer);
|
|
||||||
|
|
||||||
if (this->FBO)
|
|
||||||
{
|
|
||||||
this->makeCurrent();
|
|
||||||
this->recreateFBO();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::startEventCallback()
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("startEventCallback");
|
|
||||||
this->makeCurrent();
|
|
||||||
if (this->FBO)
|
|
||||||
{
|
|
||||||
// ensure that before vtkRenderWindow starts to render, we activate the FBO
|
|
||||||
// to render into. VTK code can be a bit lax with it. This just ensures that
|
|
||||||
// we have the FBO activated.
|
|
||||||
this->FBO->bind();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
vtkRenderWindow* myQVTKOpenGLNativeWidget::GetRenderWindow()
|
|
||||||
{
|
|
||||||
if (!this->RenderWindow)
|
|
||||||
{
|
|
||||||
// create a default
|
|
||||||
vtkGenericOpenGLRenderWindow* win = vtkGenericOpenGLRenderWindow::New();
|
|
||||||
this->SetRenderWindow(win);
|
|
||||||
win->Delete();
|
|
||||||
}
|
|
||||||
return this->RenderWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
QVTKInteractor* myQVTKOpenGLNativeWidget::GetInteractor()
|
|
||||||
{
|
|
||||||
return QVTKInteractor::SafeDownCast(this->GetRenderWindow()->GetInteractor());
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::copyFromFormat(const QSurfaceFormat& format, vtkRenderWindow* win)
|
|
||||||
{
|
|
||||||
if (vtkOpenGLRenderWindow* oglWin = vtkOpenGLRenderWindow::SafeDownCast(win))
|
|
||||||
{
|
|
||||||
oglWin->SetStereoCapableWindow(format.stereo() ? 1 : 0);
|
|
||||||
// samples may not be correct if format is obtained from
|
|
||||||
// QOpenGLWidget::format() after the context is created. That's because
|
|
||||||
// QOpenGLWidget always created context to samples=0.
|
|
||||||
oglWin->SetMultiSamples(format.samples());
|
|
||||||
oglWin->SetStencilCapable(format.stencilBufferSize() > 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::copyToFormat(vtkRenderWindow* win, QSurfaceFormat& format)
|
|
||||||
{
|
|
||||||
if (vtkOpenGLRenderWindow* oglWin = vtkOpenGLRenderWindow::SafeDownCast(win))
|
|
||||||
{
|
|
||||||
format.setStereo(oglWin->GetStereoCapableWindow());
|
|
||||||
format.setSamples(oglWin->GetMultiSamples());
|
|
||||||
format.setStencilBufferSize(oglWin->GetStencilCapable() ? 8 : 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
QSurfaceFormat myQVTKOpenGLNativeWidget::defaultFormat()
|
|
||||||
{
|
|
||||||
QSurfaceFormat fmt;
|
|
||||||
fmt.setRenderableType(QSurfaceFormat::OpenGL);
|
|
||||||
fmt.setVersion(3, 2);
|
|
||||||
fmt.setProfile(QSurfaceFormat::CoreProfile);
|
|
||||||
fmt.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
|
|
||||||
fmt.setRedBufferSize(1);
|
|
||||||
fmt.setGreenBufferSize(1);
|
|
||||||
fmt.setBlueBufferSize(1);
|
|
||||||
fmt.setDepthBufferSize(1);
|
|
||||||
fmt.setStencilBufferSize(0);
|
|
||||||
fmt.setAlphaBufferSize(1);
|
|
||||||
fmt.setStereo(false);
|
|
||||||
fmt.setSamples(vtkOpenGLRenderWindow::GetGlobalMaximumNumberOfMultiSamples());
|
|
||||||
#ifdef DEBUG_QVTKOPENGL_WIDGET
|
|
||||||
fmt.setOption(QSurfaceFormat::DebugContext);
|
|
||||||
#endif
|
|
||||||
return fmt;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::setEnableHiDPI(bool enable)
|
|
||||||
{
|
|
||||||
this->EnableHiDPI = enable;
|
|
||||||
|
|
||||||
if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
if (this->OriginalDPI == 0)
|
|
||||||
{
|
|
||||||
this->OriginalDPI = this->RenderWindow->GetDPI();
|
|
||||||
}
|
|
||||||
if (this->EnableHiDPI)
|
|
||||||
{
|
|
||||||
this->RenderWindow->SetDPI(this->OriginalDPI * this->devicePixelRatio());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
this->RenderWindow->SetDPI(this->OriginalDPI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::setQVTKCursor(const QCursor &cursor)
|
|
||||||
{
|
|
||||||
this->setCursor(cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::recreateFBO()
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("recreateFBO");
|
|
||||||
delete this->FBO;
|
|
||||||
this->FBO = nullptr;
|
|
||||||
if (!this->RenderWindow)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since myQVTKOpenGLNativeWidget::initializeGL() cannot set multi-samples
|
|
||||||
// state on the RenderWindow correctly, we do it here.
|
|
||||||
QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
|
|
||||||
GLint samples;
|
|
||||||
f->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
|
|
||||||
|
|
||||||
// Some graphics drivers report the number of samples as 1 when
|
|
||||||
// multisampling is off. Set the number of samples to 0 in this case.
|
|
||||||
samples = samples > 1 ? samples : 0;
|
|
||||||
this->RenderWindow->SetMultiSamples(static_cast<int>(samples));
|
|
||||||
|
|
||||||
QOpenGLFramebufferObjectFormat format;
|
|
||||||
format.setAttachment(QOpenGLFramebufferObject::Depth);
|
|
||||||
format.setSamples(samples);
|
|
||||||
|
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
|
|
||||||
// Qt < 5.6 only has an integer API for device pixel ratio.
|
|
||||||
const double devicePixelRatio_ = this->devicePixelRatio();
|
|
||||||
#else
|
|
||||||
const double devicePixelRatio_ = this->devicePixelRatioF();
|
|
||||||
#endif
|
|
||||||
const QSize widgetSize = this->size();
|
|
||||||
const QSize deviceSize = QSize(static_cast<int>(widgetSize.width() * devicePixelRatio_ + DevicePixelRatioTolerance),
|
|
||||||
static_cast<int>(widgetSize.height() * devicePixelRatio_ + DevicePixelRatioTolerance));
|
|
||||||
|
|
||||||
// This is as good an opportunity as any to communicate size to the render
|
|
||||||
// window.
|
|
||||||
this->InteractorAdapter->SetDevicePixelRatio(devicePixelRatio_);
|
|
||||||
if (vtkRenderWindowInteractor* iren = this->RenderWindow->GetInteractor())
|
|
||||||
{
|
|
||||||
iren->SetSize(deviceSize.width(), deviceSize.height());
|
|
||||||
}
|
|
||||||
this->RenderWindow->SetSize(deviceSize.width(), deviceSize.height());
|
|
||||||
this->RenderWindow->SetPosition(static_cast<int>(this->x() * devicePixelRatio_ + DevicePixelRatioTolerance),
|
|
||||||
static_cast<int>(this->y() * devicePixelRatio_ + DevicePixelRatioTolerance));
|
|
||||||
|
|
||||||
// Set screen size on render window.
|
|
||||||
const QRect screenGeometry = QApplication::desktop()->screenGeometry(this);
|
|
||||||
this->RenderWindow->SetScreenSize(screenGeometry.width(), screenGeometry.height());
|
|
||||||
|
|
||||||
this->FBO = new QOpenGLFramebufferObject(deviceSize, format);
|
|
||||||
this->FBO->bind();
|
|
||||||
this->RenderWindow->SetForceMaximumHardwareLineWidth(1);
|
|
||||||
this->RenderWindow->SetReadyForRendering(true);
|
|
||||||
this->RenderWindow->InitializeFromCurrentContext();
|
|
||||||
|
|
||||||
this->setEnableHiDPI(this->EnableHiDPI);
|
|
||||||
|
|
||||||
// Since the context or frame buffer was recreated, if a paintGL call ensues,
|
|
||||||
// we need to ensure we're requesting VTK to render.
|
|
||||||
this->DoVTKRenderInPaintGL = true;
|
|
||||||
|
|
||||||
// Clear to ensure that an uninitialized framebuffer is never displayed.
|
|
||||||
vtkOpenGLState *ostate = this->RenderWindow->GetState();
|
|
||||||
// have to keep vtk state up to date as well
|
|
||||||
ostate->vtkglDisable(GL_SCISSOR_TEST);
|
|
||||||
ostate->vtkglClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
ostate->vtkglViewport(0, 0, deviceSize.width(), deviceSize.height());
|
|
||||||
f->glDisable(GL_SCISSOR_TEST);
|
|
||||||
f->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::initializeGL()
|
|
||||||
{
|
|
||||||
this->Superclass::initializeGL();
|
|
||||||
|
|
||||||
#ifdef DEBUG_QVTKOPENGL_WIDGET
|
|
||||||
delete this->Logger;
|
|
||||||
this->Logger = new QOpenGLDebugLogger(this);
|
|
||||||
this->Logger->initialize(); // initializes in the current context.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("initializeGL");
|
|
||||||
if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
// use QSurfaceFormat for the widget, update ivars on the vtkRenderWindow.
|
|
||||||
myQVTKOpenGLNativeWidget::copyFromFormat(this->format(), this->RenderWindow);
|
|
||||||
// When a QOpenGLWidget is told to use a QSurfaceFormat with samples > 0,
|
|
||||||
// QOpenGLWidget doesn't actually create a context with multi-samples and
|
|
||||||
// internally changes the QSurfaceFormat to be samples=0. Thus, we can't
|
|
||||||
// rely on the QSurfaceFormat to indicate to us if multisampling is being
|
|
||||||
// used. We should use glGetRenderbufferParameteriv(..) to get
|
|
||||||
// GL_RENDERBUFFER_SAMPLES to determine the samples used. This is done by
|
|
||||||
// in recreateFBO().
|
|
||||||
}
|
|
||||||
this->connect(
|
|
||||||
this->context(), SIGNAL(aboutToBeDestroyed()), SLOT(cleanupContext()), Qt::UniqueConnection);
|
|
||||||
this->requireRenderWindowInitialization();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::requireRenderWindowInitialization()
|
|
||||||
{
|
|
||||||
if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
this->RenderWindow->SetReadyForRendering(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::resizeGL(int w, int h)
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("resizeGL");
|
|
||||||
this->Superclass::resizeGL(w, h);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::paintGL()
|
|
||||||
{
|
|
||||||
if (this->InPaintGL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->RenderWindow)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this->FBO
|
|
||||||
|| this->FBO->handle() != this->RenderWindow->GetDefaultFrameBufferId())
|
|
||||||
{
|
|
||||||
this->recreateFBO();
|
|
||||||
}
|
|
||||||
|
|
||||||
QScopedValueRollback<bool> var(this->InPaintGL, true);
|
|
||||||
this->Superclass::paintGL();
|
|
||||||
|
|
||||||
if (this->DoVTKRenderInPaintGL && !this->renderVTK())
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("paintGL:skipped-renderVTK");
|
|
||||||
// This should be very rare, but it's conceivable that subclasses of
|
|
||||||
// myQVTKOpenGLNativeWidget are simply not ready to do a
|
|
||||||
// render on VTK render window when widget is being painted.
|
|
||||||
// Leave the buffer unchanged.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We just did a render, if we needed it. Turn the flag off.
|
|
||||||
this->DoVTKRenderInPaintGL = false;
|
|
||||||
|
|
||||||
// If render was triggered by above calls, that may change the current context
|
|
||||||
// due to things like progress events triggering updates on other widgets
|
|
||||||
// (e.g. progress bar). Hence we need to make sure to call makeCurrent()
|
|
||||||
// before proceeding with blit-ing.
|
|
||||||
this->makeCurrent();
|
|
||||||
|
|
||||||
// blit from this->FBO to QOpenGLWidget's FBO.
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("paintGL::blit-to-defaultFBO");
|
|
||||||
QOpenGLFunctions_3_2_Core* f =
|
|
||||||
QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>();
|
|
||||||
if (f)
|
|
||||||
{
|
|
||||||
vtkOpenGLState *ostate = this->RenderWindow->GetState();
|
|
||||||
|
|
||||||
f->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->defaultFramebufferObject());
|
|
||||||
f->glDrawBuffer(GL_COLOR_ATTACHMENT0);
|
|
||||||
|
|
||||||
f->glBindFramebuffer(GL_READ_FRAMEBUFFER, this->FBO->handle());
|
|
||||||
f->glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
||||||
|
|
||||||
// The viewport state may be modified outside the vtkOpenGLState mechanism, so reset the state here.
|
|
||||||
ostate->ResetGlViewportState();
|
|
||||||
|
|
||||||
// If you get a vtkOpenGLState warning from the call below, you can add
|
|
||||||
// a call to ostate->ResetEnumState(GL_SCISSOR_TEST); to reset the cache state
|
|
||||||
// to whatever the value in OpenGL is.
|
|
||||||
ostate->vtkglDisable(GL_SCISSOR_TEST); // Scissor affects glBindFramebuffer.
|
|
||||||
f->glBlitFramebuffer(0, 0, this->RenderWindow->GetSize()[0], this->RenderWindow->GetSize()[1],
|
|
||||||
0, 0, this->RenderWindow->GetSize()[0], this->RenderWindow->GetSize()[1], GL_COLOR_BUFFER_BIT,
|
|
||||||
GL_NEAREST);
|
|
||||||
|
|
||||||
// now clear alpha otherwise we end up blending the rendering with
|
|
||||||
// background windows in certain cases. It happens on OsX
|
|
||||||
// (if QSurfaceFormat::alphaBufferSize() > 0) or when using Mesa on Linux
|
|
||||||
// (see paraview/paraview#17159).
|
|
||||||
GLboolean colorMask[4];
|
|
||||||
f->glGetBooleanv(GL_COLOR_WRITEMASK, colorMask);
|
|
||||||
f->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
|
|
||||||
|
|
||||||
GLfloat clearColor[4];
|
|
||||||
f->glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor);
|
|
||||||
f->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
f->glColorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
|
|
||||||
f->glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::cleanupContext()
|
|
||||||
{
|
|
||||||
// logger gets uninitialized when this gets called. We get errors from
|
|
||||||
// QOpenGLDebugLogger if logMessage is called here. So we just destroy the
|
|
||||||
// logger.
|
|
||||||
delete this->Logger;
|
|
||||||
this->Logger = nullptr;
|
|
||||||
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("cleanupContext");
|
|
||||||
|
|
||||||
// QOpenGLWidget says when this slot is called, the context may not be current
|
|
||||||
// and hence is a good practice to make it so.
|
|
||||||
this->makeCurrent();
|
|
||||||
if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
if (this->FBO)
|
|
||||||
{
|
|
||||||
this->FBO->bind();
|
|
||||||
}
|
|
||||||
this->RenderWindow->Finalize();
|
|
||||||
this->RenderWindow->SetReadyForRendering(false);
|
|
||||||
}
|
|
||||||
delete this->FBO;
|
|
||||||
this->FBO = nullptr;
|
|
||||||
this->requireRenderWindowInitialization();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::windowFrameEventCallback()
|
|
||||||
{
|
|
||||||
Q_ASSERT(this->RenderWindow);
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("frame");
|
|
||||||
|
|
||||||
if (!this->InPaintGL)
|
|
||||||
{
|
|
||||||
// Handing vtkOpenGLRenderWindow::Frame is tricky. VTK code traditionally
|
|
||||||
// calls `Frame` to indicate that VTK is done rendering 1 frame. Now, when
|
|
||||||
// that happens, should we tell Qt to update the widget -- that's the
|
|
||||||
// question? In general, yes, but sometimes VTK does things in the
|
|
||||||
// background i.e. back buffer without wanting to update the front buffer
|
|
||||||
// e.g. when making selections. In that case, we don't want to update Qt
|
|
||||||
// widget either, since whatever it did was not meant to be visible.
|
|
||||||
// To handle that, we check if vtkOpenGLRenderWindow::SwapBuffers is true,
|
|
||||||
// and request an update only when it is.
|
|
||||||
if (this->RenderWindow->GetSwapBuffers() || this->RenderWindow->GetDoubleBuffer() == 0)
|
|
||||||
{
|
|
||||||
// Means that the vtkRenderWindow rendered outside a paintGL call. That can
|
|
||||||
// happen when application code call vtkRenderWindow::Render() directly,
|
|
||||||
// instead of calling myQVTKOpenGLNativeWidget::update() or letting Qt update the
|
|
||||||
// widget. In that case, since QOpenGLWidget rendering into an offscreen
|
|
||||||
// FBO, the result still needs to be composed by Qt widget stack. We request
|
|
||||||
// that using `update()`.
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("update");
|
|
||||||
this->update();
|
|
||||||
|
|
||||||
this->DoVTKRenderInPaintGL = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("buffer bad -- do not show");
|
|
||||||
|
|
||||||
// Since this->FBO right now is garbage, if paint event is received before
|
|
||||||
// a Render request is made on the render window, we will have to Render
|
|
||||||
// explicitly.
|
|
||||||
this->DoVTKRenderInPaintGL = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
bool myQVTKOpenGLNativeWidget::renderVTK()
|
|
||||||
{
|
|
||||||
vtkmyQVTKOpenGLNativeWidgetDebugMacro("renderVTK");
|
|
||||||
Q_ASSERT(this->FBO);
|
|
||||||
Q_ASSERT(this->FBO->handle() == this->RenderWindow->GetDefaultFrameBufferId());
|
|
||||||
|
|
||||||
// Bind the FBO we'll be rendering into. This may not be needed, since VTK will
|
|
||||||
// bind it anyways, but we'll be extra cautious.
|
|
||||||
this->FBO->bind();
|
|
||||||
|
|
||||||
vtkRenderWindowInteractor* iren = this->RenderWindow ? this->RenderWindow->GetInteractor() : nullptr;
|
|
||||||
if (iren)
|
|
||||||
{
|
|
||||||
iren->Render();
|
|
||||||
}
|
|
||||||
else if (this->RenderWindow)
|
|
||||||
{
|
|
||||||
this->RenderWindow->Render();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// no render window set, just fill with white.
|
|
||||||
QOpenGLFunctions* f = QOpenGLContext::currentContext()->functions();
|
|
||||||
f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
|
||||||
f->glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
bool myQVTKOpenGLNativeWidget::event(QEvent* evt)
|
|
||||||
{
|
|
||||||
switch (evt->type())
|
|
||||||
{
|
|
||||||
//case QEvent::MouseMove:
|
|
||||||
//case QEvent::MouseButtonPress:
|
|
||||||
//case QEvent::MouseButtonRelease:
|
|
||||||
//case QEvent::MouseButtonDblClick:
|
|
||||||
// skip events that are explicitly handled by overrides to avoid duplicate
|
|
||||||
// calls to InteractorAdapter->ProcessEvent().
|
|
||||||
//break;
|
|
||||||
|
|
||||||
//case QEvent::Resize:
|
|
||||||
case QEvent::Wheel:
|
|
||||||
// we don't let QVTKInteractorAdapter process resize since we handle it
|
|
||||||
// in this->recreateFBO().
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
// On MacOS, because of https://bugreports.qt.io/browse/QTBUG-69644
|
|
||||||
// It is needed to hide/show currently visible QVTKOpenGLWidget
|
|
||||||
// Just after initialization of myQVTKOpenGLNativeWidget
|
|
||||||
// This triggers a timer so as soon as Qt is able to process events,
|
|
||||||
// it will fix the broken QVTKOpenGLWidgets.
|
|
||||||
case QEvent::WindowActivate:
|
|
||||||
case QEvent::PolishRequest:
|
|
||||||
{
|
|
||||||
QWidget* window = this->window();
|
|
||||||
QTimer::singleShot(1, [window]() {::QVTKOpenGLWidgetMacOSCheck(window); });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif // __APPLE__
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (this->RenderWindow && this->RenderWindow->GetInteractor())
|
|
||||||
{
|
|
||||||
this->InteractorAdapter->ProcessEvent(evt, this->RenderWindow->GetInteractor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this->Superclass::event(evt);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//void myQVTKOpenGLNativeWidget::wheelEvent(QWheelEvent *event)
|
|
||||||
//{
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//void myQVTKOpenGLNativeWidget::mouseMoveEvent(QMouseEvent* event)
|
|
||||||
//{
|
|
||||||
// //emit mouseEvent(event);
|
|
||||||
//
|
|
||||||
// //if (this->RenderWindow && this->RenderWindow->GetInteractor())
|
|
||||||
// //{
|
|
||||||
// // this->InteractorAdapter->ProcessEvent(event,
|
|
||||||
// // this->RenderWindow->GetInteractor());
|
|
||||||
// //}
|
|
||||||
//}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//void myQVTKOpenGLNativeWidget::mouseReleaseEvent(QMouseEvent* event)
|
|
||||||
//{
|
|
||||||
// //emit mouseEvent(event);
|
|
||||||
//
|
|
||||||
// //if (this->RenderWindow && this->RenderWindow->GetInteractor())
|
|
||||||
// //{
|
|
||||||
// // this->InteractorAdapter->ProcessEvent(event,
|
|
||||||
// // this->RenderWindow->GetInteractor());
|
|
||||||
// //}
|
|
||||||
//}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
//void myQVTKOpenGLNativeWidget::mouseDoubleClickEvent(QMouseEvent* event)
|
|
||||||
//{
|
|
||||||
// //emit mouseEvent(event);
|
|
||||||
//
|
|
||||||
// //if (this->RenderWindow && this->RenderWindow->GetInteractor())
|
|
||||||
// //{
|
|
||||||
// // this->InteractorAdapter->ProcessEvent(event,
|
|
||||||
// // this->RenderWindow->GetInteractor());
|
|
||||||
// //}
|
|
||||||
//}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
void myQVTKOpenGLNativeWidget::cursorChangedCallback(vtkObject*, unsigned long,
|
|
||||||
void*, void* call_data)
|
|
||||||
{
|
|
||||||
if (!this->RenderWindow)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int* cShape = reinterpret_cast<int*> (call_data);
|
|
||||||
if (!cShape)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (*cShape)
|
|
||||||
{
|
|
||||||
case VTK_CURSOR_CROSSHAIR:
|
|
||||||
this->setCursor(QCursor(Qt::CrossCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZEALL:
|
|
||||||
this->setCursor(QCursor(Qt::SizeAllCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZENS:
|
|
||||||
this->setCursor(QCursor(Qt::SizeVerCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZEWE:
|
|
||||||
this->setCursor(QCursor(Qt::SizeHorCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZENE:
|
|
||||||
this->setCursor(QCursor(Qt::SizeBDiagCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZENW:
|
|
||||||
this->setCursor(QCursor(Qt::SizeFDiagCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZESE:
|
|
||||||
this->setCursor(QCursor(Qt::SizeFDiagCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_SIZESW:
|
|
||||||
this->setCursor(QCursor(Qt::SizeBDiagCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_HAND:
|
|
||||||
this->setCursor(QCursor(Qt::PointingHandCursor));
|
|
||||||
break;
|
|
||||||
case VTK_CURSOR_ARROW:
|
|
||||||
default:
|
|
||||||
this->setCursor(QCursor(Qt::ArrowCursor));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -207,7 +207,7 @@ void ViewContainerWidget::Slot_SyncEvent(DicomImageView *view, int interactionMo
|
|||||||
void ViewContainerWidget::SetInteractionMode(int InteractionMode)
|
void ViewContainerWidget::SetInteractionMode(int InteractionMode)
|
||||||
{
|
{
|
||||||
for (auto *v : view_list_) {
|
for (auto *v : view_list_) {
|
||||||
myQVTKOpenGLNativeWidget*gl_w = v->getGLWidget();
|
QVTKOpenGLNativeWidget*gl_w = v->getGLWidget();
|
||||||
if (gl_w->GetRenderWindow() && gl_w->GetRenderWindow()->GetInteractor() && v->HasSeries())
|
if (gl_w->GetRenderWindow() && gl_w->GetRenderWindow()->GetInteractor() && v->HasSeries())
|
||||||
{
|
{
|
||||||
infinitiViewer* viewer = v->getSeriesInstance()->getImageViewer2();
|
infinitiViewer* viewer = v->getSeriesInstance()->getImageViewer2();
|
||||||
|
|||||||
Reference in New Issue
Block a user