Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 131 additions & 16 deletions FlingEngine/Core/inc/Random.h
Original file line number Diff line number Diff line change
@@ -1,44 +1,159 @@
#pragma once

#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <random>
#include "FlingMath.h"
#include "FlingTypes.h"

namespace Fling
{
/**
* A RandomStream object is a random number generator.
*
* Each RandomStream object has its own random number generator.
*
* Do not call the methods of one RandomStream object from more than one
* thread at the same time.
*/
class FLING_API RandomStream
{
public:

/**
* This constructor makes a new RandomStream object. It seeds the
* object with a random value from the operating system.
*/
RandomStream();

/**
* This constructor makes a new RandomStream object. It seeds the
* object with the value t_Seed.
*
* Two RandomStream objects with the same seed value give the same
* sequence of numbers.
*
* @param t_Seed Use this value to seed the random number generator.
*/
explicit RandomStream(uint32 t_Seed);

/**
* This method gives the stream a new seed. It gets the seed from
* the operating system.
*/
void Reseed();

/**
* This method gives the stream the seed value t_Seed. The stream
* then starts a new sequence of numbers.
*
* @param t_Seed Use this value to seed the random number generator.
*/
void Reseed(uint32 t_Seed);

/**
* This method gives a random whole number. The number is 0 or
* more. The number is less than t_max.
*
* @param t_max t_max must be more than 0.
*/
int Random0ToN(const int t_max);

/**
* This method gives a random whole number between t_min and
* t_max. The number can be equal to t_min. The number can be
* equal to t_max.
*
* @param t_min This is the lowest possible value.
* @param t_max This is the highest possible value.
*/
int RandomBetween(const int t_min, const int t_max);

/**
* This method gives a random decimal number. The number is greater
* than or equal to t_Min. The number is less than t_Max.
*/
float GetRandomFloat(float t_Min, float t_Max);

/**
* This method gives a random vec3 value. Each component of the
* vec3 value (x, y, z) is a separate random number. Each number is
* more than or equal to the related component of t_Min. Each
* number is less than the related component of t_Max.
*/
glm::vec3 GetRandomVec3(const glm::vec3 t_Min, const glm::vec3 t_Max);

private:

/**
* This is the random number engine for this stream. It is
* separate from the engine of every other RandomStream object. It
* is separate from the engine of the Random class.
*/
std::mt19937 m_Engine;
};

/**
* Random is a static class. It gives random numbers to the whole
* process. It uses one shared RandomStream object.
*
* Call methods of the Random class from one thread only. If you need
* random numbers on a worker thread, make your own RandomStream
* object.
*/
class FLING_API Random
{
public:

/**
* Initialize the random number generator
* Initialize the random number generator with a non-deterministic seed
*
* @return True if successful
*/
*/
static bool Init();

/**
* Get a random int between 0 and the max
*
* @param t_max number to generate to
* @return Number between 0 and the given
* Initialize the random number generator with an explicit seed. Two
* engines seeded with the same value produce the same sequence of
* results, which is useful for reproducing a run in tests or when
* tracking down a gameplay bug.
*
* @param t_Seed Seed value to reproduce a given sequence of random values
* @return True if successful
*/
static const int Random0ToN( const int t_max );
static bool Init(uint32 t_Seed);

/**
* Get a random int in [0, t_max): inclusive of 0, exclusive of t_max.
*
* @param t_max Exclusive upper bound; must be greater than 0
*/
static const int Random0ToN(const int t_max);

/**
* Generate a random number between the two given values
*
* @param t_min Min number to gerneate between
* @param t_max Max number to generate between
* @return Random int between the two values
* Generate a random int in [t_min, t_max]: inclusive of both bounds.
*
* @param t_min Inclusive lower bound
* @param t_max Inclusive upper bound
*/
static const int RandomBetween( const int t_min, const int t_max );
static const int RandomBetween(const int t_min, const int t_max);

/** Flag to determine if random has been initialized */
static bool bIsInitalized;

/**
* Generate a random vec3 with each component independently sampled
* from [t_Min, t_Max): inclusive of t_Min, exclusive of t_Max.
*/
static glm::vec3 GetRandomVec3(const glm::vec3 t_Min, const glm::vec3 t_Max);

/**
* Generate a random float in [t_Min, t_Max): inclusive of t_Min,
* exclusive of t_Max.
*/
static float GetRandomFloat(float t_Min, float t_Max);

private:

/** This is the shared RandomStream object for the Random class. */
static RandomStream s_Stream;
};
} // namespace Fling
} // namespace Fling
114 changes: 97 additions & 17 deletions FlingEngine/Core/src/Random.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,122 @@

