From 5f586390d8c70815a180e1bce69e86df1c8bcc87 Mon Sep 17 00:00:00 2001 From: vrld Date: Mon, 25 Feb 2013 18:32:54 +0100 Subject: [PATCH] Add module `love.math`. Implements xorshift RNG. Contains just a RNG for now, but may include other functionality (e.g. transforms) later on. New Functions: -- as in the lua math library: love.math.randomseed(number) -- set random seed love.math.random() -- get random number in [0:1) (uniformly distributed) love.math.random(high) -- get integer random number in [1:high] love.math.random(low, high) -- get integer random number in [low:high] -- additional functions love.math.randnormal() -- get normally distributed number with zero mean -- and unit variance love.math.randnormal(o) -- get normally distributed number with zero mean -- and standard deviation `o` love.math.randnormal(m, o) -- get normally distributed number with mean `m` -- and standard deviation `o` --- src/modules/love/love.cpp | 2 + src/modules/math/Math.cpp | 66 ++++++++++++++++ src/modules/math/Math.h | 91 ++++++++++++++++++++++ src/modules/math/wrap_Math.cpp | 135 +++++++++++++++++++++++++++++++++ src/modules/math/wrap_Math.h | 42 ++++++++++ src/scripts/boot.lua | 2 + src/scripts/boot.lua.h | 2 + 7 files changed, 340 insertions(+) create mode 100644 src/modules/math/Math.cpp create mode 100644 src/modules/math/Math.h create mode 100644 src/modules/math/wrap_Math.cpp create mode 100644 src/modules/math/wrap_Math.h diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 350ba65e4..657d7b8b7 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -103,6 +103,7 @@ extern "C" extern int luaopen_love_sound(lua_State*); extern int luaopen_love_timer(lua_State*); extern int luaopen_love_thread(lua_State*); + extern int luaopen_love_math(lua_State*); extern int luaopen_love_boot(lua_State*); } @@ -120,6 +121,7 @@ static const luaL_Reg modules[] = { { "love.sound", luaopen_love_sound }, { "love.timer", luaopen_love_timer }, { "love.thread", luaopen_love_thread }, + { "love.math", luaopen_love_math }, { "love.boot", luaopen_love_boot }, { 0, 0 } }; diff --git a/src/modules/math/Math.cpp b/src/modules/math/Math.cpp new file mode 100644 index 000000000..5bbe05006 --- /dev/null +++ b/src/modules/math/Math.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "Math.h" +#include "common/math.h" + +#include + +namespace love +{ +namespace math +{ + +// 64 bit Xorshift implementation taken from the end of Sec. 3 (page 4) in +// George Marsaglia, "Xorshift RNGs", Journal of Statistical Software, Vol.8 (Issue 14), 2003 +Math::Math() +{ + RNGState.seed = 0x0139408DCBBF7A44; + RNGState.last_randnormal = std::numeric_limits::infinity(); +} + +uint32_t Math::rand() +{ + uint64_t &x = RNGState.seed; + x ^= (x << 13); + x ^= (x >> 7); + x ^= (x << 17); + return x; +} + +// Box–Muller transform +double Math::randnormal(double stddev) +{ + if (RNGState.last_randnormal != std::numeric_limits::infinity()) + { + double r = RNGState.last_randnormal; + RNGState.last_randnormal = std::numeric_limits::infinity(); + return r * stddev; + } + + double r = sqrt(-2.0 * log(1. - random())); + double phi = 2.0 * LOVE_M_PI * (1. - random()); + + RNGState.last_randnormal = r * cos(phi); + return r * sin(phi) * stddev; +} + +} // math +} // love diff --git a/src/modules/math/Math.h b/src/modules/math/Math.h new file mode 100644 index 000000000..97a0be6bf --- /dev/null +++ b/src/modules/math/Math.h @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_MATH_MATH_H +#define LOVE_MATH_MATH_H + +// LOVE +#include "common/Module.h" + +// STL +#include +#include + +namespace love +{ +namespace math +{ + +class Math : public Module +{ +public: + Math(); + virtual ~Math() {} + + /** Set pseudo random seed. + * + * It's up to the implementation how to use this. + * + * @param seed The random seed. + */ + inline void randomseed(uint64_t seed) + { + RNGState.seed = seed; + } + + /** Return uniformly distributed pseudo random integer. + * + * @returns Pseudo random integer in [0,2^32). + */ + uint32_t rand(); + + /** Get uniformly distributed pseudo random number in [0,1). + * + * @returns Pseudo random number in [0,1). + */ + inline double random() + { + return double(rand()) / (double(std::numeric_limits::max()) + 1.0); + } + + /** Get normally distributed pseudo random number. + * + * @param stddev Standard deviation of the distribution. + * @returns Normally distributed random number with mean 0 and variance (stddev)². + */ + double randnormal(double stddev); + + virtual const char *getName() const + { + return "love.math"; + } + +private: + struct + { + uint64_t seed; + double last_randnormal; + } RNGState; +}; + +} // math +} // love + +#endif diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp new file mode 100644 index 000000000..706ff208f --- /dev/null +++ b/src/modules/math/wrap_Math.cpp @@ -0,0 +1,135 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#include "wrap_Math.h" +#include "Math.h" + +#include +#include + +namespace +{ + +union SeedConverter +{ + double seed_double; + uint64_t seed_uint; +}; + +} // anonymous namespace + +namespace love +{ +namespace math +{ + +static Math *instance = 0; + +int w_randomseed(lua_State *L) +{ + SeedConverter s; + s.seed_double = luaL_checknumber(L, 1); + instance->randomseed(s.seed_uint); + return 0; +} + +int w_random(lua_State *L) +{ + double r = instance->random(); + int l, u; + // verbatim from lua 5.1.4 source code: lmathlib.c:185 ff. + switch (lua_gettop(L)) + { + case 0: + lua_pushnumber(L, r); + break; + case 1: + u = luaL_checkint(L, 1); + luaL_argcheck(L, 1 <= u, 1, "interval is empty"); + lua_pushnumber(L, floor(r * u) + 1); + break; + case 2: + l = luaL_checkint(L, 1); + u = luaL_checkint(L, 2); + luaL_argcheck(L, l <= u, 2, "interval is empty"); + lua_pushnumber(L, floor(r * (u - l + 1)) + l); + break; + default: + return luaL_error(L, "wrong number of arguments"); + } + return 1; +} + +int w_randnormal(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 r = instance->randnormal(stddev); + lua_pushnumber(L, r + mean); + return 1; +} + +// List of functions to wrap. +static const luaL_Reg functions[] = +{ + { "randomseed", w_randomseed }, + { "random", w_random }, + { "randnormal", w_randnormal }, + { 0, 0 } +}; + +static const lua_CFunction types[] = +{ + 0 +}; + +extern "C" int luaopen_love_math(lua_State *L) +{ + if (instance == 0) + instance = new love::math::Math(); + else + instance->retain(); + + if (instance == 0) + return luaL_error(L, "Could not open module math."); + + WrappedModule w; + w.module = instance; + w.name = "math"; + w.flags = MODULE_T; + w.functions = functions; + w.types = types; + + int n = luax_register_module(L, w); + + return n; +} + +} // math +} // love diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h new file mode 100644 index 000000000..b907013ee --- /dev/null +++ b/src/modules/math/wrap_Math.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2006-2013 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_MATH_WRAP_MATH_H +#define LOVE_MATH_WRAP_MATH_H + +// LOVE +#include "common/config.h" +#include "common/runtime.h" + +namespace love +{ +namespace math +{ + +int w_randomseed(lua_State *L); +int w_random(lua_State *L); +int w_randnormal(lua_State *L); +extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L); + +} // random +} // love + +#endif // LOVE_MATH_WRAP_MATH_H + diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index ae93b4ac7..84ead7547 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -257,6 +257,7 @@ function love.init() image = true, graphics = true, audio = true, + math = true, physics = true, sound = true, font = true, @@ -307,6 +308,7 @@ function love.init() "image", "font", "graphics", + "math", "physics", } do if c.modules[v] then diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index cabe2f397..fe51b9f57 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -429,6 +429,7 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x09, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, + 0x09, 0x09, 0x09, 0x6d, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x73, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, 0x09, 0x09, 0x09, 0x66, 0x6f, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a, @@ -501,6 +502,7 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x22, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x66, 0x6f, 0x6e, 0x74, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x22, 0x2c, 0x0a, + 0x09, 0x09, 0x22, 0x6d, 0x61, 0x74, 0x68, 0x22, 0x2c, 0x0a, 0x09, 0x09, 0x22, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x22, 0x2c, 0x0a, 0x09, 0x7d, 0x20, 0x64, 0x6f, 0x0a, 0x09, 0x09, 0x69, 0x66, 0x20, 0x63, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x5b, 0x76, 0x5d, 0x20,