/*
	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:   Track
// Purpose:      Track generation, organisation of track sections and drawing.
//               Management and moving of track entities.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "Track.h"
#include "PI.h"

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

const float Track::SECTION_SIZE_X       = 4500.0f;      // X size of each section (normally)
const float Track::SECTION_SIZE_Z       = 3000.0f;      // Z size of each section
const float Track::SECTION_LINE_SIZE_X  = 50.0f;        // X size of the road lines
const float Track::VIEW_PLANE_NEAR      = 1.0f;         // view volume plane z distance from camera: near
const float Track::VIEW_PLANE_FAR       = 175000.0f;    // view volume plane z distance from camera: far
const float Track::LINE_CULL_DISTANCE   = 75000.0f;     // Distance to avoid drawing lines at

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

Name:     Track::Track
Purpose:  Constructs the track
Params:   as commented
Returns:  n/a

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

Track::Track
(
    unsigned    lenght,             // lenght of the track (in sections)
    float       minHillHeight,      // minimum height of a hill
    float       maxHillHeight,      // maximum height of a hill
    float       minTurnAmount,      // minimum turn amount
    float       maxTurnAmount       // maximum turn amount
)
{
    //--------------------------------------------------------------------------
    // Validate parameters
    //--------------------------------------------------------------------------

    if ( lenght < 256   ) lenght = 256;     // Don't allow lenght < 256
    if ( lenght > 65535 ) lenght = 65535;   // Don't allow lenght > 65535

    //--------------------------------------------------------------------------
    // Set the lenght of the track
    //--------------------------------------------------------------------------

    this->sections_count = lenght;

    //--------------------------------------------------------------------------
    // Create the array of pointers to the track sections
    //--------------------------------------------------------------------------

    this->sections_array = new TrackSection * [lenght];

    //--------------------------------------------------------------------------
    // Create temporary arrays to hold the x,y,z values for each section of the
    // track as we are creating it
    //--------------------------------------------------------------------------

    float * track_l_x = new float[lenght+1];     // x values for left  side of each track section
    float * track_r_x = new float[lenght+1];     // x values for right side of each track section
    float * track_y   = new float[lenght+1];     // y values for each track section

    //--------------------------------------------------------------------------
    // Initialise the x,y,z values for each track section to the defaults.
    // This code basically creates a dead level, straight track.
    //--------------------------------------------------------------------------

    // Get this constant like this to work around stupid GCC linker: if used within the for loop the linker complains! why??

    float size_x = SECTION_SIZE_X;

    // Set the xyz values for each section of the track

    for ( unsigned int i = 0 ; i < sections_count + 1  ; i++ )
    {
        // Set the xyz values for the section

        track_l_x[i] = -size_x / 2;       // set left  x value
        track_r_x[i] = +size_x / 2;       // set right x value
        track_y[i]   = 0;                 // set y value
    }

    //--------------------------------------------------------------------------
    // Generate hills for the track
    //--------------------------------------------------------------------------

    generateHills
    (
        track_y,                                            // array holding y coordinates for each section of the track
        Game::HILLS_TURNS_START_FROM_START,                 // section number: where to start generating hills
        sections_count - Game::HILLS_TURNS_END_FROM_END,    // section number: where to end   generating hills
        8,                                                  // minimum lenght of one particular stretch of a hill (in track sections)
        32,                                                 // maximum lenght of one particular stretch of a hill (in track sections)
        minHillHeight,                                      // minimum positive/negative height of one particular stretch of a hill
        maxHillHeight                                       // maximum positive/negative height of one particular stretch of a hill
    );

    //--------------------------------------------------------------------------
    // Generate curves for the track
    //--------------------------------------------------------------------------

    generateTurns
    (
        track_l_x,                                          // array holding left  x coordinates for each section of the track
        track_r_x,                                          // array holding right x coordinates for each section of the track
        Game::HILLS_TURNS_START_FROM_START,                 // section number: where to start generating turns
        sections_count - Game::HILLS_TURNS_END_FROM_END,    // section number: where to end   generating turns
        9,                                                  // minimum lenght of one particular stretch of a turn (in track sections)
        36,                                                 // maximum lenght of one particular stretch of a turn (in track sections)
        minTurnAmount,                                      // minimum positive/negative turn amount for one particular turn
        maxTurnAmount                                       // maximum positive/negative turn amount for one particular turn
    );

    //--------------------------------------------------------------------------
    // Create the actual track section objects from our set of xyz values
    //--------------------------------------------------------------------------

    for ( unsigned int i = 0 ; i < sections_count ; i++ )
    {
        // Create this track segment

        sections_array[i] = new TrackSection
            (
            i,                  // Section number of the track
            track_l_x[i+1],     // front left  of section:  x value
            track_r_x[i+1],     // front right of section:  x value
            track_l_x[i],       // back  left  of section:  x value
            track_r_x[i],       // front right of section:  x value
            track_y[i+1],       // front of section:        y value
            track_y[i]          // back  of section:        y value
            );
    }

    //--------------------------------------------------------------------------
    // Now done with these: cleanup
    //--------------------------------------------------------------------------

	delete[] track_l_x;
	delete[] track_r_x;
	delete[] track_y;
}

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

Name:     Track::~Track
Purpose:  Track destructor: frees the tracks used resources.
Params:   n/a
Returns:  n/a

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

Track::~Track()
{
    // Delete each track section

    for ( unsigned int i = 0 ; i < sections_count ; i++ )
    {
        // Free this particular section from ram

        delete sections_array[i];
    }

    // Delete the array of pointers to track sections

    delete sections_array;
}

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

Name:     Track::draw
Purpose:  Draws the track
Params:   Window to draw to, camera position to draw from
Returns:  none

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

void Track::draw(Window & window, Camera * viewpoint)
{
    // Figure out which track sections to draw or which fall within view range

    int draw_s = (int)(  viewpoint->getZ() / Track::SECTION_SIZE_Z );                               // start drawing at this section
    int draw_e = (int)(( viewpoint->getZ() + Track::VIEW_PLANE_FAR ) / (Track::SECTION_SIZE_Z ));   // end drawing at this section

    // Clamp start section to 0

    draw_s = draw_s < 0 ? 0 : draw_s;

    // Clamp end section to the last section of the track

    draw_e = draw_e >= (int)(sections_count) ? sections_count - 1 : draw_e;

    // If end section is less than zero then return

    if ( draw_e < 0 ) return;

    // If start section is over the end of the track then abort

    if ( draw_s >= (int)(sections_count) ) return;

    // Draw each section of the track: sections self cull with respect to view planes

    for ( int i = draw_e ; i >= draw_s  ; i-- )
    {
        // Draw this section of the track

        sections_array[i]->draw(window,viewpoint);
    }
}

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

Name:     Track::getY
Purpose:  Gets the y value (aka height) of the track at a particular z value
Params:   Z value to query height at
Returns:  none

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

float Track::getY(float z)
{
    // If z is less than zero then use the back height of the first section

    if ( z < 0 ) return sections_array[0]->get_b_y();

    // If z is greater than or equal to track lenght then use the height at the end of the last section

    if ( z >= Track::SECTION_SIZE_Z * sections_count ) return sections_array[sections_count-1]->get_f_y();

    // Otherwise calculate what section we are on

    unsigned int section = (unsigned int)( z / SECTION_SIZE_Z );

    // Figure out the percentage z is along the lenght of the section

    z -= section * SECTION_SIZE_Z;   // Get z relative to the start of the section
    z /= SECTION_SIZE_Z;             // Divide it by section lenght to get how far along (percent) the section the z value is

    // Now use interpolation between back and front y values and z percentage to get height

    return ( (1.0f - z) * sections_array[section]->get_b_y() + sections_array[section]->get_f_y() * z );
}

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

Name:     Track::getLX
Purpose:  Gets the left x value of the tarmac part of the track at a particular z value
Params:   Z value to query left x value at
Returns:  none

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

float Track::getLX(float z)
{
    // If z is less than zero then use the back left x value of the first section

    if ( z < 0 ) return sections_array[0]->get_bl_x();

    // If z is greater than or equal to track lenght then use the left x value at the end of the last section

    if ( z >= Track::SECTION_SIZE_Z * sections_count ) return sections_array[sections_count-1]->get_fl_x();

    // Otherwise calculate what section we are on

    unsigned int section = (unsigned int)( z / SECTION_SIZE_Z );

    // Figure out the percentage z is along the lenght of the section

    z -= section * SECTION_SIZE_Z;   // Get z relative to the start of the section
    z /= SECTION_SIZE_Z;             // Divide it by section lenght to get how far along (percent) the section the z value is

    // Now use interpolation between back and front left x values and z percentage to get left x value

    return ( (1.0f - z) * sections_array[section]->get_bl_x() + sections_array[section]->get_fl_x() * z );
}

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

Name:     Track::getRX
Purpose:  Gets the right x value of the tarmac part of the track at a particular z value
Params:   Z value to query right x value at
Returns:  none

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

float Track::getRX(float z)
{
    // If z is less than zero then use the back right x value of the first section

    if ( z < 0 ) return sections_array[0]->get_br_x();

    // If z is greater than or equal to track lenght then use the right x value at the end of the last section

    if ( z >= Track::SECTION_SIZE_Z * sections_count ) return sections_array[sections_count-1]->get_fr_x();

    // Otherwise calculate what section we are on

    unsigned int section = (unsigned int)( z / SECTION_SIZE_Z );

    // Figure out the percentage z is along the lenght of the section

    z -= section * SECTION_SIZE_Z;   // Get z relative to the start of the section
    z /= SECTION_SIZE_Z;             // Divide it by section lenght to get how far along (percent) the section the z value is

    // Now use interpolation between back and front right x values and z percentage to get left x value

    return ( (1.0f - z) * sections_array[section]->get_br_x() + sections_array[section]->get_fr_x() * z );
}

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

Name:     Track::generateHills
Purpose:  Generate hills along a specified section of the track.
Params:   As commented.
Returns:  none

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

void Track::generateHills
(
    float *             track_y,             // y coordinates for each section of the track
    const unsigned int  HILLS_START,         // section number: where to start generating hills
    const unsigned int  HILLS_END,           // section number: where to end   generating hills
    const unsigned int  HILL_LENGHT_MIN,     // minimum lenght of one particular stretch of a hill (in track sections)
    const unsigned int  HILL_LENGHT_MAX,     // maximum lenght of one particular stretch of a hill (in track sections)
    const float         HILL_HEIGHT_MIN,     // minimum positive/negative height of one particular stretch of a hill
    const float         HILL_HEIGHT_MAX      // maximum positive/negative height of one particular stretch of a hill
)
{
    //--------------------------------------------------------------------------
    // current section to start generating hill stretch at
    //--------------------------------------------------------------------------

    unsigned int hill_start = HILLS_START;

    //--------------------------------------------------------------------------
    // Keep generating hill stretches until reached end of area to generate hills over
    //--------------------------------------------------------------------------

    while ( hill_start < HILLS_END )
    {
        //----------------------------------------------------------------------
        // Decide on lenght of hill stretch
        //----------------------------------------------------------------------

        // Randomnly decide how long the hill should be in sections

        unsigned int hill_lenght;

        hill_lenght  = rand();                                  // pick a random number
        hill_lenght %= HILL_LENGHT_MAX - HILL_LENGHT_MIN + 1;   // map the number to lenght range
        hill_lenght += HILL_LENGHT_MIN;                         // map the number to lenght interval begining

        // See if the desired hill extends beyond the last section where hills can be made, if so then abort

        if ( hill_start + hill_lenght >= HILLS_END ) break;

        //----------------------------------------------------------------------
        // Decide on height of the hill
        //----------------------------------------------------------------------

        // Randomnly decide on a float in range of values between HILL_HEIGHT_MIN and MAX

        float hill_height;

        hill_height  = ( rand() & 0xffffff ) / (float)(0xffffff);   // get a random float between 0.0-1.0
        hill_height *= HILL_HEIGHT_MAX - HILL_HEIGHT_MIN;           // Scale float to hill height range
        hill_height += HILL_HEIGHT_MIN;                             // Translate float to hill height interval

        // Now randomly decide if the hill is going up or down

        if ( rand() & 1 ) hill_height *= -1;

        //----------------------------------------------------------------------
        // Generate the curve for the hill
        //----------------------------------------------------------------------

        for ( unsigned int track_section = hill_start; track_section <= hill_start + hill_lenght; track_section++ )
        {
            //------------------------------------------------------------------
            // Curve is basically generated by taking the resulting output of the
            // sine function for a 180 degree range of evenly spaced input values
            // and scaling them to the height of the hill stretch.
            //------------------------------------------------------------------

            // First decide on input angle to sine function

            float angle;

            angle  = M_PI;                      // 180 degrees is the maximum value input of the sine function and represents the end of the hill curve
            angle /= hill_lenght;               // Get the change in angle along each track section of the hill curve
            angle *= track_section-hill_start;  // Get what angle corresponds to the current section we are on
            angle += M_PI_2;                    // Add 90 degrees to the function input to get to a point where the output values smoothly decrease. want smooth start to curve.

            // Now figure out the height of the current track section

            float height;

            height  = hill_height*0.5f;               // Height value of the middle point along the curve
            height -= (float)sin(angle) * (height);   // Get sine of angle and scale to middle point height, since sine will range from 1 to -1 over this interval

            // Set the height at this point in the track

            track_y[track_section] += height;
        }

        //----------------------------------------------------------------------
        // Add the height of this hill to the rest of the track, such that the
        // change in height caused by the new hill is propogated along the rest of the track
        //----------------------------------------------------------------------

        for ( unsigned int track_section = hill_start + hill_lenght + 1;  track_section < this->sections_count + 1 ; track_section++ )
        {
            track_y[track_section] += hill_height;
        }

        //----------------------------------------------------------------------
        // Move the current section to generate hill at past the newly generated
        // hill stretch.
        //----------------------------------------------------------------------

        hill_start += hill_lenght;

    } // end of generate hills loop
}

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

Name:     Track::generateTurns
Purpose:  Generate turns along a specified section of the track. nasty...
Params:   As commented.
Returns:  none

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

void Track::generateTurns
(
    float * track_l_x,                     // array holding left  x coordinates for each section of the track
    float * track_r_x,                     // array holding right x coordinates for each section of the track
    const unsigned int  TURNS_START,       // section number: where to start generating turns
    const unsigned int  TURNS_END,         // section number: where to end   generating turns
    const unsigned int  TURN_LENGHT_MIN,   // minimum lenght of one particular stretch of a turn (in track sections)
    const unsigned int  TURN_LENGHT_MAX,   // maximum lenght of one particular stretch of a turn (in track sections)
    const float         TURN_AMOUNT_MIN,   // minimum positive/negative amount along x axis a turn must go
    const float         TURN_AMOUNT_MAX    // maximum positive/negative amount along x axis a turn must go
)
{
    //--------------------------------------------------------------------------
    // current section to start generating turn stretch at
    //--------------------------------------------------------------------------

    unsigned int turn_start = TURNS_START;

    //--------------------------------------------------------------------------
    // Keep generating turn stretches until reached end of area to generate turns over
    //--------------------------------------------------------------------------

    while ( turn_start < TURNS_END )
    {
        //----------------------------------------------------------------------
        // Decide on lenght of the turn stretch
        //----------------------------------------------------------------------

        // Randomnly decide how long the turn should be in sections

        unsigned int turn_lenght;

        turn_lenght  = rand();                                  // pick a random number
        turn_lenght %= TURN_LENGHT_MAX - TURN_LENGHT_MIN + 1;   // map the number to lenght range
        turn_lenght += TURN_LENGHT_MIN;                         // map the number to lenght interval begining
        turn_lenght -= turn_lenght % 3;                         // turn lenght has to be multiple of 3 because of the way turn is generated

        // See if the desired turn extends beyond the last section where turns can be made, if so then abort

        if ( turn_start + turn_lenght >= TURNS_END ) break;

        //----------------------------------------------------------------------
        // Decide on amount of the turn
        //----------------------------------------------------------------------

        // Randomnly decide on a float in range of values between TURN_AMOUNT_MIN and MAX

        float turn_amount;

        turn_amount  = (float)( rand() & 0xffffff ) / (float)(0xffffff);    // get a random float between 0.0-1.0
        turn_amount *= TURN_AMOUNT_MAX - TURN_AMOUNT_MIN;                   // Scale float to turn amount range
        turn_amount += TURN_AMOUNT_MIN;                                     // Translate float to turn amount interval

        // Now randomly decide if the turn is going left or right

        if ( rand() & 1 ) turn_amount *= -1;

        //----------------------------------------------------------------------
        // Crap attempt at explanation of turn generation code:
        //
        // (SEE "\code diagram suplements\turns.bmp" for much better graphical diagram of turns)
        //
        // Basically the number of sections a turn will stretch over and the amount
        // that the turn will take are decided first. I imagine then a straight line going
        // from the start of the turn (on the left) to the end of the turn (on the left)
        // and and imagine points at 1/3rd and 2/3rds of the way along the line. The end
        // of the turn's x position is simply the start of the turns x-position plus the
        // turn amount.
        //
        // If the turn is going left:
        //
        // For the first 1/3rd of the turn's sections, x coordinates are evaluated on a scaled 90 degree
        // quarter circle at each track section. The quarter circles x values are a product of the sine function.
        // The circle section has an x-size of 1/3 of the turn amount, and z-size of
        // 1/3 of the lenght of the turn. The circle section veers leftwards, gently at first then steeply.
        // The circle begins at the first turn section's left x position and ends at the x position
        // 1/3 of the way along the previously imagined line.
        //
        // X coordinates are then evaluated for the remaining 2/3rds of the track in a similar fashion
        // along another 1/4 circle.
        //
        // If the turn is going right:
        //
        // Evaluate points on a scaled 1/4 circle similar to the left turn case, only
        // this time the first scaled 1/4 circle ends at 2/3rds the distance along
        // the imaginary line. X coordinates are then evaluated along another 1/4 circle,
        // starting at 2/3rds the way along the imaginary line and ending at the end.
        //
        // The right hand side x value is the value of the left plus the road width.
        //
        //----------------------------------------------------------------------

        //----------------------------------------------------------------------
        // Generate the curve differently depending which way bend is going
        //----------------------------------------------------------------------

        if ( turn_amount < 0 )
        {
            //------------------------------------------------------------------
            // Generate the first part of the curve on the left side of the road
            //------------------------------------------------------------------

            {
                // Calculate the start and end section of this curve part

                unsigned int part_start =  turn_start;
                unsigned int part_end   =  turn_start + ( turn_lenght / 3 );

                // Go ahead and generate the curve

                for ( unsigned int section = part_start; section < part_end ; section++ )
                {
                    // Calculate input angle into sine function:

                    float angle;

                    angle  = (float)(M_PI_2);               // 90 circle section
                    angle /= (float)(part_end-part_start);  // get number of degrees change per track section
                    angle *= (float)(section -part_start);  // get number of degrees along circle this section is
                    angle += (M_PI_2);                      // add 90 degrees to sine function to get intially smooth change in values

                    // Calculate change in x from original x value at track section

                    float delta_x;

                    delta_x  = 1.0f - (float)(sin(angle));
                    delta_x *= turn_amount * 0.333333f;

                    // Add to track x coordinate and copy and set the right side to x coordinate on left + track width

                    track_l_x[section] += delta_x;
                    track_r_x[section]  = track_l_x[section] + Track::SECTION_SIZE_X;
                }
            }

            //------------------------------------------------------------------
            // Generate the second part of the curve on the left side of the road
            //------------------------------------------------------------------

            {
                // Calculate the start and end section of this curve part

                unsigned int part_start =  turn_start + ( turn_lenght / 3 );
                unsigned int part_end   =  turn_start +  turn_lenght;

                // Go ahead and generate the curve

                for ( unsigned int section = part_start; section <= part_end ; section++ )
                {
                    // Calculate input angle into sine function:

                    float angle;

                    angle  = (float)(M_PI_2);               // 90 circle section
                    angle /= (float)(part_end-part_start);  // get number of degrees change per track section
                    angle *= (float)(section -part_start);  // get number of degrees along circle this section is
                    angle += (M_PI);                        // add 180 degrees to sine function to get intially abrupt change in x valuies

                    // Add to track x coordinate and copy and set the right side to x coordinate on left + track width

                    float delta_x;

                    delta_x  = -(float)(sin(angle));
                    delta_x *= turn_amount * 0.666666f;

                    track_l_x[section] += delta_x + turn_amount * 0.333333f;
                    track_r_x[section]  = track_l_x[section] + Track::SECTION_SIZE_X;
                }
            }

        }
        else
        {
            //------------------------------------------------------------------
            // bend is going right or straight
            //------------------------------------------------------------------

            //------------------------------------------------------------------
            // Generate the first part of the curve on the left side of the road
            //------------------------------------------------------------------

            {
                // Calculate the start and end section of this curve part

                unsigned int part_start =  turn_start;
                unsigned int part_end   =  turn_start + ( turn_lenght / 3 ) * 2;

                // Go ahead and generate the curve

                for ( unsigned int section = part_start; section < part_end ; section++ )
                {
                    // Calculate input angle into sine function:

                    float angle;

                    angle  = (float)(M_PI_2);               // 90 circle section
                    angle /= (float)(part_end-part_start);  // get number of degrees change per track section
                    angle *= (float)(section -part_start);  // get number of degrees along circle this section is
                    angle += (M_PI_2);                      // add 90 degrees to sine function to get intially smooth change in values

                    // Add to track x coordinate and copy and set the right side to x coordinate on left + track width

                    float delta_x;

                    delta_x  = 1.0f - (float)(sin(angle));
                    delta_x *= turn_amount * 0.666666f;

                    track_l_x[section] += delta_x;
                    track_r_x[section]  = track_l_x[section] + Track::SECTION_SIZE_X;
                }
            }

            //------------------------------------------------------------------
            // Generate the second part of the curve on the left side of the road
            //------------------------------------------------------------------

            {
                // Calculate the start and end section of this curve part

                unsigned int part_start =  turn_start + ( turn_lenght / 3 ) * 2;
                unsigned int part_end   =  turn_start +  turn_lenght;

                // Go ahead and generate the curve

                for ( unsigned int section = part_start; section <= part_end ; section++ )
                {
                    // Calculate input angle into sine function:

                    float angle;

                    angle  = (float)(M_PI_2);               // 90 circle section
                    angle /= (float)(part_end-part_start);  // get number of degrees change per track section
                    angle *= (float)(section -part_start);  // get number of degrees along circle this section is
                    angle += (M_PI);                        // add 180 degrees to sine function to get intially abrupt change in x valuies

                    // Add to track x coordinate and copy and set the right side to x coordinate on left + track width

                    float delta_x;

                    delta_x  = -(float)(sin(angle));
                    delta_x *= turn_amount * 0.333333f;

                    track_l_x[section] += delta_x + turn_amount * 0.666666f;
                    track_r_x[section]  = track_l_x[section] + Track::SECTION_SIZE_X;
                }
            }

        } // end if ( turn_amount < 0 )

        //----------------------------------------------------------------------
        // Add the amount of this curve to the rest of the track, such that the
        // change in x values caused by the new curve is propogated along the rest of the track
        //----------------------------------------------------------------------

        for ( unsigned int track_section = turn_start + turn_lenght + 1;  track_section < this->sections_count + 1 ; track_section++ )
        {
            track_l_x[track_section] += turn_amount;    // add to left  x value for section
            track_r_x[track_section] += turn_amount;    // add to right x value for section
        }


        //----------------------------------------------------------------------
        // Move the current section to generate hill at past the newly generated
        // hill stretch.
        //----------------------------------------------------------------------

        turn_start += turn_lenght;

    } // end of generate turns loop
}
