/******************************************************************************/
/*                                                                            */
/*       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.                  */

/******************************************************************************/
/* 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 
        {
        vector diffuse     : COLOR0;   /* Diffuse Colour.                     */
        vector specular    : COLOR1;   /* Specular Colour.                    */
        } T_colour_pair;


/******************************************************************************/
/* 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.                       */
matrix v_matrix      :register(c12);   /* View Matrix.                        */
matrix p_matrix      :register(c16);   /* Projection Matrix.                  */

T_material material  :register(c20);   /* Material colours.                   */
T_light    light     :register(c25);   /* Material colours.                   */

/******************************************************************************/
/* Declare the Input parameters.                                              */
/******************************************************************************/
struct VS_INPUT
{
   float3 position    : POSITION0;
   float3 normal      : NORMAL0;
   float2 text1       : TEXCOORD0;
};

/******************************************************************************/
/* Declare the Output parameters.                                             */
/******************************************************************************/
struct VS_OUTPUT
{
   float4 position    : POSITION0;
   vector diffuse     : COLOR0;
   vector specular    : COLOR1;
   float2 text1       : TEXCOORD0;
};

/******************************************************************************/
/* Directional Lighting.                                                      */
/******************************************************************************/
T_colour_pair directional_lighting( float3    normal,
                                    float3    view_direction)
{
   /* Declare the output.                                                     */
   T_colour_pair colour;

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

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

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

   return colour;

}

/******************************************************************************/
/* Point Lighting.                                                            */
/******************************************************************************/
T_colour_pair point_lighting( float3    position,
                              float3    normal,
                              float3    view_direction)
{
   /* Declare the output.                                                     */
   T_colour_pair colour;

   /* Determine the Light Direction.                                          */
   vector world_position = mul( float4( position,1), w_matrix);
   float3 light_direction = normalize( light.position.xyz - world_position.xyz);
                                       
   /* Calculate the Half vector.                                              */
   float3 half_vector = normalize( light_direction + view_direction);

   /* Calculate the diffuse and specular light.                               */
   colour.diffuse = ( light.ambient * material.ambient) +
                    (( light.diffuse * material.diffuse) *
                    max( 0, dot( normal, light_direction)));

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

   return colour;

}

/******************************************************************************/
/* 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 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( output.position.xyz);

   /***************************************************************************/
   /* Calculate the Lighting.                                                 */
   /***************************************************************************/
   if( light.type <= D3DLIGHT_POINT)
   {
      T_colour_pair colour = point_lighting( input.position,
                                             ( float3)normal, 
                                             view_direction);
      output.diffuse = colour.diffuse;
      output.specular = colour.specular;

   }                                   /* End of if( light.type == ...        */
   else
   {
      if( light.type <= D3DLIGHT_DIRECTIONAL)
      {
         T_colour_pair colour = directional_lighting( ( float3)normal, 
                                                      view_direction);

         output.diffuse = colour.diffuse;
         output.specular = colour.specular;

      }                                /* End of if( light.type == ...        */

   }                                   /* End of ..else( light.type == ...    */

   /***************************************************************************/
   /* Default the Alpha value.                                                */
   /***************************************************************************/
   output.diffuse.a = 1.0f;

   /***************************************************************************/
   /* Extract the Text Coordinates.                                           */
   /***************************************************************************/
   output.text1 = input.text1;

   return output;

}