namespace Fling
{
namespace
{
uint32 GenerateEntropySeed()
{
std::random_device seedSource;
return seedSource();
}

int Random0ToNImpl(std::mt19937& t_Engine, const int t_max)
{
assert(t_max > 0);
// value from 0 to max;
std::uniform_int_distribution<int> dist(0, t_max - 1);
return dist(t_Engine);
}

int RandomBetweenImpl(std::mt19937& t_Engine, const int t_min, const int t_max)
{
// Range from min to max, inclusive
std::uniform_int_distribution<int> dist(t_min, t_max);
return dist(t_Engine);
}

float GetRandomFloatImpl(std::mt19937& t_Engine, float t_Min, float t_Max)
{
std::uniform_real_distribution<float> dist(t_Min, t_Max);
return dist(t_Engine);
}

glm::vec3 GetRandomVec3Impl(std::mt19937& t_Engine, const glm::vec3 t_Min, const glm::vec3 t_Max)
{
glm::vec3 rand = {};
rand.x = GetRandomFloatImpl(t_Engine, t_Min.x, t_Max.x);
rand.y = GetRandomFloatImpl(t_Engine, t_Min.y, t_Max.y);
rand.z = GetRandomFloatImpl(t_Engine, t_Min.z, t_Max.z);
return rand;
}
} // namespace

RandomStream::RandomStream()
: m_Engine(GenerateEntropySeed())
{
}

RandomStream::RandomStream(uint32 t_Seed)
: m_Engine(t_Seed)
{
}

void RandomStream::Reseed()
{
m_Engine.seed(GenerateEntropySeed());
}

void RandomStream::Reseed(uint32 t_Seed)
{
m_Engine.seed(t_Seed);
}

int RandomStream::Random0ToN(const int t_max)
{
return Random0ToNImpl(m_Engine, t_max);
}

int RandomStream::RandomBetween(const int t_min, const int t_max)
{
return RandomBetweenImpl(m_Engine, t_min, t_max);
}

float RandomStream::GetRandomFloat(float t_Min, float t_Max)
{
return GetRandomFloatImpl(m_Engine, t_Min, t_Max);
}

glm::vec3 RandomStream::GetRandomVec3(const glm::vec3 t_Min, const glm::vec3 t_Max)
{
return GetRandomVec3Impl(m_Engine, t_Min, t_Max);
}

bool Random::bIsInitalized = false;
RandomStream Random::s_Stream;

bool Random::Init()
{
/* initialize random seed */
srand( static_cast<unsigned int>( time( NULL ) ) );
// Seed once from a real entropy source; every call afterwards just
// advances the mt19937 state, which is cheap (no per-call syscalls).
return Init(GenerateEntropySeed());
}

bool Random::Init(uint32 t_Seed)
{
s_Stream.Reseed(t_Seed);

bIsInitalized = true;
return bIsInitalized;
}

const int Random::Random0ToN( const int t_max )
const int Random::Random0ToN(const int t_max)
{
assert( t_max > 0 && bIsInitalized );
// value from 0 to max;
return rand() % t_max;
assert(bIsInitalized);
return s_Stream.Random0ToN(t_max);
}

const int Random::RandomBetween( const int t_min, const int t_max )
const int Random::RandomBetween(const int t_min, const int t_max)
{
assert( bIsInitalized );
// Range from minx to max
return rand() % t_max + t_min;
assert(bIsInitalized);
return s_Stream.RandomBetween(t_min, t_max);
}

glm::vec3 Random::GetRandomVec3(const glm::vec3 t_Min, const glm::vec3 t_Max)
{
glm::vec3 rand = {};
rand.x = GetRandomFloat(t_Min.x, t_Max.x);
rand.y = GetRandomFloat(t_Min.y, t_Max.y);
rand.z = GetRandomFloat(t_Min.z, t_Max.z);
return rand;
return s_Stream.GetRandomVec3(t_Min, t_Max);
}

float Random::GetRandomFloat(float t_Min, float t_Max)
{
return (static_cast<float>(rand()) / static_cast<float>(static_cast<float>(RAND_MAX) / (t_Max - t_Min))) + t_Min;
return s_Stream.GetRandomFloat(t_Min, t_Max);
}
} // namespace Fling
} // namespace Fling
Loading
Loading