Browse Source

Added love.math.newRandomGenerator. Returns a RNG object with its own seed and random methods.

--HG--
branch : math-randobject
Alex Szpakowski 12 years ago
parent
commit
3046981fce

+ 16 - 0
platform/macosx/love-framework.xcodeproj/project.pbxproj

@@ -224,6 +224,10 @@
 		FA577ACB16C7514400860150 /* physfs.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7316C719F900860150 /* physfs.framework */; };
 		FA577ACC16C7514700860150 /* SDL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7516C719FF00860150 /* SDL.framework */; };
 		FA577ACD16C7514C00860150 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA577A7716C71A0800860150 /* Vorbis.framework */; };
+		FA636D8A171B70920065623F /* RandomGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA636D88171B70920065623F /* RandomGenerator.cpp */; };
+		FA636D8B171B70920065623F /* RandomGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FA636D89171B70920065623F /* RandomGenerator.h */; };
+		FA636D8E171B72A70065623F /* wrap_RandomGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA636D8C171B72A70065623F /* wrap_RandomGenerator.cpp */; };
+		FA636D8F171B72A70065623F /* wrap_RandomGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */; };
 		FA7C937A16DCC6C2006F2BEE /* wrap_Math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */; };
 		FA7C937B16DCC6C2006F2BEE /* wrap_Math.h in Headers */ = {isa = PBXBuildFile; fileRef = FA7C937616DCC6C2006F2BEE /* wrap_Math.h */; };
 		FAAC6B02170A373B008A61C5 /* CompressedData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAAC6B00170A373A008A61C5 /* CompressedData.cpp */; };
@@ -715,6 +719,10 @@
 		FA577A8D16C71D3600860150 /* boot.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = boot.lua; sourceTree = "<group>"; };
 		FA577A8E16C71D3600860150 /* graphics.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = graphics.lua; sourceTree = "<group>"; };
 		FA577AAF16C7507900860150 /* love.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = love.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+		FA636D88171B70920065623F /* RandomGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RandomGenerator.cpp; sourceTree = "<group>"; };
+		FA636D89171B70920065623F /* RandomGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RandomGenerator.h; sourceTree = "<group>"; };
+		FA636D8C171B72A70065623F /* wrap_RandomGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_RandomGenerator.cpp; sourceTree = "<group>"; };
+		FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_RandomGenerator.h; sourceTree = "<group>"; };
 		FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Math.cpp; sourceTree = "<group>"; };
 		FA7C937616DCC6C2006F2BEE /* wrap_Math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Math.h; sourceTree = "<group>"; };
 		FAAC6B00170A373A008A61C5 /* CompressedData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedData.cpp; sourceTree = "<group>"; };
@@ -1653,8 +1661,12 @@
 			children = (
 				FA5454C016F1310000D30303 /* MathModule.cpp */,
 				FA5454C116F1310000D30303 /* MathModule.h */,
+				FA636D88171B70920065623F /* RandomGenerator.cpp */,
+				FA636D89171B70920065623F /* RandomGenerator.h */,
 				FA7C937516DCC6C2006F2BEE /* wrap_Math.cpp */,
 				FA7C937616DCC6C2006F2BEE /* wrap_Math.h */,
+				FA636D8C171B72A70065623F /* wrap_RandomGenerator.cpp */,
+				FA636D8D171B72A70065623F /* wrap_RandomGenerator.h */,
 			);
 			path = math;
 			sourceTree = "<group>";
@@ -1705,6 +1717,8 @@
 				FA0CDE3D1710F9A50056E8D7 /* FormatHandler.h in Headers */,
 				FAEC808B1710FEA60057279A /* ImageData.h in Headers */,
 				FAEC808F1711E76C0057279A /* CompressedData.h in Headers */,
+				FA636D8B171B70920065623F /* RandomGenerator.h in Headers */,
+				FA636D8F171B72A70065623F /* wrap_RandomGenerator.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1986,6 +2000,8 @@
 				FAE010E4170DF75C006F29D0 /* wrap_CompressedData.cpp in Sources */,
 				FAEC808A1710FEA60057279A /* ImageData.cpp in Sources */,
 				FAEC808E1711E76C0057279A /* CompressedData.cpp in Sources */,
