#include "../include/circuit.h"
#include "../include/segment.h"
#include "../include/camera.h"
#include "../include/clouds.h"
#include "../include/cars.h"

#include "../parameters.h"

#include <gint/display.h>
#include <gint/std/stdlib.h>
#include <gint/rtc.h>

#include "../include/drawstuff.h"
#include "../colors.h"
#include "../include/utils.h"

#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <gint/kmalloc.h>
#include <stdio.h>


extern uint16_t NB_CARS_TRAFFIC;

extern std::vector<Segment*> circuit;
extern std::vector<Clouds*> nuages;
extern std::vector<Cars*> traffic;
extern std::vector<MileStone*> jalons;

extern camera *cam;
extern uint16_t currentcurve;
extern uint8_t shiftcolor;
extern int MAX_SEGMENT;
extern bool ShowDebug1;


extern bopti_image_t car1, car2, car3, car4, car5, car6, car7, car8;

extern bopti_image_t pl_tree1, pl_tree2, pl_tree3, pl_tree4, dt_tree1, dt_tree2, dt_tree3, dt_tree4, us_tree1, us_tree2, us_tree4, fi_tree1, fi_tree2, fi_tree4, af_tree1, af_tree2, af_tree3;
extern bopti_image_t cc_void, us_bigleaf, us_smallleaf, cc_bigleaf, cc_smallleaf, cc_rocks, af_bigleaf, dt_smallleaf, fi_rocks;

extern bopti_image_t sky1, sky2, sky3;
extern bopti_image_t mountain, canyon, snowmount, kilimandjaro, dunes;
extern bopti_image_t treeline, rockline, treelinesnow;
extern bopti_image_t leftturn, rightturn, uphill, downhill;
extern bopti_image_t checkpoint, startlights, stoplights, waitlights;


bopti_image_t *scaledTrees[NB_TREES_TYPES][MAX_SUBIMAGES_TREES] = { 0 };
bopti_image_t *scaledCars[NB_CARS_TYPES][MAX_SUBIMAGES_CARS] = { 0 };


extern int CurrentCircuitBiome;

extern int DiffLevel;


void initData( void )
{
    cam = new camera();
    cam->cX = fixdouble(0.0f);
    cam->cY = fixdouble(350.0f);
    cam->cZ = fixdouble(100.0f);
}


