From 2be6c85b8023f41d964c4c9d45343368b26a0830 Mon Sep 17 00:00:00 2001 From: Paul Olav Tvete Date: Thu, 18 Jun 2020 15:32:21 +0200 Subject: New custom material example Fixes: QTBUG-78577 Change-Id: I280ffeda4bba1a9c170feb1ffa4b6c95eb0e6d28 Reviewed-by: Laszlo Agocs --- .../quick/scenegraph/custommaterial/customitem.cpp | 267 +++++++++++++++++++++ .../quick/scenegraph/custommaterial/customitem.h | 113 +++++++++ .../scenegraph/custommaterial/custommaterial.pro | 16 ++ .../scenegraph/custommaterial/custommaterial.qrc | 7 + .../doc/images/custom-material-example.jpg | Bin 0 -> 72603 bytes .../custommaterial/doc/src/custommaterial.qdoc | 104 ++++++++ examples/quick/scenegraph/custommaterial/main.cpp | 69 ++++++ examples/quick/scenegraph/custommaterial/main.qml | 99 ++++++++ .../custommaterial/shaders/mandelbrot.frag | 48 ++++ .../custommaterial/shaders/mandelbrot.frag.qsb | Bin 0 -> 2605 bytes .../custommaterial/shaders/mandelbrot.vert | 22 ++ .../custommaterial/shaders/mandelbrot.vert.qsb | Bin 0 -> 1643 bytes 12 files changed, 745 insertions(+) create mode 100644 examples/quick/scenegraph/custommaterial/customitem.cpp create mode 100644 examples/quick/scenegraph/custommaterial/customitem.h create mode 100644 examples/quick/scenegraph/custommaterial/custommaterial.pro create mode 100644 examples/quick/scenegraph/custommaterial/custommaterial.qrc create mode 100644 examples/quick/scenegraph/custommaterial/doc/images/custom-material-example.jpg create mode 100644 examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc create mode 100644 examples/quick/scenegraph/custommaterial/main.cpp create mode 100644 examples/quick/scenegraph/custommaterial/main.qml create mode 100644 examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag create mode 100644 examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb create mode 100644 examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert create mode 100644 examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb (limited to 'examples/quick/scenegraph/custommaterial') diff --git a/examples/quick/scenegraph/custommaterial/customitem.cpp b/examples/quick/scenegraph/custommaterial/customitem.cpp new file mode 100644 index 0000000000..62dc962455 --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/customitem.cpp @@ -0,0 +1,267 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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 The Qt Company Ltd 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 "customitem.h" + +#include + +#include +#include +#include +#include + +//! [2] +class CustomShader : public QSGMaterialShader +{ +public: + CustomShader() + { + setShaderFileName(VertexStage, QLatin1String(":/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb")); + setShaderFileName(FragmentStage, QLatin1String(":/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb")); + } + bool updateUniformData(RenderState &state, + QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; +}; +//! [2] + +//! [1] +class CustomMaterial : public QSGMaterial +{ +public: + CustomMaterial(); + QSGMaterialType *type() const override; + int compare(const QSGMaterial *other) const override; + + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode) const override + { + return new CustomShader; + } + + struct { + float center[2]; + float zoom; + int limit; + bool dirty; + } uniforms; +}; +//! [1] + +CustomMaterial::CustomMaterial() +{ +} + +QSGMaterialType *CustomMaterial::type() const +{ + static QSGMaterialType type; + return &type; +} + +int CustomMaterial::compare(const QSGMaterial *o) const +{ + Q_ASSERT(o && type() == o->type()); + const auto *other = static_cast(o); + return other == this ? 0 : 1; // ### TODO: compare state??? +} + +//! [3] +bool CustomShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) +{ + bool changed = false; + QByteArray *buf = state.uniformData(); + Q_ASSERT(buf->size() >= 84); + + if (state.isMatrixDirty()) { + const QMatrix4x4 m = state.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + changed = true; + } + + if (state.isOpacityDirty()) { + const float opacity = state.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + changed = true; + } + + auto *customMaterial = static_cast(newMaterial); + if (oldMaterial != newMaterial || customMaterial->uniforms.dirty) { + memcpy(buf->data() + 68, &customMaterial->uniforms.zoom, 4); + memcpy(buf->data() + 72, &customMaterial->uniforms.center, 8); + memcpy(buf->data() + 80, &customMaterial->uniforms.limit, 4); + customMaterial->uniforms.dirty = false; + changed = true; + } + return changed; +} +//! [3] + +//! [4] +class CustomNode : public QSGGeometryNode +{ +public: + CustomNode() + { + auto *m = new CustomMaterial; + setMaterial(m); + setFlag(OwnsMaterial, true); + + QSGGeometry *g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4); + QSGGeometry::updateTexturedRectGeometry(g, QRect(), QRect()); + setGeometry(g); + setFlag(OwnsGeometry, true); + } + + void setRect(const QRectF &bounds) + { + QSGGeometry::updateTexturedRectGeometry(geometry(), bounds, QRectF(0, 0, 1, 1)); + markDirty(QSGNode::DirtyGeometry); + } + + void setZoom(qreal zoom) + { + auto *m = static_cast(material()); + m->uniforms.zoom = zoom; + m->uniforms.dirty = true; + markDirty(DirtyMaterial); + } + + void setLimit(int limit) + { + auto *m = static_cast(material()); + m->uniforms.limit = limit; + m->uniforms.dirty = true; + markDirty(DirtyMaterial); + } + + void setCenter(const QPointF ¢er) + { + auto *m = static_cast(material()); + m->uniforms.center[0] = center.x(); + m->uniforms.center[1] = center.y(); + m->uniforms.dirty = true; + markDirty(DirtyMaterial); + } +}; +//! [4] + +CustomItem::CustomItem(QQuickItem *parent) + : QQuickItem(parent) +{ + setFlag(ItemHasContents, true); +} + +//! [5] +void CustomItem::setZoom(qreal zoom) +{ + if (qFuzzyCompare(m_zoom, zoom)) + return; + + m_zoom = zoom; + m_zoomChanged = true; + emit zoomChanged(m_zoom); + update(); +} + +void CustomItem::setIterationLimit(int limit) +{ + if (m_limit == limit) + return; + + m_limit = limit; + m_limitChanged = true; + emit iterationLimitChanged(m_limit); + update(); +} + +void CustomItem::setCenter(QPointF center) +{ + if (m_center == center) + return; + + m_center = center; + m_centerChanged = true; + emit centerChanged(m_center); + update(); +} +//! [5] + +void CustomItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + m_geometryChanged = true; + update(); + QQuickItem::geometryChange(newGeometry, oldGeometry); +} + +//! [6] +QSGNode *CustomItem::updatePaintNode(QSGNode *old, UpdatePaintNodeData *) +{ + auto *node = static_cast(old); + + if (!node) + node = new CustomNode; + + if (m_geometryChanged) + node->setRect(boundingRect()); + m_geometryChanged = false; + + if (m_zoomChanged) + node->setZoom(m_zoom); + m_zoomChanged = false; + + if (m_limitChanged) + node->setLimit(m_limit); + m_limitChanged = false; + + if (m_centerChanged) + node->setCenter(m_center); + m_centerChanged = false; + + return node; +} +//! [6] diff --git a/examples/quick/scenegraph/custommaterial/customitem.h b/examples/quick/scenegraph/custommaterial/customitem.h new file mode 100644 index 0000000000..5cc1fa09f4 --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/customitem.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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 The Qt Company Ltd 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 CUSTOMITEM_H +#define CUSTOMITEM_H + +//! [1] +#include + +class CustomItem : public QQuickItem +{ + Q_OBJECT +//! [2] + Q_PROPERTY(qreal zoom READ zoom WRITE setZoom NOTIFY zoomChanged) + Q_PROPERTY(int iterationLimit READ iterationLimit WRITE setIterationLimit NOTIFY iterationLimitChanged) + Q_PROPERTY(QPointF center READ center WRITE setCenter NOTIFY centerChanged) +//! [2] + QML_ELEMENT + +public: + explicit CustomItem(QQuickItem *parent = 0); + + qreal zoom() const + { + return m_zoom; + } + + int iterationLimit() const + { + return m_limit; + } + + QPointF center() const + { + return m_center; + } + +public slots: + void setZoom(qreal zoom); + + void setIterationLimit(int iterationLimit); + + void setCenter(QPointF center); + +signals: + void zoomChanged(qreal zoom); + + void iterationLimitChanged(int iterationLimit); + + void centerChanged(QPointF center); + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + +private: + bool m_geometryChanged = true; + qreal m_zoom; + bool m_zoomChanged = true; + int m_limit; + bool m_limitChanged = true; + QPointF m_center; + bool m_centerChanged = true; +}; +//! [1] +#endif // CUSTOMITEM_H diff --git a/examples/quick/scenegraph/custommaterial/custommaterial.pro b/examples/quick/scenegraph/custommaterial/custommaterial.pro new file mode 100644 index 0000000000..46a1a6603c --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/custommaterial.pro @@ -0,0 +1,16 @@ +QT += qml quick + +CONFIG += qmltypes +QML_IMPORT_NAME = ExampleCustomMaterial +QML_IMPORT_MAJOR_VERSION = 1 + +HEADERS += customitem.h +SOURCES += customitem.cpp main.cpp + +RESOURCES += custommaterial.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/custommaterial +INSTALLS += target + +OTHER_FILES += \ + main.qml diff --git a/examples/quick/scenegraph/custommaterial/custommaterial.qrc b/examples/quick/scenegraph/custommaterial/custommaterial.qrc new file mode 100644 index 0000000000..18e586bf65 --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/custommaterial.qrc @@ -0,0 +1,7 @@ + + + main.qml + shaders/mandelbrot.frag.qsb + shaders/mandelbrot.vert.qsb + + diff --git a/examples/quick/scenegraph/custommaterial/doc/images/custom-material-example.jpg b/examples/quick/scenegraph/custommaterial/doc/images/custom-material-example.jpg new file mode 100644 index 0000000000..e4040cfcf2 Binary files /dev/null and b/examples/quick/scenegraph/custommaterial/doc/images/custom-material-example.jpg differ diff --git a/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc b/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc new file mode 100644 index 0000000000..5cb7b38ab0 --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/doc/src/custommaterial.qdoc @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** 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 The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/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: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example scenegraph/custommaterial + \title Scene Graph - Custom Material + \ingroup qtquickexamples + \brief Shows how to implement a custom material in the Qt Quick Scene Graph. + + The custom material example shows how to implement an item that is rendered + using a material with a custom vertex and fragment shader. + + \image custom-material-example.jpg + + \section1 Shader and material + + The main functionality is in the fragment shader + + \quotefile scenegraph/custommaterial/shaders/mandelbrot.frag + + The fragment and vertex shaders are combined into a \l QSGMaterialShader subclass. + + \snippet scenegraph/custommaterial/customitem.cpp 2 + + A QSGMaterial subclass encapsulates the shader together with the render state. In + this example, we add state information corresponding to the shader uniforms. The + material is responsible for creating the shader by reimplementing + \l QSGMaterial::createShader(). + + \snippet scenegraph/custommaterial/customitem.cpp 1 + + + To update the uniform data, we reimplement \l QSGMaterialShader::updateUniformData(). + + \snippet scenegraph/custommaterial/customitem.cpp 3 + + \section1 Item and node + + We create a custom item to show off our new material: + + \snippet scenegraph/custommaterial/customitem.h 1 + + The CustomItem declaration adds three + properties corresponding to the uniforms that we want to expose to QML. + + \snippet scenegraph/custommaterial/customitem.h 2 + + As with every custom Qt Quick item, the implementation is split in two: + in addition to \c CustomItem, which lives in the GUI thread, we create + a \l QSGNode subclass that lives in the render thread. + + \snippet scenegraph/custommaterial/customitem.cpp 4 + + The node owns an instance of the material, and has logic to update + the material's state. The item maintains the corresponding QML properties. + It needs to duplicate the information from the material since the item and + material live on different threads. + + \snippet scenegraph/custommaterial/customitem.cpp 5 + + The information is copied from the item to the scene graph in a + reimplementation of \l QQuickItem::updatePaintNode(). The two threads + are at a synchronization point when the function is called, so it is safe + to access both classes. + + \snippet scenegraph/custommaterial/customitem.cpp 6 + + \section1 The rest of the example + + The application is a straightforward QML application, with a + QGuiApplication and a QQuickView that we pass a .qml file. + + In the QML file, we create the + customitem which we anchor to fill the root. + + \snippet scenegraph/custommaterial/main.qml 1 + + To make the example a bit more interesting we add an animation to + change the zoom level and iteration limit. The center stays constant. + */ diff --git a/examples/quick/scenegraph/custommaterial/main.cpp b/examples/quick/scenegraph/custommaterial/main.cpp new file mode 100644 index 0000000000..ce1bcd9dfe --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/main.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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 The Qt Company Ltd 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 + +#include + +#include "customitem.h" + +//! [1] +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.setSource(QUrl("qrc:///scenegraph/custommaterial/main.qml")); + view.show(); + + return app.exec(); +} +//! [1] diff --git a/examples/quick/scenegraph/custommaterial/main.qml b/examples/quick/scenegraph/custommaterial/main.qml new file mode 100644 index 0000000000..e552c4ee48 --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/main.qml @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, 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 The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import ExampleCustomMaterial 1.0 + +Item { + id: root + + width: 640 + height: 480 + + +//! [1] + CustomItem { + property real t: 1 + anchors.fill: parent + center: Qt.point(-0.748, 0.1); + iterationLimit: 3 * (zoom + 30) + zoom: t * t / 10 + NumberAnimation on t { + from: 1 + to: 60 + duration: 30*1000; + running: true + loops: Animation.Infinite + } + } +//! [1] + + Rectangle { + id: labelFrame + anchors.margins: -10 + radius: 10 + color: "white" + border.color: "black" + opacity: 0.8 + anchors.fill: description + } + + Text { + id: description + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: 20 + wrapMode: Text.WordWrap + text: "This example shows how to create a custom material in C++ and use it in QML.\n" + + "The custom material uses a fragment shader that calculates the Mandelbrot set," + + " and exposes the shader uniforms as QML properties." + } +} diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag new file mode 100644 index 0000000000..0e5f63e7a8 --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag @@ -0,0 +1,48 @@ +//! [1] +#version 440 + +layout(location = 0) in vec2 vTexCoord; + +layout(location = 0) out vec4 fragColor; + +//! [2] +// uniform block: 84 bytes +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; // offset 0 + float qt_Opacity; // offset 64 + float zoom; // offset 68 + vec2 center; // offset 72 + int limit; // offset 80 +} ubuf; +//! [2] + +void main() +{ + vec4 color1 = vec4(1.0, 0.85, 0.55, 1); + vec4 color2 = vec4(0.226, 0.0, 0.615, 1); + + float aspect_ratio = -ubuf.qt_Matrix[0][0]/ubuf.qt_Matrix[1][1]; + vec2 z, c; + + c.x = (vTexCoord.x - 0.5) / ubuf.zoom + ubuf.center.x; + c.y = aspect_ratio * (vTexCoord.y - 0.5) / ubuf.zoom + ubuf.center.y; + + int i; + z = c; + for (i = 0; i < ubuf.limit; i++) { + float x = (z.x * z.x - z.y * z.y) + c.x; + float y = (z.y * z.x + z.x * z.y) + c.y; + + if ((x * x + y * y) > 4.0) break; + z.x = x; + z.y = y; + } + + if (i == ubuf.limit) { + fragColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + float f = (i * 1.0) / ubuf.limit; + fragColor = mix(color1, color2, sqrt(f)); + } +} +//! [1] diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb new file mode 100644 index 0000000000..dce5a9d934 Binary files /dev/null and b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.frag.qsb differ diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert new file mode 100644 index 0000000000..00c519cd9d --- /dev/null +++ b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert @@ -0,0 +1,22 @@ +#version 440 + +layout(location = 0) in vec4 aVertex; +layout(location = 1) in vec2 aTexCoord; + +layout(location = 0) out vec2 vTexCoord; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + float scale; + vec2 center; + int limit; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; }; + +void main() +{ + gl_Position = ubuf.qt_Matrix * aVertex; + vTexCoord = aTexCoord; +} diff --git a/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb new file mode 100644 index 0000000000..445b986ebd Binary files /dev/null and b/examples/quick/scenegraph/custommaterial/shaders/mandelbrot.vert.qsb differ -- cgit v1.2.3