src/imports/particles/qdeclarativeparticles.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     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