Remove myQVTKOpenGLNativeWidget

This commit is contained in:
Krad
2022-02-23 11:24:42 +08:00
parent 32628aa41e
commit d810fea7c5
6 changed files with 8 additions and 1115 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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();