+				FA636D8A171B70920065623F /* RandomGenerator.cpp in Sources */,
+				FA636D8E171B72A70065623F /* wrap_RandomGenerator.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

+ 6 - 0
src/common/types.h

@@ -58,6 +58,9 @@ enum Type
 	IMAGE_IMAGE_DATA_ID,
 	IMAGE_COMPRESSED_DATA_ID,
 
+	// Math
+	MATH_RANDOM_GENERATOR_ID,
+
 	// Audio
 	AUDIO_SOURCE_ID,
 
@@ -130,6 +133,9 @@ const bits GRAPHICS_SHADER_T = (bits(1) << GRAPHICS_SHADER_ID) | OBJECT_T;
 const bits IMAGE_IMAGE_DATA_T = (bits(1) << IMAGE_IMAGE_DATA_ID) | DATA_T;
 const bits IMAGE_COMPRESSED_DATA_T = (bits(1) << IMAGE_COMPRESSED_DATA_ID) | DATA_T;
 
+// Math.
+const bits MATH_RANDOM_GENERATOR_T = (bits(1) << MATH_RANDOM_GENERATOR_ID) | OBJECT_T;
+
 // Audio.
 const bits AUDIO_SOURCE_T = (bits(1) << AUDIO_SOURCE_ID) | OBJECT_T;
 

+ 7 - 45
src/modules/math/MathModule.cpp

@@ -18,7 +18,7 @@
  * 3. This notice may not be removed or altered from any source distribution.
  **/
 
-#include "modules/math/MathModule.h"
+#include "MathModule.h"
 #include "common/math.h"
 
 #include <cmath>
@@ -81,60 +81,22 @@ namespace math
 
 Math Math::instance;
 
-// 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()
-	: last_randnormal(numeric_limits<double>::infinity())
+	: rng(newRandomGenerator())
 {
-	// 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;
-#else
-	converter.b32.b = 0x0139408D;
-	converter.b32.a = 0xCBBF7A44;
-#endif
-	rng_state = converter.b64;
-
 	// prevent the runtime from free()-ing this
 	retain();
 }
 
-uint64 Math::rand()
+Math::~Math()
 {
-	rng_state ^= (rng_state << 13);
-	rng_state ^= (rng_state >> 7);
-	rng_state ^= (rng_state << 17);
-	return rng_state;
+	if (rng)
+		rng->release();
 }
 
-// Box–Muller transform
-double Math::randnormal(double stddev)
+RandomGenerator *Math::newRandomGenerator()
 {
-	// use cached number if possible
-	if (last_randnormal != numeric_limits<double>::infinity())
-	{
-		double r = last_randnormal;
-		last_randnormal = numeric_limits<double>::infinity();
-		return r * stddev;
-	}
-
-	double r   = sqrt(-2.0 * log(1. - random()));
-	double phi = 2.0 * LOVE_M_PI * (1. - random());
-
-	last_randnormal = r * cos(phi);
-	return r * sin(phi) * stddev;
+	return new RandomGenerator();
 }
 
 vector<Triangle> Math::triangulate(const vector<vertex> &polygon)

+ 44 - 44
src/modules/math/MathModule.h

@@ -21,6 +21,8 @@
 #ifndef LOVE_MATH_MODMATH_H
 #define LOVE_MATH_MODMATH_H
 
+#include "RandomGenerator.h"
+
 // LOVE
 #include "common/Module.h"
 #include "common/math.h"
@@ -28,7 +30,6 @@
 
 // STL
 #include <limits>
-#include <stdint.h>
 #include <vector>
 
 namespace love
@@ -38,80 +39,79 @@ namespace math
 
 class Math : public Module
 {
+private:
+
+	RandomGenerator *rng;
+
 public:
-	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)
+	virtual ~Math();
+
+	/**
+	 * @copydoc RandomGenerator::randomseed()
+	 **/
+	inline void randomseed(uint64 seed)
 	{
-		rng_state = seed;
+		rng->randomseed(seed);
 	}
 
-	/** Return uniformly distributed pseudo random integer.
-	 *
-	 * @returns Pseudo random integer in [0,2^64).
-	 */
-	uint64 rand();
-
-	/** Get uniformly distributed pseudo random number in [0,1).
-	 *
-	 * @returns Pseudo random number in [0,1).
-	 */
+	/**
+	 * @copydoc RandomGenerator::random()
+	 **/
 	inline double random()
 	{
-		return double(rand()) / (double(std::numeric_limits<uint64>::max()) + 1.0);
+		return rng->random();
 	}
 
-	/** Get uniformly distributed pseudo random number in [0,max).
-	 *
-	 * @returns Pseudo random number in [0,max).
-	 */
+	/**
+	 * @copydoc RandomGenerator::random(double)
+	 **/
 	inline double random(double max)
 	{
-		return random() * max;
+		return rng->random(max);
 	}
 
-	/** Get uniformly distributed pseudo random number in [min, max).
-	 *
-	 * @returns Pseudo random number in [min, max).
-	 */
+	/**
+	 * @copydoc RandomGenerator::random(double,double)
+	 **/
 	inline double random(double min, double max)
 	{
-		return random() * (max - min) + min;
+		return rng->random(min, max);
 	}
 
