/*********************************************************************NVMH3****

Sky
******************************************************************************/

#define BONEMODE_4x3 1

#include "..\mrt.fx"
#include "..\generic.fx"
#include "..\GameLights.fx"


float4x4 viewProj : ViewProjection;
float4x4 world : World;
float3 campos : CAMERAPOS;

// Optional darkSphere
float3 DarkSpherePos : DarkSpherePos;
float4 DarkSphereColorModulate : DarkSphereColorModulate;
float DarkSphereRange : DarkSphereRange;
float DarkSphereFalloff : DarkSphereFalloff;

float FinalColorModulate : FinalColorModulate;

float4x4 UVTransform0 : UVTransform0;
float4x4 UVTransform1 : UVTransform1;

float2 UVScale0 : UVScale0; // should be part of UVTransform0
float2 UVScale1 : UVScale1;

float4 ColorModulate0 : ColorModulate0;
float4 ColorModulate1 : ColorModulate1;

float TaggedBloom : TaggedBloom;

float BlendAmount : BlendAmount;
float UseDiffuse : UseDiffuse;
float BlendType : BlendType;

float FresnelModulate : FresnelModulate;
float FresnelIndex : FresnelIndex;
float FresnelExponent : FresnelExponent;


//texture DiffuseTexture : DiffuseTexture;
texture PrimaryDiffuseTexture : PrimaryDiffuseTexture;
sampler DiffuseTextureSampler = sampler_state 
{
  //  texture = <DiffuseTexture>;
    texture = <PrimaryDiffuseTexture>;
    AddressU  = WRAP;        
    AddressV  = WRAP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

texture Texture2 : Texture2;
sampler Texture2Sampler = sampler_state 
{
    texture = <Texture2>;
    AddressU  = WRAP;        
    AddressV  = WRAP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

struct vertexInput{
    float4 position				: POSITION;
    float3 normal				: NORMAL;
    float2 texCoordDiffuse		: TEXCOORD0;
};

struct vertexOutput {
    float4 hPosition		: POSITION;
    float2 texCoordDiffuse	: TEXCOORD0;
    float2 texCoordDiffuse2	: TEXCOORD1;
    float3 posWorld         : TEXCOORD2;
    float3 normalWorld      : TEXCOORD3;
    float  distanceToCam    : TEXCOORD4;
};

vertexOutput VS_Transform(vertexInput IN) 
{
    float4 pos;
    vertexOutput OUT;
    
    pos = mul(IN.position, world);    
    OUT.posWorld = pos;
    OUT.hPosition = mul( pos , viewProj);       
     
    float4 baseUVs = float4(IN.texCoordDiffuse.x,IN.texCoordDiffuse.y,0,1);
    float2 coords0 = mul( baseUVs, UVTransform0 );
    coords0 *= UVScale0;
	OUT.texCoordDiffuse = coords0;
    
    float2 coords1 = mul( baseUVs, UVTransform1 );
    coords1 *= UVScale1;
	OUT.texCoordDiffuse2 = coords1;
    
    OUT.normalWorld = mul( IN.normal , world);
    
    OUT.distanceToCam = length( pos/100000 - campos/100000 );
    return OUT;
}


// Fresnel effect
void DoFresnel( inout float3 inOutColor, in float3 posWorld, in float3 normalWorld )
{
    
    float3 toCam = campos/10000 - posWorld/10000;  // floats out of range
    float nDotV = saturate( dot( normalize(normalWorld), normalize(toCam) ));
    
    float fresnel = FresnelIndex + (1.0f - FresnelIndex ) * pow( (1 - nDotV ), FresnelExponent);
    fresnel = saturate( fresnel );    

	// should be 2 techniques
	if( FresnelModulate < 0.0f )
    	inOutColor = lerp( inOutColor, inOutColor * (1-fresnel), -FresnelModulate );
   	else
   		inOutColor = lerp( inOutColor, inOutColor * fresnel, FresnelModulate );
     
}

void DoDarkSphere( inout float3 inOutColor, in float3 posWorld )
{
   
 	float3 darkModulate = float3(1.0f, 1.0f, 1.0f);
    float distance = length( posWorld.xyz - DarkSpherePos ); 
    if( distance < DarkSphereRange )
    {
        float where = 1.0f - (distance / DarkSphereRange);
        where = pow( where, DarkSphereFalloff );
        darkModulate = lerp( float3(1,1,1), DarkSphereColorModulate.xyz, where );
    }    
    
    inOutColor.xyz *= darkModulate;
}

//-----------------------------------
PS_OUTPUT PS_2Textures( vertexOutput IN)
{    
    float4 outColor;    
    float4 diffuse;
    float4 diffuse2;
    
    diffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse );
    diffuse2 = tex2D( Texture2Sampler, IN.texCoordDiffuse2 );

    diffuse.xyz *= ColorModulate0.xyz;
    diffuse2.xyz *= ColorModulate1.xyz;
    
	// Screen
    diffuse.xyz = ( 1 - ( (1 - diffuse.xyz) * ( 1 - diffuse2.xyz)) );
 	if( BlendType == 0.0f )  // blend
        diffuse = lerp( diffuse, diffuse2, BlendAmount );
    if( BlendType == 1.0f )       // modulate
        diffuse = saturate( diffuse*diffuse2*BlendAmount );

	float3 normalWorld = normalize(IN.normalWorld);
    float3 eyeVecW = campos - IN.posWorld.xyz;

    float4 diffuseTexture = diffuse;
    
    // add in lights:
  	float3 colorSum = 0;
    float3 specularSum = 0;
    
#if PerVertexPreference
	colorSum = float3(0,0,0);
#else
	AddLights(normalWorld, IN.posWorld, colorSum, matSettings.Specular_Power.w, eyeVecW, specularSum);
#endif

    colorSum += matSettings.Ambient + ambientLevel;
    // ignore material properties
    //outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor = diffuseTexture;
    outColor.xyz *= colorSum;
    outColor.xyz += specularSum * matSettings.Specular_Power.xyz;
    outColor.xyz += matSettings.Emissive;
    
    outColor.xyz *= FinalColorModulate;

#if PerVertexPreference == 0
	DoFresnel( outColor.xyz, IN.posWorld, normalWorld );
#endif

    outColor.a *= ColorModulate0.a;
    
    
    PS_OUTPUT Out;
	SetPSOutput( Out, outColor, float4( 1, 1, IN.distanceToCam, 1) );
	return Out;
}



//-----------------------------------
PS_OUTPUT PS_1Texture( vertexOutput IN)
{    
    float4 outColor;    
    float4 diffuse;
    
    diffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse );    
    diffuse.xyz *= ColorModulate0.xyz;
    
    // add in lights:
    float4 diffuseTexture = diffuse;
    float3 normalWorld = normalize(IN.normalWorld);
    float3 eyeVecW = campos - IN.posWorld.xyz;

	float3 colorSum = 0;
    float3 specularSum = 0;

#if PerVertexPreference     
	colorSum = float3(0,0,0);
#else  
	AddLights(normalWorld, IN.posWorld, colorSum, matSettings.Specular_Power.w, eyeVecW, specularSum);
#endif

    colorSum += matSettings.Ambient + ambientLevel;
    // ignore material properties
    //outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor = diffuseTexture;
    outColor.xyz *= colorSum;
    outColor.xyz += specularSum * matSettings.Specular_Power.xyz;
    outColor.xyz += matSettings.Emissive;
  
#if PerVertexPreference == 0
	DoFresnel( outColor.xyz, IN.posWorld, normalWorld );
#endif

    outColor.xyz *= FinalColorModulate;
            
    PS_OUTPUT Out;
	SetPSOutput( Out, outColor, float4( 1, 1, IN.distanceToCam, 1) );
	return Out;
}




