Blob Blame Raw
#ifndef GENERATOR_H
#define GENERATOR_H


#include <climits>
#include <map>

#include "surface.h"
#include "vector.h"


class Generator: public Shared {
public:
	enum {
		gray0    = 1ull << 28,
		one      = 1ull << 32,
		gray1    = 1ull << 36,
		big      = 1ull << 60,
		max_side = 1ull << 16,
		max_area = 1ull << 32,
	};
	
	struct CacheEntry;
	typedef std::map<ULongIntVector2, CacheEntry> Cache;
	
	struct CacheEntry {
		Cache::iterator next, previous;
		bool in_use;
		Vector4 value;
	};
	
	class GenSurface {
	private:
		Vector4 *data;
		ULongInt w, h;
		ULongIntVector2 m_offset;
		ULongInt m_step;
		
	public:
		inline GenSurface():
			data(), w(), h(), m_step() { }
		inline GenSurface(const ULongIntPair2 &bounds, ULongInt step):
			GenSurface() { create(bounds, step); }
		inline GenSurface(const GenSurface &other):
			GenSurface() { *this = other; }
		inline GenSurface(GenSurface &&other):
			data(other.data), w(other.w), h(other.h), m_offset(other.m_offset), m_step(other.m_step)
			{ if (&other != this) other.data = nullptr; }
		inline ~GenSurface()
			{ reset(); }
		
		void create(const ULongIntPair2 &bounds, ULongInt step);
		void reset();
		GenSurface& operator= (const GenSurface &other);
		
		inline bool is_valid() const {
			return data
				&& w < max_side
				&& h < max_side
				&& w*h < max_area
				&& w%2 && h%2
				&& !(m_step     & (m_step - 1))
				&& !(m_offset.x & (m_step - 1))
				&& !(m_offset.y & (m_step - 1))
				&& m_offset.x & m_step
				&& m_offset.y & m_step;
		}
		
		inline ULongInt width() const { return w; }
		inline ULongInt height() const { return h; }
		inline const ULongIntVector2& offset() const { return m_offset; }
		inline ULongInt step() const { return m_step; }

		inline Vector4* operator[] (ULongInt row) { return data + row*w; }
		inline const Vector4* operator[] (ULongInt row) const { return data + row*w; }
		
		inline ULongIntVector2 p0() const { return m_offset; }
		inline ULongIntVector2 p1() const { return m_offset + ULongIntVector2(w-1, h-1)*m_step; }
	};
	
	
	static inline ULongInt random(ULongInt x)
		{ return x*2862933555777941757ull + 3037000493ull; }

	static inline Real random_to_real(ULongInt x)
		{ return Real(x)/Real(ULLONG_MAX); }
	static inline Real random_to_normal(ULongInt x, ULongInt y)
		{ return sqrt(-2*log(random_to_real(x))) * sin(2*M_PI*random_to_real(y)); }
	
private:
	const int max_cache_count;
	
	mutable Cache m_cache;
	mutable Cache::iterator m_cache_top;
	mutable int m_cache_count;
	
	ULongInt m_seeds[2][4];
	
public:
	Generator();
	explicit Generator(ULongInt seed);
	
	inline const ULongInt* seeds_x() const { return m_seeds[0]; }
	inline const ULongInt* seeds_y() const { return m_seeds[1]; }
	inline ULongInt seed() const { return seeds_x()[0]; }
	void set_seed(ULongInt x);

	Real random(const ULongIntVector2 &coord, int index) const;
	inline Vector4 random(const ULongIntVector2 &coord) const
		{ return Vector4(random(coord, 0), random(coord, 1), random(coord, 2), random(coord, 3)); }
	
	Vector4 generate(const ULongIntVector2 &coord, bool shrink_cache = true) const;
	Vector4 generate(const Vector2 &coord, const Vector2 &precision) const;
	void generate(Surface &target, const Pair2 &bounds) const;
	
	void generate(GenSurface &target) const;
	void generate(GenSurface &target, const GenSurface &source) const;
};


#endif