Added an example that shows how to consume texture providers from C++.

And how to use use two textures in the same material.

Change-Id: Idcc618ed359422c2a104eeed105b7c4f5086ee4e
Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
This commit is contained in:
Gunnar Sletta 2014-08-22 16:52:05 +02:00
parent 3035fd9ad9
commit 1075dca1b5
10 changed files with 610 additions and 1 deletions

View File

@ -6,4 +6,5 @@ SUBDIRS += \
simplematerial \ simplematerial \
textureinsgnode \ textureinsgnode \
textureinthread \ textureinthread \
threadedanimation threadedanimation \
twotextureproviders

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,36 @@
/****************************************************************************
**
** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
** 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$
**
****************************************************************************/
/*!
\example scenegraph/twotextureproviders
\title Scene Graph - Two Texture Providers
\ingroup qtquickexamples
\brief Shows how to combine two textures from two texture providers in a custom scene graph node.
\image twotextureproviders-example.jpg
*/

View File

@ -0,0 +1,59 @@
/****************************************************************************
**
** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
** 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 <QtQuick/QQuickView>
#include "xorblender.h"
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
qmlRegisterType<XorBlender>("SceneGraphRendering", 1, 0, "XorBlender");
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///scenegraph/twotextureproviders/main.qml"));
view.show();
return app.exec();
}

View File

@ -0,0 +1,146 @@
/****************************************************************************
**
** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
** 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$
**
****************************************************************************/
import QtQuick 2.2
import SceneGraphRendering 1.0
Item {
id: root
// The checkers background
ShaderEffect {
anchors.fill: parent
property real tileSize: 16
property color color1: Qt.rgba(0.9, 0.9, 0.9, 1);
property color color2: Qt.rgba(0.8, 0.8, 0.8, 1);
property size pixelSize: Qt.size(width / tileSize, height / tileSize);
fragmentShader:
"
uniform lowp vec4 color1;
uniform lowp vec4 color2;
uniform highp vec2 pixelSize;
varying highp vec2 qt_TexCoord0;
void main() {
highp vec2 tc = sign(sin(3.14152 * qt_TexCoord0 * pixelSize));
if (tc.x != tc.y)
gl_FragColor = color1;
else
gl_FragColor = color2;
}
"
}
width: 320
height: 480
Item {
id: box
width: root.width * 0.9
height: width
Rectangle {
anchors.centerIn: parent
width: parent.width * 0.9
height: parent.width * 0.4
radius: width * 0.1;
gradient: Gradient {
GradientStop { position: 0; color: Qt.hsla(0.6, 0.9, 0.9, 1); }
GradientStop { position: 1; color: Qt.hsla(0.6, 0.6, 0.3, 1); }
}
RotationAnimator on rotation { from: 0; to: 360; duration: 10000; loops: Animation.Infinite }
}
visible: false
layer.enabled: true
}
Item {
id: text
width: box.width
height: width
Text {
anchors.centerIn: parent
color: "black" // Qt.hsla(0.8, 0.8, 0.8);
text: "Qt\nQuick"
horizontalAlignment: Text.AlignHCenter
font.bold: true
font.pixelSize: text.width * 0.25
RotationAnimator on rotation { from: 360; to: 0; duration: 9000; loops: Animation.Infinite }
}
visible: false
layer.enabled: true
}
XorBlender {
anchors.horizontalCenter: parent.horizontalCenter
y: root.height * 0.05;
width: box.width
height: box.height
source1: box
source2: text
}
Rectangle {
id: labelFrame
anchors.margins: -10
radius: 10
color: "white"
border.color: "black"
opacity: 0.8
anchors.fill: description
}
Text {
id: description
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 20
wrapMode: Text.WordWrap
text: "This example creates two animated items and sets 'layer.enabled: true' on both of them. " +
"This turns the items into texture providers and we can access their texture from C++ in a custom material. " +
"The XorBlender is a custom C++ item which uses performs an Xor blend between them."
}
}

View File

@ -0,0 +1,12 @@
QT += qml quick
HEADERS += xorblender.h
SOURCES += xorblender.cpp main.cpp
RESOURCES += twotextureproviders.qrc
target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/twotextureproviders
INSTALLS += target
OTHER_FILES += \
main.qml

View File

@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/scenegraph/twotextureproviders">
<file>main.qml</file>
</qresource>
</RCC>

View File

