///////////////
//	TV-out tweaks	
//	Author: aliaspider - aliaspider@gmail.com
//	License: GPLv3      
////////////////////////////////////////////////////////


// this shader is meant to be used when running
// an emulator on a real CRT-TV @240p or @480i
////////////////////////////////////////////////////////
// Basic settings:

// signal resolution
// higher = sharper 
#pragma parameter TVOUT_RESOLUTION "TVOut Signal Resolution" 256.0 0.0 1024.0 32.0 // default, minimum, maximum, optional step

// simulate a composite connection instead of RGB
#pragma parameter TVOUT_COMPOSITE_CONNECTION "TVOut Composite Enable" 0.0 0.0 1.0 1.0

// use TV video color range (16-235) 
// instead of PC full range (0-255)
#pragma parameter TVOUT_TV_COLOR_LEVELS "TVOut TV Color Levels Enable" 0.0 0.0 1.0 1.0
////////////////////////////////////////////////////////

////////////////////////////////////////////////////////
// Advanced settings:
//
// these values will be used instead 
// if COMPOSITE_CONNECTION is defined
// to simulate different signal resolutions(bandwidth)
// for luma (Y) and chroma ( I and Q )
// this is just an approximation
// and will only simulate the low bandwidth anspect of
// composite signal, not the crosstalk between luma and chroma
// Y = 4MHz I=1.3MHz Q=0.4MHz
#pragma parameter TVOUT_RESOLUTION_Y "TVOut Luma (Y) Resolution" 256.0 0.0 1024.0 32.0
#pragma parameter TVOUT_RESOLUTION_I "TVOut Chroma (I) Resolution" 83.2 0.0 256.0 8.0
#pragma parameter TVOUT_RESOLUTION_Q "TVOut Chroma (Q) Resolution" 25.6 0.0 256.0 8.0

// formula is MHz=resolution*15750Hz
// 15750Hz being the horizontal Frequency of NTSC
// (=262.5*60Hz)
////////////////////////////////////////////////////////

#ifdef PARAMETER_UNIFORM // If the shader implementation understands #pragma parameters, this is defined.
uniform float TVOUT_RESOLUTION;
uniform float TVOUT_COMPOSITE_CONNECTION;
uniform float TVOUT_TV_COLOR_LEVELS;
uniform float TVOUT_RESOLUTION_Y;
uniform float TVOUT_RESOLUTION_I;
uniform float TVOUT_RESOLUTION_Q;
#else
// Fallbacks if parameters are not supported.
#define TVOUT_RESOLUTION 256.0 // Default
#define TVOUT_COMPOSITE_CONNECTION 0
#define TVOUT_TV_COLOR_LEVELS 0
#define TVOUT_RESOLUTION_Y 256.0
#define TVOUT_RESOLUTION_I 83.2
#define TVOUT_RESOLUTION_Q 25.6
#endif


struct input
{
    half2 video_size;
    float2 texture_size;
    half2 output_size;
};

void main_vertex
(
	float4 position	: POSITION ,
	out float4 outPosition	: POSITION ,
	float2 texCoord : TEXCOORD0 ,
	out float2 outTexCoord : TEXCOORD0 ,
    uniform half4x4 modelViewProj
)
{
    outPosition = mul(modelViewProj, position);
    outTexCoord = texCoord;
 
}
float3x3 RGB_to_YIQ = float3x3(
         0.299,0.587,0.114, 
		 0.595716,-0.274453,-0.321263,
		 0.211456,-0.522591, 0.311135);
float3x3 YIQ_to_RGB = float3x3(
         1.0,0.9563,0.6210, 
		 1.0,-0.2721,-0.6474,
		 1.0,-1.1070, 1.7046);




#define pi			3.14159265358
#define a(x) abs(x)
#define d(x,b) (pi*b*min(a(x)+0.5,1.0/b))
#define e(x,b) (pi*b*min(max(a(x)-0.5,-1.0/b),1.0/b))
#define STU(x,b) ((d(x,b)+sin(d(x,b))-e(x,b)-sin(e(x,b)))/(2.0*pi))
#define X(i) (offset-(i))
#define L(C) clamp((C -16.5/ 256.0)*256.0/(236.0-16.0),0.0,1.0)
#define LCHR(C) clamp((C -16.5/ 256.0)*256.0/(240.0-16.0),0.0,1.0)

float3 LEVELS(float3 c0)
{
   if (TVOUT_TV_COLOR_LEVELS)
   {
      if (TVOUT_COMPOSITE_CONNECTION)
         return float3(L(c0.x),LCHR(c0.y),LCHR(c0.z));
      else
         return L(c0);
   }
   else
      return c0;
}


#define GETC(c) \
   if (TVOUT_COMPOSITE_CONNECTION) \
      c = mul(RGB_to_YIQ,LEVELS(tex2D(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz)); \
   else \
      c = (LEVELS(tex2D(tex, float2(texCoord.x - X*oneT,texCoord.y)).xyz))

#define VAL(tempColor) \
   if (TVOUT_COMPOSITE_CONNECTION) \
      tempColor += float3((c.x*STU(X,(TVOUT_RESOLUTION_Y*oneI))),(c.y*STU(X,(TVOUT_RESOLUTION_I*oneI))),(c.z*STU(X,(TVOUT_RESOLUTION_Q*oneI)))); \
   else \
      tempColor += (c*STU(X,(TVOUT_RESOLUTION*oneI)))

float4 main_fragment(in float2 texCoord : TEXCOORD0 , uniform sampler2D tex : TEXUNIT0, uniform input IN) : COLOR
{
   float3 tempColor=float3(0.0,0.0,0.0);
   float	offset	= fract((texCoord.x * IN.texture_size.x) - 0.5);
   float oneT=1.0/IN.texture_size.x;
   float oneI=1.0/IN.video_size.x;

   float X;
   float3 c;

   X = X(-1);
   GETC(c);
   VAL(tempColor);

   X = X(0);
   GETC(c);
   VAL(tempColor);

   X = X(1);
   GETC(c);
   VAL(tempColor);

   X = X(2);
   GETC(c);
   VAL(tempColor);

   if (TVOUT_COMPOSITE_CONNECTION)
      tempColor=mul(YIQ_to_RGB,tempColor);
   return float4(tempColor, 1.0);
}
