Horde3D

Next-Generation Graphics Engine
It is currently 08.12.2021, 17:20

All times are UTC + 1 hour




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: 08.08.2013, 04:14 
Offline

Joined: 08.01.2008, 14:57
Posts: 66
Hi guys,

I'm trying to integrate Horde3D (from horde3d-x branch) inside the new Qt Quick 2(.1) system of Qt 5(.1).

This is the current code:

view3d.h
Code:
#ifndef VIEW3D_H
#define VIEW3D_H

#include <QQuickItem>
#include <QDateTime>
#include <Horde3D.h>

class View3D : public QQuickItem
{
    Q_OBJECT

protected:
    H3DRes  m_pipeline;
    H3DNode m_cam;

public:
    View3D(
        QQuickItem* parent = 0
    );
    virtual ~View3D();

private slots:
    void onPaint();
    void onRendered();
    void onWindowChanged(QQuickWindow* win);

signals:
    void rendered();
};

#endif // VIEW3D_H


view3d.cpp
Code:
#include "view3d.h"
#include <QQuickWindow>
#include <Horde3DUtils.h>

View3D::View3D(QQuickItem* parent)
   :    QQuickItem(parent),
        m_cam(0)
{
    this->setObjectName("View3D");

    QObject::connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(onWindowChanged(QQuickWindow*)));
    QObject::connect(this, SIGNAL(rendered()), this, SLOT(onRendered()), Qt::DirectConnection);
}

View3D::~View3D()
{
    h3dRelease();
}

void View3D::onPaint()
{
    // Initialize engine.
    h3dInit();

    if (!m_cam)
    {
        // Add a pipeline resource.
        m_pipeline = h3dAddResource(H3DResTypes::Pipeline, "pipelines/forward.pipeline.xml", 0);

        // Add a model.
        H3DRes modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/knight/knight.scene.xml", 0);
        H3DNode model = h3dAddNodes(H3DRootNode, modelRes);

        // Add a light source.
        H3DNode light = h3dAddLightNode(H3DRootNode, "Light1", 0, "LIGHTING", "SHADOWMAP");
        h3dSetNodeTransform(light, 0, 20, 0, 0, 0, 0, 1, 1, 1);
        h3dSetNodeParamF(light, H3DLight::RadiusF, 0, 50.0f);

        // Add a camera
        m_cam = h3dAddCameraNode(H3DRootNode, "Camera", m_pipeline);

        // Load added resources.
        h3dutLoadResourcesFromDisk("");
    }

    int x = this->x();
    int y = this->y();
    int width = this->width();
    int height = this->height();

    // Setup viewport and render target sizes
    h3dSetNodeParamI(m_cam, H3DCamera::ViewportXI, x);
    h3dSetNodeParamI(m_cam, H3DCamera::ViewportYI, y);
    h3dSetNodeParamI(m_cam, H3DCamera::ViewportWidthI, width);
    h3dSetNodeParamI(m_cam, H3DCamera::ViewportHeightI, height);
    h3dSetupCameraView(m_cam, 45.0f, (float)width / height, 0.5f, 2048.0f);
    h3dResizePipelineBuffers(m_pipeline, width, height);

    // Render scene
    h3dRender(m_cam);

    // Finish rendering of frame
    h3dFinalizeFrame();

    emit rendered();
}

void View3D::onRendered()
{
    this->window()->update();
}

void View3D::onWindowChanged(QQuickWindow* win)
{
    if (win)
    {
        QObject::connect(win, SIGNAL(beforeRendering()), this, SLOT(onPaint()), Qt::DirectConnection);

        win->setClearBeforeRendering(false);
    }
}



main.cpp
Code:
#include "view3d.h"
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QQuickWindow>
#include <QApplication>

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    app.setApplicationName(QObject::tr("Qt5 + Horde3D-x"));

    qmlRegisterType<View3D>("View3D", 1, 0, "View3D");

    QQmlApplicationEngine engine(QUrl("main.qml"));
    QObject* topLevel = engine.rootObjects().value(0);
    QQuickWindow* win = qobject_cast<QQuickWindow*>(topLevel);

    if (!win)
    {
        qWarning("Error: not a valid window.");
        return -1;
    }

    win->showMaximized();

    return app.exec();
}


