Horde3D
http://horde3d.org/forums/

Integrating Horde3D with QtQuick 1.0
http://horde3d.org/forums/viewtopic.php?f=2&t=1645
Page 1 of 1

Author:  Christoph [ 25.02.2012, 16:48 ]
Post subject:  Integrating Horde3D with QtQuick 1.0

Hi,

I have a working implementation of Horde3D along with QtQuick 1.0 (see stripped code snipped below). There is a very fundamental problem with this implementation: The Horde3DViewport won't render correctly if flipped or rotated by QML (think of taking the result image and putting it inside a Flippable). To make this work properly I think Horde3D should be rendering to an FBO. This FBO should then be rendered to a quad - with proper rotation and projection matrices.

I have thought about using h3dGetRenderTargetData(...), but I think that won't perform well, because it will copy every frame from VRAM to RAM and back again. Any hints how to get this working?

Code:
class Horde3DViewport : public QDeclarativeItem
{
    Q_OBJECT
public:
    Horde3DViewport(QDeclarativeItem *parent)
        : QDeclarativeItem(parent), m_initialized(false), m_animation(this)
    {
        setFlag(QGraphicsItem::ItemHasNoContents, false);
        // XXX: start redraw animation (a timer, that calls QDeclarativeItem::update()).
    }

    ~Horde3DViewport()
    {
        // XXX: destroy scene and release Horde3D.
    }
       
protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        Q_UNUSED(option);
        QPaintEngine::Type engineType = painter->paintEngine()->type();
        if (engineType == QPaintEngine::OpenGL || engineType == QPaintEngine::OpenGL2) {
            painter->beginNativePainting();
            // Initialize.
            if (!m_initialized) {
                // XXX: initialize Horde3D and create a scene
                m_initialized = true;
            }
            // Render.
            h3dRender(m_camera);
            h3dFinalizeFrame();
            // Restore render state.
            glBindBuffer(GL_ARRAY_BUFFER, 0);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
            glBindRenderbuffer(GL_RENDERBUFFER, 0);
            glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
            painter->endNativePainting();
        }
    }
   

private:
    // XXX: Pipeline, etc.
    H3DNode m_camera;
};

Author:  Volker [ 25.02.2012, 19:54 ]
Post subject:  Re: Integrating Horde3D with QtQuick 1.0

One of the last changes to the SVN trunk was that Horde does not bind 0 as the main render target anymore but does retain the currently bound FBO and use that to render the main output into. So if you create an bind an FBO outside of Horde and then call it's render function you should get what you want.

Author:  Christoph [ 26.02.2012, 02:18 ]
Post subject:  Re: Integrating Horde3D with QtQuick 1.0

Thanks alot. I had to work around one thing: GL_CULL_FACE, GL_DEPTH_TEST and GL_MULTISAMPLE dont get restored (had to brute-force-check the OpenGL state using glIsEnabled :mrgreen: ).

A simplified (untested) version of my code is below (Header+Source+QDeclarativeView usage). Steal it if you want to :)

Cheers,
Christoph

Code:
#ifndef HORDEVIEWPORT_H
#define HORDEVIEWPORT_H

#include <QtDeclarative/QDeclarativeItem>
#include <QtCore/QBasicTimer>
#include <Horde3D.h>

class QGLFramebufferObject;
class HordeViewport;

class HordeViewportAnimation : public QAbstractAnimation
{
    Q_OBJECT
public:
    HordeViewportAnimation(HordeViewport *parent = 0);
    ~HordeViewportAnimation();

    int duration() const;

protected:
    void updateCurrentTime(int currentTime);

private:
    HordeViewport* m_viewport;
};

class HordeViewport : public QDeclarativeItem
{
    Q_OBJECT
public:
    HordeViewport(QDeclarativeItem *parent = 0);
    ~HordeViewport();

protected:
    void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);

private:
    void validateGL(int deviceWidth, int deviceHeight);
    void paintGL();

   bool m_firstRun;
    bool m_valid;
    QGLFramebufferObject *m_fbo;
    HordeViewportAnimation m_animation;
    H3DNode m_camera;
};

