#include "scattering.h"

float4x4	worldviewproj; 
float4x4	viewproj; 
float4x4	worldMatrix;
float4		lightDir;
float4		camPos;

float4		ambient;
float4		specular;
float		SpecularPower;
//float		bumpHeight = 10.0f; //brp hardcoded for now.

#define PI 3.1415926

texture2D		diffuseTexture;
texture2D		normalTexture;
texture2D		specularTexture;



sampler2D diffuseMap = sampler_state
{
    Texture		= (diffuseTexture);
    AddressU	= WRAP;
    AddressV	= WRAP;       
	MinFilter	= LINEAR;
	MagFilter	= LINEAR;
	MipFilter	= LINEAR;
    MIPMAPLODBIAS	= 0.0f;
    MAXMIPLEVEL		= 0;
    MAXANISOTROPY	= 1.0f;
};

sampler2D normalMap = sampler_state
{
    Texture		= (normalTexture);
    AddressU	= WRAP;
    AddressV	= WRAP;       
	MinFilter	= LINEAR;
	MagFilter	= LINEAR;
	MipFilter	= LINEAR;
    MIPMAPLODBIAS	= 0.0f;
    MAXMIPLEVEL		= 0;
    MAXANISOTROPY	= 1.0f;
};

sampler2D specularMap = sampler_state
{
    Texture		= (specularTexture);
    AddressU	= WRAP;
    AddressV	= WRAP;       
	MinFilter	= LINEAR;
	MagFilter	= LINEAR;
	MipFilter	= LINEAR;
    MIPMAPLODBIAS	= 0.0f;
    MAXMIPLEVEL		= 0;
    MAXANISOTROPY	= 1.0f;
};

struct VS_OUT
{
	float4	pos		:	POSITION;
	float3	N		:	TEXCOORD0;
	float2	uvDiff	:	TEXCOORD1;
	float3	T		:	TEXCOORD2;
	float3	B		:	TEXCOORD3;
	float2	uvNorm	:	TEXCOORD4;
	float2	uvSpec	:	TEXCOORD5;
	float4	vpos	:	TEXCOORD6;
	float	depth	:	TEXCOORD7;
};

VS_OUT VShader(
	float3	pos		:	POSITION	: register(v0),
	float3	N		:	NORMAL		: register(v1),		
	float2	uv0		:	TEXCOORD0	: register(v2),		//<- Diffuse 
	float3	T		:	TANGENT		: register(v3),		// in object space
	float3	B		:	BINORMAL	: register(v4),		// in object space
	float2	uv1		:	TEXCOORD1	: register(v5),		//<- Bump
	float2	uv2		:	TEXCOORD2	: register(v6)		//<- Specular
	)
{
	VS_OUT Out	= (VS_OUT)0;
	pos.xz*=3.0;//additional scale just because my puddles is too small
	Out.pos	= mul(float4(pos, 1), worldviewproj);	
	///////////////////////////////////////////////////////////////////////////////////////
        
        float4x4 worldMatrixTranspose=transpose(worldMatrix);//use intrinsic function
        Out.N = normalize(mul(N,worldMatrixTranspose));
	Out.T = normalize(mul(B,worldMatrixTranspose));//flyp B to N
	Out.B = normalize(mul(T,worldMatrixTranspose));//N to B work good

        ///////////////////////////////////////////////////////////////////////////////////////
	
	Out.uvDiff	= uv0;
	Out.uvNorm	= uv1;
	Out.uvSpec	= uv2;
	
	Out.vpos = mul(float4(pos, 1), worldMatrix);
	Out.depth = Out.pos.z;

    return Out;
}

VS_OUT VShaderInstanced(
	float3	pos		:	POSITION	: register(v0),
	float3	N		:	NORMAL		: register(v1),		
	float2	uv0		:	TEXCOORD0	: register(v2),		//<- Diffuse 
	float3	T		:	TANGENT		: register(v3),		// in object space
	float3	B		:	BINORMAL	: register(v4),		// in object space
	float2	uv1		:	TEXCOORD1	: register(v5),		//<- Bump
	float2	uv2		:	TEXCOORD2	: register(v6),		//<- Specular
	float4 row1			: TEXCOORD3,
	float4 row2			: TEXCOORD4,
	float4 row3			: TEXCOORD5,
	float4 row4			: TEXCOORD6)
{
	VS_OUT Out	= (VS_OUT)0;

        pos.xz*=3.0;//additional scale just because my puddles is too small
	float4x4 mWorld = float4x4(row1, row2, row3, row4);
	Out.vpos = mul(mWorld, float4(pos, 1));
	Out.pos = mul(Out.vpos, viewproj);
	///////////////////////////////////////////////////////////////////////

        float4x4 worldMatrixTranspose=transpose(mWorld);//use intrinsic function
        //worldMatrixTranspose[0]=float4(row1.x,row2.x,row3.x,row4.x);
        //worldMatrixTranspose[1]=float4(row1.y,row2.y,row3.y,row4.y);
        //worldMatrixTranspose[2]=float4(row1.z,row2.z,row3.z,row4.z);
        //worldMatrixTranspose[3]=float4(row1.w,row2.w,row3.w,row4.w);
        Out.N = normalize(mul(N,worldMatrixTranspose));
	Out.T = normalize(mul(B,worldMatrixTranspose));//flyp B to N
	Out.B = normalize(mul(T,worldMatrixTranspose));//N to B work good

        //////////////////////////////////////////////////////////////////
	
	Out.uvDiff	= uv0;
	Out.uvNorm	= uv1;
	Out.uvSpec	= uv2;

	Out.depth = Out.pos.z;

    return Out;
}

