//----------------------------------------------------------------------------------
// Uniform Variables
//----------------------------------------------------------------------------------
float4x4 coreWorldViewProj;
float4x4 coreWorld;
float4x4 coreWorldInverseTranspose;
float4x4 coreViewInverse;

float4x4 coreLight0;
float4x4 coreLight1;
float coreShininess;

texture coreDiffuseTexture;
texture coreDiffuseTexture1;

float4 coreMaterialDiffuse;
float4 coreMaterialSpecular;

float fireWaveRadius;
float fireRichtor;
float3 firePlayerPosition;

float boulderWaveRadius;
float boulderRichtor;
float3 boulderPlayerPosition;

float4 boulderLookVector;
bool boulderIsMoving;

float4 boulderEnergyValue;

float fireFrequency = 10.0f;			// Between 1-300 --> Never 0!!!
float fireAmplitude = 0.2f;				// 0.01 < amplituted < 0.10 --> very sensitive
float fireRedShift =  0.7f;				// Increase red components of color

float waveForm = 2.0f;
float boulderAmplitude = 0.05f;			// 
float boudlerRedShift =  0.3f;			// Increase red components of color
float waveFormScaler = 0.5f;;			// Scale the height of the flame

float4x4 playerWorldViewProj;

Texture colorMap;
sampler colorMapSampler = sampler_state 
{ 
	texture = <colorMap> ; 
	AddressU = mirror; 
	AddressV = mirror;
	magfilter = LINEAR; 
	minfilter = LINEAR; 
	mipfilter=LINEAR; 
};


sampler coreTextureSampler = sampler_state 
{
    texture = <coreDiffuseTexture>;
    AddressU  = CLAMP;        
    AddressV  = CLAMP;
    AddressW  = CLAMP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

sampler coreTextureSampler1 = sampler_state 
{
    texture = <coreDiffuseTexture1>;
    AddressU  = CLAMP;        
    AddressV  = CLAMP;
    AddressW  = CLAMP;
    MIPFILTER = LINEAR;
    MINFILTER = LINEAR;
    MAGFILTER = LINEAR;
};

struct coreVertexInput 
{
    float3 position				: POSITION;
    float3 normal				: NORMAL;
    float3 binormal				: BINORMAL;
    float3 tangent				: TANGENT;
    float4 texCoordDiffuse		: TEXCOORD0;
    float4 color				: COLOR0;
};

struct coreVertexOutput 
{
    float4 hPosition		: POSITION;
    float4 texCoordDiffuse	: TEXCOORD0;
    float3 norm 			: TEXCOORD1;
    float3 Position3D  		: TEXCOORD2;
    float3 eyePos 			: TEXCOORD3;	
    float4 color			: COLOR0;
};


struct GeneralVertexInput 
{
    float4 position				: POSITION;
    //float3 position			: POSITION;

    float2 texCoords			: TEXCOORD0;
	//float4 texCoordDiffuse			: TEXCOORD0;
	
    float3 normal				: NORMAL;
    float3 binormal				: BINORMAL;
    float3 tangent				: TANGENT;
    float4 color				: COLOR0;
};

struct GeneralVertexToPixel
{
    float4 position			: POSITION;
    //float4 hPosition		: POSITION;

    float2 texCoords		: TEXCOORD0;
    // float4 texCoordDiffuse	: TEXCOORD0;

    
	float4 color			: COLOR0;    
    float3 norm 			: TEXCOORD1;
    float3 texCoords2  		: TEXCOORD2;
    float3 eyePos 			: TEXCOORD3;	
};


//----------------------------------------------------------------------------------
// Fire Shader AOE
	// The two distance equations take into account 3D distance which is why it moves up the mountain last
	// To switch to a 2D wave, just use distance formula on x and z values
	// We want to raise vertex based on reciprocal distance 
	// cos func() rotates between -1 && 1 based on distance to wave front and the frequency
	// mult times distance to wave front taking abs value or result to clamp to upward movement only
	// sqrt to create the parabaloid wave form
	// amplituded to muffle the height to which the flame can rise
	// take inverse so that as waveDistance goes to 0, waveForm gets larger
//----------------------------------------------------------------------------------

GeneralVertexToPixel FireVertexShader(GeneralVertexInput IN)
{
	// Distance between Player and Vertex
	float groundZeroDistance = abs( distance( IN.position, firePlayerPosition) );

	// Distance between vertex and wave crest
	float waveDistance = abs( (groundZeroDistance - fireWaveRadius) );
	
	// Create the waveForm
	float waveForm =  1.0f/ (fireAmplitude + sqrt( abs( waveDistance * cos( waveDistance / fireFrequency) )));

	// New vertex height based on wave form;
	IN.position.y = IN.position.y + fireRichtor * waveForm - 2.5f;
	
	// Now burn it down based on time
	//IN.position.y -= fireWaveRadius/500 * IN.position.y;
	
	// Pack it up
    GeneralVertexToPixel Output = (GeneralVertexToPixel)0;
	Output.position = mul(IN.position, coreWorldViewProj);
    Output.texCoords = IN.texCoords;
    
    // Pass red to fragment shader based on height
    Output.color.r = waveForm * fireRedShift; 
    
    // Pass to fragShader
    return Output;    
}

float4 FirePixelShader(GeneralVertexToPixel IN) : Color
{
    float4 Output = (float4)0;
	clip(IN.color.r - 0.1f);
	Output = tex1D(coreTextureSampler, IN.color.r);
    return Output;
}

technique FireWave
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 FireVertexShader();
        PixelShader = compile ps_2_0 FirePixelShader();
        
        FillMode = Solid;
    }
}

