1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dparticlespritesequence_p.h"
5#include "qquick3dparticlespriteparticle_p.h"
6
7QT_BEGIN_NAMESPACE
8
9/*!
10 \qmltype SpriteSequence3D
11 \inherits QtObject
12 \inqmlmodule QtQuick3D.Particles3D
13 \brief Provides image sequence features for the Sprite particles.
14 \since 6.2
15
16 The SpriteSequence3D element provides support for animated images with multiple frames. The frames
17 should be aligned horizontally in the image, first frame being on the left and last on the right.
18
19 To make a \l SpriteParticle3D an animated sequence, set its \l {SpriteParticle3D::spriteSequence}{spriteSequence} property.
20*/
21
22QQuick3DParticleSpriteSequence::QQuick3DParticleSpriteSequence(QObject *parent)
23 : QObject(parent)
24{
25
26}
27
28QQuick3DParticleSpriteSequence::~QQuick3DParticleSpriteSequence()
29{
30 if (m_parentParticle)
31 m_parentParticle->setSpriteSequence(nullptr);
32}
33
34/*!
35 \qmlproperty int SpriteSequence3D::frameCount
36
37 This property defines the amount of image frames in \l {SpriteParticle3D::}{sprite}.
38 Particle animates through these frames during its \l duration.
39 The frames should be laid out horizontally in the same image file. For example,
40 \e sprite could be a \c {512x64} image, with \c frameCount of \c 8. This would make
41 each particle frame size \c {64x64} pixels.
42
43 The default value is \c 1.
44
45 \note If your image only has a single sprite frame, don't define the
46 \l {SpriteParticle3D::}{spriteSequence} property at all.
47
48 \sa interpolate
49*/
50int QQuick3DParticleSpriteSequence::frameCount() const
51{
52 return m_frameCount;
53}
54
55/*!
56 \qmlproperty int SpriteSequence3D::frameIndex
57
58 This property defines the initial index of the frame. This is the position in between frames
59 where the animation is started. For example when the \c frameIndex is 5 and the \l animationDirection
60 is \c Normal, the first rendered frame is 5. If the \l animationDirection is \c Reverse, the
61 first rendered frame is 4.
62
63 The value of frameIndex must be between 0 and \l{frameCount} - \c 1. When the \l animationDirection
64 is \c SingleFrame and \l randomStart is \c false, all the particles will render sprites with the
65 \c frameIndex.
66
67 The default value is \c 0.
68
69 \sa randomStart, animationDirection
70*/
71int QQuick3DParticleSpriteSequence::frameIndex() const
72{
73 return m_frameIndex;
74}
75
76/*!
77 \qmlproperty bool SpriteSequence3D::interpolate
78
79 This property defines if the sprites are interpolated (blended) between frames
80 to make the animation appear smoother.
81
82 The default value is \c true.
83
84 \sa frameCount
85*/
86bool QQuick3DParticleSpriteSequence::interpolate() const
87{
88 return m_interpolate;
89}
90
91/*!
92 \qmlproperty int SpriteSequence3D::duration
93
94 This property defines the duration in milliseconds how long it takes for the
95 sprite sequence to animate. For example, if the \l duration is \c 400 and the
96 \l frameCount is 8, each frame will be shown for 50 milliseconds. When the
97 value is -1, the particle lifeSpan is used as the duration.
98
99 The default value is \c -1.
100*/
101int QQuick3DParticleSpriteSequence::duration() const
102{
103 return m_duration;
104}
105
106/*!
107 \qmlproperty int SpriteSequence3D::durationVariation
108
109 This property defines the duration variation in milliseconds. The actual duration
110 of the animation is between \c duration - \c durationVariation and \c duration +
111 \c durationVariation.
112
113 The default value is \c 0 (no variation).
114*/
115int QQuick3DParticleSpriteSequence::durationVariation() const
116{
117 return m_durationVariation;
118}
119
120/*!
121 \qmlproperty bool SpriteSequence3D::randomStart
122
123 This property defines if the animation should start from a random frame between \c 0 and \l frameCount - \c 1.
124 This allows animations to not look like they all just started when the animation begins.
125
126 The default value is \c false.
127
128 \sa animationDirection
129*/
130bool QQuick3DParticleSpriteSequence::randomStart() const
131{
132 return m_randomStart;
133}
134
135/*!
136 \qmlproperty AnimationDirection SpriteSequence3D::animationDirection
137
138 This property defines the animation direction of the sequence.
139
140 The default value is \c SpriteSequence3D.Normal.
141
142 \sa randomStart
143*/
144
145/*!
146 \qmlproperty enumeration SpriteSequence3D::AnimationDirection
147
148 Defines the animation playback direction of the sequence.
149
150 \value SpriteSequence3D.Normal
151 Animate from the first frame to the last frame. When the last frame is reached, jump back to the first frame.
152 \value SpriteSequence3D.Reverse
153 Animate from the last frame to the first frame. When the first frame is reached, jump back to the last frame.
154 \value SpriteSequence3D.Alternate
155 Animate from the first frame to the last frame. When the last or first frame is reached, switch the animation direction.
156 This makes the sequence animation smooth even when the first and the last frames don't match.
157 \value SpriteSequence3D.AlternateReverse
158 Animate from the last frame to the first frame. When the last or first frame is reached, switch the animation direction.
159 This makes the sequence animation smooth even when the first and the last frames don't match.
160 \value SpriteSequence3D.SingleFrame
161 Don't animate the frame. When the \l randomStart is false, \l frameIndex frame is rendered.
162 When the \l randomStart is true, each particle renders a random frame.
163*/
164QQuick3DParticleSpriteSequence::AnimationDirection QQuick3DParticleSpriteSequence::animationDirection() const
165{
166 return m_animationDirection;
167}
168
169void QQuick3DParticleSpriteSequence::setFrameCount(int frameCount)
170{
171 if (m_frameCount == frameCount)
172 return;
173 m_frameCount = std::max(a: 1, b: frameCount);
174 markNodesDirty();
175 Q_EMIT frameCountChanged();
176}
177
178void QQuick3DParticleSpriteSequence::setFrameIndex(int frameIndex)
179{
180 if (m_frameIndex == frameIndex)
181 return;
182 m_frameIndex = std::max(a: 0, b: frameIndex);
183 markNodesDirty();
184 Q_EMIT frameIndexChanged();
185}
186
187void QQuick3DParticleSpriteSequence::setInterpolate(bool interpolate)
188{
189 if (m_interpolate == interpolate)
190 return;
191 m_interpolate = interpolate;
192 markNodesDirty();
193 Q_EMIT interpolateChanged();
194}
195
196void QQuick3DParticleSpriteSequence::setDuration(int duration)
197{
198 if (m_duration == duration)
199 return;
200
201 m_duration = duration;
202 markNodesDirty();
203 Q_EMIT durationChanged();
204}
205
206void QQuick3DParticleSpriteSequence::setDurationVariation(int durationVariation)
207{
208 if (m_durationVariation == durationVariation)
209 return;
210
211 m_durationVariation = durationVariation;
212 markNodesDirty();
213 Q_EMIT durationVariationChanged();
214}
215
216void QQuick3DParticleSpriteSequence::setRandomStart(bool randomStart)
217{
218 if (m_randomStart == randomStart)
219 return;
220 m_randomStart = randomStart;
221 markNodesDirty();
222 Q_EMIT randomStartChanged();
223}
224
225void QQuick3DParticleSpriteSequence::setAnimationDirection(QQuick3DParticleSpriteSequence::AnimationDirection animationDirection)
226{
227 if (m_animationDirection == animationDirection)
228 return;
229 m_animationDirection = animationDirection;
230 markNodesDirty();
231 Q_EMIT animationDirectionChanged();
232}
233
234void QQuick3DParticleSpriteSequence::componentComplete()
235{
236 m_parentParticle = qobject_cast<QQuick3DParticleSpriteParticle *>(object: parent());
237 if (!m_parentParticle)
238 qWarning() << "SpriteSequence3D requires parent SpriteParticle3D to function correctly!";
239}
240
241void QQuick3DParticleSpriteSequence::markNodesDirty()
242{
243 if (m_parentParticle)
244 m_parentParticle->markNodesDirty();
245}
246
247// Returns the first frame of the sequence.
248// Return range [0..1) where 0.0 is the first frame and 0.9999 is the last.
249float QQuick3DParticleSpriteSequence::firstFrame(int index, bool singleFrame)
250{
251 float firstFrame = 0.0f;
252 if (m_randomStart) {
253 if (!m_parentParticle || !m_parentParticle->m_system)
254 return firstFrame;
255 auto rand = m_parentParticle->m_system->rand();
256 firstFrame = rand->get(particleIndex: index, user: QPRand::SpriteAnimationI);
257 } else if (m_frameCount > 1 && m_frameIndex > 0) {
258 int frameIndex = std::min(a: m_frameIndex, b: m_frameCount - 1);
259 if (singleFrame)
260 firstFrame = float(frameIndex) / (float(m_frameCount - 1) + 0.0001f);
261 else
262 firstFrame = float(frameIndex) / float(m_frameCount);
263 }
264 return firstFrame;
265}
266
267QT_END_NAMESPACE
268

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