float2 latlong(float3 v,float halfSphereMap) 
{
  v = normalize(v);
  float theta = acos(v.y); // +y is up
  float phi = atan2(v.z, v.x)+ PI;
  return float2(phi, theta) * float2(0.1591549f, 0.3183099f*(1.0f+halfSphereMap));//*2.0 only for half spherical map(sky texture)
}

float4 PShader(
	float3	N		:	TEXCOORD0	: register(v0),
	float2	uvDiff	:	TEXCOORD1	: register(v1),
	float3	T		:	TEXCOORD2	: register(v2),
	float3	B		:	TEXCOORD3	: register(v3),
	float2	uvNorm	:	TEXCOORD4	: register(v4),
	float2	uvSpec	:	TEXCOORD5	: register(v5),
	float4	vpos	:	TEXCOORD6	: register(v6),
	float	depth	:	TEXCOORD7	: register(v7)
	) : COLOR
{	
	
	float4 bumpVector		= tex2D(normalMap,	uvNorm.xy*float2(16.0f,8.0f));
//return float4(bumpVector.xyz,1);
	float mask	= tex2D(specularMap,uvSpec.xy).a;//alpha mask

	

	float3 bumpNormal	=	bumpVector;
	bumpNormal.xyz		=	bumpNormal.xyz * 2.0 - 1.0;
        bumpNormal.xy*=0.5f;//bumpinness
	bumpNormal			=	normalize(bumpNormal);
	bumpNormal.xyz		=	bumpNormal.x * T + bumpNormal.y * B + bumpNormal.z * N;
//return float4(bumpNormal.xyz,1);//ok
	float  diff			=	max(0, dot(bumpNormal, lightDir.xyz));

	float3 E			=	normalize(camPos.xyz - vpos.xyz);//eye vector
	float3 L			=	lightDir.xyz;
	float3 H			=	normalize(E + L);
        float fresnel=1-saturate(dot(E,N));
        float kA=max(fresnel,0.5f);
        float kR=max(pow(fresnel,2),0.2f);
        //return float4(float3(fresnel.xxx),1);

////////reflect sphere mapping
/////////////////////////////////////////////////////////////////////////////////////////////////////////
        float3 R=reflect(E,bumpNormal);
//return float4(R,1);//ok
        float2 uv = latlong(R,1);//1 if halfSphereMap, 0 if fullSphereMap
        uv=float2(uv.x-0.25f,1-uv.y);//-0.25 <- 45 degree offset in long direction(x coord)
        float3 Reflection= tex2D(diffuseMap, uv);//reflect map in diffuse map slot
        Reflection*=kR;
//return float4(Reflection,1);//ok
/////////////////////////////////////////////////////////////////////////////////////////////////////////											
//return float4(Reflection,mask);


	float spec			=	pow(max(0 , dot(bumpNormal, H)) , 32)*0.5f*mask;
//return float4(spec.xxx,1);//ok	
	
        float3 color={0.2f,0.2f,0.2f};
        color=color+Reflection+spec;
	color = Scattering(vpos.xyz, camPos.xyz, lightDir.xyz, float4(color,1));
	
        float alpha=mask*kA;
	return float4(color,alpha);
}


technique Default
{
    pass Pass0
    {    
		FillMode = SOLID;
		Lighting = FALSE;
		Clipping = FALSE;
		CullMode = NONE;
		
		FogEnable	= FALSE;
		FogColor	= 0x00000000;
		FogDensity	= 1.0f;
		FogEnd		= 10000.0f;
		FogStart	= 50.0f;
				
		//Pixel Pipe Render States
		AlphaBlendEnable	= FALSE;
		AlphaRef			= 0x50;
		AlphaTestEnable		= FALSE;
		AlphaFunc			= GREATER;	
					
		ZEnable				= TRUE;
		ZWriteEnable		= TRUE;
		ZFunc				= LESSEQUAL;

		SrcBlend			= SRCALPHA;
		DestBlend			= INVSRCALPHA;

		VertexShader = compile vs_3_0 VShader();
		PixelShader  = compile ps_3_0 PShader();	
    }
}