//---------------------------------------------------------------------------------
//Water Shader
//---------------------------------------------------------------------------------

GeneralVertexToPixel WaterVertexShader( GeneralVertexInput IN)
{
	if( IN.position.y > 0.0f ) 
	{
		// Distance between vertex and wave crest
		float waveDistance = abs( length(IN.position - boulderWaveRadius) );
		
		// See Fire Shader Notes for explanation
		float waveForm = 1.0f / (1.0f + boulderAmplitude + cos(waveDistance * 3.14159265f / 60 ));

		// We only want protrusions, not indentions into the object
		float adjustment = boulderRichtor / waveForm * waveFormScaler;

		if(adjustment > 1.0f)
		{
			// New vertex height
			IN.position = IN.position + (adjustment * boulderLookVector);
		}
	}

	// Pack it up
    GeneralVertexToPixel Output = (GeneralVertexToPixel)0;
	Output.position = mul(IN.position, coreWorldViewProj);
    Output.texCoords = IN.texCoords;
    
    // Pass red to fragment shader based on height
    Output.color.r = waveForm * boudlerRedShift; 
    
    // Pass to fragShader
    return Output;    
}

float4 WaterPixelShader(GeneralVertexToPixel IN) : Color
{
    float4 Output = (float4)0;
	clip(IN.color.r - 0.1f);
	Output = tex1D(coreTextureSampler, IN.color.r);
    return Output;
}

technique WaterWave
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 WaterVertexShader();
        PixelShader = compile ps_2_0 WaterPixelShader();
        
        FillMode = Solid;
    }
}

//----------------------------------------------------------------------------------------------------------------
// Fire Boulder Shader
//----------------------------------------------------------------------------------------------------------------
GeneralVertexToPixel BoulderVertexShader(GeneralVertexInput IN)
{
	float waveForm = 2.0f;
	
	if( true ) 
	{
		// Distance between vertex and wave crest
		float waveDistance = abs( length(IN.position - boulderWaveRadius) );
		
		// Height Offsetting variable
		// Create sharp wave...  log() for rounded??
		// As distance between flame and vert grows, waveForm shinks
		// Ensure that wave burns upward
		// Cos creates a circular algorithm from linear distance
		// See Fire Shader Notes for explanation
		waveForm = boulderAmplitude + sqrt(waveDistance * abs( cos( waveDistance ) ) );

		// We only want protrusions, not indentions into the object
		float adjustment = boulderRichtor / waveForm * waveFormScaler;

		if(adjustment > 1.0f)
		{
			// New vertex height
			IN.position = IN.position + (adjustment * boulderLookVector);
		}
	}

	// Pack it up
    GeneralVertexToPixel Output = (GeneralVertexToPixel)0;
	Output.position = mul(IN.position, coreWorldViewProj);
    Output.texCoords = IN.texCoords;
    
    // Pass red to fragment shader based on height
    Output.color.r = waveForm * boudlerRedShift; 
    
    // Pass to fragShader
    return Output;    
}

float4 BoulderPixelShader(GeneralVertexToPixel IN) : Color
{
    float4 Output = (float4)0;
	clip(IN.color.r - 0.1f);
	Output = tex1D(coreTextureSampler, IN.color.r);
    return Output;
}

technique FireBoulder
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 BoulderVertexShader();
        PixelShader = compile ps_2_0 BoulderPixelShader();
        
		// Alpha blending
        AlphaBlendEnable = true;
		SrcBlend = SrcAlpha;
		DestBlend = InvSrcAlpha;
                
		FillMode = Solid;
    }
}

//------------------------------------------------------------
// Normal Boulder Shader
//------------------------------------------------------------
GeneralVertexToPixel NormalBoulderTransform(GeneralVertexInput IN)
{
    GeneralVertexToPixel Output = (GeneralVertexToPixel)0;

    Output.position = mul(IN.position, coreWorldViewProj);
    Output.texCoords = IN.texCoords;

    return Output;
}

