Commits

Alex Szpakowski  committed 87d9b6c Merge

Merged math-randobject into default (also addresses issue #586)

  • Participants
  • Parent commits 6975bf6, 2e849d6

Comments (0)

Files changed (11)

File platform/macosx/love-framework.xcodeproj/project.pbxproj

 		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 */; };
 		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>"; };
 			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>";
 				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;
 		};
 				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;
 		};

File src/common/types.h

 	IMAGE_IMAGE_DATA_ID,
 	IMAGE_COMPRESSED_DATA_ID,
 
+	// Math
+	MATH_RANDOM_GENERATOR_ID,
+
 	// Audio
 	AUDIO_SOURCE_ID,
 
 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;
 

File src/modules/graphics/opengl/ParticleSystem.cpp

 #include "ParticleSystem.h"
 
 #include "common/math.h"
-#include "modules/math/MathModule.h"
+#include "modules/math/RandomGenerator.h"
 
 #include "OpenGL.h"
 #include <cmath>
 #include <cstdlib>
 
-using love::math::Math;
-
 namespace love
 {
 namespace graphics
 
 namespace
 {
+
+love::math::RandomGenerator rng;
+
 Colorf colorToFloat(const Color &c)
 {
 	return Colorf((GLfloat)c.r/255.0f, (GLfloat)c.g/255.0f, (GLfloat)c.b/255.0f, (GLfloat)c.a/255.0f);
 }
-}
 
 float calculate_variation(float inner, float outer, float var)
 {
 	float low = inner - (outer/2.0f)*var;
 	float high = inner + (outer/2.0f)*var;
-	float r = Math::instance.random();
+	float r = rng.random();
 	return low*(1-r)+high*r;
 }
 
+} // anonymous namespace
+
 StringMap<ParticleSystem::AreaSpreadDistribution, ParticleSystem::DISTRIBUTION_MAX_ENUM>::Entry ParticleSystem::distributionsEntries[] = {
 	{ "none",     ParticleSystem::DISTRIBUTION_NONE },
 	{ "uniform",  ParticleSystem::DISTRIBUTION_UNIFORM },
 	if (min == max)
 		pLast->life = min;
 	else
-		pLast->life = Math::instance.random(min, max);
+		pLast->life = rng.random(min, max);
 	pLast->lifetime = pLast->life;
 
 	pLast->position[0] = position.getX();
 	switch (areaSpreadDistribution)
 	{
 		case DISTRIBUTION_UNIFORM:
-			pLast->position[0] += Math::instance.random(-areaSpread.getX(), areaSpread.getX());
-			pLast->position[1] += Math::instance.random(-areaSpread.getY(), areaSpread.getY());
+			pLast->position[0] += rng.random(-areaSpread.getX(), areaSpread.getX());
+			pLast->position[1] += rng.random(-areaSpread.getY(), areaSpread.getY());
 			break;
 		case DISTRIBUTION_NORMAL:
-			pLast->position[0] += Math::instance.randnormal(areaSpread.getX());
-			pLast->position[1] += Math::instance.randnormal(areaSpread.getY());
+			pLast->position[0] += rng.randomnormal(areaSpread.getX());
+			pLast->position[1] += rng.randomnormal(areaSpread.getY());
 			break;
 		case DISTRIBUTION_NONE:
 		default:
 
 	min = direction - spread/2.0f;
 	max = direction + spread/2.0f;
-	pLast->direction = Math::instance.random(min, max);
+	pLast->direction = rng.random(min, max);
 
 	pLast->origin = position;
 
 	min = speedMin;
 	max = speedMax;
-	float speed = Math::instance.random(min, max);
+	float speed = rng.random(min, max);
 	pLast->speed = love::Vector(cos(pLast->direction), sin(pLast->direction));
 	pLast->speed *= speed;
 
 	min = gravityMin;
 	max = gravityMax;
-	pLast->gravity = Math::instance.random(min, max);
+	pLast->gravity = rng.random(min, max);
 
 	min = radialAccelerationMin;
 	max = radialAccelerationMax;
-	pLast->radialAcceleration = Math::instance.random(min, max);
+	pLast->radialAcceleration = rng.random(min, max);
 
 	min = tangentialAccelerationMin;
 	max = tangentialAccelerationMax;
-	pLast->tangentialAcceleration = Math::instance.random(min, max);
+	pLast->tangentialAcceleration = rng.random(min, max);
 
-	pLast->sizeOffset       = Math::instance.random(sizeVariation); // time offset for size change
-	pLast->sizeIntervalSize = (1.0f - Math::instance.random(sizeVariation)) - pLast->sizeOffset;
+	pLast->sizeOffset       = rng.random(sizeVariation); // time offset for size change
+	pLast->sizeIntervalSize = (1.0f - rng.random(sizeVariation)) - pLast->sizeOffset;
 	pLast->size = sizes[(size_t)(pLast->sizeOffset - .5f) * (sizes.size() - 1)];
 
 	min = rotationMin;
 	max = rotationMax;
 	pLast->spinStart = calculate_variation(spinStart, spinEnd, spinVariation);
 	pLast->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
-	pLast->rotation = Math::instance.random(min, max);
+	pLast->rotation = rng.random(min, max);
 
 	pLast->color = colors[0];
 

File src/modules/math/MathModule.cpp

  * 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>
 
 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)

File src/modules/math/MathModule.h

 #ifndef LOVE_MATH_MODMATH_H
 #define LOVE_MATH_MODMATH_H
 
+#include "RandomGenerator.h"
+
 // LOVE
 #include "common/Module.h"
 #include "common/math.h"
 
 // STL
 #include <limits>
-#include <stdint.h>
 #include <vector>
 
 namespace love
 
 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::randomnormal()
+	 **/
+	inline double randomnormal(double stddev)
+	{
+		return rng->randomnormal(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

File src/modules/math/RandomGenerator.cpp

+/**
+ * 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_randomnormal(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::randomnormal(double stddev)
+{
+	// use cached number if possible
+	if (last_randomnormal != std::numeric_limits<double>::infinity())
+	{
+		double r = last_randomnormal;
+		last_randomnormal = 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_randomnormal = r * cos(phi);
+	return r * sin(phi) * stddev;
+}
+
+} // math
+} // love

File src/modules/math/RandomGenerator.h

+/**
+ * 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 randomnormal(double stddev);
+
+private:
+
+	uint64 rng_state;
+	double last_randomnormal;
+
+}; // RandomGenerator
+
+} // math
+} // love
+
+#endif // LOVE_MATH_RANDOM_GENERATOR_H

File src/modules/math/wrap_Math.cpp

  **/
 
 #include "wrap_Math.h"
-#include "modules/math/MathModule.h"
+#include "wrap_RandomGenerator.h"
+#include "MathModule.h"
 
 #include <cmath>
 #include <iostream>
 
 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)
+int w_randomnormal(lua_State *L)
 {
 	double mean = 0.0, stddev = 1.0;
 	if (lua_gettop(L) > 1)
 		stddev = luaL_optnumber(L, 1, 1.);
 	}
 
-	double r = Math::instance.randnormal(stddev);
+	double r = Math::instance.randomnormal(stddev);
 	lua_pushnumber(L, r + mean);
 	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;
 {
 	{ "randomseed", w_randomseed },
 	{ "random", w_random },
-	{ "randnormal", w_randnormal },
+	{ "randomnormal", w_randomnormal },
+	{ "newRandomGenerator", w_newRandomGenerator },
 	{ "triangulate", w_triangulate },
 	{ 0, 0 }
 };
 
 static const lua_CFunction types[] =
 {
+	luaopen_randomgenerator,
 	0
 };
 

File src/modules/math/wrap_Math.h

 
 int w_randomseed(lua_State *L);
 int w_random(lua_State *L);
-int w_randnormal(lua_State *L);
+int w_randomnormal(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);
 

File src/modules/math/wrap_RandomGenerator.cpp

+/**
+ * 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_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 r = rng->randomnormal(stddev);
+	lua_pushnumber(L, r + mean);
+	return 1;
+}
+
+static const luaL_Reg functions[] =
+{
+	{ "randomseed", w_RandomGenerator_randomseed },
+	{ "random", w_RandomGenerator_random },
+	{ "randomnormal", w_RandomGenerator_randomnormal },
+	{ 0, 0 }
+};
+
+extern "C" int luaopen_randomgenerator(lua_State *L)
+{
+	return luax_register_type(L, "RandomGenerator", functions);
+}
+
+} // math
+} // love

File src/modules/math/wrap_RandomGenerator.h

+/**
+ * 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_randomnormal(lua_State *L);
+extern "C" int luaopen_randomgenerator(lua_State *L);
+
+} // math
+} // love
+
+#endif // LOVE_MATH_WRAP_RANDOM_GENERATOR_H