#version 330 core
precision highp float;

in vec3 position;
in vec2 uv;
in vec3 normal;
in vec2 uvheightmap;

out vec2 ex_Uv;
out vec3 ex_Normal;
out vec3 ex_FragPos;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

struct Heightmap {
	sampler2D texture;
	float maxHeight;
};

uniform Heightmap heightmap;
uniform float     iTime;                 // shader playback time (in seconds)
uniform float     iTimeDelta;            // render time (in seconds)
uniform float      waveSpeedY;
uniform vec2      waveOffsetXZ;


vec3 calculateSurfaceNormal(vec3 p1, vec3 p2, vec3 p3)
{
	vec3 normal;
	vec3 u = p2 - p1;
	vec3 v = p3 - p1;

	normal.x = (u.y * v.z) - (u.z * v.y);
	normal.y = (u.z * v.x) - (u.x * v.z);
	normal.z = (u.x * v.y) - (u.y * v.x);

	return normalize(normal);
}


const vec2 size = vec2(2.0, 0.0);
const ivec3 off = ivec3(-1, 0, 1);


void main()
{
	float sinTime = sin(iTime * waveSpeedY);
	vec2 uvheightmapWave = uvheightmap + waveOffsetXZ;
	float s11 = texture(heightmap.texture, uvheightmapWave).r * sinTime * heightmap.maxHeight;
	float s01 = textureOffset(heightmap.texture, uvheightmapWave, off.xy).r * sinTime * heightmap.maxHeight;
	float s21 = textureOffset(heightmap.texture, uvheightmapWave, off.zy).r * sinTime * heightmap.maxHeight;
	float s10 = textureOffset(heightmap.texture, uvheightmapWave, off.yx).r * sinTime * heightmap.maxHeight;
	float s12 = textureOffset(heightmap.texture, uvheightmapWave, off.yz).r * sinTime * heightmap.maxHeight;

	vec3 va = normalize(vec3(size.x, s21-s01, size.y));
	vec3 vb = normalize(vec3(size.y, s12-s10, -size.x));

	vec4 newPos = vec4(position, 1.0);
	newPos.y = newPos.y + s11;

	gl_Position = projection * view * model * newPos;
	ex_FragPos = vec3(model * vec4(position, 1.0f));
	ex_Uv = uv;
	ex_Normal = mat3(transpose(inverse(model))) * cross(va, vb);
}
