Revision control
Copy as Markdown
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#ifndef QQUICK3DPARTICLERANDOMIZER_H
#define QQUICK3DPARTICLERANDOMIZER_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QRandomGenerator>
#include <QList>
#include <private/qglobal_p.h>
QT_BEGIN_NAMESPACE
/*
Simple helper to get pseudo-random numbers which remain the same per particle & user.
Particles don't need strong randomization and the ability to seed can be useful.
Based on brief testing on my laptop, getting 1.000.000 random numbers:
1) Using QRandomGenerator::global()->generateDouble()
-> ~120ms
2) Using QPRand::get(), with m_size 4096
-> ~8ms
3) Using QPRand::get(i, j), with m_size 4096
-> ~10ms
4) Using QPRand::get(i, j), with m_size 100000
-> ~10ms
So QPRand seems fast and increasing keys amount doesn't notably affect the performance,
just the memory usage. With more particles m_size should be relatively big to make sure
particles appear random enough.
Bounded usage tips:
- qrg->bounded(4.0) == QPRand::get() * 4.0
- qrg->bounded(4) == int(QPRand::get() * 4)
*/
class QPRand
{
public:
// Add here new enums for diferent "users".
// This way e.g. particle can vary little on colors but more on sizes.
enum UserType {
Default = 0,
WanderXPS, // PaceStart
WanderYPS,
WanderZPS,
WanderXPV, // PaceVariation
WanderYPV,
WanderZPV,
WanderXAV, // AmountVariation
WanderYAV,
WanderZAV,
AttractorDurationV,
AttractorPosVX,
AttractorPosVY,
AttractorPosVZ,
Shape1, // Shape
Shape2,
Shape3,
Shape4,
SpriteAnimationI,
DeterministicSeparator, // Note: Enums before this must always be
// deterministic based on the particle index
LifeSpanV, // Emitter
ScaleV,
ScaleEV,
RotXV,
RotYV,
RotZV,
RotXVV,
RotYVV,
RotZVV,
ColorRV,
ColorGV,
ColorBV,
ColorAV,
TDirPosXV, // TargetDirection
TDirPosYV,
TDirPosZV,
TDirMagV,
VDirXV, // VectorDirection
VDirYV,
VDirZV,
SpriteAnimationV
};
void init(quint32 seed, int size = 65536) {
m_size = size;
m_generator.seed(seed);
m_randomList.clear();
m_randomList.reserve(m_size);
for (int i = 0; i < m_size; i++)
m_randomList << float(m_generator.generateDouble());
}
void setDeterministic(bool deterministic) {
m_deterministic = deterministic;
}
// Return float 0.0 - 1.0
// With the same input values, returns always the same output.
inline float get(int particleIndex, UserType user = Default) {
if (!m_deterministic && user > DeterministicSeparator)
return get();
int i = (particleIndex + user) % m_size;
return m_randomList.at(i);
}
// Return float 0.0 - 1.0 from random list
// Note: Not deterministic between runs
inline float get() {
m_index = (m_index < m_size - 1) ? m_index + 1 : 0;
return m_randomList.at(m_index);
}
QRandomGenerator generator() const
{
return m_generator;
}
private:
QRandomGenerator m_generator;
int m_size = 0;
int m_index = 0;
bool m_deterministic = false;
QList<float> m_randomList;
};
QT_END_NAMESPACE
#endif // QQUICK3DPARTICLERANDOMIZER_H