/*
    Raydium - CQFD Corp.
    http://raydium.org/
    License: GPL - GNU General Public License, see "gpl.txt" file.
*/



char *version="version 1.0";

char *svn_rev="$Rev: 258 $";

//Extended commands / debug options
#define EXT

//#define FDS
//#define CETSIS
//#define JPO
#define STR
//#define ISIMA

#if defined _ISIMA
#define ISIMA
#endif // defined

#if defined _GE
#undef ISIMA
#define STR
#endif

/*
#else
#warning Building Default Str Simulator
#endif*/

#define CAR_CAR_COLLIDE 0

#ifndef WIN32
#define max(a,b)  (((a)>=(b))?(a):(b))
#define min(a,b)  (((a)<(b))?(a):(b))
#endif // WIN32

#include "raydium/index.c"
#include "../libremote/remote_periph.h"
#include "_raydium.h"

//TODO utiliser les poids fort et garder les poids faible pour le numero de capteur
// Plus efficace pour les retrouver.
#define TYPE_WHEEL		1
#define TYPE_CAR_BODY   2
#define TYPE_CAPTEUR    4
#define TYPE_BALANCIER	8



#define RAYDIUM_ODE_SLIP_SIMUL  RAYDIUM_ODE_SLIP_NORMAL / 50.0f

#define CHANGE_TRACK RAYDIUM_NETWORK_PACKET_BASE
#define CHANGE_MODE  RAYDIUM_NETWORK_PACKET_BASE+1
#define CAR_FINISH   RAYDIUM_NETWORK_PACKET_BASE+2

#define C_VERT        (1<<0)
#define C_JAUNE       (1<<1)
#define C_ROUGE       (1<<2)
#define C_BLEUE       (1<<3)
#define C_CYAN        (1<<4)

#define COLLISION     (1<<6)
#define FINAL         (1<<7)

#define PISTE_CHANGE  (1<<8)
#define MODE_CHANGE   (1<<9)

#define ARRIVEE       (1<<11)
#define HORS_PISTE    (1<<12)
#define TELEPORT      (1<<13)
#define EXPLODE       (1<<14)


#define FEU_VERT      (1<<15)

#ifdef FDS
char *pistes[]={"piste_fds.tri","piste_elem_v1.tri","piste_elem_v2.tri","piste_elem_v3.tri","piste_elem_v4.tri",""};
#endif
#ifdef JPO
char *pistes[]={"simple.tri","hopla.tri","waou.tri",""};
#endif
#ifdef STR
char *pistes[]={"piste_elem_v1.tri","piste_elem_v2.tri","piste_elem_v3.tri","piste_elem_v4.tri",""};
#endif
int npiste=-1;

enum {camera_suivi,camera_fixe,camera_libre,camera_global} camera_mode=camera_suivi;
enum {couleur_osd_noir,couleur_osd_blanc} couleur_osd=couleur_osd_blanc;

enum {mesh,ode,mesh_ode} affichage_mode=mesh;
enum {vehicule_on,vehicule_off} vehicule_test=vehicule_off;
enum {attente,course,essais}course_mode=essais;
enum {disconnected,searching,connected,connected_master,error}net_mode=searching;
enum {info_off,info_on,info_pos,info_flag} affichage_info=info_off;
enum {quiet_on,quiet_off} quiet=quiet_on;

typedef enum {vert,orange,rouge} _etat_feux;
_etat_feux etat_feux=vert;

typedef enum {vehicule_invalide,vehicule_cours,vehicule_arrivee} vehicule_etat_;

double timer;
int n_suivi=-1;

vehicule_etat_ vehicule_etat[REMOTE_MAX_CLIENT+1];
double vehicule_ref_time[REMOTE_MAX_CLIENT+1];
double vehicule_lap_time[REMOTE_MAX_CLIENT+1];
double vehicule_lap_time_best[REMOTE_MAX_CLIENT+1];
int vehicule_checkpoint_num[REMOTE_MAX_CLIENT+1];
float vehicule_checkpoint_time[REMOTE_MAX_CLIENT+1];
unsigned int vehicule_event_local[REMOTE_MAX_CLIENT+1];
int vehicule_capteur_trig[REMOTE_MAX_CLIENT+1];
int vehicule_capteur_trig_last[REMOTE_MAX_CLIENT+1];
double vehicule_capteur_trig_time[REMOTE_MAX_CLIENT+1];
int vehicule_capteur_last[REMOTE_MAX_CLIENT+1];
char vehicule_name[REMOTE_MAX_CLIENT+1][8+1];
int vehicule_name_ind[REMOTE_MAX_CLIENT+1];

int piste_checkpoint_last;


#define COURSE_MAX_ARRIVEE (8*REMOTE_MAX_CLIENT+1)

typedef struct course_arrivee_{
    float temps;
    int lap_num;
    int id;
    char nom[9];
}course_arrivee_;

course_arrivee_ course_arrivee[COURSE_MAX_ARRIVEE];
int course_n_arrivees;

void step(void);

// Automatically called by libremote to test for an event to send
float simul_event(float a, int n){
static unsigned int levent[REMOTE_MAX_CLIENT+1];
unsigned int event;

    if (a) // Clear pending event
        levent[n]=vehicule_event_local[n]=0;

    event=vehicule_event_local[n]^levent[n];

    levent[n]=vehicule_event_local[n];

    return (vehicule_event_local[n] & event);

}

float simul_score(float a, int n){
float score;

    if (vehicule_lap_time[n]>0){
        return vehicule_lap_time[n];
    }
    score = piste_checkpoint_last-vehicule_checkpoint_num[n];
    score = score *1000.0f + vehicule_checkpoint_time[n];
    return score;
}

float simul_id (float a, int n){ return n;}

float simul_mode(float a, int n){
unsigned int val;

    val = (((course_mode+1) <<8) | (npiste+1)) & 0x7fff;
    if (etat_feux==vert)
        val|=FEU_VERT;

    vehicule_event_local[n]&=~(PISTE_CHANGE) | (MODE_CHANGE);
    return val;
}

float simul_capt(float a, int n){

    vehicule_event_local[n]&=~(C_VERT | C_JAUNE | C_ROUGE | C_JAUNE | C_CYAN | FINAL );
    return vehicule_capteur_last[n];

}

float simul_flags(float a, int n){
    return vehicule_event_local[n];
}

float simul_time(float a, int n){
    return timer-vehicule_ref_time[n];
}

float simul_name(float a,int n){
char c;
    c=a;
//    raydium_log("Nom:%c",c);
    vehicule_name[n][vehicule_name_ind[n]]=c;
    vehicule_name_ind[n]++;
    vehicule_name[n][vehicule_name_ind[n]]=0;
    if (vehicule_name_ind[n]>8)
        vehicule_name_ind[n]=0;
    if (c==0)
        vehicule_name_ind[n]=0;
}

float rlap_time(float a,int n){
    return vehicule_lap_time[n];
}

float simul_teleport(float chk,int n){
char cpt_name[16];
char name[RAYDIUM_MAX_NAME_LEN];
int a;
dReal * pos;
dReal rx,ry,rz;
int ichk;

    if (vehicule_etat[n]==vehicule_invalide)
        return;

    ichk=chk;
    sprintf (cpt_name,"V!%3.3d",ichk);
    a=raydium_ode_element_find(cpt_name);
    if (a!=-1){
        pos=raydium_ode_element_pos_get(a);
        remote_client_name("#voiture",n,name);
        raydium_ode_object_move_name_3f(name,pos[0],pos[1],0.5);
        raydium_ode_element_rot_get(a,&rx,&ry,&rz);
        raydium_ode_object_rotate_name_3f(name,rx,ry,rz);
        vehicule_event_local[n]|= TELEPORT;
    }
}

