Sign In

Curves (based on G'MIC) and HSV dither hlsl

Author
Time
 (Edited)

Since I thought that the Curves function in G’MIC (GIMP) was very good for colour mapping, I wanted to use it for video in some way. So I created this code that lets you remap RGB and HSV values. It just does straight line interpolation, not curves.

I also have a dithering shader that allows you to increase the mean or standard deviation of a channel by adding (pseudo-)random amounts according to a uniform distribution (almost). I strongly suggest using grey dithering’s standard deviation settings for deblocking video.

sampler s0 : register(s0);
float4 p0 :  register(c0);
float4 p1 :  register(c1);

#define width   (p0[0])
#define height  (p0[1])
#define counter (p0[2])
#define clock   (p0[3])
#define one_over_width  (p1[0])
#define one_over_height (p1[1])


float3 rgb2hsv(float3 c)
{
    float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
    float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
 
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}


float3 hsv2rgb(float3 c)
{
    float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
//Source: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl

//Bounds for interpolation//
static float r_x_b[2]={0,1};static float r_y_b[2]={0,1};static float g_x_b[2]={0,1};static float g_y_b[2]={0,1};static float b_x_b[2]={0,1};static float b_y_b[2]={0,1};static float h_x_b[2]={0,1};static float h_y_b[2]={0,1};static float s_x_b[2]={0,1};static float s_y_b[2]={0,1};static float v_x_b[2]={0,1};static float v_y_b[2]={0,1};

#define red_on 0
#define red_points 3

static float2 r[red_points] = {
0, 0,    // row 1; x,y
128,128,
255,255
};

#define green_on 0
#define green_points 3

static float2 g[green_points] = {
0, 0,    // row 1; x,y
128,128,
255,255
};

#define blue_on 0
#define blue_points 3

static float2 b[blue_points] = {
0, 0,    // row 1; x,y
128,128,
255,255
};


static float rotate_hues = 0; //-360 to 360

#define hue_on 1
#define hue_points 7

static float2 h[hue_points] = {
0, 0,    // row 1; x,y
10,10,
120,128,
185,183,
294,302,
302,310,
360,360
};

#define sat_on 1
#define sat_range 100
#define sat_points 3

static float2 s[sat_points] = {
0, 0,    // row 1; x,y
69,80,
100,100
};

#define val_on 1
#define val_range 100
#define val_points 4

static float2 v[val_points]= {
0, 0,    // row 1; x,y
35,34,
77,84,
100,100
};

#define split 1
#define noWorseWB 0

float red_map(float red){int i=0;int exact=0;[unroll(red_points)]for(i=0;i<red_points;i++){if(r[i][0]/255==red) {red=r[i][1]/255;exact=1;i=red_points-1;}else{if(r[i][0]/255<red&&r[i][0]/255>=r_x_b[0]){r_x_b[0]=r[i][0]/255;r_y_b[0]=r[i][1]/255;} if(r[i][0]/255<=r_x_b[1]&&red<r[i][0]/255){r_x_b[1]=r[i][0]/255;r_y_b[1]=r[i][1]/255;}}} if(exact==0){red=r_y_b[0]+(red-r_x_b[0])*((r_y_b[1]-r_y_b[0])/(r_x_b[1]-r_x_b[0]));}return red;} 

float green_map(float green){int i=0;int exact=0;[unroll(green_points)]for(i=0;i<green_points;i++){if(g[i][0]/255==green) {green=g[i][1]/255;exact=1;i=green_points-1;}else{if(g[i][0]/255<green&&g[i][0]/255>=g_x_b[0]){g_x_b[0]=g[i][0]/255;g_y_b[0]=g[i][1]/255;} if(g[i][0]/255<=g_x_b[1]&&green<g[i][0]/255){g_x_b[1]=g[i][0]/255;g_y_b[1]=g[i][1]/255;}}} if(exact==0){green=g_y_b[0]+(green-g_x_b[0])*((g_y_b[1]-g_y_b[0])/(g_x_b[1]-g_x_b[0]));}return green;} 

float blue_map(float blue){int i=0;int exact=0;[unroll(blue_points)]for(i=0;i<blue_points;i++){if(b[i][0]/255==blue) {blue=b[i][1]/255;exact=1;i=blue_points-1;}else{if(b[i][0]/255<blue&&b[i][0]/255>=b_x_b[0]){b_x_b[0]=b[i][0]/255;b_y_b[0]=b[i][1]/255;} if(b[i][0]/255<=b_x_b[1]&&blue<b[i][0]/255){b_x_b[1]=b[i][0]/255;b_y_b[1]=b[i][1]/255;}}} if(exact==0){blue=b_y_b[0]+(blue-b_x_b[0])*((b_y_b[1]-b_y_b[0])/(b_x_b[1]-b_x_b[0]));}return blue;} 

float hue_rotate(float hue,float rot){rot*=pow(360,-1);float r=hue+rot;if(r<0){return 1+r;}else if(r>1){return r-1;}else{return r;}}

float hue_map(float hue){int i=0;int exact=0;[unroll(hue_points)]for(i=0;i<hue_points;i++){if(h[i][0]/360==hue) {hue=h[i][1]/360;exact=1;i=hue_points-1;}else{if(h[i][0]/360<hue&&h[i][0]/360>=h_x_b[0]){h_x_b[0]=h[i][0]/360;h_y_b[0]=h[i][1]/360;} if(h[i][0]/360<=h_x_b[1]&&hue<h[i][0]/360){h_x_b[1]=h[i][0]/360;h_y_b[1]=h[i][1]/360;}}} if(exact==0){hue=h_y_b[0]+(hue-h_x_b[0])*((h_y_b[1]-h_y_b[0])/(h_x_b[1]-h_x_b[0]));}return hue;} 

float sat_map(float sat){int i=0;int exact=0;[unroll(sat_points)]for(i=0;i<sat_points;i++){if(s[i][0]/sat_range==sat) {sat=s[i][1]/sat_range;exact=1;i=sat_points-1;}else{if(s[i][0]/sat_range<sat&&s[i][0]/sat_range>=s_x_b[0]){s_x_b[0]=s[i][0]/sat_range;s_y_b[0]=s[i][1]/sat_range;} if(s[i][0]/sat_range<=s_x_b[1]&&sat<s[i][0]/sat_range){s_x_b[1]=s[i][0]/sat_range;s_y_b[1]=s[i][1]/sat_range;}}} if(exact==0){sat=s_y_b[0]+(sat-s_x_b[0])*((s_y_b[1]-s_y_b[0])/(s_x_b[1]-s_x_b[0]));}return sat;} 

float val_map(float val){int i=0;int exact=0;[unroll(val_points)]for(i=0;i<val_points;i++){if(v[i][0]/val_range==val) {val=v[i][1]/val_range;exact=1;i=val_points-1;}else{if(v[i][0]/val_range<val&&v[i][0]/val_range>=v_x_b[0]){v_x_b[0]=v[i][0]/val_range;v_y_b[0]=v[i][1]/val_range;} if(v[i][0]/val_range<=v_x_b[1]&&val<v[i][0]/val_range){v_x_b[1]=v[i][0]/val_range;v_y_b[1]=v[i][1]/val_range;}}} if(exact==0){val=v_y_b[0]+(val-v_x_b[0])*((v_y_b[1]-v_y_b[0])/(v_x_b[1]-v_x_b[0]));}return val;}

float4 remapper(float4 c0){
float3 orig=c0.rgb;
if(red_on==1){c0.r=red_map(c0.r);}		//red
if(green_on==1){c0.g=green_map(c0.g);}	//green
if(blue_on==1){c0.b=blue_map(c0.b);}	//blue

if (noWorseWB==1){

float3 origHSV=rgb2hsv(orig.rgb);
float3 newHSV=rgb2hsv(c0.rgb);
float origMin=min(orig.r,min(orig.g,orig.b));
float newMin=min(c0.r,min(c0.g,c0.b));

float ogChoice=origMin*(1-origHSV.y)+pow(1-origMin,2);
float nwChoice=newMin*(1-newHSV.y)+pow(1-newMin,2);

if (ogChoice>nwChoice){
c0.rgb=orig.rgb;
}

}

float3 colorHSV= rgb2hsv(c0.rgb);
	if(rotate_hues!=0){
	colorHSV.x=hue_rotate(colorHSV.x,rotate_hues);
	c0.rgb=hsv2rgb(colorHSV); colorHSV= rgb2hsv(c0.rgb); //hue rotate
}


	if(hue_on==1){
colorHSV.x=hue_map(colorHSV.x);
c0.rgb=hsv2rgb(colorHSV); 
colorHSV= rgb2hsv(c0.rgb); //hue
	}

if(sat_on==1){
colorHSV.y=sat_map(colorHSV.y); 
c0.rgb=hsv2rgb(colorHSV); 
colorHSV= rgb2hsv(c0.rgb); //sat
}

if(val_on==1){
colorHSV.z=val_map(colorHSV.z);
c0.rgb=hsv2rgb(colorHSV);
colorHSV= rgb2hsv(c0.rgb); //val
}

	return c0;


}


float4 main(float2 tex : TEXCOORD0) : COLOR {
	float4 c0 = tex2D(s0, tex);
	
float divLine=0.5;

float divThk=(0.0008*width)*one_over_width;

if (split==1){
if(tex.x*width>=(divLine-divThk)*width && tex.x*width<=(divLine+divThk)*width){
c0.xyz=0;
return c0;

}

if(tex.x*width>(divLine+divThk)*width){
	
return remapper(c0);

}
else {

return c0;

}
}else{

return remapper(c0);

}

}

Here’s the HSV+CMY dither:

sampler s0 : register(s0);
float4 p0 :  register(c0);
float4 p1 :  register(c1);

#define width   (p0[0])
#define height  (p0[1])
#define counter (p0[2])
#define clock   (p0[3])
#define one_over_width  (p1[0])
#define one_over_height (p1[1])



float3 rgb2hsv(float3 c)
{
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));

float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}