@ -0,0 +1,272 @@
/****************************************************************************
**
** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
** 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 "xorblender.h"
#include <QtCore/QPointer>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
#include <QtQuick/QSGSimpleMaterial>
#include <QtQuick/QSGTexture>
#include <QtQuick/QSGGeometryNode>
#include <QtQuick/QSGTextureProvider>
/* This example could just as well have been implemented all in QML using
* a ShaderEffect, and for 90% of all usecases, using a ShaderEffect will
* be sufficient. This example exists to illustrate how to consume
* texture providers from C++ and how to use multiple texture sources in
* a custom material.
*/
struct XorBlendState {
QSGTexture *texture1;
QSGTexture *texture2;
};
class XorBlendShader : public QSGSimpleMaterialShader<XorBlendState>
{
QSG_DECLARE_SIMPLE_SHADER(XorBlendShader, XorBlendState)
public:
const char *vertexShader() const {
return
"attribute highp vec4 aVertex; \n"
"attribute highp vec2 aTexCoord; \n"
"uniform highp mat4 qt_Matrix; \n"
"varying highp vec2 vTexCoord; \n"
"void main() { \n"
" gl_Position = qt_Matrix * aVertex; \n"
" vTexCoord = aTexCoord; \n"
"}";
}
const char *fragmentShader() const {
return
"uniform lowp float qt_Opacity; \n"
"uniform lowp sampler2D uSource1; \n"
"uniform lowp sampler2D uSource2; \n"
"varying highp vec2 vTexCoord; \n"
"void main() { \n"
" lowp vec4 p1 = texture2D(uSource1, vTexCoord); \n"
" lowp vec4 p2 = texture2D(uSource2, vTexCoord); \n"
" gl_FragColor = (p1 * (1.0 - p2.a) + p2 * (1.0 - p1.a)) * qt_Opacity; \n"
"}";
}
QList<QByteArray> attributes() const {
return QList<QByteArray>() << "aVertex" << "aTexCoord";
}
void updateState(const XorBlendState *state, const XorBlendState *) {
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
// We bind the textures in inverse order so that we leave the updateState
// function with GL_TEXTURE0 as the active texture unit. This is maintain
// the "contract" that updateState should not mess up the GL state beyond
// what is needed for this material.
f->glActiveTexture(GL_TEXTURE1);
state->texture2->bind();
f->glActiveTexture(GL_TEXTURE0);
state->texture1->bind();
}
void resolveUniforms() {
// The texture units never change, only the texturess we bind to them so
// we set these once and for all here.
program()->setUniformValue("uSource1", 0); // GL_TEXTURE0
program()->setUniformValue("uSource2", 1); // GL_TEXTURE1
}
};
/* The rendering is split into two nodes. The top-most node is not actually
* rendering anything, but is responsible for managing the texture providers.
* The XorNode also has a geometry node internally which it uses to render
* the texture providers using the XorBlendShader when all providers and
* textures are all present.
*
* The texture providers are updated solely on the render thread (when rendering
* is happening on a separate thread). This is why we are using preprocess
* and direct signals between the the texture providers and the node rather
* than updating state in updatePaintNode.
*/
class XorNode : public QObject, public QSGNode
{
Q_OBJECT
public:
XorNode(QSGTextureProvider *p1, QSGTextureProvider *p2)
: m_provider1(p1)
, m_provider2(p2)
{
setFlag(QSGNode::UsePreprocess, true);
// Set up material so it is all set for later..
m_material = XorBlendShader::createMaterial();
m_material->state()->texture1 = 0;
m_material->state()->texture2 = 0;
m_material->setFlag(QSGMaterial::Blending);
m_node.setMaterial(m_material);
m_node.setFlag(QSGNode::OwnsMaterial);
// Set up geometry, actual vertices will be initialized in updatePaintNode
m_node.setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4));
m_node.setFlag(QSGNode::OwnsGeometry);
// If this node is used as in a shader effect source, we need to propegate
// changes that will occur in this node outwards.
connect(m_provider1, SIGNAL(textureChanged()), this, SLOT(textureChange()), Qt::DirectConnection);
connect(m_provider2, SIGNAL(textureChanged()), this, SLOT(textureChange()), Qt::DirectConnection);
}
void preprocess() {
XorBlendState *state = m_material->state();
// Update the textures from the providers, calling into QSGDynamicTexture if required
if (m_provider1) {
state->texture1 = m_provider1->texture();
if (QSGDynamicTexture *dt1 = qobject_cast<QSGDynamicTexture *>(state->texture1))
dt1->updateTexture();
}
if (m_provider2) {
state->texture2 = m_provider2->texture();
if (QSGDynamicTexture *dt2 = qobject_cast<QSGDynamicTexture *>(state->texture2))
dt2->updateTexture();
}
// Remove node from the scene graph if it is there and either texture is missing...
if (m_node.parent() && (!state->texture1 || !state->texture2))
removeChildNode(&m_node);
// Add it if it is not already there and both textures are present..
else if (!m_node.parent() && state->texture1 && state->texture2)
appendChildNode(&m_node);
}
void setRect(const QRectF &rect) {
// Update geometry if it has changed and mark the change in the scene graph.
if (m_rect != rect) {
m_rect = rect;
QSGGeometry::updateTexturedRectGeometry(m_node.geometry(), m_rect, QRectF(0, 0, 1, 1));
m_node.markDirty(QSGNode::DirtyGeometry);
}
}
public slots:
void textureChange() {
// When our sources change, we will look different, so signal the change to the
// scene graph.
markDirty(QSGNode::DirtyMaterial);
}
private:
QRectF m_rect;
QSGSimpleMaterial<XorBlendState> *m_material;
QSGGeometryNode m_node;
QPointer<QSGTextureProvider> m_provider1;
QPointer<QSGTextureProvider> m_provider2;
};
XorBlender::XorBlender(QQuickItem *parent)
: QQuickItem(parent)
, m_source1(0)
, m_source2(0)
, m_source1Changed(false)
, m_source2Changed(false)
{
setFlag(ItemHasContents, true);
}
void XorBlender::setSource1(QQuickItem *i)
{
if (i == m_source1)
return;
m_source1 = i;
emit source1Changed(m_source1);
m_source1Changed = true;
update();
}
void XorBlender::setSource2(QQuickItem *i)
{
if (i == m_source2)
return;
m_source2 = i;
emit source2Changed(m_source2);
m_source2Changed = true;
update();
}
QSGNode *XorBlender::updatePaintNode(QSGNode *old, UpdatePaintNodeData *)
{
// Check if our input is valid and abort if not, deleting the old node.
bool abort = false;
if (!m_source1 || !m_source1->isTextureProvider()) {
qDebug() << "source1 is missing or not a texture provider";
abort = true;
}
if (!m_source2 || !m_source2->isTextureProvider()) {
qDebug() << "source2 is missing or not a texture provider";
abort = true;
}
if (abort) {
delete old;
return 0;
}
XorNode *node = static_cast<XorNode *>(old);
// If the sources have changed, recreate the nodes
if (m_source1Changed || m_source2Changed) {
delete node;
node = 0;
m_source1Changed = false;
m_source2Changed = false;
}
// Create a new XorNode for us to render with.
if (!node)
node = new XorNode(m_source1->textureProvider(), m_source2->textureProvider());
// Update the geometry of the node to match the new bounding rect
node->setRect(boundingRect());
return node;
}
#include "xorblender.moc"

