#include "proctext.h"
#include "noise.h"

#define NEXT(h)     (((h)+1) & TABMASK)
#define NIMPULSES   3

static float impulseTab[TABSIZE*4];

static void impulseTabInit(int seed);

float
scnoise(float x, float y, float z)
{
    static int initialized;
    float *fp;
    int i, j, k, h, n;
    int ix, iy, iz;
    float sum = 0;
    float fx, fy, fz, dx, dy, dz, distsq;

    /* Initialize the random impulse table if necessary. */
    if (!initialized) {
        impulseTabInit(665);
        initialized = 1;
    }

    ix = FLOOR(x); fx = x - ix;
    iy = FLOOR(y); fy = y - iy;
    iz = FLOOR(z); fz = z - iz;
    
    /* Perform the sparse convolution. */
    for (i = -2; i <= 2; i++) {
      for (j = -2; j <= 2; j++) {
        for (k = -2; k <= 2; k++) {
            /* Compute voxel hash code. */
            h = INDEX(ix+i,iy+j,iz+k);
            
            for (n = NIMPULSES; n > 0; n--, h = NEXT(h)) {
                /* Convolve filter and impulse. */
                fp = &impulseTab[h*4];
                dx = fx - (i + *fp++);
                dy = fy - (j + *fp++);
                dz = fz - (k + *fp++);
                distsq = dx*dx + dy*dy + dz*dz;
                sum += catrom2(distsq) * *fp;
            }
        }
      }
    }

    return sum / NIMPULSES;
}

static void
impulseTabInit(int seed)
{
    int i;
    float *f = impulseTab;

    srandom(seed); /* Set random number generator seed. */
    for (i = 0; i < TABSIZE; i++) {
        *f++ = RANDNBR;
        *f++ = RANDNBR;
        *f++ = RANDNBR;
        *f++ = 1. - 2.*RANDNBR;
    }
}
