   /*-----------------------------------------------------------.   
  /                       GEM                                /
  '-----------------------------------------------------------*/
/*
by Lucifer Hawk
Using algorithms from Christian Cann Schuldt Jensen ~ CeeJay.dk
*/

Texture2D srcTex;
Texture3D noiseTex;

#if (USE_SHADER3VERSION == 0)
SamplerState LinearSamplerWrap {
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
    AddressW = Wrap;
};
#endif
  
#define CoefLuma float3(0.2126, 0.7152, 0.0722)

float4 GEMSharpen1(float4 inputcolor, float2 tex, float sharp_strength1, float sharp_clamp1, float offset_bias1)
{
  float3 ori = myTex2D(s0, tex).rgb;       
  float3 sharp_strength1_luma = (CoefLuma * sharp_strength1); 

    half3 blur_ori = myTex2D(s0, tex + float2(-px,py) * offset_bias1).rgb; // North West
    blur_ori += myTex2D(s0, tex + float2(px,-py) * offset_bias1).rgb;     // South East
    blur_ori += myTex2D(s0, tex + float2(-px,-py)  * offset_bias1).rgb;  // South West
    blur_ori += myTex2D(s0, tex + float2(px,py) * offset_bias1).rgb;    // North East

    half3 blur_ori2 = myTex2D(s0, tex + float2(0,py) * offset_bias1).rgb; // North
    blur_ori2 += myTex2D(s0, tex + float2(0,-py) * offset_bias1).rgb;    // South
    blur_ori2 += myTex2D(s0, tex + float2(-px,0) * offset_bias1).rgb;   // West
    blur_ori2 += myTex2D(s0, tex + float2(px,0) * offset_bias1).rgb;   // East
    blur_ori2 *= 2.0;

    blur_ori += blur_ori2;
    blur_ori += (ori * 4);

    blur_ori /= 16.0; 

  float3 sharp = ori - blur_ori; 

    float4 sharp_strength1_luma_clamp = float4(sharp_strength1_luma * (0.5 / sharp_clamp1),0.5); 

    float sharp_luma = saturate(dot(float4(sharp,1.0), sharp_strength1_luma_clamp)); //Calculate the luma, adjust the strength, scale up and clamp
    sharp_luma = (sharp_clamp1 * 2.0) * sharp_luma - sharp_clamp1; 
  inputcolor.rgb = inputcolor.rgb + sharp_luma;   

  return saturate(inputcolor);

}

	float GStrenght 	= 0.60;	//1.5		
	float GBaseGamma 	= 1.60;			
	float GFade		= 0.165;	//0.03	
	float GContrast		= 1.005;			
	float GSaturation	= 0.155;			
	float GBleach		= -0.12; 	
	float GRedCurve		= 6.0;			
	float GGreenCurve	= 6.0;			
	float GBlueCurve	= 6.0;			
	float GBaseCurve	= 1.5;			
	float GEffectGammaR	= 1.0;			
	float GEffectGammaG	= 1.0;			
	float GEffectGammaB	= 1.0;			
	float GEffectGamma	= 0.72;			
	float GLinearization	= 1.5;			