char ray_collide(int e1, int e2, dContact *c){
int i1,i2;
int n1,n2;

    i1=raydium_ode_element_tag_get(e1);
    i2=raydium_ode_element_tag_get(e2);
    n1=i1 & 0x0ffff;
    n2=i2 & 0x0ffff;
    i1=i1>>16;
    i2=i2>>16;

    if (raydium_ode_network_element_isdistant(e1))
        return 0;
    if (raydium_ode_network_element_isdistant(e2))
        return 0;
    if (e1==0 || e2==0) // Ground collide
        return 1;
    if (c[0].geom.depth<1) // Collision avec le corps du capteur lui meme
        return 0;
    if (i1==TYPE_CAR_BODY || i2==TYPE_CAR_BODY)
        return CAR_CAR_COLLIDE;
    if (i1==TYPE_WHEEL || i2==TYPE_WHEEL)
        return CAR_CAR_COLLIDE;
    if (i1==TYPE_CAPTEUR || i2==TYPE_CAPTEUR)
        return 0;
return 1;
}

char collide(int e1, int e2, dContact *c){
    int i1,i2;
    int n1,n2;
    int nv,nc;
    int e,capt,n;
    c++;
    i1=raydium_ode_element_tag_get(e1);
    i2=raydium_ode_element_tag_get(e2);

    n1=i1 &  0x0ffff;
    n2=i2 &  0x0ffff;
    i1=i1 >> 16;
    if (i2!=RAYDIUM_ODE_TAG_GROUND)
        i2=i2 >> 16;
    //raydium_log ("%s <-> %s ",raydium_ode_element[e1].name,raydium_ode_element[e2].name);

    if ((i1==TYPE_CAR_BODY || i1==TYPE_WHEEL) && (i2==TYPE_CAR_BODY || i2==TYPE_WHEEL))
        return CAR_CAR_COLLIDE;
    if(i1==TYPE_BALANCIER || i2==TYPE_BALANCIER)
        return 0;
    e=-1;
    if (i1==TYPE_CAPTEUR || i2==TYPE_CAPTEUR){
        if (i1==TYPE_WHEEL || i1==TYPE_CAR_BODY) {e=e1;capt=e2;nv=n1;}
        if (i2==TYPE_WHEEL || i2==TYPE_CAR_BODY) {e=e2;capt=e1;nv=n2;}

        if(e!=-1 && vehicule_capteur_trig[nv]<0){
            vehicule_capteur_trig[nv]=capt; //Traité dans gestion course
            vehicule_capteur_trig_time[nv]=timer;
        }
        return 0;
    }
    e=-1;
    //raydium_log ("%s <-> %s ",raydium_ode_element[e1].name,raydium_ode_element[e2].name);
    if ((i1==TYPE_CAR_BODY && i2==RAYDIUM_ODE_TAG_GROUND) || (i2==TYPE_CAR_BODY && i1==RAYDIUM_ODE_TAG_GROUND)){
        if (i1==TYPE_CAR_BODY) {e=e1;capt=e2;}
        if (i2==TYPE_CAR_BODY) {e=e2;capt=e1;}
        if(e!=-1){
            n=strlen(raydium_ode_element[e].name);
            n=atoi(&raydium_ode_element[e].name[n-2]);
            vehicule_event_local[n]|=COLLISION;
        }
    }

return 1;
}

char near_collide(int i1, int i2){
    return 1; //TODO verifier si utile tout le temps
    if (i1 ==0 || i2 ==0)
        return 1;
    return 0;
}

void simul_init(int n){

    vehicule_ref_time[n]=timer;
    vehicule_lap_time[n]=-1;
    vehicule_lap_time_best[n]=-1;
    vehicule_checkpoint_time[n]=-1;
    vehicule_checkpoint_num[n]=0;
    vehicule_capteur_trig[n]=-1;
    vehicule_capteur_trig_last[n]=-1;
    vehicule_capteur_trig_time[n]=0;
    vehicule_capteur_last[n]=0;
    vehicule_event_local[n]=0;
}

