#[compute]
#version 450

float clamp01( float value )
{
  return clamp( value, 0.0, 1.0 );
} 

vec4 clamp01_v4( vec4 value )
{
  value.r = clamp01( value.r );
  value.g = clamp01( value.g );
  value.b = clamp01( value.b );
  value.a = clamp01( value.a );

  return value;
}

vec2 clamp01( vec2 value )
{
  return clamp( value, 0.0, 1.0 );
}

vec3 clamp01( vec3 value )
{
  return clamp( value, 0.0, 1.0 );
}

vec4 clamp01( vec4 value )
{
  return clamp( value, 0.0, 1.0 );
}

float normalizeToRange( float value, float min, float max )
{
  return ( value - min ) / ( max - min );
}

float normalizeToRange01( float value, float min, float max )
{
  return clamp01( normalizeToRange( value, min, max ) );
}

float map( float value, float inMin, float inMax, float outMin, float outMax )
{
  return mix( outMin, outMax, normalizeToRange( value, inMin, inMax ) );
}

vec2 map_v2( vec2 value, vec2 inMin, vec2 inMax, vec2 outMin, vec2 outMax )
{
  float x = map( value.x, inMin.x, inMax.x, outMin.x, outMax.x );
  float y = map( value.y, inMin.y, inMax.y, outMin.y, outMax.y ); 

  return vec2( x, y );
}

float mapClamped( float value, float inMin, float inMax, float outMin, float outMax )
{
  return mix( outMin, outMax, normalizeToRange01( value, inMin, inMax ) );
}

vec3 colorize( vec3 original, vec3 color ) 
{
  float grey = ( original.r + original.g + original.b ) / 3.0;
  
  return grey < 0.5 ? mix( vec3( 0.0 ), color, grey * 2.0 ) : 
                      mix( color, vec3( 1.0 ), ( grey - 0.5 ) * 2.0 );
}

layout( local_size_x = 16, local_size_y = 16, local_size_z = 1 ) in;

layout( rgba16f, set = 0, binding = 0) 
uniform image2D inputImage;

layout( rgba16f, set = 1, binding = 0) 
uniform image2D outputImage;

layout( push_constant, std430 )
uniform Parameters 
{	  
  vec4 topColor; // 4
  vec4 bottomColor; // 8
  vec2 rasterSize;  // 6
	float amount; // 7
  float fadeIn; // 8
  float fadeOut; // 9

  float circelize; // 10
  float power;  // 12

  float replace; // 13
  float add; // 14
  float multiply; // 15
  float colorize; // 16
  

} parameters;


void main() 
{
	ivec2 coordinate   = ivec2( gl_GlobalInvocationID.xy );
	ivec2 size         = ivec2( parameters.rasterSize );

	if ( coordinate.x >= size.x || coordinate.y >= size.y ) 
  {
		return;
	}

	vec4 color = imageLoad( inputImage, coordinate );
  // color = vec4( 0.0, 0.0, 0.0, 1.0 );
  vec2 uv = ( vec2( coordinate ) + vec2( 0.5 ) ) / vec2( parameters.rasterSize ) ;

  float ratio = parameters.rasterSize.y / parameters.rasterSize.x;

  uv.y = mix( uv.y, ( uv.y - 0.5 ) * ratio + 0.5, parameters.circelize );
  
  float centerDistance = length( uv - vec2( 0.5 ) );
  float distanceAmount = mapClamped( centerDistance, parameters.fadeIn, parameters.fadeOut, 0.0, 1.0 );
  distanceAmount = pow( distanceAmount, parameters.power );

  vec4 vignetteColor = mix( parameters.topColor, parameters.bottomColor, uv.y );

  vec4 multiplied = vignetteColor * color;
  vec4 added = vignetteColor + color;
  vec4 colorized = vec4( colorize( color.rgb, vignetteColor.rgb ), 1.0 );


  vec4 mixed = vignetteColor * parameters.replace + 
                added * parameters.add + 
                multiplied * parameters.multiply + 
                colorized * parameters.colorize;

	color.rgb = mix( color.rgb, mixed.rgb, vignetteColor.a * distanceAmount * parameters.amount );
  // color.rgb = vignetteColor.rgb; 

	imageStore( outputImage, coordinate, color );
}