//////// CONNECTOR DATA STRUCTURES ///////////

/* data from application vertex buffer */
struct appdata {
    float3 Position	: POSITION;
    float4 Color	: COLOR;
    float4 ModelUV		: TEXCOORD0;
    float3 Normal	: NORMAL;
    float3 Tangent	: TANGENT0;
};


/* data passed from vertex shader to pixel shader */
struct vertexOutputPrecise {
    float4 HPosition	: POSITION;
    float4 Color		: COLOR;		
    float3 ModelUV		: TEXCOORD0;
    float4 TextureUVW   : TEXCOORD1;
    float3 Light0Vec	: TEXCOORD2;
    float3 Light1Vec	: TEXCOORD3;
    float3 WorldNormal	: TEXCOORD4;
    float3 WorldTangent	: TEXCOORD5;
    float3 WorldBinormal : TEXCOORD6;
    float3 WorldView	: TEXCOORD7;
};

struct vertexOutputSimple {
    float4 HPosition	: POSITION;
    float4 DiffuseContrib : COLOR;
    float3 ModelUV		: TEXCOORD0;
    float3 Light0Vec	: TEXCOORD1;
    float3 WorldNormal	: TEXCOORD2;
    float4 WorldView	: TEXCOORD3; // w = view space depth for SSAO
    float Fresnel		: TEXCOORD4;
};

struct vertexOutputGBuffer {
    float4 HPosition	: POSITION;
    float4 DiffuseContrib : COLOR;
    float3 ModelUV		: TEXCOORD0;
    float3 Light0Vec	: TEXCOORD1;
    float3 WorldNormal	: TEXCOORD2;
    float3 WorldView	: TEXCOORD3;
    float Fresnel		: TEXCOORD4;
    float3 oViewPos		: TEXCOORD5;
    float3 oNormal		: TEXCOORD6;
};

#ifdef FXCOMPOSER_VERSION // in fxcompser editor
#include "include/common.cgh"
#else
#include "common.cgh"
#endif

///////// VERTEX SHADING /////////////////////


/*********** Generic Vertex Shader ******/

vertexOutputSimple plastic_vp_simple(appdata IN,
	uniform float4x4 WorldITXf, // our four standard "untweakable" xforms
	uniform float4x4 WorldXf,
	uniform float4x4 ViewIXf,
	uniform float4x4 WvpXf,
	uniform float4x4 WvXf,	
	uniform float4 Lamp0Pos,
	uniform float4 Lamp1Pos,
	uniform float Kr,
	uniform float FresnelMin,
	uniform float FresnelExp,
	uniform float3 Lamp0Color,
	uniform float3 Lamp1Color,
	uniform float3 AmbiColor
	) {
    vertexOutputSimple OUT = (vertexOutputSimple)0;

#ifdef FXCOMPOSER_VERSION // in fxcompser editor
	IN.Color = float4(gSurfaceColor,1);
#endif
	
	float3 diffuseContrib;
	float3 ignore;
	
	float3 worldView;
	
	vs_shared_lighting_diffuse(
		IN.Position,
		IN.Normal,
		IN.Tangent,
		IN.Color.xyz,
    	WorldITXf, // our four standard "untweakable" xforms
		WorldXf,
		ViewIXf,
		WvpXf,
    	Lamp0Pos,
    	Lamp1Pos,
		Lamp0Color,
		Lamp1Color,
		AmbiColor,
		OUT.Light0Vec,
		diffuseContrib,
		worldView,
		OUT.HPosition,
		OUT.WorldNormal,
		ignore,
		ignore);


	OUT.WorldView.xyz = worldView;
	OUT.DiffuseContrib = float4(diffuseContrib, IN.Color.w); // keep input color alpha
	
	OUT.ModelUV = IN.ModelUV.xyz;
	
	OUT.WorldView.w = -vs_compute_gbuffer_depth(IN.Position, WvXf) / GBUFFER_MAX_DEPTH;


#ifdef ENABLE_FRESNEL
	float3 Nn = normalize(OUT.WorldNormal);
    float3 Vn = normalize(OUT.WorldView);
    float KrMin = (Kr * FresnelMin);
    float InvFrExp = (1.0/FresnelExp);
    OUT.Fresnel = lerp(Kr,KrMin,pow(abs(dot(Nn,Vn)),InvFrExp));
#else
	OUT.Fresnel = Kr * FresnelMin * 2;
#endif
	
    return OUT;
}

