//
// Project:
//
//   D3D RightMark
//
// Description:
//
//   Effect file for "Pixel Shading 2" test.
//
// Effect Version: 
//
//   DirectX 9.0 (Oct 2005 SDK Update)
//
// Shader Profile:
//
//   Pixel Shaders (various versions) ( HLSL )
//
//   Vertex Shaders (various versions) ( HLSL )
//

//
// Defines
//

// #define NORMALIZATION_CUBEMAP_A8R8G8B8 0
// #define NORMALIZATION_CUBEMAP_Q8W8V8U8 0
// #define SINUS_LUT 0
// #define POW_LUT 0
// #define HALF_PRECISION 0
// #define PS_VERSION ps_2_0
// #define VS_VERSION vs_2_0

#if HALF_PRECISION
   #define rm_float		half		
   #define rm_float2	vector<half, 2> 
   #define rm_float3	vector<half, 3> 
   #define rm_float4	vector<half, 4> 
   #define rm_float4x4	matrix<half, 4, 4> 
#else 
   #define rm_float		float 
   #define rm_float2	vector<float, 2> 
   #define rm_float3	vector<float, 3> 
   #define rm_float4	vector<float, 4> 
   #define rm_float4x4	matrix<float, 4, 4> 
#endif 

//
// Global Variables
//

#define rm_PI 3.141592654

rm_float4 vZero  = { 0.0,  0.0, 0.0, 0.0 };
rm_float4 vOne   = { 1.0,  1.0, 1.0, 1.0 };
rm_float4 vHalf  = { 0.5,  0.5, 0.5, 0.5 };
rm_float4 vBias  = { 2.0, -1.0, 0.5, 0.5 };

rm_float fGeometryScale = 0.01;
rm_float fParallaxOffset = 0.03;

// Lights

struct rm_light
{
	rm_float4 vPosition;

	rm_float4 vDiffuse;
	rm_float4 vSpecular;

	rm_float  fAttenuation;
};

rm_light Lights[3];

// Material

rm_float fMaterialPower = 16.0;

// Misc

rm_float4   vCameraPos;			// Camera Position

rm_float4x4 mW;					// World Matrix
rm_float4x4 mWVP;				// World * View * Projection Matrix

// Textures

texture texDiffuse;				// Diffuse Map Texture			( A8R8G8B8 format )
texture texSpecular;			// Specular Map Texture			( A8R8G8B8 format )
texture texHeight;				// Height Map Texture			( A8R8G8B8 format )
texture texNormal;				// Normal Map Texture			( Q8W8V8U8 format )

texture texNormalizationCubeMap; // Normalization CubeMap		( A8R8G8B8 or Q8W8V8U8 format )

texture texNoise; 				// Noise 3D Texture				( A8R8G8B8 format )
texture texSin;					// Sinus LUT Texture			( Q8W8V8U8 format )
texture texPow;					// Specular Power LUT Texture	( A8R8G8B8 format )
texture texLinear;				// Linear LUT Texture			( A8R8G8B8 format )

texture texEnvironment;			// Background Texture			( A8R8G8B8 format )

// Procedural Texture Variables

rm_float fFactor;
rm_float fScale;
rm_float fInitFreq;  
rm_float fFreqScale;

rm_float4 vAmp;
rm_float4 vTime;

// Misc

int nPixelShader;
int nVertexShader;

//
// Samplers
//

sampler DiffuseMapSampler = sampler_state
{
   Texture = (texDiffuse);

   MinFilter = Anisotropic;
   MagFilter = Linear;
   MipFilter = Linear;

   AddressU  = Wrap;
   AddressV  = Wrap;

   MaxAnisotropy = 16;
};

sampler NormalMapSampler = sampler_state
{
   Texture = (texNormal);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Point;

   AddressU  = Wrap;
   AddressV  = Wrap;

   MaxAnisotropy = 16;
};

sampler SpecularMapSampler = sampler_state
{
   Texture = (texSpecular);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Linear;

   AddressU  = Wrap;
   AddressV  = Wrap;

   MaxAnisotropy = 16;
};

sampler HeightMapSampler = sampler_state
{
   Texture = (texHeight);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Point;

   AddressU  = Wrap;
   AddressV  = Wrap;

   MaxAnisotropy = 16;
};

sampler NoiseSampler = sampler_state
{
   Texture = (texNoise);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Linear;

   AddressU  = Wrap;
   AddressV  = Wrap;

   MaxAnisotropy = 16;
};

