/************************************************************************
* noises.h - various noise-based patterns
*
* Author: Larry Gritz (gritzl@acm.org), though they're obvious to any
*         experience shader writer.
*
* $Revision: 1.3 $    $Date: 2003/12/28 18:26:24 $
*
************************************************************************/




#ifndef NOISES_H
#define NOISES_H 1


/*
 * Define metrics for estimating filter widths, if none has already
 * been defined.  This is crucial for antialiasing.
 */
#ifndef MINFILTWIDTH
#  define MINFILTWIDTH 1.0e-6
#endif
#ifndef filterwidth
#  define filterwidth(x)  max (abs(Du(x)*du) + abs(Dv(x)*dv), MINFILTWIDTH)
#endif
#ifndef filterwidthp
#  define filterwidthp(p) max (sqrt(area(p)), MINFILTWIDTH)
#endif



#ifndef snoise 
/*
 * Signed noise -- the original Perlin kind with range (-1,1) We prefer
 * signed noise to regular noise mostly because its average is zero.
 * We define three simple macros:
 *   snoise(p) - Perlin noise on either a 1-D (float) or 3-D (point) domain.
 *   snoisexy(x,y) - Perlin noise on a 2-D domain.
 *   vsnoise(p) - vector-valued Perlin noise on either 1-D or 3-D domain.
 */
#define snoise(p) (2 * (float noise(p)) - 1)
#define snoisexy(x,y) (2 * (float noise(x,y)) - 1)
#define vsnoise(p) (2 * (vector noise(p)) - 1)
#endif


/* If we know the filter size, we can crudely antialias snoise by fading
 * to its average value at approximately the Nyquist limit.
 */
#define filteredsnoise(p,width) (snoise(p) * (1-smoothstep (0.2,0.75,width)))
#define filteredvsnoise(p,width) (vsnoise(p) * (1-smoothstep (0.2,0.75,width)))



/* Having filteredsnoise leads easily to an antialiased version of fBm. */
float fBm ( point p; float filtwidth;
            uniform float maxoctaves, lacunarity, gain )
{
    uniform float i;
    uniform float amp = 1;
    varying point pp = p;
    varying float sum = 0, fw = filtwidth;

    for ( i = 0; i < maxoctaves && fw < 1.0; i += 1 )
    {
#pragma nolint
        sum += amp * filteredsnoise ( pp, fw );
        amp *= gain; pp *= lacunarity; fw *= lacunarity;
    }
    return sum;
}


/* Typical use of fBm: */
#define fBm_default(p)  fBm (p, sqrt(area(p)), 4, 2, 0.5)





/* A vector-valued antialiased fBm. */
vector
vfBm ( point p; float filtwidth;
       uniform float maxoctaves, lacunarity, gain )
{
    uniform float i;
    uniform float amp = 1;
    varying point pp = p;
    varying vector sum = 0;
    varying float fw = filtwidth;

    for ( i = 0; i < maxoctaves && fw < 1.0; i += 1 )
    {
        sum += amp * filteredvsnoise ( pp, fw );
        amp *= gain; pp *= lacunarity; fw *= lacunarity;
    }
    return sum;
}


/* Typical use of vfBm: */
#define vfBm_default(p)  vfBm (p, sqrt(area(p)), 4, 2, 0.5)



/* The stuff that Ken Musgrave calls "VLNoise" */
#define VLNoise(Pt,scale) (snoise(vsnoise(Pt)*scale+Pt))
#define filteredVLNoise(Pt,fwidth,scale) \
            (filteredsnoise(filteredvsnoise(Pt,fwidth)*scale+Pt,fwidth))


float
VLfBm ( point p; float filtwidth;
        uniform float maxoctaves, lacunarity, gain, scale )
{
    uniform float i;
    uniform float amp = 1;
    varying point pp = p;
    varying float sum = 0;
    varying float fw = filtwidth;

    for ( i = 0; i < maxoctaves && fw < 1.0; i += 1 )
    {
#pragma nolint
        sum += amp * filteredVLNoise ( pp, fw, scale );
        amp *= gain; pp *= lacunarity; fw *= lacunarity;
    }
    return sum;
}


/* Typical use of vfBm: */
#define VLfBm_default(p)      VLfBm (p, sqrt(area(p)), 4, 2, 0.5, 1.0)




/* Antialiased turbulence.  Watch out -- the abs() call introduces infinite
 * frequency content, which makes our antialiasing efforts much trickier!
 */
float turbulence ( point p; float filtwidth;
                   uniform float maxoctaves, lacunarity, gain )
{
    uniform float i;
    uniform float amp = 1;
    varying point pp = p;
    varying float sum = 0, fw = filtwidth;

    for ( i = 0; i < maxoctaves && fw < 1.0; i += 1 )
    {
#pragma nolint
        sum += amp * abs( filteredsnoise ( pp, fw ) );
        amp *= gain; pp *= lacunarity; fw *= lacunarity;
    }
    return sum;
}


/* Typical use of turbulence: */
#define turbulence_default(p)  turbulence (p, sqrt(area(p)), 4, 2, 0.5)


#endif /* NOISES_H */
