#[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 intensity;
  float noise;
  float kernelOffset;
  float kernelRadius;  

} parameters;

vec3 SRGBtoLINEAR( vec3 sRGB )
{
  return mix( pow( (sRGB + vec3( 0.055 )) * ( 1.0 / ( 1.0 + 0.055 )),vec3( 2.4 )),sRGB * ( 1.0 / 12.92 ),lessThan( sRGB,vec3( 0.04045 )) );
}

vec4 SRGBtoLINEAR( vec4 sRGB )
{
  return vec4( SRGBtoLINEAR( sRGB.rgb ), sRGB.a );
}

vec3 LINEARtoSRGB( vec3 linear )
{
  vec3 color = linear;
  const vec3 a = vec3(0.055f);
	return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}

vec4 LINEARtoSRGB( vec4 linear )
{
  return vec4( LINEARtoSRGB( linear.rgb ), linear.a );
}

float randomFloat( vec2 uv ) 
{
  return fract( sin( dot( uv.xy, vec2( 12.9898,78.233 ) ) ) * 43758.5453123 );
}

vec2 random( vec2 uv ) 
{
	float x = randomFloat( uv );
  float y = randomFloat( uv + vec2( 10002, -23589 ) );
 
  return vec2( x, y ) * 2.0 - vec2( 1.0, 1.0 );
}



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

  vec4 color = vec4( 0.0 );

  int kernelRadius = int( parameters.kernelRadius );
  int kernelOffset = int( parameters.kernelOffset );

  if ( parameters.noise > 0.0 )
  {
    for ( int x = -kernelRadius; x <= kernelRadius; x++ ) 
    {
      for ( int y = -kernelRadius; y <= kernelRadius; y++ ) 
      {      
        ivec2 xy = ivec2( x, y ) * kernelOffset;
        ivec2 kernelUV = pixelUV + xy;

        kernelUV += ivec2( random( kernelUV ) * parameters.noise );

        kernelUV.x = clamp( kernelUV.x, 0, size.x - 1 );
        kernelUV.y = clamp( kernelUV.y, 0, size.y - 1 );

        color += ( imageLoad( inputImage, kernelUV ) );
      }
    }
  }
  else
  {
     for ( int x = -kernelRadius; x <= kernelRadius; x++ ) 
    {
      for ( int y = -kernelRadius; y <= kernelRadius; y++ ) 
      {      
        ivec2 xy = ivec2( x, y ) * kernelOffset;
        ivec2 kernelUV = pixelUV + xy;

        kernelUV.x = clamp( kernelUV.x, 0, size.x - 1 );
        kernelUV.y = clamp( kernelUV.y, 0, size.y - 1 );

        color += ( imageLoad( inputImage, kernelUV ) );
      }
    }
  }

  
  
  int numPixels = ( kernelRadius * 2 + 1 ) *  ( kernelRadius * 2 + 1 );

  color /= numPixels;

  color = ( color );

  vec4 originalColor = imageLoad( inputImage, pixelUV );
  vec4 mixedColor = mix( originalColor, color, parameters.intensity );

  imageStore( outputImage, pixelUV, mixedColor );
}