#[compute]
#version 450

layout( local_size_x = 8, local_size_y = 8, 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 
{
  float amount;
  float steps;
  float gamma;
  float off;

} parameters;


vec3 RGBtoHSL( vec3 c )
{
  float h = 0.0;
  float s = 0.0; 
  float l = 0.0; 
  
  float cmin = min( min( c.r, c.g ), c.b );
  float cmax = max( max( c.r, c.g ), c.b );
  
  l = ( cmin + cmax ) / 2.0;
  
  if ( cmin == cmax ) 
  {
    s = 0.0;
    h = 0.0;
  } 
  else 
  {
    float delta = cmax - cmin;
    
    s = ( l <= 0.5 ) ? ( delta / ( cmax + cmin ) ) : ( delta / ( 2.0 - ( cmax + cmin ) ) );
    
    h = 0.0;
    
    if ( c.r == cmax ) 
    {
      h = ( c.g - c.b ) / delta;
    } 
    else if ( c.g == cmax ) 
    {
      h = 2.0 + ( c.b - c.r ) / delta;
    }
    else if ( c.b == cmax ) 
    {
      h = 4.0 + ( c.r - c.g ) / delta;
    }
    
    h = h / 6.0;

    if ( h > 1.0 )
    {
      h -= 1.0;
    }

  }

  return vec3( h, s, l );
}

vec3 hueToRGB( float hue )
{
  float R = abs( hue * 6.0 - 3.0 ) - 1.0;
  float G = 2.0 - abs( hue * 6.0 - 2.0 );
  float B = 2.0 - abs( hue * 6.0 - 4.0 );
  return clamp( vec3( R,G,B ), 0, 1 );
}

vec3 HSLtoRGB( vec3 hsl )
{
  if ( hsl.y == 0.0 )
  {
    return vec3( hsl.z, hsl.z, hsl.z );
  }

  vec3 rgb = hueToRGB( hsl.x );
  float C = ( 1.0 - abs( 2.0 * hsl.z - 1.0 )) * hsl.y;
  return ( rgb - 0.5 ) * C + hsl.z;
}

float applyGamma( float x, float power )
{
  if ( x <= 0.0 )
  {
    return 0.0;
  }

  return pow( x, power );
}

vec4 gammaColor( vec4 v, float power )
{
  v.x = applyGamma( v.x, power );
  v.y = applyGamma( v.y, power );
  v.z = applyGamma( v.z, power );

  return v;
}

void main( ) 
{
    ivec2 size = imageSize( inputImage );
    ivec2 texel_coord = ivec2( gl_GlobalInvocationID.xy );
    
    if ( any( greaterThanEqual( texel_coord, size ) )  ) 
    {
      return;
    }

    vec2 uv = ( vec2( texel_coord ) + 0.5 ) / vec2( size );    

    vec4 color = imageLoad( inputImage, ivec2( uv * size ) ); 

    float off = parameters.off;
    vec4 offset = vec4( off, off, off, 0);

    vec4 gColor = color;
    gColor = gammaColor( color + offset, parameters.gamma );
    vec4 posterColor = round( gColor * parameters.steps ) / parameters.steps;
    posterColor = gammaColor( posterColor, parameters.gamma ) - offset;


    vec4 blended = mix( color, posterColor, parameters.amount );


    imageStore( outputImage, texel_coord, blended );
}