shader_type canvas_item;

// 输入参数
uniform int PaletteCount;
uniform vec4 BasicColor[8] : source_color;
uniform vec4 ModulateColor[8] : source_color;
uniform float Tolerance[8];
uniform int BlendMode[8];

//#define DEBUG
#ifdef DEBUG
uniform sampler2D BlendTexture : source_color;
#endif

// ################################################################################################
// ################################################################################################
// ################################################################################################
// ClusteringColor by CIEDE2000
// https://www.shadertoy.com/view/msXyz8
const float epsilon = 0.00001;
float my_sin(float x) { return sin(radians(x)); }
float my_cos(float x) { return cos(radians(x)); }
float my_atan(float y, float x) {
    float v = degrees(atan(y, x));
    return (v < 0.0) ? v + 360.0 : v;
}

float get_h(float a, float b) {
    bool a_and_b_are_zeros = (abs(a) < epsilon)&&(abs(b) < epsilon);
    return a_and_b_are_zeros ? 0.0 : my_atan(b, a);
}

float get_delta_h(float C1, float C2, float h1, float h2) {
    float diff = h2 - h1;
    return (C1 * C2 < epsilon) ? 0.0 :
    (abs(diff) <= 180.0) ? diff :
    (diff > 180.0) ? diff - 360.0 :
    diff + 360.0;
}

float get_h_bar(float C1, float C2, float h1, float h2) {
    float dist = abs(h1 - h2);
    float sum = h1 + h2;
    return (C1 * C2 < epsilon) ? h1 + h2 :
    (dist <= 180.0) ? 0.5 * sum :
    (sum < 360.0) ? 0.5 * (sum + 360.0) :
    0.5 * (sum - 360.0);

}

float calculate_CIEDE2000(vec3 Lab1, vec3 Lab2) {
    float L1 = Lab1.x;
    float a1 = Lab1.y;
    float b1 = Lab1.z;
    float L2 = Lab2.x;
    float a2 = Lab2.y;
    float b2 = Lab2.z;

    float C1_ab = sqrt(a1 * a1 + b1 * b1);
    float C2_ab = sqrt(a2 * a2 + b2 * b2);
    float C_ab_bar = 0.5 * (C1_ab + C2_ab);
    float G = 0.5 * (1.0 - sqrt(pow(C_ab_bar, 7.0) / (pow(C_ab_bar, 7.0) + pow(25.0, 7.0))));
    float a_1 = (1.0 + G) * a1;
    float a_2 = (1.0 + G) * a2;
    float C1 = sqrt(a_1 * a_1 + b1 * b1);
    float C2 = sqrt(a_2 * a_2 + b2 * b2);
    float h1 = get_h(a_1, b1);
    float h2 = get_h(a_2, b2);

    float delta_L = L2 - L1;
    float delta_C = C2 - C1;
    float delta_h = get_delta_h(C1, C2, h1, h2);
    float delta_H = 2.0 * sqrt(C1 * C2) * my_sin(0.5 * delta_h);

    float L_bar = 0.5 * (L1 + L2);
    float C_bar = 0.5 * (C1 + C2);
    float h_bar = get_h_bar(C1, C2, h1, h2);

    float T = 1.0 - 0.17 * my_cos(h_bar - 30.0) + 0.24 * my_cos(2.0 * h_bar) +
    0.32 * my_cos(3.0 * h_bar + 6.0) - 0.20 * my_cos(4.0 * h_bar - 63.0);

    float delta_theta = 30.0 * exp(-((h_bar - 275.0) / 25.0) * ((h_bar - 275.0) / 25.0));

    float R_C = 2.0 * sqrt(pow(C_bar, 7.0) / (pow(C_bar, 7.0) + pow(25.0, 7.0)));
    float S_L = 1.0 + (0.015 * (L_bar - 50.0) * (L_bar - 50.0)) / sqrt(20.0 + (L_bar - 50.0) * (L_bar - 50.0));
    float S_C = 1.0 + 0.045 * C_bar;
    float S_H = 1.0 + 0.015 * C_bar * T;
    float R_T = -my_sin(2.0 * delta_theta) * R_C;

    const float k_L = 1.0;
    const float k_C = 1.0;
    const float k_H = 1.0;

    float deltaL = delta_L / (k_L * S_L);
    float deltaC = delta_C / (k_C * S_C);
    float deltaH = delta_H / (k_H * S_H);

    float delta_E_squared = deltaL * deltaL + deltaC * deltaC + deltaH * deltaH + R_T * deltaC * deltaH;

    return sqrt(delta_E_squared);
}