void plastic_fp_simple(vertexOutputSimple IN,
		uniform float3 Lamp0Color,
		uniform float Ks,
		uniform float SpecExpon,
		uniform float Kr,
		uniform sampler2D StudsSampler,		
		uniform samplerCUBE EnvSampler,
		uniform float4 FogParams,
		uniform float4 FogColour,
#ifdef GBUFFER		
		out float4 oColor1 : COLOR1,
#endif
		out float4 oColor : COLOR0
)
{
#ifdef ENABLE_STUDS
	float4 StudShade = tex2D(StudsSampler, IN.ModelUV.xy);
#endif
	
    float3 specContrib;
    float3 reflContrib;
    float3 result;

	float3 fresnel = IN.Fresnel;
	
	ps_shared_lighting_env_specularonly(
				IN.WorldNormal, IN.WorldView, IN.Light0Vec,
				Lamp0Color, // use lamp0Color as specular.
				Ks, SpecExpon, Kr,
				specContrib,
				EnvSampler,
				reflContrib);

	float3 diffContrib;
#ifdef ENABLE_STUDS
	diffContrib = lerp(IN.DiffuseContrib.xyz, StudShade.xyz, StudShade.w);
#else
	diffContrib = IN.DiffuseContrib.xyz;
#endif
	result = diffContrib + specContrib; 
	
#ifdef ENABLE_REFLECTIONS
	result = lerp(result, reflContrib, fresnel);
#endif
	
	float fogAlpha = clamp( ( FogParams.z - ( IN.WorldView.w * 500.0 ) ) * FogParams.w, 0.0, 1.0 );
	
	oColor = float4( result, IN.DiffuseContrib.a ); 
	oColor = lerp( FogColour, oColor, fogAlpha );
    
	#ifdef GBUFFER
		oColor1 = packDeferred( lerp( 1.0, IN.WorldView.w, fogAlpha ), diffContrib, specContrib );
	#endif
}


vertexOutputPrecise plastic_vp_precise(appdata IN,
	uniform float4x4 WorldITXf, // our four standard "untweakable" xforms
	uniform float4x4 WorldXf,
	uniform float4x4 ViewIXf,
	uniform float4x4 WvpXf,
	uniform float4x4 WvXf,	
	uniform float4 Lamp0Pos,
	uniform float4 Lamp1Pos) {
    vertexOutputPrecise OUT = (vertexOutputPrecise)0;
	
	vs_shared_lighting(
		IN.Position,
		IN.Normal,
		IN.Tangent,
    	WorldITXf, // our four standard "untweakable" xforms
		WorldXf,
		ViewIXf,
		WvpXf,
    	Lamp0Pos,
    	Lamp1Pos,
		OUT.Light0Vec,
		OUT.Light1Vec,
		OUT.WorldView,
		OUT.HPosition,
		OUT.WorldNormal,
		OUT.WorldTangent,
		OUT.WorldBinormal);
	
	OUT.ModelUV = IN.ModelUV.xyz;
	OUT.TextureUVW = float4(IN.Position.xyz, 0);
#ifdef FXCOMPOSER_VERSION // in fxcompser editor
	OUT.Color = float4(gSurfaceColor,1);
#else
	OUT.Color = IN.Color;
#endif
	OUT.TextureUVW.w = -vs_compute_gbuffer_depth(IN.Position, WvXf) / GBUFFER_MAX_DEPTH;
	
    return OUT;
}

///////// PIXEL SHADING //////////////////////

float3 rebase(float3 v, float3 xrow, float3 yrow, float3 zrow)
{
	//todo: faster? put in matrix, then mul? or just mul?
 	return v.x*xrow +  // normal mapping had this at -, why?
		   v.y*yrow + 
		   v.z*zrow;		
}

void plastic_fp_precise(vertexOutputPrecise IN,
		uniform float Ks,
		uniform float SpecExpon,
		uniform float Kr,
		uniform float FresnelMin,
		uniform float FresnelExp,
		uniform sampler2D StudsSampler,		
		uniform samplerCUBE EnvSampler,
		uniform float3 Lamp0Color,
		uniform float3 Lamp1Color,
		uniform float3 AmbiColor,
		uniform float4 FogParams,
		uniform float4 FogColour,
#ifdef GBUFFER		
		out float4 oColor1 : COLOR1,
#endif
		out float4 oColor : COLOR0
) {
#ifdef ENABLE_STUDS
	float4 StudShade = tex2D(StudsSampler, IN.ModelUV.xy);
#endif
	
    float3 diffContrib;
    float3 specContrib;
    float3 reflContrib;
	float3 result;

#ifdef ENABLE_FRESNEL
	float3 Nn = normalize(IN.WorldNormal);
    float3 Vn = normalize(IN.WorldView);
    float KrMin = (Kr * FresnelMin);
    float InvFrExp = (1.0/FresnelExp);
    float fresnel = lerp(Kr,KrMin,pow(abs(dot(Nn,Vn)),InvFrExp));
#else
	float fresnel = FresnelMin*Kr;	
#endif
	
	ps_shared_lighting_env(IN.Color.xyz, 
				IN.WorldNormal, IN.WorldView, IN.Light0Vec, IN.Light1Vec,
				Lamp0Color, Lamp1Color,
				AmbiColor,
				Ks, SpecExpon, Kr,
				diffContrib,specContrib
				,EnvSampler
				,reflContrib
				);
				
#ifdef ENABLE_STUDS
	diffContrib = lerp(diffContrib, StudShade.xyz, StudShade.w);
#endif

	result = diffContrib;
	result += specContrib; 
	
#ifdef ENABLE_REFLECTIONS
	result = lerp(result, reflContrib, fresnel);
#endif

	float fogAlpha = clamp( ( FogParams.z - ( IN.TextureUVW.w * 500.0 ) ) * FogParams.w, 0.0, 1.0 );
	
	oColor = float4( result, IN.Color.a ); 
	oColor = lerp( FogColour, oColor, fogAlpha );
    
	#ifdef GBUFFER
		oColor1 = packDeferred( lerp( 1.0, IN.TextureUVW.w, fogAlpha ), diffContrib, specContrib );
	#endif
}