void createCircuit( int circuitNumber )
{
    if (circuitNumber==0)
    {
        addStraightLine( L_VERYSHORT, PLAINS );
        addStartLine( PLAINS, 70 );                 // Start = 0s

        addStraightLine( L_VERYLONG, PLAINS );
        addCurve( L_LONG, C_EASY, LEFT_CURVE, PLAINS );
        addCurve( L_LONG, C_EASY, RIGHT_CURVE, PLAINS );
        addCurve( L_LONG, C_EASY, LEFT_CURVE, PLAINS );
        addStraightLine( L_MEDIUM, PLAINS );
        addCheckPoint( PLAINS, 55 );                // time around 66s

        addStraightLine( L_MEDIUM, PLAINS );
        addHill( L_MEDIUM, H_SMALL, UP_HILL, PLAINS );
        addHill( L_MEDIUM, H_SMALL, DOWN_HILL, PLAINS );
        addCurve( L_LONG, C_EASY, RIGHT_CURVE, PLAINS );
        addStraightLine( L_VERYLONG, PLAINS );
        addCheckPoint( PLAINS, 20 );                // time around 188s = Delta: 67s

        addStraightLine( L_VERYSHORT, PLAINS );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, PLAINS );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, PLAINS );
        addStraightLine( L_VERYSHORT, PLAINS );
        addCheckPoint( PLAINS, 55 );                // time around 204s = Delta: 16s

        addStraightLine( L_MEDIUM, PLAINS );
        addHill( L_MEDIUM, H_SMALL, UP_HILL, PLAINS );
        addHill( L_MEDIUM, H_SMALL, DOWN_HILL, PLAINS );
        addCurve( L_LONG, C_EASY, RIGHT_CURVE, PLAINS );
        addStraightLine( L_VERYLONG, PLAINS );

        addFinishLine( PLAINS, 0 );                 // time around 326s = Delta: 67s
        addStraightLine( L_VERYSHORT, PLAINS );
    }
    else if (circuitNumber==1)
    {
        addStraightLine( L_VERYSHORT, DESERT );
        addStartLine( DESERT, 55 );                 // Start = 0s

        addStraightLine( L_LONG, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, DESERT );
        addStraightLine( L_LONG, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, RIGHT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCurve( L_MEDIUM, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCheckPoint( DESERT, 45 );

        addStraightLine( L_VERYSHORT, DESERT );
        addHill( L_MEDIUM, H_BIG, UP_HILL, DESERT );
        addStraightLine( L_LONG, DESERT );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, DESERT );
        addCurve( L_SHORT, C_EASY, LEFT_CURVE, DESERT );
        addStraightLine( L_LONG, DESERT );
        addCheckPoint( DESERT, 40 );

        addStraightLine( L_VERYSHORT, DESERT );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addHill( L_MEDIUM, H_BIG, UP_HILL, DESERT );
        addStraightLine( L_LONG, DESERT );
        addCheckPoint( DESERT, 28 );

        addStraightLine( L_VERYSHORT, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_EASY, RIGHT_CURVE, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCheckPoint( DESERT, 29 );

        addStraightLine( L_VERYSHORT, DESERT );
        addCurve( L_SHORT, C_HARD, LEFT_CURVE, DESERT );
        addCurve( L_SHORT, C_HARD, RIGHT_CURVE, DESERT );
        addStraightLine( L_LONG, DESERT );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );


        addFinishLine( DESERT, 0 );
        addStraightLine( L_VERYSHORT, DESERT );
    }
    else if (circuitNumber==2)
    {
        addStraightLine( L_VERYSHORT, USA );
        addStartLine( USA, 35 );

        addStraightLine( L_VERYSHORT, USA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, USA );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, USA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, USA );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, USA );
        addCurvyHill( L_MEDIUM, H_MEDIUM, UP_HILL, C_HARD, LEFT_CURVE, USA );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, RIGHT_CURVE, USA );
        addStraightLine( L_SHORT, USA );
        addCheckPoint( USA, 60 );


        addStraightLine( L_LONG, USA );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, USA );
        addStraightLine( L_VERYSHORT, USA );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, LEFT_CURVE, USA );
        addStraightLine( L_VERYSHORT, USA );
        addCurve( L_LONG, C_MEDIUM, LEFT_CURVE, USA );
        addHill( L_MEDIUM, H_BIG, UP_HILL, USA );
        addStraightLine( L_VERYSHORT, USA );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, USA );
        addStraightLine( L_VERYSHORT, USA );
        addCheckPoint( USA, 62 );


        addStraightLine( L_VERYLONG, USA );
        addCurve( L_LONG, C_EASY, LEFT_CURVE, USA );
        addCurve( L_LONG, C_EASY, RIGHT_CURVE, USA );
        addCurve( L_LONG, C_EASY, LEFT_CURVE, USA );
        addStraightLine( L_MEDIUM, USA );

        addFinishLine( USA, 0 );
        addStraightLine( L_VERYSHORT, USA );
    }
    else if (circuitNumber==3)
    {
        addStraightLine( L_VERYSHORT, FINLAND );
        addStartLine( FINLAND, 30 );

        addStraightLine( L_SHORT, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_EASY, LEFT_CURVE, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_MEDIUM, LEFT_CURVE, FINLAND );
        addStraightLine( L_VERYSHORT, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, FINLAND );
        addStraightLine( L_VERYSHORT, FINLAND );
        addCheckPoint( FINLAND, 90 );

        addStraightLine( L_VERYSHORT, FINLAND );
        addCurve( L_SHORT, C_HARD, LEFT_CURVE, FINLAND );
        addCurve( L_SHORT, C_HARD, RIGHT_CURVE, FINLAND );
        addStraightLine( L_LONG, FINLAND );
        addHill( L_MEDIUM, H_BIG, UP_HILL, FINLAND );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, FINLAND );
        addStraightLine( L_VERYLONG, FINLAND );
        addCurve( L_SHORT, C_HARD, LEFT_CURVE, FINLAND );
        addStraightLine( L_VERYLONG, FINLAND );
        addCurve( L_SHORT, C_EASY, LEFT_CURVE, FINLAND );
        addCheckPoint( FINLAND, 95 );

        addStraightLine( L_LONG, FINLAND );
        addHill( L_MEDIUM, H_BIG, UP_HILL, FINLAND );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, FINLAND );
        addStraightLine( L_VERYLONG, FINLAND );
        addCurve( L_SHORT, C_HARD, LEFT_CURVE, FINLAND );
        addStraightLine( L_VERYLONG, FINLAND );
        addCurve( L_SHORT, C_EASY, LEFT_CURVE, FINLAND );
        addStraightLine( L_LONG, FINLAND );

        addFinishLine( FINLAND, 0 );
        addStraightLine( L_VERYSHORT, FINLAND );
    }
    else if (circuitNumber==4)
    {
        addStraightLine( L_VERYSHORT, AFRICA );
        addStartLine( AFRICA, 55 );                 // Start = 0s

        addStraightLine( L_LONG, AFRICA );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, AFRICA );
        addStraightLine( L_LONG, AFRICA );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, RIGHT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );
        addCurve( L_MEDIUM, C_MEDIUM, RIGHT_CURVE, AFRICA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );
        addCheckPoint( AFRICA, 38 );

        addStraightLine( L_VERYSHORT, AFRICA );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, AFRICA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, AFRICA );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, AFRICA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );
        addHill( L_MEDIUM, H_BIG, UP_HILL, AFRICA );
        addStraightLine( L_LONG, AFRICA );
        addCheckPoint( AFRICA, 25 );

        addStraightLine( L_VERYSHORT, AFRICA );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_EASY, RIGHT_CURVE, AFRICA );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );
        addCheckPoint( AFRICA, 80 );

        addStraightLine( L_VERYSHORT, AFRICA );
        addHill( L_MEDIUM, H_BIG, UP_HILL, AFRICA );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, AFRICA );
        addStraightLine( L_VERYLONG, AFRICA );
        addCurve( L_LONG, C_HARD, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYLONG, AFRICA );
        addCurve( L_SHORT, C_EASY, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );

        addFinishLine( AFRICA, 0 );
        addStraightLine( L_VERYSHORT, AFRICA );
    }
    else if (circuitNumber==5)
    {
        addStraightLine( L_VERYSHORT, PLAINS );
        addStartLine( PLAINS, 43 );

        addStraightLine( L_VERYSHORT, PLAINS );
        addCurve( L_SHORT, C_HARD, LEFT_CURVE, PLAINS );
        addStraightLine( L_VERYSHORT, PLAINS );
        addCurve( L_SHORT, C_HARD, RIGHT_CURVE, PLAINS );
        addHill( L_MEDIUM, H_SMALL, UP_HILL, PLAINS );
        addStraightLine( L_SHORT, PLAINS );
        addHill( L_MEDIUM, H_SMALL, DOWN_HILL, PLAINS );
        addCurve( L_LONG, C_EASY, RIGHT_CURVE, PLAINS );
        addStraightLine( L_VERYSHORT, PLAINS );

        addFinishLine( PLAINS, 43 );
        addStraightLine( L_VERYSHORT, PLAINS );
    }
    else if (circuitNumber==6)
    {
        addStraightLine( L_VERYSHORT, DESERT );
        addStartLine( DESERT, 60  );

        addStraightLine( L_LONG, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, DESERT );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, DESERT );
        addStraightLine( L_VERYSHORT, DESERT );

        addFinishLine( DESERT, 60 );
        addStraightLine( L_VERYSHORT, DESERT );
    }
    else if (circuitNumber==7)
    {
        addStraightLine( L_VERYSHORT, USA );
        addStartLine( USA, 53 );

        addStraightLine( L_VERYSHORT, USA );
        addCurvyHill( L_MEDIUM, H_MEDIUM, UP_HILL, C_HARD, RIGHT_CURVE, USA );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_HARD, LEFT_CURVE, USA );
        addStraightLine( L_SHORT, USA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, USA );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, USA );
        addStraightLine( L_VERYSHORT, USA );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, USA );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, USA );
        addStraightLine( L_SHORT, USA );
        addCurvyHill( L_MEDIUM, H_MEDIUM, DOWN_HILL, C_HARD, LEFT_CURVE, USA );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, USA );
        addStraightLine( L_SHORT, USA );

        addFinishLine( USA, 53 );
        addStraightLine( L_VERYSHORT, USA );
    }
    else if (circuitNumber==8)
    {
        addStraightLine( L_VERYSHORT, FINLAND );
        addStartLine( FINLAND, 68 );

        addStraightLine( L_VERYSHORT, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_EASY, LEFT_CURVE, FINLAND );
        addCurvyHill( L_MEDIUM, H_SMALL, UP_HILL, C_MEDIUM, LEFT_CURVE, FINLAND );
        addStraightLine( L_VERYSHORT, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, FINLAND );
        addCurvyHill( L_MEDIUM, H_SMALL, DOWN_HILL, C_MEDIUM, LEFT_CURVE, FINLAND );
        addCurve( L_SHORT, C_MEDIUM, LEFT_CURVE, FINLAND );
        addCurve( L_SHORT, C_MEDIUM, RIGHT_CURVE, FINLAND );
        addStraightLine( L_VERYSHORT, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, UP_HILL, C_EASY, LEFT_CURVE, FINLAND );
        addCurvyHill( L_MEDIUM, H_SMALL, UP_HILL, C_MEDIUM, LEFT_CURVE, FINLAND );
        addStraightLine( L_VERYSHORT, FINLAND );
        addCurvyHill( L_MEDIUM, H_BIG, DOWN_HILL, C_HARD, RIGHT_CURVE, FINLAND );
        addCurvyHill( L_MEDIUM, H_SMALL, DOWN_HILL, C_MEDIUM, LEFT_CURVE, FINLAND );
        addStraightLine( L_VERYSHORT, FINLAND );

        addFinishLine( FINLAND, 68 );
        addStraightLine( L_VERYSHORT, FINLAND );
    }
    else if (circuitNumber==9)
    {
        addStraightLine( L_VERYSHORT, AFRICA );
        addStartLine( AFRICA, 84 );

        addStraightLine( L_VERYSHORT, AFRICA );
        addHill( L_MEDIUM, H_BIG, UP_HILL, AFRICA );
        addHill( L_MEDIUM, H_BIG, DOWN_HILL, AFRICA );
        addStraightLine( L_VERYLONG, AFRICA );
        addCurve( L_LONG, C_HARD, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYLONG, AFRICA );
        addCurve( L_SHORT, C_EASY, LEFT_CURVE, AFRICA );
        addStraightLine( L_VERYSHORT, AFRICA );

        addFinishLine( AFRICA, 84 );
        addStraightLine( L_VERYSHORT, AFRICA );
    }
};

