/*
								+----------------------------------+
								|                                  |
								|  ***  GPU noise shader lib  ***  |
								|                                  |
								|   Copyright © -tHE SWINe- 2008   |
								|                                  |
								|           GPUNoise.cpp           |
								|                                  |
								+----------------------------------+
*/

/**
 *	@file dev/GPUNoise.cpp
 *	@date 2008
 *	@author -tHE SWINe-
 *	@brief GPU noise shader lib
 *
 *	@date 2008-08-08
 *
 *	added \#ifdef for windows 64, added \#define for GL_GLEXT_LEGACY (for linux builds)
 *
 */

#include "../NewFix.h"

#include "../CallStack.h"
#include <vector>
#include "../OpenGL20.h"
#include "../OpenGLState.h"
#include "../Texture.h"
#include "GPUNoise.h"

/*
 *								=== CGLNoise ===
 */
const uint8_t CGLNoise::m_p_perm_table[256] = {
	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};

const int8_t CGLNoise::m_p_grad3_table[16][3] = {
	{0, 1, 1}, {0, 1, -1}, {0, -1, 1}, {0, -1, -1},
	{1, 0, 1}, {1, 0, -1}, {-1, 0, 1}, {-1, 0, -1},
	{1, 1, 0}, {1, -1, 0}, {-1, 1, 0}, {-1, -1, 0},
	{1, 0, -1}, {-1, 0, -1}, {0, -1, 1}, {0, 1, 1}};

const int8_t CGLNoise::m_p_grad4_table[32][4] = {
	{0, 1, 1, 1}, {0, 1, 1, -1}, {0, 1, -1, 1}, {0, 1, -1, -1},
	{0, -1, 1, 1}, {0, -1, 1, -1}, {0, -1, -1, 1}, {0, -1, -1, -1},
	{1, 0, 1, 1}, {1, 0, 1, -1}, {1, 0, -1, 1}, {1, 0, -1, -1},
	{-1, 0, 1, 1}, {-1, 0, 1, -1}, {-1, 0, -1, 1}, {-1, 0, -1, -1},
	{1, 1, 0, 1}, {1, 1, 0, -1}, {1, -1, 0, 1}, {1, -1, 0, -1},
	{-1, 1, 0, 1}, {-1, 1, 0, -1}, {-1, -1, 0, 1}, {-1, -1, 0, -1},
	{1, 1, 1, 0}, {1, 1, -1, 0}, {1, -1, 1, 0}, {1, -1, -1, 0},
	{-1, 1, 1, 0}, {-1, 1, -1, 0}, {-1, -1, 1, 0}, {-1, -1, -1, 0}};

const uint8_t CGLNoise::m_p_simplex4_table[64][4] = {
	{0, 64, 128, 192}, {0, 64, 192, 128}, {0, 0, 0, 0}, {0, 128, 192, 64},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 128, 192, 0},
	{0, 128, 64, 192}, {0, 0, 0, 0}, {0, 192, 64, 128}, {0, 192, 128, 64},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {64, 192, 128, 0},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{64, 128, 0, 192}, {0, 0, 0, 0}, {64, 192, 0, 128}, {0, 0, 0, 0},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {128, 192, 0, 64}, {128, 192, 64, 0},
	{64, 0, 128, 192}, {64, 0, 192, 128}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{0, 0, 0, 0}, {128, 0, 192, 64}, {0, 0, 0, 0}, {128, 64, 192, 0},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{128, 0, 64, 192}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{192, 0, 64, 128}, {192, 0, 128, 64}, {0, 0, 0, 0}, {192, 64, 128, 0},
	{128, 64, 0, 192}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0},
	{192, 64, 0, 128}, {0, 0, 0, 0}, {192, 128, 0, 64}, {192, 128, 64, 0}};