//--- RGB2Lab
vec3 rgb2xyz(vec3 c) {
    vec3 tmp;
    tmp.x = (c.r > 0.04045) ? pow((c.r + 0.055) / 1.055, 2.4) : c.r / 12.92;
    tmp.y = (c.g > 0.04045) ? pow((c.g + 0.055) / 1.055, 2.4) : c.g / 12.92;
    tmp.z = (c.b > 0.04045) ? pow((c.b + 0.055) / 1.055, 2.4) : c.b / 12.92;
    return 100.0 * tmp * mat3(vec3(0.4124, 0.3576, 0.1805), vec3(0.2126, 0.7152, 0.0722), vec3(0.0193, 0.1192, 0.9505));
}
vec3 xyz2lab(vec3 c) {
    vec3 n = c / vec3(95.047, 100.0, 108.883);
    vec3 v;
    v.x = (n.x > 0.008856) ? pow(n.x, 1.0 / 3.0) : (7.787 * n.x) + (16.0 / 116.0);
    v.y = (n.y > 0.008856) ? pow(n.y, 1.0 / 3.0) : (7.787 * n.y) + (16.0 / 116.0);
    v.z = (n.z > 0.008856) ? pow(n.z, 1.0 / 3.0) : (7.787 * n.z) + (16.0 / 116.0);
    return vec3((116.0 * v.y) - 16.0, 500.0 * (v.x - v.y), 200.0 * (v.y - v.z));
}

vec3 rgb2lab(vec3 c) {
    vec3 lab = xyz2lab(rgb2xyz(c));
    return vec3(lab.x / 100.0, 0.5 + 0.5 * (lab.y / 127.0), 0.5 + 0.5 * (lab.z / 127.0));
}

float colorCompare(vec3 rgb1, vec3 rgb2) {
    vec3 lab1 = rgb2lab(rgb1);
    vec3 lab2 = rgb2lab(rgb2);
    return calculate_CIEDE2000(lab1, lab2);
}

// ################################################################################################
// ################################################################################################
// ################################################################################################
// blends modes
// https://en.wikipedia.org/wiki/Blend_modes
// pdf page 389 blend mode: https://developer.adobe.com/document-services/docs/assets/5b15559b96303194340b99820d3a70fa/PDF_ISO_32000-2.pdf

// functions
#define VEC3(C, FUNC) vec3(FUNC(C.r), FUNC(C.g), FUNC(C.b))
#define MAKE_VEC3(BASE, BLEND, FUNC) vec3(FUNC(BASE.r, BLEND.r), FUNC(BASE.g, BLEND.g), FUNC(BASE.b, BLEND.b))
#define CMIN(C) min(C.r, min(C.g, C.b))
#define CMAX(C) max(C.r, max(C.g, C.b))

float unionAlpha(float b, float s) { return b + s * (1.0 - b); }

float getLum(vec3 c) { return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b; } // Luminosity

vec3 clipColor(vec3 c)
{
	float l = getLum(c);
	float n = CMIN(c);
	float x = CMAX(c);
	if (n < 0.0) return l + (((c - l) * l) / (l - n));
	if (x > 1.0) return l + (((c - l) * (1.0 - l)) / (l - n));
	return c;
}

vec3 setLum(vec3 c, float l)
{
    float d = l - getLum(c);
    c += d;
	return clipColor(c);
}

float getSat(vec3 c) { return CMAX(c) - CMIN(c); } // Saturation

vec3 setSat(vec3 C, float s)
{
	// subscripts for Cmin, Cmid, and Cmax
	int indices[3];
    if (C.x <= C.y) {
		if (C.y <= C.z) indices = int[3](0, 1, 2); 		// x <= y <= z
		else if (C.x <= C.z) indices = int[3](0, 2, 1); 	// x <= z < y
		else indices = int[3](2, 0, 1); 					// z < x <= y
    } else {
        if (C.x <= C.z) indices = int[3](1, 0, 2); 		// y < x <= z
        else if (C.y <= C.z)indices = int[3](1, 2, 0); 	// y <= z < x
        else indices = int[3](2, 1, 0); 					// z < y < x
    }

	// set Saturation
	if (C[indices[2]] > C[indices[0]])
	{
		C[indices[1]] = (((C[indices[1]] - C[indices[0]]) * s) / (C[indices[2]] - C[indices[0]]));
		C[indices[2]] = s;
	} else {
		C[indices[1]] = 0.0;
		C[indices[2]] = 0.0;
	}
	C[indices[0]] = 0.0;

	return C;
}