float4 GEMHDR( float4 colorInput, float2 tex ) 
{
	float3 c_center = myTex2D(s0, tex).rgb; //reuse SMAA center sample or lumasharpen center sample?
	
	float radius1 = 0.793;
	float3 bloom_sum1 = myTex2D(s0, tex + float2(1.5, -1.5) * radius1).rgb;
	bloom_sum1 += myTex2D(s0, tex + float2(-1.5, -1.5) * radius1).rgb; //rearrange sample order to minimize ALU and maximize cache usage
	bloom_sum1 += myTex2D(s0, tex + float2(1.5, 1.5) * radius1).rgb;
	bloom_sum1 += myTex2D(s0, tex + float2(-1.5, 1.5) * radius1).rgb;
	
	bloom_sum1 += myTex2D(s0, tex + float2(0, -2.5) * radius1).rgb;
	bloom_sum1 += myTex2D(s0, tex + float2(0, 2.5) * radius1).rgb;
	bloom_sum1 += myTex2D(s0, tex + float2(-2.5, 0) * radius1).rgb;
	bloom_sum1 += myTex2D(s0, tex + float2(2.5, 0) * radius1).rgb;
	
	bloom_sum1 *= 0.005;
	
	float3 bloom_sum2 = myTex2D(s0, tex + float2(1.5, -1.5) * 0.75).rgb;
	bloom_sum2 += myTex2D(s0, tex + float2(-1.5, -1.5) * 0.75).rgb;
	bloom_sum2 += myTex2D(s0, tex + float2(1.5, 1.5) * 0.75).rgb;
	bloom_sum2 += myTex2D(s0, tex + float2(-1.5, 1.5) * 0.75).rgb;


	bloom_sum2 += myTex2D(s0, tex + float2(0, -2.5) * 0.75).rgb;	
	bloom_sum2 += myTex2D(s0, tex + float2(0, 2.5) * 0.75).rgb;
	bloom_sum2 += myTex2D(s0, tex + float2(-2.5, 0) * 0.75).rgb;
	bloom_sum2 += myTex2D(s0, tex + float2(2.5, 0) * 0.75).rgb;

	bloom_sum2 *= 0.010;
	
	float dist = 0.75 - radius1;
	
	float3 HDR = (c_center + (bloom_sum2 - bloom_sum1)) * dist;
	float3 blend = HDR + colorInput.rgb;
	colorInput.rgb = HDR + pow(blend, GSceneDepth); // pow - don't use fractions for HDRpower
	
	return saturate(colorInput);
}

