summaryrefslogblamecommitdiffstats
path: root/src/Noise/Noise.h
blob: 4286d13fb502882184ede54bedcf64ce7fabd013 (plain) (tree)
1
2
3
4
5
6
7
8
9




                                                                                 

            

                                                     
 
                       
                         
                        






            
         
                           
                                       
 
                                                                               


                                                                          
                                                               
 
                                                        
                                                                                                 



                                                                                

                                                                                                                   


                                                                  
                                                       
 

                                                               
                                                              
                                                    
 
                                                                                  
 
                                                                                                      
 
                                                     
                                                  
 






                                                      

                                                                                                                     
 
          
                   
  




 

                 
         

                                                                  

 
                                                              
                                

 
                                                             
                        






                                                                                               
                

 
                                                             
                        









                                                                                                                
                
 
            








                                                                                                               

                           





                                        
                
  




 

                                                                                               

                    
         






                                                                                                 






                                                                                               
                

 

                                                             









                                                                                                                




                                                                                                  
            




                                                                                        
                                                                                                                       














                                                                                                                 
                                                
                                                                   



 
 
                                                                                





                                                                       
                                                                                                                        










                                                         
                                                                                                                        










                                                                       

                                                

                                                                                                                     






                                                         








                                                       































                                                                          








                                                        






                                        














                                                                                                      
                                                                                 


                                                                                                                         







                                                                                                      
                                               




 
 
                                                                                

                    

                                                                                                         






                                       


                                                                                                         







                                       



























                                                                                                       

// Noise.h

// Declares the cNoise, cCubicNoise and cPerlinNoise classes for generating noise

#pragma once

/** The datatype used by all the noise generators. */
typedef float NOISE_DATATYPE;

#include "../Vector3.h"
#include "OctavedNoise.h"
#include "RidgedNoise.h"





class cNoise
{
  public:
	cNoise(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;
	inline NOISE_DATATYPE IntNoise3D(Vector3i a_Pos) const;

	// Return a float number in the specified range:
	inline NOISE_DATATYPE IntNoise2DInRange(int a_X, int a_Y, float a_Min, float a_Max) const
	{
		return a_Min + std::abs(IntNoise2D(a_X, a_Y)) * (a_Max - a_Min);
	}

	// 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;
	inline int IntNoise3DInt(Vector3i a_Pos) 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(int a_Seed) { m_Seed = a_Seed; }
	int GetSeed(void) const { return m_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:
	int m_Seed;
};





class cCubicNoise
{
  public:
	/** Maximum size of each dimension of the query arrays. */
	static const int MAX_SIZE = 512;


	/** Creates a new instance with the specified seed. */
	cCubicNoise(int a_Seed);


	/** Fills a 2D array with the values of the noise. */
	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;


	/** Fills a 3D array with the values of the noise. */
	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:
	/** Noise used for integral random values. */
	cNoise m_Noise;


	/** Calculates the integral and fractional parts along one axis.
	a_Floor will receive the integral parts (array of a_Size ints).
	a_Frac will receive the fractional parts (array of a_Size floats).
	a_Same will receive the counts of items that have the same integral parts (array of up to a_Size ints).
	a_NumSame will receive the count of a_Same elements (total count of different integral parts). */
	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;
};





/** Improved noise, as described by Ken Perlin: https://mrl.nyu.edu/~perlin/paper445.pdf
Implementation adapted from Perlin's Java implementation: https://mrl.nyu.edu/~perlin/noise/ */
class cImprovedNoise
{
  public:
	/** Constructs a new instance of the noise obbject.
	Note that this operation is quite expensive (the permutation array being constructed). */
	cImprovedNoise(int a_Seed);


	/** Fills a 2D array with the values of the noise. */
	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;


	/** Fills a 3D array with the values of the noise. */
	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;

	/** Returns the value at the specified integral coords. Used for raw speed measurement. */
	NOISE_DATATYPE GetValueAt(int a_X, int a_Y, int a_Z);

  protected:
	/** The permutation table used by the noise function. Initialized using seed. */
	int m_Perm[512];


	/** Calculates the fade curve, 6 * t^5 - 15 * t^4 + 10 * t^3. */
	inline static NOISE_DATATYPE Fade(NOISE_DATATYPE a_T) { return a_T * a_T * a_T * (a_T * (a_T * 6 - 15) + 10); }

	/** Returns the gradient value based on the hash. */
	inline static NOISE_DATATYPE Grad(int a_Hash, NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z)
	{
		int hash = a_Hash % 16;
		NOISE_DATATYPE u = (hash < 8) ? a_X : a_Y;
		NOISE_DATATYPE v = (hash < 4) ? a_Y : (((hash == 12) || (hash == 14)) ? a_X : a_Z);
		return (((hash & 1) == 0) ? u : -u) + (((hash & 2) == 0) ? v : -v);
	}
};





typedef cOctavedNoise<cCubicNoise> cPerlinNoise;
typedef cOctavedNoise<cRidgedNoise<cCubicNoise>> cRidgedMultiNoise;





////////////////////////////////////////////////////////////////////////////////
// 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 - static_cast<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 - static_cast<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 (
		static_cast<NOISE_DATATYPE>(1) -
		static_cast<NOISE_DATATYPE>((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f
	);
	// returns a float number in the range of [-1, 1]
}





NOISE_DATATYPE cNoise::IntNoise3D(Vector3i a_Pos) const
{
	return IntNoise3D(a_Pos.x, a_Pos.y, a_Pos.z);
}





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





int cNoise::IntNoise3DInt(Vector3i a_Pos) const
{
	return IntNoise3DInt(a_Pos.x, a_Pos.y, a_Pos.z);
}





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 * static_cast<NOISE_DATATYPE>(3.1415927);
	const NOISE_DATATYPE f =
		static_cast<NOISE_DATATYPE>(static_cast<NOISE_DATATYPE>(1 - cos(ft)) * static_cast<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;
}





////////////////////////////////////////////////////////////////////////////////
// Global functions:

/** Exports the noise array into a file.
a_Coeff specifies the value that each array value is multiplied by before being converted into a byte. */
extern void Debug2DNoise(
	const NOISE_DATATYPE * a_Array,
	size_t a_SizeX,
	size_t a_SizeY,
	const AString & a_FileNameBase,
	NOISE_DATATYPE a_Coeff = 32
);

/** Exports the noise array into a set of files, ordered by XY and XZ.
a_Coeff specifies the value that each array value is multiplied by before being converted into a byte. */
extern void Debug3DNoise(
	const NOISE_DATATYPE * a_Array,
	size_t a_SizeX,
	size_t a_SizeY,
	size_t a_SizeZ,
	const AString & a_FileNameBase,
	NOISE_DATATYPE a_Coeff = 32
);




/** Linearly interpolates between two values.
Assumes that a_Ratio is in range [0, 1]. */
inline NOISE_DATATYPE Lerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
{
	return a_Val1 + (a_Val2 - a_Val1) * a_Ratio;
}





/** Linearly interpolates between two values, clamping the ratio to [0, 1] first. */
inline NOISE_DATATYPE ClampedLerp(NOISE_DATATYPE a_Val1, NOISE_DATATYPE a_Val2, NOISE_DATATYPE a_Ratio)
{
	if (a_Ratio < 0)
	{
		return a_Val1;
	}
	if (a_Ratio > 1)
	{
		return a_Val2;
	}
	return Lerp(a_Val1, a_Val2, a_Ratio);
}