float3 hsv2rgb(float3 c)
{
float4 K = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
float3 p = abs(frac(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * lerp(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
} 
//Source: http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl

static float d_x_b[2]={0,1};static float d_y_b[2]={0,1};
 
#define dither_points 7

static float2 d[dither_points] = {
0,0,
1,0,
64.90915,63.75,
131.4898,127.5,
194.1036,191.25,
254,255,
255,255
};

float dither_map(float dither){int i=0;int exact=0;[unroll(dither_points)]for(i=0;i<dither_points;i++){if(d[i][0]/255==dither) {dither=d[i][1]/255;exact=1;i=dither_points-1;}else{if(d[i][0]/255<dither&&d[i][0]/255>=d_x_b[0]){d_x_b[0]=d[i][0]/255;d_y_b[0]=d[i][1]/255;} if(d[i][0]/255<=d_x_b[1]&&dither<d[i][0]/255){d_x_b[1]=d[i][0]/255;d_y_b[1]=d[i][1]/255;}}} if(exact==0){dither=d_y_b[0]+(dither-d_x_b[0])*((d_y_b[1]-d_y_b[0])/(d_x_b[1]-d_x_b[0]));}return dither;} 


float random( float2 p )
{
// We need irrationals for pseudo randomness.
// Most (all?) known transcendental numbers will (generally) work.
const float2 r = float2(
23.1406926327792690,  // e^pi (Gelfond's constant)
 2.6651441426902251); // 2^sqrt(2) (Gelfond-Schneider constant)

float t=frac(acos(p.x/p.y)+sin(p.x)*r.y+cos(p.y)*r.x+p.x*p.y*r.y);

t= frac((800*cos(t/20)+1400)*t);  
t= frac(pow( frac((0.01*t+sin(500*t*t))+tan(t*500)*500),2));

float rMap =3.98;
float tOld=t;
int i=0;

[unroll(100)]for (i=0;i<100;i++){
tOld=rMap*tOld*(1-tOld);
}
 
 float w = frac(10000*tOld+0.597*tOld);


return dither_map(w);

}

float hue_rotate(float hue,float rot){rot*=pow(360,-1);float r=hue+rot;if(r<0){return 1+r;}else if(r>1){return r-1;}else{return r;}} 


float3 h_dither(float3 colorHSV,float2 tex,float rnd,float sdv, float gamma){

float rand=random(float2((tex.x+width*one_over_height)*colorHSV.x,(tex.y+height*one_over_width)*colorHSV.x));
float randm=rnd*-1*((rand*-4)+1); // averages to rnd

 //shift the hue by dither_shift
colorHSV.x= hue_rotate(colorHSV.x,randm);
float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
colorHSV.x= hue_rotate(colorHSV.x,randm);

if(gamma!=1){


float colorSc=colorHSV.x*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-colorHSV.x)*-1*((rand*-4)+1);
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-colorHSV.x)*-1*((rand*-4)+1);  
}
colorHSV.x= hue_rotate(colorHSV.x,randm*360);
}


float3 color = hsv2rgb(colorHSV);

return color;
}