void putBillBoards( void )
{

    for (unsigned int k = 0; k<circuit.size()-7; k++ )
    {

        int nextcurve = circuit[k+7]->Curve;
        int currentcurve = circuit[k]->Curve;
        int nextslope = circuit[k+7]->Slope;
        int currentslope = circuit[k]->Slope;

        if (nextcurve==currentcurve && nextslope==currentslope)
        {
            // no turn and no hill
        }
        else if (nextcurve==currentcurve && nextslope!=currentslope)
        {
            // no turn but hill
            if (nextslope>0) //uphill
            {
                circuit[k]->RDeco=UPHILL;
                circuit[k]->LDeco=UPHILL;

                circuit[k+1]->RDeco=UPHILL;
                circuit[k+1]->LDeco=UPHILL;

                circuit[k+2]->RDeco=UPHILL;
                circuit[k+2]->LDeco=UPHILL;

                circuit[k+4]->RDeco=UPHILL;
                circuit[k+4]->LDeco=UPHILL;

                circuit[k+6]->RDeco=UPHILL;
                circuit[k+6]->LDeco=UPHILL;
            }
            else if (nextslope<0) //downhill
            {
                circuit[k]->RDeco=DOWNHILL;
                circuit[k]->LDeco=DOWNHILL;

                circuit[k+1]->RDeco=DOWNHILL;
                circuit[k+1]->LDeco=DOWNHILL;

                circuit[k+2]->RDeco=DOWNHILL;
                circuit[k+2]->LDeco=DOWNHILL;

                circuit[k+4]->RDeco=DOWNHILL;
                circuit[k+4]->LDeco=DOWNHILL;

                circuit[k+6]->RDeco=DOWNHILL;
                circuit[k+6]->LDeco=DOWNHILL;
            }
            k+=7;
        }
        else if (nextcurve!=currentcurve && nextslope==currentslope)
        {
            // no turn but hill
            if (nextcurve<0) //uphill
            {
                circuit[k]->RDeco=LEFTTURN;
                circuit[k]->LDeco=LEFTTURN;

                circuit[k+1]->RDeco=LEFTTURN;
                circuit[k+1]->LDeco=LEFTTURN;

                circuit[k+2]->RDeco=LEFTTURN;
                circuit[k+2]->LDeco=LEFTTURN;

                circuit[k+4]->RDeco=LEFTTURN;
                circuit[k+4]->LDeco=LEFTTURN;

                circuit[k+6]->RDeco=LEFTTURN;
                circuit[k+6]->LDeco=LEFTTURN;
            }
            else if (nextcurve>0) //downhill
            {
                circuit[k]->RDeco=RIGHTTURN;
                circuit[k]->LDeco=RIGHTTURN;

                circuit[k+1]->RDeco=RIGHTTURN;
                circuit[k+1]->LDeco=RIGHTTURN;

                circuit[k+2]->RDeco=RIGHTTURN;
                circuit[k+2]->LDeco=RIGHTTURN;

                circuit[k+4]->RDeco=RIGHTTURN;
                circuit[k+4]->LDeco=RIGHTTURN;

                circuit[k+6]->RDeco=RIGHTTURN;
                circuit[k+6]->LDeco=RIGHTTURN;
            }
            k+=7;
        }
        else if (nextcurve!=currentcurve && nextslope!=currentslope)
        {
            // no turn but hill
            if (nextcurve<0) //uphill
            {
                circuit[k]->RDeco=LEFTTURN;
                circuit[k+1]->RDeco=LEFTTURN;
                circuit[k+2]->RDeco=LEFTTURN;
                circuit[k+4]->RDeco=LEFTTURN;
                circuit[k+6]->RDeco=LEFTTURN;

                if (nextslope>0)
                {
                    circuit[k]->LDeco=UPHILL;
                    circuit[k+1]->LDeco=UPHILL;
                    circuit[k+2]->LDeco=UPHILL;
                    circuit[k+4]->LDeco=UPHILL;
                    circuit[k+6]->LDeco=UPHILL;
                }
                else if (nextslope<0)
                {
                    circuit[k]->LDeco=DOWNHILL;
                    circuit[k+1]->LDeco=DOWNHILL;
                    circuit[k+2]->LDeco=DOWNHILL;
                    circuit[k+4]->LDeco=DOWNHILL;
                    circuit[k+6]->LDeco=DOWNHILL;
                }
                k+=7;
            }
            else if (nextcurve>0) //downhill
            {
                circuit[k]->LDeco=RIGHTTURN;
                circuit[k+1]->LDeco=RIGHTTURN;
                circuit[k+2]->LDeco=RIGHTTURN;
                circuit[k+4]->LDeco=RIGHTTURN;
                circuit[k+6]->LDeco=RIGHTTURN;

                if (nextslope>0)
                {
                    circuit[k]->RDeco=UPHILL;
                    circuit[k+1]->RDeco=UPHILL;
                    circuit[k+2]->RDeco=UPHILL;
                    circuit[k+4]->RDeco=UPHILL;
                    circuit[k+6]->RDeco=UPHILL;
                }
                else if (nextslope<0)
                {
                    circuit[k]->RDeco=DOWNHILL;
                    circuit[k+1]->RDeco=DOWNHILL;
                    circuit[k+2]->RDeco=DOWNHILL;
                    circuit[k+4]->RDeco=DOWNHILL;
                    circuit[k+6]->RDeco=DOWNHILL;
                }
                k+=7;
            }
        }
        else if (nextcurve<0 && currentcurve!=nextcurve)
        {
            circuit[k]->RDeco=LEFTTURN;
            circuit[k+1]->RDeco=LEFTTURN;
            circuit[k+2]->RDeco=LEFTTURN;
            circuit[k+4]->RDeco=LEFTTURN;
            circuit[k+6]->RDeco=LEFTTURN;
            k+=7;
        }
        else if (nextcurve>0 && currentcurve!=nextcurve)
        {
            circuit[k]->LDeco=RIGHTTURN;
            circuit[k+1]->LDeco=RIGHTTURN;
            circuit[k+2]->LDeco=RIGHTTURN;
            circuit[k+4]->LDeco=RIGHTTURN;
            circuit[k+6]->LDeco=RIGHTTURN;
            k+=7;
        }
    }

}

