   /*-----------------------------------------------------------.   
  /                       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)

#define sharp_strength1 1.05   
#define sharp_clamp1    0.006  
#define pattern1 8   
#define offset_bias1 1.4                    
#define show_sharpen1 0

float4 GEMSharpen1(float4 inputcolor, float2 tex )
{
  // -- Get the original pixel --
  float3 ori = myTex2D(s0, tex).rgb;       // ori = original pixel

  // -- Combining the strength and luma multipliers --
  float3 sharp_strength1_luma = (CoefLuma * sharp_strength1); //I'll be combining even more multipliers with it later on

  // -- pattern1 8 -- A (slower) 9 tap gaussian using 9 texture fetches.
  #if pattern1 == 8

	// -- Gaussian filter --
	//   [ 1 , 2 , 1 ]
	//   [ 2 , 4 , 2 ]
 	//   [ 1 , 2 , 1 ]

    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); // Probably not needed. Only serves to lessen the effect.

    // dot()s with gaussian strengths here?

    blur_ori /= 16.0;  //Divide by the number of texture fetches

    //sharp_strength1_luma *= 0.75; // Adjust strength to aproximate the strength of pattern1 2
  #endif

   /*-----------------------------------------------------------.
  /                            Sharpen                          /
  '-----------------------------------------------------------*/

  // -- Calculate the sharpening --
  float3 sharp = ori - blur_ori;  //Subtracting the blurred image from the original image

  #if 0 //New experimental limiter .. not yet finished
    float sharp_luma = dot(sharp, sharp_strength1_luma); //Calculate the luma
    sharp_luma = (abs(sharp_luma)*8.0) * exp(1.0-(abs(sharp_luma)*8.0)) * sign(sharp_luma) / 16.0; //I should probably move the strength modifier here

  #else //SweetFX 1.5.1 code
    // -- Adjust strength of the sharpening and clamp it--
    float4 sharp_strength1_luma_clamp = float4(sharp_strength1_luma * (0.5 / sharp_clamp1),0.5); //Roll part of the clamp into the dot

    //sharp_luma = saturate((0.5 / sharp_clamp1) * sharp_luma + 0.5); //scale up and clamp
    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; //scale down
  #endif

  // -- Combining the values to get the final sharpened pixel	--
  //float4 done = ori + sharp_luma;    // Add the sharpening to the original.
  inputcolor.rgb = inputcolor.rgb + sharp_luma;    // Add the sharpening to the input color.

   /*-----------------------------------------------------------.
  /                     Returning the output                    /
  '-----------------------------------------------------------*/
  #if show_sharpen1 == 1
    //inputcolor.rgb = abs(sharp * 4.0);
    inputcolor.rgb = saturate(0.5 + (sharp_luma * 4)).rrr;
  #endif

  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.20; 	
	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 GEMHD( float4 colorInput, float2 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.15 + 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));

	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, GShadowDepth); // pow - don't use fractions for HDRpower
	
	colorInput = saturate(colorInput);	

	//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.55; 					
float GGamma=1.98; 					
float GBlueShift=0.0;

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.0; //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.006;		
	float CrossSaturation2 = 1.05;	
	float CrossBrightness = 0.0025;		
	float CrossAmount = 3.0;		
	float2 crossMatrix [3] =
		{
			float2 (0.94, 0.007),
			float2 (0.945, 0.0065),
			float2 (1.055, 0.0045)
		};

		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);
	Fn = GEMSharpen1(Fn,tex);	

	Fn = GEMSharpen1(Fn,tex);
	return Fn;
}