#define ColorShift_distance float2(0.0,3.5)
float4 GEMHD( float4 colorInput, float2 tex )
{ 	
#if (GColorBoost == 1)
float3 Ccolor = float3(0.0,0.0,0.0);

Ccolor.r = myTex2D(s0, tex + (pixel * ColorShift_distance)).r;
Ccolor.g = myTex2D(s0, tex).g;
Ccolor.b = myTex2D(s0, tex - (pixel * ColorShift_distance)).b;

colorInput.rgb = lerp(colorInput.rgb, Ccolor, 0.125);

	float4 V1color = colorInput;
	#define V1Vibrance 0.2
	#define V1Vibrance_RGB_balance float3(0.20, 1.00, 1.00)
	#define V1Vibrance_coeff float3(V1Vibrance_RGB_balance * V1Vibrance)
	float3 V1lumCoeff = float3(0.212656, 0.715158, 0.072186);
	float V1luma = dot(V1lumCoeff, V1color.rgb);
	float V1max_color = max(colorInput.r, max(colorInput.g,colorInput.b)); 
	float V1min_color = min(colorInput.r, min(colorInput.g,colorInput.b)); 
	float V1color_saturation = V1max_color - V1min_color;
	V1color.rgb = lerp(V1luma, V1color.rgb, (1.0 + (V1Vibrance_coeff * (1.0 - (sign(V1Vibrance_coeff) * V1color_saturation)))));
	colorInput = V1color;
#endif		
	colorInput = GEMHDR(colorInput,tex);

	#if (SSAO == 1)
	float3 CoefLuma2 = float3(0.2126, 0.7152, 0.0722);  //Values to calculate luma with
  
  	float diff1 = dot(CoefLuma2,myTex2D(s0, tex + pixel).rgb);
  	diff1 = dot(float4(CoefLuma2,-1.0),float4(myTex2D(s0, tex - pixel).rgb , diff1));
  	
  	float diff2 = dot(CoefLuma2,myTex2D(s0, tex +float2(pixel.x,-pixel.y)).rgb);
  	diff2 = dot(float4(CoefLuma2,-1.0),float4(myTex2D(s0, tex +float2(-pixel.x,pixel.y)).rgb , diff2));
    
  	float edge = dot(float2(diff1,diff2),float2(diff1,diff2));
  	
  	colorInput.rgb =  pow(edge,0.40) * -0.05 + colorInput.rgb;
	
  	colorInput = saturate(colorInput); 
	#endif	

	float3 Dcolor = saturate(colorInput.rgb);
	Dcolor = Dcolor + (float3(1.10, 1.10, 1.08) / 2.0 - 0.5) * (1.0 - Dcolor);
	Dcolor = saturate(Dcolor); 
	colorInput.rgb = pow(float3(0.941, 0.938, 0.921) * Dcolor, 1.0 / float3(0.97, 1.018, 0.992));
	colorInput = float4(colorInput.rgbb);	
	
	float4 Vcolor = colorInput;
	#define VVibrance -0.044
	#define VVibrance_RGB_balance float3(1.00, 1.00, 1.00)
	#define VVibrance_coeff float3(VVibrance_RGB_balance * VVibrance)
	float3 VlumCoeff = float3(0.212656, 0.715158, 0.072186);
	float Vluma = dot(VlumCoeff, Vcolor.rgb);
	float Vmax_color = max(colorInput.r, max(colorInput.g,colorInput.b)); 
	float Vmin_color = min(colorInput.r, min(colorInput.g,colorInput.b)); 
	float Vcolor_saturation = Vmax_color - Vmin_color;
	Vcolor.rgb = lerp(Vluma, Vcolor.rgb, (1.0 + (VVibrance_coeff * (1.0 - (sign(VVibrance_coeff) * Vcolor_saturation)))));
	colorInput = Vcolor;
	
  	float PI = acos(-1);
	float Xluma = dot(VlumCoeff, colorInput.rgb);
	float3 Xchroma = colorInput.rgb - Xluma;
	float3 x = Xchroma;
	x = x * 0.5 + 0.5;
	x = x*x*(3.0-2.0*x);
	x = x * 2.0 - 1.0;
	float3 Xcolor = Xluma + x;
	colorInput.rgb = lerp(colorInput.rgb, Xcolor, 0.30);
	
	colorInput.rgb = (colorInput.rgb  - (3/255.0)) * (255.0/(255.0-8));

	colorInput = GEMHDR(colorInput,tex);	

	//colorInput = GEMSharpen1(colorInput,tex);	

	//colorInput = GEMSharpen1(colorInput,tex);

	colorInput = pow(colorInput, 1.23);	

	float4 B = colorInput;
	float3 coord=0.0;
	coord.xy=tex.xy;		

B = pow(B, 1/GTBright);

float GDefog=0.000; 					
float4 GFogColor={0.0, 0.0, 0.0, 0.0}; 			
float GExposure=0.65; 					
float GGamma=1.32; 					
float GBlueShift=0.2;

B.xyz = max(0, B.xyz - GDefog * GFogColor.xyz);
B.xyz *= pow(2.0f, GExposure);
B.xyz = pow(B.xyz, GGamma);
float3 trollface = B.xyz * float3(1.05f, 0.97f, 1.27f);
B.xyz = lerp(B.xyz, trollface, GBlueShift);

	#define GLUM_FACTOR float4(0.299, 0.187, 0.114, 0.0)
	float pixelLumi = dot(B.xyz, GLUM_FACTOR.xyz);
	float toneMapCalc = pixelLumi / (pixelLumi + 1);
	B =  toneMapCalc * pow(B / pixelLumi, GSat);
	B = B * 1.3; //EXP

	float origgray=max(B.x, B.y);
	origgray=max(origgray, B.z);
	coord.xy=tex.xy*16.0 + origgray;

	B=lerp(B, (0.035+GCBright)*B, 3.5*saturate(1.0-origgray*1.8));


	float CrossContrast =1.002;		
	float CrossSaturation2 = 1.05;	
	float CrossBrightness = 0.0065;		
	float CrossAmount = 3.0;		
	float2 crossMatrix [3] =
		{
			float2 (0.94, 0.007*GShadowDepth),
			float2 (0.945, 0.0065*GShadowDepth),
			float2 (1.055, 0.0045*GShadowDepth)
		};

		float4 image1 = B;
		float4 image2 = B;
		float gray = dot(float3(0.5,0.5,0.5), image1);

		image1 = lerp (gray, image1,CrossSaturation2);

		image1 = lerp (0.35, image1,CrossContrast);

		image1 +=CrossBrightness;
		image1 *=1.2;

		image2.r = image1.r * crossMatrix[0].x + crossMatrix[0].y;
		image2.g = image1.g * crossMatrix[1].x + crossMatrix[1].y;
		image2.b = image1.b * crossMatrix[2].x + crossMatrix[2].y;

		B = lerp(image1, image2, CrossAmount);

        float4 G = B;
	float4 H = 0.01;
 
	B = pow(abs(B), GLinearization);
	B = lerp(H, B, GContrast);
 
	float A = dot(B.rgb.xyz, 0.333);
	float4 D = A;
 
	B = pow(abs(B), 1.0 / GBaseGamma);
 
	float a = GRedCurve;
	float b = GGreenCurve;
	float c = GBlueCurve;
	float d = GBaseCurve;
 
	float y = 1.0 / (1.0 + exp(a / 2.0));
	float z = 1.0 / (1.0 + exp(b / 2.0));
	float w = 1.0 / (1.0 + exp(c / 2.0));
	float v = 1.0 / (1.0 + exp(d / 2.0));
 
	float4 C = B;
 
	D.r = (1.0 / (1.0 + exp(-a * (D.r - 0.5))) - y) / (1.0 - 2.0 * y);
	D.g = (1.0 / (1.0 + exp(-b * (D.g - 0.5))) - z) / (1.0 - 2.0 * z);
	D.b = (1.0 / (1.0 + exp(-c * (D.b - 0.5))) - w) / (1.0 - 2.0 * w);
 
	D = pow(abs(D), 1.0 / GEffectGamma);
 
	float4 Di = 1.0 - D;
 
	D = lerp(D, Di, GBleach);
 
	D.r = pow(abs(D.r), 1.0 / GEffectGammaR);
	D.g = pow(abs(D.g), 1.0 / GEffectGammaG);
	D.b = pow(abs(D.b), 1.0 / GEffectGammaB);
 
	if (D.r < 0.5)
		C.r = (2.0 * D.r - 1.0) * (B.r - B.r * B.r) + B.r;
	else
		C.r = (2.0 * D.r - 1.0) * (sqrt(B.r) - B.r) + B.r;
 
	if (D.g < 0.5)
		C.g = (2.0 * D.g - 1.0) * (B.g - B.g * B.g) + B.g;
	else
		C.g = (2.0 * D.g - 1.0) * (sqrt(B.g) - B.g) + B.g;
 	
	if (D.b < 0.5)
		C.b = (2.0 * D.b - 1.0) * (B.b - B.b * B.b) + B.b;
	else
		C.b = (2.0 * D.b - 1.0) * (sqrt(B.b) - B.b) + B.b;
 
	float4 F = lerp(B, C, GStrenght);
 
	F = (1.0 / (1.0 + exp(-d * (F - 0.5))) - v) / (1.0 - 2.0 * v);
 
	float r2R = 1.0 - GSaturation;
	float g2R = 0.0 + GSaturation;
	float b2R = 0.0 + GSaturation;
 
	float r2G = 0.0 + GSaturation;
	float g2G = (1.0 - (GFade - 0.1)) - GSaturation;
	float b2G = (0.0 + GFade) + GSaturation;
 
	float r2B = 0.0 + Saturation;
	float g2B = (0.0 + GFade) + GSaturation;
	float b2B = (1.0 - GFade) - GSaturation;
 
	float4 iF = F;
 
	F.r = (iF.r * r2R + iF.g * g2R + iF.b * b2R);
	F.g = (iF.r * r2G + iF.g * g2G + iF.b * b2G);
	F.b = (iF.r * r2B + iF.g * g2B + iF.b * b2B);
 
	float N = dot(F.rgb.xyz, 0.333);
	float4 Cn = F;
 
	if (N < 0.5)
		Cn = (2.0 * N - 1.0) * (F - F * F) + F;
	else
		Cn = (2.0 * N - 1.0) * (sqrt(F) - F) + F;
 
	Cn = pow(abs(Cn), 1.0 / GLinearization);
 
	float4 Fn = lerp(B, Cn, GStrenght);

	Fn = pow(Fn, 1/1.25);	

	float gdither_bit  = 8.0;      
     	float gseed = dot(tex, float2(12.9898,78.233)); 
     	float gsine = sin(gseed); 
    	float gnoise = frac(gsine * 43758.5453 + tex.x); 

     	float gdither_shift = (1.0 / (pow(2,gdither_bit) - 1.0)); 
	float gdither_shift_half = (gdither_shift * 0.5); 
     	gdither_shift = gdither_shift * gnoise - gdither_shift_half;  
     	Fn.rgb += float3(-gdither_shift, gdither_shift, -gdither_shift);

	#if ( USE_GEMHBO == 1 )
	Fn = GEMSharpen1(Fn,tex, 9.45, 0.036, 0.2);
	#endif
	return Fn;
}