const char *CGLNoise::m_p_s_noise_func_source_list[6] = {
	// 2D noise (perm texture)
	"#ifndef _HAVE_2D_PERLIN_NOISE_\n"
	"#define _HAVE_2D_PERLIN_NOISE_\n"
	"\n"
	"#ifndef _HAVE_PERM_TEX_\n"
	"#define _HAVE_PERM_TEX_\n"
	"uniform sampler2D n_perm_tex;\n"
	"#endif // _HAVE_PERM_TEX_\n"
	"\n"
	"#ifndef ONE\n"
	"#define ONE			0.00390625\n"
	"#endif // ONE\n"
	"\n"
	"#ifndef ONEHALF\n"
	"#define ONEHALF		0.001953125\n"
	"#endif // ONEHALF\n"
	"\n"
	"#ifndef _HAVE_FADE_\n"
	"#define _HAVE_FADE_\n"
	"float fade(float t)\n"
	"{\n"
	"	return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n"
	"}\n"
	"#endif // _HAVE_FADE_\n"
	"\n"
	"float noise(vec2 v_point)\n"
	"{\n"
	"	vec2 v_point_int = ONE * floor(v_point) + ONEHALF;\n"
	"	vec2 v_point_frac = fract(v_point);\n"
	"	vec2 grad00 = texture2D(n_perm_tex, v_point_int).xy * 4.0 - 1.0;\n"
	"	float n00 = dot(grad00, v_point_frac);\n"
	"	vec2 grad10 = texture2D(n_perm_tex, v_point_int + vec2(ONE, 0.0)).xy * 4.0 - 1.0;\n"
	"	float n10 = dot(grad10, v_point_frac - vec2(1.0, 0.0));\n"
	"	vec2 grad01 = texture2D(n_perm_tex, v_point_int + vec2(0.0, ONE)).xy * 4.0 - 1.0;\n"
	"	float n01 = dot(grad01, v_point_frac - vec2(0.0, 1.0));\n"
	"	vec2 grad11 = texture2D(n_perm_tex, v_point_int + vec2(ONE, ONE)).xy * 4.0 - 1.0;\n"
	"	float n11 = dot(grad11, v_point_frac - vec2(1.0, 1.0));\n"
	"	vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade(v_point_frac.x));\n"
	"	float n_xy = mix(n_x.x, n_x.y, fade(v_point_frac.y));\n"
	"	return n_xy;\n"
	"}\n"
	"#endif // _HAVE_2D_PERLIN_NOISE_\n",

	// 2D simplex noise (perm texture)
	"#ifndef _HAVE_2D_SIMPLEX_NOISE_\n"
	"#define _HAVE_2D_SIMPLEX_NOISE_\n"
	"\n"
	"#ifndef _HAVE_PERM_TEX_\n"
	"#define _HAVE_PERM_TEX_\n"
	"uniform sampler2D n_perm_tex;\n"
	"#endif // _HAVE_PERM_TEX_\n"
	"\n"
	"#ifndef ONE\n"
	"#define ONE			0.00390625\n"
	"#endif // ONE\n"
	"\n"
	"#ifndef ONEHALF\n"
	"#define ONEHALF		0.001953125\n"
	"#endif // ONEHALF\n"
	"\n"
	"#ifndef _HAVE_FADE_\n"
	"#define _HAVE_FADE_\n"
	"float fade(float t)\n"
	"{\n"
	"	return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n"
	"}\n"
	"#endif // _HAVE_FADE_\n"
	"\n"
	"#ifndef F2\n"
	"#define F2				0.366025403784\n"
	"#endif // F2\n"
	"\n"
	"#ifndef G2\n"
	"#define G2				0.211324865405\n"
	"#endif // G2\n"
	"\n"
	"float snoise(vec2 v_point)\n"
	"{\n"
	"	float s = (v_point.x + v_point.y) * F2;\n"
	"	vec2 v_point_int = floor(v_point + s);\n"
	"	float t = (v_point_int.x + v_point_int.y) * G2;\n"
	"	vec2 P0 = v_point_int - t;\n"
	"	v_point_int = v_point_int * ONE + ONEHALF;\n"
	"	vec2 Pf0 = v_point - P0;\n"
	"	vec2 o1;\n"
	"	if(Pf0.x > Pf0.y) o1 = vec2(1.0, 0.0);\n"
	"	else o1 = vec2(0.0, 1.0);\n"
	"	vec2 grad0 = texture2D(n_perm_tex, v_point_int).xy * 4.0 - 1.0;\n"
	"	float t0 = 0.5 - dot(Pf0, Pf0);\n"
	"	float n0;\n"
	"	if(t0 < 0.0)\n"
	"		n0 = 0.0;\n"
	"	else {\n"
	"		t0 *= t0;\n"
	"		n0 = t0 * t0 * dot(grad0, Pf0);\n"
	"	}\n"
	"	vec2 Pf1 = Pf0 - o1 + G2;\n"
	"	vec2 grad1 = texture2D(n_perm_tex, v_point_int + o1 * ONE).xy * 4.0 - 1.0;\n"
	"	float t1 = 0.5 - dot(Pf1, Pf1);\n"
	"	float n1;\n"
	"	if(t1 < 0.0)\n"
	"		n1 = 0.0;\n"
	"	else {\n"
	"		t1 *= t1;\n"
	"		n1 = t1 * t1 * dot(grad1, Pf1);\n"
	"	}\n"
	"	vec2 Pf2 = Pf0 - vec2(1.0 - 2.0 * G2);\n"
	"	vec2 grad2 = texture2D(n_perm_tex, v_point_int + vec2(ONE, ONE)).xy * 4.0 - 1.0;\n"
	"	float t2 = 0.5 - dot(Pf2, Pf2);\n"
	"	float n2;\n"
	"	if(t2 < 0.0)\n"
	"		n2 = 0.0;\n"
	"	else {\n"
	"		t2 *= t2;\n"
	"		n2 = t2 * t2 * dot(grad2, Pf2);\n"
	"	}\n"
	"	return 70.0 * (n0 + n1 + n2);\n"
	"}\n"
	"#endif // _HAVE_2D_SIMPLEX_NOISE_\n",

	// 3D noise (perm texture)
	"#ifndef _HAVE_3D_PERLIN_NOISE_\n"
	"#define _HAVE_3D_PERLIN_NOISE_\n"
	"\n"
	"#ifndef _HAVE_PERM_TEX_\n"
	"#define _HAVE_PERM_TEX_\n"
	"uniform sampler2D n_perm_tex;\n"
	"#endif // _HAVE_PERM_TEX_\n"
	"\n"
	"#ifndef ONE\n"
	"#define ONE			0.00390625\n"
	"#endif // ONE\n"
	"\n"
	"#ifndef ONEHALF\n"
	"#define ONEHALF		0.001953125\n"
	"#endif // ONEHALF\n"
	"\n"
	"#ifndef _HAVE_FADE_\n"
	"#define _HAVE_FADE_\n"
	"float fade(float t)\n"
	"{\n"
	"	return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n"
	"}\n"
	"#endif // _HAVE_FADE_\n"
	"\n"
	"float noise(vec3 v_point)\n"
	"{\n"
	"	vec3 v_point_int = ONE * floor(v_point) + ONEHALF;\n"
	"	vec3 v_point_frac = fract(v_point);\n"
	"	float perm00 = texture2D(n_perm_tex, v_point_int.xy).w;\n"
	"	vec3 grad000 = texture2D(n_perm_tex, vec2(perm00, v_point_int.z)).xyz * 4.0 - 1.0;\n"
	"	float n000 = dot(grad000, v_point_frac);\n"
	"	vec3 grad001 = texture2D(n_perm_tex, vec2(perm00, v_point_int.z + ONE)).xyz * 4.0 - 1.0;\n"
	"	float n001 = dot(grad001, v_point_frac - vec3(0.0, 0.0, 1.0));\n"
	"	float perm01 = texture2D(n_perm_tex, v_point_int.xy + vec2(0.0, ONE)).w;\n"
	"	vec3 grad010 = texture2D(n_perm_tex, vec2(perm01, v_point_int.z)).xyz * 4.0 - 1.0;\n"
	"	float n010 = dot(grad010, v_point_frac - vec3(0.0, 1.0, 0.0));\n"
	"	vec3 grad011 = texture2D(n_perm_tex, vec2(perm01, v_point_int.z + ONE)).xyz * 4.0 - 1.0;\n"
	"	float n011 = dot(grad011, v_point_frac - vec3(0.0, 1.0, 1.0));\n"
	"	float perm10 = texture2D(n_perm_tex, v_point_int.xy + vec2(ONE, 0.0)).w;\n"
	"	vec3 grad100 = texture2D(n_perm_tex, vec2(perm10, v_point_int.z)).xyz * 4.0 - 1.0;\n"
	"	float n100 = dot(grad100, v_point_frac - vec3(1.0, 0.0, 0.0));\n"
	"	vec3 grad101 = texture2D(n_perm_tex, vec2(perm10, v_point_int.z + ONE)).xyz * 4.0 - 1.0;\n"
	"	float n101 = dot(grad101, v_point_frac - vec3(1.0, 0.0, 1.0));\n"
	"	float perm11 = texture2D(n_perm_tex, v_point_int.xy + vec2(ONE, ONE)).w;\n"
	"	vec3 grad110 = texture2D(n_perm_tex, vec2(perm11, v_point_int.z)).xyz * 4.0 - 1.0;\n"
	"	float n110 = dot(grad110, v_point_frac - vec3(1.0, 1.0, 0.0));\n"
	"	vec3 grad111 = texture2D(n_perm_tex, vec2(perm11, v_point_int.z + ONE)).xyz * 4.0 - 1.0;\n"
	"	float n111 = dot(grad111, v_point_frac - vec3(1.0, 1.0, 1.0));\n"
	"	vec4 n_x = mix(vec4(n000, n001, n010, n011),\n"
	"		vec4(n100, n101, n110, n111), fade(v_point_frac.x));\n"
	"	vec2 n_xy = mix(n_x.xy, n_x.zw, fade(v_point_frac.y));\n"
	"	float n_xyz = mix(n_xy.x, n_xy.y, fade(v_point_frac.z));\n"
	"	return n_xyz;\n"
	"}\n"
	"#endif // _HAVE_3D_PERLIN_NOISE_\n",

	// 3D simplex noise (perm texture and simplex texture)
	"#ifndef _HAVE_3D_SIMPLEX_NOISE_\n"
	"#define _HAVE_3D_SIMPLEX_NOISE_\n"
	"\n"
	"#ifndef _HAVE_PERM_TEX_\n"
	"#define _HAVE_PERM_TEX_\n"
	"uniform sampler2D n_perm_tex;\n"
	"#endif // _HAVE_PERM_TEX_\n"
	"\n"
	"#ifndef _HAVE_SIMPLEX_TEX_\n"
	"#define _HAVE_SIMPLEX_TEX_\n"
	"uniform sampler1D n_simplex_tex;\n"
	"#endif // _HAVE_SIMPLEX_TEX_\n"
	"\n"
	"#ifndef ONE\n"
	"#define ONE			0.00390625\n"
	"#endif // ONE\n"
	"\n"
	"#ifndef ONEHALF\n"
	"#define ONEHALF		0.001953125\n"
	"#endif // ONEHALF\n"
	"\n"
	"#ifndef _HAVE_FADE_\n"
	"#define _HAVE_FADE_\n"
	"float fade(float t)\n"
	"{\n"
	"	return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n"
	"}\n"
	"#endif // _HAVE_FADE_\n"
	"\n"
	"#ifndef F3\n"
	"#define F3				0.333333333333\n"
	"#endif // F3\n"
	"\n"
	"#ifndef G3\n"
	"#define G3				0.166666666667\n"
	"#endif // G3\n"
	"\n"
	"float snoise(vec3 v_point)\n"
	"{\n"
	"	float s = (v_point.x + v_point.y + v_point.z) * F3;\n"
	"	vec3 v_point_int = floor(v_point + s);\n"
	"	float t = (v_point_int.x + v_point_int.y + v_point_int.z) * G3;\n"
	"	vec3 P0 = v_point_int - t;\n"
	"	v_point_int = v_point_int * ONE + ONEHALF;\n"
	"	vec3 Pf0 = v_point - P0;\n"
	"	float c1 = (Pf0.x > Pf0.y)? 0.5078125 : 0.0078125;\n"
	"	float c2 = (Pf0.x > Pf0.z)? 0.25 : 0.0;\n"
	"	float c3 = (Pf0.y > Pf0.z)? 0.125 : 0.0;\n"
	"	float sindex = c1 + c2 + c3;\n"
	"	vec3 offsets = texture1D(n_simplex_tex, sindex).xyz;\n"
	"	vec3 o1 = step(0.375, offsets);\n"
	"	vec3 o2 = step(0.125, offsets);\n"
	"	float perm0 = texture2D(n_perm_tex, v_point_int.xy).w;\n"
	"	vec3 grad0 = texture2D(n_perm_tex, vec2(perm0, v_point_int.z)).xyz * 4.0 - 1.0;\n"
	"	float t0 = 0.6 - dot(Pf0, Pf0);\n"
	"	float n0;\n"
	"	if(t0 < 0.0)\n"
	"		n0 = 0.0;\n"
	"	else {\n"
	"		t0 *= t0;\n"
	"		n0 = t0 * t0 * dot(grad0, Pf0);\n"
	"	}\n"
	"	vec3 Pf1 = Pf0 - o1 + G3;\n"
	"	float perm1 = texture2D(n_perm_tex, v_point_int.xy + o1.xy * ONE).w;\n"
	"	vec3 grad1 = texture2D(n_perm_tex, vec2(perm1, v_point_int.z + o1.z * ONE)).xyz * 4.0 - 1.0;\n"
	"	float t1 = 0.6 - dot(Pf1, Pf1);\n"
	"	float n1;\n"
	"	if(t1 < 0.0)\n"
	"		n1 = 0.0;\n"
	"	else {\n"
	"		t1 *= t1;\n"
	"		n1 = t1 * t1 * dot(grad1, Pf1);\n"
	"	}\n"
	"	vec3 Pf2 = Pf0 - o2 + 2.0 * G3;\n"
	"	float perm2 = texture2D(n_perm_tex, v_point_int.xy + o2.xy * ONE).w;\n"
	"	vec3 grad2 = texture2D(n_perm_tex, vec2(perm2, v_point_int.z + o2.z * ONE)).xyz * 4.0 - 1.0;\n"
	"	float t2 = 0.6 - dot(Pf2, Pf2);\n"
	"	float n2;\n"
	"	if(t2 < 0.0)\n"
	"		n2 = 0.0;\n"
	"	else {\n"
	"		t2 *= t2;\n"
	"		n2 = t2 * t2 * dot(grad2, Pf2);\n"
	"	}\n"
	"	vec3 Pf3 = Pf0 - vec3(1.0 - 3.0 * G3);\n"
	"	float perm3 = texture2D(n_perm_tex, v_point_int.xy + vec2(ONE, ONE)).w;\n"
	"	vec3 grad3 = texture2D(n_perm_tex, vec2(perm3, v_point_int.z + ONE)).xyz * 4.0 - 1.0;\n"
	"	float t3 = 0.6 - dot(Pf3, Pf3);\n"
	"	float n3;\n"
	"	if(t3 < 0.0)\n"
	"		n3 = 0.0;\n"
	"	else {\n"
	"		t3 *= t3;\n"
	"		n3 = t3 * t3 * dot(grad3, Pf3);\n"
	"	}\n"
	"	return 32.0 * (n0 + n1 + n2 + n3);\n"
	"}\n"
	"#endif // _HAVE_3D_SIMPLEX_NOISE_\n",

	// 4D noise (perm texture and grad texture)
	"#ifndef _HAVE_4D_PERLIN_NOISE_\n"
	"#define _HAVE_4D_PERLIN_NOISE_\n"
	"\n"
	"#ifndef _HAVE_PERM_TEX_\n"
	"#define _HAVE_PERM_TEX_\n"
	"uniform sampler2D n_perm_tex;\n"
	"#endif // _HAVE_PERM_TEX_\n"
	"\n"
	"#ifndef _HAVE_GRAD_TEX_\n"
	"#define _HAVE_GRAD_TEX_\n"
	"uniform sampler2D n_grad_tex;\n"
	"#endif // _HAVE_GRAD_TEX_\n"
	"\n"
	"#ifndef ONE\n"
	"#define ONE			0.00390625\n"
	"#endif // ONE\n"
	"\n"
	"#ifndef ONEHALF\n"
	"#define ONEHALF		0.001953125\n"
	"#endif // ONEHALF\n"
	"\n"
	"#ifndef _HAVE_FADE_\n"
	"#define _HAVE_FADE_\n"
	"float fade(float t)\n"
	"{\n"
	"	return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n"
	"}\n"
	"#endif // _HAVE_FADE_\n"
	"\n"
	"float noise(vec4 v_point)\n"
	"{\n"
	"	vec4 v_point_int = ONE * floor(v_point) + ONEHALF;\n"
	"	vec4 v_point_frac = fract(v_point);\n"
	"	float perm00xy = texture2D(n_perm_tex, v_point_int.xy).w;\n"
	"	float perm00zw = texture2D(n_perm_tex, v_point_int.zw).w;\n"
	"	vec4 grad0000 = texture2D(n_grad_tex, vec2(perm00xy, perm00zw)) * 4.0 - 1.0;\n"
	"	float n0000 = dot(grad0000, v_point_frac);\n"
	"	float perm01zw = texture2D(n_perm_tex, v_point_int.zw + vec2(0.0, ONE)).w;\n"
	"	vec4 grad0001 = texture2D(n_grad_tex, vec2(perm00xy, perm01zw)) * 4.0 - 1.0;\n"
	"	float n0001 = dot(grad0001, v_point_frac - vec4(0.0, 0.0, 0.0, 1.0));\n"
	"	float perm10zw = texture2D(n_perm_tex, v_point_int.zw + vec2(ONE, 0.0)).w;\n"
	"	vec4 grad0010 = texture2D(n_grad_tex, vec2(perm00xy, perm10zw)) * 4.0 - 1.0;\n"
	"	float n0010 = dot(grad0010, v_point_frac - vec4(0.0, 0.0, 1.0, 0.0));\n"
	"	float perm11zw = texture2D(n_perm_tex, v_point_int.zw + vec2(ONE, ONE)).w;\n"
	"	vec4 grad0011 = texture2D(n_grad_tex, vec2(perm00xy, perm11zw)) * 4.0 - 1.0;\n"
	"	float n0011 = dot(grad0011, v_point_frac - vec4(0.0, 0.0, 1.0, 1.0));\n"
	"	float perm01xy = texture2D(n_perm_tex, v_point_int.xy + vec2(0.0, ONE)).w;\n"
	"	vec4 grad0100 = texture2D(n_grad_tex, vec2(perm01xy, perm00zw)) * 4.0 - 1.0;\n"
	"	float n0100 = dot(grad0100, v_point_frac - vec4(0.0, 1.0, 0.0, 0.0));\n"
	"	vec4 grad0101 = texture2D(n_grad_tex, vec2(perm01xy, perm01zw)) * 4.0 - 1.0;\n"
	"	float n0101 = dot(grad0101, v_point_frac - vec4(0.0, 1.0, 0.0, 1.0));\n"
	"	vec4 grad0110 = texture2D(n_grad_tex, vec2(perm01xy, perm10zw)) * 4.0 - 1.0;\n"
	"	float n0110 = dot(grad0110, v_point_frac - vec4(0.0, 1.0, 1.0, 0.0));\n"
	"	vec4 grad0111 = texture2D(n_grad_tex, vec2(perm01xy, perm11zw)) * 4.0 - 1.0;\n"
	"	float n0111 = dot(grad0111, v_point_frac - vec4(0.0, 1.0, 1.0, 1.0));\n"
	"	float perm10xy = texture2D(n_perm_tex, v_point_int.xy + vec2(ONE, 0.0)).w;\n"
	"	vec4 grad1000 = texture2D(n_grad_tex, vec2(perm10xy, perm00zw)) * 4.0 - 1.0;\n"
	"	float n1000 = dot(grad1000, v_point_frac - vec4(1.0, 0.0, 0.0, 0.0));\n"
	"	vec4 grad1001 = texture2D(n_grad_tex, vec2(perm10xy, perm01zw)) * 4.0 - 1.0;\n"
	"	float n1001 = dot(grad1001, v_point_frac - vec4(1.0, 0.0, 0.0, 1.0));\n"
	"	vec4 grad1010 = texture2D(n_grad_tex, vec2(perm10xy, perm10zw)) * 4.0 - 1.0;\n"
	"	float n1010 = dot(grad1010, v_point_frac - vec4(1.0, 0.0, 1.0, 0.0));\n"
	"	vec4 grad1011 = texture2D(n_grad_tex, vec2(perm10xy, perm11zw)) * 4.0 - 1.0;\n"
	"	float n1011 = dot(grad1011, v_point_frac - vec4(1.0, 0.0, 1.0, 1.0));\n"
	"	float perm11xy = texture2D(n_perm_tex, v_point_int.xy + vec2(ONE, ONE)).w;\n"
	"	vec4 grad1100 = texture2D(n_grad_tex, vec2(perm11xy, perm00zw)) * 4.0 - 1.0;\n"
	"	float n1100 = dot(grad1100, v_point_frac - vec4(1.0, 1.0, 0.0, 0.0));\n"
	"	vec4 grad1101 = texture2D(n_grad_tex, vec2(perm11xy, perm01zw)) * 4.0 - 1.0;\n"
	"	float n1101 = dot(grad1101, v_point_frac - vec4(1.0, 1.0, 0.0, 1.0));\n"
	"	vec4 grad1110 = texture2D(n_grad_tex, vec2(perm11xy, perm10zw)) * 4.0 - 1.0;\n"
	"	float n1110 = dot(grad1110, v_point_frac - vec4(1.0, 1.0, 1.0, 0.0));\n"
	"	vec4 grad1111 = texture2D(n_grad_tex, vec2(perm11xy, perm11zw)) * 4.0 - 1.0;\n"
	"	float n1111 = dot(grad1111, v_point_frac - vec4(1.0, 1.0, 1.0, 1.0));\n"
	"	float fadex = fade(v_point_frac.x);\n"
	"	vec4 n_x0 = mix(vec4(n0000, n0001, n0010, n0011),\n"
	"		vec4(n1000, n1001, n1010, n1011), fadex);\n"
	"	vec4 n_x1 = mix(vec4(n0100, n0101, n0110, n0111),\n"
	"		vec4(n1100, n1101, n1110, n1111), fadex);\n"
	"	vec4 n_xy = mix(n_x0, n_x1, fade(v_point_frac.y));\n"
	"	vec2 n_xyz = mix(n_xy.xy, n_xy.zw, fade(v_point_frac.z));\n"
	"	float n_xyzw = mix(n_xyz.x, n_xyz.y, fade(v_point_frac.w));\n"
	"	return n_xyzw;\n"
	"}\n"
	"#endif // _HAVE_4D_PERLIN_NOISE_\n",

	// 4D simplex noise (all textures)
	"#ifndef _HAVE_4D_SIMPLEX_NOISE_\n"
	"#define _HAVE_4D_SIMPLEX_NOISE_\n"
	"\n"
	"#ifndef _HAVE_PERM_TEX_\n"
	"#define _HAVE_PERM_TEX_\n"
	"uniform sampler2D n_perm_tex;\n"
	"#endif // _HAVE_PERM_TEX_\n"
	"\n"
	"#ifndef _HAVE_SIMPLEX_TEX_\n"
	"#define _HAVE_SIMPLEX_TEX_\n"
	"uniform sampler1D n_simplex_tex;\n"
	"#endif // _HAVE_SIMPLEX_TEX_\n"
	"\n"
	"#ifndef _HAVE_GRAD_TEX_\n"
	"#define _HAVE_GRAD_TEX_\n"
	"uniform sampler2D n_grad_tex;\n"
	"#endif // _HAVE_GRAD_TEX_\n"
	"\n"
	"#ifndef ONE\n"
	"#define ONE			0.00390625\n"
	"#endif // ONE\n"
	"\n"
	"#ifndef ONEHALF\n"
	"#define ONEHALF		0.001953125\n"
	"#endif // ONEHALF\n"
	"\n"
	"#ifndef _HAVE_FADE_\n"
	"#define _HAVE_FADE_\n"
	"float fade(float t)\n"
	"{\n"
	"	return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);\n"
	"}\n"
	"#endif // _HAVE_FADE_\n"
	"\n"
	"#ifndef F4\n"
	"#define F4				0.309016994375\n"
	"#endif // F4\n"
	"\n"
	"#ifndef G4\n"
	"#define G4				0.138196601125\n"
	"#endif // G4\n"
	"\n"
	"float snoise(vec4 v_point)\n"
	"{\n"
	"	float s = (v_point.x + v_point.y + v_point.z + v_point.w) * F4;\n"
	"	vec4 v_point_int = floor(v_point + s);\n"
	"	float t = (v_point_int.x + v_point_int.y + v_point_int.z + v_point_int.w) * G4;\n"
	"	vec4 P0 = v_point_int - t;\n"
	"	v_point_int = v_point_int * ONE + ONEHALF;\n"
	"	vec4 Pf0 = v_point - P0;\n"
	"	float c1 = (Pf0.x > Pf0.y)? 0.5078125 : 0.0078125;\n"
	"	float c2 = (Pf0.x > Pf0.z)? 0.25 : 0.0;\n"
	"	float c3 = (Pf0.y > Pf0.z)? 0.125 : 0.0;\n"
	"	float c4 = (Pf0.x > Pf0.w)? 0.0625 : 0.0;\n"
	"	float c5 = (Pf0.y > Pf0.w)? 0.03125 : 0.0;\n"
	"	float c6 = (Pf0.z > Pf0.w)? 0.015625 : 0.0;\n"
	"	float sindex = c1 + c2 + c3 + c4 + c5 + c6;\n"
	"	vec4 offsets = texture1D(n_simplex_tex, sindex);\n"
	"	vec4 o1 = step(0.625, offsets);\n"
	"	vec4 o2 = step(0.375, offsets);\n"
	"	vec4 o3 = step(0.125, offsets);\n"
	"	float perm0xy = texture2D(n_perm_tex, v_point_int.xy).w;\n"
	"	float perm0zw = texture2D(n_perm_tex, v_point_int.zw).w;\n"
	"	vec4 grad0 = texture2D(n_grad_tex, vec2(perm0xy, perm0zw)) * 4.0 - 1.0;\n"
	"	float t0 = 0.6 - dot(Pf0, Pf0);\n"
	"	float n0;\n"
	"	if(t0 < 0.0)\n"
	"		n0 = 0.0;\n"
	"	else {\n"
	"		t0 *= t0;\n"
	"		n0 = t0 * t0 * dot(grad0, Pf0);\n"
	"	}\n"
	"	vec4 Pf1 = Pf0 - o1 + G4;\n"
	"	o1 = o1 * ONE;\n"
	"	float perm1xy = texture2D(n_perm_tex, v_point_int.xy + o1.xy).w;\n"
	"	float perm1zw = texture2D(n_perm_tex, v_point_int.zw + o1.zw).w;\n"
	"	vec4 grad1 = texture2D(n_grad_tex, vec2(perm1xy, perm1zw)) * 4.0 - 1.0;\n"
	"	float t1 = 0.6 - dot(Pf1, Pf1);\n"
	"	float n1;\n"
	"	if(t1 < 0.0)\n"
	"		n1 = 0.0;\n"
	"	else {\n"
	"		t1 *= t1;\n"
	"		n1 = t1 * t1 * dot(grad1, Pf1);\n"
	"	}\n"
	"	vec4 Pf2 = Pf0 - o2 + 2.0 * G4;\n"
	"	o2 = o2 * ONE;\n"
	"	float perm2xy = texture2D(n_perm_tex, v_point_int.xy + o2.xy).w;\n"
	"	float perm2zw = texture2D(n_perm_tex, v_point_int.zw + o2.zw).w;\n"
	"	vec4 grad2 = texture2D(n_grad_tex, vec2(perm2xy, perm2zw)) * 4.0 - 1.0;\n"
	"	float t2 = 0.6 - dot(Pf2, Pf2);\n"
	"	float n2;\n"
	"	if(t2 < 0.0)\n"
	"		n2 = 0.0;\n"
	"	else {\n"
	"		t2 *= t2;\n"
	"		n2 = t2 * t2 * dot(grad2, Pf2);\n"
	"	}\n"
	"	vec4 Pf3 = Pf0 - o3 + 3.0 * G4;\n"
	"	o3 = o3 * ONE;\n"
	"	float perm3xy = texture2D(n_perm_tex, v_point_int.xy + o3.xy).w;\n"
	"	float perm3zw = texture2D(n_perm_tex, v_point_int.zw + o3.zw).w;\n"
	"	vec4 grad3 = texture2D(n_grad_tex, vec2(perm3xy, perm3zw)) * 4.0 - 1.0;\n"
	"	float t3 = 0.6 - dot(Pf3, Pf3);\n"
	"	float n3;\n"
	"	if(t3 < 0.0)\n"
	"		n3 = 0.0;\n"
	"	else {\n"
	"		t3 *= t3;\n"
	"		n3 = t3 * t3 * dot(grad3, Pf3);\n"
	"	}\n"
	"	vec4 Pf4 = Pf0 - vec4(1.0 - 4.0 * G4);\n"
	"	float perm4xy = texture2D(n_perm_tex, v_point_int.xy + vec2(ONE, ONE)).w;\n"
	"	float perm4zw = texture2D(n_perm_tex, v_point_int.zw + vec2(ONE, ONE)).w;\n"
	"	vec4 grad4 = texture2D(n_grad_tex, vec2(perm4xy, perm4zw)) * 4.0 - 1.0;\n"
	"	float t4 = 0.6 - dot(Pf4, Pf4);\n"
	"	float n4;\n"
	"	if(t4 < 0.0)\n"
	"		n4 = 0.0;\n"
	"	else {\n"
	"		t4 *= t4;\n"
	"		n4 = t4 * t4 * dot(grad4, Pf4);\n"
	"	}\n"
	"	return 27.0 * (n0 + n1 + n2 + n3 + n4);\n"
	"}\n"
	"#endif // _HAVE_4D_SIMPLEX_NOISE_\n"
};

