#version 120
uniform mat4 gxl3d_ModelViewProjectionMatrix;
uniform mat4 gxl3d_ModelViewMatrix;

uniform vec4 wave1; // dir_x, dir_y, steepness, wavelength
uniform vec4 wave2; // dir_x, dir_y, steepness, wavelength
uniform vec4 wave3; // dir_x, dir_y, steepness, wavelength

uniform float time;

varying vec4 v_normal;

#define GXL_PI 3.14159265

// Based on: https://catlikecoding.com/unity/tutorials/flow/waves/

vec3 GerstnerWave (vec4 wave, vec3 p, inout vec3 tangent, inout vec3 binormal)
{
  float steepness = wave.z;
  float wavelength = wave.w;
  float k = 2.0 * GXL_PI / wavelength;
  float c = sqrt(9.8 / k);
  vec2 d = normalize(wave.xy);
  float f = k * (dot(d, p.xz) - c * time);
  float a = steepness / k;

  tangent += vec3(
    -d.x * d.x * (steepness * sin(f)),
    d.x * (steepness * cos(f)),
    -d.x * d.y * (steepness * sin(f))
  );

  binormal += vec3(
    -d.x * d.y * (steepness * sin(f)),
    d.y * (steepness * cos(f)),
    -d.y * d.y * (steepness * sin(f))
  );

  return vec3(
    d.x * (a * cos(f)),
    a * sin(f),
    d.y * (a * cos(f))
  );
}


void main()
{
  vec3 gridPoint = gl_Vertex.xyz;
  vec3 tangent = vec3(1, 0, 0);
	vec3 binormal = vec3(0, 0, 1);
	vec3 p = gridPoint;
	p += GerstnerWave(wave1, gridPoint, tangent, binormal);
	p += GerstnerWave(wave2, gridPoint, tangent, binormal);
	p += GerstnerWave(wave3, gridPoint, tangent, binormal);

	vec3 normal = normalize(cross(binormal, tangent));

  gl_Position = gxl3d_ModelViewProjectionMatrix * vec4(p, 1.0);

  v_normal = gxl3d_ModelViewMatrix * vec4(normal, 0.0);
}