float3 s_dither(float3 colorHSV,float2 tex,float rnd,float sdv, float gamma){

float rand=random(float2((tex.x+width*one_over_height)*colorHSV.y,(tex.y+height*one_over_width)*colorHSV.y));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

 //shift the saturation by dither_shift
colorHSV.y= saturate(colorHSV.y+(randm/100));

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
colorHSV.y= saturate(colorHSV.y+(randm/100));


if(gamma!=1){


float colorSc=colorHSV.y*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-colorHSV.y)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-colorHSV.y)*-1*((rand*-4)+1);   //;
}

colorHSV.y= saturate(colorHSV.y+randm);
}


float3 color = hsv2rgb(colorHSV);

return color;
}


float3 v_dither(float3 colorHSV,float2 tex,float rnd,float sdv, float gamma){

float rand=random(float2((tex.x+width*one_over_height)*colorHSV.z,(tex.y+height*one_over_width)*colorHSV.z));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

colorHSV.z= saturate(colorHSV.z+(randm/100));

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
colorHSV.z= saturate(colorHSV.z+(randm/100));

if(gamma!=1){


float colorSc=colorHSV.z*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-colorHSV.z)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-colorHSV.z)*-1*((rand*-4)+1);   //;
}

colorHSV.z= saturate(colorHSV.z+randm);
}