sampler NormalizationCubeMapSampler = sampler_state
{
   Texture = (texNormalizationCubeMap);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Linear;

   AddressU  = Clamp;
   AddressV  = Clamp;

   MaxAnisotropy = 16;
};

sampler SinSampler = sampler_state
{
   Texture = (texSin);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = None;

   AddressU  = Wrap;
   AddressV  = Wrap;

   MaxAnisotropy = 16;
};


sampler PowSampler = sampler_state
{
   Texture = (texPow);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = None;

   AddressU  = Clamp;
   AddressV  = Clamp;

   MaxAnisotropy = 16;
};


sampler EnvironmentSampler = sampler_state
{
   Texture = (texEnvironment);

   MinFilter = Linear;
   MagFilter = Linear;
   MipFilter = Linear;

   AddressU  = Clamp;
   AddressV  = Clamp;

   MaxAnisotropy = 16;
};

//
// Shaders
//

// function used to fill the noise LUT texture ( based on Microsoft's DirectX 9.0 SDK EffectEdit demo (wood shader) )

float4 GenerateNoiseFunction(float3 Pos : POSITION) : COLOR
{
 // float4 vColor;

	float4 Noise = (float4)0;

	for (int i = 1; i < 256; i += i)
	{
		Noise.r += abs(noise(Pos * 500 * i)) / i;
		Noise.g += abs(noise((Pos + 1)* 500 * i)) / i;
		Noise.b += abs(noise((Pos + 2) * 500 * i)) / i;
		Noise.a += abs(noise((Pos + 3) * 500 * i)) / i;
	}

	return Noise;
}

// function used to fill the sin LUT texture
float4 GenerateSinFunction(float3 Pos : POSITION) : COLOR
{
	return sin( Pos.x * rm_PI * 2.0 );
}

// function used to fill the specular power LUT texture
float4 GeneratePowFunction(float3 Pos : POSITION) : COLOR
{
	return pow( Pos.x, 16.0 );
}

//
// Simple parallax mapping shader ( (c) 2004 Terry Welsh (Infiscape Corporation) )
//

struct PARALLAX_DATA
{
	rm_float4 vPosition	: POSITION;
	rm_float2 vTexCoord	: TEXCOORD0;
	rm_float3 vEye		: TEXCOORD1;
	rm_float3 vLight0	: TEXCOORD2;
	rm_float3 vLight1	: TEXCOORD3;
	rm_float3 vLight2	: TEXCOORD4;
};

PARALLAX_DATA ParallaxVS(
	rm_float4 vPosition : POSITION,
   	rm_float4 vNormal   : NORMAL,
	rm_float2 vTexCoord : TEXCOORD0,
	rm_float3 vTangent  : TEXCOORD1,
	rm_float3 vBinormal : TEXCOORD2
)
{
	PARALLAX_DATA o;

	// Tangent Space

	rm_float3 binormal = mul( vBinormal.xyz, mW );
	rm_float3 tangent  = mul( vTangent.xyz,  mW );
	rm_float3 normal   = mul( vNormal.xyz,   mW );

	// Vertex Position -> World Space

	rm_float4 vPositionWorld = mul( vPosition, mW );

	// Eye Vector

	rm_float3 eye = vCameraPos.xyz - vPositionWorld.xyz;
	o.vEye.x = dot( eye, binormal ); 
	o.vEye.y = dot( eye, tangent ); 
	o.vEye.z = dot( eye, normal ); 

	vPositionWorld *= fGeometryScale;
	
	// Light 0

	rm_float3 light0 = (Lights[0].vPosition.xyz - vPositionWorld.xyz)*Lights[0].fAttenuation;
	o.vLight0.x = dot( light0, binormal );
	o.vLight0.y = dot( light0, tangent );
	o.vLight0.z = dot( light0, normal );

	// Light 1

	rm_float3 light1 = (Lights[1].vPosition.xyz - vPositionWorld.xyz)*Lights[1].fAttenuation;
	o.vLight1.x = dot( light1, binormal );
	o.vLight1.y = dot( light1, tangent );
	o.vLight1.z = dot( light1, normal );

	// Light 2

	rm_float3 light2 = (Lights[2].vPosition.xyz - vPositionWorld.xyz)*Lights[2].fAttenuation;
	o.vLight2.x = dot( light2, binormal );
	o.vLight2.y = dot( light2, tangent );
	o.vLight2.z = dot( light2, normal );


	// Texture Coords

	o.vTexCoord  = vTexCoord;

	// Position

	o.vPosition = mul( vPosition, mWVP );

	// Finalize

	return o;
}