float4 NormalBoulderPixelShader( GeneralVertexToPixel IN) : Color
{
	float4 Output = (float4)0;

	Output = tex2D(coreTextureSampler, IN.texCoords);
	Output.rgb += boulderEnergyValue;
    return Output;
}

technique NormalBoulder
{
    pass P0
    {
        vertexShader = compile vs_2_0 NormalBoulderTransform();
        pixelShader = compile ps_2_0 NormalBoulderPixelShader();

		// Alpha blending
        AlphaBlendEnable = true;
		SrcBlend = SrcAlpha;
		DestBlend = InvSrcAlpha;
                
        FillMode = Solid;
    }
}

//---------------------------------------------------------------------------------------
// Character Shader
//---------------------------------------------------------------------------------------

GeneralVertexToPixel CharacterVertexShader(GeneralVertexInput IN)
{
	// Pack it up
    GeneralVertexToPixel Output = (GeneralVertexToPixel)0;

	Output.position = mul(IN.position, coreWorldViewProj);
    Output.texCoords = IN.texCoords;
    
    // Pass to fragShader
    return Output;    
}

float4 CharacterPixelShader(GeneralVertexToPixel PSIn): Color
{
    float4 Output = (float4)0;
    Output = tex2D(coreTextureSampler, PSIn.texCoords);
    
    return Output;
}

technique CharacterShader
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 CharacterVertexShader();
        PixelShader = compile ps_2_0 CharacterPixelShader();
        
        FillMode = Solid;
    }
}

//--------------------------------------------------------------------------------------------------
// Core Light Shader
//--------------------------------------------------------------------------------------------------

coreVertexOutput CoreVS_TransformAndTexture(coreVertexInput IN) 
{
    coreVertexOutput Output = (coreVertexOutput)0;
    
    Output.hPosition = mul(float4(IN.position.xyz , 1.0) , coreWorldViewProj);
    Output.texCoordDiffuse = IN.texCoordDiffuse;

	//calculate our vectors N, E, L, and H
	float3 coreWorldEyePos = coreViewInverse[3].xyz;
    float3 coreWorldVertPos = mul(IN.position, coreWorld).xyz;
	float4 N = mul(IN.normal, coreWorldInverseTranspose); //normal vector
   
	Output.norm = N;
	Output.Position3D = coreWorldVertPos;
	Output.eyePos = coreWorldEyePos;

	//coreLight = L;
	//halfvec = H;
    return Output;
}

float4 CorePS_Textured(coreVertexOutput IN) : Color
{
	//calculate the diffuse and specular contributions
	float3 E = normalize(IN.eyePos - IN.Position3D); //eye vector
	float3 H0 = normalize(E + -float3(coreLight0[0][0], coreLight0[0][1], coreLight0[0][2])); //half angle vector
    float  diff0 = max(0, dot(normalize(IN.norm), normalize(-float3(coreLight0[0][0], coreLight0[0][1], coreLight0[0][2]))));
    float  spec0 = pow(max(0, dot(normalize(IN.norm), H0)), coreShininess);
    if( diff0 <= .0 )
    {
        spec0 = 0;
    }
    
  	float3 H1 = normalize(E + -float3(coreLight1[0][0], coreLight1[0][1], coreLight1[0][2])); //half angle vector
    float  diff1 = max(0, dot(normalize(IN.norm), normalize(-float3(coreLight1[0][0], coreLight1[0][1], coreLight1[0][2]))));
    float  spec1 = pow(max(0, dot(normalize(IN.norm), H1)), coreShininess );
    if( diff1 <= .0 )
    {
        spec1 = 0;
    }

	//output diffuse
    float4 ambColor = coreMaterialDiffuse * float4(coreLight0[1][0], coreLight0[1][1], coreLight0[1][2], 0) +  coreMaterialDiffuse * float4(coreLight1[1][0], coreLight1[1][1], coreLight1[1][2], 0);
    float4 diffColor = coreMaterialDiffuse * diff0 * float4(coreLight0[2][0], coreLight0[2][1], coreLight0[2][2], 0) + coreMaterialDiffuse * diff1 * float4(coreLight1[2][0], coreLight1[2][1], coreLight1[2][2], 0);

	//output specular
    float4 specColor = coreMaterialSpecular * float4(coreLight0[3][0], coreLight0[3][1], coreLight0[3][2], 0) * spec0 + coreMaterialSpecular * float4(coreLight1[3][0], coreLight1[3][1], coreLight1[3][2], 0) * spec1;

 	float4 coreDiffuseTexture = tex2D(coreTextureSampler, IN.texCoordDiffuse);
 	float4 diffAmbColor = (diffColor * coreDiffuseTexture) + ambColor * coreDiffuseTexture;
 	return ((diffAmbColor) + specColor);
}

technique coreTextured
{
    pass p0 
    {		
		VertexShader = compile vs_2_0 CoreVS_TransformAndTexture();
		PixelShader  = compile ps_2_0 CorePS_Textured();
    }
}