// #include "res://addons/rokojori_action_library/Runtime/Shading/Library/Colors.gdshaderinc"

#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Math.gdshaderinc"


const float HCV_EPSILON = 1e-10;
const float HSL_EPSILON = 1e-10;

vec3 RGBtoHCV( vec3 rgb )
{
  vec4 P = ( rgb.g < rgb.b ) ? vec4( rgb.bg, -1.0, 2.0/3.0 ) : vec4( rgb.gb, 0.0, -1.0/3.0 );
  vec4 Q = ( rgb.r < P.x ) ? vec4( P.xyw, rgb.r ) : vec4( rgb.r, P.yzx );
  float C = Q.x - min( Q.w, Q.y );
  float H = abs( (Q.w - Q.y ) / ( 6.0 * C + HCV_EPSILON ) + Q.z );
  return vec3( H, C, Q.x );
}


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;
}

vec3 adjustHSL( vec3 color, vec3 hslAdjustment )
{
  vec3 hsl = RGBtoHSL( color );
  hsl += hslAdjustment;
  hsl.x = mod( hsl.x, 1.0 );
  hsl = clamp( hsl, 0, 1 );

  return HSLtoRGB( hsl );
}



vec3 toLinear( 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 )) );
}

float modPolarDegrees( float value )
{
  return mod( value + 180.0, 360.0 ) - 180.0;
}

float hue360ToYB( float hue )
{
  return modPolarDegrees( hue - 240.0 );
}

float ybToHue360( float yb )
{
  return mod( yb + 240.0, 360.0 );
}

float changeHue360( float hue, float change )
{
  float yb = hue360ToYB( hue );

  float absYB = abs( yb );

  absYB = clamp( absYB + change, 0.0, 180.0 );

  float realYB = sign( yb ) * absYB;

  return ybToHue360( realYB );
}

vec3 shiftHSL360( vec3 hslWithH360, vec3 offset, float blendRadius )
{
  float distanceToYellow = min( 1.0, abs( hslWithH360.x - 60.0 ) / blendRadius );
  float distanceToBlue   = min( 1.0, abs( hslWithH360.x - 240.0 ) / blendRadius );

  hslWithH360.x = changeHue360( hslWithH360.x, offset.x );
  hslWithH360.y = clamp( hslWithH360.y + offset.y, 0, 1 );
  hslWithH360.z = clamp( hslWithH360.z + offset.z, 0, 1 );

  return hslWithH360;
}


vec3 shiftHSL( vec3 hsl, vec3 offset, float blendRadius )
{
  hsl.x *= 360.0;
  offset.x *= 360.0;
  hsl = shiftHSL360( hsl, offset, blendRadius );
  hsl.x /= 360.0;

  return hsl;
}

vec3 shiftRGBwithHSL( vec3 rgb, vec3 offset, float blendRadius )
{
  vec3 hsl = RGBtoHSL( rgb );
  hsl = shiftHSL( hsl, offset, blendRadius );
  return HSLtoRGB( hsl );
}

vec3 RGBtoHSV( vec3 c )
{
  vec4 K = vec4( 0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0 );
  vec4 p = mix( vec4( c.bg, K.wz ), vec4( c.gb, K.xy ), step( c.b, c.g ));
  vec4 q = mix( vec4( p.xyw, c.r ), vec4( c.r, p.yzx ), step( p.x, c.r ));

  float d = q.x - min( q.w, q.y );
  float e = 1.0e-10;

  return vec3( abs( q.z + ( q.w - q.y ) / ( 6.0 * d + e )), d / ( q.x + e ), q.x );
}

vec3 HSVtoRGB( vec3 c )
{
  vec4 K = vec4( 1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0 );
  vec3 p = abs( fract( c.xxx + K.xyz ) * 6.0 - K.www );

  return c.z * mix( K.xxx, clamp( p - K.xxx, 0.0, 1.0 ), c.y );
}

vec3 mix3( vec3 a, vec3 b, vec3 c, float t )
{
  float weightA = mapClamped( t, 0, 0.5, 1, 0 );
  float weightB = triangle( t );
  float weightC = mapClamped( t, 0.5, 1, 0, 1 );

  return a * weightA + b * weightB + c * weightC;
}

vec4 mix3_v4( vec4 a, vec4 b, vec4 c, float t )
{
  float weightA = mapClamped( t, 0, 0.5, 1, 0 );
  float weightB = triangle( t );
  float weightC = mapClamped( t, 0.5, 1, 0, 1 );

  return a * weightA + b * weightB + c * weightC;
}