rm_float4 ParallaxPS ( PARALLAX_DATA In ) : COLOR
{
#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vEye = texCUBE( NormalizationCubeMapSampler, In.vEye ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vEye = texCUBE( NormalizationCubeMapSampler, In.vEye );
#else
	rm_float3 vEye = normalize( In.vEye );
#endif

	rm_float3 vHeight = tex2D( HeightMapSampler, In.vTexCoord );
	vHeight = fParallaxOffset * ( 1.0 - 2.0 * vHeight ) * vEye;
	rm_float2 vTexCoord = In.vTexCoord + vHeight.xy;

	// Bump Mapping

	rm_float3 vN = tex2D( NormalMapSampler, vTexCoord ) * 2.0 - 1.0;

	// Light 0

#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vLight0 = texCUBE( NormalizationCubeMapSampler, In.vLight0 ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vLight0 = texCUBE( NormalizationCubeMapSampler, In.vLight0 );
#else
	rm_float3 vLight0 = normalize( In.vLight0 );
#endif

	rm_float3 vHalfAngle0 = vLight0 + vEye;

#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vHalf0 = texCUBE( NormalizationCubeMapSampler, vHalfAngle0 ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vHalf0 = texCUBE( NormalizationCubeMapSampler, vHalfAngle0 );
#else
	rm_float3 vHalf0 = normalize( vHalfAngle0 );
#endif

	rm_float fNdotL0 = saturate( dot( vN.xyz, vLight0.xyz ) );
	rm_float fNdotH0 = saturate( dot( vN.xyz, vHalf0.xyz ) );

#if POW_LUT
	rm_float fSpec0 = tex2D( PowSampler, fNdotH0 );
#else
	rm_float fSpec0 = pow( fNdotH0, fMaterialPower );
#endif
	rm_float vAttenuation0 = saturate( 1.0 - dot( In.vLight0, In.vLight0 ) );
	rm_float4 vDiffuse  = Lights[0].vDiffuse * fNdotL0 * vAttenuation0;
	rm_float4 vSpecular = Lights[0].vSpecular * fSpec0 * vAttenuation0;
	
	// Light 1

#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vLight1 = texCUBE( NormalizationCubeMapSampler, In.vLight1 ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vLight1 = texCUBE( NormalizationCubeMapSampler, In.vLight1 );
#else
	rm_float3 vLight1 = normalize( In.vLight1 );
#endif

	rm_float3 vHalfAngle1 = vLight1 + vEye;

#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vHalf1 = texCUBE( NormalizationCubeMapSampler, vHalfAngle1 ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vHalf1 = texCUBE( NormalizationCubeMapSampler, vHalfAngle1 );
#else
	rm_float3 vHalf1 = normalize( vHalfAngle1 );
#endif

	rm_float fNdotL1 = saturate( dot( vN.xyz, vLight1.xyz ) );
	rm_float fNdotH1 = saturate( dot( vN.xyz, vHalf1.xyz ) );

#if POW_LUT
	rm_float fSpec1 = tex2D( PowSampler, fNdotH1 );
#else
	rm_float fSpec1 = pow( fNdotH1, fMaterialPower );
#endif
	rm_float vAttenuation1 = saturate( 1.0 - dot( In.vLight1, In.vLight1 ) );
	vDiffuse  += Lights[1].vDiffuse * fNdotL1 * vAttenuation1;
	vSpecular += Lights[1].vSpecular * fSpec1 * vAttenuation1;
	
	// Light 2

#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vLight2 = texCUBE( NormalizationCubeMapSampler, In.vLight2 ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vLight2 = texCUBE( NormalizationCubeMapSampler, In.vLight2 );
#else
	rm_float3 vLight2 = normalize( In.vLight2 );
#endif

	rm_float3 vHalfAngle2 = vLight2 + vEye;

#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 vHalf2 = texCUBE( NormalizationCubeMapSampler, vHalfAngle2 ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 vHalf2 = texCUBE( NormalizationCubeMapSampler, vHalfAngle2 );
#else
	rm_float3 vHalf2 = normalize( vHalfAngle2 );
#endif

	rm_float fNdotL2 = saturate( dot( vN.xyz, vLight2.xyz ) );
	rm_float fNdotH2 = saturate( dot( vN.xyz, vHalf2.xyz ) );

#if POW_LUT
	rm_float fSpec2 = tex2D( PowSampler, fNdotH2 );
#else
	rm_float fSpec2 = pow( fNdotH2, fMaterialPower );
#endif
	rm_float vAttenuation2 = saturate( 1.0 - dot( In.vLight2, In.vLight2 ) );
	vDiffuse  += Lights[2].vDiffuse * fNdotL2 * vAttenuation2;
	vSpecular += Lights[2].vSpecular * fSpec2 * vAttenuation2;
	
	// Finalize
	
	return vDiffuse * tex2D( DiffuseMapSampler, vTexCoord ) +
		   vSpecular * tex2D( SpecularMapSampler, vTexCoord );
}

