1 | // Copyright (C) 2019 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 QQUICKIMAGEPARTICLE_P_H |
5 | #define QQUICKIMAGEPARTICLE_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 purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qquickparticlepainter_p.h" |
19 | #include "qquickdirection_p.h" |
20 | #include <private/qquickpixmapcache_p.h> |
21 | #include <QQmlListProperty> |
22 | #include <QtGui/qcolor.h> |
23 | #include <QtQuick/qsgmaterial.h> |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | class ImageMaterialData; |
28 | class QSGGeometryNode; |
29 | class QSGMaterial; |
30 | |
31 | class QQuickSprite; |
32 | class QQuickStochasticEngine; |
33 | |
34 | class QRhi; |
35 | |
36 | struct SimplePointVertex { |
37 | float x; |
38 | float y; |
39 | float t; |
40 | float lifeSpan; |
41 | float size; |
42 | float endSize; |
43 | float vx; |
44 | float vy; |
45 | float ax; |
46 | float ay; |
47 | }; |
48 | |
49 | struct ColoredPointVertex { |
50 | float x; |
51 | float y; |
52 | float t; |
53 | float lifeSpan; |
54 | float size; |
55 | float endSize; |
56 | float vx; |
57 | float vy; |
58 | float ax; |
59 | float ay; |
60 | Color4ub color; |
61 | }; |
62 | |
63 | // Like Colored, but using DrawTriangles instead of DrawPoints |
64 | struct ColoredVertex { |
65 | float x; |
66 | float y; |
67 | float t; |
68 | float lifeSpan; |
69 | float size; |
70 | float endSize; |
71 | float vx; |
72 | float vy; |
73 | float ax; |
74 | float ay; |
75 | Color4ub color; |
76 | uchar tx; |
77 | uchar ty; |
78 | uchar _padding[2]; // feel free to use |
79 | }; |
80 | |
81 | struct DeformableVertex { |
82 | float x; |
83 | float y; |
84 | float rotation; |
85 | float rotationVelocity; |
86 | float t; |
87 | float lifeSpan; |
88 | float size; |
89 | float endSize; |
90 | float vx; |
91 | float vy; |
92 | float ax; |
93 | float ay; |
94 | Color4ub color; |
95 | float xx; |
96 | float xy; |
97 | float yx; |
98 | float yy; |
99 | uchar tx; |
100 | uchar ty; |
101 | uchar autoRotate; |
102 | uchar _padding; // feel free to use |
103 | }; |
104 | |
105 | struct SpriteVertex { |
106 | float x; |
107 | float y; |
108 | float rotation; |
109 | float rotationVelocity; |
110 | float t; |
111 | float lifeSpan; |
112 | float size; |
113 | float endSize; |
114 | float vx; |
115 | float vy; |
116 | float ax; |
117 | float ay; |
118 | Color4ub color; |
119 | float xx; |
120 | float xy; |
121 | float yx; |
122 | float yy; |
123 | uchar tx; |
124 | uchar ty; |
125 | uchar autoRotate; |
126 | uchar _padding; // feel free to use |
127 | float animW; |
128 | float animH; |
129 | float animProgress; |
130 | float animX1; |
131 | float animY1; |
132 | float animX2; |
133 | }; |
134 | |
135 | template <typename Vertex> |
136 | struct Vertices { |
137 | Vertex v1; |
138 | Vertex v2; |
139 | Vertex v3; |
140 | Vertex v4; |
141 | }; |
142 | |
143 | class ImageMaterial : public QSGMaterial |
144 | { |
145 | public: |
146 | virtual ImageMaterialData *state() = 0; |
147 | }; |
148 | |
149 | class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickImageParticle : public QQuickParticlePainter |
150 | { |
151 | Q_OBJECT |
152 | Q_PROPERTY(QUrl source READ image WRITE setImage NOTIFY imageChanged FINAL) |
153 | Q_PROPERTY(QQmlListProperty<QQuickSprite> sprites READ sprites FINAL) |
154 | Q_PROPERTY(Status status READ status NOTIFY statusChanged FINAL) |
155 | //### Is it worth having progress like Image has? |
156 | //Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) |
157 | |
158 | Q_PROPERTY(QUrl colorTable READ colortable WRITE setColortable NOTIFY colortableChanged FINAL) |
159 | Q_PROPERTY(QUrl sizeTable READ sizetable WRITE setSizetable NOTIFY sizetableChanged FINAL) |
160 | Q_PROPERTY(QUrl opacityTable READ opacitytable WRITE setOpacitytable NOTIFY opacitytableChanged FINAL) |
161 | |
162 | //###Now just colorize - add a flag for 'solid' color particles(where the img is just a mask?)? |
163 | Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged RESET resetColor FINAL) |
164 | //Stacks (added) with individual colorVariations |
165 | Q_PROPERTY(qreal colorVariation READ colorVariation WRITE setColorVariation NOTIFY colorVariationChanged RESET resetColor FINAL) |
166 | Q_PROPERTY(qreal redVariation READ redVariation WRITE setRedVariation NOTIFY redVariationChanged RESET resetColor FINAL) |
167 | Q_PROPERTY(qreal greenVariation READ greenVariation WRITE setGreenVariation NOTIFY greenVariationChanged RESET resetColor FINAL) |
168 | Q_PROPERTY(qreal blueVariation READ blueVariation WRITE setBlueVariation NOTIFY blueVariationChanged RESET resetColor FINAL) |
169 | //Stacks (multiplies) with the Alpha in the color, mostly here so you can use svg color names (which have full alpha) |
170 | Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha NOTIFY alphaChanged RESET resetColor FINAL) |
171 | Q_PROPERTY(qreal alphaVariation READ alphaVariation WRITE setAlphaVariation NOTIFY alphaVariationChanged RESET resetColor FINAL) |
172 | |
173 | Q_PROPERTY(qreal rotation READ rotation WRITE setRotation NOTIFY rotationChanged RESET resetRotation) |
174 | Q_PROPERTY(qreal rotationVariation READ rotationVariation WRITE setRotationVariation NOTIFY rotationVariationChanged RESET resetRotation FINAL) |
175 | Q_PROPERTY(qreal rotationVelocity READ rotationVelocity WRITE setRotationVelocity NOTIFY rotationVelocityChanged RESET resetRotation FINAL) |
176 | Q_PROPERTY(qreal rotationVelocityVariation READ rotationVelocityVariation WRITE setRotationVelocityVariation NOTIFY rotationVelocityVariationChanged RESET resetRotation FINAL) |
177 | //If true, then will face the direction of motion. Stacks with rotation, e.g. setting rotation |
178 | //to 180 will lead to facing away from the direction of motion |
179 | Q_PROPERTY(bool autoRotation READ autoRotation WRITE setAutoRotation NOTIFY autoRotationChanged RESET resetRotation FINAL) |
180 | |
181 | //xVector is the vector from the top-left point to the top-right point, and is multiplied by current size |
182 | Q_PROPERTY(QQuickDirection* xVector READ xVector WRITE setXVector NOTIFY xVectorChanged RESET resetDeformation FINAL) |
183 | //yVector is the same, but top-left to bottom-left. The particle is always a parallelogram. |
184 | Q_PROPERTY(QQuickDirection* yVector READ yVector WRITE setYVector NOTIFY yVectorChanged RESET resetDeformation FINAL) |
185 | Q_PROPERTY(bool spritesInterpolate READ spritesInterpolate WRITE setSpritesInterpolate NOTIFY spritesInterpolateChanged FINAL) |
186 | |
187 | Q_PROPERTY(EntryEffect entryEffect READ entryEffect WRITE setEntryEffect NOTIFY entryEffectChanged FINAL) |
188 | QML_NAMED_ELEMENT(ImageParticle) |
189 | QML_ADDED_IN_VERSION(2, 0) |
190 | public: |
191 | explicit QQuickImageParticle(QQuickItem *parent = nullptr); |
192 | virtual ~QQuickImageParticle(); |
193 | |
194 | enum Status { Null, Ready, Loading, Error }; |
195 | Q_ENUM(Status) |
196 | |
197 | QQmlListProperty<QQuickSprite> sprites(); |
198 | QQuickStochasticEngine* spriteEngine() {return m_spriteEngine;} |
199 | |
200 | enum EntryEffect { |
201 | None = 0, |
202 | Fade = 1, |
203 | Scale = 2 |
204 | }; |
205 | Q_ENUM(EntryEffect) |
206 | |
207 | enum PerformanceLevel{//TODO: Expose? |
208 | Unknown = 0, |
209 | SimplePoint, |
210 | ColoredPoint, |
211 | Colored, |
212 | Deformable, |
213 | Tabled, |
214 | Sprites |
215 | }; |
216 | |
217 | QUrl image() const { return m_image ? m_image->source : QUrl(); } |
218 | void setImage(const QUrl &image); |
219 | |
220 | QUrl colortable() const { return m_colorTable ? m_colorTable->source : QUrl(); } |
221 | void setColortable(const QUrl &table); |
222 | |
223 | QUrl sizetable() const { return m_sizeTable ? m_sizeTable->source : QUrl(); } |
224 | void setSizetable (const QUrl &table); |
225 | |
226 | QUrl opacitytable() const { return m_opacityTable ? m_opacityTable->source : QUrl(); } |
227 | void setOpacitytable(const QUrl &table); |
228 | |
229 | QColor color() const { return m_color; } |
230 | void setColor(const QColor &color); |
231 | |
232 | qreal colorVariation() const { return m_color_variation; } |
233 | void setColorVariation(qreal var); |
234 | |
235 | qreal alphaVariation() const { return m_alphaVariation; } |
236 | |
237 | qreal alpha() const { return m_alpha; } |
238 | |
239 | qreal redVariation() const { return m_redVariation; } |
240 | |
241 | qreal greenVariation() const { return m_greenVariation; } |
242 | |
243 | qreal blueVariation() const { return m_blueVariation; } |
244 | |
245 | qreal rotation() const { return m_rotation; } |
246 | |
247 | qreal rotationVariation() const { return m_rotationVariation; } |
248 | |
249 | qreal rotationVelocity() const { return m_rotationVelocity; } |
250 | |
251 | qreal rotationVelocityVariation() const { return m_rotationVelocityVariation; } |
252 | |
253 | bool autoRotation() const { return m_autoRotation; } |
254 | |
255 | QQuickDirection* xVector() const { return m_xVector; } |
256 | |
257 | QQuickDirection* yVector() const { return m_yVector; } |
258 | |
259 | bool spritesInterpolate() const { return m_spritesInterpolate; } |
260 | |
261 | bool bypassOptimizations() const { return m_bypassOptimizations; } |
262 | |
263 | EntryEffect entryEffect() const { return m_entryEffect; } |
264 | |
265 | Status status() const { return m_status; } |
266 | |
267 | void resetColor(); |
268 | void resetRotation(); |
269 | void resetDeformation(); |
270 | |
271 | Q_SIGNALS: |
272 | |
273 | void imageChanged(); |
274 | void colortableChanged(); |
275 | void sizetableChanged(); |
276 | void opacitytableChanged(); |
277 | |
278 | void colorChanged(); |
279 | void colorVariationChanged(); |
280 | |
281 | void alphaVariationChanged(qreal arg); |
282 | |
283 | void alphaChanged(qreal arg); |
284 | |
285 | void redVariationChanged(qreal arg); |
286 | |
287 | void greenVariationChanged(qreal arg); |
288 | |
289 | void blueVariationChanged(qreal arg); |
290 | |
291 | void rotationChanged(qreal arg); |
292 | |
293 | void rotationVariationChanged(qreal arg); |
294 | |
295 | void rotationVelocityChanged(qreal arg); |
296 | |
297 | void rotationVelocityVariationChanged(qreal arg); |
298 | |
299 | void autoRotationChanged(bool arg); |
300 | |
301 | void xVectorChanged(QQuickDirection* arg); |
302 | |
303 | void yVectorChanged(QQuickDirection* arg); |
304 | |
305 | void spritesInterpolateChanged(bool arg); |
306 | |
307 | void bypassOptimizationsChanged(bool arg); |
308 | |
309 | void entryEffectChanged(EntryEffect arg); |
310 | |
311 | void statusChanged(Status arg); |
312 | |
313 | public Q_SLOTS: |
314 | void setAlphaVariation(qreal arg); |
315 | |
316 | void setAlpha(qreal arg); |
317 | |
318 | void setRedVariation(qreal arg); |
319 | |
320 | void setGreenVariation(qreal arg); |
321 | |
322 | void setBlueVariation(qreal arg); |
323 | |
324 | void setRotation(qreal arg); |
325 | |
326 | void setRotationVariation(qreal arg); |
327 | |
328 | void setRotationVelocity(qreal arg); |
329 | |
330 | void setRotationVelocityVariation(qreal arg); |
331 | |
332 | void setAutoRotation(bool arg); |
333 | |
334 | void setXVector(QQuickDirection* arg); |
335 | |
336 | void setYVector(QQuickDirection* arg); |
337 | |
338 | void setSpritesInterpolate(bool arg); |
339 | |
340 | void setBypassOptimizations(bool arg); |
341 | |
342 | void setEntryEffect(EntryEffect arg); |
343 | |
344 | protected: |
345 | void reset() override; |
346 | void initialize(int gIdx, int pIdx) override; |
347 | void commit(int gIdx, int pIdx) override; |
348 | |
349 | QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; |
350 | bool prepareNextFrame(QSGNode**); |
351 | void buildParticleNodes(QSGNode**); |
352 | |
353 | void sceneGraphInvalidated() override; |
354 | |
355 | private Q_SLOTS: |
356 | void createEngine(); //### method invoked by sprite list changing (in engine.h) - pretty nasty |
357 | |
358 | void spriteAdvance(int spriteIndex); |
359 | void spritesUpdate(qreal time = 0 ); |
360 | void mainThreadFetchImageData(); |
361 | void finishBuildParticleNodes(QSGNode **n); |
362 | void invalidateSceneGraph(); |
363 | |
364 | private: |
365 | struct ImageData { |
366 | QUrl source; |
367 | QQuickPixmap pix; |
368 | }; |
369 | QScopedPointer<ImageData> m_image; |
370 | QScopedPointer<ImageData> m_colorTable; |
371 | QScopedPointer<ImageData> m_sizeTable; |
372 | QScopedPointer<ImageData> m_opacityTable; |
373 | bool loadingSomething(); |
374 | |
375 | |
376 | QColor m_color; |
377 | qreal m_color_variation; |
378 | |
379 | QSGNode *m_outgoingNode; |
380 | QHash<int, QSGGeometryNode *> m_nodes; |
381 | QHash<int, int> m_idxStarts;//TODO: Proper resizing will lead to needing a spriteEngine per particle - do this after sprite engine gains transparent sharing? |
382 | QList<QPair<int, int> > m_startsIdx;//Same data, optimized for alternate retrieval |
383 | |
384 | int m_lastIdxStart; |
385 | QSGMaterial *m_material; |
386 | |
387 | // derived values... |
388 | |
389 | qreal m_alphaVariation; |
390 | qreal m_alpha; |
391 | qreal m_redVariation; |
392 | qreal m_greenVariation; |
393 | qreal m_blueVariation; |
394 | qreal m_rotation; |
395 | qreal m_rotationVariation; |
396 | qreal m_rotationVelocity; |
397 | qreal m_rotationVelocityVariation; |
398 | bool m_autoRotation; |
399 | QQuickDirection* m_xVector; |
400 | QQuickDirection* m_yVector; |
401 | |
402 | QList<QQuickSprite*> m_sprites; |
403 | QQuickSpriteEngine* m_spriteEngine; |
404 | bool m_spritesInterpolate; |
405 | |
406 | bool m_explicitColor; |
407 | bool m_explicitRotation; |
408 | bool m_explicitDeformation; |
409 | bool m_explicitAnimation; |
410 | QHash<int, QVector<QQuickParticleData*> > m_shadowData; |
411 | void clearShadows(); |
412 | QQuickParticleData* getShadowDatum(QQuickParticleData* datum); |
413 | |
414 | bool m_bypassOptimizations; |
415 | PerformanceLevel perfLevel; |
416 | PerformanceLevel m_targetPerfLevel; |
417 | void checkPerfLevel(PerformanceLevel level); |
418 | |
419 | bool m_debugMode; |
420 | |
421 | template<class Vertex> |
422 | void initTexCoords(Vertex* v, int count){ |
423 | Vertex* end = v + count; |
424 | // Vertex coords between (0.0, 0.0) and (1.0, 1.0) |
425 | while (v < end){ |
426 | v[0].tx = 0; |
427 | v[0].ty = 0; |
428 | |
429 | v[1].tx = 255; |
430 | v[1].ty = 0; |
431 | |
432 | v[2].tx = 0; |
433 | v[2].ty = 255; |
434 | |
435 | v[3].tx = 255; |
436 | v[3].ty = 255; |
437 | |
438 | v += 4; |
439 | } |
440 | } |
441 | |
442 | ImageMaterialData *getState(QSGMaterial *m) { |
443 | return static_cast<ImageMaterial *>(m)->state(); |
444 | } |
445 | |
446 | EntryEffect m_entryEffect; |
447 | Status m_status; |
448 | int m_startedImageLoading; |
449 | QRhi *m_rhi; |
450 | bool m_apiChecked; |
451 | qreal m_dpr; |
452 | bool m_previousActive; |
453 | }; |
454 | |
455 | QT_END_NAMESPACE |
456 | |
457 | #endif // QQUICKIMAGEPARTICLE_P_H |
458 | |