/*
 *	CGLNoise::CGLNoise()
 *		- default constructor; has no effect
 */
CGLNoise::CGLNoise()
	:m_p_grad(0), m_p_perm(0), m_p_simplex(0)
{}

/*
 *	CGLNoise::~CGLNoise()
 *		- destructor
 */
CGLNoise::~CGLNoise()
{
	if(m_p_grad)
		delete m_p_grad;
	if(m_p_perm)
		delete m_p_perm;
	if(m_p_simplex)
		delete m_p_simplex;
}

/*
 *	bool CGLNoise::Create_GradTex(CGLState *p_state)
 *		- creates gradient texture (in case it hasn't been created already)
 *		- p_state is OpenGL state guard
 *		- returns true on success, false on failure
 */
bool CGLNoise::Create_GradTex(CGLState *p_state)
{
	if(m_p_grad)
		return true;
	// it's been created already

	uint8_t *p_data;
	if(!(p_data = new(std::nothrow) uint8_t[256 * 256 * 4]))
		return false;
	// alloc temp array

	uint8_t *p_dest = p_data;
	for(int i = 0; i < 65536; ++ i, p_dest += 4) {
		uint8_t n_value = m_p_perm_table[((i & 0xff) + m_p_perm_table[i >> 8]) & 0xff];
		for(int j = 0; j < 4; ++ j)
			p_dest[j] = (m_p_grad4_table[n_value & 0x1f][j] + 1) << 6;
	}
	// calculate texture data

	if(!(m_p_grad = new(std::nothrow) CGLTexture_2D(p_state, 256, 256, GL_RGBA8, // RGBA2 is enough
	   false, 0, GL_RGBA, GL_UNSIGNED_BYTE, p_data))) {
		delete[] p_data;
		return false;
	}
	// create texture

	delete[] p_data;
	// don't need this anymore

	if(!m_p_grad->b_Status()) {
		delete m_p_grad;
		m_p_grad = 0;
		return false;
	}
	// check texture status

	CGLTextureParams &r_params = m_p_grad->r_Parameters(p_state);
	r_params.Set_Texture_Min_Filter(GL_NEAREST);
	r_params.Set_Texture_Mag_Filter(GL_NEAREST);
	// nearest filtering

	p_state->DisableTexture2D();
	p_state->BindTexture2D(0);
	// do not keep it bound

	return true;
}

