diff --git a/source/Noise.cpp b/source/Noise.cpp index 93a710970..2a1734497 100644 --- a/source/Noise.cpp +++ b/source/Noise.cpp @@ -74,7 +74,7 @@ class cCubicCell2D { public: cCubicCell2D( - cNoise & a_Noise, ///< Noise to use for generating the random values + const cNoise & a_Noise, ///< Noise to use for generating the random values 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 const NOISE_DATATYPE * a_FracX, ///< Pointer to the array that stores the X fractional values @@ -96,7 +96,7 @@ public: protected: typedef NOISE_DATATYPE Workspace[4][4]; - cNoise & m_Noise; + const cNoise & m_Noise; Workspace * m_WorkRnds; ///< The current random values; points to either m_Workspace1 or m_Workspace2 (doublebuffering) Workspace m_Workspace1; ///< Buffer 1 for workspace doublebuffering, used in Move() @@ -115,7 +115,7 @@ protected: cCubicCell2D::cCubicCell2D( - cNoise & a_Noise, ///< Noise to use for generating the random values + const cNoise & a_Noise, ///< Noise to use for generating the random values 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 const NOISE_DATATYPE * a_FracX, ///< Pointer to the array that stores the X fractional values @@ -228,6 +228,15 @@ cNoise::cNoise(unsigned int a_Seed) : +cNoise::cNoise(const cNoise & a_Noise) : + m_Seed(a_Noise.m_Seed) +{ +} + + + + + NOISE_DATATYPE cNoise::LinearNoise1D(NOISE_DATATYPE a_X) const { int BaseX = FAST_FLOOR(a_X); @@ -370,6 +379,13 @@ NOISE_DATATYPE cNoise::CubicNoise3D(NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOIS /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cCubicNoise: +#ifdef _DEBUG + int cCubicNoise::m_NumSingleX = 0; + int cCubicNoise::m_NumSingleXY = 0; + int cCubicNoise::m_NumSingleY = 0; + int cCubicNoise::m_NumCalls = 0; +#endif // _DEBUG + cCubicNoise::cCubicNoise(int a_Seed) : m_Noise(a_Seed) { @@ -383,9 +399,8 @@ void cCubicNoise::Generate2D( NOISE_DATATYPE * a_Array, ///< Array to generate into [x + a_SizeX * y] int a_SizeX, int a_SizeY, ///< Size of the array (num doubles), 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 ///< Workspace that this function can use and trash -) + NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction +) const { ASSERT(a_SizeX < MAX_SIZE); ASSERT(a_SizeY < MAX_SIZE); @@ -407,6 +422,23 @@ void cCubicNoise::Generate2D( Cell.InitWorkRnds(FloorX[0], FloorY[0]); + #ifdef _DEBUG + // Statistics on the noise-space coords: + if (NumSameX == 1) + { + m_NumSingleX++; + if (NumSameY == 1) + { + m_NumSingleXY++; + } + } + if (NumSameY == 1) + { + m_NumSingleY++; + } + m_NumCalls++; + #endif _DEBUG + // Calculate query values using Cell: int FromY = 0; for (int y = 0; y < NumSameY; y++) @@ -435,7 +467,7 @@ void cCubicNoise::CalcFloorFrac( NOISE_DATATYPE a_Start, NOISE_DATATYPE a_End, int * a_Floor, NOISE_DATATYPE * a_Frac, int * a_Same, int & a_NumSame -) +) const { NOISE_DATATYPE val = a_Start; NOISE_DATATYPE dif = (a_End - a_Start) / a_Size; @@ -470,3 +502,102 @@ void cCubicNoise::CalcFloorFrac( + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cPerlinNoise: + +cPerlinNoise::cPerlinNoise(void) : + m_Seed(0) +{ +} + + + + + +cPerlinNoise::cPerlinNoise(int a_Seed) : + m_Seed(a_Seed) +{ +} + + + + + +void cPerlinNoise::SetSeed(int a_Seed) +{ + m_Seed = a_Seed; +} + + + + + +void cPerlinNoise::AddOctave(float a_Frequency, float a_Amplitude) +{ + m_Octaves.push_back(cOctave(m_Seed * (m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude)); +} + + + + + +void cPerlinNoise::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 ///< Workspace that this function can use and trash +) const +{ + if (m_Octaves.empty()) + { + // No work to be done + return; + } + + bool ShouldFreeWorkspace = (a_Workspace == NULL); + int ArrayCount = a_SizeX * a_SizeY; + if (ShouldFreeWorkspace) + { + a_Workspace = new NOISE_DATATYPE[ArrayCount]; + } + + // Generate the first octave directly into array: + m_Octaves.front().m_Noise.Generate2D( + a_Workspace, a_SizeX, a_SizeY, + a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency, + a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency + ); + NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude; + for (int i = 0; i < ArrayCount; i++) + { + a_Array[i] *= Amplitude; + } + + // Add each octave: + for (cOctaves::const_iterator itr = m_Octaves.begin() + 1, end = m_Octaves.end(); itr != end; ++itr) + { + // Generate cubic noise for the octave: + itr->m_Noise.Generate2D( + a_Workspace, a_SizeX, a_SizeY, + a_StartX * itr->m_Frequency, a_EndX * itr->m_Frequency, + a_StartY * itr->m_Frequency, a_EndY * itr->m_Frequency + ); + // Add the cubic noise into the output: + NOISE_DATATYPE Amplitude = itr->m_Amplitude; + for (int i = 0; i < ArrayCount; i++) + { + a_Array[i] += a_Workspace[i] * Amplitude; + } + } + + if (ShouldFreeWorkspace) + { + delete[] a_Workspace; + } +} + + + + diff --git a/source/Noise.h b/source/Noise.h index 2829ac827..983ecb4b6 100644 --- a/source/Noise.h +++ b/source/Noise.h @@ -26,6 +26,7 @@ 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; @@ -139,18 +140,16 @@ public: 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 - ); + 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 - NOISE_DATATYPE * a_Workspace = NULL ///< Workspace that this function can use and trash - ); + NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction + ) const; void Generate3D( @@ -158,15 +157,22 @@ public: 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 - ); + 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( @@ -174,7 +180,7 @@ protected: 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, @@ -182,7 +188,7 @@ protected: int a_LastFloorX, int a_NewFloorX, int a_FloorY, NOISE_DATATYPE a_FractionY - ); + ) const; } ; @@ -192,12 +198,20 @@ protected: 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( @@ -206,7 +220,7 @@ public: 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( @@ -216,7 +230,29 @@ public: 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 cOctaves; + + int m_Seed; + cOctaves m_Octaves; } ;