main.qml
Code:
import QtQuick 2.1
import QtQuick.Controls 1.0
import View3D 1.0

ApplicationWindow {
    id: main

    menuBar: MenuBar {

        Menu {
            title: qsTr("&File")

            MenuItem {
                text: qsTr("&New Project")
                shortcut: "Ctrl+N"
            }
        }
    }

    View3D {
        id: centralArea

        anchors.fill: parent
    }

    Rectangle {
        width: 200
        height: 200
        color: "#ffffff"
    }
}


The problem is that after h3dInit call, something goes wrong with the OpenGL context and the ApplicationWindow is rendered all black (also the menubar becomes black) and Horde3D doesn't render anything.

The front Rectangle element, instead, is rendered correctly.

Any hints?

Thanks,
Emanuele


Top
 Profile  
Reply with quote  
PostPosted: 09.08.2013, 12:50 
Offline

Joined: 26.08.2008, 18:48
Posts: 120
I haven't used Qt for years, so probably I am not the best person to help.

What i would try:
- You should call h3dInit only once / not per frame (before any other h3d call)
- In order to successfully initialize the engine the calling application must provide a valid OpenGL context.
this could be done using h3dut on windows or using qt for creating the context, I found this: http://qt-project.org/forums/viewthread/4109 maybe you should subclass QGLWidget.

Hope it helps


Top
 Profile  
Reply with quote  
PostPosted: 15.08.2013, 07:13 
Offline

Joined: 08.01.2008, 14:57
Posts: 66
Hi attila,

thanks for your reply.

BTW the approach you suggested is valid for Qt4 (is still valid for Qt5, but only if you want to use widgets), but my purpose is to integrate Horde3D inside the new QtQuick (2.1) framework which is OpenGL-based (so the OGL context is already there).


Top
 Profile  
Reply with quote  
PostPosted: 17.08.2013, 00:41 
Offline

Joined: 08.01.2008, 14:57
Posts: 66
Here it is a first working prototype :)

It's not perfect and has many limitations, but it's a starting point to reach something more cool!

Feel free to use it:

view3d.h
Code:
#ifndef VIEW3D_H
#define VIEW3D_H

#include <QQuickItem>
#include <QOpenGLFramebufferObject>
#include <Horde3D.h>

class View3D : public QQuickItem
{
    Q_OBJECT

private:
    int m_timerID;
    QOpenGLFramebufferObject* m_fbo;
    H3DNode m_cam;

public:
    View3D(
        QQuickItem* parent = 0
    );
    virtual ~View3D();

protected:
    void timerEvent(QTimerEvent* evt);

private slots:
    void paint();
    void cleanup();
    void handleWindowChanged(QQuickWindow* win);
};

#endif // VIEW3D_H


view3d.cpp
Code:
#include "view3d.h"
#include <QQuickWindow>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <Horde3DUtils.h>

View3D::View3D(QQuickItem* parent)
   :    QQuickItem(parent),
        m_timerID(0),
        m_fbo(0),
        m_cam(0)
{
    this->setFlag(QQuickItem::ItemHasContents);

    QObject::connect(this, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(handleWindowChanged(QQuickWindow*)));
}

View3D::~View3D()
{
    this->cleanup();
}

void View3D::timerEvent(QTimerEvent* evt)
{
    if (evt && evt->timerId() == m_timerID)
        this->window()->update();
}