void outputMilestones( void )
{
    char texttosend[1024];
    if (usb_is_open())
    {
        for(int k = 0; k< jalons.size(); k++)
        {
            sprintf( texttosend, "Jalons %d --> Lap = %d : Type = %d ; Position = %.0f \n", k, jalons[k]->lap, jalons[k]->type, jalons[k]->wZ );
            usb_fxlink_text(texttosend, 0);
        }
    }
}

void createMilestones( uint8_t nblap )
{
    for( unsigned int l=0; l<nblap;l++)
    {
        for (unsigned int k = 0; k<circuit.size(); k++ )
        {
            if (circuit[k]->Special != -1)
            {
                MileStone *mile=new MileStone( );
                mile->type = circuit[k]->Special;
                mile->wZ = (double) ((double) k * (double) SEGMENT_LENGTH);
                mile->lap = l ;
                jalons.push_back(mile);
            }
        }
    }
#if DEBUGXXX==1
    outputMilestones();
#endif // DEBUGXXX
}




void createClouds( void )
{
    srand( rtc_ticks() );

    for( int k = 0; k < NB_CLOUDS_SKY; k++)
    {
        int X = (rand() % 792);
        int Y = rand() % 60;
        int T = rand() % 3;

        Clouds* cl=new Clouds( X, Y, T );
        if (cl!=nullptr) nuages.push_back( cl );
    }
}


void createTraffic( uint16_t maxSegment )
{
    for( int k = 0; k < NB_CARS_TRAFFIC; k++)
    {
        int8_t X = rand() % 4;
        double Z = (double) (SEGMENT_LENGTH * (rand() % (maxSegment-5)) + 10.0);
        //int8_t X = 0;
        //double Z = (k+1)*SEGMENT_LENGTH;

        uint8_t S;

        // if Difficulty = easy, all cars are at the same speed 175km/h)
        if (DiffLevel==0) S=4.0;
        else S = 3.5 + (rand() % 2);  // else speed is random and then overtaking can happen


        uint8_t T = rand() % 8;

        Cars* car;

        // Depending on which line the car is placed, we choose the right fraction of W
        if (X==0) car = new Cars( -0.75, (double) Z, S, T );
        else if (X==1) car = new Cars( -0.25, (double) Z, S, T );
        else if (X==2) car = new Cars( 0.25, (double) Z, S, T );
        else if (X==3) car = new Cars( 0.75, (double) Z, S, T );

        if (car!=nullptr)
            traffic.push_back( car );
    }
}


inline int getRandom( int8_t biome )
{
    //Needed to generate integer between -1 and +6;
    int a = (rand() % 15)-8;
    if (a<0) a=-1;      // we clamp a to above -1;

    return a;
}


void addCheckPoint( int8_t biome, uint8_t extra )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<5; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, -1 );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }

    for( int i=5; i<10; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, CHECK, CHECK );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            if (i==7)
            {
                seg->Special = CHECKPOINT;
                seg->Extratime = (uint32_t) (extra)*1000000;
            }
            circuit.push_back( seg );
        }
    }

    for( int i=10; i<15; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, -1 );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}


void addStartLine( int8_t biome, uint8_t extra )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<5; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, -1 );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }

    for( int i=5; i<10; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, STARTLIGHT, STARTLIGHT );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            if (i==7)
            {
                seg->Special = START;
                seg->Extratime = (uint32_t) (extra)*1000000;
            }
            circuit.push_back( seg );
        }
    }

    for( int i=10; i<15; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, -1 );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}



void addFinishLine( int8_t biome, uint8_t extra )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<5; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, -1 );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }

    for( int i=5; i<10; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, STOPLIGHT, STOPLIGHT );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            if (i==7)
            {
                seg->Special = FINISH;
                seg->Extratime = (uint32_t) (extra)*1000000;
            }
            circuit.push_back( seg );
        }
    }

    for( int i=10; i<15; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, -1 );
        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}




void addStraightLine( Length l, int8_t biome )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<l; i++)
    {
        Segment *seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, getRandom( biome ), getRandom( biome ) );

//        int deco = rand() % 8;
//        Segment *seg;
//        if (deco==0) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, TREE1, -1 );
//        else if (deco==1) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, -1, TREE2 );
//        else if (deco==2) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, TREE3, LEAF1 );
//        else if (deco==3) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, LEAF2, TREE1 );
//        else if (deco==4) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, TREE4, TREE2 );
//        else if (deco==5) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, ROCKS, -1 );
//        else if (deco==6) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, TREE2, TREE1 );
//        else if (deco==7) seg=new Segment( 0, lastY, lastZ + i*SEGMENT_LENGTH, 0, 0, TREE3, TREE4 );

        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}

void addCurve( Length l, CurveStrength s, CurveType t, int8_t biome )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<l; i++)
    {


        Segment *seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, getRandom( biome ), getRandom( biome ) );


//        int deco = rand() % 8;
//        if (deco==0) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, -1, -1 );
//        else if (deco==1) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, -1, TREE1 );
//        else if (deco==2) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, TREE2, ROCKS );
//        else if (deco==3) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, TREE3, LEAF1 );
//        else if (deco==4) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, -1, -1 );
//        else if (deco==5) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, TREE3, -1 );
//        else if (deco==6) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, TREE4, LEAF1 );
//        else if (deco==7) seg=new Segment( 0, lastY, lastZ+i*SEGMENT_LENGTH, s*t, 0, -1, LEAF2 );

        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}


void addHill( Length l, HillSize s, HillType t, int8_t biome )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<l; i++)
    {

        Segment *seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, getRandom( biome ), getRandom( biome ) );
//        int deco = rand() % 8;
//        Segment *seg;

//        if (deco==0) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, -1, ROCKS );
//        else if (deco==1) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, -1, TREE2 );
//        else if (deco==2) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, TREE3, -1 );
//        else if (deco==3) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, TREE1, LEAF2 );
//        else if (deco==4) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, ROCKS, LEAF1 );
//        else if (deco==5) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, TREE1, -1 );
//        else if (deco==6) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, TREE3, TREE1 );
//        else if (deco==7) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, 0, s*t, TREE2, TREE4 );

        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}


