/*
 * 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.
 */
 
/* COMPATIBILITY 
   - HLSL compilers
   - Cg   compilers
   - FX11 compilers
*/

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

struct out_vertex
{
	float4 position : COMPAT_POS;
	float2 texCoord : TEXCOORD0;
	float2 precalc_texel : TEXCOORD1;
	float2 precalc_scale : TEXCOORD2;
#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;
	OUT.precalc_texel = texCoord * COMPAT_texture_size.xy;
	OUT.precalc_scale = max(floor(COMPAT_output_size.xy / COMPAT_video_size.xy), float2(1.0, 1.0));
	
	return OUT;
}

#pragma parameter SHARP_BILINEAR_PRE_SCALE "Sharp Bilinear Prescale" 4.0 1.0 10.0 1.0
#pragma parameter AUTO_PRESCALE "Automatic Prescale" 1.0 0.0 1.0 1.0

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

float4 sharp_bilinear(float2 texture_size, float2 video_size, float2 output_size, float2 texCoord, COMPAT_Texture2D(decal), float2 precalc_texel, float2 precalc_scale)
{
   float2 texel = precalc_texel;//texCoord * texture_size;
//   float2 texel_floored = floor(texel);
//   float scale = (AUTO_PRESCALE > 0.5) ? floor(output_size.y / video_size.y) : SHARP_BILINEAR_PRE_SCALE;
   float2 scale = precalc_scale;
   float2 texel_floored = floor(texel);
   float2 s = frac(texel);
   float2 region_range = 0.5 - 0.5 / 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)) * scale + 0.5;

   float2 mod_texel = texel_floored + f;
   return COMPAT_Sample(decal, mod_texel / texture_size);
}

float4 main_fragment(COMPAT_IN_FRAGMENT) : COMPAT_Output
{
	return sharp_bilinear(COMPAT_texture_size, COMPAT_video_size, COMPAT_output_size, VOUT.texCoord, decal, VOUT.precalc_texel, VOUT.precalc_scale);
}
COMPAT_END
