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

Sky
******************************************************************************/
#include "..\mrt.fx"


float4x4 worldViewProj : WorldViewProjection;
float4x4 viewProj : ViewProjection;
float4x4 world : World;

float4 StartColor : StartColor;
float3 MidColor : MidColor;
float4 EndColor : EndColor;
float4 UpperHorizonColor : UpperHorizonColor;

float MidBlendPoint : MidBlendPoint;


float4 CloudColorLight : CloudColorLight;
float4 CloudColorDark : CloudColorDark;
float CloudColorBlendPoint : CloudColorBlendPoint;

float2 SunPos : SunPos;
float DebugSunPos : DebugSunPos;

float FinalColorModulate : FinalColorModulate;
float SkipForceBloom : SkipForceBloom;

texture NoiseTexture0 : NoiseTexture0;
sampler NoiseTextureSampler0 = sampler_state 
{
    texture = <NoiseTexture0>;
    AddressU  = CLAMP;        
    AddressV  = CLAMP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};


texture NoiseTexture1 : NoiseTexture1;
sampler NoiseTextureSampler1 = sampler_state 
{
    texture = <NoiseTexture1>;
    AddressU  = CLAMP;        
    AddressV  = CLAMP;
    AddressW  = WRAP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};


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


float3 campos : CAMERAPOS;

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

struct vertexOutput {
    float4 hPosition		: POSITION;
    float3 posWorld         : TEXCOORD0;
    float3 normObj          : TEXCOORD1;
    float2 texCoordStars	: TEXCOORD2;
    float  dist		: TEXCOORD3;
};


struct vertexOutputFixed {
    float4 hPosition		: POSITION;
    float4 diffColor			: COLOR0;
};

struct vertexOutputLight {
    float4 hPosition		: POSITION;
    float2 texCoordStars	: TEXCOORD0;
    float4 diffColor			: COLOR0;
};

vertexOutputLight VS_TransformLight(vertexInputUnboned IN) 
{
    float4 pos;
    float3 norm;
    float3 tang;
    vertexOutputLight OUT;
    
    pos = mul(IN.position, world);
    norm = mul(IN.normal, world);
  
    float fade = -IN.normal.y;
    fade *= 1.8f;
    
    float4 gradient;
    
    float whereGradient = 1.0f - fade;    
    float mix;
    
    if( whereGradient < MidBlendPoint )
    {
        mix = saturate( whereGradient / MidBlendPoint );
        gradient.xyz = lerp( StartColor, MidColor, mix );   
    }
    else
    {
        mix = saturate( whereGradient - MidBlendPoint );
        mix /= (1.0f -MidBlendPoint) ;
        
        if( mix < 0.5f )   
        {     
        	gradient.xyz = lerp( MidColor, UpperHorizonColor , mix / 0.5f );
        }
        else
        {
        	mix = saturate( (mix - 0.5f) / 0.5f );
      
        	gradient.xyz = lerp( UpperHorizonColor, EndColor, mix );
        }      
    }
    gradient.w = 1.0f;
    
    float2 basecoords = IN.normal.xz / IN.normal.y * 2.5;
    OUT.texCoordStars = IN.texCoordDiffuse;
   
        
    OUT.hPosition = mul( pos , viewProj);
 	OUT.diffColor = gradient;
    return OUT;
}

vertexOutputFixed VS_TransformFixed(vertexInputUnboned IN) 
{
    float4 pos;
    float3 norm;
    float3 tang;
    vertexOutputFixed OUT;
    
    pos = mul(IN.position, world);
    norm = mul(IN.normal, world);
  
    float fade = -IN.normal.y;
    fade *= 1.8f;
    
    float4 gradient;
    
    float whereGradient = 1.0f - fade;    
    float mix;
    if( whereGradient < MidBlendPoint )
    {
        mix = saturate( whereGradient / MidBlendPoint );
        gradient.xyz = lerp( StartColor, MidColor, mix );   
    }
    else
    {
        mix = saturate( whereGradient - MidBlendPoint );
        mix /= (1.0f -MidBlendPoint) ;
        
        if( mix < 0.5f )   
        {     
        	gradient.xyz = lerp( MidColor, UpperHorizonColor , mix / 0.5f );
        }
        else
        {
        	mix = saturate( (mix - 0.5f) / 0.5f );
      
        	gradient.xyz = lerp( UpperHorizonColor, EndColor, mix );
        }      
    }    
    gradient.w = 1.0f;
        
    OUT.hPosition = mul( pos , viewProj);
 	OUT.diffColor = gradient;
    return OUT;
}

