diff --git a/Modules/OpenViewCore/include/QVTKFramebufferObjectRenderer.h b/Modules/OpenViewCore/include/QVTKFramebufferObjectRenderer.h index c0c0271bad..5c8ee59810 100644 --- a/Modules/OpenViewCore/include/QVTKFramebufferObjectRenderer.h +++ b/Modules/OpenViewCore/include/QVTKFramebufferObjectRenderer.h @@ -1,50 +1,49 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __QVTKFramebufferObjectRenderer_h #define __QVTKFramebufferObjectRenderer_h #include -#include -#include "QVTKInternalOpenglRenderWindow.h" #include "QVTKQuickItem.h" #include +class vtkInternalOpenGLRenderWindow; + class MITKOPENVIEWCORE_EXPORT QVTKFramebufferObjectRenderer : public QQuickFramebufferObject::Renderer { public: bool m_neverRendered; bool m_readyToRender; vtkInternalOpenGLRenderWindow *m_vtkRenderWindow; - vtkFrameBufferObject2* m_vtkFBO; QVTKQuickItem *m_vtkQuickItem; public: QVTKFramebufferObjectRenderer(vtkInternalOpenGLRenderWindow *rw); ~QVTKFramebufferObjectRenderer(); virtual void synchronize(QQuickFramebufferObject * item); virtual void render(); QOpenGLFramebufferObject *createFramebufferObject(const QSize &size); friend class vtkInternalOpenGLRenderWindow; }; #endif diff --git a/Modules/OpenViewCore/include/QVTKQuickItem.h b/Modules/OpenViewCore/include/QVTKQuickItem.h index 8d987b0099..bf6c22bc00 100644 --- a/Modules/OpenViewCore/include/QVTKQuickItem.h +++ b/Modules/OpenViewCore/include/QVTKQuickItem.h @@ -1,116 +1,122 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // original copyright below /*======================================================================== OpenView -- http://openview.kitware.com Copyright 2012 Kitware, Inc. Licensed under the BSD license. See LICENSE file for details. ========================================================================*/ #ifndef __QVTKQuickItem_h #define __QVTKQuickItem_h #include #include #include "vtkSmartPointer.h" #include "vtkNew.h" #include #include class QOpenGLContext; class QOpenGLFramebufferObject; class QVTKMitkInteractorAdapter; class QVTKInteractor; class QVTKFramebufferObjectRenderer; class vtkEventQtSlotConnect; class vtkOpenGLRenderWindow; class vtkObject; class vtkContextView; class MITKOPENVIEWCORE_EXPORT QVTKQuickItem : public QQuickFramebufferObject { Q_OBJECT public: QVTKQuickItem(QQuickItem* parent = 0); // Description: // destructor ~QVTKQuickItem(); - Renderer *createRenderer() const; + Renderer* createRenderer() const; // Description: // get the render window used with this item vtkOpenGLRenderWindow* GetRenderWindow() const; // Description: // get the render window interactor used with this item // this item enforces its own interactor QVTKInteractor* GetInteractor() const; QMutex m_viewLock; protected slots: // slot called when vtk wants to know if the context is current virtual void IsCurrent(vtkObject* caller, unsigned long vtk_event, void* client_data, void* call_data); // slot called when vtk wants to know if a window is direct virtual void IsDirect(vtkObject* caller, unsigned long vtk_event, void* client_data, void* call_data); // slot called when vtk wants to know if a window supports OpenGL virtual void SupportsOpenGL(vtkObject* caller, unsigned long vtk_event, void* client_data, void* call_data); void onTextureFollowsItemSizeChanged(bool follows); protected: // Called ONCE from the render thread before the FBO is first created and while the GUI thread is blocked virtual void init(); // Called from the render thread BEFORE each update while the GUI thread blocked virtual bool prepareForRender(); // Called from the render thread AFTER each update while the GUI thread is NOT blocked virtual void cleanupAfterRender(); // handle item key events virtual void keyPressEvent(QKeyEvent* e); virtual void keyReleaseEvent(QKeyEvent* e); // handle item mouse events virtual void mousePressEvent(QMouseEvent* e); virtual void mouseReleaseEvent(QMouseEvent* e); virtual void mouseDoubleClickEvent(QMouseEvent* e); virtual void mouseMoveEvent(QMouseEvent* e); virtual void geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry); virtual void wheelEvent(QWheelEvent* e); virtual void hoverEnterEvent(QHoverEvent* e); virtual void hoverLeaveEvent(QHoverEvent* e); virtual void hoverMoveEvent(QHoverEvent* e); QSGNode* updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *nodeData); + //! To be called from rendering thread while synchronized + //! with UI thread - should execute a list of queued UI events. + //! + //! Not yet implemented for QVTKQuickItem but possibly for sub-classes + virtual void processPendingEvents() {} + private: vtkOpenGLRenderWindow *m_win; vtkSmartPointer m_interactor; QVTKMitkInteractorAdapter* m_interactorAdapter; vtkSmartPointer m_connect; friend class QVTKFramebufferObjectRenderer; }; #endif diff --git a/Modules/OpenViewCore/src/QVTKFramebufferObjectRenderer.cxx b/Modules/OpenViewCore/src/QVTKFramebufferObjectRenderer.cxx index 6ca47209a2..d0a423bf5f 100644 --- a/Modules/OpenViewCore/src/QVTKFramebufferObjectRenderer.cxx +++ b/Modules/OpenViewCore/src/QVTKFramebufferObjectRenderer.cxx @@ -1,91 +1,98 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QVTKInternalOpenglRenderWindow.h" #include "QVTKFramebufferObjectRenderer.h" + +#include + #include #include #include #include #include #include #include #include #include #include #include #include #include #include QVTKFramebufferObjectRenderer::QVTKFramebufferObjectRenderer(vtkInternalOpenGLRenderWindow *rw) : m_vtkRenderWindow(rw), m_neverRendered(true), m_readyToRender(false) { m_vtkRenderWindow->Register(NULL); m_vtkRenderWindow->QtParentRenderer = this; } -QOpenGLFramebufferObject * QVTKFramebufferObjectRenderer::createFramebufferObject(const QSize &size) +QOpenGLFramebufferObject* QVTKFramebufferObjectRenderer::createFramebufferObject(const QSize &size) { - QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::Depth); format.setTextureTarget(GL_TEXTURE_2D); format.setInternalTextureFormat(GL_RGBA32F_ARB); - QOpenGLFramebufferObject *fbo = new QOpenGLFramebufferObject(size, format); - + QOpenGLFramebufferObject* fbo = new QOpenGLFramebufferObject(size, format); m_vtkRenderWindow->SetFramebufferObject(fbo); return fbo; } void QVTKFramebufferObjectRenderer::render() { if (!m_readyToRender) { return; } + // Ask VTK to render to OpenGL m_vtkQuickItem->m_viewLock.lock(); m_vtkRenderWindow->PushState(); m_vtkRenderWindow->OpenGLInitState(); m_vtkRenderWindow->InternalRender(); m_vtkRenderWindow->OpenGLEndState(); m_vtkRenderWindow->PopState(); m_vtkQuickItem->m_viewLock.unlock(); - } void QVTKFramebufferObjectRenderer::synchronize(QQuickFramebufferObject * item) { m_vtkQuickItem = static_cast(item); if (m_neverRendered) { m_neverRendered = false; m_vtkQuickItem->init(); } + + // Execute events (that might call VTK picking to obtain z coordinates) + // while UI and rendering are synchronized. + m_vtkQuickItem->processPendingEvents(); + + // Update MITK mapper list, then mapper outputs m_readyToRender = m_vtkQuickItem->prepareForRender(); } QVTKFramebufferObjectRenderer::~QVTKFramebufferObjectRenderer() { m_vtkRenderWindow->QtParentRenderer = 0; m_vtkRenderWindow->Delete(); } diff --git a/Modules/OpenViewCore/src/QVTKInternalOpenglRenderWindow.cxx b/Modules/OpenViewCore/src/QVTKInternalOpenglRenderWindow.cxx index 4692118e1c..44912edd15 100644 --- a/Modules/OpenViewCore/src/QVTKInternalOpenglRenderWindow.cxx +++ b/Modules/OpenViewCore/src/QVTKInternalOpenglRenderWindow.cxx @@ -1,81 +1,82 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QVTKInternalOpenglRenderWindow.h" #include "QVTKFramebufferObjectRenderer.h" #include #include vtkStandardNewMacro(vtkInternalOpenGLRenderWindow); vtkInternalOpenGLRenderWindow::~vtkInternalOpenGLRenderWindow() { this->OffScreenRendering = false; } vtkInternalOpenGLRenderWindow::vtkInternalOpenGLRenderWindow() : QtParentRenderer(0) { } void vtkInternalOpenGLRenderWindow::InternalRender() { Superclass::Render(); } void vtkInternalOpenGLRenderWindow::OpenGLEndState() { glDepthMask(GL_TRUE); } void vtkInternalOpenGLRenderWindow::OpenGLInitState() { Superclass::OpenGLInitState(); vtkgl::UseProgram(0); glEnable(GL_BLEND); glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); glDepthMask(GL_TRUE); } void vtkInternalOpenGLRenderWindow::Render() { if (this->QtParentRenderer) { this->QtParentRenderer->update(); } } void vtkInternalOpenGLRenderWindow::SetFramebufferObject(QOpenGLFramebufferObject *fbo) { this->SetFrontBuffer(vtkgl::COLOR_ATTACHMENT0); + // Why all those buffers, too?? this->SetFrontRightBuffer(vtkgl::COLOR_ATTACHMENT0); this->SetBackLeftBuffer(vtkgl::COLOR_ATTACHMENT0); this->SetBackRightBuffer(vtkgl::COLOR_ATTACHMENT0); QSize fboSize = fbo->size(); this->SetSize(fboSize.width(), fboSize.height()); this->NumberOfFrameBuffers = 1; this->FrameBufferObject = static_cast(fbo->handle()); this->DepthRenderBufferObject = 0; // static_cast(depthRenderBufferObject); this->TextureObjects[0] = static_cast(fbo->texture()); this->OffScreenRendering = true; this->OffScreenUseFrameBuffer = true; this->Modified(); } diff --git a/Modules/OpenViewCore/src/QVTKQuickItem.cxx b/Modules/OpenViewCore/src/QVTKQuickItem.cxx index 63d59948ec..80d8b8829a 100644 --- a/Modules/OpenViewCore/src/QVTKQuickItem.cxx +++ b/Modules/OpenViewCore/src/QVTKQuickItem.cxx @@ -1,258 +1,257 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // original copyright below /*======================================================================== OpenView -- http://openview.kitware.com Copyright 2012 Kitware, Inc. Licensed under the BSD license. See LICENSE file for details. ========================================================================*/ #include "QVTKQuickItem.h" #include #include #include #include #include #include "QVTKInteractor.h" #include "QVTKMitkInteractorAdapter.h" #include "vtkGenericOpenGLRenderWindow.h" #include "vtkEventQtSlotConnect.h" #include "vtkgl.h" #include "vtkOpenGLExtensionManager.h" #include "vtkRenderer.h" +#include "vtkRendererCollection.h" #include "vtkCubeSource.h" #include "vtkPolyDataMapper.h" #include "vtkProperty.h" #include #include "QVTKInternalOpenglRenderWindow.h" #include "QVTKFramebufferObjectRenderer.h" QVTKQuickItem::QVTKQuickItem(QQuickItem* parent) : QQuickFramebufferObject(parent) { setAcceptHoverEvents(true); setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton); m_interactor = vtkSmartPointer::New(); m_interactorAdapter = new QVTKMitkInteractorAdapter(this); m_connect = vtkSmartPointer::New(); m_win = vtkInternalOpenGLRenderWindow::New(); m_interactor->SetRenderWindow(m_win); m_connect->Connect(m_win, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*)), NULL, 0.0, Qt::DirectConnection); m_connect->Connect(m_win, vtkCommand::WindowIsDirectEvent, this, SLOT(IsDirect(vtkObject*, unsigned long, void*, void*)), NULL, 0.0, Qt::DirectConnection); m_connect->Connect(m_win, vtkCommand::WindowSupportsOpenGLEvent, this, SLOT(SupportsOpenGL(vtkObject*, unsigned long, void*, void*)), NULL, 0.0, Qt::DirectConnection); connect(this, SIGNAL(textureFollowsItemSizeChanged(bool)), this, SLOT(onTextureFollowsItemSizeChanged(bool))); } QVTKQuickItem::~QVTKQuickItem() { if(m_win) { m_connect->Disconnect(m_win, vtkCommand::WindowIsCurrentEvent, this, SLOT(IsCurrent(vtkObject*, unsigned long, void*, void*))); m_connect->Disconnect(m_win, vtkCommand::WindowIsDirectEvent, this, SLOT(IsDirect(vtkObject*, unsigned long, void*, void*))); m_connect->Disconnect(m_win, vtkCommand::WindowSupportsOpenGLEvent, this, SLOT(SupportsOpenGL(vtkObject*, unsigned long, void*, void*))); m_win->Delete(); } } QSGNode* QVTKQuickItem::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *nodeData) { - if (!node) { - node = QQuickFramebufferObject::updatePaintNode(node, nodeData); - QSGSimpleTextureNode *n = static_cast(node); - if (n) - n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically); - return node; + node = QQuickFramebufferObject::updatePaintNode(node, nodeData); + if ( node != nullptr ) { + QSGSimpleTextureNode* texNode = static_cast(node); + texNode->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically); } - return QQuickFramebufferObject::updatePaintNode(node, nodeData); + return node; } -QQuickFramebufferObject::Renderer *QVTKQuickItem::createRenderer() const +QQuickFramebufferObject::Renderer* QVTKQuickItem::createRenderer() const { return new QVTKFramebufferObjectRenderer(static_cast(m_win)); } vtkOpenGLRenderWindow* QVTKQuickItem::GetRenderWindow() const { return m_win; } QVTKInteractor* QVTKQuickItem::GetInteractor() const { return m_interactor; } void QVTKQuickItem::IsCurrent(vtkObject*, unsigned long, void*, void* call_data) { bool* ptr = reinterpret_cast(call_data); *ptr = QOpenGLContext::currentContext() == this->window()->openglContext(); } void QVTKQuickItem::IsDirect(vtkObject*, unsigned long, void*, void* call_data) { int* ptr = reinterpret_cast(call_data); *ptr = 1; } void QVTKQuickItem::SupportsOpenGL(vtkObject*, unsigned long, void*, void* call_data) { int* ptr = reinterpret_cast(call_data); *ptr = 1; } void QVTKQuickItem::onTextureFollowsItemSizeChanged(bool follows) { if (!follows) { qWarning("QVTKQuickItem: Mouse interaction is not (yet) supported when textureFollowsItemSize==false"); } } void QVTKQuickItem::geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry) { QQuickFramebufferObject::geometryChanged(newGeometry, oldGeometry); QSize oldSize(oldGeometry.width(), oldGeometry.height()); QSize newSize(newGeometry.width(), newGeometry.height()); QResizeEvent e(newSize, oldSize); if (m_interactorAdapter) { this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(&e, m_interactor); this->m_viewLock.unlock(); } } void QVTKQuickItem::keyPressEvent(QKeyEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::keyReleaseEvent(QKeyEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::mousePressEvent(QMouseEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::mouseReleaseEvent(QMouseEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::mouseDoubleClickEvent(QMouseEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::mouseMoveEvent(QMouseEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::wheelEvent(QWheelEvent* e) { e->accept(); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(e, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::hoverEnterEvent(QHoverEvent* e) { e->accept(); QEvent e2(QEvent::Enter); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(&e2, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::hoverLeaveEvent(QHoverEvent* e) { e->accept(); QEvent e2(QEvent::Leave); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(&e2, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::hoverMoveEvent(QHoverEvent* e) { e->accept(); QMouseEvent e2(QEvent::MouseMove, e->pos(), Qt::NoButton, Qt::NoButton, e->modifiers()); this->m_viewLock.lock(); m_interactorAdapter->ProcessEvent(&e2, m_interactor); this->m_viewLock.unlock(); update(); } void QVTKQuickItem::init() { m_win->OpenGLInitContext(); m_win->GetExtensionManager()->LoadExtension("GL_VERSION_1_4"); m_win->GetExtensionManager()->LoadExtension("GL_VERSION_2_0"); } bool QVTKQuickItem::prepareForRender() { return true; } void QVTKQuickItem::cleanupAfterRender() { } diff --git a/Modules/QmlItems/include/QmlMitkRenderWindowItem.h b/Modules/QmlItems/include/QmlMitkRenderWindowItem.h index 5b20a23a2e..80a9041a83 100644 --- a/Modules/QmlItems/include/QmlMitkRenderWindowItem.h +++ b/Modules/QmlItems/include/QmlMitkRenderWindowItem.h @@ -1,92 +1,108 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef __QmlMitkRenderWindowItem_h #define __QmlMitkRenderWindowItem_h #include "MitkQmlItemsExports.h" #include "QVTKQuickItem.h" #include "mitkRenderWindowBase.h" #include #include class QmlMitkStdMultiItem; class MITKQMLITEMS_EXPORT QmlMitkRenderWindowItem : public QVTKQuickItem, public mitk::RenderWindowBase { Q_OBJECT Q_PROPERTY(int viewType READ getViewType WRITE setViewType NOTIFY viewTypeChanged); Q_PROPERTY(QmlMitkStdMultiItem* multiItem READ getMultiItem WRITE setMultiItem NOTIFY multiItemChanged); private: QmlMitkStdMultiItem* m_multiItem; vtkSmartPointer m_annotation; vtkSmartPointer m_rectangle; int m_viewType; public: static QmlMitkRenderWindowItem* instance; static QmlMitkRenderWindowItem* GetInstanceForVTKRenderWindow( vtkRenderWindow* rw ); QmlMitkRenderWindowItem(QQuickItem* parent = 0, const QString& name = "QML render window", mitk::VtkPropRenderer* renderer = NULL, mitk::RenderingManager* renderingManager = NULL); ~QmlMitkRenderWindowItem(); virtual vtkRenderWindow* GetVtkRenderWindow(); virtual vtkRenderWindowInteractor* GetVtkRenderWindowInteractor(); void SetDataStorage(mitk::DataStorage::Pointer storage); void InitView( mitk::BaseRenderer::MapperSlotId mapperID, mitk::SliceNavigationController::ViewDirection viewDirection ); virtual bool prepareForRender(); virtual void cleanupAfterRender(); void createPlaneNode(); void setMultiItem(QmlMitkStdMultiItem* multiItem); QmlMitkStdMultiItem* getMultiItem(); void setDecorationProperties(std::string text, mitk::Color color); void setViewType(int type); int getViewType(); void geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry); virtual void mousePressEvent(QMouseEvent* e); virtual void mouseReleaseEvent(QMouseEvent* e); virtual void mouseMoveEvent(QMouseEvent* e); virtual void wheelEvent(QWheelEvent* e); mitk::Point2D GetMousePosition(QMouseEvent* me) const; + mitk::Point2D GetMousePositionFlipY(QMouseEvent* me) const; mitk::Point2D GetMousePosition(QWheelEvent* we) const; + mitk::Point2D GetMousePositionFlipY(QWheelEvent* we) const; mitk::InteractionEvent::MouseButtons GetEventButton(QMouseEvent* me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QMouseEvent* me) const; mitk::InteractionEvent::ModifierKeys GetModifiers(QInputEvent* me) const; mitk::InteractionEvent::MouseButtons GetButtonState(QWheelEvent* we) const; static QMap& GetInstances(); public slots: void setupView(); signals: void multiItemChanged(); void viewTypeChanged(); + +protected: + + //! Add an event to the event queue to be executed in rendering. + //! + //! Avoids collisions between rendering and event handling, + //! both of which might act on GL buffers (e.g. picking) + void QueueEvent(mitk::InteractionEvent::Pointer e); + + //! List of events that should be treated during next rendering. + std::vector m_PendingEvents; + + //! Executes (then clears) the list of unhandled UI events (m_PendingEvents). + void processPendingEvents() override; }; #endif diff --git a/Modules/QmlItems/src/QmlMitkRenderWindowItem.cpp b/Modules/QmlItems/src/QmlMitkRenderWindowItem.cpp index c8ddc7ee19..445ffe5138 100644 --- a/Modules/QmlItems/src/QmlMitkRenderWindowItem.cpp +++ b/Modules/QmlItems/src/QmlMitkRenderWindowItem.cpp @@ -1,367 +1,410 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmlMitkRenderWindowItem.h" #include #include #include #include #include "mitkMouseWheelEvent.h" #include "mitkMousePressEvent.h" #include "mitkMouseMoveEvent.h" #include "mitkMouseDoubleClickEvent.h" #include "mitkMouseReleaseEvent.h" #include "mitkInteractionKeyEvent.h" #include "mitkInternalEvent.h" #include "mitkPlaneGeometryDataMapper2D.h" #include "mitkCameraController.h" #include "QmlMitkStdMultiItem.h" +#include "QVTKFramebufferObjectRenderer.h" #include QmlMitkRenderWindowItem* QmlMitkRenderWindowItem::instance = nullptr; QmlMitkRenderWindowItem* QmlMitkRenderWindowItem::GetInstanceForVTKRenderWindow(vtkRenderWindow* rw) { if (GetInstances().contains(rw)) { return GetInstances()[rw]; } return 0; } QMap& QmlMitkRenderWindowItem::GetInstances() { static QMap s_Instances; return s_Instances; } QmlMitkRenderWindowItem::QmlMitkRenderWindowItem(QQuickItem* parent, const QString& name, mitk::VtkPropRenderer* , mitk::RenderingManager* renderingManager) : QVTKQuickItem(parent) { instance = this; mitk::RenderWindowBase::Initialize(renderingManager, name.toStdString().c_str()); GetInstances()[QVTKQuickItem::GetRenderWindow()] = this; this->m_annotation = vtkSmartPointer::New(); this->m_rectangle = vtkSmartPointer::New(); } void QmlMitkRenderWindowItem::createPlaneNode() { mitk::DataStorage::Pointer m_DataStorage = mitk::RenderWindowBase::GetRenderer()->GetDataStorage(); if (m_DataStorage.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( m_DataStorage->ComputeBoundingGeometry3D(m_DataStorage->GetAll()) ); } if (this->GetRenderer()->GetSliceNavigationController()->GetDefaultViewDirection() == mitk::SliceNavigationController::Original) return; mitk::DataNode::Pointer planeNode; mitk::IntProperty::Pointer layer; mitk::PlaneGeometryDataMapper2D::Pointer mapper = mitk::PlaneGeometryDataMapper2D::New(); layer = mitk::IntProperty::New(1000); planeNode = this->GetRenderer()->GetCurrentWorldPlaneGeometryNode(); planeNode->SetProperty("visible", mitk::BoolProperty::New(true)); planeNode->SetProperty("name", mitk::StringProperty::New("plane")); planeNode->SetProperty("isPlane", mitk::BoolProperty::New(true)); planeNode->SetProperty("includeInBoundingBox", mitk::BoolProperty::New(false)); planeNode->SetProperty("helper object", mitk::BoolProperty::New(true)); planeNode->SetProperty("layer", layer); planeNode->SetMapper(mitk::BaseRenderer::Standard2D, mapper); switch (this->GetRenderer()->GetSliceNavigationController()->GetDefaultViewDirection()) { case mitk::SliceNavigationController::Axial: planeNode->SetColor(0.88, 0.35, 0.27); break; case mitk::SliceNavigationController::Sagittal: planeNode->SetColor(0.25, 0.7, 0.35); break; case mitk::SliceNavigationController::Frontal: planeNode->SetColor(0.01, 0.31, 0.67); break; default: planeNode->SetColor(1.0, 1.0, 0.0); } } void QmlMitkRenderWindowItem::setViewType(int viewType) { this->m_viewType = viewType; emit this->viewTypeChanged(); } void QmlMitkRenderWindowItem::setDecorationProperties(std::string text, mitk::Color color) { this->m_annotation->SetText(0, text.c_str()); this->m_annotation->SetMaximumFontSize(12); this->m_annotation->GetTextProperty()->SetColor( color[0],color[1],color[2] ); if(!this->GetRenderer()->GetVtkRenderer()->HasViewProp(this->m_annotation)) { this->GetRenderer()->GetVtkRenderer()->AddViewProp(this->m_annotation); } this->m_rectangle->SetColor(color[0],color[1],color[2]); if(!this->GetRenderer()->GetVtkRenderer()->HasViewProp(this->m_rectangle)) { this->GetRenderer()->GetVtkRenderer()->AddViewProp(this->m_rectangle); } } void QmlMitkRenderWindowItem::setupView() { switch (this->m_viewType) { case 0: this->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); this->GetRenderer()->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Axial); break; case 1: this->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); this->GetRenderer()->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Frontal); break; case 2: this->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard2D); this->GetRenderer()->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Sagittal); break; case 3: this->GetRenderer()->SetMapperID(mitk::BaseRenderer::Standard3D); this->GetRenderer()->GetSliceNavigationController()->SetDefaultViewDirection(mitk::SliceNavigationController::Original); break; default: break; } } void QmlMitkRenderWindowItem::setMultiItem(QmlMitkStdMultiItem* multiItem) { if(this->m_multiItem == multiItem) return; this->m_multiItem = multiItem; this->m_multiItem->registerViewerItem(this); } QmlMitkStdMultiItem* QmlMitkRenderWindowItem::getMultiItem() { return this->m_multiItem; } void QmlMitkRenderWindowItem::SetDataStorage(mitk::DataStorage::Pointer storage) { this->GetRenderer()->SetDataStorage(storage); } mitk::Point2D QmlMitkRenderWindowItem::GetMousePosition(QMouseEvent* me) const { qreal ratio = this->window()->effectiveDevicePixelRatio(); mitk::Point2D point; point[0] = me->x()*ratio; point[1] = me->y()*ratio; return point; } +mitk::Point2D QmlMitkRenderWindowItem::GetMousePositionFlipY(QMouseEvent* me) const +{ + mitk::Point2D point = GetMousePosition(me); + point[1] = const_cast(this)->GetRenderer()->GetSizeY() - point[1]; + return point; +} + mitk::Point2D QmlMitkRenderWindowItem::GetMousePosition(QWheelEvent* we) const { qreal ratio = this->window()->effectiveDevicePixelRatio(); mitk::Point2D point; point[0] = we->x()*ratio; point[1] = we->y()*ratio; return point; } +mitk::Point2D QmlMitkRenderWindowItem::GetMousePositionFlipY(QWheelEvent* we) const +{ + mitk::Point2D point = GetMousePosition(we); + point[1] = const_cast(this)->GetRenderer()->GetSizeY() - point[1]; + return point; +} + mitk::InteractionEvent::MouseButtons QmlMitkRenderWindowItem::GetEventButton(QMouseEvent* me) const { mitk::InteractionEvent::MouseButtons eventButton; switch (me->button()) { case Qt::LeftButton: eventButton = mitk::InteractionEvent::LeftMouseButton; break; case Qt::RightButton: eventButton = mitk::InteractionEvent::RightMouseButton; break; case Qt::MidButton: eventButton = mitk::InteractionEvent::MiddleMouseButton; break; default: eventButton = mitk::InteractionEvent::NoButton; break; } return eventButton; } mitk::InteractionEvent::MouseButtons QmlMitkRenderWindowItem::GetButtonState(QMouseEvent* me) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (me->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (me->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (me->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } mitk::InteractionEvent::ModifierKeys QmlMitkRenderWindowItem::GetModifiers(QInputEvent* me) const { mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey; if (me->modifiers() & Qt::ALT) { modifiers = modifiers | mitk::InteractionEvent::AltKey; } if (me->modifiers() & Qt::CTRL) { modifiers = modifiers | mitk::InteractionEvent::ControlKey; } if (me->modifiers() & Qt::SHIFT) { modifiers = modifiers | mitk::InteractionEvent::ShiftKey; } return modifiers; } mitk::InteractionEvent::MouseButtons QmlMitkRenderWindowItem::GetButtonState(QWheelEvent* we) const { mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton; if (we->buttons() & Qt::LeftButton) { buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton; } if (we->buttons() & Qt::RightButton) { buttonState = buttonState | mitk::InteractionEvent::RightMouseButton; } if (we->buttons() & Qt::MidButton) { buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton; } return buttonState; } int QmlMitkRenderWindowItem::getViewType() { return this->m_viewType; } void QmlMitkRenderWindowItem::mousePressEvent(QMouseEvent* me) { - mitk::Point2D mousePosition = GetMousePosition(me); - //mousePosition[1] = this->GetRenderer()->GetSizeY() - mousePosition[1]; + mitk::Point2D mousePosition = GetMousePositionFlipY(me); - mitk::MousePressEvent::Pointer mPressEvent = - mitk::MousePressEvent::New(mitk::RenderWindowBase::GetRenderer(), mousePosition, GetButtonState(me), GetModifiers(me), GetEventButton(me)); + auto mitkEvent = mitk::MousePressEvent::New(mitk::RenderWindowBase::GetRenderer(), + mousePosition, + GetButtonState(me), + GetModifiers(me), + GetEventButton(me)); + + QueueEvent(mitkEvent.GetPointer()); - mitk::RenderWindowBase::HandleEvent(mPressEvent.GetPointer()); QVTKQuickItem::mousePressEvent(me); } void QmlMitkRenderWindowItem::mouseReleaseEvent(QMouseEvent* me) { - mitk::Point2D mousePosition = GetMousePosition(me); - //mousePosition[1] = this->GetRenderer()->GetSizeY() - mousePosition[1]; + mitk::Point2D mousePosition = GetMousePositionFlipY(me); + + auto mitkEvent = mitk::MouseReleaseEvent::New(mitk::RenderWindowBase::GetRenderer(), + mousePosition, + GetButtonState(me), + GetModifiers(me), + GetEventButton(me)); - mitk::MouseReleaseEvent::Pointer mReleaseEvent = - mitk::MouseReleaseEvent::New(mitk::RenderWindowBase::GetRenderer(), mousePosition, GetButtonState(me), GetModifiers(me), GetEventButton(me)); + QueueEvent(mitkEvent.GetPointer()); - mitk::RenderWindowBase::HandleEvent(mReleaseEvent.GetPointer()); QVTKQuickItem::mouseReleaseEvent(me); } void QmlMitkRenderWindowItem::mouseMoveEvent(QMouseEvent* me) { - mitk::Point2D mousePosition = GetMousePosition(me); - //mousePosition[1] = this->GetRenderer()->GetSizeY() - mousePosition[1]; + mitk::Point2D mousePosition = GetMousePositionFlipY(me); - mitk::MouseMoveEvent::Pointer mMoveEvent = - mitk::MouseMoveEvent::New(mitk::RenderWindowBase::GetRenderer(), mousePosition, GetButtonState(me), GetModifiers(me)); + auto mitkEvent = mitk::MouseMoveEvent::New(mitk::RenderWindowBase::GetRenderer(), + mousePosition, + GetButtonState(me), + GetModifiers(me)); + + QueueEvent(mitkEvent.GetPointer()); - mitk::RenderWindowBase::HandleEvent(mMoveEvent.GetPointer()); QVTKQuickItem::mouseMoveEvent(me); } void QmlMitkRenderWindowItem::wheelEvent(QWheelEvent *we) { - mitk::Point2D mousePosition = GetMousePosition(we); + mitk::Point2D mousePosition = GetMousePositionFlipY(we); + + auto mitkEvent = mitk::MouseWheelEvent::New(mitk::RenderWindowBase::GetRenderer(), + mousePosition, + GetButtonState(we), + GetModifiers(we), + we->delta()); - mitk::MouseWheelEvent::Pointer mWheelEvent = - mitk::MouseWheelEvent::New(mitk::RenderWindowBase::GetRenderer(), mousePosition, GetButtonState(we), GetModifiers(we), we->delta()); + QueueEvent(mitkEvent.GetPointer()); - mitk::RenderWindowBase::HandleEvent(mWheelEvent.GetPointer()); QVTKQuickItem::wheelEvent(we); } bool QmlMitkRenderWindowItem::prepareForRender() { mitk::VtkPropRenderer *vPR = dynamic_cast(mitk::BaseRenderer::GetInstance(this->GetRenderWindow())); if (vPR) { vPR->PrepareRender(); } mitk::RenderWindowBase::GetRenderer()->ForceImmediateUpdate(); return true; } void QmlMitkRenderWindowItem::cleanupAfterRender() { } void QmlMitkRenderWindowItem::geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry) { QVTKQuickItem::geometryChanged(newGeometry, oldGeometry); mitk::BaseRenderer::GetInstance(this->GetRenderWindow())->GetCameraController()->Fit(); } QmlMitkRenderWindowItem::~QmlMitkRenderWindowItem() { this->Destroy(); } vtkRenderWindow* QmlMitkRenderWindowItem::GetVtkRenderWindow() { return QVTKQuickItem::GetRenderWindow(); } vtkRenderWindowInteractor* QmlMitkRenderWindowItem::GetVtkRenderWindowInteractor() { return QVTKQuickItem::GetInteractor(); } + +void QmlMitkRenderWindowItem::QueueEvent(mitk::InteractionEvent::Pointer e) +{ + m_PendingEvents.push_back(e); +} + +// To be called while rendering is blocked (in Qml sync methods) +// so picking can access a "still image" and data to be rendered +// can be modified by interaction +void QmlMitkRenderWindowItem::processPendingEvents() +{ + for (auto e : m_PendingEvents) { + mitk::RenderWindowBase::HandleEvent(e); + } + m_PendingEvents.clear(); +}