Browse Source

Implement random number generator
Co-authored-by: Zirak <[email protected]>

Chaosus 6 years ago
parent
commit
f8151a9e50

+ 9 - 16
core/math/math_funcs.cpp

@@ -30,30 +30,27 @@
 
 #include "math_funcs.h"
 
-#include "core/os/os.h"
-
-pcg32_random_t Math::default_pcg = { 12047754176567800795ULL, PCG_DEFAULT_INC_64 };
+RandomPCG Math::default_rand(RandomPCG::DEFAULT_SEED, RandomPCG::DEFAULT_INC);
 
 #define PHI 0x9e3779b9
 
-// TODO: we should eventually expose pcg.inc too
 uint32_t Math::rand_from_seed(uint64_t *seed) {
-	pcg32_random_t pcg = { *seed, PCG_DEFAULT_INC_64 };
-	uint32_t r = pcg32_random_r(&pcg);
-	*seed = pcg.state;
+	RandomPCG rng = RandomPCG(*seed, RandomPCG::DEFAULT_INC);
+	uint32_t r = rng.rand();
+	*seed = rng.get_seed();
 	return r;
 }
 
 void Math::seed(uint64_t x) {
-	default_pcg.state = x;
+	default_rand.seed(x);
 }
 
 void Math::randomize() {
-	seed(OS::get_singleton()->get_ticks_usec() * default_pcg.state + PCG_DEFAULT_INC_64);
+	default_rand.randomize();
 }
 
 uint32_t Math::rand() {
-	return pcg32_random_r(&default_pcg);
+	return default_rand.rand();
 }
 
 int Math::step_decimals(double p_step) {
@@ -169,13 +166,9 @@ uint32_t Math::larger_prime(uint32_t p_val) {
 }
 
 double Math::random(double from, double to) {
-	unsigned int r = Math::rand();
-	double ret = (double)r / (double)RANDOM_MAX;
-	return (ret) * (to - from) + from;
+	return default_rand.random(from, to);
 }
 
 float Math::random(float from, float to) {
-	unsigned int r = Math::rand();
-	float ret = (float)r / (float)RANDOM_MAX;
-	return (ret) * (to - from) + from;
+	return default_rand.random(from, to);
 }

+ 2 - 1
core/math/math_funcs.h

@@ -32,6 +32,7 @@
 #define MATH_FUNCS_H
 
 #include "core/math/math_defs.h"
+#include "core/math/random_pcg.h"
 #include "core/typedefs.h"
 
 #include "thirdparty/misc/pcg.h"
@@ -41,7 +42,7 @@
 
 class Math {
 
-	static pcg32_random_t default_pcg;
+	static RandomPCG default_rand;
 
 public:
 	Math() {} // useless to instance

+ 45 - 0
core/math/random_number_generator.cpp

@@ -0,0 +1,45 @@
+/*************************************************************************/
+/*  random_number_generator.cpp                                          */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "random_number_generator.h"
+
+RandomNumberGenerator::RandomNumberGenerator() :
+		randbase() {}
+
+void RandomNumberGenerator::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_seed", "seed"), &RandomNumberGenerator::set_seed);
+	ClassDB::bind_method(D_METHOD("get_seed"), &RandomNumberGenerator::get_seed);
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
+
+	ClassDB::bind_method(D_METHOD("randi"), &RandomNumberGenerator::randi);
+	ClassDB::bind_method(D_METHOD("randf"), &RandomNumberGenerator::randf);
+	ClassDB::bind_method(D_METHOD("rand_range", "from", "to"), &RandomNumberGenerator::rand_range);
+	ClassDB::bind_method(D_METHOD("randomize"), &RandomNumberGenerator::randomize);
+}

+ 61 - 0
core/math/random_number_generator.h

@@ -0,0 +1,61 @@
+/*************************************************************************/
+/*  random_number_generator.h                                            */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef RANDOM_NUMBER_GENERATOR_H
+#define RANDOM_NUMBER_GENERATOR_H
+
+#include "core/math/random_pcg.h"
+#include "core/reference.h"
+
+class RandomNumberGenerator : public Reference {
+	GDCLASS(RandomNumberGenerator, Reference);
+
+	RandomPCG randbase;
+
+protected:
+	static void _bind_methods();
+
+public:
+	_FORCE_INLINE_ void set_seed(uint64_t seed) { randbase.seed(seed); }
+
+	_FORCE_INLINE_ uint64_t get_seed() { return randbase.get_seed(); }
+
+	_FORCE_INLINE_ void randomize() { return randbase.randomize(); }
+
+	_FORCE_INLINE_ uint32_t randi() { return randbase.rand(); }
+
+	_FORCE_INLINE_ real_t randf() { return randbase.randf(); }
+
+	_FORCE_INLINE_ real_t rand_range(real_t from, real_t to) { return randbase.random(from, to); }
+
+	RandomNumberGenerator();
+};
+
+#endif // RANDOM_NUMBER_GENERATOR_H

+ 55 - 0
core/math/random_pcg.cpp

@@ -0,0 +1,55 @@
+/*************************************************************************/
+/*  random_pcg.cpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "random_pcg.h"
+
+#include "core/os/os.h"
+
+RandomPCG::RandomPCG(uint64_t seed, uint64_t inc) :
+		pcg() {
+	pcg.state = seed;
+	pcg.inc = inc;
+}
+
+void RandomPCG::randomize() {
+	seed(OS::get_singleton()->get_ticks_usec() * pcg.state + PCG_DEFAULT_INC_64);
+}
+
+double RandomPCG::random(double from, double to) {
+	unsigned int r = rand();
+	double ret = (double)r / (double)RANDOM_MAX;
+	return (ret) * (to - from) + from;
+}
+
+float RandomPCG::random(float from, float to) {
+	unsigned int r = rand();
+	float ret = (float)r / (float)RANDOM_MAX;
+	return (ret) * (to - from) + from;
+}

+ 61 - 0
core/math/random_pcg.h

@@ -0,0 +1,61 @@
+/*************************************************************************/
+/*  random_pcg.h                                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef RANDOM_PCG_H
+#define RANDOM_PCG_H
+
+#include "core/math/math_defs.h"
+
+#include "thirdparty/misc/pcg.h"
+
+class RandomPCG {
+	pcg32_random_t pcg;
+
+public:
+	static const uint64_t DEFAULT_SEED = 12047754176567800795ULL;
+	static const uint64_t DEFAULT_INC = PCG_DEFAULT_INC_64;
+	static const uint64_t RANDOM_MAX = 4294967295;
+
+	RandomPCG(uint64_t seed = DEFAULT_SEED, uint64_t inc = PCG_DEFAULT_INC_64);
+
+	_FORCE_INLINE_ void seed(uint64_t seed) { pcg.state = seed; }
+	_FORCE_INLINE_ uint64_t get_seed() { return pcg.state; }
+
+	void randomize();
+	_FORCE_INLINE_ uint32_t rand() { return pcg32_random_r(&pcg); }
+	_FORCE_INLINE_ double randf() { return (double)rand() / (double)RANDOM_MAX; }
+	_FORCE_INLINE_ float randd() { return (float)rand() / (float)RANDOM_MAX; }
+
+	double random(double from, double to);
+	float random(float from, float to);
+	real_t random(int from, int to) { return (real_t)random((real_t)from, (real_t)to); }
+};
+
+#endif // RANDOM_PCG_H

+ 2 - 0
core/register_core_types.cpp

@@ -55,6 +55,7 @@
 #include "core/math/a_star.h"
 #include "core/math/expression.h"
 #include "core/math/geometry.h"
+#include "core/math/random_number_generator.h"
 #include "core/math/triangle_mesh.h"
 #include "core/os/input.h"
 #include "core/os/main_loop.h"
@@ -180,6 +181,7 @@ void register_core_types() {
 	ClassDB::register_virtual_class<PackedDataContainerRef>();
 	ClassDB::register_class<AStar>();
 	ClassDB::register_class<EncodedObjectAsID>();
+	ClassDB::register_class<RandomNumberGenerator>();
 
 	ClassDB::register_class<JSONParseResult>();
 

+ 52 - 0
doc/classes/RandomNumberGenerator.xml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="RandomNumberGenerator" inherits="Reference" category="Core" version="3.1">
+	<brief_description>
+		A class for generation pseudo-random numbers.
+	</brief_description>
+	<description>
+	</description>
+	<tutorials>
+	</tutorials>
+	<demos>
+	</demos>
+	<methods>
+		<method name="randi">
+			<return type="int">
+			</return>
+			<description>
+				Generates pseudo-random 32-bit integer between '0' and '4294967295'.
+			</description>
+		</method>
+		<method name="randf">
+			<return type="float">
+			</return>
+			<description>
+				Generates pseudo-random float between '0.0' and '1.0'.
+			</description>
+		</method>
+		<method name="rand_range">
+			<return type="float">
+			</return>
+			<argument index="0" name="from" type="float">
+			</argument>
+			<argument index="1" name="to" type="float">
+			</argument>
+			<description>
+				Generates pseudo-random float between [code]from[/code] and [code]to[/code].
+			</description>
+		</method>
+		<method name="randomize">
+			<return type="void">
+			</return>
+			<description>
+				Setups a time-based seed to generator. 
+			</description>
+		</method>
+	</methods>
+	<members>
+		<member name="seed" type="int" setter="set_seed" getter="get_seed">
+		</member>
+	</members>
+	<constants>
+	</constants>
+</class>