//-----------------------------------
PS_OUTPUT PS_2TexturesNoLights( vertexOutput IN)
{    
    float4 outColor;    
    float4 diffuse;
    float4 diffuse2;
    
    diffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse );
    diffuse2 = tex2D( Texture2Sampler, IN.texCoordDiffuse2 );

    diffuse.xyz *= ColorModulate0.xyz;
    diffuse2.xyz *= ColorModulate1.xyz;
    
    
    // Screen
    diffuse.xyz = ( 1 - ( (1 - diffuse.xyz) * ( 1 - diffuse2.xyz)) );
 	if( BlendType == 0.0f )  // blend
        diffuse = lerp( diffuse, diffuse2, BlendAmount );
    if( BlendType == 1.0f )       // modulate
        diffuse = saturate( diffuse*diffuse2*BlendAmount );
    // 'add' is disabled
    //else if( BlendType == 1.0f )       // add
    //    diffuse = ( (diffuse + diffuse2) * BlendAmount );
    

	float3 normalWorld = normalize(IN.normalWorld);
    float3 eyeVecW = campos - IN.posWorld.xyz;

    float4 diffuseTexture = diffuse;
    
   
  	float3 colorSum = 1;
    
    colorSum += matSettings.Ambient + ambientLevel;
    // ignore material properties
    //outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor = diffuseTexture;
    outColor.xyz *= colorSum;
    outColor.xyz += matSettings.Emissive;
    
    outColor.xyz *= FinalColorModulate;

