817b9ba235
git-svn-id: http://mc-server.googlecode.com/svn/trunk@1408 0a769ca7-a7f5-676a-18bf-c427514a06d6
358 lines
10 KiB
C++
358 lines
10 KiB
C++
|
|
// Noise.h
|
|
|
|
// Declares the cNoise, cCubicNoise and cPerlinNoise classes for generating noise
|
|
|
|
#pragma once
|
|
|
|
// Some settings
|
|
#define NOISE_DATATYPE float
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
#define INLINE __forceinline
|
|
#else
|
|
#define INLINE inline
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
class cNoise
|
|
{
|
|
public:
|
|
cNoise(unsigned int a_Seed);
|
|
cNoise(const cNoise & a_Noise);
|
|
|
|
// The following functions, if not marked INLINE, are about 20 % slower
|
|
INLINE NOISE_DATATYPE IntNoise1D(int a_X) const;
|
|
INLINE NOISE_DATATYPE IntNoise2D(int a_X, int a_Y) const;
|
|
INLINE NOISE_DATATYPE IntNoise3D(int a_X, int a_Y, int a_Z) const;
|
|
|
|
// Note: These functions have a mod8-irregular chance - each of the mod8 remainders has different chance of occurrence. Divide by 8 to rectify.
|
|
INLINE int IntNoise1DInt(int a_X) const;
|
|
INLINE int IntNoise2DInt(int a_X, int a_Y) const;
|
|
INLINE int IntNoise3DInt(int a_X, int a_Y, int a_Z) const;
|
|
|
|
NOISE_DATATYPE LinearNoise1D(NOISE_DATATYPE a_X) const;
|
|
NOISE_DATATYPE CosineNoise1D(NOISE_DATATYPE a_X) const;
|
|
NOISE_DATATYPE CubicNoise1D (NOISE_DATATYPE a_X) const;
|
|
NOISE_DATATYPE SmoothNoise1D(int a_X) const;
|
|
|
|
NOISE_DATATYPE CubicNoise2D (NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y) const;
|
|
|
|
NOISE_DATATYPE CubicNoise3D (NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z) const;
|
|
|
|
void SetSeed(unsigned int a_Seed) { m_Seed = a_Seed; }
|
|
|
|
INLINE static NOISE_DATATYPE CubicInterpolate (NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_C, NOISE_DATATYPE a_D, NOISE_DATATYPE a_Pct);
|
|
INLINE static NOISE_DATATYPE CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct);
|
|
INLINE static NOISE_DATATYPE LinearInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct);
|
|
|
|
private:
|
|
unsigned int m_Seed;
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
/// Linearly interpolates values in the array between the anchor points
|
|
extern void IntArrayLinearInterpolate2D(
|
|
int * a_Array,
|
|
int a_SizeX, int a_SizeY, // Dimensions of the array
|
|
int a_AnchorStepX, int a_AnchorStepY // Distances between the anchor points in each direction
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/// Linearly interpolates values in the array between the anchor points; universal data type
|
|
template<typename TYPE> void ArrayLinearInterpolate2D(
|
|
TYPE * a_Array,
|
|
int a_SizeX, int a_SizeY, // Dimensions of the array
|
|
int a_AnchorStepX, int a_AnchorStepY // Distances between the anchor points in each direction
|
|
)
|
|
{
|
|
// First interpolate columns where the anchor points are:
|
|
int LastYCell = a_SizeY - a_AnchorStepY;
|
|
for (int y = 0; y < LastYCell; y += a_AnchorStepY)
|
|
{
|
|
int Idx = a_SizeX * y;
|
|
for (int x = 0; x < a_SizeX; x += a_AnchorStepX)
|
|
{
|
|
TYPE StartValue = a_Array[Idx];
|
|
TYPE EndValue = a_Array[Idx + a_SizeX * a_AnchorStepY];
|
|
TYPE Diff = EndValue - StartValue;
|
|
for (int CellY = 1; CellY < a_AnchorStepY; CellY++)
|
|
{
|
|
a_Array[Idx + a_SizeX * CellY] = StartValue + Diff * CellY / a_AnchorStepY;
|
|
} // for CellY
|
|
Idx += a_AnchorStepX;
|
|
} // for x
|
|
} // for y
|
|
|
|
// Now interpolate in rows, each row has values in the anchor columns
|
|
int LastXCell = a_SizeX - a_AnchorStepX;
|
|
for (int y = 0; y < a_SizeY; y++)
|
|
{
|
|
int Idx = a_SizeX * y;
|
|
for (int x = 0; x < LastXCell; x += a_AnchorStepX)
|
|
{
|
|
TYPE StartValue = a_Array[Idx];
|
|
TYPE EndValue = a_Array[Idx + a_AnchorStepX];
|
|
TYPE Diff = EndValue - StartValue;
|
|
for (int CellX = 1; CellX < a_AnchorStepX; CellX++)
|
|
{
|
|
a_Array[Idx + CellX] = StartValue + CellX * Diff / a_AnchorStepX;
|
|
} // for CellY
|
|
Idx += a_AnchorStepX;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class cCubicNoise
|
|
{
|
|
public:
|
|
static const int MAX_SIZE = 512; ///< Maximum size of each dimension of the query arrays.
|
|
|
|
|
|
cCubicNoise(int a_Seed);
|
|
|
|
|
|
void Generate1D(
|
|
NOISE_DATATYPE * a_Array, ///< Array to generate into
|
|
int a_SizeX, ///< Count of the array
|
|
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX ///< Noise-space coords of the array
|
|
) const;
|
|
|
|
|
|
void Generate2D(
|
|
NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y]
|
|
int a_SizeX, int a_SizeY, ///< Count of the array, in each direction
|
|
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
|
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction
|
|
) const;
|
|
|
|
|
|
void Generate3D(
|
|
NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y + a_SizeX * a_SizeY * z]
|
|
int a_SizeX, int a_SizeY, int a_SizeZ, ///< Count of the array, in each direction
|
|
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
|
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction
|
|
NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ ///< Noise-space coords of the array in the Z direction
|
|
) const;
|
|
|
|
protected:
|
|
typedef NOISE_DATATYPE Workspace1D[4];
|
|
typedef NOISE_DATATYPE Workspace2D[4][4];
|
|
|
|
cNoise m_Noise; // Used for integral rnd values
|
|
|
|
#ifdef _DEBUG
|
|
// Statistics on the noise-space coords:
|
|
static int m_NumSingleX;
|
|
static int m_NumSingleXY;
|
|
static int m_NumSingleY;
|
|
static int m_NumCalls;
|
|
#endif // _DEBUG
|
|
|
|
/// Calculates the integral and fractional parts along one axis.
|
|
void CalcFloorFrac(
|
|
int a_Size,
|
|
NOISE_DATATYPE a_Start, NOISE_DATATYPE a_End,
|
|
int * a_Floor, NOISE_DATATYPE * a_Frac,
|
|
int * a_Same, int & a_NumSame
|
|
) const;
|
|
|
|
void UpdateWorkRnds2DX(
|
|
Workspace2D & a_WorkRnds,
|
|
Workspace1D & a_Interps,
|
|
int a_LastFloorX, int a_NewFloorX,
|
|
int a_FloorY,
|
|
NOISE_DATATYPE a_FractionY
|
|
) const;
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
class cPerlinNoise
|
|
{
|
|
public:
|
|
cPerlinNoise(void);
|
|
cPerlinNoise(int a_Seed);
|
|
|
|
|
|
void SetSeed(int a_Seed);
|
|
|
|
void AddOctave(NOISE_DATATYPE a_Frequency, NOISE_DATATYPE a_Amplitude);
|
|
|
|
void Generate1D(
|
|
NOISE_DATATYPE * a_Array, ///< Array to generate into
|
|
int a_SizeX, ///< Count of the array
|
|
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array
|
|
NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash
|
|
) const;
|
|
|
|
|
|
void Generate2D(
|
|
NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y]
|
|
int a_SizeX, int a_SizeY, ///< Count of the array, in each direction
|
|
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
|
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction
|
|
NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash
|
|
) const;
|
|
|
|
|
|
void Generate3D(
|
|
NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y + a_SizeX * a_SizeY * z]
|
|
int a_SizeX, int a_SizeY, int a_SizeZ, ///< Count of the array, in each direction
|
|
NOISE_DATATYPE a_StartX, NOISE_DATATYPE a_EndX, ///< Noise-space coords of the array in the X direction
|
|
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY, ///< Noise-space coords of the array in the Y direction
|
|
NOISE_DATATYPE a_StartZ, NOISE_DATATYPE a_EndZ, ///< Noise-space coords of the array in the Z direction
|
|
NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash
|
|
) const;
|
|
|
|
protected:
|
|
class cOctave
|
|
{
|
|
public:
|
|
cCubicNoise m_Noise;
|
|
|
|
NOISE_DATATYPE m_Frequency; // Coord multiplier
|
|
NOISE_DATATYPE m_Amplitude; // Value multiplier
|
|
|
|
cOctave(int a_Seed, NOISE_DATATYPE a_Frequency, NOISE_DATATYPE a_Amplitude) :
|
|
m_Noise(a_Seed),
|
|
m_Frequency(a_Frequency),
|
|
m_Amplitude(a_Amplitude)
|
|
{
|
|
}
|
|
} ;
|
|
|
|
typedef std::vector<cOctave> cOctaves;
|
|
|
|
int m_Seed;
|
|
cOctaves m_Octaves;
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Inline function definitions:
|
|
// These need to be in the header, otherwise linker error occur in MSVC
|
|
|
|
NOISE_DATATYPE cNoise::IntNoise1D(int a_X) const
|
|
{
|
|
int x = ((a_X * m_Seed) << 13) ^ a_X;
|
|
return (1 - (NOISE_DATATYPE)((x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824);
|
|
// returns a float number in the range of [-1, 1]
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NOISE_DATATYPE cNoise::IntNoise2D(int a_X, int a_Y) const
|
|
{
|
|
int n = a_X + a_Y * 57 + m_Seed * 57 * 57;
|
|
n = (n << 13) ^ n;
|
|
return (1 - (NOISE_DATATYPE)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824);
|
|
// returns a float number in the range of [-1, 1]
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NOISE_DATATYPE cNoise::IntNoise3D(int a_X, int a_Y, int a_Z) const
|
|
{
|
|
int n = a_X + a_Y * 57 + a_Z * 57 * 57 + m_Seed * 57 * 57 * 57;
|
|
n = (n << 13) ^ n;
|
|
return ((NOISE_DATATYPE)1 - (NOISE_DATATYPE)((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
|
// returns a float number in the range of [-1, 1]
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cNoise::IntNoise1DInt(int a_X) const
|
|
{
|
|
int x = ((a_X * m_Seed) << 13) ^ a_X;
|
|
return ((x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cNoise::IntNoise2DInt(int a_X, int a_Y) const
|
|
{
|
|
int n = a_X + a_Y * 57 + m_Seed * 57 * 57;
|
|
n = (n << 13) ^ n;
|
|
return ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int cNoise::IntNoise3DInt(int a_X, int a_Y, int a_Z) const
|
|
{
|
|
int n = a_X + a_Y * 57 + a_Z * 57 * 57 + m_Seed * 57 * 57 * 57;
|
|
n = (n << 13) ^ n;
|
|
return ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NOISE_DATATYPE cNoise::CubicInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_C, NOISE_DATATYPE a_D, NOISE_DATATYPE a_Pct)
|
|
{
|
|
NOISE_DATATYPE P = (a_D - a_C) - (a_A - a_B);
|
|
NOISE_DATATYPE Q = (a_A - a_B) - P;
|
|
NOISE_DATATYPE R = a_C - a_A;
|
|
NOISE_DATATYPE S = a_B;
|
|
|
|
return ((P * a_Pct + Q) * a_Pct + R) * a_Pct + S;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NOISE_DATATYPE cNoise::CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct)
|
|
{
|
|
const NOISE_DATATYPE ft = a_Pct * (NOISE_DATATYPE)3.1415927;
|
|
const NOISE_DATATYPE f = (1 - cos(ft)) * (NOISE_DATATYPE)0.5;
|
|
return a_A * (1 - f) + a_B * f;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NOISE_DATATYPE cNoise::LinearInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct)
|
|
{
|
|
return a_A * (1 - a_Pct) + a_B * a_Pct;
|
|
}
|
|
|
|
|
|
|
|
|