float3 color = hsv2rgb(colorHSV);

return color;
}

float r_dither(float color,float2 tex,float rnd,float sdv, float gamma){

float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= saturate(color+(randm/255));

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
color= saturate(color+(randm/255));





if(gamma!=1){


float colorSc=color*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-color)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-color)*-1*((rand*-4)+1);   //;
}

color= saturate(color+randm);
}





return color;

}

float g_dither(float color,float2 tex,float rnd,float sdv, float gamma){

float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= saturate(color+(randm/255));

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
color= saturate(color+(randm/255));

if(gamma!=1){


float colorSc=color*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-color)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-color)*-1*((rand*-4)+1);   //;
}

color= saturate(color+randm);
}

return color;
}

float b_dither(float color,float2 tex,float rnd,float sdv, float gamma){


float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= saturate(color+(randm/255));

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
color= saturate(color+(randm/255));

if(gamma!=1){


float colorSc=color*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-color)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-color)*-1*((rand*-4)+1);   //;
}

color= saturate(color+randm);
}

return color;
}



float3 c_dither(float color,float2 tex,float rnd,float sdv, float gamma){

color=1-color; //Red -> cyan

float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= saturate(color+(randm/255));  //Act on cyan
float newCyan=color;	//Remember cyan
color=1-color; //Cyan -> red

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
newCyan= saturate(newCyan+(randm/255));

if(gamma!=1){


float colorSc=newCyan*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-newCyan)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-newCyan)*-1*((rand*-4)+1);   //;
}