void simul_create(float f, int n){
char nom[RAYDIUM_MAX_NAME_LEN];

int objet;
int corps,balancier,joint_balancier,pneu_ad,pneu_ag,pneu_rd,pneu_rg,susp_ad,susp_ag,susp_rd,susp_rg;
int moteur,direction,tel_us,mot_tel_us,pivot_tel_us;
int num;

#define BREAK_FORCE     0     //200
#define ERP_CFM		0.99,0.1  //#define ERP_CFM         0.1,1.0
#define ROTFRICTION	0.005     //#define ROTFRICTION     0.05


    remote_client_name("#voiture",n,nom);
    objet=raydium_ode_object_create(nom);
    remote_client_name("#corps",n,nom);
    corps=raydium_ode_object_box_add(nom,objet,6,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,(TYPE_CAR_BODY<<16)+n,"jeepch.tri");
    raydium_ode_element_slip(corps,RAYDIUM_ODE_SLIP_ICE/10.0f); // /4.0f

    raydium_ode_network_next_local_only=1;
    remote_client_name("#balancier",n,nom);
    balancier=raydium_ode_object_box_add(nom,objet,3,0.1,0.1,0.1,RAYDIUM_ODE_STANDARD,(TYPE_BALANCIER<<16)+n,"");
    raydium_ode_element_move_3f(balancier,0,0,-0.9);
    remote_client_name("#joint_balancier",n,nom);
    joint_balancier=raydium_ode_joint_attach_fixed(nom,corps,balancier);

    raydium_ode_network_next_local_only=1;
    remote_client_name("#pneu_ag",n,nom);
    pneu_ag=raydium_ode_object_sphere_add(nom,objet,0.01,0.22,RAYDIUM_ODE_STANDARD,(TYPE_WHEEL<<16)+n,"roue_barbare.tri");
    raydium_ode_element_rotfriction(pneu_ag,ROTFRICTION);
    raydium_ode_element_slip(pneu_ag,RAYDIUM_ODE_SLIP_SIMUL);
    raydium_ode_element_move_3f(pneu_ag,0.42,0.453,-0.180);
    remote_client_name("#susp_ag",n,nom);
    susp_ag=raydium_ode_joint_attach_hinge2(nom,corps,pneu_ag,RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
    raydium_ode_joint_hinge2_limits (susp_ag,-M_PI/3.5,M_PI/3.5);
    raydium_ode_joint_break_force(susp_ag,BREAK_FORCE);
    raydium_ode_joint_suspension(susp_ag,ERP_CFM);

    raydium_ode_network_next_local_only=1;
    remote_client_name("#pneu_ad",n,nom);
    pneu_ad=raydium_ode_object_sphere_add(nom,objet,0.01,0.22,RAYDIUM_ODE_STANDARD,(TYPE_WHEEL<<16)+n,"roue_barbare.tri");
    raydium_ode_element_rotfriction(pneu_ad,ROTFRICTION);
    raydium_ode_element_slip (pneu_ad,RAYDIUM_ODE_SLIP_SIMUL);
    raydium_ode_element_move_3f(pneu_ad,0.42,-0.453,-0.180);
    remote_client_name("#susp_ad",n,nom);
    susp_ad=raydium_ode_joint_attach_hinge2(nom,corps,pneu_ad,RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
    raydium_ode_joint_hinge2_limits(susp_ad,-M_PI/3.5,M_PI/3.5);
    raydium_ode_joint_break_force(susp_ad,BREAK_FORCE);
    raydium_ode_joint_suspension(susp_ad,ERP_CFM);

    raydium_ode_network_next_local_only=1;
    remote_client_name("#pneu_rg",n,nom);
    pneu_rg=raydium_ode_object_sphere_add(nom,objet,0.01,0.22,RAYDIUM_ODE_STANDARD,(TYPE_WHEEL<<16)+n,"roue_barbare.tri");
    raydium_ode_element_rotfriction(pneu_rg,ROTFRICTION);
    raydium_ode_element_slip(pneu_rg,RAYDIUM_ODE_SLIP_SIMUL);
    raydium_ode_element_move_3f(pneu_rg,-0.444,0.453,-0.180);
    remote_client_name("#susp_rg",n,nom);
    susp_rg=raydium_ode_joint_attach_hinge2(nom,corps,pneu_rg,RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
    raydium_ode_joint_hinge2_block(susp_rg,1);
    raydium_ode_joint_break_force(susp_rg,BREAK_FORCE);
    raydium_ode_joint_suspension(susp_rg,ERP_CFM);

    raydium_ode_network_next_local_only=1;
    remote_client_name("#pneu_rd",n,nom);
    pneu_rd=raydium_ode_object_sphere_add(nom,objet,0.01,0.22,RAYDIUM_ODE_STANDARD,(TYPE_WHEEL<<16)+n,"roue_barbare.tri");
    raydium_ode_element_rotfriction(pneu_rd,ROTFRICTION);
    raydium_ode_element_slip (pneu_rd,RAYDIUM_ODE_SLIP_SIMUL);
    raydium_ode_element_move_3f(pneu_rd,-0.444,-0.453,-0.180);
    remote_client_name("#susp_rd",n,nom);
    susp_rd=raydium_ode_joint_attach_hinge2(nom,corps,pneu_rd,RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
    raydium_ode_joint_hinge2_block(susp_rd,1);
    raydium_ode_joint_break_force(susp_rd,BREAK_FORCE);
    raydium_ode_joint_suspension(susp_rd,ERP_CFM);

    remote_client_name("#moteur",n,nom);
    moteur=raydium_ode_motor_create(nom,objet,RAYDIUM_ODE_MOTOR_ENGINE);
    raydium_ode_motor_attach(moteur,susp_ad,1);
    raydium_ode_motor_attach(moteur,susp_ag,1);
    raydium_ode_motor_attach(moteur,susp_rd,1);
    raydium_ode_motor_attach(moteur,susp_rg,1);
    raydium_ode_motor_power_max(moteur,3);


    remote_client_name("#direction",n,nom);
    direction=raydium_ode_motor_create(nom,objet,RAYDIUM_ODE_MOTOR_ANGULAR);
    raydium_ode_motor_attach(direction,susp_ad,0);
    raydium_ode_motor_attach(direction,susp_ag,0);
    raydium_ode_motor_power_max(direction,100); //0.5

    //raydium_sound_SourcePlay(sound_car);
    //raydium_ode_element_sound_update(corps,sound_car);

    dReal pos[3];
    memcpy(pos,raydium_ode_element_pos_get(corps),sizeof(dReal)*3); //TODO a modifie memcpy inutile

    raydium_ode_network_next_local_only=1;
    remote_client_name("#tel_us",n,nom);
    tel_us=raydium_ode_object_box_add(nom,objet,0.01,0.1,0.1,0.1,RAYDIUM_ODE_STANDARD,(TYPE_CAR_BODY<<16)+n,"");
    raydium_ode_element_move_3f(tel_us,pos[0],pos[1],pos[2]+0.12 /*0.21*/); // pos[2]+0.21

    remote_client_name("#pivot_tel_us",n,nom);
    pivot_tel_us=raydium_ode_joint_attach_hinge(nom,tel_us,corps,pos[0],pos[1],pos[2]+0.16,RAYDIUM_ODE_JOINT_AXE_Z);
    raydium_ode_joint_hinge_limits(pivot_tel_us,-3.1415/0.9,3.1415/0.9);
    remote_client_name("#mot_tel_us",n,nom);
#ifdef FDS
    mot_tel_us=raydium_ode_motor_create(nom,objet,RAYDIUM_ODE_MOTOR_ANGULAR);
    raydium_ode_motor_attach(mot_tel_us,pivot_tel_us,0);
    raydium_ode_motor_power_max(mot_tel_us,1e-2); // Allow motor to drift
#endif
#ifdef JPO
    mot_tel_us=raydium_ode_motor_create(nom,objet,RAYDIUM_ODE_MOTOR_ANGULAR);
    raydium_ode_motor_attach(mot_tel_us,pivot_tel_us,0);
    raydium_ode_motor_power_max(mot_tel_us,1e-2); // Allow motor to drift
#endif
#ifdef STR
    mot_tel_us=raydium_ode_motor_create(nom,objet,RAYDIUM_ODE_MOTOR_ENGINE);
    raydium_ode_motor_attach(mot_tel_us,pivot_tel_us,0);
    raydium_ode_motor_power_max(mot_tel_us,1e-4); // Allow motor to drift
#endif

#ifdef STR
    raydium_ode_element_ray_attach(tel_us, 100, 1, 0, 1*(-M_PI)/128.0);
#endif

#ifdef JPO
    raydium_ode_element_ray_attach(tel_us, 100, 1, 0, 0);
#endif

    dReal posv[3]={0,0,0.5};
    raydium_ode_object_move(objet,posv);
    raydium_ode_element_material_name("ground",1,0);
//    if ((camera_mode!=camera_global) && (comera_mode!=camera_libre))
//      camera_mode=camera_suivi;
//      camera_mode=camera_suivi;
#ifdef JPO
    if (n_suivi==-1)
#endif
        n_suivi=n;
    simul_init(n);
    vehicule_etat[n]=vehicule_cours;
    if (raydium_network_uid>=0)
        num=(raydium_network_uid+1)*1000+n;
    else
        num=n;
    if (n == REMOTE_MAX_CLIENT)
        sprintf(nom,"Test%4.4d",num);
    else
        sprintf(nom,"Auto%4.4d",num);
    strncpy(vehicule_name[n],nom,8);
    strcpy(raydium_network_name_local,nom);
    vehicule_name_ind[n]=0;
}

void simul_destroy(float f,int n){
char nom[RAYDIUM_MAX_NAME_LEN];
char nom_joueur[RAYDIUM_MAX_NAME_LEN];
char piste[RAYDIUM_MAX_NAME_LEN];



int rev;
float t=0;

#ifndef STR
    if ((vehicule_lap_time_best[n]!=-1) || (vehicule_checkpoint_time[n]>0)){
        if (quiet_off){
            raydium_log("Post Scores");
            rev=atoi(&svn_rev[5]);
            strcpy(nom_joueur,vehicule_name[n]);
            strcpy(piste,pistes[npiste]);

            raydium_register_variable(nom_joueur,RAYDIUM_REGISTER_STR,"nom_joueur");
            raydium_register_variable(piste,RAYDIUM_REGISTER_STR,"nom_circuit");
            raydium_register_variable(&rev,RAYDIUM_REGISTER_INT,"revision");

            raydium_register_variable(&vehicule_lap_time_best[n],RAYDIUM_REGISTER_FLOAT,"lap_time");
            raydium_register_variable(&course_arrivee[n].lap_num,RAYDIUM_REGISTER_INT,"lap_num");

            raydium_register_variable(&vehicule_checkpoint_num[n],RAYDIUM_REGISTER_INT,"checkpoint_num");
            raydium_register_variable(&piste_checkpoint_last,RAYDIUM_REGISTER_INT,"checkpoint_total");
            raydium_register_variable(&vehicule_checkpoint_time[n],RAYDIUM_REGISTER_FLOAT,"checkpoint_time");

            raydium_register_variable(&t,RAYDIUM_REGISTER_FLOAT,"resultat");

            //raydium_php_exec("post.php");

            //raydium_log("Resultat:%f",t);

            raydium_register_variable_unregister_last();
            raydium_register_variable_unregister_last();
            raydium_register_variable_unregister_last();

            raydium_register_variable_unregister_last();
            raydium_register_variable_unregister_last();

            raydium_register_variable_unregister_last();
            raydium_register_variable_unregister_last();
            raydium_register_variable_unregister_last();

            raydium_register_variable_unregister_last();
        }

    }
#endif

    remote_client_name("#voiture",n,nom);
    raydium_ode_object_delete_name(nom);

    vehicule_etat[n]=vehicule_invalide;
}

void camera(int vehicule) {
    if (camera_mode==camera_suivi){
        if (n_suivi!=-1){
            char nom[RAYDIUM_MAX_NAME_LEN];
            dReal *vel,*pos,cam[3],mpos[3];
            int corps;

            remote_client_name("#corps",n_suivi,nom);
            corps =  raydium_ode_element_find(nom);
            if (corps!=-1){
                pos=raydium_ode_element_pos_get(corps);
                vel=raydium_ode_element_linearvelocity_get(corps);

                // get position of camera in world coords
                raydium_ode_element_RelPointPos(corps,-2,0,0,cam);

                // correct z pos (always at top of the car, for example)
                cam[2]=pos[2]+0.6;

                mpos[0]=pos[0]+vel[0]/16;
                mpos[1]=pos[1]+vel[1]/16;
                mpos[2]=pos[2]+vel[2]/16;

                // standard smooth lookat camera
                raydium_camera_smooth(cam[0],cam[1],cam[2]+1,mpos[1],-mpos[2],mpos[0],80,0,raydium_frame_time*10);
            }else {
                camera_mode=camera_fixe;
                n_suivi=-1;
            }
        }else
            raydium_camera_freemove(RAYDIUM_CAMERA_FREEMOVE_FIXED);
    }

    if (camera_mode==camera_libre)
        raydium_camera_freemove(RAYDIUM_CAMERA_FREEMOVE_NORMAL);
    if (camera_mode==camera_fixe)
        raydium_camera_freemove(RAYDIUM_CAMERA_FREEMOVE_FIXED);
    if (camera_mode==camera_global)
#ifdef STR
        raydium_camera_look_at(-18.77,-18.18,33.6923,+00,+100,100);
#else
		raydium_camera_look_at(220,285,233,+00,+100,100);
#endif
}

void vehicule_commande() {
char nom[RAYDIUM_MAX_NAME_LEN];

float mpow;
float vit;

    if (camera_mode==camera_libre)
        return;
    raydium_joy_key_emul();

#ifndef STR
    switch((int)raydium_joy_y){
        case +1: mpow=5;vit=-90; break;
        case  0: mpow=0;vit=0; break;
        case -1: mpow=10;vit=20; break;
    }
#else
    switch((int)raydium_joy_y){
        case +1: mpow=2;vit=-30; break;
        case  0: mpow=0;vit=0; break;
        case -1: mpow=4;vit=10; break;
    }
#endif

    remote_client_name("#moteur",REMOTE_MAX_CLIENT,nom);
    raydium_ode_motor_speed_name(nom,vit);

    raydium_ode_motor_power_max_name(nom,mpow);
    remote_client_name("#direction",REMOTE_MAX_CLIENT,nom);

    raydium_ode_motor_angle_name(nom,raydium_joy_x/1.0f);
}

void course_arrivee_init(int i){
    course_arrivee[i].id=-1;
    course_arrivee[i].lap_num=0;
    course_arrivee[i].nom[0]=0;
    course_arrivee[i].temps=-1;
}

void vehicule_arrive(int i,float lap,char * nom){
int j,k;
char buff[RAYDIUM_NETWORK_PACKET_SIZE];
int val;
int temp_lap_num=1;

    raydium_log("Arrive de %d en %f",i,lap);


    if (i<1000){//Local car
        val=(raydium_network_uid+1)*1000+i+1;
        vehicule_etat[i]=vehicule_arrivee;
        if (net_mode== connected || net_mode == connected_master){
            raydium_log("Network broadcast Finish (%d).",val);
            memcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET,(char *) &val,sizeof(int));
            memcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET+4,(char *) &lap,sizeof(float));
            memcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET+12,(char *) nom,9);
            raydium_network_write(NULL,raydium_network_uid,CAR_FINISH,buff);
        }
    }else
        val=i;

    if(course_mode==course)
        if(course_n_arrivees == (COURSE_MAX_ARRIVEE-1))
            return;
    if(course_mode==essais)
        course_n_arrivees=0;
    // Not first Lap
    for(j=0;j<course_n_arrivees;j++)
        if (course_arrivee[j].id==val && !strcmp(course_arrivee[j].nom,nom)){
            course_arrivee[j].lap_num++;
            temp_lap_num=course_arrivee[j].lap_num;
            //Keep best time
            if (course_arrivee[j].temps<lap)
                lap=course_arrivee[j].temps;
            //Remove from list probably not at the same place
            for(k=j+1;k<course_n_arrivees;k++)
                memcpy(&course_arrivee[k-1],&course_arrivee[k],sizeof(course_arrivee_));

            course_n_arrivees--;
            course_arrivee_init(course_n_arrivees);

            break;
        }

   //Add vehicule to the finish list
    for (j=0;j<course_n_arrivees;j++)
        if (lap<=course_arrivee[j].temps)
            break;

    for (k=course_n_arrivees-1;k>=j;k--)
        memcpy(&course_arrivee[k+1],&course_arrivee[k],sizeof(course_arrivee_));

    course_arrivee[j].temps=lap;
    course_arrivee[j].id=val;
    strncpy(course_arrivee[j].nom,nom,9);
    course_arrivee[j].lap_num=temp_lap_num;

    course_n_arrivees++;

}

void vehicule_son(int vehicule) {
}

void change_piste(int a){ // a= npiste if a==-1 next piste.
int i;

    if (npiste==a)
        return;
    if (a==-1)
        npiste++;
    else
        npiste=a;



    if (strlen(pistes[npiste])==0)
        npiste=0;

    course_n_arrivees=0;

    raydium_ode_ground_set_name(pistes[npiste]);
    raydium_ode_element_slip_name("ground",RAYDIUM_ODE_SLIP_SIMUL);

    for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++){
        if(raydium_ode_element[i].name[1]=='!')
            raydium_ode_element_delete(i,1);
    }

#ifndef t_tSTR
    {
        char pos_file[RAYDIUM_MAX_NAME_LEN];
        FILE * f_pos;
        strcpy(pos_file,pistes[npiste]);
        strcat(pos_file,".pos");

        f_pos=raydium_file_fopen(pos_file,"r");
        if (!f_pos)
            return;

        piste_checkpoint_last=0;
        while (!feof(f_pos)){
            char n1[1024];
            char n2[1024];
            float x,y,z,rx,ry,rz;


            fscanf(f_pos,"%s %s %f %f %f %f %f %f\n",n1,n2,&x,&y,&z,&rx,&ry,&rz);
            //raydium_log ("%s %s %f %f %f %f %f %f",n1,n2,x,y,z,rx,ry,rz);
            if (!strncmp("capt",n1,4)){
                char n[RAYDIUM_MAX_NAME_LEN];
                char pref[16];
                char *pn;
                int nc;

                pn=strchr(n1,'_');

                pref[0]=*(pn+1);
                pref[1]='!';
                pref[2]=0;

                pn=strchr(n1,'.');
                pn++;
                nc=atoi(pn);
                strcat(pref,pn);
                pref[0]=toupper(pref[0]);
                strcat(n2,".tri");
                raydium_ode_object_box_add(pref,0,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,(TYPE_CAPTEUR<<16)+nc,n2);
                raydium_ode_element_move_name_3f(pref,x,y,z);

                raydium_ode_element_rot_set_name(pref,-rx,-ry,-rz);
                raydium_log ("Addign %s",pref);
                if (pref[0]=='V')
                    piste_checkpoint_last=max(piste_checkpoint_last,atoi(pn));
            }
        }
        fclose(f_pos);

    }
#else
    piste_checkpoint_last=4;
#endif

    raydium_log ("Need to go trought %d checkpoints\n",piste_checkpoint_last);
    for (i=0;i<REMOTE_MAX_CLIENT+1;i++){
        if(vehicule_etat[i]!=vehicule_invalide){
            simul_teleport(1,i);
            simul_init(i);
            vehicule_event_local[i]|=PISTE_CHANGE;
        }

    }


}

