/*
	Wheels Of Steel
	Copyright (c) 2006, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Class Name:   Game
// Purpose:      Main game logic and initialisation
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "Game.h"
#include <cstdio>

//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------

// Number of frames over which the current frame rate is determined

const unsigned Game::FRAME_TIME_UPDATE_FRAMES = 8;

// Game resolution

const unsigned short Game::RESOLUTION_X = 640;     // game resoultion: x
const unsigned short Game::RESOLUTION_Y = 480;     // game resoultion: y

// Starting position for the grid of cars

const float Game::CAR_STARTING_Z  = 4096;

// How many sections from the end the race finishes at

const int Game::RACE_FINISH_SECTION_FROM_END   = 80;

// Hills and turns settings

const int Game::HILLS_TURNS_START_FROM_START = 64;  // how many sections from the start the hills and turns begin at
const int Game::HILLS_TURNS_END_FROM_END     = 64;  // how many sections from the end   the hills and turns end at

// Camera settings

const float Game::CAMERA_CORNER_LEAN   =  0.025f;	// amount the camera leans into turn when turning
const float Game::CAMERA_OFFSET_Y      =  1000.0f;	// distance from target: y
const float Game::CAMERA_OFFSET_Z      = -1500.0f;	// distance from target: z

// General physics-y settings

const float Game::GRAVITY          = 40000.0f;		// gravity amount
const float Game::FRICTION_AIR     = 0.80f;			// multiplier that controls how much contact with the air slows down an object
const float Game::FRICTION_TRACK   = 0.95f;			// multiplier that controls how much contact with the track slows down an object
const float Game::FRICTION_GROUND  = 0.15f;			// multiplier that controls how much contact with the rough ground slows down an object

//------------------------------------------------------------------------------
// Static initialisers
//------------------------------------------------------------------------------

bool            Game::run                       = false;
Background  *   Game::background                = 0;
Window      *   Game::window                    = 0;
Camera      *   Game::camera                    = 0;
Timer       *   Game::frameTimer                = 0;
float           Game::frameTime                 = 0;
float           Game::frameTimesAccum           = 0;
unsigned        Game::frameTimesCounted         = 0;
BitmapFont  *   Game::bitFont                   = 0;
Track       *   Game::track                     = 0;
float           Game::timeToRaceStart           = 0;
float           Game::timeToGoPromptEnd         = 0;
int             Game::playerFinishPosition      = 0;
Obj_Car  **     Game::carArray                  = 0;
unsigned        Game::carCount                  = 0;
AIPlayer **     Game::aiArray                   = 0;
Bitmap      *   Game::bmpHudGuageFL             = 0;
Bitmap      *   Game::bmpHudGuageFR             = 0;
Bitmap      *   Game::bmpHudGuageEL             = 0;
Bitmap      *   Game::bmpHudGuageER             = 0;

//------------------------------------------------------------------------------
// Debug only variable: allows camera to be cycled between cars
//------------------------------------------------------------------------------

// int carCamNum = 0;

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Name:     Game::initGame
Purpose:  Initialises the game
Params:   as commented
Returns:  none

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

void Game::initGame
(
    Window * window,                        // The game window

    unsigned trackLenght,                   // Game setting: track lenght, in sections
    unsigned numCompetitors,                // Game setting: number of competitors
    float    minHillHeight,                 // Game setting: minimum hill height
    float    maxHillHeight,                 // Game setting: maximum hill height
    float    minTurnAmount,                 // Game setting: minimum turn amount
    float    maxTurnAmount,                 // Game setting: maximum turn amount
    float    playerSpeedHandicap,           // Game setting: amount of acceleration to subtract from acceleration of all AI cars
    float    aiCarGridSpeedDifference,      // Game setting: amount of difference in acceleration between AI cars on the grid. furhter back in the grid cars are slower.
    float    gridSpacing                    // Game setting: spacing between cars on the starting grid
)
{
    //--------------------------------------------------------------------------
    // Show the beginging of race menu which just displays the key layout for
    // the game and waits for a keypress before returning. only do if the window
    // is open.
    //--------------------------------------------------------------------------

    if ( window->exists() )
    {
        // Show the pre-race menu screen

        Menu_BeginRace::display(window);
    }
    else
    {
        // No window left: abort the game

        return;
    }

    //--------------------------------------------------------------------------
    // If the window has been closed then return: do not start the game
    //--------------------------------------------------------------------------

    if ( ! window->exists() ) return;

    //--------------------------------------------------------------------------
    // Validate some of the input parameters
    //--------------------------------------------------------------------------

    if ( numCompetitors < 2     ) numCompetitors    = 2;       // Must have at least two cars
    if ( gridSpacing    < 512   ) gridSpacing       = 512;     // Must be some sort of gap between cars on the grid

    //--------------------------------------------------------------------------
    // Set the number of cars and construct the array of pointers to both the
    // cars and AI players
    //--------------------------------------------------------------------------

    carCount = numCompetitors;

    carArray = new Obj_Car  * [carCount     ];
    aiArray  = new AIPlayer * [carCount - 1 ];

    //--------------------------------------------------------------------------
    // Init variables
    //--------------------------------------------------------------------------

    Game::run                   = true;
    Game::window                = window;
    Game::frameTimer            = 0;
    Game::frameTime             = 0;
    Game::frameTimesAccum       = 0;
    Game::frameTimesCounted     = 0;
    Game::camera                = 0;
    Game::background            = 0;
    Game::track                 = 0;

    //--------------------------------------------------------------------------
    // Set the window event handlers
    //--------------------------------------------------------------------------

    window->setEvent_paint(Game::gameLoop);
    window->setEvent_closed(Game::windowClosed);

    //--------------------------------------------------------------------------
    // Set the fill mode for the window as filled
    //--------------------------------------------------------------------------

    window->setFillMode(Window::FILL_MODE_FILLED);      // always used filled primtives
    window->setLinePattern(Window::LINE_PATTERN_NONE);  // disable the outline around primitives: much much faster!

    //--------------------------------------------------------------------------
    // Initalise the game
    //--------------------------------------------------------------------------

    // Create timer

    frameTimer = new Timer();

    // Initialise the random number generator with current hardware clock time stamp

    srand( frameTimer->getClockTimeStamp() );

    // Create various game objects

    camera       = new Camera(0,384,0);       // create the camera
    background   = new Background(*window);   // create the background

    // Create the track using the settings passed into this function

    track = new Track
    (
        trackLenght,
        minHillHeight,
        maxHillHeight,
        minTurnAmount,
        maxTurnAmount
    );

    // Create the color lookup tables for the track sections

    TrackSection::createColorLookupTables();

    // Initialise the game object manager

    GameObjectManager::initObjects(track);

    // Load all the games mipmap resources

    MipmapManager::loadAllMipmaps(window);

    // Load the game's bitmap font

    bitFont = new BitmapFont("gfx\\font\\font1.bmp",window);

    // Load the HUD speed guage images:

    bmpHudGuageFL = window->loadBitmap("gfx\\hud\\guageFullLeft.bmp"    ,true);
    bmpHudGuageFR = window->loadBitmap("gfx\\hud\\guageFullRight.bmp"   ,true);
    bmpHudGuageEL = window->loadBitmap("gfx\\hud\\guageEmptyLeft.bmp"   ,true);
    bmpHudGuageER = window->loadBitmap("gfx\\hud\\guageEmptyRight.bmp"  ,true);

    // Create the various track objects

    TrackPopulator::createTreesAndRocks(track);                     // populate track with trees and rocks
    TrackPopulator::createOilSpills(track);                         // Create the slippy oil spills along the track
    TrackPopulator::createFinishFlags(track);                       // Create the finish flags at the end of the track

    // Create the cars that are in the race. create AIs for cpu cars.

    TrackPopulator::createCars
    (
        track,
        carCount,
        carArray,
        aiArray,
        playerSpeedHandicap,
        aiCarGridSpeedDifference,
        gridSpacing
    );

    // Set the countdown to race start settings

    timeToRaceStart     = 2.99999f; // Set the time left till the race start as just under 3 seconds
    timeToGoPromptEnd   = 1.50000f; // Set the time left till the go prompt dissapeers after the race has started

    // Set the finish position of the player to '-1' meaning they haven't yet finished the race

    playerFinishPosition = -1;

    //--------------------------------------------------------------------------
    // Update frame timer twice to invalidate any time spent initialising.
    // Puts the time of the last frame to more or less zero.
    //--------------------------------------------------------------------------

    frameTimer->updateTimes();
    frameTimer->updateTimes();

    //--------------------------------------------------------------------------
    // Run while the run flag is true
    //--------------------------------------------------------------------------

    while ( run )
    {
        window->requestRepaint();   // Request a window repaint
        window->run();              // Do window message processing
    }

    //--------------------------------------------------------------------------
    // Display the end of race screen if the window is not closed
    //--------------------------------------------------------------------------

    if ( window->exists() )
    {
        // Window still in action. show the end of race display.

        Menu_EndRace::display( playerFinishPosition, window );
    }
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Name:     Game::endGame
Purpose:  Frees up all game resources
Params:   none
Returns:  none

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

void Game::endGame()
{
    delete camera;          camera          = 0;    // delete camera
    delete frameTimer;      frameTimer      = 0;    // delete frame timer
    delete background;      background      = 0;    // delete the background
    delete track;           track           = 0;    // delete the games track

    // Remove all AI players

    for ( unsigned int i = 0; i < carCount - 1; i++ )
    {
        delete aiArray[i]; aiArray[i] = 0;
    }

    delete aiArray;         // Remove the AI player array
    delete carArray;        // Remove the car array

    // Delete the color lookup tables for the track sections

    TrackSection::deleteColorLookupTables();

    // Delete all objects held reference to by the game object manager

    GameObjectManager::freeObjects();

    // Free all the game's mipmap resources

    MipmapManager::freeAllMipmaps();

    // Delete the hud images

    delete bmpHudGuageFL; bmpHudGuageFL = 0;
    delete bmpHudGuageFR; bmpHudGuageFR = 0;
    delete bmpHudGuageEL; bmpHudGuageEL = 0;
    delete bmpHudGuageER; bmpHudGuageER = 0;

    // Free up the bitmap font used by the game

    delete bitFont; bitFont = 0;

    // Remove window event handlers

    window->setEvent_paint (0);     // deactivate this event handler
    window->setEvent_closed(0);     // deactivate this event handler

    // run the game no more

    run = false;
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Name:     Game::windowClosed
Purpose:  Called when the window is closed during the game
Params:   Window that was closed
Returns:  none

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

// No unreferenced params warning

#pragma warning (disable:4100)

void Game::windowClosed( Window & window )
{
    // End the game if it is still running

    if ( run ) Game::endGame();
}

// Return this warning to normal

#pragma warning (default:4100)

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Name:     Game::gameLoop
Purpose:  Runs the game loop
Params:   none
Returns:  none

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

void Game::gameLoop(Window & window)
{
    //--------------------------------------------------------------------------
    // Update the current frame rate if it is time:
    //--------------------------------------------------------------------------

    // Update frame timer first

    frameTimer->updateTimes();

    // Add frame time to accumalated frame times

    frameTimesAccum += frameTimer->getTimeSeconds(); frameTimesCounted++;

    // See if it is time to update the current frame rate amount:

    if ( frameTimesCounted >= FRAME_TIME_UPDATE_FRAMES )
    {
        // Average the accumalted frame times:

        frameTimesAccum /= float(FRAME_TIME_UPDATE_FRAMES);

        // Save as current frame time:

        frameTime = frameTimesAccum;

        // Reset everything else:

        frameTimesAccum     = 0;
        frameTimesCounted   = 0;
    }

    //--------------------------------------------------------------------------
    // Do input
    //--------------------------------------------------------------------------

    doInput(window);

    //--------------------------------------------------------------------------
    // If the user hasn't quit then run the game
    //--------------------------------------------------------------------------

    if ( run )
    {
        //----------------------------------------------------------------------
        // Do the AI for all the aiPlayers.let them decide on their next actions
        //----------------------------------------------------------------------

        for ( unsigned int i = 0 ; i < carCount - 1 ; i++ )
        {
            aiArray[i]->makeMove(frameTime);
        }

        //----------------------------------------------------------------------
        // Move all the objects if the race has started
        //----------------------------------------------------------------------

        if ( timeToRaceStart <= 0 )
        {
            //------------------------------------------------------------------
            // Race has begun.. Move everything..
            //------------------------------------------------------------------

            GameObjectManager::moveObjects(frameTime);
        }

        //----------------------------------------------------------------------
        // Get the camera to follow the players car. Players car is first car
        // in the array of cars.
        //----------------------------------------------------------------------

        camera->setPosition
        (
            carArray[0]->getPos_x() + carArray[0]->getVel_x() * CAMERA_CORNER_LEAN,
            carArray[0]->getPos_y() + CAMERA_OFFSET_Y,
            carArray[0]->getPos_z() + CAMERA_OFFSET_Z
        );

        //  DEBUG ONLY: ALLOW CAMERA TO FOLLOW ANY OF THE CARS

        /*

        camera->setPosition
        (
            carArray[carCamNum]->getPos_x() + carArray[carCamNum]->getVel_x() * CAMERA_CORNER_LEAN,
            carArray[carCamNum]->getPos_y() + CAMERA_OFFSET_Y,
            carArray[carCamNum]->getPos_z() + CAMERA_OFFSET_Z
        );

        */

        //----------------------------------------------------------------------
        // Draw the scene
        //----------------------------------------------------------------------

        drawScene(window);

        //----------------------------------------------------------------------
        // Check to see if the player is past the finishing line.
        // If so then set the finishing position of the player and end the game.
        //----------------------------------------------------------------------

        // Get the finish line z value

        float finishZ;

        finishZ  = (float) track->getSections_count();
        finishZ -= Game::RACE_FINISH_SECTION_FROM_END;
        finishZ *= Track::SECTION_SIZE_Z;

        // Now see if the player is past the finish line

        if ( carArray[0]->getPos_z() > finishZ )
        {
            //------------------------------------------------------------------
            // Set the finishing position of the player in the grid
            //------------------------------------------------------------------

            // 1st position initially

            playerFinishPosition = 1;

            // See how many cars are ahead of the player

            for ( unsigned int i = 1; i < carCount; i++ )
            {
                if ( carArray[i]->getPos_z() >= carArray[0]->getPos_z() )
                {
                    // This car is ahead of the players car (car 0). increment position.

                    playerFinishPosition++;
                }
            }

            //------------------------------------------------------------------
            // End the game.
            //------------------------------------------------------------------

            endGame();
        }

    }   // end if (run game)
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Name:     Game::doInput
Purpose:  Does input processing for the game
Params:   game window
Returns:  none

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

