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

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