#include "common.h"

TEX_DECLARE2D(tex, 0);
TEX_DECLARE2D(cstrip, 1);
TEX_DECLARE2D(astrip, 2);

uniform float4 throttleFactor; // .x = alpha cutoff, .y = alpha boost (clamp), .w - additive/alpha ratio for Crazy shaders
uniform float4 modulateColor;
uniform float4 zOffset;

struct VS_INPUT
{
	float4 pos : POSITION;
	ATTR_INT4 scaleRotLife : TEXCOORD0; // transform matrix
	ATTR_INT2 disp  : TEXCOORD1; // .xy = corner, either (0,0), (1,0), (0,1), or (1,1)
	ATTR_INT2 cline:  TEXCOORD2; // .x = color line [0...32767]
};

struct VS_OUTPUT
{
	float4 pos   : POSITION;
	float3 uvFog : TEXCOORD0;
	float2 colorLookup : TEXCOORD1;
};

float4 rotScale( float4 scaleRotLife )
{
	float cr = cos( scaleRotLife.z );
	float sr = sin( scaleRotLife.z );

	float4 r;
	r.x = cr  * scaleRotLife.x;
	r.y = -sr * scaleRotLife.x;
	r.z =  sr * scaleRotLife.y;
	r.w =  cr * scaleRotLife.y;
	
	return r;
}

float4 mulq( float4 a, float4 b )
{
	float3 i = cross( a.xyz, b.xyz )  + a.w * b.xyz + b.w * a.xyz;
	float  r = a.w * b.w - dot( a.xyz, b.xyz );
	return float4( i, r );
}

float4 conj( float4 a ) { return float4( -a.xyz, a.w ); }

float4 rotate( float4 v, float4 q ) 
{
	return mulq( mulq( q, v ), conj( q ) );
}

float4 axis_angle( float3 axis, float angle )
{
	return float4( sin(angle/2) * axis, cos(angle/2) );
}

VS_OUTPUT vs( VS_INPUT input )
{
	VS_OUTPUT o;
	
	float4 pos  = float4( input.pos.xyz, 1 );
	float2 disp = input.disp.xy * 2 - 1; // -1..1

	float4 scaleRotLifeFlt = (float4)input.scaleRotLife * float4( 1.0/256.0f, 1.0/256.0f, 2.0 * 3.1415926f / 32767.0, 1.0 / 32767.0f );
	
	float4 rs = rotScale( scaleRotLifeFlt );

	pos += G(ViewRight) * dot( disp, rs.xy );
	pos += G(ViewUp) * dot( disp, rs.zw );

        float4 pos2 = pos + G(ViewDir)*zOffset.x; // Z-offset position in world space

        o.pos = mul( G(ViewProjection), pos );
	
	o.uvFog.xy = input.disp.xy;
	o.uvFog.y = 1 - o.uvFog.y;
	o.uvFog.z = (G(FogParams).z - o.pos.w) * G(FogParams).w;
	
	o.colorLookup.x = 1 - max( 0, min(1, scaleRotLifeFlt.w ) );
	o.colorLookup.y = (float)input.cline.x * (1.0 / 32767.0f);


        pos2 = mul( G(ViewProjection), pos2 ); // Z-offset position in clip space
        o.pos.z = pos2.z * o.pos.w/pos2.w;     // Only need z
        

	return o;
}


float4 psAdd( VS_OUTPUT input ) : COLOR0 // #0
{
	float4 texcolor = tex2D( tex, input.uvFog.xy );
	float4   vcolor = tex2D( cstrip, input.colorLookup.xy );
           vcolor.a = tex2D( astrip, input.colorLookup.xy ).r;
	
	float4 result;

	result.rgb = (texcolor.rgb + vcolor.rgb) * modulateColor.rgb;
	result.a   = texcolor.a   * vcolor.a;
	result.rgb *= result.a;

	result.rgb = lerp( 0.0f.xxx, result.rgb, saturate( input.uvFog.zzz ) );
	return result;
}

