mirror of
https://github.com/love2d/love.git
synced 2026-08-16 00:02:12 +02:00
Merged bartbes/love-experiments/RandomGenerator-2 into default (resolves issue #692)
This commit is contained in:
@@ -217,8 +217,8 @@ void ParticleSystem::initParticle(particle *p)
|
||||
p->position[1] += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
|
||||
break;
|
||||
case DISTRIBUTION_NORMAL:
|
||||
p->position[0] += (float) rng.randomnormal(areaSpread.getX());
|
||||
p->position[1] += (float) rng.randomnormal(areaSpread.getY());
|
||||
p->position[0] += (float) rng.randomNormal(areaSpread.getX());
|
||||
p->position[1] += (float) rng.randomNormal(areaSpread.getY());
|
||||
break;
|
||||
case DISTRIBUTION_NONE:
|
||||
default:
|
||||
|
||||
@@ -53,12 +53,24 @@ public:
|
||||
virtual ~Math()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @copydoc RandomGenerator::randomseed()
|
||||
**/
|
||||
inline void randomseed(uint64 seed)
|
||||
inline void setRandomState(RandomGenerator::State state)
|
||||
{
|
||||
rng.randomseed(seed);
|
||||
rng.setState(state);
|
||||
}
|
||||
|
||||
inline void setRandomState(uint32 low, uint32 high)
|
||||
{
|
||||
rng.setState(low, high);
|
||||
}
|
||||
|
||||
inline RandomGenerator::State getRandomState() const
|
||||
{
|
||||
return rng.getState();
|
||||
}
|
||||
|
||||
inline void getRandomState(uint32 &low, uint32 &high) const
|
||||
{
|
||||
rng.getState(low, high);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,11 +98,11 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc RandomGenerator::randomnormal()
|
||||
* @copydoc RandomGenerator::randomNormal()
|
||||
**/
|
||||
inline double randomnormal(double stddev)
|
||||
inline double randomNormal(double stddev)
|
||||
{
|
||||
return rng.randomnormal(stddev);
|
||||
return rng.randomNormal(stddev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,37 +36,34 @@ RandomGenerator::RandomGenerator()
|
||||
{
|
||||
// because it is too big for some compilers to handle ... if you know what
|
||||
// i mean
|
||||
union
|
||||
{
|
||||
uint64 b64;
|
||||
struct
|
||||
{
|
||||
uint32 a;
|
||||
uint32 b;
|
||||
} b32;
|
||||
} converter;
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
converter.b32.a = 0x0139408D;
|
||||
converter.b32.b = 0xCBBF7A44;
|
||||
rng_state.b32.a = 0x0139408D;
|
||||
rng_state.b32.b = 0xCBBF7A44;
|
||||
#else
|
||||
converter.b32.b = 0x0139408D;
|
||||
converter.b32.a = 0xCBBF7A44;
|
||||
rng_state.b32.b = 0x0139408D;
|
||||
rng_state.b32.a = 0xCBBF7A44;
|
||||
#endif
|
||||
}
|
||||
|
||||
rng_state = converter.b64;
|
||||
void RandomGenerator::setState(RandomGenerator::State state)
|
||||
{
|
||||
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
|
||||
if (state.b64 == 0)
|
||||
throw love::Exception("Invalid random state.");
|
||||
|
||||
rng_state = state;
|
||||
}
|
||||
|
||||
uint64 RandomGenerator::rand()
|
||||
{
|
||||
rng_state ^= (rng_state << 13);
|
||||
rng_state ^= (rng_state >> 7);
|
||||
rng_state ^= (rng_state << 17);
|
||||
return rng_state;
|
||||
rng_state.b64 ^= (rng_state.b64 << 13);
|
||||
rng_state.b64 ^= (rng_state.b64 >> 7);
|
||||
rng_state.b64 ^= (rng_state.b64 << 17);
|
||||
return rng_state.b64;
|
||||
}
|
||||
|
||||
// Box–Muller transform
|
||||
double RandomGenerator::randomnormal(double stddev)
|
||||
double RandomGenerator::randomNormal(double stddev)
|
||||
{
|
||||
// use cached number if possible
|
||||
if (last_randomnormal != std::numeric_limits<double>::infinity())
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#define LOVE_MATH_RANDOM_GENERATOR_H
|
||||
|
||||
// LOVE
|
||||
#include "common/config.h"
|
||||
#include "common/Exception.h"
|
||||
#include "common/math.h"
|
||||
#include "common/int.h"
|
||||
#include "common/Object.h"
|
||||
@@ -38,19 +40,57 @@ class RandomGenerator : public Object
|
||||
{
|
||||
public:
|
||||
|
||||
RandomGenerator();
|
||||
union State
|
||||
{
|
||||
uint64 b64;
|
||||
struct
|
||||
{
|
||||
uint32 a;
|
||||
uint32 b;
|
||||
} b32;
|
||||
};
|
||||
|
||||
virtual ~RandomGenerator() {};
|
||||
RandomGenerator();
|
||||
virtual ~RandomGenerator() {}
|
||||
|
||||
/**
|
||||
* Set pseudo random seed.
|
||||
* Set pseudo-random state.
|
||||
* It's up to the implementation how to use this.
|
||||
*
|
||||
* @param seed The random seed.
|
||||
**/
|
||||
inline void randomseed(uint64 seed)
|
||||
void setState(State state);
|
||||
|
||||
/**
|
||||
* Separately set the low and high parts of the pseudo-random state.
|
||||
**/
|
||||
inline void setState(uint32 low, uint32 high)
|
||||
{
|
||||
rng_state = seed;
|
||||
State newstate;
|
||||
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
newstate.b32.a = high;
|
||||
newstate.b32.b = low;
|
||||
#else
|
||||
newstate.b32.b = high;
|
||||
newstate.b32.a = low;
|
||||
#endif
|
||||
|
||||
setState(newstate);
|
||||
}
|
||||
|
||||
inline State getState() const
|
||||
{
|
||||
return rng_state;
|
||||
}
|
||||
|
||||
inline void getState(uint32 &low, uint32 &high) const
|
||||
{
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
high = rng_state.b32.a;
|
||||
low = rng_state.b32.b;
|
||||
#else
|
||||
high = rng_state.b32.b;
|
||||
low = rng_state.b32.a;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,11 +136,11 @@ public:
|
||||
* @param stddev Standard deviation of the distribution.
|
||||
* @return Normally distributed random number with mean 0 and variance (stddev)².
|
||||
**/
|
||||
double randomnormal(double stddev);
|
||||
double randomNormal(double stddev);
|
||||
|
||||
private:
|
||||
|
||||
uint64 rng_state;
|
||||
State rng_state;
|
||||
double last_randomnormal;
|
||||
|
||||
}; // RandomGenerator
|
||||
|
||||
@@ -32,44 +32,62 @@ namespace love
|
||||
namespace math
|
||||
{
|
||||
|
||||
int w_randomseed(lua_State *L)
|
||||
int w_setRandomState(lua_State *L)
|
||||
{
|
||||
uint64 seed = luax_checkrandomseed(L, 1);
|
||||
Math::instance.randomseed(seed);
|
||||
try
|
||||
{
|
||||
Math::instance.setRandomState(luax_checkrandomstate(L, 1));
|
||||
}
|
||||
catch (love::Exception &e)
|
||||
{
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_getRandomState(lua_State *L)
|
||||
{
|
||||
uint32 low = 0, high = 0;
|
||||
Math::instance.getRandomState(low, high);
|
||||
lua_pushnumber(L, (lua_Number) low);
|
||||
lua_pushnumber(L, (lua_Number) high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_random(lua_State *L)
|
||||
{
|
||||
return luax_getrandom(L, 1, Math::instance.random());
|
||||
}
|
||||
|
||||
int w_randomnormal(lua_State *L)
|
||||
int w_randomNormal(lua_State *L)
|
||||
{
|
||||
double mean = 0.0, stddev = 1.0;
|
||||
if (lua_gettop(L) > 1)
|
||||
{
|
||||
mean = luaL_checknumber(L, 1);
|
||||
stddev = luaL_checknumber(L, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
stddev = luaL_optnumber(L, 1, 1.);
|
||||
}
|
||||
double stddev = luaL_optnumber(L, 1, 1.0);
|
||||
double mean = luaL_optnumber(L, 2, 0.0);
|
||||
double r = Math::instance.randomNormal(stddev);
|
||||
|
||||
double r = Math::instance.randomnormal(stddev);
|
||||
lua_pushnumber(L, r + mean);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_newRandomGenerator(lua_State *L)
|
||||
{
|
||||
RandomGenerator::State s;
|
||||
if (lua_gettop(L) > 0)
|
||||
s = luax_checkrandomstate(L, 1);
|
||||
|
||||
RandomGenerator *t = Math::instance.newRandomGenerator();
|
||||
|
||||
if (lua_gettop(L) > 0)
|
||||
{
|
||||
uint64 seed = luax_checkrandomseed(L, 1);
|
||||
t->randomseed(seed);
|
||||
try
|
||||
{
|
||||
t->setState(s);
|
||||
}
|
||||
catch (love::Exception &e)
|
||||
{
|
||||
t->release();
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
luax_newtype(L, "RandomGenerator", MATH_RANDOM_GENERATOR_T, (void *) t);
|
||||
@@ -264,9 +282,10 @@ int w_noise(lua_State *L)
|
||||
// List of functions to wrap.
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "randomseed", w_randomseed },
|
||||
{ "setRandomState", w_setRandomState },
|
||||
{ "getRandomState", w_getRandomState },
|
||||
{ "random", w_random },
|
||||
{ "randomnormal", w_randomnormal },
|
||||
{ "randomNormal", w_randomNormal },
|
||||
{ "newRandomGenerator", w_newRandomGenerator },
|
||||
{ "newBezierCurve", w_newBezierCurve },
|
||||
{ "triangulate", w_triangulate },
|
||||
@@ -285,6 +304,7 @@ static const lua_CFunction types[] =
|
||||
extern "C" int luaopen_love_math(lua_State *L)
|
||||
{
|
||||
Math::instance.retain();
|
||||
|
||||
WrappedModule w;
|
||||
w.module = &Math::instance;
|
||||
w.name = "math";
|
||||
|
||||
@@ -30,9 +30,10 @@ namespace love
|
||||
namespace math
|
||||
{
|
||||
|
||||
int w_randomseed(lua_State *L);
|
||||
int w_setRandomState(lua_State *L);
|
||||
int w_getRandomState(lua_State *L);
|
||||
int w_random(lua_State *L);
|
||||
int w_randomnormal(lua_State *L);
|
||||
int w_randomNormal(lua_State *L);
|
||||
int w_newRandomGenerator(lua_State *L);
|
||||
int w_newBezierCurve(lua_State *L);
|
||||
int w_triangulate(lua_State *L);
|
||||
|
||||
@@ -21,23 +21,47 @@
|
||||
#include "wrap_RandomGenerator.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace math
|
||||
{
|
||||
|
||||
uint64 luax_checkrandomseed(lua_State *L, int idx)
|
||||
template <typename T>
|
||||
static T checkrandomstate_part(lua_State *L, int idx)
|
||||
{
|
||||
union
|
||||
double num = luaL_checknumber(L, idx);
|
||||
double inf = std::numeric_limits<double>::infinity();
|
||||
|
||||
// Disallow conversions from infinity and NaN.
|
||||
if (num == inf || num == -inf || num != num)
|
||||
luaL_argerror(L, idx, "invalid random state");
|
||||
|
||||
return (T) num;
|
||||
}
|
||||
|
||||
RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx)
|
||||
{
|
||||
RandomGenerator::State s;
|
||||
|
||||
if (!lua_isnoneornil(L, idx + 1))
|
||||
{
|
||||
double seed_double;
|
||||
uint64 seed_uint;
|
||||
} s;
|
||||
uint32 low = checkrandomstate_part<uint32>(L, idx);
|
||||
uint32 high = checkrandomstate_part<uint32>(L, idx + 1);
|
||||
|
||||
s.seed_double = luaL_checknumber(L, idx);
|
||||
#ifdef LOVE_BIG_ENDIAN
|
||||
s.b32.a = high;
|
||||
s.b32.b = low;
|
||||
#else
|
||||
s.b32.b = high;
|
||||
s.b32.a = low;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
s.b64 = checkrandomstate_part<uint64>(L, idx);
|
||||
|
||||
return s.seed_uint;
|
||||
return s;
|
||||
}
|
||||
|
||||
int luax_getrandom(lua_State *L, int startidx, double r)
|
||||
@@ -71,45 +95,56 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx)
|
||||
return luax_checktype<RandomGenerator>(L, idx, "RandomGenerator", MATH_RANDOM_GENERATOR_T);
|
||||
}
|
||||
|
||||
int w_RandomGenerator_randomseed(lua_State *L)
|
||||
int w_RandomGenerator_setState(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
uint64 seed = luax_checkrandomseed(L, 2);
|
||||
rng->randomseed(seed);
|
||||
try
|
||||
{
|
||||
rng->setState(luax_checkrandomstate(L, 2));
|
||||
}
|
||||
catch (love::Exception &e)
|
||||
{
|
||||
return luaL_error(L, "%s", e.what());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_getState(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
|
||||
uint32 low = 0, high = 0;
|
||||
rng->getState(low, high);
|
||||
|
||||
lua_pushnumber(L, (lua_Number) low);
|
||||
lua_pushnumber(L, (lua_Number) high);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_RandomGenerator_random(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
return luax_getrandom(L, 2, rng->random());
|
||||
}
|
||||
|
||||
int w_RandomGenerator_randomnormal(lua_State *L)
|
||||
int w_RandomGenerator_randomNormal(lua_State *L)
|
||||
{
|
||||
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
|
||||
|
||||
double mean = 0.0, stddev = 1.0;
|
||||
if (lua_gettop(L) > 2)
|
||||
{
|
||||
mean = luaL_checknumber(L, 2);
|
||||
stddev = luaL_checknumber(L, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
stddev = luaL_optnumber(L, 2, 1.0);
|
||||
}
|
||||
double stddev = luaL_optnumber(L, 2, 1.0);
|
||||
double mean = luaL_optnumber(L, 3, 0.0);
|
||||
double r = rng->randomNormal(stddev);
|
||||
|
||||
double r = rng->randomnormal(stddev);
|
||||
lua_pushnumber(L, r + mean);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg functions[] =
|
||||
{
|
||||
{ "randomseed", w_RandomGenerator_randomseed },
|
||||
{ "setState", w_RandomGenerator_setState },
|
||||
{ "getState", w_RandomGenerator_getState },
|
||||
{ "random", w_RandomGenerator_random },
|
||||
{ "randomnormal", w_RandomGenerator_randomnormal },
|
||||
{ "randomNormal", w_RandomGenerator_randomNormal },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
@@ -32,13 +32,14 @@ namespace math
|
||||
{
|
||||
|
||||
// Helper functions.
|
||||
uint64 luax_checkrandomseed(lua_State *L, int idx);
|
||||
RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx);
|
||||
int luax_getrandom(lua_State *L, int startidx, double r);
|
||||
|
||||
RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx);
|
||||
int w_RandomGenerator_randomseed(lua_State *L);
|
||||
int w_RandomGenerator_setState(lua_State *L);
|
||||
int w_RandomGenerator_getState(lua_State *L);
|
||||
int w_RandomGenerator_random(lua_State *L);
|
||||
int w_RandomGenerator_randomnormal(lua_State *L);
|
||||
int w_RandomGenerator_randomNormal(lua_State *L);
|
||||
extern "C" int luaopen_randomgenerator(lua_State *L);
|
||||
|
||||
} // math
|
||||
|
||||
Reference in New Issue
Block a user