#pragma once #include "platform.h" #include "math.h" namespace stingray_plugin_foundation { // A fast LCG random number generator. The numbers it produces are not completely // random but it is faster and more random than vanilla C rand(). It should be good // enough for most purposes. class Random { // This variable should NOT need to be volatile, but there is a bug in VC++. If // this variable is not volatile Vector3(random(), random(), random()) sets all // components to the same value. volatile unsigned _state; public: static const unsigned A = 1664525 , B = 1013904223; __forceinline Random() : _state(0) {} __forceinline Random(unsigned s) : _state(s) {} __forceinline unsigned seed() const {return _state;} __forceinline void set_seed(unsigned s) {_state = s;} __forceinline void next() {_state = A * _state + B;} __forceinline unsigned rand_u32() {next(); return _state;} __forceinline double rand_double() {return double(rand_u32()) * (0.5 / 0x80000000);} __forceinline float rand_float() {return float(rand_u32()) * (0.5f / 0x80000000);} __forceinline double operator()(double max) {return max * rand_double();} __forceinline double operator()(double min, double max) {return min + (max - min)*rand_double();} __forceinline float operator()() {return rand_float();} __forceinline float operator()(float max) {return max * rand_float();} __forceinline float operator()(float min, float max) {return min + (max - min)*rand_float();} __forceinline int operator()(int max_plus_1) {return (int)floor(max_plus_1*rand_double());} __forceinline int operator()(int min, int max) {return (int)floor(min + (max - min + 1)*rand_double());} __forceinline unsigned operator()(unsigned max_plus_1) {return unsigned(max_plus_1*rand_double());} __forceinline unsigned operator()(unsigned min, unsigned max) {return unsigned(min + (max - min + 1)*rand_double());} // Convenience methods -- coin toss __forceinline bool heads() {return rand_float() < 0.5f;} __forceinline bool tails() {return rand_float() > 0.5f;} // Convenience methods -- random picking template __forceinline T &pick(T &t1, T &t2) {return rand_float() < 0.5f ? t1 : t2;} template __forceinline const T &pick(const T &t1, const T &t2) {return rand_float() < 0.5f ? t1 : t2;} template __forceinline T &pick( T &v ) {return v[ (*this)(v.size()) ];} template __forceinline const T &pick( const T &v ) {return v[ (*this)(v.size()) ];} // Random pick with weight. T must have "weight" field. template __forceinline T &pick_weighted( T &v ) { float sum = 0; typename T::iterator it, begin = v.begin(), end = v.end(); for (it=begin; itweight; float pick = (*this)(sum); float acc = 0; for (it=begin; itweight; if (pick < acc) return *it; } return v.back(); } template __forceinline const T &pick_weighted( T &v ) { float sum = 0; typename T::const_iterator it, begin = v.begin(), end = v.end(); for (it=begin; itweight; float pick = (*this)(sum); float acc = 0; for (it=begin; itweight; if (pick < acc) return *it; } return v.back(); } }; }