You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
920 lines
23 KiB
C++
920 lines
23 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: QVTKWidget.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.
|
|
|
|
=========================================================================*/
|
|
/*
|
|
* Copyright 2004 Sandia Corporation.
|
|
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
|
|
* license for use of this work by or on behalf of the
|
|
* U.S. Government. Redistribution and use in source and binary forms, with
|
|
* or without modification, are permitted provided that this Notice and any
|
|
* statement of authorship are reproduced on all copies.
|
|
*/
|
|
|
|
/*========================================================================
|
|
For general information about using VTK and Qt, see:
|
|
http://www.vtk.org/Wiki/VTK/Examples/Cxx#Qt
|
|
=========================================================================*/
|
|
|
|
#ifdef _MSC_VER
|
|
// Disable warnings that Qt headers give.
|
|
#pragma warning(disable:4127)
|
|
#pragma warning(disable:4512)
|
|
#endif
|
|
|
|
#include "QVTKWidget.h"
|
|
|
|
#include "QVTKPaintEngine.h"
|
|
#include "QVTKInteractorAdapter.h"
|
|
#include "QVTKInteractor.h"
|
|
|
|
#include "qevent.h"
|
|
#include "qapplication.h"
|
|
#include "qpainter.h"
|
|
#include "qsignalmapper.h"
|
|
#include "qtimer.h"
|
|
#include "vtkRenderingOpenGLConfigure.h"
|
|
#if defined(Q_WS_X11) // aka Qt4
|
|
# include "qx11info_x11.h"
|
|
#elif defined(Q_OS_LINUX) // aka Qt5
|
|
# include <QX11Info>
|
|
#endif
|
|
|
|
#if defined(Q_OS_WIN)
|
|
# include <windows.h>
|
|
# include <QSysInfo>
|
|
#endif
|
|
|
|
#include "vtkInteractorStyleTrackballCamera.h"
|
|
#include "vtkRenderWindow.h"
|
|
#include "vtkCommand.h"
|
|
#include "vtkOStrStreamWrapper.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkCallbackCommand.h"
|
|
#include "vtkConfigure.h"
|
|
#include "vtkUnsignedCharArray.h"
|
|
#include "vtkImageData.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkRenderer.h"
|
|
#include "vtkRendererCollection.h"
|
|
|
|
#if defined(VTK_USE_TDX) && (defined(Q_WS_X11) || defined(Q_OS_LINUX))
|
|
# include "vtkTDxUnixDevice.h"
|
|
#endif
|
|
|
|
/*! constructor */
|
|
QVTKWidget::QVTKWidget(QWidget* p, Qt::WindowFlags f)
|
|
: QWidget(p, f | Qt::MSWindowsOwnDC), mRenWin(NULL),
|
|
cachedImageCleanFlag(false),
|
|
automaticImageCache(false), maxImageCacheRenderRate(1.0),
|
|
mDeferRenderInPaintEvent(false),
|
|
renderEventCallbackObserverId(0)
|
|
{
|
|
this->UseTDx=false;
|
|
// no background
|
|
this->setAttribute(Qt::WA_NoBackground);
|
|
// no double buffering
|
|
this->setAttribute(Qt::WA_PaintOnScreen);
|
|
|
|
// default to strong focus
|
|
this->setFocusPolicy(Qt::StrongFocus);
|
|
|
|
// default to enable mouse events when a mouse button isn't down
|
|
// so we can send enter/leave events to VTK
|
|
this->setMouseTracking(true);
|
|
|
|
// set expanding to take up space for better default layouts
|
|
this->setSizePolicy(
|
|
QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding )
|
|
);
|
|
|
|
mPaintEngine = new QVTKPaintEngine;
|
|
|
|
this->mCachedImage = vtkImageData::New();
|
|
this->mCachedImage->SetOrigin(0,0,0);
|
|
this->mCachedImage->SetSpacing(1,1,1);
|
|
|
|
mIrenAdapter = new QVTKInteractorAdapter(this);
|
|
|
|
this->mDeferedRenderTimer.setSingleShot(true);
|
|
this->mDeferedRenderTimer.setInterval(0);
|
|
this->connect(&this->mDeferedRenderTimer, SIGNAL(timeout()), SLOT(doDeferredRender()));
|
|
}
|
|
|
|
/*! destructor */
|
|
|
|
QVTKWidget::~QVTKWidget()
|
|
{
|
|
// get rid of the VTK window
|
|
this->SetRenderWindow(NULL);
|
|
|
|
this->mCachedImage->Delete();
|
|
|
|
delete mPaintEngine;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
void QVTKWidget::SetUseTDx(bool useTDx)
|
|
{
|
|
if(useTDx!=this->UseTDx)
|
|
{
|
|
this->UseTDx=useTDx;
|
|
|
|
if(this->UseTDx)
|
|
{
|
|
#if defined(VTK_USE_TDX) && (defined(Q_WS_X11) || defined(Q_OS_LINUX))
|
|
QByteArray theSignal=
|
|
QMetaObject::normalizedSignature("CreateDevice(vtkTDxDevice *)");
|
|
if(QApplication::instance()->metaObject()->indexOfSignal(theSignal)!=-1)
|
|
{
|
|
QObject::connect(QApplication::instance(),
|
|
SIGNAL(CreateDevice(vtkTDxDevice *)),
|
|
this,
|
|
SLOT(setDevice(vtkTDxDevice *)));
|
|
}
|
|
else
|
|
{
|
|
vtkGenericWarningMacro("Missing signal CreateDevice on QApplication. 3DConnexion device will not work. Define it or derive your QApplication from QVTKApplication.");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
bool QVTKWidget::GetUseTDx() const
|
|
{
|
|
return this->UseTDx;
|
|
}
|
|
|
|
/*! get the render window
|
|
*/
|
|
vtkRenderWindow* QVTKWidget::GetRenderWindow()
|
|
{
|
|
if (!this->mRenWin)
|
|
{
|
|
// create a default vtk window
|
|
vtkRenderWindow* win = vtkRenderWindow::New();
|
|
this->SetRenderWindow(win);
|
|
win->Delete();
|
|
}
|
|
|
|
return this->mRenWin;
|
|
}
|
|
|
|
/*! set the render window
|
|
this will bind a VTK window with the Qt window
|
|
it'll also replace an existing VTK window
|
|
*/
|
|
void QVTKWidget::SetRenderWindow(vtkRenderWindow* w)
|
|
{
|
|
// do nothing if we don't have to
|
|
if(w == this->mRenWin)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// unregister previous window
|
|
if(this->mRenWin)
|
|
{
|
|
if (this->renderEventCallbackObserverId)
|
|
{
|
|
this->mRenWin->RemoveObserver(this->renderEventCallbackObserverId);
|
|
this->renderEventCallbackObserverId = 0;
|
|
}
|
|
//clean up window as one could remap it
|
|
if(this->mRenWin->GetMapped())
|
|
{
|
|
this->mRenWin->Finalize();
|
|
}
|
|
#if defined(Q_WS_X11) || defined(Q_OS_LINUX)
|
|
this->mRenWin->SetDisplayId(NULL);
|
|
#endif
|
|
this->mRenWin->SetWindowId(NULL);
|
|
this->mRenWin->UnRegister(NULL);
|
|
}
|
|
|
|
// now set the window
|
|
this->mRenWin = w;
|
|
|
|
if(this->mRenWin)
|
|
{
|
|
// register new window
|
|
this->mRenWin->Register(NULL);
|
|
|
|
// if it is mapped somewhere else, unmap it
|
|
if(this->mRenWin->GetMapped())
|
|
{
|
|
this->mRenWin->Finalize();
|
|
}
|
|
|
|
#if defined(Q_WS_X11) || defined(Q_OS_LINUX)
|
|
// give the qt display id to the vtk window
|
|
this->mRenWin->SetDisplayId(QX11Info::display());
|
|
#endif
|
|
|
|
// special x11 setup
|
|
x11_setup_window();
|
|
|
|
// give the qt window id to the vtk window
|
|
this->mRenWin->SetWindowId( reinterpret_cast<void*>(this->winId()));
|
|
|
|
// tell the vtk window what the size of this window is
|
|
this->mRenWin->vtkRenderWindow::SetSize(this->width(), this->height());
|
|
this->mRenWin->vtkRenderWindow::SetPosition(this->x(), this->y());
|
|
|
|
// have VTK start this window and create the necessary graphics resources
|
|
if(isVisible())
|
|
{
|
|
this->mRenWin->Start();
|
|
}
|
|
|
|
// if an interactor wasn't provided, we'll make one by default
|
|
if(!this->mRenWin->GetInteractor())
|
|
{
|
|
// create a default interactor
|
|
QVTKInteractor* iren = QVTKInteractor::New();
|
|
iren->SetUseTDx(this->UseTDx);
|
|
this->mRenWin->SetInteractor(iren);
|
|
iren->Initialize();
|
|
|
|
// now set the default style
|
|
vtkInteractorStyle* s = vtkInteractorStyleTrackballCamera::New();
|
|
iren->SetInteractorStyle(s);
|
|
|
|
iren->Delete();
|
|
s->Delete();
|
|
}
|
|
|
|
// tell the interactor the size of this window
|
|
this->mRenWin->GetInteractor()->SetSize(this->width(), this->height());
|
|
|
|
// Add an observer to monitor when the image changes. Should work most
|
|
// of the time. The application will have to call
|
|
// markCachedImageAsDirty for any other case.
|
|
this->renderEventCallbackObserverId =
|
|
this->mRenWin->AddObserver(vtkCommand::RenderEvent,
|
|
this, &QVTKWidget::renderEventCallback);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*! get the Qt/VTK interactor
|
|
*/
|
|
QVTKInteractor* QVTKWidget::GetInteractor()
|
|
{
|
|
return QVTKInteractor
|
|
::SafeDownCast(this->GetRenderWindow()->GetInteractor());
|
|
}
|
|
|
|
void QVTKWidget::markCachedImageAsDirty()
|
|
{
|
|
if (this->cachedImageCleanFlag)
|
|
{
|
|
this->cachedImageCleanFlag = false;
|
|
emit cachedImageDirty();
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::saveImageToCache()
|
|
{
|
|
if (this->cachedImageCleanFlag)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int w = this->width();
|
|
int h = this->height();
|
|
this->mCachedImage->SetExtent(0, w-1, 0, h-1, 0, 0);
|
|
this->mCachedImage->AllocateScalars(VTK_UNSIGNED_CHAR, 3);
|
|
vtkUnsignedCharArray* array = vtkArrayDownCast<vtkUnsignedCharArray>(
|
|
this->mCachedImage->GetPointData()->GetScalars());
|
|
// We use back-buffer if
|
|
this->mRenWin->GetPixelData(0, 0, this->width()-1, this->height()-1,
|
|
this->mRenWin->GetDoubleBuffer()? 0 /*back*/ : 1 /*front*/, array);
|
|
this->cachedImageCleanFlag = true;
|
|
emit cachedImageClean();
|
|
}
|
|
|
|
void QVTKWidget::setAutomaticImageCacheEnabled(bool flag)
|
|
{
|
|
this->automaticImageCache = flag;
|
|
if (!flag)
|
|
{
|
|
this->mCachedImage->Initialize();
|
|
this->mCachedImage->SetOrigin(0,0,0);
|
|
this->mCachedImage->SetSpacing(1,1,1);
|
|
this->markCachedImageAsDirty();
|
|
}
|
|
}
|
|
bool QVTKWidget::isAutomaticImageCacheEnabled() const
|
|
{
|
|
return this->automaticImageCache;
|
|
}
|
|
|
|
void QVTKWidget::setMaxRenderRateForImageCache(double rate)
|
|
{
|
|
this->maxImageCacheRenderRate = rate;
|
|
}
|
|
double QVTKWidget::maxRenderRateForImageCache() const
|
|
{
|
|
return this->maxImageCacheRenderRate;
|
|
}
|
|
|
|
void QVTKWidget::setDeferRenderInPaintEvent(bool val)
|
|
{
|
|
this->mDeferRenderInPaintEvent = val;
|
|
}
|
|
|
|
bool QVTKWidget::deferRenderInPaintEvent() const
|
|
{
|
|
return this->mDeferRenderInPaintEvent;
|
|
}
|
|
|
|
vtkImageData* QVTKWidget::cachedImage()
|
|
{
|
|
// Make sure image is up to date.
|
|
this->paintEvent(NULL);
|
|
this->saveImageToCache();
|
|
|
|
return this->mCachedImage;
|
|
}
|
|
|
|
/*! overloaded Qt's event handler to capture additional keys that Qt has
|
|
default behavior for (for example the Tab and Shift-Tab key)
|
|
*/
|
|
bool QVTKWidget::event(QEvent* e)
|
|
{
|
|
if(e->type() == QEvent::ParentAboutToChange)
|
|
{
|
|
this->markCachedImageAsDirty();
|
|
if (this->mRenWin)
|
|
{
|
|
// Finalize the window to remove graphics resources associated with
|
|
// this window
|
|
if(this->mRenWin->GetMapped())
|
|
{
|
|
this->mRenWin->Finalize();
|
|
}
|
|
}
|
|
}
|
|
else if(e->type() == QEvent::ParentChange)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
x11_setup_window();
|
|
// connect to new window
|
|
this->mRenWin->SetWindowId( reinterpret_cast<void*>(this->winId()));
|
|
|
|
// start up the window to create graphics resources for this window
|
|
if(isVisible())
|
|
{
|
|
this->mRenWin->Start();
|
|
}
|
|
}
|
|
}
|
|
else if(e->type() == QEvent::TouchBegin ||
|
|
e->type() == QEvent::TouchUpdate ||
|
|
e->type() == QEvent::TouchEnd)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
if (e->isAccepted())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(QObject::event(e))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(e->type() == QEvent::KeyPress)
|
|
{
|
|
QKeyEvent* ke = static_cast<QKeyEvent*>(e);
|
|
this->keyPressEvent(ke);
|
|
return ke->isAccepted();
|
|
}
|
|
|
|
return QWidget::event(e);
|
|
}
|
|
|
|
|
|
/*! handle resize event
|
|
*/
|
|
void QVTKWidget::resizeEvent(QResizeEvent* e)
|
|
{
|
|
QWidget::resizeEvent(e);
|
|
|
|
if(!this->mRenWin)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't set size on subclass of vtkRenderWindow or it triggers recursion.
|
|
// Getting this event in the first place means the window was already
|
|
// resized and we're updating the sizes in VTK.
|
|
this->mRenWin->vtkRenderWindow::SetSize(this->width(), this->height());
|
|
|
|
// and update the interactor
|
|
if(this->mRenWin->GetInteractor())
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
|
|
this->markCachedImageAsDirty();
|
|
}
|
|
|
|
void QVTKWidget::moveEvent(QMoveEvent* e)
|
|
{
|
|
QWidget::moveEvent(e);
|
|
|
|
if(!this->mRenWin)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Don't set size on subclass of vtkRenderWindow or it triggers recursion.
|
|
// Getting this event in the first place means the window was already
|
|
// resized and we're updating the sizes in VTK.
|
|
this->mRenWin->vtkRenderWindow::SetPosition(this->x(), this->y());
|
|
}
|
|
|
|
/*! handle paint event
|
|
*/
|
|
void QVTKWidget::paintEvent(QPaintEvent* )
|
|
{
|
|
vtkRenderWindowInteractor* iren = this->mRenWin ? this->mRenWin->GetInteractor() : NULL;
|
|
if (!iren || !iren->GetEnabled())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// In Qt 4.1+ let's support redirected painting
|
|
// if redirected, let's grab the image from VTK, and paint it to the device
|
|
QPaintDevice* device = QPainter::redirected(this);
|
|
bool usingRedirectedDevice = (device != NULL && device != this);
|
|
|
|
// if we have a saved image, use it
|
|
if (this->paintCachedImage() == false)
|
|
{
|
|
// we don't defer render in redirected painting is active since the target
|
|
// being painted to may not be around when the deferred render call happens.
|
|
if (!usingRedirectedDevice && this->mDeferRenderInPaintEvent)
|
|
{
|
|
this->deferRender();
|
|
}
|
|
else
|
|
{
|
|
iren->Render();
|
|
}
|
|
}
|
|
|
|
// Irrespective of whether cache was used on or, if using redirected painting
|
|
// is being employed, we need to "paint" the image from the render window to
|
|
// the redirected target.
|
|
if (usingRedirectedDevice)
|
|
{
|
|
Q_ASSERT(device);
|
|
|
|
int w = this->width();
|
|
int h = this->height();
|
|
QImage img(w, h, QImage::Format_RGB32);
|
|
vtkUnsignedCharArray* pixels = vtkUnsignedCharArray::New();
|
|
pixels->SetArray(img.bits(), w*h*4, 1);
|
|
this->mRenWin->GetRGBACharPixelData(0, 0, w-1, h-1, 1, pixels);
|
|
pixels->Delete();
|
|
img = img.rgbSwapped();
|
|
img = img.mirrored();
|
|
|
|
QPainter painter(this);
|
|
painter.drawImage(QPointF(0.0,0.0), img);
|
|
}
|
|
}
|
|
|
|
/*! handle mouse press event
|
|
*/
|
|
void QVTKWidget::mousePressEvent(QMouseEvent* e)
|
|
{
|
|
|
|
// Emit a mouse press event for anyone who might be interested
|
|
emit mouseEvent(e);
|
|
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
|
|
}
|
|
|
|
/*! handle mouse move event
|
|
*/
|
|
void QVTKWidget::mouseMoveEvent(QMouseEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
|
|
// Emit a mouse press event for anyone who might be interested
|
|
emit mouseEvent(e);
|
|
}
|
|
}
|
|
|
|
|
|
/*! handle enter event
|
|
*/
|
|
void QVTKWidget::enterEvent(QEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
/*! handle leave event
|
|
*/
|
|
void QVTKWidget::leaveEvent(QEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
/*! handle mouse release event
|
|
*/
|
|
void QVTKWidget::mouseReleaseEvent(QMouseEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
|
|
// Emit a mouse press event for anyone who might be interested
|
|
emit mouseEvent(e);
|
|
}
|
|
}
|
|
|
|
/*! handle key press event
|
|
*/
|
|
void QVTKWidget::keyPressEvent(QKeyEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
/*! handle key release event
|
|
*/
|
|
void QVTKWidget::keyReleaseEvent(QKeyEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::wheelEvent(QWheelEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::focusInEvent(QFocusEvent* e)
|
|
{
|
|
// These prevent updates when the window
|
|
// gains or loses focus. By default, Qt
|
|
// does an update because the color group's
|
|
// active status changes. We don't even use
|
|
// color groups so we do nothing here.
|
|
|
|
// also pass to interactor
|
|
mIrenAdapter->ProcessEvent(e, this->GetInteractor());
|
|
}
|
|
|
|
void QVTKWidget::focusOutEvent(QFocusEvent* e)
|
|
{
|
|
// These prevent updates when the window
|
|
// gains or loses focus. By default, Qt
|
|
// does an update because the color group's
|
|
// active status changes. We don't even use
|
|
// color groups so we do nothing here.
|
|
|
|
// also pass to interactor
|
|
mIrenAdapter->ProcessEvent(e, this->GetInteractor());
|
|
}
|
|
|
|
|
|
void QVTKWidget::contextMenuEvent(QContextMenuEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::dragEnterEvent(QDragEnterEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::dragMoveEvent(QDragMoveEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::dragLeaveEvent(QDragLeaveEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::dropEvent(QDropEvent* e)
|
|
{
|
|
if(this->mRenWin)
|
|
{
|
|
mIrenAdapter->ProcessEvent(e, this->mRenWin->GetInteractor());
|
|
}
|
|
}
|
|
|
|
void QVTKWidget::showEvent(QShowEvent* e)
|
|
{
|
|
this->markCachedImageAsDirty();
|
|
|
|
QWidget::showEvent(e);
|
|
}
|
|
|
|
QPaintEngine* QVTKWidget::paintEngine() const
|
|
{
|
|
return mPaintEngine;
|
|
}
|
|
|
|
|
|
// X11 stuff near the bottom of the file
|
|
// to prevent namespace collisions with Qt headers
|
|
|
|
#if defined(Q_WS_X11) || defined (Q_OS_LINUX)
|
|
#if defined(VTK_USE_OPENGL_LIBRARY)
|
|
#include "vtkXOpenGLRenderWindow.h"
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VTK_USE_TDX
|
|
// Description:
|
|
// Receive notification of the creation of the TDxDevice
|
|
void QVTKWidget::setDevice(vtkTDxDevice *device)
|
|
{
|
|
#if defined(Q_WS_X11) || defined(Q_OS_LINUX)
|
|
if(this->GetInteractor()->GetDevice()!=device)
|
|
{
|
|
this->GetInteractor()->SetDevice(device);
|
|
}
|
|
#else
|
|
(void)device; // to avoid warnings.
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
void QVTKWidget::x11_setup_window()
|
|
{
|
|
#if defined(Q_WS_X11)
|
|
// NOTE: deliberately not executing this code for Qt5. It caused issues with
|
|
// glewInit() when I did that. Just letting the Qt create the visual/colormap
|
|
// seems to work better.
|
|
|
|
// this whole function is to allow this window to have a
|
|
// different colormap and visual than the rest of the Qt application
|
|
// this is very important if Qt's default visual and colormap is
|
|
// not enough to get a decent graphics window
|
|
|
|
|
|
// save widget states
|
|
bool tracking = this->hasMouseTracking();
|
|
Qt::FocusPolicy focus_policy = focusPolicy();
|
|
bool visible = isVisible();
|
|
if(visible)
|
|
{
|
|
hide();
|
|
}
|
|
|
|
|
|
// get visual and colormap from VTK
|
|
XVisualInfo* vi = 0;
|
|
Colormap cmap = 0;
|
|
Display* display = reinterpret_cast<Display*>(mRenWin->GetGenericDisplayId());
|
|
|
|
// check ogl and mesa and get information we need to create a decent window
|
|
#if defined(VTK_USE_OPENGL_LIBRARY)
|
|
vtkXOpenGLRenderWindow* ogl_win = vtkXOpenGLRenderWindow::SafeDownCast(mRenWin);
|
|
if(ogl_win)
|
|
{
|
|
vi = ogl_win->GetDesiredVisualInfo();
|
|
cmap = ogl_win->GetDesiredColormap();
|
|
}
|
|
#endif
|
|
|
|
// can't get visual, oh well.
|
|
// continue with Qt's default visual as it usually works
|
|
if(!vi)
|
|
{
|
|
if(visible)
|
|
{
|
|
show();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// create the X window based on information VTK gave us
|
|
XSetWindowAttributes attrib;
|
|
attrib.colormap = cmap;
|
|
attrib.border_pixel = 0;
|
|
attrib.background_pixel = 0;
|
|
|
|
Window p = RootWindow(display, DefaultScreen(display));
|
|
if(parentWidget())
|
|
{
|
|
p = parentWidget()->winId();
|
|
}
|
|
|
|
XWindowAttributes a;
|
|
XGetWindowAttributes(display, this->winId(), &a);
|
|
|
|
Window win = XCreateWindow(display, p, a.x, a.y, a.width, a.height,
|
|
0, vi->depth, InputOutput, vi->visual,
|
|
CWBackPixel|CWBorderPixel|CWColormap, &attrib);
|
|
|
|
// backup colormap stuff
|
|
Window *cmw;
|
|
Window *cmwret;
|
|
int count;
|
|
if ( XGetWMColormapWindows(display, topLevelWidget()->winId(), &cmwret, &count) )
|
|
{
|
|
cmw = new Window[count+1];
|
|
memcpy( (char *)cmw, (char *)cmwret, sizeof(Window)*count );
|
|
XFree( (char *)cmwret );
|
|
int i;
|
|
for ( i=0; i<count; i++ )
|
|
{
|
|
if ( cmw[i] == winId() )
|
|
{
|
|
cmw[i] = win;
|
|
break;
|
|
}
|
|
}
|
|
if ( i >= count )
|
|
{
|
|
cmw[count++] = win;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
count = 1;
|
|
cmw = new Window[count];
|
|
cmw[0] = win;
|
|
}
|
|
|
|
|
|
// tell Qt to initialize anything it needs to for this window
|
|
create(win);
|
|
|
|
// restore colormaps
|
|
XSetWMColormapWindows( display, topLevelWidget()->winId(), cmw, count );
|
|
|
|
delete [] cmw;
|
|
XFree(vi);
|
|
|
|
XFlush(display);
|
|
|
|
// restore widget states
|
|
this->setMouseTracking(tracking);
|
|
this->setAttribute(Qt::WA_NoBackground);
|
|
this->setAttribute(Qt::WA_PaintOnScreen);
|
|
this->setFocusPolicy(focus_policy);
|
|
if(visible)
|
|
{
|
|
show();
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
#if defined(Q_OS_WIN)
|
|
bool QVTKWidget::winEvent(MSG* msg, long*)
|
|
{
|
|
// Starting with Windows Vista, Microsoft introduced WDDM.
|
|
// We need to call InvalidateRect() to work with WDDM correctly,
|
|
// especially when AERO is off.
|
|
if(msg->message == WM_PAINT &&
|
|
QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA)
|
|
{
|
|
InvalidateRect((HWND)this->winId(), NULL, FALSE);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#if QT_VERSION >= 0x050000
|
|
bool QVTKWidget::nativeEvent(const QByteArray& eventType, void* message, long* result)
|
|
{
|
|
if (eventType == "windows_generic_MSG")
|
|
{
|
|
winEvent((MSG*)message, result);
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
bool QVTKWidget::paintCachedImage()
|
|
{
|
|
// if we have a saved image, use it
|
|
if (this->cachedImageCleanFlag)
|
|
{
|
|
vtkUnsignedCharArray* array = vtkArrayDownCast<vtkUnsignedCharArray>(
|
|
this->mCachedImage->GetPointData()->GetScalars());
|
|
// put cached image into back buffer if we can
|
|
this->mRenWin->SetPixelData(0, 0, this->width()-1, this->height()-1,
|
|
array, !this->mRenWin->GetDoubleBuffer());
|
|
// swap buffers, if double buffering
|
|
this->mRenWin->Frame();
|
|
// or should we just put it on the front buffer?
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void QVTKWidget::renderEventCallback()
|
|
{
|
|
if (this->mRenWin)
|
|
{
|
|
// prevent capturing the selection buffer as the cached image. to do this
|
|
// we iterate through each renderer in the view and check if they have an
|
|
// active selector object. if so we return without saving the image
|
|
vtkRendererCollection *renderers = this->mRenWin->GetRenderers();
|
|
if(renderers)
|
|
{
|
|
renderers->InitTraversal();
|
|
|
|
while(vtkRenderer *renderer = renderers->GetNextItem())
|
|
{
|
|
if(renderer->GetSelector() != NULL)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Render happened. If we have requested a render to happen, it has happened,
|
|
// so no need to request another render. Stop the timer.
|
|
this->mDeferedRenderTimer.stop();
|
|
|
|
this->markCachedImageAsDirty();
|
|
if (this->isAutomaticImageCacheEnabled() &&
|
|
(this->mRenWin->GetDesiredUpdateRate() < this->maxRenderRateForImageCache()))
|
|
{
|
|
this->saveImageToCache();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void QVTKWidget::deferRender()
|
|
{
|
|
this->mDeferedRenderTimer.start();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void QVTKWidget::doDeferredRender()
|
|
{
|
|
vtkRenderWindowInteractor* iren = this->mRenWin ? this->mRenWin->GetInteractor() : NULL;
|
|
if (iren && iren->GetEnabled())
|
|
{
|
|
iren->Render();
|
|
}
|
|
}
|