void change_mode(int a){//a = nouveau mode if a==-1 next mode
int i;

        if (course_mode==a)
            return;

        if (a==-1)
            course_mode++;
        else
            course_mode=a;

        course_n_arrivees=0;
        if (course_mode>essais)
            course_mode=attente;
        if (course_mode==course){
            timer=0;
        }
        for (i=0;i<(REMOTE_MAX_CLIENT+1);i++){
            if (vehicule_etat[i]!=vehicule_invalide){
                //simul_teleport(1,i);
                //simul_init(i);
                vehicule_event_local[i]|=MODE_CHANGE;
            }
        }
}

void clavier() {

    if(raydium_key_last==1027)
        exit(0);
#ifdef EXT
    if(raydium_key_last==1097) raydium_ode_time_change(0);
    if(raydium_key_last==1122) raydium_ode_time_change(10);
    if(raydium_key_last==1101) raydium_ode_time_change(100);
#endif
    if (raydium_key_last==1000+'p'){
        change_piste(-1);
        if (net_mode==connected_master){
            char buff[RAYDIUM_NETWORK_PACKET_SIZE];
            raydium_log("Network broadcast change track.");
            memcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET,(char *) &npiste,sizeof(int));
            raydium_network_write(NULL,raydium_network_uid,CHANGE_TRACK,buff);
        }
    }

    if ((raydium_key_last>=1000+'0') && (raydium_key_last<=1000+'9')){
        if (vehicule_test==vehicule_on)
            simul_teleport(raydium_key_last-1000-'0',REMOTE_MAX_CLIENT);
    }

    if ((raydium_key_last==1000+'s') || (raydium_key_last==1000+'S'))
        camera_mode=camera_suivi;
    if ((raydium_key_last==1000+'l') || (raydium_key_last==1000+'L'))
        if (camera_mode!=camera_libre)
            camera_mode=camera_libre;
        else
            camera_mode=camera_fixe;
    if ((raydium_key_last==1000+'g') || (raydium_key_last==1000+'G'))
        camera_mode=camera_global;
