/******************************************************************************/
/*                                                                            */
/*       Module Name          : terrain_vs.c                                  */
/*                                                                            */
/*       Author               : S.Chapman                                     */
/*                                                                            */
/*       Comment              : Simple vertex Shader for the fractal planets. */
/*                                                                            */
/******************************************************************************/

/******************************************************************************/
/* Define Lighting types.                                                     */
/******************************************************************************/
#define D3DLIGHT_POINT           1.1f  /* Point Light.                        */
#define D3DLIGHT_SPOT            2.1f  /* Spot Light.                         */
#define D3DLIGHT_DIRECTIONAL     3.1f  /* Directional Light.                  */

/******************************************************************************/
/* Define Fog types.                                                          */
/******************************************************************************/
#define D3DFOG_NONE              0.1f  /* No Fog.                             */
#define D3DFOG_EXP               1.1f  /* Exponential Fog.                    */
#define D3DFOG_EXP2              2.1f  /* Exponential Fog.                    */
#define D3DFOG_LINEAR            3.1f  /* Linear Fog.                         */

/******************************************************************************/
/* Declare the structures.                                                    */
/******************************************************************************/
typedef struct
        {
        vector   diffuse;              /* Diffuse colour.                     */
        vector   ambient;              /* Ambient colour.                     */
        vector   specular;             /* Specular 'shininess' colour.        */
        vector   emissive;             /* Emissive colour.                    */
        float    power;                /* Sharpness of specular highlight.    */
        } T_material;

typedef struct 
        {
        float    type;                 /* Type of Light.                      */
        vector   diffuse;              /* Diffuse colour.                     */
        vector   specular;             /* Specular 'shininess' colour.        */
        vector   ambient;              /* Ambient colour.                     */
        vector   position;             /* Position of Light.                  */
        vector   direction;            /* Direction of Light.                 */
        vector   view_direction;       /* View Direction.                     */
        float4   range;                /* Cutoff Range.                       */
        float4   attenuation;          /* Constant Attenuation.               */
        float4   spotlight;            /* Inner/Outer angle + falloff.        */
        } T_light;

typedef struct 
        {
        float    type;                 /* Type of Fog.                        */
        vector   colour;               /* Colour of Fog.                      */
        float4   range_density;        /* Fog Range and Density.              */
        } T_fog;

/******************************************************************************/
/* Declare Constants.                                                         */
/******************************************************************************/
matrix wv_matrix     :register( c0);   /* Combined World view Matrix.         */
matrix wvp_matrix    :register( c4);   /* Combined World view Project Matrix. */
matrix w_matrix      :register( c8);   /* World Matrix.                       */

T_material material  :register(c12);   /* Material colours.                   */
T_fog      fog       :register(c17);   /* Fog.                                */
T_light    light     :register(c20);   /* Lighting.                           */

/******************************************************************************/
/* Declare the Input parameters.                                              */
/******************************************************************************/
struct VS_INPUT
{
   float3 position    : POSITION0;
   float3 normal      : NORMAL0;
   vector diffuse     : COLOR0;
   float2 text1       : TEXCOORD0;     /* Detail Map coordinates.             */
   float2 text2       : TEXCOORD1;     /* Colour Map coordinates.             */
};

/******************************************************************************/
/* Declare the Output parameters.                                             */
/******************************************************************************/
struct VS_OUTPUT
{
   float4 position    : POSITION0;
   vector diffuse     : COLOR0;
   vector specular    : COLOR1;
   float2 text1       : TEXCOORD0;     /* Detail Map coordinates.             */
   float2 text2       : TEXCOORD1;     /* Colour Map coordinates.             */
   float  fog         : FOG;
};

/******************************************************************************/
/* Terrain Vertex Shader Entry function.                                      */
/******************************************************************************/

VS_OUTPUT main( VS_INPUT  input)
{
   /* Declare and initialise the output.                                      */
   VS_OUTPUT output = ( VS_OUTPUT)0;

   /***************************************************************************/
   /* Calculate the position in World view space.                             */
   /***************************************************************************/
   vector position = mul( float4( input.position, 1), wv_matrix);

   /***************************************************************************/
   /* Calculate the position in world view projected space.                   */
   /***************************************************************************/
   output.position = mul( float4( input.position, 1), wvp_matrix);

   /***************************************************************************/
   /* Calculate intermediate values used in the lighting calculations.        */
   /***************************************************************************/

   /* Calulate the normal in world view space.                                */
   float3 normal = ( mul( input.normal, ( float3x3)w_matrix));

   /* Calculate the View Direction.                                           */
   float3 view_direction = -normalize( position.xyz);

   /* Calculate the Half vector.                                              */
//   float3 half_vector = normalize( light.direction + view_direction);
   float3 half_vector = normalize( light.direction + light.view_direction);

   /***************************************************************************/
   /* Calculate the diffuse and specular light.                               */
   /***************************************************************************/
   output.diffuse = ( light.ambient * material.ambient) +
                    (( light.diffuse * material.diffuse) *
                    max( 0, dot( normal, light.direction)));
   output.diffuse.a = input.diffuse.a;

   output.specular = ( light.specular * material.specular) *
                     pow( max( 0, dot( half_vector, normal)),( material.power));

   /***************************************************************************/
   /* Determine the Fog value.                                                */
   /***************************************************************************/
//   output.fog = (( fog.range_density[ 1] - length( position.xyz)) / 
//                 ( fog.range_density[ 1] - fog.range_density[ 0]));
   output.fog = (( fog.range_density[ 1] - position.z) / 
                 ( fog.range_density[ 1] - fog.range_density[ 0]));

   output.fog = clamp( output.fog, 0, 1);
 
   /***************************************************************************/
   /* Extract the Text Coordinates.                                           */
   /***************************************************************************/
   output.text1 = input.text1;
   output.text2 = input.text2;

   return output;
}