/*
 *	bool CGLNoise::Create_PermTex(CGLState *p_state)
 *		- creates permutation texture (in case it hasn't been created already)
 *		- p_state is OpenGL state guard
 *		- returns true on success, false on failure
 */
bool CGLNoise::Create_PermTex(CGLState *p_state)
{
	if(m_p_perm)
		return true;
	// it's been created already

	uint8_t *p_data;
	if(!(p_data = new(std::nothrow) uint8_t[256 * 256 * 4]))
		return false;
	// alloc temp array

	uint8_t *p_dest = p_data;
	for(int i = 0; i < 65536; ++ i, p_dest += 4) {
		uint8_t n_value = m_p_perm_table[((i & 0xff) + m_p_perm_table[i >> 8]) & 0xff];
		for(int j = 0; j < 3; ++ j)
			p_dest[j] = (m_p_grad3_table[n_value & 0x0f][j] + 1) << 6;
		p_dest[3] = n_value;
	}
	// calculate texture data

	if(!(m_p_perm = new(std::nothrow) CGLTexture_2D(p_state, 256, 256, GL_RGBA8,
	   false, 0, GL_RGBA, GL_UNSIGNED_BYTE, p_data))) {
		delete[] p_data;
		return false;
	}
	// create texture

	delete[] p_data;
	// don't need this anymore

	if(!m_p_perm->b_Status()) {
		delete m_p_perm;
		m_p_perm = 0;
		return false;
	}
	// check texture status

	CGLTextureParams &r_params = m_p_perm->r_Parameters(p_state);
	r_params.Set_Texture_Min_Filter(GL_NEAREST);
	r_params.Set_Texture_Mag_Filter(GL_NEAREST);
	// nearest filtering

	p_state->DisableTexture2D();
	p_state->BindTexture2D(0);
	// do not keep it bound

	return true;
}

