diff options
53 files changed, 6027 insertions, 18 deletions
diff --git a/examples/quick/pathitem/content/item1.qml b/examples/quick/pathitem/content/item1.qml new file mode 100644 index 0000000000..c22f200929 --- /dev/null +++ b/examples/quick/pathitem/content/item1.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: ctr + anchors.fill: parent + + strokeColor: "red" + fillColor: "blue" + + SequentialAnimation on strokeWidth { + loops: Animation.Infinite + NumberAnimation { from: 1; to: 30; duration: 5000 } + NumberAnimation { from: 30; to: 1; duration: 5000 } + PauseAnimation { duration: 2000 } + } + + path: Path { + startX: 30; startY: 30 + PathLine { x: ctr.width - 30; y: ctr.height - 30 } + PathLine { x: 30; y: ctr.height - 30 } + PathLine { x: 30; y: 30 } + } + } +} diff --git a/examples/quick/pathitem/content/item10.qml b/examples/quick/pathitem/content/item10.qml new file mode 100644 index 0000000000..703d7b38f9 --- /dev/null +++ b/examples/quick/pathitem/content/item10.qml @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: pathItem + width: 200 + height: 200 + anchors.centerIn: parent + + strokeWidth: 4 + strokeColor: "black" + fillColor: "lightBlue" + + path: Path { + startX: 50; startY: 100 + PathCubic { + x: 150; y: 100 + control1X: cp1.x; control1Y: cp1.y + control2X: cp2.x; control2Y: cp2.y + } + } + + Rectangle { + id: cp1 + color: "red" + width: 10; height: 10 + SequentialAnimation { + loops: Animation.Infinite + running: true + NumberAnimation { + target: cp1 + property: "x" + from: 0 + to: pathItem.width - cp1.width + duration: 5000 + } + NumberAnimation { + target: cp1 + property: "x" + from: pathItem.width - cp1.width + to: 0 + duration: 5000 + } + NumberAnimation { + target: cp1 + property: "y" + from: 0 + to: pathItem.height - cp1.height + duration: 5000 + } + NumberAnimation { + target: cp1 + property: "y" + from: pathItem.height - cp1.height + to: 0 + duration: 5000 + } + } + } + Rectangle { + id: cp2 + color: "blue" + width: 10; height: 10 + x: pathItem.width - width + SequentialAnimation { + loops: Animation.Infinite + running: true + NumberAnimation { + target: cp2 + property: "y" + from: 0 + to: pathItem.height - cp2.height + duration: 5000 + } + NumberAnimation { + target: cp2 + property: "y" + from: pathItem.height - cp2.height + to: 0 + duration: 5000 + } + NumberAnimation { + target: cp2 + property: "x" + from: pathItem.width - cp2.width + to: 0 + duration: 5000 + } + NumberAnimation { + target: cp2 + property: "x" + from: 0 + to: pathItem.width - cp2.width + duration: 5000 + } + } + } + } +} diff --git a/examples/quick/pathitem/content/item11.qml b/examples/quick/pathitem/content/item11.qml new file mode 100644 index 0000000000..2b49655fdd --- /dev/null +++ b/examples/quick/pathitem/content/item11.qml @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: pathItem + width: 220 + height: 200 + anchors.centerIn: parent + + fillGradient: PathLinearGradient { + y2: pathItem.height + PathGradientStop { position: 0; color: "yellow" } + PathGradientStop { position: 1; color: "green" } + } + + path: Path { + startX: 10; startY: 100 + PathArc { + relativeX: 50; y: 100 + radiusX: 25; radiusY: 25 + } + PathArc { + relativeX: 50; y: 100 + radiusX: 25; radiusY: 35 + } + PathArc { + relativeX: 50; y: 100 + radiusX: 25; radiusY: 60 + } + PathArc { + relativeX: 50; y: 100 + radiusX: 50; radiusY: 120 + } + } + } + + PathItem { + width: 120 + height: 130 + anchors.bottom: parent.bottom + anchors.right: parent.right + + scale: 0.5 + + fillColor: "transparent" + strokeColor: "darkBlue" + strokeWidth: 20 + capStyle: PathItem.RoundCap + + path: Path { + startX: 20; startY: 50 + PathArc { + x: 20; y: 90 + radiusX: 45; radiusY: 45 + useLargeArc: true + } + } + } +} diff --git a/examples/quick/pathitem/content/item12.qml b/examples/quick/pathitem/content/item12.qml new file mode 100644 index 0000000000..91ab9c1417 --- /dev/null +++ b/examples/quick/pathitem/content/item12.qml @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + Rectangle { + border.color: "black" + width: 200 + height: 200 + anchors.centerIn: parent + + PathItem { + anchors.fill: parent + + strokeColor: "transparent" + + fillGradient: PathLinearGradient { + id: grad + y1: 50; y2: 150 + PathGradientStop { position: 0; color: "black" } + PathGradientStop { position: 1; color: "red" } + } + Timer { + id: spreadTimer + interval: 3000 + running: true + repeat: true + property variant spreads: [ PathGradient.PadSpread, PathGradient.RepeatSpread, PathGradient.ReflectSpread ] + property variant spreadTexts: [ "PadSpread", "RepeatSpread", "ReflectSpread" ] + property int spreadIdx: 0 + onTriggered: { spreadIdx = (spreadIdx + 1) % spreads.length; grad.spread = spreads[spreadIdx] } + } + + path: Path { + startX: 10; startY: 10 + PathLine { relativeX: 180; relativeY: 0 } + PathLine { relativeX: 0; relativeY: 180 } + PathLine { relativeX: -180; relativeY: 0 } + PathLine { relativeX: 0; relativeY: -180 } + } + + PathItem { + anchors.fill: parent + strokeColor: "gray" + strokeWidth: 2 + fillColor: "transparent" + path: Path { + PathMove { x: 0; y: 50 } + PathLine { relativeX: 200; relativeY: 0 } + PathMove { x: 0; y: 150 } + PathLine { relativeX: 200; relativeY: 0 } + } + } + } + } + + Text { + anchors.right: parent.right + text: spreadTimer.spreadTexts[spreadTimer.spreadIdx] + } +} diff --git a/examples/quick/pathitem/content/item2.qml b/examples/quick/pathitem/content/item2.qml new file mode 100644 index 0000000000..bccacdcdeb --- /dev/null +++ b/examples/quick/pathitem/content/item2.qml @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + Repeater { + model: 10 + PathItem { + id: ctr + anchors.fill: parent + scale: 1.0 - 0.1 * model.index + + fillColor: "transparent" + strokeWidth: 4 + + SequentialAnimation on strokeColor { + loops: Animation.Infinite + ColorAnimation { + from: "red" + to: "yellow" + duration: 5000 + } + ColorAnimation { + from: "yellow" + to: "green" + duration: 5000 + } + ColorAnimation { + from: "green" + to: "red" + duration: 5000 + } + } + + path: Path { + startX: 60; startY: 50 + PathLine { x: ctr.width - 70; y: 50 } + PathLine { x: ctr.width - 10; y: ctr.height - 50 } + PathLine { x: 10; y: ctr.height - 50 } + PathLine { x: 60; y: 50 } + } + } + } +} diff --git a/examples/quick/pathitem/content/item3.qml b/examples/quick/pathitem/content/item3.qml new file mode 100644 index 0000000000..9ea3de30b6 --- /dev/null +++ b/examples/quick/pathitem/content/item3.qml @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: pathItem + width: 200 + height: 200 + anchors.centerIn: parent + + strokeWidth: 0 // or strokeColor: "transparent" + + SequentialAnimation on fillColor { + loops: Animation.Infinite + ColorAnimation { + from: "gray" + to: "purple" + duration: 3000 + } + ColorAnimation { + from: "purple" + to: "red" + duration: 3000 + } + ColorAnimation { + from: "red" + to: "gray" + duration: 3000 + } + } + SequentialAnimation on opacity { + loops: Animation.Infinite + NumberAnimation { from: 1.0; to: 0.0; duration: 5000 } + NumberAnimation { from: 0.0; to: 1.0; duration: 5000 } + } + + path: Path { + id: p + property real r: 50 + startX: pathItem.width / 2 - r + startY: pathItem.height / 2 - r + PathArc { + x: pathItem.width / 2 + p.r + y: pathItem.height / 2 + p.r + radiusX: p.r; radiusY: p.r + useLargeArc: true + } + PathArc { + x: pathItem.width / 2 - p.r + y: pathItem.height / 2 - p.r + radiusX: p.r; radiusY: p.r + useLargeArc: true + } + } + } +} diff --git a/examples/quick/pathitem/content/item4.qml b/examples/quick/pathitem/content/item4.qml new file mode 100644 index 0000000000..62c4a8f0a1 --- /dev/null +++ b/examples/quick/pathitem/content/item4.qml @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: pathItem + anchors.fill: parent + + strokeWidth: 5 + strokeColor: "blue" + strokeStyle: PathItem.DashLine + dashPattern: [ 1, 4, 4, 4 ] + fillColor: "lightBlue" + + path: Path { + id: p + property real xr: 70 + property real yr: 30 + startX: pathItem.width / 2 - xr + startY: pathItem.height / 2 - yr + PathArc { + x: pathItem.width / 2 + p.xr + y: pathItem.height / 2 + p.yr + radiusX: p.xr; radiusY: p.yr + useLargeArc: true + } + PathArc { + x: pathItem.width / 2 - p.xr + y: pathItem.height / 2 - p.yr + radiusX: p.xr; radiusY: p.yr + useLargeArc: true + } + } + } +} diff --git a/examples/quick/pathitem/content/item5.qml b/examples/quick/pathitem/content/item5.qml new file mode 100644 index 0000000000..2e22574064 --- /dev/null +++ b/examples/quick/pathitem/content/item5.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + width: 200 + height: 150 + anchors.centerIn: parent + strokeWidth: 4 + strokeColor: "red" + fillGradient: PathLinearGradient { + x1: 20; y1: 20 + x2: 180; y2: 130 + PathGradientStop { position: 0; color: "blue" } + PathGradientStop { position: 0.2; color: "green" } + PathGradientStop { position: 0.4; color: "red" } + PathGradientStop { position: 0.6; color: "yellow" } + PathGradientStop { position: 1; color: "cyan" } + } + fillColor: "blue" // ignored with the gradient set + strokeStyle: PathItem.DashLine + dashPattern: [ 1, 4 ] + path: Path { + startX: 20; startY: 20 + PathLine { x: 180; y: 130 } + PathLine { x: 20; y: 130 } + PathLine { x: 20; y: 20 } + } + transform: Rotation { origin.x: 100; origin.y: 50; axis { x: 0; y: 1; z: 0 } + SequentialAnimation on angle { + NumberAnimation { from: 0; to: 75; duration: 2000 } + NumberAnimation { from: 75; to: -75; duration: 4000 } + NumberAnimation { from: -75; to: 0; duration: 2000 } + loops: Animation.Infinite + } + } + } +} diff --git a/examples/quick/pathitem/content/item6.qml b/examples/quick/pathitem/content/item6.qml new file mode 100644 index 0000000000..4a8f965702 --- /dev/null +++ b/examples/quick/pathitem/content/item6.qml @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: star + width: 100 + height: 100 + anchors.centerIn: parent + strokeColor: "blue" + fillColor: "magenta" + strokeWidth: 2 + path: Path { + PathMove { x: 90; y: 50 } + PathLine { x: 50 + 40 * Math.cos(0.8 * 1 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 1 * Math.PI) } + PathLine { x: 50 + 40 * Math.cos(0.8 * 2 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 2 * Math.PI) } + PathLine { x: 50 + 40 * Math.cos(0.8 * 3 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 3 * Math.PI) } + PathLine { x: 50 + 40 * Math.cos(0.8 * 4 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 4 * Math.PI) } + PathLine { x: 90; y: 50 } + } + Timer { + interval: 2000 + onTriggered: star.fillRule = (star.fillRule === PathItem.OddEvenFill ? PathItem.WindingFill : PathItem.OddEvenFill) + repeat: true + running: true + } + NumberAnimation on rotation { + from: 0 + to: 360 + duration: 5000 + loops: Animation.Infinite + } + } + Text { + anchors.right: parent.right + text: star.fillRule === PathItem.OddEvenFill ? "OddEvenFill" : "WindingFill" + } +} diff --git a/examples/quick/pathitem/content/item7.qml b/examples/quick/pathitem/content/item7.qml new file mode 100644 index 0000000000..3adc5d4a3a --- /dev/null +++ b/examples/quick/pathitem/content/item7.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: joinTest + width: 120 + height: 120 + anchors.centerIn: parent + + strokeColor: "black" + strokeWidth: 16 + fillColor: "transparent" + capStyle: PathItem.RoundCap + + property int joinStyleIdx: 0 + property variant styles: [ PathItem.BevelJoin, PathItem.MiterJoin, PathItem.RoundJoin ] + property variant styleTexts: [ "BevelJoin", "MiterJoin", "RoundJoin" ] + + joinStyle: styles[joinStyleIdx] + + path: Path { + startX: 30 + startY: 30 + PathLine { x: 100; y: 100 } + PathLine { x: 30; y: 100 } + } + Timer { + interval: 1000 + repeat: true + running: true + onTriggered: joinTest.joinStyleIdx = (joinTest.joinStyleIdx + 1) % joinTest.styles.length + } + } + Text { + id: txt + anchors.right: parent.right + text: joinTest.styleTexts[joinTest.joinStyleIdx] + } +} diff --git a/examples/quick/pathitem/content/item8.qml b/examples/quick/pathitem/content/item8.qml new file mode 100644 index 0000000000..9b2330c365 --- /dev/null +++ b/examples/quick/pathitem/content/item8.qml @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: capTest + anchors.centerIn: parent + width: 200 + height: 100 + + strokeColor: "green" + strokeWidth: 20 + fillColor: "transparent" + + property int capStyleIdx: 0 + property variant styles: [ PathItem.FlatCap, PathItem.SquareCap, PathItem.RoundCap ] + property variant styleTexts: [ "FlatCap", "SquareCap", "RoundCap" ] + + capStyle: styles[capStyleIdx] + + path: Path { + startX: 40; startY: 30 + PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 } + PathLine { x: 150; y: 80 } + PathQuad { x: 160; y: 30; controlX: 200; controlY: 80 } + } + + Timer { + interval: 1000 + repeat: true + running: true + onTriggered: capTest.capStyleIdx = (capTest.capStyleIdx + 1) % capTest.styles.length + } + } + + Text { + id: txt + anchors.right: parent.right + text: capTest.styleTexts[capTest.capStyleIdx] + } +} diff --git a/examples/quick/pathitem/content/item9.qml b/examples/quick/pathitem/content/item9.qml new file mode 100644 index 0000000000..876d508e22 --- /dev/null +++ b/examples/quick/pathitem/content/item9.qml @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + color: "lightGray" + PathItem { + id: pathItem + width: 200 + height: 100 + anchors.centerIn: parent + + strokeWidth: 4 + strokeColor: "black" + fillColor: "transparent" + + path: Path { + startX: 50 + startY: 50 + PathQuad { + x: 150; y: 50 + controlX: cp.x; controlY: cp.y + } + } + + Rectangle { + id: cp + color: "red" + width: 10 + height: 10 + SequentialAnimation on x { + loops: Animation.Infinite + NumberAnimation { + from: 0 + to: pathItem.width - cp.width + duration: 5000 + } + NumberAnimation { + from: pathItem.width - cp.width + to: 0 + duration: 5000 + } + } + } + } +} diff --git a/examples/quick/pathitem/content/pathitem.qml b/examples/quick/pathitem/content/pathitem.qml new file mode 100644 index 0000000000..e3a28b2bbe --- /dev/null +++ b/examples/quick/pathitem/content/pathitem.qml @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.0 + +Item { + width: 1024 + height: 768 + LauncherList { + anchors.fill: parent + Component.onCompleted: { + addExample("PathItem Gallery", "Simple path rendering examples", Qt.resolvedUrl("pathitemgallery.qml")) + addExample("Interactive paths", "Dynamic path examples", Qt.resolvedUrl("pathiteminteract.qml")) + } + } +} diff --git a/examples/quick/pathitem/content/pathitemgallery.qml b/examples/quick/pathitem/content/pathitemgallery.qml new file mode 100644 index 0000000000..5a5e6b7188 --- /dev/null +++ b/examples/quick/pathitem/content/pathitemgallery.qml @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 + +Rectangle { + id: root + width: 1024 + height: 768 + + property color col: "lightsteelblue" + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.tint(root.col, "#20FFFFFF") } + GradientStop { position: 0.1; color: Qt.tint(root.col, "#20AAAAAA") } + GradientStop { position: 0.9; color: Qt.tint(root.col, "#20666666") } + GradientStop { position: 1.0; color: Qt.tint(root.col, "#20000000") } + } + + ListModel { + id: pathGalleryModel + ListElement { + name: "Stroke and fill" + pathItemUrl: "item1.qml" + } + ListElement { + name: "Stroke only" + pathItemUrl: "item2.qml" + } + ListElement { + name: "Fill only" + pathItemUrl: "item3.qml" + } + ListElement { + name: "Dash pattern" + pathItemUrl: "item4.qml" + } + ListElement { + name: "Linear gradient" + pathItemUrl: "item5.qml" + } + ListElement { + name: "Fill rules" + pathItemUrl: "item6.qml" + } + ListElement { + name: "Join styles" + pathItemUrl: "item7.qml" + } + ListElement { + name: "Cap styles" + pathItemUrl: "item8.qml" + } + ListElement { + name: "Quadratic curve" + pathItemUrl: "item9.qml" + } + ListElement { + name: "Cubic curve" + pathItemUrl: "item10.qml" + } + ListElement { + name: "Elliptical arc" + pathItemUrl: "item11.qml" + } + ListElement { + name: "Gradient spread modes" + pathItemUrl: "item12.qml" + } + } + + property int gridSpacing: 10 + + Component { + id: pathGalleryDelegate + Rectangle { + border.color: "purple" + width: grid.cellWidth - root.gridSpacing + height: grid.cellHeight - root.gridSpacing + Column { + anchors.fill: parent + anchors.margins: 4 + Item { + width: parent.width + height: parent.height - delegText.height + Loader { + source: Qt.resolvedUrl(pathItemUrl) + anchors.fill: parent + } + } + Text { + id: delegText + text: model.name + font.pointSize: 16 + anchors.horizontalCenter: parent.horizontalCenter + } + } + } + } + + Rectangle { + anchors.fill: parent + anchors.margins: 10 + color: "lightBlue" + clip: true + + GridView { + id: grid + anchors.fill: parent + anchors.margins: root.gridSpacing + cellWidth: 300 + cellHeight: 300 + delegate: pathGalleryDelegate + model: pathGalleryModel + } + } + + Text { + anchors.right: parent.right + PathItem { id: dummyPathItem; strokeWidth: 4 } // used only to get the renderer type + color: "darkBlue" + font.pointSize: 12 + property variant rendererStrings: [ "Unknown", "Generic (QtGui triangulator)", "GL_NV_path_rendering", "Software (QPainter)" ] + text: "Active PathItem backend: " + rendererStrings[dummyPathItem.renderer] + SequentialAnimation on opacity { + NumberAnimation { from: 1; to: 0; duration: 5000 } + PauseAnimation { duration: 5000 } + NumberAnimation { from: 0; to: 1; duration: 1000 } + PauseAnimation { duration: 5000 } + loops: Animation.Infinite + } + } +} diff --git a/examples/quick/pathitem/content/pathiteminteract.qml b/examples/quick/pathitem/content/pathiteminteract.qml new file mode 100644 index 0000000000..78b3b25b55 --- /dev/null +++ b/examples/quick/pathitem/content/pathiteminteract.qml @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + id: root + width: 1024 + height: 768 + + property color col: "lightsteelblue" + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.tint(root.col, "#20FFFFFF") } + GradientStop { position: 0.1; color: Qt.tint(root.col, "#20AAAAAA") } + GradientStop { position: 0.9; color: Qt.tint(root.col, "#20666666") } + GradientStop { position: 1.0; color: Qt.tint(root.col, "#20000000") } + } +} diff --git a/examples/quick/pathitem/main.cpp b/examples/quick/pathitem/main.cpp new file mode 100644 index 0000000000..3a81c4da05 --- /dev/null +++ b/examples/quick/pathitem/main.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 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 "../shared/shared.h" +DECLARATIVE_EXAMPLE_MAIN(pathitem/pathitem) diff --git a/examples/quick/pathitem/pathitem.pro b/examples/quick/pathitem/pathitem.pro new file mode 100644 index 0000000000..69aa11fa45 --- /dev/null +++ b/examples/quick/pathitem/pathitem.pro @@ -0,0 +1,23 @@ +TEMPLATE = app + +QT += quick qml +SOURCES += main.cpp +RESOURCES += pathitem.qrc +OTHER_FILES += content/pathitem.qml \ + content/pathitemgallery.qml \ + content/pathiteminteract.qml \ + content/item1.qml \ + content/item2.qml \ + content/item3.qml \ + content/item4.qml \ + content/item5.qml \ + content/item6.qml \ + content/item7.qml \ + content/item8.qml \ + content/item9.qml \ + content/item10.qml \ + content/item11.qml \ + content/item12.qml + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/pathitem +INSTALLS += target diff --git a/examples/quick/pathitem/pathitem.qrc b/examples/quick/pathitem/pathitem.qrc new file mode 100644 index 0000000000..fe92d8c007 --- /dev/null +++ b/examples/quick/pathitem/pathitem.qrc @@ -0,0 +1,23 @@ +<RCC> + <qresource prefix="/pathitem"> + <file alias="LauncherList.qml">../shared/LauncherList.qml</file> + <file alias="SimpleLauncherDelegate.qml">../shared/SimpleLauncherDelegate.qml</file> + <file alias="images/next.png">../shared/images/next.png</file> + <file alias="images/back.png">../shared/images/back.png</file> + <file alias="pathitem.qml">content/pathitem.qml</file> + <file alias="pathitemgallery.qml">content/pathitemgallery.qml</file> + <file alias="pathiteminteract.qml">content/pathiteminteract.qml</file> + <file alias="item1.qml">content/item1.qml</file> + <file alias="item2.qml">content/item2.qml</file> + <file alias="item3.qml">content/item3.qml</file> + <file alias="item4.qml">content/item4.qml</file> + <file alias="item5.qml">content/item5.qml</file> + <file alias="item6.qml">content/item6.qml</file> + <file alias="item7.qml">content/item7.qml</file> + <file alias="item8.qml">content/item8.qml</file> + <file alias="item9.qml">content/item9.qml</file> + <file alias="item10.qml">content/item10.qml</file> + <file alias="item11.qml">content/item11.qml</file> + <file alias="item12.qml">content/item12.qml</file> + </qresource> +</RCC> diff --git a/examples/quick/shared/shared.h b/examples/quick/shared/shared.h index 0eed618d9d..ae04667c8f 100644 --- a/examples/quick/shared/shared.h +++ b/examples/quick/shared/shared.h @@ -56,6 +56,11 @@ f.setVersion(4, 4);\ view.setFormat(f);\ }\ + if (qgetenv("QT_QUICK_MULTISAMPLE").toInt()) {\ + QSurfaceFormat f = view.format();\ + f.setSamples(4);\ + view.setFormat(f);\ + }\ view.connect(view.engine(), &QQmlEngine::quit, &app, &QCoreApplication::quit);\ new QQmlFileSelector(view.engine(), &view);\ view.setSource(QUrl("qrc:///" #NAME ".qml")); \ diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index 0f8061b5ef..511c6f18d8 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -148,9 +148,20 @@ qtConfig(quick-listview) { qtConfig(quick-pathview) { HEADERS += \ $$PWD/qquickpathview_p.h \ - $$PWD/qquickpathview_p_p.h + $$PWD/qquickpathview_p_p.h \ + $$PWD/qquickpathitem_p.h \ + $$PWD/qquickpathitem_p_p.h \ + $$PWD/qquickpathitemgenericrenderer_p.h \ + $$PWD/qquickpathitemsoftwarerenderer_p.h SOURCES += \ - $$PWD/qquickpathview.cpp + $$PWD/qquickpathview.cpp \ + $$PWD/qquickpathitem.cpp \ + $$PWD/qquickpathitemgenericrenderer.cpp \ + $$PWD/qquickpathitemsoftwarerenderer.cpp + qtConfig(opengl) { + HEADERS += $$PWD/qquickpathitemnvprrenderer_p.h + SOURCES += $$PWD/qquickpathitemnvprrenderer.cpp + } } qtConfig(quick-positioners) { diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc index 6aaf757c29..da9bf0c828 100644 --- a/src/quick/items/items.qrc +++ b/src/quick/items/items.qrc @@ -8,5 +8,9 @@ <file>shaders/shadereffect_core.vert</file> <file>shaders/shadereffectfallback_core.frag</file> <file>shaders/shadereffectfallback_core.vert</file> + <file>shaders/lineargradient.vert</file> + <file>shaders/lineargradient.frag</file> + <file>shaders/lineargradient_core.vert</file> + <file>shaders/lineargradient_core.frag</file> </qresource> </RCC> diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index dbe30fbc83..b0d7f7f8a3 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -70,6 +70,7 @@ #if QT_CONFIG(quick_path) #include <private/qquickpath_p.h> #include <private/qquickpathinterpolator_p.h> +#include "qquickpathitem_p.h" #endif #if QT_CONFIG(quick_positioners) #include "qquickpositioners_p.h" @@ -370,6 +371,14 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #endif qmlRegisterType<QQuickMouseArea, 9>(uri, 2, 9, "MouseArea"); + +#if QT_CONFIG(quick_path) + qmlRegisterType<QQuickPathMove>(uri, 2, 9, "PathMove"); + qmlRegisterType<QQuickPathItem>(uri, 2, 9, "PathItem"); + qmlRegisterType<QQuickPathGradientStop>(uri, 2, 9, "PathGradientStop"); + qmlRegisterUncreatableType<QQuickPathGradient>(uri, 2, 9, "PathGradient", QQuickPathGradient::tr("PathGradient is an abstract base class")); + qmlRegisterType<QQuickPathLinearGradient>(uri, 2, 9, "PathLinearGradient"); +#endif } static void initResources() diff --git a/src/quick/items/qquickpathitem.cpp b/src/quick/items/qquickpathitem.cpp new file mode 100644 index 0000000000..0d2c7a8bbe --- /dev/null +++ b/src/quick/items/qquickpathitem.cpp @@ -0,0 +1,792 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitem_p.h" +#include "qquickpathitem_p_p.h" +#include "qquickpathitemgenericrenderer_p.h" +#include "qquickpathitemnvprrenderer_p.h" +#include "qquickpathitemsoftwarerenderer_p.h" +#include <private/qsgtexture_p.h> +#include <QtGui/private/qdrawhelper_p.h> +#include <QOpenGLFunctions> + +QT_BEGIN_NAMESPACE + +QQuickPathItemPrivate::QQuickPathItemPrivate() + : rendererType(QQuickPathItem::UnknownRenderer), + renderer(nullptr), + path(nullptr), + dirty(DirtyAll), + strokeColor(Qt::white), + strokeWidth(1), + fillColor(Qt::white), + fillRule(QQuickPathItem::OddEvenFill), + joinStyle(QQuickPathItem::BevelJoin), + miterLimit(2), + capStyle(QQuickPathItem::SquareCap), + strokeStyle(QQuickPathItem::SolidLine), + dashOffset(0), + fillGradient(nullptr) +{ + dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space +} + +QQuickPathItemPrivate::~QQuickPathItemPrivate() +{ + delete renderer; +} + +/*! + \qmltype PathItem + \instantiates QQuickPathItem + \inqmlmodule QtQuick + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits Item + \brief Renders a path + + Renders a path either by generating geometry via QPainterPath and manual + triangulation or by using an extension like \c{GL_NV_path_rendering}. + + This approach is different from rendering shapes via QQuickPaintedItem or + the 2D Canvas because the path never gets rasterized in software. Therefore + it is suitable for creating shapes spreading over larger areas of the + screen, avoiding the performance penalty for texture uploads or framebuffer + blits. + + Nonetheless it is important to be aware of performance implications, in + particular when the application is running on the generic PathItem + implementation due to not having support for accelerated path rendering. + The geometry generation happens entirely on the CPU in this case, and this + is potentially expensive. Changing the set of path elements, changing the + properties of these elements, or changing certain properties of the + PathItem itself all lead to retriangulation on every change. Therefore, + applying animation to such properties can heavily affect performance on + less powerful systems. If animating properties other than stroke and fill + colors is a must, it is recommended to target systems providing + \c{GL_NV_path_rendering} where the cost of path property changes is much + smaller. + + \note The types for specifying path elements are shared between PathView + and PathItem. However, not all PathItem implementations support all path + element types, while some may not make sense for PathView. PathItem's + currently supported subset is: PathMove, PathLine, PathQuad, PathCubic, + PathArc. + + \sa Path, PathMove, PathLine, PathQuad, PathCubic, PathArc +*/ + +QQuickPathItem::QQuickPathItem(QQuickItem *parent) + : QQuickItem(*(new QQuickPathItemPrivate), parent) +{ + setFlag(ItemHasContents); +} + +QQuickPathItem::~QQuickPathItem() +{ +} + +QQuickPathItem::RendererType QQuickPathItem::rendererType() const +{ + Q_D(const QQuickPathItem); + return d->rendererType; +} + +/*! + \qmlproperty Path QtQuick::PathItem::path + This property holds the path to be rendered. + For more information see the \l Path documentation. +*/ +QQuickPath *QQuickPathItem::path() const +{ + Q_D(const QQuickPathItem); + return d->path; +} + +void QQuickPathItem::setPath(QQuickPath *path) +{ + Q_D(QQuickPathItem); + if (d->path == path) + return; + + if (d->path) + qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()), + this, QQuickPathItem, SLOT(_q_pathChanged())); + d->path = path; + qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()), + this, QQuickPathItem, SLOT(_q_pathChanged())); + + d->dirty |= QQuickPathItemPrivate::DirtyPath; + emit pathChanged(); + polish(); +} + +void QQuickPathItemPrivate::_q_pathChanged() +{ + Q_Q(QQuickPathItem); + dirty |= DirtyPath; + q->polish(); +} + +QColor QQuickPathItem::strokeColor() const +{ + Q_D(const QQuickPathItem); + return d->strokeColor; +} + +void QQuickPathItem::setStrokeColor(const QColor &color) +{ + Q_D(QQuickPathItem); + if (d->strokeColor != color) { + d->strokeColor = color; + d->dirty |= QQuickPathItemPrivate::DirtyStrokeColor; + emit strokeColorChanged(); + polish(); + } +} + +qreal QQuickPathItem::strokeWidth() const +{ + Q_D(const QQuickPathItem); + return d->strokeWidth; +} + +void QQuickPathItem::setStrokeWidth(qreal w) +{ + Q_D(QQuickPathItem); + if (d->strokeWidth != w) { + d->strokeWidth = w; + d->dirty |= QQuickPathItemPrivate::DirtyStrokeWidth; + emit strokeWidthChanged(); + polish(); + } +} + +QColor QQuickPathItem::fillColor() const +{ + Q_D(const QQuickPathItem); + return d->fillColor; +} + +void QQuickPathItem::setFillColor(const QColor &color) +{ + Q_D(QQuickPathItem); + if (d->fillColor != color) { + d->fillColor = color; + d->dirty |= QQuickPathItemPrivate::DirtyFillColor; + emit fillColorChanged(); + polish(); + } +} + +QQuickPathItem::FillRule QQuickPathItem::fillRule() const +{ + Q_D(const QQuickPathItem); + return d->fillRule; +} + +void QQuickPathItem::setFillRule(FillRule fillRule) +{ + Q_D(QQuickPathItem); + if (d->fillRule != fillRule) { + d->fillRule = fillRule; + d->dirty |= QQuickPathItemPrivate::DirtyFillRule; + emit fillRuleChanged(); + polish(); + } +} + +QQuickPathItem::JoinStyle QQuickPathItem::joinStyle() const +{ + Q_D(const QQuickPathItem); + return d->joinStyle; +} + +void QQuickPathItem::setJoinStyle(JoinStyle style) +{ + Q_D(QQuickPathItem); + if (d->joinStyle != style) { + d->joinStyle = style; + d->dirty |= QQuickPathItemPrivate::DirtyStyle; + emit joinStyleChanged(); + polish(); + } +} + +int QQuickPathItem::miterLimit() const +{ + Q_D(const QQuickPathItem); + return d->miterLimit; +} + +void QQuickPathItem::setMiterLimit(int limit) +{ + Q_D(QQuickPathItem); + if (d->miterLimit != limit) { + d->miterLimit = limit; + d->dirty |= QQuickPathItemPrivate::DirtyStyle; + emit miterLimitChanged(); + polish(); + } +} + +QQuickPathItem::CapStyle QQuickPathItem::capStyle() const +{ + Q_D(const QQuickPathItem); + return d->capStyle; +} + +void QQuickPathItem::setCapStyle(CapStyle style) +{ + Q_D(QQuickPathItem); + if (d->capStyle != style) { + d->capStyle = style; + d->dirty |= QQuickPathItemPrivate::DirtyStyle; + emit capStyleChanged(); + polish(); + } +} + +QQuickPathItem::StrokeStyle QQuickPathItem::strokeStyle() const +{ + Q_D(const QQuickPathItem); + return d->strokeStyle; +} + +void QQuickPathItem::setStrokeStyle(StrokeStyle style) +{ + Q_D(QQuickPathItem); + if (d->strokeStyle != style) { + d->strokeStyle = style; + d->dirty |= QQuickPathItemPrivate::DirtyDash; + emit strokeStyleChanged(); + polish(); + } +} + +qreal QQuickPathItem::dashOffset() const +{ + Q_D(const QQuickPathItem); + return d->dashOffset; +} + +void QQuickPathItem::setDashOffset(qreal offset) +{ + Q_D(QQuickPathItem); + if (d->dashOffset != offset) { + d->dashOffset = offset; + d->dirty |= QQuickPathItemPrivate::DirtyDash; + emit dashOffsetChanged(); + polish(); + } +} + +QVector<qreal> QQuickPathItem::dashPattern() const +{ + Q_D(const QQuickPathItem); + return d->dashPattern; +} + +void QQuickPathItem::setDashPattern(const QVector<qreal> &array) +{ + Q_D(QQuickPathItem); + if (d->dashPattern != array) { + d->dashPattern = array; + d->dirty |= QQuickPathItemPrivate::DirtyDash; + emit dashPatternChanged(); + polish(); + } +} + +QQuickPathGradient *QQuickPathItem::fillGradient() const +{ + Q_D(const QQuickPathItem); + return d->fillGradient; +} + +void QQuickPathItem::setFillGradient(QQuickPathGradient *gradient) +{ + Q_D(QQuickPathItem); + if (d->fillGradient != gradient) { + if (d->fillGradient) + qmlobject_disconnect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()), + this, QQuickPathItem, SLOT(_q_fillGradientChanged())); + d->fillGradient = gradient; + if (d->fillGradient) + qmlobject_connect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()), + this, QQuickPathItem, SLOT(_q_fillGradientChanged())); + d->dirty |= QQuickPathItemPrivate::DirtyFillGradient; + polish(); + } +} + +void QQuickPathItemPrivate::_q_fillGradientChanged() +{ + Q_Q(QQuickPathItem); + dirty |= DirtyFillGradient; + q->polish(); +} + +void QQuickPathItem::resetFillGradient() +{ + setFillGradient(nullptr); +} + +void QQuickPathItem::updatePolish() +{ + Q_D(QQuickPathItem); + + if (!d->dirty) + return; + + if (!d->renderer) { + d->createRenderer(); + if (!d->renderer) + return; + emit rendererChanged(); + } + + // endSync() is where expensive calculations may happen, depending on the + // backend. Therefore do this only when the item is visible. + if (isVisible()) + d->sync(); + + update(); +} + +void QQuickPathItem::itemChange(ItemChange change, const ItemChangeData &data) +{ + // sync may have been deferred; do it now if the item became visible + if (change == ItemVisibleHasChanged && data.boolValue) + polish(); + + QQuickItem::itemChange(change, data); +} + +QSGNode *QQuickPathItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) +{ + // Called on the render thread, with the gui thread blocked. We can now + // safely access gui thread data. + + Q_D(QQuickPathItem); + if (d->renderer) { + if (!node) + node = d->createRenderNode(); + d->renderer->updatePathRenderNode(); + } + return node; +} + +// the renderer object lives on the gui thread +void QQuickPathItemPrivate::createRenderer() +{ + Q_Q(QQuickPathItem); + QSGRendererInterface *ri = q->window()->rendererInterface(); + if (!ri) + return; + + switch (ri->graphicsApi()) { +#ifndef QT_NO_OPENGL + case QSGRendererInterface::OpenGL: + if (QQuickPathItemNvprRenderNode::isSupported()) { + rendererType = QQuickPathItem::NvprRenderer; + renderer = new QQuickPathItemNvprRenderer; + } else { + rendererType = QQuickPathItem::GeometryRenderer; + renderer = new QQuickPathItemGenericRenderer(q); + } + break; +#endif + case QSGRendererInterface::Software: + rendererType = QQuickPathItem::SoftwareRenderer; + renderer = new QQuickPathItemSoftwareRenderer; + break; + default: + qWarning("No path backend for this graphics API yet"); + break; + } +} + +// the node lives on the render thread +QSGNode *QQuickPathItemPrivate::createRenderNode() +{ + Q_Q(QQuickPathItem); + QSGNode *node = nullptr; + if (!q->window()) + return node; + QSGRendererInterface *ri = q->window()->rendererInterface(); + if (!ri) + return node; + + const bool hasFill = fillColor != Qt::transparent; + const bool hasStroke = !qFuzzyIsNull(strokeWidth) && strokeColor != Qt::transparent; + + switch (ri->graphicsApi()) { +#ifndef QT_NO_OPENGL + case QSGRendererInterface::OpenGL: + if (QQuickPathItemNvprRenderNode::isSupported()) { + node = new QQuickPathItemNvprRenderNode(q); + static_cast<QQuickPathItemNvprRenderer *>(renderer)->setNode( + static_cast<QQuickPathItemNvprRenderNode *>(node)); + } else { + node = new QQuickPathItemGenericRootRenderNode(q->window(), hasFill, hasStroke); + static_cast<QQuickPathItemGenericRenderer *>(renderer)->setRootNode( + static_cast<QQuickPathItemGenericRootRenderNode *>(node)); + } + break; +#endif + case QSGRendererInterface::Software: + node = new QQuickPathItemSoftwareRenderNode(q); + static_cast<QQuickPathItemSoftwareRenderer *>(renderer)->setNode( + static_cast<QQuickPathItemSoftwareRenderNode *>(node)); + break; + default: + qWarning("No path backend for this graphics API yet"); + break; + } + + return node; +} + +void QQuickPathItemPrivate::sync() +{ + renderer->beginSync(); + + if (dirty & QQuickPathItemPrivate::DirtyPath) + renderer->setPath(path); + if (dirty & DirtyStrokeColor) + renderer->setStrokeColor(strokeColor); + if (dirty & DirtyStrokeWidth) + renderer->setStrokeWidth(strokeWidth); + if (dirty & DirtyFillColor) + renderer->setFillColor(fillColor); + if (dirty & DirtyFillRule) + renderer->setFillRule(fillRule); + if (dirty & DirtyStyle) { + renderer->setJoinStyle(joinStyle, miterLimit); + renderer->setCapStyle(capStyle); + } + if (dirty & DirtyDash) + renderer->setStrokeStyle(strokeStyle, dashOffset, dashPattern); + if (dirty & DirtyFillGradient) + renderer->setFillGradient(fillGradient); + + renderer->endSync(); + dirty = 0; +} + +// ***** gradient support ***** + +QQuickPathGradientStop::QQuickPathGradientStop(QObject *parent) + : QObject(parent), + m_position(0), + m_color(Qt::black) +{ +} + +qreal QQuickPathGradientStop::position() const +{ + return m_position; +} + +void QQuickPathGradientStop::setPosition(qreal position) +{ + if (m_position != position) { + m_position = position; + if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(parent())) + emit grad->updated(); + } +} + +QColor QQuickPathGradientStop::color() const +{ + return m_color; +} + +void QQuickPathGradientStop::setColor(const QColor &color) +{ + if (m_color != color) { + m_color = color; + if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(parent())) + emit grad->updated(); + } +} + +QQuickPathGradient::QQuickPathGradient(QObject *parent) + : QObject(parent), + m_spread(PadSpread) +{ +} + +void QQuickPathGradient::appendStop(QQmlListProperty<QObject> *list, QObject *stop) +{ + QQuickPathGradientStop *sstop = qobject_cast<QQuickPathGradientStop *>(stop); + if (!sstop) { + qWarning("Gradient stop list only supports QQuickPathGradientStop elements"); + return; + } + QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(list->object); + Q_ASSERT(grad); + sstop->setParent(grad); + grad->m_stops.append(sstop); +} + +QQmlListProperty<QObject> QQuickPathGradient::stops() +{ + return QQmlListProperty<QObject>(this, nullptr, &QQuickPathGradient::appendStop, nullptr, nullptr, nullptr); +} + +QGradientStops QQuickPathGradient::sortedGradientStops() const +{ + QGradientStops result; + for (int i = 0; i < m_stops.count(); ++i) { + QQuickPathGradientStop *s = static_cast<QQuickPathGradientStop *>(m_stops[i]); + int j = 0; + while (j < result.count() && result[j].first < s->position()) + ++j; + result.insert(j, QGradientStop(s->position(), s->color())); + } + return result; +} + +QQuickPathGradient::SpreadMode QQuickPathGradient::spread() const +{ + return m_spread; +} + +void QQuickPathGradient::setSpread(SpreadMode mode) +{ + if (m_spread != mode) { + m_spread = mode; + emit spreadChanged(); + emit updated(); + } +} + +QQuickPathLinearGradient::QQuickPathLinearGradient(QObject *parent) + : QQuickPathGradient(parent) +{ +} + +qreal QQuickPathLinearGradient::x1() const +{ + return m_start.x(); +} + +void QQuickPathLinearGradient::setX1(qreal v) +{ + if (m_start.x() != v) { + m_start.setX(v); + emit x1Changed(); + emit updated(); + } +} + +qreal QQuickPathLinearGradient::y1() const +{ + return m_start.y(); +} + +void QQuickPathLinearGradient::setY1(qreal v) +{ + if (m_start.y() != v) { + m_start.setY(v); + emit y1Changed(); + emit updated(); + } +} + +qreal QQuickPathLinearGradient::x2() const +{ + return m_end.x(); +} + +void QQuickPathLinearGradient::setX2(qreal v) +{ + if (m_end.x() != v) { + m_end.setX(v); + emit x2Changed(); + emit updated(); + } +} + +qreal QQuickPathLinearGradient::y2() const +{ + return m_end.y(); +} + +void QQuickPathLinearGradient::setY2(qreal v) +{ + if (m_end.y() != v) { + m_end.setY(v); + emit y2Changed(); + emit updated(); + } +} + +#ifndef QT_NO_OPENGL + +// contexts sharing with each other get the same cache instance +class QQuickPathItemGradientCacheWrapper +{ +public: + QQuickPathItemGradientCache *get(QOpenGLContext *context) + { + return m_resource.value<QQuickPathItemGradientCache>(context); + } + +private: + QOpenGLMultiGroupSharedResource m_resource; +}; + +QQuickPathItemGradientCache *QQuickPathItemGradientCache::currentCache() +{ + static QQuickPathItemGradientCacheWrapper qt_path_gradient_caches; + return qt_path_gradient_caches.get(QOpenGLContext::currentContext()); +} + +// let QOpenGLContext manage the lifetime of the cached textures +QQuickPathItemGradientCache::~QQuickPathItemGradientCache() +{ + m_cache.clear(); +} + +void QQuickPathItemGradientCache::invalidateResource() +{ + m_cache.clear(); +} + +void QQuickPathItemGradientCache::freeResource(QOpenGLContext *) +{ + qDeleteAll(m_cache); + m_cache.clear(); +} + +static void generateGradientColorTable(const QQuickPathItemGradientCache::GradientDesc &gradient, + uint *colorTable, int size, float opacity) +{ + int pos = 0; + const QGradientStops &s = gradient.stops; + const bool colorInterpolation = true; + + uint alpha = qRound(opacity * 256); + uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha); + qreal incr = 1.0 / qreal(size); + qreal fpos = 1.5 * incr; + colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color)); + + while (fpos <= s.first().first) { + colorTable[pos] = colorTable[pos - 1]; + pos++; + fpos += incr; + } + + if (colorInterpolation) + current_color = qPremultiply(current_color); + + const int sLast = s.size() - 1; + for (int i = 0; i < sLast; ++i) { + qreal delta = 1/(s[i+1].first - s[i].first); + uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha); + if (colorInterpolation) + next_color = qPremultiply(next_color); + + while (fpos < s[i+1].first && pos < size) { + int dist = int(256 * ((fpos - s[i].first) * delta)); + int idist = 256 - dist; + if (colorInterpolation) + colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); + else + colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); + ++pos; + fpos += incr; + } + current_color = next_color; + } + + Q_ASSERT(s.size() > 0); + + uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha))); + for ( ; pos < size; ++pos) + colorTable[pos] = last_color; + + colorTable[size-1] = last_color; +} + +QSGTexture *QQuickPathItemGradientCache::get(const GradientDesc &grad) +{ + QSGPlainTexture *tx = m_cache[grad]; + if (!tx) { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + GLuint id; + f->glGenTextures(1, &id); + f->glBindTexture(GL_TEXTURE_2D, id); + static const uint W = 1024; // texture size is 1024x1 + uint buf[W]; + generateGradientColorTable(grad, buf, W, 1.0f); + f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); + tx = new QSGPlainTexture; + tx->setTextureId(id); + switch (grad.spread) { + case QQuickPathGradient::PadSpread: + tx->setHorizontalWrapMode(QSGTexture::ClampToEdge); + tx->setVerticalWrapMode(QSGTexture::ClampToEdge); + break; + case QQuickPathGradient::RepeatSpread: + tx->setHorizontalWrapMode(QSGTexture::Repeat); + tx->setVerticalWrapMode(QSGTexture::Repeat); + break; + case QQuickPathGradient::ReflectSpread: + tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat); + tx->setVerticalWrapMode(QSGTexture::MirroredRepeat); + break; + default: + qWarning("Unknown gradient spread mode %d", grad.spread); + break; + } + m_cache[grad] = tx; + } + return tx; +} + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#include "moc_qquickpathitem_p.cpp" diff --git a/src/quick/items/qquickpathitem_p.h b/src/quick/items/qquickpathitem_p.h new file mode 100644 index 0000000000..39b407cf87 --- /dev/null +++ b/src/quick/items/qquickpathitem_p.h @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEM_P_H +#define QQUICKPATHITEM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickitem.h" + +#include <private/qtquickglobal_p.h> +#include <private/qquickpath_p.h> +#include <QGradientStops> + +QT_REQUIRE_CONFIG(quick_path); + +QT_BEGIN_NAMESPACE + +class QQuickPathItemPrivate; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathGradientStop : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal position READ position WRITE setPosition) + Q_PROPERTY(QColor color READ color WRITE setColor) + +public: + QQuickPathGradientStop(QObject *parent = nullptr); + + qreal position() const; + void setPosition(qreal position); + + QColor color() const; + void setColor(const QColor &color); + +private: + qreal m_position; + QColor m_color; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathGradient : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<QObject> stops READ stops) + Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + enum SpreadMode { + PadSpread, + RepeatSpread, + ReflectSpread + }; + Q_ENUM(SpreadMode) + + QQuickPathGradient(QObject *parent = nullptr); + + QQmlListProperty<QObject> stops(); + + QGradientStops sortedGradientStops() const; + + SpreadMode spread() const; + void setSpread(SpreadMode mode); + +signals: + void updated(); + void spreadChanged(); + +private: + static void appendStop(QQmlListProperty<QObject> *list, QObject *stop); + + QVector<QObject *> m_stops; + SpreadMode m_spread; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathLinearGradient : public QQuickPathGradient +{ + Q_OBJECT + Q_PROPERTY(qreal x1 READ x1 WRITE setX1 NOTIFY x1Changed) + Q_PROPERTY(qreal y1 READ y1 WRITE setY1 NOTIFY y1Changed) + Q_PROPERTY(qreal x2 READ x2 WRITE setX2 NOTIFY x2Changed) + Q_PROPERTY(qreal y2 READ y2 WRITE setY2 NOTIFY y2Changed) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + QQuickPathLinearGradient(QObject *parent = nullptr); + + qreal x1() const; + void setX1(qreal v); + qreal y1() const; + void setY1(qreal v); + qreal x2() const; + void setX2(qreal v); + qreal y2() const; + void setY2(qreal v); + +signals: + void x1Changed(); + void y1Changed(); + void x2Changed(); + void y2Changed(); + +private: + QPointF m_start; + QPointF m_end; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathItem : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(RendererType renderer READ rendererType NOTIFY rendererChanged) + + Q_PROPERTY(QQuickPath *path READ path WRITE setPath NOTIFY pathChanged) + + Q_PROPERTY(QColor strokeColor READ strokeColor WRITE setStrokeColor NOTIFY strokeColorChanged) + Q_PROPERTY(qreal strokeWidth READ strokeWidth WRITE setStrokeWidth NOTIFY strokeWidthChanged) + Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged) + Q_PROPERTY(FillRule fillRule READ fillRule WRITE setFillRule NOTIFY fillRuleChanged) + Q_PROPERTY(JoinStyle joinStyle READ joinStyle WRITE setJoinStyle NOTIFY joinStyleChanged) + Q_PROPERTY(int miterLimit READ miterLimit WRITE setMiterLimit NOTIFY miterLimitChanged) + Q_PROPERTY(CapStyle capStyle READ capStyle WRITE setCapStyle NOTIFY capStyleChanged) + Q_PROPERTY(StrokeStyle strokeStyle READ strokeStyle WRITE setStrokeStyle NOTIFY strokeStyleChanged) + Q_PROPERTY(qreal dashOffset READ dashOffset WRITE setDashOffset NOTIFY dashOffsetChanged) + Q_PROPERTY(QVector<qreal> dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged) + Q_PROPERTY(QQuickPathGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient) + +public: + enum FillRule { + OddEvenFill = Qt::OddEvenFill, + WindingFill = Qt::WindingFill + }; + Q_ENUM(FillRule) + + enum JoinStyle { + MiterJoin = Qt::MiterJoin, + BevelJoin = Qt::BevelJoin, + RoundJoin = Qt::RoundJoin + }; + Q_ENUM(JoinStyle) + + enum CapStyle { + FlatCap = Qt::FlatCap, + SquareCap = Qt::SquareCap, + RoundCap = Qt::RoundCap + }; + Q_ENUM(CapStyle) + + enum StrokeStyle { + SolidLine = Qt::SolidLine, + DashLine = Qt::DashLine + }; + Q_ENUM(StrokeStyle) + + enum RendererType { + UnknownRenderer, + GeometryRenderer, + NvprRenderer, + SoftwareRenderer + }; + Q_ENUM(RendererType) + + QQuickPathItem(QQuickItem *parent = nullptr); + ~QQuickPathItem(); + + RendererType rendererType() const; + + QQuickPath *path() const; + void setPath(QQuickPath *path); + + QColor strokeColor() const; + void setStrokeColor(const QColor &color); + + qreal strokeWidth() const; + void setStrokeWidth(qreal w); + + QColor fillColor() const; + void setFillColor(const QColor &color); + + FillRule fillRule() const; + void setFillRule(FillRule fillRule); + + JoinStyle joinStyle() const; + void setJoinStyle(JoinStyle style); + + int miterLimit() const; + void setMiterLimit(int limit); + + CapStyle capStyle() const; + void setCapStyle(CapStyle style); + + StrokeStyle strokeStyle() const; + void setStrokeStyle(StrokeStyle style); + + qreal dashOffset() const; + void setDashOffset(qreal offset); + + QVector<qreal> dashPattern() const; + void setDashPattern(const QVector<qreal> &array); + + QQuickPathGradient *fillGradient() const; + void setFillGradient(QQuickPathGradient *gradient); + void resetFillGradient(); + +protected: + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; + void updatePolish() override; + void itemChange(ItemChange change, const ItemChangeData &data) override; + +Q_SIGNALS: + void rendererChanged(); + void pathChanged(); + void strokeColorChanged(); + void strokeWidthChanged(); + void fillColorChanged(); + void fillRuleChanged(); + void joinStyleChanged(); + void miterLimitChanged(); + void capStyleChanged(); + void strokeStyleChanged(); + void dashOffsetChanged(); + void dashPatternChanged(); + void fillGradientChanged(); + +private: + Q_DISABLE_COPY(QQuickPathItem) + Q_DECLARE_PRIVATE(QQuickPathItem) + Q_PRIVATE_SLOT(d_func(), void _q_pathChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged()) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPathItem) + +#endif // QQUICKPATHITEM_P_H diff --git a/src/quick/items/qquickpathitem_p_p.h b/src/quick/items/qquickpathitem_p_p.h new file mode 100644 index 0000000000..366628d867 --- /dev/null +++ b/src/quick/items/qquickpathitem_p_p.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEM_P_P_H +#define QQUICKPATHITEM_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p.h" +#include "qquickitem_p.h" +#include <QPainterPath> +#include <QColor> +#include <QBrush> +#include <private/qopenglcontext_p.h> + +QT_BEGIN_NAMESPACE + +class QSGPlainTexture; + +class QQuickAbstractPathRenderer +{ +public: + virtual ~QQuickAbstractPathRenderer() { } + + // Gui thread + virtual void beginSync() = 0; + virtual void setPath(const QQuickPath *path) = 0; + virtual void setStrokeColor(const QColor &color) = 0; + virtual void setStrokeWidth(qreal w) = 0; + virtual void setFillColor(const QColor &color) = 0; + virtual void setFillRule(QQuickPathItem::FillRule fillRule) = 0; + virtual void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) = 0; + virtual void setCapStyle(QQuickPathItem::CapStyle capStyle) = 0; + virtual void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) = 0; + virtual void setFillGradient(QQuickPathGradient *gradient) = 0; + virtual void endSync() = 0; + + // Render thread, with gui blocked + virtual void updatePathRenderNode() = 0; +}; + +class QQuickPathItemPrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickPathItem) + +public: + enum Dirty { + DirtyPath = 0x01, + DirtyStrokeColor = 0x02, + DirtyStrokeWidth = 0x04, + DirtyFillColor = 0x08, + DirtyFillRule = 0x10, + DirtyStyle = 0x20, + DirtyDash = 0x40, + DirtyFillGradient = 0x80, + + DirtyAll = 0xFF + }; + + QQuickPathItemPrivate(); + ~QQuickPathItemPrivate(); + + void createRenderer(); + QSGNode *createRenderNode(); + void sync(); + + void _q_pathChanged(); + void _q_fillGradientChanged(); + + QQuickPathItem::RendererType rendererType; + QQuickAbstractPathRenderer *renderer; + QQuickPath *path; + int dirty; + QColor strokeColor; + qreal strokeWidth; + QColor fillColor; + QQuickPathItem::FillRule fillRule; + QQuickPathItem::JoinStyle joinStyle; + int miterLimit; + QQuickPathItem::CapStyle capStyle; + QQuickPathItem::StrokeStyle strokeStyle; + qreal dashOffset; + QVector<qreal> dashPattern; + QQuickPathGradient *fillGradient; +}; + +#ifndef QT_NO_OPENGL + +class QQuickPathItemGradientCache : public QOpenGLSharedResource +{ +public: + struct GradientDesc { + QGradientStops stops; + QPointF start; + QPointF end; + QQuickPathGradient::SpreadMode spread; + bool operator==(const GradientDesc &other) const + { + return start == other.start && end == other.end && spread == other.spread + && stops == other.stops; + } + }; + + QQuickPathItemGradientCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { } + ~QQuickPathItemGradientCache(); + + void invalidateResource() override; + void freeResource(QOpenGLContext *) override; + + QSGTexture *get(const GradientDesc &grad); + + static QQuickPathItemGradientCache *currentCache(); + +private: + QHash<GradientDesc, QSGPlainTexture *> m_cache; +}; + +inline uint qHash(const QQuickPathItemGradientCache::GradientDesc &v, uint seed = 0) +{ + uint h = seed; + h += v.start.x() + v.end.y() + v.spread; + for (int i = 0; i < 3 && i < v.stops.count(); ++i) + h += v.stops[i].second.rgba(); + return h; +} + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/items/qquickpathitemgenericrenderer.cpp b/src/quick/items/qquickpathitemgenericrenderer.cpp new file mode 100644 index 0000000000..9bd03c0e51 --- /dev/null +++ b/src/quick/items/qquickpathitemgenericrenderer.cpp @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitemgenericrenderer_p.h" +#include <QtGui/private/qtriangulator_p.h> +#include <QSGVertexColorMaterial> + +QT_BEGIN_NAMESPACE + +static const qreal SCALE = 100; + +struct ColoredVertex // must match QSGGeometry::ColoredPoint2D +{ + float x, y; + QQuickPathItemGenericRenderer::Color4ub color; + void set(float nx, float ny, QQuickPathItemGenericRenderer::Color4ub ncolor) + { + x = nx; y = ny; color = ncolor; + } +}; + +static inline QQuickPathItemGenericRenderer::Color4ub colorToColor4ub(const QColor &c) +{ + QQuickPathItemGenericRenderer::Color4ub color = { + uchar(qRound(c.redF() * c.alphaF() * 255)), + uchar(qRound(c.greenF() * c.alphaF() * 255)), + uchar(qRound(c.blueF() * c.alphaF() * 255)), + uchar(qRound(c.alphaF() * 255)) + }; + return color; +} + +QQuickPathItemGenericRootRenderNode::QQuickPathItemGenericRootRenderNode(QQuickWindow *window, + bool hasFill, + bool hasStroke) + : m_fillNode(nullptr), + m_strokeNode(nullptr) +{ + if (hasFill) { + m_fillNode = new QQuickPathItemGenericRenderNode(window, this); + appendChildNode(m_fillNode); + } + if (hasStroke) { + m_strokeNode = new QQuickPathItemGenericRenderNode(window, this); + appendChildNode(m_strokeNode); + } +} + +QQuickPathItemGenericRootRenderNode::~QQuickPathItemGenericRootRenderNode() +{ +} + +QQuickPathItemGenericRenderNode::QQuickPathItemGenericRenderNode(QQuickWindow *window, + QQuickPathItemGenericRootRenderNode *rootNode) + : m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0), + m_window(window), + m_rootNode(rootNode), + m_material(nullptr) +{ + setGeometry(&m_geometry); + activateMaterial(MatSolidColor); +} + +QQuickPathItemGenericRenderNode::~QQuickPathItemGenericRenderNode() +{ +} + +void QQuickPathItemGenericRenderNode::activateMaterial(Material m) +{ + switch (m) { + case MatSolidColor: + // Use vertexcolor material. Items with different colors remain batchable + // this way, at the expense of having to provide per-vertex color values. + if (!m_solidColorMaterial) + m_solidColorMaterial.reset(QQuickPathItemGenericMaterialFactory::createVertexColor(m_window)); + m_material = m_solidColorMaterial.data(); + break; + case MatLinearGradient: + if (!m_linearGradientMaterial) + m_linearGradientMaterial.reset(QQuickPathItemGenericMaterialFactory::createLinearGradient(m_window, this)); + m_material = m_linearGradientMaterial.data(); + break; + default: + qWarning("Unknown material %d", m); + return; + } + + if (material() != m_material) + setMaterial(m_material); +} + +// sync, and so triangulation too, happens on the gui thread +void QQuickPathItemGenericRenderer::beginSync() +{ + m_syncDirty = 0; +} + +void QQuickPathItemGenericRenderer::setPath(const QQuickPath *path) +{ + m_path = path ? path->path() : QPainterPath(); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setStrokeColor(const QColor &color) +{ + m_strokeColor = colorToColor4ub(color); + m_syncDirty |= DirtyColor; +} + +void QQuickPathItemGenericRenderer::setStrokeWidth(qreal w) +{ + m_pen.setWidthF(w); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setFillColor(const QColor &color) +{ + m_fillColor = colorToColor4ub(color); + m_syncDirty |= DirtyColor; +} + +void QQuickPathItemGenericRenderer::setFillRule(QQuickPathItem::FillRule fillRule) +{ + m_fillRule = Qt::FillRule(fillRule); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) +{ + m_pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); + m_pen.setMiterLimit(miterLimit); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle) +{ + m_pen.setCapStyle(Qt::PenCapStyle(capStyle)); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) +{ + m_pen.setStyle(Qt::PenStyle(strokeStyle)); + if (strokeStyle == QQuickPathItem::DashLine) { + m_pen.setDashPattern(dashPattern); + m_pen.setDashOffset(dashOffset); + } + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setFillGradient(QQuickPathGradient *gradient) +{ + m_fillGradientActive = gradient != nullptr; + if (gradient) { + m_fillGradient.stops = gradient->sortedGradientStops(); + m_fillGradient.spread = gradient->spread(); + if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) { + m_fillGradient.start = QPointF(g->x1(), g->y1()); + m_fillGradient.end = QPointF(g->x2(), g->y2()); + } else { + Q_UNREACHABLE(); + } + } + m_syncDirty |= DirtyFillGradient; +} + +void QQuickPathItemGenericRenderer::endSync() +{ + if (!m_syncDirty) + return; + + // Use a shadow dirty flag in order to avoid losing state in case there are + // multiple syncs with different dirty flags before we get to + // updatePathRenderNode() on the render thread (with the gui thread + // blocked). For our purposes here m_syncDirty is still required since + // geometry regeneration must only happen when there was an actual change + // in this particular sync round. + m_effectiveDirty |= m_syncDirty; + + if (m_path.isEmpty()) { + m_fillVertices.clear(); + m_fillIndices.clear(); + m_strokeVertices.clear(); + return; + } + + triangulateFill(); + triangulateStroke(); +} + +void QQuickPathItemGenericRenderer::triangulateFill() +{ + m_path.setFillRule(m_fillRule); + + const QVectorPath &vp = qtVectorPathForPath(m_path); + + QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(SCALE, SCALE)); + const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2 + m_fillVertices.resize(vertexCount); + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(m_fillVertices.data()); + const qreal *vsrc = ts.vertices.constData(); + for (int i = 0; i < vertexCount; ++i) + vdst[i].set(vsrc[i * 2] / SCALE, vsrc[i * 2 + 1] / SCALE, m_fillColor); + + m_fillIndices.resize(ts.indices.size()); + quint16 *idst = m_fillIndices.data(); + if (ts.indices.type() == QVertexIndexVector::UnsignedShort) { + memcpy(idst, ts.indices.data(), m_fillIndices.count() * sizeof(quint16)); + } else { + const quint32 *isrc = (const quint32 *) ts.indices.data(); + for (int i = 0; i < m_fillIndices.count(); ++i) + idst[i] = isrc[i]; + } +} + +void QQuickPathItemGenericRenderer::triangulateStroke() +{ + const QVectorPath &vp = qtVectorPathForPath(m_path); + + const QRectF clip(0, 0, m_item->width(), m_item->height()); + const qreal inverseScale = 1.0 / SCALE; + m_stroker.setInvScale(inverseScale); + if (m_pen.style() == Qt::SolidLine) { + m_stroker.process(vp, m_pen, clip, 0); + } else { + m_dashStroker.setInvScale(inverseScale); + m_dashStroker.process(vp, m_pen, clip, 0); + QVectorPath dashStroke(m_dashStroker.points(), m_dashStroker.elementCount(), + m_dashStroker.elementTypes(), 0); + m_stroker.process(dashStroke, m_pen, clip, 0); + } + + if (!m_stroker.vertexCount()) { + m_strokeVertices.clear(); + return; + } + + const int vertexCount = m_stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2 + m_strokeVertices.resize(vertexCount); + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(m_strokeVertices.data()); + const float *vsrc = m_stroker.vertices(); + for (int i = 0; i < vertexCount; ++i) + vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], m_strokeColor); +} + +void QQuickPathItemGenericRenderer::setRootNode(QQuickPathItemGenericRootRenderNode *rn) +{ + if (m_rootNode != rn) { + m_rootNode = rn; + // Scenegraph nodes can be destroyed and then replaced by new ones over + // time; hence it is important to mark everything dirty for + // updatePathRenderNode(). We can assume the renderer has a full sync + // of the data at this point. + m_effectiveDirty = DirtyAll; + } +} + +// on the render thread with gui blocked +void QQuickPathItemGenericRenderer::updatePathRenderNode() +{ + if (!m_effectiveDirty || !m_rootNode) + return; + + if (m_fillColor.a == 0) { + delete m_rootNode->m_fillNode; + m_rootNode->m_fillNode = nullptr; + } else if (!m_rootNode->m_fillNode) { + m_rootNode->m_fillNode = new QQuickPathItemGenericRenderNode(m_item->window(), m_rootNode); + if (m_rootNode->m_strokeNode) + m_rootNode->removeChildNode(m_rootNode->m_strokeNode); + m_rootNode->appendChildNode(m_rootNode->m_fillNode); + if (m_rootNode->m_strokeNode) + m_rootNode->appendChildNode(m_rootNode->m_strokeNode); + m_effectiveDirty |= DirtyGeom; + } + + if (qFuzzyIsNull(m_pen.widthF()) || m_strokeColor.a == 0) { + delete m_rootNode->m_strokeNode; + m_rootNode->m_strokeNode = nullptr; + } else if (!m_rootNode->m_strokeNode) { + m_rootNode->m_strokeNode = new QQuickPathItemGenericRenderNode(m_item->window(), m_rootNode); + m_rootNode->appendChildNode(m_rootNode->m_strokeNode); + m_effectiveDirty |= DirtyGeom; + } + + updateFillNode(); + updateStrokeNode(); + + m_effectiveDirty = 0; +} + +void QQuickPathItemGenericRenderer::updateFillNode() +{ + if (!m_rootNode->m_fillNode) + return; + + QQuickPathItemGenericRenderNode *n = m_rootNode->m_fillNode; + QSGGeometry *g = &n->m_geometry; + if (m_fillVertices.isEmpty()) { + g->allocate(0, 0); + n->markDirty(QSGNode::DirtyGeometry); + return; + } + + if (m_fillGradientActive) { + n->activateMaterial(QQuickPathItemGenericRenderNode::MatLinearGradient); + if (m_effectiveDirty & DirtyFillGradient) { + // Make a copy of the data that will be accessed by the material on + // the render thread. + n->m_fillGradient = m_fillGradient; + // Gradients are implemented via a texture-based material. + n->markDirty(QSGNode::DirtyMaterial); + // stop here if only the gradient changed; no need to touch the geometry + if (!(m_effectiveDirty & DirtyGeom)) + return; + } + } else { + n->activateMaterial(QQuickPathItemGenericRenderNode::MatSolidColor); + // fast path for updating only color values when no change in vertex positions + if ((m_effectiveDirty & DirtyColor) && !(m_effectiveDirty & DirtyGeom)) { + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData()); + for (int i = 0; i < g->vertexCount(); ++i) + vdst[i].set(vdst[i].x, vdst[i].y, m_fillColor); + n->markDirty(QSGNode::DirtyGeometry); + return; + } + } + + g->allocate(m_fillVertices.count(), m_fillIndices.count()); + g->setDrawingMode(QSGGeometry::DrawTriangles); + memcpy(g->vertexData(), m_fillVertices.constData(), g->vertexCount() * g->sizeOfVertex()); + memcpy(g->indexData(), m_fillIndices.constData(), g->indexCount() * g->sizeOfIndex()); + + n->markDirty(QSGNode::DirtyGeometry); +} + +void QQuickPathItemGenericRenderer::updateStrokeNode() +{ + if (!m_rootNode->m_strokeNode) + return; + if (m_effectiveDirty == DirtyFillGradient) // not applicable + return; + + QQuickPathItemGenericRenderNode *n = m_rootNode->m_strokeNode; + n->markDirty(QSGNode::DirtyGeometry); + + QSGGeometry *g = &n->m_geometry; + if (m_strokeVertices.isEmpty()) { + g->allocate(0, 0); + return; + } + + if ((m_effectiveDirty & DirtyColor) && !(m_effectiveDirty & DirtyGeom)) { + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData()); + for (int i = 0; i < g->vertexCount(); ++i) + vdst[i].set(vdst[i].x, vdst[i].y, m_strokeColor); + return; + } + + g->allocate(m_strokeVertices.count(), 0); + g->setDrawingMode(QSGGeometry::DrawTriangleStrip); + memcpy(g->vertexData(), m_strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex()); +} + +QSGMaterial *QQuickPathItemGenericMaterialFactory::createVertexColor(QQuickWindow *window) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#ifndef QT_NO_OPENGL + if (api == QSGRendererInterface::OpenGL) // ### so much for "generic"... + return new QSGVertexColorMaterial; +#endif + + qWarning("Vertex-color material: Unsupported graphics API %d", api); + return nullptr; +} + +QSGMaterial *QQuickPathItemGenericMaterialFactory::createLinearGradient(QQuickWindow *window, + QQuickPathItemGenericRenderNode *node) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#ifndef QT_NO_OPENGL + if (api == QSGRendererInterface::OpenGL) // ### so much for "generic"... + return new QQuickPathItemLinearGradientMaterial(node); +#endif + + qWarning("Linear gradient material: Unsupported graphics API %d", api); + return nullptr; +} + +#ifndef QT_NO_OPENGL + +QSGMaterialType QQuickPathItemLinearGradientShader::type; + +QQuickPathItemLinearGradientShader::QQuickPathItemLinearGradientShader() +{ + setShaderSourceFile(QOpenGLShader::Vertex, + QStringLiteral(":/qt-project.org/items/shaders/lineargradient.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, + QStringLiteral(":/qt-project.org/items/shaders/lineargradient.frag")); +} + +void QQuickPathItemLinearGradientShader::initialize() +{ + m_opacityLoc = program()->uniformLocation("opacity"); + m_matrixLoc = program()->uniformLocation("matrix"); + m_gradStartLoc = program()->uniformLocation("gradStart"); + m_gradEndLoc = program()->uniformLocation("gradEnd"); +} + +void QQuickPathItemLinearGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) +{ + QQuickPathItemLinearGradientMaterial *m = static_cast<QQuickPathItemLinearGradientMaterial *>(mat); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacityLoc, state.opacity()); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); + + QQuickPathItemGenericRenderNode *node = m->node(); + program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.start)); + program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.end)); + + QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(node->m_fillGradient); + tx->bind(); +} + +char const *const *QQuickPathItemLinearGradientShader::attributeNames() const +{ + static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; + return attr; +} + +int QQuickPathItemLinearGradientMaterial::compare(const QSGMaterial *other) const +{ + Q_ASSERT(other && type() == other->type()); + const QQuickPathItemLinearGradientMaterial *m = static_cast<const QQuickPathItemLinearGradientMaterial *>(other); + + QQuickPathItemGenericRenderNode *a = node(); + QQuickPathItemGenericRenderNode *b = m->node(); + Q_ASSERT(a && b); + if (a == b) + return 0; + + const QQuickPathItemGradientCache::GradientDesc *ga = &a->m_fillGradient; + const QQuickPathItemGradientCache::GradientDesc *gb = &b->m_fillGradient; + if (int d = ga->start.x() - gb->start.x()) + return d; + if (int d = ga->start.y() - gb->start.y()) + return d; + if (int d = ga->end.x() - gb->end.x()) + return d; + if (int d = ga->end.y() - gb->end.y()) + return d; + + if (int d = ga->stops.count() - gb->stops.count()) + return d; + + for (int i = 0; i < ga->stops.count(); ++i) { + if (int d = ga->stops[i].first - gb->stops[i].first) + return d; + if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba()) + return d; + } + + return 0; +} + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickpathitemgenericrenderer_p.h b/src/quick/items/qquickpathitemgenericrenderer_p.h new file mode 100644 index 0000000000..c186959c88 --- /dev/null +++ b/src/quick/items/qquickpathitemgenericrenderer_p.h @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEMGENERICRENDERER_P_H +#define QQUICKPATHITEMGENERICRENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p_p.h" +#include <qsgnode.h> +#include <qsggeometry.h> +#include <qsgmaterial.h> +#include <QtGui/private/qtriangulatingstroker_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickPathItemGenericRootRenderNode; + +class QQuickPathItemGenericRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyGeom = 0x01, + DirtyColor = 0x02, + DirtyFillGradient = 0x04, + + DirtyAll = 0xFF + }; + + QQuickPathItemGenericRenderer(QQuickItem *item) + : m_item(item), + m_rootNode(nullptr), + m_effectiveDirty(0) + { } + + void beginSync() override; + void setPath(const QQuickPath *path) override; + void setStrokeColor(const QColor &color) override; + void setStrokeWidth(qreal w) override; + void setFillColor(const QColor &color) override; + void setFillRule(QQuickPathItem::FillRule fillRule) override; + void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(QQuickPathItem::CapStyle capStyle) override; + void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) override; + void setFillGradient(QQuickPathGradient *gradient) override; + void endSync() override; + void updatePathRenderNode() override; + + void setRootNode(QQuickPathItemGenericRootRenderNode *rn); + + struct Color4ub { unsigned char r, g, b, a; }; + +private: + void triangulateFill(); + void triangulateStroke(); + void updateFillNode(); + void updateStrokeNode(); + + QQuickItem *m_item; + QQuickPathItemGenericRootRenderNode *m_rootNode; + QTriangulatingStroker m_stroker; + QDashedStrokeProcessor m_dashStroker; + + QPen m_pen; + Color4ub m_strokeColor; + Color4ub m_fillColor; + Qt::FillRule m_fillRule; + QPainterPath m_path; + bool m_fillGradientActive; + QQuickPathItemGradientCache::GradientDesc m_fillGradient; + + QVector<QSGGeometry::ColoredPoint2D> m_fillVertices; + QVector<quint16> m_fillIndices; + QVector<QSGGeometry::ColoredPoint2D> m_strokeVertices; + + int m_syncDirty; + int m_effectiveDirty; +}; + +class QQuickPathItemGenericRenderNode : public QSGGeometryNode +{ +public: + QQuickPathItemGenericRenderNode(QQuickWindow *window, QQuickPathItemGenericRootRenderNode *rootNode); + ~QQuickPathItemGenericRenderNode(); + + enum Material { + MatSolidColor, + MatLinearGradient + }; + + void activateMaterial(Material m); + + QQuickWindow *window() const { return m_window; } + QQuickPathItemGenericRootRenderNode *rootNode() const { return m_rootNode; } + + // shadow data for custom materials + QQuickPathItemGradientCache::GradientDesc m_fillGradient; + +private: + QSGGeometry m_geometry; + QQuickWindow *m_window; + QQuickPathItemGenericRootRenderNode *m_rootNode; + QSGMaterial *m_material; + QScopedPointer<QSGMaterial> m_solidColorMaterial; + QScopedPointer<QSGMaterial> m_linearGradientMaterial; + + friend class QQuickPathItemGenericRenderer; +}; + +class QQuickPathItemGenericRootRenderNode : public QSGNode +{ +public: + QQuickPathItemGenericRootRenderNode(QQuickWindow *window, bool hasFill, bool hasStroke); + ~QQuickPathItemGenericRootRenderNode(); + +private: + QQuickPathItemGenericRenderNode *m_fillNode; + QQuickPathItemGenericRenderNode *m_strokeNode; + + friend class QQuickPathItemGenericRenderer; +}; + +class QQuickPathItemGenericMaterialFactory +{ +public: + static QSGMaterial *createVertexColor(QQuickWindow *window); + static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickPathItemGenericRenderNode *node); +}; + +#ifndef QT_NO_OPENGL + +class QQuickPathItemLinearGradientShader : public QSGMaterialShader +{ +public: + QQuickPathItemLinearGradientShader(); + + void initialize() override; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; + + static QSGMaterialType type; + +private: + int m_opacityLoc; + int m_matrixLoc; + int m_gradStartLoc; + int m_gradEndLoc; +}; + +class QQuickPathItemLinearGradientMaterial : public QSGMaterial +{ +public: + QQuickPathItemLinearGradientMaterial(QQuickPathItemGenericRenderNode *node) + : m_node(node) + { + // Passing RequiresFullMatrix is essential in order to prevent the + // batch renderer from baking in simple, translate-only transforms into + // the vertex data. The shader will rely on the fact that + // vertexCoord.xy is the PathItem-space coordinate and so no modifications + // are welcome. + setFlag(Blending | RequiresFullMatrix); + } + + QSGMaterialType *type() const override + { + return &QQuickPathItemLinearGradientShader::type; + } + + int compare(const QSGMaterial *other) const override; + + QSGMaterialShader *createShader() const override + { + return new QQuickPathItemLinearGradientShader; + } + + QQuickPathItemGenericRenderNode *node() const { return m_node; } + +private: + QQuickPathItemGenericRenderNode *m_node; +}; + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif // QQUICKPATHITEMGENERICRENDERER_P_H diff --git a/src/quick/items/qquickpathitemnvprrenderer.cpp b/src/quick/items/qquickpathitemnvprrenderer.cpp new file mode 100644 index 0000000000..d07a63c86d --- /dev/null +++ b/src/quick/items/qquickpathitemnvprrenderer.cpp @@ -0,0 +1,567 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitemnvprrenderer_p.h" +#include <QOpenGLExtraFunctions> +#include <private/qquickpath_p_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickPathItemNvprRenderer::beginSync() +{ + // nothing to do here +} + +void QQuickPathItemNvprRenderer::setPath(const QQuickPath *path) +{ + convertPath(path); + m_dirty |= DirtyPath; +} + +void QQuickPathItemNvprRenderer::setStrokeColor(const QColor &color) +{ + m_strokeColor = color; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setStrokeWidth(qreal w) +{ + m_strokeWidth = w; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setFillColor(const QColor &color) +{ + m_fillColor = color; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setFillRule(QQuickPathItem::FillRule fillRule) +{ + m_fillRule = fillRule; + m_dirty |= DirtyFillRule; +} + +void QQuickPathItemNvprRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) +{ + m_joinStyle = joinStyle; + m_miterLimit = miterLimit; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle) +{ + m_capStyle = capStyle; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) +{ + m_dashActive = strokeStyle == QQuickPathItem::DashLine; + m_dashOffset = dashOffset; + m_dashPattern = dashPattern; + m_dirty |= DirtyDash; +} + +void QQuickPathItemNvprRenderer::setFillGradient(QQuickPathGradient *gradient) +{ + m_fillGradientActive = gradient != nullptr; + if (gradient) { + m_fillGradient.stops = gradient->sortedGradientStops(); + m_fillGradient.spread = gradient->spread(); + if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) { + m_fillGradient.start = QPointF(g->x1(), g->y1()); + m_fillGradient.end = QPointF(g->x2(), g->y2()); + } else { + Q_UNREACHABLE(); + } + } + m_dirty |= DirtyFillGradient; +} + +void QQuickPathItemNvprRenderer::endSync() +{ + // nothing to do here +} + +void QQuickPathItemNvprRenderer::setNode(QQuickPathItemNvprRenderNode *node) +{ + if (m_node != node) { + m_node = node; + // Scenegraph nodes can be destroyed and then replaced by new ones over + // time; hence it is important to mark everything dirty for + // updatePathRenderNode(). We can assume the renderer has a full sync + // of the data at this point. + m_dirty = DirtyAll; + } +} + +QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path) +{ + QDebugStateSaver saver(debug); + debug.space().noquote(); + debug << "Path with" << path.cmd.count() << "commands"; + int ci = 0; + for (GLubyte cmd : path.cmd) { + static struct { GLubyte cmd; const char *s; int coordCount; } nameTab[] = { + { GL_MOVE_TO_NV, "moveTo", 2 }, + { GL_LINE_TO_NV, "lineTo", 2 }, + { GL_QUADRATIC_CURVE_TO_NV, "quadTo", 4 }, + { GL_CUBIC_CURVE_TO_NV, "cubicTo", 6 }, + { GL_LARGE_CW_ARC_TO_NV, "arcTo-large-CW", 5 }, + { GL_LARGE_CCW_ARC_TO_NV, "arcTo-large-CCW", 5 }, + { GL_SMALL_CW_ARC_TO_NV, "arcTo-small-CW", 5 }, + { GL_SMALL_CCW_ARC_TO_NV, "arcTo-small-CCW", 5 }, + { GL_CLOSE_PATH_NV, "closePath", 0 } }; + for (size_t i = 0; i < sizeof(nameTab) / sizeof(nameTab[0]); ++i) { + if (nameTab[i].cmd == cmd) { + QByteArray cs; + for (int j = 0; j < nameTab[i].coordCount; ++j) { + cs.append(QByteArray::number(path.coord[ci++])); + cs.append(' '); + } + debug << "\n " << nameTab[i].s << " " << cs; + break; + } + } + } + return debug; +} + +static inline void appendCoords(QVector<GLfloat> *v, QQuickCurve *c, QPointF *pos) +{ + QPointF p(c->hasRelativeX() ? pos->x() + c->relativeX() : c->x(), + c->hasRelativeY() ? pos->y() + c->relativeY() : c->y()); + v->append(p.x()); + v->append(p.y()); + *pos = p; +} + +static inline void appendControlCoords(QVector<GLfloat> *v, QQuickPathQuad *c, const QPointF &pos) +{ + QPointF p(c->hasRelativeControlX() ? pos.x() + c->relativeControlX() : c->controlX(), + c->hasRelativeControlY() ? pos.y() + c->relativeControlY() : c->controlY()); + v->append(p.x()); + v->append(p.y()); +} + +static inline void appendControl1Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos) +{ + QPointF p(c->hasRelativeControl1X() ? pos.x() + c->relativeControl1X() : c->control1X(), + c->hasRelativeControl1Y() ? pos.y() + c->relativeControl1Y() : c->control1Y()); + v->append(p.x()); + v->append(p.y()); +} + +static inline void appendControl2Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos) +{ + QPointF p(c->hasRelativeControl2X() ? pos.x() + c->relativeControl2X() : c->control2X(), + c->hasRelativeControl2Y() ? pos.y() + c->relativeControl2Y() : c->control2Y()); + v->append(p.x()); + v->append(p.y()); +} + +void QQuickPathItemNvprRenderer::convertPath(const QQuickPath *path) +{ + m_path = NvprPath(); + if (!path) + return; + + const QList<QQuickPathElement *> &pp(QQuickPathPrivate::get(path)->_pathElements); + if (pp.isEmpty()) + return; + + QPointF pos(path->startX(), path->startY()); + m_path.cmd.append(GL_MOVE_TO_NV); + m_path.coord.append(pos.x()); + m_path.coord.append(pos.y()); + + for (QQuickPathElement *e : pp) { + if (QQuickPathMove *o = qobject_cast<QQuickPathMove *>(e)) { + m_path.cmd.append(GL_MOVE_TO_NV); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathLine *o = qobject_cast<QQuickPathLine *>(e)) { + m_path.cmd.append(GL_LINE_TO_NV); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathQuad *o = qobject_cast<QQuickPathQuad *>(e)) { + m_path.cmd.append(GL_QUADRATIC_CURVE_TO_NV); + appendControlCoords(&m_path.coord, o, pos); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathCubic *o = qobject_cast<QQuickPathCubic *>(e)) { + m_path.cmd.append(GL_CUBIC_CURVE_TO_NV); + appendControl1Coords(&m_path.coord, o, pos); + appendControl2Coords(&m_path.coord, o, pos); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathArc *o = qobject_cast<QQuickPathArc *>(e)) { + const bool sweepFlag = o->direction() == QQuickPathArc::Clockwise; // maps to CCW, not a typo + GLenum cmd; + if (o->useLargeArc()) + cmd = sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV; + else + cmd = sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV; + m_path.cmd.append(cmd); + m_path.coord.append(o->radiusX()); + m_path.coord.append(o->radiusY()); + m_path.coord.append(0.0f); // X axis rotation + appendCoords(&m_path.coord, o, &pos); + } else { + qWarning() << "PathItem/NVPR: unsupported Path element" << e; + } + } + + if (qFuzzyCompare(pos.x(), path->startX()) && qFuzzyCompare(pos.y(), path->startY())) + m_path.cmd.append(GL_CLOSE_PATH_NV); +} + +static inline QVector4D qsg_premultiply(const QColor &c, float globalOpacity) +{ + const float o = c.alphaF() * globalOpacity; + return QVector4D(c.redF() * o, c.greenF() * o, c.blueF() * o, o); +} + +void QQuickPathItemNvprRenderer::updatePathRenderNode() +{ + // Called on the render thread with gui blocked -> update the node with its + // own copy of all relevant data. + + if (!m_dirty) + return; + + // updatePathRenderNode() can be called several times with different dirty + // state before render() gets invoked. So accumulate. + m_node->m_dirty |= m_dirty; + + if (m_dirty & DirtyPath) + m_node->m_source = m_path; + + if (m_dirty & DirtyStyle) { + m_node->m_strokeWidth = m_strokeWidth; + m_node->m_strokeColor = qsg_premultiply(m_strokeColor, 1.0f); + m_node->m_fillColor = qsg_premultiply(m_fillColor, 1.0f); + switch (m_joinStyle) { + case QQuickPathItem::MiterJoin: + m_node->m_joinStyle = GL_MITER_TRUNCATE_NV; + break; + case QQuickPathItem::BevelJoin: + m_node->m_joinStyle = GL_BEVEL_NV; + break; + case QQuickPathItem::RoundJoin: + m_node->m_joinStyle = GL_ROUND_NV; + break; + default: + Q_UNREACHABLE(); + } + m_node->m_miterLimit = m_miterLimit; + switch (m_capStyle) { + case QQuickPathItem::FlatCap: + m_node->m_capStyle = GL_FLAT; + break; + case QQuickPathItem::SquareCap: + m_node->m_capStyle = GL_SQUARE_NV; + break; + case QQuickPathItem::RoundCap: + m_node->m_capStyle = GL_ROUND_NV; + break; + default: + Q_UNREACHABLE(); + } + } + + if (m_dirty & DirtyFillRule) { + switch (m_fillRule) { + case QQuickPathItem::OddEvenFill: + m_node->m_fillRule = GL_COUNT_UP_NV; + break; + case QQuickPathItem::WindingFill: + m_node->m_fillRule = GL_INVERT; + break; + default: + Q_UNREACHABLE(); + } + } + + if (m_dirty & DirtyDash) { + m_node->m_dashOffset = m_dashOffset; + if (m_dashActive) { + m_node->m_dashPattern.resize(m_dashPattern.count()); + // Multiply by strokeWidth because the PathItem API follows QPen + // meaning the input dash pattern here is in width units. + for (int i = 0; i < m_dashPattern.count(); ++i) + m_node->m_dashPattern[i] = GLfloat(m_dashPattern[i]) * m_strokeWidth; + } else { + m_node->m_dashPattern.clear(); + } + } + + if (m_dirty & DirtyFillGradient) { + m_node->m_fillGradientActive = m_fillGradientActive; + if (m_fillGradientActive) + m_node->m_fillGradient = m_fillGradient; + } + + m_node->markDirty(QSGNode::DirtyMaterial); + m_dirty = 0; +} + +bool QQuickPathItemNvprRenderNode::nvprInited = false; +QQuickNvprFunctions QQuickPathItemNvprRenderNode::nvpr; +QQuickNvprMaterialManager QQuickPathItemNvprRenderNode::mtlmgr; + +QQuickPathItemNvprRenderNode::QQuickPathItemNvprRenderNode(QQuickPathItem *item) + : m_item(item) +{ +} + +QQuickPathItemNvprRenderNode::~QQuickPathItemNvprRenderNode() +{ + releaseResources(); +} + +void QQuickPathItemNvprRenderNode::releaseResources() +{ + if (m_path) { + nvpr.deletePaths(m_path, 1); + m_path = 0; + } +} + +void QQuickNvprMaterialManager::create(QQuickNvprFunctions *nvpr) +{ + m_nvpr = nvpr; +} + +void QQuickNvprMaterialManager::releaseResources() +{ + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + for (MaterialDesc &mtl : m_materials) { + if (mtl.ppl) { + f->glDeleteProgramPipelines(1, &mtl.ppl); + mtl = MaterialDesc(); + } + } +} + +QQuickNvprMaterialManager::MaterialDesc *QQuickNvprMaterialManager::activateMaterial(Material m) +{ + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + MaterialDesc &mtl(m_materials[m]); + + if (!mtl.ppl) { + if (m == MatSolid) { + static const char *fragSrc = + "#version 310 es\n" + "precision highp float;\n" + "out vec4 fragColor;\n" + "uniform vec4 color;\n" + "uniform float opacity;\n" + "void main() {\n" + " fragColor = color * opacity;\n" + "}\n"; + if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { + qWarning("NVPR: Failed to create shader pipeline for solid fill"); + return nullptr; + } + Q_ASSERT(mtl.ppl && mtl.prg); + mtl.uniLoc[0] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "color"); + Q_ASSERT(mtl.uniLoc[0] >= 0); + mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity"); + Q_ASSERT(mtl.uniLoc[1] >= 0); + } else if (m == MatLinearGradient) { + static const char *fragSrc = + "#version 310 es\n" + "precision highp float;\n" + "layout(location = 0) in vec2 uv;" + "uniform float opacity;\n" + "uniform sampler2D gradTab;\n" + "uniform vec2 gradStart;\n" + "uniform vec2 gradEnd;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec2 gradVec = gradEnd - gradStart;\n" + " float gradTabIndex = dot(gradVec, uv - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);\n" + " fragColor = texture(gradTab, vec2(gradTabIndex, 0.5)) * opacity;\n" + "}\n"; + if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { + qWarning("NVPR: Failed to create shader pipeline for linear gradient"); + return nullptr; + } + Q_ASSERT(mtl.ppl && mtl.prg); + mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity"); + Q_ASSERT(mtl.uniLoc[1] >= 0); + mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradStart"); + Q_ASSERT(mtl.uniLoc[2] >= 0); + mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradEnd"); + Q_ASSERT(mtl.uniLoc[3] >= 0); + } else { + Q_UNREACHABLE(); + } + } + + f->glBindProgramPipeline(mtl.ppl); + + return &mtl; +} + +void QQuickPathItemNvprRenderNode::updatePath() +{ + if (m_dirty & QQuickPathItemNvprRenderer::DirtyPath) { + if (!m_path) { + m_path = nvpr.genPaths(1); + Q_ASSERT(m_path != 0); + } + nvpr.pathCommands(m_path, m_source.cmd.count(), m_source.cmd.constData(), + m_source.coord.count(), GL_FLOAT, m_source.coord.constData()); + } + + if (m_dirty & QQuickPathItemNvprRenderer::DirtyStyle) { + nvpr.pathParameterf(m_path, GL_PATH_STROKE_WIDTH_NV, m_strokeWidth); + nvpr.pathParameteri(m_path, GL_PATH_JOIN_STYLE_NV, m_joinStyle); + nvpr.pathParameteri(m_path, GL_PATH_MITER_LIMIT_NV, m_miterLimit); + nvpr.pathParameteri(m_path, GL_PATH_END_CAPS_NV, m_capStyle); + nvpr.pathParameteri(m_path, GL_PATH_DASH_CAPS_NV, m_capStyle); + } + + if (m_dirty & QQuickPathItemNvprRenderer::DirtyDash) { + nvpr.pathParameterf(m_path, GL_PATH_DASH_OFFSET_NV, m_dashOffset); + // count == 0 -> no dash + nvpr.pathDashArray(m_path, m_dashPattern.count(), m_dashPattern.constData()); + } +} + +void QQuickPathItemNvprRenderNode::render(const RenderState *state) +{ + if (!nvprInited) { + if (!nvpr.create()) { + qWarning("NVPR init failed"); + return; + } + mtlmgr.create(&nvpr); + nvprInited = true; + } + + updatePath(); + + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + f->glUseProgram(0); + QQuickNvprMaterialManager::MaterialDesc *mtl; + if (m_fillGradientActive) + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient); + else + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); + if (!mtl) + return; + + // Assume stencil buffer is cleared to 0 for each frame. + // Within the frame dppass=GL_ZERO for glStencilOp ensures stencil is reset and so no need to clear. + f->glStencilMask(~0); + f->glEnable(GL_STENCIL_TEST); + f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + // Depth test against the opaque batches rendered before. + f->glEnable(GL_DEPTH_TEST); + f->glDepthFunc(GL_LESS); + nvpr.pathCoverDepthFunc(GL_LESS); + nvpr.pathStencilDepthOffset(-0.05f, -1); + + nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData()); + nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData()); + + if (state->scissorEnabled()) { + // scissor rect is already set, just enable scissoring + f->glEnable(GL_SCISSOR_TEST); + } + + if (!qFuzzyIsNull(m_fillColor.w()) || m_fillGradientActive) { + if (m_fillGradientActive) { + QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(m_fillGradient); + tx->bind(); + // uv = vec2(coeff[0] * x + coeff[1] * y + coeff[2], coeff[3] * x + coeff[4] * y + coeff[5]) + // where x and y are in path coordinate space, which is just what + // we need since the gradient's start and stop are in that space too. + GLfloat coeff[6] = { 1, 0, 0, + 0, 1, 0 }; + nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], m_fillGradient.start.x(), m_fillGradient.start.y()); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], m_fillGradient.end.x(), m_fillGradient.end.y()); + } else { + f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], + m_fillColor.x(), m_fillColor.y(), m_fillColor.z(), m_fillColor.w()); + } + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); + nvpr.stencilThenCoverFillPath(m_path, m_fillRule, 0xFF, GL_BOUNDING_BOX_NV); + } + + if (!qFuzzyIsNull(m_strokeWidth) && !qFuzzyIsNull(m_strokeColor.w())) { + if (m_fillGradientActive) + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); + f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], + m_strokeColor.x(), m_strokeColor.y(), m_strokeColor.z(), m_strokeColor.w()); + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); + nvpr.stencilThenCoverStrokePath(m_path, 0x1, ~0, GL_CONVEX_HULL_NV); + } + + f->glBindProgramPipeline(0); + + m_dirty = 0; +} + +QSGRenderNode::StateFlags QQuickPathItemNvprRenderNode::changedStates() const +{ + return BlendState | StencilState | DepthState | ScissorState; +} + +QSGRenderNode::RenderingFlags QQuickPathItemNvprRenderNode::flags() const +{ + return DepthAwareRendering; // avoid hitting the less optimal no-opaque-batch path in the renderer +} + +QRectF QQuickPathItemNvprRenderNode::rect() const +{ + return QRect(0, 0, m_item->width(), m_item->height()); +} + +bool QQuickPathItemNvprRenderNode::isSupported() +{ + static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0; + return !nvprDisabled && QQuickNvprFunctions::isSupported(); +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickpathitemnvprrenderer_p.h b/src/quick/items/qquickpathitemnvprrenderer_p.h new file mode 100644 index 0000000000..0075572324 --- /dev/null +++ b/src/quick/items/qquickpathitemnvprrenderer_p.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEMNVPRRENDERER_P_H +#define QQUICKPATHITEMNVPRRENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p_p.h" +#include <qsgrendernode.h> +#include <private/qquicknvprfunctions_p.h> +#include <QColor> +#include <QVector4D> +#include <QDebug> + +#ifndef QT_NO_OPENGL + +QT_BEGIN_NAMESPACE + +class QQuickPathItemNvprRenderNode; + +class QQuickPathItemNvprRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyPath = 0x01, + DirtyStyle = 0x02, + DirtyFillRule = 0x04, + DirtyDash = 0x08, + DirtyFillGradient = 0x10, + + DirtyAll = 0xFF + }; + + void beginSync() override; + void setPath(const QQuickPath *path) override; + void setStrokeColor(const QColor &color) override; + void setStrokeWidth(qreal w) override; + void setFillColor(const QColor &color) override; + void setFillRule(QQuickPathItem::FillRule fillRule) override; + void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(QQuickPathItem::CapStyle capStyle) override; + void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) override; + void setFillGradient(QQuickPathGradient *gradient) override; + void endSync() override; + void updatePathRenderNode() override; + + void setNode(QQuickPathItemNvprRenderNode *node); + + struct NvprPath { + QVector<GLubyte> cmd; + QVector<GLfloat> coord; + }; + +private: + void convertPath(const QQuickPath *path); + + QQuickPathItemNvprRenderNode *m_node = nullptr; + int m_dirty = 0; + + NvprPath m_path; + qreal m_strokeWidth; + QColor m_strokeColor; + QColor m_fillColor; + QQuickPathItem::JoinStyle m_joinStyle; + int m_miterLimit; + QQuickPathItem::CapStyle m_capStyle; + QQuickPathItem::FillRule m_fillRule; + bool m_dashActive; + qreal m_dashOffset; + QVector<qreal> m_dashPattern; + bool m_fillGradientActive; + QQuickPathItemGradientCache::GradientDesc m_fillGradient; +}; + +QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path); + +class QQuickNvprMaterialManager +{ +public: + enum Material { + MatSolid, + MatLinearGradient, + + NMaterials + }; + + struct MaterialDesc { + GLuint ppl = 0; + GLuint prg = 0; + int uniLoc[4]; + }; + + void create(QQuickNvprFunctions *nvpr); + MaterialDesc *activateMaterial(Material m); + void releaseResources(); + +private: + QQuickNvprFunctions *m_nvpr; + MaterialDesc m_materials[NMaterials]; +}; + +class QQuickPathItemNvprRenderNode : public QSGRenderNode +{ +public: + QQuickPathItemNvprRenderNode(QQuickPathItem *item); + ~QQuickPathItemNvprRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + QRectF rect() const override; + + static bool isSupported(); + +private: + void updatePath(); + + static bool nvprInited; + static QQuickNvprFunctions nvpr; + static QQuickNvprMaterialManager mtlmgr; + + QQuickPathItem *m_item; + GLuint m_path = 0; + int m_dirty = 0; + + QQuickPathItemNvprRenderer::NvprPath m_source; + GLfloat m_strokeWidth; + QVector4D m_strokeColor; + QVector4D m_fillColor; + GLenum m_joinStyle; + GLint m_miterLimit; + GLenum m_capStyle; + GLenum m_fillRule; + GLfloat m_dashOffset; + QVector<GLfloat> m_dashPattern; + bool m_fillGradientActive; + QQuickPathItemGradientCache::GradientDesc m_fillGradient; + + friend class QQuickPathItemNvprRenderer; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL + +#endif // QQUICKPATHITEMNVPRRENDERER_P_H diff --git a/src/quick/items/qquickpathitemsoftwarerenderer.cpp b/src/quick/items/qquickpathitemsoftwarerenderer.cpp new file mode 100644 index 0000000000..40732e4bf9 --- /dev/null +++ b/src/quick/items/qquickpathitemsoftwarerenderer.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitemsoftwarerenderer_p.h" +#include <private/qquickpath_p_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickPathItemSoftwareRenderer::beginSync() +{ + // nothing to do here +} + +void QQuickPathItemSoftwareRenderer::setPath(const QQuickPath *path) +{ + m_path = path ? path->path() : QPainterPath(); + m_dirty |= DirtyPath; +} + +void QQuickPathItemSoftwareRenderer::setStrokeColor(const QColor &color) +{ + m_pen.setColor(color); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setStrokeWidth(qreal w) +{ + m_pen.setWidthF(w); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setFillColor(const QColor &color) +{ + m_fillColor = color; + m_brush.setColor(m_fillColor); + m_dirty |= DirtyBrush; +} + +void QQuickPathItemSoftwareRenderer::setFillRule(QQuickPathItem::FillRule fillRule) +{ + m_fillRule = Qt::FillRule(fillRule); + m_dirty |= DirtyFillRule; +} + +void QQuickPathItemSoftwareRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) +{ + m_pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); + m_pen.setMiterLimit(miterLimit); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle) +{ + m_pen.setCapStyle(Qt::PenCapStyle(capStyle)); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) +{ + switch (strokeStyle) { + case QQuickPathItem::SolidLine: + m_pen.setStyle(Qt::SolidLine); + break; + case QQuickPathItem::DashLine: + m_pen.setStyle(Qt::CustomDashLine); + m_pen.setDashPattern(dashPattern); + m_pen.setDashOffset(dashOffset); + break; + default: + break; + } + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setFillGradient(QQuickPathGradient *gradient) +{ + if (QQuickPathLinearGradient *linearGradient = qobject_cast<QQuickPathLinearGradient *>(gradient)) { + QLinearGradient painterGradient(linearGradient->x1(), linearGradient->y1(), + linearGradient->x2(), linearGradient->y2()); + painterGradient.setStops(linearGradient->sortedGradientStops()); + switch (gradient->spread()) { + case QQuickPathGradient::PadSpread: + painterGradient.setSpread(QGradient::PadSpread); + break; + case QQuickPathGradient::RepeatSpread: + painterGradient.setSpread(QGradient::RepeatSpread); + break; + case QQuickPathGradient::ReflectSpread: + painterGradient.setSpread(QGradient::ReflectSpread); + break; + default: + break; + } + m_brush = QBrush(painterGradient); + } else { + m_brush = QBrush(m_fillColor); + } + m_dirty |= DirtyBrush; +} + +void QQuickPathItemSoftwareRenderer::endSync() +{ + // nothing to do here +} + +void QQuickPathItemSoftwareRenderer::setNode(QQuickPathItemSoftwareRenderNode *node) +{ + if (m_node != node) { + m_node = node; + // Scenegraph nodes can be destroyed and then replaced by new ones over + // time; hence it is important to mark everything dirty for + // updatePathRenderNode(). We can assume the renderer has a full sync + // of the data at this point. + m_dirty = DirtyAll; + } +} + +void QQuickPathItemSoftwareRenderer::updatePathRenderNode() +{ + if (!m_dirty) + return; + + // updatePathRenderNode() can be called several times with different dirty + // state before render() gets invoked. So accumulate. + m_node->m_dirty |= m_dirty; + + if (m_dirty & DirtyPath) { + m_node->m_path = m_path; + m_node->m_path.setFillRule(m_fillRule); + } + + if (m_dirty & DirtyFillRule) + m_node->m_path.setFillRule(m_fillRule); + + if (m_dirty & DirtyPen) + m_node->m_pen = m_pen; + + if (m_dirty & DirtyBrush) + m_node->m_brush = m_brush; + + m_node->markDirty(QSGNode::DirtyMaterial); + m_dirty = 0; +} + +QQuickPathItemSoftwareRenderNode::QQuickPathItemSoftwareRenderNode(QQuickPathItem *item) + : m_item(item) +{ +} + +QQuickPathItemSoftwareRenderNode::~QQuickPathItemSoftwareRenderNode() +{ + releaseResources(); +} + +void QQuickPathItemSoftwareRenderNode::releaseResources() +{ +} + +void QQuickPathItemSoftwareRenderNode::render(const RenderState *state) +{ + if (m_path.isEmpty()) + return; + + QSGRendererInterface *rif = m_item->window()->rendererInterface(); + QPainter *p = static_cast<QPainter *>(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource)); + Q_ASSERT(p); + + p->setTransform(matrix()->toTransform()); + p->setOpacity(inheritedOpacity()); + + const QRegion *clipRegion = state->clipRegion(); + if (clipRegion && !clipRegion->isEmpty()) + p->setClipRegion(*clipRegion, Qt::IntersectClip); + + p->setPen(!qFuzzyIsNull(m_pen.widthF()) && m_pen.color() != Qt::transparent ? m_pen : Qt::NoPen); + p->setBrush(m_brush.color() != Qt::transparent ? m_brush : Qt::NoBrush); + p->drawPath(m_path); + + m_dirty = 0; +} + +QSGRenderNode::StateFlags QQuickPathItemSoftwareRenderNode::changedStates() const +{ + return 0; +} + +QSGRenderNode::RenderingFlags QQuickPathItemSoftwareRenderNode::flags() const +{ + return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect() +} + +QRectF QQuickPathItemSoftwareRenderNode::rect() const +{ + return QRect(0, 0, m_item->width(), m_item->height()); +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickpathitemsoftwarerenderer_p.h b/src/quick/items/qquickpathitemsoftwarerenderer_p.h new file mode 100644 index 0000000000..584771425d --- /dev/null +++ b/src/quick/items/qquickpathitemsoftwarerenderer_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEMSOFTWARERENDERER_P_H +#define QQUICKPATHITEMSOFTWARERENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p_p.h" +#include <qsgrendernode.h> +#include <QPen> +#include <QBrush> + +QT_BEGIN_NAMESPACE + +class QQuickPathItemSoftwareRenderNode; + +class QQuickPathItemSoftwareRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyPath = 0x01, + DirtyPen = 0x02, + DirtyFillRule = 0x04, + DirtyBrush = 0x08, + + DirtyAll = 0xFF + }; + + void beginSync() override; + void setPath(const QQuickPath *path) override; + void setStrokeColor(const QColor &color) override; + void setStrokeWidth(qreal w) override; + void setFillColor(const QColor &color) override; + void setFillRule(QQuickPathItem::FillRule fillRule) override; + void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(QQuickPathItem::CapStyle capStyle) override; + void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) override; + void setFillGradient(QQuickPathGradient *gradient) override; + void endSync() override; + void updatePathRenderNode() override; + + void setNode(QQuickPathItemSoftwareRenderNode *node); + +private: + QQuickPathItemSoftwareRenderNode *m_node = nullptr; + int m_dirty = 0; + + QPainterPath m_path; + QPen m_pen; + QColor m_fillColor; + QBrush m_brush; + Qt::FillRule m_fillRule; +}; + +class QQuickPathItemSoftwareRenderNode : public QSGRenderNode +{ +public: + QQuickPathItemSoftwareRenderNode(QQuickPathItem *item); + ~QQuickPathItemSoftwareRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + QRectF rect() const override; + +private: + QQuickPathItem *m_item; + int m_dirty = 0; + + QPainterPath m_path; + QPen m_pen; + QBrush m_brush; + + friend class QQuickPathItemSoftwareRenderer; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPATHITEMSOFTWARERENDERER_P_H diff --git a/src/quick/items/shaders/lineargradient.frag b/src/quick/items/shaders/lineargradient.frag new file mode 100644 index 0000000000..7f4a739109 --- /dev/null +++ b/src/quick/items/shaders/lineargradient.frag @@ -0,0 +1,9 @@ +uniform sampler2D gradTabTexture; +uniform highp float opacity; + +varying highp float gradTabIndex; + +void main() +{ + gl_FragColor = texture2D(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity; +} diff --git a/src/quick/items/shaders/lineargradient.vert b/src/quick/items/shaders/lineargradient.vert new file mode 100644 index 0000000000..eb21b8886b --- /dev/null +++ b/src/quick/items/shaders/lineargradient.vert @@ -0,0 +1,15 @@ +attribute vec4 vertexCoord; +attribute vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 gradStart; +uniform vec2 gradEnd; + +varying float gradTabIndex; + +void main() +{ + vec2 gradVec = gradEnd - gradStart; + gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y); + gl_Position = matrix * vertexCoord; +} diff --git a/src/quick/items/shaders/lineargradient_core.frag b/src/quick/items/shaders/lineargradient_core.frag new file mode 100644 index 0000000000..5908acfa67 --- /dev/null +++ b/src/quick/items/shaders/lineargradient_core.frag @@ -0,0 +1,12 @@ +#version 150 core + +uniform sampler2D gradTabTexture; +uniform float opacity; + +in float gradTabIndex; +out vec4 fragColor; + +void main() +{ + fragColor = texture(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity; +} diff --git a/src/quick/items/shaders/lineargradient_core.vert b/src/quick/items/shaders/lineargradient_core.vert new file mode 100644 index 0000000000..60b56f38e3 --- /dev/null +++ b/src/quick/items/shaders/lineargradient_core.vert @@ -0,0 +1,17 @@ +#version 150 core + +in vec4 vertexCoord; +in vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 gradStart; +uniform vec2 gradEnd; + +out float gradTabIndex; + +void main() +{ + vec2 gradVec = gradEnd - gradStart; + gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y); + gl_Position = matrix * vertexCoord; +} diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 8de205fc98..b8ed190b33 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -978,6 +978,10 @@ void Renderer::nodeChangedBatchRoot(Node *node, Node *root) e->root = root; e->boundsComputed = false; } + } else if (node->type() == QSGNode::RenderNodeType) { + RenderNodeElement *e = node->renderNodeElement(); + if (e) + e->root = root; } SHADOWNODE_TRAVERSE(node) diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index 5915d51f2b..1bc0210b72 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -160,10 +160,7 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const \list \li glDepthMask(false) \li glDisable(GL_DEPTH_TEST) - \li glStencilMask(0) - \li glEnable(GL_STENCIL_TEST)/glDisable(GL_STENCIL_TEST) depending on clip \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip - \li glEnable(GL_SCISSOR_TEST)/glDisable(GL_SCISSOR_TEST) depending on clip \li glScissor(state.scissorRect.x(), state.scissorRect.y(), state.scissorRect.width(), state.scissorRect.height()) depending on clip \li glEnable(GL_BLEND) diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 2c5b4ff5c8..aaf4635c0c 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -260,7 +260,7 @@ void QSGDefaultRenderContext::compileShader(QSGMaterialShader *shader, QSGMateri if (vertexCode || fragmentCode) { Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0, "QSGRenderContext::compile()", - "materials with custom compile step cannot have custom vertex/fragment code"); + "materials with custom compile step cannot have modified vertex or fragment code"); QOpenGLShaderProgram *p = shader->program(); p->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader()); p->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader()); diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 47248f2f37..d761eac62f 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -251,11 +251,15 @@ static void qt_debug_remove_texture(QSGTexture* texture) Specifies how the texture should treat texture coordinates. - \value Repeat Only the factional part of the texture coordiante is + \value Repeat Only the fractional part of the texture coordinate is used, causing values above 1 and below 0 to repeat. \value ClampToEdge Values above 1 are clamped to 1 and values below 0 are clamped to 0. + + \value MirroredRepeat When the texture coordinate is even, only the + fractional part is used. When odd, the texture coordinate is set to + \c{1 - fractional part}. This value has been introduced in Qt 5.10. */ /*! @@ -550,7 +554,9 @@ void QSGTexture::updateBindOptions(bool force) if (force || d->wrapChanged) { #ifndef QT_NO_DEBUG - if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) { + if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat + || d->horizontalWrap == MirroredRepeat || d->verticalWrap == MirroredRepeat) + { bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); QSize size = textureSize(); bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height()); @@ -558,8 +564,18 @@ void QSGTexture::updateBindOptions(bool force) qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures."); } #endif - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + GLenum wrapS = GL_CLAMP_TO_EDGE; + if (d->horizontalWrap == Repeat) + wrapS = GL_REPEAT; + else if (d->horizontalWrap == MirroredRepeat) + wrapS = GL_MIRRORED_REPEAT; + GLenum wrapT = GL_CLAMP_TO_EDGE; + if (d->verticalWrap == Repeat) + wrapT = GL_REPEAT; + else if (d->verticalWrap == MirroredRepeat) + wrapT = GL_MIRRORED_REPEAT; + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); d->wrapChanged = false; } #else diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h index f0509b58ae..2b29525efd 100644 --- a/src/quick/scenegraph/util/qsgtexture.h +++ b/src/quick/scenegraph/util/qsgtexture.h @@ -58,7 +58,8 @@ public: enum WrapMode { Repeat, - ClampToEdge + ClampToEdge, + MirroredRepeat }; enum Filtering { diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h index b6fcfc31c4..3a10d85b4d 100644 --- a/src/quick/scenegraph/util/qsgtexture_p.h +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -70,8 +70,8 @@ public: uint wrapChanged : 1; uint filteringChanged : 1; - uint horizontalWrap : 1; - uint verticalWrap : 1; + uint horizontalWrap : 2; + uint verticalWrap : 2; uint mipmapMode : 2; uint filterMode : 2; }; diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp index 9326ea640d..fcafbba6a2 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.cpp +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -278,7 +278,7 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) Returns this material's horizontal wrap mode. - The default horizontal wrap mode is \c QSGTexutre::ClampToEdge. + The default horizontal wrap mode is \c QSGTexture::ClampToEdge. */ @@ -299,7 +299,7 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) Returns this material's vertical wrap mode. - The default vertical wrap mode is \c QSGTexutre::ClampToEdge. + The default vertical wrap mode is \c QSGTexture::ClampToEdge. */ diff --git a/src/quick/util/qquicknvprfunctions.cpp b/src/quick/util/qquicknvprfunctions.cpp new file mode 100644 index 0000000000..40eb2bb932 --- /dev/null +++ b/src/quick/util/qquicknvprfunctions.cpp @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicknvprfunctions_p.h" + +#ifndef QT_NO_OPENGL + +#include <QOpenGLContext> +#include <QOffscreenSurface> +#include <QOpenGLExtraFunctions> +#include "qquicknvprfunctions_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QQuickNvprFunctions + + \brief Function resolvers and other helpers for GL_NV_path_rendering + for both desktop (GL 4.3+) and mobile/embedded (GLES 3.1+) in a manner + that does not distract builds that do not have NVPR support either at + compile or run time. + + \internal + */ + +QQuickNvprFunctions::QQuickNvprFunctions() + : d(new QQuickNvprFunctionsPrivate(this)) +{ +} + +QQuickNvprFunctions::~QQuickNvprFunctions() +{ + delete d; +} + +/*! + \return a recommended QSurfaceFormat suitable for GL_NV_path_rendering on top + of OpenGL 4.3 or OpenGL ES 3.1. + */ +QSurfaceFormat QQuickNvprFunctions::format() +{ + QSurfaceFormat fmt; + fmt.setDepthBufferSize(24); + fmt.setStencilBufferSize(8); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { + fmt.setVersion(4, 3); + fmt.setProfile(QSurfaceFormat::CompatibilityProfile); + } else if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { + fmt.setVersion(3, 1); + } + return fmt; +} + +/*! + \return true if GL_NV_path_rendering is supported with the current OpenGL + context. + + When there is no current context, a temporary dummy one will be created and + made current. + */ +bool QQuickNvprFunctions::isSupported() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QScopedPointer<QOpenGLContext> tempContext; + QScopedPointer<QOffscreenSurface> tempSurface; + if (!ctx) { + tempContext.reset(new QOpenGLContext); + if (!tempContext->create()) + return false; + ctx = tempContext.data(); + tempSurface.reset(new QOffscreenSurface); + tempSurface->setFormat(ctx->format()); + tempSurface->create(); + if (!ctx->makeCurrent(tempSurface.data())) + return false; + } + + if (!ctx->hasExtension(QByteArrayLiteral("GL_NV_path_rendering"))) + return false; + + // Do not check for DSA as the string may not be exposed on ES + // drivers, yet the functions we need are resolvable. +#if 0 + if (!ctx->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) { + qWarning("QtQuickPath/NVPR: GL_EXT_direct_state_access not supported"); + return false; + } +#endif + + return true; +} + +/*! + Initializes using the current OpenGL context. + + \return true when GL_NV_path_rendering is supported and initialization was + successful. + */ +bool QQuickNvprFunctions::create() +{ + return isSupported() && d->resolve(); +} + +/*! + Creates a program pipeline consisting of a separable fragment shader program. + + This is essential for using NVPR with OpenGL ES 3.1+ since normal, + GLES2-style programs would not work without a vertex shader. + + \note \a fragmentShaderSource should be a \c{version 310 es} shader since + this works both on desktop and embedded NVIDIA drivers, thus avoiding the + need to fight GLSL and GLSL ES differences. + + The pipeline object is stored into \a pipeline, the fragment shader program + into \a program. + + Use QOpenGLExtraFunctions to set uniforms, bind the pipeline, etc. + + \return \c false on failure in which case the error log is printed on the + debug output. \c true on success. + */ +bool QQuickNvprFunctions::createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) + return false; + + QOpenGLExtraFunctions *f = ctx->extraFunctions(); + *program = f->glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragmentShaderSource); + GLint status = 0; + f->glGetProgramiv(*program, GL_LINK_STATUS, &status); + if (!status) { + GLint len = 0; + f->glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &len); + if (len) { + QByteArray s; + s.resize(len); + f->glGetProgramInfoLog(*program, s.count(), nullptr, s.data()); + qWarning("Failed to create separable shader program:\n%s", s.constData()); + } + return false; + } + + f->glGenProgramPipelines(1, pipeline); + f->glUseProgramStages(*pipeline, GL_FRAGMENT_SHADER_BIT, *program); + f->glActiveShaderProgram(*pipeline, *program); + + f->glValidateProgramPipeline(*pipeline); + status = 0; + f->glGetProgramPipelineiv(*pipeline, GL_VALIDATE_STATUS, &status); + if (!status) { + GLint len = 0; + f->glGetProgramPipelineiv(*pipeline, GL_INFO_LOG_LENGTH, &len); + if (len) { + QByteArray s; + s.resize(len); + f->glGetProgramPipelineInfoLog(*pipeline, s.count(), nullptr, s.data()); + qWarning("Program pipeline validation failed:\n%s", s.constData()); + } + return false; + } + + return true; +} + +#define PROC(type, name) reinterpret_cast<type>(ctx->getProcAddress(#name)) + +bool QQuickNvprFunctionsPrivate::resolve() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + + q->genPaths = PROC(PFNGLGENPATHSNVPROC, glGenPathsNV); + q->deletePaths = PROC(PFNGLDELETEPATHSNVPROC, glDeletePathsNV); + q->isPath = PROC(PFNGLISPATHNVPROC, glIsPathNV); + q->pathCommands = PROC(PFNGLPATHCOMMANDSNVPROC, glPathCommandsNV); + q->pathCoords = PROC(PFNGLPATHCOORDSNVPROC, glPathCoordsNV); + q->pathSubCommands = PROC(PFNGLPATHSUBCOMMANDSNVPROC, glPathSubCommandsNV); + q->pathSubCoords = PROC(PFNGLPATHSUBCOORDSNVPROC, glPathSubCoordsNV); + q->pathString = PROC(PFNGLPATHSTRINGNVPROC, glPathStringNV); + q->pathGlyphs = PROC(PFNGLPATHGLYPHSNVPROC, glPathGlyphsNV); + q->pathGlyphRange = PROC(PFNGLPATHGLYPHRANGENVPROC, glPathGlyphRangeNV); + q->weightPaths = PROC(PFNGLWEIGHTPATHSNVPROC, glWeightPathsNV); + q->copyPath = PROC(PFNGLCOPYPATHNVPROC, glCopyPathNV); + q->interpolatePaths = PROC(PFNGLINTERPOLATEPATHSNVPROC, glInterpolatePathsNV); + q->transformPath = PROC(PFNGLTRANSFORMPATHNVPROC, glTransformPathNV); + q->pathParameteriv = PROC(PFNGLPATHPARAMETERIVNVPROC, glPathParameterivNV); + q->pathParameteri = PROC(PFNGLPATHPARAMETERINVPROC, glPathParameteriNV); + q->pathParameterfv = PROC(PFNGLPATHPARAMETERFVNVPROC, glPathParameterfvNV); + q->pathParameterf = PROC(PFNGLPATHPARAMETERFNVPROC, glPathParameterfNV); + q->pathDashArray = PROC(PFNGLPATHDASHARRAYNVPROC, glPathDashArrayNV); + q->pathStencilFunc = PROC(PFNGLPATHSTENCILFUNCNVPROC, glPathStencilFuncNV); + q->pathStencilDepthOffset = PROC(PFNGLPATHSTENCILDEPTHOFFSETNVPROC, glPathStencilDepthOffsetNV); + q->stencilFillPath = PROC(PFNGLSTENCILFILLPATHNVPROC, glStencilFillPathNV); + q->stencilStrokePath = PROC(PFNGLSTENCILSTROKEPATHNVPROC, glStencilStrokePathNV); + q->stencilFillPathInstanced = PROC(PFNGLSTENCILFILLPATHINSTANCEDNVPROC, glStencilFillPathInstancedNV); + q->stencilStrokePathInstanced = PROC(PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC, glStencilStrokePathInstancedNV); + q->pathCoverDepthFunc = PROC(PFNGLPATHCOVERDEPTHFUNCNVPROC, glPathCoverDepthFuncNV); + q->pathColorGen = PROC(PFNGLPATHCOLORGENNVPROC, glPathColorGenNV); + q->pathTexGen = PROC(PFNGLPATHTEXGENNVPROC, glPathTexGenNV); + q->pathFogGen = PROC(PFNGLPATHFOGGENNVPROC, glPathFogGenNV); + q->coverFillPath = PROC(PFNGLCOVERFILLPATHNVPROC, glCoverFillPathNV); + q->coverStrokePath = PROC(PFNGLCOVERSTROKEPATHNVPROC, glCoverStrokePathNV); + q->coverFillPathInstanced = PROC(PFNGLCOVERFILLPATHINSTANCEDNVPROC, glCoverFillPathInstancedNV); + q->coverStrokePathInstanced = PROC(PFNGLCOVERSTROKEPATHINSTANCEDNVPROC, glCoverStrokePathInstancedNV); + q->getPathParameteriv = PROC(PFNGLGETPATHPARAMETERIVNVPROC, glGetPathParameterivNV); + q->getPathParameterfv = PROC(PFNGLGETPATHPARAMETERFVNVPROC, glGetPathParameterfvNV); + q->getPathCommands = PROC(PFNGLGETPATHCOMMANDSNVPROC, glGetPathCommandsNV); + q->getPathCoords = PROC(PFNGLGETPATHCOORDSNVPROC, glGetPathCoordsNV); + q->getPathDashArray = PROC(PFNGLGETPATHDASHARRAYNVPROC, glGetPathDashArrayNV); + q->getPathMetrics = PROC(PFNGLGETPATHMETRICSNVPROC, glGetPathMetricsNV); + q->getPathMetricRange = PROC(PFNGLGETPATHMETRICRANGENVPROC, glGetPathMetricRangeNV); + q->getPathSpacing = PROC(PFNGLGETPATHSPACINGNVPROC, glGetPathSpacingNV); + q->getPathColorgeniv = PROC(PFNGLGETPATHCOLORGENIVNVPROC, glGetPathColorGenivNV); + q->getPathColorgenfv = PROC(PFNGLGETPATHCOLORGENFVNVPROC, glGetPathColorGenfvNV); + q->getPathTexGeniv = PROC(PFNGLGETPATHTEXGENIVNVPROC, glGetPathTexGenivNV); + q->getPathTexGenfv = PROC(PFNGLGETPATHTEXGENFVNVPROC, glGetPathTexGenfvNV); + q->isPointInFillPath = PROC(PFNGLISPOINTINFILLPATHNVPROC, glIsPointInFillPathNV); + q->isPointInStrokePath = PROC(PFNGLISPOINTINSTROKEPATHNVPROC, glIsPointInStrokePathNV); + q->getPathLength = PROC(PFNGLGETPATHLENGTHNVPROC, glGetPathLengthNV); + q->getPointAlongPath = PROC(PFNGLPOINTALONGPATHNVPROC, glPointAlongPathNV); + q->matrixLoad3x2f = PROC(PFNGLMATRIXLOAD3X2FNVPROC, glMatrixLoad3x2fNV); + q->matrixLoad3x3f = PROC(PFNGLMATRIXLOAD3X3FNVPROC, glMatrixLoad3x3fNV); + q->matrixLoadTranspose3x3f = PROC(PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC, glMatrixLoadTranspose3x3fNV); + q->matrixMult3x2f = PROC(PFNGLMATRIXMULT3X2FNVPROC, glMatrixMult3x2fNV); + q->matrixMult3x3f = PROC(PFNGLMATRIXMULT3X3FNVPROC, glMatrixMult3x3fNV); + q->matrixMultTranspose3x3f = PROC(PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC, glMatrixMultTranspose3x3fNV); + q->stencilThenCoverFillPath = PROC(PFNGLSTENCILTHENCOVERFILLPATHNVPROC, glStencilThenCoverFillPathNV); + q->stencilThenCoverStrokePath = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC, glStencilThenCoverStrokePathNV); + q->stencilThenCoverFillPathInstanced = PROC(PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC, glStencilThenCoverFillPathInstancedNV); + q->stencilThenCoverStrokePathInstanced = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC, glStencilThenCoverStrokePathInstancedNV); + q->pathGlyphIndexRange = PROC(PFNGLPATHGLYPHINDEXRANGENVPROC, glPathGlyphIndexRangeNV); + q->pathGlyphIndexArray = PROC(PFNGLPATHGLYPHINDEXARRAYNVPROC, glPathGlyphIndexArrayNV); + q->pathMemoryGlyphIndexArray = PROC(PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC, glPathMemoryGlyphIndexArrayNV); + q->programPathFragmentInputGen = PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV); + q->getProgramResourcefv = PROC(PFNGLGETPROGRAMRESOURCEFVNVPROC, glGetProgramResourcefvNV); + + q->matrixLoadf = PROC(PFNGLMATRIXLOADFEXTPROC, glMatrixLoadfEXT); + q->matrixLoadIdentity = PROC(PFNGLMATRIXLOADIDENTITYEXTPROC, glMatrixLoadIdentityEXT); + + return q->genPaths != nullptr // base path rendering ext + && q->programPathFragmentInputGen != nullptr // updated path rendering ext + && q->matrixLoadf != nullptr // direct state access ext + && q->matrixLoadIdentity != nullptr; +} + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL diff --git a/src/quick/util/qquicknvprfunctions_p.h b/src/quick/util/qquicknvprfunctions_p.h new file mode 100644 index 0000000000..7900388305 --- /dev/null +++ b/src/quick/util/qquicknvprfunctions_p.h @@ -0,0 +1,406 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKNVPRFUNCTIONS_P_H +#define QQUICKNVPRFUNCTIONS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <qopengl.h> +#include <QtGui/qsurfaceformat.h> + +#ifndef QT_NO_OPENGL + +QT_BEGIN_NAMESPACE + +#ifndef GL_NV_path_rendering +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +#define GL_ROUNDED_RECT_NV 0xE8 +#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 +#define GL_ROUNDED_RECT2_NV 0xEA +#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB +#define GL_ROUNDED_RECT4_NV 0xEC +#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED +#define GL_ROUNDED_RECT8_NV 0xEE +#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF +#define GL_RELATIVE_RECT_NV 0xF7 +#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 +#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 +#define GL_FONT_UNAVAILABLE_NV 0x936A +#define GL_FONT_UNINTELLIGIBLE_NV 0x936B +#define GL_CONIC_CURVE_TO_NV 0x1A +#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B +#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 +#define GL_STANDARD_FONT_FORMAT_NV 0x936C +#define GL_2_BYTES_NV 0x1407 +#define GL_3_BYTES_NV 0x1408 +#define GL_4_BYTES_NV 0x1409 +#define GL_EYE_LINEAR_NV 0x2400 +#define GL_OBJECT_LINEAR_NV 0x2401 +#define GL_CONSTANT_NV 0x8576 +#define GL_PATH_PROJECTION_NV 0x1701 +#define GL_PATH_MODELVIEW_NV 0x1700 +#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 +#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 +#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 +#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 +#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 +#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 +#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 +#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 +#define GL_FRAGMENT_INPUT_NV 0x936D + +typedef GLuint (QOPENGLF_APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); +typedef void (QOPENGLF_APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPATHNVPROC) (GLuint path); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (QOPENGLF_APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +typedef void (QOPENGLF_APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); +typedef void (QOPENGLF_APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void (QOPENGLF_APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); +typedef GLfloat (QOPENGLF_APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (QOPENGLF_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); +#endif + +#ifndef GL_FLAT +#define GL_FLAT 0x1D00 +#endif + +#ifndef GL_INVERT +#define GL_INVERT 0x150A +#endif + +#ifndef GL_EXT_direct_state_access +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); +#endif + +// When building on a system with GLES 2.0 or 3.0, we may still compile the NVPR +// code path even though it's never used. Keep it compiling by defining the +// necessary ES 3.1 separable program constants. +#ifndef GL_FRAGMENT_SHADER_BIT +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#endif +#ifndef GL_UNIFORM +#define GL_UNIFORM 0x92E1 +#endif + +class QQuickNvprFunctionsPrivate; + +class QQuickNvprFunctions +{ +public: + QQuickNvprFunctions(); + ~QQuickNvprFunctions(); + + static QSurfaceFormat format(); + static bool isSupported(); + + bool create(); + + bool createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program); + + PFNGLGENPATHSNVPROC genPaths = nullptr; + PFNGLDELETEPATHSNVPROC deletePaths = nullptr; + PFNGLISPATHNVPROC isPath = nullptr; + PFNGLPATHCOMMANDSNVPROC pathCommands = nullptr; + PFNGLPATHCOORDSNVPROC pathCoords = nullptr; + PFNGLPATHSUBCOMMANDSNVPROC pathSubCommands = nullptr; + PFNGLPATHSUBCOORDSNVPROC pathSubCoords = nullptr; + PFNGLPATHSTRINGNVPROC pathString = nullptr; + PFNGLPATHGLYPHSNVPROC pathGlyphs = nullptr; + PFNGLPATHGLYPHRANGENVPROC pathGlyphRange = nullptr; + PFNGLWEIGHTPATHSNVPROC weightPaths = nullptr; + PFNGLCOPYPATHNVPROC copyPath = nullptr; + PFNGLINTERPOLATEPATHSNVPROC interpolatePaths = nullptr; + PFNGLTRANSFORMPATHNVPROC transformPath = nullptr; + PFNGLPATHPARAMETERIVNVPROC pathParameteriv = nullptr; + PFNGLPATHPARAMETERINVPROC pathParameteri = nullptr; + PFNGLPATHPARAMETERFVNVPROC pathParameterfv = nullptr; + PFNGLPATHPARAMETERFNVPROC pathParameterf = nullptr; + PFNGLPATHDASHARRAYNVPROC pathDashArray = nullptr; + PFNGLPATHSTENCILFUNCNVPROC pathStencilFunc = nullptr; + PFNGLPATHSTENCILDEPTHOFFSETNVPROC pathStencilDepthOffset = nullptr; + PFNGLSTENCILFILLPATHNVPROC stencilFillPath = nullptr; + PFNGLSTENCILSTROKEPATHNVPROC stencilStrokePath = nullptr; + PFNGLSTENCILFILLPATHINSTANCEDNVPROC stencilFillPathInstanced = nullptr; + PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC stencilStrokePathInstanced = nullptr; + PFNGLPATHCOVERDEPTHFUNCNVPROC pathCoverDepthFunc = nullptr; + PFNGLPATHCOLORGENNVPROC pathColorGen = nullptr; + PFNGLPATHTEXGENNVPROC pathTexGen = nullptr; + PFNGLPATHFOGGENNVPROC pathFogGen = nullptr; + PFNGLCOVERFILLPATHNVPROC coverFillPath = nullptr; + PFNGLCOVERSTROKEPATHNVPROC coverStrokePath = nullptr; + PFNGLCOVERFILLPATHINSTANCEDNVPROC coverFillPathInstanced = nullptr; + PFNGLCOVERSTROKEPATHINSTANCEDNVPROC coverStrokePathInstanced = nullptr; + PFNGLGETPATHPARAMETERIVNVPROC getPathParameteriv = nullptr; + PFNGLGETPATHPARAMETERFVNVPROC getPathParameterfv = nullptr; + PFNGLGETPATHCOMMANDSNVPROC getPathCommands = nullptr; + PFNGLGETPATHCOORDSNVPROC getPathCoords = nullptr; + PFNGLGETPATHDASHARRAYNVPROC getPathDashArray = nullptr; + PFNGLGETPATHMETRICSNVPROC getPathMetrics = nullptr; + PFNGLGETPATHMETRICRANGENVPROC getPathMetricRange = nullptr; + PFNGLGETPATHSPACINGNVPROC getPathSpacing = nullptr; + PFNGLGETPATHCOLORGENIVNVPROC getPathColorgeniv = nullptr; + PFNGLGETPATHCOLORGENFVNVPROC getPathColorgenfv = nullptr; + PFNGLGETPATHTEXGENIVNVPROC getPathTexGeniv = nullptr; + PFNGLGETPATHTEXGENFVNVPROC getPathTexGenfv = nullptr; + PFNGLISPOINTINFILLPATHNVPROC isPointInFillPath = nullptr; + PFNGLISPOINTINSTROKEPATHNVPROC isPointInStrokePath = nullptr; + PFNGLGETPATHLENGTHNVPROC getPathLength = nullptr; + PFNGLPOINTALONGPATHNVPROC getPointAlongPath = nullptr; + PFNGLMATRIXLOAD3X2FNVPROC matrixLoad3x2f = nullptr; + PFNGLMATRIXLOAD3X3FNVPROC matrixLoad3x3f = nullptr; + PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC matrixLoadTranspose3x3f = nullptr; + PFNGLMATRIXMULT3X2FNVPROC matrixMult3x2f = nullptr; + PFNGLMATRIXMULT3X3FNVPROC matrixMult3x3f = nullptr; + PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC matrixMultTranspose3x3f = nullptr; + PFNGLSTENCILTHENCOVERFILLPATHNVPROC stencilThenCoverFillPath = nullptr; + PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC stencilThenCoverStrokePath = nullptr; + PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC stencilThenCoverFillPathInstanced = nullptr; + PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC stencilThenCoverStrokePathInstanced = nullptr; + PFNGLPATHGLYPHINDEXRANGENVPROC pathGlyphIndexRange = nullptr; + PFNGLPATHGLYPHINDEXARRAYNVPROC pathGlyphIndexArray = nullptr; + PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC pathMemoryGlyphIndexArray = nullptr; + PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC programPathFragmentInputGen = nullptr; + PFNGLGETPROGRAMRESOURCEFVNVPROC getProgramResourcefv = nullptr; + + PFNGLMATRIXLOADFEXTPROC matrixLoadf = nullptr; + PFNGLMATRIXLOADIDENTITYEXTPROC matrixLoadIdentity = nullptr; + +private: + QQuickNvprFunctionsPrivate *d; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL + +#endif // QQUICKNVPRFUNCTIONS_P_H diff --git a/src/quick/util/qquicknvprfunctions_p_p.h b/src/quick/util/qquicknvprfunctions_p_p.h new file mode 100644 index 0000000000..6df20566af --- /dev/null +++ b/src/quick/util/qquicknvprfunctions_p_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKNVPRFUNCTIONS_P_P_H +#define QQUICKNVPRFUNCTIONS_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquicknvprfunctions_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickNvprFunctionsPrivate +{ +public: + QQuickNvprFunctionsPrivate(QQuickNvprFunctions *q_ptr) : q(q_ptr) { } + + bool resolve(); + + QQuickNvprFunctions *q; +}; + +QT_END_NAMESPACE + +#endif // QQUICKNVPRFUNCTIONS_P_P_H diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 25a4433a9b..a6fa21d696 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE \instantiates QQuickPath \inqmlmodule QtQuick \ingroup qtquick-animation-paths - \brief Defines a path for use by \l PathView + \brief Defines a path for use by \l PathView and \l PathItem A Path is composed of one or more path segments - PathLine, PathQuad, PathCubic, PathArc, PathCurve, PathSvg. @@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE PathAttribute allows named attributes with values to be defined along the path. - \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic, PathArc, PathCurve, PathSvg + \sa PathView, PathItem, PathAttribute, PathPercent, PathLine, PathMove, PathQuad, PathCubic, PathArc, PathCurve, PathSvg */ QQuickPath::QQuickPath(QObject *parent) : QObject(*(new QQuickPathPrivate), parent) @@ -1017,7 +1017,7 @@ void QQuickPathAttribute::setValue(qreal value) } \endqml - \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg + \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg, PathMove */ /*! @@ -1060,6 +1060,66 @@ void QQuickPathLine::addToPath(QPainterPath &path, const QQuickPathData &data) /****************************************************************************/ /*! + \qmltype PathMove + \instantiates QQuickPathMove + \inqmlmodule QtQuick + \ingroup qtquick-animation-paths + \brief Moves the Path's position + + While not relevant with PathView, for Path elements used with PathItem it + is important to distinguish between the operations of drawing a straight + line and moving the path position without drawing anything. + + \note PathMove should not be used in a Path associated with a PathView. Use + PathLine instead. + + The example below creates a path consisting of two horizontal lines with + some empty space between them. All three segments have a width of 100: + + \qml + Path { + startX: 0; startY: 100 + PathLine { relativeX: 100; y: 100 } + PathMove { relativeX: 100; y: 100 } + PathLine { relativeX: 100; y: 100 } + } + \endqml + + \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg, PathLine +*/ + +/*! + \qmlproperty real QtQuick::PathMove::x + \qmlproperty real QtQuick::PathMove::y + + Defines the position to move to. + + \sa relativeX, relativeY +*/ + +/*! + \qmlproperty real QtQuick::PathMove::relativeX + \qmlproperty real QtQuick::PathMove::relativeY + + Defines the position to move to relative to its start. + + If both a relative and absolute end position are specified for a single axis, the relative + position will be used. + + Relative and absolute positions can be mixed, for example it is valid to set a relative x + and an absolute y. + + \sa x, y +*/ + +void QQuickPathMove::addToPath(QPainterPath &path, const QQuickPathData &data) +{ + path.moveTo(positionForCurve(data, path.currentPosition())); +} + +/****************************************************************************/ + +/*! \qmltype PathQuad \instantiates QQuickPathQuad \inqmlmodule QtQuick @@ -1655,6 +1715,7 @@ void QQuickPathArc::setRadiusX(qreal radius) _radiusX = radius; emit radiusXChanged(); + emit changed(); } qreal QQuickPathArc::radiusY() const @@ -1669,6 +1730,7 @@ void QQuickPathArc::setRadiusY(qreal radius) _radiusY = radius; emit radiusYChanged(); + emit changed(); } /*! @@ -1702,6 +1764,7 @@ void QQuickPathArc::setUseLargeArc(bool largeArc) _useLargeArc = largeArc; emit useLargeArcChanged(); + emit changed(); } /*! @@ -1733,6 +1796,7 @@ void QQuickPathArc::setDirection(ArcDirection direction) _direction = direction; emit directionChanged(); + emit changed(); } void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data) diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index 06ad389b49..283283f377 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -159,6 +159,15 @@ public: void addToPath(QPainterPath &path, const QQuickPathData &) override; }; +class Q_QUICK_PRIVATE_EXPORT QQuickPathMove : public QQuickCurve +{ + Q_OBJECT +public: + QQuickPathMove(QObject *parent=0) : QQuickCurve(parent) {} + + void addToPath(QPainterPath &path, const QQuickPathData &) override; +}; + class Q_QUICK_PRIVATE_EXPORT QQuickPathQuad : public QQuickCurve { Q_OBJECT @@ -459,6 +468,7 @@ QML_DECLARE_TYPE(QQuickPathElement) QML_DECLARE_TYPE(QQuickPathAttribute) QML_DECLARE_TYPE(QQuickCurve) QML_DECLARE_TYPE(QQuickPathLine) +QML_DECLARE_TYPE(QQuickPathMove) QML_DECLARE_TYPE(QQuickPathQuad) QML_DECLARE_TYPE(QQuickPathCubic) QML_DECLARE_TYPE(QQuickPathCatmullRomCurve) diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index 1ef1018a31..22f23f7598 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -74,4 +74,11 @@ qtConfig(quick-path) { $$PWD/qquickpath_p.h \ $$PWD/qquickpath_p_p.h \ $$PWD/qquickpathinterpolator_p.h + qtConfig(opengl) { + SOURCES += \ + $$PWD/qquicknvprfunctions.cpp + HEADERS += \ + $$PWD/qquicknvprfunctions_p.h \ + $$PWD/qquicknvprfunctions_p_p.h + } } diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp index 1ca809c05f..1673915c27 100644 --- a/tests/auto/quick/examples/tst_examples.cpp +++ b/tests/auto/quick/examples/tst_examples.cpp @@ -87,6 +87,7 @@ tst_examples::tst_examples() excludedDirs << "snippets/qml/visualdatamodel_rootindex"; excludedDirs << "snippets/qml/qtbinding"; excludedDirs << "snippets/qml/imports"; + excludedFiles << "examples/quick/pathitem/content/pathitem.qml"; // relies on resources #ifdef QT_NO_WEBKIT excludedDirs << "qtquick/modelviews/webview"; diff --git a/tests/manual/pathitem/main.cpp b/tests/manual/pathitem/main.cpp new file mode 100644 index 0000000000..62ef4385d6 --- /dev/null +++ b/tests/manual/pathitem/main.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** 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 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 <QGuiApplication> +#include <QSurfaceFormat> +#include <QQuickView> +#include <QQmlEngine> + +int main(int argc, char **argv) +{ + QGuiApplication app(argc, argv); + + QQuickView view; + + if (app.arguments().contains(QStringLiteral("--multisample"))) { + QSurfaceFormat fmt; + fmt.setSamples(4); + view.setFormat(fmt); + } + + view.setResizeMode(QQuickView::SizeRootObjectToView); + view.resize(1024, 768); + view.setSource(QUrl("qrc:/pathitemtest/pathitemtest.qml")); + view.show(); + + return app.exec(); +} diff --git a/tests/manual/pathitem/pathitem.pro b/tests/manual/pathitem/pathitem.pro new file mode 100644 index 0000000000..291b0e3ab9 --- /dev/null +++ b/tests/manual/pathitem/pathitem.pro @@ -0,0 +1,6 @@ +TEMPLATE = app + +QT += quick qml +SOURCES += main.cpp +RESOURCES += pathitem.qrc +OTHER_FILES += pathitemtest.qml diff --git a/tests/manual/pathitem/pathitem.qrc b/tests/manual/pathitem/pathitem.qrc new file mode 100644 index 0000000000..d128548ccf --- /dev/null +++ b/tests/manual/pathitem/pathitem.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/pathitemtest"> + <file>pathitemtest.qml</file> + </qresource> +</RCC> diff --git a/tests/manual/pathitem/pathitemtest.qml b/tests/manual/pathitem/pathitemtest.qml new file mode 100644 index 0000000000..cf8a3deece --- /dev/null +++ b/tests/manual/pathitem/pathitemtest.qml @@ -0,0 +1,303 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module 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.9 // to get PathItem + +Rectangle { + id: root + width: 1024 + height: 768 + + property color col: "lightsteelblue" + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.tint(root.col, "#20FFFFFF") } + GradientStop { position: 0.1; color: Qt.tint(root.col, "#20AAAAAA") } + GradientStop { position: 0.9; color: Qt.tint(root.col, "#20666666") } + GradientStop { position: 1.0; color: Qt.tint(root.col, "#20000000") } + } + + Row { + anchors.top: parent.top + anchors.centerIn: parent + spacing: 20 + + Column { + spacing: 20 + + Rectangle { + border.color: "purple" + color: "transparent" + width: 200 + height: 100 + PathItem { + id: triangle + anchors.fill: parent + strokeWidth: 4 + strokeColor: "red" + fillGradient: PathLinearGradient { + x1: 0; y1: 0 + x2: 200; y2: 100 + PathGradientStop { position: 0; color: "blue" } + PathGradientStop { position: 0.2; color: "green" } + PathGradientStop { position: 0.4; color: "red" } + PathGradientStop { position: 0.6; color: "yellow" } + PathGradientStop { position: 1; color: "cyan" } + } + fillColor: "blue" // ignored with the gradient set + strokeStyle: PathItem.DashLine + dashPattern: [ 1, 4 ] + path: Path { + PathLine { x: 200; y: 100 } + PathLine { x: 0; y: 100 } + PathLine { x: 0; y: 0 } + } + transform: Rotation { origin.x: 100; origin.y: 50; axis { x: 0; y: 1; z: 0 } + SequentialAnimation on angle { + NumberAnimation { from: 0; to: 75; duration: 2000 } + NumberAnimation { from: 75; to: -75; duration: 4000 } + NumberAnimation { from: -75; to: 0; duration: 2000 } + loops: Animation.Infinite + } + } + } + } + + Rectangle { + border.color: "purple" + color: "transparent" + width: 200 + height: 100 + PathItem { + id: someCurve + anchors.fill: parent + property color sc: "gray" + strokeColor: sc + property color fc: "yellow" + fillColor: fc + path: Path { + startX: 20; startY: 10 + PathQuad { x: 50; y: 80; controlX: 0; controlY: 80 } + PathLine { x: 150; y: 80 } + PathQuad { x: 180; y: 10; controlX: 200; controlY: 80 } + PathLine { x: 20; y: 10 } + } + // Dynamic changes via property bindings etc. all work but can + // be computationally expense with the generic backend for properties + // that need retriangulating on every change. Should be cheap with NVPR. + NumberAnimation on strokeWidth { + from: 1; to: 20; duration: 10000 + } + // Changing colors for a solid stroke or fill is simple and + // (relatively) cheap. However, changing to/from transparent + // stroke/fill color and stroke width 0 are special as these + // change the scenegraph node tree (with the generic backend). + Timer { + interval: 2000 + running: true + repeat: true + onTriggered: someCurve.fillColor = (someCurve.fillColor === someCurve.fc ? "transparent" : someCurve.fc) + } + Timer { + interval: 1000 + running: true + repeat: true + onTriggered: someCurve.strokeColor = (someCurve.strokeColor === someCurve.sc ? "transparent" : someCurve.sc) + } + } + } + + Rectangle { + border.color: "purple" + color: "transparent" + width: 300 + height: 100 + PathItem { + id: linesAndMoves + anchors.fill: parent + strokeColor: "black" + path: Path { + startX: 0; startY: 50 + PathLine { relativeX: 100; y: 50 } + PathMove { relativeX: 100; y: 50 } + PathLine { relativeX: 100; y: 50 } + } + } + } + + Rectangle { + border.color: "purple" + color: "transparent" + width: 200 + height: 120 + PathItem { + id: joinTest + anchors.fill: parent + strokeColor: "black" + strokeWidth: 16 + fillColor: "transparent" + capStyle: PathItem.RoundCap + path: Path { + startX: 30 + startY: 30 + PathLine { x: 100; y: 100 } + PathLine { x: 30; y: 100 } + } + Timer { + interval: 1000 + repeat: true + running: true + property variant styles: [ PathItem.BevelJoin, PathItem.MiterJoin, PathItem.RoundJoin ] + onTriggered: { + for (var i = 0; i < styles.length; ++i) + if (styles[i] === joinTest.joinStyle) { + joinTest.joinStyle = styles[(i + 1) % styles.length]; + break; + } + } + } + } + } + + Rectangle { + border.color: "purple" + color: "transparent" + width: 200 + height: 100 + PathItem { + id: star + anchors.fill: parent + strokeColor: "blue" + fillColor: "lightGray" + strokeWidth: 2 + path: Path { + PathMove { x: 90; y: 50 } + PathLine { x: 50 + 40 * Math.cos(0.8 * 1 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 1 * Math.PI) } + PathLine { x: 50 + 40 * Math.cos(0.8 * 2 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 2 * Math.PI) } + PathLine { x: 50 + 40 * Math.cos(0.8 * 3 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 3 * Math.PI) } + PathLine { x: 50 + 40 * Math.cos(0.8 * 4 * Math.PI); y: 50 + 40 * Math.sin(0.8 * 4 * Math.PI) } + PathLine { x: 90; y: 50 } + } + Timer { + interval: 1000 + onTriggered: star.fillRule = (star.fillRule === PathItem.OddEvenFill ? PathItem.WindingFill : PathItem.OddEvenFill) + repeat: true + running: true + } + } + } + + Rectangle { + border.color: "purple" + color: "transparent" + width: 200 + height: 100 + PathItem { + anchors.fill: parent + strokeWidth: 4 + strokeColor: "black" + fillColor: "transparent" + path: Path { + startX: 20; startY: 10 + PathCubic { + id: cb + x: 180; y: 10 + control1X: -10; control1Y: 90; control2Y: 90 + NumberAnimation on control2X { from: 400; to: 0; duration: 5000; loops: Animation.Infinite } + } + } + } + } + } + + Column { + spacing: 20 + + Rectangle { + border.color: "purple" + color: "transparent" + width: 200 + height: 100 + PathItem { + anchors.fill: parent + fillColor: "transparent" + strokeColor: "red" + strokeWidth: 4 + path: Path { + startX: 10; startY: 40 + PathArc { + x: 10; y: 60 + radiusX: 40; radiusY: 40 + useLargeArc: true + } + } + } + } + } + } + + Rectangle { + id: stackTestRect + SequentialAnimation on opacity { + NumberAnimation { from: 0; to: 1; duration: 5000 } + PauseAnimation { duration: 2000 } + NumberAnimation { from: 1; to: 0; duration: 5000 } + PauseAnimation { duration: 2000 } + loops: Animation.Infinite + id: opAnim + } + color: "blue" + anchors.margins: 10 + anchors.fill: parent + } + MouseArea { + anchors.fill: parent + onClicked: stackTestRect.visible = !stackTestRect.visible + } +} |