//#if PerVertexPreference == 0
    DoFresnel( outColor.xyz, IN.posWorld, normalWorld );
// #endif

    outColor.a *= ColorModulate0.a;    
        
    PS_OUTPUT Out;
	SetPSOutput( Out, outColor, float4( 1, 1, IN.distanceToCam, 1) );
	return Out;
}



//-----------------------------------
PS_OUTPUT PS_1TextureNoLights( vertexOutput IN)
{    
    float4 outColor;    
    float4 diffuse;
    
    diffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse );    
    diffuse.xyz *= ColorModulate0.xyz;
    
    // add in lights:
    float4 diffuseTexture = diffuse;
    float3 normalWorld = normalize(IN.normalWorld);
    float3 eyeVecW = campos - IN.posWorld.xyz;

	float3 colorSum = 1;
    
    colorSum += matSettings.Ambient + ambientLevel;
    // ignore material properties
    //outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor = diffuseTexture;
    outColor.xyz *= colorSum;
    outColor.xyz += matSettings.Emissive;
  
  
#if PerVertexPreference == 0
	DoFresnel( outColor.xyz, IN.posWorld, normalWorld );
#endif

    outColor.xyz *= FinalColorModulate;    
            
    PS_OUTPUT Out;
	SetPSOutput( Out, outColor, float4( 1, 1, IN.distanceToCam, 1) );
	return Out;
}






//-----------------------------------
PS_OUTPUT PS_2TexturesDarkSphere( vertexOutput IN)
{    
    float4 outColor;    
    float4 diffuse;
    float4 diffuse2;
    
    diffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse );
    diffuse2 = tex2D( Texture2Sampler, IN.texCoordDiffuse2 );

    diffuse.xyz *= ColorModulate0.xyz;
    diffuse2.xyz *= ColorModulate1.xyz;
   
   // Screen 
    diffuse.xyz = ( 1 - ( (1 - diffuse.xyz) * ( 1 - diffuse2.xyz)) );
 	if( BlendType == 0.0f )  // blend
        diffuse = lerp( diffuse, diffuse2, BlendAmount );
    if( BlendType == 1.0f )       // modulate
        diffuse = saturate( diffuse*diffuse2*BlendAmount );

	float3 normalWorld = normalize(IN.normalWorld);
    float3 eyeVecW = campos - IN.posWorld.xyz;

    float4 diffuseTexture = diffuse;
    
    // add in lights:
  	float3 colorSum = 0;
    float3 specularSum = 0;
    
