1// Copyright (C) 2024 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 <QtQuick/private/qsggradientcache_p.h>
21#include <qsgnode.h>
22#include <qsggeometry.h>
23#include <qsgmaterial.h>
24#include <qsgrendererinterface.h>
25#include <qsgtexture.h>
26#include <QtCore/qrunnable.h>
27
28QT_BEGIN_NAMESPACE
29
30class QQuickShapeGenericNode;
31class QQuickShapeGenericStrokeFillNode;
32class QQuickShapeFillRunnable;
33class QQuickShapeStrokeRunnable;
34
35class QQuickShapeGenericRenderer : public QQuickAbstractPathRenderer
36{
37public:
38 enum Dirty {
39 DirtyFillGeom = 0x01,
40 DirtyStrokeGeom = 0x02,
41 DirtyColor = 0x04,
42 DirtyFillGradient = 0x08,
43 DirtyFillTransform = 0x10,
44 DirtyFillTexture = 0x20,
45 DirtyList = 0x40 // only for accDirty
46 };
47
48 QQuickShapeGenericRenderer(QQuickItem *item)
49 : m_item(item),
50 m_api(QSGRendererInterface::Unknown),
51 m_rootNode(nullptr),
52 m_accDirty(0),
53 m_asyncCallback(nullptr),
54 m_asyncCallbackData(nullptr)
55 { }
56 ~QQuickShapeGenericRenderer();
57
58 void beginSync(int totalCount, bool *countChanged) override;
59 void setPath(int index, const QPainterPath &path, QQuickShapePath::PathHints pathHints = {}) override;
60 void setStrokeColor(int index, const QColor &color) override;
61 void setStrokeWidth(int index, qreal w) override;
62 void setFillColor(int index, const QColor &color) override;
63 void setFillRule(int index, QQuickShapePath::FillRule fillRule) override;
64 void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override;
65 void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override;
66 void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle,
67 qreal dashOffset, const QVector<qreal> &dashPattern) override;
68 void setFillGradient(int index, QQuickShapeGradient *gradient) override;
69 void setFillTextureProvider(int index, QQuickItem *textureProviderItem) override;
70 void setFillTransform(int index, const QSGTransform &transform) override;
71 void setTriangulationScale(qreal scale) override;
72 void endSync(bool async) override;
73 void setAsyncCallback(void (*)(void *), void *) override;
74 Flags flags() const override { return SupportsAsync; }
75 void handleSceneChange(QQuickWindow *window) override;
76
77 void updateNode() override;
78
79 void setRootNode(QQuickShapeGenericNode *node);
80
81 struct Color4ub { unsigned char r, g, b, a; };
82 typedef QVector<QSGGeometry::ColoredPoint2D> VertexContainerType;
83 typedef QVector<QSGGeometry::TexturedPoint2D> TexturedVertexContainerType;
84 typedef QVector<quint32> IndexContainerType;
85
86 static void triangulateFill(const QPainterPath &path,
87 const Color4ub &fillColor,
88 VertexContainerType *fillVertices,
89 IndexContainerType *fillIndices,
90 QSGGeometry::Type *indexType,
91 bool supportsElementIndexUint,
92 qreal triangulationScale);
93 static void triangulateStroke(const QPainterPath &path,
94 const QPen &pen,
95 const Color4ub &strokeColor,
96 VertexContainerType *strokeVertices,
97 const QSize &clipSize,
98 qreal triangulationScale);
99
100private:
101 void maybeUpdateAsyncItem();
102
103 struct ShapePathData {
104 float strokeWidth;
105 QPen pen;
106 Color4ub strokeColor = { .r: uchar(0), .g: uchar(0), .b: uchar(0), .a: uchar(0) };
107 Color4ub fillColor = { .r: uchar(0), .g: uchar(0), .b: uchar(0), .a: uchar(0) };
108 Qt::FillRule fillRule;
109 QPainterPath path;
110 FillGradientType fillGradientActive;
111 QSGGradientCache::GradientDesc fillGradient;
112 QQuickItem *fillTextureProviderItem = nullptr;
113 QSGTransform fillTransform;
114 VertexContainerType fillVertices;
115 IndexContainerType fillIndices;
116 QSGGeometry::Type indexType;
117 VertexContainerType strokeVertices;
118 int syncDirty;
119 int effectiveDirty = 0;
120 QQuickShapeFillRunnable *pendingFill = nullptr;
121 QQuickShapeStrokeRunnable *pendingStroke = nullptr;
122 };
123
124 void updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n);
125 void updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node);
126 void updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node);
127
128 QQuickItem *m_item;
129 QSGRendererInterface::GraphicsApi m_api;
130 QQuickShapeGenericNode *m_rootNode;
131 QVector<ShapePathData> m_sp;
132 int m_accDirty;
133 void (*m_asyncCallback)(void *);
134 void *m_asyncCallbackData;
135 float m_triangulationScale = 1.0;
136};
137
138class QQuickShapeFillRunnable : public QObject, public QRunnable
139{
140 Q_OBJECT
141
142public:
143 void run() override;
144
145 bool orphaned = false;
146
147 // input
148 QPainterPath path;
149 QQuickShapeGenericRenderer::Color4ub fillColor;
150 bool supportsElementIndexUint;
151 qreal triangulationScale;
152
153 // output
154 QQuickShapeGenericRenderer::VertexContainerType fillVertices;
155 QQuickShapeGenericRenderer::IndexContainerType fillIndices;
156 QSGGeometry::Type indexType;
157
158Q_SIGNALS:
159 void done(QQuickShapeFillRunnable *self);
160};
161
162class QQuickShapeStrokeRunnable : public QObject, public QRunnable
163{
164 Q_OBJECT
165
166public:
167 void run() override;
168
169 bool orphaned = false;
170
171 // input
172 QPainterPath path;
173 QPen pen;
174 QQuickShapeGenericRenderer::Color4ub strokeColor;
175 QSize clipSize;
176 qreal triangulationScale;
177
178 // output
179 QQuickShapeGenericRenderer::VertexContainerType strokeVertices;
180
181Q_SIGNALS:
182 void done(QQuickShapeStrokeRunnable *self);
183};
184
185class QQuickShapeGenericStrokeFillNode : public QObject, public QSGGeometryNode
186{
187 Q_OBJECT
188public:
189 QQuickShapeGenericStrokeFillNode(QQuickWindow *window);
190
191 enum Material {
192 MatSolidColor,
193 MatLinearGradient,
194 MatRadialGradient,
195 MatConicalGradient,
196 MatTextureFill
197 };
198
199 void activateMaterial(QQuickWindow *window, Material m);
200
201 // shadow data for custom materials
202 QSGGradientCache::GradientDesc m_fillGradient;
203 QSGTextureProvider *m_fillTextureProvider = nullptr;
204 QSGTransform m_fillTransform;
205 void preprocess() override;
206
207private Q_SLOTS:
208 void handleTextureChanged();
209 void handleTextureProviderDestroyed();
210
211private:
212 QScopedPointer<QSGMaterial> m_material;
213
214 friend class QQuickShapeGenericRenderer;
215};
216
217class QQuickShapeGenericNode : public QSGNode
218{
219public:
220 QQuickShapeGenericStrokeFillNode *m_fillNode = nullptr;
221 QQuickShapeGenericStrokeFillNode *m_strokeNode = nullptr;
222 QQuickShapeGenericNode *m_next = nullptr;
223};
224
225class QQuickShapeGenericMaterialFactory
226{
227public:
228 static QSGMaterial *createVertexColor(QQuickWindow *window);
229 static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
230 static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
231 static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
232 static QSGMaterial *createTextureFill(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node);
233};
234
235class QQuickShapeLinearGradientRhiShader : public QSGMaterialShader
236{
237public:
238 QQuickShapeLinearGradientRhiShader(int viewCount);
239
240 bool updateUniformData(RenderState &state, QSGMaterial *newMaterial,
241 QSGMaterial *oldMaterial) override;
242 void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
243 QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
244
245private:
246 QSGTransform m_fillTransform;
247 QVector2D m_gradA;
248 QVector2D m_gradB;
249};
250
251class QQuickShapeLinearGradientMaterial : public QSGMaterial
252{
253public:
254 QQuickShapeLinearGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
255 : m_node(node)
256 {
257 // Passing RequiresFullMatrix is essential in order to prevent the
258 // batch renderer from baking in simple, translate-only transforms into
259 // the vertex data. The shader will rely on the fact that
260 // vertexCoord.xy is the Shape-space coordinate and so no modifications
261 // are welcome.
262 setFlag(flags: Blending | RequiresFullMatrix);
263 }
264
265 QSGMaterialType *type() const override;
266 int compare(const QSGMaterial *other) const override;
267 QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
268
269 QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
270
271private:
272 QQuickShapeGenericStrokeFillNode *m_node;
273};
274
275class QQuickShapeRadialGradientRhiShader : public QSGMaterialShader
276{
277public:
278 QQuickShapeRadialGradientRhiShader(int viewCount);
279
280 bool updateUniformData(RenderState &state, QSGMaterial *newMaterial,
281 QSGMaterial *oldMaterial) override;
282 void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
283 QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
284
285private:
286 QSGTransform m_fillTransform;
287 QVector2D m_focalPoint;
288 QVector2D m_focalToCenter;
289 float m_centerRadius;
290 float m_focalRadius;
291};
292
293class QQuickShapeRadialGradientMaterial : public QSGMaterial
294{
295public:
296 QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
297 : m_node(node)
298 {
299 setFlag(flags: Blending | RequiresFullMatrix);
300 }
301
302 QSGMaterialType *type() const override;
303 int compare(const QSGMaterial *other) const override;
304 QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
305
306 QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
307
308private:
309 QQuickShapeGenericStrokeFillNode *m_node;
310};
311
312class QQuickShapeConicalGradientRhiShader : public QSGMaterialShader
313{
314public:
315 QQuickShapeConicalGradientRhiShader(int viewCount);
316
317 bool updateUniformData(RenderState &state, QSGMaterial *newMaterial,
318 QSGMaterial *oldMaterial) override;
319 void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
320 QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
321
322private:
323 QSGTransform m_fillTransform;
324 QVector2D m_centerPoint;
325 float m_angle;
326};
327
328class QQuickShapeConicalGradientMaterial : public QSGMaterial
329{
330public:
331 QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node)
332 : m_node(node)
333 {
334 setFlag(flags: Blending | RequiresFullMatrix);
335 }
336
337 QSGMaterialType *type() const override;
338 int compare(const QSGMaterial *other) const override;
339 QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
340
341 QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
342
343private:
344 QQuickShapeGenericStrokeFillNode *m_node;
345};
346
347class QQuickShapeTextureFillRhiShader : public QSGMaterialShader
348{
349public:
350 QQuickShapeTextureFillRhiShader(int viewCount);
351
352 bool updateUniformData(RenderState &state, QSGMaterial *newMaterial,
353 QSGMaterial *oldMaterial) override;
354 void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
355 QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
356
357private:
358 QSGTransform m_fillTransform;
359 QVector2D m_boundsOffset;
360 QVector2D m_boundsSize;
361};
362
363class QQuickShapeTextureFillMaterial : public QSGMaterial
364{
365public:
366 QQuickShapeTextureFillMaterial(QQuickShapeGenericStrokeFillNode *node)
367 : m_node(node)
368 {
369 setFlag(flags: Blending | RequiresFullMatrix);
370 }
371 ~QQuickShapeTextureFillMaterial() override;
372
373 QSGMaterialType *type() const override;
374 int compare(const QSGMaterial *other) const override;
375 QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;
376
377 QQuickShapeGenericStrokeFillNode *node() const { return m_node; }
378
379 QSGPlainTexture *dummyTexture() const
380 {
381 return m_dummyTexture;
382 }
383
384 void setDummyTexture(QSGPlainTexture *texture)
385 {
386 m_dummyTexture = texture;
387 }
388
389private:
390 QQuickShapeGenericStrokeFillNode *m_node;
391 QSGPlainTexture *m_dummyTexture = nullptr;
392};
393
394QT_END_NAMESPACE
395
396#endif // QQUICKSHAPEGENERICRENDERER_P_H
397

source code of qtdeclarative/src/quickshapes/qquickshapegenericrenderer_p.h