void QSGCustomEmitter::emitWindow(int timeStamp) { if (m_system == 0) return; if ((!m_emitting || !m_particlesPerSecond)&& !m_burstLeft && m_burstQueue.isEmpty()){ m_reset_last = true; return; } if (m_reset_last) { m_last_emitter = m_last_last_emitter = QPointF(x(), y()); m_last_timestamp = timeStamp/1000.; m_last_emission = m_last_timestamp; m_reset_last = false; } if (m_burstLeft){ m_burstLeft -= timeStamp - m_last_timestamp * 1000.; if (m_burstLeft < 0){ if (!m_emitting) timeStamp += m_burstLeft; m_burstLeft = 0; } } qreal time = timeStamp / 1000.; qreal particleRatio = 1. / m_particlesPerSecond; qreal pt = m_last_emission; qreal opt = pt; // original particle time qreal dt = time - m_last_timestamp; // timestamp delta... if (!dt) dt = 0.000001; // emitter difference since last... qreal dex = (x() - m_last_emitter.x()); qreal dey = (y() - m_last_emitter.y()); qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; qreal emitter_x_offset = m_last_emitter.x() - x(); qreal emitter_y_offset = m_last_emitter.y() - y(); if (!m_burstQueue.isEmpty() && !m_burstLeft && !m_emitting)//'outside time' emissions only pt = time; while (pt < time || !m_burstQueue.isEmpty()) { //int pos = m_last_particle % m_particle_count; QSGParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]); if (datum){//actually emit(otherwise we've been asked to skip this one) datum->e = this;//###useful? qreal t = 1 - (pt - opt) / dt; // Particle timestamp datum->t = pt; datum->lifeSpan = //TODO:Promote to base class? (m_particleDuration + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) / 1000.0; // Particle position QRectF boundsRect; if (!m_burstQueue.isEmpty()){ boundsRect = QRectF(m_burstQueue.first().second.x() - x(), m_burstQueue.first().second.y() - y(), width(), height()); } else { boundsRect = QRectF(emitter_x_offset + dex * (pt - opt) / dt, emitter_y_offset + dey * (pt - opt) / dt , width(), height()); } QPointF newPos = effectiveExtruder()->extrude(boundsRect); datum->x = newPos.x(); datum->y = newPos.y(); // Particle speed const QPointF &speed = m_speed->sample(newPos); datum->vx = speed.x(); datum->vy = speed.y(); // Particle acceleration const QPointF &accel = m_acceleration->sample(newPos); datum->ax = accel.x(); datum->ay = accel.y(); // Particle size float sizeVariation = -m_particleSizeVariation + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; float size = qMax((qreal)0.0 , m_particleSize + sizeVariation); float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation); datum->size = size; datum->endSize = endSize; emitParticle(datum->v8Value());//A chance for arbitrary JS changes m_system->emitParticle(datum); } if (m_burstQueue.isEmpty()){ pt += particleRatio; }else{ m_burstQueue.first().first--; if (m_burstQueue.first().first <= 0) m_burstQueue.pop_front(); } } m_last_emission = pt; m_last_last_last_emitter = m_last_last_emitter; m_last_last_emitter = m_last_emitter; m_last_emitter = QPointF(x(), y()); m_last_timestamp = time; }
void QQuickTrailEmitter::emitWindow(int timeStamp) { if (m_system == 0) return; if (!m_enabled && !m_pulseLeft && m_burstQueue.isEmpty()) return; if (m_followCount != m_system->groupData[m_system->groupIds[m_follow]]->size()){ qreal oldPPS = m_particlesPerSecond; recalcParticlesPerSecond(); if (m_particlesPerSecond != oldPPS) return;//system may need to update } if (m_pulseLeft){ m_pulseLeft -= timeStamp - m_lastTimeStamp * 1000.; if (m_pulseLeft < 0){ timeStamp += m_pulseLeft; m_pulseLeft = 0; } } //TODO: Implement startTime and velocityFromMovement qreal time = timeStamp / 1000.; qreal particleRatio = 1. / m_particlesPerParticlePerSecond; qreal pt; qreal maxLife = (m_particleDuration + m_particleDurationVariation)/1000.0; //Have to map it into this system, because particlesystem automaps it back QPointF offset = m_system->mapFromItem(this, QPointF(0, 0)); qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; int gId = m_system->groupIds[m_follow]; int gId2 = m_system->groupIds[m_group]; for (int i=0; i<m_system->groupData[gId]->data.count(); i++) { QQuickParticleData *d = m_system->groupData[gId]->data[i]; if (!d->stillAlive()){ m_lastEmission[i] = time; //Should only start emitting when it returns to life continue; } pt = m_lastEmission[i]; if (pt < d->t) pt = d->t; if (pt + maxLife < time)//We missed so much, that we should skip emiting particles that are dead by now pt = time - maxLife; if ((width() || height()) && !effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){ m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside continue; } QList<QQuickParticleData*> toEmit; while (pt < time || !m_burstQueue.isEmpty()){ QQuickParticleData* datum = m_system->newDatum(gId2, !m_overwrite); if (datum){//else, skip this emission datum->e = this;//###useful? // Particle timestamp datum->t = pt; datum->lifeSpan = (m_particleDuration + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) / 1000.0; // Particle position // Note that burst location doesn't get used for follow emitter qreal followT = pt - d->t; qreal followT2 = followT * followT * 0.5; qreal eW = m_emitterXVariation < 0 ? d->curSize() : m_emitterXVariation; qreal eH = m_emitterYVariation < 0 ? d->curSize() : m_emitterYVariation; //Subtract offset, because PS expects this in emitter coordinates QRectF boundsRect(d->x - offset.x() + d->vx * followT + d->ax * followT2 - eW/2, d->y - offset.y() + d->vy * followT + d->ay * followT2 - eH/2, eW, eH); QQuickParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder; const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect); datum->x = newPos.x(); datum->y = newPos.y(); // Particle velocity const QPointF &velocity = m_velocity->sample(newPos); datum->vx = velocity.x() + m_velocity_from_movement * d->vx; datum->vy = velocity.y() + m_velocity_from_movement * d->vy; // Particle acceleration const QPointF &accel = m_acceleration->sample(newPos); datum->ax = accel.x(); datum->ay = accel.y(); // Particle size float sizeVariation = -m_particleSizeVariation + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; float size = qMax((qreal)0.0, m_particleSize + sizeVariation); float endSize = qMax((qreal)0.0, sizeAtEnd + sizeVariation); datum->size = size * float(m_enabled); datum->endSize = endSize * float(m_enabled); toEmit << datum; m_system->emitParticle(datum); } if (!m_burstQueue.isEmpty()){ m_burstQueue.first().first--; if (m_burstQueue.first().first <= 0) m_burstQueue.pop_front(); }else{ pt += particleRatio; } } foreach (QQuickParticleData* d, toEmit) m_system->emitParticle(d); if (isEmitConnected() || isEmitFollowConnected()) { v8::HandleScope handle_scope; v8::Context::Scope scope(QQmlEnginePrivate::getV8Engine(qmlEngine(this))->context()); v8::Handle<v8::Array> array = v8::Array::New(toEmit.size()); for (int i=0; i<toEmit.size(); i++) array->Set(i, toEmit[i]->v8Value().toHandle()); if (isEmitFollowConnected()) emitFollowParticles(QQmlV8Handle::fromHandle(array), d->v8Value());//A chance for many arbitrary JS changes else if (isEmitConnected()) emitParticles(QQmlV8Handle::fromHandle(array));//A chance for arbitrary JS changes } m_lastEmission[d->index] = pt; } m_lastTimeStamp = time; }