vec4 scaleRGB( vec4 rgba, float scale )
{
  return vec4( rgba.rgb * scale, rgba.a );
}

vec4 fade( vec4 rgba, float fade )
{
  return vec4( rgba.rgb, rgba.a * fade );
}


vec4 straightToPremultipliedColor( vec4 color )
{
  return vec4( color.rgb * color.a, color.a );
}

vec4 premultipliedToStraightColor( vec4 color )
{
  return color.a == 0.0 ? color : vec4( color.rgb / color.a, color.a );
}



 

vec4 mixThreeColors( vec4 a, vec4 b, vec4 c, float t )
{
  float wa = mapClamped( t, 0.0, 0.5, 1.0, 0.0 );   
  float wb = triangle( t ); 
  float wc = mapClamped( t, 0.5, 1, 0.0, 1.0 ); 

  return a * wa + b * wb + c * wc;
}

vec3 gamma( vec3 color, float gamma )
{
  color.r = pow( color.r, gamma );  
  color.g = pow( color.g, gamma );  
  color.b = pow( color.b, gamma );  
  
  return color;
}

vec4 gamma( vec4 color, float gamma )
{
  color.r = pow( color.r, gamma );  
  color.g = pow( color.g, gamma );  
  color.b = pow( color.b, gamma );  
  color.a = color.a;
  
  return color;
}

vec3 gammaSRGB( vec3 color )
{
  return gamma( color, 2.2 );
}

vec4 gammaSRGB( vec4 color )
{
  return gamma( color, 2.2 );
}

vec3 gammaSRGBInverse( vec3 color )
{
  return gamma( color, 1.0/2.2 );
}

vec4 gammaSRGBInverse( vec4 color )
{
  return gamma( color, 1.0/2.2 );
}

vec3 desaturate( vec3 color )
{
  vec3 weight = vec3( 1.0, 1.0, 1.0 ) / 3.0;

  float luminance = color.r * weight.r + color.g * weight.g + color.b * weight.b;

  return vec3( luminance );
}

vec3 desaturate( vec3 color, float amount )
{
  return mix( color, desaturate( color ), amount );
}

vec4 desaturate( vec4 color )
{
  return vec4( desaturate( color.rgb ), color.a );
}

vec4 desaturate( vec4 color, float amount )
{
  return mix( color, desaturate( color ), amount );
}

/* BLEND MODES */

vec4 blendMode_alpha( vec4 bottom, vec4 top )
{
  float fade = ( 1.0 - top.a );
  float alpha = top.a + bottom.a * fade;

  vec4 bottomPM = straightToPremultipliedColor( bottom );
  vec4 topPM    = straightToPremultipliedColor( top );

  vec3 color = topPM.rgb + bottomPM.rgb * fade; 

  return vec4( color, 1 ) / alpha;
}


vec4 blendMode_colorHSL( vec4 bottom, vec4 top )
{
  vec3 topHSL = RGBtoHSL( top.rgb );
  vec3 bottomHSL = RGBtoHSL( bottom.rgb );

  vec3 resultHSL = vec3( topHSL.x, topHSL.y, bottomHSL.z );
  vec3 resultRBG = clamp( HSLtoRGB( resultHSL ), 0, 1 );
  vec4 result = bottom.a == 0.0 ? bottom : vec4( resultRBG, top.a );

  return blendMode_alpha( bottom, result );
}

vec4 blendMode_colorHSL( vec4 bottom, vec4 top, float topOpacity )
{
  vec4 blendedColor = blendMode_colorHSL( bottom, top );
  blendedColor.a *= topOpacity;
  return blendMode_alpha( bottom, blendedColor );
}

vec4 blendMode_colorHSV( vec4 bottom, vec4 top )
{
  vec3 topHSL = RGBtoHSV( top.rgb );
  vec3 bottomHSL = RGBtoHSV( bottom.rgb );

  vec3 resultHSL = vec3( topHSL.x, topHSL.y, bottomHSL.z );
  vec3 resultRBG = clamp( HSVtoRGB( resultHSL ), 0, 1 );
  vec4 result = bottom.a == 0.0 ? bottom : vec4( resultRBG, top.a );

  return blendMode_alpha( bottom, result );
}

vec4 blendMode_colorHSV( vec4 bottom, vec4 top, float topOpacity )
{
  vec4 blendedColor = blendMode_colorHSV( bottom, top );
  blendedColor.a *= topOpacity;
  return blendMode_alpha( bottom, blendedColor );
}