float4 psModulate( VS_OUTPUT input ) : COLOR0 // #1
{

	float4 texcolor = tex2D( tex, input.uvFog.xy );
	float4   vcolor = tex2D( cstrip, input.colorLookup.xy ) * modulateColor;
           vcolor.a = tex2D( astrip, input.colorLookup.xy ).r * modulateColor.a;

	float4 result;

	result.rgb = texcolor.rgb * vcolor.rgb;
	result.a   = texcolor.a   * vcolor.a;
	
	result.rgb = lerp( G(FogColor).rgb, result.rgb, saturate( input.uvFog.zzz ) );
	return result;
}

	
// - this shader is crazy
// - used instead of additive particles to help see bright particles (e.g. fire) on top of extremely bright backgrounds 
// - requires ONE | INVSRCALPHA blend mode, useless otherwise
// - does not use color strip texture
// - outputs a blend between additive blend and alpha blend in fragment alpha
// - ratio multiplier is in throttleFactor.w
float4 psCrazy( VS_OUTPUT input ) : COLOR0
{
	float4  texcolor = tex2D( tex, input.uvFog.xy );
	float4  vcolor   = float4(1,0,0,0); //tex2D( cstrip, input.colorLookup.xy ); // not actually used
            vcolor.a = tex2D( astrip, input.colorLookup.xy ).r;
	float   blendRatio = throttleFactor.w; // yeah yeah
	
	float4 result;

	result.rgb = (texcolor.rgb ) * modulateColor.rgb  * vcolor.a * texcolor.a;
	result.a   = blendRatio * texcolor.a  * vcolor.a;

	result = lerp( 0.0f.xxxx, result, saturate( input.uvFog.zzzz ) );
	return result;
}

float4 psCrazySparkles( VS_OUTPUT input ) : COLOR0
{
	float4  texcolor = tex2D( tex, input.uvFog.xy );
	float4  vcolor   = tex2D( cstrip, input.colorLookup.xy );
            vcolor.a = tex2D( astrip, input.colorLookup.xy ).r;
	float   blendRatio = throttleFactor.w;
	
	float4 result;

	if( texcolor.a < 0.5f )
	{
		result.rgb = vcolor.rgb * modulateColor.rgb * (2 * texcolor.a);
	}
	else
	{
		result.rgb = lerp( vcolor.rgb * modulateColor.rgb, texcolor.rgb, 2*texcolor.a-1 );
	}
	
	//vcolor.a   *= modulateColor.a;
	result.rgb *= vcolor.a;
	result.a    = blendRatio * texcolor.a * vcolor.a;
	
	result = lerp( 0.0f.xxxx, result, saturate( input.uvFog.zzzz ) );
	return result;
}


///////////////////////////////////////////////////////////////////////////////////

struct VS_INPUT2
{
	float4 pos : POSITION;
	ATTR_INT4 scaleRotLife : TEXCOORD0; // transform matrix
	ATTR_INT2 disp  : TEXCOORD1; // .xy = corner, either (0,0), (1,0), (0,1), or (1,1)
	ATTR_INT2 cline:  TEXCOORD2; // .x = color line [0...32767]
	ATTR_INT4 color: TEXCOORD3; // .xyzw
};

struct VS_OUTPUT2
{
	float4 pos   : POSITION;
	float3 uvFog : TEXCOORD0;
	float4 color : TEXCOORD1;
};

VS_OUTPUT2 vsCustom( VS_INPUT2 input )
{
	VS_OUTPUT2 o;
	
	float4 pos  = input.pos;
	float2 disp = input.disp.xy * 2 - 1; // -1..1

	float4 scaleRotLifeFlt = (float4)input.scaleRotLife * float4( 1.0/256.0f, 1.0/256.0f, 2.0 * 3.1415926f / 32767.0, 1.0 / 32767.0f );
	
	float4 rs = rotScale( scaleRotLifeFlt );

	pos += G(ViewRight) * dot( disp, rs.xy );
	pos += G(ViewUp) * dot( disp, rs.zw );
	
       float4 pos2 = pos + G(ViewDir)*zOffset.x; // Z-offset position in world space

	o.pos = mul( G(ViewProjection), pos );
	
	o.uvFog.xy = input.disp.xy;
	o.uvFog.y = 1 - o.uvFog.y;
	o.uvFog.z = (G(FogParams).z - o.pos.w) * G(FogParams).w;
	
	o.color = input.color * (1/255.0f);
       
		pos2 = mul( G(ViewProjection), pos2 ); // Z-offset position in clip space
        o.pos.z = pos2.z * o.pos.w/pos2.w;     // Only need z

	
	return o;
}

float4 psCustom( VS_OUTPUT2 input ) : COLOR0 // #1
{
	float4  texcolor = tex2D( tex, input.uvFog.xy );
	float4  vcolor   = input.color;

	float   blendRatio = throttleFactor.w; // yeah yeah
	
	float4 result;

	result.rgb = texcolor.rgb * vcolor.rgb * vcolor.a * texcolor.a;
	result.a   = blendRatio * texcolor.a  * vcolor.a;

	result = lerp( 0.0f.xxxx, result, saturate( input.uvFog.zzzz ) );
	return result;
}
