#include "pch.h"
#include "Noise.h"

uint32_t Rng::hash_u_seeded(uint32_t _a) {
	uint32_t a = _a;
	a ^= a >> 16;
	a *= 0x7feb352du;
	a ^= a >> 15;
	a *= 0x846ca68bu;
	a ^= a >> 16;
	return a;
}

glm::uvec2 Rng::hash_u2_seeded(uint32_t seed) {return glm::uvec2(hash_u_seeded(seed), hash_u_seeded(seed + 45123123u));}
glm::uvec3 Rng::hash_u3_seeded(uint32_t seed) { return glm::uvec3(hash_u_seeded(seed), hash_u_seeded(seed + 425u), hash_u_seeded(seed +125125u)); }
glm::uvec4 Rng::hash_u4_seeded(uint32_t seed) { return glm::uvec4(hash_u_seeded(seed + 1251234123u), hash_u_seeded(seed + 125123123u), hash_u_seeded(seed + 5123123u), hash_u_seeded(seed +25125125u)); }

Rng::Rng(uint32_t _seed) {
	seed = _seed;
}
uint32_t Rng::hash_u() {
	uint32_t s = hash_u_seeded(this->seed);
	return this->seed = s;
}

glm::uvec2 Rng::hash_u2() {return glm::uvec2(hash_u(), hash_u()); }
glm::uvec3 Rng::hash_u3() {return glm::uvec3(hash_u(), hash_u(), hash_u()); }
glm::uvec4 Rng::hash_u4() { return glm::uvec4(hash_u(), hash_u(), hash_u(), hash_u()); }

float Rng::hash_f() {
	uint32_t s = hash_u_seeded(this->seed);
	return ( float( this->seed = s ) / float( 0xffffffffu ) );
}
glm::vec2 Rng::hash_v2() { return glm::vec2(hash_f(), hash_f()); }
glm::vec3 Rng::hash_v3() { return glm::vec3(hash_f(), hash_f(), hash_f()); }
glm::vec4 Rng::hash_v4() { return glm::vec4(hash_f(), hash_f(), hash_f(), hash_f()); }
float Rng::hash_f_seeded(uint32_t seed) {
	return ( float( hash_u_seeded(seed) ) / float( 0xffffffffu ) );
}
glm::vec2 Rng::hash_v2_seeded(uint32_t seed) { return glm::vec2(hash_f_seeded(seed), hash_f_seeded(seed + 45123123u)); }
glm::vec3 Rng::hash_v3_seeded(uint32_t seed) { return glm::vec3(hash_f_seeded(seed), hash_f_seeded(seed + 425u), hash_f_seeded(seed +125125u)); }
glm::vec4 Rng::hash_v4_seeded(uint32_t seed) { return glm::vec4(hash_f_seeded(seed + 1251234123u), hash_f_seeded(seed + 125123123u), hash_f_seeded(seed + 5123123u), hash_f_seeded(seed +25125125u)); }
float Rng::hash11(float p) {
	p = fract(p * .1031f);
	p *= p + 33.33f;
	p *= p + p;
	return fract(p);
}
float Rng::hash12(vec2 p) {
	vec3 p3  = fract(vec3(p.xyx) * .1031f);
	p3 += dot(p3, p3.yzx + vec3(33.33f));
	return fract((p3.x + p3.y) * p3.z);
}
float Rng::hash13(vec3 p3) {
	p3  = fract(p3 * .1031f);
	p3 += dot(p3, p3.zyx + vec3(31.32f));
	return fract((p3.x + p3.y) * p3.z);
}
float Rng::hash14(vec4 p4) {
	p4 = fract(p4  * vec4(.1031, .1030, .0973, .1099));
	p4 += dot(p4, p4.wzxy+vec4(33.33f));
	return fract((p4.x + p4.y) * (p4.z + p4.w));
}
vec2 Rng::hash21(float p) {
	vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yzx + vec3(33.33f));
	return fract((p3.xx+p3.yz)*p3.zy);

}
vec2 Rng::hash22(vec2 p) {
	vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yzx+vec3(33.33f));
	return fract((p3.xx+p3.yz)*p3.zy);

}
vec2 Rng::hash23(vec3 p3) {
	p3 = fract(p3 * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yzx+vec3(33.33f));
	return fract((p3.xx+p3.yz)*p3.zy);
}
vec3 Rng::hash31(float p) {
	vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yzx+vec3(33.33f));
	return fract((p3.xxy+p3.yzz)*p3.zyx); 
}
vec3 Rng::hash32(vec2 p) {
	vec3 p3 = fract(vec3(p.xyx) * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yxz+vec3(33.33f));
	return fract((p3.xxy+p3.yzz)*p3.zyx);
}
vec3 Rng::hash33(vec3 p3) {
	p3 = fract(p3 * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yxz+vec3(33.33f));
	return fract((p3.xxy + p3.yxx)*p3.zyx);

}
vec4 Rng::hash41(float p) {
	vec4 p4 = fract(vec4(p) * vec4(.1031, .1030, .0973, .1099));
	p4 += dot(p4, p4.wzxy+vec4(33.33f));
	return fract((p4.xxyz+p4.yzzw)*p4.zywx);
			
}
vec4 Rng::hash42(vec2 p) {
	vec4 p4 = fract(vec4(p.xyxy) * vec4(.1031, .1030, .0973, .1099));
	p4 += dot(p4, p4.wzxy+vec4(33.33f));
	return fract((p4.xxyz+p4.yzzw)*p4.zywx);

}
vec4 Rng::hash43(vec3 p) {
	vec4 p4 = fract(vec4(p.xyzx)  * vec4(.1031, .1030, .0973, .1099));
	p4 += dot(p4, p4.wzxy+vec4(33.33f));
	return fract((p4.xxyz+p4.yzzw)*p4.zywx);
}
vec4 Rng::hash44(vec4 p4) {
	p4 = fract(p4  * vec4(.1031, .1030, .0973, .1099));
	p4 += dot(p4, p4.wzxy+vec4(33.33f));
	return fract((p4.xxyz+p4.yzzw)*p4.zywx);
}