#ifdef EXT
    if ((raydium_key_last==1000+'d') || (raydium_key_last==1000+'D')){
        affichage_mode++;
        if (affichage_mode > mesh_ode)
            affichage_mode=mesh;
    }
#endif
    if ((raydium_key_last==1000+'i') || (raydium_key_last==1000+'I')){
        if (affichage_info==info_off)
            affichage_info=info_on;
        else
            affichage_info=info_off;
    }
    if ((raydium_key_last==1000+'b') || (raydium_key_last==1000+'B'))
        if (net_mode==connected) net_mode=connected_master;
    if (raydium_key_last==1000+'n'){
        if (net_mode==disconnected){
            raydium_network_client_discover("STR",1);
            net_mode=searching;
        }
        else{
            raydium_network_client_disconnect();
            net_mode=disconnected;
        }
    }
    if (raydium_key_last==1000+' '){
        change_mode(-1);
        if (net_mode==connected_master){
            char buff[RAYDIUM_NETWORK_PACKET_SIZE];
            raydium_log("Network broadcast change Mode.");
            memcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET,(char *) &course_mode,sizeof(int));
            raydium_network_write(NULL,raydium_network_uid,CHANGE_MODE,buff);
        }
    }
    if (raydium_key_last == 1000 + 'f'){
        if (raydium_render_max_fps>0)
            raydium_render_fps_limit(0);
        else
            raydium_render_fps_limit(60);

    }
    if (raydium_key_last == 1000 + 'w')
        if(remote_dump_toggle())
            raydium_log("Communication Dump Log enabled.");
        else
            raydium_log("Communication Dump Log disabled.");

#ifdef EXT
    if (raydium_key_last==1000+'t' /*|| raydium_key_last==1000+'T'*/){
        if (vehicule_test==vehicule_on){
            simul_destroy(0,REMOTE_MAX_CLIENT);
            vehicule_test=vehicule_off;
        }else{
//Initial collision binarie explode test
//            static int i=0;
//            for (i=0;i<min(32,REMOTE_MAX_CLIENT);i++)
//                simul_create(0,i++);
//End test
            simul_create(0,REMOTE_MAX_CLIENT);
            vehicule_test=vehicule_on;
            n_suivi=REMOTE_MAX_CLIENT;
            camera_mode=camera_suivi;
        }
    }
    if (vehicule_test==vehicule_on)
        vehicule_commande();
#endif
    if (raydium_key_last==1009){
        int i,j;
        camera_mode=camera_suivi;
        i=n_suivi+1;
        for (j=0;j<REMOTE_MAX_CLIENT+1;j++){
            if (vehicule_etat[i]!=vehicule_invalide){
                break;
            }
            i++;
            if (i>REMOTE_MAX_CLIENT+1)
                i=0;
        }
        n_suivi=i;
        if (vehicule_etat[n_suivi]==vehicule_invalide){
            //camera_mode=camera_fixe;
            n_suivi=-1;
        }
    }
#ifdef EXT
    if(raydium_key_last==1000+'x'){
        char buff[RAYDIUM_NETWORK_PACKET_SIZE];

        strcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET,"Test1");
        raydium_log("Send...");
        raydium_network_write(NULL,raydium_network_uid,RAYDIUM_NETWORK_PACKET_BASE+1,buff);
        raydium_log("...done");
    }
#endif
    if (raydium_key_last==1046){//Suppr
        //TODO suppress vehicule
        if (n_suivi!=-1){
            if (n_suivi<1000)
                if (n_suivi<REMOTE_MAX_CLIENT)
                    periph_id_delete(n_suivi);
                else{
                    simul_destroy(0,n_suivi);
                    vehicule_test=vehicule_off;
                }
        }
    }
    if (raydium_key_last==1000+'c'){
        if (couleur_osd==couleur_osd_blanc)
            couleur_osd=couleur_osd_noir;
        else
            couleur_osd=couleur_osd_blanc;
    }
    if (raydium_key_last==1000+'q'){
            if (quiet==quiet_on)
                quiet=quiet_off;
            else
                quiet=quiet_on;
            raydium_log("Quiet : %s",(quiet==quiet_on)?"On":"Off");
    }
}

void network(void){
    if (net_mode==searching){
        if (raydium_network_discover_numservers()>0){
            char str[RAYDIUM_MAX_NAME_LEN];
            char name[RAYDIUM_MAX_NAME_LEN];
            char ip[RAYDIUM_MAX_NAME_LEN];
            char info[RAYDIUM_MAX_NAME_LEN];
            int player_count;
            int player_max;

            if (raydium_network_discover_getserver(0,name,ip,info,&player_count,&player_max)>0){
                if (raydium_network_client_connect_to(ip))
                    net_mode=connected;
                else
                    net_mode=disconnected;
            }
            else
                net_mode=disconnected;
        }
    }

    if (net_mode==connected || net_mode==connected_master)
        raydium_ode_network_element_send_iterative(RAYDIUM_ODE_NETWORK_OPTIMAL);
}

