summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@theqtcompany.com>2015-06-04 14:19:10 +0300
committerPasi Keränen <pasi.keranen@digia.com>2015-06-17 10:36:47 +0000
commit4c374429f96d3ba24d0ea81a1aeeec06af20c09a (patch)
tree070a3cd8393e840e54979fb88388ecf030640b30
parent611e2e940f54210346330657077038324deabd02 (diff)
Using Qt Quick item as Canvas3D texture
Implemented QTCANVAS3D_texture_provider extension for creating a texture object for QQuickItems that implement texture providers. [ChangeLog][Renderer] Enabled using Qt Quick items as textures. Change-Id: I947304155734af50c8a21f34292b244bb099702f Reviewed-by: Tomi Korpipää <tomi.korpipaa@theqtcompany.com> Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com> Reviewed-by: Topi Reiniö <topi.reinio@digia.com> Reviewed-by: Pasi Keränen <pasi.keranen@digia.com>
-rw-r--r--examples/canvas3d/canvas3d/canvas3d.pro2
-rw-r--r--examples/canvas3d/canvas3d/quickitemtexture/doc/src/quickitemtexture.qdoc74
-rw-r--r--examples/canvas3d/canvas3d/quickitemtexture/main.cpp49
-rw-r--r--examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/main.qml197
-rw-r--r--examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/quickitemtexture.js365
-rw-r--r--examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.pro12
-rw-r--r--examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.qrc7
-rw-r--r--src/imports/qtcanvas3d/canvas3d.cpp4
-rw-r--r--src/imports/qtcanvas3d/canvas3d_p.h3
-rw-r--r--src/imports/qtcanvas3d/canvasrenderer.cpp44
-rw-r--r--src/imports/qtcanvas3d/canvasrenderer_p.h3
-rw-r--r--src/imports/qtcanvas3d/canvastextureprovider.cpp144
-rw-r--r--src/imports/qtcanvas3d/canvastextureprovider_p.h81
-rw-r--r--src/imports/qtcanvas3d/context3d.cpp57
-rw-r--r--src/imports/qtcanvas3d/context3d_p.h7
-rw-r--r--src/imports/qtcanvas3d/glcommandqueue.cpp47
-rw-r--r--src/imports/qtcanvas3d/glcommandqueue_p.h30
-rw-r--r--src/imports/qtcanvas3d/qcanvas3d_plugin.cpp10
-rw-r--r--src/imports/qtcanvas3d/qcanvas3d_plugin.h2
-rw-r--r--src/imports/qtcanvas3d/qtcanvas3d.pro6
-rw-r--r--src/imports/qtcanvas3d/texture3d.cpp34
-rw-r--r--src/imports/qtcanvas3d/texture3d_p.h12
-rw-r--r--tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.js215
-rw-r--r--tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.qml308
24 files changed, 1698 insertions, 15 deletions
diff --git a/examples/canvas3d/canvas3d/canvas3d.pro b/examples/canvas3d/canvas3d/canvas3d.pro
index 978d455..0f603bc 100644
--- a/examples/canvas3d/canvas3d/canvas3d.pro
+++ b/examples/canvas3d/canvas3d/canvas3d.pro
@@ -3,7 +3,7 @@ SUBDIRS += textureandlight \
framebuffer \
interaction \
jsonmodels \
+ quickitemtexture \
threejs
OTHER_FILES += 3rdparty/*
-
diff --git a/examples/canvas3d/canvas3d/quickitemtexture/doc/src/quickitemtexture.qdoc b/examples/canvas3d/canvas3d/quickitemtexture/doc/src/quickitemtexture.qdoc
new file mode 100644
index 0000000..9db0227
--- /dev/null
+++ b/examples/canvas3d/canvas3d/quickitemtexture/doc/src/quickitemtexture.qdoc
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example canvas3d/quickitemtexture
+ \since QtCanvas3D 1.0
+ \title Qt Quick Item as Texture Example
+ \ingroup qtcanvas3d-examples
+ \brief A simple cube with a Qt Quick item as a texture
+
+ The Qt Quick Item as Texture example shows how to use other Qt Quick items as
+ a texture source for Qt Canvas3D textures.
+
+ \image quickitemtexture-example.png
+
+ \section1 Using Qt Quick Item as a Texture
+
+ First we create a \l Rectangle with a label that displays the current frame rate and rotation
+ values of the cube:
+
+ \snippet canvas3d/quickitemtexture/qml/quickitemtexture/main.qml 0
+
+ We want to use the above \l Rectangle as the texture on our 3D cube. As a \l Rectangle item
+ doesn't implement QQuickItem::textureProvider() by itself, we make it layered by setting the
+ \c{layer.enabled} property to \c{true}.
+
+ To create a Canvas3DTexture out of our layered \l{Rectangle}, we create a
+ \l{Canvas3DTextureProvider}{QTCANVAS3D_texture_provider} extension and the texture
+ in the \c initializeGL() function in our JavaScript implementation:
+
+ \snippet canvas3d/quickitemtexture/qml/quickitemtexture/quickitemtexture.js 0
+
+ Once the \c cubeTexture item is created, it can be used like any other texture item in
+ the JavaScript.
+
+ \note The method of creating the texture from a Qt Quick item differs from how one would create
+ texture from an HTML item in WebGL API. Textures created with
+ \l{Canvas3DTextureProvider}{QTCANVAS3D_texture_provider} extension
+ support automatic live updates, without having to call textureImage2D each frame
+ to re-upload fresh texture data from the item.
+*/
diff --git a/examples/canvas3d/canvas3d/quickitemtexture/main.cpp b/examples/canvas3d/canvas3d/quickitemtexture/main.cpp
new file mode 100644
index 0000000..a5264fb
--- /dev/null
+++ b/examples/canvas3d/canvas3d/quickitemtexture/main.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/main.qml b/examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/main.qml
new file mode 100644
index 0000000..27def02
--- /dev/null
+++ b/examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/main.qml
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtCanvas3D 1.1
+import QtQuick.Controls 1.1
+import QtQuick.Layouts 1.1
+import QtQuick.Window 2.2
+
+import "quickitemtexture.js" as GLCode
+
+Window {
+ id: mainview
+ width: 800
+ height: 600
+ visible: true
+ title: "Qt Quick Item as Texture"
+
+ Canvas3D {
+ id: canvas3d
+ anchors.fill:parent
+ focus: true
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+ property bool isRunning: true
+
+ ColumnLayout {
+ Layout.fillWidth: true
+ x: 4
+ y: 4
+ //! [0]
+ Rectangle {
+ id: textureSource
+ color: "lightgreen"
+ width: 256
+ height: 256
+ border.color: "blue"
+ border.width: 4
+ layer.enabled: true
+ layer.smooth: true
+ opacity: 0.8
+ Label {
+ anchors.fill: parent
+ anchors.margins: 16
+ text: "X Rot:" + (canvas3d.xRotAnim | 0) + "\n"
+ + "Y Rot:" + (canvas3d.yRotAnim | 0) + "\n"
+ + "Z Rot:" + (canvas3d.zRotAnim | 0) + "\n"
+ + "FPS:" + canvas3d.fps
+ color: "red"
+ font.pointSize: 30
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ //! [0]
+ Button {
+ Layout.fillWidth: true
+ Layout.minimumWidth: 256
+ text: textureSource.visible ? "Hide texture source" : "Show texture source"
+ onClicked: textureSource.visible = !textureSource.visible
+ }
+ Button {
+ Layout.fillWidth: true
+ Layout.minimumWidth: 256
+ text: "Quit"
+ onClicked: Qt.quit()
+ }
+ }
+
+ // Emitted when one time initializations should happen
+ onInitializeGL: {
+ GLCode.initializeGL(canvas3d, textureSource);
+ }
+
+ // Emitted each time Canvas3D is ready for a new frame
+ onPaintGL: {
+ GLCode.paintGL(canvas3d);
+ }
+
+ onResizeGL: {
+ GLCode.resizeGL(canvas3d);
+ }
+
+ Keys.onSpacePressed: {
+ canvas3d.isRunning = !canvas3d.isRunning
+ if (canvas3d.isRunning) {
+ objAnimationX.pause();
+ objAnimationY.pause();
+ objAnimationZ.pause();
+ } else {
+ objAnimationX.resume();
+ objAnimationY.resume();
+ objAnimationZ.resume();
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 0.0
+ to: 120.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 120.0
+ to: 0.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 240.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 240.0
+ to: 0.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: -100.0
+ to: 100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: 100.0
+ to: -100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ }
+ }
+}
diff --git a/examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/quickitemtexture.js b/examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/quickitemtexture.js
new file mode 100644
index 0000000..3ac898d
--- /dev/null
+++ b/examples/canvas3d/canvas3d/quickitemtexture/qml/quickitemtexture/quickitemtexture.js
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+Qt.include("/gl-matrix.js")
+
+//
+// Draws a cube that has a Qt Quick item as decal texture on each face.
+// A simple per vertex lighting equation is used to emulate light landing on the rotating cube.
+//
+
+var gl;
+var cubeTexture = 0;
+var vertexPositionAttribute;
+var textureCoordAttribute;
+var vertexNormalAttribute;
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+var nMatrix = mat4.create();
+var pMatrixUniform;
+var mvMatrixUniform;
+var nUniform;
+var width = 0;
+var height = 0;
+var canvas3d;
+var pixelSize;
+var canvasTextureProvider = null;
+var textureSourceItem = null;
+
+function initializeGL(canvas, textureSource) {
+ canvas3d = canvas;
+ textureSourceItem = textureSource;
+
+ // Get the OpenGL context object that represents the API we call
+ gl = canvas.getContext("canvas3d", {depth:true, antialias:true});
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.depthFunc(gl.LESS);
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ gl.clearColor(0.98, 0.98, 0.98, 1.0);
+ gl.clearDepth(1.0);
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
+
+ // Set viewport
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ // Initialize the shader program
+ initShaders();
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Create a texture from the Qt Quick item
+ //! [0]
+ canvasTextureProvider = gl.getExtension("QTCANVAS3D_texture_provider");
+ cubeTexture = canvasTextureProvider.createTextureFromSource(textureSourceItem);
+ //! [0]
+
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+}
+
+function resizeGL(canvas)
+{
+ var pixelRatio = canvas.devicePixelRatio;
+ canvas.pixelSize = Qt.size(canvas.width * pixelRatio,
+ canvas.height * pixelRatio);
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function paintGL(canvas) {
+ var pixelRatio = canvas.devicePixelRatio;
+ var currentWidth = canvas.width * pixelRatio;
+ var currentHeight = canvas.height * pixelRatio;
+ if (currentWidth !== width || currentHeight !== height ) {
+ width = currentWidth;
+ height = currentHeight;
+ gl.viewport(0, 0, width, height);
+ mat4.perspective(pMatrix, degToRad(45), width / height, 0.1, 500.0);
+ gl.uniformMatrix4fv(pMatrixUniform, false, pMatrix);
+ }
+
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [(canvas.yRotAnim - 120.0) / 120.0,
+ (canvas.xRotAnim - 60.0) / 50.0,
+ -7.0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotAnim), [0, 1, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim), [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 0, 1]);
+ gl.uniformMatrix4fv(mvMatrixUniform, false, mvMatrix);
+
+ mat4.invert(nMatrix, mvMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fv(nUniform, false, nMatrix);
+
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+}
+
+function initBuffers()
+{
+ var cubeVertexPositionBuffer = gl.createBuffer();
+ cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ new Float32Array([// Front face
+ -1.0, -1.0, 1.0,
+ 1.0, -1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ -1.0, 1.0, 1.0,
+
+ // Back face
+ -1.0, -1.0, -1.0,
+ -1.0, 1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, -1.0, -1.0,
+
+ // Top face
+ -1.0, 1.0, -1.0,
+ -1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, 1.0, -1.0,
+
+ // Bottom face
+ -1.0, -1.0, -1.0,
+ 1.0, -1.0, -1.0,
+ 1.0, -1.0, 1.0,
+ -1.0, -1.0, 1.0,
+
+ // Right face
+ 1.0, -1.0, -1.0,
+ 1.0, 1.0, -1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, -1.0, 1.0,
+
+ // Left face
+ -1.0, -1.0, -1.0,
+ -1.0, -1.0, 1.0,
+ -1.0, 1.0, 1.0,
+ -1.0, 1.0, -1.0
+ ]),
+ gl.STATIC_DRAW);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ var cubeVertexIndexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ new Uint16Array([
+ 0, 1, 2, 0, 2, 3, // front
+ 4, 5, 6, 4, 6, 7, // back
+ 8, 9, 10, 8, 10, 11, // top
+ 12, 13, 14, 12, 14, 15, // bottom
+ 16, 17, 18, 16, 18, 19, // right
+ 20, 21, 22, 20, 22, 23 // left
+ ]),
+ gl.STATIC_DRAW);
+
+ var cubeVerticesTextureCoordBuffer = gl.createBuffer();
+ cubeVerticesTextureCoordBuffer.name = "cubeVerticesTextureCoordBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
+ var textureCoordinates = [
+ // Front
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ // Back
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ // Top
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ // Bottom
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ // Right
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0,
+ // Left
+ 1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0
+ ];
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates),
+ gl.STATIC_DRAW);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ var cubeVerticesNormalBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
+ // Front
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 1.0,
+
+ // Back
+ 0.0, 0.0, -1.0,
+ 0.0, 0.0, -1.0,
+ 0.0, 0.0, -1.0,
+ 0.0, 0.0, -1.0,
+
+ // Top
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 1.0, 0.0,
+
+ // Bottom
+ 0.0, -1.0, 0.0,
+ 0.0, -1.0, 0.0,
+ 0.0, -1.0, 0.0,
+ 0.0, -1.0, 0.0,
+
+ // Right
+ 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+
+ // Left
+ -1.0, 0.0, 0.0,
+ -1.0, 0.0, 0.0,
+ -1.0, 0.0, 0.0,
+ -1.0, 0.0, 0.0
+ ]), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+}
+
+function initShaders()
+{
+ var vertexShader = getShader(gl,
+ "attribute highp vec3 aVertexNormal; \
+ attribute highp vec3 aVertexPosition; \
+ attribute highp vec2 aTextureCoord; \
+ \
+ uniform highp mat4 uNormalMatrix; \
+ uniform mat4 uMVMatrix; \
+ uniform mat4 uPMatrix; \
+ \
+ varying mediump vec4 vColor; \
+ varying highp vec2 vTextureCoord; \
+ varying highp vec3 vLighting; \
+ \
+ void main(void) { \
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \
+ vTextureCoord = aTextureCoord; \
+ highp vec3 ambientLight = vec3(0.5, 0.5, 0.5); \
+ highp vec3 directionalLightColor = vec3(0.75, 0.75, 0.75); \
+ highp vec3 directionalVector = vec3(0.85, 0.8, 0.75); \
+ highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0); \
+ highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0); \
+ vLighting = ambientLight + (directionalLightColor * directional); \
+ }", gl.VERTEX_SHADER);
+
+ var fragmentShader = getShader(gl,
+ "varying highp vec2 vTextureCoord; \
+ varying highp vec3 vLighting; \
+ \
+ uniform sampler2D uSampler; \
+ \
+ void main(void) { \
+ mediump vec3 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)).rgb; \
+ gl_FragColor = vec4(texelColor * vLighting, 1.0); \
+ }", gl.FRAGMENT_SHADER);
+
+ // Create the Program3D for shader
+ var shaderProgram = gl.createProgram();
+
+ // Attach the shader sources to the shader program
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+
+ // Link the program
+ gl.linkProgram(shaderProgram);
+
+ // Check the linking status
+ if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialize shaders");
+ console.log(gl.getProgramInfoLog(shaderProgram));
+ }
+
+ // Take the shader program into use
+ gl.useProgram(shaderProgram);
+
+ // Look up where the vertex data needs to go
+ vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+
+ // Get the uniform locations
+ pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
+ mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+ nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");
+
+ // Setup texture sampler uniform
+ var textureSamplerUniform = gl.getUniformLocation(shaderProgram, "uSampler")
+ gl.activeTexture(gl.TEXTURE0);
+ gl.uniform1i(textureSamplerUniform, 0);
+ gl.bindTexture(gl.TEXTURE_2D, 0);
+}
+
+function getShader(gl, str, type) {
+ var shader = gl.createShader(type);
+ gl.shaderSource(shader, str);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ console.log("JS:Shader compile failed");
+ console.log(gl.getShaderInfoLog(shader));
+ return null;
+ }
+
+ return shader;
+}
diff --git a/examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.pro b/examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.pro
new file mode 100644
index 0000000..bbfa099
--- /dev/null
+++ b/examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.pro
@@ -0,0 +1,12 @@
+!include( ../../../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+RESOURCES += quickitemtexture.qrc
+
+OTHER_FILES += qml/quickitemtexture/* \
+ doc/src/* \
+ doc/images/*
+
diff --git a/examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.qrc b/examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.qrc
new file mode 100644
index 0000000..b0e7ecb
--- /dev/null
+++ b/examples/canvas3d/canvas3d/quickitemtexture/quickitemtexture.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/">
+ <file alias="gl-matrix.js">../3rdparty/gl-matrix.js</file>
+ <file alias="main.qml">qml/quickitemtexture/main.qml</file>
+ <file alias="quickitemtexture.js">qml/quickitemtexture/quickitemtexture.js</file>
+ </qresource>
+</RCC>
diff --git a/src/imports/qtcanvas3d/canvas3d.cpp b/src/imports/qtcanvas3d/canvas3d.cpp
index e110a13..b367650 100644
--- a/src/imports/qtcanvas3d/canvas3d.cpp
+++ b/src/imports/qtcanvas3d/canvas3d.cpp
@@ -292,6 +292,10 @@ QJSValue Canvas::getContext(const QString &type, const QVariantMap &options)
contextVersion, extensions,
m_renderer->commandQueue());
+ connect(m_renderer, &CanvasRenderer::textureIdResolved,
+ m_context3D, &CanvasContext::handleTextureIdResolved,
+ Qt::QueuedConnection);
+
// Verify that width and height are not initially too large, in case width and height
// were set before getting GL_MAX_VIEWPORT_DIMS
if (width() > m_maxSize.width()) {
diff --git a/src/imports/qtcanvas3d/canvas3d_p.h b/src/imports/qtcanvas3d/canvas3d_p.h
index bf1af58..dacc127 100644
--- a/src/imports/qtcanvas3d/canvas3d_p.h
+++ b/src/imports/qtcanvas3d/canvas3d_p.h
@@ -94,14 +94,11 @@ public:
float devicePixelRatio();
QSize pixelSize();
void setPixelSize(QSize pixelSize);
- void createFBOs();
void setWidth(int width);
int width();
void setHeight(int height);
int height();
- void bindCurrentRenderTarget();
-
uint fps();
Q_INVOKABLE QJSValue getContext(const QString &name);
diff --git a/src/imports/qtcanvas3d/canvasrenderer.cpp b/src/imports/qtcanvas3d/canvasrenderer.cpp
index cd3d716..678b0f9 100644
--- a/src/imports/qtcanvas3d/canvasrenderer.cpp
+++ b/src/imports/qtcanvas3d/canvasrenderer.cpp
@@ -178,6 +178,10 @@ void CanvasRenderer::shutDown()
// Nothing to do, uniforms do not actually consume resources
break;
}
+ case CanvasGlCommandQueue::internalClearQuickItemAsTexture: {
+ // Nothing to do, scenegraph will handle texture clearing
+ break;
+ }
default:
qWarning() << __FUNCTION__ << "Invalid command, cannot cleanup:"
<< commandId << "Resource:" << glId;
@@ -408,6 +412,40 @@ void CanvasRenderer::render()
{
// Skip render if there is no context or nothing to render
if (m_glContext && m_executeQueueCount) {
+ // Update tracked quick item textures
+ int providerCount = m_commandQueue.providerCache().size();
+ if (providerCount) {
+ QMap<GLint, CanvasGlCommandQueue::ProviderCacheItem *>::iterator i =
+ m_commandQueue.providerCache().begin();
+ while (i != m_commandQueue.providerCache().end()) {
+ CanvasGlCommandQueue::ProviderCacheItem *cacheItem = i.value();
+ QSGTextureProvider *texProvider = cacheItem->providerPtr.data();
+ GLint id = i.key();
+ QMap<GLint, CanvasGlCommandQueue::ProviderCacheItem *>::iterator prev = i;
+ i++;
+
+ if (texProvider) {
+ QSGDynamicTexture *texture =
+ qobject_cast<QSGDynamicTexture *>(texProvider->texture());
+ if (texture) {
+ texture->updateTexture();
+ int textureId = texture->textureId();
+ int currentTextureId = m_commandQueue.getGlId(id);
+ if (textureId && textureId != currentTextureId) {
+ m_commandQueue.setGlIdToMap(
+ id, textureId,
+ CanvasGlCommandQueue::internalClearQuickItemAsTexture);
+ emit textureIdResolved(cacheItem->quickItem);
+ }
+ }
+ } else {
+ // Clean obsolete providers off the cache
+ m_commandQueue.providerCache().erase(prev);
+ delete cacheItem;
+ }
+ }
+ }
+
// Render to offscreen fbo
QOpenGLContext *oldContext = QOpenGLContext::currentContext();
QSurface *oldSurface = oldContext->surface();
@@ -1275,6 +1313,12 @@ void CanvasRenderer::executeCommandQueue()
bindCurrentRenderTarget();
break;
}
+ case CanvasGlCommandQueue::internalClearQuickItemAsTexture: {
+ // Used to clear mapped quick item texture ids when no longer needed
+ m_commandQueue.removeResourceIdFromMap(command.i1);
+ delete m_commandQueue.providerCache().take(command.i1);
+ break;
+ }
default: {
qWarning() << __FUNCTION__
<< "Unsupported GL command handled:" << command.id;
diff --git a/src/imports/qtcanvas3d/canvasrenderer_p.h b/src/imports/qtcanvas3d/canvasrenderer_p.h
index 5b2f248..4525f48 100644
--- a/src/imports/qtcanvas3d/canvasrenderer_p.h
+++ b/src/imports/qtcanvas3d/canvasrenderer_p.h
@@ -55,6 +55,7 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLFramebufferObject>
+#include <QtQuick/QQuickItem>
QT_BEGIN_NAMESPACE
@@ -106,8 +107,8 @@ public slots:
signals:
void fpsChanged(uint fps);
-
void textureReady(int id, const QSize &size);
+ void textureIdResolved(QQuickItem *item);
private:
QSize m_fboSize;
diff --git a/src/imports/qtcanvas3d/canvastextureprovider.cpp b/src/imports/qtcanvas3d/canvastextureprovider.cpp
new file mode 100644
index 0000000..e2aaf89
--- /dev/null
+++ b/src/imports/qtcanvas3d/canvastextureprovider.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "canvastextureprovider_p.h"
+#include "texture3d_p.h"
+
+#include <QtQuick/QQuickItem>
+
+QT_BEGIN_NAMESPACE
+QT_CANVAS3D_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Canvas3DTextureProvider
+ \since QtCanvas3D 1.1
+ \inqmlmodule QtCanvas3D
+ \brief Provides means to get QQuickItem as Canvas3DTexture.
+
+ An uncreatable QML type that provides an extension API that can be used to get QQuickItem as
+ Canvas3DTexture. Only QQuickItems that implement QQuickItem::textureProvider() method can be
+ used as a texture source, which in most cases means the \c{layer.enabled} property of the
+ item must be set to \c {true}.
+
+ Typical usage would be something like this:
+ \code
+ // In QML code, declare a layered item you wish to show as texture
+ Rectangle {
+ id: textureSource
+ layer.enabled: true
+ // ...
+ }
+ .
+ .
+ // In JavaScript code, declare the variables for the extension and the texture
+ var textureProvider;
+ var myTexture;
+ .
+ .
+ // Get the extension after the context has been created
+ textureProvider = gl.getExtension("QTCANVAS3D_texture_provider");
+ .
+ .
+ // Get the Canvas3DTexture object representing our source item
+ if (textureProvider)
+ myTexture = textureProvider.createTextureFromSource(textureSource);
+ .
+ .
+ // Normally the above is enough. However, in cases where you utilize synchronous OpenGL
+ // commands or dynamically enable the source item layer, it is not guaranteed that the texture
+ // is valid immediately after calling createTextureFromSource().
+ // To ensure you don't use the texture before it is ready, connect the textureReady() signal
+ // to a handler function that will use the texture.
+ textureProvider.textureReady.connect(function(sourceItem) {
+ if (sourceItem === textureSource) {
+ gl.bindTexture(gl.TEXTURE_2D, myTexture);
+ // ...
+ }
+ });
+ \endcode
+
+ \sa Context3D
+ */
+CanvasTextureProvider::CanvasTextureProvider(CanvasContext *canvasContext,
+ QObject *parent) :
+ QObject(parent),
+ m_canvasContext(canvasContext)
+{
+}
+
+CanvasTextureProvider::~CanvasTextureProvider()
+{
+}
+
+/*!
+ * \qmlmethod QJSValue Canvas3DTextureProvider::createTextureFromSource(Item *source)
+ *
+ * Creates and returns a Canvas3DTexture object for the supplied \a source item.
+ *
+ * The \a source item must be of a type that implements a texture provider, which in most
+ * cases means the \c{layer.enabled} property of the item must be set to \c {true}.
+ * ShaderEffectSource items can also be used as texture sources.
+ * The texture provider of the \a source item owns the OpenGL texture.
+ * If the \a source item is deleted or the \c{layer.enabled} property is set to \c{false}
+ * while the texture is still in use in Canvas3D, the rendered texture contents become undefined.
+ *
+ * Trying to bind the returned Canvas3DTexture object is not guaranteed to work until
+ * a \l{Canvas3DTextureProvider::textureReady}{textureReady()} signal corresponding to the \a source item has been emitted.
+ * However, if you don't have any synchronous OpenGL calls between the first use of the texture
+ * and the end of your paingGL() handler, and if you can guarantee that the source item has been
+ * fully rendered at least once after its layer was enabled, you can immediately use the returned
+ * texture without waiting for the \l{Canvas3DTextureProvider::textureReady}{textureReady()} signal.
+ *
+ * Disabling the \a source item's layer will destroy the underlying texture provider, so it
+ * is necessary to call this method again for the \a source item if you re-enable its layer.
+ *
+ * If this function is called twice for same \a source, it doesn't create a new Canvas3DTexture
+ * instance, but instead returns a reference to a previously created one, as long as the previous
+ * instance is still alive.
+ */
+QJSValue CanvasTextureProvider::createTextureFromSource(QQuickItem *source)
+{
+ return m_canvasContext->createTextureFromSource(source);
+}
+
+/*!
+ * \qmlsignal void Canvas3DTextureProvider::textureReady(Item *source)
+ *
+ * Indicates that the texture created with createTextureFromSource() method for the \a source item
+ * is ready to be used.
+ */
+QT_CANVAS3D_END_NAMESPACE
+QT_END_NAMESPACE
diff --git a/src/imports/qtcanvas3d/canvastextureprovider_p.h b/src/imports/qtcanvas3d/canvastextureprovider_p.h
new file mode 100644
index 0000000..285739b
--- /dev/null
+++ b/src/imports/qtcanvas3d/canvastextureprovider_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CANVASTEXTUREPROVIDER_P_H
+#define CANVASTEXTUREPROVIDER_P_H
+
+#include "canvas3dcommon_p.h"
+
+#include <QtCore/QObject>
+#include <QtGui/qopengl.h>
+#include <QtQuick/QQuickItem>
+
+QT_BEGIN_NAMESPACE
+QT_CANVAS3D_BEGIN_NAMESPACE
+
+class CanvasContext;
+
+class CanvasTextureProvider : public QObject
+{
+ Q_OBJECT
+public:
+ CanvasTextureProvider(CanvasContext *canvasContext, QObject *parent = 0);
+ ~CanvasTextureProvider();
+
+ Q_INVOKABLE QJSValue createTextureFromSource(QQuickItem *source);
+
+signals:
+ void textureReady(QQuickItem *source);
+
+private:
+ CanvasContext *m_canvasContext;
+ QJSValue m_textureObject;
+};
+
+QT_CANVAS3D_END_NAMESPACE
+QT_END_NAMESPACE
+
+#endif // CANVASTEXTUREPROVIDER_P_H
diff --git a/src/imports/qtcanvas3d/context3d.cpp b/src/imports/qtcanvas3d/context3d.cpp
index b7e0e4b..16a09df 100644
--- a/src/imports/qtcanvas3d/context3d.cpp
+++ b/src/imports/qtcanvas3d/context3d.cpp
@@ -104,6 +104,7 @@ CanvasContext::CanvasContext(QQmlEngine *engine, bool isES2, int maxVertexAttrib
m_isOpenGLES2(isES2),
m_commandQueue(commandQueue),
m_stateDumpExt(0),
+ m_textureProviderExt(0),
m_standardDerivatives(0),
m_compressedTextureS3TC(0),
m_compressedTexturePVRTC(0)
@@ -120,6 +121,11 @@ CanvasContext::~CanvasContext()
{
qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__;
EnumToStringMap::deleteInstance();
+
+ // Cleanup quick item textures to avoid crash when parent gets deleted before children
+ QList<CanvasTexture *> quickItemTextures = m_quickItemToTextureMap.values();
+ foreach (CanvasTexture *texture, quickItemTextures)
+ texture->del();
}
/*!
@@ -6103,6 +6109,42 @@ QJSValue CanvasContext::getVertexAttrib(uint index, glEnums pname)
}
/*!
+ * \internal
+ *
+ * Implements CanvasTextureProvider::createTextureFromSource() extension functionality
+ */
+QJSValue CanvasContext::createTextureFromSource(QQuickItem *item)
+{
+ // First check if we have a CanvasTexture already for this item
+ CanvasTexture *texture = m_quickItemToTextureMap.value(item, 0);
+ if (!texture)
+ texture = new CanvasTexture(m_commandQueue, this, item);
+
+ m_quickItemToTextureMap.insert(item, texture);
+
+ QJSValue value = m_engine->newQObject(texture);
+
+ qCDebug(canvas3drendering).nospace() << "Context3D::" << __FUNCTION__
+ << "(quickItem:" << item
+ << "):" << value.toString();
+
+ // We attempt to add item as texture again even if it is already created to make sure the
+ // provider is cached. This allows user to fix the texture after e.g. disabling and enabling
+ // a layer, which destroys and recreates the texture provider.
+ m_commandQueue->addQuickItemAsTexture(item, texture->textureId());
+
+ return value;
+}
+
+/*!
+ * \internal
+ */
+QMap<QQuickItem *, CanvasTexture *> &CanvasContext::quickItemToTextureMap()
+{
+ return m_quickItemToTextureMap;
+}
+
+/*!
* \qmlmethod variant Context3D::getUniform(Canvas3DProgram program, Canvas3DUniformLocation location3D)
* Returns the uniform value at the given \a location3D in the \a program.
* The type returned is dependent on the uniform type, as shown in the table:
@@ -6413,7 +6455,6 @@ void CanvasContext::scheduleSyncCommand(GlSyncCommand *command)
* \internal
* Schedules a blocking job to clear the queue.
*/
-
void CanvasContext::handleFullCommandQueue()
{
// Use no command to simply force the execution of the pending queue
@@ -6421,6 +6462,16 @@ void CanvasContext::handleFullCommandQueue()
}
/*!
+ * \internal
+ */
+void CanvasContext::handleTextureIdResolved(QQuickItem *item)
+{
+ CanvasTexture *texture = m_quickItemToTextureMap.value(item, 0);
+ if (texture && texture->isAlive() && m_textureProviderExt)
+ emit m_textureProviderExt->textureReady(item);
+}
+
+/*!
* \qmlmethod variant Context3D::getExtension(string name)
* \return object if given \a name matches a supported extension.
* Otherwise returns \c{null}. The returned object may contain constants and/or functions provided
@@ -6442,6 +6493,10 @@ QVariant CanvasContext::getExtension(const QString &name)
if (!m_stateDumpExt)
m_stateDumpExt = new CanvasGLStateDump(this, m_isOpenGLES2, this);
return QVariant::fromValue(m_stateDumpExt);
+ } else if (upperCaseName == QStringLiteral("QTCANVAS3D_TEXTURE_PROVIDER")) {
+ if (!m_textureProviderExt)
+ m_textureProviderExt = new CanvasTextureProvider(this, this);
+ return QVariant::fromValue(m_textureProviderExt);
} else if (upperCaseName == QStringLiteral("OES_STANDARD_DERIVATIVES") &&
m_extensions.contains("OES_standard_derivatives")) {
if (!m_standardDerivatives)
diff --git a/src/imports/qtcanvas3d/context3d_p.h b/src/imports/qtcanvas3d/context3d_p.h
index 4e209ec..b3d632b 100644
--- a/src/imports/qtcanvas3d/context3d_p.h
+++ b/src/imports/qtcanvas3d/context3d_p.h
@@ -51,6 +51,7 @@
#include "contextattributes_p.h"
#include "abstractobject3d_p.h"
#include "canvasglstatedump_p.h"
+#include "canvastextureprovider_p.h"
#include <QtCore/QMutex>
#include <QtCore/QWaitCondition>
@@ -1181,10 +1182,14 @@ public:
Q_INVOKABLE uint getVertexAttribOffset(uint index, glEnums pname);
Q_INVOKABLE QJSValue getVertexAttrib(uint index, glEnums pname);
+ QJSValue createTextureFromSource(QQuickItem *item);
+ QMap<QQuickItem *, CanvasTexture *> &quickItemToTextureMap();
+
void scheduleSyncCommand(GlSyncCommand *command);
public slots:
void handleFullCommandQueue();
+ void handleTextureIdResolved(QQuickItem *item);
signals:
void canvasChanged(Canvas *canvas);
@@ -1279,6 +1284,7 @@ private:
CanvasGlCommandQueue *m_commandQueue; // Not owned
QMutex m_renderJobMutex;
QWaitCondition m_renderJobCondition;
+ QMap<QQuickItem *, CanvasTexture *> m_quickItemToTextureMap;
bool invalidEnumFlag;
bool invalidValueFlag;
@@ -1291,6 +1297,7 @@ private:
// EXTENSIONS
CanvasGLStateDump *m_stateDumpExt;
+ CanvasTextureProvider *m_textureProviderExt;
QObject *m_standardDerivatives;
CompressedTextureS3TC *m_compressedTextureS3TC;
CompressedTexturePVRTC *m_compressedTexturePVRTC;
diff --git a/src/imports/qtcanvas3d/glcommandqueue.cpp b/src/imports/qtcanvas3d/glcommandqueue.cpp
index 7e2d1bd..9882634 100644
--- a/src/imports/qtcanvas3d/glcommandqueue.cpp
+++ b/src/imports/qtcanvas3d/glcommandqueue.cpp
@@ -35,6 +35,8 @@
****************************************************************************/
#include "glcommandqueue_p.h"
+#include "canvas3d_p.h" // for logging categories
+
#include <QtCore/QMap>
#include <QtCore/QMutexLocker>
@@ -89,6 +91,7 @@ GlCommand &CanvasGlCommandQueue::queueCommand(CanvasGlCommandQueue::GlCommandId
if (m_queuedCount) {
deleteUntransferedCommandData();
m_queuedCount = 0;
+ clearQuickItemAsTextureList();
}
}
@@ -169,6 +172,33 @@ int CanvasGlCommandQueue::transferCommands(QVector<GlCommand> &executeQueue)
const int count = m_queuedCount;
m_queuedCount = 0;
+ // Grab texture providers from quick items and cache them
+ const int quickItemCount = m_quickItemsAsTextureList.size();
+ if (quickItemCount) {
+ for (int i = 0; i < quickItemCount; i++) {
+ const ItemAndId *itemAndId = m_quickItemsAsTextureList.at(i);
+ if (!itemAndId->itemPtr.isNull()) {
+ QQuickItem *quickItem = itemAndId->itemPtr.data();
+ QSGTextureProvider *texProvider = quickItem->textureProvider();
+ if (texProvider) {
+ // Make sure the old provider, if any, gets cleared up before inserting a new one
+ delete m_providerCache.take(itemAndId->id);
+ m_providerCache.insert(itemAndId->id,
+ new ProviderCacheItem(texProvider, quickItem));
+ // Reset the mapped glId so it gets resolved at render time
+ setGlIdToMap(itemAndId->id, 0,
+ CanvasGlCommandQueue::internalClearQuickItemAsTexture);
+ } else {
+ qCWarning(canvas3drendering).nospace() << "CanvasGlCommandQueue::"
+ << __FUNCTION__
+ << ": The Quick item doesn't implement a texture provider: "
+ << quickItem;
+ }
+ }
+ }
+ clearQuickItemAsTextureList();
+ }
+
return count;
}
@@ -180,6 +210,7 @@ int CanvasGlCommandQueue::transferCommands(QVector<GlCommand> &executeQueue)
void CanvasGlCommandQueue::resetQueue(int size)
{
deleteUntransferedCommandData();
+ clearQuickItemAsTextureList();
m_queuedCount = 0;
m_maxSize = size;
@@ -344,5 +375,21 @@ void CanvasGlCommandQueue::handleGenerateCommand(const GlCommand &command, GLuin
setGlIdToMap(command.i1, glId, command.id);
}
+/*!
+ * \internal
+ * Adds a quick item to list of items that need to be converted to texture IDs on the
+ * next command transfer.
+ */
+void CanvasGlCommandQueue::addQuickItemAsTexture(QQuickItem *quickItem, GLint textureId)
+{
+ m_quickItemsAsTextureList.append(new ItemAndId(quickItem, textureId));
+}
+
+void CanvasGlCommandQueue::clearQuickItemAsTextureList()
+{
+ qDeleteAll(m_quickItemsAsTextureList);
+ m_quickItemsAsTextureList.clear();
+}
+
QT_CANVAS3D_END_NAMESPACE
QT_END_NAMESPACE
diff --git a/src/imports/qtcanvas3d/glcommandqueue_p.h b/src/imports/qtcanvas3d/glcommandqueue_p.h
index b633982..50d610c 100644
--- a/src/imports/qtcanvas3d/glcommandqueue_p.h
+++ b/src/imports/qtcanvas3d/glcommandqueue_p.h
@@ -48,12 +48,16 @@
#define GLCOMMANDQUEUE_P_H
#include "canvas3dcommon_p.h"
+#include "canvastextureprovider_p.h"
#include <QtCore/QVariantList>
#include <QtCore/QMutex>
+#include <QtCore/QPointer>
#include <QtGui/qopengl.h>
#include <QtGui/QOpenGLShader>
#include <QtGui/QOpenGLShaderProgram>
+#include <QtQuick/QQuickItem>
+#include <QtQuick/QSGTextureProvider>
QT_BEGIN_NAMESPACE
QT_CANVAS3D_BEGIN_NAMESPACE
@@ -207,6 +211,7 @@ public:
internalGetUniformType,
internalClearLocation, // Used to clear a mapped uniform location from map when no longer needed
internalTextureComplete, // Indicates texture is complete and needs to be updated to screen at this point
+ internalClearQuickItemAsTexture, // Used to clear mapped quick item texture ids when no longer needed
extStateDump
};
@@ -266,6 +271,19 @@ public:
QMutex *resourceMutex() { return &m_resourceMutex; }
+ void addQuickItemAsTexture(QQuickItem *quickItem, GLint textureId);
+ void clearQuickItemAsTextureList();
+
+ struct ProviderCacheItem {
+ ProviderCacheItem(QSGTextureProvider *provider, QQuickItem *item) :
+ providerPtr(provider),
+ quickItem(item) {}
+
+ QPointer<QSGTextureProvider> providerPtr;
+ QQuickItem *quickItem; // Not owned, nor accessed - only used as identifier
+ };
+ QMap<GLint, ProviderCacheItem *> &providerCache() { return m_providerCache; }
+
signals:
void queueFull();
@@ -280,6 +298,18 @@ private:
GLint m_nextResourceId;
bool m_resourceIdOverflow;
QMutex m_resourceMutex;
+
+ struct ItemAndId {
+ ItemAndId(QQuickItem *item, GLint itemId) :
+ itemPtr(item),
+ id(itemId) {}
+
+ QPointer<QQuickItem> itemPtr;
+ GLint id;
+ };
+ QList<ItemAndId *> m_quickItemsAsTextureList;
+
+ QMap<GLint, ProviderCacheItem *> m_providerCache;
};
class GlCommand
diff --git a/src/imports/qtcanvas3d/qcanvas3d_plugin.cpp b/src/imports/qtcanvas3d/qcanvas3d_plugin.cpp
index 3c421a5..ec905d2 100644
--- a/src/imports/qtcanvas3d/qcanvas3d_plugin.cpp
+++ b/src/imports/qtcanvas3d/qcanvas3d_plugin.cpp
@@ -46,6 +46,8 @@ void QtCanvas3DPlugin::registerTypes(const char *uri)
{
// @uri com.digia.qtcanvas3d
+ // QtCanvas3D 1.0
+
// QTCANVAS3D CORE API
qmlRegisterSingletonType<CanvasTextureImageFactory>(uri,
1, 0,
@@ -108,6 +110,14 @@ void QtCanvas3DPlugin::registerTypes(const char *uri)
1, 0,
"GLStateDumpExt",
QLatin1String("Trying to create uncreatable: GLStateDumpExt, use Context3D.getExtension(\"QTCANVAS3D_gl_state_dump\") instead."));
+
+ // QtCanvas3D 1.1
+
+ // EXTENSIONS
+ qmlRegisterUncreatableType<CanvasTextureProvider>(uri,
+ 1, 1,
+ "Canvas3DTextureProvider",
+ QLatin1String("Trying to create uncreatable: Canvas3DTextureProvider, use Context3D.getExtension(\"QTCANVAS3D_texture_provider\") instead."));
}
QT_CANVAS3D_END_NAMESPACE
diff --git a/src/imports/qtcanvas3d/qcanvas3d_plugin.h b/src/imports/qtcanvas3d/qcanvas3d_plugin.h
index 34fe771..3ee83d8 100644
--- a/src/imports/qtcanvas3d/qcanvas3d_plugin.h
+++ b/src/imports/qtcanvas3d/qcanvas3d_plugin.h
@@ -51,6 +51,7 @@
#include "shaderprecisionformat_p.h"
#include "activeinfo3d_p.h"
#include "canvasglstatedump_p.h"
+#include "canvastextureprovider_p.h"
#include <QQmlExtensionPlugin>
@@ -73,6 +74,7 @@ QML_DECLARE_TYPE(CanvasRenderBuffer)
QML_DECLARE_TYPE(CanvasShaderPrecisionFormat)
QML_DECLARE_TYPE(CanvasActiveInfo)
QML_DECLARE_TYPE(CanvasGLStateDump)
+QML_DECLARE_TYPE(CanvasTextureProvider)
QT_BEGIN_NAMESPACE
QT_CANVAS3D_BEGIN_NAMESPACE
diff --git a/src/imports/qtcanvas3d/qtcanvas3d.pro b/src/imports/qtcanvas3d/qtcanvas3d.pro
index 6ddad5a..af06b46 100644
--- a/src/imports/qtcanvas3d/qtcanvas3d.pro
+++ b/src/imports/qtcanvas3d/qtcanvas3d.pro
@@ -30,7 +30,8 @@ SOURCES += arrayutils.cpp \
compressedtexturepvrtc.cpp \
glcommandqueue.cpp \
renderjob.cpp \
- canvasrenderer.cpp
+ canvasrenderer.cpp \
+ canvastextureprovider.cpp
HEADERS += arrayutils_p.h \
qcanvas3d_plugin.h \
@@ -56,7 +57,8 @@ HEADERS += arrayutils_p.h \
compressedtexturepvrtc_p.h \
glcommandqueue_p.h \
renderjob_p.h \
- canvasrenderer_p.h
+ canvasrenderer_p.h \
+ canvastextureprovider_p.h
OTHER_FILES = qmldir \
doc/* \
diff --git a/src/imports/qtcanvas3d/texture3d.cpp b/src/imports/qtcanvas3d/texture3d.cpp
index 4ef2226..3b34152 100644
--- a/src/imports/qtcanvas3d/texture3d.cpp
+++ b/src/imports/qtcanvas3d/texture3d.cpp
@@ -53,14 +53,20 @@ QT_CANVAS3D_BEGIN_NAMESPACE
/*!
* \internal
*/
-CanvasTexture::CanvasTexture(CanvasGlCommandQueue *queue, QObject *parent) :
- CanvasAbstractObject(queue, parent),
+CanvasTexture::CanvasTexture(CanvasGlCommandQueue *queue, CanvasContext *context,
+ QQuickItem *quickItem) :
+ CanvasAbstractObject(queue, context),
m_textureId(queue->createResourceId()),
- m_isAlive(true)
+ m_isAlive(true),
+ m_context(context),
+ m_quickItem(quickItem)
{
Q_ASSERT(m_commandQueue);
- m_commandQueue->queueCommand(CanvasGlCommandQueue::glGenTextures, m_textureId);
+ if (m_quickItem)
+ connect(m_quickItem, &QObject::destroyed, this, &CanvasTexture::handleItemDestroyed);
+ else
+ m_commandQueue->queueCommand(CanvasGlCommandQueue::glGenTextures, m_textureId);
}
/*!
@@ -96,6 +102,14 @@ GLint CanvasTexture::textureId() const
/*!
* \internal
*/
+void CanvasTexture::handleItemDestroyed()
+{
+ del();
+}
+
+/*!
+ * \internal
+ */
bool CanvasTexture::isAlive() const
{
return bool(m_textureId);
@@ -106,8 +120,16 @@ bool CanvasTexture::isAlive() const
*/
void CanvasTexture::del()
{
- if (m_textureId)
- m_commandQueue->queueCommand(CanvasGlCommandQueue::glDeleteTextures, m_textureId);
+ if (m_textureId) {
+ if (m_quickItem) {
+ m_context->quickItemToTextureMap().remove(m_quickItem);
+ m_quickItem = 0;
+ m_commandQueue->queueCommand(CanvasGlCommandQueue::internalClearQuickItemAsTexture,
+ m_textureId);
+ } else {
+ m_commandQueue->queueCommand(CanvasGlCommandQueue::glDeleteTextures, m_textureId);
+ }
+ }
m_textureId = 0;
}
diff --git a/src/imports/qtcanvas3d/texture3d_p.h b/src/imports/qtcanvas3d/texture3d_p.h
index cd55ce4..88874e7 100644
--- a/src/imports/qtcanvas3d/texture3d_p.h
+++ b/src/imports/qtcanvas3d/texture3d_p.h
@@ -49,6 +49,9 @@
#include "context3d_p.h"
#include "abstractobject3d_p.h"
+#include <QtCore/QPointer>
+
+class QQuickItem;
QT_BEGIN_NAMESPACE
QT_CANVAS3D_BEGIN_NAMESPACE
@@ -58,7 +61,8 @@ class CanvasTexture : public CanvasAbstractObject
Q_OBJECT
public:
- explicit CanvasTexture(CanvasGlCommandQueue *queue, QObject *parent = 0);
+ explicit CanvasTexture(CanvasGlCommandQueue *queue, CanvasContext *context,
+ QQuickItem *quickItem = 0);
~CanvasTexture();
void bind(CanvasContext::glEnums target);
@@ -69,8 +73,14 @@ public:
friend QDebug operator<< (QDebug d, const CanvasTexture *texture);
+public slots:
+ void handleItemDestroyed();
+
+private:
GLint m_textureId;
bool m_isAlive;
+ CanvasContext *m_context;
+ QQuickItem *m_quickItem;
};
QT_CANVAS3D_END_NAMESPACE
diff --git a/tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.js b/tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.js
new file mode 100644
index 0000000..79d290f
--- /dev/null
+++ b/tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.js
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+Qt.include("../../../../examples/canvas3d/canvas3d/3rdparty/gl-matrix.js")
+
+var gl;
+
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+
+var texture = null;
+
+var pMatrixUniform;
+var mvMatrixUniform;
+
+var vertexPositionAttribute;
+var textureCoordAttribute;
+
+var vertexBuffer;
+var uvBuffer;
+var indexBuffer;
+
+var readyTextures;
+var quickTextureProvider;
+
+function initializeGL(canvas) {
+ gl = canvas.getContext("");
+
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+ var pixelRatio = canvas.devicePixelRatio;
+ gl.viewport(0, 0, pixelRatio * canvas.width, pixelRatio * canvas.height);
+
+ initShaders();
+ initBuffers();
+
+ mat4.perspective(pMatrix, degToRad(45), canvas.width / canvas.height, 0.1, 500.0);
+ gl.uniformMatrix4fv(pMatrixUniform, false, pMatrix);
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [0, 0, -5]);
+ gl.uniformMatrix4fv(mvMatrixUniform, false, mvMatrix);
+}
+
+function paintGL(x, y) {
+ gl.clearColor(64.0 / 255.0, 80.0 / 255.0, 96.0 / 255.0, 1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
+
+ var pixels = checkPixel(x, y);
+
+ return pixels;
+}
+
+function checkPixel(x, y) {
+ var pixels = new Uint8Array(4);
+ gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
+ return pixels;
+}
+
+function initBuffers()
+{
+ vertexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ new Float32Array([-1.0, -1.0, 1.0,
+ 1.0, -1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ -1.0, 1.0, 1.0]),
+ gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ uvBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ new Float32Array([1.0, 0.0,
+ 0.0, 0.0,
+ 0.0, 1.0,
+ 1.0, 1.0]),
+ gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ indexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ new Uint16Array([0, 1, 2,
+ 0, 2, 3]),
+ gl.STATIC_DRAW);
+}
+
+function initShaders()
+{
+ var vertexShader = getShader(
+ gl,
+ "attribute highp vec3 aVertexPosition; \
+ attribute mediump vec4 aVertexColor; \
+ attribute highp vec2 aTextureCoord; \
+ uniform mat4 uMVMatrix; \
+ uniform mat4 uPMatrix; \
+ varying highp vec2 vTextureCoord; \
+ void main(void) { \
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \
+ vTextureCoord = aTextureCoord; \
+ }",
+ gl.VERTEX_SHADER);
+ var fragmentShader = getShader(
+ gl,
+ "varying highp vec2 vTextureCoord; \
+ uniform sampler2D uSampler; \
+ void main(void) { \
+ gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); \
+ }",
+ gl.FRAGMENT_SHADER);
+
+ var shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.linkProgram(shaderProgram);
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+
+ if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialize shaders");
+ console.log(gl.getProgramInfoLog(shaderProgram));
+ }
+
+ gl.useProgram(shaderProgram);
+
+ vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(textureCoordAttribute);
+
+ pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
+ mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+
+ var textureSamplerUniform = gl.getUniformLocation(shaderProgram, "uSampler")
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.uniform1i(textureSamplerUniform, 0);
+}
+
+function resetReadyTextures() {
+ readyTextures = [];
+}
+
+function readyTexturesCount() {
+ return readyTextures.length;
+}
+
+function onTextureReady(sourceItem) {
+ readyTextures[readyTextures.length] = sourceItem;
+ gl.bindTexture(gl.TEXTURE_2D, texture);
+}
+
+function updateTexture(newTextureSource) {
+ if (!quickTextureProvider) {
+ quickTextureProvider = gl.getExtension("QTCANVAS3D_texture_provider");
+ quickTextureProvider.textureReady.connect(onTextureReady);
+ }
+
+ texture = quickTextureProvider.createTextureFromSource(newTextureSource);
+}
+
+function getShader(gl, str, type) {
+ var shader = gl.createShader(type);
+ gl.shaderSource(shader, str);
+ gl.compileShader(shader);
+
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
+ console.log("JS:Shader compile failed");
+ console.log(gl.getShaderInfoLog(shader));
+ return null;
+ }
+
+ return shader;
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
diff --git a/tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.qml b/tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.qml
new file mode 100644
index 0000000..7aa5953
--- /dev/null
+++ b/tests/auto/qmltest/canvas3d/tst_quick_item_as_texture.qml
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** 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 The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later 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 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtTest 1.0
+
+import "tst_quick_item_as_texture.js" as Content
+
+Item {
+ id: top
+ height: 300
+ width: 300
+
+ property var canvas3d: null
+ property var shaderEffectSource: null
+ property var shaderEffectSource2: null
+ property var activeContent: Content
+ property bool initOk: false
+ property bool renderOk: false
+ property var canvasWindow: null
+ property bool windowHidden: false
+ property int xpos: 150
+ property int ypos: 150
+ property var pixels
+ property int red: -1
+ property int green: -1
+ property int blue: -1
+ property int alpha: -1
+
+ Rectangle {
+ id: testRect
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ width: 64
+ height: 64
+ color: "#102030"
+ z:1
+ }
+
+ Rectangle {
+ id: testRect2
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ width: 64
+ height: 64
+ color: "#122232"
+ z:1
+ }
+
+ Rectangle {
+ id: testRect3
+ anchors.top: parent.top
+ anchors.right: parent.right
+ width: 64
+ height: 64
+ color: "#132333"
+ z:1
+ }
+
+ function createCanvas() {
+ canvas3d = Qt.createQmlObject("
+ import QtQuick 2.2
+ import QtCanvas3D 1.1
+ Canvas3D {
+ onInitializeGL: {
+ activeContent.initializeGL(this)
+ initOk = true;
+ }
+ onPaintGL: {
+ pixels = activeContent.paintGL(xpos, ypos)
+ red = pixels[0]
+ green = pixels[1]
+ blue = pixels[2]
+ alpha = pixels[3]
+ delete pixels
+ renderOk = true
+ }
+ }", top)
+ canvas3d.anchors.fill = top
+ }
+
+ function createShaderEffectSource(source) {
+ var effect = Qt.createQmlObject("
+ import QtQuick 2.2
+ ShaderEffectSource {
+ width: 64
+ height: 64
+ live: false
+ hideSource: false
+ mipmap: true
+ z: 1
+ }", top)
+ effect.sourceItem = source
+ return effect
+ }
+
+ function resetRenderCheck() {
+ renderOk = false
+ red = -1
+ green = -1
+ blue = -1
+ alpha = -1
+ activeContent.resetReadyTextures()
+ }
+
+ TestCase {
+ name: "Canvas3D_quick_item_as_texture"
+ when: windowShown
+
+ function test_quick_item_as_texture_1() {
+ verify(canvas3d === null)
+ verify(initOk === false)
+ verify(renderOk === false)
+ createCanvas()
+ verify(canvas3d !== null)
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "initOk", true)
+
+ shaderEffectSource = createShaderEffectSource(testRect)
+ shaderEffectSource2 = createShaderEffectSource(testRect2)
+ testRect3.layer.enabled = true
+ verify(shaderEffectSource !== null)
+ verify(shaderEffectSource2 !== null)
+
+ resetRenderCheck()
+ activeContent.updateTexture(shaderEffectSource)
+ waitForRendering(canvas3d)
+
+ tryCompare(activeContent.readyTexturesCount() === 1)
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x10)
+ tryCompare(top, "green", 0x20)
+ tryCompare(top, "blue", 0x30)
+ tryCompare(top, "alpha", 0xff)
+
+ resetRenderCheck()
+ activeContent.updateTexture(shaderEffectSource2)
+ waitForRendering(canvas3d)
+
+ tryCompare(activeContent.readyTexturesCount() === 1)
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x12)
+ tryCompare(top, "green", 0x22)
+ tryCompare(top, "blue", 0x32)
+ tryCompare(top, "alpha", 0xff)
+
+ // testRect3 is layered
+ resetRenderCheck()
+ activeContent.updateTexture(testRect3)
+ tryCompare(activeContent.readyTexturesCount() === 1)
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x13)
+ tryCompare(top, "green", 0x23)
+ tryCompare(top, "blue", 0x33)
+ tryCompare(top, "alpha", 0xff)
+
+ // Texture is not live, color should not change
+ testRect.color = "#405060"
+ resetRenderCheck()
+ activeContent.updateTexture(shaderEffectSource)
+ tryCompare(activeContent.readyTexturesCount() === 1)
+
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x10)
+ tryCompare(top, "green", 0x20)
+ tryCompare(top, "blue", 0x30)
+ tryCompare(top, "alpha", 0xff)
+
+ // Turn live on, color will change to what we previously set it
+ resetRenderCheck()
+ shaderEffectSource.live = true
+
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x40)
+ tryCompare(top, "green", 0x50)
+ tryCompare(top, "blue", 0x60)
+ tryCompare(top, "alpha", 0xff)
+
+ // Live texture, new color
+ testRect.color = "#AABBCC"
+ resetRenderCheck()
+
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0xAA)
+ tryCompare(top, "green", 0xBB)
+ tryCompare(top, "blue", 0xCC)
+ tryCompare(top, "alpha", 0xff)
+
+ // Destroy shaderEffectSources
+ shaderEffectSource.destroy()
+ shaderEffectSource2.destroy()
+ testRect3.layer.enabled = false
+
+ waitForRendering(canvas3d)
+
+ testRect.color = "#718191"
+ testRect2.color = "#728292"
+ testRect3.color = "#738393"
+
+ waitForRendering(canvas3d)
+
+ // Recreate shaderEffectSources
+ shaderEffectSource = createShaderEffectSource(testRect)
+ shaderEffectSource2 = createShaderEffectSource(testRect2)
+ testRect3.layer.enabled = true
+ verify(shaderEffectSource !== null)
+ verify(shaderEffectSource2 !== null)
+
+ waitForRendering(canvas3d)
+
+ // Test that each textureProvider is valid second time around
+ activeContent.updateTexture(shaderEffectSource)
+
+ resetRenderCheck()
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x71)
+ tryCompare(top, "green", 0x81)
+ tryCompare(top, "blue", 0x91)
+ tryCompare(top, "alpha", 0xff)
+
+ activeContent.updateTexture(shaderEffectSource2)
+
+ resetRenderCheck()
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x72)
+ tryCompare(top, "green", 0x82)
+ tryCompare(top, "blue", 0x92)
+ tryCompare(top, "alpha", 0xff)
+
+ activeContent.updateTexture(testRect3)
+
+ resetRenderCheck()
+ waitForRendering(canvas3d)
+
+ tryCompare(top, "renderOk", true)
+ tryCompare(top, "red", 0x73)
+ tryCompare(top, "green", 0x83)
+ tryCompare(top, "blue", 0x93)
+ tryCompare(top, "alpha", 0xff)
+
+ shaderEffectSource.destroy()
+ shaderEffectSource2.destroy()
+ testRect3.layer.enabled = false
+
+ waitForRendering(canvas3d)
+
+ testRect.layer.enabled = true
+ testRect2.layer.enabled = true
+ testRect3.layer.enabled = true
+
+ resetRenderCheck()
+ waitForRendering(canvas3d)
+
+ // Test that multiple items each trigger textureReady signal
+ activeContent.updateTexture(testRect)
+ activeContent.updateTexture(testRect2)
+ activeContent.updateTexture(testRect3)
+
+ tryCompare(activeContent.readyTexturesCount() === 3)
+ }
+ }
+}