// 正常
vec3 normal( vec3 Cb, vec3 Cs ) { return Cs; }

// 正片叠底
float _multiply( float Cb, float Cs ) {	return Cb * Cs; }
vec3 multiply( vec3 Cb, vec3 Cs ) {	return Cb * Cs; }

// 滤色
float _screen( float Cb, float Cs ) { return Cb + Cs - Cb * Cs; }
vec3 screen( vec3 Cb, vec3 Cs ) { return Cb + Cs - Cb * Cs; }

// 变暗
vec3 darken( vec3 Cb, vec3 Cs ) { return min(Cb, Cs); }

// 变亮
vec3 lighten( vec3 Cb, vec3 Cs ) { return max(Cb, Cs); }

// 颜色减淡
float _colorDodge( float Cb, float Cs )
{
	if(Cb <= 0.0) return 0.0;
	else if (Cb >= (1.0 - Cs)) return 1.0;
	else return Cb / (1.0 - Cs);
}
vec3 colorDodge( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _colorDodge); }

// 颜色加深
float _colorBurn(float Cb, float Cs)
{
	if (Cb >= 1.0) return 1.0;
	if ((1.0 - Cb) >= Cs) return 0.0;
	else return 1.0 - ((1.0 - Cb) / Cs);
}
vec3 colorBurn( vec3 Cb, vec3 Cs) { return MAKE_VEC3(Cb, Cs, _colorBurn); }

// 强光
float _hardLight( float Cb, float Cs ) { return (Cs <= 0.5) ? _multiply(Cb, 2.0 * Cs): _screen(Cb, 2.0 * Cs - 1.0); }
vec3 hardLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _hardLight); }

// 柔光
float _softLight( float Cb, float Cs )
{
	if(Cs <= 0.5) return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb);
	else
	{
		float d = (Cb <= 0.25) ? ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb : sqrt(Cb);
		return Cb + (2.0 * Cs - 1.0) * (d - Cb);
	}
}
vec3 softLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _softLight); }

// 叠加
vec3 overlay( vec3 Cb, vec3 Cs ) { return hardLight(Cs, Cb);  }

// 差值
vec3 difference( vec3 Cb, vec3 Cs ) { return abs(Cb - Cs); }

// 排除
vec3 exclusion( vec3 Cb, vec3 Cs ) { return Cb + Cs - 2.0 * Cb * Cs; }

// 色相
vec3 hue( vec3 Cb, vec3 Cs ) { return setLum(setSat(Cs, getSat(Cb)), getLum(Cb)); }

// 颜色
vec3 color( vec3 Cb, vec3 Cs ) { return setLum(Cs, getLum(Cb)); }

// 饱和度
vec3 saturation( vec3 Cb, vec3 Cs ) { return setLum(setSat(Cb, getSat(Cs)), getLum(Cb)); }

// 明度
vec3 luminosity( vec3 Cb, vec3 Cs ) { return setLum(Cb, getLum(Cs)); }


// 剩下的不在pdf标准中

// 线性加深
float _linearBurn(float Cb, float Cs) { return max(0, Cb + Cs - 1.0); }
vec3 linearBurn( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _linearBurn); }

// 深色
vec3 darkerColor( vec3 Cb, vec3 Cs ) { return getLum(Cb) < getLum(Cs)? Cb: Cs; }

// 线性减淡（添加）
float _linearDodge(float Cb, float Cs) { return min(1.0, Cb + Cs); }
vec3 linearDodge( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _linearDodge); }

// 浅色
vec3 lighterColor( vec3 Cb, vec3 Cs ) { return getLum(Cb) > getLum(Cs)? Cb: Cs; }

// 亮光
float _vividLight( float Cb, float Cs ) { return (Cs <= 0.5) ? _colorBurn(Cb, 2.0 * Cs): _colorDodge(Cb, 2.0 * (Cs - 0.5)); }
vec3 vividLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _vividLight); }

// 线性光
float _linearLight( float Cb, float Cs ) { return (Cs <= 0.5) ? _linearBurn(Cb, 2.0 * Cs): _linearDodge(Cb, 2.0 * (Cs - 0.5)); }
vec3 linearLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _linearLight); }

