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 <math.h>
41#include "qquickv4particledata_p.h"
42#include "qquickparticlesystem_p.h"//for QQuickParticleData
43#include <QDebug>
44#include <private/qv4engine_p.h>
45#include <private/qv4functionobject_p.h>
46#include <QtCore/private/qnumeric_p.h>
47
48QT_BEGIN_NAMESPACE
49
50/*!
51 \qmltype Particle
52 \inqmlmodule QtQuick.Particles
53 \brief Represents particles manipulated by emitters and affectors.
54 \ingroup qtquick-particles
55
56 Particle elements are always managed internally by the ParticleSystem and cannot be created in QML.
57 However, sometimes they are exposed via signals so as to allow arbitrary changes to the particle state
58*/
59
60/*!
61 \qmlproperty real QtQuick.Particles::Particle::initialX
62 The x coordinate of the particle at the beginning of its lifetime.
63
64 The method of simulation prefers to have the initial values changed, rather
65 than determining and changing the value at a given time. Change initial
66 values in CustomEmitters instead of the current values.
67*/
68
69/*!
70 \qmlproperty real QtQuick.Particles::Particle::initialVX
71 The x velocity of the particle at the beginning of its lifetime.
72
73 The method of simulation prefers to have the initial values changed, rather
74 than determining and changing the value at a given time. Change initial
75 values in CustomEmitters instead of the current values.
76*/
77
78/*!
79 \qmlproperty real QtQuick.Particles::Particle::initialAX
80 The x acceleration of the particle at the beginning of its lifetime.
81
82 The method of simulation prefers to have the initial values changed, rather
83 than determining and changing the value at a given time. Change initial
84 values in CustomEmitters instead of the current values.
85*/
86
87/*!
88 \qmlproperty real QtQuick.Particles::Particle::initialY
89 The y coordinate of the particle at the beginning of its lifetime.
90
91 The method of simulation prefers to have the initial values changed, rather
92 than determining and changing the value at a given time. Change initial
93 values in CustomEmitters instead of the current values.
94*/
95
96/*!
97 \qmlproperty real QtQuick.Particles::Particle::initialVY
98 The y velocity of the particle at the beginning of its lifetime.
99
100 The method of simulation prefers to have the initial values changed, rather
101 than determining and changing the value at a given time. Change initial
102 values in CustomEmitters instead of the current values.
103*/
104
105/*!
106 \qmlproperty real QtQuick.Particles::Particle::initialAY
107 The y acceleration of the particle at the beginning of its lifetime.
108
109 The method of simulation prefers to have the initial values changed, rather
110 than determining and changing the value at a given time. Change initial
111 values in CustomEmitters instead of the current values.
112*/
113
114/*!
115 \qmlproperty real QtQuick.Particles::Particle::x
116 The current x coordinate of the particle.
117*/
118
119/*!
120 \qmlproperty real QtQuick.Particles::Particle::vx
121 The current x velocity of the particle.
122*/
123
124/*!
125 \qmlproperty real QtQuick.Particles::Particle::ax
126 The current x acceleration of the particle.
127*/
128
129/*!
130 \qmlproperty real QtQuick.Particles::Particle::y
131 The current y coordinate of the particle.
132*/
133
134/*!
135 \qmlproperty real QtQuick.Particles::Particle::vy
136 The current y velocity of the particle.
137*/
138
139/*!
140 \qmlproperty real QtQuick.Particles::Particle::ay
141 The current y acceleration of the particle.
142*/
143
144/*!
145 \qmlproperty real QtQuick.Particles::Particle::t
146 The time, in seconds since the beginning of the simulation, that the particle was born.
147*/
148
149
150/*!
151 \qmlproperty real QtQuick.Particles::Particle::startSize
152 The size in pixels that the particle image is at the start
153 of its life.
154*/
155
156
157/*!
158 \qmlproperty real QtQuick.Particles::Particle::endSize
159 The size in pixels that the particle image is at the end
160 of its life. If this value is less than 0, then it is
161 disregarded and the particle will have its startSize for the
162 entire lifetime.
163*/
164
165/*!
166 \qmlproperty real QtQuick.Particles::Particle::lifeSpan
167 The time in seconds that the particle will live for.
168*/
169
170/*!
171 \qmlproperty real QtQuick.Particles::Particle::rotation
172 Degrees clockwise that the particle image is rotated at
173 the beginning of its life.
174*/
175
176/*!
177 \qmlproperty real QtQuick.Particles::Particle::rotationVelocity
178 Degrees clockwise per second that the particle image is rotated at while alive.
179*/
180/*!
181 \qmlproperty bool QtQuick.Particles::Particle::autoRotate
182 If autoRotate is true, then the particle's rotation will be
183 set so that it faces the direction of travel, plus any
184 rotation from the rotation or rotationVelocity properties.
185*/
186
187/*!
188 \qmlproperty bool QtQuick.Particles::Particle::update
189
190 Inside an Affector, the changes made to the particle will only be
191 applied if update is set to true.
192*/
193/*!
194 \qmlproperty real QtQuick.Particles::Particle::xDeformationVectorX
195
196 The x component of the deformation vector along the X axis. ImageParticle
197 can draw particles across non-square shapes. It will draw the texture rectangle
198 across the parallelogram drawn with the x and y deformation vectors.
199*/
200
201/*!
202 \qmlproperty real QtQuick.Particles::Particle::yDeformationVectorX
203
204 The y component of the deformation vector along the X axis. ImageParticle
205 can draw particles across non-square shapes. It will draw the texture rectangle
206 across the parallelogram drawn with the x and y deformation vectors.
207*/
208
209/*!
210 \qmlproperty real QtQuick.Particles::Particle::xDeformationVectorY
211
212 The x component of the deformation vector along the X axis. ImageParticle
213 can draw particles across non-square shapes. It will draw the texture rectangle
214 across the parallelogram drawn with the x and y deformation vectors.
215*/
216
217/*!
218 \qmlproperty real QtQuick.Particles::Particle::yDeformationVectorY
219
220 The y component of the deformation vector along the Y axis. ImageParticle
221 can draw particles across non-square shapes. It will draw the texture rectangle
222 across the parallelogram drawn with the x and y deformation vectors.
223*/
224
225/*!
226 \qmlproperty real QtQuick.Particles::Particle::red
227
228 ImageParticle can draw colorized particles. When it does so, red is used
229 as the red channel of the color applied to the source image.
230
231 Values are from 0.0 to 1.0.
232*/
233
234/*!
235 \qmlproperty real QtQuick.Particles::Particle::green
236
237 ImageParticle can draw colorized particles. When it does so, green is used
238 as the green channel of the color applied to the source image.
239
240 Values are from 0.0 to 1.0.
241*/
242
243/*!
244 \qmlproperty real QtQuick.Particles::Particle::blue
245
246 ImageParticle can draw colorized particles. When it does so, blue is used
247 as the blue channel of the color applied to the source image.
248
249 Values are from 0.0 to 1.0.
250*/
251
252/*!
253 \qmlproperty real QtQuick.Particles::Particle::alpha
254
255 ImageParticle can draw colorized particles. When it does so, alpha is used
256 as the alpha channel of the color applied to the source image.
257
258 Values are from 0.0 to 1.0.
259*/
260/*!
261 \qmlproperty real QtQuick.Particles::Particle::lifeLeft
262 The time in seconds that the particle has left to live at
263 the current point in time.
264*/
265/*!
266 \qmlproperty real QtQuick.Particles::Particle::currentSize
267 The currentSize of the particle, interpolating between startSize and endSize based on the currentTime.
268*/
269
270namespace QV4 {
271namespace Heap {
272struct QV4ParticleData : QV4::Object::Data {
273 void init(QQuickParticleData *datum, QQuickParticleSystem* particleSystem)
274 {
275 Object::init();
276 this->datum = datum;
277 this->particleSystem = particleSystem;
278 }
279 QQuickParticleData* datum;//TODO: Guard needed?
280 QQuickParticleSystem* particleSystem;
281};
282}
283}
284
285//### Particle data handles are not locked to within certain scopes like QQuickContext2D, but there's no way to reload either...
286struct QV4ParticleData : public QV4::Object
287{
288 V4_OBJECT2(QV4ParticleData, QV4::Object)
289};
290
291DEFINE_OBJECT_VTABLE(QV4ParticleData);
292
293class QV4ParticleDataDeletable : public QV4::ExecutionEngine::Deletable
294{
295public:
296 QV4ParticleDataDeletable(QV4::ExecutionEngine *engine);
297 ~QV4ParticleDataDeletable() override;
298
299 QV4::PersistentValue proto;
300};
301
302static QV4::ReturnedValue particleData_discard(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
303{
304 QV4::Scope scope(b);
305 QV4::Scoped<QV4ParticleData> r(scope, *thisObject);
306
307 if (!r || !r->d()->datum)
308 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));
309
310 r->d()->datum->lifeSpan = 0; //Don't kill(), because it could still be in the middle of being created
311 RETURN_RESULT(QV4::Encode::undefined());
312}
313
314static QV4::ReturnedValue particleData_lifeLeft(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
315{
316 QV4::Scope scope(b);
317 QV4::Scoped<QV4ParticleData> r(scope, *thisObject);
318
319 if (!r || !r->d()->datum)
320 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));
321
322 RETURN_RESULT(QV4::Encode(r->d()->datum->lifeLeft(r->d()->particleSystem)));
323}
324
325static QV4::ReturnedValue particleData_curSize(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int)
326{
327 QV4::Scope scope(b);
328 QV4::Scoped<QV4ParticleData> r(scope, *thisObject);
329
330 if (!r || !r->d()->datum)
331 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));
332
333 RETURN_RESULT(QV4::Encode(r->d()->datum->curSize(r->d()->particleSystem)));
334}
335#define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) \
336{ \
337 QV4::Scope scope(b); \
338 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
339 if (!r || !r->d()->datum) \
340 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \
341\
342 RETURN_RESULT(QV4::Encode((r->d()->datum->color. VAR )/255.0));\
343}\
344\
345static QV4::ReturnedValue particleData_set_ ## NAME (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)\
346{\
347 QV4::Scope scope(b); \
348 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
349 if (!r || !r->d()->datum)\
350 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\
351\
352 double d = argc ? argv[0].toNumber() : 0; \
353 r->d()->datum->color. VAR = qMin(255, qMax(0, (int)::floor(d * 255.0)));\
354 RETURN_UNDEFINED(); \
355}
356
357
358#define SEMIBOOL_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) \
359{ \
360 QV4::Scope scope(b); \
361 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
362 if (!r || !r->d()->datum) \
363 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \
364\
365 RETURN_RESULT(QV4::Encode(r->d()->datum-> VARIABLE));\
366}\
367\
368static QV4::ReturnedValue particleData_set_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)\
369{\
370 QV4::Scope scope(b); \
371 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
372 if (!r || !r->d()->datum)\
373 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\
374\
375 r->d()->datum-> VARIABLE = (argc && argv[0].toBoolean()) ? 1.0 : 0.0;\
376 RETURN_UNDEFINED(); \
377}
378
379#define FLOAT_GETTER_AND_SETTER(VARIABLE) static QV4::ReturnedValue particleData_get_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) \
380{ \
381 QV4::Scope scope(b); \
382 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
383 if (!r || !r->d()->datum) \
384 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \
385\
386 RETURN_RESULT(QV4::Encode(r->d()->datum-> VARIABLE));\
387}\
388\
389static QV4::ReturnedValue particleData_set_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)\
390{\
391 QV4::Scope scope(b); \
392 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
393 if (!r || !r->d()->datum)\
394 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\
395\
396 r->d()->datum-> VARIABLE = argc ? argv[0].toNumber() : qt_qnan();\
397 RETURN_UNDEFINED(); \
398}
399
400#define FAKE_FLOAT_GETTER_AND_SETTER(VARIABLE, GETTER, SETTER) static QV4::ReturnedValue particleData_get_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *, int) \
401{ \
402 QV4::Scope scope(b); \
403 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
404 if (!r || !r->d()->datum) \
405 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object"))); \
406\
407 RETURN_RESULT(QV4::Encode(r->d()->datum-> GETTER (r->d()->particleSystem)));\
408}\
409\
410static QV4::ReturnedValue particleData_set_ ## VARIABLE (const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)\
411{\
412 QV4::Scope scope(b); \
413 QV4::Scoped<QV4ParticleData> r(scope, *thisObject); \
414 if (!r || !r->d()->datum)\
415 RETURN_RESULT(scope.engine->throwError(QStringLiteral("Not a valid ParticleData object")));\
416\
417 r->d()->datum-> SETTER (argc ? argv[0].toNumber() : qt_qnan(), r->d()->particleSystem);\
418 RETURN_UNDEFINED(); \
419}
420
421#define REGISTER_ACCESSOR(PROTO, ENGINE, VARIABLE, NAME) \
422 PROTO ->defineAccessorProperty( QStringLiteral( #NAME ), particleData_get_ ## VARIABLE , particleData_set_ ## VARIABLE )
423
424COLOR_GETTER_AND_SETTER(r, red)
425COLOR_GETTER_AND_SETTER(g, green)
426COLOR_GETTER_AND_SETTER(b, blue)
427COLOR_GETTER_AND_SETTER(a, alpha)
428SEMIBOOL_GETTER_AND_SETTER(autoRotate)
429SEMIBOOL_GETTER_AND_SETTER(update)
430FLOAT_GETTER_AND_SETTER(x)
431FLOAT_GETTER_AND_SETTER(y)
432FLOAT_GETTER_AND_SETTER(t)
433FLOAT_GETTER_AND_SETTER(lifeSpan)
434FLOAT_GETTER_AND_SETTER(size)
435FLOAT_GETTER_AND_SETTER(endSize)
436FLOAT_GETTER_AND_SETTER(vx)
437FLOAT_GETTER_AND_SETTER(vy)
438FLOAT_GETTER_AND_SETTER(ax)
439FLOAT_GETTER_AND_SETTER(ay)
440FLOAT_GETTER_AND_SETTER(xx)
441FLOAT_GETTER_AND_SETTER(xy)
442FLOAT_GETTER_AND_SETTER(yx)
443FLOAT_GETTER_AND_SETTER(yy)
444FLOAT_GETTER_AND_SETTER(rotation)
445FLOAT_GETTER_AND_SETTER(rotationVelocity)
446FLOAT_GETTER_AND_SETTER(animIdx)
447FLOAT_GETTER_AND_SETTER(frameDuration)
448FLOAT_GETTER_AND_SETTER(frameAt)
449FLOAT_GETTER_AND_SETTER(frameCount)
450FLOAT_GETTER_AND_SETTER(animT)
451FLOAT_GETTER_AND_SETTER(r)
452FAKE_FLOAT_GETTER_AND_SETTER(curX, curX, setInstantaneousX)
453FAKE_FLOAT_GETTER_AND_SETTER(curVX, curVX, setInstantaneousVX)
454FAKE_FLOAT_GETTER_AND_SETTER(curAX, curAX, setInstantaneousAX)
455FAKE_FLOAT_GETTER_AND_SETTER(curY, curY, setInstantaneousY)
456FAKE_FLOAT_GETTER_AND_SETTER(curVY, curVY, setInstantaneousVY)
457FAKE_FLOAT_GETTER_AND_SETTER(curAY, curAY, setInstantaneousAY)
458
459QV4ParticleDataDeletable::QV4ParticleDataDeletable(QV4::ExecutionEngine *v4)
460{
461 QV4::Scope scope(v4);
462 QV4::ScopedObject p(scope, v4->newObject());
463
464 p->defineDefaultProperty(QStringLiteral("discard"), code: particleData_discard);
465 p->defineDefaultProperty(QStringLiteral("lifeLeft"), code: particleData_lifeLeft);
466 p->defineDefaultProperty(QStringLiteral("currentSize"), code: particleData_curSize);
467
468 REGISTER_ACCESSOR(p, v4, x, initialX);
469 REGISTER_ACCESSOR(p, v4, y, initialY);
470 REGISTER_ACCESSOR(p, v4, t, t);
471 REGISTER_ACCESSOR(p, v4, lifeSpan, lifeSpan);
472 REGISTER_ACCESSOR(p, v4, size, startSize);
473 REGISTER_ACCESSOR(p, v4, endSize, endSize);
474 REGISTER_ACCESSOR(p, v4, vx, initialVX);
475 REGISTER_ACCESSOR(p, v4, vy, initialVY);
476 REGISTER_ACCESSOR(p, v4, ax, initialAX);
477 REGISTER_ACCESSOR(p, v4, ay, initialAY);
478 REGISTER_ACCESSOR(p, v4, xx, xDeformationVectorX);
479 REGISTER_ACCESSOR(p, v4, xy, xDeformationVectorY);
480 REGISTER_ACCESSOR(p, v4, yx, yDeformationVectorX);
481 REGISTER_ACCESSOR(p, v4, yy, yDeformationVectorY);
482 REGISTER_ACCESSOR(p, v4, rotation, rotation);
483 REGISTER_ACCESSOR(p, v4, rotationVelocity, rotationVelocity);
484 REGISTER_ACCESSOR(p, v4, autoRotate, autoRotate);
485 REGISTER_ACCESSOR(p, v4, animIdx, animationIndex);
486 REGISTER_ACCESSOR(p, v4, frameDuration, frameDuration);
487 REGISTER_ACCESSOR(p, v4, frameAt, frameAt);
488 REGISTER_ACCESSOR(p, v4, frameCount, frameCount);
489 REGISTER_ACCESSOR(p, v4, animT, animationT);
490 REGISTER_ACCESSOR(p, v4, r, r);
491 REGISTER_ACCESSOR(p, v4, update, update);
492 REGISTER_ACCESSOR(p, v4, curX, x);
493 REGISTER_ACCESSOR(p, v4, curVX, vx);
494 REGISTER_ACCESSOR(p, v4, curAX, ax);
495 REGISTER_ACCESSOR(p, v4, curY, y);
496 REGISTER_ACCESSOR(p, v4, curVY, vy);
497 REGISTER_ACCESSOR(p, v4, curAY, ay);
498 REGISTER_ACCESSOR(p, v4, red, red);
499 REGISTER_ACCESSOR(p, v4, green, green);
500 REGISTER_ACCESSOR(p, v4, blue, blue);
501 REGISTER_ACCESSOR(p, v4, alpha, alpha);
502
503 proto = p;
504}
505
506QV4ParticleDataDeletable::~QV4ParticleDataDeletable()
507{
508}
509
510V4_DEFINE_EXTENSION(QV4ParticleDataDeletable, particleV4Data);
511
512
513QQuickV4ParticleData::QQuickV4ParticleData(QV4::ExecutionEngine* v4, QQuickParticleData* datum,
514 QQuickParticleSystem *system)
515{
516 if (!v4 || !datum)
517 return;
518
519 QV4::Scope scope(v4);
520 QV4ParticleDataDeletable *d = particleV4Data(engine: scope.engine);
521 QV4::ScopedObject o(scope, v4->memoryManager->allocate<QV4ParticleData>(args: datum, args: system));
522 QV4::ScopedObject p(scope, d->proto.value());
523 o->setPrototypeUnchecked(p);
524 m_v4Value = o;
525}
526
527QQuickV4ParticleData::~QQuickV4ParticleData()
528{
529}
530
531QV4::ReturnedValue QQuickV4ParticleData::v4Value() const
532{
533 return m_v4Value.value();
534}
535
536QT_END_NAMESPACE
537

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