void display(void) {
int i;

    clavier();

    if (vehicule_etat[n_suivi]==vehicule_invalide)
        n_suivi=-1;

    raydium_clear_frame();
    camera(n_suivi);
    raydium_ode_draw_all(RAYDIUM_ODE_DRAW_RAY);
    raydium_camera_replace();
    if (affichage_mode==mesh || affichage_mode==mesh_ode)
        raydium_ode_draw_all(RAYDIUM_ODE_DRAW_NORMAL);
    if (affichage_mode==ode || affichage_mode==mesh_ode)
        raydium_ode_draw_all(RAYDIUM_ODE_DRAW_DEBUG);
#ifndef STR
    {
        char col[][3]={"^A","^9","^C","^0",""};
        raydium_osd_printf(2,93,16,0.5,"font2.tga","Piste:%s%s%s change with 'p'",col[npiste],pistes[npiste],(couleur_osd==couleur_osd_noir)?"^0":"^F" );
    }
#endif
    if (couleur_osd==couleur_osd_noir)
        raydium_osd_printf(2,98,16,0.5,"font2.tga","^0");
    else
        raydium_osd_printf(2,98,16,0.5,"font2.tga","^F");
#ifdef FDS
    raydium_osd_printf(2,98,16,0.5,"font2.tga","- %3i FPS - Simulateur FDS Polytech GE 2015.(%d) %s",raydium_render_fps,raydium_network_uid,(net_mode==connected_master)?":o)":"---");
#endif
#ifdef JPO
    raydium_osd_printf(2,98,16,0.5,"font2.tga","- %3i FPS - Simulateur JPO Polytech GE 2015.(%d) %s",raydium_render_fps,raydium_network_uid,(net_mode==connected_master)?":o)":"---");
#endif
#ifdef STR
    #ifndef ISIMA
        raydium_osd_printf(2,98,16,0.5,"font2.tga","- %3i FPS - Simulateur STR Polytech GE 2015.(%d) %s",raydium_render_fps,raydium_network_uid,(net_mode==connected_master)?":o)":"---");
    #else
        raydium_osd_printf(2,98,16,0.5,"font2.tga","- %3i FPS - Simulateur Temps Reel ISIMA.(%d) %s",raydium_render_fps,raydium_network_uid,(net_mode==connected_master)?":o)":"---");
    #endif
#endif




    if (course_mode==essais) raydium_osd_printf(2,96,16,0.5,"font2.tga","Essais en cours");
    if (course_mode==attente) raydium_osd_printf(30,30,32,0.5,"font2.tga","Attente Depart");
    if (course_mode==course) raydium_osd_printf(2,96,16,0.5,"font2.tga","Course");



    raydium_osd_printf(80,98,16,0.5,"font2.tga","Chrono: %3.2f", timer);

    if (n_suivi!=-1){
        char chk[17];
        int i;
        int m=1;
        if (n_suivi!=REMOTE_MAX_CLIENT){
            raydium_osd_printf(80,95,16,0.5,"font2.tga","In :%4.4d",id_client[n_suivi].stat_msg_in);
            raydium_osd_printf(80,92,16,0.5,"font2.tga","Out:%4.4d",id_client[n_suivi].stat_msg_out);
            raydium_osd_printf(80,89,16,0.5,"font2.tga","Err:%4.4d",id_client[n_suivi].stat_msg_err);
            raydium_osd_printf(80,86,16,0.5,"font2.tga","Tout:%3.2f",id_client[n_suivi].timeout/2000.0f);
        }

        strcpy(chk,"----------------");
        for(i=0;i<16;i++){
            if (vehicule_event_local[n_suivi] & m)
                chk[15-i]='*';
            m=m<<1;
        }
        chk[17]=0;
        raydium_osd_printf(10,10,16,0.5,"font2.tga","%d %3.2f (%s)%04.4X Lap:%3.2f Best:%3.2f", n_suivi,timer-vehicule_ref_time[n_suivi],chk,vehicule_event_local[n_suivi],vehicule_lap_time[n_suivi],vehicule_lap_time_best[n_suivi]);

        if ((affichage_info==info_flag) || (affichage_info==info_on))
            if (n_suivi>=0){
                raydium_osd_printf(10,80,16,0.5,"font2.tga","vehicule_event_local:%4.4X",vehicule_event_local[n_suivi]);
                raydium_osd_printf(10,77,16,0.5,"font2.tga","vehicule_capteur_last:%4.4X %c %2.2d",vehicule_capteur_last[n_suivi],vehicule_capteur_last[n_suivi]>>8,vehicule_capteur_last[n_suivi]&0xff);
                raydium_osd_printf(10,74,16,0.5,"font2.tga","vehicule_capteur_trig:%d",vehicule_capteur_trig[n_suivi]);
                raydium_osd_printf(10,71,16,0.5,"font2.tga","vehicule_capteur_trig_last:%d",vehicule_capteur_trig_last[n_suivi]);
                raydium_osd_printf(10,68,16,0.5,"font2.tga","vehicule_capteur_trig_time:%3.2f",vehicule_capteur_trig_time[n_suivi]);
                raydium_osd_printf(10,65,16,0.5,"font2.tga","vehicule_checkpoint num:%d",vehicule_checkpoint_num[n_suivi]);
                raydium_osd_printf(10,62,16,0.5,"font2.tga","vehicule_checkpoint time:%3.2f",vehicule_checkpoint_time[n_suivi]);
                raydium_osd_printf(10,59,16,0.5,"font2.tga","vehciule_ref time:%3.2f",vehicule_ref_time[n_suivi]);
                raydium_osd_printf(10,56,16,0.5,"font2.tga","vehciule_lap_time:%3.2f",vehicule_lap_time[n_suivi]);
                raydium_osd_printf(10,53,16,0.5,"font2.tga","vehciule_lap_time_best:%3.2f",vehicule_lap_time_best[n_suivi]);

                if (raydium_key_last=='T'+1000){
                    simul_event(1,n_suivi);
                }
            }
    }
    for (i=0;i<REMOTE_MAX_CLIENT+1;i++){
        if (vehicule_etat[i]!=vehicule_invalide)
        {
            dReal *pos;
            char nom[RAYDIUM_MAX_NAME_LEN];

            remote_client_name("#corps",i,nom);
            pos = raydium_ode_element_pos_get_name(nom);
            if (pos[2]<-10) // Hors Piste
                vehicule_event_local[i]|=HORS_PISTE;
            raydium_osd_printf_3D(pos[0],pos[1],pos[2]+0.2,18,0.5,"font2.tga","%s",vehicule_name[i]);

            if (course_mode==attente){
                raydium_osd_printf(80,90-i*5,20,0.5,"font2.tga","%d Pret",i);
                if (vehicule_event_local[i] & (EXPLODE)){ // Vehicule didn't respect start->explode.
                    raydium_ode_element_addforce_name_3f(nom,raydium_random_f(7000,10000)*raydium_random_neg_pos_1(),raydium_random_f(7000,10000)*raydium_random_neg_pos_1(),raydium_random_f(20000,50000));
                    raydium_ode_explosion_blow_rand_3f(5,200,0.12,pos[0]+0.01,pos[1]+0.01,pos[2]); // bonne explosion
                    raydium_ode_element_particle_point_name(nom,"explosion.prt");
                    raydium_ode_element_particle_point_name(nom,"explosmoke.prt");
                    raydium_ode_element_particle_point_name(nom,"exploparts.prt");
                    vehicule_event_local[i]&=~(EXPLODE | FINAL | C_CYAN | C_BLEUE | C_ROUGE | C_JAUNE | C_VERT);
                }
            }
        }
    }
    for (i=0;i<course_n_arrivees;i++){
        int size=9,ec=2;
        static int dy=0;

        if (i<12) {size=26;ec=4;}
        if (i<9) {size=28;ec=4;}
        if (i<6) {size=30;ec=4;}
        if (i<3) {size=32;ec=5;}
        if(i==0) dy=0;
        dy+=ec;

        if (quiet_off)
#ifdef JPO
            if (course_mode!=essais)
#endif // JPO
                raydium_osd_printf(30,90-dy,size,0.5,"font2.tga","**%d** %3.2f * %8.8s (%d)",i+1,course_arrivee[i].temps,course_arrivee[i].nom,course_arrivee[i].lap_num);
    }
    if (camera_mode==camera_libre){
        raydium_osd_printf(10,70,20,0.5,"font2.tga","%f\n%f\n%f\n%f\n%f\n%f\n",raydium_camera_data[0],
                           raydium_camera_data[1],
                           raydium_camera_data[2],
                           raydium_camera_data[3],
                           raydium_camera_data[4],
                           raydium_camera_data[5]);
    }
    //raydium_log("%f %f %f",raydium_camera_x,raydium_camera_y,raydium_camera_z);
    raydium_osd_logo("logo.tga");
    raydium_rendering_finish();

    network();
}

