1 | // Copyright (C) 2016 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 QQUICKSHAPEGENERICRENDERER_P_H |
5 | #define QQUICKSHAPEGENERICRENDERER_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of a number of Qt sources files. This header file may change from |
13 | // version to version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtQuickShapes/private/qquickshapesglobal_p.h> |
19 | #include <QtQuickShapes/private/qquickshape_p_p.h> |
20 | #include <qsgnode.h> |
21 | #include <qsggeometry.h> |
22 | #include <qsgmaterial.h> |
23 | #include <qsgrendererinterface.h> |
24 | #include <qsgtexture.h> |
25 | #include <QtCore/qrunnable.h> |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | class QQuickShapeGenericNode; |
30 | class QQuickShapeGenericStrokeFillNode; |
31 | class QQuickShapeFillRunnable; |
32 | class QQuickShapeStrokeRunnable; |
33 | |
34 | class QQuickShapeGenericRenderer : public QQuickAbstractPathRenderer |
35 | { |
36 | public: |
37 | enum Dirty { |
38 | DirtyFillGeom = 0x01, |
39 | DirtyStrokeGeom = 0x02, |
40 | DirtyColor = 0x04, |
41 | DirtyFillGradient = 0x08, |
42 | DirtyList = 0x10 // only for accDirty |
43 | }; |
44 | |
45 | QQuickShapeGenericRenderer(QQuickItem *item) |
46 | : m_item(item), |
47 | m_api(QSGRendererInterface::Unknown), |
48 | m_rootNode(nullptr), |
49 | m_accDirty(0), |
50 | m_asyncCallback(nullptr), |
51 | m_asyncCallbackData(nullptr) |
52 | { } |
53 | ~QQuickShapeGenericRenderer(); |
54 | |
55 | void beginSync(int totalCount, bool *countChanged) override; |
56 | void setPath(int index, const QQuickPath *path) override; |
57 | void setStrokeColor(int index, const QColor &color) override; |
58 | void setStrokeWidth(int index, qreal w) override; |
59 | void setFillColor(int index, const QColor &color) override; |
60 | void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; |
61 | void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; |
62 | void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; |
63 | void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, |
64 | qreal dashOffset, const QVector<qreal> &dashPattern) override; |
65 | void setFillGradient(int index, QQuickShapeGradient *gradient) override; |
66 | void setTriangulationScale(qreal scale) override; |
67 | void endSync(bool async) override; |
68 | void setAsyncCallback(void (*)(void *), void *) override; |
69 | Flags flags() const override { return SupportsAsync; } |
70 | |
71 | void updateNode() override; |
72 | |
73 | void setRootNode(QQuickShapeGenericNode *node); |
74 | |
75 | struct Color4ub { unsigned char r, g, b, a; }; |
76 | typedef QVector<QSGGeometry::ColoredPoint2D> VertexContainerType; |
77 | typedef QVector<quint32> IndexContainerType; |
78 | |
79 | static void triangulateFill(const QPainterPath &path, |
80 | const Color4ub &fillColor, |
81 | VertexContainerType *fillVertices, |
82 | IndexContainerType *fillIndices, |
83 | QSGGeometry::Type *indexType, |
84 | bool supportsElementIndexUint, |
85 | qreal triangulationScale); |
86 | static void triangulateStroke(const QPainterPath &path, |
87 | const QPen &pen, |
88 | const Color4ub &strokeColor, |
89 | VertexContainerType *strokeVertices, |
90 | const QSize &clipSize, |
91 | qreal triangulationScale); |
92 | |
93 | private: |
94 | void maybeUpdateAsyncItem(); |
95 | |
96 | struct ShapePathData { |
97 | float strokeWidth; |
98 | QPen pen; |
99 | Color4ub strokeColor; |
100 | Color4ub fillColor; |
101 | Qt::FillRule fillRule; |
102 | QPainterPath path; |
103 | FillGradientType fillGradientActive; |
104 | GradientDesc fillGradient; |
105 | VertexContainerType fillVertices; |
106 | IndexContainerType fillIndices; |
107 | QSGGeometry::Type indexType; |
108 | VertexContainerType strokeVertices; |
109 | int syncDirty; |
110 | int effectiveDirty = 0; |
111 | QQuickShapeFillRunnable *pendingFill = nullptr; |
112 | QQuickShapeStrokeRunnable *pendingStroke = nullptr; |
113 | }; |
114 | |
115 | void updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n); |
116 | void updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node); |
117 | void updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node); |
118 | |
119 | QQuickItem *m_item; |
120 | QSGRendererInterface::GraphicsApi m_api; |
121 | QQuickShapeGenericNode *m_rootNode; |
122 | QVector<ShapePathData> m_sp; |
123 | int m_accDirty; |
124 | void (*m_asyncCallback)(void *); |
125 | void *m_asyncCallbackData; |
126 | float m_triangulationScale = 1.0; |
127 | }; |
128 | |
129 | class QQuickShapeFillRunnable : public QObject, public QRunnable |
130 | { |
131 | Q_OBJECT |
132 | |
133 | public: |
134 | void run() override; |
135 | |
136 | bool orphaned = false; |
137 | |
138 | // input |
139 | QPainterPath path; |
140 | QQuickShapeGenericRenderer::Color4ub fillColor; |
141 | bool supportsElementIndexUint; |
142 | qreal triangulationScale; |
143 | |
144 | // output |
145 | QQuickShapeGenericRenderer::VertexContainerType fillVertices; |
146 | QQuickShapeGenericRenderer::IndexContainerType fillIndices; |
147 | QSGGeometry::Type indexType; |
148 | |
149 | Q_SIGNALS: |
150 | void done(QQuickShapeFillRunnable *self); |
151 | }; |
152 | |
153 | class QQuickShapeStrokeRunnable : public QObject, public QRunnable |
154 | { |
155 | Q_OBJECT |
156 | |
157 | public: |
158 | void run() override; |
159 | |
160 | bool orphaned = false; |
161 | |
162 | // input |
163 | QPainterPath path; |
164 | QPen pen; |
165 | QQuickShapeGenericRenderer::Color4ub strokeColor; |
166 | QSize clipSize; |
167 | qreal triangulationScale; |
168 | |
169 | // output |
170 | QQuickShapeGenericRenderer::VertexContainerType strokeVertices; |
171 | |
172 | Q_SIGNALS: |
173 | void done(QQuickShapeStrokeRunnable *self); |
174 | }; |
175 | |
176 | class QQuickShapeGenericStrokeFillNode : public QSGGeometryNode |
177 | { |
178 | public: |
179 | QQuickShapeGenericStrokeFillNode(QQuickWindow *window); |
180 | |
181 | enum Material { |
182 | MatSolidColor, |
183 | MatLinearGradient, |
184 | MatRadialGradient, |
185 | MatConicalGradient |
186 | }; |
187 | |
188 | void activateMaterial(QQuickWindow *window, Material m); |
189 | |
190 | // shadow data for custom materials |
191 | QQuickAbstractPathRenderer::GradientDesc m_fillGradient; |
192 | |
193 | private: |
194 | QScopedPointer<QSGMaterial> m_material; |
195 | |
196 | friend class QQuickShapeGenericRenderer; |
197 | }; |
198 | |
199 | class QQuickShapeGenericNode : public QSGNode |
200 | { |
201 | public: |
202 | QQuickShapeGenericStrokeFillNode *m_fillNode = nullptr; |
203 | QQuickShapeGenericStrokeFillNode *m_strokeNode = nullptr; |
204 | QQuickShapeGenericNode *m_next = nullptr; |
205 | }; |
206 | |
207 | class QQuickShapeGenericMaterialFactory |
208 | { |
209 | public: |
210 | static QSGMaterial *createVertexColor(QQuickWindow *window); |
211 | static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); |
212 | static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); |
213 | static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); |
214 | }; |
215 | |
216 | class QQuickShapeLinearGradientRhiShader : public QSGMaterialShader |
217 | { |
218 | public: |
219 | QQuickShapeLinearGradientRhiShader(); |
220 | |
221 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, |
222 | QSGMaterial *oldMaterial) override; |
223 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
224 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
225 | |
226 | private: |
227 | QVector2D m_gradA; |
228 | QVector2D m_gradB; |
229 | }; |
230 | |
231 | class QQuickShapeLinearGradientMaterial : public QSGMaterial |
232 | { |
233 | public: |
234 | QQuickShapeLinearGradientMaterial(QQuickShapeGenericStrokeFillNode *node) |
235 | : m_node(node) |
236 | { |
237 | // Passing RequiresFullMatrix is essential in order to prevent the |
238 | // batch renderer from baking in simple, translate-only transforms into |
239 | // the vertex data. The shader will rely on the fact that |
240 | // vertexCoord.xy is the Shape-space coordinate and so no modifications |
241 | // are welcome. |
242 | setFlag(flags: Blending | RequiresFullMatrix); |
243 | } |
244 | |
245 | QSGMaterialType *type() const override; |
246 | int compare(const QSGMaterial *other) const override; |
247 | QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override; |
248 | |
249 | QQuickShapeGenericStrokeFillNode *node() const { return m_node; } |
250 | |
251 | private: |
252 | QQuickShapeGenericStrokeFillNode *m_node; |
253 | }; |
254 | |
255 | class QQuickShapeRadialGradientRhiShader : public QSGMaterialShader |
256 | { |
257 | public: |
258 | QQuickShapeRadialGradientRhiShader(); |
259 | |
260 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, |
261 | QSGMaterial *oldMaterial) override; |
262 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
263 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
264 | |
265 | private: |
266 | QVector2D m_focalPoint; |
267 | QVector2D m_focalToCenter; |
268 | float m_centerRadius; |
269 | float m_focalRadius; |
270 | }; |
271 | |
272 | class QQuickShapeRadialGradientMaterial : public QSGMaterial |
273 | { |
274 | public: |
275 | QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node) |
276 | : m_node(node) |
277 | { |
278 | setFlag(flags: Blending | RequiresFullMatrix); |
279 | } |
280 | |
281 | QSGMaterialType *type() const override; |
282 | int compare(const QSGMaterial *other) const override; |
283 | QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override; |
284 | |
285 | QQuickShapeGenericStrokeFillNode *node() const { return m_node; } |
286 | |
287 | private: |
288 | QQuickShapeGenericStrokeFillNode *m_node; |
289 | }; |
290 | |
291 | class QQuickShapeConicalGradientRhiShader : public QSGMaterialShader |
292 | { |
293 | public: |
294 | QQuickShapeConicalGradientRhiShader(); |
295 | |
296 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, |
297 | QSGMaterial *oldMaterial) override; |
298 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
299 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
300 | |
301 | private: |
302 | QVector2D m_centerPoint; |
303 | float m_angle; |
304 | }; |
305 | |
306 | class QQuickShapeConicalGradientMaterial : public QSGMaterial |
307 | { |
308 | public: |
309 | QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node) |
310 | : m_node(node) |
311 | { |
312 | setFlag(flags: Blending | RequiresFullMatrix); |
313 | } |
314 | |
315 | QSGMaterialType *type() const override; |
316 | int compare(const QSGMaterial *other) const override; |
317 | QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override; |
318 | |
319 | QQuickShapeGenericStrokeFillNode *node() const { return m_node; } |
320 | |
321 | private: |
322 | QQuickShapeGenericStrokeFillNode *m_node; |
323 | }; |
324 | |
325 | QT_END_NAMESPACE |
326 | |
327 | #endif // QQUICKSHAPEGENERICRENDERER_P_H |
328 | |