src/imports/particles/qdeclarativeparticles.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
child 37 758a864f9613
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
   151 {
   151 {
   152     Q_UNUSED(particle);
   152     Q_UNUSED(particle);
   153 }
   153 }
   154 
   154 
   155 /*!
   155 /*!
   156     \qmlclass ParticleMotionLinear
   156     \qmlclass ParticleMotionLinear QDeclarativeParticleMotionLinear
   157     \since 4.7
   157     \since 4.7
   158     \brief The ParticleMotionLinear object moves particles linearly.
   158     \brief The ParticleMotionLinear object moves particles linearly.
   159 
   159 
   160     \sa Particles
   160     \sa Particles
       
   161 
       
   162     This is the default motion, and moves the particles according to the
       
   163     properties specified in the Particles element.
       
   164 
       
   165     It has no further properties.
   161 */
   166 */
   162 
   167 
   163 /*!
   168 /*!
   164     \internal
   169     \internal
   165     \class QDeclarativeParticleMotionLinear
   170     \class QDeclarativeParticleMotionLinear
   172     p.x += interval * p.x_velocity;
   177     p.x += interval * p.x_velocity;
   173     p.y += interval * p.y_velocity;
   178     p.y += interval * p.y_velocity;
   174 }
   179 }
   175 
   180 
   176 /*!
   181 /*!
   177     \qmlclass ParticleMotionGravity
   182     \qmlclass ParticleMotionGravity QDeclarativeParticleMotionGravity
   178     \since 4.7
   183     \since 4.7
   179     \brief The ParticleMotionGravity object moves particles towards a point.
   184     \brief The ParticleMotionGravity object moves particles towards a point.
       
   185 
       
   186     This motion attracts the particles to the specified point with the specified acceleration.
       
   187     To mimic earth gravity, set yattractor to -6360000 and acceleration to 9.8.
       
   188 
       
   189     The defaults are all 0, not earth gravity, and so no motion will occur without setting
       
   190     at least the acceleration property.
       
   191 
   180 
   192 
   181     \sa Particles
   193     \sa Particles
   182 */
   194 */
   183 
   195 
   184 /*!
   196 /*!
   185     \internal
   197     \internal
   186     \class QDeclarativeParticleMotionGravity
   198     \class QDeclarativeParticleMotionGravity
   187     \ingroup group_effects
   199     \ingroup group_effects
   188     \brief The QDeclarativeParticleMotionGravity class moves the particles towards a point.
   200     \brief The QDeclarativeParticleMotionGravity class moves the particles towards a point.
       
   201 
   189 */
   202 */
   190 
   203 
   191 /*!
   204 /*!
   192     \qmlproperty real ParticleMotionGravity::xattractor
   205     \qmlproperty real ParticleMotionGravity::xattractor
   193     \qmlproperty real ParticleMotionGravity::yattractor
   206     \qmlproperty real ParticleMotionGravity::yattractor
   239     emit accelerationChanged();
   252     emit accelerationChanged();
   240 }
   253 }
   241 
   254 
   242 void QDeclarativeParticleMotionGravity::advance(QDeclarativeParticle &p, int interval)
   255 void QDeclarativeParticleMotionGravity::advance(QDeclarativeParticle &p, int interval)
   243 {
   256 {
   244     qreal xdiff = p.x - _xAttr;
   257     qreal xdiff = _xAttr - p.x;
   245     qreal ydiff = p.y - _yAttr;
   258     qreal ydiff = _yAttr - p.y;
   246 
   259     qreal absXdiff = qAbs(xdiff);
   247     qreal xcomp = xdiff / (xdiff + ydiff);
   260     qreal absYdiff = qAbs(ydiff);
   248     qreal ycomp = ydiff / (xdiff + ydiff);
   261 
       
   262     qreal xcomp = xdiff / (absXdiff + absYdiff);
       
   263     qreal ycomp = ydiff / (absXdiff + absYdiff);
   249 
   264 
   250     p.x_velocity += xcomp * _accel * interval;
   265     p.x_velocity += xcomp * _accel * interval;
   251     p.y_velocity += ycomp * _accel * interval;
   266     p.y_velocity += ycomp * _accel * interval;
   252 
   267 
   253     p.x += interval * p.x_velocity;
   268     p.x += interval * p.x_velocity;
   254     p.y += interval * p.y_velocity;
   269     p.y += interval * p.y_velocity;
   255 }
   270 }
   256 
   271 
   257 /*!
   272 /*!
   258     \qmlclass ParticleMotionWander
   273     \qmlclass ParticleMotionWander QDeclarativeParticleMotionWander
   259     \since 4.7
   274     \since 4.7
   260     \brief The ParticleMotionWander object moves particles in a somewhat random fashion.
   275     \brief The ParticleMotionWander object moves particles in a somewhat random fashion.
   261 
   276 
   262     The particles will continue roughly in the original direction, however will randomly
   277     The particles will continue roughly in the original direction, however will randomly
   263     drift to each side.
   278     drift to each side.
   301     The particles will continue roughly in the original direction, however will randomly
   316     The particles will continue roughly in the original direction, however will randomly
   302     drift to each side.
   317     drift to each side.
   303 */
   318 */
   304 
   319 
   305 /*!
   320 /*!
   306     \qmlproperty real QDeclarativeParticleMotionWander::xvariance
   321     \qmlproperty real ParticleMotionWander::xvariance
   307     \qmlproperty real QDeclarativeParticleMotionWander::yvariance
   322     \qmlproperty real ParticleMotionWander::yvariance
   308 
   323 
   309     These properties set the amount to wander in the x and y directions.
   324     These properties set the amount to wander in the x and y directions.
   310 */
   325 */
   311 
   326 
   312 /*!
   327 /*!
   313     \qmlproperty real QDeclarativeParticleMotionWander::pace
   328     \qmlproperty real ParticleMotionWander::pace
   314     This property holds how quickly the paricles will move from side to side.
   329     This property holds how quickly the paricles will move from side to side.
   315 */
   330 */
   316 
   331 
   317 void QDeclarativeParticleMotionWander::advance(QDeclarativeParticle &p, int interval)
   332 void QDeclarativeParticleMotionWander::advance(QDeclarativeParticle &p, int interval)
   318 {
   333 {
   433     QDeclarativeParticlesPrivate()
   448     QDeclarativeParticlesPrivate()
   434         : count(1), emissionRate(-1), emissionVariance(0.5), lifeSpan(1000)
   449         : count(1), emissionRate(-1), emissionVariance(0.5), lifeSpan(1000)
   435         , lifeSpanDev(1000), fadeInDur(200), fadeOutDur(300)
   450         , lifeSpanDev(1000), fadeInDur(200), fadeOutDur(300)
   436         , angle(0), angleDev(0), velocity(0), velocityDev(0), emissionCarry(0.)
   451         , angle(0), angleDev(0), velocity(0), velocityDev(0), emissionCarry(0.)
   437         , addParticleTime(0), addParticleCount(0), lastAdvTime(0)
   452         , addParticleTime(0), addParticleCount(0), lastAdvTime(0)
   438         , motion(0), pendingPixmapCache(false), clock(this)
   453         , motion(0), clock(this)
   439     {
   454     {
   440     }
   455     }
   441 
   456 
   442     ~QDeclarativeParticlesPrivate()
   457     ~QDeclarativeParticlesPrivate()
   443     {
   458     {
   452     void tick(int time);
   467     void tick(int time);
   453     void createParticle(int time);
   468     void createParticle(int time);
   454     void updateOpacity(QDeclarativeParticle &p, int age);
   469     void updateOpacity(QDeclarativeParticle &p, int age);
   455 
   470 
   456     QUrl url;
   471     QUrl url;
   457     QPixmap image;
   472     QDeclarativePixmap image;
   458     int count;
   473     int count;
   459     int emissionRate;
   474     int emissionRate;
   460     qreal emissionVariance;
   475     qreal emissionVariance;
   461     int lifeSpan;
   476     int lifeSpan;
   462     int lifeSpanDev;
   477     int lifeSpanDev;
   471     int addParticleCount;
   486     int addParticleCount;
   472     int lastAdvTime;
   487     int lastAdvTime;
   473     QDeclarativeParticleMotion *motion;
   488     QDeclarativeParticleMotion *motion;
   474     QDeclarativeParticlesPainter *paintItem;
   489     QDeclarativeParticlesPainter *paintItem;
   475 
   490 
   476     bool pendingPixmapCache;
       
   477 
   491 
   478     QList<QPair<int, int> > bursts;//countLeft, emissionRate pairs
   492     QList<QPair<int, int> > bursts;//countLeft, emissionRate pairs
   479     QList<QDeclarativeParticle> particles;
   493     QList<QDeclarativeParticle> particles;
   480     TickAnimationProxy<QDeclarativeParticlesPrivate, &QDeclarativeParticlesPrivate::tick> clock;
   494     TickAnimationProxy<QDeclarativeParticlesPrivate, &QDeclarativeParticlesPrivate::tick> clock;
   481 
   495 
   617         break;
   631         break;
   618     }
   632     }
   619 }
   633 }
   620 
   634 
   621 /*!
   635 /*!
   622     \qmlclass Particles
   636     \qmlclass Particles QDeclarativeParticles
   623     \since 4.7
   637     \since 4.7
   624     \brief The Particles object generates and moves particles.
   638     \brief The Particles object generates and moves particles.
   625     \inherits Item
   639     \inherits Item
   626 
   640 
   627     Particles are available in the \bold{Qt.labs.particles 1.0} module.
   641     Particles are available in the \bold{Qt.labs.particles 1.0} module.
   705     d->init();
   719     d->init();
   706 }
   720 }
   707 
   721 
   708 QDeclarativeParticles::~QDeclarativeParticles()
   722 QDeclarativeParticles::~QDeclarativeParticles()
   709 {
   723 {
   710     Q_D(QDeclarativeParticles);
       
   711     if (d->pendingPixmapCache)
       
   712         QDeclarativePixmapCache::cancel(d->url, this);
       
   713 }
   724 }
   714 
   725 
   715 /*!
   726 /*!
   716     \qmlproperty string Particles::source
   727     \qmlproperty string Particles::source
   717     This property holds the URL of the particle image.
   728     This property holds the URL of the particle image.
   728 }
   739 }
   729 
   740 
   730 void QDeclarativeParticles::imageLoaded()
   741 void QDeclarativeParticles::imageLoaded()
   731 {
   742 {
   732     Q_D(QDeclarativeParticles);
   743     Q_D(QDeclarativeParticles);
   733     d->pendingPixmapCache = false;
   744     if (d->image.isError())
   734     QString errorString;
   745         qmlInfo(this) << d->image.error();
   735     if (QDeclarativePixmapCache::get(d->url, &d->image, &errorString)==QDeclarativePixmapReply::Error)
       
   736         qmlInfo(this) << errorString;
       
   737     d->paintItem->updateSize();
   746     d->paintItem->updateSize();
   738     d->paintItem->update();
   747     d->paintItem->update();
   739 }
   748 }
   740 
   749 
   741 void QDeclarativeParticles::setSource(const QUrl &name)
   750 void QDeclarativeParticles::setSource(const QUrl &name)
   743     Q_D(QDeclarativeParticles);
   752     Q_D(QDeclarativeParticles);
   744 
   753 
   745     if ((d->url.isEmpty() == name.isEmpty()) && name == d->url)
   754     if ((d->url.isEmpty() == name.isEmpty()) && name == d->url)
   746         return;
   755         return;
   747 
   756 
   748     if (d->pendingPixmapCache) {
       
   749         QDeclarativePixmapCache::cancel(d->url, this);
       
   750         d->pendingPixmapCache = false;
       
   751     }
       
   752     if (name.isEmpty()) {
   757     if (name.isEmpty()) {
   753         d->url = name;
   758         d->url = name;
   754         d->image = QPixmap();
   759         d->image.clear(this);
   755         d->paintItem->updateSize();
   760         d->paintItem->updateSize();
   756         d->paintItem->update();
   761         d->paintItem->update();
   757     } else {
   762     } else {
   758         d->url = name;
   763         d->url = name;
   759         Q_ASSERT(!name.isRelative());
   764         Q_ASSERT(!name.isRelative());
   760         QString errorString;
   765         d->image.load(qmlEngine(this), d->url);
   761         QDeclarativePixmapReply::Status status = QDeclarativePixmapCache::get(d->url, &d->image, &errorString);
   766         if (d->image.isLoading()) {
   762         if (status != QDeclarativePixmapReply::Ready && status != QDeclarativePixmapReply::Error) {
   767             d->image.connectFinished(this, SLOT(imageLoaded()));
   763             QDeclarativePixmapReply *reply = QDeclarativePixmapCache::request(qmlEngine(this), d->url);
       
   764             connect(reply, SIGNAL(finished()), this, SLOT(imageLoaded()));
       
   765             d->pendingPixmapCache = true;
       
   766         } else {
   768         } else {
   767             if (status == QDeclarativePixmapReply::Error)
   769             if (d->image.isError()) 
   768                 qmlInfo(this) << errorString;
   770                 qmlInfo(this) << d->image.error();
   769             //### unify with imageLoaded
   771             //### unify with imageLoaded
   770             d->paintItem->updateSize();
   772             d->paintItem->updateSize();
   771             d->paintItem->update();
   773             d->paintItem->update();
   772         }
   774         }
   773     }
   775     }
  1241         d->clock.start();
  1243         d->clock.start();
  1242 }
  1244 }
  1243 
  1245 
  1244 void QDeclarativeParticlesPainter::updateSize()
  1246 void QDeclarativeParticlesPainter::updateSize()
  1245 {
  1247 {
  1246     if (!d->_componentComplete)
  1248     if (!d->componentComplete)
  1247         return;
  1249         return;
  1248 
  1250 
  1249     const int parentX = parentItem()->x();
  1251     const int parentX = parentItem()->x();
  1250     const int parentY = parentItem()->y();
  1252     const int parentY = parentItem()->y();
  1251     for (int i = 0; i < d->particles.count(); ++i) {
  1253     for (int i = 0; i < d->particles.count(); ++i) {
  1282         return;
  1284         return;
  1283 
  1285 
  1284     const int myX = x() + parentItem()->x();
  1286     const int myX = x() + parentItem()->x();
  1285     const int myY = y() + parentItem()->y();
  1287     const int myY = y() + parentItem()->y();
  1286 
  1288 
  1287 #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0))
       
  1288     QVarLengthArray<QPainter::PixmapFragment, 256> pixmapData;
  1289     QVarLengthArray<QPainter::PixmapFragment, 256> pixmapData;
  1289 #else
       
  1290     QVarLengthArray<QDrawPixmaps::Data, 256> pixmapData;
       
  1291 #endif
       
  1292     pixmapData.resize(d->particles.count());
  1290     pixmapData.resize(d->particles.count());
  1293 
  1291 
  1294     const QRectF sourceRect = d->image.rect();
  1292     const QRectF sourceRect = d->image.rect();
  1295     qreal halfPWidth = sourceRect.width()/2.;
  1293     qreal halfPWidth = sourceRect.width()/2.;
  1296     qreal halfPHeight = sourceRect.height()/2.;
  1294     qreal halfPHeight = sourceRect.height()/2.;
  1297     for (int i = 0; i < d->particles.count(); ++i) {
  1295     for (int i = 0; i < d->particles.count(); ++i) {
  1298         const QDeclarativeParticle &particle = d->particles.at(i);
  1296         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;
  1297         pixmapData[i].x = particle.x - myX + halfPWidth;
  1301         pixmapData[i].y = particle.y - myY + halfPHeight;
  1298         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;
  1299         pixmapData[i].opacity = particle.opacity;
  1306 
  1300 
  1307         //these never change
  1301         //these never change
  1308         pixmapData[i].rotation = 0;
  1302         pixmapData[i].rotation = 0;
  1309         pixmapData[i].scaleX = 1;
  1303         pixmapData[i].scaleX = 1;
  1310         pixmapData[i].scaleY = 1;
  1304         pixmapData[i].scaleY = 1;
  1311 #if (QT_VERSION >= QT_VERSION_CHECK(4,7,0))
       
  1312         pixmapData[i].sourceLeft = sourceRect.left();
  1305         pixmapData[i].sourceLeft = sourceRect.left();
  1313         pixmapData[i].sourceTop = sourceRect.top();
  1306         pixmapData[i].sourceTop = sourceRect.top();
  1314         pixmapData[i].width = sourceRect.width();
  1307         pixmapData[i].width = sourceRect.width();
  1315         pixmapData[i].height = sourceRect.height();
  1308         pixmapData[i].height = sourceRect.height();
  1316 #else
  1309     }
  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);
  1310     p->drawPixmapFragments(pixmapData.data(), d->particles.count(), d->image);
  1322 #else
       
  1323     qDrawPixmaps(p, pixmapData.data(), d->particles.count(), d->image);
       
  1324 #endif
       
  1325 }
  1311 }
  1326 
  1312 
  1327 void QDeclarativeParticles::componentComplete()
  1313 void QDeclarativeParticles::componentComplete()
  1328 {
  1314 {
  1329     Q_D(QDeclarativeParticles);
  1315     Q_D(QDeclarativeParticles);