char draw_element_after(int elem){
int type;
dReal *pos;

    type=raydium_ode_element_tag_get(elem);
    if(((type>>16)==TYPE_CAR_BODY) && raydium_ode_network_element_isdistant(elem))
    {
        int player;
        pos=raydium_ode_element_pos_get(elem);
        player=raydium_ode_network_element_distantowner(elem);
        raydium_osd_printf_3D(pos[0],pos[1],pos[2]+0.2,12,0.5,"font2.tga","%s",raydium_network_name[player]);
        raydium_ode_element[elem].mesh=raydium_object_find_load("jeep_roues.tri");
    }
#ifdef STR
    if (etat_feux==vert){
        raydium_ode_element[raydium_ode_element_find("V!001")].mesh=raydium_object_find_load("capt_vlv.tri");
    }
    if (etat_feux==orange){
        raydium_ode_element[raydium_ode_element_find("V!001")].mesh=raydium_object_find_load("capt_vlo.tri");
    }
    if (etat_feux==rouge){
        raydium_ode_element[raydium_ode_element_find("V!001")].mesh=raydium_object_find_load("capt_vlr.tri");
    }
#endif
    return 1;
}

void gestion_feux(double timer){
static double elaps=0;
static double delais=0;
double dt;
static _etat_feux etat_suivant_feux;

    dt=elaps-timer;

    //raydium_log("%+03.2f / %+03.2f / %+03.2f",elaps,delais,dt);

    if (dt<0){
        etat_feux=etat_suivant_feux;
        elaps=timer+delais;
    }

    switch(course_mode){
        case essais:
            if (etat_feux==vert){
                etat_suivant_feux=orange;delais=1;}
            if (etat_feux==orange){
                etat_suivant_feux=rouge;delais=1;}
            if (etat_feux==rouge){
                etat_suivant_feux=vert;delais=1;}
            break;
        case attente:
            if (etat_feux==vert){
                etat_suivant_feux=orange;delais=1;}
            if (etat_feux==orange){
                etat_suivant_feux=rouge;delais=3;}
            if (etat_feux==rouge){
                etat_suivant_feux=rouge;delais=0;}
            break;
        case course:
            etat_suivant_feux=vert;delais=0,elaps=0;
            break;
    }

}

void gestion_course(float dt){
int i;
    for (i=0;i<REMOTE_MAX_CLIENT+1;i++){
        if (vehicule_etat[i]==vehicule_invalide) continue;

        //TODO A valider
        //Hors piste -> destruction
        if (vehicule_event_local[i] & (HORS_PISTE)){
            if (i<REMOTE_MAX_CLIENT)
                periph_id_delete(i);
            else{
                simul_destroy(0,REMOTE_MAX_CLIENT);
                vehicule_test=vehicule_off;
            }
        }

        //Capteur touché
        if (vehicule_capteur_trig[i]>=0){
            //Capteur collide reported
            if(vehicule_capteur_trig[i]!=vehicule_capteur_trig_last[i]){
                //Capteur collide not already updated
                int n;
                int e;
                int cc,cn;

                e=vehicule_capteur_trig_last[i]=vehicule_capteur_trig[i];
                n=raydium_ode_element_tag_get(e);

                cn=n & 0x0ffff;
                cc=raydium_ode_element[e].name[0];
                vehicule_capteur_last[i]=cc<<8 | cn;

                //Capteur Vert => Checkpoint
                //TODO define capteur color in capteur type
                if(cc=='V') {

                    if (vehicule_checkpoint_num[i]+1==cn){
                        vehicule_checkpoint_num[i]=cn;
                        if (cn==1){
                            vehicule_ref_time[i]=vehicule_capteur_trig_time[i];
                            vehicule_event_local[i]&=~(C_VERT | C_JAUNE | C_ROUGE | C_BLEUE | C_CYAN | FINAL);
                        }
                        vehicule_checkpoint_time[i]=vehicule_capteur_trig_time[i]-vehicule_ref_time[i];
                        if (cn==piste_checkpoint_last)
                            vehicule_event_local[i]|=FINAL;
                    }
                }
                if(cc=='V') vehicule_event_local[i]|=C_VERT;
                if(cc=='J') vehicule_event_local[i]|=C_JAUNE;
                if(cc=='R') vehicule_event_local[i]|=C_ROUGE;
                if(cc=='B') vehicule_event_local[i]|=C_BLEUE;
                if(cc=='C') vehicule_event_local[i]|=C_CYAN;
            }
            vehicule_capteur_trig[i]=-1;;
        }

        if (vehicule_checkpoint_num[i]==piste_checkpoint_last){
            vehicule_event_local[i]|=ARRIVEE;
            vehicule_checkpoint_num[i]=0;
            if (! (vehicule_event_local[i] & (TELEPORT))){ // Teleportation utilise ?
            //if (1){ // Tests
                vehicule_lap_time[i]=vehicule_capteur_trig_time[i]-vehicule_ref_time[i];
                if(vehicule_lap_time_best[i]<=0)
                    vehicule_lap_time_best[i]=vehicule_lap_time[i];
                vehicule_lap_time_best[i]=min(vehicule_lap_time[i],vehicule_lap_time_best[i]);
                vehicule_arrive(i,vehicule_lap_time_best[i],vehicule_name[i]);
            }
        }

        if (course_mode==attente){
            if (vehicule_event_local[i] & (FINAL | C_CYAN | C_BLEUE | C_ROUGE | C_JAUNE | C_VERT)) // Touching a waipoint
                vehicule_event_local[i]|=EXPLODE; // Asking an explosion
            continue;
        }
    }
}

void step() {
int i;

    timer=timer+(1.0f/raydium_ode_physics_freq);
    gestion_course(timer);
    gestion_feux(timer);
}

void create_env(){

GLfloat light_color[] = {1.0, 1.0, 1.0, 1.0};
GLfloat sun[]={1.0,1.0,1.0,1.0};
GLfloat amb[]={1.0,1.0,1.0,1.0};

    memcpy(raydium_light_color[0],sun,raydium_internal_size_vector_float_4);
    raydium_light_on(0);
    raydium_light_position[0][0]=0;
    raydium_light_position[0][1]=0;
    raydium_light_position[0][2]=20000;
    raydium_light_position[0][3]=1.0;
    raydium_light_update_position(0);
    raydium_light_intensity[0]=1e40;
    raydium_light_update_all(0);

    memcpy(raydium_light_color[1],amb,raydium_internal_size_vector_float_4);
    raydium_light_on(1);
    raydium_light_intensity[1]=100000;
    raydium_light_update_all(1);

    raydium_background_color_change(light_color[0],light_color[1],light_color[2],light_color[3]);

    raydium_window_view_update();
}

void create_capteurs(){

#ifdef JPO
    return;
#endif
    raydium_ode_object_box_add("V!V",0,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,(TYPE_CAPTEUR<<16)+1,"capt_v.tri");
#ifndef FDS
    raydium_ode_element_move_name_3f("V!V",20,0,0);
#else
    raydium_ode_element_move_name_3f("V!V",20,0,0);
#endif


    raydium_ode_object_box_add("J!J",0,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,(TYPE_CAPTEUR<<16)+2,"capt_j.tri");
#ifndef FDS
    raydium_ode_element_move_name_3f("J!J",95,4,0);
#else
    raydium_ode_element_move_name_3f("J!J",-32.84,-17.76,0);
#endif

    raydium_ode_object_box_add("R!R",0,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,(TYPE_CAPTEUR<<16)+3,"capt_r.tri");
#ifndef FDS
    raydium_ode_element_move_name_3f("R!R",95.5,116,0);
#else
    raydium_ode_element_move_name_3f("R!R",-59,90.75,0);
#endif

    raydium_ode_object_box_add("B!B",0,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,(TYPE_CAPTEUR<<16)+4,"capt_bf.tri");
#ifndef FDS
    raydium_ode_element_move_name_3f("B!B",-16,116,0);
#else
    raydium_ode_element_move_name_3f("B!B",16,96.8,0);
#endif

    raydium_ode_object_box_add("C!C",0,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,(TYPE_CAPTEUR<<16)+5,"capt_bc.tri");
#ifndef FDS
    raydium_ode_element_move_name_3f("C!C",-16,4,0);
#else
    raydium_ode_element_move_name_3f("C!C",15.12,22,0);
#endif
}

void init(void){
int i;
    for (i=0;i<REMOTE_MAX_CLIENT+1;i++){
        simul_init(i);
        vehicule_etat[i]=vehicule_invalide;
    }
    n_suivi=-1;
    course_n_arrivees=0;
}


Periph periphs[] = {{'V',"#moteur",'S',-1.0,0,0},  //Vitesse
                    {'D',"#direction",'A',M_PI/1800,0,0}, // Direction
#ifdef FDS
                    {'T',"#mot_tel_us",'A',-M_PI/1800,0,0},
#endif
#ifdef JPO
                    {'T',"#mot_tel_us",'A',-M_PI/1800,0,0}, // Azimuth tourelle
#endif
#ifdef STR
                    {'T',"#mot_tel_us",'S',-M_PI/1800,0,0},
#endif
                    {'R',"#mot_tel_us",'A',-M_PI/1800,0,0},
                    {'U',"#tel_us",'R',0.01,0,0},
                    {'X',"#corps",'X',0.01,0,0},
                    {'Y',"#corps",'Y',0.01,0,0},
                    {'Z',"#corps",'Z',0.01,0,0},
                    {'N',"#voiture",'F',1,0,&simul_id}, // Numéro Voiture
                    {'E',"#voiture",'F',1,0,&simul_flags}, // Lecture des flags d'évènements
                    {'H',"#voiture",'F',0.01,0,&simul_time}, // Temps de course
                    {'S',"#voiture",'F',0.01,0,&rlap_time}, // Temps précedent
                    {'I',"#voiture",'F',1,0,&simul_name}, // Nom du véhicule
                    {'M',"#voiture",'F',1,0,&simul_mode}, // Retourne le mode de course / Numéro de Piste
                    {'C',"#voiture",'F',1,0,&simul_capt}, // Retourne Le dernier capteur touché et son numéro
                    {'K',"#voiture",'F',1,0,&simul_teleport},
                    {'+',"#voiture",'F',1,0,&simul_score}, // Temps obtenu au dernier tour
                    {'!',"#voiture",'F',1,0,&simul_event}, // Event polling for libremote
                    {0  ,"#voiture",'F',1,0,&simul_create},
                    {255,"#voiture",'F',1,0,&simul_destroy},
                    {0  ,"",0,0.0,0.0,0}};

void netcall_receive(int type, char *buff){
int val;

    if (type==CHANGE_TRACK){
        raydium_log("Network changing track.\n");
        memcpy(&val,buff+RAYDIUM_NETWORK_PACKET_OFFSET,sizeof(int));
        change_piste(val);
    }
    if (type==CHANGE_MODE){
        raydium_log("Network changing Mode.\n");
        memcpy(&val,buff+RAYDIUM_NETWORK_PACKET_OFFSET,sizeof(int));
        change_mode(val);
    }
    if (type==CAR_FINISH){
        float lap;
        char nom[9];
        raydium_log("Car Finish Event.\n");
        memcpy(&val,buff+RAYDIUM_NETWORK_PACKET_OFFSET,sizeof(int));
        memcpy(&lap,buff+RAYDIUM_NETWORK_PACKET_OFFSET+4,sizeof(float));
        memcpy(nom,buff+RAYDIUM_NETWORK_PACKET_OFFSET+12,9);
        vehicule_arrive(val,lap,nom);
    }
}

int main(int argc, char **argv){
int i;
char server[RAYDIUM_MAX_NAME_LEN];
char tmp[RAYDIUM_MAX_NAME_LEN];
int timeout;
char model[RAYDIUM_MAX_NAME_LEN];

    raydium_init_args(argc,argv);
#ifdef FDS
    #ifdef CETSIS
        raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Cetsis 2008");
    #else
        raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Fête de la Science 2009");
    #endif
#endif
#ifdef JPO
    raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Journées Portes Ouvertes 2015");
#endif
#ifdef STR
    #ifndef ISIMA
        raydium_window_create(320,240,RAYDIUM_RENDERING_WINDOW,"Simulateur Tp Info6");
    #else
        raydium_window_create(320,240,RAYDIUM_RENDERING_WINDOW,"Simulateur Tp ISIMA");
    #endif
#endif
    raydium_init_cli_option_default("timeout",tmp,"15");
    timeout=atoi(tmp);
    remote_periph_init(1,1,timeout);

    raydium_path_add("../simulateur_temps_reel/data");
    raydium_path_write("../simulateur_temps_reel/data");

#ifdef JPO
    raydium_path_add("..\\simulateur_temps_reel\\data_jpo");
    raydium_path_write("..\\simulateur_temps_reel\\data_jpo");
#endif

    raydium_path_write_local_deny(1);
    raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_ANISO);
    raydium_projection_near=0.01;
    raydium_projection_far=2500;
    raydium_projection_fov=60;
    raydium_fog_disable();
    raydium_shadow_disable();
    //raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_TRILINEAR);

    create_env();

    create_capteurs();

    i=0;
    while (periphs[i].adresse){
        raydium_log("-> Adresse:%c Nom:%8.8s Type:%c Gain:%f,Offset:%f",periphs[i].adresse,periphs[i].ray_nom,periphs[i].type,periphs[i].a,periphs[i].b);
        i++;
    }
    raydium_log("use command line switch --com comx to change serial port connection.");
    raydium_log("use command line switch --timeout xxx to change default timeout.");


    change_piste(0);
    raydium_ode_gravity_3f(0,0,-6);

    timer=0;
    init();

    //raydium_ode_set_physics_freq(1000);
    //raydium_ode_set_timestep(1/600.0f);

    raydium_ode_CollideCallback=collide;
    raydium_ode_RayCallback=ray_collide;
    raydium_ode_ObjectNearCollide=near_collide;
    raydium_ode_StepCallback=step;
    raydium_ode_AfterElementDrawCallback=draw_element_after;

    raydium_network_netcall_add(netcall_receive,CHANGE_TRACK,1);
    raydium_network_netcall_add(netcall_receive,CHANGE_MODE,1);
    raydium_network_netcall_add(netcall_receive,CAR_FINISH,1);

    if (net_mode==searching)
        raydium_network_client_discover("STR",1);

    if ( raydium_init_cli_option("server",server)){
        raydium_network_client_connect_to(server);
    }

    raydium_render_fps_limit(60);

    raydium_callback(&display);

    return(0);
}
// EOF
