/*
 * sharp-bilinear.cg
 * Author: Themaister
 * License: Public domain
 * 
 * Does a bilinear stretch, with a preapplied Nx nearest-neighbor scale, giving a
 * sharper image than plain bilinear.
 */

void main_vertex
(
	float4 position	: POSITION,
	float4 color	: COLOR,
	float2 texCoord : TEXCOORD0,

   uniform float4x4 modelViewProj,

	out float4 oPosition : POSITION,
	out float2 otexCoord : TEXCOORD
)
{
	oPosition = mul(modelViewProj, position);
	otexCoord = texCoord;
}

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

#pragma parameter SHARP_BILINEAR_PRE_SCALE "Sharp Bilinear Prescale" 4.0 1.0 10.0 1.0

#ifdef PARAMETER_UNIFORM
uniform float SHARP_BILINEAR_PRE_SCALE;
#else
#define SHARP_BILINEAR_PRE_SCALE 4.0
#endif

float4 main_fragment(float2 texCoord : TEXCOORD0,
   uniform sampler2D s0 : TEXUNIT0, uniform input IN) : COLOR
{
   float2 texel = texCoord * IN.texture_size;
   float2 texel_floored = floor(texel);
   float2 s = frac(texel);
   float region_range = 0.5 - 0.5 / SHARP_BILINEAR_PRE_SCALE;

   // Figure out where in the texel to sample to get correct pre-scaled bilinear.
   // Uses the hardware bilinear interpolator to avoid having to sample 4 times manually.

   float2 center_dist = s - 0.5;
   float2 f = (center_dist - clamp(center_dist, -region_range, region_range)) * SHARP_BILINEAR_PRE_SCALE + 0.5;

   float2 mod_texel = texel_floored + f;
   return tex2D(s0, mod_texel / IN.texture_size);
}