vertexOutput VS_Transform(vertexInputUnboned IN) 
{
    float4 pos;
    float3 norm;
    float3 tang;
    vertexOutput OUT;
    
    pos = mul(IN.position, world);
    norm = mul(IN.normal, world);
  
    OUT.normObj = IN.normal;
    OUT.posWorld = pos;
    
    float2 basecoords = IN.normal.xz / IN.normal.y * 2.5;
    OUT.texCoordStars = IN.texCoordDiffuse;
    
    OUT.hPosition = mul( pos , viewProj);
  
    OUT.dist = length( pos/100000 - campos/100000 );
    
    return OUT;
}

/*****************************************************************************

PS_TexturedStars

This one doesn't have clouds
******************************************************************************/
PS_OUTPUT PS_TexturedStarsLight( vertexOutputLight IN)
{    
  
    float fUVMult = 3.0f;
    float4 a = tex2D( StarsTextureSampler, IN.texCoordStars * float2(8.38978954, 8.35345) * fUVMult);
    float4 b = tex2D( StarsTextureSampler, IN.texCoordStars * float2(8.65464354, 8.543643) * fUVMult );
    float4 c = tex2D( StarsTextureSampler, IN.texCoordStars * float2(7.23576754, 7.464567) * fUVMult );
    //float4 d = tex2D( StarsTextureSampler, IN.texCoordStars * float2(9.87654754, 9.8978643) * fUVMult );

    //float4 stars = pow(a * b  * c * d * 2.2, 5) * float4(0.7,0.5,0.95,1);

    float4 stars = pow(a * b  * c * 1.4, 5) * float4(0.7,0.5,0.95,1);
    
    float3 outcolor = IN.diffColor;
   
   outcolor += stars;
    
	PS_OUTPUT Out;	
	SetPSOutput( Out, float4( outcolor, 1 ), float4( 0,0,0, 1) );
    return Out;
}


/*****************************************************************************

PS_TexturedStars

This one doesn't have clouds
******************************************************************************/
PS_OUTPUT PS_TexturedStars( vertexOutput IN)
{    
    float fade = -IN.normObj.y;
    fade *= 1.3f;
    fade = saturate( pow( fade, 1.4f) );
        
    float4 gradient;
    float3 toEye = normalize( IN.posWorld - campos );
    
    float whereGradient = saturate( 1.0f - fade );
    float mix;    
   	gradient.xyz = lerp( StartColor, MidColor, min(1, whereGradient/MidBlendPoint) );
    gradient.xyz = lerp( gradient.xyz, EndColor, max(0, (whereGradient-MidBlendPoint)) );    
    // should be as below, but levels already arted w/ this bug
    //gradient.xyz = lerp( gradient.xyz, EndColor, max(0, (whereGradient-MidBlendPoint)/(1.0f-MidBlendPoint)) );
  
    gradient.w = 1.0f;
    
    // Stars
    float fUVMult = 3.0f;
    float4 a = tex2D( StarsTextureSampler, IN.texCoordStars * float2(8.38978954, 8.35345) * fUVMult);
    float4 b = tex2D( StarsTextureSampler, IN.texCoordStars * float2(8.65464354, 8.543643) * fUVMult );
    float4 c = tex2D( StarsTextureSampler, IN.texCoordStars * float2(7.23576754, 7.464567) * fUVMult );
    float4 d = tex2D( StarsTextureSampler, IN.texCoordStars * float2(9.87654754, 9.8978643) * fUVMult );

    float4 stars = pow(a * b  * c * d * 2.2, 5) * float4(0.7,0.5,0.95,1);
    
    float3 outcolor = gradient.xyz;
   	outcolor += stars;
  	outcolor *= FinalColorModulate;    
    
	PS_OUTPUT Out;	
	// output distance in 2nd RT.z
	SetPSOutput( Out, float4( outcolor, 1 ), float4( 0, 0, IN.dist, 1) );
    return Out;
}


