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