diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index c6c99fa00..2b1d787b8 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -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: diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 51cb062ba..01af49fdc 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -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); } /** diff --git a/src/modules/math/RandomGenerator.cpp b/src/modules/math/RandomGenerator.cpp index 55f9c24aa..fd27bdcc8 100644 --- a/src/modules/math/RandomGenerator.cpp +++ b/src/modules/math/RandomGenerator.cpp @@ -36,37 +36,25 @@ 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; } 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::infinity()) diff --git a/src/modules/math/RandomGenerator.h b/src/modules/math/RandomGenerator.h index f28aebf2c..ae0975c24 100644 --- a/src/modules/math/RandomGenerator.h +++ b/src/modules/math/RandomGenerator.h @@ -22,6 +22,7 @@ #define LOVE_MATH_RANDOM_GENERATOR_H // LOVE +#include "common/config.h" #include "common/math.h" #include "common/int.h" #include "common/Object.h" @@ -38,19 +39,56 @@ 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) + inline void setState(State state) { - rng_state = seed; + rng_state = state; + } + + /** + * Separately set the low and high parts of the pseudo-random state. + **/ + inline void setState(uint32 low, uint32 high) + { +#ifdef LOVE_BIG_ENDIAN + rng_state.b32.a = high; + rng_state.b32.b = low; +#else + rng_state.b32.b = high; + rng_state.b32.a = low; +#endif + } + + 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 +134,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 diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index fa901ef56..2dc520446 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -32,32 +32,32 @@ 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); + Math::instance.setRandomState(luax_checkrandomstate(L, 1)); 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; } @@ -67,10 +67,7 @@ int w_newRandomGenerator(lua_State *L) RandomGenerator *t = Math::instance.newRandomGenerator(); if (lua_gettop(L) > 0) - { - uint64 seed = luax_checkrandomseed(L, 1); - t->randomseed(seed); - } + t->setState(luax_checkrandomstate(L, 1)); luax_newtype(L, "RandomGenerator", MATH_RANDOM_GENERATOR_T, (void *) t); return 1; @@ -264,9 +261,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 +283,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"; diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index 63b61abd5..734e46403 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -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); diff --git a/src/modules/math/wrap_RandomGenerator.cpp b/src/modules/math/wrap_RandomGenerator.cpp index 126ff7c6f..46674209f 100644 --- a/src/modules/math/wrap_RandomGenerator.cpp +++ b/src/modules/math/wrap_RandomGenerator.cpp @@ -27,17 +27,27 @@ namespace love namespace math { -uint64 luax_checkrandomseed(lua_State *L, int idx) +RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx) { - union + RandomGenerator::State s; + + if (!lua_isnoneornil(L, idx + 1)) { - double seed_double; - uint64 seed_uint; - } s; + uint32 low = (uint32) luaL_checknumber(L, idx); + uint32 high = (uint32) luaL_checknumber(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 = (uint64) luaL_checknumber(L, idx); - return s.seed_uint; + return s; } int luax_getrandom(lua_State *L, int startidx, double r) @@ -71,45 +81,49 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx) return luax_checktype(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); + rng->setState(luax_checkrandomstate(L, 2)); 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 } }; diff --git a/src/modules/math/wrap_RandomGenerator.h b/src/modules/math/wrap_RandomGenerator.h index a2fe347b0..43e1eab15 100644 --- a/src/modules/math/wrap_RandomGenerator.h +++ b/src/modules/math/wrap_RandomGenerator.h @@ -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