summaryrefslogtreecommitdiffstats
path: root/src/imports/particles/followemitter.cpp
blob: ae00e0a2d460dcb9e3cdf2d306b6ab5658e26d6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "followemitter.h"
#include "particle.h"
#include <cmath>
QT_BEGIN_NAMESPACE
FollowEmitter::FollowEmitter(QSGItem *parent) :
    ParticleEmitter(parent)
  , m_particleSize(16)
  , m_particleEndSize(-1)
  , m_particleSizeVariation(0)
  , m_xSpeed(0)
  , m_ySpeed(0)
  , m_xSpeedVariation(0)
  , m_ySpeedVariation(0)
  , m_xAccel(0)
  , m_yAccel(0)
  , m_xAccelVariation(0)
  , m_yAccelVariation(0)
  , m_lastTimeStamp(0)
{
    connect(this, SIGNAL(followChanged(QString)),
            this, SLOT(recalcParticlesPerSecond()));
    connect(this, SIGNAL(particleDurationChanged(int)),
            this, SLOT(recalcParticlesPerSecond()));
    connect(this, SIGNAL(particlesPerParticlePerSecondChanged(int)),
            this, SLOT(recalcParticlesPerSecond()));
}

void FollowEmitter::recalcParticlesPerSecond(){
    if(!m_system)
        return;
    m_followCount = m_system->m_groupData[m_system->m_groupIds[m_follow]]->size;
    if(!m_followCount){
        setParticlesPerSecond(1000);//XXX: Fix this horrendous hack, needed so they aren't turned off from start
    }else{
        setParticlesPerSecond(m_particlesPerParticlePerSecond * m_followCount);
        m_lastEmission.resize(m_followCount);
    }
}

void FollowEmitter::emitWindow(int timeStamp)
{
    if (m_system == 0)
        return;
    if(!m_emitting && !m_burstLeft)
        return;
    if(m_followCount != m_system->m_groupData[m_system->m_groupIds[m_follow]]->size){
        recalcParticlesPerSecond();
        return;//system may need to update
    }

    if(m_burstLeft){
        m_burstLeft -= timeStamp - m_lastTimeStamp * 1000.;
        if(m_burstLeft < 0){
            timeStamp += m_burstLeft;
            m_burstLeft = 0;
        }
    }

    qreal time = timeStamp / 1000.;
    qreal particleRatio = 1. / m_particlesPerParticlePerSecond;
    qreal pt;

    //Have to map it into this system, because particlesystem automaps it back
    QPointF offset = this->mapFromItem(m_system, QPointF(0, 0));
    float sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize;

    int gId = m_system->m_groupIds[m_follow];
    int gId2 = m_system->m_groupIds[m_particle];
    for(int i=0; i<m_system->m_groupData[gId]->size; i++){
        pt = m_lastEmission[i];
        ParticleData* d = m_system->m_data[i + m_system->m_groupData[gId]->start];
        if(!d)
            continue;
        if(pt < d->pv.t)
            pt = d->pv.t;
        if(!QRect(offset.x(), offset.y(), width(), height()).contains(d->curX(), d->curY())){
            m_lastEmission[i] = time;//jump over this time period without emitting, because it's outside
            continue;
        }
        while(pt < time){
            ParticleData* datum = m_system->newDatum(gId2);
            datum->e = this;//###useful?
            ParticleVertex &p = datum->pv;

            // Particle timestamp
            p.t = pt;
            p.lifeSpan =
                    (m_particleDuration
                     + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation))
                    / 1000.0;

            // Particle position
            qreal followT =  pt - d->pv.t;
            qreal followT2 = followT * followT * 0.5;
            qreal sizeOffset = d->pv.size/2;//TODO: Current size
            //TODO: Set variations
//            QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - m_emitterXVariation/2,
//                              d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - m_emitterYVariation/2,
//                              m_emitterXVariation,
//                              m_emitterYVariation);
            QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - sizeOffset,
                              d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - sizeOffset,
                              sizeOffset*2,
                              sizeOffset*2);

            const QPointF &newPos = effectiveExtruder()->extrude(boundsRect);
            p.x = newPos.x();
            p.y = newPos.y();

            // Particle speed
            const QPointF &speed = m_speed->sample(newPos);
            p.sx = speed.x();
            p.sy = speed.y();

            // Particle acceleration
            const QPointF &accel = m_acceleration->sample(newPos);
            p.ax = accel.x();
            p.ay = accel.y();

            // Particle size
            float sizeVariation = -m_particleSizeVariation
                    + rand() / float(RAND_MAX) * m_particleSizeVariation * 2;

            float size = m_particleSize + sizeVariation;
            float endSize = sizeAtEnd + sizeVariation;

            p.size = size * float(m_emitting);
            p.endSize = endSize * float(m_emitting);

            pt += particleRatio;
            m_system->emitParticle(datum);
        }
        m_lastEmission[i] = pt;
    }

    m_lastTimeStamp = time;
}
QT_END_NAMESPACE