/* COMPATIBILITY 
   - HLSL compilers
   - Cg   compilers
*/

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

struct out_vertex
{
#ifndef HLSL_4
	float4 Color    : COLOR;
#endif
	float4 position : COMPAT_POS;
	float2 texCoord : TEXCOORD0;
};

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;
	
	return OUT;
}

// "LeiFX" shader - "dither" and reduction process
// 
// 	Copyright (C) 2013-2014 leilei
// 
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.

// This table came from the wikipedia article about Ordered Dithering. NOT MAME.  Just to clarify.
float erroredtable[16] = {
	16,4,13,1,   
	8,12,5,9,
	14,2,15,3,
	6,10,7,11		
};


#define DITHERAMOUNT		0.5f // was 0.33f
#define DITHERBIAS		-1  // 0 to 16, biases the value of the dither up.  - was 8

#pragma parameter LEIFX_LINES "LeiFX Line Intensity" 0.05 0.00 1.00 0.01

#ifdef PARAMETER_UNIFORM
uniform float LEIFX_LINES;
#else
#define LEIFX_LINES 0.05f
#endif


float4 _3dfx_pass_0(float2 texture_size, float2 video_size, float2 output_size, COMPAT_Texture2D(decal), float2 coord)
{
   	float4 final = COMPAT_Sample(decal, coord);

	float2 res;
	res.x = texture_size.x;
	res.y = texture_size.y;
	
	float2 ditheu = coord.xy * res.xy;

	ditheu.x = coord.x * res.x;
	ditheu.y = coord.y * res.y;

	// Dither. Total rewrite.
	// NOW, WHAT PIXEL AM I!??

	int ditdex = 	int(fmod(ditheu.x, 4.0)) * 4 + int(fmod(ditheu.y, 4.0)); // 4x4!
	int3 color;
	int3 colord;
	color.r = final.r * 255;
	color.g = final.g * 255;
	color.b = final.b * 255;
	int yeh = 0;
	int ohyes = 0;


	// looping through a lookup table matrix
	//for (yeh=ditdex; yeh<(ditdex+16); yeh++) ohyes = pow(erroredtable[yeh-15], 0.72f);
	// Unfortunately, RetroArch doesn't support loops so I have to unroll this. =(
	// Dither method adapted from xTibor on Shadertoy ("Ordered Dithering"), generously
	// put into the public domain.  Thanks!
	if (yeh++==ditdex) ohyes = erroredtable[0];
	else if (yeh++==ditdex) ohyes = erroredtable[1];
	else if (yeh++==ditdex) ohyes = erroredtable[2];
	else if (yeh++==ditdex) ohyes = erroredtable[3];
	else if (yeh++==ditdex) ohyes = erroredtable[4];
	else if (yeh++==ditdex) ohyes = erroredtable[5];
	else if (yeh++==ditdex) ohyes = erroredtable[6];
	else if (yeh++==ditdex) ohyes = erroredtable[7];
	else if (yeh++==ditdex) ohyes = erroredtable[8];
	else if (yeh++==ditdex) ohyes = erroredtable[9];
	else if (yeh++==ditdex) ohyes = erroredtable[10];
	else if (yeh++==ditdex) ohyes = erroredtable[11];
	else if (yeh++==ditdex) ohyes = erroredtable[12];
	else if (yeh++==ditdex) ohyes = erroredtable[13];
	else if (yeh++==ditdex) ohyes = erroredtable[14];
	else if (yeh++==ditdex) ohyes = erroredtable[15];

	// Adjust the dither thing
	ohyes = 17 - (ohyes - 1); // invert
	ohyes *= DITHERAMOUNT;
	ohyes += DITHERBIAS;

	colord.r = color.r + ohyes;
	colord.g = color.g + (ohyes / 2);
	colord.b = color.b + ohyes;
	final.rgb = colord.rgb * 0.003921568627451; // divide by 255, i don't trust em

	//
	// Reduce to 16-bit color
	//

	float3 why = float3(1.0, 1.0, 1.0);
	float3 reduceme = float3(1.0, 1.0, 1.0);
	float radooct = 32;	// 32 is usually the proper value

	reduceme.r = pow(final.r, why.r);  
	reduceme.r *= radooct;	
	reduceme.r = int(floor(reduceme.r));	
	reduceme.r /= radooct; 
	reduceme.r = pow(reduceme.r, why.r);

	reduceme.g = pow(final.g, why.g);  
	reduceme.g *= radooct * 2;	
	reduceme.g = int(floor(reduceme.g));	
	reduceme.g /= radooct * 2; 
	reduceme.g = pow(reduceme.g, why.g);

	reduceme.b = pow(final.b, why.b);  
	reduceme.b *= radooct;	
	reduceme.b = int(floor(reduceme.b));	
	reduceme.b /= radooct; 
	reduceme.b = pow(reduceme.b, why.b);

	final.rgb = reduceme.rgb;

	// Add the purple line of lineness here, so the filter process catches it and gets gammaed.
	{
		float leifx_linegamma = (LEIFX_LINES / 10);
		float horzline1 = 	(fmod(ditheu.y, 	2.0));
		if (horzline1 < 1)	leifx_linegamma = 0;
	
		final.r += leifx_linegamma;
		final.b += leifx_linegamma;	
	}


   return final;
}

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