/*
 *	bool CGLNoise::Create_SimplexTex(CGLState *p_state)
 *		- creates simplex texture (in case it hasn't been created already)
 *		- note simplex texture is one-dimensional
 *		- p_state is OpenGL state guard
 *		- returns true on success, false on failure
 */
bool CGLNoise::Create_SimplexTex(CGLState *p_state)
{
	if(m_p_simplex)
		return true;
	// it's been created already

	if(!(m_p_simplex = new(std::nothrow) CGLTexture_1D(p_state, 64, GL_RGBA8,
	   false, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_p_simplex4_table)))
		return false;
	// create texture

	if(!m_p_simplex->b_Status()) {
		delete m_p_simplex;
		m_p_simplex = 0;
		return false;
	}
	// check texture status

	CGLTextureParams &r_params = m_p_simplex->r_Parameters(p_state);
	r_params.Set_Texture_Min_Filter(GL_NEAREST);
	r_params.Set_Texture_Mag_Filter(GL_NEAREST);
	// nearest filtering

	p_state->DisableTexture1D();
	p_state->BindTexture1D(0);
	// do not keep it bound

	return true;
}

/*
 *	bool CGLNoise::b_GradTex_Required(int n_noise_type) const
 *		- returns true if gradient texture is required for noise function n_noise_type
 *		  (one of noise_2D, noise_2D_Simplex, noise_3D, noise_3D_Simplex, noise_4D or
 *		  noise_4D_Simplex) otherwise returns false
 *		- gradient texture is required for 4D noise (both simplex and regular)
 *		- note permutation texture is always required
 */
