|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtDeclarative module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qdeclarativeparticles_p.h" |
|
43 |
|
44 #include <qdeclarativeinfo.h> |
|
45 #include <private/qdeclarativeitem_p.h> |
|
46 |
|
47 #include <private/qdeclarativepixmapcache_p.h> |
|
48 #include <QtCore/QAbstractAnimation> |
|
49 |
|
50 #include <QPainter> |
|
51 #include <QtGui/qdrawutil.h> |
|
52 #include <QVarLengthArray> |
|
53 |
|
54 #include <stdlib.h> |
|
55 #include <math.h> |
|
56 |
|
57 #ifndef M_PI |
|
58 #define M_PI 3.14159265358979323846 |
|
59 #define M_PI_2 (M_PI / 2.) |
|
60 #endif |
|
61 #ifndef INT_MAX |
|
62 #define INT_MAX 2147483647 |
|
63 #endif |
|
64 |
|
65 QT_BEGIN_NAMESPACE |
|
66 #define PI_SQR 9.8696044 |
|
67 // parabolic approximation |
|
68 inline qreal fastSin(qreal theta) |
|
69 { |
|
70 const qreal b = 4 / M_PI; |
|
71 const qreal c = -4 / PI_SQR; |
|
72 |
|
73 qreal y = b * theta + c * theta * qAbs(theta); |
|
74 return y; |
|
75 } |
|
76 |
|
77 inline qreal fastCos(qreal theta) |
|
78 { |
|
79 theta += M_PI_2; |
|
80 if (theta > M_PI) |
|
81 theta -= 2 * M_PI; |
|
82 |
|
83 return fastSin(theta); |
|
84 } |
|
85 |
|
86 class QDeclarativeParticle |
|
87 { |
|
88 public: |
|
89 QDeclarativeParticle(int time) : lifeSpan(1000), fadeOutAge(800) |
|
90 , opacity(0), birthTime(time), x_velocity(0), y_velocity(0) |
|
91 , state(FadeIn), data(0) |
|
92 { |
|
93 } |
|
94 |
|
95 int lifeSpan; |
|
96 int fadeOutAge; |
|
97 qreal x; |
|
98 qreal y; |
|
99 qreal opacity; |
|
100 int birthTime; |
|
101 qreal x_velocity; |
|
102 qreal y_velocity; |
|
103 enum State { FadeIn, Solid, FadeOut }; |
|
104 State state; |
|
105 void *data; |
|
106 }; |
|
107 |
|
108 //--------------------------------------------------------------------------- |
|
109 |
|
110 /*! |
|
111 \class QDeclarativeParticleMotion |
|
112 \ingroup group_effects |
|
113 \brief The QDeclarativeParticleMotion class is the base class for particle motion. |
|
114 \internal |
|
115 |
|
116 This class causes the particles to remain static. |
|
117 */ |
|
118 |
|
119 /*! |
|
120 Constructs a QDeclarativeParticleMotion with parent object \a parent. |
|
121 */ |
|
122 QDeclarativeParticleMotion::QDeclarativeParticleMotion(QObject *parent) : |
|
123 QObject(parent) |
|
124 { |
|
125 } |
|
126 |
|
127 /*! |
|
128 Move the \a particle to its new position. \a interval is the number of |
|
129 milliseconds elapsed since it was last moved. |
|
130 */ |
|
131 void QDeclarativeParticleMotion::advance(QDeclarativeParticle &particle, int interval) |
|
132 { |
|
133 Q_UNUSED(particle); |
|
134 Q_UNUSED(interval); |
|
135 } |
|
136 |
|
137 /*! |
|
138 The \a particle has just been created. Some motion strategies require |
|
139 additional state information. This can be allocated by this function. |
|
140 */ |
|
141 void QDeclarativeParticleMotion::created(QDeclarativeParticle &particle) |
|
142 { |
|
143 Q_UNUSED(particle); |
|
144 } |
|
145 |
|
146 /*! |
|
147 The \a particle is about to be destroyed. Any additional memory |
|
148 that has been allocated for the particle should be freed. |
|
149 */ |
|
150 void QDeclarativeParticleMotion::destroy(QDeclarativeParticle &particle) |
|
151 { |
|
152 Q_UNUSED(particle); |
|
153 } |
|
154 |
|
155 /*! |
|
156 \qmlclass ParticleMotionLinear |
|
157 \since 4.7 |
|
158 \brief The ParticleMotionLinear object moves particles linearly. |
|
159 |
|
160 \sa Particles |
|
161 */ |
|
162 |
|
163 /*! |
|
164 \internal |
|
165 \class QDeclarativeParticleMotionLinear |
|
166 \ingroup group_effects |
|
167 \brief The QDeclarativeParticleMotionLinear class moves the particles linearly. |
|
168 */ |
|
169 |
|
170 void QDeclarativeParticleMotionLinear::advance(QDeclarativeParticle &p, int interval) |
|
171 { |
|
172 p.x += interval * p.x_velocity; |
|
173 p.y += interval * p.y_velocity; |
|
174 } |
|
175 |
|
176 /*! |
|
177 \qmlclass ParticleMotionGravity |
|
178 \since 4.7 |
|
179 \brief The ParticleMotionGravity object moves particles towards a point. |
|
180 |
|
181 \sa Particles |
|
182 */ |
|
183 |
|
184 /*! |
|
185 \internal |
|
186 \class QDeclarativeParticleMotionGravity |
|
187 \ingroup group_effects |
|
188 \brief The QDeclarativeParticleMotionGravity class moves the particles towards a point. |
|
189 */ |
|
190 |
|
191 /*! |
|
192 \qmlproperty real ParticleMotionGravity::xattractor |
|
193 \qmlproperty real ParticleMotionGravity::yattractor |
|
194 These properties hold the x and y coordinates of the point attracting the particles. |
|
195 */ |
|
196 |
|
197 /*! |
|
198 \qmlproperty real ParticleMotionGravity::acceleration |
|
199 This property holds the acceleration to apply to the particles. |
|
200 */ |
|
201 |
|
202 /*! |
|
203 \property QDeclarativeParticleMotionGravity::xattractor |
|
204 \brief the x coordinate of the point attracting the particles. |
|
205 */ |
|
206 |
|
207 /*! |
|
208 \property QDeclarativeParticleMotionGravity::yattractor |
|
209 \brief the y coordinate of the point attracting the particles. |
|
210 */ |
|
211 |
|
212 /*! |
|
213 \property QDeclarativeParticleMotionGravity::acceleration |
|
214 \brief the acceleration to apply to the particles. |
|
215 */ |
|
216 |
|
217 void QDeclarativeParticleMotionGravity::setXAttractor(qreal x) |
|
218 { |
|
219 if (qFuzzyCompare(x, _xAttr)) |
|
220 return; |
|
221 _xAttr = x; |
|
222 emit xattractorChanged(); |
|
223 } |
|
224 |
|
225 void QDeclarativeParticleMotionGravity::setYAttractor(qreal y) |
|
226 { |
|
227 if (qFuzzyCompare(y, _yAttr)) |
|
228 return; |
|
229 _yAttr = y; |
|
230 emit yattractorChanged(); |
|
231 } |
|
232 |
|
233 void QDeclarativeParticleMotionGravity::setAcceleration(qreal accel) |
|
234 { |
|
235 qreal scaledAccel = accel/1000000.0; |
|
236 if (qFuzzyCompare(scaledAccel, _accel)) |
|
237 return; |
|
238 _accel = scaledAccel; |
|
239 emit accelerationChanged(); |
|
240 } |
|
241 |
|
242 void QDeclarativeParticleMotionGravity::advance(QDeclarativeParticle &p, int interval) |
|
243 { |
|
244 qreal xdiff = p.x - _xAttr; |
|
245 qreal ydiff = p.y - _yAttr; |
|
246 |
|
247 qreal xcomp = xdiff / (xdiff + ydiff); |
|
248 qreal ycomp = ydiff / (xdiff + ydiff); |
|
249 |
|
250 p.x_velocity += xcomp * _accel * interval; |
|
251 p.y_velocity += ycomp * _accel * interval; |
|
252 |
|
253 p.x += interval * p.x_velocity; |
|
254 p.y += interval * p.y_velocity; |
|
255 } |
|
256 |
|
257 /*! |
|
258 \qmlclass ParticleMotionWander |
|
259 \since 4.7 |
|
260 \brief The ParticleMotionWander object moves particles in a somewhat random fashion. |
|
261 |
|
262 The particles will continue roughly in the original direction, however will randomly |
|
263 drift to each side. |
|
264 |
|
265 The code below produces an effect similar to falling snow. |
|
266 |
|
267 \qml |
|
268 Rectangle { |
|
269 width: 240 |
|
270 height: 320 |
|
271 color: "black" |
|
272 |
|
273 Particles { |
|
274 y: 0 |
|
275 width: parent.width |
|
276 height: 30 |
|
277 source: "star.png" |
|
278 lifeSpan: 5000 |
|
279 count: 50 |
|
280 angle: 70 |
|
281 angleDeviation: 36 |
|
282 velocity: 30 |
|
283 velocityDeviation: 10 |
|
284 ParticleMotionWander { |
|
285 xvariance: 30 |
|
286 pace: 100 |
|
287 } |
|
288 } |
|
289 } |
|
290 \endqml |
|
291 |
|
292 \sa Particles |
|
293 */ |
|
294 |
|
295 /*! |
|
296 \internal |
|
297 \class QDeclarativeParticleMotionWander |
|
298 \ingroup group_effects |
|
299 \brief The QDeclarativeParticleMotionWander class moves particles in a somewhat random fashion. |
|
300 |
|
301 The particles will continue roughly in the original direction, however will randomly |
|
302 drift to each side. |
|
303 */ |
|
304 |
|
305 /*! |
|
306 \qmlproperty real QDeclarativeParticleMotionWander::xvariance |
|
307 \qmlproperty real QDeclarativeParticleMotionWander::yvariance |
|
308 |
|
309 These properties set the amount to wander in the x and y directions. |
|
310 */ |
|
311 |
|
312 /*! |
|
313 \qmlproperty real QDeclarativeParticleMotionWander::pace |
|
314 This property holds how quickly the paricles will move from side to side. |
|
315 */ |
|
316 |
|
317 void QDeclarativeParticleMotionWander::advance(QDeclarativeParticle &p, int interval) |
|
318 { |
|
319 if (!particles) |
|
320 particles = qobject_cast<QDeclarativeParticles*>(parent()); |
|
321 if (particles) { |
|
322 Data *d = (Data*)p.data; |
|
323 if (_xvariance != 0.) { |
|
324 qreal xdiff = p.x_velocity - d->x_targetV; |
|
325 if ((xdiff > d->x_peak && d->x_var > 0.0) || (xdiff < -d->x_peak && d->x_var < 0.0)) { |
|
326 d->x_var = -d->x_var; |
|
327 d->x_peak = _xvariance + _xvariance * qreal(qrand()) / RAND_MAX; |
|
328 } |
|
329 p.x_velocity += d->x_var * interval; |
|
330 } |
|
331 p.x += interval * p.x_velocity; |
|
332 |
|
333 if (_yvariance != 0.) { |
|
334 qreal ydiff = p.y_velocity - d->y_targetV; |
|
335 if ((ydiff > d->y_peak && d->y_var > 0.0) || (ydiff < -d->y_peak && d->y_var < 0.0)) { |
|
336 d->y_var = -d->y_var; |
|
337 d->y_peak = _yvariance + _yvariance * qreal(qrand()) / RAND_MAX; |
|
338 } |
|
339 p.y_velocity += d->y_var * interval; |
|
340 } |
|
341 p.y += interval * p.y_velocity; |
|
342 } |
|
343 } |
|
344 |
|
345 void QDeclarativeParticleMotionWander::created(QDeclarativeParticle &p) |
|
346 { |
|
347 if (!p.data) { |
|
348 Data *d = new Data; |
|
349 p.data = (void*)d; |
|
350 d->x_targetV = p.x_velocity; |
|
351 d->y_targetV = p.y_velocity; |
|
352 d->x_peak = _xvariance; |
|
353 d->y_peak = _yvariance; |
|
354 d->x_var = _pace * qreal(qrand()) / RAND_MAX / 1000.0; |
|
355 d->y_var = _pace * qreal(qrand()) / RAND_MAX / 1000.0; |
|
356 } |
|
357 } |
|
358 |
|
359 void QDeclarativeParticleMotionWander::destroy(QDeclarativeParticle &p) |
|
360 { |
|
361 if (p.data) |
|
362 delete (Data*)p.data; |
|
363 } |
|
364 |
|
365 void QDeclarativeParticleMotionWander::setXVariance(qreal var) |
|
366 { |
|
367 qreal scaledVar = var / 1000.0; |
|
368 if (qFuzzyCompare(scaledVar, _xvariance)) |
|
369 return; |
|
370 _xvariance = scaledVar; |
|
371 emit xvarianceChanged(); |
|
372 } |
|
373 |
|
374 void QDeclarativeParticleMotionWander::setYVariance(qreal var) |
|
375 { |
|
376 qreal scaledVar = var / 1000.0; |
|
377 if (qFuzzyCompare(scaledVar, _yvariance)) |
|
378 return; |
|
379 _yvariance = scaledVar; |
|
380 emit yvarianceChanged(); |
|
381 } |
|
382 |
|
383 void QDeclarativeParticleMotionWander::setPace(qreal pace) |
|
384 { |
|
385 qreal scaledPace = pace / 1000.0; |
|
386 if (qFuzzyCompare(scaledPace, _pace)) |
|
387 return; |
|
388 _pace = scaledPace; |
|
389 emit paceChanged(); |
|
390 } |
|
391 |
|
392 //--------------------------------------------------------------------------- |
|
393 class QDeclarativeParticlesPainter : public QDeclarativeItem |
|
394 { |
|
395 public: |
|
396 QDeclarativeParticlesPainter(QDeclarativeParticlesPrivate *p, QDeclarativeItem* parent) |
|
397 : QDeclarativeItem(parent), d(p) |
|
398 { |
|
399 setFlag(QGraphicsItem::ItemHasNoContents, false); |
|
400 maxX = minX = maxY = minY = 0; |
|
401 } |
|
402 |
|
403 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); |
|
404 |
|
405 void updateSize(); |
|
406 |
|
407 qreal maxX; |
|
408 qreal minX; |
|
409 qreal maxY; |
|
410 qreal minY; |
|
411 QDeclarativeParticlesPrivate* d; |
|
412 }; |
|
413 |
|
414 //an animation that just gives a tick |
|
415 template<class T, void (T::*method)(int)> |
|
416 class TickAnimationProxy : public QAbstractAnimation |
|
417 { |
|
418 public: |
|
419 TickAnimationProxy(T *p, QObject *parent = 0) : QAbstractAnimation(parent), m_p(p) {} |
|
420 virtual int duration() const { return -1; } |
|
421 protected: |
|
422 virtual void updateCurrentTime(int msec) { (m_p->*method)(msec); } |
|
423 |
|
424 private: |
|
425 T *m_p; |
|
426 }; |
|
427 |
|
428 //--------------------------------------------------------------------------- |
|
429 class QDeclarativeParticlesPrivate : public QDeclarativeItemPrivate |
|
430 { |
|
431 Q_DECLARE_PUBLIC(QDeclarativeParticles) |
|
432 public: |
|
433 QDeclarativeParticlesPrivate() |
|
434 : count(1), emissionRate(-1), emissionVariance(0.5), lifeSpan(1000) |
|
435 , lifeSpanDev(1000), fadeInDur(200), fadeOutDur(300) |
|
436 , angle(0), angleDev(0), velocity(0), velocityDev(0), emissionCarry(0.) |
|
437 , addParticleTime(0), addParticleCount(0), lastAdvTime(0) |
|
438 , motion(0), pendingPixmapCache(false), clock(this) |
|
439 { |
|
440 } |
|
441 |
|
442 ~QDeclarativeParticlesPrivate() |
|
443 { |
|
444 } |
|
445 |
|
446 void init() |
|
447 { |
|
448 Q_Q(QDeclarativeParticles); |
|
449 paintItem = new QDeclarativeParticlesPainter(this, q); |
|
450 } |
|
451 |
|
452 void tick(int time); |
|
453 void createParticle(int time); |
|
454 void updateOpacity(QDeclarativeParticle &p, int age); |
|
455 |
|
456 QUrl url; |
|
457 QPixmap image; |
|
458 int count; |
|
459 int emissionRate; |
|
460 qreal emissionVariance; |
|
461 int lifeSpan; |
|
462 int lifeSpanDev; |
|
463 int fadeInDur; |
|
464 int fadeOutDur; |
|
465 qreal angle; |
|
466 qreal angleDev; |
|
467 qreal velocity; |
|
468 qreal velocityDev; |
|
469 qreal emissionCarry; |
|
470 int addParticleTime; |
|
471 int addParticleCount; |
|
472 int lastAdvTime; |
|
473 QDeclarativeParticleMotion *motion; |
|
474 QDeclarativeParticlesPainter *paintItem; |
|
475 |
|
476 bool pendingPixmapCache; |
|
477 |
|
478 QList<QPair<int, int> > bursts;//countLeft, emissionRate pairs |
|
479 QList<QDeclarativeParticle> particles; |
|
480 TickAnimationProxy<QDeclarativeParticlesPrivate, &QDeclarativeParticlesPrivate::tick> clock; |
|
481 |
|
482 }; |
|
483 |
|
484 void QDeclarativeParticlesPrivate::tick(int time) |
|
485 { |
|
486 Q_Q(QDeclarativeParticles); |
|
487 if (!motion) |
|
488 motion = new QDeclarativeParticleMotionLinear(q); |
|
489 |
|
490 int oldCount = particles.count(); |
|
491 int removed = 0; |
|
492 int interval = time - lastAdvTime; |
|
493 for (int i = 0; i < particles.count(); ) { |
|
494 QDeclarativeParticle &particle = particles[i]; |
|
495 int age = time - particle.birthTime; |
|
496 if (age >= particle.lifeSpan) { |
|
497 QDeclarativeParticle part = particles.takeAt(i); |
|
498 motion->destroy(part); |
|
499 ++removed; |
|
500 } else { |
|
501 updateOpacity(particle, age); |
|
502 motion->advance(particle, interval); |
|
503 ++i; |
|
504 } |
|
505 } |
|
506 |
|
507 if(emissionRate == -1)//Otherwise leave emission to the emission rate |
|
508 while(removed-- && ((count == -1) || particles.count() < count)) |
|
509 createParticle(time); |
|
510 |
|
511 if (!addParticleTime) |
|
512 addParticleTime = time; |
|
513 |
|
514 //Possibly emit new particles |
|
515 if (((count == -1) || particles.count() < count) && emissionRate |
|
516 && !(count==-1 && emissionRate==-1)) { |
|
517 int emissionCount = -1; |
|
518 if (emissionRate != -1){ |
|
519 qreal variance = 1.; |
|
520 if (emissionVariance > 0.){ |
|
521 variance += (qreal(qrand())/RAND_MAX) * emissionVariance * (qrand()%2?-1.:1.); |
|
522 } |
|
523 qreal emission = emissionRate * (qreal(interval)/1000.); |
|
524 emission = emission * variance + emissionCarry; |
|
525 double tmpDbl; |
|
526 emissionCarry = modf(emission, &tmpDbl); |
|
527 emissionCount = (int)tmpDbl; |
|
528 emissionCount = qMax(0,emissionCount); |
|
529 } |
|
530 while(((count == -1) || particles.count() < count) && |
|
531 (emissionRate==-1 || emissionCount--)) |
|
532 createParticle(time); |
|
533 } |
|
534 |
|
535 //Deal with emissions from requested bursts |
|
536 for(int i=0; i<bursts.size(); i++){ |
|
537 int emission = 0; |
|
538 if(bursts[i].second == -1){ |
|
539 emission = bursts[i].first; |
|
540 }else{ |
|
541 qreal variance = 1.; |
|
542 if (emissionVariance > 0.){ |
|
543 variance += (qreal(qrand())/RAND_MAX) * emissionVariance * (qrand()%2?-1.:1.); |
|
544 } |
|
545 qreal workingEmission = bursts[i].second * (qreal(interval)/1000.); |
|
546 workingEmission *= variance; |
|
547 emission = (int)workingEmission; |
|
548 emission = qMax(emission, 0); |
|
549 } |
|
550 emission = qMin(emission, bursts[i].first); |
|
551 bursts[i].first -= emission; |
|
552 while(emission--) |
|
553 createParticle(time); |
|
554 } |
|
555 for(int i=bursts.size()-1; i>=0; i--) |
|
556 if(bursts[i].first <= 0) |
|
557 bursts.removeAt(i); |
|
558 |
|
559 lastAdvTime = time; |
|
560 paintItem->updateSize(); |
|
561 paintItem->update(); |
|
562 if (!(oldCount || particles.count()) && (!count || !emissionRate) && bursts.isEmpty()) { |
|
563 lastAdvTime = 0; |
|
564 clock.stop(); |
|
565 } |
|
566 } |
|
567 |
|
568 void QDeclarativeParticlesPrivate::createParticle(int time) |
|
569 { |
|
570 Q_Q(QDeclarativeParticles); |
|
571 QDeclarativeParticle p(time); |
|
572 p.x = q->x() + q->width() * qreal(qrand()) / RAND_MAX - image.width()/2.0; |
|
573 p.y = q->y() + q->height() * qreal(qrand()) / RAND_MAX - image.height()/2.0; |
|
574 p.lifeSpan = lifeSpan; |
|
575 if (lifeSpanDev) |
|
576 p.lifeSpan += int(lifeSpanDev/2 - lifeSpanDev * qreal(qrand()) / RAND_MAX); |
|
577 p.fadeOutAge = p.lifeSpan - fadeOutDur; |
|
578 if (fadeInDur == 0.) { |
|
579 p.state= QDeclarativeParticle::Solid; |
|
580 p.opacity = 1.0; |
|
581 } |
|
582 qreal a = angle; |
|
583 if (angleDev) |
|
584 a += angleDev/2 - angleDev * qreal(qrand()) / RAND_MAX; |
|
585 if (a > M_PI) |
|
586 a = a - 2 * M_PI; |
|
587 qreal v = velocity; |
|
588 if (velocityDev) |
|
589 v += velocityDev/2 - velocityDev * qreal(qrand()) / RAND_MAX; |
|
590 p.x_velocity = v * fastCos(a); |
|
591 p.y_velocity = v * fastSin(a); |
|
592 particles.append(p); |
|
593 motion->created(particles.last()); |
|
594 } |
|
595 |
|
596 void QDeclarativeParticlesPrivate::updateOpacity(QDeclarativeParticle &p, int age) |
|
597 { |
|
598 switch (p.state) { |
|
599 case QDeclarativeParticle::FadeIn: |
|
600 if (age <= fadeInDur) { |
|
601 p.opacity = qreal(age) / fadeInDur; |
|
602 break; |
|
603 } else { |
|
604 p.opacity = 1.0; |
|
605 p.state = QDeclarativeParticle::Solid; |
|
606 // Fall through |
|
607 } |
|
608 case QDeclarativeParticle::Solid: |
|
609 if (age <= p.fadeOutAge) { |
|
610 break; |
|
611 } else { |
|
612 p.state = QDeclarativeParticle::FadeOut; |
|
613 // Fall through |
|
614 } |
|
615 case QDeclarativeParticle::FadeOut: |
|
616 p.opacity = qreal(p.lifeSpan - age) / fadeOutDur; |
|
617 break; |
|
618 } |
|
619 } |
|
620 |
|
621 /*! |
|
622 \qmlclass Particles |
|
623 \since 4.7 |
|
624 \brief The Particles object generates and moves particles. |
|
625 \inherits Item |
|
626 |
|
627 Particles are available in the \bold{Qt.labs.particles 1.0} module. |
|
628 \e {Elements in the Qt.labs module are not guaranteed to remain compatible |
|
629 in future versions.} |
|
630 |
|
631 This element provides preliminary support for particles in QML, |
|
632 and may be heavily changed or removed in later versions. |
|
633 |
|
634 The particles created by this object cannot be dealt with |
|
635 directly, they can only be controlled through the parameters of |
|
636 the Particles object. The particles are all the same pixmap, |
|
637 specified by the user. |
|
638 |
|
639 The particles are painted relative to the parent of the Particles |
|
640 object. Moving the Particles object will not move the particles |
|
641 already emitted. |
|
642 |
|
643 The below example creates two differently behaving particle |
|
644 sources. The top one has particles falling from the top like |
|
645 snow, the lower one has particles expelled up like a fountain. |
|
646 |
|
647 \qml |
|
648 import Qt 4.7 |
|
649 import Qt.labs.particles 1.0 |
|
650 |
|
651 Rectangle { |
|
652 width: 240 |
|
653 height: 320 |
|
654 color: "black" |
|
655 Particles { |
|
656 y: 0 |
|
657 width: parent.width |
|
658 height: 30 |
|
659 source: "star.png" |
|
660 lifeSpan: 5000 |
|
661 count: 50 |
|
662 angle: 70 |
|
663 angleDeviation: 36 |
|
664 velocity: 30 |
|
665 velocityDeviation: 10 |
|
666 ParticleMotionWander { |
|
667 xvariance: 30 |
|
668 pace: 100 |
|
669 } |
|
670 } |
|
671 Particles { |
|
672 y: 300 |
|
673 x: 120 |
|
674 width: 1 |
|
675 height: 1 |
|
676 source: "star.png" |
|
677 lifeSpan: 5000 |
|
678 count: 200 |
|
679 angle: 270 |
|
680 angleDeviation: 45 |
|
681 velocity: 50 |
|
682 velocityDeviation: 30 |
|
683 ParticleMotionGravity { |
|
684 yattractor: 1000 |
|
685 xattractor: 0 |
|
686 acceleration: 25 |
|
687 } |
|
688 } |
|
689 } |
|
690 \endqml |
|
691 \image particles.gif |
|
692 */ |
|
693 |
|
694 /*! |
|
695 \internal |
|
696 \class QDeclarativeParticles |
|
697 \ingroup group_effects |
|
698 \brief The QDeclarativeParticles class generates and moves particles. |
|
699 */ |
|
700 |
|
701 QDeclarativeParticles::QDeclarativeParticles(QDeclarativeItem *parent) |
|
702 : QDeclarativeItem(*(new QDeclarativeParticlesPrivate), parent) |
|
703 { |
|
704 Q_D(QDeclarativeParticles); |
|
705 d->init(); |
|
706 } |
|
707 |
|
708 QDeclarativeParticles::~QDeclarativeParticles() |
|
709 { |
|
710 Q_D(QDeclarativeParticles); |
|
711 if (d->pendingPixmapCache) |
|
712 QDeclarativePixmapCache::cancel(d->url, this); |
|
713 } |
|
714 |
|
715 /*! |
|
716 \qmlproperty string Particles::source |
|
717 This property holds the URL of the particle image. |
|
718 */ |
|
719 |
|
720 /*! |
|
721 \property QDeclarativeParticles::source |
|
722 \brief the URL of the particle image. |
|
723 */ |
|
724 QUrl QDeclarativeParticles::source() const |
|
725 { |
|
726 Q_D(const QDeclarativeParticles); |
|
727 return d->url; |
|
728 } |
|
729 |
|
730 void QDeclarativeParticles::imageLoaded() |
|
731 { |
|
732 Q_D(QDeclarativeParticles); |
|
733 d->pendingPixmapCache = false; |
|
734 QString errorString; |
|
735 if (QDeclarativePixmapCache::get(d->url, &d->image, &errorString)==QDeclarativePixmapReply::Error) |
|
736 qmlInfo(this) << errorString; |
|
737 d->paintItem->updateSize(); |
|
738 d->paintItem->update(); |
|
739 } |
|
740 |
|
741 void QDeclarativeParticles::setSource(const QUrl &name) |
|
742 { |
|
743 Q_D(QDeclarativeParticles); |
|
744 |
|
745 if ((d->url.isEmpty() == name.isEmpty()) && name == d->url) |
|
746 return; |
|
747 |
|
748 if (d->pendingPixmapCache) { |
|
749 QDeclarativePixmapCache::cancel(d->url, this); |
|
750 d->pendingPixmapCache = false; |
|
751 } |
|
752 if (name.isEmpty()) { |
|
753 d->url = name; |
|
754 d->image = QPixmap(); |
|
755 d->paintItem->updateSize(); |
|
756 d->paintItem->update(); |
|
757 } else { |
|
758 d->url = name; |
|
759 Q_ASSERT(!name.isRelative()); |
|
760 QString errorString; |
|
761 QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->image, &errorString); |
|
762 if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) { |
|
763 QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url); |
|
764 connect(reply, SIGNAL(finished()), this, SLOT(imageLoaded())); |
|
765 d->pendingPixmapCache = true; |
|
766 } else { |
|
767 if (status == QDeclarativePixmapReply::Error) |
|
768 qmlInfo(this) << errorString; |
|
769 //### unify with imageLoaded |
|
770 d->paintItem->updateSize(); |
|
771 d->paintItem->update(); |
|
772 } |
|
773 } |
|
774 emit sourceChanged(); |
|
775 } |
|
776 |
|
777 /*! |
|
778 \qmlproperty int Particles::count |
|
779 This property holds the maximum number of particles |
|
780 |
|
781 The particles element emits particles until it has count active |
|
782 particles. When this number is reached, new particles are not emitted until |
|
783 some of the current particles reach the end of their lifespan. |
|
784 |
|
785 If count is -1 then there is no maximum number of active particles, and |
|
786 particles will be constantly emitted at the rate specified by emissionRate. |
|
787 |
|
788 The default value for count is 1. |
|
789 |
|
790 If both count and emissionRate are set to -1, nothing will be emitted. |
|
791 |
|
792 */ |
|
793 |
|
794 /*! |
|
795 \property QDeclarativeParticles::count |
|
796 \brief the maximum number of particles |
|
797 */ |
|
798 int QDeclarativeParticles::count() const |
|
799 { |
|
800 Q_D(const QDeclarativeParticles); |
|
801 return d->count; |
|
802 } |
|
803 |
|
804 void QDeclarativeParticles::setCount(int cnt) |
|
805 { |
|
806 Q_D(QDeclarativeParticles); |
|
807 if (cnt == d->count) |
|
808 return; |
|
809 |
|
810 int oldCount = d->count; |
|
811 d->count = cnt; |
|
812 d->addParticleTime = 0; |
|
813 d->addParticleCount = d->particles.count(); |
|
814 if (!oldCount && d->clock.state() != QAbstractAnimation::Running && d->count && d->emissionRate) { |
|
815 d->clock.start(); |
|
816 } |
|
817 d->paintItem->updateSize(); |
|
818 d->paintItem->update(); |
|
819 emit countChanged(); |
|
820 } |
|
821 |
|
822 |
|
823 /*! |
|
824 \qmlproperty int Particles::emissionRate |
|
825 This property holds the target number of particles to emit every second. |
|
826 |
|
827 The particles element will emit up to emissionRate particles every |
|
828 second. Fewer particles may be emitted per second if the maximum number of |
|
829 particles has been reached. |
|
830 |
|
831 If emissionRate is set to -1 there is no limit to the number of |
|
832 particles emitted per second, and particles will be instantly emitted to |
|
833 reach the maximum number of particles specified by count. |
|
834 |
|
835 The default value for emissionRate is -1. |
|
836 |
|
837 If both count and emissionRate are set to -1, nothing will be emitted. |
|
838 */ |
|
839 |
|
840 /*! |
|
841 \property QDeclarativeParticles::emissionRate |
|
842 \brief the emission rate of particles |
|
843 */ |
|
844 int QDeclarativeParticles::emissionRate() const |
|
845 { |
|
846 Q_D(const QDeclarativeParticles); |
|
847 return d->emissionRate; |
|
848 } |
|
849 void QDeclarativeParticles::setEmissionRate(int er) |
|
850 { |
|
851 Q_D(QDeclarativeParticles); |
|
852 if(er == d->emissionRate) |
|
853 return; |
|
854 d->emissionRate = er; |
|
855 if (d->clock.state() != QAbstractAnimation::Running && d->count && d->emissionRate) { |
|
856 d->clock.start(); |
|
857 } |
|
858 emit emissionRateChanged(); |
|
859 } |
|
860 |
|
861 /*! |
|
862 \qmlproperty real Particles::emissionVariance |
|
863 This property holds how inconsistent the rate of particle emissions are. |
|
864 It is a number between 0 (no variance) and 1 (some variance). |
|
865 |
|
866 The expected number of particles emitted per second is emissionRate. If |
|
867 emissionVariance is 0 then particles will be emitted consistently throughout |
|
868 each second to reach that number. If emissionVariance is greater than 0 the |
|
869 rate of particle emission will vary randomly throughout the second, with the |
|
870 consequence that the actual number of particles emitted in one second will |
|
871 vary randomly as well. |
|
872 |
|
873 emissionVariance is the maximum deviation from emitting |
|
874 emissionRate particles per second. An emissionVariance of 0 means you should |
|
875 get exactly emissionRate particles emitted per second, |
|
876 and an emissionVariance of 1 means you will get between zero and two times |
|
877 emissionRate particles per second, but you should get emissionRate particles |
|
878 per second on average. |
|
879 |
|
880 Note that even with an emissionVariance of 0 there may be some variance due |
|
881 to performance and hardware constraints. |
|
882 |
|
883 The default value of emissionVariance is 0.5 |
|
884 */ |
|
885 |
|
886 /*! |
|
887 \property QDeclarativeParticles::emissionVariance |
|
888 \brief how much the particle emission amounts vary per tick |
|
889 */ |
|
890 |
|
891 qreal QDeclarativeParticles::emissionVariance() const |
|
892 { |
|
893 Q_D(const QDeclarativeParticles); |
|
894 return d->emissionVariance; |
|
895 } |
|
896 |
|
897 void QDeclarativeParticles::setEmissionVariance(qreal ev) |
|
898 { |
|
899 Q_D(QDeclarativeParticles); |
|
900 if(d->emissionVariance == ev) |
|
901 return; |
|
902 d->emissionVariance = ev; |
|
903 emit emissionVarianceChanged(); |
|
904 } |
|
905 |
|
906 /*! |
|
907 \qmlproperty int Particles::lifeSpan |
|
908 \qmlproperty int Particles::lifeSpanDeviation |
|
909 |
|
910 These properties describe the life span of each particle. |
|
911 |
|
912 The default lifespan for a particle is 1000ms. |
|
913 |
|
914 lifeSpanDeviation randomly varies the lifeSpan up to the specified variation. For |
|
915 example, the following creates particles whose lifeSpan will vary |
|
916 from 150ms to 250ms: |
|
917 |
|
918 \qml |
|
919 Particles { |
|
920 source: "star.png" |
|
921 lifeSpan: 200 |
|
922 lifeSpanDeviation: 100 |
|
923 } |
|
924 \endqml |
|
925 */ |
|
926 |
|
927 /*! |
|
928 \property QDeclarativeParticles::lifeSpan |
|
929 \brief the life span of each particle. |
|
930 |
|
931 Default value is 1000ms. |
|
932 |
|
933 \sa QDeclarativeParticles::lifeSpanDeviation |
|
934 */ |
|
935 int QDeclarativeParticles::lifeSpan() const |
|
936 { |
|
937 Q_D(const QDeclarativeParticles); |
|
938 return d->lifeSpan; |
|
939 } |
|
940 |
|
941 void QDeclarativeParticles::setLifeSpan(int ls) |
|
942 { |
|
943 Q_D(QDeclarativeParticles); |
|
944 if(d->lifeSpan == ls) |
|
945 return; |
|
946 d->lifeSpan = ls; |
|
947 emit lifeSpanChanged(); |
|
948 } |
|
949 |
|
950 /*! |
|
951 \property QDeclarativeParticles::lifeSpanDeviation |
|
952 \brief the maximum possible deviation from the set lifeSpan. |
|
953 |
|
954 Randomly varies the lifeSpan up to the specified variation. For |
|
955 example, the following creates particles whose lifeSpan will vary |
|
956 from 150ms to 250ms: |
|
957 |
|
958 \qml |
|
959 Particles { |
|
960 source: "star.png" |
|
961 lifeSpan: 200 |
|
962 lifeSpanDeviation: 100 |
|
963 } |
|
964 \endqml |
|
965 |
|
966 \sa QDeclarativeParticles::lifeSpan |
|
967 */ |
|
968 int QDeclarativeParticles::lifeSpanDeviation() const |
|
969 { |
|
970 Q_D(const QDeclarativeParticles); |
|
971 return d->lifeSpanDev; |
|
972 } |
|
973 |
|
974 void QDeclarativeParticles::setLifeSpanDeviation(int dev) |
|
975 { |
|
976 Q_D(QDeclarativeParticles); |
|
977 if(d->lifeSpanDev == dev) |
|
978 return; |
|
979 d->lifeSpanDev = dev; |
|
980 emit lifeSpanDeviationChanged(); |
|
981 } |
|
982 |
|
983 /*! |
|
984 \qmlproperty int Particles::fadeInDuration |
|
985 \qmlproperty int Particles::fadeOutDuration |
|
986 These properties hold the time taken to fade the particles in and out. |
|
987 |
|
988 By default fade in is 200ms and fade out is 300ms. |
|
989 */ |
|
990 |
|
991 /*! |
|
992 \property QDeclarativeParticles::fadeInDuration |
|
993 \brief the time taken to fade in the particles. |
|
994 |
|
995 Default value is 200ms. |
|
996 */ |
|
997 int QDeclarativeParticles::fadeInDuration() const |
|
998 { |
|
999 Q_D(const QDeclarativeParticles); |
|
1000 return d->fadeInDur; |
|
1001 } |
|
1002 |
|
1003 void QDeclarativeParticles::setFadeInDuration(int dur) |
|
1004 { |
|
1005 Q_D(QDeclarativeParticles); |
|
1006 if (dur < 0.0 || dur == d->fadeInDur) |
|
1007 return; |
|
1008 d->fadeInDur = dur; |
|
1009 emit fadeInDurationChanged(); |
|
1010 } |
|
1011 |
|
1012 /*! |
|
1013 \property QDeclarativeParticles::fadeOutDuration |
|
1014 \brief the time taken to fade out the particles. |
|
1015 |
|
1016 Default value is 300ms. |
|
1017 */ |
|
1018 int QDeclarativeParticles::fadeOutDuration() const |
|
1019 { |
|
1020 Q_D(const QDeclarativeParticles); |
|
1021 return d->fadeOutDur; |
|
1022 } |
|
1023 |
|
1024 void QDeclarativeParticles::setFadeOutDuration(int dur) |
|
1025 { |
|
1026 Q_D(QDeclarativeParticles); |
|
1027 if (dur < 0.0 || d->fadeOutDur == dur) |
|
1028 return; |
|
1029 d->fadeOutDur = dur; |
|
1030 emit fadeOutDurationChanged(); |
|
1031 } |
|
1032 |
|
1033 /*! |
|
1034 \qmlproperty real Particles::angle |
|
1035 \qmlproperty real Particles::angleDeviation |
|
1036 |
|
1037 These properties control particle direction. |
|
1038 |
|
1039 angleDeviation randomly varies the direction up to the specified variation. For |
|
1040 example, the following creates particles whose initial direction will |
|
1041 vary from 15 degrees to 105 degrees: |
|
1042 |
|
1043 \qml |
|
1044 Particles { |
|
1045 source: "star.png" |
|
1046 angle: 60 |
|
1047 angleDeviation: 90 |
|
1048 } |
|
1049 \endqml |
|
1050 */ |
|
1051 |
|
1052 /*! |
|
1053 \property QDeclarativeParticles::angle |
|
1054 \brief the initial angle of direction. |
|
1055 |
|
1056 \sa QDeclarativeParticles::angleDeviation |
|
1057 */ |
|
1058 qreal QDeclarativeParticles::angle() const |
|
1059 { |
|
1060 Q_D(const QDeclarativeParticles); |
|
1061 return d->angle * 180.0 / M_PI; |
|
1062 } |
|
1063 |
|
1064 void QDeclarativeParticles::setAngle(qreal angle) |
|
1065 { |
|
1066 Q_D(QDeclarativeParticles); |
|
1067 qreal radAngle = angle * M_PI / 180.0; |
|
1068 if(radAngle == d->angle) |
|
1069 return; |
|
1070 d->angle = radAngle; |
|
1071 emit angleChanged(); |
|
1072 } |
|
1073 |
|
1074 /*! |
|
1075 \property QDeclarativeParticles::angleDeviation |
|
1076 \brief the maximum possible deviation from the set angle. |
|
1077 |
|
1078 Randomly varies the direction up to the specified variation. For |
|
1079 example, the following creates particles whose initial direction will |
|
1080 vary from 15 degrees to 105 degrees: |
|
1081 |
|
1082 \qml |
|
1083 Particles { |
|
1084 source: "star.png" |
|
1085 angle: 60 |
|
1086 angleDeviation: 90 |
|
1087 } |
|
1088 \endqml |
|
1089 |
|
1090 \sa QDeclarativeParticles::angle |
|
1091 */ |
|
1092 qreal QDeclarativeParticles::angleDeviation() const |
|
1093 { |
|
1094 Q_D(const QDeclarativeParticles); |
|
1095 return d->angleDev * 180.0 / M_PI; |
|
1096 } |
|
1097 |
|
1098 void QDeclarativeParticles::setAngleDeviation(qreal dev) |
|
1099 { |
|
1100 Q_D(QDeclarativeParticles); |
|
1101 qreal radDev = dev * M_PI / 180.0; |
|
1102 if(radDev == d->angleDev) |
|
1103 return; |
|
1104 d->angleDev = radDev; |
|
1105 emit angleDeviationChanged(); |
|
1106 } |
|
1107 |
|
1108 /*! |
|
1109 \qmlproperty real Particles::velocity |
|
1110 \qmlproperty real Particles::velocityDeviation |
|
1111 |
|
1112 These properties control the velocity of the particles. |
|
1113 |
|
1114 velocityDeviation randomly varies the velocity up to the specified variation. For |
|
1115 example, the following creates particles whose initial velocity will |
|
1116 vary from 40 to 60. |
|
1117 |
|
1118 \qml |
|
1119 Particles { |
|
1120 source: "star.png" |
|
1121 velocity: 50 |
|
1122 velocityDeviation: 20 |
|
1123 } |
|
1124 \endqml |
|
1125 */ |
|
1126 |
|
1127 /*! |
|
1128 \property QDeclarativeParticles::velocity |
|
1129 \brief the initial velocity of the particles. |
|
1130 |
|
1131 \sa QDeclarativeParticles::velocityDeviation |
|
1132 */ |
|
1133 qreal QDeclarativeParticles::velocity() const |
|
1134 { |
|
1135 Q_D(const QDeclarativeParticles); |
|
1136 return d->velocity * 1000.0; |
|
1137 } |
|
1138 |
|
1139 void QDeclarativeParticles::setVelocity(qreal velocity) |
|
1140 { |
|
1141 Q_D(QDeclarativeParticles); |
|
1142 qreal realVel = velocity / 1000.0; |
|
1143 if(realVel == d->velocity) |
|
1144 return; |
|
1145 d->velocity = realVel; |
|
1146 emit velocityChanged(); |
|
1147 } |
|
1148 |
|
1149 /*! |
|
1150 \property QDeclarativeParticles::velocityDeviation |
|
1151 \brief the maximum possible deviation from the set velocity. |
|
1152 |
|
1153 Randomly varies the velocity up to the specified variation. For |
|
1154 example, the following creates particles whose initial velocity will |
|
1155 vary from 40 to 60. |
|
1156 |
|
1157 \qml |
|
1158 Particles { |
|
1159 source: "star.png" |
|
1160 velocity: 50 |
|
1161 velocityDeviation: 20 |
|
1162 } |
|
1163 \endqml |
|
1164 |
|
1165 \sa QDeclarativeParticles::velocity |
|
1166 */ |
|
1167 qreal QDeclarativeParticles::velocityDeviation() const |
|
1168 { |
|
1169 Q_D(const QDeclarativeParticles); |
|
1170 return d->velocityDev * 1000.0; |
|
1171 } |
|
1172 |
|
1173 void QDeclarativeParticles::setVelocityDeviation(qreal velocity) |
|
1174 { |
|
1175 Q_D(QDeclarativeParticles); |
|
1176 qreal realDev = velocity / 1000.0; |
|
1177 if(realDev == d->velocityDev) |
|
1178 return; |
|
1179 d->velocityDev = realDev; |
|
1180 emit velocityDeviationChanged(); |
|
1181 } |
|
1182 |
|
1183 /*! |
|
1184 \qmlproperty ParticleMotion Particles::motion |
|
1185 This property sets the type of motion to apply to the particles. |
|
1186 |
|
1187 When a particle is created it will have an initial direction and velocity. |
|
1188 The motion of the particle during its lifeSpan is then influenced by the |
|
1189 motion property. |
|
1190 |
|
1191 Default motion is ParticleMotionLinear. |
|
1192 */ |
|
1193 |
|
1194 /*! |
|
1195 \property QDeclarativeParticles::motion |
|
1196 \brief sets the type of motion to apply to the particles. |
|
1197 |
|
1198 When a particle is created it will have an initial direction and velocity. |
|
1199 The motion of the particle during its lifeSpan is then influenced by the |
|
1200 motion property. |
|
1201 |
|
1202 Default motion is QDeclarativeParticleMotionLinear. |
|
1203 */ |
|
1204 QDeclarativeParticleMotion *QDeclarativeParticles::motion() const |
|
1205 { |
|
1206 Q_D(const QDeclarativeParticles); |
|
1207 return d->motion; |
|
1208 } |
|
1209 |
|
1210 void QDeclarativeParticles::setMotion(QDeclarativeParticleMotion *motion) |
|
1211 { |
|
1212 Q_D(QDeclarativeParticles); |
|
1213 if (motion == d->motion) |
|
1214 return; |
|
1215 d->motion = motion; |
|
1216 emit motionChanged(); |
|
1217 } |
|
1218 |
|
1219 /*! |
|
1220 \qmlmethod Particles::burst(int count, int emissionRate) |
|
1221 |
|
1222 Initiates a burst of particles. |
|
1223 |
|
1224 This method takes two arguments. The first argument is the number |
|
1225 of particles to emit and the second argument is the emissionRate for the |
|
1226 burst. If the second argument is omitted, it is treated as -1. The burst |
|
1227 of particles has a separate emissionRate and count to the normal emission of |
|
1228 particles. The burst uses the same values as normal emission for all other |
|
1229 properties, including emissionVariance. |
|
1230 |
|
1231 The normal emission of particles will continue during the burst, however |
|
1232 the particles created by the burst count towards the maximum number used by |
|
1233 normal emission. To avoid this behavior, use two Particles elements. |
|
1234 |
|
1235 */ |
|
1236 void QDeclarativeParticles::burst(int count, int emissionRate) |
|
1237 { |
|
1238 Q_D(QDeclarativeParticles); |
|
1239 d->bursts << qMakePair(count, emissionRate); |
|
1240 if (d->clock.state() != QAbstractAnimation::Running) |
|
1241 d->clock.start(); |
|
1242 } |
|
1243 |
|
1244 void QDeclarativeParticlesPainter::updateSize() |
|
1245 { |
|
1246 if (!d->_componentComplete) |
|
1247 return; |
|
1248 |
|
1249 const int parentX = parentItem()->x(); |
|
1250 const int parentY = parentItem()->y(); |
|
1251 for (int i = 0; i < d->particles.count(); ++i) { |
|
1252 const QDeclarativeParticle &particle = d->particles.at(i); |
|
1253 if(particle.x > maxX) |
|
1254 maxX = particle.x; |
|
1255 if(particle.x < minX) |
|
1256 minX = particle.x; |
|
1257 if(particle.y > maxY) |
|
1258 maxY = particle.y; |
|
1259 if(particle.y < minY) |
|
1260 minY = particle.y; |
|
1261 } |
|
1262 |
|
1263 int myWidth = (int)(maxX-minX+0.5)+d->image.width(); |
|
1264 int myX = (int)(minX - parentX); |
|
1265 int myHeight = (int)(maxY-minY+0.5)+d->image.height(); |
|
1266 int myY = (int)(minY - parentY); |
|
1267 setWidth(myWidth); |
|
1268 setHeight(myHeight); |
|
1269 setX(myX); |
|
1270 setY(myY); |
|
1271 } |
|
1272 |
|
1273 void QDeclarativeParticles::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) |
|
1274 { |
|
1275 Q_UNUSED(p); |
|
1276 //painting is done by the ParticlesPainter, so it can have the right size |
|
1277 } |
|
1278 |
|
1279 void QDeclarativeParticlesPainter::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) |
|
1280 { |
|
1281 if (d->image.isNull() || d->particles.isEmpty()) |
|
1282 return; |
|
1283 |
|
1284 const int myX = x() + parentItem()->x(); |
|
1285 const int myY = y() + parentItem()->y(); |
|
1286 |
|
1287 #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0)) |
|
1288 QVarLengthArray<QPainter::PixmapFragment, 256> pixmapData; |
|
1289 #else |
|
1290 QVarLengthArray<QDrawPixmaps::Data, 256> pixmapData; |
|
1291 #endif |
|
1292 pixmapData.resize(d->particles.count()); |
|
1293 |
|
1294 const QRectF sourceRect = d->image.rect(); |
|
1295 qreal halfPWidth = sourceRect.width()/2.; |
|
1296 qreal halfPHeight = sourceRect.height()/2.; |
|
1297 for (int i = 0; i < d->particles.count(); ++i) { |
|
1298 const QDeclarativeParticle &particle = d->particles.at(i); |
|
1299 #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0)) |
|
1300 pixmapData[i].x = particle.x - myX + halfPWidth; |
|
1301 pixmapData[i].y = particle.y - myY + halfPHeight; |
|
1302 #else |
|
1303 pixmapData[i].point = QPointF(particle.x - myX + halfPWidth, particle.y - myY + halfPHeight); |
|
1304 #endif |
|
1305 pixmapData[i].opacity = particle.opacity; |
|
1306 |
|
1307 //these never change |
|
1308 pixmapData[i].rotation = 0; |
|
1309 pixmapData[i].scaleX = 1; |
|
1310 pixmapData[i].scaleY = 1; |
|
1311 #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0)) |
|
1312 pixmapData[i].sourceLeft = sourceRect.left(); |
|
1313 pixmapData[i].sourceTop = sourceRect.top(); |
|
1314 pixmapData[i].width = sourceRect.width(); |
|
1315 pixmapData[i].height = sourceRect.height(); |
|
1316 #else |
|
1317 pixmapData[i].source = sourceRect; |
|
1318 #endif |
|
1319 } |
|
1320 #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0)) |
|
1321 p->drawPixmapFragments(pixmapData.data(), d->particles.count(), d->image); |
|
1322 #else |
|
1323 qDrawPixmaps(p, pixmapData.data(), d->particles.count(), d->image); |
|
1324 #endif |
|
1325 } |
|
1326 |
|
1327 void QDeclarativeParticles::componentComplete() |
|
1328 { |
|
1329 Q_D(QDeclarativeParticles); |
|
1330 QDeclarativeItem::componentComplete(); |
|
1331 if (d->count && d->emissionRate) { |
|
1332 d->paintItem->updateSize(); |
|
1333 d->clock.start(); |
|
1334 } |
|
1335 if (d->lifeSpanDev > d->lifeSpan) |
|
1336 d->lifeSpanDev = d->lifeSpan; |
|
1337 } |
|
1338 |
|
1339 QT_END_NAMESPACE |