void View3D::paint()
{
    // Save (push) Qt state.
    glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    glShadeModel(GL_FLAT);
    glDisable(GL_CULL_FACE);
    glDisable(GL_LIGHTING);
    glDisable(GL_STENCIL_TEST);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    // Clear back surface.
    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    // Render Horde3D.
    int x = this->x();
    int y = this->y();
    int width = this->width();
    int height = this->height();

    delete m_fbo;
    m_fbo = 0;

    if (width && height)
        m_fbo = new QOpenGLFramebufferObject(width, height);

    if (m_fbo)
    {
        QOpenGLFunctions glFunctions(QOpenGLContext::currentContext());
        glFunctions.glUseProgram(0);

        m_fbo->bind();

        if (!m_cam)
        {
            // Initialize engine.
            h3dInit();

            h3dSetOption(H3DOptions::LoadTextures, 1);
            h3dSetOption(H3DOptions::TexCompression, 0);
            h3dSetOption(H3DOptions::FastAnimation, 0);
            h3dSetOption(H3DOptions::MaxAnisotropy, 4);
            h3dSetOption(H3DOptions::ShadowMapSize, 2048);

            // Add resources.
            H3DRes pipelineRes = h3dAddResource(H3DResTypes::Pipeline, "pipelines/forward.pipeline.xml", 0);
            H3DRes modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/platform/platform.scene.xml", 0);

            // Load added resources.
            h3dutLoadResourcesFromDisk("data/");

            // Add an environment.
            H3DNode model = h3dAddNodes(H3DRootNode, modelRes);
            h3dSetNodeTransform(model, 0, -20, 0, 0, 0, 0, 20, 20, 20 );

            // Add a light source.
            H3DNode light = h3dAddLightNode( H3DRootNode, "Light1", 0, "LIGHTING", "SHADOWMAP" );
            h3dSetNodeTransform( light, 0, 15, 10, -60, 0, 0, 1, 1, 1 );
            h3dSetNodeParamF( light, H3DLight::RadiusF, 0, 30 );
            h3dSetNodeParamF( light, H3DLight::FovF, 0, 90 );
            h3dSetNodeParamI( light, H3DLight::ShadowMapCountI, 1 );
            h3dSetNodeParamF( light, H3DLight::ShadowMapBiasF, 0, 0.01f );
            h3dSetNodeParamF( light, H3DLight::ColorF3, 0, 1.0f );
            h3dSetNodeParamF( light, H3DLight::ColorF3, 1, 0.8f );
            h3dSetNodeParamF( light, H3DLight::ColorF3, 2, 0.7f );
            h3dSetNodeParamF( light, H3DLight::ColorMultiplierF, 0, 1.0f );

            // Add a camera.
            m_cam = h3dAddCameraNode(H3DRootNode, "Camera", pipelineRes);

            QObject::connect(QOpenGLContext::currentContext(), SIGNAL(aboutToBeDestroyed()), this, SLOT(cleanup()), Qt::DirectConnection);
        }

        // Setup viewport and render target sizes.
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportXI, 0);
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportYI, 0);
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportWidthI, width);
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportHeightI, height);
        h3dSetupCameraView(m_cam, 45.0f, (float)width / height, 0.1f, 1000.0f);
        h3dResizePipelineBuffers(h3dGetNodeParamI(m_cam, H3DCamera::PipeResI), width, height);

        // Render scene.
        h3dRender(m_cam);

        // Finish rendering of frame.
        h3dFinalizeFrame();

        m_fbo->release();
        m_fbo->blitFramebuffer(this->window()->renderTarget(), m_fbo);

        // Restore (pop) Qt state.
        glMatrixMode(GL_TEXTURE);
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
        glPopAttrib();
        glPopClientAttrib();
    }
}

void View3D::cleanup()
{
    this->handleWindowChanged(0);

    if (m_cam)
    {
        h3dRelease();
        m_cam = 0;

        delete m_fbo;
        m_fbo = 0;
    }
}

void View3D::handleWindowChanged(QQuickWindow *win)
{
    if (m_timerID)
    {
        this->killTimer(m_timerID);

        m_timerID = 0;
    }

    if (win)
    {
        QObject::connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);

        win->setClearBeforeRendering(false);

        m_timerID = this->startTimer(16);
    }
}


Top
 Profile  
Reply with quote  
PostPosted: 17.08.2013, 08:27 
Offline

Joined: 08.01.2008, 14:57
Posts: 66
Another version! :)

This time I'm using QSGSimpleTextureNode, doing things (almost) right.