void addCurvyHill( Length l, HillSize s, HillType t, CurveStrength cs, CurveType ct, int8_t biome )
{
    double lastZ=0;
    int16_t lastY=0;

    uint16_t lastIndex = circuit.size();
    if (lastIndex!=0)
    {
        lastY=circuit[lastIndex-1]->wY;
        lastZ=circuit[lastIndex-1]->wZ+SEGMENT_LENGTH;
    }

    for( int i=0; i<l; i++)
    {
        Segment *seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, getRandom( biome ), getRandom( biome ) );

//        int deco = rand() % 8;
//        Segment *seg;

//        if (deco==0) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, -1, -1 );
//        else if (deco==1) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, -1, TREE1 );
//        else if (deco==2) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, TREE2, -1 );
//        else if (deco==3) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, TREE3, LEAF2 );
//        else if (deco==4) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, ROCKS, LEAF2 );
//        else if (deco==5) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, TREE1, TREE2 );
//        else if (deco==6) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, TREE3, LEAF2 );
//        else if (deco==7) seg=new Segment( 0, lastY+i*t*s, lastZ+i*SEGMENT_LENGTH, cs*ct, s*t, -1, TREE4 );


        if (seg!=nullptr)
        {
            seg->Environment = biome;
            circuit.push_back( seg );
        }
    }
}


void projectCircuitFP( void )
{
    for( unsigned int i=0; i<circuit.size(); i++)
    {
        circuit[i]->Project3DFP( cam );
    }
};


void projectCircuitFP( uint16_t index )
{
    circuit[index]->Project3DFP( cam );
};


