Noise-1.0.0: libnoise/noise/src/noisegen.cpp
// noisegen.cpp
//
// Copyright (C) 2003, 2004 Jason Bevins
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or (at
// your option) any later version.
//
// This library 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 Lesser General Public
// License (COPYING.txt) for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this library; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// The developer's email is jlbezigvins@gmzigail.com (for great email, take
// off every 'zig'.)
//
#include "noisegen.h"
#include "interp.h"
#include "vectortable.h"
using namespace noise;
// Specifies the version of the coherent-noise functions to use.
// - Set to 2 to use the current version.
// - Set to 1 to use the flawed version from the original version of libnoise.
// If your application requires coherent-noise values that were generated by
// an earlier version of libnoise, change this constant to the appropriate
// value and recompile libnoise.
#define NOISE_VERSION 2
// These constants control certain parameters that all coherent-noise
// functions require.
#if (NOISE_VERSION == 1)
// Constants used by the original version of libnoise.
// Because X_NOISE_GEN is not relatively prime to the other values, and
// Z_NOISE_GEN is close to 256 (the number of random gradient vectors),
// patterns show up in high-frequency coherent noise.
const int X_NOISE_GEN = 1;
const int Y_NOISE_GEN = 31337;
const int Z_NOISE_GEN = 263;
const int SEED_NOISE_GEN = 1013;
const int SHIFT_NOISE_GEN = 13;
#else
// Constants used by the current version of libnoise.
const int X_NOISE_GEN = 1619;
const int Y_NOISE_GEN = 31337;
const int Z_NOISE_GEN = 6971;
const int SEED_NOISE_GEN = 1013;
const int SHIFT_NOISE_GEN = 8;
#endif
double noise::GradientCoherentNoise3D (double x, double y, double z, int seed,
NoiseQuality noiseQuality)
{
// Create a unit-length cube aligned along an integer boundary. This cube
// surrounds the input point.
int x0 = (x > 0.0? (int)x: (int)x - 1);
int x1 = x0 + 1;
int y0 = (y > 0.0? (int)y: (int)y - 1);
int y1 = y0 + 1;
int z0 = (z > 0.0? (int)z: (int)z - 1);
int z1 = z0 + 1;
// Map the difference between the coordinates of the input value and the
// coordinates of the cube's outer-lower-left vertex onto an S-curve.
double xs = 0, ys = 0, zs = 0;
switch (noiseQuality) {
case QUALITY_FAST:
xs = (x - (double)x0);
ys = (y - (double)y0);
zs = (z - (double)z0);
break;
case QUALITY_STD:
xs = SCurve3 (x - (double)x0);
ys = SCurve3 (y - (double)y0);
zs = SCurve3 (z - (double)z0);
break;
case QUALITY_BEST:
xs = SCurve5 (x - (double)x0);
ys = SCurve5 (y - (double)y0);
zs = SCurve5 (z - (double)z0);
break;
}
// Now calculate the noise values at each vertex of the cube. To generate
// the coherent-noise value at the input point, interpolate these eight
// noise values using the S-curve value as the interpolant (trilinear
// interpolation.)
double n0, n1, ix0, ix1, iy0, iy1;
n0 = GradientNoise3D (x, y, z, x0, y0, z0, seed);
n1 = GradientNoise3D (x, y, z, x1, y0, z0, seed);
ix0 = LinearInterp (n0, n1, xs);
n0 = GradientNoise3D (x, y, z, x0, y1, z0, seed);
n1 = GradientNoise3D (x, y, z, x1, y1, z0, seed);
ix1 = LinearInterp (n0, n1, xs);
iy0 = LinearInterp (ix0, ix1, ys);
n0 = GradientNoise3D (x, y, z, x0, y0, z1, seed);
n1 = GradientNoise3D (x, y, z, x1, y0, z1, seed);
ix0 = LinearInterp (n0, n1, xs);
n0 = GradientNoise3D (x, y, z, x0, y1, z1, seed);
n1 = GradientNoise3D (x, y, z, x1, y1, z1, seed);
ix1 = LinearInterp (n0, n1, xs);
iy1 = LinearInterp (ix0, ix1, ys);
return LinearInterp (iy0, iy1, zs);
}
double noise::GradientNoise3D (double fx, double fy, double fz, int ix,
int iy, int iz, int seed)
{
// Randomly generate a gradient vector given the integer coordinates of the
// input value. This implementation generates a random number and uses it
// as an index into a normalized-vector lookup table.
int vectorIndex = (
X_NOISE_GEN * ix
+ Y_NOISE_GEN * iy
+ Z_NOISE_GEN * iz
+ SEED_NOISE_GEN * seed)
& 0xffffffff;
vectorIndex ^= (vectorIndex >> SHIFT_NOISE_GEN);
vectorIndex &= 0xff;
double xvGradient = g_randomVectors[(vectorIndex << 2) ];
double yvGradient = g_randomVectors[(vectorIndex << 2) + 1];
double zvGradient = g_randomVectors[(vectorIndex << 2) + 2];
// Set up us another vector equal to the distance between the two vectors
// passed to this function.
double xvPoint = (fx - (double)ix);
double yvPoint = (fy - (double)iy);
double zvPoint = (fz - (double)iz);
// Now compute the dot product of the gradient vector with the distance
// vector. The resulting value is gradient noise. Apply a scaling value
// so that this noise value ranges from -1.0 to 1.0.
return ((xvGradient * xvPoint)
+ (yvGradient * yvPoint)
+ (zvGradient * zvPoint)) * 2.12;
}
int noise::IntValueNoise3D (int x, int y, int z, int seed)
{
// All constants are primes and must remain prime in order for this noise
// function to work correctly.
int n = (
X_NOISE_GEN * x
+ Y_NOISE_GEN * y
+ Z_NOISE_GEN * z
+ SEED_NOISE_GEN * seed)
& 0x7fffffff;
n = (n >> 13) ^ n;
return (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
}
double noise::ValueCoherentNoise3D (double x, double y, double z, int seed,
NoiseQuality noiseQuality)
{
// Create a unit-length cube aligned along an integer boundary. This cube
// surrounds the input point.
int x0 = (x > 0.0? (int)x: (int)x - 1);
int x1 = x0 + 1;
int y0 = (y > 0.0? (int)y: (int)y - 1);
int y1 = y0 + 1;
int z0 = (z > 0.0? (int)z: (int)z - 1);
int z1 = z0 + 1;
// Map the difference between the coordinates of the input value and the
// coordinates of the cube's outer-lower-left vertex onto an S-curve.
double xs = 0, ys = 0, zs = 0;
switch (noiseQuality) {
case QUALITY_FAST:
xs = (x - (double)x0);
ys = (y - (double)y0);
zs = (z - (double)z0);
break;
case QUALITY_STD:
xs = SCurve3 (x - (double)x0);
ys = SCurve3 (y - (double)y0);
zs = SCurve3 (z - (double)z0);
break;
case QUALITY_BEST:
xs = SCurve5 (x - (double)x0);
ys = SCurve5 (y - (double)y0);
zs = SCurve5 (z - (double)z0);
break;
}
// Now calculate the noise values at each vertex of the cube. To generate
// the coherent-noise value at the input point, interpolate these eight
// noise values using the S-curve value as the interpolant (trilinear
// interpolation.)
double n0, n1, ix0, ix1, iy0, iy1;
n0 = ValueNoise3D (x0, y0, z0, seed);
n1 = ValueNoise3D (x1, y0, z0, seed);
ix0 = LinearInterp (n0, n1, xs);
n0 = ValueNoise3D (x0, y1, z0, seed);
n1 = ValueNoise3D (x1, y1, z0, seed);
ix1 = LinearInterp (n0, n1, xs);
iy0 = LinearInterp (ix0, ix1, ys);
n0 = ValueNoise3D (x0, y0, z1, seed);
n1 = ValueNoise3D (x1, y0, z1, seed);
ix0 = LinearInterp (n0, n1, xs);
n0 = ValueNoise3D (x0, y1, z1, seed);
n1 = ValueNoise3D (x1, y1, z1, seed);
ix1 = LinearInterp (n0, n1, xs);
iy1 = LinearInterp (ix0, ix1, ys);
return LinearInterp (iy0, iy1, zs);
}
double noise::ValueNoise3D (int x, int y, int z, int seed)
{
return 1.0 - ((double)IntValueNoise3D (x, y, z, seed) / 1073741824.0);
}