Editor/Noise/Lanczos.cs
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;

namespace Sturnus.TerrainGenerationTool.Noise.Lanczos
{
	//A version of value-noise using Lanczos-Resampling. Also has classic billiniar-noise
	//Made by Zomare

	class ValueNoise
	{
		//Hash-Function for rng, outputs in range [-1, 1]
		static float Random( int x1, int y1 )
		{
			byte[] table = {151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7,
							225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247,
							120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,
							88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134,
							139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220,
							105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80,
							73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86,
							164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38,
							147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189,
							28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101,
							155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
							178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12,
							191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181,
							199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236,
							205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180};

			return ((float)table[(x1 + table[y1 & 255]) & 255] / 255f) * 2 - 1;
		}


		public static float Compute( float x, float y )
		{
			int ix = (int)x;
			int iy = (int)y;

			float dx = x - ix;
			float dy = y - iy;

			//averages used for normalizing
			float avgY = 0;
			float avgX = 0;

			//Calculating lookup table for faster horizontal interpolation
			float[] lanczosX = new float[6];

			for ( int px = -2; px < 4; px++ )
			{
				float f = Lanczos( dx - px );
				avgX += f;
				lanczosX[px + 2] = f;
			}

			float n = 0;

			for ( int py = -2; py < 4; py++ )
			{
				float a = 0;

				for ( int px = -2; px < 4; px++ )
				{
					a += Random( ix + px, iy + py ) * lanczosX[px + 2];
				}

				a /= avgX;
				n += a * Lanczos( dy - py );
				avgY += Lanczos( dy - py );
			}

			//!Not correctly normalized!
			return smoothstep( -1, 1, (n / avgY / 1.25f + 1) / 2f );
		}

		//Lanczos function used for interpolation
		//L(x)=sinc(x)sinc(x/a)
		static float Lanczos( float t )
		{
			if ( t == 0 )
			{
				return 1;
			}
			else if ( t > 4 || t < -4 )
			{
				return 0;
			}

			return 3 * (float)((Math.Sin( Math.PI * t ) * Math.Sin( Math.PI * (t / 3) )) / (Math.PI * Math.PI * t * t));
		}


		//Left in for the purpose of maybe using it later
		static float Sinc( float x )
		{
			return (float)(Math.Sin( Math.PI * x ) / (Math.PI * x));
		}

		//Outputs an low frequency octave of noise as a png
		/*static public void Test( int d )
		{
			var bm = new Bitmap( d, d );

			int off = new Random().Next( -1000, 1000 );

			for ( int y = 0; y < d; y++ )
			{
				for ( int x = 0; x < d; x++ )
				{
					int c = (int)(255 * (Compute( x * 0.025f, y * 0.025f + off ) + 1) / 2f);

					bm.SetPixel( x, y, Color.FromArgb( c, c, c ) );
				}
			}

			bm.Save( "test.png" );
		}*/

		//Generates a worldmap and outputs it as a png
		/*static public void Generate( int d )
		{
			var bm = new Bitmap( d, d );

			int off = new Random().Next( -1000, 1000 );

			for ( int y = 0; y < d; y++ )
			{
				for ( int x = 0; x < d; x++ )
				{
					float a = Math.Abs( ComputeFractal( x * 0.02f, y * 0.02f + off, 4 ) );

					if ( a > 0.2f )
					{
						a = 0.2f;
					}
					a /= 0.2f;


					a *= ComputeFractal( x * 0.025f, y * 0.025f + 1000 + off, 8 ) * 0.5f + 0.5f;

					Color c = Color.Aqua;


					if ( a > 0.9f )
					{
						c = Color.White;
					}
					else if ( a > 0.75f )
					{
						c = Color.LightGray;
					}
					else if ( a > 0.4f )
					{
						c = Color.ForestGreen;
					}

					bm.SetPixel( x, y, c );
				}
			}

			bm.Save( "map.png" );
		}*/

		//Fractal Noise; n: amount of octaves
		static public float ComputeFractal( float x, float y, int n )
		{
			float a = 0;
			float avg = 0;
			float w = 1;
			float frq = 1;

			for ( int i = 0; i < n; i++ )
			{
				a += Compute( x * frq, y * frq ) * w;
				avg += w;
				w *= 0.25f;
				frq *= 3;
			}

			return a / avg;
		}

		//"Normal" Value-Noise
		static public float ComputeLinear( float x, float y )
		{
			int ix = (int)x;
			int iy = (int)y;

			float dx = x - ix;
			float dy = y - iy;

			float fx1 = lerp( Random( ix, iy ), Random( ix + 1, iy ), dx );
			float fx2 = lerp( Random( ix, iy + 1 ), Random( ix + 1, iy + 1 ), dx );

			return lerp( fx1, fx2, dy );
		}


		//Basic interpolation Functions

		//7th order smoothstep
		static float smootherstep( float a1, float a2, float t )
		{
			return lerp( a1, a2, t * t * t * t * (t * (t * (70 - 20 * t) - 84) + 35) );
		}

		//Normal smoothstep
		static float smoothstep( float a1, float a2, float t )
		{
			return lerp( a1, a2, t * t * (3 - 2 * t) );
		}

		static float lerp( float a1, float a2, float t )
		{
			t = Math.Clamp( t, 0f, 1f );

			return (1 - t) * a1 + t * a2;
		}
	}
}