void drawCircuitSegment( uint16_t index )
{
    if (index>=circuit.size()-1) return;

    int X1 = (int) circuit[index]->X;
    int Y1 = (int) circuit[index]->Y;
    int W1 = (int) circuit[index]->W;
    int X2 = (int) circuit[(index+1)]->X + circuit[index]->Curve;
    int Y2 = (int) circuit[(index+1)]->Y;
    int W2 = (int) circuit[(index+1)]->W;

    if (Y1==Y2) return;

    if (circuit[index]->Environment == PLAINS)
    {
        if (index%2==0)
        {
            drawPolygon( 0, X2-W2/16-W2+currentcurve, Y2, 0, X1-W1/16-W1+currentcurve, Y1, DARK_GREEN_GRASS );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, LIGHT_GREY_ROAD );
            drawPolygon( X2-W2/16-W2+currentcurve, X2-W2+currentcurve, Y2, X1-W1/16-W1+currentcurve, X1-W1+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50-W2/2+currentcurve, X2+W2/50-W2/2+currentcurve, Y2, X1-W1/50-W1/2+currentcurve, X1+W1/50-W1/2+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50+currentcurve, X2+W2/50+currentcurve, Y2, X1-W1/50+currentcurve, X1+W1/50+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50+W2/2+currentcurve, X2+W2/50+W2/2+currentcurve, Y2, X1-W1/50+W1/2+currentcurve, X1+W1/50+W1/2+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2+currentcurve, X2+W2+W2/16+currentcurve, Y2, X1+W1+currentcurve, X1+W1+W1/16+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2/16+W2+currentcurve, 396, Y2, X1+W1/16+W1+currentcurve, 396, Y1, DARK_GREEN_GRASS );
        }
        else
        {
            drawPolygon( 0, X2-W2/16-W2+currentcurve, Y2, 0, X1-W1/16-W1+currentcurve, Y1, LIGHT_GREEN_GRASS );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2-W2/16-W2+currentcurve, X2-W2+currentcurve, Y2, X1-W1/16-W1+currentcurve, X1-W1+currentcurve, Y1, RED_STRIPE );
            drawPolygon( X2+W2+currentcurve, X2+W2+W2/16+currentcurve, Y2, X1+W1+currentcurve, X1+W1+W1/16+currentcurve, Y1, RED_STRIPE );
            drawPolygon( X2+W2/16+W2+currentcurve, 396, Y2, X1+W1/16+W1+currentcurve, 396, Y1, LIGHT_GREEN_GRASS );
        }
    }
    else if (circuit[index]->Environment == DESERT)
    {
        if (index%2==0)
        {
            drawPolygon( 0, X2-W2/16-W2+currentcurve, Y2, 0, X1-W1/16-W1+currentcurve, Y1, DARK_YELLOW_GRASS );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, LIGHT_GREY_ROAD );
            drawPolygon( X2-W2/16-W2+currentcurve, X2-W2+currentcurve, Y2, X1-W1/16-W1+currentcurve, X1-W1+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50-W2/2+currentcurve, X2+W2/50-W2/2+currentcurve, Y2, X1-W1/50-W1/2+currentcurve, X1+W1/50-W1/2+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50+currentcurve, X2+W2/50+currentcurve, Y2, X1-W1/50+currentcurve, X1+W1/50+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50+W2/2+currentcurve, X2+W2/50+W2/2+currentcurve, Y2, X1-W1/50+W1/2+currentcurve, X1+W1/50+W1/2+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2+currentcurve, X2+W2+W2/16+currentcurve, Y2, X1+W1+currentcurve, X1+W1+W1/16+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2/16+W2+currentcurve, 396, Y2, X1+W1/16+W1+currentcurve, 396, Y1, DARK_YELLOW_GRASS );
        }
        else
        {
            drawPolygon( 0, X2-W2/16-W2+currentcurve, Y2, 0, X1-W1/16-W1+currentcurve, Y1, LIGHT_YELLOW_GRASS );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2-W2/16-W2+currentcurve, X2-W2+currentcurve, Y2, X1-W1/16-W1+currentcurve, X1-W1+currentcurve, Y1, RED_STRIPE );
            drawPolygon( X2+W2+currentcurve, X2+W2+W2/16+currentcurve, Y2, X1+W1+currentcurve, X1+W1+W1/16+currentcurve, Y1, RED_STRIPE );
            drawPolygon( X2+W2/16+W2+currentcurve, 396, Y2, X1+W1/16+W1+currentcurve, 396, Y1, LIGHT_YELLOW_GRASS );
        }
    }
    else if (circuit[index]->Environment == USA)
    {
        if (index%2==0)
        {
            drawPolygon( 0, X2-W2/16-W2+currentcurve, Y2, 0, X1-W1/16-W1+currentcurve, Y1, DARK_ORANGE );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, BLACK_ROAD );
            drawPolygon( X2-W2/16-W2+currentcurve, X2-W2+currentcurve, Y2, X1-W1/16-W1+currentcurve, X1-W1+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/50-W2/2+currentcurve, X2+W2/50-W2/2+currentcurve, Y2, X1-W1/50-W1/2+currentcurve, X1+W1/50-W1/2+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/25+currentcurve, X2-W2/50+currentcurve, Y2, X1-W1/25+currentcurve, X1-W1/50+currentcurve, Y1, YELLOW_STRIPE );
            drawPolygon( X2+W2/50+currentcurve, X2+W2/25+currentcurve, Y2, X1+W1/50+currentcurve, X1+W1/25+currentcurve, Y1, YELLOW_STRIPE );
            drawPolygon( X2-W2/50+W2/2+currentcurve, X2+W2/50+W2/2+currentcurve, Y2, X1-W1/50+W1/2+currentcurve, X1+W1/50+W1/2+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2+currentcurve, X2+W2+W2/16+currentcurve, Y2, X1+W1+currentcurve, X1+W1+W1/16+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2/16+W2+currentcurve, 396, Y2, X1+W1/16+W1+currentcurve, 396, Y1, DARK_ORANGE );
        }
        else
        {
            drawPolygon( 0, X2-W2/16-W2+currentcurve, Y2, 0, X1-W1/16-W1+currentcurve, Y1, LIGHT_ORANGE );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, BLACK_ROAD );
            drawPolygon( X2-W2/16-W2+currentcurve, X2-W2+currentcurve, Y2, X1-W1/16-W1+currentcurve, X1-W1+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2-W2/25+currentcurve, X2-W2/50+currentcurve, Y2, X1-W1/25+currentcurve, X1-W1/50+currentcurve, Y1, YELLOW_STRIPE );
            drawPolygon( X2+W2/50+currentcurve, X2+W2/25+currentcurve, Y2, X1+W1/50+currentcurve, X1+W1/25+currentcurve, Y1, YELLOW_STRIPE );
            drawPolygon( X2+W2+currentcurve, X2+W2+W2/16+currentcurve, Y2, X1+W1+currentcurve, X1+W1+W1/16+currentcurve, Y1, WHITE_STRIPE );
            drawPolygon( X2+W2/16+W2+currentcurve, 396, Y2, X1+W1/16+W1+currentcurve, 396, Y1, LIGHT_ORANGE );
        }
    }
    else if (circuit[index]->Environment == FINLAND)
    {
        if (index%2==0)
        {
            drawPolygon( 0, X2-W2+currentcurve, Y2, 0, X1-W1+currentcurve, Y1, DARK_SNOW_GRASS );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, SNOW_ROAD );

            drawPolygon( X2-W2/2-W2/12+currentcurve, X2-W2/2-W2/12-W2/25+currentcurve, Y2, X1-W1/2-W1/12+currentcurve, X1-W1/2-W1/12-W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2-W2+W2/12+W2/25+currentcurve, X2-W2+W2/12+currentcurve, Y2, X1-W1+W1/12+W1/25+currentcurve, X1-W1+W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2-W2/12+currentcurve, X2-W2/12-W2/25+currentcurve, Y2, X1-W1/12+currentcurve, X1-W1/12-W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2-W2/2+W2/12+W2/25+currentcurve, X2-W2/2+W2/12+currentcurve, Y2, X1-W1/2+W1/12+W1/25+currentcurve, X1-W1/2+W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2+W2/12+currentcurve, X2+W2/12+W2/25+currentcurve, Y2, X1+W1/12+currentcurve, X1+W1/12+W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2+W2/2-W2/12-W2/25+currentcurve, X2+W2/2-W2/12+currentcurve, Y2, X1+W1/2-W1/12-W1/25+currentcurve, X1+W1/2-W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2+W2/2+W2/12+currentcurve, X2+W2/2+W2/12+W2/25+currentcurve, Y2, X1+W1/2+W1/12+currentcurve, X1+W1/2+W1/12+W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2+W2-W2/12-W2/25+currentcurve, X2+W2-W2/12+currentcurve, Y2, X1+W1-W1/12-W1/25+currentcurve, X1+W1-W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2+W2+currentcurve, 396, Y2, X1+W1+currentcurve, 396, Y1, DARK_SNOW_GRASS );
        }
        else
        {
            drawPolygon( 0, X2-W2+currentcurve, Y2, 0, X1-W1+currentcurve, Y1, LIGHT_SNOW_GRASS );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, SNOW_ROAD );

            drawPolygon( X2-W2/2-W2/12+currentcurve, X2-W2/2-W2/12-W2/25+currentcurve, Y2, X1-W1/2-W1/12+currentcurve, X1-W1/2-W1/12-W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2-W2+W2/12+W2/25+currentcurve, X2-W2+W2/12+currentcurve, Y2, X1-W1+W1/12+W1/25+currentcurve, X1-W1+W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2-W2/12+currentcurve, X2-W2/12-W2/25+currentcurve, Y2, X1-W1/12+currentcurve, X1-W1/12-W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2-W2/2+W2/12+W2/25+currentcurve, X2-W2/2+W2/12+currentcurve, Y2, X1-W1/2+W1/12+W1/25+currentcurve, X1-W1/2+W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2+W2/12+currentcurve, X2+W2/12+W2/25+currentcurve, Y2, X1+W1/12+currentcurve, X1+W1/12+W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2+W2/2-W2/12-W2/25+currentcurve, X2+W2/2-W2/12+currentcurve, Y2, X1+W1/2-W1/12-W1/25+currentcurve, X1+W1/2-W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2+W2/2+W2/12+currentcurve, X2+W2/2+W2/12+W2/25+currentcurve, Y2, X1+W1/2+W1/12+currentcurve, X1+W1/2+W1/12+W1/25+currentcurve, Y1, DARK_GREY_ROAD );
            drawPolygon( X2+W2-W2/12-W2/25+currentcurve, X2+W2-W2/12+currentcurve, Y2, X1+W1-W1/12-W1/25+currentcurve, X1+W1-W1/12+currentcurve, Y1, DARK_GREY_ROAD );

            drawPolygon( X2+W2+currentcurve, 396, Y2, X1+W1+currentcurve, 396, Y1, LIGHT_SNOW_GRASS );
        }
    }
    else if (circuit[index]->Environment == AFRICA)
    {
        if (index%2==0)
        {
            drawPolygon( 0, X2-W2+currentcurve, Y2, 0, X1-W1+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, OCRE_ROAD );

            drawPolygon( X2-W2/2-W2/12+currentcurve, X2-W2/2-W2/12-W2/25+currentcurve, Y2, X1-W1/2-W1/12+currentcurve, X1-W1/2-W1/12-W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2-W2+W2/12+W2/25+currentcurve, X2-W2+W2/12+currentcurve, Y2, X1-W1+W1/12+W1/25+currentcurve, X1-W1+W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2-W2/12+currentcurve, X2-W2/12-W2/25+currentcurve, Y2, X1-W1/12+currentcurve, X1-W1/12-W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2-W2/2+W2/12+W2/25+currentcurve, X2-W2/2+W2/12+currentcurve, Y2, X1-W1/2+W1/12+W1/25+currentcurve, X1-W1/2+W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2+W2/12+currentcurve, X2+W2/12+W2/25+currentcurve, Y2, X1+W1/12+currentcurve, X1+W1/12+W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2+W2/2-W2/12-W2/25+currentcurve, X2+W2/2-W2/12+currentcurve, Y2, X1+W1/2-W1/12-W1/25+currentcurve, X1+W1/2-W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2+W2/2+W2/12+currentcurve, X2+W2/2+W2/12+W2/25+currentcurve, Y2, X1+W1/2+W1/12+currentcurve, X1+W1/2+W1/12+W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2+W2-W2/12-W2/25+currentcurve, X2+W2-W2/12+currentcurve, Y2, X1+W1-W1/12-W1/25+currentcurve, X1+W1-W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2+W2+currentcurve, 396, Y2, X1+W1+currentcurve, 396, Y1, DARK_EARTH );
        }
        else
        {
            drawPolygon( 0, X2-W2+currentcurve, Y2, 0, X1-W1+currentcurve, Y1, LIGHT_EARTH );
            drawPolygon( X2-W2+currentcurve, X2+W2+currentcurve, Y2, X1-W1+currentcurve, X1+W1+currentcurve, Y1, OCRE_ROAD );

            drawPolygon( X2-W2/2-W2/12+currentcurve, X2-W2/2-W2/12-W2/25+currentcurve, Y2, X1-W1/2-W1/12+currentcurve, X1-W1/2-W1/12-W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2-W2+W2/12+W2/25+currentcurve, X2-W2+W2/12+currentcurve, Y2, X1-W1+W1/12+W1/25+currentcurve, X1-W1+W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2-W2/12+currentcurve, X2-W2/12-W2/25+currentcurve, Y2, X1-W1/12+currentcurve, X1-W1/12-W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2-W2/2+W2/12+W2/25+currentcurve, X2-W2/2+W2/12+currentcurve, Y2, X1-W1/2+W1/12+W1/25+currentcurve, X1-W1/2+W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2+W2/12+currentcurve, X2+W2/12+W2/25+currentcurve, Y2, X1+W1/12+currentcurve, X1+W1/12+W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2+W2/2-W2/12-W2/25+currentcurve, X2+W2/2-W2/12+currentcurve, Y2, X1+W1/2-W1/12-W1/25+currentcurve, X1+W1/2-W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2+W2/2+W2/12+currentcurve, X2+W2/2+W2/12+W2/25+currentcurve, Y2, X1+W1/2+W1/12+currentcurve, X1+W1/2+W1/12+W1/25+currentcurve, Y1, DARK_EARTH );
            drawPolygon( X2+W2-W2/12-W2/25+currentcurve, X2+W2-W2/12+currentcurve, Y2, X1+W1-W1/12-W1/25+currentcurve, X1+W1-W1/12+currentcurve, Y1, DARK_EARTH );

            drawPolygon( X2+W2+currentcurve, 396, Y2, X1+W1+currentcurve, 396, Y1, LIGHT_EARTH );
        }
    }
}


