4#include <QtQuick3D/private/qquick3dquaternionutils_p.h>
10#include <private/qqmldelegatemodel_p.h>
15#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
16#include <qtquick3d_tracepoints_p.h>
68 , m_initialized(
false)
69 , m_componentComplete(
false)
76 m_loggingTimer.
setInterval(m_loggingData->m_loggingInterval);
83 m_updateAnimation->
stop();
85 for (
const auto &
connection : std::as_const(m_connections))
88 const auto particles = m_particles;
89 const auto emitters = m_emitters;
90 const auto trailEmitters = m_trailEmitters;
91 const auto affectors = m_affectors;
92 for (
auto *particle : particles)
93 particle->setSystem(
nullptr);
94 for (
auto *emitter : emitters)
95 emitter->setSystem(
nullptr);
96 for (
auto *emitter : trailEmitters)
97 emitter->setSystem(
nullptr);
98 for (
auto *affector : affectors)
99 affector->setSystem(
nullptr);
188 return m_useRandomSeed;
241 return m_loggingData;
255 for (
auto emitter : std::as_const(m_emitters))
257 for (
auto emitter : std::as_const(m_trailEmitters))
259 for (
auto particle : std::as_const(m_particles))
261 m_particleIdIndex = 0;
270 return m_currentTime;
283 if (m_componentComplete && !m_running && m_useRandomSeed)
284 doSeedRandomization();
286 (m_running && !isEditorModeOn()) ? m_animation->
start() : m_animation->
stop();
295 m_paused ? m_animation->
pause() : m_animation->
resume();
323 if (m_useRandomSeed == randomize)
326 m_useRandomSeed = randomize;
330 doSeedRandomization();
352 resetLoggingVariables();
353 m_loggingData->resetData();
356 m_loggingTimer.
start();
358 m_loggingTimer.
stop();
369 if (m_editorTime ==
time)
380 m_componentComplete =
true;
381 m_updateAnimation->
start();
384 m_loggingTimer.
setInterval(m_loggingData->m_loggingInterval);
387 doSeedRandomization();
400 if (m_running && !isEditorModeOn())
401 m_animation->
start();
403 m_animation->
pause();
405 m_initialized =
true;
408void QQuick3DParticleSystem::refresh()
413 if (!m_running || m_paused || isEditorModeOn())
414 m_animation->
setCurrentTime(isEditorModeOn() ? m_editorTime : m_time);
417void QQuick3DParticleSystem::markDirty()
426 for (
auto particle : std::as_const(m_particles))
427 pCount += particle->maxAmount();
433 auto *
model = qobject_cast<QQuick3DParticleModelParticle *>(particle);
435 registerParticleModel(
model);
438 auto *sprite = qobject_cast<QQuick3DParticleSpriteParticle *>(particle);
440 registerParticleSprite(sprite);
443 m_particles << particle;
458 auto *
model = qobject_cast<QQuick3DParticleModelParticle *>(particle);
463 auto *sprite = qobject_cast<QQuick3DParticleSpriteParticle *>(particle);
474 auto te = qobject_cast<QQuick3DParticleTrailEmitter *>(
e);
476 m_trailEmitters << te;
483 auto te = qobject_cast<QQuick3DParticleTrailEmitter *>(
e);
505 if (!m_initialized || isGloballyDisabled() || (isEditorModeOn() && !
visible()))
510 Q_TRACE(QSSG_particleUpdate_entry);
513 const float timeS = float(m_currentTime / 1000.0f);
522 for (
auto emitter : std::as_const(m_emitters))
523 emitter->emitParticles();
526 for (
auto affector : std::as_const(m_affectors)) {
527 if (affector->m_enabled)
528 affector->prepareToAffect();
532 for (
auto particle : std::as_const(m_particles)) {
536 for (
auto emitter : std::as_const(m_trailEmitters)) {
537 if (emitter->follow() == particle) {
538 int emitAmount = emitter->getEmitAmount();
539 if (emitAmount > 0 || emitter->hasBursts()) {
542 e.amount = emitAmount;
548 m_particlesMax += particle->maxAmount();
551 if (spriteParticle) {
552 processSpriteParticle(spriteParticle, trailEmits, timeS);
557 processModelParticle(modelParticle, trailEmits, timeS);
562 processModelBlendParticle(mbp, trailEmits, timeS);
568 for (
auto emitter : std::as_const(m_trailEmitters))
569 emitter->clearBursts();
575 Q_TRACE(QSSG_particleUpdate_exit, m_particlesUsed);
581 modelParticle->clearInstanceTable();
585 for (
int i = 0;
i <
c;
i++) {
588 const float particleTimeEnd =
d->startTime +
d->lifetime;
590 if (timeS < d->
startTime || timeS > particleTimeEnd) {
591 if (timeS > particleTimeEnd &&
d->lifetime > 0.0f) {
592 for (
auto trailEmit :
std::as_const(trailEmits))
599 const float particleTimeS = timeS -
d->startTime;
601 if (timeS >=
d->startTime &&
d->lifetime <= 0.0f) {
602 for (
auto trailEmit :
std::as_const(trailEmits))
606 processParticleCommon(currentData, d, particleTimeS);
610 processParticleAlignment(currentData, modelParticle, d);
613 const float timeChange = std::max(0.0f, std::min(1.0f, particleTimeS /
d->lifetime));
616 currentData.
scale = modelParticle->m_initialScale * (
d->endSize * timeChange +
d->startSize * (1.0f - timeChange));
619 const float particleTimeLeftS =
d->lifetime - particleTimeS;
620 processParticleFadeInOut(currentData, modelParticle, particleTimeS, particleTimeLeftS);
623 for (
auto affector :
std::as_const(m_affectors)) {
625 if (affector->m_enabled && (affector->m_particles.isEmpty() || affector->m_particles.contains(modelParticle)))
626 affector->affectParticle(*d, ¤tData, particleTimeS);
630 for (
auto trailEmit :
std::as_const(trailEmits))
637 modelParticle->commitInstance();
642 return (
b -
a) *
f +
a;
649 for (
int i = 0;
i <
c;
i++) {
652 const float particleTimeEnd =
d->startTime +
d->lifetime;
654 if (timeS < d->
startTime || timeS > particleTimeEnd) {
655 if (timeS > particleTimeEnd &&
d->lifetime > 0.0f) {
656 for (
auto trailEmit :
std::as_const(trailEmits))
665 float(
d->startColor.g)/ 255.0f,
666 float(
d->startColor.b)/ 255.0f,
667 float(
d->startColor.a)/ 255.0f);
668 if (
d->startTime > 0.0f && timeS > particleTimeEnd
689 const float particleTimeS = timeS -
d->startTime;
691 if (timeS >=
d->startTime &&
d->lifetime <= 0.0f) {
692 for (
auto trailEmit :
std::as_const(trailEmits))
697 processParticleCommon(currentData, d, particleTimeS);
700 const float timeChange = std::max(0.0f, std::min(1.0f, particleTimeS /
d->lifetime));
703 const float scale =
d->endSize * timeChange +
d->startSize * (1.0f - timeChange);
707 const float particleTimeLeftS =
d->lifetime - particleTimeS;
708 processParticleFadeInOut(currentData, particle, particleTimeS, particleTimeLeftS);
711 for (
auto affector :
std::as_const(m_affectors)) {
713 if (affector->m_enabled && (affector->m_particles.isEmpty() || affector->m_particles.contains(particle)))
714 affector->affectParticle(*d, ¤tData, particleTimeS);
718 for (
auto trailEmit :
std::as_const(trailEmits))
723 float(currentData.
color.
g) / 255.0f,
724 float(currentData.
color.
b) / 255.0f,
725 float(currentData.
color.
a) / 255.0f);
726 float endTimeS = particle->
endTime() * 0.001f;
729 && particleTimeLeftS < endTimeS) {
732 float factor = 1.0f - particleTimeLeftS / endTimeS;
746 for (
int i = 0;
i <
c;
i++) {
749 const float particleTimeEnd =
d->startTime +
d->lifetime;
751 if (timeS < d->
startTime || timeS > particleTimeEnd) {
752 if (timeS > particleTimeEnd && particleData.age > 0.0f) {
753 for (
auto trailEmit :
std::as_const(trailEmits))
755 auto *lineParticle = qobject_cast<QQuick3DParticleLineParticle *>(spriteParticle);
757 lineParticle->saveLineSegment(
i, timeS);
763 const float particleTimeS = timeS -
d->startTime;
765 if (timeS >=
d->startTime && timeS < particleTimeEnd && particleData.age == 0.0f) {
766 for (
auto trailEmit :
std::as_const(trailEmits))
770 processParticleCommon(currentData, d, particleTimeS);
774 processParticleAlignment(currentData, spriteParticle, d);
777 const float timeChange = std::max(0.0f, std::min(1.0f, particleTimeS /
d->lifetime));
780 const float scale =
d->endSize * timeChange +
d->startSize * (1.0f - timeChange);
784 const float particleTimeLeftS =
d->lifetime - particleTimeS;
785 processParticleFadeInOut(currentData, spriteParticle, particleTimeS, particleTimeLeftS);
787 float animationFrame = 0.0f;
792 float startFrame = sequence->firstFrame(
d->index, isSingleFrame);
794 animationFrame = fmodf(startFrame + particleTimeS /
d->animationTime, 1.0f);
796 animationFrame = fmodf(startFrame + 0.9999f - fmodf(particleTimeS /
d->animationTime, 1.0f), 1.0f);
798 animationFrame = startFrame + particleTimeS /
d->animationTime;
799 animationFrame = fabsf(fmodf(1.0f + animationFrame, 2.0f) - 1.0f);
801 animationFrame = fmodf(startFrame + 0.9999f, 1.0f) - particleTimeS /
d->animationTime;
802 animationFrame = fabsf(fmodf(fabsf(1.0f + animationFrame), 2.0f) - 1.0f);
805 animationFrame = startFrame;
807 animationFrame = std::clamp(animationFrame, 0.0f, 0.9999f);
811 for (
auto affector :
std::as_const(m_affectors)) {
813 if (affector->m_enabled && (affector->m_particles.isEmpty() || affector->m_particles.contains(spriteParticle)))
814 affector->affectParticle(*d, ¤tData, particleTimeS);
818 for (
auto trailEmit :
std::as_const(trailEmits))
824 float(currentData.
color.
g) / 255.0f,
825 float(currentData.
color.
b) / 255.0f,
826 float(currentData.
color.
a) / 255.0f);
842 currentData.
color =
d->startColor;
845 currentData.
position +=
d->startVelocity * particleTimeS;
848 constexpr float step = 360.0f / 127.0f;
850 d->startRotation.x * step + abs(
d->startRotationVelocity.x) *
d->startRotationVelocity.x * particleTimeS,
851 d->startRotation.y * step + abs(
d->startRotationVelocity.y) *
d->startRotationVelocity.y * particleTimeS,
852 d->startRotation.z * step + abs(
d->startRotationVelocity.z) *
d->startRotationVelocity.z * particleTimeS);
857 const float fadeInS = particle->m_fadeInDuration / 1000.0f;
858 const float fadeOutS = particle->m_fadeOutDuration / 1000.0f;
859 if (particleTimeS < fadeInS) {
861 const float fadeIn = particleTimeS / fadeInS;
863 currentData.
color.
a *= fadeIn;
865 currentData.
scale *= fadeIn;
867 if (particleTimeLeftS < fadeOutS) {
869 const float fadeOut = particleTimeLeftS / fadeOutS;
871 currentData.
color.
a *= fadeOut;
873 currentData.
scale *= fadeOut;
888bool QQuick3DParticleSystem::isGloballyDisabled()
894bool QQuick3DParticleSystem::isEditorModeOn()
900void QQuick3DParticleSystem::updateLoggingData()
905 if (m_loggingData->m_particlesMax != m_particlesMax) {
906 m_loggingData->m_particlesMax = m_particlesMax;
909 if (m_loggingData->m_particlesUsed != m_particlesUsed) {
910 m_loggingData->m_particlesUsed = m_particlesUsed;
913 if (m_loggingData->m_updates != m_updates) {
914 m_loggingData->m_updates = m_updates;
918 m_loggingData->updateTimes(m_timeAnimation);
921 resetLoggingVariables();
924void QQuick3DParticleSystem::resetLoggingVariables()
937void QQuick3DParticleSystem::doSeedRandomization()
946 for (
auto emitter : std::as_const(m_emitters)) {
947 count += emitter->particle() == particle;
951 for (
auto emitter : std::as_const(m_trailEmitters)) {
952 count += emitter->particle() == particle;
State state
state of the animation.
void resume()
Resumes the animation after it was paused.
void stop()
Stops the animation.
void start(QAbstractAnimation::DeletionPolicy policy=KeepWhenStopped)
Starts the animation.
void setCurrentTime(int msecs)
void pause()
Pauses the animation.
The QColor class provides colors based on RGB, HSV or CMYK values.
qint64 restart() noexcept
Restarts the timer and returns the number of milliseconds elapsed since the previous start.
qint64 nsecsElapsed() const noexcept
const_reference at(qsizetype i) const noexcept
qsizetype removeAll(const AT &t)
iterator insert(const Key &key, const T &value)
size_type remove(const Key &key)
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
void init(quint32 seed, int size=65536)
void setDeterministic(bool deterministic)
The QQuaternion class represents a quaternion consisting of a vector and scalar.
static QQuaternion fromEulerAngles(const QVector3D &eulerAngles)
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
QVector3D particleCenter(int particleIndex) const
ModelBlendMode modelBlendMode
QVector3D particleEndPosition(int particleIndex) const
void setParticleData(int particleIndex, const QVector3D &position, const QVector3D &rotation, const QVector4D &color, float size, float age)
QVector3D particleEndRotation(int particleIndex) const
virtual void setParticleData(int particleIndex, const QVector3D &position, const QVector3D &rotation, const QVector4D &color, float size, float age, float animationFrame)
virtual void commitParticles(float)
virtual void resetParticleData(int particleIndex)
QVector< SpriteParticleData > m_spriteParticleData
void particlesMaxChanged()
void loggingIntervalChanged()
void particlesUsedChanged()
void setDirty(bool dirty)
bool isPaused() const
\qmlproperty bool ParticleSystem3D::paused
void loggingDataChanged()
~QQuick3DParticleSystem() override
void unRegisterParticleEmitter(QQuick3DParticleEmitter *e)
void unRegisterParticle(QQuick3DParticle *particle)
void registerParticleAffector(QQuick3DParticleAffector *a)
bool isShared(const QQuick3DParticle *particle) const
void setStartTime(int startTime)
bool isRunning() const
\qmlproperty bool ParticleSystem3D::running
void updateCurrentTime(int currentTime)
void registerParticle(QQuick3DParticle *particle)
int particleCount() const
void useRandomSeedChanged()
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
QQuick3DParticleSystemLogging * loggingData
void setRunning(bool running)
void setUseRandomSeed(bool randomize)
void setLogging(bool logging)
void registerParticleEmitter(QQuick3DParticleEmitter *e)
Q_INVOKABLE void reset()
\qmlmethod ParticleSystem3D::reset()
void unRegisterParticleAffector(QQuick3DParticleAffector *a)
void setEditorTime(int time)
Set editor time which in editor mode overwrites the time.
int currentTime() const
Returns the current time of the system (m_time + m_startTime).
void setPaused(bool paused)
QQuick3DParticleSystem(QQuick3DNode *parent=nullptr)
QList< QQuick3DParticleData > m_particleData
QQuick3DParticleSpriteSequence * m_spriteSequence
@ AlignTowardsStartVelocity
QVector3D alignTargetPosition
static Q_INVOKABLE QQuaternion lookAt(const QVector3D &sourcePosition, const QVector3D &targetPosition, const QVector3D &forwardDirection=QVector3D(0, 0, -1), const QVector3D &upDirection=QVector3D(0, 1, 0))
static Q_DECL_CONST_FUNCTION QRandomGenerator * global()
\threadsafe
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
void setInterval(int msec)
void stop()
Stops the timer.
void timeout(QPrivateSignal)
This signal is emitted when the timer times out.
The QVector3D class represents a vector or vertex in 3D space.
constexpr float x() const noexcept
Returns the x coordinate of this point.
The QVector4D class represents a vector or vertex in 4D space.
Combined button and popup list for selecting options.
DBusConnection * connection
static Q_CONSTINIT QBasicAtomicInt running
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLenum GLuint GLintptr offset
GLenum GLenum GLenum GLenum GLenum scale
static QVector3D mix(const QVector3D &a, const QVector3D &b, float f)
#define Q_QUICK3D_PROFILE_START(Type)
#define Q_QUICK3D_PROFILE_END_WITH_ID(Type, Payload, POID)
#define Q_QUICK3D_PROFILE_GET_ID
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_TRACE_POINT(provider, tracepoint,...)
static double currentTime()
QSqlQueryModel * model
[16]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent