#include <gint/display.h>
#include <gint/drivers/r61524.h>
#include <gint/rtc.h>

#include <gint/keyboard.h>
#include <gint/gint.h>
#include <gint/defs/types.h>
#include <fxlibc/printf.h>

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

#include <math.h>
#include <vector>

#include "parameters.h"
#include "colors.h"

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

#include "include/saves.h"

#include <gint/kmalloc.h>
#include <stdio.h>


#include "clock.h"

#define DEBUGXXX 0
#define OVERCLCK_ACTIVABLE 1

char version[5] = {'V','1','.','0','8'};


extern bopti_image_t player, smoke1, smoke2, smoke3;
extern font_t speedfont, startseq, plate, autofont;
extern bopti_image_t speedhud;
extern bopti_image_t flag, bigflag;

int CurrentCircuitBiome = PLAINS;

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

int MAX_SEGMENT=0;
camera *cam;

char texttosend[1024];

int32_t start_time = 100000000;
uint32_t elapsed_time = 0;
uint32_t score=0;
uint8_t stage=0, mode=0;
int8_t selectedCircuit=0, secondvalidation=0;
uint32_t time_update=0, time_create=0, time_project=0, time_render=0;


uint8_t DiffLevel = 1;
uint8_t CarsNumb = 1;
char PlayerName[3] = { 'S', 'L', 'Y' };

Parameters PlayerPara[1];

struct DataPerf
{
    uint8_t update=0;
    uint8_t project=0;
    uint8_t render=0;
};

extern bool saveexist;
BestRanking HallOfFame[10][5];          // Table of score : 10 levels * 5 best scores
uint32_t FinalTime=0;
bool skipranking=false;
int ranking = -1;                       // ranking is -1 if not ranked and between 1 and 5 if ranked

#define MAXDATA 120
DataPerf GraphPerf[ MAXDATA ];
unsigned int DataIndex=0;

uint16_t NB_CARS_TRAFFIC=200;

bool stop = false;
bool exitToOS = false;
bool record = false;
bool screenshot = false;

bool ShowDebug1 = false;
bool ShowDebug2 = false;
bool ShowDebug3 = false;

bool BDrawDeco = true;
bool BDrawClds = true;
bool BDrawCars = true;
bool BDrawBack = true;
bool BDrawFPS = false;

bool isOCPossible = false;
bool isOCActivated = false;

bool OptionMode = false;
bool PauseMode = false;
bool SkipTime = false;


///HUD options
bool visualspeedindicator = false;
bool visualnextpoint = true;

// for multilap
bool multilap = false;
uint8_t numlap = 1;
uint8_t currentLap = 1;

int currentpoint = 0;

uint16_t currentcurve=0;
uint8_t shiftcolor=0;


float speed = 0.0;
float maxspeedforward = 5.0;
float maxspeedbackward = 2.0;
int direction = 1;
bool speedcontrol = false;


uint8_t minYRoad = 224;     // We will track the upper Y (in fact the minimum Y during the RoadDrawing to optimize the rendering of the Sky
int8_t viewside = 0;

int deltaFarbackground = 0;
int deltaNearbackground = 0;
int lastindex=0;

int CC=0; // current curve
int CS=0;

overclock_level EntryLevel;


void initEverything( void )
{
    CurrentCircuitBiome = PLAINS;

    circuit.clear();
    nuages.clear();
    traffic.clear();
    MAX_SEGMENT=0;

    DataIndex=0;

    stop = false;
    record = false;
    screenshot = false;

    ShowDebug1 = false;
    ShowDebug2 = false;
    ShowDebug3 = false;

    BDrawDeco = true;
    BDrawClds = true;
    BDrawCars = true;
    BDrawFPS = false;


    currentcurve=0;
    shiftcolor=0;


    speed = 0.0;
    maxspeedforward = 5.0;
    maxspeedbackward = 2.0;
    direction = 1;
    speedcontrol = false;


    minYRoad = 224;     // We will track the upper Y (in fact the minimum Y during the RoadDrawing to optimize the rendering of the Sky
    viewside = 0;

    deltaFarbackground = 0;
    deltaNearbackground = 0;
    lastindex=0;

    CC=0; // current curve
    CS=0;

    multilap = false;
    numlap = 1;
    currentLap = 1;
}


float timepressed = 0.0f;
int directionPressed = 0;
bool CarIsSliding = false;
uint16_t framesmoke = 0;

static void get_inputs( float dt, int index  )
{
    CC = circuit[index]->Curve;
    CS = circuit[index]->Slope;


    maxspeedforward = 5.0 - (((float) CS)/100.0f) + (((float) CC)*f2float(cam->cX)/ROAD_WIDTH/20.0f);


    key_event_t ev;
    while((ev = pollevent()).type != KEYEV_NONE)
    {

    }
    speedcontrol = false;


    viewside=0;
    if (CC<0)
    {
        viewside=-1;

        if (CurrentCircuitBiome==FINLAND) cam->decX( CC*dt*speed/50); // 50 );              // very hard to turn in Finland with snow
        else if (CurrentCircuitBiome==AFRICA) cam->decX( CC*dt*speed/70); //75 );          // hard in Africa with dirt
        else cam->decX( CC*dt*speed/85); // 100 );                                          // more easy on normal roads
    }
    else if (CC>0)
    {
        viewside=+1;

        if (CurrentCircuitBiome==FINLAND) cam->decX( CC*dt*speed/50); // 50 );              // very hard to turn in Finland with snow
        else if (CurrentCircuitBiome==AFRICA) cam->decX( CC*dt*speed/70); //75 );          // hard in Africa with dirt
        else cam->decX( CC*dt*speed/85); // 100 );                                          // more easy on normal roads
    }

    if(keydown(KEY_LEFT) || keydown(KEY_F5))
    {
        cam->decX(5.0*speed*direction);

        /// This is to implement sliding and speed loss
        if (directionPressed!=-1) directionPressed=-1, timepressed = 0.0f;
        else if (directionPressed==-1 && CC<0) timepressed += dt;

        viewside=-1;
        if (CC<0) viewside=-2;  // We are in a curve and turning
        if (CC>0) viewside=0;
    }
    else if(keydown(KEY_RIGHT) || keydown(KEY_F6))
    {
        cam->incX(5.0*speed*direction);

        /// This is to implement sliding and speed loss
        if (directionPressed!=1) directionPressed=1, timepressed = 0.0f;
        else if (directionPressed==1 && CC>0) timepressed += dt;

        viewside=1;
        if (CC>0) viewside=+2;
        if (CC<0) viewside=0;
    }
    else if (!keydown(KEY_RIGHT) && !keydown(KEY_F6) && !keydown(KEY_LEFT) && !keydown(KEY_F5))
    {
        directionPressed=0, timepressed = 0.0f;
    }

    if(keydown(KEY_SHIFT) || keydown(KEY_XOT) || keydown(KEY_F1))              // Accelerates
    {
        if (direction==-1 && speed > 0)
        {
            direction = -1;
            speed -= 0.5;
            if (speed<0) speed=0;
            cam->decZ(speed*dt);
        }
        else
        {
            direction = 1;
            speed+=0.05;
            if (speed>maxspeedforward) speed=maxspeedforward;
            cam->incZ(speed*dt);
        }

        speedcontrol = true;
    }

    if(keydown(KEY_ALPHA) || keydown(KEY_FRAC) || keydown(KEY_F2))              // breaks or rear if speed <0
    {
        if (direction==1 && speed > 0)
        {
            direction = 1;
            speed -= 0.5;
            if (speed<0) speed=0;
            cam->incZ(speed*dt);
        }
        else
        {
            direction = -1;
            speed+=0.025;
            if (speed>maxspeedbackward) speed=maxspeedbackward;
            cam->decZ(speed*dt);
        }

        speedcontrol = true;
    }

    if(keydown(KEY_EXIT)) drawPauseQuit();

    if(keydown(KEY_OPTN)) drawOptions();

#if IS_FXLIB==1
    if(keydown(KEY_7))    screenshot = true;
    if(keydown(KEY_8))    record = !record;
#endif // IS_FXLIB

    if (speedcontrol==false)
    {
        speed-=0.1;
        if (speed<0) speed=0;

        if (direction==1)
            cam->incZ(speed*dt);
        else
            cam->decZ(speed*dt);
    }


    // Adjust position of the background
    if (lastindex!=index)
    {
        deltaFarbackground -= CC*speed*dt/250;
        deltaNearbackground -= CC*speed*dt/100;
    }
    lastindex = index;

    // adjust speed if we drive on the side of the road
    if (fround(cam->cX)<-1*ROAD_WIDTH && speed>2.0) speed=2.0;
    if (fround(cam->cX)>ROAD_WIDTH && speed>2.0) speed=2.0;

    if (fround(cam->cX)<-1.35*ROAD_WIDTH && speed>0.0)
    {
        speed=0.0;
        cam->cX=fix(-0.0*ROAD_WIDTH);        //set the car in the center of the road (was formerly -0.75)
    }
    if (fround(cam->cX)>1.35*ROAD_WIDTH && speed>0.0)
    {
        speed=0.0;
        cam->cX=fix(0.0*ROAD_WIDTH);        //set the car in the center of the road (was formerly 0.75)
    }


    /// This part controls the sliding of player's car, if we keep pressed the keys to turn too long, the car starts sliding, smoke will appear and speed is decreasing
    if (timepressed>=300.0f) // was 500.0f
    {
        CarIsSliding = true;
        cam->decX( CC*dt*speed/50 );
        speed = speed * 0.975;
        framesmoke++;
    }
    else
    {
        CarIsSliding = false;
        framesmoke=0;
    }

}


static void get_minimum_inputs( void  )
{
    key_event_t ev;
    while((ev = pollevent()).type != KEYEV_NONE)
    {

    }

    if(keydown(KEY_EXIT)  || keydown(KEY_SHIFT)) drawPauseQuit();

    if(keydown(KEY_OPTN)) drawOptions();

#if IS_FXLIB==1
    if(keydown(KEY_7))    screenshot = true;
    if(keydown(KEY_8))    record = !record;
#endif // IS_FXLIB
}



int main(void)
{
    __printf_enable_fp();
    __printf_enable_fixed();

#if IS_FXLIB==1
    usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
    usb_open(interfaces, GINT_CALL_NULL);
#endif



    gint_world_switch( GINT_CALL( is_save_existing ));

    if (!saveexist) // if we do not have saves
        gint_world_switch( GINT_CALL( saveprogress )  ); // we create a progress file which is empty

    gint_world_switch( GINT_CALL( loadprogress )); // then we load it



    gint_world_switch( GINT_CALL( is_param_existing ));

    if (!saveexist) // if we do not have saves
        gint_world_switch( GINT_CALL( saveparameters )  ); // we create a progress file which is empty

    gint_world_switch( GINT_CALL( loadparameters )); // then we load it


    DiffLevel=PlayerPara[0].DiffLevel;
    CarsNumb=PlayerPara[0].CarsNumb;
    PlayerName[0]=PlayerPara[0].PlayerName[0];
    PlayerName[1]=PlayerPara[0].PlayerName[1];
    PlayerName[2]=PlayerPara[0].PlayerName[2];


    kmalloc_arena_t *_uram = kmalloc_get_arena("_uram");
    kmalloc_gint_stats_t *_uram_stats;


    /* allow more RAM */
    char const *osv = (char*) 0x80020020;

    static kmalloc_arena_t extended_ram = { 0 };
    kmalloc_gint_stats_t *extram_stats;
    bool canWeAllocate3Mb = false;

#if (OVERCLCK_ACTIVABLE==1)
    if (gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM)
    {
        EntryLevel = overclock_detect();
        isOCPossible = true;
    }
    else
        isOCPossible = false;
#endif

    if((!strncmp(osv, "03.", 3) && osv[3] <= '6') && gint[HWCALC] == HWCALC_FXCG50) // CG-50
    {
        extended_ram.name = "extram";
        extended_ram.is_default = true;
        extended_ram.start =   (void *)0x8c200000;
        extended_ram.end = (void *)0x8c500000 ;

        kmalloc_init_arena(&extended_ram, true);
        kmalloc_add_arena(&extended_ram );
        canWeAllocate3Mb = true;
    }
    else if (gint[HWCALC] == HWCALC_PRIZM)  // CG-10/20
    {

        extended_ram.name = "extram";
        extended_ram.is_default = true;

        uint16_t *vram1, *vram2;
        dgetvram(&vram1, &vram2);
        dsetvram(vram1, vram1);

        extended_ram.start = vram2;
        extended_ram.end = (char *)vram2 + 396*224*2;

        kmalloc_init_arena(&extended_ram, true);
        kmalloc_add_arena(&extended_ram );
        canWeAllocate3Mb = false;

    }
    else if (gint[HWCALC] == HWCALC_FXCG_MANAGER) // CG-50 EMULATOR
    {

        extended_ram.name = "extram";
        extended_ram.is_default = true;
        extended_ram.start =   (void *)0x88200000;
        extended_ram.end = (void *)0x88500000 ;

        kmalloc_init_arena(&extended_ram, true);
        kmalloc_add_arena(&extended_ram );
        canWeAllocate3Mb = true;

    }
    else abort();


    srand( rtc_ticks() );

    prof_init();



    drawStartTitle();


    exitToOS = false;


    do
    {
        // Try to restart from  very begining
        initEverything();

        prof_t perf_update, perf_create, perf_project, perf_render;
        start_time = 100000000;
        elapsed_time = 0;
        score=0;
        stage=0;
        mode=0;
        selectedCircuit=0;
        secondvalidation=0;
        time_update=0;
        time_create=0;
        time_project=0;
        time_render=0;
        ranking = -1;

        currentpoint = 0;

        exitToOS = false;

        stop = false;
        bool exitflag = false;


        do
        {
            exitflag = false;
            mode = drawMainMenu();

            if (mode==0)
            {
                selectedCircuit = drawMenuCircuitSelect();

                if (selectedCircuit != -1) secondvalidation = drawMenuCircuitDetails( selectedCircuit );
                if (selectedCircuit != -1 && secondvalidation != -1) exitflag=true;
            }
            else if (mode==1)
            {
                selectedCircuit = drawMenuCircuitSelect();

                if (selectedCircuit != -1) secondvalidation = drawMenuCircuitDetails( selectedCircuit );
                if (selectedCircuit != -1 && secondvalidation != -1) secondvalidation = drawMenuBestTime( selectedCircuit );
                if (selectedCircuit != -1 && secondvalidation != -1) exitflag=true;
            }
            else if (mode==2)
            {
                drawGameOptions();

                PlayerPara[0].DiffLevel = DiffLevel;
                PlayerPara[0].CarsNumb = CarsNumb;
                PlayerPara[0].PlayerName[0]=PlayerName[0];
                PlayerPara[0].PlayerName[1]=PlayerName[1];
                PlayerPara[0].PlayerName[2]=PlayerName[2];

                gint_world_switch( GINT_CALL( saveparameters )  );

                if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == true) clock_overclock( OC_PtuneF5 );
                else if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == false && EntryLevel != OC_Undefined) clock_overclock( EntryLevel );
                else if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == false && EntryLevel == OC_Undefined) clock_overclock( OC_Default );
            }
            else if (mode==3)
            {
                drawOptions();
            }
            else if (mode==4)
            {
                drawCredit();
            }
            else if (mode==5)
            {
                exitToOS = true;
                exitflag=true;
            }
        }
        while (!exitflag);

        skipranking = false;

        if (!exitToOS)
        {
            if (selectedCircuit==0) CurrentCircuitBiome = PLAINS, multilap = false, currentLap = 1, numlap = 1;
            else if (selectedCircuit==1) CurrentCircuitBiome = DESERT, multilap = false, currentLap = 1, numlap = 1;
            else if (selectedCircuit==2) CurrentCircuitBiome = USA, multilap = false, currentLap = 1, numlap = 1;
            else if (selectedCircuit==3) CurrentCircuitBiome = FINLAND, multilap = false, currentLap = 1, numlap = 1;
            else if (selectedCircuit==4) CurrentCircuitBiome = AFRICA, multilap = false, currentLap = 1, numlap = 1;
            else if (selectedCircuit==5) CurrentCircuitBiome = PLAINS, multilap = true, currentLap = 1, numlap = 3;
            else if (selectedCircuit==6) CurrentCircuitBiome = DESERT, multilap = true, currentLap = 1, numlap = 3;
            else if (selectedCircuit==7) CurrentCircuitBiome = USA, multilap = true, currentLap = 1, numlap = 3;
            else if (selectedCircuit==8) CurrentCircuitBiome = FINLAND, multilap = true, currentLap = 1, numlap = 3;
            else if (selectedCircuit==9) CurrentCircuitBiome = AFRICA, multilap = true, currentLap = 1, numlap = 3;
            else CurrentCircuitBiome = PLAINS, multilap = false, currentLap = 1, numlap = 1;


            int nbInterestingSegments = (MAX_RENDER_DISTANCE / SEGMENT_LENGTH); // the number of segments to be projected considering the rendering distance


            perf_create = prof_make();
            prof_enter(perf_create);


            initData( );            // Positioning of the Camera

            createCircuit( selectedCircuit );        // Creates the circuit

            MAX_SEGMENT = circuit.size();

            double maxDistance = (double) ((MAX_SEGMENT-1)*SEGMENT_LENGTH);

            putBillBoards();

            createMilestones( numlap );

            createClouds();         // Creates the Sky and Clouds

            if (mode==0)
            {
                // linear circuits needs many cars
                if (selectedCircuit>=0 && selectedCircuit<=3)
                {
                    if (CarsNumb==0) NB_CARS_TRAFFIC=50;
                    else if (CarsNumb==1) NB_CARS_TRAFFIC=100;
                    else if (CarsNumb==2) NB_CARS_TRAFFIC=200;
                    else if (CarsNumb==3) NB_CARS_TRAFFIC=300;
                    else NB_CARS_TRAFFIC=100;
                }
                else    // while circular needs much less
                {
                    if (CarsNumb==0) NB_CARS_TRAFFIC=25;
                    else if (CarsNumb==1) NB_CARS_TRAFFIC=50;
                    else if (CarsNumb==2) NB_CARS_TRAFFIC=100;
                    else if (CarsNumb==3) NB_CARS_TRAFFIC=150;
                    else NB_CARS_TRAFFIC=10;
                }

                createTraffic( MAX_SEGMENT );        // Creates the cars
                prepareTraffic();       // Prepares the multiple variations of Cars (image scaling)
            }

            prepareDecoration( CurrentCircuitBiome );    // Prepares the multiple variations of Decoration (image scaling)

            prof_leave(perf_create);
            time_create = prof_time(perf_create);

            //--------------


            int indexstart = 0;
            int indexend = 0;



            float dt=0;
            uint16_t l=0;
            uint32_t remaining_time;

            DataIndex = 0;

            bool initiateStart = true;  // are we in the start sequence ?
            int32_t startCount = 6000000;
            int32_t startRemaining;


            bool finishSequence = false;  // Did we reached the end of the race ?
            bool failSequence = false;    // Did we run out of time ?
            bool stopcounting = false;

            while (!stop)
            {


                //new position
                if (!SkipTime)
                {
                    dt = ((float) (time_update+time_render+time_project) / 1000.0);
                }
                else
                {
                    dt = 0;
                    SkipTime=false;
                }


                perf_update = prof_make();
                prof_enter(perf_update);

                if (!initiateStart && !finishSequence && !failSequence) get_inputs( dt, indexstart );       // The racer is not started : no need to get inputs and we are not in fail or finish sequence
                else get_minimum_inputs();      // the we can just have minimum inputs

//former position


                if (initiateStart)
                {
                    startCount -= dt*1000;
                    startRemaining = ((float) (startCount) / 100000.0);
                }

                if (!stopcounting) start_time -= dt*1000;
                if (!stopcounting) elapsed_time += dt*1000;
                if (start_time<0) start_time=0;
                remaining_time = ((float) (start_time) / 1000000.0);

                //--------------
                if (fround(cam->cZ)<=0) cam->cZ=fixdouble(0.0);

                indexstart = fround(cam->cZ) / SEGMENT_LENGTH;
                if (indexstart<0) indexstart=0;

                indexend = indexstart+nbInterestingSegments+1;

                prof_leave(perf_update);
                time_update = prof_time(perf_update);

                //--------------

                perf_project = prof_make();
                prof_enter(perf_project);

                minYRoad = SCREEN_HEIGHT;

                if (BDrawCars && mode==0)
                {

                    updateTraffic( dt, maxDistance );

                    for (unsigned int k=0; k<traffic.size(); k++)       // Need to project 1 more segment than actual drawing
                    {
                        uint16_t CarSegment = traffic[k]->wZ / SEGMENT_LENGTH;
                        if (CarSegment>=indexstart && CarSegment<indexend)
                        {
                            circuit[CarSegment]->CarList.push_back(k);
                        }
                    }

                    float roadpart = f2float(cam->cX)/(float) ROAD_WIDTH;

                    // Update car positions : car with higher speed change line not to collide with player
                    for(unsigned int l=0; l<circuit[indexstart]->CarList.size(); l++ )  // For all cars inside that road segment
                    {
                        uint8_t indexCar = circuit[indexstart]->CarList[l];

                        if (traffic[indexCar]->wX>(roadpart-0.25f) && traffic[indexCar]->wX<(roadpart+0.25f) && traffic[indexCar]->Speed>speed)
                        {
                            if (traffic[indexCar]->wX>=-0.25) traffic[indexCar]->wX-=0.5;            // if we are on one of the most right lanes, we overtake by the left
                            else traffic[indexCar]->wX<-0.25;               // else we change to the lane on the right
                        }
                    }

                    for( unsigned int l=0; l<circuit[indexstart+1]->CarList.size(); l++ )  // For all cars inside that road segment
                    {
                        uint8_t indexCar = circuit[indexstart+1]->CarList[l];

                        if (traffic[indexCar]->wX>(roadpart-0.22f) && traffic[indexCar]->wX<(roadpart+0.22f) && traffic[indexCar]->Speed<speed)
                        {
                            speed = traffic[indexCar]->Speed - 0.5;
                            score = max(0, score-250);
                        }
                    }

                    if (DiffLevel>=1)       // Normal or Hard : cars can overtake the other opponents
                    {

                        for( unsigned int k=indexstart; k<indexend; k++)
                        {
                            for( unsigned int l=0; l<circuit[k]->CarList.size(); l++ )  // For all cars inside that road segment
                            {
                                uint8_t indexCar = circuit[k]->CarList[l];

                                for( unsigned int m=0; m<circuit[k+1]->CarList.size(); m++ )
                                {
                                    uint8_t indexCar2 = circuit[k+1]->CarList[m];

                                    if (traffic[indexCar]->wX==traffic[indexCar2]->wX && traffic[indexCar]->Speed>=traffic[indexCar2]->Speed)   // a car is following and other one just in front of ehr, at the same speed or quicker
                                    {
                                        //if (traffic[indexCar]->wX>=-0.25) traffic[indexCar]->wX-=0.5;
                                        //else traffic[indexCar]->wX=-0.25;

                                        if (traffic[indexCar]->wX>=-0.25) traffic[indexCar]->Turn = -1;
                                        else traffic[indexCar]->Turn = +1;
                                    }
                                }
                            }
                        }

                        if (DiffLevel==2)   // if difficulty set to hard, we allo changing lane (random based if not currently overtaking an other car)
                        {

                            for (unsigned int u=indexstart; u<indexend; u++)
                            {
                                for (unsigned int v=0; v<circuit[u]->CarList.size(); v++)
                                {
                                    unsigned int k = circuit[u]->CarList[v];

                                    if (traffic[k]->Turn == 0)
                                    {
                                        int mov = rand() % 1000;

                                        if (mov>=990) // we let the car change its lane in 5% of cases
                                        {
                                            if (traffic[k]->wX==-0.75) traffic[k]->Turn = +1;
                                            else if (traffic[k]->wX==0.75) traffic[k]->Turn = -1;
                                            else
                                            {
                                                int side = -1 + (rand()%3);
                                                traffic[k]->Turn = side;
                                            }
                                        }
                                    }
                                }
                            }
                        }


                        for (unsigned int u=indexstart; u<indexend; u++)
                        {
                            for (unsigned int v=0; v<circuit[u]->CarList.size(); v++)
                            {

                                unsigned int k = circuit[u]->CarList[v];

                                traffic[k]->wX += (float) traffic[k]->Turn * 0.05f;
                                if (traffic[k]->wX>=-0.775 && traffic[k]->wX<=-0.725) traffic[k]->wX = -0.75, traffic[k]->Turn = 0;
                                else if (traffic[k]->wX>=-0.275 && traffic[k]->wX<=-0.225) traffic[k]->wX = -0.25, traffic[k]->Turn = 0;
                                else if (traffic[k]->wX>=0.225 && traffic[k]->wX<=0.275) traffic[k]->wX = 0.25, traffic[k]->Turn = 0;
                                else if (traffic[k]->wX>=0.725 && traffic[k]->wX<=0.775) traffic[k]->wX = 0.75, traffic[k]->Turn = 0;
                            }
                        }

                    }
                }

                uint16_t cumulCurve=0;

                for (int k=indexstart; k<=indexend; k++)        // Need to project 1 more segment than actual drawing
                {
                    projectCircuitFP( k );                      // We project the current segment

                    if (circuit[k]->Y <= minYRoad)    minYRoad = circuit[k]->Y;

                    circuit[k]->CumulatedCurve = cumulCurve;    // This is the curve accumulated when we are drawing curves
                    cumulCurve += circuit[k]->Curve;

                    if (BDrawCars && mode==0)
                        for( unsigned int l=0; l<circuit[k]->CarList.size(); l++ )  // For all cars inside that road segment
                        {
                            uint8_t indexCar = circuit[k]->CarList[l];
                            traffic[indexCar]->Project3DFP( cam, k );
                        }
                }


                prof_leave(perf_project);
                time_project = prof_time(perf_project);

                //--------------

                perf_render = prof_make();
                prof_enter(perf_render);


                //if (BDrawBack) drawSkyOptimised( DAY_BLUE_SKY );
                //else drawSkyFull( DAY_BLUE_SKY );

                //drawSkyFull( DAY_BLUE_SKY );
                drawSkyQuick( DAY_BLUE_SKY );


                if (BDrawClds)
                {
                    drawClouds( );
                }

                if (BDrawBack)
                {
                    drawFarBackground( deltaFarbackground, CurrentCircuitBiome );
                    drawNearBackground( deltaNearbackground, CurrentCircuitBiome );
                }


                cam->cY = fix( 350+2*CS ) + interpolatePositionY(fround(cam->cZ) );

                for( int k=indexend-1; k>=indexstart; k--)
                {
                    currentcurve = circuit[k]->CumulatedCurve;

                    drawCircuitSegment( k );

                    if (BDrawDeco)
                        drawDecoration( k );

                    if (BDrawCars && mode==0)
                        for( unsigned int l=0; l<circuit[k]->CarList.size(); l++ )  // For all cars inside that road segment
                        {
                            uint8_t indexCar = circuit[k]->CarList[l];
                            drawTraffic( indexCar );
                        }

                    if (BDrawCars && mode==0)
                        circuit[k]->CarList.clear();
                }

                uint32_t handicap;
                if (DiffLevel==0)   handicap=0;              // we use normal additional time when easy
                else if (DiffLevel==1)   handicap=1000000;   // we remove 2 seconds when normal
                else if (DiffLevel==2)   handicap=2000000;   // we remove 4 seconds when hard
                else handicap=0;

                // Action raised when passing through the different points : START, CHECKPOINTS/ FINISH LINE

                if (circuit[indexstart]->Special == CHECKPOINT && circuit[indexstart]->CheckValidated == false && circuit[indexstart]->CheckLap!=currentLap)
                {
                    start_time += circuit[indexstart]->Extratime - handicap;
                    circuit[indexstart]->CheckLap=currentLap;

                    stage++;

                    score += 5000;
                    circuit[indexstart]->CheckValidated = true;
                }
                else if (circuit[indexstart]->Special == FINISH && circuit[indexstart]->CheckValidated == false && circuit[indexstart]->CheckLap!=currentLap)
                {
                    circuit[indexstart]->CheckLap=currentLap;

                    stage++;

                    if (currentLap<numlap)
                    {
                        currentLap++;
                        start_time += circuit[indexstart]->Extratime - handicap;
                        score += 5000;
                        cam->decZ( indexstart*SEGMENT_LENGTH );

                        if (mode==0)
                            for( unsigned int k=0; k<traffic.size(); k++ )
                                traffic[k]->wZ-=indexstart*SEGMENT_LENGTH;
                    }
                    else
                    {
                        circuit[indexstart]->CheckValidated = true;
                        score+=20000;
                        finishSequence=true;
                        stopcounting = true;
                        FinalTime = elapsed_time;
                    }
#if DEBUGXXX==1
                    if (usb_is_open())
                    {
                        //sprintf( texttosend, "FNSH : Chrono %D - %D", elapsed_time/1000000, start_time/1000000 );
                        sprintf( texttosend, "FNSH : Chrono %D - Reste %D - Extra %D --> Total %D", elapsed_time/1000000, (start_time-circuit[indexstart]->Extratime+handicap)/1000000, (circuit[indexstart]->Extratime-handicap)/1000000, start_time/1000000 );
                        usb_fxlink_text(texttosend, 0);
                    }
#endif
                }
                else if (circuit[indexstart]->Special == START && circuit[indexstart]->CheckValidated == false && circuit[indexstart]->CheckLap!=currentLap)
                {
                    if (currentLap==1)
                    {
                        score = 0;
                        start_time = circuit[indexstart]->Extratime - handicap;
                        circuit[indexstart]->CheckLap=currentLap;
                        elapsed_time = 0;
                    }
                    else
                    {
                        circuit[indexstart]->CheckLap = currentLap;
                        //start_time += circuit[indexstart]->Extratime - handicap;
                        circuit[indexstart]->CheckValidated = true;
                    }
#if DEBUGXXX==1
                    if (usb_is_open())
                    {
                        //sprintf( texttosend, "STRT : Chrono %D - %D", elapsed_time/1000000, start_time/1000000 );
                        sprintf( texttosend, "STRT : Chrono %D - Reste %D - Extra %D --> Total %D", elapsed_time/1000000, (start_time-circuit[indexstart]->Extratime+handicap)/1000000, (circuit[indexstart]->Extratime-handicap)/1000000, start_time/1000000 );
                        usb_fxlink_text(texttosend, 0);
                    }
#endif
                }


                // Draw a message when time is over
                if (start_time<=0 && mode == 0)
                {
                    failSequence=true;
                    stopcounting = true;
                }


                int mod_base=20;
                int mod_comp=10;


                if (abs(speed)<1.0)  mod_base = 30, mod_comp = 15;
                else if (abs(speed)<2.0)  mod_base = 20, mod_comp = 10;
                else if (abs(speed)<3.0)  mod_base = 16, mod_comp = 8;
                else if (abs(speed)<4.0)  mod_base = 12, mod_comp = 6;
                else if (abs(speed)<5.0)  mod_base = 8, mod_comp = 4;
                else mod_base = 4, mod_comp = 2;


                if ((speed==0) || (l%mod_base<=mod_comp))    // the small rick to have the speed impression on wheels and to have the correct view of the car during turns
                {
                    if (viewside==-2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 99,1,80,46,  DIMAGE_NONE);
                    else if (viewside==-1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 181,1,74,46,  DIMAGE_NONE);
                    else if (viewside==0) dsubimage( SCREEN_CX-36, SCREEN_HEIGHT-46, &player, 257,1,72,46,  DIMAGE_NONE);
                    else if (viewside==1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 331,1,74,46,  DIMAGE_NONE);
                    else if (viewside==2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 407,1,80,46,  DIMAGE_NONE);
                }
                else
                {
                    if (viewside==-2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 99,49,80,46,  DIMAGE_NONE);
                    else if (viewside==-1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 181,49,74,46,  DIMAGE_NONE);
                    else if (viewside==0) dsubimage( SCREEN_CX-36, SCREEN_HEIGHT-46, &player, 257,49,72,46,  DIMAGE_NONE);
                    else if (viewside==1) dsubimage( SCREEN_CX-37, SCREEN_HEIGHT-46, &player, 331,49,74,46,  DIMAGE_NONE);
                    else if (viewside==2) dsubimage( SCREEN_CX-40, SCREEN_HEIGHT-46, &player, 407,49,80,46,  DIMAGE_NONE);
                }

                dfont(&plate);
                if (viewside==-2) dprint_opt( 205, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2]  );
                else if (viewside==-1) dprint_opt( 202, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2]  );
                else if (viewside==0) dprint_opt( 197, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2]  );
                else if (viewside==1) dprint_opt( 193, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2]  );
                else if (viewside==2) dprint_opt( 189, 203, C_WHITE, C_BLACK, DTEXT_CENTER, DTEXT_CENTER, "%c%c%c", PlayerName[0], PlayerName[1], PlayerName[2]  );

                if (CarIsSliding)
                {
                    if (framesmoke>=0 && framesmoke<10) dimage(SCREEN_CX-smoke1.width/2, SCREEN_HEIGHT-smoke1.height, &smoke1 );
                    else if (framesmoke>=10 && framesmoke<20) dimage(SCREEN_CX-smoke2.width/2, SCREEN_HEIGHT-smoke2.height, &smoke2 );
                    else if (framesmoke>=30 && framesmoke<30) dimage(SCREEN_CX-smoke3.width/2, SCREEN_HEIGHT-smoke3.height, &smoke3 );
                    else framesmoke=0;
                }

                if (direction==+1) score += speed*dt/10;


                float drawspeed = (float) (speed*5.0f);


                dsubimage( 5, 5, &speedhud, 0, 117, 37, 13,  DIMAGE_NONE);          // speed logo
                dsubimage( 135, 5, &speedhud, 0, 130, 37, 13,  DIMAGE_NONE);          // timer logo

                dsubimage( 245, 5, &speedhud, 37, 117, 38, 13,  DIMAGE_NONE);          // speed logo
                dsubimage( 245, 25, &speedhud, 37, 130, 38, 13,  DIMAGE_NONE);          // timer logo

                dfont(&speedfont);
                if (drawspeed==0.0)
                {
                    dprint_opt(122,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "0 :", drawspeed );
                    dprint_opt(120,1, C_RGB(255,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "0 :", drawspeed );
                }
                else
                {
                    dprint_opt(122,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.1f :", drawspeed );
                    dprint_opt(120,1, C_RGB(255,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.1f :", drawspeed );      //the ':' char corresponds to "Km/h"
                }

                if (mode==0)
                {
                    dprint_opt(238,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", remaining_time );
                    dprint_opt(237,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", remaining_time );    // the ';' char corresponds to "s"
                }
                else if (mode==1)
                {
                    dprint_opt(238,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", elapsed_time/1000000 );
                    dprint_opt(237,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D ;", elapsed_time/1000000 );    // the ';' char corresponds to "s"
                }


                dprint_opt(390,3, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", score );
                dprint_opt(388,1, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", score );    // the ';' char corresponds to "s"

                dprint_opt(390,23, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", stage );
                dprint_opt(388,21, C_RGB(255,255,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%.3D", stage );    // the ';' char corresponds to "s"


                if (multilap)
                {
                    dsubimage( 135, 25, &speedhud, 28, 143, 27, 13, DIMAGE_NONE);  // Lap logo

                    dprint_opt(233,23, C_RGB(0,0,0), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%d/%d", currentLap, numlap );
                    dprint_opt(231,21, C_RGB(255,0,255), C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%d/%d", currentLap, numlap );    // the ';' char corresponds to "s"
                }


                /// Graphical speed indicator
                if (visualspeedindicator)
                {
                    if (drawspeed==0.0) dsubimage( 48, 25, &speedhud, 0, 0, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<3.30) dsubimage( 48, 25, &speedhud, 0, 13, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<6.70) dsubimage( 48, 25, &speedhud, 0, 26, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<10.0) dsubimage( 48, 25, &speedhud, 0, 39, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<13.3) dsubimage( 48, 25, &speedhud, 0, 52, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<16.7) dsubimage( 48, 25, &speedhud, 0, 65, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<20.0) dsubimage( 48, 25, &speedhud, 0, 78, 76, 13,  DIMAGE_NONE);
                    else if (drawspeed<23.3) dsubimage( 48, 25, &speedhud, 0, 91, 76, 13,  DIMAGE_NONE);
                    else dsubimage( 48, 25, &speedhud, 0, 104, 76, 13,  DIMAGE_NONE);
                }


                /// Checkpoint indicator
                if (visualnextpoint)
                {
                    double Z1 = jalons[currentpoint]->wZ;
                    double Z2 = jalons[currentpoint+1]->wZ;

                    double frac = (fround(cam->cZ) - Z1) / (Z2 - Z1 );
                    if (frac<0) frac=0;

                    if (fround(cam->cZ) >= Z2) currentpoint++;

                        drect( 15, 50, 20, 150, C_WHITE );

                    drect( 10, 49+frac*100, 25, 51+frac*100, C_RED );
                }


                if (finishSequence)
                {
                    if (mode==1 && !skipranking)
                    {

                        bool donerank = false;
                        int k=0;

                        while (!donerank && k<5)
                        {
                            if (FinalTime<=HallOfFame[selectedCircuit][k].bestTime)
                            {

                                for( int l=4; l>k; l--)
                                {
                                    HallOfFame[selectedCircuit][l].playerName[0] = HallOfFame[selectedCircuit][l-1].playerName[0];
                                    HallOfFame[selectedCircuit][l].playerName[1] = HallOfFame[selectedCircuit][l-1].playerName[1];
                                    HallOfFame[selectedCircuit][l].playerName[2] = HallOfFame[selectedCircuit][l-1].playerName[2];
                                    HallOfFame[selectedCircuit][l].padding = HallOfFame[selectedCircuit][l-1].padding;
                                    HallOfFame[selectedCircuit][l].bestScore = HallOfFame[selectedCircuit][l-1].bestScore;
                                    HallOfFame[selectedCircuit][l].bestTime = HallOfFame[selectedCircuit][l-1].bestTime;
                                }

                                HallOfFame[selectedCircuit][k].playerName[0] = PlayerName[0];
                                HallOfFame[selectedCircuit][k].playerName[1] = PlayerName[1];
                                HallOfFame[selectedCircuit][k].playerName[2] = PlayerName[2];
                                HallOfFame[selectedCircuit][k].padding = 'X';
                                HallOfFame[selectedCircuit][k].bestScore = score;
                                HallOfFame[selectedCircuit][k].bestTime = FinalTime;

                                donerank = true;
                                skipranking = true;

                                ranking = k;

                                gint_world_switch( GINT_CALL( saveprogress )  );

                            }
                            else k++;
                        }

                    }

                    speed = 0;

                    dimage( 198-bigflag.width/2, 112-bigflag.height/2, &bigflag );

                    if (ranking!=-1 || mode==0)
                    {

                    dfont(&startseq);

                    dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" );
                    dprint_opt(198,112, C_RGB(0,255,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" );

                    dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "WIN", ranking );
                    dprint_opt(198,112, C_RGB(0,255,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "WIN", ranking );

                    dfont(&autofont);

                    uint32_t temp1 = FinalTime/1000000/60;
                    uint32_t temp2 = FinalTime/1000000 - temp1*60;
                    uint32_t temp3 = (FinalTime - temp1*60*1000000 - temp2*1000000)/1000;
                    dprint_opt(200, 202, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "%d - %D:%D,%D", ranking+1, temp1, temp2, temp3 );
                    dprint_opt(198, 200, C_RGB(255, 255, 255), C_NONE, DTEXT_CENTER, DTEXT_TOP, "%d - %D:%D,%D", ranking+1, temp1, temp2, temp3 );


                    }

                    else
                    {

                    dfont(&startseq);

                    dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" );
                    dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" );

                    dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" );
                    dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" );

                    }

                }


                if (failSequence)
                {
                    speed = 0;

                    dimage( 198-bigflag.width/2, 112-bigflag.height/2, &bigflag );

                    dfont(&startseq);

                    dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" );
                    dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_BOTTOM, "YOU" );

                    dprint_opt(200,108, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" );
                    dprint_opt(198,112, C_RGB(255,0,0), C_NONE, DTEXT_CENTER, DTEXT_TOP, "LOSE" );
                }


                if (initiateStart)          // We are in the start sequence with the countdown
                {
                    dfont(&startseq);
                    if (startRemaining<54 && startRemaining>46)
                    {
                        dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">5<" );
                        dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">5<" );
                    }
                    else if (startRemaining<44 && startRemaining>36)
                    {
                        dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">4<" );
                        dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">4<" );
                    }
                    else if (startRemaining<34 && startRemaining>26)
                    {
                        dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">3<" );
                        dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">3<" );
                    }
                    else if (startRemaining<24 && startRemaining>16)
                    {
                        dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">2<" );
                        dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">2<" );
                    }
                    else if (startRemaining<14 && startRemaining>6)
                    {
                        dprint_opt(200,114, C_RGB(0,0,0), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">1<" );
                        dprint_opt(198,112, C_RGB(255,0,255), C_NONE, DTEXT_CENTER, DTEXT_CENTER, ">1<" );
                    }
                    else if (startRemaining<4 && startRemaining>-4)
                    {
                        dimage( 198-bigflag.width/2, 112-bigflag.height/2, &bigflag );
                    }
                    else if (startRemaining<-4)
                    {
                        start_time = 99000000;
                        initiateStart=false;
                    }

                }

                //dupdate();

                //dprint( 3, 202, C_BLACK, "%.0f", dt );
                //dprint( 1, 200, C_WHITE, "%.0f", dt );

                if (BDrawFPS)
                {
                    dfont(&speedfont);
                    dsubimage( 5, 205, &speedhud, 0, 143, 27, 13,  DIMAGE_NONE);          // fps logo

                    dprint_opt(42,202, C_RGB(0,0,0), C_NONE, DTEXT_LEFT, DTEXT_TOP, "%.0f <", (float) (1000.0f/dt) );       // the '>' symbol corresponds to "fps"
                    dprint_opt(40,200, C_RGB(255,255,0), C_NONE, DTEXT_LEFT, DTEXT_TOP, "%.0f <", (float) (1000.0f/dt) );


                    GraphPerf[DataIndex].update = (uint8_t) (time_update/1000);
                    GraphPerf[DataIndex].project = (uint8_t) (time_project/1000);
                    GraphPerf[DataIndex].render = (uint8_t) (time_render/1000);

                    DataIndex++;
                    DataIndex = DataIndex % MAXDATA;

                    dline( 249, 201, 375, 201, C_BLACK );
                    dline( 249, 202, 375, 202, C_BLACK );

                    dline( 249, 200-33, 375, 200-33, C_BLACK );
                    dline( 249, 200-40, 375, 200-40, C_BLACK );
                    dline( 249, 200-50, 375, 200-50, C_BLACK );

                    dline( 249, 201, 249, 100, C_BLACK );
                    dline( 248, 201, 248, 100, C_BLACK );

                    for( unsigned int k=0; k<MAXDATA-1; k++)
                    {
                        dpixel( 250+k, 200-GraphPerf[k].update, C_RGB(255,0,0) );
                        dpixel( 250+k, 201-GraphPerf[k].update, C_RGB(255,0,0) );

                        dpixel( 250+k, 200-GraphPerf[k].update-GraphPerf[k].project, C_RGB(0,255,0) );
                        dpixel( 250+k, 201-GraphPerf[k].update-GraphPerf[k].project, C_RGB(0,255,0) );

                        dpixel( 250+k, 200-GraphPerf[k].update-GraphPerf[k].project-GraphPerf[k].render, C_RGB(0,0,255) );
                        dpixel( 250+k, 201-GraphPerf[k].update-GraphPerf[k].project-GraphPerf[k].render, C_RGB(0,0,255) );
                    }
                }

                r61524_display(gint_vram, 0, DHEIGHT, R61524_DMA_WAIT);


                prof_leave(perf_render);
                time_render = prof_time(perf_render);

#if IS_FXLIB==1
                if (screenshot && usb_is_open())
                {
                    usb_fxlink_screenshot(false);
                    screenshot = false;
                }

                if(record && usb_is_open())
                {
                    usb_fxlink_videocapture(false);
                }
#endif

                l++;
            }

            /*
                    _uram_stats = kmalloc_get_gint_stats(_uram);
                    sprintf( texttosend, "Memory Status - Used: %d - Free: %d - Peak Used: %d", _uram_stats->used_memory, _uram_stats->free_memory, _uram_stats->peak_used_memory);
                    usb_fxlink_text(texttosend, 0);
            */

            // Free all memory


            freeDecoration();

            for(unsigned int i=0; i<circuit.size(); i++ )    delete circuit[i];  // Not to forget to delete each elements
            circuit.clear();

            for(unsigned int i=0; i<jalons.size(); i++ )    delete jalons[i];  // Not to forget to delete each elements
            jalons.clear();

            for(unsigned int i=0; i<nuages.size(); i++ )    delete nuages[i];    // Not to forget to delete each elements
            nuages.clear();

            if (mode==0)
            {
                freeTraffic();

                for(unsigned int i=0; i<traffic.size(); i++ )
                    delete traffic[i];  // Not to forget to delete each elements

                traffic.clear();
            }

        }
    }
    while (exitToOS==false);






    prof_quit();

#if IS_FXLIB==1
    usb_close();
#endif

    if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == true && EntryLevel != OC_Undefined) clock_overclock( EntryLevel );
    else if ((gint[HWCALC] == HWCALC_FXCG50 || gint[HWCALC] == HWCALC_PRIZM) && isOCActivated == true && EntryLevel == OC_Undefined) clock_overclock( OC_Default );


    delete cam;


    // We set back zeros at the end of the program
    memset(extended_ram.start, 0, (char *)extended_ram.end - (char *)extended_ram.start);


    return 1;
}
