#include <ctime>
#include "generator.h"
Generator::Generator(): Generator(random(time(NULL))) { }
Generator::Generator(ULongInt seed):
one(1ull << 32),
max_cache_count(8*1024*1024)
{
set_seed(seed);
LongIntVector2 a(1, 2);
LongIntVector2 b(3);
m_cache[ULongIntVector2()];
m_cache_top = m_cache.begin();
m_cache_top->second.next = m_cache_top->second.previous = m_cache_top;
}
void
Generator::set_seed(ULongInt x) {
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 4; ++j)
x = random( m_seeds[i][j] = x );
}
Real
Generator::random(const ULongIntVector2 &coord, int index) const {
ULongInt seed = random(random(coord.x) ^ seeds_x()[index]);
seed = random(seed ^ random(coord.y) ^ seeds_y()[index]);
seed = random(seed ^ random(coord.x) ^ random(coord.y));
return Real(seed)/Real(ULLONG_MAX)*Real(2) - Real(1);
}
Vector4
Generator::generate(const ULongIntVector2 &coord, bool shrink_cache) const {
// search value in cache
Cache::iterator i = m_cache.find(coord);
bool found = i != m_cache.end();
if (found) {
i->second.previous->second.next = i->second.next;
i->second.next->second.previous = i->second.previous;
assert(!i->second.in_use);
if (i->second.in_use) return i->second.value;
} else {
i = m_cache.insert(Cache::value_type(coord, CacheEntry())).first;
++m_cache_count;
}
i->second.in_use = true;
i->second.previous = m_cache_top;
i->second.next = i->second.previous->second.next;
m_cache_top = i;
i->second.previous->second.next = i;
i->second.next->second.previous = i;
while (shrink_cache && m_cache_count > max_cache_count) {
Cache::iterator ri = m_cache_top->second.next;
if (ri->second.in_use) break;
ri->second.previous->second.next = ri->second.next;
ri->second.next->second.previous = ri->second.previous;
m_cache.erase(ri);
--m_cache_count;
}
Vector4 &value = i->second.value;
if (!found) {
// generate new value
for(int j = 0; j < 4; ++j)
value[j] = random(coord, j);
ULongInt x_minus_one = coord.x - 1;
ULongInt y_minus_one = coord.y - 1;
ULongInt level_x = coord.x ? (coord.x ^ x_minus_one) >> 1 : (ULongInt)-1;
ULongInt level_y = coord.y ? (coord.y ^ y_minus_one) >> 1 : (ULongInt)-1;
ULongInt level = (level_x < level_y ? level_x : level_y) + 1;
if (level && level < one) {
value /= one/level;
if (level_x == level_y) {
// square corners
value += ( generate(ULongIntVector2(coord.x - level, coord.y - level))
+ generate(ULongIntVector2(coord.x - level, coord.y + level))
+ generate(ULongIntVector2(coord.x + level, coord.y - level))
+ generate(ULongIntVector2(coord.x + level, coord.y + level)) )*0.25;
} else {
// diamond corners
value += ( generate(ULongIntVector2(coord.x - level, coord.y))
+ generate(ULongIntVector2(coord.x + level, coord.y))
+ generate(ULongIntVector2(coord.x, coord.y - level))
+ generate(ULongIntVector2(coord.x, coord.y + level)) )*0.25;
}
}
}
i->second.in_use = false;
return value;
}
Vector4
Generator::generate(const Vector2 &coord, const Vector2 &precision) const {
const int bits = clz(ULongInt(0));
ULongIntVector2 coord_int(
(ULongInt)(LongInt)(coord.x*one),
(ULongInt)(LongInt)(coord.y*one) );
ULongIntVector2 precision_int(
(ULongInt)(LongInt)(precision.x*one),
(ULongInt)(LongInt)(precision.y*one) );
int level_x = bits - clz(precision_int.x);
int level_y = bits - clz(precision_int.y);
coord_int.x = (coord_int.x >> level_x) << level_x;
coord_int.y = (coord_int.y >> level_y) << level_y;
return generate(coord_int);
}
void
Generator::generate(Surface &target, const Vector2 <, const Vector2 &rb) const {
if (target.empty()) return;
Vector2 d = rb - lt;
d.x /= target.width();
d.y /= target.height();
Vector2 precision = d/2.0;
Vector2 p = lt;
for(int r = 0; r < target.height(); ++r, p.x = lt.x, p.y += d.y) {
Color *row = target[r];
for(int c = 0; c < target.width(); ++c, p.x += d.x) {
Vector4 v = generate(p, precision);
row[c].r = flip_clamp(v.x);
row[c].g = flip_clamp(v.y);
row[c].b = flip_clamp(v.z);
row[c].a = flip_clamp(v.w);
}
}
}