In fact it solved almost all of the issues of the previous solution and it's now perfectly integrated in the QtQuick scene graph instead of simply copying the render content on the window background.

view3d.h
Code:
#ifndef VIEW3D_H
#define VIEW3D_H

#include <QQuickItem>
#include <QOpenGLFramebufferObject>
#include <Horde3D.h>

class View3D : public QQuickItem
{
    Q_OBJECT

private:
    int m_timerID;
    QOpenGLFramebufferObject* m_fbo;
    H3DNode m_cam;

public:
    View3D(
        QQuickItem* parent = 0
    );
    virtual ~View3D();

protected:
    QSGNode* updatePaintNode(QSGNode* old, UpdatePaintNodeData* data);
    void timerEvent(QTimerEvent* evt);

private slots:
    void cleanup();
};

#endif // VIEW3D_H



view3d.cpp
Code:
#include "view3d.h"
#include <QQuickWindow>
#include <QOpenGLContext>
#include <QSGSimpleTextureNode>
#include <Horde3DUtils.h>

View3D::View3D(QQuickItem* parent)
   :    QQuickItem(parent),
        m_timerID(0),
        m_fbo(0),
        m_cam(0)
{
    this->setFlag(QQuickItem::ItemHasContents);
}

View3D::~View3D()
{
    this->cleanup();
}

void View3D::timerEvent(QTimerEvent* evt)
{
    if (evt && evt->timerId() == m_timerID)
        this->update();
}

QSGNode* View3D::updatePaintNode(QSGNode* node, UpdatePaintNodeData* data)
{
    QSGSimpleTextureNode* textureNode = static_cast<QSGSimpleTextureNode*>(node);

    if (!textureNode)
        textureNode = new QSGSimpleTextureNode();

    // Push Qt state.
    glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS);
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_TEXTURE);
    glPushMatrix();
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    glShadeModel(GL_FLAT);
    glDisable(GL_CULL_FACE);
    glDisable(GL_LIGHTING);
    glDisable(GL_STENCIL_TEST);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

    // Render Horde3D.
    int x = this->x();
    int y = this->y();
    int width = this->width();
    int height = this->height();

    delete m_fbo;
    m_fbo = 0;

   if (width && height)
    {
        m_fbo = new QOpenGLFramebufferObject(width, height);
        textureNode->setTexture(this->window()->createTextureFromId(m_fbo->texture(), m_fbo->size()));
    }
    else
    {
        textureNode->setTexture(this->window()->createTextureFromId(0, QSize(0,0)));
    }

    textureNode->setRect(this->boundingRect());

    // Flip Y-axis between Horde3D and GLSL.
    QMatrix4x4 flipY;
    flipY.translate(width*0.5, height*0.5);
    flipY.scale(1.0, -1.0);
    flipY.translate(-width*0.5, -height*0.5);
    data->transformNode->setMatrix(flipY);

    if (m_fbo)
    {
        m_fbo->bind();

        if (!m_cam)
        {
            // Initialize engine.
            h3dInit();

            h3dSetOption(H3DOptions::LoadTextures, 1);
            h3dSetOption(H3DOptions::TexCompression, 0);
            h3dSetOption(H3DOptions::FastAnimation, 0);
            h3dSetOption(H3DOptions::MaxAnisotropy, 4);
            h3dSetOption(H3DOptions::ShadowMapSize, 2048);

            // Add resources.
            H3DRes pipelineRes = h3dAddResource(H3DResTypes::Pipeline, "pipelines/forward.pipeline.xml", 0);
            H3DRes envRes = h3dAddResource(H3DResTypes::SceneGraph, "models/platform/platform.scene.xml", 0);
            H3DRes modelRes = h3dAddResource(H3DResTypes::SceneGraph, "models/knight/knight.scene.xml", 0);

            // Load added resources.
            h3dutLoadResourcesFromDisk("data");

            // Add an environment.
            H3DNode env = h3dAddNodes(H3DRootNode, envRes);
            h3dSetNodeTransform(env, 0, 0, 0, 0, 0, 0, 20, 20, 20 );

            // Add a model.
            H3DNode model = h3dAddNodes(H3DRootNode, modelRes);
            h3dSetNodeTransform(model, 0, 0, 0, 0, 180, 0, 1, 1, 1 );

            // Add a light source.
            H3DNode light = h3dAddLightNode( H3DRootNode, "Light1", 0, "LIGHTING", "SHADOWMAP" );
            h3dSetNodeTransform( light, 0, 15, 40, 0, 0, 0, 100, 100, 100 );
            h3dSetNodeParamF( light, H3DLight::RadiusF, 0, 1000 );
            h3dSetNodeParamF( light, H3DLight::FovF, 0, 90 );
            h3dSetNodeParamI( light, H3DLight::ShadowMapCountI, 1 );
            h3dSetNodeParamF( light, H3DLight::ShadowMapBiasF, 0, 0.01f );
            h3dSetNodeParamF( light, H3DLight::ColorF3, 0, 1.0f );
            h3dSetNodeParamF( light, H3DLight::ColorF3, 1, 0.8f );
            h3dSetNodeParamF( light, H3DLight::ColorF3, 2, 0.7f );
            h3dSetNodeParamF( light, H3DLight::ColorMultiplierF, 0, 1.0f );

            // Add a camera.
            m_cam = h3dAddCameraNode(H3DRootNode, "Camera", pipelineRes);
            h3dSetNodeTransform(m_cam, 0, 30, 100, 0, 0, 0, 1, 1, 1 );

            QObject::connect(QOpenGLContext::currentContext(), SIGNAL(aboutToBeDestroyed()), this, SLOT(cleanup()), Qt::DirectConnection);
        }

        // Setup viewport and render target sizes.
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportXI, 0);
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportYI, 0);
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportWidthI, width);
        h3dSetNodeParamI(m_cam, H3DCamera::ViewportHeightI, height);
        h3dSetupCameraView(m_cam, 45.0f, (float)width / height, 0.1f, 1000.0f);
        h3dResizePipelineBuffers(h3dGetNodeParamI(m_cam, H3DCamera::PipeResI), width, height);

        // Render scene.
        h3dRender(m_cam);

        // Finish rendering of frame.
        h3dFinalizeFrame();

        m_fbo->release();

        // Restore (pop) Qt state.
        glMatrixMode(GL_TEXTURE);
        glPopMatrix();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
        glPopAttrib();
        glPopClientAttrib();
    }

    if (!m_timerID)
        m_timerID = this->startTimer(16);

    return textureNode;
}