void Game::doInput(Window & window)
{
    //--------------------------------------------------------------------------
    // Move the players car: players car is first car in the car array
    //--------------------------------------------------------------------------

    if ( window.keyboardKeyPressed(Window::KEYBOARD_LEFT  ) ) carArray[0]->turnLeft();
    if ( window.keyboardKeyPressed(Window::KEYBOARD_RIGHT ) ) carArray[0]->turnRight();
    if ( window.keyboardKeyPressed(Window::KEYBOARD_UP    ) ) carArray[0]->accelerate();
    if ( window.keyboardKeyPressed(Window::KEYBOARD_SPACE ) ) carArray[0]->brake();

    //--------------------------------------------------------------------------
    // Check for quit key
    //--------------------------------------------------------------------------

    if ( window.keyboardKeyPressed(Window::KEYBOARD_ESCAPE) ) endGame();

    //--------------------------------------------------------------------------
    // Debug: allow camera to be cycled between cars
    //--------------------------------------------------------------------------

    /*

    if ( window.keyboardKeyPressed(Window::KEYBOARD_PAGE_UP ) )
    {
        carCamNum++;

        if  ( unsigned(carCamNum) > carCount - 1 ) carCamNum = carCount - 1;
    }

    if ( window.keyboardKeyPressed(Window::KEYBOARD_PAGE_DOWN ) )
    {
        carCamNum--;

        if  ( carCamNum < 0 ) carCamNum = 0;
    }

    */
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Name:     Game::drawScene
Purpose:  Initialises the track and randomly generates it
Params:   none
Returns:  none

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

void Game::drawScene(Window & window)
{

    //--------------------------------------------------------------------------
    // Draw the background
    //--------------------------------------------------------------------------

    background->draw(window,frameTime);

    //--------------------------------------------------------------------------
    // Draw the track
    //--------------------------------------------------------------------------

    track->draw(window,camera);

    //--------------------------------------------------------------------------
    // Get the position amongst the other cars the player car is..
    //--------------------------------------------------------------------------

    // 1st position initially

    int position = 1;

    // See how many cars are ahead of the player

    for ( unsigned int i = 1; i < carCount; i++ )
    {
        if ( carArray[i]->getPos_z() >= carArray[0]->getPos_z() )
        {
            // This car is ahead of the players car (car 0).. increment position

            position++;
        }
    }

    //--------------------------------------------------------------------------
    // Make up a null terminated string with the position text
    //--------------------------------------------------------------------------

    // Null terminate the array.

    char positionText[16] = {0};

    // Convert the position number to a string. number is in base 10.
    
    sprintf_s(positionText,16,"%i",position);

    // Now decide what post fix to append to the string

    if ( position % 10 == 1 && ( position < 10 || position > 20 ) )
    {
        // in position-st position

        strcat_s(positionText,16,"st");
    }
    else if ( position % 10 == 2 && ( position < 10 || position > 20 ) )
    {
        // in position-nd position

        strcat_s(positionText,16,"nd");
    }
    else if ( position % 10 == 3 && ( position < 10 || position > 20 ) )
    {
        // in position-rd position

        strcat_s(positionText,16,"rd");
    }
    else
    {
        // in position-th position

        strcat_s(positionText,16,"th");
    }

    // Figure out the lenght of the position text

    int positionTextLenght = strlen(positionText);

    //--------------------------------------------------------------------------
    // Draw the position text at the top right of the screen
    //--------------------------------------------------------------------------

    bitFont->drawText
    (
        positionText,                                                           // text to draw
        RESOLUTION_X / 2 - ( positionTextLenght *  bitFont->getWidth() ) / 2,   // x position
        0,                                                                      // y position
        &window                                                                 // pointer to window to draw to
    );

    //--------------------------------------------------------------------------
    // Get the players speed
    //--------------------------------------------------------------------------

    float playerSpeed;

    playerSpeed  = carArray[0]->getVel_x() * carArray[0]->getVel_x();
    playerSpeed  = carArray[0]->getVel_z() * carArray[0]->getVel_z();
    playerSpeed  = sqrt(playerSpeed);

    //--------------------------------------------------------------------------
    // Divide the players speed by some amount then multiply by the width of
    // the gauage image to get how much of the 'full' speed guage to show.
    //--------------------------------------------------------------------------

    // Get width of the full guage

    int fullGuageWidth = int( ( playerSpeed / 75000.0f ) * bmpHudGuageFL->getWidth() );

    // Clamp maximum amount of full gauage to show to the width of the full gauage image

    if ( fullGuageWidth > bmpHudGuageFL->getWidth() )
    {
        fullGuageWidth = bmpHudGuageFL->getWidth();
    }

    //--------------------------------------------------------------------------
    // Draw the left speed guage
    //--------------------------------------------------------------------------

    // Draw the full part of the guage: whatever width it is

    window.drawBitmapSection
    (
        bmpHudGuageFL,              // bitmap to draw
        0,                          // destination x
        0,                          // destination y
        0,                          // source x
        0,                          // source y
        fullGuageWidth,             // source width
        bmpHudGuageFL->getHeight()  // source height
    );

    // Draw the empty part of the guage: whatever width it is

    window.drawBitmapSection
    (
        bmpHudGuageEL,                                  // bitmap to draw
        fullGuageWidth,                                 // destination x
        0,                                              // destination y
        fullGuageWidth,                                 // source x
        0,                                              // source y
        bmpHudGuageEL->getWidth() - fullGuageWidth,     // source width
        bmpHudGuageEL->getHeight()                      // source height
    );

    //--------------------------------------------------------------------------
    // Draw the right speed guage
    //--------------------------------------------------------------------------

    // Draw the full part of the guage: whatever width it is

    window.drawBitmapSection
    (
        bmpHudGuageFR,                              // bitmap to draw
        RESOLUTION_X - fullGuageWidth,              // destination x
        0,                                          // destination y
        bmpHudGuageFR->getWidth() - fullGuageWidth, // source x
        0,                                          // source y
        fullGuageWidth,                             // source width
        bmpHudGuageFR->getHeight()                  // source height
    );

    // Draw the empty part of the guage: whatever width it is

    window.drawBitmapSection
    (
        bmpHudGuageER,                              // bitmap to draw
        RESOLUTION_X - bmpHudGuageER->getWidth(),   // destination x
        0,                                          // destination y
        0,                                          // source x
        0,                                          // source y
        bmpHudGuageER->getWidth() - fullGuageWidth, // source width
        bmpHudGuageFR->getHeight()                  // source height
    );

    //--------------------------------------------------------------------------
    // If the race is beginning then draw the countdown. If the race has
    // just started then display the 'go' prompt for a little while..
    //--------------------------------------------------------------------------

    if ( timeToRaceStart > 0 )
    {
        //----------------------------------------------------------------------
        // Race has not started: display the countdown.
        //----------------------------------------------------------------------

        // Convert time to race start to an integer and add 1 to the count.

        int countTime = int(timeToRaceStart) + 1;

        // Convert the countdown time to a string

        char countString[16]={0}; sprintf_s(countString,16,"%i",countTime);

        // Draw the countdown centered in the middle of the screen

        bitFont->drawText
        (
            countString,
            RESOLUTION_X / 2 - bitFont->getWidth () / 2,
            RESOLUTION_Y / 2 - bitFont->getHeight() / 2,
            &window
        );

        // Decrease time left till race starts by frame time

        timeToRaceStart -= frameTimer->getTimeSeconds();
    }
    else if ( timeToGoPromptEnd > 0 )
    {
        //----------------------------------------------------------------------
        // The race has started but its still time to display the 'go'
        // prompt.
        //----------------------------------------------------------------------

        // Display the 'go' prompt centered in the screen

        bitFont->drawText
        (
            "GO!",
            RESOLUTION_X / 2 - (bitFont->getWidth ()*3) / 2,
            RESOLUTION_Y / 2 - (bitFont->getHeight()*1) / 2,
            &window
        );

        // Decrement the time left to display the go prompt by frame time

        timeToGoPromptEnd -= frameTimer->getTimeSeconds();
    }

}