bool CGLNoise::b_GradTex_Required(int n_noise_type) const
{
	return n_noise_type == noise_4D || n_noise_type == noise_4D_Simplex;
}

/*
 *	bool CGLNoise::b_SimplexTex_Required(int n_noise_type) const
 *		- returns true if simplex texture is required for noise function n_noise_type
 *		  (one of noise_2D, noise_2D_Simplex, noise_3D, noise_3D_Simplex, noise_4D or
 *		  noise_4D_Simplex) otherwise returns false
 *		- simplex texture is required for any kind of simplex noise but 2D
 *		- note permutation texture is always required
 */
bool CGLNoise::b_SimplexTex_Required(int n_noise_type) const
{
	return /*n_noise_type == noise_2D_Simplex ||*/ // not for 2D
		n_noise_type == noise_3D_Simplex || n_noise_type == noise_4D_Simplex;
}

/*
 *	const char *CGLNoise::p_s_GradTex_SamplerName() const
 *		- returns name of sampler for gradient texture
 */
const char *CGLNoise::p_s_GradTex_SamplerName() const
{
	return "n_grad_tex";
}

/*
 *	const char *CGLNoise::p_s_PermTex_SamplerName() const
 *		- returns name of sampler for permutation texture
 */
const char *CGLNoise::p_s_PermTex_SamplerName() const
{
	return "n_perm_tex";
}

