/*
* This file is part of Deliantra, the Roguelike Realtime MMORPG.
*
* Copyright (©) 2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
*
* Deliantra is free software: you can redistribute it and/or modify it under
* the terms of the Affero GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the Affero GNU General Public License
* and the GNU General Public License along with this program. If not, see
* .
*
* The authors can be reached via e-mail to
*/
#ifndef NOISE_H_
#define NOISE_H_
#include
#include
#include "global.h"
typedef blitz::TinyVector vec2d;
typedef blitz::TinyVector vec3d;
vec2d
inline floor (vec2d v)
{
return vec2d (fastfloor (v[0]), fastfloor (v[1]));
}
vec3d
inline floor (vec3d v)
{
return vec3d (fastfloor (v[0]), fastfloor (v[1]), fastfloor (v[2]));
}
vec2d
inline pow (vec2d v, vec2d p)
{
return vec2d (pow (v[0], p[0]), pow (v[1], p[1]));
}
/////////////////////////////////////////////////////////////////////////////
// various s-shaped curves, smooth to, first, or second derivative
// used for smooth interpolation from 0..1
// linear
template
inline T
sigmoid0 (T x)
{
return x;
}
// 3x²-2x³
template
inline T
sigmoid1 (T x)
{
return (3 - 2 * x) * x * x;
}
// 6x⁵ - 15x⁴ + 10x³
template
inline T
sigmoid2 (T x)
{
#ifdef MORE_PARALLELITY
float x2 = x * x;
float x4 = x2 * x2;
return (6 * x4 + 10 * x2) * x - 15 * x4;
#endif
// simple horner
return ((6 * x - 15) * x + 10) * x * x * x;
}
// blend between a and b
// c is the control function - if lower than ca
// then return a, if higher than cb, return b
template
inline T
blend (T a, T b, U c, U ca, U cb, U weight (U) = sigmoid1)
{
if (c <= ca) return a;
if (c >= cb) return b;
U w = weight ((c - ca) / (cb - ca));
return (U(1) - w) * a + w * b;
}
// blend between a and b
// c is the control function - if lower than -c_w
// then return a, if higher than +c_w then b.
template
inline T
blend0 (T a, T b, U c, U c_w, U weight (U) = sigmoid1)
{
return blend (a, b, c, -c_w, c_w, weight);
}
template
struct rotate_nn
{
typename vec_t::T_numtype s, c;
void set (typename vec_t::T_numtype angle)
{
s = sin (angle);
c = cos (angle);
}
void operator ()(vec_t &P) const
{
vec_t o = P;
P[a] = o[a] * c - o[b] * s;
P[b] = o[a] * s + o[b] * c;
}
};
template
struct rotate_xy : rotate_nn
{
};
template
struct rotate_xz : rotate_nn
{
};
template
struct rotate_yz : rotate_nn
{
};
/////////////////////////////////////////////////////////////////////////////
template< int N, typename T>
struct permutation
{
T pmap[N];
void seed (seedable_rand_gen &rng);
T operator ()(T v) func_pure
{
return pmap[v & T(N - 1)];
}
};
/////////////////////////////////////////////////////////////////////////////
template
struct noise_gen_base
{
permutation<256, uint8_t> rvmap[vec_t::numElements + 1];
typedef typename vec_t::T_numtype value_t;
void seed (seedable_rand_gen &rng);
void seed (seed_t seed);
value_t operator ()(vec_t P, uint32_t seed = 0) func_pure;
};
template
struct noise_gen;
// modelled after 2d/3d kensler noise without projection
template<>
struct noise_gen
: noise_gen_base
{
static value_t abs_avg() { return 0.2231; } // avg(abs(noise))
};
template<>
struct noise_gen
: noise_gen_base
{
static vec3d::T_numtype abs_avg() { return 0.415; } // avg(abs(noise))
using noise_gen_base::operator ();
// noise projected on a surface with normal n
vec2d::T_numtype operator() (vec3d P, vec3d N, uint32_t seed = 0) func_pure;
};
typedef noise_gen noise2d;
typedef noise_gen noise3d;
/////////////////////////////////////////////////////////////////////////////
template
struct frac_gen
: noise_gen
{
enum { MAX_OCTAVES = 32 };
typedef typename vec_t::T_numtype value_t;
int octaves;
value_t h, lac, ex[MAX_OCTAVES];
value_t fbm_mul[MAX_OCTAVES];
rotate_xy rot[MAX_OCTAVES];
frac_gen (int octaves = 3, value_t lacunarity = 2, value_t hurst_expo = .5, uint32_t seed = 0);
value_t noise (vec_t P, uint32_t seed = 0) func_pure
{
return operator() (P, seed);
}
value_t fBm (vec_t P) func_pure;
value_t turbulence (vec_t P) func_pure;
value_t multifractal (vec_t P, value_t offset = 1) func_pure;
value_t heterofractal (vec_t P, value_t offset = 1) func_pure;
value_t hybridfractal (vec_t P, value_t offset = 1, value_t gain = 1) func_pure;
value_t ridgedmultifractal (vec_t P, value_t offset = 1, value_t gain = 8) func_pure;
value_t billowfractal (vec_t P, value_t offset = 1, value_t gain = 2) func_pure;
value_t terrain (vec_t P) func_pure;
value_t terrain2 (vec_t P) func_pure;
};
typedef frac_gen frac2d;
typedef frac_gen frac3d;
/////////////////////////////////////////////////////////////////////////////
template
inline T
border_blend (T a, T b, vec2d P, U N, U W)
{
U border = W; // within n places of the border
min_it (border, P [0]);
min_it (border, N - P [0]);
min_it (border, P [1]);
min_it (border, N - P [1]);
return blend (a, b, border, U(0), W);
}
#endif