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

/*
 * (Inaccurate) Phosphor shader
 * Author: Themaister
 * License: Public Domain
 */

#include "../../compat_includes.inc"

#pragma parameter INPUT_GAMMA "Input Gamma" 2.4 0.0 10.0 0.01
#pragma parameter OUTPUT_GAMMA "Output Gamma" 2.2 0.0 10.0 0.01
// Used to counteract the desaturation effect of weighting.
#pragma parameter COLOR_BOOST "Color Boost" 1.45 0.0 10.0 0.01

#ifdef PARAMETER_UNIFORM
uniform float INPUT_GAMMA;
uniform float OUTPUT_GAMMA;
uniform float COLOR_BOOST;
#else
// Constants used with gamma correction.
#define INPUT_GAMMA 2.4
#define OUTPUT_GAMMA 2.2
#define COLOR_BOOST 1.45
#endif

#define GAMMA_IN(color)     pow(color, float3(INPUT_GAMMA, INPUT_GAMMA, INPUT_GAMMA))
#define GAMMA_OUT(color)    pow(color, float3(1.0 / OUTPUT_GAMMA, 1.0 / OUTPUT_GAMMA, 1.0 / OUTPUT_GAMMA))

#define TEX2D(coords)	GAMMA_IN( COMPAT_Sample(decal, coords).rgb )

struct out_vertex
{
	float4 position : COMPAT_POS;
	float2 texCoord : TEXCOORD0;

	// Extra args defined here
	float2 coord : TEXCOORD2;
	float2 coord_prev : TEXCOORD3;
	float2 coord_prev_prev : TEXCOORD4;
	float2 tex_index : TEXCOORD5;
#ifndef HLSL_4
	float4 Color    : COLOR;
#endif
};

uniform COMPAT_Texture2D(decal);
uniform float4x4 modelViewProj;

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);
	float2 one_x = float2(1.0 / (3.0 * COMPAT_texture_size.x), 0.0);
	OUT.coord = texCoord - 0.0 * one_x;
	OUT.coord_prev = texCoord - 1.0 * one_x;
	OUT.coord_prev_prev = texCoord - 2.0 * one_x;
	OUT.tex_index = texCoord * COMPAT_texture_size;
	
	return OUT;
}

float3 to_focus(float pixel)
{
   pixel = fmod(pixel + 3.0, 3.0);
   if (pixel >= 2.0) // Blue
      return float3(pixel - 2.0, 0.0, 3.0 - pixel);
   else if (pixel >= 1.0) // Green
      return float3(0.0, 2.0 - pixel, pixel - 1.0);
   else // Red
      return float3(1.0 - pixel, pixel, 0.0);
}

float4 phosphor(float2 coord, float2 coord_prev, float2 coord_prev_prev, float2 tex_index)
{
   float y = fmod(tex_index.y, 1.0);
   float intensity = exp(-0.2 * y);

   float3 color = TEX2D(coord);
   float3 color_prev = TEX2D(coord_prev);
   float3 color_prev_prev = TEX2D(coord_prev_prev);

   float pixel_x = 3.0 * tex_index.x;

   float3 focus = to_focus(pixel_x - 0.0);
   float3 focus_prev = to_focus(pixel_x - 1.0);
   float3 focus_prev_prev = to_focus(pixel_x - 2.0);

   float3 result =
      0.8 * color * focus +
      0.6 * color_prev * focus_prev +
      0.3 * color_prev_prev * focus_prev_prev;

   result = 2.3 * pow(result, float3(1.4, 1.4, 1.4));

   result *= float3( COLOR_BOOST, COLOR_BOOST, COLOR_BOOST );

   return float4(clamp( GAMMA_OUT(intensity * result), 0.0, 1.0 ), 1.0);
}

float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output
{
	return phosphor(VOUT.coord, VOUT.coord_prev, VOUT.coord_prev_prev, VOUT.tex_index);
}

COMPAT_END