/*
 *	const char *CGLNoise::p_s_SimplexTex_SamplerName() const
 *		- returns name of sampler for simplex texture
 */
const char *CGLNoise::p_s_SimplexTex_SamplerName() const
{
	return "n_simplex_tex";
}

/*
 *	const char *CGLNoise::p_s_NoiseShader(int n_noise_type) const
 *		- returns source code for noise function n_noise_type (one of noise_2D,
 *		  noise_2D_Simplex, noise_3D, noise_3D_Simplex, noise_4D or noise_4D_Simplex)
 *		- regular noise is implemented by the functions:
 *			float noise(vec2 v_point)
 *			float noise(vec3 v_point)
 *			float noise(vec4 v_point)
 * 
 *		  simplex noise is implemented by the functions:
 *			float snoise(vec2 v_point)
 *			float snoise(vec3 v_point)
 *			float snoise(vec4 v_point)
 * 
 *		  author: Stefan Gustavson ITN-LiTH (stegu@itn.liu.se) 2004-12-05
 *		- note the original source code was reformatted and comments were stripped off
 *		- note it is possible to include more noise functions in a single shader,
 *		  shared variables / functions are properly \#ifdef-ed
 */
const char *CGLNoise::p_s_NoiseShader(int n_noise_type) const
{
	return m_p_s_noise_func_source_list[n_noise_type];
}

/*
 *								=== ~CGLNoise ===
 */