newCyan= saturate(newCyan+randm);
}
color=1-newCyan;
return color;
}


float3 m_dither(float color,float2 tex,float rnd,float sdv, float gamma){
color=1-color;

float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= saturate(color+(randm/255));
float newMagenta=color;
color=1-color;

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
newMagenta= saturate(newMagenta+(randm/255));

if(gamma!=1){


float colorSc=newMagenta*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-newMagenta)*-1*((rand*-4)+1);
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-newMagenta)*-1*((rand*-4)+1); 
}

newMagenta= saturate(newMagenta+randm);
}

color=1-newMagenta;
return color;

}


float3 y_dither(float color,float2 tex,float rnd,float sdv, float gamma){
color=1-color;

float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= saturate(color+(randm/255));
float newYellow=color;
color=1-color;

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
newYellow= saturate(newYellow+(randm/255));

if(gamma!=1){


float colorSc=newYellow*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-newYellow)*-1*((rand*-4)+1);
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-newYellow)*-1*((rand*-4)+1); 
}

newYellow= saturate(newYellow+randm);
}

color=1-newYellow;

return color;

}

float grey_dither(float color,float2 tex,float rnd,float sdv, float gamma){

float rand=random(float2((tex.x+width*one_over_height)*color,(tex.y+height*one_over_width)*color));
float randm=rnd*-1*((rand*-4)+1); // averages to color + rnd

color= color+(randm/255);

float sAB=sdv*sqrt(12)*0.5;
randm=sAB*(2*rand-1)*-1;
color= color+(randm/255);
if(gamma!=1){


float colorSc=color*2;
if(colorSc<0.5){
randm=(pow(abs(0.5*colorSc),gamma)-color)*-1*((rand*-4)+1); //
}else{
randm=((1-(0.5*pow(abs(2-colorSc),gamma)))-color)*-1*((rand*-4)+1);   //;
}

color= color+randm;
}
return color;

}

#define greyDebug 0
#define split 0

#define hueDither  0
#define hueDitherAmnt 0  //Move average value up or down by an amount by dithering
#define hueDitherSdv 0 //Change standard deviation
#define hueDitherScurve 1



#define satDither 0
#define satDitherAmnt 0
#define satDitherSdv 0
#define satDitherScurve 1


#define valDither 0
#define valDitherAmnt 0
#define valDitherSdv 0
#define valDitherScurve 1


#define redDither 0
#define redDitherAmnt 0
#define redDitherSdv 0
#define redDitherScurve 1


#define greenDither 0
#define greenDitherAmnt 0
#define greenDitherSdv 0
#define greenDitherScurve 1



#define blueDither 0
#define blueDitherAmnt 0
#define blueDitherSdv 0
#define blueDitherScurve 1


#define cyanDither 0
#define cyanDitherAmnt 0
#define cyanDitherSdv 0
#define cyanDitherScurve 1



#define magentaDither 0
#define magentaDitherAmnt 0
#define magentaDitherSdv 0
#define magentaDitherScurve 1


#define yellowDither 0
#define yellowDitherAmnt 0
#define yellowDitherSdv 0
#define yellowDitherScurve 1

#define rgbDither 0
#define rgbDitherAmnt 0
#define rgbDitherSdv 0
#define rgbDitherScurve 1


#define greyDither 0
#define greyDitherAmnt 0
#define greyDitherSdv 0
#define greyDitherScurve 1