#if PerVertexPreference
	colorSum = float3( 0, 0, 0 );
#else    
	AddLights(normalWorld, IN.posWorld, colorSum, matSettings.Specular_Power.w, eyeVecW, specularSum);
#endif
    
    colorSum += matSettings.Ambient + ambientLevel;    
    // ignore material properties
    //outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor = diffuseTexture;
    outColor.xyz *= colorSum;
    outColor.xyz += specularSum * matSettings.Specular_Power.xyz;
    outColor.xyz += matSettings.Emissive;
    
    outColor.xyz *= FinalColorModulate;
   
   
#if PerVertexPreference == 0
    DoDarkSphere( outColor.xyz, IN.posWorld );    
#endif
  
    outColor.a *= ColorModulate0.a;
    
    PS_OUTPUT Out;
	SetPSOutput( Out, outColor, float4( 1, 1, IN.distanceToCam, 1) );
	return Out;
}



//-----------------------------------
PS_OUTPUT PS_1TextureDarkSphere( vertexOutput IN)
{    
    float4 outColor;    
    float4 diffuse;
    
    diffuse = tex2D( DiffuseTextureSampler, IN.texCoordDiffuse );    
    diffuse.xyz *= ColorModulate0.xyz;
    
    // add in lights:
    float4 diffuseTexture = diffuse;
    float3 normalWorld = normalize(IN.normalWorld);
    float3 eyeVecW = campos - IN.posWorld.xyz;

	float3 colorSum = 0;
    float3 specularSum = 0;

#if PerVertexPreference
	colorSum = float3( 0, 0, 0 );
#else	
	AddLights(normalWorld, IN.posWorld, colorSum, matSettings.Specular_Power.w, eyeVecW, specularSum);
#endif

    colorSum += matSettings.Ambient + ambientLevel;
    // ignore material properties
    //outColor = matSettings.Diffuse_Opacity * diffuseTexture;
    outColor = diffuseTexture;
    outColor.xyz *= colorSum;
    outColor.xyz += specularSum * matSettings.Specular_Power.xyz;
    outColor.xyz += matSettings.Emissive;
  

#ifndef PerVertexPreference
	DoDarkSphere( outColor.xyz, IN.posWorld );
#endif

    outColor.xyz *= FinalColorModulate;
            
    PS_OUTPUT Out;
	SetPSOutput( Out, outColor, float4( 1, 1, IN.distanceToCam, 1) );
	return Out;
}



technique textured
{
    pass p0 
    {	
    	VertexShader = compile vs_2_0 VS_Transform();
		PixelShader  = compile ps_2_0 PS_1Texture();
    }
}

//-----------------------------------
technique textured2layers
{
    pass p0 
    {	
    	VertexShader = compile vs_2_0 VS_Transform();
		PixelShader  = compile ps_2_0 PS_2Textures();
    }
}

technique texturedDarkSphere
{
    pass p0 
    {	
    	VertexShader = compile vs_2_0 VS_Transform();
		PixelShader  = compile ps_2_0 PS_1TextureDarkSphere();
    }
}

//-----------------------------------
technique textured2layersDarkSphere
{
    pass p0 
    {	
    	VertexShader = compile vs_2_0 VS_Transform();
		PixelShader  = compile ps_2_0 PS_2TexturesDarkSphere();
    }
}




technique texturedNoLights
{
    pass p0 
    {	
    	VertexShader = compile vs_2_0 VS_Transform();
		PixelShader  = compile ps_2_0 PS_1TextureNoLights();
    }
}

//-----------------------------------
technique textured2layersNoLights
{
    pass p0 
    {	
    	VertexShader = compile vs_2_0 VS_Transform();
		PixelShader  = compile ps_2_0 PS_2TexturesNoLights();
    }
}