Improve random number generation

The global RNG state is now protected from simultaneous accesses by
employing a mutex.

Performance sensitive code requiring generation of a large number of
random numbers can utilize `LocalRNG`. This is not thread-safe but
provides a much greater throughput. `LocalRNG` is seeded by the global
RNG only at construction time.
This commit is contained in:
yvt 2018-09-17 23:37:11 +09:00
parent 995e7f2ffc
commit 585cbfce1c
24 changed files with 367 additions and 245 deletions

View File

@ -52,13 +52,9 @@ DEFINE_SPADES_SETTING(s_gain, "1");
namespace spades { namespace spades {
namespace audio { namespace audio {
std::uniform_real_distribution<float> real_dist_audio(0, 1);
static Vector3 TransformVectorToAL(Vector3 v) { return MakeVector3(v.x, v.y, v.z); } static Vector3 TransformVectorToAL(Vector3 v) { return MakeVector3(v.x, v.y, v.z); }
static Vector3 TransformVectorFromAL(Vector3 v) { return MakeVector3(v.x, v.y, v.z); } static Vector3 TransformVectorFromAL(Vector3 v) { return MakeVector3(v.x, v.y, v.z); }
static float NextRandom() { return real_dist_audio(mt_engine); }
namespace { namespace {
std::vector<uint8_t> ConvertFloatBufferToSignedShort(const std::vector<uint8_t> &bytes) { std::vector<uint8_t> ConvertFloatBufferToSignedShort(const std::vector<uint8_t> &bytes) {
if (bytes.size() & 3) { if (bytes.size() & 3) {
@ -562,7 +558,7 @@ namespace spades {
ALSrc *AllocChunk() { ALSrc *AllocChunk() {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
size_t start = mt_engine() % srcs.size(); size_t start = SampleRandomInt<std::size_t>(0, srcs.size() - 1);
for (size_t i = 0; i < srcs.size(); i++) { for (size_t i = 0; i < srcs.size(); i++) {
ALSrc *src = srcs[(i + start) % srcs.size()]; ALSrc *src = srcs[(i + start) % srcs.size()];
if (src->IsPlaying()) if (src->IsPlaying())
@ -570,7 +566,7 @@ namespace spades {
return src; return src;
} }
ALSrc *src = srcs[mt_engine() % srcs.size()]; ALSrc *src = SampleRandomElement(srcs);
src->Terminate(); src->Terminate();
return src; return src;
} }
@ -649,9 +645,9 @@ namespace spades {
Vector3 rayTo; Vector3 rayTo;
for (int rays = 0; rays < 4; rays++) { for (int rays = 0; rays < 4; rays++) {
rayTo.x = NextRandom() - NextRandom(); rayTo.x = SampleRandomFloat() - SampleRandomFloat();
rayTo.y = NextRandom() - NextRandom(); rayTo.y = SampleRandomFloat() - SampleRandomFloat();
rayTo.z = NextRandom() - NextRandom(); rayTo.z = SampleRandomFloat() - SampleRandomFloat();
rayTo = rayTo.Normalize(); rayTo = rayTo.Normalize();
IntVector3 hitPos; IntVector3 hitPos;
@ -742,7 +738,7 @@ namespace spades {
for (size_t i = 0; i < srcs.size(); i++) { for (size_t i = 0; i < srcs.size(); i++) {
ALSrc *s = srcs[i]; ALSrc *s = srcs[i];
if ((mt_engine() % 8 == 0) && s->IsPlaying()) if ((SampleRandomInt(0, 7) == 0) && s->IsPlaying())
s->UpdateObstruction(); s->UpdateObstruction();
} }
} }

View File

@ -453,8 +453,6 @@ namespace spades {
old->Release(); old->Release();
} }
static float NextRandom() { return real_dist(mt_engine); }
void YsrDevice::Respatialize(const spades::Vector3 &eye, const spades::Vector3 &front, void YsrDevice::Respatialize(const spades::Vector3 &eye, const spades::Vector3 &front,
const spades::Vector3 &up) { const spades::Vector3 &up) {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
@ -480,9 +478,9 @@ namespace spades {
Vector3 rayTo; Vector3 rayTo;
for (int rays = 0; rays < 4; rays++) { for (int rays = 0; rays < 4; rays++) {
rayTo.x = NextRandom() - NextRandom(); rayTo.x = SampleRandomFloat() - SampleRandomFloat();
rayTo.y = NextRandom() - NextRandom(); rayTo.y = SampleRandomFloat() - SampleRandomFloat();
rayTo.z = NextRandom() - NextRandom(); rayTo.z = SampleRandomFloat() - SampleRandomFloat();
rayTo = rayTo.Normalize(); rayTo = rayTo.Normalize();
IntVector3 hitPos; IntVector3 hitPos;

View File

@ -65,11 +65,7 @@ SPADES_SETTING(cg_playerName);
namespace spades { namespace spades {
namespace client { namespace client {
std::random_device r_device_client;
std::mt19937_64 mt_engine_client(
r_device_client()); // Seed Mersenne twister with non-deterministic 32-bit seed
Client::Client(IRenderer *r, IAudioDevice *audioDev, const ServerAddress &host, Client::Client(IRenderer *r, IAudioDevice *audioDev, const ServerAddress &host,
FontManager *fontManager) FontManager *fontManager)
: playerName(cg_playerName.operator std::string().substr(0, 15)), : playerName(cg_playerName.operator std::string().substr(0, 15)),

View File

@ -67,8 +67,6 @@ namespace spades {
class ClientUI; class ClientUI;
extern std::mt19937_64 mt_engine_client; // randomness generator
class Client : public IWorldListener, public gui::View { class Client : public IWorldListener, public gui::View {
friend class ScoreboardView; friend class ScoreboardView;
friend class LimboView; friend class LimboView;
@ -101,6 +99,11 @@ namespace spades {
FPSCounter fpsCounter; FPSCounter fpsCounter;
FPSCounter upsCounter; FPSCounter upsCounter;
/**
* A random number generator. Only can be accessed by a main thread.
*/
LocalRNG rng;
std::unique_ptr<NetClient> net; std::unique_ptr<NetClient> net;
std::string playerName; std::string playerName;
std::unique_ptr<IStream> logStream; std::unique_ptr<IStream> logStream;

View File

@ -1192,7 +1192,7 @@ namespace spades {
case RIFLE_WEAPON: case RIFLE_WEAPON:
model = renderer->RegisterModel("Models/Weapons/Rifle/Casing.kv6"); model = renderer->RegisterModel("Models/Weapons/Rifle/Casing.kv6");
snd = snd =
(mt_engine_client() & 0x1000) SampleRandomBool()
? audioDevice->RegisterSound("Sounds/Weapons/Rifle/ShellDrop1.opus") ? audioDevice->RegisterSound("Sounds/Weapons/Rifle/ShellDrop1.opus")
: audioDevice->RegisterSound( : audioDevice->RegisterSound(
"Sounds/Weapons/Rifle/ShellDrop2.opus"); "Sounds/Weapons/Rifle/ShellDrop2.opus");
@ -1207,7 +1207,7 @@ namespace spades {
case SMG_WEAPON: case SMG_WEAPON:
model = renderer->RegisterModel("Models/Weapons/SMG/Casing.kv6"); model = renderer->RegisterModel("Models/Weapons/SMG/Casing.kv6");
snd = snd =
(mt_engine_client() & 0x1000) SampleRandomBool()
? audioDevice->RegisterSound("Sounds/Weapons/SMG/ShellDrop1.opus") ? audioDevice->RegisterSound("Sounds/Weapons/SMG/ShellDrop1.opus")
: audioDevice->RegisterSound("Sounds/Weapons/SMG/ShellDrop2.opus"); : audioDevice->RegisterSound("Sounds/Weapons/SMG/ShellDrop2.opus");
snd2 = audioDevice->RegisterSound("Sounds/Weapons/SMG/ShellWater.opus"); snd2 = audioDevice->RegisterSound("Sounds/Weapons/SMG/ShellWater.opus");

View File

@ -151,18 +151,19 @@ namespace spades {
if ((int)cg_particles < 1) if ((int)cg_particles < 1)
return; return;
Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga"); Handle<IImage> img = renderer->RegisterImage("Gfx/White.tga");
Vector4 color = {0.5f, 0.02f, 0.04f, 1.f}; Vector4 color = {0.5f, 0.02f, 0.04f, 1.f};
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(v, ent->SetTrajectory(v,
MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) *
10.f, 10.f,
1.f, 0.7f); 1.f, 0.7f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.1f + GetRandom() * GetRandom() * 0.2f); ent->SetRadius(0.1f + rng.SampleFloat() * rng.SampleFloat() * 0.2f);
ent->SetLifeTime(3.f, 0.f, 1.f); ent->SetLifeTime(3.f, 0.f, 1.f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -175,14 +176,15 @@ namespace spades {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 100.f, SmokeSpriteEntity::Type::Explosion); new SmokeSpriteEntity(this, color, 100.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory(v, ent->SetTrajectory(v,
MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) *
.7f, .7f,
.8f, 0.f); .8f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(.5f + GetRandom() * GetRandom() * 0.2f, 2.f); ent->SetRadius(.5f + rng.SampleFloat() * rng.SampleFloat() * 0.2f, 2.f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(.20f + GetRandom() * .2f, 0.06f, .20f); ent->SetLifeTime(.20f + rng.SampleFloat() * .2f, 0.06f, .20f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -191,14 +193,15 @@ namespace spades {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 40.f, SmokeSpriteEntity::Type::Steady); new SmokeSpriteEntity(this, color, 40.f, SmokeSpriteEntity::Type::Steady);
ent->SetTrajectory(v, ent->SetTrajectory(v,
MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) *
.7f, .7f,
.8f, 0.f); .8f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(.7f + GetRandom() * GetRandom() * 0.2f, 2.f, 0.1f); ent->SetRadius(.7f + rng.SampleFloat() * rng.SampleFloat() * 0.2f, 2.f, 0.1f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(.80f + GetRandom() * 0.4f, 0.06f, 1.0f); ent->SetLifeTime(.80f + rng.SampleFloat() * 0.4f, 0.06f, 1.0f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
} }
@ -219,12 +222,13 @@ namespace spades {
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) *
7.f, 7.f,
1.f, .9f); 1.f, .9f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.2f + GetRandom() * GetRandom() * 0.1f); ent->SetRadius(0.2f + rng.SampleFloat() * rng.SampleFloat() * 0.1f);
ent->SetLifeTime(2.f, 0.f, 1.f); ent->SetLifeTime(2.f, 0.f, 1.f);
if (distPowered < 16.f * 16.f) if (distPowered < 16.f * 16.f)
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
@ -237,13 +241,13 @@ namespace spades {
if (distPowered < 32.f * 32.f) { if (distPowered < 32.f * 32.f) {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, MakeVector3(GetRandom() - GetRandom(), ent->SetTrajectory(origin, MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom(), rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat()) *
12.f, 12.f,
1.f, .9f); 1.f, .9f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.1f + GetRandom() * GetRandom() * 0.14f); ent->SetRadius(0.1f + rng.SampleFloat() * rng.SampleFloat() * 0.14f);
ent->SetLifeTime(2.f, 0.f, 1.f); ent->SetLifeTime(2.f, 0.f, 1.f);
if (distPowered < 16.f * 16.f) if (distPowered < 16.f * 16.f)
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
@ -256,13 +260,14 @@ namespace spades {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 100.f); ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 100.f);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) *
.7f, .7f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(.6f + GetRandom() * GetRandom() * 0.2f, 0.8f); ent->SetRadius(.6f + rng.SampleFloat() * rng.SampleFloat() * 0.2f, 0.8f);
ent->SetLifeTime(.3f + GetRandom() * .3f, 0.06f, .4f); ent->SetLifeTime(.3f + rng.SampleFloat() * .3f, 0.06f, .4f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -285,12 +290,13 @@ namespace spades {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) * rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) *
7.f, 7.f,
1.f, 1.f); 1.f, 1.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.3f + GetRandom() * GetRandom() * 0.2f); ent->SetRadius(0.3f + rng.SampleFloat() * rng.SampleFloat() * 0.2f);
ent->SetLifeTime(2.f, 0.f, 1.f); ent->SetLifeTime(2.f, 0.f, 1.f);
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
@ -317,15 +323,16 @@ namespace spades {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 120.f, SmokeSpriteEntity::Type::Explosion); new SmokeSpriteEntity(this, color, 120.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory( ent->SetTrajectory(
origin, (MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), origin, (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) + rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) +
velBias * .5f) * velBias * .5f) *
0.3f, 0.3f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(.4f, 3.f, 0.0000005f); ent->SetRadius(.4f, 3.f, 0.0000005f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(0.2f + GetRandom() * 0.1f, 0.f, .30f); ent->SetLifeTime(0.2f + rng.SampleFloat() * 0.1f, 0.f, .30f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
} }
@ -381,15 +388,16 @@ namespace spades {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 60.f, SmokeSpriteEntity::Type::Explosion); new SmokeSpriteEntity(this, color, 60.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory( ent->SetTrajectory(
origin, (MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), origin, (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) + rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat()) +
velBias * .5f) * velBias * .5f) *
2.f, 2.f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(.6f + GetRandom() * GetRandom() * 0.4f, 2.f, .2f); ent->SetRadius(.6f + rng.SampleFloat() * rng.SampleFloat() * 0.4f, 2.f, .2f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(1.8f + GetRandom() * 0.1f, 0.f, .20f); ent->SetLifeTime(1.8f + rng.SampleFloat() * 0.1f, 0.f, .20f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -398,18 +406,19 @@ namespace spades {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f); ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f);
ent->SetTrajectory( ent->SetTrajectory(
origin, (MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), origin, (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
(GetRandom() - GetRandom()) * .2f)) * rng.SampleFloat() - rng.SampleFloat(),
(rng.SampleFloat() - rng.SampleFloat()) * .2f)) *
2.f, 2.f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(1.5f + GetRandom() * GetRandom() * 0.8f, 0.2f); ent->SetRadius(1.5f + rng.SampleFloat() * rng.SampleFloat() * 0.8f, 0.2f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
switch ((int)cg_particles) { switch ((int)cg_particles) {
case 1: ent->SetLifeTime(0.8f + GetRandom() * 1.f, 0.1f, 8.f); break; case 1: ent->SetLifeTime(0.8f + rng.SampleFloat() * 1.f, 0.1f, 8.f); break;
case 2: ent->SetLifeTime(1.5f + GetRandom() * 2.f, 0.1f, 8.f); break; case 2: ent->SetLifeTime(1.5f + rng.SampleFloat() * 2.f, 0.1f, 8.f); break;
case 3: case 3:
default: ent->SetLifeTime(2.f + GetRandom() * 5.f, 0.1f, 8.f); break; default: ent->SetLifeTime(2.f + rng.SampleFloat() * 5.f, 0.1f, 8.f); break;
} }
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -419,14 +428,15 @@ namespace spades {
color = MakeVector4(0.01, 0.03, 0, 1.f); color = MakeVector4(0.01, 0.03, 0, 1.f);
for (int i = 0; i < 42; i++) { for (int i = 0; i < 42; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
Vector3 dir = MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), Vector3 dir = MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()); rng.SampleFloat() - rng.SampleFloat(),
rng.SampleFloat() - rng.SampleFloat());
dir += velBias * .5f; dir += velBias * .5f;
float radius = 0.1f + GetRandom() * GetRandom() * 0.2f; float radius = 0.1f + rng.SampleFloat() * rng.SampleFloat() * 0.2f;
ent->SetTrajectory(origin + dir * .2f, dir * 20.f, .1f + radius * 3.f, 1.f); ent->SetTrajectory(origin + dir * .2f, dir * 20.f, .1f + radius * 3.f, 1.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(radius); ent->SetRadius(radius);
ent->SetLifeTime(3.5f + GetRandom() * 2.f, 0.f, 1.f); ent->SetLifeTime(3.5f + rng.SampleFloat() * 2.f, 0.f, 1.f);
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -437,15 +447,15 @@ namespace spades {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new SmokeSpriteEntity(this, color, 120.f, SmokeSpriteEntity::Type::Explosion); new SmokeSpriteEntity(this, color, 120.f, SmokeSpriteEntity::Type::Explosion);
ent->SetTrajectory( ent->SetTrajectory(
origin, (MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), origin, (MakeVector3(rng.SampleFloat() - rng.SampleFloat(), rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom()) + rng.SampleFloat() - rng.SampleFloat()) +
velBias) * velBias) *
6.f, 6.f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(.3f + GetRandom() * GetRandom() * 0.4f, 3.f, .1f); ent->SetRadius(.3f + rng.SampleFloat() * rng.SampleFloat() * 0.4f, 3.f, .1f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(.18f + GetRandom() * 0.03f, 0.f, .10f); ent->SetLifeTime(.18f + rng.SampleFloat() * 0.03f, 0.f, .10f);
// ent->SetAdditive(true); // ent->SetAdditive(true);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -471,14 +481,14 @@ namespace spades {
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
(MakeVector3(GetRandom() - GetRandom(), (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom(), -GetRandom() * 7.f)) * rng.SampleFloat() - rng.SampleFloat(), -rng.SampleFloat() * 7.f)) *
2.5f, 2.5f,
.3f, .6f); .3f, .6f);
ent->SetRotation(0.f); ent->SetRotation(0.f);
ent->SetRadius(1.5f + GetRandom() * GetRandom() * 0.4f, 1.3f); ent->SetRadius(1.5f + rng.SampleFloat() * rng.SampleFloat() * 0.4f, 1.3f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(3.f + GetRandom() * 0.3f, 0.f, .60f); ent->SetLifeTime(3.f + rng.SampleFloat() * 0.3f, 0.f, .60f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -490,14 +500,14 @@ namespace spades {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
(MakeVector3(GetRandom() - GetRandom(), (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom(), -GetRandom() * 10.f)) * rng.SampleFloat() - rng.SampleFloat(), -rng.SampleFloat() * 10.f)) *
3.5f, 3.5f,
1.f, 1.f); 1.f, 1.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.9f + GetRandom() * GetRandom() * 0.4f, 0.7f); ent->SetRadius(0.9f + rng.SampleFloat() * rng.SampleFloat() * 0.4f, 0.7f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(3.f + GetRandom() * 0.3f, .7f, .60f); ent->SetLifeTime(3.f + rng.SampleFloat() * 0.3f, .7f, .60f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -508,18 +518,18 @@ namespace spades {
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f); ParticleSpriteEntity *ent = new SmokeSpriteEntity(this, color, 20.f);
ent->SetTrajectory( ent->SetTrajectory(
origin, (MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), origin, (MakeVector3(rng.SampleFloat() - rng.SampleFloat(), rng.SampleFloat() - rng.SampleFloat(),
(GetRandom() - GetRandom()) * .2f)) * (rng.SampleFloat() - rng.SampleFloat()) * .2f)) *
2.f, 2.f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(1.4f + GetRandom() * GetRandom() * 0.8f, 0.2f); ent->SetRadius(1.4f + rng.SampleFloat() * rng.SampleFloat() * 0.8f, 0.2f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
switch ((int)cg_particles) { switch ((int)cg_particles) {
case 1: ent->SetLifeTime(3.f + GetRandom() * 5.f, 0.1f, 8.f); break; case 1: ent->SetLifeTime(3.f + rng.SampleFloat() * 5.f, 0.1f, 8.f); break;
case 2: case 2:
case 3: case 3:
default: ent->SetLifeTime(6.f + GetRandom() * 5.f, 0.1f, 8.f); break; default: ent->SetLifeTime(6.f + rng.SampleFloat() * 5.f, 0.1f, 8.f); break;
} }
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -529,15 +539,15 @@ namespace spades {
color = MakeVector4(1, 1, 1, 0.7f); color = MakeVector4(1, 1, 1, 0.7f);
for (int i = 0; i < 42; i++) { for (int i = 0; i < 42; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
Vector3 dir = MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), Vector3 dir = MakeVector3(rng.SampleFloat() - rng.SampleFloat(), rng.SampleFloat() - rng.SampleFloat(),
-GetRandom() * 3.f); -rng.SampleFloat() * 3.f);
dir += velBias * .5f; dir += velBias * .5f;
float radius = 0.1f + GetRandom() * GetRandom() * 0.2f; float radius = 0.1f + rng.SampleFloat() * rng.SampleFloat() * 0.2f;
ent->SetTrajectory(origin + dir * .2f + MakeVector3(0, 0, -1.2f), dir * 13.f, ent->SetTrajectory(origin + dir * .2f + MakeVector3(0, 0, -1.2f), dir * 13.f,
.1f + radius * 3.f, 1.f); .1f + radius * 3.f, 1.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(radius); ent->SetRadius(radius);
ent->SetLifeTime(3.5f + GetRandom() * 2.f, 0.f, 1.f); ent->SetLifeTime(3.5f + rng.SampleFloat() * 2.f, 0.f, 1.f);
ent->SetBlockHitAction(ParticleSpriteEntity::Delete); ent->SetBlockHitAction(ParticleSpriteEntity::Delete);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -554,7 +564,7 @@ namespace spades {
if ((int)cg_particles < 1) if ((int)cg_particles < 1)
return; return;
Vector4 color; Vector4 color;
color = MakeVector4(.95f, .95f, .95f, .3f); color = MakeVector4(.95f, .95f, .95f, .3f);
// water1 // water1
@ -564,14 +574,14 @@ namespace spades {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
(MakeVector3(GetRandom() - GetRandom(), (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom(), -GetRandom() * 7.f)) * rng.SampleFloat() - rng.SampleFloat(), -rng.SampleFloat() * 7.f)) *
1.f, 1.f,
.3f, .6f); .3f, .6f);
ent->SetRotation(0.f); ent->SetRotation(0.f);
ent->SetRadius(0.6f + GetRandom() * GetRandom() * 0.4f, .7f); ent->SetRadius(0.6f + rng.SampleFloat() * rng.SampleFloat() * 0.4f, .7f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(3.f + GetRandom() * 0.3f, 0.1f, .60f); ent->SetLifeTime(3.f + rng.SampleFloat() * 0.3f, 0.1f, .60f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -583,14 +593,14 @@ namespace spades {
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
ent->SetTrajectory(origin, ent->SetTrajectory(origin,
(MakeVector3(GetRandom() - GetRandom(), (MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
GetRandom() - GetRandom(), -GetRandom() * 10.f)) * rng.SampleFloat() - rng.SampleFloat(), -rng.SampleFloat() * 10.f)) *
2.f, 2.f,
1.f, 1.f); 1.f, 1.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.6f + GetRandom() * GetRandom() * 0.6f, 0.6f); ent->SetRadius(0.6f + rng.SampleFloat() * rng.SampleFloat() * 0.6f, 0.6f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(3.f + GetRandom() * 0.3f, GetRandom() * 0.3f, .60f); ent->SetLifeTime(3.f + rng.SampleFloat() * 0.3f, rng.SampleFloat() * 0.3f, .60f);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }
@ -599,14 +609,15 @@ namespace spades {
color = MakeVector4(1, 1, 1, 0.7f); color = MakeVector4(1, 1, 1, 0.7f);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color); ParticleSpriteEntity *ent = new ParticleSpriteEntity(this, img, color);
Vector3 dir = MakeVector3(GetRandom() - GetRandom(), GetRandom() - GetRandom(), Vector3 dir = MakeVector3(rng.SampleFloat() - rng.SampleFloat(),
-GetRandom() * 3.f); rng.SampleFloat() - rng.SampleFloat(),
float radius = 0.03f + GetRandom() * GetRandom() * 0.05f; -rng.SampleFloat() * 3.f);
float radius = 0.03f + rng.SampleFloat() * rng.SampleFloat() * 0.05f;
ent->SetTrajectory(origin + dir * .2f + MakeVector3(0, 0, -1.2f), dir * 5.f, ent->SetTrajectory(origin + dir * .2f + MakeVector3(0, 0, -1.2f), dir * 5.f,
.1f + radius * 3.f, 1.f); .1f + radius * 3.f, 1.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(rng.SampleFloat() * (float)M_PI * 2.f);
ent->SetRadius(radius); ent->SetRadius(radius);
ent->SetLifeTime(3.5f + GetRandom() * 2.f, 0.f, 1.f); ent->SetLifeTime(3.5f + rng.SampleFloat() * 2.f, 0.f, 1.f);
ent->SetBlockHitAction(ParticleSpriteEntity::Delete); ent->SetBlockHitAction(ParticleSpriteEntity::Delete);
localEntities.emplace_back(ent); localEntities.emplace_back(ent);
} }

View File

@ -46,10 +46,6 @@ DEFINE_SPADES_SETTING(cg_manualFocus, "0");
DEFINE_SPADES_SETTING(cg_depthOfFieldAmount, "1"); DEFINE_SPADES_SETTING(cg_depthOfFieldAmount, "1");
DEFINE_SPADES_SETTING(cg_shake, "1"); DEFINE_SPADES_SETTING(cg_shake, "1");
static float nextRandom() {
return spades::real_dist(spades::client::mt_engine_client);
}
namespace spades { namespace spades {
namespace client { namespace client {
@ -210,8 +206,8 @@ namespace spades {
localFireVibration *= 0.4f; localFireVibration *= 0.4f;
} }
roll += (nextRandom() - nextRandom()) * 0.03f * localFireVibration; roll += (SampleRandomFloat() - SampleRandomFloat()) * 0.03f * localFireVibration;
scale += nextRandom() * 0.04f * localFireVibration; scale += SampleRandomFloat() * 0.04f * localFireVibration;
vibPitch += localFireVibration * (1.f - localFireVibration) * 0.01f; vibPitch += localFireVibration * (1.f - localFireVibration) * 0.01f;
vibYaw += sinf(localFireVibration * (float)M_PI * 2.f) * 0.001f; vibYaw += sinf(localFireVibration * (float)M_PI * 2.f) * 0.001f;
@ -391,10 +387,10 @@ namespace spades {
grenVib *= 10.f; grenVib *= 10.f;
if (grenVib > 1.f) if (grenVib > 1.f)
grenVib = 1.f; grenVib = 1.f;
roll += (nextRandom() - nextRandom()) * 0.2f * grenVib; roll += (SampleRandomFloat() - SampleRandomFloat()) * 0.2f * grenVib;
vibPitch += (nextRandom() - nextRandom()) * 0.1f * grenVib; vibPitch += (SampleRandomFloat() - SampleRandomFloat()) * 0.1f * grenVib;
vibYaw += (nextRandom() - nextRandom()) * 0.1f * grenVib; vibYaw += (SampleRandomFloat() - SampleRandomFloat()) * 0.1f * grenVib;
scale -= (nextRandom() - nextRandom()) * 0.1f * grenVib; scale -= (SampleRandomFloat() - SampleRandomFloat()) * 0.1f * grenVib;
def.radialBlur += grenVib * 0.1f; def.radialBlur += grenVib * 0.1f;
} }

View File

@ -524,7 +524,7 @@ namespace spades {
lastHurtTime = world->GetTime(); lastHurtTime = world->GetTime();
Handle<IAudioChunk> c; Handle<IAudioChunk> c;
switch ((mt_engine_client() >> 3) & 3) { switch (SampleRandomInt(0, 3)) {
case 0: case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal1.opus"); c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/FleshLocal1.opus");
break; break;
@ -545,10 +545,10 @@ namespace spades {
hurtSprites.resize(std::max(cnt, 6)); hurtSprites.resize(std::max(cnt, 6));
for (size_t i = 0; i < hurtSprites.size(); i++) { for (size_t i = 0; i < hurtSprites.size(); i++) {
HurtSprite &spr = hurtSprites[i]; HurtSprite &spr = hurtSprites[i];
spr.angle = GetRandom() * (2.f * static_cast<float>(M_PI)); spr.angle = SampleRandomFloat() * (2.f * static_cast<float>(M_PI));
spr.scale = .2f + GetRandom() * GetRandom() * .7f; spr.scale = .2f + SampleRandomFloat() * SampleRandomFloat() * .7f;
spr.horzShift = GetRandom(); spr.horzShift = SampleRandomFloat();
spr.strength = .3f + GetRandom() * .7f; spr.strength = .3f + SampleRandomFloat() * .7f;
if (hpper > .5f) { if (hpper > .5f) {
spr.strength *= 1.5f - hpper; spr.strength *= 1.5f - hpper;
} }
@ -605,17 +605,17 @@ namespace spades {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
if (!IsMuted()) { if (!IsMuted()) {
const char *snds[] = {"Sounds/Player/Footstep1.opus", "Sounds/Player/Footstep2.opus", std::array<const char *, 8> snds = {"Sounds/Player/Footstep1.opus", "Sounds/Player/Footstep2.opus",
"Sounds/Player/Footstep3.opus", "Sounds/Player/Footstep4.opus", "Sounds/Player/Footstep3.opus", "Sounds/Player/Footstep4.opus",
"Sounds/Player/Footstep5.opus", "Sounds/Player/Footstep6.opus", "Sounds/Player/Footstep5.opus", "Sounds/Player/Footstep6.opus",
"Sounds/Player/Footstep7.opus", "Sounds/Player/Footstep8.opus"}; "Sounds/Player/Footstep7.opus", "Sounds/Player/Footstep8.opus"};
const char *rsnds[] = { std::array<const char *, 12> rsnds = {
"Sounds/Player/Run1.opus", "Sounds/Player/Run2.opus", "Sounds/Player/Run3.opus", "Sounds/Player/Run1.opus", "Sounds/Player/Run2.opus", "Sounds/Player/Run3.opus",
"Sounds/Player/Run4.opus", "Sounds/Player/Run5.opus", "Sounds/Player/Run6.opus", "Sounds/Player/Run4.opus", "Sounds/Player/Run5.opus", "Sounds/Player/Run6.opus",
"Sounds/Player/Run7.opus", "Sounds/Player/Run8.opus", "Sounds/Player/Run9.opus", "Sounds/Player/Run7.opus", "Sounds/Player/Run8.opus", "Sounds/Player/Run9.opus",
"Sounds/Player/Run10.opus", "Sounds/Player/Run11.opus", "Sounds/Player/Run12.opus", "Sounds/Player/Run10.opus", "Sounds/Player/Run11.opus", "Sounds/Player/Run12.opus",
}; };
const char *wsnds[] = {"Sounds/Player/Wade1.opus", "Sounds/Player/Wade2.opus", std::array<const char *, 8> wsnds = {"Sounds/Player/Wade1.opus", "Sounds/Player/Wade2.opus",
"Sounds/Player/Wade3.opus", "Sounds/Player/Wade4.opus", "Sounds/Player/Wade3.opus", "Sounds/Player/Wade4.opus",
"Sounds/Player/Wade5.opus", "Sounds/Player/Wade6.opus", "Sounds/Player/Wade5.opus", "Sounds/Player/Wade6.opus",
"Sounds/Player/Wade7.opus", "Sounds/Player/Wade8.opus"}; "Sounds/Player/Wade7.opus", "Sounds/Player/Wade8.opus"};
@ -623,13 +623,13 @@ namespace spades {
? clientPlayers[p->GetId()]->GetSprintState() > 0.5f ? clientPlayers[p->GetId()]->GetSprintState() > 0.5f
: false; : false;
Handle<IAudioChunk> c = Handle<IAudioChunk> c =
p->GetWade() ? audioDevice->RegisterSound(wsnds[(mt_engine_client() >> 8) % 8]) p->GetWade() ? audioDevice->RegisterSound(SampleRandomElement(wsnds))
: audioDevice->RegisterSound(snds[(mt_engine_client() >> 8) % 8]); : audioDevice->RegisterSound(SampleRandomElement(snds));
audioDevice->Play(c, p->GetOrigin(), AudioParam()); audioDevice->Play(c, p->GetOrigin(), AudioParam());
if (sprinting && !p->GetWade()) { if (sprinting && !p->GetWade()) {
AudioParam param; AudioParam param;
param.volume *= clientPlayers[p->GetId()]->GetSprintState(); param.volume *= clientPlayers[p->GetId()]->GetSprintState();
c = audioDevice->RegisterSound(rsnds[(mt_engine_client() >> 8) % 12]); c = audioDevice->RegisterSound(SampleRandomElement(rsnds));
audioDevice->Play(c, p->GetOrigin(), param); audioDevice->Play(c, p->GetOrigin(), param);
} }
} }
@ -779,7 +779,7 @@ namespace spades {
if (victim != world->GetLocalPlayer()) { if (victim != world->GetLocalPlayer()) {
if (!IsMuted()) { if (!IsMuted()) {
Handle<IAudioChunk> c; Handle<IAudioChunk> c;
switch (mt_engine_client() % 3) { switch (SampleRandomInt(0, 2)) {
case 0: case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus"); c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus");
break; break;
@ -839,7 +839,7 @@ namespace spades {
} }
corp->AddImpulse(dir); corp->AddImpulse(dir);
} else if (kt == KillTypeGrenade) { } else if (kt == KillTypeGrenade) {
corp->AddImpulse(MakeVector3(0, 0, -4.f - GetRandom() * 4.f)); corp->AddImpulse(MakeVector3(0, 0, -4.f - SampleRandomFloat() * 4.f));
} }
corp->AddImpulse(victim->GetVelocty() * 32.f); corp->AddImpulse(victim->GetVelocty() * 32.f);
corpses.emplace_back(corp); corpses.emplace_back(corp);
@ -964,7 +964,7 @@ namespace spades {
audioDevice->Play(c, hitPos, AudioParam()); audioDevice->Play(c, hitPos, AudioParam());
} else { } else {
Handle<IAudioChunk> c; Handle<IAudioChunk> c;
switch ((mt_engine_client() >> 6) % 3) { switch (SampleRandomInt(0, 2)) {
case 0: case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus"); c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Flesh1.opus");
break; break;
@ -1019,8 +1019,8 @@ namespace spades {
Handle<IAudioChunk> c; Handle<IAudioChunk> c;
param.pitch = .9f + GetRandom() * 0.2f; param.pitch = .9f + SampleRandomFloat() * 0.2f;
switch ((mt_engine_client() >> 6) & 3) { switch (SampleRandomInt(0, 3)) {
case 0: case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Water1.opus"); c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Water1.opus");
break; break;
@ -1044,20 +1044,12 @@ namespace spades {
param.volume = 2.f; param.volume = 2.f;
Handle<IAudioChunk> c; Handle<IAudioChunk> c;
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Block.opus");
switch ((mt_engine_client() >> 6) & 3) {
case 0:
case 1:
case 2:
case 3:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Block.opus");
break;
}
audioDevice->Play(c, shiftedHitPos, param); audioDevice->Play(c, shiftedHitPos, param);
param.pitch = .9f + GetRandom() * 0.2f; param.pitch = .9f + SampleRandomFloat() * 0.2f;
param.volume = 2.f; param.volume = 2.f;
switch ((mt_engine_client() >> 6) & 3) { switch (SampleRandomInt(0, 3)) {
case 0: case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Ricochet1.opus"); c = audioDevice->RegisterSound("Sounds/Weapons/Impacts/Ricochet1.opus");
break; break;
@ -1170,7 +1162,7 @@ namespace spades {
if (!IsMuted()) { if (!IsMuted()) {
Handle<IAudioChunk> c, cs; Handle<IAudioChunk> c, cs;
switch ((mt_engine_client() >> 8) & 1) { switch (SampleRandomInt(0, 1)) {
case 0: case 0:
c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode1.opus"); c = audioDevice->RegisterSound("Sounds/Weapons/Grenade/Explode1.opus");
cs = audioDevice->RegisterSound( cs = audioDevice->RegisterSound(

View File

@ -54,50 +54,56 @@ namespace spades {
Matrix4 torso; Matrix4 torso;
LocalRNG rng;
if (crouch) { if (crouch) {
lower = lower * Matrix4::Translate(0, 0, -0.4f); lower = lower * Matrix4::Translate(0, 0, -0.4f);
torso = lower * Matrix4::Translate(0, 0, -0.3f); torso = lower * Matrix4::Translate(0, 0, -0.3f);
SetNode(Torso1, torso * MakeVector3(0.4f, -.15f, 0.1f)); SetNode(rng, Torso1, torso * MakeVector3(0.4f, -.15f, 0.1f));
SetNode(Torso2, torso * MakeVector3(-0.4f, -.15f, 0.1f)); SetNode(rng, Torso2, torso * MakeVector3(-0.4f, -.15f, 0.1f));
SetNode(Torso3, torso * MakeVector3(-0.4f, .8f, 0.7f)); SetNode(rng, Torso3, torso * MakeVector3(-0.4f, .8f, 0.7f));
SetNode(Torso4, torso * MakeVector3(0.4f, .8f, 0.7f)); SetNode(rng, Torso4, torso * MakeVector3(0.4f, .8f, 0.7f));
SetNode(Leg1, lower * MakeVector3(-0.4f, .1f, 1.f)); SetNode(rng, Leg1, lower * MakeVector3(-0.4f, .1f, 1.f));
SetNode(Leg2, lower * MakeVector3(0.4f, .1f, 1.f)); SetNode(rng, Leg2, lower * MakeVector3(0.4f, .1f, 1.f));
SetNode(Arm1, torso * MakeVector3(0.2f, -.4f, .2f)); SetNode(rng, Arm1, torso * MakeVector3(0.2f, -.4f, .2f));
SetNode(Arm2, torso * MakeVector3(-0.2f, -.4f, .2f)); SetNode(rng, Arm2, torso * MakeVector3(-0.2f, -.4f, .2f));
} else { } else {
torso = lower * Matrix4::Translate(0, 0, -1.1f); torso = lower * Matrix4::Translate(0, 0, -1.1f);
SetNode(Torso1, torso * MakeVector3(0.4f, 0.f, 0.1f)); SetNode(rng, Torso1, torso * MakeVector3(0.4f, 0.f, 0.1f));
SetNode(Torso2, torso * MakeVector3(-0.4f, 0.f, 0.1f)); SetNode(rng, Torso2, torso * MakeVector3(-0.4f, 0.f, 0.1f));
SetNode(Torso3, torso * MakeVector3(-0.4f, .0f, 1.f)); SetNode(rng, Torso3, torso * MakeVector3(-0.4f, .0f, 1.f));
SetNode(Torso4, torso * MakeVector3(0.4f, .0f, 1.f)); SetNode(rng, Torso4, torso * MakeVector3(0.4f, .0f, 1.f));
SetNode(Leg1, lower * MakeVector3(-0.4f, .0f, 1.f)); SetNode(rng, Leg1, lower * MakeVector3(-0.4f, .0f, 1.f));
SetNode(Leg2, lower * MakeVector3(0.4f, .0f, 1.f)); SetNode(rng, Leg2, lower * MakeVector3(0.4f, .0f, 1.f));
SetNode(Arm1, torso * MakeVector3(0.2f, -.4f, .2f)); SetNode(rng, Arm1, torso * MakeVector3(0.2f, -.4f, .2f));
SetNode(Arm2, torso * MakeVector3(-0.2f, -.4f, .2f)); SetNode(rng, Arm2, torso * MakeVector3(-0.2f, -.4f, .2f));
} }
SetNode(Head, (nodes[Torso1].pos + nodes[Torso2].pos) * .5f + MakeVector3(0, 0, -0.6f)); SetNode(rng, Head,
(nodes[Torso1].pos + nodes[Torso2].pos) * .5f + MakeVector3(0, 0, -0.6f));
} }
static float VelNoise() { return (GetRandom() - GetRandom()) * 2.f; } void Corpse::SetNode(LocalRNG &rng, NodeType n, spades::Vector3 v) {
auto velNoise = [&] { return (rng.SampleFloat() - rng.SampleFloat()) * 2.0f; };
void Corpse::SetNode(NodeType n, spades::Vector3 v) {
SPAssert(n >= 0); SPAssert(n >= 0);
SPAssert(n < NodeCount); SPAssert(n < NodeCount);
nodes[n].pos = v; nodes[n].pos = v;
nodes[n].vel = MakeVector3(VelNoise(), VelNoise(), 0.f); nodes[n].vel = MakeVector3(velNoise(), velNoise(), 0.f);
nodes[n].lastPos = v; nodes[n].lastPos = v;
nodes[n].lastForce = MakeVector3(0, 0, 0); nodes[n].lastForce = MakeVector3(0, 0, 0);
} }
void Corpse::SetNode(NodeType n, spades::Vector4 v) { SetNode(n, v.GetXYZ()); } void Corpse::SetNode(LocalRNG &rng, NodeType n, spades::Vector4 v) {
SetNode(rng, n, v.GetXYZ());
}
Corpse::~Corpse() {} Corpse::~Corpse() {}

View File

@ -69,8 +69,8 @@ namespace spades {
Node nodes[NodeCount]; Node nodes[NodeCount];
Edge edges[8]; Edge edges[8];
void SetNode(NodeType n, Vector3); void SetNode(LocalRNG&, NodeType n, Vector3);
void SetNode(NodeType n, Vector4); void SetNode(LocalRNG&, NodeType n, Vector4);
void Spring(NodeType n1, NodeType n2, float distance, float dt); void Spring(NodeType n1, NodeType n2, float distance, float dt);
void Spring(NodeType n1a, NodeType n1b, NodeType n2, float distance, float dt); void Spring(NodeType n1a, NodeType n1b, NodeType n2, float distance, float dt);

View File

@ -135,6 +135,9 @@ namespace spades {
client->grenadeVibration += impact / (dist + 5.f); client->grenadeVibration += impact / (dist + 5.f);
if (client->grenadeVibration > 1.f) if (client->grenadeVibration > 1.f)
client->grenadeVibration = 1.f; client->grenadeVibration = 1.f;
LocalRNG rng;
auto getRandom = [&] { return rng.SampleFloat(); };
for (int x = 0; x < w; x++) { for (int x = 0; x < w; x++) {
Vector3 p1 = vmOrigin + vmAxis1 * (float)x; Vector3 p1 = vmOrigin + vmAxis1 * (float)x;
@ -162,15 +165,15 @@ namespace spades {
{ {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new SmokeSpriteEntity(client, col, 70.f); new SmokeSpriteEntity(client, col, 70.f);
ent->SetTrajectory(p3, (MakeVector3(GetRandom() - GetRandom(), ent->SetTrajectory(p3, (MakeVector3(getRandom() - getRandom(),
GetRandom() - GetRandom(), getRandom() - getRandom(),
GetRandom() - GetRandom())) * getRandom() - getRandom())) *
0.2f, 0.2f,
1.f, 0.f); 1.f, 0.f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(getRandom() * (float)M_PI * 2.f);
ent->SetRadius(1.0f, 0.5f); ent->SetRadius(1.0f, 0.5f);
ent->SetBlockHitAction(ParticleSpriteEntity::Ignore); ent->SetBlockHitAction(ParticleSpriteEntity::Ignore);
ent->SetLifeTime(1.0f + GetRandom() * 0.5f, 0.f, 1.0f); ent->SetLifeTime(1.0f + getRandom() * 0.5f, 0.f, 1.0f);
client->AddLocalEntity(ent); client->AddLocalEntity(ent);
} }
@ -178,13 +181,13 @@ namespace spades {
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
ParticleSpriteEntity *ent = ParticleSpriteEntity *ent =
new ParticleSpriteEntity(client, img, col); new ParticleSpriteEntity(client, img, col);
ent->SetTrajectory(p3, MakeVector3(GetRandom() - GetRandom(), ent->SetTrajectory(p3, MakeVector3(getRandom() - getRandom(),
GetRandom() - GetRandom(), getRandom() - getRandom(),
GetRandom() - GetRandom()) * getRandom() - getRandom()) *
13.f, 13.f,
1.f, .6f); 1.f, .6f);
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); ent->SetRotation(getRandom() * (float)M_PI * 2.f);
ent->SetRadius(0.35f + GetRandom() * GetRandom() * 0.1f); ent->SetRadius(0.35f + getRandom() * getRandom() * 0.1f);
ent->SetLifeTime(2.f, 0.f, 1.f); ent->SetLifeTime(2.f, 0.f, 1.f);
if (usePrecisePhysics) if (usePrecisePhysics)
ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak); ent->SetBlockHitAction(ParticleSpriteEntity::BounceWeak);
@ -215,4 +218,4 @@ namespace spades {
client->GetRenderer()->RenderModel(model, param); client->GetRenderer()->RenderModel(model, param);
} }
} }
} }

View File

@ -37,12 +37,14 @@ namespace spades {
GameMap::GameMap() { GameMap::GameMap() {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
LocalRNG rng;
for (int x = 0; x < DefaultWidth; x++) for (int x = 0; x < DefaultWidth; x++)
for (int y = 0; y < DefaultHeight; y++) { for (int y = 0; y < DefaultHeight; y++) {
solidMap[x][y] = 1; // ground only solidMap[x][y] = 1; // ground only
for (int z = 0; z < DefaultDepth; z++) { for (int z = 0; z < DefaultDepth; z++) {
uint32_t col = 0x00284067; uint32_t col = 0x00284067;
col ^= 0x070707 & static_cast<uint32_t>(mt_engine()); col ^= 0x070707 & static_cast<uint32_t>(rng());
colorMap[x][y][z] = col + (100UL * 0x1000000UL); colorMap[x][y][z] = col + (100UL * 0x1000000UL);
} }
} }

View File

@ -64,9 +64,9 @@ namespace spades {
} }
static Vector3 RandomAxis() { static Vector3 RandomAxis() {
Vector3 v; Vector3 v;
v.x = GetRandom() - GetRandom(); v.x = SampleRandomFloat() - SampleRandomFloat();
v.y = GetRandom() - GetRandom(); v.y = SampleRandomFloat() - SampleRandomFloat();
v.z = GetRandom() - GetRandom(); v.z = SampleRandomFloat() - SampleRandomFloat();
return v.Normalize(); return v.Normalize();
} }
bool GunCasing::Update(float dt) { bool GunCasing::Update(float dt) {
@ -100,7 +100,7 @@ namespace spades {
IAudioDevice *dev = client->GetAudioDevice(); IAudioDevice *dev = client->GetAudioDevice();
AudioParam param; AudioParam param;
param.referenceDistance = .6f; param.referenceDistance = .6f;
param.pitch = .9f + GetRandom() * .2f; param.pitch = .9f + SampleRandomFloat() * .2f;
dev->Play(waterSound, lastMat.GetOrigin(), param); dev->Play(waterSound, lastMat.GetOrigin(), param);
} }
@ -108,7 +108,7 @@ namespace spades {
} }
if (dist < 40.f * 40.f) { if (dist < 40.f * 40.f) {
int splats = mt_engine_client() % 3; int splats = SampleRandomInt(0, 2);
Handle<IImage> img = client->GetRenderer()->RegisterImage("Gfx/White.tga"); Handle<IImage> img = client->GetRenderer()->RegisterImage("Gfx/White.tga");
@ -117,13 +117,15 @@ namespace spades {
pt.z = 62.99f; pt.z = 62.99f;
for (int i = 0; i < splats; i++) { for (int i = 0; i < splats; i++) {
ParticleSpriteEntity *ent = new ParticleSpriteEntity(client, img, col); ParticleSpriteEntity *ent = new ParticleSpriteEntity(client, img, col);
ent->SetTrajectory(pt, MakeVector3(GetRandom() - GetRandom(), ent->SetTrajectory(
GetRandom() - GetRandom(), pt,
-GetRandom()) * MakeVector3(SampleRandomFloat() - SampleRandomFloat(),
2.f, SampleRandomFloat() - SampleRandomFloat(),
1.f, .4f); -SampleRandomFloat()) *
ent->SetRotation(GetRandom() * (float)M_PI * 2.f); 2.f,
ent->SetRadius(0.1f + GetRandom() * GetRandom() * 0.1f); 1.f, .4f);
ent->SetRotation(SampleRandomFloat() * (float)M_PI * 2.f);
ent->SetRadius(0.1f + SampleRandomFloat() * SampleRandomFloat() * 0.1f);
ent->SetLifeTime(2.f, 0.f, 1.f); ent->SetLifeTime(2.f, 0.f, 1.f);
client->AddLocalEntity(ent); client->AddLocalEntity(ent);
} }
@ -194,9 +196,9 @@ namespace spades {
rotAxis = RandomAxis(); rotAxis = RandomAxis();
Vector3 r; Vector3 r;
r.x = GetRandom() - GetRandom(); r.x = SampleRandomFloat() - SampleRandomFloat();
r.y = GetRandom() - GetRandom(); r.y = SampleRandomFloat() - SampleRandomFloat();
r.z = GetRandom() - GetRandom(); r.z = SampleRandomFloat() - SampleRandomFloat();
vel += r * 0.1f; vel += r * 0.1f;

View File

@ -665,7 +665,7 @@ namespace spades {
visibleLength = shutterTime * velocity; visibleLength = shutterTime * velocity;
curDistance = -visibleLength; curDistance = -visibleLength;
curDistance += maxTimeSpread * GetRandom(); curDistance += maxTimeSpread * SampleRandomFloat();
firstUpdate = true; firstUpdate = true;
} }

View File

@ -27,9 +27,11 @@ namespace spades {
namespace client { namespace client {
CoherentNoiseSampler1D::CoherentNoiseSampler1D() { CoherentNoiseSampler1D::CoherentNoiseSampler1D() {
LocalRNG rng;
values.resize(1024); values.resize(1024);
for (float &value : values) { for (float &value : values) {
value = GetRandom() - GetRandom(); value = rng.SampleFloat() - rng.SampleFloat();
} }
} }
@ -54,9 +56,11 @@ namespace spades {
} }
GradientCoherentNoiseSampler1D::GradientCoherentNoiseSampler1D() { GradientCoherentNoiseSampler1D::GradientCoherentNoiseSampler1D() {
LocalRNG rng;
derivatives.resize(1024); derivatives.resize(1024);
for (float &derivative : derivatives) { for (float &derivative : derivatives) {
derivative = (GetRandom() - GetRandom()) * 4.f; derivative = (rng.SampleFloat() - rng.SampleFloat()) * 4.f;
} }
} }

View File

@ -564,14 +564,16 @@ namespace spades {
// pyspades takes destroying more than one block as a // pyspades takes destroying more than one block as a
// speed hack (shotgun does this) // speed hack (shotgun does this)
bool blockDestroyed = false; bool blockDestroyed = false;
LocalRNG rng;
Vector3 dir2 = GetFront(); Vector3 dir2 = GetFront();
for (int i = 0; i < pellets; i++) { for (int i = 0; i < pellets; i++) {
// AoS 0.75's way (dir2 shouldn't be normalized!) // AoS 0.75's way (dir2 shouldn't be normalized!)
dir2.x += (GetRandom() - GetRandom()) * spread; dir2.x += (rng.SampleFloat() - rng.SampleFloat()) * spread;
dir2.y += (GetRandom() - GetRandom()) * spread; dir2.y += (rng.SampleFloat() - rng.SampleFloat()) * spread;
dir2.z += (GetRandom() - GetRandom()) * spread; dir2.z += (rng.SampleFloat() - rng.SampleFloat()) * spread;
Vector3 dir = dir2.Normalize(); Vector3 dir = dir2.Normalize();
bulletVectors.push_back(dir); bulletVectors.push_back(dir);

View File

@ -25,7 +25,7 @@ namespace spades {
visibleLength = shutterTime * velocity; visibleLength = shutterTime * velocity;
curDistance = -visibleLength; curDistance = -visibleLength;
curDistance += maxTimeSpread * GetRandom(); curDistance += maxTimeSpread * SampleRandomFloat();
firstUpdate = true; firstUpdate = true;

View File

@ -20,6 +20,7 @@
#include <new> #include <new>
#include <cstdlib> #include <cstdlib>
#include <mutex>
#include "Math.h" #include "Math.h"
#include <Core/Debug.h> #include <Core/Debug.h>
@ -37,11 +38,37 @@ namespace spades {
} }
*/ */
std::random_device r_device; namespace {
std::mt19937_64 std::random_device r_device;
mt_engine(r_device()); // Seed Mersenne twister with non-deterministic 32-bit seed } // namespace
std::uniform_real_distribution<float> real_dist(0, 1); ThreadSafeRNG globalThreadSafeRNG;
// Seed Mersenne twister with non-deterministic seed
ThreadSafeRNG::ThreadSafeRNG() : inner{r_device()} {}
auto ThreadSafeRNG::operator()() -> result_type {
std::lock_guard<std::mutex> lock{mutex};
return inner();
}
LocalRNG::LocalRNG() {
do {
s[0] = SampleRandom();
} while (s[0] == 0);
do {
s[1] = SampleRandom();
} while (s[1] == 0);
}
auto LocalRNG::operator()() -> result_type {
uint64_t x = s[0];
uint64_t y = s[1];
s[0] = y;
x ^= x << 23; // a
s[1] = x ^ y ^ (x >> 17) ^ (y >> 26); // b, c
return s[1] + y;
}
void Matrix4Multiply(const float a[16], const float b[16], float out[16]) { void Matrix4Multiply(const float a[16], const float b[16], float out[16]) {
out[0] = b[0] * a[0] + b[1] * a[4] + b[2] * a[8] + b[3] * a[12]; out[0] = b[0] * a[0] + b[1] * a[4] + b[2] * a[8] + b[3] * a[12];
@ -634,7 +661,6 @@ namespace spades {
return (uint32_t)str[start]; return (uint32_t)str[start];
} }
float GetRandom() { return real_dist(mt_engine); }
float SmoothStep(float v) { return v * v * (3.f - 2.f * v); } float SmoothStep(float v) { return v * v * (3.f - 2.f * v); }
float Mix(float a, float b, float frac) { return a + (b - a) * frac; } float Mix(float a, float b, float frac) { return a + (b - a) * frac; }

View File

@ -30,9 +30,88 @@
namespace spades { namespace spades {
// Make mt_engine and a real dist [0,1] accesible everywhere in the spades namespace #pragma mark - Random number generation
extern std::mt19937_64 mt_engine; /**
extern std::uniform_real_distribution<float> real_dist; * A thread-safe random number generator satistying
* `UniformRandomBitGenerator`.
*/
class ThreadSafeRNG {
public:
using inner_type = std::mt19937_64;
using result_type = inner_type::result_type;
ThreadSafeRNG();
result_type operator()();
static constexpr result_type min() { return inner_type::min(); }
static constexpr result_type max() { return inner_type::max(); }
private:
inner_type inner;
std::mutex mutex;
};
extern ThreadSafeRNG globalThreadSafeRNG;
/** Generates a random `uint_fast64_t`. This function is thread-safe. */
inline std::uint_fast64_t SampleRandom() { return globalThreadSafeRNG(); }
/** Generates a random `float`. This function is thread-safe. */
inline float SampleRandomFloat() {
return std::uniform_real_distribution<float>{}(globalThreadSafeRNG);
}
/**
* Generates an integer in a specified inclusive range.
* This function is thread-safe.
*/
template <class T = int> inline T SampleRandomInt(T a, T b) {
return std::uniform_int_distribution<T>{a, b}(globalThreadSafeRNG);
}
/** Generates a random `bool`. This function is thread-safe. */
inline bool SampleRandomBool() { return globalThreadSafeRNG() & 0x1; }
/** Get a mutable reference to a random element from a container. */
template <class T> inline typename T::reference SampleRandomElement(T &container) {
auto begin = std::begin(container);
auto end = std::end(container);
auto numElements = std::distance(begin, end);
begin += SampleRandomInt<typeof(numElements)>(0, numElements - 1);
return *begin;
}
/** Get a constant reference to a random element from a container. */
template <class T> inline typename T::const_reference SampleRandomElement(const T &container) {
auto begin = std::begin(container);
auto end = std::end(container);
auto numElements = std::distance(begin, end);
begin += SampleRandomInt(0, numElements - 1);
return *begin;
}
/** Thread-unsafe random number generator. */
class LocalRNG {
public:
using result_type = std::uint64_t;
LocalRNG();
result_type operator()();
float SampleFloat() { return std::uniform_real_distribution<float>{}(*this); }
template <class T = int> inline T SampleInt(T a, T b) {
return std::uniform_int_distribution<T>{a, b}(*this);
}
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return std::numeric_limits<result_type>::max(); }
private:
std::uint64_t s[2];
};
#pragma mark - Integer Vector #pragma mark - Integer Vector
@ -936,7 +1015,6 @@ namespace spades {
std::string TrimSpaces(const std::string &); std::string TrimSpaces(const std::string &);
float GetRandom();
float SmoothStep(float); float SmoothStep(float);
} }

View File

@ -47,9 +47,11 @@ namespace spades {
GLAmbientShadowRenderer::GLAmbientShadowRenderer(GLRenderer *r, client::GameMap *m) GLAmbientShadowRenderer::GLAmbientShadowRenderer(GLRenderer *r, client::GameMap *m)
: renderer(r), device(r->GetGLDevice()), map(m) { : renderer(r), device(r->GetGLDevice()), map(m) {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
LocalRNG rng;
for (int i = 0; i < NumRays; i++) { for (int i = 0; i < NumRays; i++) {
Vector3 dir = MakeVector3(GetRandom(), GetRandom(), GetRandom()); Vector3 dir = MakeVector3(rng.SampleFloat(), rng.SampleFloat(), rng.SampleFloat());
dir = dir.Normalize(); dir = dir.Normalize();
dir += 0.01f; dir += 0.01f;
rays[i] = dir; rays[i] = dir;
@ -337,10 +339,11 @@ namespace spades {
} }
// limit update count per frame // limit update count per frame
LocalRNG rng;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
if (numDirtyChunks <= 0) if (numDirtyChunks <= 0)
break; break;
int idx = mt_engine() % numDirtyChunks; int idx = rng.SampleInt(0, numDirtyChunks - 1);
Chunk &c = chunks[dirtyChunkIds[idx]]; Chunk &c = chunks[dirtyChunkIds[idx]];
// remove from list (fast) // remove from list (fast)

View File

@ -139,9 +139,10 @@ namespace spades {
void GLLensDustFilter::UpdateNoise() { void GLLensDustFilter::UpdateNoise() {
SPADES_MARK_FUNCTION(); SPADES_MARK_FUNCTION();
LocalRNG rng;
noise.resize(128 * 128); noise.resize(128 * 128);
for (size_t i = 0; i < 128 * 128; i++) { for (size_t i = 0; i < 128 * 128; i++) {
noise[i] = static_cast<std::uint32_t>(mt_engine()); noise[i] = static_cast<std::uint32_t>(rng());
} }
IGLDevice *dev = renderer->GetGLDevice(); IGLDevice *dev = renderer->GetGLDevice();

View File

@ -438,10 +438,11 @@ namespace spades {
} }
// limit update count per frame // limit update count per frame
LocalRNG rng;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
if (numDirtyChunks <= 0) if (numDirtyChunks <= 0)
break; break;
int idx = mt_engine() % numDirtyChunks; int idx = rng.SampleInt(0, numDirtyChunks - 1);
Chunk &c = chunks[dirtyChunkIds[idx]]; Chunk &c = chunks[dirtyChunkIds[idx]];
// remove from list (fast) // remove from list (fast)

View File

@ -187,6 +187,9 @@ namespace spades {
public: public:
FFTWaveTank() : IWaveTank(Size) { FFTWaveTank() : IWaveTank(Size) {
LocalRNG rng;
auto getRandom = [&] { return rng.SampleFloat(); };
fft = kiss_fft_alloc(Size, 1, NULL, NULL); fft = kiss_fft_alloc(Size, 1, NULL, NULL);
for (int x = 0; x < Size; x++) { for (int x = 0; x < Size; x++) {
@ -207,14 +210,14 @@ namespace spades {
mag *= expf(-scal * 3.f); mag *= expf(-scal * 3.f);
cell.magnitude = mag; cell.magnitude = mag;
cell.phase = static_cast<uint32_t>(mt_engine()); cell.phase = static_cast<uint32_t>(rng());
cell.phasePerSecond = dist * 1.e+9f * 128 / Size; cell.phasePerSecond = dist * 1.e+9f * 128 / Size;
} }
cell.m00 = GetRandom() - GetRandom(); cell.m00 = getRandom() - getRandom();
cell.m01 = GetRandom() - GetRandom(); cell.m01 = getRandom() - getRandom();
cell.m10 = GetRandom() - GetRandom(); cell.m10 = getRandom() - getRandom();
cell.m11 = GetRandom() - GetRandom(); cell.m11 = getRandom() - getRandom();
} }
} }
} }
@ -420,12 +423,13 @@ namespace spades {
int count = (int)floorf(dt * 600.f); int count = (int)floorf(dt * 600.f);
if (count > 400) if (count > 400)
count = 400; count = 400;
LocalRNG rng;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int ox = mt_engine() % (size - 2); int ox = rng.SampleInt(0, size - 3);
int oy = mt_engine() % (size - 2); int oy = rng.SampleInt(0, size - 3);
static const float gauss[] = {0.225610111284052f, 0.548779777431897f, static const float gauss[] = {0.225610111284052f, 0.548779777431897f,
0.225610111284052f}; 0.225610111284052f};
float strength = (GetRandom() - GetRandom()) * 0.15f * 100.f; float strength = (rng.SampleFloat() - rng.SampleFloat()) * 0.15f * 100.f;
for (int x = 0; x < 3; x++) for (int x = 0; x < 3; x++)
for (int y = 0; y < 3; y++) { for (int y = 0; y < 3; y++) {
velocity[(x + ox) + (y + oy) * size] += strength * gauss[x] * gauss[y]; velocity[(x + ox) + (y + oy) * size] += strength * gauss[x] * gauss[y];

View File

@ -35,24 +35,22 @@ namespace spades {
case 1: case 1:
return 0; return 0;
case 2: case 2:
return mt_engine() & 1; return SampleRandom() & 1;
case 4: case 4:
return mt_engine() & 3; return SampleRandom() & 3;
case 8: case 8:
return mt_engine() & 7; return SampleRandom() & 7;
case 16: case 16:
return mt_engine() & 15; return SampleRandom() & 15;
case 32: case 32:
return mt_engine() & 31; return SampleRandom() & 31;
case 64: case 64:
return mt_engine() & 63; return SampleRandom() & 63;
} }
// We can't directly use the engine here, we need a distribution // We can't directly use the engine here, we need a distribution
// range - 1 because it's inclusive and we want exclusive // range - 1 because it's inclusive and we want exclusive
std::uniform_int_distribution<unsigned int> int_dist(0, range - 1); return SampleRandomInt<unsigned int>(0, range - 1);
return int_dist(mt_engine);
} }
static unsigned int GetRandomUIntRange(unsigned int a, static unsigned int GetRandomUIntRange(unsigned int a,
unsigned int b){ unsigned int b){
@ -70,7 +68,7 @@ namespace spades {
return (int)(GetRandomInt((unsigned int)(b - a)) + (unsigned int)a); return (int)(GetRandomInt((unsigned int)(b - a)) + (unsigned int)a);
} }
static float GetRandomFloatRange(float a, float b) { static float GetRandomFloatRange(float a, float b) {
return GetRandom() * (b - a) + a; return SampleRandomFloat() * (b - a) + a;
} }
public: public:
MathScriptObjectRegistrar(): MathScriptObjectRegistrar():
@ -995,7 +993,7 @@ namespace spades {
manager->CheckError(r); manager->CheckError(r);
r = eng->RegisterGlobalFunction("float GetRandom()", r = eng->RegisterGlobalFunction("float GetRandom()",
asFUNCTION(GetRandom), asFUNCTION(SampleRandomFloat),
asCALL_CDECL); asCALL_CDECL);
manager->CheckError(r); manager->CheckError(r);