//
// Frozen Glass Shader ( (c) 2005 Alexander Sakharoff )
//

struct FROZENGLASS_DATA
{
	rm_float4 vPosition	: POSITION;
	rm_float3 vPos		: TEXCOORD0;
	rm_float2 vTex		: TEXCOORD1;
	rm_float3 vEye		: TEXCOORD2;
	rm_float  vPhase	: TEXCOORD3;
};

FROZENGLASS_DATA FrozenGlassVS(
	rm_float4 vPosition : POSITION,
	rm_float4 vNormal   : NORMAL,
	rm_float2 vTexCoord : TEXCOORD0,
	rm_float3 vTangent  : TEXCOORD1,
	rm_float3 vBinormal : TEXCOORD2
)
{
	FROZENGLASS_DATA o;

	// Vertex Position -> World Space

	rm_float4 vPositionWorld = mul( vPosition, mW ) * fGeometryScale;

	// Eye Vector

	o.vEye = vCameraPos.xyz - vPositionWorld.xyz;

	// Position

	o.vPosition = mul( vPosition, mWVP );

	o.vPos = 0.0005 * o.vPosition.xyz;
	o.vTex = vTexCoord;
	o.vPhase = 0.1 * length( vTexCoord );

	// Finalize

	return o;
}

const rm_float fTimeNoiseCoeff = 1.0 / 35000.0;
const rm_float fTimeScaleCoeff = 1.0 / 25000.0;

rm_float4 FrozenGlassPS( FROZENGLASS_DATA vIn ) : COLOR
{
	rm_float texz = frac( vTime.w * fTimeNoiseCoeff );
	rm_float3 ntex = tex3D( NoiseSampler, rm_float3( vIn.vTex.xy, texz + vIn.vPhase ) );
	rm_float scaleCoeff = frac( vTime.w * fTimeScaleCoeff );
#if SINUS_LUT
	rm_float scaleCoeffSin = tex2D( SinSampler, rm_float2( scaleCoeff, 0 ) ).x;
#else
	rm_float scaleCoeffSin = sin( 2 * rm_PI * scaleCoeff );
#endif
	rm_float coeff = saturate( abs( scaleCoeffSin ) - 0.05 );
	rm_float scale = 0.1 * vIn.vPos.z * coeff;
	rm_float3 pos = vIn.vPos + scale * ( tex3D( NoiseSampler, ntex ) * 2.0 - 1.0 );
#if NORMALIZATION_CUBEMAP_A8R8G8B8
	rm_float3 E = texCUBE( NormalizationCubeMapSampler, vIn.vEye ) * 2.0 - 1.0;
#elif NORMALIZATION_CUBEMAP_Q8W8V8U8
	rm_float3 E = texCUBE( NormalizationCubeMapSampler, vIn.vEye );
#else
	rm_float3 E = normalize( vIn.vEye );
#endif
	rm_float3 vR = reflect( E, ntex );
	rm_float fRdotE = dot( E, vR );
	rm_float highlight = 
#if POW_LUT
		tex2D( PowSampler, fRdotE );
#else
		pow( fRdotE, fMaterialPower );
#endif
	highlight *= pow( coeff, 8.0 );
	coeff = max( 0.4, coeff );
	rm_float whiteSize = 0.5 - 0.011 * coeff;
	rm_float2 tex = abs( frac( vIn.vTex ) - 0.5 ) - whiteSize;
	rm_float whiteness = saturate( tex.x * tex.y / ( 0.5 - whiteSize ) );
	return lerp( 1, texCUBE( EnvironmentSampler, pos ), whiteness ) + highlight;
}

VertexShader vsArray[2] = 
{ 
		compile vs_2_0 FrozenGlassVS(),
		compile vs_2_0 ParallaxVS(),
}; 

PixelShader psArray[2] = 
{ 
		compile ps_2_0 FrozenGlassPS(),
		compile ps_2_0 ParallaxPS(),
}; 

//
// Default Technique
//

technique TDefault
{   
	pass p0
	{
		PixelShader = ( psArray[nPixelShader] );
		VertexShader = ( vsArray[nVertexShader] );
	}
}