/*****************************************************************************

PS_TexturedClouds

This one has clouds
******************************************************************************/
PS_OUTPUT PS_TexturedClouds( vertexOutput IN)
{    
    float2 coordsNoise;    
    float uvScale = -IN.normObj.y;
    
    // give more UV range at top:
    //uvScale = pow(uvScale * 0.5f, 0.6f );
    uvScale = pow(uvScale * 0.2f, 0.55f );
    uvScale = 1.0f / uvScale; // pow( uvScale, 2.0f );
    coordsNoise = IN.normObj.xz * uvScale;
    
    coordsNoise *= 0.035f;

    coordsNoise += 0.50f;
         
    float noise0 = tex2D( NoiseTextureSampler0, coordsNoise ).x; 
    float noise1 = tex2D( NoiseTextureSampler1, coordsNoise ).x; 
    
    float fade = -IN.normObj.y;
    fade *= 1.8f;
    
    float opacity = noise0; //  * fade;
   
    float fRange0 = 0.450f; 
    //float fRange1 = 0.085f;
    float fRange1 = 0.090f;
    if( fade < fRange0 )
    {
		float fFadeOff = (fRange0 - fade) / fRange0 ;
		fFadeOff = saturate( fFadeOff * 1.2f );
    	
    	if( fade < fRange1 )
    	{
    		fFadeOff = saturate( fFadeOff + (fRange1 - fade) / fRange1 );
    	}
    	opacity *=  1.0f - fFadeOff; 
    }
     
    float bright = noise1;
    
    if( bright < CloudColorBlendPoint )
        bright = 0.5f * (bright / CloudColorBlendPoint);
    else
        bright = 0.5f + (bright-CloudColorBlendPoint) / (1.0f - CloudColorBlendPoint);
     
    float3 cloudColor = lerp( CloudColorDark, CloudColorLight, bright ).xyz;
    
    float4 gradient;
    float3 toEye = normalize( IN.posWorld - campos );
    
    float whereGradient = 1.0f - fade;    
    float mix;
    if( whereGradient < MidBlendPoint )
    {
        mix = saturate( whereGradient / MidBlendPoint );
        gradient.xyz = lerp( StartColor, MidColor, mix );   
    }
    else
    {
        mix = saturate( whereGradient - MidBlendPoint );
        mix /= (1.0f -MidBlendPoint) ;
        
        if( mix < 0.5f )   
        {     
        	gradient.xyz = lerp( MidColor, UpperHorizonColor , mix / 0.5f );
        }
        else
        {
        	mix = saturate( (mix - 0.5f) / 0.5f );
      
        	gradient.xyz = lerp( UpperHorizonColor, EndColor, mix );
        }
      
    }    
    gradient.w = 1.0f;
  
    float3 outcolor = lerp( gradient, cloudColor, opacity );
    
    //!! remove this from production code!
    //if( DebugSunPos > 0.0f )
    //{
    //
    //    if( length( coordsNoise - SunPos.yx ) < 0.01f )
    //    {
    //        outcolor = float3( 1, 0, 0 );
    //    }
    //}    
    
    outcolor *= FinalColorModulate;
        
   // outcolor = float4( 1, 1, 1, 1 );
    
	PS_OUTPUT Out;	
	SetPSOutput( Out, float4(outcolor, 1.0f), float4( 0, 0, IN.dist, 0 ) );
    return Out;
}

