layout( std140 ) uniform view {
	mat4 V;
	mat4 P;
	vec3 camera_pos;
};

layout( std140 ) uniform sun {
	vec3 sun_dir;
	float sun_angle;
};

layout( std140 ) uniform clipmap {
	vec2 offset;
	float scale;
};

struct VSOut {
	vec4 view_position;
	vec3 world_position;
	vec2 uv;
};

uniform sampler2D heightmap;
uniform sampler2D normalmap;
uniform sampler2D horizonmap;
uniform sampler2D blue_noise;

#ifdef VERTEX_SHADER

in vec3 position;
out VSOut v2f;

void main() {
	vec2 xy = offset + position.xy * scale + camera_pos.xy;
	vec2 snapped_xy = floor( xy / scale ) * scale;
	vec2 uv = ( snapped_xy + 0.5 ) / textureSize( heightmap, 0 );
	vec2 height_sample = texelFetch( heightmap, ivec2( snapped_xy ), 0 ).rg;
	float z = 256.0 * height_sample.r + height_sample.g;

	v2f.view_position = V * vec4( snapped_xy, z, 1.0 );
	v2f.world_position = vec3( xy, z );
	v2f.uv = uv;
	gl_Position = P * v2f.view_position;
}

#else

in VSOut v2f;
out vec4 screen_colour;

void main() {
	vec2 normal_xy = texture( normalmap, v2f.uv ).xy * 2.0 - 1.0;
	float normal_z = sqrt( 1.0 - normal_xy.x * normal_xy.x - normal_xy.y * normal_xy.y );
	vec3 normal = vec3( normal_xy.x, normal_xy.y, normal_z );

	float horizon = texture( horizonmap, v2f.uv ).r;

	// ground colour
	vec3 ground;
	if( v2f.world_position.z > 175 ) {
		// snow/rocks
		if( normal.z > 0.5 ) {
			ground = vec3( 0.8, 0.8, 0.8 );
		}
		else {
			ground = vec3( 0.6, 0.6, 0.6 );
		}
	}
	else if( v2f.world_position.z < 5 ) {
		ground = vec3( 0.0, 0.25, 1.0 );
	}
	else {
		if( normal.z > 0.8 ) {
			ground = vec3( 0.4, 1.0, 0.4 );
		}
		else {
			ground = vec3( 0.7, 0.7, 0.5 );
		}
	}

	// sunlight + sky ambient lighting
	// area of a chord is somewhat similar to smoothstep
	float sun_visible_fraction = smoothstep( -0.2, 0.2, sun_angle - horizon );
	float sunlight_lambert = max( 0, dot( normal, sun_dir ) );
	vec3 sunlight = sun_visible_fraction * sunlight_lambert * vec3( 0.9, 0.9, 0.5 );
	vec3 ambient = vec3( 0.05, 0.05, 0.15 );

	vec3 c = ( sunlight + ambient ) * ground;

	screen_colour = vec4( linear_to_srgb( apply_fog( c + get_dither_noise(), length( v2f.view_position ) ) ), 1.0 );
}

#endif