float4 ditherer(float4 c0, float2 tex){
float3 colorHSV= rgb2hsv(c0.rgb);
if (hueDither==1){
c0.rgb=h_dither(colorHSV,tex,hueDitherAmnt,hueDitherSdv,hueDitherScurve); colorHSV= rgb2hsv(c0.rgb);
}

if (satDither==1){
c0.rgb=s_dither(colorHSV,tex,satDitherAmnt,satDitherSdv,satDitherScurve); colorHSV= rgb2hsv(c0.rgb);
}

if (valDither==1){
c0.rgb =v_dither(colorHSV,tex,valDitherAmnt,valDitherSdv,valDitherScurve); colorHSV= rgb2hsv(c0.rgb);
}

if (redDither==1){
c0.r =r_dither(c0.r,tex,redDitherAmnt,redDitherSdv,redDitherScurve);
}

if (greenDither==1){
c0.g =g_dither(c0.g,tex,greenDitherAmnt,greenDitherSdv,greenDitherScurve);
}

if (blueDither==1){
c0.b =b_dither(c0.b,tex,blueDitherAmnt,blueDitherSdv,blueDitherScurve);
}

if (cyanDither==1){
c0.r =c_dither(c0.r,tex,cyanDitherAmnt,cyanDitherSdv,cyanDitherScurve);
}

if (magentaDither==1){
c0.g =m_dither(c0.g,tex,magentaDitherAmnt,magentaDitherSdv,magentaDitherScurve);
}

if (yellowDither==1){
c0.b =y_dither(c0.b,tex,yellowDitherAmnt,yellowDitherSdv,yellowDitherScurve);
}

if (rgbDither==1){
c0.r =r_dither(c0.r,tex,rgbDitherAmnt,rgbDitherSdv,rgbDitherScurve);
c0.g =g_dither(c0.g,tex,rgbDitherAmnt,rgbDitherSdv,rgbDitherScurve);
c0.b =b_dither(c0.b,tex,rgbDitherAmnt,rgbDitherSdv,rgbDitherScurve);
}

if (greyDither==1){
c0.rgb =saturate(c0.rgb +(grey_dither(max(c0.r,max(c0.g,c0.b)),tex,greyDitherAmnt,greyDitherSdv,greyDitherScurve)-(max(c0.r,max(c0.g,c0.b)))));
}

if (greyDebug==1){
float greyDebugPwr=5;

float3 mxrgb=c0.rgb;



if(abs(max(max(c0.r,c0.g),c0.b)-min(min(c0.r,c0.g),c0.b))==0){
mxrgb.rgb=max(max(c0.r,c0.g),c0.b);
}else{
float mmdiff=abs(max(max(c0.r,c0.g),c0.b)-min(min(c0.r,c0.g),c0.b));
if(c0.r==max(max(c0.r,c0.g),c0.b)){
//mxrgb.r+=1;
mxrgb.r=-pow(pow(mmdiff,-1*(mmdiff-1)),greyDebugPwr)+1;
}

if(c0.g==max(max(c0.r,c0.g),c0.b)){
//mxrgb.g+=1;
mxrgb.g=-pow(pow(mmdiff,-1*(mmdiff-1)),greyDebugPwr)+1;
}

if(c0.b==max(max(c0.r,c0.g),c0.b)){
//mxrgb.b+=1;
mxrgb.b=-pow(pow(mmdiff,-1*(mmdiff-1)),greyDebugPwr)+1;
}



}

c0.rgb=mxrgb.rgb;

}
return c0;
} 

float4 main(float2 tex : TEXCOORD0) : COLOR {
float4 c0 = tex2D(s0, tex);

float divLine=0.5;

float divThk=(0.0008*width)*one_over_width;

if (split==1){
if(tex.x*width>=(divLine-divThk)*width && tex.x*width<=(divLine+divThk)*width){
c0.xyz=0;
return c0;

}
if(tex.x*width>(divLine+divThk)*width){

return ditherer(c0,tex);

}
else {

return c0;

}}
else{

return ditherer(c0,tex);

}
return c0;
}