|
#include "QVTKFramebufferObjectItem.h" |
|
|
|
// Use the OpenGL API abstraction from Qt instead of from VTK because vtkgl.h |
|
// and other Qt OpenGL-related headers do not play nice when included in the |
|
// same compilation unit |
|
#include <QOpenGLFunctions> |
|
|
|
#include <QQuickFramebufferObject> |
|
#include <QOpenGLFramebufferObject> |
|
|
|
#include <vtkGenericOpenGLRenderWindow.h> |
|
#include <vtkObjectFactory.h> |
|
|
|
#include <vtkRendererCollection.h> |
|
#include <vtkCamera.h> |
|
|
|
class QVTKFramebufferObjectRenderer; |
|
|
|
class vtkInternalOpenGLRenderWindow : public vtkGenericOpenGLRenderWindow, protected QOpenGLFunctions |
|
{ |
|
public: |
|
static vtkInternalOpenGLRenderWindow* New(); |
|
vtkTypeMacro(vtkInternalOpenGLRenderWindow, vtkGenericOpenGLRenderWindow) |
|
|
|
virtual void OpenGLInitState() |
|
{ |
|
Superclass::OpenGLInitState(); |
|
|
|
// Before any of the gl* functions in QOpenGLFunctions are called for a |
|
// given OpenGL context, an initialization must be run within that context |
|
this->MakeCurrent(); |
|
initializeOpenGLFunctions(); |
|
|
|
glUseProgram(0); // Shouldn't Superclass::OpenGLInitState() handle this? |
|
glDisable(GL_DEPTH_TEST); // depth buffer fighting between the cone and the backround without this |
|
glDisable(GL_BLEND); // doesn't seem crucial (?) but it is one of the differnces that showed up in apitrace analysis |
|
} |
|
|
|
// Override to use deferred rendering - Tell the QSG that we need to |
|
// be rendered which will then, at the appropriate time, call |
|
// InternalRender to do the actual OpenGL rendering. |
|
virtual void Render(); |
|
|
|
// Do the actual OpenGL rendering |
|
void InternalRender() |
|
{ |
|
Superclass::Render(); |
|
} |
|
|
|
// Provides a convenient way to set the protected FBO ivars from an existing |
|
// FBO that was created and owned by Qt's FBO abstraction class |
|
// QOpenGLFramebufferObject |
|
void SetFramebufferObject(QOpenGLFramebufferObject *fbo); |
|
|
|
QVTKFramebufferObjectRenderer *QtParentRenderer; |
|
|
|
protected: |
|
vtkInternalOpenGLRenderWindow() : |
|
QtParentRenderer(0) |
|
{ |
|
} |
|
|
|
~vtkInternalOpenGLRenderWindow() |
|
{ |
|
// Prevent superclass destructors from destroying the framebuffer object. |
|
// QOpenGLFramebufferObject owns the FBO and manages it's lifecyle. |
|
this->OffScreenRendering = 0; |
|
} |
|
}; |
|
vtkStandardNewMacro(vtkInternalOpenGLRenderWindow); |
|
|
|
|
|
class QVTKFramebufferObjectRenderer : public QQuickFramebufferObject::Renderer |
|
{ |
|
friend class vtkInternalOpenGLRenderWindow; |
|
|
|
public: |
|
QVTKFramebufferObjectRenderer(vtkInternalOpenGLRenderWindow *rw) : |
|
m_vtkRenderWindow(rw), |
|
m_framebufferObject(0) |
|
{ |
|
m_vtkRenderWindow->Register(NULL); |
|
m_vtkRenderWindow->QtParentRenderer = this; |
|
} |
|
|
|
~QVTKFramebufferObjectRenderer() |
|
{ |
|
m_vtkRenderWindow->QtParentRenderer = 0; |
|
m_vtkRenderWindow->Delete(); |
|
} |
|
|
|
virtual void synchronize(QQuickFramebufferObject * item) |
|
{ |
|
// the first synchronize call - right before the the framebufferObject |
|
// is created for the first time |
|
if (!m_framebufferObject) |
|
{ |
|
QVTKFrameBufferObjectItem *vtkItem = static_cast<QVTKFrameBufferObjectItem*>(item); |
|
vtkItem->init(); |
|
} |
|
} |
|
|
|
// Called from the render thread when the GUI thread is NOT blocked |
|
virtual void render() |
|
{ |
|
m_vtkRenderWindow->PushState(); |
|
m_vtkRenderWindow->OpenGLInitState(); |
|
m_vtkRenderWindow->InternalRender(); // vtkXOpenGLRenderWindow renders the scene to the FBO |
|
m_vtkRenderWindow->PopState(); |
|
|
|
// Dolly camera back and forth - FOR DEMONSTRATION PURPOSES ONLY |
|
static int callCount = 0; |
|
++callCount; |
|
double dolly = 1.0 + ((callCount % 200) > 100 ? -0.001 : 0.001); |
|
m_vtkRenderWindow->GetRenderers()->GetFirstRenderer()->GetActiveCamera()->Dolly(dolly); |
|
this->update(); |
|
} |
|
|
|
QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) |
|
{ |
|
qDebug("QVTKFramebufferObjectRenderer::createFramebufferObject"); |
|
QOpenGLFramebufferObjectFormat format; |
|
format.setAttachment(QOpenGLFramebufferObject::Depth); |
|
m_framebufferObject = new QOpenGLFramebufferObject(size, format); |
|
|
|
m_vtkRenderWindow->SetFramebufferObject(m_framebufferObject); |
|
|
|
return m_framebufferObject; |
|
} |
|
|
|
vtkInternalOpenGLRenderWindow *m_vtkRenderWindow; |
|
QOpenGLFramebufferObject *m_framebufferObject; |
|
}; |
|
|
|
// |
|
// vtkInternalOpenGLRenderWindow Definitions |
|
// |
|
|
|
void vtkInternalOpenGLRenderWindow::Render() |
|
{ |
|
if (this->QtParentRenderer) |
|
{ |
|
this->QtParentRenderer->update(); |
|
} |
|
} |
|
|
|
void vtkInternalOpenGLRenderWindow::SetFramebufferObject(QOpenGLFramebufferObject *fbo) |
|
{ |
|
// QOpenGLFramebufferObject documentation states that "The color render |
|
// buffer or texture will have the specified internal format, and will |
|
// be bound to the GL_COLOR_ATTACHMENT0 attachment in the framebuffer |
|
// object" |
|
this->BackLeftBuffer = this->FrontLeftBuffer = this->BackBuffer = this->FrontBuffer = |
|
static_cast<unsigned int>(GL_COLOR_ATTACHMENT0); |
|
|
|
// Save GL objects by static casting to standard C types. GL* types |
|
// are not allowed in VTK header files. |
|
QSize fboSize = fbo->size(); |
|
this->Size[0] = fboSize.width(); |
|
this->Size[1] = fboSize.height(); |
|
this->NumberOfFrameBuffers = 1; |
|
this->FrameBufferObject = static_cast<unsigned int>(fbo->handle()); |
|
this->DepthRenderBufferObject = 0; // static_cast<unsigned int>(depthRenderBufferObject); |
|
this->TextureObjects[0] = static_cast<unsigned int>(fbo->texture()); |
|
this->OffScreenRendering = 1; |
|
this->OffScreenUseFrameBuffer = 1; |
|
this->Modified(); |
|
} |
|
|
|
// |
|
// QVTKFrameBufferObjectItem Definitions |
|
// |
|
|
|
QVTKFrameBufferObjectItem::QVTKFrameBufferObjectItem() |
|
{ |
|
m_win = vtkInternalOpenGLRenderWindow::New(); |
|
} |
|
|
|
QVTKFrameBufferObjectItem::~QVTKFrameBufferObjectItem() |
|
{ |
|
m_win->Delete(); |
|
} |
|
|
|
QQuickFramebufferObject::Renderer *QVTKFrameBufferObjectItem::createRenderer() const |
|
{ |
|
return new QVTKFramebufferObjectRenderer(static_cast<vtkInternalOpenGLRenderWindow*>(m_win)); |
|
} |
|
|
|
vtkGenericOpenGLRenderWindow *QVTKFrameBufferObjectItem::GetRenderWindow() const |
|
{ |
|
return m_win; |
|
} |
|
|
|
void QVTKFrameBufferObjectItem::init() |
|
{ |
|
qDebug("QVTKFrameBufferObjectItem::init"); |
|
} |
I don't think you can do that. I first attempted to add a vtkRenderWindowInteractor to my renderer too but it crashes fairly often. I was responding to Qt even (mouse, wheel, etc.) and calling methods from the interactor to forward the events. The issue is that the QuickItem is executed in the main thread so the events are received and processed on the main thread. But the interactor executes some OpenGL functions and there is no OpenGL context. It's probably something similar in your case.
For implementing a zoom in the image I displayed for instance, I implemented wheelEvent(QWheelEvent * p_event) in the QuickItem and managed the position of the VTK renderers'camera directly. I was implementing my own zoom via a custom vtkInteractorStyleImage so I was kind of doing that already anyway. And I no longer use any interactor.