1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickcustomaffector_p.h"
41#include <private/qqmlengine_p.h>
42#include <private/qqmlglobal_p.h>
43#include <private/qjsvalue_p.h>
44#include <QQmlEngine>
45#include <QDebug>
46QT_BEGIN_NAMESPACE
47
48//TODO: Move docs (and inheritence) to real base when docs can propagate. Currently this pretends to be the base class!
49/*!
50 \qmlsignal QtQuick.Particles::Affector::affectParticles(Array particles, real dt)
51
52 This signal is emitted when particles are selected to be affected. particles contains
53 an array of particle objects which can be directly manipulated.
54
55 dt is the time since the last time it was affected. Use dt to normalize
56 trajectory manipulations to real time.
57
58 Note that JavaScript is slower to execute, so it is not recommended to use this in
59 high-volume particle systems.
60*/
61
62/*!
63 \qmlproperty StochasticDirection QtQuick.Particles::Affector::position
64
65 Affected particles will have their position set to this direction,
66 relative to the ParticleSystem. When interpreting directions as points,
67 imagine it as an arrow with the base at the 0,0 of the ParticleSystem and the
68 tip at where the specified position will be.
69*/
70
71/*!
72 \qmlproperty StochasticDirection QtQuick.Particles::Affector::velocity
73
74 Affected particles will have their velocity set to this direction.
75*/
76
77
78/*!
79 \qmlproperty StochasticDirection QtQuick.Particles::Affector::acceleration
80
81 Affected particles will have their acceleration set to this direction.
82*/
83
84
85/*!
86 \qmlproperty bool QtQuick.Particles::Affector::relative
87
88 Whether the affected particles have their existing position/velocity/acceleration added
89 to the new one.
90
91 Default is true.
92*/
93QQuickCustomAffector::QQuickCustomAffector(QQuickItem *parent) :
94 QQuickParticleAffector(parent)
95 , m_position(&m_nullVector)
96 , m_velocity(&m_nullVector)
97 , m_acceleration(&m_nullVector)
98 , m_relative(true)
99{
100}
101
102bool QQuickCustomAffector::isAffectConnected()
103{
104 IS_SIGNAL_CONNECTED(this, QQuickCustomAffector, affectParticles, (const QJSValue &, qreal));
105}
106
107void QQuickCustomAffector::affectSystem(qreal dt)
108{
109 //Acts a bit differently, just emits affected for everyone it might affect, when the only thing is connecting to affected(x,y)
110 bool justAffected = (m_acceleration == &m_nullVector
111 && m_velocity == &m_nullVector
112 && m_position == &m_nullVector
113 && isAffectedConnected());
114 if (!isAffectConnected() && !justAffected) {
115 QQuickParticleAffector::affectSystem(dt);
116 return;
117 }
118 if (!m_enabled)
119 return;
120 updateOffsets();
121
122 QList<QQuickParticleData*> toAffect;
123 foreach (QQuickParticleGroupData* gd, m_system->groupData) {
124 if (activeGroup(g: gd->index)) {
125 foreach (QQuickParticleData* d, gd->data) {
126 if (shouldAffect(datum: d)) {
127 toAffect << d;
128 }
129 }
130 }
131 }
132
133 if (toAffect.isEmpty())
134 return;
135
136 if (justAffected) {
137 foreach (QQuickParticleData* d, toAffect) {//Not postAffect to avoid saying the particle changed
138 if (m_onceOff)
139 m_onceOffed << qMakePair(x: d->groupId, y: d->index);
140 emit affected(x: d->curX(particleSystem: m_system), y: d->curY(particleSystem: m_system));
141 }
142 return;
143 }
144
145 if (m_onceOff)
146 dt = 1.0;
147
148 QQmlEngine *qmlEngine = ::qmlEngine(this);
149 QV4::ExecutionEngine *v4 = qmlEngine->handle();
150
151 QV4::Scope scope(v4);
152 QV4::ScopedArrayObject array(scope, v4->newArrayObject(count: toAffect.size()));
153 QV4::ScopedValue v(scope);
154 for (int i=0; i<toAffect.size(); i++)
155 array->put(idx: i, v: (v = toAffect[i]->v4Value(particleSystem: m_system)));
156
157 const auto doAffect = [&](qreal dt) {
158 affectProperties(particles: toAffect, dt);
159 QJSValue particles;
160 QJSValuePrivate::setValue(jsval: &particles, engine: v4, v: array);
161 emit affectParticles(particles, dt);
162 };
163
164 if (dt >= simulationCutoff || dt <= simulationDelta) {
165 doAffect(dt);
166 } else {
167 int realTime = m_system->timeInt;
168 m_system->timeInt -= dt * 1000.0;
169 while (dt > simulationDelta) {
170 m_system->timeInt += simulationDelta * 1000.0;
171 dt -= simulationDelta;
172 doAffect(simulationDelta);
173 }
174 m_system->timeInt = realTime;
175 if (dt > 0.0)
176 doAffect(dt);
177 }
178
179 foreach (QQuickParticleData* d, toAffect)
180 if (d->update == 1.0)
181 postAffect(datum: d);
182}
183
184bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt)
185{
186 //This does the property based affecting, called by superclass if signal isn't hooked up.
187 bool changed = false;
188 QPointF curPos(d->curX(particleSystem: m_system), d->curY(particleSystem: m_system));
189
190 if (m_acceleration != &m_nullVector){
191 QPointF pos = m_acceleration->sample(from: curPos);
192 QPointF curAcc = QPointF(d->curAX(), d->curAY());
193 if (m_relative) {
194 pos *= dt;
195 pos += curAcc;
196 }
197 if (pos != curAcc) {
198 d->setInstantaneousAX(ax: pos.x(), particleSystem: m_system);
199 d->setInstantaneousAY(ay: pos.y(), particleSystem: m_system);
200 changed = true;
201 }
202 }
203
204 if (m_velocity != &m_nullVector){
205 QPointF pos = m_velocity->sample(from: curPos);
206 QPointF curVel = QPointF(d->curVX(particleSystem: m_system), d->curVY(particleSystem: m_system));
207 if (m_relative) {
208 pos *= dt;
209 pos += curVel;
210 }
211 if (pos != curVel) {
212 d->setInstantaneousVX(vx: pos.x(), particleSystem: m_system);
213 d->setInstantaneousVY(vy: pos.y(), particleSystem: m_system);
214 changed = true;
215 }
216 }
217
218 if (m_position != &m_nullVector){
219 QPointF pos = m_position->sample(from: curPos);
220 if (m_relative) {
221 pos *= dt;
222 pos += curPos;
223 }
224 if (pos != curPos) {
225 d->setInstantaneousX(x: pos.x(), particleSystem: m_system);
226 d->setInstantaneousY(y: pos.y(), particleSystem: m_system);
227 changed = true;
228 }
229 }
230
231 return changed;
232}
233
234void QQuickCustomAffector::affectProperties(const QList<QQuickParticleData*> &particles, qreal dt)
235{
236 foreach (QQuickParticleData* d, particles)
237 if ( affectParticle(d, dt) )
238 d->update = 1.0;
239}
240
241QT_END_NAMESPACE
242
243#include "moc_qquickcustomaffector_p.cpp"
244

source code of qtdeclarative/src/particles/qquickcustomaffector.cpp