fixed_t interpolatePositionX( double currentZ )
{
    int index = (int) (currentZ / SEGMENT_LENGTH);
    fixed_t x1 = fix(circuit[index]->wX);
    fixed_t x2 = fix(circuit[index+1]->wX);
    fixed_t dZ = fixdouble(currentZ-index*SEGMENT_LENGTH);

    fixed_t result = x1 + fmul( x2-x1, fdiv( dZ, fix(SEGMENT_LENGTH)));

    if(ShowDebug1)
    {
        dprint( 120,  1, C_WHITE, "CZ=%.0lf", f2double(currentZ) );
        dprint( 120, 15, C_WHITE, "y1=%d", fround(x1) );
        dprint( 120, 29, C_WHITE, "y2=%d", fround(x2) );

        dprint( 240, 15, C_WHITE, "Dz=%d", fround(dZ) );
        dprint( 240, 29, C_GREEN, "CX=%d", fround(result) );
    }

    return result;
}


fixed_t interpolatePositionY( double currentZ )
{
    int index = (int) (currentZ / SEGMENT_LENGTH);
    fixed_t y1 = fix(circuit[index]->wY);
    fixed_t y2 = fix(circuit[index+1]->wY);
    fixed_t dZ = fixdouble(currentZ-index*SEGMENT_LENGTH);

    fixed_t result = y1 + fmul( y2-y1, fdiv( dZ, fix(SEGMENT_LENGTH)));

    if(ShowDebug1)
    {
        dprint( 120,  1, C_WHITE, "CZ=%.0lf", f2double(currentZ) );
        dprint( 120, 15, C_WHITE, "y1=%d", fround(y1) );
        dprint( 120, 29, C_WHITE, "y2=%d", fround(y2) );

        dprint( 240, 15, C_WHITE, "Dz=%d", fround(dZ) );
        dprint( 240, 43, C_GREEN, "CY=%d", fround(result) );
    }

    return result;
}


uint16_t findIndex( double currentZ )
{
    return (uint16_t) (currentZ / SEGMENT_LENGTH);
}


void prepareDecoration( int biometoload )
{
    bopti_image_t const *src;

    for( int k=0; k<NB_TREES_TYPES; k++)
    {
        float scale=1.0f;
        for( int i=0; i<MAX_SUBIMAGES_TREES; i++)
        {
            scale=3.0f/((float) (i+2));

            if (biometoload==PLAINS)
            {
                if(k==0) src = &pl_tree1;
                else if (k==1) src = &pl_tree2;
                else if (k==2) src = &pl_tree3;
                else if (k==3) src = &pl_tree4;
                else if (k==4) src = &cc_bigleaf;
                else if (k==5) src = &cc_smallleaf;
                else if (k==6) src = &cc_rocks;
            }
            else if (biometoload==DESERT)
            {
                if(k==0) src = &dt_tree1;
                else if (k==1) src = &dt_tree2;
                else if (k==2) src = &dt_tree3;
                else if (k==3) src = &dt_tree4;
                else if (k==4) src = &cc_void; //&cc_bigleaf;
                else if (k==5) src = &dt_smallleaf;
                else if (k==6) src = &cc_rocks;
            }
            else if (biometoload==USA)
            {
                if(k==0) src = &us_tree1; //&pl_tree1;
                else if (k==1) src = &us_tree2; //&pl_tree2;
                else if (k==2) src = &dt_smallleaf; //&pl_tree3;
                else if (k==3) src = &us_tree4;
                else if (k==4) src = &us_bigleaf;
                else if (k==5) src = &us_smallleaf;
                else if (k==6) src = &cc_rocks;
            }
            else if (biometoload==FINLAND)
            {
                if(k==0) src = &fi_tree1;
                else if (k==1) src = &fi_tree2;
                else if (k==2) src = &cc_void; //&pl_tree3; // to be added
                else if (k==3) src = &fi_tree4;
                else if (k==4) src = &cc_void; //&cc_bigleaf; // to be added
                else if (k==5) src = &cc_void; //&cc_smallleaf; // to be added
                else if (k==6) src = &fi_rocks; // to be added
            }
            else if (biometoload==AFRICA)
            {
                if(k==0) src = &af_tree1; //&pl_tree1;
                else if (k==1) src = &af_tree2; //&pl_tree2;
                else if (k==2) src = &af_tree3; //&pl_tree3;
                else if (k==3) src = &us_tree4; //&pl_tree4;
                else if (k==4) src = &af_bigleaf;
                else if (k==5) src = &cc_smallleaf;
                else if (k==6) src = &cc_rocks;
            }

            if (k==7) src = &leftturn;
            else if (k==8) src = &rightturn;
            else if (k==9) src = &uphill;
            else if (k==10) src = &downhill;
            else if (k==11) src = &checkpoint;
            else if (k==12) src = &startlights;
            else if (k==13) src = &stoplights;
            else if (k==14) src = &waitlights;

            int width = (int) ((float) src->width * scale);
            int height = (int) ((float) src->height * scale);
            scaledTrees[k][i] = resize(src, width, height);
            //scale*=0.82;
        }
    }
}

