1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativeparticles_p.h"
44 #include <qdeclarativeinfo.h>
45 #include <QtQuick1/private/qdeclarativeitem_p.h>
47 #include <QtQuick1/private/qdeclarativepixmapcache_p.h>
48 #include <QtCore/QAbstractAnimation>
51 #include <QtWidgets/qdrawutil.h>
52 #include <QVarLengthArray>
58 #define M_PI 3.14159265358979323846
59 #define M_PI_2 (M_PI / 2.)
62 #define INT_MAX 2147483647
66 #define PI_SQR 9.8696044
67 // parabolic approximation
68 inline qreal fastSin(qreal theta)
70 const qreal b = 4 / M_PI;
71 const qreal c = -4 / PI_SQR;
73 qreal y = b * theta + c * theta * qAbs(theta);
77 inline qreal fastCos(qreal theta)
83 return fastSin(theta);
86 class QDeclarativeParticle
89 QDeclarativeParticle(int time) : lifeSpan(1000), fadeOutAge(800)
90 , opacity(0), birthTime(time), x_velocity(0), y_velocity(0)
91 , state(FadeIn), data(0)
103 enum State { FadeIn, Solid, FadeOut };
108 //---------------------------------------------------------------------------
111 \class QDeclarativeParticleMotion
112 \ingroup group_effects
113 \brief The QDeclarativeParticleMotion class is the base class for particle motion.
116 This class causes the particles to remain static.
120 Constructs a QDeclarativeParticleMotion with parent object \a parent.
122 QDeclarativeParticleMotion::QDeclarativeParticleMotion(QObject *parent) :
128 Move the \a particle to its new position. \a interval is the number of
129 milliseconds elapsed since it was last moved.
131 void QDeclarativeParticleMotion::advance(QDeclarativeParticle &particle, int interval)
138 The \a particle has just been created. Some motion strategies require
139 additional state information. This can be allocated by this function.
141 void QDeclarativeParticleMotion::created(QDeclarativeParticle &particle)
147 The \a particle is about to be destroyed. Any additional memory
148 that has been allocated for the particle should be freed.
150 void QDeclarativeParticleMotion::destroy(QDeclarativeParticle &particle)
156 \qmlclass ParticleMotionLinear QDeclarativeParticleMotionLinear
157 \ingroup qml-particle-elements
159 \brief The ParticleMotionLinear object moves particles linearly.
163 This is the default motion, and moves the particles according to the
164 properties specified in the Particles element.
166 It has no further properties.
168 void QDeclarativeParticleMotionLinear::advance(QDeclarativeParticle &p, int interval)
170 p.x += interval * p.x_velocity;
171 p.y += interval * p.y_velocity;
175 \qmlclass ParticleMotionGravity QDeclarativeParticleMotionGravity
176 \ingroup qml-particle-elements
178 \brief The ParticleMotionGravity object moves particles towards a point.
180 This motion attracts the particles to the specified point with the specified acceleration.
181 To mimic earth gravity, set yattractor to -6360000 and acceleration to 9.8.
183 The defaults are all 0, not earth gravity, and so no motion will occur without setting
184 at least the acceleration property.
191 \qmlproperty real ParticleMotionGravity::xattractor
192 \qmlproperty real ParticleMotionGravity::yattractor
193 These properties hold the x and y coordinates of the point attracting the particles.
197 \qmlproperty real ParticleMotionGravity::acceleration
198 This property holds the acceleration to apply to the particles.
202 \property QDeclarativeParticleMotionGravity::xattractor
203 \brief the x coordinate of the point attracting the particles.
207 \property QDeclarativeParticleMotionGravity::yattractor
208 \brief the y coordinate of the point attracting the particles.
212 \property QDeclarativeParticleMotionGravity::acceleration
213 \brief the acceleration to apply to the particles.
216 void QDeclarativeParticleMotionGravity::setXAttractor(qreal x)
218 if (qFuzzyCompare(x, _xAttr))
221 emit xattractorChanged();
224 void QDeclarativeParticleMotionGravity::setYAttractor(qreal y)
226 if (qFuzzyCompare(y, _yAttr))
229 emit yattractorChanged();
232 void QDeclarativeParticleMotionGravity::setAcceleration(qreal accel)
234 qreal scaledAccel = accel/1000000.0;
235 if (qFuzzyCompare(scaledAccel, _accel))
237 _accel = scaledAccel;
238 emit accelerationChanged();
241 void QDeclarativeParticleMotionGravity::advance(QDeclarativeParticle &p, int interval)
243 qreal xdiff = _xAttr - p.x;
244 qreal ydiff = _yAttr - p.y;
245 qreal absXdiff = qAbs(xdiff);
246 qreal absYdiff = qAbs(ydiff);
248 qreal xcomp = xdiff / (absXdiff + absYdiff);
249 qreal ycomp = ydiff / (absXdiff + absYdiff);
251 p.x_velocity += xcomp * _accel * interval;
252 p.y_velocity += ycomp * _accel * interval;
254 p.x += interval * p.x_velocity;
255 p.y += interval * p.y_velocity;
259 \qmlclass ParticleMotionWander QDeclarativeParticleMotionWander
260 \ingroup qml-particle-elements
262 \brief The ParticleMotionWander object moves particles in a somewhat random fashion.
264 The particles will continue roughly in the original direction, however will randomly
267 The code below produces an effect similar to falling snow.
285 velocityDeviation: 10
286 ParticleMotionWander {
298 \qmlproperty real ParticleMotionWander::xvariance
299 \qmlproperty real ParticleMotionWander::yvariance
301 These properties set the amount to wander in the x and y directions.
305 \qmlproperty real ParticleMotionWander::pace
306 This property holds how quickly the paricles will move from side to side.
309 void QDeclarativeParticleMotionWander::advance(QDeclarativeParticle &p, int interval)
312 particles = qobject_cast<QDeclarativeParticles*>(parent());
314 Data *d = (Data*)p.data;
315 if (_xvariance != 0.) {
316 qreal xdiff = p.x_velocity - d->x_targetV;
317 if ((xdiff > d->x_peak && d->x_var > 0.0) || (xdiff < -d->x_peak && d->x_var < 0.0)) {
318 d->x_var = -d->x_var;
319 d->x_peak = _xvariance + _xvariance * qreal(qrand()) / RAND_MAX;
321 p.x_velocity += d->x_var * interval;
323 p.x += interval * p.x_velocity;
325 if (_yvariance != 0.) {
326 qreal ydiff = p.y_velocity - d->y_targetV;
327 if ((ydiff > d->y_peak && d->y_var > 0.0) || (ydiff < -d->y_peak && d->y_var < 0.0)) {
328 d->y_var = -d->y_var;
329 d->y_peak = _yvariance + _yvariance * qreal(qrand()) / RAND_MAX;
331 p.y_velocity += d->y_var * interval;
333 p.y += interval * p.y_velocity;
337 void QDeclarativeParticleMotionWander::created(QDeclarativeParticle &p)
342 d->x_targetV = p.x_velocity;
343 d->y_targetV = p.y_velocity;
344 d->x_peak = _xvariance;
345 d->y_peak = _yvariance;
346 d->x_var = _pace * qreal(qrand()) / RAND_MAX / 1000.0;
347 d->y_var = _pace * qreal(qrand()) / RAND_MAX / 1000.0;
351 void QDeclarativeParticleMotionWander::destroy(QDeclarativeParticle &p)
354 delete (Data*)p.data;
357 void QDeclarativeParticleMotionWander::setXVariance(qreal var)
359 qreal scaledVar = var / 1000.0;
360 if (qFuzzyCompare(scaledVar, _xvariance))
362 _xvariance = scaledVar;
363 emit xvarianceChanged();
366 void QDeclarativeParticleMotionWander::setYVariance(qreal var)
368 qreal scaledVar = var / 1000.0;
369 if (qFuzzyCompare(scaledVar, _yvariance))
371 _yvariance = scaledVar;
372 emit yvarianceChanged();
375 void QDeclarativeParticleMotionWander::setPace(qreal pace)
377 qreal scaledPace = pace / 1000.0;
378 if (qFuzzyCompare(scaledPace, _pace))
384 //---------------------------------------------------------------------------
385 class QDeclarativeParticlesPainter : public QDeclarativeItem
388 QDeclarativeParticlesPainter(QDeclarativeParticlesPrivate *p, QDeclarativeItem* parent)
389 : QDeclarativeItem(parent), d(p)
391 setFlag(QGraphicsItem::ItemHasNoContents, false);
392 maxX = minX = maxY = minY = 0;
395 void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);
403 QDeclarativeParticlesPrivate* d;
406 //an animation that just gives a tick
407 template<class T, void (T::*method)(int)>
408 class TickAnimationProxy : public QAbstractAnimation
411 TickAnimationProxy(T *p, QObject *parent = 0) : QAbstractAnimation(parent), m_p(p) {}
412 virtual int duration() const { return -1; }
414 virtual void updateCurrentTime(int msec) { (m_p->*method)(msec); }
420 //---------------------------------------------------------------------------
421 class QDeclarativeParticlesPrivate : public QDeclarativeItemPrivate
423 Q_DECLARE_PUBLIC(QDeclarativeParticles)
425 QDeclarativeParticlesPrivate()
426 : count(1), emissionRate(-1), emissionVariance(0.5), lifeSpan(1000)
427 , lifeSpanDev(1000), fadeInDur(200), fadeOutDur(300)
428 , angle(0), angleDev(0), velocity(0), velocityDev(0), emissionCarry(0.)
429 , addParticleTime(0), addParticleCount(0), lastAdvTime(0)
430 , motion(0), clock(this)
434 ~QDeclarativeParticlesPrivate()
440 Q_Q(QDeclarativeParticles);
441 paintItem = new QDeclarativeParticlesPainter(this, q);
445 void createParticle(int time);
446 void updateOpacity(QDeclarativeParticle &p, int age);
449 QDeclarative1Pixmap image;
452 qreal emissionVariance;
463 int addParticleCount;
465 QDeclarativeParticleMotion *motion;
466 QDeclarativeParticlesPainter *paintItem;
469 QList<QPair<int, int> > bursts;//countLeft, emissionRate pairs
470 QList<QDeclarativeParticle> particles;
471 TickAnimationProxy<QDeclarativeParticlesPrivate, &QDeclarativeParticlesPrivate::tick> clock;
475 void QDeclarativeParticlesPrivate::tick(int time)
477 Q_Q(QDeclarativeParticles);
479 motion = new QDeclarativeParticleMotionLinear(q);
481 int oldCount = particles.count();
483 int interval = time - lastAdvTime;
484 for (int i = 0; i < particles.count(); ) {
485 QDeclarativeParticle &particle = particles[i];
486 int age = time - particle.birthTime;
487 if (age >= particle.lifeSpan) {
488 QDeclarativeParticle part = particles.takeAt(i);
489 motion->destroy(part);
492 updateOpacity(particle, age);
493 motion->advance(particle, interval);
498 if(emissionRate == -1)//Otherwise leave emission to the emission rate
499 while(removed-- && ((count == -1) || particles.count() < count))
500 createParticle(time);
502 if (!addParticleTime)
503 addParticleTime = time;
505 //Possibly emit new particles
506 if (((count == -1) || particles.count() < count) && emissionRate
507 && !(count==-1 && emissionRate==-1)) {
508 int emissionCount = -1;
509 if (emissionRate != -1){
511 if (emissionVariance > 0.){
512 variance += (qreal(qrand())/RAND_MAX) * emissionVariance * (qrand()%2?-1.:1.);
514 qreal emission = emissionRate * (qreal(interval)/1000.);
515 emission = emission * variance + emissionCarry;
517 emissionCarry = modf(emission, &tmpDbl);
518 emissionCount = (int)tmpDbl;
519 emissionCount = qMax(0,emissionCount);
521 while(((count == -1) || particles.count() < count) &&
522 (emissionRate==-1 || emissionCount--))
523 createParticle(time);
526 //Deal with emissions from requested bursts
527 for(int i=0; i<bursts.size(); i++){
529 if(bursts[i].second == -1){
530 emission = bursts[i].first;
533 if (emissionVariance > 0.){
534 variance += (qreal(qrand())/RAND_MAX) * emissionVariance * (qrand()%2?-1.:1.);
536 qreal workingEmission = bursts[i].second * (qreal(interval)/1000.);
537 workingEmission *= variance;
538 emission = (int)workingEmission;
539 emission = qMax(emission, 0);
541 emission = qMin(emission, bursts[i].first);
542 bursts[i].first -= emission;
544 createParticle(time);
546 for(int i=bursts.size()-1; i>=0; i--)
547 if(bursts[i].first <= 0)
551 paintItem->updateSize();
553 if (!(oldCount || particles.count()) && (!count || !emissionRate) && bursts.isEmpty()) {
559 void QDeclarativeParticlesPrivate::createParticle(int time)
561 Q_Q(QDeclarativeParticles);
562 QDeclarativeParticle p(time);
563 p.x = q->x() + q->width() * qreal(qrand()) / RAND_MAX - image.width()/2.0;
564 p.y = q->y() + q->height() * qreal(qrand()) / RAND_MAX - image.height()/2.0;
565 p.lifeSpan = lifeSpan;
567 p.lifeSpan += int(lifeSpanDev/2 - lifeSpanDev * qreal(qrand()) / RAND_MAX);
568 p.fadeOutAge = p.lifeSpan - fadeOutDur;
569 if (fadeInDur == 0.) {
570 p.state= QDeclarativeParticle::Solid;
575 a += angleDev/2 - angleDev * qreal(qrand()) / RAND_MAX;
580 v += velocityDev/2 - velocityDev * qreal(qrand()) / RAND_MAX;
581 p.x_velocity = v * fastCos(a);
582 p.y_velocity = v * fastSin(a);
584 motion->created(particles.last());
587 void QDeclarativeParticlesPrivate::updateOpacity(QDeclarativeParticle &p, int age)
590 case QDeclarativeParticle::FadeIn:
591 if (age <= fadeInDur) {
592 p.opacity = qreal(age) / fadeInDur;
596 p.state = QDeclarativeParticle::Solid;
599 case QDeclarativeParticle::Solid:
600 if (age <= p.fadeOutAge) {
603 p.state = QDeclarativeParticle::FadeOut;
606 case QDeclarativeParticle::FadeOut:
607 p.opacity = qreal(p.lifeSpan - age) / fadeOutDur;
613 \qmlclass Particles QDeclarativeParticles
614 \ingroup qml-particle-elements
616 \brief The Particles object generates and moves particles.
619 Particles are available in the \bold{Qt.labs.particles 1.0} module.
620 \e {Elements in the Qt.labs module are not guaranteed to remain compatible
623 This element provides preliminary support for particles in QML,
624 and may be heavily changed or removed in later versions.
626 The particles created by this object cannot be dealt with
627 directly, they can only be controlled through the parameters of
628 the Particles object. The particles are all the same pixmap,
629 specified by the user.
631 The particles are painted relative to the parent of the Particles
632 object. Moving the Particles object will not move the particles
635 The below example creates two differently behaving particle
636 sources. The top one has particles falling from the top like
637 snow, the lower one has particles expelled up like a fountain.
641 import Qt.labs.particles 1.0
657 velocityDeviation: 10
658 ParticleMotionWander {
674 velocityDeviation: 30
675 ParticleMotionGravity {
686 QDeclarativeParticles::QDeclarativeParticles(QDeclarativeItem *parent)
687 : QDeclarativeItem(*(new QDeclarativeParticlesPrivate), parent)
689 Q_D(QDeclarativeParticles);
693 QDeclarativeParticles::~QDeclarativeParticles()
698 \qmlproperty string Particles::source
699 This property holds the URL of the particle image.
703 \property QDeclarativeParticles::source
704 \brief the URL of the particle image.
706 QUrl QDeclarativeParticles::source() const
708 Q_D(const QDeclarativeParticles);
712 void QDeclarativeParticles::imageLoaded()
714 Q_D(QDeclarativeParticles);
715 if (d->image.isError())
716 qmlInfo(this) << d->image.error();
717 d->paintItem->updateSize();
718 d->paintItem->update();
721 void QDeclarativeParticles::setSource(const QUrl &name)
723 Q_D(QDeclarativeParticles);
725 if ((d->url.isEmpty() == name.isEmpty()) && name == d->url)
728 if (name.isEmpty()) {
730 d->image.clear(this);
731 d->paintItem->updateSize();
732 d->paintItem->update();
735 Q_ASSERT(!name.isRelative());
736 d->image.load(qmlEngine(this), d->url);
737 if (d->image.isLoading()) {
738 d->image.connectFinished(this, SLOT(imageLoaded()));
740 if (d->image.isError())
741 qmlInfo(this) << d->image.error();
742 //### unify with imageLoaded
743 d->paintItem->updateSize();
744 d->paintItem->update();
747 emit sourceChanged();
751 \qmlproperty int Particles::count
752 This property holds the maximum number of particles
754 The particles element emits particles until it has count active
755 particles. When this number is reached, new particles are not emitted until
756 some of the current particles reach the end of their lifespan.
758 If count is -1 then there is no maximum number of active particles, and
759 particles will be constantly emitted at the rate specified by emissionRate.
761 The default value for count is 1.
763 If both count and emissionRate are set to -1, nothing will be emitted.
768 \property QDeclarativeParticles::count
769 \brief the maximum number of particles
771 int QDeclarativeParticles::count() const
773 Q_D(const QDeclarativeParticles);
777 void QDeclarativeParticles::setCount(int cnt)
779 Q_D(QDeclarativeParticles);
783 int oldCount = d->count;
785 d->addParticleTime = 0;
786 d->addParticleCount = d->particles.count();
787 if (!oldCount && d->clock.state() != QAbstractAnimation::Running && d->count && d->emissionRate) {
790 d->paintItem->updateSize();
791 d->paintItem->update();
797 \qmlproperty int Particles::emissionRate
798 This property holds the target number of particles to emit every second.
800 The particles element will emit up to emissionRate particles every
801 second. Fewer particles may be emitted per second if the maximum number of
802 particles has been reached.
804 If emissionRate is set to -1 there is no limit to the number of
805 particles emitted per second, and particles will be instantly emitted to
806 reach the maximum number of particles specified by count.
808 The default value for emissionRate is -1.
810 If both count and emissionRate are set to -1, nothing will be emitted.
814 \property QDeclarativeParticles::emissionRate
815 \brief the emission rate of particles
817 int QDeclarativeParticles::emissionRate() const
819 Q_D(const QDeclarativeParticles);
820 return d->emissionRate;
822 void QDeclarativeParticles::setEmissionRate(int er)
824 Q_D(QDeclarativeParticles);
825 if(er == d->emissionRate)
827 d->emissionRate = er;
828 if (d->clock.state() != QAbstractAnimation::Running && d->count && d->emissionRate) {
831 emit emissionRateChanged();
835 \qmlproperty real Particles::emissionVariance
836 This property holds how inconsistent the rate of particle emissions are.
837 It is a number between 0 (no variance) and 1 (some variance).
839 The expected number of particles emitted per second is emissionRate. If
840 emissionVariance is 0 then particles will be emitted consistently throughout
841 each second to reach that number. If emissionVariance is greater than 0 the
842 rate of particle emission will vary randomly throughout the second, with the
843 consequence that the actual number of particles emitted in one second will
844 vary randomly as well.
846 emissionVariance is the maximum deviation from emitting
847 emissionRate particles per second. An emissionVariance of 0 means you should
848 get exactly emissionRate particles emitted per second,
849 and an emissionVariance of 1 means you will get between zero and two times
850 emissionRate particles per second, but you should get emissionRate particles
851 per second on average.
853 Note that even with an emissionVariance of 0 there may be some variance due
854 to performance and hardware constraints.
856 The default value of emissionVariance is 0.5
860 \property QDeclarativeParticles::emissionVariance
861 \brief how much the particle emission amounts vary per tick
864 qreal QDeclarativeParticles::emissionVariance() const
866 Q_D(const QDeclarativeParticles);
867 return d->emissionVariance;
870 void QDeclarativeParticles::setEmissionVariance(qreal ev)
872 Q_D(QDeclarativeParticles);
873 if(d->emissionVariance == ev)
875 d->emissionVariance = ev;
876 emit emissionVarianceChanged();
880 \qmlproperty int Particles::lifeSpan
881 \qmlproperty int Particles::lifeSpanDeviation
883 These properties describe the life span of each particle.
885 The default lifespan for a particle is 1000ms.
887 lifeSpanDeviation randomly varies the lifeSpan up to the specified variation. For
888 example, the following creates particles whose lifeSpan will vary
895 lifeSpanDeviation: 100
901 \property QDeclarativeParticles::lifeSpan
902 \brief the life span of each particle.
904 Default value is 1000ms.
906 \sa QDeclarativeParticles::lifeSpanDeviation
908 int QDeclarativeParticles::lifeSpan() const
910 Q_D(const QDeclarativeParticles);
914 void QDeclarativeParticles::setLifeSpan(int ls)
916 Q_D(QDeclarativeParticles);
917 if(d->lifeSpan == ls)
920 emit lifeSpanChanged();
924 \property QDeclarativeParticles::lifeSpanDeviation
925 \brief the maximum possible deviation from the set lifeSpan.
927 Randomly varies the lifeSpan up to the specified variation. For
928 example, the following creates particles whose lifeSpan will vary
935 lifeSpanDeviation: 100
939 \sa QDeclarativeParticles::lifeSpan
941 int QDeclarativeParticles::lifeSpanDeviation() const
943 Q_D(const QDeclarativeParticles);
944 return d->lifeSpanDev;
947 void QDeclarativeParticles::setLifeSpanDeviation(int dev)
949 Q_D(QDeclarativeParticles);
950 if(d->lifeSpanDev == dev)
952 d->lifeSpanDev = dev;
953 emit lifeSpanDeviationChanged();
957 \qmlproperty int Particles::fadeInDuration
958 \qmlproperty int Particles::fadeOutDuration
959 These properties hold the time taken to fade the particles in and out.
961 By default fade in is 200ms and fade out is 300ms.
965 \property QDeclarativeParticles::fadeInDuration
966 \brief the time taken to fade in the particles.
968 Default value is 200ms.
970 int QDeclarativeParticles::fadeInDuration() const
972 Q_D(const QDeclarativeParticles);
976 void QDeclarativeParticles::setFadeInDuration(int dur)
978 Q_D(QDeclarativeParticles);
979 if (dur < 0.0 || dur == d->fadeInDur)
982 emit fadeInDurationChanged();
986 \property QDeclarativeParticles::fadeOutDuration
987 \brief the time taken to fade out the particles.
989 Default value is 300ms.
991 int QDeclarativeParticles::fadeOutDuration() const
993 Q_D(const QDeclarativeParticles);
994 return d->fadeOutDur;
997 void QDeclarativeParticles::setFadeOutDuration(int dur)
999 Q_D(QDeclarativeParticles);
1000 if (dur < 0.0 || d->fadeOutDur == dur)
1002 d->fadeOutDur = dur;
1003 emit fadeOutDurationChanged();
1007 \qmlproperty real Particles::angle
1008 \qmlproperty real Particles::angleDeviation
1010 These properties control particle direction.
1012 angleDeviation randomly varies the direction up to the specified variation. For
1013 example, the following creates particles whose initial direction will
1014 vary from 15 degrees to 105 degrees:
1026 \property QDeclarativeParticles::angle
1027 \brief the initial angle of direction.
1029 \sa QDeclarativeParticles::angleDeviation
1031 qreal QDeclarativeParticles::angle() const
1033 Q_D(const QDeclarativeParticles);
1034 return d->angle * 180.0 / M_PI;
1037 void QDeclarativeParticles::setAngle(qreal angle)
1039 Q_D(QDeclarativeParticles);
1040 qreal radAngle = angle * M_PI / 180.0;
1041 if(radAngle == d->angle)
1043 d->angle = radAngle;
1044 emit angleChanged();
1048 \property QDeclarativeParticles::angleDeviation
1049 \brief the maximum possible deviation from the set angle.
1051 Randomly varies the direction up to the specified variation. For
1052 example, the following creates particles whose initial direction will
1053 vary from 15 degrees to 105 degrees:
1063 \sa QDeclarativeParticles::angle
1065 qreal QDeclarativeParticles::angleDeviation() const
1067 Q_D(const QDeclarativeParticles);
1068 return d->angleDev * 180.0 / M_PI;
1071 void QDeclarativeParticles::setAngleDeviation(qreal dev)
1073 Q_D(QDeclarativeParticles);
1074 qreal radDev = dev * M_PI / 180.0;
1075 if(radDev == d->angleDev)
1077 d->angleDev = radDev;
1078 emit angleDeviationChanged();
1082 \qmlproperty real Particles::velocity
1083 \qmlproperty real Particles::velocityDeviation
1085 These properties control the velocity of the particles.
1087 velocityDeviation randomly varies the velocity up to the specified variation. For
1088 example, the following creates particles whose initial velocity will
1095 velocityDeviation: 20
1101 \property QDeclarativeParticles::velocity
1102 \brief the initial velocity of the particles.
1104 \sa QDeclarativeParticles::velocityDeviation
1106 qreal QDeclarativeParticles::velocity() const
1108 Q_D(const QDeclarativeParticles);
1109 return d->velocity * 1000.0;
1112 void QDeclarativeParticles::setVelocity(qreal velocity)
1114 Q_D(QDeclarativeParticles);
1115 qreal realVel = velocity / 1000.0;
1116 if(realVel == d->velocity)
1118 d->velocity = realVel;
1119 emit velocityChanged();
1123 \property QDeclarativeParticles::velocityDeviation
1124 \brief the maximum possible deviation from the set velocity.
1126 Randomly varies the velocity up to the specified variation. For
1127 example, the following creates particles whose initial velocity will
1134 velocityDeviation: 20
1138 \sa QDeclarativeParticles::velocity
1140 qreal QDeclarativeParticles::velocityDeviation() const
1142 Q_D(const QDeclarativeParticles);
1143 return d->velocityDev * 1000.0;
1146 void QDeclarativeParticles::setVelocityDeviation(qreal velocity)
1148 Q_D(QDeclarativeParticles);
1149 qreal realDev = velocity / 1000.0;
1150 if(realDev == d->velocityDev)
1152 d->velocityDev = realDev;
1153 emit velocityDeviationChanged();
1157 \qmlproperty ParticleMotion Particles::motion
1158 This property sets the type of motion to apply to the particles.
1160 When a particle is created it will have an initial direction and velocity.
1161 The motion of the particle during its lifeSpan is then influenced by the
1164 Default motion is ParticleMotionLinear.
1168 \property QDeclarativeParticles::motion
1169 \brief sets the type of motion to apply to the particles.
1171 When a particle is created it will have an initial direction and velocity.
1172 The motion of the particle during its lifeSpan is then influenced by the
1175 Default motion is QDeclarativeParticleMotionLinear.
1177 QDeclarativeParticleMotion *QDeclarativeParticles::motion() const
1179 Q_D(const QDeclarativeParticles);
1183 void QDeclarativeParticles::setMotion(QDeclarativeParticleMotion *motion)
1185 Q_D(QDeclarativeParticles);
1186 if (motion == d->motion)
1189 emit motionChanged();
1193 \qmlmethod Particles::burst(int count, int emissionRate)
1195 Initiates a burst of particles.
1197 This method takes two arguments. The first argument is the number
1198 of particles to emit and the second argument is the emissionRate for the
1199 burst. If the second argument is omitted, it is treated as -1. The burst
1200 of particles has a separate emissionRate and count to the normal emission of
1201 particles. The burst uses the same values as normal emission for all other
1202 properties, including emissionVariance.
1204 The normal emission of particles will continue during the burst, however
1205 the particles created by the burst count towards the maximum number used by
1206 normal emission. To avoid this behavior, use two Particles elements.
1209 void QDeclarativeParticles::burst(int count, int emissionRate)
1211 Q_D(QDeclarativeParticles);
1212 d->bursts << qMakePair(count, emissionRate);
1213 if (d->clock.state() != QAbstractAnimation::Running)
1217 void QDeclarativeParticlesPainter::updateSize()
1219 if (!d->componentComplete)
1222 const int parentX = parentItem()->x();
1223 const int parentY = parentItem()->y();
1224 for (int i = 0; i < d->particles.count(); ++i) {
1225 const QDeclarativeParticle &particle = d->particles.at(i);
1226 if(particle.x > maxX)
1228 if(particle.x < minX)
1230 if(particle.y > maxY)
1232 if(particle.y < minY)
1236 int myWidth = (int)(maxX-minX+0.5)+d->image.width();
1237 int myX = (int)(minX - parentX);
1238 int myHeight = (int)(maxY-minY+0.5)+d->image.height();
1239 int myY = (int)(minY - parentY);
1241 setHeight(myHeight);
1246 void QDeclarativeParticles::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
1249 //painting is done by the ParticlesPainter, so it can have the right size
1252 void QDeclarativeParticlesPainter::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
1254 if (d->image.isNull() || d->particles.isEmpty())
1257 const int myX = x() + parentItem()->x();
1258 const int myY = y() + parentItem()->y();
1260 QVarLengthArray<QPainter::PixmapFragment, 256> pixmapData;
1261 pixmapData.resize(d->particles.count());
1263 const QRectF sourceRect = d->image.rect();
1264 qreal halfPWidth = sourceRect.width()/2.;
1265 qreal halfPHeight = sourceRect.height()/2.;
1266 for (int i = 0; i < d->particles.count(); ++i) {
1267 const QDeclarativeParticle &particle = d->particles.at(i);
1268 pixmapData[i].x = particle.x - myX + halfPWidth;
1269 pixmapData[i].y = particle.y - myY + halfPHeight;
1270 pixmapData[i].opacity = particle.opacity;
1272 //these never change
1273 pixmapData[i].rotation = 0;
1274 pixmapData[i].scaleX = 1;
1275 pixmapData[i].scaleY = 1;
1276 pixmapData[i].sourceLeft = sourceRect.left();
1277 pixmapData[i].sourceTop = sourceRect.top();
1278 pixmapData[i].width = sourceRect.width();
1279 pixmapData[i].height = sourceRect.height();
1281 p->drawPixmapFragments(pixmapData.data(), d->particles.count(), d->image);
1284 void QDeclarativeParticles::componentComplete()
1286 Q_D(QDeclarativeParticles);
1287 QDeclarativeItem::componentComplete();
1288 if (d->count && d->emissionRate) {
1289 d->paintItem->updateSize();
1292 if (d->lifeSpanDev > d->lifeSpan)
1293 d->lifeSpanDev = d->lifeSpan;