// 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); }