// 点光
float _pinLight( float Cb, float Cs ) { return (Cs <= 0.5) ? min(Cb,2.0 * Cs) : max(Cb,2.0 * (Cs - 0.5)); }
vec3 pinLight( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _pinLight); }

// 实色混合
float _hardMix( float Cb, float Cs ) { return (Cb + Cs >= 1.0) ? 1.0 : 0.0; }
vec3 hardMix( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _hardMix); }

// 减去
vec3 subtract( vec3 Cb, vec3 Cs ) { return max(vec3(0.0), Cb - Cs); }

// 划分
float _divide( float Cb, float Cs ) { return Cs > 0.0 ? min(1.0, Cb / Cs) : 1.0; }
vec3 divide( vec3 Cb, vec3 Cs ) { return MAKE_VEC3(Cb, Cs, _divide); }



vec3 blendFunctions( vec3 Cb, vec3 Cs, int id )
{
	if(id==0)	return normal(Cb,Cs);        // 正常

	if(id==1)	return darken(Cb,Cs);        // 变暗
	if(id==2)	return multiply(Cb,Cs);      // 正片叠底
	if(id==3)	return colorBurn(Cb,Cs);     // 颜色加深
	if(id==4)	return linearBurn(Cb,Cs);    // 线性加深
	if(id==5)	return darkerColor(Cb,Cs);   // 深色

	if(id==6)	return lighten(Cb,Cs);       // 变亮
	if(id==7)	return screen(Cb,Cs);        // 滤色
	if(id==8)	return colorDodge(Cb,Cs);    // 颜色减淡
	if(id==9)	return linearDodge(Cb,Cs);   // 线性减淡（添加）
	if(id==10)	return lighterColor(Cb,Cs);  // 浅色

	if(id==11)	return overlay(Cb,Cs);       // 叠加
	if(id==12)	return softLight(Cb,Cs);     // 柔光
	if(id==13)	return hardLight(Cb,Cs);     // 强光
	if(id==14)	return vividLight(Cb,Cs);    // 亮光
	if(id==15)	return linearLight(Cb,Cs);   // 线性光
	if(id==16)	return pinLight(Cb,Cs);      // 点光
	if(id==17)	return hardMix(Cb,Cs);       // 实色混合

	if(id==18)	return difference(Cb,Cs);    // 差值
	if(id==19)	return exclusion(Cb,Cs);     // 排除
	if(id==20)	return subtract(Cb,Cs);      // 减去
	if(id==21)	return divide(Cb,Cs);        // 划分

	if(id==22)	return hue(Cb,Cs);           // 色相
	if(id==23)	return saturation(Cb,Cs);    // 饱和度
	if(id==24)	return color(Cb,Cs);         // 颜色
	if(id==25)	return luminosity(Cb,Cs);    // 明度

    return vec3(0.0);
}



// ################################################################################################
// ################################################################################################
// ################################################################################################
// gd shader script
void fragment() {
	COLOR = texture(TEXTURE, UV);

	for (int i =0; i< PaletteCount; i++)
	{
		vec4 modulate_color = ModulateColor[i];
		vec4 basic_color = BasicColor[i];
		int blend_mode = BlendMode[i];
		float tolerance = Tolerance[i];

	    // 将容差转换为0-1范围的阈值
	    float tolerance_factor = tolerance / 100.0;

		// Backdrop colour 背景色
	    vec3 Cb = COLOR.rgb;
		float Ab = COLOR.a;

		// Source colour 混合色
#ifdef DEBUG
		vec4 source_colour = texture(BlendTexture, UV);
	    vec3 Cs = source_colour.rgb;
		float As = source_colour.a;
#else
		vec4 source_colour = modulate_color;
	    vec3 Cs = source_colour.rgb;
		float As = Ab > 0.0? source_colour.a: 0.0;
#endif

		// Result colour
		float Ar = unionAlpha(Ab, As);
		vec3 Cr = (1.0 - As / Ar) * Cb + As / Ar * ((1.0 - Ab) * Cs + Ab * blendFunctions(Cb, Cs, blend_mode));

	    // 混合原始颜色和调制后的颜色
		if (tolerance_factor >= 1.0)
			COLOR = vec4(Cr, Ar);
		else
		{
		    // 计算颜色差异
	    	float dis = colorCompare(Cb, basic_color.rgb);
			if (dis < tolerance_factor)
		    	COLOR = vec4(Cr, Ar);
		}
	}
}