diff options
author | Laszlo Agocs <laszlo.agocs@digia.com> | 2014-03-31 15:59:18 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@digia.com> | 2014-06-24 14:22:19 +0200 |
commit | 745a71196c8893a35a80a679674bee396606f79b (patch) | |
tree | f9bc32b7cfe88e65b54372987baf95fcd1db2ada /examples/quick | |
parent | 8eafef976f2a53b5c05967de8b4fb8f01b8e9e7b (diff) |
Make QQuickRenderControl public
QQuickRenderControl allows rendering Qt Quick 2 scenes into framebuffer
objects which can then be used in arbitrary ways in Qt-based or 3rd party
OpenGL renderers.
[ChangeLog][QtQuick] Introduced QQuickRenderControl as a public API.
Task-number: QTBUG-37944
Change-Id: I84262243b261b35cefdf67ec6bba8127a0f29275
Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
Diffstat (limited to 'examples/quick')
-rw-r--r-- | examples/quick/quick.pro | 3 | ||||
-rw-r--r-- | examples/quick/rendercontrol/demo.qml | 198 | ||||
-rw-r--r-- | examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg | bin | 0 -> 44196 bytes | |||
-rw-r--r-- | examples/quick/rendercontrol/doc/src/rendercontrol.qdoc | 33 | ||||
-rw-r--r-- | examples/quick/rendercontrol/main.cpp | 51 | ||||
-rw-r--r-- | examples/quick/rendercontrol/rendercontrol.pro | 11 | ||||
-rw-r--r-- | examples/quick/rendercontrol/rendercontrol.qrc | 5 | ||||
-rw-r--r-- | examples/quick/rendercontrol/window.cpp | 403 | ||||
-rw-r--r-- | examples/quick/rendercontrol/window.h | 100 |
9 files changed, 803 insertions, 1 deletions
diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro index 421f95a162..a412c53a65 100644 --- a/examples/quick/quick.pro +++ b/examples/quick/quick.pro @@ -22,7 +22,8 @@ SUBDIRS = quick-accessibility \ imageprovider \ window \ particles \ - demos + demos \ + rendercontrol # Widget dependent examples qtHaveModule(widgets) { diff --git a/examples/quick/rendercontrol/demo.qml b/examples/quick/rendercontrol/demo.qml new file mode 100644 index 0000000000..e7ede91540 --- /dev/null +++ b/examples/quick/rendercontrol/demo.qml @@ -0,0 +1,198 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtQuick.Particles 2.0 + +Rectangle { + id: root + color: "green" + + Rectangle { + width: 400 + height: 400 + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + Text { + anchors.centerIn: parent + text: "Qt Quick in a texture" + font.pointSize: 40 + color: "cyan" + } + + ParticleSystem { + id: particles + anchors.fill: parent + + ImageParticle { + id: smoke + system: particles + anchors.fill: parent + groups: ["A", "B"] + source: "qrc:///particleresources/glowdot.png" + colorVariation: 0 + color: "#00111111" + } + ImageParticle { + id: flame + anchors.fill: parent + system: particles + groups: ["C", "D"] + source: "qrc:///particleresources/glowdot.png" + colorVariation: 0.1 + color: "#00ff400f" + } + + Emitter { + id: fire + system: particles + group: "C" + + y: parent.height + width: parent.width + + emitRate: 350 + lifeSpan: 3500 + + acceleration: PointDirection { y: -17; xVariation: 3 } + velocity: PointDirection {xVariation: 3} + + size: 24 + sizeVariation: 8 + endSize: 4 + } + + TrailEmitter { + id: fireSmoke + group: "B" + system: particles + follow: "C" + width: root.width + height: root.height - 68 + + emitRatePerParticle: 1 + lifeSpan: 2000 + + velocity: PointDirection {y:-17*6; yVariation: -17; xVariation: 3} + acceleration: PointDirection {xVariation: 3} + + size: 36 + sizeVariation: 8 + endSize: 16 + } + + TrailEmitter { + id: fireballFlame + anchors.fill: parent + system: particles + group: "D" + follow: "E" + + emitRatePerParticle: 120 + lifeSpan: 180 + emitWidth: TrailEmitter.ParticleSize + emitHeight: TrailEmitter.ParticleSize + emitShape: EllipseShape{} + + size: 16 + sizeVariation: 4 + endSize: 4 + } + + TrailEmitter { + id: fireballSmoke + anchors.fill: parent + system: particles + group: "A" + follow: "E" + + emitRatePerParticle: 128 + lifeSpan: 2400 + emitWidth: TrailEmitter.ParticleSize + emitHeight: TrailEmitter.ParticleSize + emitShape: EllipseShape{} + + velocity: PointDirection {yVariation: 16; xVariation: 16} + acceleration: PointDirection {y: -16} + + size: 24 + sizeVariation: 8 + endSize: 8 + } + + Emitter { + id: balls + system: particles + group: "E" + + y: parent.height + width: parent.width + + emitRate: 2 + lifeSpan: 7000 + + velocity: PointDirection {y:-17*4*2; xVariation: 6*6} + acceleration: PointDirection {y: 17*2; xVariation: 6*6} + + size: 8 + sizeVariation: 4 + } + + Turbulence { //A bit of turbulence makes the smoke look better + anchors.fill: parent + groups: ["A","B"] + strength: 32 + system: particles + } + } + + onWidthChanged: particles.reset() + onHeightChanged: particles.reset() + + MouseArea { + anchors.fill: parent + onPressed: root.color = "gray" + onReleased: root.color = "green" + } +} diff --git a/examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg b/examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg Binary files differnew file mode 100644 index 0000000000..a899ebe7f5 --- /dev/null +++ b/examples/quick/rendercontrol/doc/images/rendercontrol-example.jpg diff --git a/examples/quick/rendercontrol/doc/src/rendercontrol.qdoc b/examples/quick/rendercontrol/doc/src/rendercontrol.qdoc new file mode 100644 index 0000000000..f8a9849a8a --- /dev/null +++ b/examples/quick/rendercontrol/doc/src/rendercontrol.qdoc @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \title QQuickRenderControl Example + \example rendercontrol + \brief Shows how to render a Qt Quick scene into a texture that is then used by a non-Quick based OpenGL renderer + \image rendercontrol-example.jpg +*/ diff --git a/examples/quick/rendercontrol/main.cpp b/examples/quick/rendercontrol/main.cpp new file mode 100644 index 0000000000..d362278ddf --- /dev/null +++ b/examples/quick/rendercontrol/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include "window.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + Window window; + window.resize(1024, 768); + window.show(); + return app.exec(); +} diff --git a/examples/quick/rendercontrol/rendercontrol.pro b/examples/quick/rendercontrol/rendercontrol.pro new file mode 100644 index 0000000000..ed25a11c1b --- /dev/null +++ b/examples/quick/rendercontrol/rendercontrol.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +QT += quick qml + +SOURCES += main.cpp window.cpp +HEADERS += window.h + +RESOURCES += rendercontrol.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/rendercontrol +INSTALLS += target diff --git a/examples/quick/rendercontrol/rendercontrol.qrc b/examples/quick/rendercontrol/rendercontrol.qrc new file mode 100644 index 0000000000..2246eeb842 --- /dev/null +++ b/examples/quick/rendercontrol/rendercontrol.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/rendercontrol"> + <file>demo.qml</file> + </qresource> +</RCC> diff --git a/examples/quick/rendercontrol/window.cpp b/examples/quick/rendercontrol/window.cpp new file mode 100644 index 0000000000..396e9f8afa --- /dev/null +++ b/examples/quick/rendercontrol/window.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "window.h" +#include <QOpenGLContext> +#include <QOpenGLFunctions> +#include <QOpenGLFramebufferObject> +#include <QOpenGLShaderProgram> +#include <QOpenGLVertexArrayObject> +#include <QOpenGLBuffer> +#include <QOpenGLVertexArrayObject> +#include <QOffscreenSurface> +#include <QQmlEngine> +#include <QQmlComponent> +#include <QQuickItem> +#include <QQuickWindow> +#include <QQuickRenderControl> +#include <QCoreApplication> + +Window::Window() + : m_rootItem(0), + m_fbo(0), + m_program(0), + m_vbo(0), + m_quickInitialized(false), + m_quickReady(false) +{ + setSurfaceType(QSurface::OpenGLSurface); + + QSurfaceFormat format; + // Qt Quick may need a depth and stencil buffer. Always make sure these are available. + format.setDepthBufferSize(16); + format.setStencilBufferSize(8); + setFormat(format); + + m_context = new QOpenGLContext; + m_context->setFormat(format); + m_context->create(); + + m_offscreenSurface = new QOffscreenSurface; + // Pass m_context->format(), not format. Format does not specify and color buffer + // sizes, while the context, that has just been created, reports a format that has + // these values filled in. Pass this to the offscreen surface to make sure it will be + // compatible with the context's configuration. + m_offscreenSurface->setFormat(m_context->format()); + m_offscreenSurface->create(); + + m_renderControl = new QQuickRenderControl(this); + + // Create a QQuickWindow that is associated with out render control. Note that this + // window never gets created or shown, meaning that it will never get an underlying + // native (platform) window. + m_quickWindow = new QQuickWindow(m_renderControl); + + // Create a QML engine. + m_qmlEngine = new QQmlEngine; + if (!m_qmlEngine->incubationController()) + m_qmlEngine->setIncubationController(m_quickWindow->incubationController()); + + // When Quick says there is a need to render, we will not render immediately. Instead, + // a timer with a small interval is used to get better performance. + m_updateTimer.setSingleShot(true); + m_updateTimer.setInterval(5); + connect(&m_updateTimer, &QTimer::timeout, this, &Window::updateQuick); + + // Now hook up the signals. For simplicy we don't differentiate between + // renderRequested (only render is needed, no sync) and sceneChanged (polish and sync + // is needed too). + connect(m_quickWindow, &QQuickWindow::sceneGraphInitialized, this, &Window::createFbo); + connect(m_quickWindow, &QQuickWindow::sceneGraphInvalidated, this, &Window::destroyFbo); + connect(m_renderControl, &QQuickRenderControl::renderRequested, this, &Window::requestUpdate); + connect(m_renderControl, &QQuickRenderControl::sceneChanged, this, &Window::requestUpdate); +} + +Window::~Window() +{ + // Make sure the context is current while doing cleanup. + m_context->makeCurrent(this); + + // Delete the render control first since it will free the scenegraph resources. + // Destroy the QQuickWindow only afterwards. + delete m_renderControl; + + delete m_qmlComponent; + delete m_quickWindow; + delete m_qmlEngine; + delete m_fbo; + delete m_program; + delete m_vbo; + delete m_vao; + + m_context->doneCurrent(); + + delete m_offscreenSurface; + delete m_context; +} + +void Window::createFbo() +{ + // The scene graph has been initialized. It is now time to create an FBO and associate + // it with the QQuickWindow. + m_fbo = new QOpenGLFramebufferObject(size(), QOpenGLFramebufferObject::CombinedDepthStencil); + m_quickWindow->setRenderTarget(m_fbo); +} + +void Window::destroyFbo() +{ + delete m_fbo; + m_fbo = 0; +} + +void Window::requestUpdate() +{ + if (!m_updateTimer.isActive()) + m_updateTimer.start(); +} + +void Window::run() +{ + disconnect(m_qmlComponent, SIGNAL(statusChanged(QQmlComponent::Status)), this, SLOT(run())); + + if (m_qmlComponent->isError()) { + QList<QQmlError> errorList = m_qmlComponent->errors(); + foreach (const QQmlError &error, errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + QObject *rootObject = m_qmlComponent->create(); + if (m_qmlComponent->isError()) { + QList<QQmlError> errorList = m_qmlComponent->errors(); + foreach (const QQmlError &error, errorList) + qWarning() << error.url() << error.line() << error; + return; + } + + m_rootItem = qobject_cast<QQuickItem *>(rootObject); + if (!m_rootItem) { + qWarning("run: Not a QQuickItem"); + delete rootObject; + return; + } + + // The root item is ready. Associate it with the window. + m_rootItem->setParentItem(m_quickWindow->contentItem()); + + // Update item and rendering related geometries. + updateSizes(); + + // Initialize the render control and our OpenGL resources. + m_context->makeCurrent(m_offscreenSurface); + m_renderControl->initialize(m_context); + + static const char *vertexShaderSource = + "attribute highp vec4 vertex;\n" + "attribute lowp vec2 coord;\n" + "varying lowp vec2 v_coord;\n" + "uniform highp mat4 matrix;\n" + "void main() {\n" + " v_coord = coord;\n" + " gl_Position = matrix * vertex;\n" + "}\n"; + static const char *fragmentShaderSource = + "varying lowp vec2 v_coord;\n" + "uniform sampler2D sampler;\n" + "void main() {\n" + " gl_FragColor = vec4(texture2D(sampler, v_coord).rgb, 1.0);\n" + "}\n"; + m_program = new QOpenGLShaderProgram; + m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource); + m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource); + m_program->bindAttributeLocation("vertex", 0); + m_program->bindAttributeLocation("coord", 1); + m_program->link(); + m_matrixLoc = m_program->uniformLocation("matrix"); + + m_vao = new QOpenGLVertexArrayObject; + m_vao->create(); + m_vao->bind(); + + m_vbo = new QOpenGLBuffer; + m_vbo->create(); + m_vbo->bind(); + + GLfloat v[] = { + -0.5, 0.5, 0.5, 0.5,-0.5,0.5,-0.5,-0.5,0.5, + 0.5, -0.5, 0.5, -0.5,0.5,0.5,0.5,0.5,0.5, + -0.5, -0.5, -0.5, 0.5,-0.5,-0.5,-0.5,0.5,-0.5, + 0.5, 0.5, -0.5, -0.5,0.5,-0.5,0.5,-0.5,-0.5, + + 0.5, -0.5, -0.5, 0.5,-0.5,0.5,0.5,0.5,-0.5, + 0.5, 0.5, 0.5, 0.5,0.5,-0.5,0.5,-0.5,0.5, + -0.5, 0.5, -0.5, -0.5,-0.5,0.5,-0.5,-0.5,-0.5, + -0.5, -0.5, 0.5, -0.5,0.5,-0.5,-0.5,0.5,0.5, + + 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, + -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, + -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, -0.5, + 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5 + }; + GLfloat texCoords[] = { + 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f, + 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f, + 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f, + 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f, + + 1.0f,1.0f, 1.0f,0.0f, 0.0f,1.0f, + 0.0f,0.0f, 0.0f,1.0f, 1.0f,0.0f, + 0.0f,0.0f, 1.0f,1.0f, 1.0f,0.0f, + 1.0f,1.0f, 0.0f,0.0f, 0.0f,1.0f, + + 0.0f,1.0f, 1.0f,0.0f, 1.0f,1.0f, + 1.0f,0.0f, 0.0f,1.0f, 0.0f,0.0f, + 1.0f,0.0f, 1.0f,1.0f, 0.0f,0.0f, + 0.0f,1.0f, 0.0f,0.0f, 1.0f,1.0f + }; + + const int vertexCount = 36; + m_vbo->allocate(sizeof(GLfloat) * vertexCount * 5); + m_vbo->write(0, v, sizeof(GLfloat) * vertexCount * 3); + m_vbo->write(sizeof(GLfloat) * vertexCount * 3, texCoords, sizeof(GLfloat) * vertexCount * 2); + m_vbo->release(); + + if (m_vao->isCreated()) + setupVertexAttribs(); + + // Must unbind before changing the current context. Hence the absence of + // QOpenGLVertexArrayObject::Binder here. + m_vao->release(); + + m_context->doneCurrent(); + m_quickInitialized = true; +} + +void Window::updateSizes() +{ + // Behave like SizeRootObjectToView. + m_rootItem->setWidth(width()); + m_rootItem->setHeight(height()); + + m_quickWindow->setGeometry(0, 0, width(), height()); + + m_proj.setToIdentity(); + m_proj.perspective(45, width() / float(height()), 0.01f, 100.0f); +} + +void Window::setupVertexAttribs() +{ + m_vbo->bind(); + m_program->enableAttributeArray(0); + m_program->enableAttributeArray(1); + m_context->functions()->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + m_context->functions()->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, + (const void *)(36 * 3 * sizeof(GLfloat))); + m_vbo->release(); +} + +void Window::startQuick(const QString &filename) +{ + m_qmlComponent = new QQmlComponent(m_qmlEngine, QUrl(filename)); + if (m_qmlComponent->isLoading()) + connect(m_qmlComponent, &QQmlComponent::statusChanged, this, &Window::run); + else + run(); +} + +void Window::exposeEvent(QExposeEvent *) +{ + if (isExposed()) { + render(); + if (!m_quickInitialized) + startQuick(QStringLiteral("qrc:/rendercontrol/demo.qml")); + } +} + +void Window::resizeEvent(QResizeEvent *) +{ + // If this is a resize after the scene is up and running, recreate the fbo and the + // Quick item and scene. + if (m_rootItem && m_context->makeCurrent(m_offscreenSurface)) { + delete m_fbo; + createFbo(); + m_context->doneCurrent(); + updateSizes(); + } +} + +void Window::updateQuick() +{ + if (!m_context->makeCurrent(m_offscreenSurface)) + return; + + // Polish, synchronize and render the next frame (into our fbo). In this example + // everything happens on the same thread and therefore all three steps are performed + // in succession from here. In a threaded setup the render() call would happen on a + // separate thread. + m_renderControl->polishItems(); + m_renderControl->sync(); + m_renderControl->render(); + + m_quickWindow->resetOpenGLState(); + QOpenGLFramebufferObject::bindDefault(); + + m_quickReady = true; + + // Get something onto the screen. + render(); +} + +void Window::render() +{ + if (!m_context->makeCurrent(this)) + return; + + QOpenGLFunctions *f = m_context->functions(); + f->glClearColor(0.0f, 0.1f, 0.25f, 1.0f); + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (m_quickReady) { + f->glFrontFace(GL_CW); // because our cube's vertex data is such + f->glEnable(GL_CULL_FACE); + f->glEnable(GL_DEPTH_TEST); + + f->glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); + + m_program->bind(); + QOpenGLVertexArrayObject::Binder vaoBinder(m_vao); + // If VAOs are not supported, set the vertex attributes every time. + if (!m_vao->isCreated()) + setupVertexAttribs(); + + static GLfloat angle = 0; + QMatrix4x4 m; + m.translate(0, 0, -2); + m.rotate(90, 0, 0, 1); + m.rotate(angle, 0.5, 1, 0); + angle += 0.5f; + + m_program->setUniformValue(m_matrixLoc, m_proj * m); + + // Draw the cube. + f->glDrawArrays(GL_TRIANGLES, 0, 36); + + m_program->release(); + f->glDisable(GL_DEPTH_TEST); + f->glDisable(GL_CULL_FACE); + } + + m_context->swapBuffers(this); +} + +void Window::mousePressEvent(QMouseEvent *e) +{ + // Use the constructor taking localPos and screenPos. That puts localPos into the + // event's localPos and windowPos, and screenPos into the event's screenPos. This way + // the windowPos in e is ignored and is replaced by localPos. This is necessary + // because QQuickWindow thinks of itself as a top-level window always. + QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers()); + QCoreApplication::sendEvent(m_quickWindow, &mappedEvent); +} + +void Window::mouseReleaseEvent(QMouseEvent *e) +{ + QMouseEvent mappedEvent(e->type(), e->localPos(), e->screenPos(), e->button(), e->buttons(), e->modifiers()); + QCoreApplication::sendEvent(m_quickWindow, &mappedEvent); +} diff --git a/examples/quick/rendercontrol/window.h b/examples/quick/rendercontrol/window.h new file mode 100644 index 0000000000..2723aeb011 --- /dev/null +++ b/examples/quick/rendercontrol/window.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QWindow> +#include <QMatrix4x4> +#include <QTimer> + +QT_FORWARD_DECLARE_CLASS(QOpenGLContext) +QT_FORWARD_DECLARE_CLASS(QOpenGLFramebufferObject) +QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) +QT_FORWARD_DECLARE_CLASS(QOpenGLBuffer) +QT_FORWARD_DECLARE_CLASS(QOpenGLVertexArrayObject) +QT_FORWARD_DECLARE_CLASS(QOffscreenSurface) +QT_FORWARD_DECLARE_CLASS(QQuickRenderControl) +QT_FORWARD_DECLARE_CLASS(QQuickWindow) +QT_FORWARD_DECLARE_CLASS(QQmlEngine) +QT_FORWARD_DECLARE_CLASS(QQmlComponent) +QT_FORWARD_DECLARE_CLASS(QQuickItem) + +class Window : public QWindow +{ + Q_OBJECT + +public: + Window(); + ~Window(); + +protected: + void exposeEvent(QExposeEvent *e) Q_DECL_OVERRIDE; + void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + +private slots: + void render(); + void updateQuick(); + void run(); + void createFbo(); + void destroyFbo(); + void requestUpdate(); + +private: + void startQuick(const QString &filename); + void setupVertexAttribs(); + void updateSizes(); + + QOpenGLContext *m_context; + QOffscreenSurface *m_offscreenSurface; + QQuickRenderControl *m_renderControl; + QQuickWindow *m_quickWindow; + QQmlEngine *m_qmlEngine; + QQmlComponent *m_qmlComponent; + QQuickItem *m_rootItem; + QOpenGLFramebufferObject *m_fbo; + QOpenGLShaderProgram *m_program; + QOpenGLBuffer *m_vbo; + QOpenGLVertexArrayObject *m_vao; + bool m_quickInitialized; + bool m_quickReady; + int m_matrixLoc; + QMatrix4x4 m_proj; + QTimer m_updateTimer; +}; |