QML_DECLARE_TYPE(HordeViewport)

#endif


Code:
#include "hordeviewport.h"
#include <QGLFramebufferObject>

HordeViewportAnimation::HordeViewportAnimation(HordeViewport *parent)
    : QAbstractAnimation(parent), m_viewport(parent)
{
    // Do nothing.
}

HordeViewportAnimation::~HordeViewportAnimation()
{
    // Do nothing.
}

int HordeViewportAnimation::duration() const
{
    // Duration is undefined (infinite).
    return -1;
}

void HordeViewportAnimation::updateCurrentTime(int currentTime)
{
    // Schedule redraw.
    m_viewport->update();
}

HordeViewport::HordeViewport(QDeclarativeItem *parent)
    : QDeclarativeItem(parent), m_firstRun(true), m_valid(false),
      m_fbo(0), m_animation(this), m_camera(0)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);
    m_animation.start();
}

HordeViewport::~HordeViewport()
{
    h3dRelease();
    m_animation.stop();
    if (m_fbo) {
        delete m_fbo;
    }
}

void HordeViewport::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    QPaintEngine::Type engineType = painter->paintEngine()->type();
    if (engineType == QPaintEngine::OpenGL || engineType == QPaintEngine::OpenGL2) {
        painter->beginNativePainting();
        // Validate if required.
        if (!m_valid) {
            validateGL(painter->device()->width(),
                       painter->device()->height());
            m_valid = true;
        }
        // Render to FBO.
        m_fbo->bind();
        paintGL();
        m_fbo->release();
        // Render FBO to quad.
        glEnable(GL_TEXTURE_2D);
        m_fbo->drawTexture(QPointF(0, 0), m_fbo->texture());
        painter->endNativePainting();
    }
}

void HordeViewport::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
    QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
    m_valid = false;
}

void HordeViewport::validateGL(int deviceWidth, int deviceHeight)
{
   if (m_firstRun) {
      if (!h3dInit()) {
         qCritical() << "h3dInit failed";
      }
      // XXX: other init code
        m_firstRun = false;
   }
    if (m_fbo) {
        delete m_fbo;
    }
    m_fbo = new QGLFramebufferObject(deviceWidth, deviceHeight);
    if (m_camera) {
        // Resize viewport
        h3dSetNodeParamI(m_camera, H3DCamera::ViewportXI, 0);
        h3dSetNodeParamI(m_camera, H3DCamera::ViewportYI, 0);
        h3dSetNodeParamI(m_camera, H3DCamera::ViewportWidthI, deviceWidth);
        h3dSetNodeParamI(m_camera, H3DCamera::ViewportHeightI, deviceHeight);
        // Set virtual camera parameters
        float aspectRatio = static_cast<float>(deviceWidth) / deviceHeight;
        h3dSetupCameraView(m_camera, 45.0f, aspectRatio, 0.1f, 1000.0f);
        H3DRes cameraPipeRes = h3dGetNodeParamI(m_camera, H3DCamera::PipeResI);
        h3dResizePipelineBuffers(cameraPipeRes, deviceWidth, deviceHeight);
    }
}

void HordeViewport::paintGL()
{
    if (...camera changed...) {
        m_camera = // XXX: get camera.
        m_valid = false;
    }
    // XXX: Update scene.
    // Render scene.
    if (m_camera) {
        // Render.
        h3dRender(m_camera);
        h3dFinalizeFrame();
        // Restore render state.
        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);
    }
}


Code:
QDeclarativeView *m_view
qmlRegisterType<HordeViewport>("HordeComponents", 1, 0, "HordeViewport");
// Setup view.
m_view->setViewport(new QGLWidget(QGLFormat::defaultFormat()));
m_view->setRenderHint(QPainter::SmoothPixmapTransform);
m_view->setRenderHint(QPainter::Antialiasing);
m_view->setResizeMode(QDeclarativeView::SizeRootObjectToView);

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/