/*****************************************************************************

PS_TexturedNoClouds

This one has no clouds, no stars, just gradient
******************************************************************************/
PS_OUTPUT PS_TexturedNoClouds( vertexOutput IN)
{    
   
    float fade = -IN.normObj.y;
    fade *= 1.8f;
 
    float4 gradient;
    
    float whereGradient = 1.0f - fade;    
    float mix;
    if( whereGradient < MidBlendPoint )
    {
        mix = saturate( whereGradient / MidBlendPoint );
        gradient.xyz = lerp( StartColor, MidColor, mix );   
    }
    else
    {
        mix = saturate( whereGradient - MidBlendPoint );
        mix /= (1.0f -MidBlendPoint) ;
        
        if( mix < 0.5f )   
        {     
        	gradient.xyz = lerp( MidColor, UpperHorizonColor , mix / 0.5f );
        }
        else
        {
        	mix = saturate( (mix - 0.5f) / 0.5f );
        	gradient.xyz = lerp( UpperHorizonColor, EndColor, mix );
        }      
    }    
    gradient.w = 1.0f;
    gradient *= FinalColorModulate;

	PS_OUTPUT Out;	
	SetPSOutput( Out, gradient, float4( 0, 0, IN.dist, 0 ) );
    return Out;
}


#ifndef FixedPipe
//-----------------------------------
technique stars
{
    pass p0 
    {		
		VertexShader = compile vs_1_1 VS_Transform();
		PixelShader  = compile ps_2_0 PS_TexturedStars();
    }
}

technique starsLight
{
    pass p0 
    {		
		VertexShader = compile vs_1_1 VS_TransformLight();
		PixelShader  = compile ps_2_0 PS_TexturedStarsLight();
    }
}


//-----------------------------------
technique clouds
{
    pass p0 
    {		
		VertexShader = compile vs_1_1 VS_Transform();
		PixelShader  = compile ps_2_0 PS_TexturedClouds();
    }
}

//-----------------------------------
technique noClouds
{
    pass p0 
    {		
		VertexShader = compile vs_1_1 VS_Transform();
		PixelShader  = compile ps_2_0 PS_TexturedNoClouds();
    }
}
#else
technique stars
{
    pass p0 
    {	
    	alphablendenable = true;
		srcblend = one;
		destblend = invsrcalpha;
    	
		VertexShader = compile vs_1_1 VS_TransformFixed();
		PixelShader  = 0;
	
		ColorOp[0] = SelectArg1; ColorArg1[0] = Diffuse; 
		AlphaOp[0] = SelectArg1; AlphaArg1[0] = Diffuse;
		SpecularEnable = false;
		
		ColorOp[1] = Disable;
		AlphaOp[1] = Disable;
    }
}

technique starsLight
{
    pass p0 
    {	
    	alphablendenable = true;
		srcblend = one;
		destblend = invsrcalpha;
    	
		VertexShader = compile vs_1_1 VS_TransformFixed();
		PixelShader  = 0;
	
		ColorOp[0] = SelectArg1; ColorArg1[0] = Diffuse; 
		AlphaOp[0] = SelectArg1; AlphaArg1[0] = Diffuse;
		SpecularEnable = false;
		
		ColorOp[1] = Disable;
		AlphaOp[1] = Disable;
    }
}

technique clouds
{
    pass p0 
    {	
    	alphablendenable = true;
		srcblend = one;
		destblend = invsrcalpha;
    	
		VertexShader = compile vs_1_1 VS_TransformFixed();
		PixelShader  = 0;
	
		ColorOp[0] = SelectArg1; ColorArg1[0] = Diffuse; 
		AlphaOp[0] = SelectArg1; AlphaArg1[0] = Diffuse;
		SpecularEnable = false;
		
		ColorOp[1] = Disable;
		AlphaOp[1] = Disable;
    }
}

technique noClouds
{
    pass p0 
    {	
    	alphablendenable = true;
		srcblend = one;
		destblend = invsrcalpha;
    	
		VertexShader = compile vs_1_1 VS_TransformFixed();
		PixelShader  = 0;
	
		ColorOp[0] = SelectArg1; ColorArg1[0] = Diffuse; 
		AlphaOp[0] = SelectArg1; AlphaArg1[0] = Diffuse;
		SpecularEnable = false;
		
		ColorOp[1] = Disable;
		AlphaOp[1] = Disable;
    }
}
#endif