#version 440 core

layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec2 vertex_texcoord;
layout (location = 3) in vec3 vertex_normal;

out vec3 vs_position;
out vec3 vs_color;
out vec2 vs_texcoord;
out vec3 vs_normal;

out vec3 world_position;

uniform mat4 ModelMatrix;
uniform mat4 ViewMatrix;

uniform mat4 ProjectionMatrix;

uniform float time;
uniform float waveAmplitude;
uniform float waveFrequency;
uniform float waveSpeed;

void main()
{
    // Calculate displacement using a sine wave function
    float displacement = waveAmplitude * sin(waveFrequency * vertex_position.x + waveSpeed * time) +
                         waveAmplitude * cos(waveFrequency * vertex_position.y + waveSpeed * time);
    
    // Apply the displacement to the vertex position
    vec3 displaced_position = vertex_position + vec3(0.0, 0.0, displacement);

    // Calculate partial derivatives
    float dx = waveFrequency * waveAmplitude * cos(waveFrequency * vertex_position.x + waveSpeed * time);
    float dy = -waveFrequency * waveAmplitude * sin(waveFrequency * vertex_position.y + waveSpeed * time);

    // Original normal
    vec3 original_normal = vertex_normal;

    // Adjust normal based on partial derivatives
    vec3 adjusted_normal = normalize(original_normal + vec3(-dx, -dy, 1.0));
    
    // Transform vertex position to eye space
    vec4 eye_space_position = ViewMatrix * ModelMatrix * vec4(displaced_position, 1.0);
    
    // Outputs
    vs_position = eye_space_position.xyz;
    vs_color = vertex_color;
    vs_texcoord = vertex_texcoord;
    vs_normal = mat3(ModelMatrix) * adjusted_normal;

    // Transform to clip space
    gl_Position = ProjectionMatrix * eye_space_position;

    // Output world position
    world_position = (ModelMatrix * vec4(displaced_position, 1.0)).xyz;
}