-	/** 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);
+	/**
+	 * @copydoc RandomGenerator::randnormal()
+	 **/
+	inline double randnormal(double stddev)
+	{
+		return rng->randnormal(stddev);
+	}
+
+	/**
+	 * Create a new random number generator.
+	 **/
+	RandomGenerator *newRandomGenerator();
 
 	virtual const char *getName() const
 	{
 		return "love.math";
 	}
 
-	/** Triangulate a simple polygon.
+	/**
+	 * Triangulate a simple polygon.
+	 *
 	 * @param polygon Polygon to triangulate. Must not intersect itself.
-	 * @returns List of triangles the polygon is composed of.
-	 */
+	 * @return List of triangles the polygon is composed of.
+	 **/
 	std::vector<Triangle> triangulate(const std::vector<vertex> &polygon);
 
 	static Math instance;
 
 private:
+
 	Math();
 
-	uint64 rng_state;
-	double last_randnormal;
-};
+}; // Math
 
 } // math
 } // love

+ 87 - 0
src/modules/math/RandomGenerator.cpp

@@ -0,0 +1,87 @@
+/**
+ * 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 "RandomGenerator.h"
+
+// STL
+#include <cmath>
+
+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
+
+RandomGenerator::RandomGenerator()
+	: last_randnormal(std::numeric_limits<double>::infinity())
+{
+	// 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;
+#else
+	converter.b32.b = 0x0139408D;
+	converter.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;
+}
+
+// Box–Muller transform
+double RandomGenerator::randnormal(double stddev)
+{
+	// use cached number if possible
+	if (last_randnormal != std::numeric_limits<double>::infinity())
+	{
+		double r = last_randnormal;
+		last_randnormal = std::numeric_limits<double>::infinity();
+		return r * stddev;
+	}
+
+	double r   = sqrt(-2.0 * log(1. - random()));
+	double phi = 2.0 * LOVE_M_PI * (1. - random());
+
+	last_randnormal = r * cos(phi);
+	return r * sin(phi) * stddev;
+}
+
+} // math
+} // love

+ 111 - 0
src/modules/math/RandomGenerator.h

@@ -0,0 +1,111 @@
+/**
+ * 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_RANDOM_GENERATOR_H
+#define LOVE_MATH_RANDOM_GENERATOR_H
+
+// LOVE
+#include "common/math.h"
+#include "common/int.h"
+#include "common/Object.h"
+
+// STL
+#include <limits>
+
+namespace love
+{
+namespace math
+{
+
+class RandomGenerator : public Object
+{
+public:
+
+	RandomGenerator();
+
+	virtual ~RandomGenerator() {};
+
+	/**
+	 * Set pseudo random seed.
+	 * It's up to the implementation how to use this.
+	 *
+	 * @param seed The random seed.
+	 **/
+	inline void randomseed(uint64 seed)
+	{
+		rng_state = seed;
+	}
+
+	/**
+	 * Return uniformly distributed pseudo random integer.
+	 *
+	 * @return Pseudo random integer in [0,2^64).
+	 **/
+	uint64 rand();
+
+	/**
+	 * Get uniformly distributed pseudo random number in [0,1).
+	 *
+	 * @return Pseudo random number in [0,1).
+	 **/
+	inline double random()
+	{
+		return double(rand()) / (double(std::numeric_limits<uint64>::max()) + 1.0);
+	}
+
+	/**
+	 * Get uniformly distributed pseudo random number in [0,max).
+	 *
+	 * @return Pseudo random number in [0,max).
+	 **/
+	inline double random(double max)
+	{
+		return random() * max;
+	}
+
+	/**
+	 * Get uniformly distributed pseudo random number in [min, max).
+	 *
+	 * @return Pseudo random number in [min, max).
+	 **/
+	inline double random(double min, double max)
+	{
+		return random() * (max - min) + min;
+	}
+
+	/**
+	 * Get normally distributed pseudo random number.
+	 *
+	 * @param stddev Standard deviation of the distribution.
+	 * @return Normally distributed random number with mean 0 and variance (stddev)².
+	 **/
+	double randnormal(double stddev);
+
+private:
+
+	uint64 rng_state;
+	double last_randnormal;
+
+}; // RandomGenerator
+
+} // math
+} // love
+
+#endif // LOVE_MATH_RANDOM_GENERATOR_H

+ 21 - 32
src/modules/math/wrap_Math.cpp

@@ -19,7 +19,8 @@
  **/
 
 #include "wrap_Math.h"
-#include "modules/math/MathModule.h"
+#include "wrap_RandomGenerator.h"
+#include "MathModule.h"
 
 #include <cmath>
 #include <iostream>