float Noise::get_noise_2d(glm::vec2 p, NoiseDesc desc) {
	FastNoiseLite noise;
	FastNoiseLite::NoiseType noise_type;
	if(desc.type == Type::Value){
		noise_type = FastNoiseLite::NoiseType_Value;
	} else if(desc.type == Type::Perlin){
		noise_type = FastNoiseLite::NoiseType_Perlin;
	} else if(desc.type == Type::Simplex){
		noise_type = FastNoiseLite::NoiseType_OpenSimplex2;
	} else if(desc.type == Type::Voronoi){
		noise_type = FastNoiseLite::NoiseType_Cellular;
	}
		
	noise.SetNoiseType(noise_type);
	noise.SetFractalOctaves(desc.octaves);
	noise.SetFractalLacunarity(desc.lacunarity);
	noise.SetSeed(desc.seed);
	return noise.GetNoise(p.x, p.y);
}

float Noise::get_noise_3d(glm::vec3 p, NoiseDesc desc) {
	FastNoiseLite noise;
	FastNoiseLite::NoiseType noise_type;
	if(desc.type == Type::Value){
		noise_type = FastNoiseLite::NoiseType_Value;
	} else if(desc.type == Type::Perlin){
		noise_type = FastNoiseLite::NoiseType_Perlin;
	} else if(desc.type == Type::Simplex){
		noise_type = FastNoiseLite::NoiseType_OpenSimplex2;
	} else if(desc.type == Type::Voronoi){
		noise_type = FastNoiseLite::NoiseType_Cellular;
	}
		
	noise.SetNoiseType(noise_type);
	noise.SetFractalOctaves(desc.octaves);
	noise.SetFractalLacunarity(desc.lacunarity);
	noise.SetSeed(desc.seed);
	return noise.GetNoise(p.x, p.y, p.z);
}
