1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dparticlescaleaffector_p.h"
5#include <qmath.h>
6
7QT_BEGIN_NAMESPACE
8
9/*!
10 \qmltype ScaleAffector3D
11 \inherits Affector3D
12 \inqmlmodule QtQuick3D.Particles3D
13 \brief Particle scale affector.
14 \since 6.4
15
16 Scale affector scales the particle size based on its lifetime and parameters.
17*/
18
19QQuick3DParticleScaleAffector::QQuick3DParticleScaleAffector(QQuick3DNode *parent)
20 : QQuick3DParticleAffector(parent)
21{
22
23}
24
25/*!
26 \qmlproperty real ScaleAffector3D::minSize
27
28 This property holds the minimum size the affector can scale the particle.
29 The default is 1.0.
30*/
31float QQuick3DParticleScaleAffector::minSize() const
32{
33 return m_minSize;
34}
35
36/*!
37 \qmlproperty real ScaleAffector3D::maxSize
38
39 This property holds the maximum size the affector can scale the particle.
40 The default is 1.0.
41*/
42float QQuick3DParticleScaleAffector::maxSize() const
43{
44 return m_maxSize;
45}
46
47/*!
48 \qmlproperty int ScaleAffector3D::duration
49
50 This property holds the duration of scaling cycle in milliseconds.
51 The default is 1000.
52*/
53int QQuick3DParticleScaleAffector::duration() const
54{
55 return m_duration;
56}
57
58/*!
59 \qmlproperty enumeration ScaleAffector3D::ScalingType
60
61 Defines the scaling type of the affector.
62
63 \value ScaleAffector3D.Linear
64 The scale is calculated using the easing curve to interpolate between minimum and maximum
65 scale size between duration milliseconds and then continues from the minimum size.
66 \value ScaleAffector3D.SewSaw
67 The scale is calculated using the easing curve to interpolate between minimum and maximum
68 scale size between duration milliseconds on a rising edge then continues from maximum to minimum
69 on a falling edge.
70 \value ScaleAffector3D.SineWave
71 The scale follows the sine wave. Easing curve is not used.
72 \value ScaleAffector3D.AbsSineWave
73 The scale follows the sine wave except negative values are inverted. Easing curve is not used.
74 \value ScaleAffector3D.Step
75 The scale stays at minimum size until half of the duration milliseconds have passed then steps directly
76 to the maximum size. Easing curve is not used.
77 \value ScaleAffector3D.SmoothStep
78 The scale smootly transitions from minimum to maximum size. Easing curve is not used.
79*/
80
81/*!
82 \qmlproperty ScalingType ScaleAffector3D::type
83
84 This property holds the scaling type of the affector. The default value is \c Linear.
85*/
86QQuick3DParticleScaleAffector::ScalingType QQuick3DParticleScaleAffector::type() const
87{
88 return m_type;
89}
90
91/*!
92 \qmlproperty EasingCurve ScaleAffector3D::easingCurve
93
94 This property holds the \l {QtQuick::PropertyAnimation::easing}{easing curve} providing
95 more fine tuned control on how the scaling occurs. The easing curve is used with \c Linear
96 and \c SewSaw scaling types. The default easing curve provides linear value between [0, 1].
97*/
98QEasingCurve QQuick3DParticleScaleAffector::easingCurve() const
99{
100 return m_easing;
101}
102
103void QQuick3DParticleScaleAffector::setMinSize(float size)
104{
105 if (qFuzzyCompare(p1: size, p2: m_minSize))
106 return;
107 m_minSize = size;
108 Q_EMIT minSizeChanged();
109}
110
111void QQuick3DParticleScaleAffector::setMaxSize(float size)
112{
113 if (qFuzzyCompare(p1: size, p2: m_maxSize))
114 return;
115 m_maxSize = size;
116 Q_EMIT maxSizeChanged();
117}
118
119void QQuick3DParticleScaleAffector::setDuration(int duration)
120{
121 duration = qMax(a: 0, b: duration);
122 if (duration == m_duration)
123 return;
124 m_duration = duration;
125 Q_EMIT durationChanged();
126}
127
128void QQuick3DParticleScaleAffector::setType(ScalingType type)
129{
130 if (m_type == type)
131 return;
132 m_type = type;
133 Q_EMIT typeChanged();
134}
135
136void QQuick3DParticleScaleAffector::setEasingCurve(const QEasingCurve &curve)
137{
138 if (m_easing == curve)
139 return;
140 m_easing = curve;
141 Q_EMIT easingCurveChanged();
142}
143
144void QQuick3DParticleScaleAffector::prepareToAffect()
145{
146
147}
148
149void QQuick3DParticleScaleAffector::affectParticle(const QQuick3DParticleData &, QQuick3DParticleDataCurrent *d, float time)
150{
151 float scale = 1.0f;
152
153 const auto fract = [](const float v) -> float {
154 return v - qFloor(v);
155 };
156 const auto lerp = [](const float a, const float b, const float f) -> float {
157 return a + (b - a) * f;
158 };
159 const auto smoothstep = [](const float a, const float b, const float f) -> float {
160 return a + (b - a) * f * f * (3.0f - 2.0f * f);
161 };
162
163 float pos = fract(time / float(m_duration * 0.001f));
164 switch (m_type) {
165 case Linear:
166 scale = lerp(m_minSize, m_maxSize, m_easing.valueForProgress(progress: pos));
167 scale = qMax(a: scale, b: 0.0f);
168 break;
169 case SewSaw:
170 if (pos < 0.5f)
171 scale = lerp(m_minSize, m_maxSize, m_easing.valueForProgress(progress: pos * 2.0f));
172 else
173 scale = lerp(m_maxSize, m_minSize, m_easing.valueForProgress(progress: (pos - 0.5) * 2.0f));
174 scale = qMax(a: scale, b: 0.0f);
175 break;
176 case SineWave:
177 scale = m_minSize + (m_maxSize - m_minSize) * (1.0f + qSin(v: 2.0f * M_PI * pos)) * 0.5f;
178 break;
179 case AbsSineWave:
180 scale = m_minSize + (m_maxSize - m_minSize) * qAbs(t: qSin(v: 2.0f * M_PI * pos));
181 break;
182 case Step:
183 if (pos < 0.5f)
184 scale = m_minSize;
185 else
186 scale = m_maxSize;
187 break;
188 case SmoothStep:
189 scale = smoothstep(m_minSize, m_maxSize, pos);
190 break;
191 }
192
193 d->scale *= scale;
194}
195
196QT_END_NAMESPACE
197

source code of qtquick3d/src/quick3dparticles/qquick3dparticlescaleaffector.cpp