//begin #include "Common.cg" ////////////////////////////////////////////////////
// General functions

// Expand a range-compressed vector
float4 expand(float4 v)
{
    return v * 2 - 1;
}
float3 expand(float3 v)
{
    return v * 2 - 1;
}
float2 expand(float2 v)
{
    return v * 2 - 1;
}
float1 expand(float1 v)
{
    return v * 2 - 1;
}

// Returns light direction from light position and vertex position
float3 getLightDirection(float4 lightPosition, float4 position)
{
    // calculate tangent space light vector
    // Get object space light direction
    // Non-normalised since we'll do that in the fragment program anyway
    return lightPosition.xyz -  (position.xyz * lightPosition.w);
}

// Returns eye direction from eye position and vertex position
float3 getEyeDirection(float3 eyePosition, float4 position)
{
    return eyePosition - position.xyz;
}

// Returns a Tangent Binormal Normal matrix
float3x3 getTBNMatrix(float3 tangent, float3 normal)
{
    // Calculate the binormal (NB we assume both normal and tangent are
    // already normalised)
    // NB looks like nvidia cross params are BACKWARDS to what you'd expect
    // this equates to NxT, not TxN
    float3 binormal = cross(tangent, normal);
	
    // Form a rotation matrix out of the vectors
    return float3x3(tangent, binormal, normal);
}


// Returns displacement vector from normalmaps alpha channel
float getDisplacement(sampler2D heightMap, float2 uv, float scale, float bias)
{
    // get the height using the tex coords
    float height = tex2D(heightMap, uv).a;

    // calculate displacement	
    return (height * scale) + bias;
}

// Returns a specular component from normal vector, specular colour and specular power
float3 getSpecularComponent(float3 normal, float3 halfAngle, float3 specularColour, float specularPower)
{
    return pow( saturate(dot(normal, halfAngle)), specularPower) * specularColour;
}

// Returns a per-pixel lighted component from normal vector, lightdir and colour
float3 getLightingComponent(float3 normal, float3 lightDir, float3 colour)
{
    return saturate(dot(normal, lightDir)) * colour;
}

//end #include "Common.cg" //////////////////////////////////////////////////////











//=============================================================================
// Vertex program that moves light and eye vectors into texture tangent space at vertex
//=============================================================================

void main_vp( float4 iposition	: POSITION,
              float3 inormal	  : NORMAL,
              float2 iuv		    : TEXCOORD0,
              float3 itangent   : TANGENT0,

              out float4 oposition   : POSITION,
              out float2 ouv		     : TEXCOORD0,
              out float3 olightDir   : TEXCOORD1,
              out float3 oeyeDir     : TEXCOORD2,
              out float3 ohalfAngle  : TEXCOORD3,
           
              uniform float4 uvScale,         // index 0 - texture scale
              uniform float4 lightPosition,   // index 1
              uniform float3 eyePosition,     // index 2
              uniform float4x4 worldViewProj  // index 3
            ){

    // calculate output position 
    oposition = mul(worldViewProj, iposition); 

    // pass the main uvs after scaling
    ouv = iuv * float2(uvScale.x,uvScale.y); 

    float3 lightDir = getLightDirection(lightPosition, iposition);
    float3 eyeDir = getEyeDirection(eyePosition, iposition);
    
    // Form a rotation matrix out of the vectors 
    float3x3 TBN = getTBNMatrix(itangent, inormal); 
    
    // Transform the light vector according to this matrix 
    olightDir = normalize(mul(TBN, lightDir)); 
    oeyeDir = normalize(mul(TBN, eyeDir)); 

    ohalfAngle = normalize(oeyeDir + olightDir);
}





//=============================================================================
// Fragment program that does parallax mapping
//=============================================================================
void main_fp( float4 iposition     : POSITION,
              float2 iuv           : TEXCOORD0,
              float3 ilightDir     : TEXCOORD1,
              float3 ieyeDir       : TEXCOORD2,
              float3 ihalfAngle    : TEXCOORD3,

              out float4 ocolour   : COLOR,

              uniform float4 renderParams,    // index 0 - render params: renderDiffuseGrey(-1 or 0..1) renderNormal(0 or 1) renderDisplacement(-1 or 0..1) renderSpecular(-1 or 0..1)
              uniform float4 scaleBias,       // index 1 - parallax height scale and bias: height is mult by scale and bias is added
              uniform float3 lightAmbient,    // index 2
              uniform float3 lightDiffuse,    // index 3
              uniform float3 lightSpecular,   // index 4

              uniform sampler2D diffuseMap  : TEXUNIT0,
              uniform sampler2D normalMap   : TEXUNIT1,
              uniform sampler2D heightMap   : TEXUNIT2,
              uniform sampler2D specularMap : TEXUNIT3
             ){

    float displacement;
    if(renderParams.z < 0) // we're using displacement from the bitmap
      displacement = getDisplacement(heightMap, iuv, scaleBias.x, scaleBias.y);
    else
      displacement = renderParams.z;
	
    float3 uv2 = float3(iuv, 1);
	
// calculate the new tex coord to use for normal and diffuse
    float2 newTexCoord = ((ieyeDir * displacement) + uv2).xy;
	
// get the new normal and diffuse values
    float3 normal = expand( tex2D(normalMap, newTexCoord).xyz ); // WAS: getNormalMapVector(normalHeightMap, newTexCoord);
	
// diffuse or grey?
    float3 diffuse;
    if(renderParams.x < 0) // use diffuse from bitmap
      diffuse = tex2D(diffuseMap, newTexCoord).xyz;
    else
      diffuse = float3(renderParams.x,renderParams.x,renderParams.x);

// specular?
    float3 specular;
    float3 specularColor;
    if(renderParams.w < 0){ // we're multiplying by the global lightSpecular color
      specular = getSpecularComponent(normal, ihalfAngle, lightSpecular, scaleBias.z);

      specularColor = tex2D(specularMap, newTexCoord).xyz;
      specular = specular * specularColor;
    }
    else
      specular = float3(renderParams.w,renderParams.w,renderParams.w);

// normal
    float3 normalComponent;
    if(renderParams.y)
      normalComponent = getLightingComponent(normal, ilightDir, lightDiffuse);
    else
      normalComponent = float3(1,1,1);

    float3 col = diffuse.xyz * normalComponent + specular + lightAmbient;

    ocolour = float4(col, 1);
}

