1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQuick module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #ifndef QQUICKSHAPEGENERICRENDERER_P_H |
41 | #define QQUICKSHAPEGENERICRENDERER_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists for the convenience |
48 | // of a number of Qt sources files. This header file may change from |
49 | // version to version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <QtQuickShapes/private/qquickshapesglobal_p.h> |
55 | #include <QtQuickShapes/private/qquickshape_p_p.h> |
56 | #include <qsgnode.h> |
57 | #include <qsggeometry.h> |
58 | #include <qsgmaterial.h> |
59 | #include <qsgrendererinterface.h> |
60 | #include <qsgtexture.h> |
61 | #include <QtCore/qrunnable.h> |
62 | |
63 | QT_BEGIN_NAMESPACE |
64 | |
65 | class QQuickShapeGenericNode; |
66 | class QQuickShapeGenericStrokeFillNode; |
67 | class QQuickShapeFillRunnable; |
68 | class QQuickShapeStrokeRunnable; |
69 | |
70 | class QQuickShapeGenericRenderer : public QQuickAbstractPathRenderer |
71 | { |
72 | public: |
73 | enum Dirty { |
74 | DirtyFillGeom = 0x01, |
75 | DirtyStrokeGeom = 0x02, |
76 | DirtyColor = 0x04, |
77 | DirtyFillGradient = 0x08, |
78 | DirtyList = 0x10 // only for accDirty |
79 | }; |
80 | |
81 | QQuickShapeGenericRenderer(QQuickItem *item) |
82 | : m_item(item), |
83 | m_api(QSGRendererInterface::Unknown), |
84 | m_rootNode(nullptr), |
85 | m_accDirty(0), |
86 | m_asyncCallback(nullptr), |
87 | m_asyncCallbackData(nullptr) |
88 | { } |
89 | ~QQuickShapeGenericRenderer(); |
90 | |
91 | void beginSync(int totalCount) override; |
92 | void setPath(int index, const QQuickPath *path) override; |
93 | void setStrokeColor(int index, const QColor &color) override; |
94 | void setStrokeWidth(int index, qreal w) override; |
95 | void setFillColor(int index, const QColor &color) override; |
96 | void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; |
97 | void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; |
98 | void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; |
99 | void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, |
100 | qreal dashOffset, const QVector<qreal> &dashPattern) override; |
101 | void setFillGradient(int index, QQuickShapeGradient *gradient) override; |
102 | void endSync(bool async) override; |
103 | void setAsyncCallback(void (*)(void *), void *) override; |
104 | Flags flags() const override { return SupportsAsync; } |
105 | |
106 | void updateNode() override; |
107 | |
108 | void setRootNode(QQuickShapeGenericNode *node); |
109 | |
110 | struct Color4ub { unsigned char r, g, b, a; }; |
111 | typedef QVector<QSGGeometry::ColoredPoint2D> VertexContainerType; |
112 | typedef QVector<quint32> IndexContainerType; |
113 | |
114 | static void triangulateFill(const QPainterPath &path, |
115 | const Color4ub &fillColor, |
116 | VertexContainerType *fillVertices, |
117 | IndexContainerType *fillIndices, |
118 | QSGGeometry::Type *indexType, |
119 | bool supportsElementIndexUint); |
120 | static void triangulateStroke(const QPainterPath &path, |
121 | const QPen &pen, |
122 | const Color4ub &strokeColor, |
123 | VertexContainerType *strokeVertices, |
124 | const QSize &clipSize); |
125 | |
126 | private: |
127 | void maybeUpdateAsyncItem(); |
128 | |
129 | struct ShapePathData { |
130 | float strokeWidth; |
131 | QPen pen; |
132 | Color4ub strokeColor; |
133 | Color4ub fillColor; |
134 | Qt::FillRule fillRule; |
135 | QPainterPath path; |
136 | FillGradientType fillGradientActive; |
137 | GradientDesc fillGradient; |
138 | VertexContainerType fillVertices; |
139 | IndexContainerType fillIndices; |
140 | QSGGeometry::Type indexType; |
141 | VertexContainerType strokeVertices; |
142 | int syncDirty; |
143 | int effectiveDirty = 0; |
144 | QQuickShapeFillRunnable *pendingFill = nullptr; |
145 | QQuickShapeStrokeRunnable *pendingStroke = nullptr; |
146 | }; |
147 | |
148 | void updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n); |
149 | void updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node); |
150 | void updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node); |
151 | |
152 | QQuickItem *m_item; |
153 | QSGRendererInterface::GraphicsApi m_api; |
154 | QQuickShapeGenericNode *m_rootNode; |
155 | QVector<ShapePathData> m_sp; |
156 | int m_accDirty; |
157 | void (*m_asyncCallback)(void *); |
158 | void *m_asyncCallbackData; |
159 | }; |
160 | |
161 | class QQuickShapeFillRunnable : public QObject, public QRunnable |
162 | { |
163 | Q_OBJECT |
164 | |
165 | public: |
166 | void run() override; |
167 | |
168 | bool orphaned = false; |
169 | |
170 | // input |
171 | QPainterPath path; |
172 | QQuickShapeGenericRenderer::Color4ub fillColor; |
173 | bool supportsElementIndexUint; |
174 | |
175 | // output |
176 | QQuickShapeGenericRenderer::VertexContainerType fillVertices; |
177 | QQuickShapeGenericRenderer::IndexContainerType fillIndices; |
178 | QSGGeometry::Type indexType; |
179 | |
180 | Q_SIGNALS: |
181 | void done(QQuickShapeFillRunnable *self); |
182 | }; |
183 | |
184 | class QQuickShapeStrokeRunnable : public QObject, public QRunnable |
185 | { |
186 | Q_OBJECT |
187 | |
188 | public: |
189 | void run() override; |
190 | |
191 | bool orphaned = false; |
192 | |
193 | // input |
194 | QPainterPath path; |
195 | QPen pen; |
196 | QQuickShapeGenericRenderer::Color4ub strokeColor; |
197 | QSize clipSize; |
198 | |
199 | // output |
200 | QQuickShapeGenericRenderer::VertexContainerType strokeVertices; |
201 | |
202 | Q_SIGNALS: |
203 | void done(QQuickShapeStrokeRunnable *self); |
204 | }; |
205 | |
206 | class QQuickShapeGenericStrokeFillNode : public QSGGeometryNode |
207 | { |
208 | public: |
209 | QQuickShapeGenericStrokeFillNode(QQuickWindow *window); |
210 | |
211 | enum Material { |
212 | MatSolidColor, |
213 | MatLinearGradient, |
214 | MatRadialGradient, |
215 | MatConicalGradient |
216 | }; |
217 | |
218 | void activateMaterial(QQuickWindow *window, Material m); |
219 | |
220 | // shadow data for custom materials |
221 | QQuickAbstractPathRenderer::GradientDesc m_fillGradient; |
222 | |
223 | private: |
224 | QScopedPointer<QSGMaterial> m_material; |
225 | |
226 | friend class QQuickShapeGenericRenderer; |
227 | }; |
228 | |
229 | class QQuickShapeGenericNode : public QSGNode |
230 | { |
231 | public: |
232 | QQuickShapeGenericStrokeFillNode *m_fillNode = nullptr; |
233 | QQuickShapeGenericStrokeFillNode *m_strokeNode = nullptr; |
234 | QQuickShapeGenericNode *m_next = nullptr; |
235 | }; |
236 | |
237 | class QQuickShapeGenericMaterialFactory |
238 | { |
239 | public: |
240 | static QSGMaterial *createVertexColor(QQuickWindow *window); |
241 | static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); |
242 | static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); |
243 | static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); |
244 | }; |
245 | |
246 | #if QT_CONFIG(opengl) |
247 | |
248 | class QQuickShapeLinearGradientShader : public QSGMaterialShader |
249 | { |
250 | public: |
251 | QQuickShapeLinearGradientShader(); |
252 | |
253 | void initialize() override; |
254 | void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; |
255 | char const *const *attributeNames() const override; |
256 | |
257 | private: |
258 | int m_opacityLoc = -1; |
259 | int m_matrixLoc = -1; |
260 | int m_gradStartLoc = -1; |
261 | int m_gradEndLoc = -1; |
262 | }; |
263 | |
264 | #endif // QT_CONFIG(opengl) |
265 | |
266 | class QQuickShapeLinearGradientRhiShader : public QSGMaterialRhiShader |
267 | { |
268 | public: |
269 | QQuickShapeLinearGradientRhiShader(); |
270 | |
271 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, |
272 | QSGMaterial *oldMaterial) override; |
273 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
274 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
275 | |
276 | private: |
277 | QVector2D m_gradA; |
278 | QVector2D m_gradB; |
279 | }; |
280 | |
281 | class QQuickShapeLinearGradientMaterial : public QSGMaterial |
282 | { |
283 | public: |
284 | QQuickShapeLinearGradientMaterial(QQuickShapeGenericStrokeFillNode *node) |
285 | : m_node(node) |
286 | { |
287 | // Passing RequiresFullMatrix is essential in order to prevent the |
288 | // batch renderer from baking in simple, translate-only transforms into |
289 | // the vertex data. The shader will rely on the fact that |
290 | // vertexCoord.xy is the Shape-space coordinate and so no modifications |
291 | // are welcome. |
292 | setFlag(flags: Blending | RequiresFullMatrix | SupportsRhiShader); |
293 | } |
294 | |
295 | QSGMaterialType *type() const override; |
296 | int compare(const QSGMaterial *other) const override; |
297 | QSGMaterialShader *createShader() const override; |
298 | |
299 | QQuickShapeGenericStrokeFillNode *node() const { return m_node; } |
300 | |
301 | private: |
302 | QQuickShapeGenericStrokeFillNode *m_node; |
303 | }; |
304 | |
305 | #if QT_CONFIG(opengl) |
306 | |
307 | class QQuickShapeRadialGradientShader : public QSGMaterialShader |
308 | { |
309 | public: |
310 | QQuickShapeRadialGradientShader(); |
311 | |
312 | void initialize() override; |
313 | void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; |
314 | char const *const *attributeNames() const override; |
315 | |
316 | private: |
317 | int m_opacityLoc = -1; |
318 | int m_matrixLoc = -1; |
319 | int m_translationPointLoc = -1; |
320 | int m_focalToCenterLoc = -1; |
321 | int m_centerRadiusLoc = -1; |
322 | int m_focalRadiusLoc = -1; |
323 | }; |
324 | |
325 | #endif // QT_CONFIG(opengl) |
326 | |
327 | class QQuickShapeRadialGradientRhiShader : public QSGMaterialRhiShader |
328 | { |
329 | public: |
330 | QQuickShapeRadialGradientRhiShader(); |
331 | |
332 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, |
333 | QSGMaterial *oldMaterial) override; |
334 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
335 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
336 | |
337 | private: |
338 | QVector2D m_focalPoint; |
339 | QVector2D m_focalToCenter; |
340 | float m_centerRadius; |
341 | float m_focalRadius; |
342 | }; |
343 | |
344 | class QQuickShapeRadialGradientMaterial : public QSGMaterial |
345 | { |
346 | public: |
347 | QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node) |
348 | : m_node(node) |
349 | { |
350 | setFlag(flags: Blending | RequiresFullMatrix | SupportsRhiShader); |
351 | } |
352 | |
353 | QSGMaterialType *type() const override; |
354 | int compare(const QSGMaterial *other) const override; |
355 | QSGMaterialShader *createShader() const override; |
356 | |
357 | QQuickShapeGenericStrokeFillNode *node() const { return m_node; } |
358 | |
359 | private: |
360 | QQuickShapeGenericStrokeFillNode *m_node; |
361 | }; |
362 | |
363 | #if QT_CONFIG(opengl) |
364 | |
365 | class QQuickShapeConicalGradientShader : public QSGMaterialShader |
366 | { |
367 | public: |
368 | QQuickShapeConicalGradientShader(); |
369 | |
370 | void initialize() override; |
371 | void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; |
372 | char const *const *attributeNames() const override; |
373 | |
374 | private: |
375 | int m_opacityLoc = -1; |
376 | int m_matrixLoc = -1; |
377 | int m_angleLoc = -1; |
378 | int m_translationPointLoc = -1; |
379 | }; |
380 | |
381 | #endif // QT_CONFIG(opengl) |
382 | |
383 | class QQuickShapeConicalGradientRhiShader : public QSGMaterialRhiShader |
384 | { |
385 | public: |
386 | QQuickShapeConicalGradientRhiShader(); |
387 | |
388 | bool updateUniformData(RenderState &state, QSGMaterial *newMaterial, |
389 | QSGMaterial *oldMaterial) override; |
390 | void updateSampledImage(RenderState &state, int binding, QSGTexture **texture, |
391 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; |
392 | |
393 | private: |
394 | QVector2D m_centerPoint; |
395 | float m_angle; |
396 | }; |
397 | |
398 | class QQuickShapeConicalGradientMaterial : public QSGMaterial |
399 | { |
400 | public: |
401 | QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node) |
402 | : m_node(node) |
403 | { |
404 | setFlag(flags: Blending | RequiresFullMatrix | SupportsRhiShader); |
405 | } |
406 | |
407 | QSGMaterialType *type() const override; |
408 | int compare(const QSGMaterial *other) const override; |
409 | QSGMaterialShader *createShader() const override; |
410 | |
411 | QQuickShapeGenericStrokeFillNode *node() const { return m_node; } |
412 | |
413 | private: |
414 | QQuickShapeGenericStrokeFillNode *m_node; |
415 | }; |
416 | |
417 | QT_END_NAMESPACE |
418 | |
419 | #endif // QQUICKSHAPEGENERICRENDERER_P_H |
420 | |