technique Transparent
{
    pass Pass0
    {    
		FillMode = SOLID;

		Lighting	= FALSE;
		Clipping	= FALSE;
		CullMode	= NONE;

		FogEnable	= FALSE;
		FogColor	= 0x00000000;
		FogDensity	= 1.0f;
		FogEnd		= 10000.0f;
		FogStart	= 50.0f;

		AlphaBlendEnable	= TRUE;
		AlphaRef			= 100;
		AlphaTestEnable		= FALSE;		
		AlphaFunc			= GREATER;

		ZEnable				= TRUE;
		ZWriteEnable		= FALSE;
		ZFunc				= LESSEQUAL;

		SrcBlend			= SRCALPHA;
		DestBlend			= INVSRCALPHA;  

		VertexShader = compile vs_3_0 VShader();
		PixelShader  = compile ps_3_0 PShader();
    }

	pass Pass1
    {    
		FillMode	= SOLID;

		Lighting	= FALSE;
		Clipping	= FALSE;
		CullMode	= NONE;

		FogEnable	= FALSE;
		FogColor	= 0x00000000;
		FogDensity	= 1.0f;
		FogEnd		= 10000.0f;
		FogStart	= 50.0f;

		AlphaBlendEnable	= FALSE;
		AlphaRef			= 200;
		AlphaTestEnable		= TRUE;		
		AlphaFunc			= GREATEREQUAL;	

		ZEnable				= TRUE;
		ZWriteEnable		= TRUE;
		ZFunc				= LESSEQUAL;

		SrcBlend			= SRCALPHA;
		DestBlend			= INVSRCALPHA;  

		VertexShader = compile vs_3_0 VShader();
		PixelShader  = compile ps_3_0 PShader();
    }   
}

technique DefaultInstanced
{
    pass Pass0
    {    
		FillMode = SOLID;
		Lighting = FALSE;
		Clipping = FALSE;
		CullMode = NONE;
		
		FogEnable	= FALSE;
		FogColor	= 0x00000000;
		FogDensity	= 1.0f;
		FogEnd		= 10000.0f;
		FogStart	= 50.0f;
				
		//Pixel Pipe Render States
		AlphaBlendEnable	= FALSE;
		AlphaRef			= 0x50;
		AlphaTestEnable		= FALSE;
		AlphaFunc			= GREATER;	
					
		ZEnable				= TRUE;
		ZWriteEnable		= TRUE;
		ZFunc				= LESSEQUAL;

		SrcBlend			= SRCALPHA;
		DestBlend			= INVSRCALPHA;

		VertexShader = compile vs_3_0 VShaderInstanced();
		PixelShader  = compile ps_3_0 PShader();	
    }
}

technique TransparentInstanced
{
    pass Pass0
    {    
		FillMode = SOLID;

		Lighting	= FALSE;
		Clipping	= FALSE;
		CullMode	= NONE;

		FogEnable	= FALSE;
		FogColor	= 0x00000000;
		FogDensity	= 1.0f;
		FogEnd		= 10000.0f;
		FogStart	= 50.0f;

		AlphaBlendEnable	= TRUE;
		AlphaRef			= 100;
		AlphaTestEnable		= FALSE;		
		AlphaFunc			= GREATER;

		ZEnable				= TRUE;
		ZWriteEnable		= FALSE;
		ZFunc				= LESSEQUAL;

		SrcBlend			= SRCALPHA;
		DestBlend			= INVSRCALPHA;  

		VertexShader = compile vs_3_0 VShaderInstanced();
		PixelShader  = compile ps_3_0 PShader();
    }

	pass Pass1
    {    
		FillMode	= SOLID;

		Lighting	= FALSE;
		Clipping	= FALSE;
		CullMode	= NONE;

		FogEnable	= FALSE;
		FogColor	= 0x00000000;
		FogDensity	= 1.0f;
		FogEnd		= 10000.0f;
		FogStart	= 50.0f;

		AlphaBlendEnable	= FALSE;
		AlphaRef			= 200;
		AlphaTestEnable		= TRUE;		
		AlphaFunc			= GREATEREQUAL;	

		ZEnable				= TRUE;
		ZWriteEnable		= TRUE;
		ZFunc				= LESSEQUAL;

		SrcBlend			= SRCALPHA;
		DestBlend			= INVSRCALPHA;  

		VertexShader = compile vs_3_0 VShaderInstanced();
		PixelShader  = compile ps_3_0 PShader();
    }   
}
