#pragma parameter WIDTH "Side-by-Side Image Width" 2.5 1.0 5.0 0.05
#pragma parameter HEIGHT "Side-by-Side Image Height" 1.25 0.5 1.75 0.005
#pragma parameter HORIZ "Right Eye X" 0.5 -2.0 2.0 0.005
#pragma parameter BOTH "Both Eye X" 0.13 -1.0 1.0 0.005
#pragma parameter VERT "Both Eye Y" 0.055 0.0 0.5 0.005
#pragma parameter R "Curvature Radius" 0.55 0.5 2.0 0.05
#pragma parameter DEPTH "Faux 3D Depth" 1.5 0.0 10.0 0.25
#pragma parameter PINCUSHION "Pincushion" 0.0 0.0 1.0 1.0
#ifdef PARAMETER_UNIFORM
uniform float WIDTH;
uniform float HORIZ;
uniform float BOTH;
uniform float VERT;
uniform float HEIGHT;
uniform float R;
uniform float TOGGLE;
uniform float DEPTH;
uniform float PINCUSHION;
#else
#define WIDTH 2.5
#define HORIZ 0.5
#define BOTH 0.13
#define VERT 0.055
#define HEIGHT 1.25
#define R 0.55
#define DEPTH 1.5
#define PINCUSHION 1.0
#endif

/* COMPATIBILITY 
   - HLSL compilers
   - Cg   compilers
   - FX11 compilers
*/

#include "../compat_includes.inc"
uniform COMPAT_Texture2D(decal) : TEXUNIT0;
uniform float4x4 modelViewProj;

#define overscan_x 100.0
#define overscan_y 100.0
#define d 6.0
#define x_tilt 0.0
#define y_tilt 0.0

#define FIX(c) max(abs(c), 1e-5);
  
static float2 aspect = float2(1.0, 1.0);

float intersect(float2 xy, float2 sinangle, float2 cosangle)
{
	float A = dot(xy,xy)+d*d;
	float B = 2.0*(R*(dot(xy,sinangle)-d*cosangle.x*cosangle.y)-d*d);
	float C = d*d + 2.0*R*d*cosangle.x*cosangle.y;
	return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}

float2 bkwtrans(float2 xy, float2 sinangle, float2 cosangle)
{
	float c = intersect(xy, sinangle, cosangle);
	float2 _point = float2(c,c)*xy;
	_point -= float2(-R,-R)*sinangle;
	_point /= float2(R,R);
	float2 tang = sinangle/cosangle;
	float2 poc = _point/cosangle;
	float A = dot(tang,tang)+1.0;
	float B = -2.0*dot(poc,tang);
	float C = dot(poc,poc)-1.0;
	float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
	float2 uv = (_point-a*sinangle)/cosangle;
	float r = FIX(R*acos(a));
	return uv*r/sin(r/R);
}
   
float2 fwtrans(float2 uv, float2 sinangle, float2 cosangle)
{
	float r = FIX(sqrt(dot(uv,uv)));
	uv *= sin(r/R)/r;
	float x = 1.0-cos(r/R);
	float D = d/R + x*cosangle.x*cosangle.y+dot(uv,sinangle);
	return d*(uv*cosangle-x*sinangle)/D;
}
	
float3 maxscale(float2 sinangle, float2 cosangle)
{
	float2 c = bkwtrans(-R * sinangle / (1.0 + R/d*cosangle.x*cosangle.y), sinangle, cosangle);
	float2 a = float2(0.5,0.5)*aspect;
	float2 lo = float2(fwtrans(float2(-a.x,c.y), sinangle, cosangle).x,
		fwtrans(float2(c.x,-a.y), sinangle, cosangle).y)/aspect;
	float2 hi = float2(fwtrans(float2(+a.x,c.y), sinangle, cosangle).x,
		fwtrans(float2(c.x,+a.y), sinangle, cosangle).y)/aspect;
	return float3((hi+lo)*aspect*0.5,max(hi.x-lo.x,hi.y-lo.y));
}

