819dd128fa9d1c9b498e615df0b8cacf83b92890
[profile/ivi/qtdeclarative.git] / src / particles / qquickcustomaffector.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQuick module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickcustomaffector_p.h"
43 #include <private/qv8engine_p.h>
44 #include <private/qqmlengine_p.h>
45 #include <private/qqmlglobal_p.h>
46 #include <QQmlEngine>
47 #include <QDebug>
48 QT_BEGIN_NAMESPACE
49
50 //TODO: Move docs (and inheritence) to real base when docs can propagate. Currently this pretends to be the base class!
51 /*!
52     \qmlsignal QtQuick.Particles2::Affector::affectParticles(Array particles, real dt)
53
54     This handler is called when particles are selected to be affected. particles contains
55     an array of particle objects which can be directly manipulated.
56
57     dt is the time since the last time it was affected. Use dt to normalize
58     trajectory manipulations to real time.
59
60     Note that JS is slower to execute, so it is not recommended to use this in
61     high-volume particle systems.
62 */
63
64 /*!
65     \qmlproperty StochasticDirection QtQuick.Particles2::Affector::position
66
67     Affected particles will have their position set to this direction,
68     relative to the ParticleSystem. When interpreting directions as points,
69     imagine it as an arrow with the base at the 0,0 of the ParticleSystem and the
70     tip at where the specified position will be.
71 */
72
73 /*!
74     \qmlproperty StochasticDirection QtQuick.Particles2::Affector::speed
75
76     Affected particles will have their speed set to this direction.
77 */
78
79
80 /*!
81     \qmlproperty StochasticDirection QtQuick.Particles2::Affector::acceleration
82
83     Affected particles will have their acceleration set to this direction.
84 */
85
86
87 /*!
88     \qmlproperty bool QtQuick.Particles2::Affector::relative
89
90     Whether the affected particles have their existing position/speed/acceleration added
91     to the new one.
92
93     Default is true.
94 */
95 QQuickCustomAffector::QQuickCustomAffector(QQuickItem *parent) :
96     QQuickParticleAffector(parent)
97     , m_position(&m_nullVector)
98     , m_speed(&m_nullVector)
99     , m_acceleration(&m_nullVector)
100     , m_relative(true)
101 {
102 }
103
104 bool QQuickCustomAffector::isAffectConnected()
105 {
106     IS_SIGNAL_CONNECTED(this, QQuickCustomAffector, affectParticles, (QQmlV8Handle,qreal));
107 }
108
109 void QQuickCustomAffector::affectSystem(qreal dt)
110 {
111     //Acts a bit differently, just emits affected for everyone it might affect, when the only thing is connecting to affected(x,y)
112     bool justAffected = (m_acceleration == &m_nullVector
113         && m_speed == &m_nullVector
114         && m_position == &m_nullVector
115         && isAffectedConnected());
116     if (!isAffectConnected() && !justAffected) {
117         QQuickParticleAffector::affectSystem(dt);
118         return;
119     }
120     if (!m_enabled)
121         return;
122     updateOffsets();
123
124     QList<QQuickParticleData*> toAffect;
125     foreach (QQuickParticleGroupData* gd, m_system->groupData)
126         if (activeGroup(m_system->groupData.key(gd)))
127             foreach (QQuickParticleData* d, gd->data)
128                 if (shouldAffect(d))
129                     toAffect << d;
130
131     if (toAffect.isEmpty())
132         return;
133
134     if (justAffected) {
135         foreach (QQuickParticleData* d, toAffect) {//Not postAffect to avoid saying the particle changed
136             if (m_onceOff)
137                 m_onceOffed << qMakePair(d->group, d->index);
138             emit affected(d->curX(), d->curY());
139         }
140         return;
141     }
142
143     if (m_onceOff)
144         dt = 1.0;
145
146     v8::HandleScope handle_scope;
147     v8::Context::Scope scope(QQmlEnginePrivate::getV8Engine(qmlEngine(this))->context());
148     v8::Handle<v8::Array> array = v8::Array::New(toAffect.size());
149     for (int i=0; i<toAffect.size(); i++)
150         array->Set(i, toAffect[i]->v8Value().toHandle());
151
152     if (dt >= simulationCutoff || dt <= simulationDelta) {
153         affectProperties(toAffect, dt);
154         emit affectParticles(QQmlV8Handle::fromHandle(array), dt);
155     } else {
156         int realTime = m_system->timeInt;
157         m_system->timeInt -= dt * 1000.0;
158         while (dt > simulationDelta) {
159             m_system->timeInt += simulationDelta * 1000.0;
160             dt -= simulationDelta;
161             affectProperties(toAffect, simulationDelta);
162             emit affectParticles(QQmlV8Handle::fromHandle(array), simulationDelta);
163         }
164         m_system->timeInt = realTime;
165         if (dt > 0.0) {
166             affectProperties(toAffect, dt);
167             emit affectParticles(QQmlV8Handle::fromHandle(array), dt);
168         }
169     }
170
171     foreach (QQuickParticleData* d, toAffect)
172         if (d->update == 1.0)
173             postAffect(d);
174 }
175
176 bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt)
177 {
178     //This does the property based affecting, called by superclass if signal isn't hooked up.
179     bool changed = false;
180     QPointF curPos(d->curX(), d->curY());
181
182     if (m_acceleration != &m_nullVector){
183         QPointF pos = m_acceleration->sample(curPos);
184         QPointF curAcc = QPointF(d->curAX(), d->curAY());
185         if (m_relative) {
186             pos *= dt;
187             pos += curAcc;
188         }
189         if (pos != curAcc) {
190             d->setInstantaneousAX(pos.x());
191             d->setInstantaneousAY(pos.y());
192             changed = true;
193         }
194     }
195
196     if (m_speed != &m_nullVector){
197         QPointF pos = m_speed->sample(curPos);
198         QPointF curVel = QPointF(d->curVX(), d->curVY());
199         if (m_relative) {
200             pos *= dt;
201             pos += curVel;
202         }
203         if (pos != curVel) {
204             d->setInstantaneousVX(pos.x());
205             d->setInstantaneousVY(pos.y());
206             changed = true;
207         }
208     }
209
210     if (m_position != &m_nullVector){
211         QPointF pos = m_position->sample(curPos);
212         if (m_relative) {
213             pos *= dt;
214             pos += curPos;
215         }
216         if (pos != curPos) {
217             d->setInstantaneousX(pos.x());
218             d->setInstantaneousY(pos.y());
219             changed = true;
220         }
221     }
222
223     return changed;
224 }
225
226 void QQuickCustomAffector::affectProperties(const QList<QQuickParticleData*> particles, qreal dt)
227 {
228     foreach (QQuickParticleData* d, particles)
229         if ( affectParticle(d, dt) )
230             d->update = 1.0;
231 }
232
233 QT_END_NAMESPACE