aboutsummaryrefslogtreecommitdiffstats
path: root/tests/manual/painterpathquickshape
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2023-07-13 11:45:55 +0200
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2023-07-14 08:40:47 +0200
commit73324c379f8c638106203d679549e7785d16af38 (patch)
tree87bb90f877290aba3f4023ea23dc2f73dcb0d3e1 /tests/manual/painterpathquickshape
parentcb644288976b6abd2c9bda4caaf7e447660336a9 (diff)
Improve Qt Quick Shapes curve renderer strokes
This adds a specialized stroke shader which replaces the curve flattening triangulating stroker as the default. The triangulating stroker is still available via an environment variable for testing. Dashed strokes are now done by cutting the path into segments ahead of time and applying the normal solid stroking algorithm to the corresponding path. In addition, the fill shader no longer depends on the derivatives extension except when used in 3D scenes to support perspective transforms. The preprocessing of the shape has also gotten a few bug fixes and improvements and there are extremely few artifacts left. Done-with: Paul Olav Tvete <paul.tvete@qt.io> Done-with: Eirik Aavitsland <eirik.aavitsland@qt.io> Done-with: Matthias Rauter <matthias.rauter@qt.io> Task-number: QTBUG-104122 Change-Id: Ib49b41019956be3e3cd509d1f3cef6842658aceb Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Matthias Rauter <matthias.rauter@qt.io>
Diffstat (limited to 'tests/manual/painterpathquickshape')
-rw-r--r--tests/manual/painterpathquickshape/CMakeLists.txt78
-rw-r--r--tests/manual/painterpathquickshape/ControlPanel.qml41
-rw-r--r--tests/manual/painterpathquickshape/ControlledShape.qml8
-rw-r--r--tests/manual/painterpathquickshape/DashedStroke.qml24
-rw-r--r--tests/manual/painterpathquickshape/SimpleShape.qml9
-rw-r--r--tests/manual/painterpathquickshape/SvgShape.qml9
-rw-r--r--tests/manual/painterpathquickshape/main.cpp1
-rw-r--r--tests/manual/painterpathquickshape/main.qml83
-rw-r--r--tests/manual/painterpathquickshape/zoombox.frag22
9 files changed, 229 insertions, 46 deletions
diff --git a/tests/manual/painterpathquickshape/CMakeLists.txt b/tests/manual/painterpathquickshape/CMakeLists.txt
index 67f5b142ef..1f92afaba5 100644
--- a/tests/manual/painterpathquickshape/CMakeLists.txt
+++ b/tests/manual/painterpathquickshape/CMakeLists.txt
@@ -1,6 +1,15 @@
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
+cmake_minimum_required(VERSION 3.16)
+
+if (NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT)
+ project(painterPathQuickShape LANGUAGES C CXX ASM)
+ find_package(Qt6BuildInternals COMPONENTS STANDALONE_TEST)
+endif()
+
+find_package(Qt6 COMPONENTS ShaderTools)
+
qt_internal_add_manual_test(painterPathQuickShape
GUI
SOURCES
@@ -20,35 +29,36 @@ qt_internal_add_manual_test(painterPathQuickShape
set(qml_resource_files
"1535737773.svg"
"main.qml"
- "SvgShape.qml"
- "ControlPanel.qml"
- "ControlPoint.qml"
- "TextShape.qml"
- "SimpleShape.qml"
- "SmallPolygon.qml"
- "Squircle.qml"
- "ControlledShape.qml"
- "Mussel.qml"
- "Graziano.ttf"
- "CubicShape.qml"
- "hand-print.svg"
- "background.png"
- "arcDirection.qml"
- "arcRotation.qml"
- "capStyles.qml"
- "cubicCurve.qml"
- "dashPattern.qml"
- "ellipticalArcs.qml"
- "fillRules.qml"
- "gradientSpreadModes.qml"
- "joinStyles.qml"
- "largeOrSmallArc.qml"
- "linearGradient.qml"
- "quadraticCurve.qml"
- "radialGradient.qml"
- "strokeOrFill.qml"
- "text.qml"
- "tiger.qml"
+ "SvgShape.qml"
+ "ControlPanel.qml"
+ "ControlPoint.qml"
+ "TextShape.qml"
+ "SimpleShape.qml"
+ "SmallPolygon.qml"
+ "Squircle.qml"
+ "ControlledShape.qml"
+ "Mussel.qml"
+ "Graziano.ttf"
+ "CubicShape.qml"
+ "DashedStroke.qml"
+ "hand-print.svg"
+ "background.png"
+ "arcDirection.qml"
+ "arcRotation.qml"
+ "capStyles.qml"
+ "cubicCurve.qml"
+ "dashPattern.qml"
+ "ellipticalArcs.qml"
+ "fillRules.qml"
+ "gradientSpreadModes.qml"
+ "joinStyles.qml"
+ "largeOrSmallArc.qml"
+ "linearGradient.qml"
+ "quadraticCurve.qml"
+ "radialGradient.qml"
+ "strokeOrFill.qml"
+ "text.qml"
+ "tiger.qml"
)
qt_internal_add_resource(painterPathQuickShape "qml"
@@ -58,6 +68,16 @@ qt_internal_add_resource(painterPathQuickShape "qml"
${qml_resource_files}
)
+qt_add_shaders(painterPathQuickShape "shaders"
+ BATCHABLE
+ PRECOMPILE
+ OPTIMIZED
+ PREFIX
+ "/"
+ FILES
+ "zoombox.frag"
+)
+
qt_add_qml_module(painterPathQuickShape
VERSION 1.0
URI InstancingTest
diff --git a/tests/manual/painterpathquickshape/ControlPanel.qml b/tests/manual/painterpathquickshape/ControlPanel.qml
index 1b34bb6eab..bb26e658f3 100644
--- a/tests/manual/painterpathquickshape/ControlPanel.qml
+++ b/tests/manual/painterpathquickshape/ControlPanel.qml
@@ -6,6 +6,7 @@ import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Shapes
import QtQuick.Dialogs
+import QtCore
Item {
property real scale: +scaleSlider.value.toFixed(4)
@@ -15,7 +16,7 @@ Item {
property color fillColor: Qt.rgba(fillColor.color.r, fillColor.color.g, fillColor.color.b, pathAlpha)
property alias pathAlpha: alphaSlider.value
property alias outlineAlpha: outlineAlphaSlider.value
- property real outlineWidth: cosmeticPen.checked ? outlineWidth.value / scale : outlineWidth.value ** 2
+ property real outlineWidth: cosmeticPen.checked ? outlineWidthEdit.text / scale : outlineWidthEdit.text
property alias outlineStyle: outlineStyle.currentValue
property alias capStyle: capStyle.currentValue
property alias joinStyle: joinStyle.currentValue
@@ -34,6 +35,23 @@ Item {
property real pathMargin: marginEdit.text
+ Settings {
+ property alias enableOutline: enableOutline.checked
+ property alias outlineColor: outlineColor.color
+ property alias outlineWidth: outlineWidthEdit.text
+ property alias outlineAlpha: outlineAlphaSlider.value
+ property alias outlineStyle: outlineStyle.currentIndex
+ property alias joinStyle: joinStyle.currentIndex
+ property alias capStyle: capStyle.currentIndex
+ property alias cosmeticPen: cosmeticPen.checked
+
+ property alias pathAlpha: alphaSlider.value
+ property alias fillColor: fillColor.color
+
+ property alias setBackground: setBackground.checked
+ property alias backgroundColor: bgColor.color
+ }
+
function setScale(x) {
scaleSlider.value = x
}
@@ -200,7 +218,7 @@ Item {
model: [ "NoGradient", "LinearGradient", "RadialGradient", "ConicalGradient" ]
}
Label {
- text: "Path alpha:"
+ text: "Fill alpha(" + Math.round(alphaSlider.value*100)/100 + "):"
color: "white"
}
Slider {
@@ -290,11 +308,24 @@ Item {
}
}
Label {
- text: "Outline width"
+ text: "Outline width:"
color: "white"
}
+ TextField {
+ id: outlineWidthEdit
+ text: (cosmeticPen.checked ? outlineWidthSlider.value: outlineWidthSlider.value ** 2).toFixed(2)
+ onEditingFinished: {
+ let val = +text
+ if (val > 0) {
+ if (cosmeticPen.checked)
+ outlineWidth.value = val * scale
+ else
+ outlineWidth.value = Math.sqrt(val)
+ }
+ }
+ }
Slider {
- id: outlineWidth
+ id: outlineWidthSlider
Layout.fillWidth: true
from: 0.0
to: 10.0
@@ -306,7 +337,7 @@ Item {
palette.windowText: "white"
}
Label {
- text: "Outline alpha"
+ text: "Outline alpha (" + Math.round(outlineAlphaSlider.value*100)/100 + "):"
color: "white"
}
Slider {
diff --git a/tests/manual/painterpathquickshape/ControlledShape.qml b/tests/manual/painterpathquickshape/ControlledShape.qml
index cf9cbaa5d8..b0f4492eb2 100644
--- a/tests/manual/painterpathquickshape/ControlledShape.qml
+++ b/tests/manual/painterpathquickshape/ControlledShape.qml
@@ -7,12 +7,14 @@ import io.qt
Item {
id: topLevel
- property alias fillColor: shapePath.fillColor
- property alias strokeStyle: shapePath.strokeStyle
property alias capStyle: shapePath.capStyle
+ property alias dashOffset: shapePath.dashOffset
+ property alias dashPattern: shapePath.dashPattern
+ property alias fillColor: shapePath.fillColor
+ property alias fillRule: shapePath.fillRule
property alias strokeColor: shapePath.strokeColor
+ property alias strokeStyle: shapePath.strokeStyle
property alias strokeWidth: shapePath.strokeWidth
- property alias fillRule: shapePath.fillRule
property alias shapeTransform: shape.transform
property alias startX: shapePath.startX
diff --git a/tests/manual/painterpathquickshape/DashedStroke.qml b/tests/manual/painterpathquickshape/DashedStroke.qml
new file mode 100644
index 0000000000..60952ec599
--- /dev/null
+++ b/tests/manual/painterpathquickshape/DashedStroke.qml
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Shapes
+
+ControlledShape {
+ fillColor: "transparent"
+ strokeStyle: ShapePath.DashLine
+ dashOffset: 6.5
+ dashPattern: [ 4, 2, 1, 2, 1, 2 ]
+ delegate: [
+ PathMove { x: 200; y: 200 },
+ PathLine { x: 1000; y: 200 },
+ PathMove { x: 200; y: 300 },
+ PathLine { x: 1000; y: 300 },
+ PathMove { x: 200; y: 400 },
+ PathQuad { x: 1000; y: 400; controlX: 450; controlY: 600 },
+ PathLine { x: 1600; y: 500 },
+ PathMove { x: 200; y: 500 },
+ PathQuad { x: 1000; y: 500; controlX: 450; controlY: 700 },
+ PathLine { x: 1600; y: 600 }
+ ]
+}
diff --git a/tests/manual/painterpathquickshape/SimpleShape.qml b/tests/manual/painterpathquickshape/SimpleShape.qml
index 3458e26f4a..cb6261c39a 100644
--- a/tests/manual/painterpathquickshape/SimpleShape.qml
+++ b/tests/manual/painterpathquickshape/SimpleShape.qml
@@ -11,12 +11,11 @@ ControlledShape {
PathPolyline {
id: ppl
path: [ Qt.point(150.0, 100.0),
- Qt.point(1250.0, 150.0),
- Qt.point(100.0, 1000.0),
- Qt.point(150, 100)
- ]
+ Qt.point(1250.0, 150.0),
+ Qt.point(100.0, 1000.0),
+ Qt.point(150, 100)
+ ]
},
-
// A very narrow shape with one convex and one concave curve
PathMove { x: 600; y: 1200},
PathQuad { x: 800; y: 1200; controlX: 700; controlY: 600 },
diff --git a/tests/manual/painterpathquickshape/SvgShape.qml b/tests/manual/painterpathquickshape/SvgShape.qml
index 697ede2524..429ca507e6 100644
--- a/tests/manual/painterpathquickshape/SvgShape.qml
+++ b/tests/manual/painterpathquickshape/SvgShape.qml
@@ -63,12 +63,13 @@ Item {
strokeWidth = "1.0" // default value defined by SVG standard
strokeText = "strokeColor: \"" + strokeColor + "\"; strokeWidth: " + strokeWidth + ";"
}
- if (!fillColor) {
- fillColor = "#00000000"
- }
+
+ let fillText = "";
+ if (fillColor)
+ fillText = "fillColor: \"" + fillColor + "\";\n";
var obj = Qt.createQmlObject("import QtQuick\nimport QtQuick.Shapes\n ControlledShape { \n"
- + "fillColor: \"" + fillColor + "\";\n"
+ + fillText
+ "shapeTransform: Matrix4x4 { matrix: Qt.matrix4x4(" + transform + "); }\n"
+ strokeText + "\n"
+ "fillRule: ShapePath.WindingFill; delegate: [ PathSvg { path: \"" + s + "\"; } ] }\n",
diff --git a/tests/manual/painterpathquickshape/main.cpp b/tests/manual/painterpathquickshape/main.cpp
index 5b780b9439..c1fa790bd4 100644
--- a/tests/manual/painterpathquickshape/main.cpp
+++ b/tests/manual/painterpathquickshape/main.cpp
@@ -15,6 +15,7 @@ int main(int argc, char *argv[])
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
+ app.setOrganizationName("QtProject");
qmlRegisterType<DebugPaintItem>("io.qt", 1, 0, "DebugPaintItem");
qmlRegisterType<SvgPathLoader>("io.qt", 1, 0, "SvgPathLoader");
diff --git a/tests/manual/painterpathquickshape/main.qml b/tests/manual/painterpathquickshape/main.qml
index 9ad5d1f1a4..c7c1f60579 100644
--- a/tests/manual/painterpathquickshape/main.qml
+++ b/tests/manual/painterpathquickshape/main.qml
@@ -6,8 +6,10 @@ import QtQuick.Window
import QtQuick.Shapes
import QtQuick.Controls
import QtQuick.Layouts
+import QtCore
Window {
+ id: theWindow
width: 1024
height: 768
visible: true
@@ -42,6 +44,10 @@ Window {
source: "CubicShape.qml"
}
ListElement {
+ text: "DashedStroke"
+ source: "DashedStroke.qml"
+ }
+ ListElement {
text: "Mussel"
source: "Mussel.qml"
}
@@ -189,8 +195,80 @@ Window {
y: controlPanel.pathMargin
id: loader
}
+ MouseArea {
+ acceptedButtons: Qt.NoButton
+ anchors.fill: parent
+ onMouseXChanged: {
+ let p = Qt.point(Math.round(mouseX), Math.round(mouseY))
+ p = mapToItem(loader.item, p)
+ zoomTarget.sourceRect.x = p.x - zoomTarget.sourceRect.width/2
+ }
+ onMouseYChanged: {
+ let p = Qt.point(Math.round(mouseX), Math.round(mouseY))
+ p = mapToItem(loader.item, p)
+ zoomTarget.sourceRect.y = p.y - zoomTarget.sourceRect.height/2
+ }
+ hoverEnabled: true
+ }
+ ShaderEffectSource {
+ id: zoomTarget
+ sourceItem: loader.item
+ sourceRect.width: 16
+ sourceRect.height: 16
+ }
+ }
+
+
+ Rectangle {
+ anchors.top: flickable.top
+ anchors.right: flickable.right
+ anchors.margins: 5
+ width: 256
+ height: 256
+ border.color: Qt.black
+ ShaderEffect {
+ anchors.fill: parent
+ anchors.margins: 1
+ property variant src: zoomTarget
+ property real textureWidth: zoomTarget.sourceRect.width
+ property real textureHeight: zoomTarget.sourceRect.height
+ fragmentShader: "zoombox.frag.qsb"
+ }
+ Button {
+ id: plusButton
+ text: "+"
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.margins: 2
+ width: 20
+ height: 20
+ onPressed: {
+ zoomTarget.sourceRect.width = Math.max(zoomTarget.sourceRect.width / 2, 4)
+ zoomTarget.sourceRect.height = Math.max(zoomTarget.sourceRect.height / 2, 4)
+ }
+ }
+ Button {
+ id: minusButton
+ text: "-"
+ anchors.top: plusButton.bottom
+ anchors.right: parent.right
+ anchors.margins: 2
+ width: 20
+ height: 20
+ onPressed: {
+ zoomTarget.sourceRect.width = Math.max(zoomTarget.sourceRect.width * 2, 4)
+ zoomTarget.sourceRect.height = Math.max(zoomTarget.sourceRect.height * 2, 4)
+ }
+ }
+ Text {
+ text: "x"+parent.width / zoomTarget.sourceRect.width
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ anchors.margins: 2
+ }
}
+
ControlPanel {
id: controlPanel
anchors.bottom: parent.bottom
@@ -198,4 +276,9 @@ Window {
anchors.right: parent.right
height: parent.height / 4
}
+ Settings {
+ property alias currentTab: comboBox.currentIndex
+ property alias windowWidth: theWindow.width
+ property alias windowHeight: theWindow.height
+ }
}
diff --git a/tests/manual/painterpathquickshape/zoombox.frag b/tests/manual/painterpathquickshape/zoombox.frag
new file mode 100644
index 0000000000..e7754cb75c
--- /dev/null
+++ b/tests/manual/painterpathquickshape/zoombox.frag
@@ -0,0 +1,22 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ float textureWidth;
+ float textureHeight;
+};
+layout(binding = 1) uniform sampler2D src;
+
+
+void main(void)
+{
+
+ float xPixelIndex = (round((textureWidth - 1.) * qt_TexCoord0.x) + 0.5) / textureWidth;
+ float yPixelIndex = (round((textureHeight - 1.) * qt_TexCoord0.y) + 0.5) / textureHeight;
+
+ fragColor = texture(src, vec2(xPixelIndex, yPixelIndex)) * qt_Opacity;
+}