@@ -31,42 +32,14 @@ namespace math
 
 int w_randomseed(lua_State *L)
 {
-	union
-	{
-		double   seed_double;
-		uint64_t seed_uint;
-	} s;
-
-	s.seed_double = luaL_checknumber(L, 1);
-	Math::instance.randomseed(s.seed_uint);
+	uint64 seed = luax_checkrandomseed(L, 1);
+	Math::instance.randomseed(seed);
 	return 0;
 }
 
 int w_random(lua_State *L)
 {
-	double r = Math::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;
+	return luax_getrandom(L, 1, Math::instance.random());
 }
 
 int w_randnormal(lua_State *L)
@@ -87,6 +60,20 @@ int w_randnormal(lua_State *L)
 	return 1;
 }
 
+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);
+	}
+
+	luax_newtype(L, "RandomGenerator", MATH_RANDOM_GENERATOR_T, (void *) t);
+	return 1;
+}
+
 int w_triangulate(lua_State *L)
 {
 	std::vector<vertex> vertices;
@@ -167,12 +154,14 @@ static const luaL_Reg functions[] =
 	{ "randomseed", w_randomseed },
 	{ "random", w_random },
 	{ "randnormal", w_randnormal },
+	{ "newRandomGenerator", w_newRandomGenerator },
 	{ "triangulate", w_triangulate },
 	{ 0, 0 }
 };
 
 static const lua_CFunction types[] =
 {
+	luaopen_randomgenerator,
 	0
 };
 

+ 1 - 0
src/modules/math/wrap_Math.h

@@ -33,6 +33,7 @@ namespace math
 int w_randomseed(lua_State *L);
 int w_random(lua_State *L);
 int w_randnormal(lua_State *L);
+int w_newRandomGenerator(lua_State *L);
 int w_triangulate(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);
 

+ 122 - 0
src/modules/math/wrap_RandomGenerator.cpp

@@ -0,0 +1,122 @@
+/**
+ * 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_RandomGenerator.h"
+
+#include <cmath>
+
+namespace love
+{
+namespace math
+{
+
+uint64 luax_checkrandomseed(lua_State *L, int idx)
+{
+	union
+	{
+		double seed_double;
+		uint64 seed_uint;
+	} s;
+
+	s.seed_double = luaL_checknumber(L, idx);
+
+	return s.seed_uint;
+}
+
+int luax_getrandom(lua_State *L, int startidx, double r)
+{
+	int l, u;
+	// from lua 5.1.4 source code: lmathlib.c:185 ff.
+	switch (lua_gettop(L) - (startidx - 1))
+	{
+	case 0:
+		lua_pushnumber(L, r);
+		break;
+	case 1:
+		u = luaL_checkint(L, startidx);
+		luaL_argcheck(L, 1 <= u, startidx, "interval is empty");
+		lua_pushnumber(L, floor(r * u) + 1);
+		break;
+	case 2:
+		l = luaL_checkint(L, startidx);
+		u = luaL_checkint(L, startidx + 1);
+		luaL_argcheck(L, l <= u, startidx + 1, "interval is empty");
+		lua_pushnumber(L, floor(r * (u - l + 1)) + l);
+		break;
+	default:
+		return luaL_error(L, "wrong number of arguments");
+	}
+	return 1;
+}
+
+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)
+{
+	RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
+	uint64 seed = luax_checkrandomseed(L, 2);
+	rng->randomseed(seed);
+	return 0;
+}
+
+int w_RandomGenerator_random(lua_State *L)
+{
+	RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
+	return luax_getrandom(L, 2, rng->random());
+}
+
+int w_RandomGenerator_randnormal(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 r = rng->randnormal(stddev);
+	lua_pushnumber(L, r + mean);
+	return 1;
+}
+
+static const luaL_Reg functions[] =
+{
+	{ "randomseed", w_RandomGenerator_randomseed },
+	{ "random", w_RandomGenerator_random },
+	{ "randnormal", w_RandomGenerator_randnormal },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_randomgenerator(lua_State *L)
+{
+	return luax_register_type(L, "RandomGenerator", functions);
+}
+
+} // math
+} // love

+ 47 - 0
src/modules/math/wrap_RandomGenerator.h

@@ -0,0 +1,47 @@
+/**
+ * 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_RANDOM_GENERATOR_H
+#define LOVE_MATH_WRAP_RANDOM_GENERATOR_H
+
+// LOVE
+#include "RandomGenerator.h"
+#include "common/config.h"
+#include "common/runtime.h"
+
+namespace love
+{
+namespace math
+{
+
+// Helper functions.
+uint64 luax_checkrandomseed(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_random(lua_State *L);
+int w_RandomGenerator_randnormal(lua_State *L);
+extern "C" int luaopen_randomgenerator(lua_State *L);
+
+} // math
+} // love
+
+#endif // LOVE_MATH_WRAP_RANDOM_GENERATOR_H