From 15e58df3386b5438f6ae114a51ad4a258085e70b Mon Sep 17 00:00:00 2001 From: Gunnar Sletta <gunnar.sletta@digia.com> Date: Wed, 27 Feb 2013 08:44:47 +0100 Subject: [PATCH] Added examples on how to use FBOs with scene graph. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I also cleaned up the naming of the other scene graph examples a bit, so that they sort together in the samples list and have a more obvious naming scheme. Task-number: QTBUG-29548 Change-Id: I455eacb02c06058a6d49e12e4f1813ec80b655f6 Reviewed-by: Samuel Rødal <samuel.rodal@digia.com> --- .../doc/src/customgeometry.qdoc | 4 +- .../doc/src/openglunderqml.qdoc | 2 +- examples/quick/scenegraph/scenegraph.pro | 7 +- .../quick/scenegraph/shared/logorenderer.cpp | 258 ++++++++++++++++++ .../quick/scenegraph/shared/logorenderer.h | 77 ++++++ .../doc/src/simplematerial.qdoc | 2 +- .../doc/images/textureinsgnode-example.jpg | Bin 0 -> 25863 bytes .../doc/src/textureinsgnode.qdoc | 36 +++ .../textureinsgnode/fboinsgrenderer.cpp | 129 +++++++++ .../textureinsgnode/fboinsgrenderer.h | 59 ++++ .../quick/scenegraph/textureinsgnode/main.cpp | 59 ++++ .../quick/scenegraph/textureinsgnode/main.qml | 132 +++++++++ .../textureinsgnode/textureinsgnode.pro | 16 ++ .../textureinsgnode/textureinsgnode.qrc | 5 + .../doc/images/textureinthread-example.jpg | Bin 0 -> 33269 bytes .../doc/src/textureinthread.qdoc | 36 +++ .../quick/scenegraph/textureinthread/main.cpp | 59 ++++ .../quick/scenegraph/textureinthread/main.qml | 132 +++++++++ .../textureinthread/textureinthread.pro | 16 ++ .../textureinthread/textureinthread.qrc | 5 + .../textureinthread/threadrenderer.cpp | 257 +++++++++++++++++ .../textureinthread/threadrenderer.h | 62 +++++ .../src/concepts/visualcanvas/scenegraph.qdoc | 26 +- src/quick/items/qquickwindow.cpp | 2 +- src/quick/scenegraph/coreapi/qsggeometry.cpp | 2 +- .../scenegraph/util/qsgsimplematerial.cpp | 2 +- src/quick/scenegraph/util/qsgtexture.cpp | 2 + 27 files changed, 1365 insertions(+), 22 deletions(-) create mode 100644 examples/quick/scenegraph/shared/logorenderer.cpp create mode 100644 examples/quick/scenegraph/shared/logorenderer.h create mode 100644 examples/quick/scenegraph/textureinsgnode/doc/images/textureinsgnode-example.jpg create mode 100644 examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc create mode 100644 examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp create mode 100644 examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h create mode 100644 examples/quick/scenegraph/textureinsgnode/main.cpp create mode 100644 examples/quick/scenegraph/textureinsgnode/main.qml create mode 100644 examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro create mode 100644 examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc create mode 100644 examples/quick/scenegraph/textureinthread/doc/images/textureinthread-example.jpg create mode 100644 examples/quick/scenegraph/textureinthread/doc/src/textureinthread.qdoc create mode 100644 examples/quick/scenegraph/textureinthread/main.cpp create mode 100644 examples/quick/scenegraph/textureinthread/main.qml create mode 100644 examples/quick/scenegraph/textureinthread/textureinthread.pro create mode 100644 examples/quick/scenegraph/textureinthread/textureinthread.qrc create mode 100644 examples/quick/scenegraph/textureinthread/threadrenderer.cpp create mode 100644 examples/quick/scenegraph/textureinthread/threadrenderer.h diff --git a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc index cc034e34ba..d99deb754f 100644 --- a/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc +++ b/examples/quick/scenegraph/customgeometry/doc/src/customgeometry.qdoc @@ -27,11 +27,11 @@ /*! \example quick/scenegraph/customgeometry - \title Custom Geometry Example + \title Scene Graph - Custom Geometry \ingroup qtquickexamples \brief Shows how to implement a custom geometry in the Qt Quick Scene Graph. - \brief The custom geometry example shows how to create a QQuickItem which + The custom geometry example shows how to create a QQuickItem which uses the scene graph API to build a custom geometry for the scene graph. It does this by creating a BezierCurve item which is made part of the CustomGeometry module and makes use of this in a QML diff --git a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc index 5ded717e5f..49f1a825e1 100644 --- a/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc +++ b/examples/quick/scenegraph/openglunderqml/doc/src/openglunderqml.qdoc @@ -27,7 +27,7 @@ /*! \example quick/scenegraph/openglunderqml - \title OpenGL Under QML + \title Scene Graph - OpenGL Under QML \ingroup qtquickexamples \brief Shows how to render OpenGL under a Qt Quick scene. diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro index 88b8d03dc3..3ddb216615 100644 --- a/examples/quick/scenegraph/scenegraph.pro +++ b/examples/quick/scenegraph/scenegraph.pro @@ -1,2 +1,7 @@ TEMPLATE = subdirs -SUBDIRS += customgeometry simplematerial openglunderqml +SUBDIRS += \ + customgeometry \ + openglunderqml \ + simplematerial \ + textureinsgnode \ + textureinthread \ diff --git a/examples/quick/scenegraph/shared/logorenderer.cpp b/examples/quick/scenegraph/shared/logorenderer.cpp new file mode 100644 index 0000000000..4c5927b543 --- /dev/null +++ b/examples/quick/scenegraph/shared/logorenderer.cpp @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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 "logorenderer.h" +#include <QPainter> +#include <QPaintEngine> +#include <math.h> + +LogoRenderer::LogoRenderer() +{ +} + +LogoRenderer::~LogoRenderer() +{ +} + + +void LogoRenderer::paintQtLogo() +{ + program1.enableAttributeArray(normalAttr1); + program1.enableAttributeArray(vertexAttr1); + program1.setAttributeArray(vertexAttr1, vertices.constData()); + program1.setAttributeArray(normalAttr1, normals.constData()); + glDrawArrays(GL_TRIANGLES, 0, vertices.size()); + program1.disableAttributeArray(normalAttr1); + program1.disableAttributeArray(vertexAttr1); +} + + +void LogoRenderer::initialize() +{ + glClearColor(0.1f, 0.1f, 0.2f, 1.0f); + + QOpenGLShader *vshader1 = new QOpenGLShader(QOpenGLShader::Vertex, &program1); + const char *vsrc1 = + "attribute highp vec4 vertex;\n" + "attribute mediump vec3 normal;\n" + "uniform mediump mat4 matrix;\n" + "varying mediump vec4 color;\n" + "void main(void)\n" + "{\n" + " vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n" + " float angle = max(dot(normal, toLight), 0.0);\n" + " vec3 col = vec3(0.40, 1.0, 0.0);\n" + " color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n" + " color = clamp(color, 0.0, 1.0);\n" + " gl_Position = matrix * vertex;\n" + "}\n"; + vshader1->compileSourceCode(vsrc1); + + QOpenGLShader *fshader1 = new QOpenGLShader(QOpenGLShader::Fragment, &program1); + const char *fsrc1 = + "varying mediump vec4 color;\n" + "void main(void)\n" + "{\n" + " gl_FragColor = color;\n" + "}\n"; + fshader1->compileSourceCode(fsrc1); + + program1.addShader(vshader1); + program1.addShader(fshader1); + program1.link(); + + vertexAttr1 = program1.attributeLocation("vertex"); + normalAttr1 = program1.attributeLocation("normal"); + matrixUniform1 = program1.uniformLocation("matrix"); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + m_fAngle = 0; + m_fScale = 1; + createGeometry(); +} + +void LogoRenderer::render() +{ + glDepthMask(true); + + glClearColor(0.5f, 0.5f, 0.7f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + glFrontFace(GL_CW); + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); + + QMatrix4x4 modelview; + modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f); + modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f); + modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f); + modelview.scale(m_fScale); + modelview.translate(0.0f, -0.2f, 0.0f); + + program1.bind(); + program1.setUniformValue(matrixUniform1, modelview); + paintQtLogo(); + program1.release(); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + m_fAngle += 1.0f; +} + +void LogoRenderer::createGeometry() +{ + vertices.clear(); + normals.clear(); + + qreal x1 = +0.06f; + qreal y1 = -0.14f; + qreal x2 = +0.14f; + qreal y2 = -0.06f; + qreal x3 = +0.08f; + qreal y3 = +0.00f; + qreal x4 = +0.30f; + qreal y4 = +0.22f; + + quad(x1, y1, x2, y2, y2, x2, y1, x1); + quad(x3, y3, x4, y4, y4, x4, y3, x3); + + extrude(x1, y1, x2, y2); + extrude(x2, y2, y2, x2); + extrude(y2, x2, y1, x1); + extrude(y1, x1, x1, y1); + extrude(x3, y3, x4, y4); + extrude(x4, y4, y4, x4); + extrude(y4, x4, y3, x3); + + const qreal Pi = 3.14159f; + const int NumSectors = 100; + + for (int i = 0; i < NumSectors; ++i) { + qreal angle1 = (i * 2 * Pi) / NumSectors; + qreal x5 = 0.30 * sin(angle1); + qreal y5 = 0.30 * cos(angle1); + qreal x6 = 0.20 * sin(angle1); + qreal y6 = 0.20 * cos(angle1); + + qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors; + qreal x7 = 0.20 * sin(angle2); + qreal y7 = 0.20 * cos(angle2); + qreal x8 = 0.30 * sin(angle2); + qreal y8 = 0.30 * cos(angle2); + + quad(x5, y5, x6, y6, x7, y7, x8, y8); + + extrude(x6, y6, x7, y7); + extrude(x8, y8, x5, y5); + } + + for (int i = 0;i < vertices.size();i++) + vertices[i] *= 2.0f; +} + +void LogoRenderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4) +{ + vertices << QVector3D(x1, y1, -0.05f); + vertices << QVector3D(x2, y2, -0.05f); + vertices << QVector3D(x4, y4, -0.05f); + + vertices << QVector3D(x3, y3, -0.05f); + vertices << QVector3D(x4, y4, -0.05f); + vertices << QVector3D(x2, y2, -0.05f); + + QVector3D n = QVector3D::normal + (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f)); + + normals << n; + normals << n; + normals << n; + + normals << n; + normals << n; + normals << n; + + vertices << QVector3D(x4, y4, 0.05f); + vertices << QVector3D(x2, y2, 0.05f); + vertices << QVector3D(x1, y1, 0.05f); + + vertices << QVector3D(x2, y2, 0.05f); + vertices << QVector3D(x4, y4, 0.05f); + vertices << QVector3D(x3, y3, 0.05f); + + n = QVector3D::normal + (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f)); + + normals << n; + normals << n; + normals << n; + + normals << n; + normals << n; + normals << n; +} + +void LogoRenderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2) +{ + vertices << QVector3D(x1, y1, +0.05f); + vertices << QVector3D(x2, y2, +0.05f); + vertices << QVector3D(x1, y1, -0.05f); + + vertices << QVector3D(x2, y2, -0.05f); + vertices << QVector3D(x1, y1, -0.05f); + vertices << QVector3D(x2, y2, +0.05f); + + QVector3D n = QVector3D::normal + (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f)); + + normals << n; + normals << n; + normals << n; + + normals << n; + normals << n; + normals << n; +} diff --git a/examples/quick/scenegraph/shared/logorenderer.h b/examples/quick/scenegraph/shared/logorenderer.h new file mode 100644 index 0000000000..48fbf87203 --- /dev/null +++ b/examples/quick/scenegraph/shared/logorenderer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +#ifndef LOGORENDERER_H +#define LOGORENDERER_H + +#include <QtGui/qvector3d.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qopenglshaderprogram.h> + +#include <QTime> +#include <QVector> + +class LogoRenderer { + +public: + LogoRenderer(); + ~LogoRenderer(); + + void render(); + void initialize(); + +private: + + qreal m_fAngle; + qreal m_fScale; + + void paintQtLogo(); + void createGeometry(); + void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4); + void extrude(qreal x1, qreal y1, qreal x2, qreal y2); + + QVector<QVector3D> vertices; + QVector<QVector3D> normals; + QOpenGLShaderProgram program1; + int vertexAttr1; + int normalAttr1; + int matrixUniform1; +}; +#endif diff --git a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc index 20d244fe99..97cc4677d5 100644 --- a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc +++ b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc @@ -27,7 +27,7 @@ /*! \example quick/scenegraph/simplematerial - \title Simple Material Example + \title Scene Graph - Simple Material \ingroup qtquickexamples \brief Shows how to define a scene graph material to fill a shape. diff --git a/examples/quick/scenegraph/textureinsgnode/doc/images/textureinsgnode-example.jpg b/examples/quick/scenegraph/textureinsgnode/doc/images/textureinsgnode-example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..306b8bab20c9b77adce25b3d44a216eeaab8081a GIT binary patch literal 25863 zcmdSBbzB|IwkEuB4eoBi-Q5Z9grFg~ThKsocMUE95}e@f4#9#u1c%`6Fujxaz31FB z=lk7n?#%o#yP8dR$*Q%UW!2pU&vVZ|L1=QXWM6?GARs_8Kmk23f+Rrju&{8jFz|42 za0m$Sh{#wkkdcs(@i8z_v4{ysNr(xEh{&jzX~-xTDT#<^dFU8f**G~lNon|mc-aM+ zIXKzDL?93l5Rj3O@m{>ZV<#sfXa8URJa>W6;UQunVxb_=L6GPWQ0NfPJs<*rRS*>L z^N$Y%6f_JZEV%7Y(|>A%1R7zV7eL5R5Fki2C^QfV;;zFC7VW=0Q0ywBe+UNr7YDnh zhqjV&NUIAo7TUingwAfP6>G=(@<Grr|E9n$6Av>5ZXD}-2L8Kd7}#FoNJifK*|%#D zV*jpGN*g1Y@p{gxt^M0(h<a%!Bova%sRk9%zlubk>IO|(k76}*Y1;7LbN<h4z>>Jn zY(xr9pG(J+l!heCB-G9dwAR%j!v8KW!UgcO9IwB%c0u}s3ls@@!Oj~vP9*Y8d<r3n z;TDCPA1xO`NVd)+e}o3h!Ibh393aa?_?t4gaKxvZ#}tPdYNNa)kszYazmD6YG~Zuw zE$zqsk>@}2FVW{Xc4obScaCThx_3J1nU<By2pwC2A>REacOhGTJfUjpw-Ugh*I~xA zx*Yw!Bw>%Xk5k4E$@59ed`t8wsf9rPjw;AE9!aTS%Gv0s;j=GL=JG0oLP$OKm&j<z zXvsHtcm~Es?OCr;W?^+(rs8oRW&Vr`oN@N9FBv`m&E9`P9~8ndkdJKC&1BrTy;b>1 z$~S&yuU#N_uIV`aM_s?<Rv){AI!|2kH;*|4@|cN9^}QzWOk~`<M}~&oD^1B@U|%pJ z?w!m?ObG`J^_vq6A|ZRtPF-KGpGt>|h80M(xe3^m^p6-$p1%h~mfydtywn0~)pmTT zYfee{a<&1uP$zNhKm8SY;r4O3o^O{Cw!XEly}m9R+nJXEvp&d^2;bt;KqB`(tL*A- zC$68E1q!7A#}!f@uD-6lx#C}epc_3eDHy~dRua4?@m2$1-o0b>Son|^x2Zm2M6)Lt z$?aGeKf5p|++HGqw{_A#_wWqjDej2xU-nWi-UEYAh~>&!_qTuG?XKTqT_PvOd_6t6 z)T$s@Ia+wyp4z#+oY?T2*c_|h-lAe;y}SG6g>$DjKDZH+d&ahVy3HtfY>Qg;3+!G0 z>`k!AR8H;;yN4edog2<^NCa5EUS_ht<%pJ!Q)Uy+xme*5){%@&5X>&v8(FsVVRX7R zF5fX-IIqGXajOfNclix>lR%0tLjOwBHGn;eL8iW)dreI7DeJWshK|qc$&IFs<gHoV zEPDPW&R-{+jBpIiN+RBEUz#B%HVb}y;0<FD!kM^7$pJei*c4FyQh}pj)6I8&LFc2} zlsQyl*YUff;&)wq!mnTH^iR6aY5BdQs&%bPetp4jUtW57!*TH87J<<_I4xWC2iPLG zX%7r-`cXZ8=>ZqQZUe=XyDb?WM2YcuUYWJ6k2!;9bP=?~*#g4J)ULm+vaGgMLijZf z(Xq0Dh;(~N;lCIaYWkVA;bj)C@W&D=uC|Cg)Ux~nDyNUXrp!l$6Z(51AgKQGA-`XT z0nJJUMfRFtOZ;bOP_xhWx67+;S5)6|wv`v)+TIFFvF)G>J%d<?kF5UkCcs6kZEZ;U z%B@xZ6%SrY1H5~Yj4d3fH@nv}7nfTfH2O1a4M`=o4Bt^zUca@sX|uBu1^l=}7U_k- zm)*`^yZ;IV-^a?~EwB2Kv$-(xi0N5?PH*D-k7<vjF~NOY@!0$Z29sqRIa}(+Y0XPh zi(PH|V2?%iN}jk|N&8D2Er;uGU%UJv1BeaycBE%NK7+VNx#E$=IQIElFNU|HR#A!C zT;Er4wG#7rXEn8`BGJ2ke5n7h2aXjJcWoJ7v*19nnAaFok>Ryp?f_gAuq5$(MD|$1 z*Fs=IDLE60s^iYq)M5Y7cyKzIFkcX%7<(ym=wMnOBpKU%X!|}g%hmnfzU1N&5(t_B zM$vsZM1K*=B^sm7mO5XWft0auF^JmT->mh3F3yVku~jagAmS1M@iJg;)?k+ho&jm# zZzruL6520v0P}RNIXmQJ<EWyAz=D%WlK#uy9;0GJW}&ay{mrsbhb*%2=)%g=k3Z?@ zpIrzVh8ey2>|;IcALzlB(6a9ZJLhF9`6n~{OJ0CgvO4-$z`+Z~7OeFa*Hzu!`qN2^ zf1ehzs-j}DyIE2*eSgPK_k*_j`fn`qa)3U57jPEQW&1n!0ac#c-wap;GdQn@bTj0Y zGxMDnNo`N=+)l@>{vPt%F8@~K@6_`r0sZ|AWf#4T)Adi8>F<WWe*X=6FimaBKNb+b z&melo(~K*Fz^Ja%v?iXfHG6D@%?PCqh<76-i6PUCv2v}O^bIRz^v&<~Vjdayu%lJ& z^xVFBXvIM*+8*`@mbC{#oHq##|4#S@=ps_-F_{<TdNbu2$I&Mx@5i_6wilWmx;(== z%#}5*&rb#7hhFTxKh)z}ZL~U72piFi%I$5MDQKuG=1IskE#1>;)i|eSCB}2kcl!Jn zVQ^AY6_H55m$M!cWUS3Gt@sc&ld{Mv!C1;hGu0ayPqHOR)gqxc!gz8@E~oV&mSB4x z5hUy>4hRM$w_Hy=-5`&x;3h|jJooX@`I`JK+o2HW9ZP+|@|Bv8YZ+IO=fXL~kwxch zQz7&;OZ97`HCkC;_?+-2lZ-Sy*f%ApD)IA$Qvf*^F#jZUKu(E-&fVaaI>RX8ZAQ)) z>vAa+uIOJfQzK*Z6YJKtX?iy}VOx}j`%~PL#6>-mXw%tZPdq^&)XecC<Hn#6RF9jm zgEc$i{Un0HUX)K8Fy=)3?AsD_>yjVB?qokcC@W1*2U}z^NJkz=Uz{?fd<Z*buHtj4 zvoub*W-V);&6kM<)F<pF-S|iI#Wd}S=lSg2od<Kujgf4^)NDNm3g*F>j4eI;!=_;a zQO*a$TB&Ti=csBR1WbS9cVOkCX8lMxFf{C6Da>l)URy{lvFDDA<BegRO_IqR(o~yc zB9xg<;>{SCRj!geUTFOc9s~Z63gxiPb<IbUT%KZHX#0Xt;VS+#{Q3TeIq1{bYFhlx z_dsC#=R#g$u^i%rWXRXlCm?!;`d=J_+IyzL%CFuT!v0r>U^cKGW<&!)Ktn)70t;lQ zKPzTP5O9u#hJnd}&Pv89sscmK#!f*=g)IiGkl}$Y5HOGr8C5BRar6V9oCX><wJ}P= z-UvoyN&TO$&`?X2{TlrY>VI=Q(eJZSa=j<ww(<FB!uz;iZ22Dz3yl%Xs(M|Gy__8> zy-ySE-U-)U2?G>a=1NLH_@=<($fu^hhZm^HZa#pYQ<d2|H+-*W*6>9MnxCUt(8&(m zRJnTOcGAz%n>zSH&6z9Dq=WL*0YgfKm{=P|iY432`;pP@UM5AAFyR-)=GyC2_=@^s z8Cc21pvT(#i|pn($&S$@<<i#~u@Oj~`l;h6t2V?7%FFu{3sg$Vc^nD7`T+;}E!FiQ zmz}@aesdCeo#fAKkIaPm(IkUX%3+x+6;p{hb!JDA!pQuV@PoZRc*eVYA?=JTJRRyA zbPfuUxuFl%542y;OErBKPpMDd7C+u8FYmE0@Xtm>dP93CdCbPdtCizZ=I`dRs>(Kg z%6SIyJDs6+y#glv^0<;ZG-#>G!g9iXo+CWtc6KL0N~Dv>mXwtKK*<yR%9VQR8B|`3 zatO={Ul;8wFf0}5!an14cBc{J_(0{wcv<{%`-Q>X9iRi__Hjc%CvtH&#Ig_E!Mf6~ z>{;+Q4T~^An+O5|{Iy?Eciud;{bp}B^BJ@dRF76SKD9cu$7Ux)FLhdHzvcs<IV2~v zkbHS524*cx0GsWc`O6cWth|K<R7;N*-1_ScD(7V^GXm8cQgA1*u3xjAqEuOvA2ZQQ z)p)&p%dRTb!#|&F9C2i?_#3Podo*jBD|J%83EEq#C!s61_x;rU=4UJ6V4QZTPkb<+ zo<ZIC_Dl@Y{iJi)?t>03Z&ScVF)m=6zCm-Q*cj=GQBF$L4#`wH!G69oXTSA`=4J^< zYvcT+t4(<I3fbmxZ7n96#ZM%e4o^M3IVue1MUFGo%Uzn2m9)n@t>X*4V>o+Mz4|xP z&mh;8#pK|X37#%XJaoC^Q-2f@vG(MP*<-+X6$_t19x&T1K`9^bOsEwF@-vgfzf*Dh z0UG`V+Ex`Ee|W3B{Ka(VJI~2VA(+EyLSyZl5$!0n29d$k<*t$@^mq1t*=@hI6{^*T z%hZm6!%c6LRT^2jrFE8HY!_Tug^qrU{uuNdnP<@5*j8Id%-G!T>5YYF0a#|KO*W6O zRNO2@+-kGCjLk0_IcRu%Y66<&iJz`$OeUDtTk6`h?Xd?kGM^UOy^{o<LBs~_viI%8 zaIOj0(u9h}C{;bBl?;q>Lm2;;PWZpeED(ZK&{jT^YKz|7D#ajAh>5X-ll`gj0r2Ui z6|K~9Wwg4r^M;SdI1Z^%AM8oAv3??v@nxh))AHEikkZQ%uq`nj(qcu5EA&vM&ZV<z zhwsDV9}ssp4hHcd(fA<GYX7vZJVa7B`)KQB3r1`DZkot!JV*^T2Ni!lDr<2zJ+RLj z^%Xaq$B}xJvB!k3EcCjmz>HczzzFoWY07uyohAfUU;9p=t9uFC_r_<9amy*CkST+@ z`KBv%JyX!M)?$M?w>(5UW+c-rzT&s5)iJC1qCMrfgk}*u#AwM_a2b(KxW8m`V^HsA zP$cb|odGN9SG!JqObEHjCgZpgd&lN*JxB8>6W{Ro$W|tLXt2zCJ|u2I!Svomhazgc zHOwVFzuN6c*)Qg{BWszN_1uTun_KX+R8DBnDg~})D~tjmqig4lEzQ;3Yo{%mYiAr` za;Ysmz*OMKFzsE}&8L}E9VzxYql*HzKOva@8FVpQM%HTa3|h9qKWKSB>-+Omk_;b- zM2XrQk&23Sh|sY`AgzZzEpC2292ea^Dt6|*m1E00*5stJwYM?uW4a!^NZh-eu{I(c z9Xo=T^|{})>qR4939B^XHx9pGOqh1MUAUVAhut^(ny0{BQ$|o4U7r?FYU}`&Kv2jK zzW`dp5h-D>o$bUZ8wC!zCt3o2g>-|PKt+YNv2MuF03$hT##?PWdm7%rumSBxLQhP7 zBMc>l1tLRQUudHg?d%=veQO|80hTjoPCqf@7)oC~fR4s3n8EhOCbo1l7z5%_WVf&V zVMq6>TK6ezLA<s{*Y}$49gVfoj%-KBC87WQTIjqlA{Vl5n)?=gAM_gv-{2*5OzhTS zdvqbAXf>@b^wr!xzaXfhQMX0(%gf4F!BEzO1-|;(gd`aMqIK8iIMKwMxNElyVTv89 zTj(1!`z<PCW8UW3kb6;?G^C}}mJ#l|3?)rhYS**j;o-XI<A`bjX=s)EGOyq1<ITQJ z-??U`@C|<Ze&n`)5y$omHyZzMz0fumKNF&5vVq)oLFJ_URst4wq?FyRm-<oAnhjPc zDg=QLi-rscK{AiM<z--pzVxo&rs!G?ti1%%Rpsja(f6vV($W$J`tSeuP9Cp;q^%YC zrT>%h_Xa9G48{+df+hY^ofQA4D~f3&O%x6kZ{b{VfYl5uI<R<wgoc8Lgan@Dfj__# zJ#;cLC^T|53{h29c5xL$N5ApT6AlMVib~(#D;i+gBLeXZ8m;;&_euB-y(j*erMg}b zqIky6z+g#~<0sDVsI-D)AA>Df4xvI7op15o?2xIOBL?IP;$YF(`KmK=&Avf4pg|xv zi1X^BTVfkFp>kSKTUsNCebzv+GqF`yh<5C=v?Css=D|Y>{d`G|yfRk+znH?;vXI2i z#l<`LnRi<<Tzh3ZI&rOTha-K2*S1ZXQE}Jqp>bq;iml3;+S1OSozF;R`PNAn8hO;7 z`>TJ3Vxir`&{a;Zk~zCk#d^Ths8*ukbz}1JD{N)%gMe^qi|%dxRy<u3Cu%;}!_n$y z`N%Bk(0pO%?UTBkJ{U%O3|><-Y0Ka_Odw=fI3~zT!tgl+b>vl8o1CMp_!>g-q0_E? z!mrR*WOlwnM&pYVD`RptrPs*)@diRd4k1vVvmUh=AR*q3@gX@3n`?Y7x#(+TV=iAo z-HVUbk<4Tb{u@Y9iVCJ<!jgfK@0m=jJ_d~>O1h31(sH6wQm9u9ELJ1GL}nGtsKIh* zVuqvTJNfj)Lmo5@>-T5^Tj7^AaVj&d<LOvTaJ6wuGtXhjr$@cG#l6Z0_0-9QvIl<% zzfZeN_(0y0_YC5aD9E)Bxz05UB+oM>?AKVvS@0|`uXSiko@iR4G&RZy4z+}u%0EiI z%9FW}w%E!OIw!c&b$W3Oz4B}CC}y+VuDHXq9H;g5=Mp-Ctgtj<l_TGn0*xsV81BI~ zEbbdkY2%})C-fE%%Erekm+={I5yW0EuL4sOSLxHMjM7Y>K-U;4{{3;!i~FrotA)>0 zU4%-m+qx?Vt<#gsq=RplU;ADwwYM+uL>FF%3scz>L((l$evEoTo9ELeeDFql60LZk zwSg2G-_Ld3T_#T2%)jyRpthOU1+m*L#ZG(VhV!eU=Ux_1ZrUzOvZM3p%Ds1a96zOT zk83)~{$#@KTZ&syzOaAqB68`060w+j_qKfryt3y5d;xF;Xm}WC2$<i_0QdqFItCjw z8aWxOm?{h=yQsLK<2Z$iU*`!HM_i=@C8t`>snKtzfCM|mZMqJ;28`(c{-I<6#jU$_ zTxU~1v}!YNpWHTIwaVgEZQAzs-fYOt{8jK`qN79CqcQG2UNAGhVr0M8we%vlZeu(8 zi)6Z+*{sp9aiXK~MH6Z6UJl%65Y;RkLi9R#C|>0v>a<i(>r=XEhrUbcc2l2|*daF` zS8u+dSTt!)y8|#u{gH!3s%oXl?nu07lk3ae!MWsgiXFnt*lQ%LCEeajl~V<m3l++- zHP^?hk)&10@HrzpRbzhgS;Ns6m~=OJYf`-nnM*|SYubj6w$XyuV|6xlSB$F23I#1K z!v~T*u)9-w`bDb}p}TfP!BX!|qk4FrL1p`g=}ax5Cw;@<UfVK|rcyn)7K?6pY}qiE zm7<YzKe`uNz|5HpC=`x+^egl5asnrj5?i%*GA)t`4z|Q)8q^XYU&#u!LPh1&UWNL< zLAYTQ=!t-g7)R#sW`B6t&Ra9;5W!p69hMEj2{3*<CbgNjU16s2H3MdQ6=_7ul)(&1 zO{vS177!Q^f(i92SFm-O*jHwXQSie9^WX>yhJ#iMu7<2>U4>)QF8TI-Jpj22_64`a zPH2R7Y~3hQo@AiRYJZznVHQLd#Y<$x9!Yzw;diIdbCE9L-F<~>_DN*cT#<faMRoJL z?oCakv#x+n>?&2Me>wF^#eTNA@P?MK*GBtjFry5pK*`ZDb(B+XRVdUkx5jtsdl9z2 zkpPD(9tCSnE<C#cG0`tarau(k{?Zj(=MSFBSl{5N98VEBmn6x0nqSXVnBeH``C1b# zAcP%Uwrt&C8g{T1ZIi2<)rWgM|BJ^SP|OaNH@<mf7{{wVxEFV!@jsb;K{BR*Odk@+ z*#Y?{1zuP>#%ftqtaYQ^lKr%))MMX6Mfs=U7-kO{Ce#^b=9S|&-uWo?eCtLUx9`Vr zaXYvjA~8$IWTq(2_P3%REB7mdp!-c4qZR=@H-;_p852{>8^ghUizKkka8KmmY5T)| z&64D+Q-wZMG{w-_D>)eB7<1#?IsH($q(i{gmN$rb<F_h*3}f@n_l4<J_e!RIu}cjN zU7_cETQg>ympL7OOU=uxV3!SOcFBo1*pnFj9&UD#QA18wW+Ou@Q`dZnwYLU@7=YI; zEQ7Yj)(EyJW(@X)-PNm+yJwI^D#9o9t)tX2OpJQVC0&3rL*D5(&$~uD1AyYN+2FlC znzWj9nx{lycxYF@%vNZa1h)gP@|56cr_^p}*#UlGtdTgod(wIC$+Dhs<*dle7Qpw? zI$=M>%gS+d%W&;6+KNCiij0X#iag1(^EprgSw({*B%V=3sEx>L49Z;Bgo=aruGn3J zBTQ`@Fu`o=e%;Y~U>c3J2*A>=rq^LE1g+cM)18(#NeUEMiRapH6CKVX*=KL8am5#` zgfW(v(s5KrgG8IsFYs!wnt;m#$&OzHb*gh_#~EyHdDT6Y2MOJE4&#NK>C}CmHY$Ar zp%MhVfe*U+IW}EUu$aRObV^;#{>GLVb57lo-y`tal?Zw5!izq=8vhR=CD`5LcL#_~ ztfJDJ!63RH@UadMsyIre@ecqRuuWhnSob|B;B6Q_xbTsleJa&86Qz)1i+YzJSr4|m z!>$~P$~n7Snz#k)2!$>?wiU8qdVGVzkP(-Y+r031Rjzb>gQLuCGf;V9LMDb6N2tJ{ zb99KxwI5pqNI%;`u3>8$26Nsuaf(w=$v=bidjX7A)*Xg>*pq307{FYJcm;R##uWZw z6viQfI6>J2M7PiFGSQqkWvvv##~`V=By8Y?KXrkUg32T7o?b;iiUGo{LsVb@VGY*X z5RnbHv+VJkV0ZPOJ@3-fUWsCu;O+s*v*Q_rkck`WI3+8w>-Z$?gNTEJ%-ro+4OsQr zH4qQLLA&b1tu-P5O2QenVi7teWAJ|9m2CV5)7Z;rP&(CsA~6rLGSJIgiF8kX_MV>l zYX|dtNyRTn1;n!F@TZsf=qIG3vJ=msiWm#hA?mAqb?1WpYsHf%Cy9{RqtKN2snzHp z-qZ6dWdecow5U@kDiZ?{mIm>zj|shUXKw5wBDMBA^X@X|S8w+NA0CsTk;CmV8UjaU zyPQ<H3S(HB!V2lGpRjAsC2BP%F%Q!jv#W>LzL^Zl-M-*%7_uIeGj{8?4Flj*Rz66) z)l}Ws#jQ}=8DM4>&URt(9g082V0s3H>dWk|7|Ahz9>mARX#D{F_$E2!?HY-Qq<y)F ziCs{CK^2h@>Q#D|w}q?p4%Qgzrymp9<;(7Vn#tu=Mhv~>REv))6K{*sSkUP5sxR;J zuL`!meop54uJ>3s2Y9c^W0o$(#@K=<k?E%^*v}>#GA{ujZ-yExh3BgV_a5W3>Awql zL0%#1-NN)_D>vDrDx0ieZibk6P~Xtp=Gq5)`#3K?sxu20wULf~Kt-KBYLS@ou`KCH z@BS5Yh`yN{y_C>wa+`k@x>de2tFcJ#$Sh;=+V?{F)Ju5p+Koy0*H-`JQOhG{d5aNP zljH2uj`28Y1UcV&b|?UldX>F?*H4z_Ba3<$>&W|ON>V?ACcu2GqUM^1Odf<FoW12P zvNDUYX!yqbu>H+^>maIs2Zou%z`?K5jgzyTYkzG1gIf~KBDc24Rw>vbD6E3Sb5sg7 z=&=$1|DO29dsSQeB36|A?;i-G&>ts(br3)BgcAw^3IP@d8n`R?`<?&_gPa{24U>XR zOf^1-jFl5u2#KmV`Bh?3s>O*LalG$bJNfH*C#(qMZ7OJ~(pjsCQ68gr+-SFwQ65(+ zBDbfKQ6Gmn0;A`@(G&`4H+r00FVOaOX=iJL@7Dd#6``H&zM&q@YM`CdNwQwKP;>YU zqI5^(&bl3RDaun4oR8d9T$*@*;|)aSDn!YAgWL>jd8^(J0iGJts_CSXpq$OpW_yyy z#^qImdEb}Tsb?zCZcdd;;??T7J8gDOtFj03M~I;4yQdp-q0J(`pSEiI%ctD}%{LbD z?TfWuPZ1ihCBr30Z?J0(PHabyjz--H-`qPM8dNHq4OOSTW)_Gc^|NzYRyI<iocBu` z^&zh{jFBqdyL?kqDBuLutK~RDoO;yfv@DH$HQHHS4aND1uVb~nl1gly18O^<Zxepb z^E7jLkgxmI1p$vMnRyk*f&iQu2dduqgYvs;V8%`4tp``v9YJUU0hs>xZCj3tBkG59 zLW@pWJCm$LDntT~-NLbt&EyrvAI7|mpFwXsf$5f-XW85!7SH**-9L{v*9HsWloU)` zb4HFG_qn+_^<2UFFkX#5?IU|oP}^s9i{2LzPdYU>n>ZXw6J7bV`%(oECdbDu)$<+6 z{PdLO+-bMGA!6IDl=qCwxTYC>TEfO}30@6|-ZXc6KkL<;B5J?7aIVf^b5~}Fq%qdX zBhVbbLXT*8b}-K)!0P-~fc0B*wdGtpDfH4#(*$ahlRL>sPN<9S>$SJooi=FY&=f~P zp@^={F=j`A66QpH+GS1E?a(>|Ec(_Cf1tI99!7aEcXQQwooq{ZbCuJjSrV!nliNLQ z_^aHvHnL2WxR4aIbab;z3i;b|j*o9aqsM+NOs!FQT%EQzW;<>}iy03s=5#g7!APMS z)ywW4dVc>e{qUzdbT|-k=VT6e@py|<aW)Uo^djc=46?at%)a=E_wyTBff|p5SbU~@ zfUS}xG&aUdJux*a9vj*ks=}I=QaSYbhlHi6>W#Ka%&aqEH8q~43$?Tj>Hc3~b=6!x zm5B3hGcRsp=^zZF;H1~kL8E<hpcjjcteh#Evwk&8pP;yQfT6X;s(Ak?6|>VCP3ZL| z4DAf3Rk&f@m)^(M;wM)Go)Z4nq)K1e54hK##_wz&5|@r7_L|Q)Oyeg@ucb4;XGJ9u zy?>AJ46;t_ebv;1rUe2XgBR{>9u>bJBP`)rDP|vJexx-oYSm=SzfwdSx7usfU{g`h z+t$|BE$to%w-XL8(OQTqw4ATfA;4rb3CfAFWEwwGqeUaQiq%ziD=vJ*Y5xTQ%Mymr zdBK&L2uZ(O^;+?b^e-kf*m1<s8rhyX&9rW-xN(k=`qi7KBvr-8xZHR48FICsr+zFU zx#BD2ua)J73P(^{7wQexA-Q$sF}egdo<W(hG;PwRYue1uER+yLa(6r1o}X(Q*Jx&l zRu~Vx|DLgwwV1K2s2lzr^kvs80LNw_D#z6JtF(0Si2NsUrhWVw(@)~fI(l>oWVWri z@4{Ur3>@9&LF4>~54l?1rag<yW@F+h<8qS<t48BUG!qk4+(DU!t?Jf(HFP}`t4mxj zXe;DOjM5K=h&a<_2|vMqxvEPq<866$7%B)U7-RCt{Um4iK4j8u(=1&atQV@lg#rx{ z`ZFw<*i@Of`XUwzz?%s&g*&FgmQ2-FbtvOb?!<U<OJ{}phull@F7z2(+t>6)6;!^V z0S+)ab#ohZWy~0dp$Wwh5mN(d$U$b3C#n{5ILjFC=xg3WL&DZw8b%q@I5f(#VgqLL z9XCt>O9vxY@<dIOEV!cG^cNGtYr2C9(aRC2D(`fkm&jYF`NspVMO%`v6SVUsbR)T{ z%(%M-15$R>O?iw-B4{Qyj|w{#>V_4t6BdmRU>nfztyq2*;j%WC=7LxVr|-nH;1H@E z?@QCz&DAR=NaWp$QCu)pefbTmJJpI5>)z^Z!=9k<(5P5s${<mt5kwh(;cGt97Rqny zmhgi}%6&q_n>fRF@V@+nsW^i2MWpNdcPsT=OZ6W(>A7;n7C#tC3z#C<EJ|~S6c5Z- zZ30Jd<aCB~Cgo1AwCTLytZ?D14t}QXOfcs&w2s>NNU5WIy*F!g@#p5o)|{{6jP~11 z8$p;voQcv}7W6{%j<^<4=fLeLmX@~R{!AsgR8_xg+BXu>65O*RBJ0_mrZc$TC{`aX zm9(&1W%a4bQ}G2^W!ap27ggP7<FrK_tryuWFF&<Qu`t^PkfdWqTqIASSX$G3+fu^+ zVr{@|j#douitsLu@ys`4#^joNB)-pQ%QOlL=@)MVN_ExRBV*YDgYq<Bmu@y-yTD)i zH+F$tDqK9BL!>#axK4VXBps)2Ax_Zsm|Vh6<8ODSM@Ujw+kxhWb=7WKhF{yN6GkF8 z9QN}|3KHPCv6bi+G7A}EumhhI@0r3tWyMs=(0#Vd&K~+{@_`J(ng#D0{DHu62EARa zn$zuvI7C3O0y3k5ps{xVn*xtO?48|1kOtDAp*B~V30Fh6F14`@V+voi3%9x}+isN? zv(m3ftRb78PHmw&;STFR`ipZyO8ZU*dD?2y^_9-TMO=);jUHwSX|7*H{rEkuXw81x z7NQOmMO)psak>MnS`?K@kUlPryg?olL>e~~$@dxGU(=RJ)fOA{gM&*}-nldJqkHR_ z#cQxEE5*DM%%p`Vq010_rIyPOI>rb!E{E)Eu0LMG5tx1DZdkCuD0&)y_bBH4suRW( zqLiP#AK#NKV82z(g&rnOa*^9;D!M4~0#*tFnqA@UNIdo#6kVg?ljw7z_V}`l+<`oq zv}w?9aEYF6N9JC@PGB0*FWSNQxO(^N)Gw~PH@rwV?G<61KQj{R;7AZ@t2+7EFrNl} zP44h=P4s(c*lKLOS4skaC8z#i{$u)m_r>BZUE_CB#nsq|jCU`J5|r}r?$fT3!h<Kh zQYn^y<Yy9;oAg$q-%6EzIfE)qUdAXuSuQ~ntA!%%Ae{2W>yY=!LsX=Xwm-A+EK#;B z*t{9Zt7DSvTBt;7nHDhn6%3(V(CUlv1x?%&?#9=AT815qI2@*%s}QG7*$Sn{*?D2` ziLy;Zu{}Qccfg@f?3?Ar=4UZ3!dSB$Yb=Z5L{a))TI1vTs_0x{u$N{}`$alCd?K;f zC$05o&{Fg3?(o6xy&);Nz=2B*;@l9#(FDSBjZ#&9F|CHFs0p`X$=VrRwJ*N&3wErj zihkQjt`S%HydeaxGTgdW!rx<aXNTzaF&!PA=ss~$aZdP^1eV4H1JCxLdE+(<=L=9! zU_V2i6;=(62-u}70#O**Q+~Yz?zRS7f2xqLW+X}`LdCw(REHiVp9mk4!o8q@y|QM_ zB|-$_cbxj2t^`6YKp#GSS_NcG&m8<_UE0`;*ef4<U#iiF+VubQ3A0lf-y)DHL>mo% zRa|OmVuut1%O@>Ok`mO{L55l$r9zt6LH~^=6)OF-S7RxIbM3%g1w9(D69N(j3L1FP z@YkCLbPzdkH&J<l#%f6B7}x2SBdRjKcKY|O2@&$AQK*ehJ&Fb?2N<A)uVHrprHdi( z4G1Xk-_Z3Sfb!pNRwI3j()^;me93m!u>SHss_DS>sokkwKYDfc$aTMB@$Rv2*_F_T zKwPni{rf%k`YyIn+j@o5gCbBZ;Dhp`YFGV)wARRYzn>zpCQB}b-3RXX=+5(_Ag%lt zsCv`Y;?~cg4+eK~^m1p?vT9K{xNbLunN0`W$NmfuatqxC@;`<;-~4=Bz{EV8#F!13 zn5x}=9h0zGl<n{g!nS!LXa;k|eT+(9&d7No8-My{kbt$2okYNX<J&vhfvpug?)}Qe zW?sjE(i0Ch4tf3n@{LyC;7s=;K!D1{2ILafOofb6#K>@Y3m<3-%UsWN@a%_$*c~N( z5PrJ{T!_7w60%AfH6M_5lAq{Dthb|DR$c{+$j4hlc)eK~-QKWke$nifcXY}AzJfue z)Qg3FPv)!WSLxGTY?-|E%Ahk3L_;-EB%+kNFOkijU<eOox4-9WJMQO?rg-=)?->an zYawv#m8UI=HM(m}CBEy8_&B{@uXiV9Z^}S7Hg&P)P24&P0P0#gv)DBM*uD4qW&JKg zpn6m9KIeLS^SC8%3To@ewhJZqAS2$2nT#R?AxHyz0O;W5cyszx)Be1jUPD&O@odja zUwORy%ZdfzrxY3U$@F7cZElqqyk}5b%+%o#H=xjJ;;ofx6mCx;l4nq|w&1+l5VH{4 z5d(~gUqs1n7nvgbOCL^XfA>P!(Thn?dV{bRY0)BJ9LDu#CKl1*DD<>q9nyL8qjh~a zE@=`-9*#_XFs)69UsO+3!xJeB4(o+Ta~78lf&Qk93r$Kel{IgL!)S!7#y`6_ook{) z3hCUI)et5JMSUDFm6Zy?seST7A<bIZ0Yl7QTJK@<(Y`-t&Lz%lnEw}geLyXMnWO?T zNl+ADw6}#c!XcpSip4rfoQU(?uB$z(jp`D#Zc<Yah>ZO>*o#&PD{TzJH(t8BVewnP z-5{<%Nkc9(482HnIa$PB!HLVcu0`hyT+Hf5aPug>e}4(;LXbn6hK~>#)!0Qvq|PfU z6;_U=I#vMzu#FtdJ$(CkfrcK}DTINm6pKrgNw;jIF&X}Jthmy$;vZ2GNl9O){k2i# zeNfz$P>jz|EiiAl-9S!!TqP_4sDP!n6(p8xn-l6`VA%P^*b2QfD^IcMb^Pq{55x|+ zAIQ>ko_q_x!L=d^uriJuxpBX9Ht2r!DPS>A`{h-wT$3l4vD<cleAa7cNzaL#^dES~ zwOA~2;pmolaiSd~x=x;+0H3ahWU=v_Wr9O@UpHL!3F2dDzCknOycr;1D{&QKwKBWI zb~LXCMDDg*!DkX6wC^l0CV)$m5Qd@7{dsM0=oG$#O;l#RQn_(St3_&F!Ut@%hH?bk zR;OsV#3$(f6D+oJyeAaE4Tzh|$;H@K>elzP#`;g{1zhG1SEML)3=g+wPqj>A*6qL{ z;|34uru-)HC3GiA`+Z`P6YyM8u16&De~K{EEbWo-(II?0(@tZ>JK3+tgiEr#-U!}( z`*5ju{;To-cJ;Stx#Jy3%1d3argx=?os<mHy3mp25W=}dSKZ>&H2d%zN)X!Q*}r%f zUr=zS>nj%r_9R4VsHR2E?rpAoIgDgollY9Gnm+x_0ijtl8J5B_E;^`Hh@Cy6W9%r< zk4RlzD!K8a)v`(zhl)bha34LH7=r>GIz}b*B<l;aDc?^}I^xI(!<H#fY)H!3H{lL! zDdX|d!B)Jru$HmD$F!ER;=ANhVd!!oS4hE>@?qU_se!b@GF<9I$Ss7zqkPR4De@rL z+m95~W_~5ZgbY3;RRZ8h`AaesiK!zTGv;GNX|kS`p(NAS&Br3DICTA!>!MCR9bW3P zqTKkzELz9_az7eS&O9<Bq0P8|u~rBI+vt;}Wv-}dB>uS3P?&<;ddBCkx&_A*By0um z*4QYaH-d8G1}gl!sfg@rC2=RHSNo*&UAl{&66H{^*9XpDO(#iZ!Pfdgdn6h{z#H{0 z+pDH>y1k?`C7gJPpdIR|cB}NkuYK!MxonaE24rPwwEk!=S_UB*<mYGoHe1a>%uu8D zo2u_SF#~)UA}sbb4C^;?)p_hyEjr2mSuY@K$}C}$NrlQ(W#h^5al2f;e2T(z5;;Ur z!RRpx>7Yu&>tN3v_<XuqWshFQ$IVqLp=W{kD|Thr%OeyBeU*!O*pRx|1l2~HIVLjc zHMHcNdRDAl<!rK|*-VH@J+ND^s5v=_PCY7cd}<7#EUQ1EvcAltLzvfs2VRM2%fr~d z)f&lO2tvop3qmG;p+M^!|Kmp*9>&i#k2rYVP8iJkp`s&MHrCP7(hU4QKL}R2hp$bS zJU=lt8>2a_oULT22D@s%P`;E2#4Azw>{6P)zr%a4rUso$!!Oy`Aa@Z4V$&fIPf?gY zZKtDyRK-+~d5;uE^BDwsN0JMUMy|U(5~2|4*a*G0Da=|s+ZV*DlV%v|jOtn|#vA<I zqDzWXr{XJdtSFaIU8(q^yqgo4afJ$8qqnz($sZ~Qt+I<zEK$2(z$fDKRX$CXLB0yk zIhWO$m0V;#mChxat?E`;_Jov8$1~2v1Ch_3jB=eTEzX8ITwkAyhe#tcz3FTP(bnMM zWq+BJlTNLgKa|tsq{FYwq(S>;v~K#bWrE@=9H}bjMzQbWDYQT$%40}~q5@lryX1A; zOJ)HT)e6Eubes7?Q7w#du3`0XvtqN=kaerWXAnMWUFO@awMt3SiW4!M5h*U{xWN6W zwUTO72<xzj*Z%P@V@*$@5QP)B`B&*vHn$Z+-bw$?eDH-BbA{9CxG#|?B$so<P!Km% z{mMRs%R%2-$W^AZcBT4SbAQHwp2`vZk@j8bf)&1u!{9FUQ0MEkM-&?jVSHE#o;CtO zIBO4%iU{r(bu67C7#@VT8SorhMGeDLyyl1M77)Cz&qHBT5QveMO61|$+OXFSmOW}d zBL3pJ`3jBIhE?iks;ep4m-Jl`i!C@KxP>!?&yZP&!|z%ONw^FB2WOIs@jT`4oDe9< z3Bs>b$<Unl--`CO7yCraZTOPClPhXln4^^HMbEM_cK8<ss8;sN$lTY{Oe8Wob`l#N z)Yz1GFlsHJHH`U;fv?qaJ=HXe1e&aSrdzjfgL6VzntJZBIuKCc`?I^gWHR?RoQg6U zzYgup6sU@oUpLi69mFC%Sx=c&L@?th6dmUB*PvQNSEyktL36Q#ME!m#C@LBdTAD~* z8CRWdFJkqcEDX(zh6LX|Um!Ph*ec0?4*{bqQiM}M^dz#p;cdCS@7%<f<S+j0M*C6N zSnLp9;U*9&vg0hKIuI0HBzwf*C84ts9t_>USIizrY2?l9mzcsXHT`^#DtlBWSE)4X z{;(&NXW7&8je(L~!Ju#%l$Q!9dM_!ffj`!`Q#CavXMp8o6zlPOWYUwR>dB#aM3<06 zTKj1AeGy}~B(bs{ZUlo$)S=}W^l9_si(;Ay_JQRm4M!{FAFPPvM7wApQGDl_H9z;s zsZbcSXqRoGz^q$h@UqI;sJts+yR2=n0V$_zTrQCW4eQ-^hpy;M&@aigAVd+_et}%) zh>0DTxuC$OB1$FRNz~IIq!$5#W_MD;68_pueIi#O)`j5^Lkj^L{%TH17Z8vl`_*@a z4`FA~9y(S0nFUf(Q_yNOG<fk-jUN;n8cpO4=%K}*jHW$u%8!K^KIF?rE7k^jT8p+T zn4w_c02!7x8ocIdiW4KJy434cfPYE_C)gK7h^8_&H&3-z(<Pc^I{(!#v2Pmr(+!KI zA+zzo{XzIoxu0@tz`cPVPy&H_18AV21NR0PK>2Sse-;+ZL~bc1J<w}G)&Xuye*d{6 z2>eC_Enb%DUk~a<+q(aJ$ZY;=A8E>et&t^){+~#_=lfUUaRdL~q-3sj2mkc{o0Jki zk!!=BiT)xbhY=1t%JI9~U!)Y`W4#U^XMPX-iz}nSUZ48=4;Wy6{*Yoq#|CPAYHz{a zev_hR2snINJ$zcZ0BZh_imp3+DnX53J*)x-{vnl3S`X+swNs=XJmqg%stWb@EU`fa z*LNm=(ULLpUd?}Nf4stS_%|)iSc8Lj>BA#ern|pssR?*sq=?kKgsb2Ci&Sh(dz}=2 z{W+WY{eO^}ei$_IU){$m|MfR1Z0~u>XOO|+(=70^@^4~sp3algV2SE$zWm`UVaTWA zLp!+UUhyx!WNjbTww{*3Vgg+JmQgTknJ{b46J-?$+JDo+zqblQ`k?y~82J}t@#sEZ zM`4PAP4qSPn|~3LseM|MpJZTqx`p|hGpfGT1D!hCr+Hx5-+;mWX6nQQT=N(9NMNS! z6n@wI!JaA#41CL<n!nU2Bl{#8`KRVD?7<ZN<M`Vm{!v5qp6g%Dv}j<Pb5ijjtE@-Y z(Khwan*^bzpEB6Iu50JXHDT7Lc6I_|2X>Mul4pKrfz7RGtaf(4ZbmVG!sb2ORlZYM z#Ji5Gi(1s&yzq3{%7LBZnHcXM({}X;*ps)3i?RTzD0)Lrwzp9Q^13cn6ce`804bSO zNo|9M<8NOlY&C%zfD|kL_eKn&0yB+t*_z)+<-i(ey5*nqzrI5#js8gxu$VGSVgKTD zb&G2M(g(Oy20wp52X=EoK)}NOz0nca>4?rojt1V@1#EGQ%c<-XJ^7F458yqHXiti! zRr5A=x=cw!{|hGpwPUB-u8mKEqq8FYsS7(d=K^}qAQE%y>^?CD-~;W02DAkGvn0M= z#R}0Qe83dYdqRXS@Pak>aQjRo0E_bgC7^dYQy}dk!3Il_68`=uv>PTRY+wT*7MYV$ z;3!&0Lt9eP)4}f;dFa%u6X6+bA*KJ8oq;_1K^+*0le;nvId_NbjnquO<cNIe)bpkm z!p5bA5g~<H6+#s{pXEDL;_$Hr3JH1UH+TCap!2?)>K4}-)6p4m=t~ZP4{uL~51qPn zcvw{1S(3J4;4%o2-&7_u_8lqVjm`?b9I}1MBjd!)B-Pp!{L>Ms%$O5Cak6380T|S& zvryz{Tko`2*QRU1;JUq34_Q9zgc^ekj3eS+Iub;LvC-i!!$sF^z!^s)3}N0TCBX-{ z;Iq+TW~y)8SbW|5foY<7(XHi$Acuh7iQa*W;`ei_JX@p)+vctvxC~g7QN_-WY`_q^ zy#_A*61znmhoDh|))Ab}HgurYYG&JjIKo!`0dbdX79N=Oqb|;J!&oPx)_5mJ?HJ68 zPOhGu+u2Nme_u73BNv=70x*dAQe(f8nO{-Df%%0hwC=DDZI5ae?5CkXbL%Ypf`;$` zijhyhPzieR7v9*Z+VQZlB0C6rf*UdEQ4YU5GI7gF<SLM>Zi>k*LD<;C9)9hpEFHkq z*y{#n{F%G!2rbVuQw{1-TWt0oX9o3y!BEg7UVAklY=Yso<ISobS|Bj<1PKr%pXzsh z0x?J)$AG!Tdcn3VXe*saqud2t;lXgIOgWrN4qM*@yEZ-`@9~Ew(<UkUIaPI%IVqsu z^!>x=wn_UcMrT?57zOV<zeCNqMt@p)%=_xrZuNA{H|31`<+zq%;F_6W!_@mm8fxaT z<law1zKMUf>QO>Jxc^n^Xx&%+vvLRTZH{p-8ipktsEl2=tKjlaw=NN)XKpFx)+sjc zaD@G^nI+1<K<5nl0QUW%6UIURE>?xDApTeG=L@(rY$)7`&w4*mlOK}Mbi`PiM;}}+ z0~+$?`R?wn)8=;Hl+9X&&+fj-;k%uj6urGoD|8b2WFiw{u)0zSIfE@wQndGl6Je%5 z-N&Q9@B`CR%LcO%Y@bcL^h4@ROv<sjL3=1nG>G`XdLf1|)v~wMN0Q5Q>&T#hV*4AX zhC4sNP_*cH{pv%eeoXtSOd7SMw{pYDo_(3+p)jnKbXGRWG&WrOQN~uk{BAj&MBUSN zguzTjy=#p8*47LQu`>M(Ki#AY0CVt;`)+}h5W&K(fyb3W;VvrhUFNUza*l>)&%1yj zM&qzT=kuJ9>-#pf+CuBb?^`8G+1y@oWv&G4?^~~5H5)W}*@IOPiT+DoW2d0|<Se6T z>glR+-cRV_{xbRN8O`^Li~EdVkzRTFwUQx&Z)&ktJQojrKZw0kemZNqZD!e3%aoHg zpyO9PlAh7G1>U~RZe4@kl&8HSl`Ux?{3tPtgr6i|-`9T73X$I*P|Eo_Q^a$s<Mad1 zW16Bf|E({}>bd}b%*1L6QuHcnL(oo(r^lNkbB>>9&!D1s0Z*FgzH~mV^GD1#L2$=e z^~jWC_tY}HZ)e_nKWtZOeYxFQdz+vZ&9r|<U5+T!zHG-|;qfs^Du=^>{APyOIPG#) zY1xR&iciqaTxl$OchxZSn_)dii?e!eR+LSd6~TVxg-FHyQW<W+wJv(S)itoI331Xo zH<MwBv~l#Sw8onnIpvVHmCUQNR{vNib8jdhUcq;gR88~kojm?qtinF`-xN0TEe>5M z+!C}XdarlpSI%U)pHx0QP$v}q(q<4fiaT%99}A1+C#AS~b7bZ=^Q*OuD>_QikT2`| zGsu)hpETGCE-PDjnpn$4i0eLIb#m;H+MH{4QN90*SV=t3Li=`RPQJ63RlBw|U&IHe zi|Pq0eXP5Sy)`zJ;?+;UvI0%tGg7S&>$J1{mY8m{y<GMy`^+Oe;{5FX^(c1E#{JHS zAN(mE;3uNR6rU88+FSC2n-me9(>|>oGw94)ewmV{8|rlW)-QKlm6x|g@tW9YXKFN# zzWEvCQlVM}!m=4X$ur44j_elD>msX$Ub-}Rvj(MPEjaq5wS&<zuPh{6ILrU$exdvq z1KqHPI(-{O>j%%_fU+i!m}K5#Y2B-ggw&(t+(w>9_nEc|6*-rJg2%~;JBjgDA%?Z+ zkkqYbkouce1Ladj9kZA!kpsEfT>*1tkL&2K7B&Xn2G=c>eQ7a5KAYPYaK|y5VEg^) z)V`)=Zk_smYbcpnukpY7RWUl1_}!E}RUu!U?tkF~?hL#UoBq#6Yy{x{r~G+S08Z7w zs{%tbRYx+`->G{1WbIT`<v(^_qdkN2`DHX;e=^nn?|dbCi1sNz+%^n8gR*(>Mb5W3 zXr4YUnLLBW(j&9ac{xx%<_Gao?Fv=Zd3b7$DO)+qOnJCa2)F?|tHHe@_fUueefSGO zD0%z2sUZh-u$%%1aS{-oF|rR0&md%QpFmH%O_KLYhKpq9+19pWKdnkX1X&MLGD7u2 zW=CL4dbW4+;0v5VRUq`?jTX#$af>&y`y*Z4$1_RKN@#^d4<xbvDBoOtuOOP~^InB2 z3dN`OGV9Kc-ECCjQZO6~>uJ?+pyHLN&gFd?>we}Uhz2q%O4#2j0B%*C!QO0x##22J zKkvNXsD&i7`<q)wAQa12OX_i7g%3D~l;Um)jtMRFPyJNh?s<OWcrdd3F*mP5d)`x0 z+V6(*W2OvDIqdThZ!Vb}byz|W#3C3yX)*d@5Q<e8bNFqs_0W#HqI#*&zU<C|{#<FI z0`FiigFyWgtq}y}f~>w~iiZ~gmqO4y1d)@`ndvT5X=MvRkd;Wn{$*+C10Zu%!szAB zZ5S|ZETqKXyv3-LO^{3C`dZ>+kSf;}yeM2rUYT!1q{b`(DXB8#8ayW(BJY5L2J(d+ zW!<1MJF&ERx`7)&=W}+lhGa7D)_K{ZO%?p`N9XM$QN?Jta^42cVYv3<Awi`6>tf~? zme)1k$Gt!12UB#;9xt7kIFZ$}ISaQ1a?9*U8@qQW3rzuHewIaf24$T_uyNF1*EN$@ z!dDUzS)F49>SKS0?{n<keMw$0KF3Ct!kXplO$Jg!neeDW8~UWuMyxuu_9Ar6w_ye* zgxk9A2+$8X+c<`-ldp`%D~{;?L_y)#UmWqGAcTB`llZ>Q-yfUMBswH2Z^Ad@24lFK zsL+$<6^5A2-DpQG0c_|Z@6<7p%VhdwULj(PrfG{8X!GR)%U56Jp<=4|9T0)2l)->$ z1r2YJk~xRou!1cW)5yguB9{|CQ5kyazW%OZJHV2iAO^f|J81Z&uy#0zgQ+!zq5XVw z;yxP6iuJWM7|rT-oDZ3HgnA$@)j<;(ML^n1BHl2%LW7<lcVd@E`jj>Yo!G-|FgbpB z*L6r$6T_J&tl|cz`d(k^qN5c??hu!*mHMbUSSz;{pROiOLk7xd3Uh<x5Cqd3e~*rr zPZXbIS=EJp;|s^G>=!or7Sh0gs0nlS+$F6x=2$}|#R$rV2(xH2dg{!7ix`Z)j3h;N z%0+O$?qL9@fQZ*RMaCXjTyOYF4!%ceZQp#sKvrouCqU<MiL|POB3uKovFMtt+O()K zH%=WbJ{~!gzJ1*shKkBUJpeg97Se`XZUq<gCAhpn?C-QC2%Y)wgdR2L(Sk*DhmTAs zdj<xJeR-Rd<ECf=(u{25;?`Q|{9cwx^QCO5Hl{~r4nuT>N>acZaf4oE<(*_{X?#VI z8Ff$=qkAD7-GN4wNUdbH-NIh`qmFGra5K8GwJ=X%;p2Bf`^h7VY9u@OIAmv2*&+T( z7cj$E#i0l=c=`6D!mc#$ly7t5szi`4L>$JT5(L;Tq?!U12T&;ox{H)H-$1+dE{aPo z-B@tuQ9@>YZhG<}_7_D_9lEbaRw(_500kjIabMIhxD5P>!4C}=(m<Q-jx)Z!?6J61 zyvI%i+C5Z@Ng^cN3;$$blMRCqXGG6j2NLWBLMZwm$XGFTGgN}6HLeAN9U=p%fvuJS z4}`*;u<3%Zxt)@3V&cxE!#mO9&XxtXU`a^4&%T#LbR`1jwK{hpt36kG6zGIxaMXxs zEKV$qH1BuJKsd-pwz1z5Izmwp&B-dDep|jFm46Ik4v92s^@1Ct3Pi@<aaRTg7fB}R zx^VIjQrVvnB3@GPIQ!RB+9Ow=KSPJtQ!;2)WIX{h1`$EU<w%2!_|Q}8Px>Dq`Y<dg zG(;`2SZF@8yOW*(MtP+LA6F<`jXfR84~0Gu+1nm0@H0<aNK4@=fZtqlc=+`D#Ksd{ z!{F-20~h#VyNc-7Q~DjtVaVU}A(e|@10iv>Wi_)_SywlK_<jP<)L7`3pi~y;XtH+m zw#%{NiZ}izJ6W5*7ng#G9{MVXjE~`-MK%;EjD+a(x;g@swAv9b^y>~3Cq9M7XAtM# ziQ@L$F+LIm^<)W81}H`&R~tGJq)Y=>sGN#K&mW2zXBQnPR_!vER}hMS6JC{;2Gh-P zLFN7mv-7^5+iq8?PjUK@41zi|nBp@{9MpGKMu!s1sX9;tmHIJl2R~~EuD|IW2C4~O zwHYUd7QJ5@dVC$Klq5AK4^*m&0?{kR>5ol07*f*q0<Xcd{}eao-ZySSWc8g5I|+lC zz+lRx^M+3#>rQfxF$KM%F5_es9GJm;a?&tN6>5|fhaMD^@Qy>Hf`g8tg~GEGhS2NI z`a)c5r>O*yVh~D3*g`ZE4+X{J$Z?Knh-UQm+%*OU<i$r+aVDe>PeX0r77wDR`~iYL zhdx!pqZ6dwh2ITBF@fEpk%axCU;9dQaHRi2^op$yg?Go~9r=29y0QV?kZ(`IJNOXD zLwIqJ<bu1qA{>w^QPm~uELhD^pcaOC6$C!eYJ?K(J@R}a#}(%HE)0u<wnUSLCl7XV zFb^ACMwmU(0F4vtC0hqzn!!gR=R6i<A-;4lcf$+3QU#Eu3VpvR4js$Se;|Qj|4H7$ zuL?x@#{Pfwa-Bg<23tFX&;us)Dj`(qO{z$!h9V|_N|7o`FH!_45_&@KQbZGaQK~2) z(!2B`Md`(WN)u5L;zhi7zB}{H+?ntDasTYj>^twy&U2n~&YrVpH$M`gjCl|<`}}H; zehCLZg#qSL=dx1%Jz&^T*gAEZ?FnK(8^GPK1d%@+cvcImEG1?#VC~&3$+$<t@yZ1> zOZ?*J;Z=Hx+#|Y1hO*kV(qY$K%F6Q1^~|pVwi~%~7v^0&WUq_R0Q!|PAj*j=Eu*S~ zGdzJC#Rh|24HO4)E`1I4nkyiW3;m3GOzI_($k+f*bWG0LW_vgUv#N{3;F$Lz0mU%> zG@Tz*G($P`0?;rd*5?2tSQm$dvIgk(^)cEX`%SR|OFNd^_9UGeg5&tLc!a1x6z}0? z@`7)TZQ%^C6@@{?VQLzx^aq`3y{S(wLcViP%3L-f?;{W-d3bYJ@9;OaEpcU}WDd5e zEpU(lqwgUiDzbh9nD4G_oA?qV!RdkF^X63E&xNlLbHeICdqJC&wbbE4YS48Alm^3c z8@>D)ub9hF&9ZdM!NZi8t2frG>nnY!UCp{a?CwjfG)yT8s7;$K131Kf0vS>v)~Ofr z+hB$W?RTJ?kEQ&CHE5PjnBM=p5SDhSVx`3^V+9A@w(-)n&{T>xG2&BpAiK}~rE4W< z!32G12Vd@~%9#3YjU5T+^uS(oF!jG#`lML0^GulKMjPfXPACBViscXg@dD%m8>Wa2 z)!1K%9XVUSPdV9Aa!d%DihsiI8{loUK1g~3p-uqZBk7CCt`}%gg#^Q*Z&Nui$b$SR zRWhf@6wbM-MlLxFMS1~W-UcTO<Va)B!@?@s(j*N;!8;W`%CS&}C>#_{lJ?_ol3Xr9 z@Mt0n{X$^}#0V;=rc%Q$weJ!rn_-0@s|jAS)v0TeA?E{;`45Z-HYrkK0)RUqmzcrY z36C9=faKInfQaqw+c~b74$9Z(7QD(u8pD;^ejr%)U{NJvE@8`Y?Ta7y?qM4vr0JSu z@9PDJ+%ZXh1h_>y=bY%ienvTf9>BhBebrLrF-C?r$e1SLc#ElzjYvvsV{vGEgrY&I z;B6iBY-?M9l9OK}YN51o2c&i&wJ?01Y(Jhnoi6+;oiEie2*{qVC+P*bUpWSdzVKGz zs9upnG#%6~-J9a8Axr7}juY=t1as8VT~!eoEIiIShSb<)e|Gn_Kn;PAW6d_BCD{6{ z4u2Fm1Ss}esXHMXU|Z7zS$+CK&v!It-9{087eHP?++EKX2COj1#T_J8&gRoeF%J4f zGz<G&i#rkmCo8k_KBl)P;_L^dr0+$FGhsx!t^jyyy}q;~Ww1G3&R^rq0f<uViHHX} z&E?>(Z=WwcJ$P5VDrnMB5Ze8RQtUde7Vqkx|KA%h`-O(Y@at24RyY4&&3R1dR_MQ~ zoyf`mRy+N@OL|uAWVZ`JkHMt><Qow+?WljNb~+7VN<0DKSE-B}F0r&PRZ6kk3#f=_ zzjdB=W$z|i?0;jh6{ANPN0^SPBZboWTeFV*JeHUbuvGuJ`^s<G?KCv%nE#(|t5gg# z5mGB91H()wvA+QypPZIDVIP!nvCaO-iElNdh<eDo;`Qf064xNxy*)&G-hLU@Im_}| zFX4hvj&8pklV^{JmiNomdY!>B;oShsrrnpJAf(mYZ$L=-!;kHL-?qP8JJ;>wx!<7p zQ`b6+jp@6dMtD7EW1U36Wv0r-wq=h`9kV;pu2IhS-K=(!^iw;~nU_lgRBT_I#^+5@ zk3gm5&p;11QmY}wGT$~CeG#ciO&4qdT4m{;zlzf(B^wha_S7$`R&yQrlSn>0XKVfb zoJ9%zV%AxewU=}RY9`9Oo>{=Z8qcYJTjJTo=z|~L@eg(13WFr~<1S7Fu@NemxEv-I z8}mZ8S+|=do^1P6r8v*&A5+~PBg;BeFRWSJj(kj%dp*Cn00D6bbV7w)CH(0+NkPqj za8>Jxud(+&EYuU*<%vC?P*lx1^{f&8@X5}|t~GbkR{Eyhw*PmfKez;Wm;x&&_q0(- zJ0J054jR%<9-GFxbf+gQufCrI+FA%2@chzYjMw~RxT$c05@viCuYfHPdhb{F_34zk z8+%hyx3KVsk?$IqE8auU=cQ}kXql|<|8r`$%|5FG^@XbSYR<`&@ZW$n_mk60B5_jV zrK>nC2+D-X-h|3iV*)J7sUzWja{njki0=Xux@3F}CeK5Wix||1nPA_(tk!Y{z*s8; zrqX1b!XjJwLQPeO+3x)O$JU;O^bCoZUP8_x>&)osOD-Q3oa$z}tR||*+_0FoR=0=c zx312#0K8gbvve9Y?^{|(``);5IZy}2cUx5XVcOmmbm0}Zj48IGp%VqVby8@{;u$$z z*jkoHNSD4j+h!7YcB*z($BR4foW})+?;3kvkTMJ7&2i2X4+-Sf6f!mVaOd4u6e~o! z!zQbU5PM%YG(SNv{ZRU;eHx0D3Y#KuVDFv0%69nU3~WVOaIe4CSAA{Mfu@6CLU<5| zO}+)QZA8fY3GWBtZ<9EdEYee(?fE;!u5l{96RI+sF@utaDi7<9hys?3;DPR6q35n_ zpFR)d8TGn~&asY)kQdKaaQHM<#D(uSz|iBP>4_&X)A0Gae)+S?n}olR!A0*_1)d*m zml3m%NPP?PXB)+Lvi{<FQAV+?Wq<W$MX5-Je0n%gui3IwGZ`+RPrOAM87cT4I{oTQ zDQ90n8O*0oh)I}%l^Yj$Q5l1vKmohaOW#rqS3lbDT4_l5B#*NN_kNsUw(RR7a;vmn zaU}c^>eYbo!$QLOScp;g!e3nP=!mh*Q;N78DlmRNH%(ywd^vCtIVtJ?;MMgWcHx?g zBS8Wswc`BzH`YEZnC`H5tEg)}Zi$NSM+pQ+!<dyTm@_S-8OVq<H%OZOc>u{ngob|n z=OQh1IId?nx!hy2&5k1c;vFF*h*qus2D~xTF64QA@=cpti@KlGc1#uO^imsTYx7dw zbZ1&S62c$sII0B~=eCVb{Yg=H*l;E#el2t#N*FEmC4`qiTEH6VCeF294xAnRkcG2W ze8XXjpeA384mFgf(~6r<m`jvRI-w^n(P|%_8JZxGe9W!3?sFwaykkb(r@F=5HIv@{ zzWh<8PO>d&v0>teU@e>+cv5pz03C1Zy{o#DNE$g~-QB+GTiK6Wvk3>$PA{uo7VXn@ z>KS(TY3Cg|{)^T}w;>noD)>G7b@YyTy^s7KhCDe_j{bHU?)aw1{)B>fK5gt)Ae`ss zj{x7Eni$cD0Hh1-%0`Z(0k3rw*$r|r<On-`X_nP#vNEJhmPV;1ogE9I^c(#6-JpM3 zFkfB0JRz2%Aq^-0>yRS5rE~7g6n=iWtD%<1TPz|OL*+2U2BSFHe%Lz}DG*Ehs;Dd| zu|Q$!%V>&*>~yy3#ptSiRIOIS2-@qTh8*uNljX*WUOZO{fbls8fEV`JbAI(xN(|!b zmouAqm@E&79!}~x*BhA0Mj?Tz4vE_t_mt0KY?sLU%A158OW};<bpLkqm;6)F>o|_I z?mMwu3awM-L>y!5HIjS{WfrxR-OfI<Wv9S>`ODY?r1>2$)z_#%#BjLprH|_8a}ks` zZDMN`j?+z_wpSR`eXIJ*mN{KpO#z(2<?E%@OGbQ@K@1-&RF=eEtK~WT8XWKVLg|~< z_=cYTd>CB-jZJy@B64e*GLKa1C72~8HQbW>XvTRG4UOzDu6^4y@^`}bF!tqWCUj8% z*m$ls&#hmgzaub5fhbd$m%BmueBJgw_~AzFz);qS$a?79`u><s#ci0;yHNS8N+l`Y z#chH;#*U8tkxeT)s$<Q0@0j6CsH<vWO#+iaNu)JSrG53PB{C86>xB{t9#wxmT2SMX zvg%lG%1O{f#j>&Nm)WG{zmDda?^p``=gaR)`<(sETQWn{yUv7oOo>~X@{ZtjjMB}N z@`h)`sDckrEVi=szX1cNREe;S7wy4i^=7lGwj{;>?V^j7p@Yz<XNCo4ctrbr>&Q<Z zA;WB0hyJwx*og=)N$uw>P0IySjNj$FdbYmJ4ap473O&m2`m)P)#@>;K;>tzo#>_NS zU#;??vY&f69W|(sB1W%BPAy7Kn&jV)M{DLBn*A$q@{t1LlUdp`9BE8Ranr7mgRf<x zF{nP=(rsS9;+zpGugT|uVce(Z4pXJrZdkSDMn1YNxqDUXc=TmBMT+VWEwC71{(&%K zK@dpREZ6x`mfNA{asci9ncueRMfoCi+zB_7mzSR?+5s|&TS-e#EvD5EMy@1R6RHB0 z%3-><pbPkT#VYu<-22^pX4+0d9>(qVrfvSOIyD!oZBH`JkBuT7L_qrGAghX?jMzvr zxu`A~?MS!&8nGhWquUlUB%Zw0i)sm2;6q{tdy4E#?xwzL{tz<fOW_(V8HcVXdug7w zkKBL&EJhwTBMs9B+ghWJj(7j;bUv-+Ouqs$H5c66$;7Kpb+q2a^U~`-2hx7Fa+F6V zrdU53*cdYQpswZ@9JPI=F5fY|XB-?B_x&+C+BBX5D~>37W>wKYB5Js4J#fDySrWyZ zB_HNj>CEN0A^zF0YdFn@Lb1z<Eed8Q>N=$y9_tV__68<2n$9EE9^STTI0F=IQ)*A} zYBu(<qX4E;-!g+05|hDX--Lgm!DV(nGHSS=C6=MP6^7w-g^Pg}U)dTtz&kgj4{K4j z@Sz@2GAc>kA+9JK-9@}0(W+J}e{r2L;sO7dVy7O7bsCcw|Hxo2if<n|By+2<sKxFv zn1h?v#C7sC!5#4~GP+Bm>+u-A$E&&n45|qs)~rlKSwxCkvx>TD=9tPs9CBV*2KJcC z5!tqI)2aFs7a?+C_t3uY(Evfp%^NlG6CI_6(vfb}TCV9_90t@~{`qS14bu`6bIC$$ zk-_kM;OV{~=TTS$fUBrcg3^UjH`&yf_Kxe;*E9D=m_(9^R#S+s;PaWneEWYscUZdf z`q+fr3&e!+D{ho0=VKNQAbdds;>3Ahn`*|&q%{^<;6-M`w6}-2mm!*hatjIMhSGBL zdq{<eLUN@7t)SYY>>XZgDcONY31pNvHyf&8*z;oK2EESfB1xJ^=Ac7D2BnxcmqOXK z>#;Y@n)}(3`?WA;G>LCzbl4^<`6TwV_b)|_`F5#X6~a%*ILyAAbPqS--yJ3D2%a)b zp7T1AN&N2n8^XT<0nWbx4TQA)G+8=jb(Zt%b>veK>hkVzyNGqCx5Ly@%_v0#6X~g` zG9yT5fd35{qMU}OQywsf26&8aFk=cEM9^YhF{_JPF-?fRN_*8w;S3H|+h0U>3o?LP z;FB|I5`7cX#tQ%?4l3L*vaB#WHZ=M+hrlhtXet2O0ePcGIt+@Ra}h|Uvu4g!K<e#| znozpO76WY>4Usk6qOz&gv;{>fxl;C7)*S=GoKyH4MTLnK@#gL-rk$XrLhO$M(A1OC z4@C2+rl3)s7tp)Q;Cwcji(rQ$U9^HBQqP?;oItz)`R*nt<1%j5CJ&*}=ZqXBZ~snh zM-YmkD75Nf_(7J%KxlXQG!iF7SDqh90*c&{q{!+6trbY-bm`->Wvw-IP0*LToZ}QS z_wAq2>|h0M(EkQ#IvYl?<WnckcB>_f3B+y>>}*1e`&j8z=Ws1jZw%Z7o*8o}3#b~i zWi;dX9r$J5y96m&-=&4nz%|%jUxj6gdW)!bxdbQ0H5Cr_@?~Y4(Cnu=@}Yf`Z4?OQ zH@@7dFo-X4FT<_y#L_|_I9ME$gtgLT3=E=yconPI=>o62)}&!LfoB=Km2HM7T5zHn z(!8X<L&?~4(H*J8IKd%0mb&@g({AUFu^xVchJni4m@8t#u|^aV!W;EzVVOI7hV*R^ zBeHkJ4Wr;lRNhKVy*5z1`r#Lo)DDqG)&ZT8<?%#O?LXG8?y-lS+nD2($hHdtal*#V zLE1DrU(~j)y|eihVr&OR#wYIO<Uq!g`FNrTT@cLuEAkn=+bsZVlpN<+^&s371xHQ4 z0dVMZ@N`~GZDHqim-7UK2|9Wc$1T%2OZ&3bCiI=)Pt9<bh4M$TGQm9WC;flXLSB8* ztPMxN{Nua98H39H{L3UKTNW~(Jp*z)K1f1H%4l0#dvLe``>vo%T2PqD03f7gEEgNX zM-%(mC{WEEc_Ci<lL>}e^YIMvVzRUupz;~nx6eP%yxl|}g>aEBnNgpw5`tU?*ddu8 z-Xn`_FaR@zJ!f@@a=T3p<)kkz&;!&j>(x0#KBb4v%C$Rcs^8J$Gc|;`gK?^8eaf4c z6+r@S=;}*+B3Ss?o(pO%Ut2^R{3ENdB|Tk0!xa}YH75;m$rhYpr1Wt~=M&JTG<<{< zXX75-IIS9{L}^Dr1B$$Z(NHQ?MeX<WE<g)2C-IrV>rGS*l!<*{cTIXD0Nf!VD){Yf zd39>njJyV$vK%|nX9EIJ;i&pD3Ow*F^oi*L><x#!lQ~W{LhSgh7Hb^RiW5jCI-85? z<WK^XudR%@TzPz8jWCC$IcPu;d1+8qx^#{nAw1pG?q>N)OidOu6A+R{-!<e4S3KzU z41XH^8?Y{;?zMOkjyJT+ofYrc_!hW{d1qm!x&1sFo>Ewbu%!MFvUurFB&ou4CBmgm z|Aq1}e<|5vvdPeUvisD%@T+M^zQN20T0r~<vlkP?%e%8s85segs$*-BA=bC9*Lv&= z-ndnHZF?H&cT$gO9LuY1O*62QxhWDn9yG?%fd`z~DzGVd6<eDP7gvjHNoE;Vq<2<I z?>m?EkeVO<gkcN{v3)2`x*!PbDMgmm6fVj$FazL|axJbZ3iEY}qSjIADl&7v62B<V z&FY09kleVrgdfouc5*E|IK|WioI0pqv!%5~i&(p=-zdsdT_bI?81&bmPpItJYBJSB zK}uOv_iA+=^&dGpN;ZFZ&nB{vR-nbMCoAM8oj@;5&f#E*XKXApQMGCp;?feyEAMcF zm<g@LF|mm{$bqVP_C4I$O8LnjXURhvn1zh7U*A;31A6UG4>uid(I+DrgXKRk98$9$ zQdrqs6cge~udjV8%!<Qf;Q0ZJxtYU~+6(l-DxXuLlPy@s6Zny4IC^;Zoa$YyAl<By zZq*P|F|`0hWY8lHUS#^FXgTubm3zt+Zzz3$U>MmI_t5n3e?q`Ju)KaAW`qG8c~p4} z3BPfJ{<=-;k5XG*vbnR!AcN~6D0%Iou0DX~l}G4XYA75L#whR~I|x3-1J&al6;BRe z7mIrRycx(YPj9ibf0HV;p?Ru%qw<`f*8{P*p<C82|Aj$O5}A08P!fXCoIaF@NgZ&u H`91p&b1yL% literal 0 HcmV?d00001 diff --git a/examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc b/examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc new file mode 100644 index 0000000000..b24b0bd97b --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/doc/src/textureinsgnode.qdoc @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +/*! + \example quick/scenegraph/textureinsgnode + \title Scene Graph - Rendering FBOs + \ingroup qtquickexamples + + \brief Shows how to use FramebufferObjects with Qt Quick. + + \image textureinsgnode-example.jpg + */ diff --git a/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp b/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp new file mode 100644 index 0000000000..67df392555 --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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 "fboinsgrenderer.h" +#include "logorenderer.h" + +#include <QtGui/QOpenGLFramebufferObject> + +#include <QtQuick/QQuickWindow> +#include <qsgsimpletexturenode.h> + + + + +class TextureNode : public QObject, public QSGSimpleTextureNode +{ + Q_OBJECT + +public: + TextureNode(QQuickWindow *window) + : m_fbo(0) + , m_texture(0) + , m_window(window) + , m_logoRenderer(0) + { + connect(m_window, SIGNAL(beforeRendering()), this, SLOT(renderFBO())); + } + + ~TextureNode() + { + delete m_texture; + delete m_fbo; + delete m_logoRenderer; + } + +public slots: + void renderFBO() + { + QSize size = rect().size().toSize(); + + if (!m_fbo) { + + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + m_fbo = new QOpenGLFramebufferObject(size, format); + m_texture = m_window->createTextureFromId(m_fbo->texture(), size); + m_logoRenderer = new LogoRenderer(); + m_logoRenderer->initialize(); + setTexture(m_texture); + } + + m_fbo->bind(); + + glViewport(0, 0, size.width(), size.height()); + + m_logoRenderer->render(); + + m_fbo->bindDefault(); + + m_window->update(); + } + +private: + QOpenGLFramebufferObject *m_fbo; + QSGTexture *m_texture; + QQuickWindow *m_window; + + LogoRenderer *m_logoRenderer; +}; + + + +FboInSGRenderer::FboInSGRenderer() +{ + setFlag(ItemHasContents, true); +} + + +QSGNode *FboInSGRenderer::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + // Don't bother with resize and such, just recreate the node from scratch + // when geometry changes. + if (oldNode) + delete oldNode; + + TextureNode *node = new TextureNode(window()); + node->setRect(boundingRect()); + + return node; +} + +#include "fboinsgrenderer.moc" diff --git a/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h b/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h new file mode 100644 index 0000000000..42e10aef6d --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/fboinsgrenderer.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +#ifndef FBOINSGRENDERER_H +#define FBOINSGRENDERER_H + +#include <QQuickItem> + + +class FboInSGRenderer : public QQuickItem +{ + Q_OBJECT + +public: + FboInSGRenderer(); + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + +}; + +#endif diff --git a/examples/quick/scenegraph/textureinsgnode/main.cpp b/examples/quick/scenegraph/textureinsgnode/main.cpp new file mode 100644 index 0000000000..8fa6f6814f --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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 <QtQuick/QQuickView> + +#include "fboinsgrenderer.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType<FboInSGRenderer>("SceneGraphRendering", 1, 0, "Renderer"); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/textureinsgnode/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/quick/scenegraph/textureinsgnode/main.qml b/examples/quick/scenegraph/textureinsgnode/main.qml new file mode 100644 index 0000000000..6f6d7d1c1a --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/main.qml @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +import SceneGraphRendering 1.0 + +Item { + width: 400 + height: 400 + + // The checkers background + ShaderEffect { + id: tileBackground + 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.85, 0.85, 0.85, 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; + } + " + } + + Renderer { + id: renderer + anchors.fill: parent + anchors.margins: 10 + + // The transform is just to show something interesting.. + transform: [ + Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; }, + Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 }, + Scale { id: scale; }, + Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 } + ] + } + + // Just to show something interesting + SequentialAnimation { + PauseAnimation { duration: 5000 } + ParallelAnimation { + NumberAnimation { target: scale; property: "xScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack } + NumberAnimation { target: scale; property: "yScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack } + } + NumberAnimation { target: rotation; property: "angle"; to: 80; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: rotation; property: "angle"; to: -80; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: renderer; property: "opacity"; to: 0.5; duration: 1000; easing.type: Easing.InOutCubic } + PauseAnimation { duration: 1000 } + NumberAnimation { target: renderer; property: "opacity"; to: 0.8; duration: 1000; easing.type: Easing.InOutCubic } + ParallelAnimation { + NumberAnimation { target: scale; property: "xScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack } + NumberAnimation { target: scale; property: "yScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack } + } + running: true + loops: Animation.Infinite + } + + Rectangle { + id: labelFrame + anchors.margins: -10 + radius: 5 + color: "white" + border.color: "black" + opacity: 0.8 + anchors.fill: label + } + + Text { + id: label + anchors.bottom: renderer.bottom + anchors.left: renderer.left + anchors.right: renderer.right + anchors.margins: 20 + wrapMode: Text.WordWrap + text: "The blue rectangle with the vintage 'Q' is an FBO, rendered by the application on the scene graph rendering thread. It is displayed using a QSGSimpleTextureNode." + } + + +} diff --git a/examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro b/examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro new file mode 100644 index 0000000000..238e20a553 --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/textureinsgnode.pro @@ -0,0 +1,16 @@ +QT += qml quick + +HEADERS += fboinsgrenderer.h +SOURCES += fboinsgrenderer.cpp main.cpp + +INCLUDEPATH += ../shared +HEADERS += ../shared/logorenderer.h +SOURCES += ../shared/logorenderer.cpp + +RESOURCES += textureinsgnode.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/textureinsgnode +INSTALLS += target + +OTHER_FILES += \ + main.qml diff --git a/examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc b/examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc new file mode 100644 index 0000000000..9ecf0ada1c --- /dev/null +++ b/examples/quick/scenegraph/textureinsgnode/textureinsgnode.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/scenegraph/textureinsgnode"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/textureinthread/doc/images/textureinthread-example.jpg b/examples/quick/scenegraph/textureinthread/doc/images/textureinthread-example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59134e07c482e16597a72dfae9cbe36e33a8378e GIT binary patch literal 33269 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 literal 0 HcmV?d00001 diff --git a/examples/quick/scenegraph/textureinthread/doc/src/textureinthread.qdoc b/examples/quick/scenegraph/textureinthread/doc/src/textureinthread.qdoc new file mode 100644 index 0000000000..476605b268 --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/doc/src/textureinthread.qdoc @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +/*! + \example quick/scenegraph/textureinthread + \title Scene Graph - Rendering FBOs in a thread + \ingroup qtquickexamples + + \brief Shows how to use FramebufferObjects in a thread together with Qt Quick. + + \image textureinthread-example.jpg + */ diff --git a/examples/quick/scenegraph/textureinthread/main.cpp b/examples/quick/scenegraph/textureinthread/main.cpp new file mode 100644 index 0000000000..e415d254a1 --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/main.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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 <QtQuick/QQuickView> + +#include "threadrenderer.h" + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + qmlRegisterType<ThreadRenderer>("SceneGraphRendering", 1, 0, "Renderer"); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/textureinsgnode/main.qml")); + view.show(); + + return app.exec(); +} diff --git a/examples/quick/scenegraph/textureinthread/main.qml b/examples/quick/scenegraph/textureinthread/main.qml new file mode 100644 index 0000000000..4493ec46fd --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/main.qml @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +import QtQuick 2.0 + +import SceneGraphRendering 1.0 + +Item { + width: 400 + height: 400 + + // The checkers background + ShaderEffect { + id: tileBackground + 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.85, 0.85, 0.85, 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; + } + " + } + + Renderer { + id: renderer + anchors.fill: parent + anchors.margins: 10 + + // The transform is just to show something interesting.. + transform: [ + Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; }, + Translate { id: txOut; x: -renderer.width / 2; y: -renderer.height / 2 }, + Scale { id: scale; }, + Translate { id: txIn; x: renderer.width / 2; y: renderer.height / 2 } + ] + } + + // Just to show something interesting + SequentialAnimation { + PauseAnimation { duration: 5000 } + ParallelAnimation { + NumberAnimation { target: scale; property: "xScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack } + NumberAnimation { target: scale; property: "yScale"; to: 0.6; duration: 1000; easing.type: Easing.InOutBack } + } + NumberAnimation { target: rotation; property: "angle"; to: 80; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: rotation; property: "angle"; to: -80; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: rotation; property: "angle"; to: 0; duration: 1000; easing.type: Easing.InOutCubic } + NumberAnimation { target: renderer; property: "opacity"; to: 0.5; duration: 1000; easing.type: Easing.InOutCubic } + PauseAnimation { duration: 1000 } + NumberAnimation { target: renderer; property: "opacity"; to: 0.8; duration: 1000; easing.type: Easing.InOutCubic } + ParallelAnimation { + NumberAnimation { target: scale; property: "xScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack } + NumberAnimation { target: scale; property: "yScale"; to: 1; duration: 1000; easing.type: Easing.InOutBack } + } + running: true + loops: Animation.Infinite + } + + Rectangle { + id: labelFrame + anchors.margins: -10 + radius: 5 + color: "white" + border.color: "black" + opacity: 0.8 + anchors.fill: label + } + + Text { + id: label + anchors.bottom: renderer.bottom + anchors.left: renderer.left + anchors.right: renderer.right + anchors.margins: 20 + wrapMode: Text.WordWrap + text: "The blue rectangle with the vintage 'Q' is an FBO, rendered by the application in a dedicated background thread. The background thread juggles two FBOs, one that is being rendered to and one for displaying. The texture to display is posted to the scene graph and displayed using a QSGSimpleTextureNode." + } + + +} diff --git a/examples/quick/scenegraph/textureinthread/textureinthread.pro b/examples/quick/scenegraph/textureinthread/textureinthread.pro new file mode 100644 index 0000000000..b48c2a1863 --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/textureinthread.pro @@ -0,0 +1,16 @@ +QT += quick + +HEADERS += threadrenderer.h +SOURCES += threadrenderer.cpp main.cpp + +INCLUDEPATH += ../shared +HEADERS += ../shared/logorenderer.h +SOURCES += ../shared/logorenderer.cpp + +RESOURCES += textureinthread.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/textureinthread +INSTALLS += target + +OTHER_FILES += \ + main.qml diff --git a/examples/quick/scenegraph/textureinthread/textureinthread.qrc b/examples/quick/scenegraph/textureinthread/textureinthread.qrc new file mode 100644 index 0000000000..9ecf0ada1c --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/textureinthread.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/scenegraph/textureinsgnode"> + <file>main.qml</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/textureinthread/threadrenderer.cpp b/examples/quick/scenegraph/textureinthread/threadrenderer.cpp new file mode 100644 index 0000000000..90b6b49880 --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/threadrenderer.cpp @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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 "threadrenderer.h" +#include "logorenderer.h" + +#include <QtCore/QMutex> +#include <QtCore/QThread> + +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFramebufferObject> + +#include <QtQuick/QQuickWindow> +#include <qsgsimpletexturenode.h> + + +/* + * The render thread shares a context with the scene graph and will + * render into two separate FBOs, one to use for display and one + * to use for rendering + */ +class RenderThread : public QThread +{ + Q_OBJECT +public: + RenderThread(const QSize &size) + : m_renderFbo(0) + , m_displayFbo(0) + , m_logoRenderer(0) + , m_size(size) + { + // Since we're using queued connections, we need affinity to the rendering thread. + moveToThread(this); + + // Set up the QOpenGLContext to use for rendering in this thread. It is sharing + // memory space with the GL context of the scene graph. This constructor is called + // during updatePaintNode, so we are currently on the scene graph thread with the + // scene graph's OpenGL context current. + QOpenGLContext *current = QOpenGLContext::currentContext(); + m_context = new QOpenGLContext(); + m_context->setShareContext(current); + m_context->setFormat(current->format()); + m_context->create(); + m_context->moveToThread(this); + + // We need a non-visible surface to make current... + m_fakeSurface = new QWindow(); + m_fakeSurface->setGeometry(0, 0, 64, 64); + m_fakeSurface->setSurfaceType(QWindow::OpenGLSurface); + m_fakeSurface->setFormat(current->format()); + m_fakeSurface->create(); + } + +public slots: + void renderNext() + { + m_context->makeCurrent(m_fakeSurface); + + if (!m_renderFbo) { + // Initialize the buffers and renderer + QOpenGLFramebufferObjectFormat format; + format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + m_renderFbo = new QOpenGLFramebufferObject(m_size, format); + m_displayFbo = new QOpenGLFramebufferObject(m_size, format); + m_logoRenderer = new LogoRenderer(); + m_logoRenderer->initialize(); + } + + m_renderFbo->bind(); + glViewport(0, 0, m_size.width(), m_size.height()); + + m_logoRenderer->render(); + + // We need to flush the contents to the FBO before posting + // the texture to the other thread, otherwise, we might + // get unexpected results. + glFlush(); + + m_renderFbo->bindDefault(); + qSwap(m_renderFbo, m_displayFbo); + + emit textureReady(m_displayFbo->texture(), m_size); + } + +signals: + void textureReady(int id, const QSize &size); + +private: + QOpenGLFramebufferObject *m_renderFbo; + QOpenGLFramebufferObject *m_displayFbo; + + LogoRenderer *m_logoRenderer; + + QWindow *m_fakeSurface; + QOpenGLContext *m_context; + QSize m_size; +}; + + + +class TextureNode : public QObject, public QSGSimpleTextureNode +{ + Q_OBJECT + +public: + TextureNode(QQuickWindow *window) + : m_id(0) + , m_size(0, 0) + , m_texture(0) + , m_window(window) + { + // Our texture node must have a texture, so use the default 0 texture. + m_texture = m_window->createTextureFromId(0, QSize(1, 1)); + setTexture(m_texture); + setFiltering(QSGTexture::Linear); + } + + ~TextureNode() + { + delete m_texture; + } + +signals: + void textureInUse(); + void pendingNewTexture(); + +public slots: + + // This function gets called on the FBO rendering thread and will store the + // texture id and size and schedule an update on the window. + void newTexture(int id, const QSize &size) { + m_mutex.lock(); + m_id = id; + m_size = size; + m_mutex.unlock(); + + // We cannot call QQuickWindow::update directly here, as this is only allowed + // from the rendering thread or GUI thread. + emit pendingNewTexture(); + } + + + // Before the scene graph starts to render, we update to the pending texture + void prepareNode() { + m_mutex.lock(); + int newId = m_id; + QSize size = m_size; + m_id = 0; + m_mutex.unlock(); + if (newId) { + delete m_texture; + m_texture = m_window->createTextureFromId(newId, size); + setTexture(m_texture); + + // This will notify the rendering thread that the texture is now being rendered + // and it can start rendering to the other one. + emit textureInUse(); + } + } + +private: + + int m_id; + QSize m_size; + + QMutex m_mutex; + + QSGTexture *m_texture; + QQuickWindow *m_window; +}; + + + +ThreadRenderer::ThreadRenderer() +{ + setFlag(ItemHasContents, true); +} + + + +QSGNode *ThreadRenderer::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + TextureNode *node = static_cast<TextureNode *>(oldNode); + + if (!node) { + node = new TextureNode(window()); + m_renderThread = new RenderThread(QSize(512, 512)); + + /* Set up connections to get the production of FBO textures in sync with vsync on the + * rendering thread. + * + * When a new texture is ready on the rendering thread, we use a direct connection to + * the texture node to let it know a new texture can be used. The node will then + * emit pendingNewTexture which we bind to QQuickWindow::update to schedule a redraw. + * + * When the scene graph starts rendering the next frame, the prepareNode() function + * is used to update the node with the new texture. Once it completes, it emits + * textureInUse() which we connect to the FBO rendering thread's renderNext() to have + * it start producing content into its current "back buffer". + * + * This FBO rendering pipeline is throttled by vsync on the scene graph rendering thread. + */ + connect(m_renderThread, SIGNAL(textureReady(int,QSize)), node, SLOT(newTexture(int,QSize)), Qt::DirectConnection); + connect(node, SIGNAL(pendingNewTexture()), window(), SLOT(update()), Qt::QueuedConnection); + connect(window(), SIGNAL(beforeRendering()), node, SLOT(prepareNode()), Qt::DirectConnection); + connect(node, SIGNAL(textureInUse()), m_renderThread, SLOT(renderNext()), Qt::QueuedConnection); + + // Start the render thread and enter let it process events. + m_renderThread->start(); + + // Get the production of FBO textures started.. + QMetaObject::invokeMethod(m_renderThread, "renderNext", Qt::QueuedConnection); + } + + node->setRect(boundingRect()); + + return node; +} + +#include "threadrenderer.moc" diff --git a/examples/quick/scenegraph/textureinthread/threadrenderer.h b/examples/quick/scenegraph/textureinthread/threadrenderer.h new file mode 100644 index 0000000000..f12e6404e5 --- /dev/null +++ b/examples/quick/scenegraph/textureinthread/threadrenderer.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2013 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$ +** +****************************************************************************/ + +#ifndef THREADRENDERER_H +#define THREADRENDERER_H + +#include <QQuickItem> + +class RenderThread; + +class ThreadRenderer : public QQuickItem +{ + Q_OBJECT + +public: + ThreadRenderer(); + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); + +private: + RenderThread *m_renderThread; +}; + +#endif diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc index 099c7eb443..40d77c3d9b 100644 --- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc +++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc @@ -106,7 +106,7 @@ during the updatePaintNode() call. The rule of thumb is to only use classes with the "QSG" prefix inside the QQuickItem::updatePaintNode() function. -For more details, see the \l {Custom Geometry Example}. +For more details, see the \l {Scene Graph - Custom Geometry}. \section3 Preprocessing @@ -140,7 +140,7 @@ type. Below is a complete list of material classes: \annotatedlist{qtquick-scenegraph-materials} -For more details, see the \l {Simple Material Example} +For more details, see the \l {Scene Graph - Simple Material} \section2 Convenience Nodes @@ -280,21 +280,19 @@ needed to perform the rendering. The downside is that Qt Quick decides when to call the signals and this is the only time the OpenGL application is allowed to draw. -The \l {OpenGL Under QML} example gives an example on how to use use -these signals. - +The \l {Scene Graph - OpenGL Under QML} example gives an example on +how to use use these signals. The other alternative is to create a FramebufferObject, render into it and use the result as a textured node in the scene graph, for instance -using a QSGSimpleTextureNode. A simple way of doing the same is to use -a QQuickPaintedItem with QQuickPaintedItem::FramebufferObject as -render target and by calling QPainter::beginNativePainting() before -the OpenGL rendering and QPainter::endNativePainting() after. When -OpenGL content is integrated with a texture and FramebufferObject, the -application has more control over when the content is rendered. For -instance, the application can create a second QOpenGLContext on the -GUI thread which shares memory with the scene graph's OpenGL context -and drive the rendering manually. +using a QSGSimpleTextureNode. The \l {Scene Graph - Rendering FBOs} +and \l {Scene Graph - Rendering FBOs in a thread} examples show how +this can be done in an optimal manner. + +A simple way of doing the same is to use a QQuickPaintedItem with +QQuickPaintedItem::FramebufferObject as render target and by calling +QPainter::beginNativePainting() before the OpenGL rendering and +QPainter::endNativePainting() after. \warning When mixing OpenGL content with scene graph rendering, it is important the application does not leave the OpenGL context in a state diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index caf60dc30f..efc67c0437 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -909,7 +909,7 @@ void QQuickWindowPrivate::cleanup(QSGNode *n) scene graph and its OpenGL context being deleted. The sceneGraphInvalidated() signal will be emitted when this happens. - \sa {OpenGL Under QML} + \sa {Scene Graph - OpenGL Under QML} */ diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp index 27d4ed413a..818b9b26aa 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.cpp +++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp @@ -284,7 +284,7 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D() setIndexDataPattern() functions. Whether this hint is respected or not is implementation specific. - \sa QSGGeometryNode, {Custom Geometry Example} + \sa QSGGeometryNode, {Scene Graph - Custom Geometry} */ diff --git a/src/quick/scenegraph/util/qsgsimplematerial.cpp b/src/quick/scenegraph/util/qsgsimplematerial.cpp index bed1b710ca..ee7a272fbe 100644 --- a/src/quick/scenegraph/util/qsgsimplematerial.cpp +++ b/src/quick/scenegraph/util/qsgsimplematerial.cpp @@ -142,7 +142,7 @@ the unique QSGSimpleMaterialShader implementation must be instantiated with a unique C++ type. - \sa {Simple Material Example} + \sa {Scene Graph - Simple Material} */ /*! diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 48927ce5e1..1a8c69a474 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -232,6 +232,8 @@ static void qt_debug_remove_texture(QSGTexture* texture) If the texture is used in such a way that atlas is not preferable, the function removedFromAtlas() can be used to extract a non-atlassed copy. + + \sa {Scene Graph - Rendering FBOs}, {Scene Graph - Rendering FBOs in a thread} */ /*! -- GitLab