void View3D::cleanup()
{
    this->killTimer(m_timerID);
    m_timerID = 0;

    if (m_cam)
    {
        h3dRelease();
        m_cam = 0;

        delete m_fbo;
        m_fbo = 0;
    }
}


main.cpp
Code:
#include "view3d.h"
#include <QQuickView>
#include <QGuiApplication>

int main(int argc, char** argv)
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<View3D>("View3DToolkit", 1, 0, "View3D");

    QQuickView win;
    win.setSource(QUrl("main.qml"));
    win.setResizeMode(QQuickView::SizeRootObjectToView);
    win.show();

    return app.exec();
}


main.qml
Code:
import QtQuick 2.1
import View3DToolkit 1.0

Item {

    width: 320
    height: 480

    View3D {
        anchors.fill: parent

        Rectangle {
            color: Qt.rgba(0, 1, 0, 0.5);
            width: 100
            height: 100
            anchors.centerIn: parent
        }
    }

    Rectangle {
        color: Qt.rgba(1, 1, 1, 0.7)
        radius: 10
        border.width: 1
        border.color: "white"
        anchors.fill: label
        anchors.margins: -10
    }

    Text {
        id: label
        color: "black"
        wrapMode: Text.WordWrap
        text: "The background here is a squircle rendered with raw OpenGL using the 'beforeRender()' signal in QQuickWindow. This text label and its border is rendered using QML"
        anchors.right: parent.right
        anchors.left: parent.left
        anchors.bottom: parent.bottom
        anchors.margins: 20
    }
}


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group