1 | // Copyright (C) 2023 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QQUICKSHAPECURVENODE_P_H |
5 | #define QQUICKSHAPECURVENODE_P_H |
6 | |
7 | #include <QtQuick/qsgnode.h> |
8 | |
9 | #include "qquickshapegenericrenderer_p.h" |
10 | |
11 | // |
12 | // W A R N I N G |
13 | // ------------- |
14 | // |
15 | // This file is not part of the Qt API. It exists for the convenience |
16 | // of a number of Qt sources files. This header file may change from |
17 | // version to version without notice, or even be removed. |
18 | // |
19 | // We mean it. |
20 | // |
21 | |
22 | QT_BEGIN_NAMESPACE |
23 | |
24 | class QQuickShapeCurveNode : public QSGGeometryNode |
25 | { |
26 | public: |
27 | QQuickShapeCurveNode(); |
28 | |
29 | void setColor(QColor col) |
30 | { |
31 | if (m_color == col) |
32 | return; |
33 | m_color = col; |
34 | updateMaterial(); |
35 | } |
36 | |
37 | QColor color() const |
38 | { |
39 | return m_color; |
40 | } |
41 | |
42 | void setStrokeColor(QColor col) |
43 | { |
44 | const bool hadStroke = hasStroke(); |
45 | m_strokeColor = col; |
46 | if (hadStroke != hasStroke()) |
47 | updateMaterial(); |
48 | } |
49 | |
50 | QColor strokeColor() const |
51 | { |
52 | return m_strokeColor; |
53 | } |
54 | |
55 | void setStrokeWidth(float width) |
56 | { |
57 | const bool hadStroke = hasStroke(); |
58 | m_strokeWidth = width; |
59 | if (hadStroke != hasStroke()) |
60 | updateMaterial(); |
61 | } |
62 | |
63 | float strokeWidth() const |
64 | { |
65 | return m_strokeWidth; |
66 | } |
67 | |
68 | void setFillGradient(const QQuickAbstractPathRenderer::GradientDesc &fillGradient) |
69 | { |
70 | m_fillGradient = fillGradient; |
71 | } |
72 | |
73 | QQuickAbstractPathRenderer::GradientDesc fillGradient() const |
74 | { |
75 | return m_fillGradient; |
76 | } |
77 | |
78 | void setGradientType(QQuickAbstractPathRenderer::FillGradientType type) |
79 | { |
80 | if (m_gradientType != type) { |
81 | m_gradientType = type; |
82 | updateMaterial(); |
83 | } |
84 | } |
85 | |
86 | float debug() const |
87 | { |
88 | return m_debug; |
89 | } |
90 | |
91 | void setDebug(float newDebug) |
92 | { |
93 | m_debug = newDebug; |
94 | } |
95 | |
96 | QQuickAbstractPathRenderer::FillGradientType gradientType() const |
97 | { |
98 | return m_gradientType; |
99 | } |
100 | |
101 | bool hasStroke() const |
102 | { |
103 | return m_strokeWidth > 0.0f && m_strokeColor.alpha() > 0; |
104 | } |
105 | |
106 | void appendTriangle(const std::array<QVector2D, 3> &v, // triangle vertices |
107 | const std::array<QVector2D, 3> &n, // vertex normals |
108 | std::function<QVector3D(QVector2D)> uvForPoint |
109 | ) |
110 | { |
111 | QVector3D uv1 = uvForPoint(v[0]); |
112 | QVector3D uv2 = uvForPoint(v[1]); |
113 | QVector3D uv3 = uvForPoint(v[2]); |
114 | |
115 | QVector2D duvdx = QVector2D(uvForPoint(v[0] + QVector2D(1, 0))) - QVector2D(uv1); |
116 | QVector2D duvdy = QVector2D(uvForPoint(v[0] + QVector2D(0, 1))) - QVector2D(uv1); |
117 | |
118 | m_uncookedIndexes.append(t: m_uncookedVertexes.size()); |
119 | m_uncookedVertexes.append( t: { .x: v[0].x(), .y: v[0].y(), |
120 | .u: uv1.x(), .v: uv1.y(), .w: uv1.z(), |
121 | .dudx: duvdx.x(), .dvdx: duvdx.y(), |
122 | .dudy: duvdy.x(), .dvdy: duvdy.y(), |
123 | .nx: n[0].x(), .ny: n[0].y() |
124 | }); |
125 | |
126 | m_uncookedIndexes.append(t: m_uncookedVertexes.size()); |
127 | m_uncookedVertexes.append( t: { .x: v[1].x(), .y: v[1].y(), |
128 | .u: uv2.x(), .v: uv2.y(), .w: uv2.z(), |
129 | .dudx: duvdx.x(), .dvdx: duvdx.y(), |
130 | .dudy: duvdy.x(), .dvdy: duvdy.y(), |
131 | .nx: n[1].x(), .ny: n[1].y() |
132 | }); |
133 | |
134 | m_uncookedIndexes.append(t: m_uncookedVertexes.size()); |
135 | m_uncookedVertexes.append( t: { .x: v[2].x(), .y: v[2].y(), |
136 | .u: uv3.x(), .v: uv3.y(), .w: uv3.z(), |
137 | .dudx: duvdx.x(), .dvdx: duvdx.y(), |
138 | .dudy: duvdy.x(), .dvdy: duvdy.y(), |
139 | .nx: n[2].x(), .ny: n[2].y() |
140 | }); |
141 | |
142 | } |
143 | |
144 | void appendTriangle(const QVector2D &v1, |
145 | const QVector2D &v2, |
146 | const QVector2D &v3, |
147 | std::function<QVector3D(QVector2D)> uvForPoint) |
148 | { |
149 | appendTriangle(v: {v1, v2, v3}, n: {}, uvForPoint); |
150 | } |
151 | |
152 | void appendIndex(quint32 index) |
153 | { |
154 | m_uncookedIndexes.append(t: index); |
155 | } |
156 | |
157 | void appendIndexes(QVector<quint32> indexes) |
158 | { |
159 | m_uncookedIndexes.append(l: indexes); |
160 | } |
161 | |
162 | QVector<quint32> uncookedIndexes() const |
163 | { |
164 | return m_uncookedIndexes; |
165 | } |
166 | |
167 | void cookGeometry(); |
168 | |
169 | private: |
170 | struct CurveNodeVertex |
171 | { |
172 | float x, y, u, v, w; |
173 | float dudx, dvdx, dudy, dvdy; // Size of pixel in curve space (must be same for all vertices in triangle) |
174 | float nx, ny; // normal vector describing the direction to shift the vertex for AA |
175 | }; |
176 | |
177 | void updateMaterial(); |
178 | static const QSGGeometry::AttributeSet &attributes(); |
179 | |
180 | QColor m_color = Qt::white; |
181 | QColor m_strokeColor = Qt::transparent; |
182 | float m_strokeWidth = 0.0f; |
183 | float m_debug = 0.0f; |
184 | QQuickAbstractPathRenderer::GradientDesc m_fillGradient; |
185 | QQuickAbstractPathRenderer::FillGradientType m_gradientType = QQuickAbstractPathRenderer::NoGradient; |
186 | |
187 | QScopedPointer<QSGMaterial> m_material; |
188 | |
189 | QVector<CurveNodeVertex> m_uncookedVertexes; |
190 | QVector<quint32> m_uncookedIndexes; |
191 | }; |
192 | |
193 | QT_END_NAMESPACE |
194 | |
195 | #endif // QQUICKSHAPECURVENODE_P_H |
196 | |