void prepareTraffic( void )
{
    bopti_image_t const *src;

    for( int k=0; k<NB_CARS_TYPES; k++)
    {
        float scale=1.0f;
        for( int i=0; i<MAX_SUBIMAGES_CARS; i++)
        {
            //scale=1.0f/((float) (i+1));
            if(k==0) src = &car1;
            else if(k==1) src = &car2;
            else if(k==2) src = &car3;
            else if(k==3) src = &car4;
            else if(k==4) src = &car5;
            else if(k==5) src = &car6;
            else if(k==6) src = &car7;
            else src = &car8;

            int width = (int) ((float) src->width * scale);
            int height = (int) ((float) src->height * scale);
            scaledCars[k][i] = resize(src, width, height);
            scale*=0.82;
        }
    }
}


void freeDecoration( void )
{
    for( int k=0; k<NB_TREES_TYPES; k++)
        for( int i=0; i<MAX_SUBIMAGES_TREES; i++)
            free(scaledTrees[k][i]);
}


void freeTraffic( void )
{
    for( int k=0; k<NB_CARS_TYPES; k++)
        for( int i=0; i<MAX_SUBIMAGES_CARS; i++)
            free(scaledCars[k][i]);
}


void drawDecoration( uint16_t index )
{
    bopti_image_t *image;

    int distance = fround(fdiv( (fixdouble(circuit[index]->wZ) - cam->cZ), fix(SEGMENT_LENGTH) )) - 1;

    if (distance<0) distance = 0;
    else if (distance>(MAX_SUBIMAGES_TREES-1)) distance = (MAX_SUBIMAGES_TREES-1);

    //circuit[index]->DScale = distance;

    int deco = circuit[index]->LDeco;

    if (deco!=-1)
    {
        image = scaledTrees[deco][distance];

        int X = circuit[index]->X + circuit[index]->CumulatedCurve - 1.5*circuit[index]->W - image->width/2;
        int Y = circuit[index]->Y - image->height;

        dimage_p4_clearbg_alt( X, Y, image, 0, image->alpha );
    }

    deco = circuit[index]->RDeco;

    if (deco!=-1)
    {
        image = scaledTrees[deco][distance];

        int X = circuit[index]->X + circuit[index]->CumulatedCurve + 1.5*circuit[index]->W - image->width/2;
        int Y = circuit[index]->Y - image->height;

        dimage_p4_clearbg_alt( X, Y, image, 0, image->alpha );
    }
}


void updateTraffic( float dt, double maxdistance )
{
    for(unsigned int k=0; k<traffic.size(); k++)
    {
        traffic[k]->wZ += traffic[k]->Speed*dt;
        if (traffic[k]->wZ>maxdistance)  traffic[k]->wZ-=maxdistance;
    }

}


void drawTraffic( uint16_t index )
{
    bopti_image_t *image;

    int distance = fround(fdiv( (fixdouble(traffic[index]->wZ) - cam->cZ), fix(SEGMENT_LENGTH/2) ))-2;
    if (distance<0) distance = 0;
    else if (distance>(MAX_SUBIMAGES_CARS-1)) distance = (MAX_SUBIMAGES_CARS-1);

    //int segnumber = findIndex( traffic[index]->wZ );
    //traffic[index]->segnum = segnumber;
    //traffic[index]->DScale = distance;

    image = scaledCars[traffic[index]->Type][distance];

    int X = traffic[index]->X - image->width/2;
    int Y = traffic[index]->Y - image->height;


    //dimage( X, Y, image );
    if (distance!=0) dimage( X, Y, image );
}


void drawClouds( void  )
{
    bopti_image_t *cloud;

    for( unsigned int k =0; k<nuages.size(); k++ )
    {
        if (nuages[k]->Type==0) cloud=&sky1;
        else if (nuages[k]->Type==1) cloud=&sky2;
        else cloud=&sky3;

        nuages[k]->X--;

        if (nuages[k]->X>792) nuages[k]->X-=396*3;
        else if (nuages[k]->X<-396) nuages[k]->X+=396*3;

        dimage( nuages[k]->X, nuages[k]->Y, cloud );
    }
}


void drawFarBackground( int offset, int currentbiome )
{
    bopti_image_t *image;

    if (currentbiome==PLAINS) image=&mountain;
    else if (currentbiome==DESERT) image=&dunes;
    else if (currentbiome==USA) image=&canyon;
    else if (currentbiome==FINLAND) image=&snowmount;
    else if (currentbiome==AFRICA) image=&kilimandjaro;
    else image=&mountain;

    int X = offset;
    int DX = image->width;

    while (X>0)
    {
        X-=DX;
    }

    do
    {
        if (X>-1*DX) dimage(X, 60, image);
        X+=DX;
    }
    while(X<SCREEN_WIDTH+DX);
}


void drawNearBackground( int offset, int currentbiome )
{
    bopti_image_t *image;

    if (currentbiome==PLAINS) image=&treeline;
    else if (currentbiome==DESERT) image=&rockline;
    else if (currentbiome==USA) image=&rockline;
    else if (currentbiome==FINLAND) image=&treelinesnow;
    else if (currentbiome==AFRICA) image=&cc_void;
    else  image=&treeline;

    int X = offset;
    int DX = image->width;

    while (X>0)
    {
        X-=DX;
    }

    do
    {
        if (X>-1*DX) dimage(X, 100, image);
        X+=DX;
    }
    while(X<SCREEN_WIDTH+DX);
}
