layout( std140 ) uniform model {
	mat4 M;
};

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

layout( std140 ) uniform light_view {
	mat4 lightV;
	mat4 lightP;
};

layout( std140 ) uniform v_cold {
	vec3 light_pos;
	float bias;
};

uniform sampler2D shadowmap;

struct VSOut {
	vec4 light_space_position;
	vec3 position;
	vec3 normal;
	vec3 colour;
};

#if VERTEX_SHADER

in vec3 position;
in vec3 normal;
in vec3 colour;

out VSOut v2f;

void main() {
	vec4 world_space = M * vec4( position, 1.0 );
	gl_Position = P * V * world_space;
	v2f.light_space_position = lightP * lightV * world_space;
	v2f.position = world_space.xyz;
	v2f.normal = mat3( M ) * normal;
	v2f.colour = colour;
}

#else

in VSOut v2f;
out vec4 screen_colour;

void main() {
	vec3 light_colour = vec3( 1.0, 1.0, 1.0 );
	vec3 lightdir = normalize( v2f.position - light_pos );

	float ambient = 0.1;
	float lambert = max( 0, dot( -lightdir, normalize( v2f.normal ) ) );

	vec3 light_ndc = v2f.light_space_position.xyz / v2f.light_space_position.w;
	vec3 light_norm = light_ndc * 0.5 + 0.5;
	float bias2 = max( bias * ( 1.0 + dot( lightdir, v2f.normal ) ), bias / 100 );
	float shadow = 0;

	if( light_norm.z > 1.0 ) {
		shadow = 1.0;
	}
	else {
		vec2 inv_shadowmap_size = 1.0 / textureSize( shadowmap, 0 );
		for( int x = -1; x <= 1; x++ ) {
			for( int y = -1; y <= 1; y++ ) {
				vec2 offset = vec2( x, y ) * inv_shadowmap_size;
				float shadow_depth = texture( shadowmap, light_norm.xy + offset ).r;
				if( light_norm.z - bias2 <= shadow_depth ) {
					shadow += 1.0 / 9.0;
				}
			}
		}
	}

	screen_colour = vec4( v2f.colour * light_colour * ( ambient + ( 1 - ambient ) * ( lambert * shadow ) ), 1.0 );
}

#endif