View File

@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2014 Gunnar Sletta <gunnar@sletta.org>
** 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$
**
****************************************************************************/
#ifndef XORBLENDER_H
#define XORBLENDER_H
#include <QQuickItem>
class XorBlender : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQuickItem *source1 READ source1 WRITE setSource1 NOTIFY source1Changed)
Q_PROPERTY(QQuickItem *source2 READ source2 WRITE setSource2 NOTIFY source2Changed)
public:
explicit XorBlender(QQuickItem *parent = 0);
QQuickItem *source1() const { return m_source1; }
QQuickItem *source2() const { return m_source2; }
void setSource1(QQuickItem *i);
void setSource2(QQuickItem *i);
protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
signals:
void source1Changed(QQuickItem *item);
void source2Changed(QQuickItem *item);
private:
QQuickItem *m_source1;
QQuickItem *m_source2;
bool m_source1Changed;
bool m_source2Changed;
};
#endif // XORBLENDER_H

View File

@ -40,6 +40,8 @@ QT_BEGIN_NAMESPACE
\brief The QSGTextureProvider class encapsulates texture based entities in QML. \brief The QSGTextureProvider class encapsulates texture based entities in QML.
The QSGTextureProvider lives primarily in the scene graph rendering thread. The QSGTextureProvider lives primarily in the scene graph rendering thread.
\sa {Scene Graph - Two Texture Providers}
*/ */