struct out_vertex
{
	float4 position : COMPAT_POS;
	float2 texCoord : TEXCOORD0;
	float3 stretch  : TEXCOORD1;
	float2 sinangle : TEXCOORD2;
	float2 cosangle : TEXCOORD3;
#ifndef HLSL_4
	float4 Color    : COLOR;
#endif
};

out_vertex main_vertex(COMPAT_IN_VERTEX)
{
	out_vertex OUT;
#ifdef HLSL_4
	float4 position = VIN.position;
	float2 texCoord = VIN.texCoord;
#else
	OUT.Color = color;
#endif
	OUT.position = mul(modelViewProj, position);
	OUT.texCoord = texCoord * float2(WIDTH, HEIGHT) - float2(BOTH, VERT);
	float2 sin_angle = sin(float2(x_tilt, y_tilt));
    float2 cos_angle = cos(float2(x_tilt, y_tilt));
	OUT.stretch = maxscale(sin_angle, cos_angle);
	OUT.sinangle = sin_angle;
	OUT.cosangle = cos_angle;
	
	return OUT;
}

float3x3 RGB_to_YIQ = float3x3(
         0.299,0.587,0.114, 
		 0.595716,-0.274453,-0.321263,
		 0.211456,-0.522591, 0.311135);
		 
#define fragcoord1 (xy.xy * (texture_size.xy / video_size.xy))
#define fragcoord2 (xy2.xy * (texture_size.xy / video_size.xy))

float4 sbs(float2 texture_size, float2 video_size, float3 stretch, float2 sinangle, float2 cosangle, float2 texCoord, COMPAT_Texture2D(decal))
{
	float2 xy = 0.0;
	if (PINCUSHION > 0.5)
	{
		float2 cd = texCoord;
		cd *= texture_size / video_size;
		cd = (cd-float2(0.5,0.5))*aspect*stretch.z+stretch.xy;
		xy =  (bkwtrans(cd, sinangle, cosangle)/float2(overscan_x / 100.0, overscan_y / 100.0)/aspect+float2(0.5,0.5)) * video_size / texture_size;
	}
	else xy = texCoord;
	float luma1 = mul(COMPAT_Sample(decal, xy).rgb, RGB_to_YIQ).r;
	float2 xyoffset = DEPTH * float2((1.0 - luma1) / texture_size.x, 0.0);
				
	float2 xy2 = 0.0;
	if (PINCUSHION > 0.5)
	{
		float2 cd2 = texCoord - float2(HORIZ * 512.0 / texture_size.x, 0.0);
		cd2 *= texture_size / video_size;
		cd2 = (cd2-float2(0.5,0.5))*aspect*stretch.z+stretch.xy;
		xy2 =  (bkwtrans(cd2, sinangle, cosangle)/float2(overscan_x / 100.0, overscan_y / 100.0)/aspect+float2(0.5,0.5)) * video_size / texture_size;
	}
	else xy2 = texCoord - float2(HORIZ * 512.0 / texture_size.x, 0.0);
	float luma2 = mul(COMPAT_Sample(decal, xy2).rgb, RGB_to_YIQ).r;
	float2 xyoffset2 = DEPTH * float2((1.0 - luma2,1.0 - luma2) / texture_size.x, 0.0);
	
	float4 leftimage = float4(COMPAT_Sample(decal, xy).rgb, luma1);
	float4 leftoffset = COMPAT_Sample(decal, xy - xyoffset);
	leftoffset.a = mul(leftoffset.rgb, RGB_to_YIQ).r;
	float4 rightimage = float4(COMPAT_Sample(decal, xy2).rgb, luma2);
	float4 rightoffset = COMPAT_Sample(decal, xy2 + xyoffset2);
	rightoffset.a = mul(rightoffset.rgb, RGB_to_YIQ).r;
				
	float4 left = ((lerp(leftimage, leftoffset, leftoffset.a)));// + leftimage) / 2.0;
	float4 right = ((lerp(rightimage, rightoffset, rightoffset.a)));// + rightimage) / 2.0;

	return left + right;
}

float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output
{
	return sbs(COMPAT_texture_size, COMPAT_video_size, VOUT.stretch, VOUT.sinangle, VOUT.cosangle, VOUT.texCoord, decal);
}
COMPAT_END