Index: ostatcomp.sh
===================================================================
--- ostatcomp.sh	(revision 0)
+++ ostatcomp.sh	(revision 1)
@@ -0,0 +1,5 @@
+ulimit -c 0
+rm test
+gcc -g $1 -Wall -o test -Wl,-dynamic-linker=/lib/ld-linux.so.2 -Wl,-Bstatic -L/usr/X11R6/lib/ -lm -lXi -lstdc++ -Iode/include/ ode/lib/libode.a libglut.a -lXmu -lopenal -lvorbisfile -lvorbis -logg -Iphp/ -Iphp/main/ -Iphp/Zend -Iphp/TSRM php/libs/libphp4.a -lresolv -lcrypt -lz -Wl,-Bdynamic -lGL -lGLU -lasound -lpthread
+sync
+./test $2 $3 $4 $5 $6

Property changes on: ostatcomp.sh
___________________________________________________________________
Added: svn:executable
\ No newline at end of property
Index: tests.c
===================================================================
--- tests.c	(revision 0)
+++ tests.c	(revision 1)
@@ -0,0 +1,70 @@
+// This is test6 mini server.
+
+#define RAYDIUM_NETWORK_ONLY
+#include "raydium/index.c"
+
+char str[RAYDIUM_NETWORK_PACKET_SIZE];
+//char str_send[RAYDIUM_NETWORK_PACKET_SIZE];
+//int freq;
+
+void infos(void)
+{
+static int steps=0;
+if(steps==10)
+    {
+    raydium_network_internal_server_delays_dump();
+    steps=0;
+    }
+steps++;
+}
+
+void quit(int sig)
+{
+raydium_network_internal_dump();
+exit(0);
+}
+
+void broad(int type,char *buff)
+{
+    raydium_network_broadcast(type,buff);
+//    raydium_log("broadcasting %i",type);
+}
+
+
+void loop(void)
+{
+char type;
+int id;
+
+if(raydium_network_read_flushed(&id, &type, str)==RAYDIUM_NETWORK_DATA_OK)
+    {
+    raydium_network_broadcast(type,str);
+//    printf(".");
+    }
+raydium_timecall_callback();
+}
+
+
+int main(int argc, char **argv)
+{
+setbuf(stdout,NULL);
+signal(SIGINT,quit);
+raydium_network_init();
+raydium_network_server_create();
+
+// Ugly hack, for now...
+raydium_network_netcall_add(broad,RAYDIUM_NETWORK_PACKET_ODE_EXPLOSION,1);
+raydium_network_netcall_add(broad,RAYDIUM_NETWORK_PACKET_ODE_NEWELEM,1);
+raydium_network_netcall_add(broad,RAYDIUM_NETWORK_PACKET_ODE_REMELEM,1);
+raydium_network_netcall_add(broad,RAYDIUM_NETWORK_PACKET_ODE_NIDWHO,1);
+raydium_network_netcall_add(broad,(RAYDIUM_NETWORK_PACKET_BASE+1),1);
+raydium_network_netcall_add(broad,(RAYDIUM_NETWORK_PACKET_BASE+2),1);
+
+raydium_timecall_add(infos,1);
+
+do{
+loop();
+usleep(1); // MUST disable this with real servers
+}while(1);
+
+}
Index: test6.c
===================================================================
--- test6.c	(revision 0)
+++ test6.c	(revision 1)
@@ -0,0 +1,850 @@
+/*
+    Xfennec - CQFD Corp.
+    test & integration program for Raydium -
+    CQFD Corp.
+*/
+
+char *version="version 0.6.12";
+
+//#define ODE_MANUAL_CALLBACK
+
+#include "raydium/index.c"
+
+GLfloat sun[]={1.0,0.9,0.8,1.0};
+GLfloat blood[]={1.0,0.0,0.0,0.2};
+GLfloat amb[]={1.0,0.0,0.0,1.0};
+
+
+#define ROCKET_FIABILITY  5
+#define ROCKET_SPEED	 70
+#define RELOAD_TIME	2.5
+#define PLAYER_SPEED    0.2
+#define PLAYER_JUMP	 20
+#define BULLET_SPEED	 50
+#define BULLET_RATE	 50
+
+#define SOUND_MAX_EXPLOS 4
+char wav_boom[SOUND_MAX_EXPLOS][128]={"xf_boom1.wav","xf_boom2.wav","xf_boom3.wav","xf_boom4.wav"};
+int son_boom[SOUND_MAX_EXPLOS];
+
+#define SOUND_MAX_BONGS 5
+char wav_bong[SOUND_MAX_BONGS][128]={"xf_bong1.wav","xf_bong2.wav","xf_bong3.wav","xf_bong4.wav","xf_bong5.wav"};
+int son_bong[SOUND_MAX_BONGS];
+
+int son;
+int son_rl;
+int son_reload;
+int son_paf;
+int son_gun;
+char vue=7;
+GLfloat camx=-20;
+GLfloat camy=50;
+GLfloat camz=40;
+char cam[255];
+char record=-1;
+char draw_debug=-1;
+char mouse_grab=1;
+char is_explosive_tag=29;
+char is_bullet=99;
+dReal cam_angle_h=0;
+dReal cam_angle_v=90;
+int movie_spf=0;
+float life;
+char already_dead;
+float reload_time;
+float paf_time=0;
+float sensivity=1;
+
+dReal ptmp=0;
+
+dReal gears[]={-0.4,0.4,0.6,0.8,0.9,1.0};
+int gear=1;
+
+void create_game(char);
+
+
+//////////////////////// RayODE Callbacks
+
+void boom(char type, dReal radius, dReal force_or_propag, dReal *pos)
+{
+int i;
+int g1,g2;
+char name1[128];
+char name2[128];
+
+i=raydium_random_i(0,SOUND_MAX_EXPLOS-1);
+//raydium_explosion_add(pos[0],pos[1],pos[2],0,0,0,0.6,3,6,0.1);
+raydium_particle_name_auto("explo",name1);
+raydium_particle_name_auto("eplo_smoke",name2);
+g1=raydium_particle_generator_load("explosion.prt",name1);
+g2=raydium_particle_generator_load("explosmoke.prt",name2);
+
+raydium_particle_generator_move(g1,pos);
+raydium_particle_generator_move(g2,pos);
+
+raydium_sound_SourcePlay(son_boom[i]);
+raydium_sound_SetSourcePos(son_boom[i],pos);
+}
+
+void blow_touched(int elem, dReal force, dReal max_force)
+{
+if(raydium_ode_element_player_get(elem))
+    {
+    //raydium_log("touched: %.2f perc. of maximum explosion force (%.2f/%.2f)",force/max_force*100,force,max_force);
+    life-=(force/2);
+    }
+else
+    {
+    // is a rocket !
+    raydium_ode_element_OnBlow(elem,NULL);
+    raydium_ode_element_delete(elem,1);
+    }
+}
+
+int rocket_delete(int explo)
+{
+dReal *pos;
+pos=raydium_ode_element_pos_get(explo);
+raydium_ode_explosion_blow(4,100,pos);
+return 1; // confirm delete
+}
+
+char collide(int e1, int e2, dContact *n)
+{
+char *c1,*c2;
+int explo=-1;
+int player=-1;
+int bullet=-1;
+
+c1=raydium_ode_element_data_get(e1);
+c2=raydium_ode_element_data_get(e2);
+
+
+//if( !raydium_ode_element_isvalid(e1) ||
+//    !raydium_ode_element_isvalid(e2) )
+//    printf("(%i|%i) (%s|%s)\n",e1,e2,raydium_ode_element[e1].name,raydium_ode_element[e2].name);
+//    return 0;
+
+if((c1 && *c1==29))
+    explo=e1;
+if((c2 && *c2==29))
+    explo=e2;
+
+if((c1 && *c1==99))
+    bullet=e1;
+if((c2 && *c2==99))
+    bullet=e2;
+
+if(raydium_ode_element_player_get(e1))
+    player=e1;
+if(raydium_ode_element_player_get(e2))
+    player=e2;
+
+if(player>=0 && n->geom.depth>0.04)
+    {
+    // Based on small tests:
+    life-=(n->geom.depth*100/5);
+    }
+
+if(explo>=0)
+    {
+    raydium_sound_SourceStop(son_rl);
+    if(raydium_random_i(0,ROCKET_FIABILITY)==0)
+     {
+     int i;
+     // no luck, this rocket will never explode ;)
+     raydium_ode_element_data_set(explo,NULL);
+     raydium_ode_element_gravity(explo,1);
+     raydium_ode_element_OnBlow(explo,blow_touched);
+     // play a random "bong"
+     i=raydium_random_i(0,SOUND_MAX_BONGS-1);
+     raydium_sound_SourcePlay(son_bong[i]); 
+     raydium_ode_element_sound_update(explo,son_bong[i]);
+     raydium_particle_generator_enable(raydium_ode_element[explo].particle,0);
+     }
+    else
+     {
+     raydium_ode_element_delete(explo,1);
+     return 1;
+     }
+    }
+
+if(bullet>=0)
+    {
+    // play a sound ?
+    raydium_ode_element_delete(bullet,1);
+    n->surface.soft_erp=0.5;
+    n->surface.soft_cfm=1;
+    return 1; // generate a contact point anyway
+    }
+return 1;
+}
+
+void frame_step(GLfloat step)
+{
+reload_time-=step;
+paf_time+=step;
+}
+
+
+void step(void)
+{
+static int cpt=0;
+if(raydium_mouse_button[1] && cpt>BULLET_RATE)
+    {
+    // fire !
+    int a;
+    char name[255];
+    cpt=0;
+    a=raydium_ode_object_find("PLAYER");
+    raydium_ode_name_auto("bullet",name);
+    strcpy(cam,name);
+    raydium_ode_object_box_add(name,a,0.01,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"bullet.tri");
+    raydium_ode_launcher_simple_name_3f(name,"player",0,cam_angle_v+5,0,BULLET_SPEED);
+    raydium_ode_element_rotate_direction_name(name,0);
+    raydium_ode_element_data_set_name(name,&is_bullet);
+    raydium_ode_element_gravity_name(name,0);
+//    raydium_ode_element_OnDelete_name(name,rocket_delete);
+    raydium_ode_element_ttl_set_name(name,RAYDIUM_ODE_PHYSICS_FREQ*5); // 5 seconds
+//    raydium_sound_SourcePlay(son_rl);
+//    raydium_ode_element_sound_update_name("player",son_rl);
+//    reload_time=RELOAD_TIME;
+    raydium_sound_SourcePlay(son_gun);
+    raydium_ode_element_sound_update_name("player",son_gun);
+    }
+cpt++;
+}
+
+
+void kill_player(void)
+{
+already_dead=1;
+create_game(0);
+raydium_log("Killed");
+} PHP_v_v(kill_player);
+
+void kill_php(void)
+{
+life=0;
+} PHP_v_v(kill_php);
+
+/////////////////////// Actors creation
+
+void create_game(char alive)
+{
+#define BREAK_FORCE	130
+#define ROTFRICTION	0.0005
+int a;
+    
+    
+if(!alive)
+{
+dQuaternion q;
+dReal pos[3];
+dReal vel[3];
+dReal accum[3];
+
+raydium_ode_element_rotq_get_name("player",q);
+memcpy(pos,raydium_ode_element_pos_get_name("player"),sizeof(dReal)*3);
+// get vel and accums
+memcpy(vel,dBodyGetLinearVel(raydium_ode_element[raydium_ode_element_find("player")].body),sizeof(dReal)*3);
+memcpy(accum,dBodyGetForce(raydium_ode_element[raydium_ode_element_find("player")].body),sizeof(dReal)*3);
+
+raydium_ode_object_delete_name("PLAYER");
+
+a=raydium_ode_object_create("PLAYER");
+raydium_ode_object_box_add("player",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"lego.tri");
+// raydium_ode_element_material_name("player",RAYDIUM_ODE_MATERIAL_SOFT2);
+raydium_ode_element_move_name("player",pos);
+raydium_ode_element_rotateq_name("player",q);
+dBodySetLinearVel(raydium_ode_element[raydium_ode_element_find("player")].body,vel[0],vel[1],vel[2]);
+dBodySetForce(raydium_ode_element[raydium_ode_element_find("player")].body,accum[0],accum[1],accum[2]);
+dBodySetTorque(raydium_ode_element[raydium_ode_element_find("player")].body,0.1,0.1,0.1);
+
+return;
+}
+
+raydium_ode_object_delete_name("BUGGY");
+    
+  a=raydium_ode_object_create("BUGGY");
+    raydium_ode_object_box_add("buggy_corps",a,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"buggy.tri");
+
+    raydium_ode_object_sphere_add("buggy_pneu_ag",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"buggy_r.tri");
+    raydium_ode_element_rotfriction_name("buggy_pneu_ag",ROTFRICTION);
+    raydium_ode_element_move_name_3f("buggy_pneu_ag",0.42,0.253,-0.280);
+    raydium_ode_joint_attach_hinge2_name("buggy_suspet_ag","buggy_corps","buggy_pneu_ag",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
+    raydium_ode_joint_break_force_name("buggy_suspet_ag",BREAK_FORCE);
+
+    raydium_ode_object_sphere_add("buggy_pneu_ad",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"buggy_r.tri");
+    raydium_ode_element_rotfriction_name("buggy_pneu_ad",ROTFRICTION);
+    raydium_ode_element_move_name_3f("buggy_pneu_ad",0.42,-0.253,-0.280);
+    raydium_ode_joint_attach_hinge2_name("buggy_suspet_ad","buggy_corps","buggy_pneu_ad",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
+    raydium_ode_joint_break_force_name("buggy_suspet_ad",BREAK_FORCE);
+
+    raydium_ode_object_sphere_add("buggy_pneu_rg",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"buggy_r.tri");
+    raydium_ode_element_rotfriction_name("buggy_pneu_rg",ROTFRICTION);
+    raydium_ode_element_move_name_3f("buggy_pneu_rg",-0.444,0.3,-0.260);
+    raydium_ode_joint_attach_hinge2_name("buggy_suspet_rg","buggy_corps","buggy_pneu_rg",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
+    raydium_ode_joint_hinge2_block_name("buggy_suspet_rg",1);
+    raydium_ode_joint_break_force_name("buggy_suspet_rg",BREAK_FORCE);
+
+    raydium_ode_object_sphere_add("buggy_pneu_rd",a,0.5,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"buggy_r.tri");
+    raydium_ode_element_rotfriction_name("buggy_pneu_rd",ROTFRICTION);
+    raydium_ode_element_move_name_3f("buggy_pneu_rd",-0.444,-0.3,-0.260);
+    raydium_ode_joint_attach_hinge2_name("buggy_suspet_rd","buggy_corps","buggy_pneu_rd",RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES);
+    raydium_ode_joint_hinge2_block_name("buggy_suspet_rd",1);
+    raydium_ode_joint_break_force_name("buggy_suspet_rd",BREAK_FORCE);
+    
+    raydium_ode_motor_create("buggy_moteur",a,RAYDIUM_ODE_MOTOR_ENGINE);
+    raydium_ode_motor_attach_name("buggy_moteur","buggy_suspet_ag",1);
+    raydium_ode_motor_attach_name("buggy_moteur","buggy_suspet_ad",1);
+    raydium_ode_motor_power_max_name("buggy_moteur",0.05);
+    raydium_ode_motor_gears_set_name("buggy_moteur",gears,6);
+    raydium_ode_motor_gear_change_name("buggy_moteur",gear);
+
+    
+    raydium_ode_motor_create("buggy_direction",a,RAYDIUM_ODE_MOTOR_ANGULAR);
+    raydium_ode_motor_attach_name("buggy_direction","buggy_suspet_ag",0);
+    raydium_ode_motor_attach_name("buggy_direction","buggy_suspet_ad",0);
+    raydium_ode_motor_power_max_name("buggy_direction",0.2);
+    {
+    //dReal pos[3]={2,2,2};
+    //raydium_ode_object_move(a,pos);
+    }
+//    raydium_ode_element_particle_offset_name_3f("buggy_corps","smoke.prt",-0.5,0,0);
+//    raydium_ode_element_particle_offset_name_3f("buggy_corps","dust.prt",-0.5,0,-0.3);
+
+/*
+raydium_ode_object_delete_name("TANK");
+    
+  a=raydium_ode_object_create("TANK");
+    raydium_ode_object_box_add("tank_corps",a,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"t80b.tri");
+    raydium_ode_element_move_name_3f("tank_corps",-2,0,0);
+
+    raydium_ode_object_box_add("tank_tour",a,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"t80t.tri");
+    raydium_ode_element_move_name_3f("tank_tour",-2,0,0.4);
+
+    raydium_ode_joint_attach_hinge_name("pivot","tank_corps","tank_tour",-2,0,0.4,RAYDIUM_ODE_JOINT_AXE_Z);
+    raydium_ode_joint_hinge_limits_name("pivot",-2.5,2.5);
+    raydium_ode_motor_create("pivot_motor",a,RAYDIUM_ODE_MOTOR_ENGINE);
+    raydium_ode_motor_attach_name("pivot_motor","pivot",0);
+    raydium_ode_motor_power_max_name("pivot_motor",0.1);
+
+    raydium_ode_object_box_add("tank_canon",a,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"t80c.tri");
+    raydium_ode_element_move_name_3f("tank_canon",-1,0,0.30);
+
+    raydium_ode_joint_attach_hinge_name("trukatach","tank_tour","tank_canon",-1.8,0,0.3,RAYDIUM_ODE_JOINT_AXE_Y);
+    raydium_ode_joint_hinge_limits_name("trukatach",0,0.5);
+    raydium_ode_motor_create("truk_motor",a,RAYDIUM_ODE_MOTOR_ANGULAR);
+    raydium_ode_motor_attach_name("truk_motor","trukatach",0);
+    raydium_ode_motor_power_max_name("truk_motor",1);
+*/
+
+    life=100;
+    already_dead=0;
+    reload_time=RELOAD_TIME;
+    raydium_ode_object_delete_name("PLAYER");
+    a=raydium_ode_object_create("PLAYER");
+    raydium_ode_object_sphere_add("player",a,0.1,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"lego.tri");
+    raydium_ode_element_material_name("player",RAYDIUM_ODE_MATERIAL_SOFT2);
+    raydium_ode_element_player_set_name("player",1);
+    raydium_ode_motor_create("player_react",a,RAYDIUM_ODE_MOTOR_ROCKET);
+    raydium_ode_motor_rocket_set_name("player_react","player",0,0,0);
+    raydium_ode_motor_rocket_playermovement_name("player_react",1);
+    raydium_ode_element_slip_name("ground",RAYDIUM_ODE_SLIP_ICE/2.f);
+    raydium_ode_element_OnBlow_name("player",blow_touched);
+//    raydium_ode_element_move_name_3f("player",3,3,1);
+#define DEFAULT_RAND_DEC raydium_random_f(-3,3)
+#define DEFAULT_DEC DEFAULT_RAND_DEC,DEFAULT_RAND_DEC,0
+raydium_ode_object_move_name_3f("BUGGY", DEFAULT_DEC);
+raydium_ode_object_move_name_3f("PLAYER",DEFAULT_DEC);
+
+}
+
+void display(void)
+{
+dReal speed;
+dReal direct;
+dReal *tmp;
+
+raydium_joy_key_emul();
+
+if(raydium_key[GLUT_KEY_F1]) { raydium_projection_fov/=(1.04); raydium_window_view_update(); }
+if(raydium_key[GLUT_KEY_F2]) { raydium_projection_fov*=(1.04); raydium_window_view_update(); }
+
+// sets motor speed
+if((vue==4 || vue==5 || vue==6) && life>0)
+{
+speed=0;
+
+// keyboard or joy settings
+if(raydium_joy_y>0) speed=raydium_joy_y*55;
+//if(raydium_joy_z<0) speed=(raydium_joy_z)*-55;
+
+
+direct=raydium_joy_x*0.3; // 0.2 is "perfect" for clio stability
+
+raydium_ode_motor_speed_name("buggy_moteur",-speed);
+raydium_ode_motor_angle_name("buggy_direction",direct);
+
+if( (raydium_key_last==1113 || raydium_joy_click==6) && gear<5)
+ gear++;
+
+if( (raydium_key_last==1119 || raydium_joy_click==5) && gear>0)
+ gear--;
+
+}
+
+if(vue==8 && life>0)
+{
+static dReal angle=0;
+speed=raydium_joy_x;
+angle+=raydium_joy_y*0.01;
+raydium_ode_motor_speed_name("pivot_motor",speed);
+raydium_ode_motor_angle_name("truk_motor",angle);
+
+if(raydium_mouse_click==1 && reload_time<0)
+    {
+    // launch projectile
+    int a;
+    char name[255];
+    a=raydium_ode_object_find("TANK");
+    raydium_ode_name_auto("ob",name);
+    strcpy(cam,name);
+    raydium_ode_object_box_add(name,a,0.02,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"rocket.tri");
+    raydium_ode_launcher_simple_name_3f(name,"tank_canon",0,90,0,ROCKET_SPEED);
+    raydium_ode_element_rotate_direction_name(name,0);
+    raydium_ode_element_data_set_name(name,&is_explosive_tag);
+//    raydium_ode_element_gravity_name(name,0);
+    raydium_ode_element_OnDelete_name(name,rocket_delete);
+    raydium_ode_element_ttl_set_name(name,RAYDIUM_ODE_PHYSICS_FREQ*10); // 10 seconds
+    raydium_sound_SourcePlay(son_rl);
+    raydium_ode_element_sound_update_name("tank_tour",son_rl);
+    reload_time=RELOAD_TIME;
+    }
+}
+
+if(vue==7 && life>0)
+{
+int dir=5;
+speed=PLAYER_SPEED;
+ptmp=0;
+
+// directions indices:
+// 1    2    3
+//      ^
+// 4 <- 5 -> 6
+//      v
+// 7    8    9
+
+if(raydium_key[GLUT_KEY_LEFT])  dir=4;
+if(raydium_key[GLUT_KEY_RIGHT]) dir=6;
+if(raydium_key[GLUT_KEY_UP]) dir=2;
+if(raydium_key[GLUT_KEY_DOWN]) dir=8;
+
+if(raydium_key[GLUT_KEY_LEFT] && raydium_key[GLUT_KEY_UP]) dir=1;
+if(raydium_key[GLUT_KEY_RIGHT] && raydium_key[GLUT_KEY_UP]) dir=3;
+
+if(raydium_key[GLUT_KEY_LEFT] && raydium_key[GLUT_KEY_DOWN]) dir=7;
+if(raydium_key[GLUT_KEY_RIGHT] && raydium_key[GLUT_KEY_DOWN]) dir=9;
+
+switch(dir)
+    {
+    case 1:
+	ptmp=-45;
+	break;
+    case 2:
+	ptmp=0;
+	break;
+    case 3:
+	ptmp=45;
+	break;
+    case 4:
+	ptmp=-90;
+	break;
+    case 5:
+	speed=0; // stops player
+	break;
+    case 6:
+	ptmp=90;
+	break;
+    case 7:
+	ptmp=-135;
+	break;
+    case 8:
+	ptmp=180;
+	break;
+    case 9:
+	ptmp=135;
+	break;
+    }
+
+raydium_ode_motor_speed_name("player_react",speed);
+raydium_ode_motor_rocket_orientation_name("player_react",0,90,ptmp);
+if(raydium_mouse_click==3 && raydium_ode_element_touched_get_name("player")) raydium_ode_launcher_name_3f("player","player",0,0,0,PLAYER_JUMP);
+if(raydium_mouse_click==1 && reload_time<0)
+    {
+    // launch rocket
+    int a;
+    char name[255];
+    a=raydium_ode_object_find("PLAYER");
+    raydium_ode_name_auto("mav",name);
+    strcpy(cam,name);
+    raydium_ode_object_box_add(name,a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"rocket.tri");
+    raydium_ode_launcher_simple_name_3f(name,"player",0,cam_angle_v+5,0,ROCKET_SPEED);
+    raydium_ode_element_rotate_direction_name(name,0);
+    raydium_ode_element_data_set_name(name,&is_explosive_tag);
+    raydium_ode_element_gravity_name(name,0);
+    raydium_ode_element_OnDelete_name(name,rocket_delete);
+    raydium_ode_element_ttl_set_name(name,RAYDIUM_ODE_PHYSICS_FREQ*10); // 10 seconds
+    raydium_ode_element_particle_name(name,"smoke.prt");
+    raydium_sound_SourcePlay(son_rl);
+    raydium_ode_element_sound_update_name("player",son_rl);
+    reload_time=RELOAD_TIME;
+    }
+
+}
+
+if(life<=0 && !already_dead)
+    kill_player();
+
+if(raydium_mouse_click==1 && life<=0)
+    create_game(1);
+
+
+if(raydium_key_last==1027) exit(0);
+if(raydium_key_last==1114) record*=-1;
+if(raydium_key_last==1116) draw_debug*=-1;
+if(raydium_key_last==1109) mouse_grab*=-1;
+
+if(raydium_key_last==1032)
+    {
+
+    int a;
+    char name[255];
+    a=raydium_ode_object_find("GLOBAL");
+    raydium_ode_name_auto("box",name);
+    raydium_ode_object_box_add(name,a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"crate.tri");
+    raydium_ode_element_move_name_3f(name,raydium_random_neg_pos_1(),raydium_random_neg_pos_1(),2);
+
+    //raydium_php_exec("test.php");
+    }
+
+if(raydium_key_last==1097) { movie_spf=0; raydium_ode_time_change(0); }
+if(raydium_key_last==1122) { movie_spf=3; raydium_ode_time_change(10); }
+if(raydium_key_last==1101) { movie_spf=16; raydium_ode_time_change(100); }
+
+if(raydium_key_last==1109 && 0)  // disabled
+ {
+ int elems[10];
+ elems[0]=raydium_ode_element_find("buggy_corps");
+ elems[1]=raydium_ode_element_find("buggy_pneu_ag");
+ elems[2]=raydium_ode_element_find("buggy_pneu_ad");
+ elems[3]=raydium_ode_element_find("buggy_pneu_rd"); 
+ elems[4]=raydium_ode_element_find("buggy_pneu_rg"); 
+ raydium_ode_element_fix("merged_elem",elems,5,0);
+ }
+
+
+//if(raydium_key_last==1098) 
+
+if(raydium_key_last==5)
+{
+vue=5;
+raydium_projection_near=10;
+raydium_projection_fov=2;
+raydium_window_view_update();
+}
+                                                                                 
+if(raydium_key_last==6)
+{
+vue=6;
+raydium_projection_near=0.05 ;
+raydium_projection_fov=60;
+raydium_window_view_update();
+                                                                                 
+}
+
+if(raydium_key_last==4)
+{
+vue=4;
+raydium_projection_near=0.05;
+raydium_projection_fov=40;
+raydium_window_view_update();
+                                                                                 
+}
+
+if(raydium_key_last==7)
+{
+vue=7;
+raydium_projection_near=0.05;
+raydium_projection_fov=70;
+raydium_window_view_update();
+}
+
+
+if(raydium_key_last==8)
+{
+vue=8;
+raydium_projection_near=0.05;
+raydium_projection_fov=70;
+raydium_window_view_update();
+}
+
+
+if(raydium_key_last==3)
+{
+vue=3;
+raydium_projection_near=0.05;
+raydium_projection_fov=120;
+raydium_window_view_update();
+}
+
+//if(raydium_key_last==1100) 
+//    raydium_ode_element_moveto_name("buggy_pneu_ag","GLOBAL",1);
+
+
+if(mouse_grab==1)
+{
+ float delta_x;
+ float delta_y;
+ float zoomfact=1;
+ zoomfact=raydium_projection_fov/70;
+ delta_x = (raydium_mouse_x - (raydium_window_tx/2.f))*sensivity*zoomfact;
+ delta_y = (raydium_mouse_y - (raydium_window_ty/2.f))*sensivity*zoomfact;
+ cam_angle_h += (delta_x*0.008f); // rads
+ if(life>0)
+  cam_angle_v += (delta_y*0.458f); // degs
+ raydium_mouse_move(raydium_window_tx/2, raydium_window_ty/2);
+ raydium_ode_element_player_angle_name("player",cam_angle_h);
+ if(cam_angle_v<1) cam_angle_v=1;
+ if(cam_angle_v>179) cam_angle_v=179;
+}
+
+
+
+{
+static int reload_done=1;
+if(reload_time<1 && !reload_done)
+    {
+    reload_done=1;
+    raydium_sound_SourcePlay(son_reload);
+    raydium_ode_element_sound_update_name("player",son_reload);
+    }
+if(reload_time>1) reload_done=0;
+}
+
+
+raydium_light_position[0][0]=50;
+raydium_light_position[0][1]=150;
+raydium_light_position[0][2]=200;
+raydium_light_position[0][3]=1.0;
+raydium_light_update_all(0);
+
+
+{
+/*dReal *pos;
+pos=raydium_ode_element_pos_get_name("buggy_corps");
+if(pos)
+    raydium_particle_generator_move_name("smoke",pos);*/
+}
+
+
+raydium_clear_frame();
+glLoadIdentity();
+
+// camera + drawing
+if(raydium_ode_element_find(cam)<0) strcpy(cam,"player");
+tmp=raydium_ode_element_pos_get_name(cam);
+if(vue==5) raydium_camera_look_at(camx,camy,camz,tmp[1],-tmp[2],tmp[0]);
+if(vue==6) raydium_ode_element_camera_inboard_name("buggy_corps",-0.15,0,0.1,2,0,0);
+if(vue==4) raydium_ode_element_camera_inboard_name("buggy_corps",0,0.35,-0.2,2,0,-0.2);
+if(vue==7) raydium_ode_element_camera_inboard_name("player",0,0,0.1, raydium_trigo_sin(cam_angle_v),0,raydium_trigo_cos(cam_angle_v));
+//if(vue==8) raydium_ode_element_camera_inboard_name("tank_tour",0,0,0.1, 1,0,0);
+if(vue==3) raydium_ode_element_camera_inboard_name(cam,0,0,0.1, 1,0,0);
+//if(vue==8) raydium_ode_element_camera_inboard_name("helico",-1,0,1,1,0,0);
+
+raydium_ode_draw_all(0);
+if(draw_debug==1) 
+    {
+    raydium_ode_draw_all(1);
+    raydium_ode_draw_all(2);
+    raydium_osd_network_stat_draw(5,30,20);
+    }
+
+
+speed=raydium_ode_motor_speed_get_name("buggy_moteur",0);
+raydium_osd_printf(2,4,12,0.5,"font2.tga","^fcar speed: %f",speed);
+raydium_joy_ff_autocenter(speed/2.f);
+
+speed=raydium_ode_motor_speed_get_name("buggy_moteur",1);
+if(vue!=7) 
+    {
+    raydium_osd_printf(10,10,30,0.5,"font2.tga","%i",gear);
+    raydium_osd_printf(13,10,15,0.5,"font2.tga","%.1f",speed);
+    }
+
+if(paf_time>0.04 && speed>1 && !raydium_key[GLUT_KEY_UP])
+    {
+    paf_time=0;
+    if(raydium_random_i(0,10)==0) raydium_sound_SourcePlay(son_paf);
+    }
+
+//if(speed<10 && gear>1) gear--;
+//if(speed>45 && gear<5) gear++;
+raydium_ode_motor_gear_change_name("buggy_moteur",gear);
+
+speed*=0.1; // wheel radius
+speed/=4;
+speed+=0.5;
+speed+=(raydium_random_neg_pos_1()/15);
+raydium_sound_SetSourcePitch(son,raydium_trigo_abs(speed));
+raydium_ode_element_sound_update_name("buggy_corps",son);
+raydium_ode_element_sound_update_name("buggy_corps",son_paf);
+
+raydium_osd_printf(2,98,16,0.5,"font2.tga","- %3i FPS - tech demo %s for Raydium %s, CQFD Corp.",raydium_render_fps,version,raydium_version);
+
+{
+char c='2';
+if(life<50) c='e';
+if(life<25) c='c';
+raydium_osd_printf(2,15,20,0.5,"font2.tga","Health: ^%c%.1f %%^f",c,life);
+}
+
+//raydium_osd_printf(2,80,18,0.5,"font2.tga","^f Lag-O-meter: %.2f ms",raydium_netwok_queue_ack_delay/(double)raydium_timecall_clocks_per_sec*1000);
+//raydium_osd_printf(2,80,18,0.5,"font2.tga","AF: %i",raydium_ode_element_ground_texture_get_name("buggy_pneu_ad"));
+{
+//dReal rx,ry,rz;
+//raydium_ode_element_rot_get_name("buggy_corps",&rx,&ry,&rz);
+//raydium_osd_printf(2,80,18,0.5,"font2.tga","^fRot %.2f %.2f %.2f",rx,ry,rz);
+}
+
+if(reload_time>0)
+ raydium_osd_printf(7,20,15,0.5,"font2.tga","^c[RELOADING]^f");
+
+if(life<=0)
+    raydium_osd_printf(10,50,30,0.5,"font2.tga","Push FIRE button to restart game.");
+else
+    if(vue==7) raydium_osd_draw_name("BOXcross.tga",49,49,51,51);
+
+if(life<=0)
+ raydium_osd_mask(blood);
+    
+//raydium_osd_network_stat_draw(5,30,20);
+raydium_osd_logo("logo6.tga");
+memset(raydium_vertex_tag,0,RAYDIUM_MAX_VERTICES);
+raydium_rendering_finish();
+
+//raydium_ode_network_element_send_random(4);
+//raydium_ode_network_element_send_all();
+raydium_ode_network_element_send_iterative(RAYDIUM_ODE_NETWORK_OPTIMAL);
+
+#ifdef ODE_MANUAL_CALLBACK
+{
+int i;
+static int movie_frame=0;
+char movie_str[255];
+for(i=0;i<movie_spf;i++)
+    raydium_ode_callback();
+sprintf(movie_str,"movie/movie%04i.tga",movie_frame);
+if(record==1) raydium_capture_frame(movie_str);
+movie_frame++;
+}
+#endif
+
+}
+
+
+int main(int argc, char **argv)
+{
+char server[128];
+char model[RAYDIUM_MAX_NAME_LEN];
+int i;
+
+raydium_init_args(argc,argv);
+raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,version);
+raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_TRILINEAR);
+raydium_projection_near=0.05;
+raydium_projection_far=1000;
+raydium_projection_fov=70;
+//raydium_light_disable();
+raydium_fog_disable();
+raydium_light_on(0);
+//raydium_light_on(1);
+memcpy(raydium_light_color[0],sun,raydium_internal_size_vector_float_4);
+//raydium_light_intensity[0]=400;
+raydium_light_intensity[0]=1000000;
+raydium_light_update_all(0);
+
+
+if(raydium_init_cli_option("server",server))
+     if(!raydium_network_client_connect_to(server)) 
+        exit(1);
+
+raydium_sound_DefaultReferenceDistance=4.f;
+
+//son=raydium_sound_LoadWav("../wav/clio/scooter.wav");
+son=raydium_sound_LoadWav("murcielago2.wav");
+raydium_sound_SetSourcePitch(son,0);
+//raydium_sound_SetSourceGain(son,0.05);  // Engine Gain
+raydium_sound_SourcePlay(son);
+
+son_rl=raydium_sound_LoadWav("xf_launch1.wav");
+raydium_sound_SetSourceLoop(son_rl,0);
+
+son_reload=raydium_sound_LoadWav("xf_reload.wav");
+raydium_sound_SetSourceLoop(son_reload,0);
+
+son_paf=raydium_sound_LoadWav("xf_paf.wav");
+raydium_sound_SetSourceLoop(son_paf,0);
+
+son_gun=raydium_sound_LoadWav("xf_gun1.wav");
+raydium_sound_SetSourceLoop(son_gun,0);
+
+for(i=0;i<SOUND_MAX_EXPLOS;i++)
+    {
+    son_boom[i]=raydium_sound_LoadWav(wav_boom[i]);
+    raydium_sound_SetSourceLoop(son_boom[i],0);
+    }
+
+for(i=0;i<SOUND_MAX_BONGS;i++)
+    {
+    son_bong[i]=raydium_sound_LoadWav(wav_bong[i]);
+    raydium_sound_SetSourceLoop(son_bong[i],0);
+    }
+
+//raydium_osd_cursor_set("BOXcursor.tga",4,4);
+strcpy(raydium_console_config_texture,"logo_console.tga");
+raydium_sky_box_cache();
+
+
+strcpy(cam,"invalid_name");
+raydium_register_variable(&sensivity,RAYDIUM_REGISTER_FLOAT,"sensivity");
+raydium_register_variable(&camx,RAYDIUM_REGISTER_FLOAT,"camx");
+raydium_register_variable(&camy,RAYDIUM_REGISTER_FLOAT,"camy");
+raydium_register_variable(&camz,RAYDIUM_REGISTER_FLOAT,"camz");
+raydium_register_variable(cam,RAYDIUM_REGISTER_STR,"cam");
+
+//raydium_register_variable(&ptmp,RAYDIUM_REGISTER_FLOAT,"ptmp");
+raydium_register_variable(&vue,RAYDIUM_REGISTER_INT,"vue");
+raydium_register_function(C2PHP(kill_php),"kill");
+raydium_timecall_add(frame_step,-1);
+
+
+raydium_init_cli_option_default("ground",model,"a.tri");
+raydium_ode_ground_set_name(model);
+
+create_game(1);
+raydium_ode_CollideCallback=collide;
+raydium_ode_ExplosionCallback=boom;
+raydium_ode_StepCallback=step;
+
+//raydium_ode_time_change(0);
+
+raydium_php_exec("test6.php");
+//raydium_sound_load_music("memak5.ogg");
+raydium_sound_load_music("memak5loud.ogg");
+
+raydium_callback(&display);
+return 0;
+}
Index: ocomp.sh
===================================================================
--- ocomp.sh	(revision 0)
+++ ocomp.sh	(revision 1)
@@ -0,0 +1,5 @@
+ulimit -c 0
+rm test
+gcc -g $1 -Wall -o test -L/usr/X11R6/lib/ -lGL -lglut -lGLU -lm -lopenal -Iode/include/ ode/lib/libode.a -lvorbis -lvorbisfile -logg -Iphp/ -Iphp/include -Iphp/main/ -Iphp/Zend -Iphp/TSRM php/libs/libphp4.a -lresolv -lcrypt -lz
+sync
+./test $2 $3 $4 $5 $6

Property changes on: ocomp.sh
___________________________________________________________________
Added: svn:executable
\ No newline at end of property
Index: playlist.php
===================================================================
--- playlist.php	(revision 0)
+++ playlist.php	(revision 1)
@@ -0,0 +1,19 @@
+<?
+// place anything you want here to modify $raydium_ogg_file 
+// with the desired file (or empty string to stop music playback)
+
+// In this example, I list music/*.ogg and play a random file
+
+$dir=opendir("music/");
+if($dir==false) die("Cannot find \"music/\" directory...");
+
+unset($tbl);
+while (($file = readdir($dir)) != false)
+    if(substr($file,-4) == ".ogg")
+	$tbl[]=$file;
+
+
+$raydium_ogg_file="music/".$tbl[rand(0,count($tbl)-1)];
+
+echo "Now playing $raydium_ogg_file ...";
+?>
\ No newline at end of file
Index: willou.c
===================================================================
--- willou.c	(revision 0)
+++ willou.c	(revision 1)
@@ -0,0 +1,111 @@
+#define NO_ODE_SUPPORT
+#include "raydium/index.c"
+
+GLfloat cam_angle_x = 0;
+GLfloat cam_angle_y = 90;
+
+GLfloat cam_pos_x = 0;
+GLfloat cam_pos_y = 0;
+GLfloat cam_pos_z = 0;
+
+GLfloat speed = 0.1;
+GLint sensibilite = 3;
+
+GLint lacet = 0;
+
+char model[RAYDIUM_MAX_NAME_LEN];
+
+GLfloat light_color[] = {1.0, 0.9, 0.8, 1.0};
+//    GLfloat back_color[] = {1, 1, 1, 1};
+GLfloat  *back_color=light_color;
+//    GLfloat light_color[] = {0, 0, 0, 1};
+
+
+void display(void)
+{
+    
+    int delta_x, delta_y;
+    raydium_joy_key_emul();
+
+    cam_pos_z += (raydium_trigo_sin(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+    cam_pos_x += (raydium_trigo_cos(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+    cam_pos_y += (raydium_trigo_cos(90-cam_angle_y)*speed*raydium_joy_y);
+    
+    cam_pos_x -= (raydium_trigo_cos(cam_angle_x)*raydium_joy_x*speed);
+    cam_pos_z -= (raydium_trigo_sin(cam_angle_x)*raydium_joy_x*speed);
+    
+    if(raydium_key_last==1027)
+	exit(0);
+
+
+    if(raydium_key_last==1)
+	raydium_light_disable();
+    if(raydium_key_last==2)
+	raydium_light_enable();
+
+    
+    delta_x = raydium_mouse_x - (raydium_window_tx/2);
+    cam_angle_x += (delta_x*sensibilite*0.1f); 
+
+    delta_y = raydium_mouse_y - (raydium_window_ty/2);
+    cam_angle_y += (delta_y*sensibilite*0.1f); 
+
+    raydium_mouse_move(raydium_window_tx/2, raydium_window_ty/2);
+    
+
+
+    raydium_light_position[0][0]=50;
+    raydium_light_position[0][1]=150;
+    raydium_light_position[0][2]=200;
+    raydium_light_position[0][3]=1.0;
+    
+    raydium_clear_frame();
+    
+    raydium_camera_place(cam_pos_x,cam_pos_y,cam_pos_z,cam_angle_x,cam_angle_y,0);
+
+    raydium_camera_replace();
+    
+    
+    raydium_object_draw_name(model);
+
+//    raydium_osd_logo("logo.tga");
+    
+    raydium_rendering_finish();
+}
+
+
+
+
+int main(int argc, char **argv)
+{
+    raydium_init_args(argc,argv);
+    
+    // creation de la fenetre et de la scene
+    raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Willou's test");
+    raydium_texture_filter=RAYDIUM_TEXTURE_FILTER_TRILINEAR;
+    raydium_projection_near=0.01;
+    raydium_projection_far=2500;
+    raydium_projection_fov=60;
+    raydium_fog_disable();
+    raydium_window_view_update();
+    
+    raydium_light_enable();
+    raydium_light_on(0);
+    memcpy(raydium_light_color[0],light_color,raydium_internal_size_vector_float_4);
+    raydium_light_intensity[0] = 10000000;
+    raydium_light_update_all(0);
+    
+//    raydium_osd_cursor_set("BOXcursor.tga",4,4);
+
+    raydium_window_view_update();
+    raydium_background_color_change(back_color[0],back_color[1],back_color[2],back_color[3]);
+
+    raydium_register_variable(&speed, RAYDIUM_REGISTER_FLOAT, "speed");
+
+    strcpy(model,"a.tri");
+    raydium_init_cli_option("model",model);
+    
+    raydium_callback(&display);
+    return(0);
+}
+// EOF
Index: raydium_modler.c
===================================================================
--- raydium_modler.c	(revision 0)
+++ raydium_modler.c	(revision 1)
@@ -0,0 +1,748 @@
+#define NO_ODE_SUPPORT
+#include "raydium/index.c"
+
+char *version="0.345 Beta";
+
+#define round(x) (int)((x)>0?(x)+0.5:(x)-0.5)
+#define MAX_CONTOUR 512
+#define defSUBDIV 10
+
+#define VIEW_XY 0
+#define VIEW_ZY 1
+#define VIEW_XZ 2
+
+#define CONTOUR_EXTRUDE 0
+#define CONTOUR_GATHER 1
+
+////////////////////
+GLfloat modl_view=VIEW_XY;
+GLfloat modl_zoom=10;
+GLfloat modl_grid=1;
+GLfloat modl_axes=1;
+GLfloat modl_tex=1;
+char    modl_light=0;
+char    modl_wire=0;
+GLfloat pz=0;
+//char entry[512];
+char arg[16][512];
+char cam_file[512];
+GLfloat contour_x[MAX_CONTOUR];
+GLfloat contour_y[MAX_CONTOUR];
+GLfloat contour_z[MAX_CONTOUR];
+GLuint contour_index=0;
+
+
+float xcos(int i)
+{
+return( (float)cos(i*PI/180) );
+}
+
+
+float xsin(int i)
+{
+return( (float)sin(i*PI/180) );
+}
+
+
+void screen_to_VIEW(GLfloat sx, GLfloat sy,GLfloat sz,GLfloat *dx, GLfloat *dy, GLfloat *dz)
+{
+if(modl_view==VIEW_XY) { (*dx)=sx; (*dy)=sy; (*dz)=sz; }
+if(modl_view==VIEW_ZY) { (*dx)=sz; (*dy)=sy; (*dz)=sx; }
+if(modl_view==VIEW_XZ) { (*dx)=sx; (*dy)=sz; (*dz)=sy; }
+}
+
+
+void screen_to_local(GLfloat *x, GLfloat *y, GLfloat *z, char modl_view)
+{
+GLfloat lx,ly,lz;
+lx=((float)raydium_mouse_x-((float)raydium_window_tx/(float)2)) * ((float)(modl_zoom*(float)2)/(float)raydium_window_tx);
+ly=-((float)raydium_mouse_y-((float)raydium_window_ty/(float)2)) * ((float)(modl_zoom*(float)2)/(float)raydium_window_ty);
+lz=pz;
+//fx=round(x);
+//fy=round(y);
+if(modl_view==VIEW_XY) { (*x)=lx; (*y)=ly; (*z)=lz; }
+if(modl_view==VIEW_ZY) { (*x)=lz; (*y)=ly; (*z)=lx; }
+if(modl_view==VIEW_XZ) { (*x)=lx; (*y)=lz; (*z)=ly; }
+ 
+ 
+}
+
+
+
+void map_uv(GLfloat x1, GLfloat x2, GLfloat y1, GLfloat y2, GLfloat z1, GLfloat z2)
+{
+GLuint i;
+GLfloat xdiff=x2-x1;
+GLfloat ydiff=y2-y1;
+GLfloat zdiff=z2-z1;
+
+
+for(i=0;i<raydium_vertex_index;i++)
+if(raydium_vertex_texture[i]==raydium_texture_current)
+     if(raydium_vertex_normal_z[i]<-0.5 ||
+     raydium_vertex_normal_z[i]>0.5 )
+     {
+     raydium_vertex_texture_u[i]=(raydium_vertex_x[i]-x1)/xdiff;
+     raydium_vertex_texture_v[i]=(raydium_vertex_y[i]-y1)/ydiff;
+     }
+else if(raydium_vertex_normal_x[i]<-0.5 ||
+     raydium_vertex_normal_x[i]>0.5 )
+     {
+     raydium_vertex_texture_u[i]=(raydium_vertex_z[i]-z1)/zdiff;
+     raydium_vertex_texture_v[i]=(raydium_vertex_y[i]-y1)/ydiff;
+     }
+else
+     {
+     raydium_vertex_texture_u[i]=(raydium_vertex_x[i]-x1)/xdiff;
+     raydium_vertex_texture_v[i]=(raydium_vertex_z[i]-z1)/zdiff;
+     }
+   
+
+}
+
+
+void contour_circle(GLfloat ray,GLuint subdiv)
+{
+GLfloat inc=360.0/(float)subdiv;
+GLfloat x,y,z;
+GLfloat mx,my,mz;
+GLfloat i;
+
+screen_to_local(&mx,&my,&mz,VIEW_XY);
+
+for(i=0;i<360;i+=inc)
+{
+x=xcos(i)*ray+round(mx);
+y=xsin(i)*ray+round(my);
+z=pz;
+screen_to_VIEW(x,y,z,&x,&y,&z);
+contour_x[contour_index]=x;
+contour_y[contour_index]=y;
+contour_z[contour_index]=z;
+contour_index++;
+}
+
+
+}
+
+
+void generate_contour_between(GLuint a, GLuint b, char type)
+{
+GLfloat ax,ay,az;
+GLfloat bx,by,bz;
+GLfloat lx,ly,lz;
+
+
+ax=contour_x[a];
+ay=contour_y[a];
+az=contour_z[a];
+
+bx=contour_x[b];
+by=contour_y[b];
+bz=contour_z[b];
+
+if(type==CONTOUR_EXTRUDE)
+{
+ if(modl_view==VIEW_XY)
+ {
+ raydium_vertex_add(ax,ay,az);
+ raydium_vertex_add(ax,ay,pz);
+ raydium_vertex_add(bx,by,bz);
+
+ raydium_vertex_add(bx,by,bz);
+ raydium_vertex_add(ax,ay,pz);
+ raydium_vertex_add(bx,by,pz);
+ }
+
+ if(modl_view==VIEW_ZY)
+ {
+ raydium_vertex_add(ax,ay,az);
+ raydium_vertex_add(pz,ay,az);
+ raydium_vertex_add(bx,by,bz);
+
+ raydium_vertex_add(bx,by,bz);
+ raydium_vertex_add(pz,ay,az);
+ raydium_vertex_add(pz,by,bz);
+ }
+
+ if(modl_view==VIEW_XZ)
+ {
+ raydium_vertex_add(ax,ay,az);
+ raydium_vertex_add(ax,pz,az);
+ raydium_vertex_add(bx,by,bz);
+
+ raydium_vertex_add(bx,by,bz);
+ raydium_vertex_add(ax,pz,az);
+ raydium_vertex_add(bx,pz,bz);
+ }
+}
+
+if(type==CONTOUR_GATHER)
+{
+ screen_to_local(&lx,&ly,&lz,modl_view);
+ raydium_vertex_add(ax,ay,az);
+ raydium_vertex_add(lx,ly,lz);
+ raydium_vertex_add(bx,by,bz);
+}
+
+
+}
+
+void generate_contour(char type)
+{
+GLuint i;
+
+if(!contour_index)
+{ printf("No contour to extrude. Aborting.\n"); return; }
+
+for(i=0;i<contour_index-1;i++)
+generate_contour_between(i,i+1,type);
+
+generate_contour_between(contour_index-1,0,type);
+
+
+contour_index=0;
+}
+
+
+void resize(float xfact,float yfact,float zfact)
+{
+int i;
+
+screen_to_VIEW(xfact,yfact,zfact,&xfact,&yfact,&zfact);
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+raydium_vertex_x[i]*=xfact;
+raydium_vertex_y[i]*=yfact;
+raydium_vertex_z[i]*=zfact;
+}
+
+}
+
+void mirror(void)
+{
+int i;
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+//raydium_vertex_x[i]*=fact;
+//raydium_vertex_y[i]*=fact;
+raydium_vertex_z[i]*=-1;
+}
+
+}
+
+void rotatez(GLfloat angle)
+{
+int i;
+GLfloat x,y;
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+x=raydium_vertex_x[i];
+y=raydium_vertex_y[i];
+
+raydium_vertex_x[i]=x*raydium_trigo_cos(angle) - y*raydium_trigo_sin(angle);
+raydium_vertex_y[i]=x*raydium_trigo_sin(angle) + y*raydium_trigo_cos(angle);
+//raydium_vertex_z[i]*=-1;
+}
+
+}
+
+
+void rotatey(GLfloat angle)
+{
+int i;
+GLfloat x,z;
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+x=raydium_vertex_x[i];
+z=raydium_vertex_z[i];
+
+raydium_vertex_x[i]=x*raydium_trigo_cos(angle) - z*raydium_trigo_sin(angle);
+raydium_vertex_z[i]=x*raydium_trigo_sin(angle) + z*raydium_trigo_cos(angle);
+//raydium_vertex_z[i]*=-1;
+}
+
+}
+
+void rotatex(GLfloat angle)
+{
+int i;
+GLfloat y,z;
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+y=raydium_vertex_y[i];
+z=raydium_vertex_z[i];
+
+raydium_vertex_y[i]=y*raydium_trigo_cos(angle) - z*raydium_trigo_sin(angle);
+raydium_vertex_z[i]=y*raydium_trigo_sin(angle) + z*raydium_trigo_cos(angle);
+//raydium_vertex_z[i]*=-1;
+}
+
+}
+
+
+void size_n(int n, GLfloat *min, GLfloat *max)
+{
+int i;
+GLfloat *tbl;
+
+if(!raydium_vertex_index) return;
+
+switch(n)
+{
+    case 0:
+	tbl=raydium_vertex_x;
+	break;
+    case 1:
+	tbl=raydium_vertex_y;
+	break;
+    case 2:
+	tbl=raydium_vertex_z;
+	break;
+}
+(*max)=(*min)=tbl[0];
+
+for(i=1;i<raydium_vertex_index;i++)
+{
+if(tbl[i]>(*max)) (*max)=tbl[i];
+if(tbl[i]<(*min)) (*min)=tbl[i];
+}
+
+}
+
+void size(void)
+{
+int i;
+GLfloat min,max;
+
+size_n(0,&min,&max);
+printf("%f < x < %f, diff= %f\n",min,max,raydium_trigo_abs(max-min));
+size_n(1,&min,&max);
+printf("%f < y < %f, diff= %f\n",min,max,raydium_trigo_abs(max-min));
+size_n(2,&min,&max);
+printf("%f < z < %f, diff= %f\n",min,max,raydium_trigo_abs(max-min));
+}
+
+
+void move(void)
+{
+int i;
+GLfloat mx,my,mz;
+
+screen_to_local(&mx,&my,&mz,modl_view);
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+raydium_vertex_x[i]+=round(mx);
+raydium_vertex_y[i]+=round(my);
+raydium_vertex_z[i]+=round(mz);
+}
+}
+
+void move_by(GLfloat x, GLfloat y, GLfloat z)
+{
+int i;
+for(i=0;i<raydium_vertex_index;i++)
+{
+raydium_vertex_x[i]+=x;
+raydium_vertex_y[i]+=y;
+raydium_vertex_z[i]+=z;
+}
+
+}
+/*
+void generate_contour_to_point(void)
+{
+
+GLuint i;
+
+if(!contour_index)
+{ printf("No contour to extrude. Aborting.\n"); return; }
+
+
+for(i=0;i<contour_index-1;i++)
+{
+printf("contour: %f %f %f\n",contour_x[i],contour_y[i],contour_z[i]);
+generate_contour_between(i,i+1);
+}
+
+
+}
+*/
+
+
+void modl_exit(void)
+{
+printf("Exit order received !\nI must go out :)\n");
+//raydium_internal_dump();
+exit(0);
+}
+
+
+void modl_help(void)
+{
+printf("Raydium Modler - CQFD Corp.\n");
+printf("---------------------------\n");
+printf("Usage: /command arguments");
+printf("help: this screen\n");
+printf("quit: exit\n");
+printf("key-below-esc: gives prompt\n");
+printf("F5 - F6 keys: previous - next texture\n");
+printf("z (a): sets current depth to a value (you can use PGUP/PGDOWN or mouse wheel)\n");
+printf("axe[s] [on|off]: enable/disable axes\n");
+printf("wire [on|off]: enable/disable wireframe rendering\n");
+printf("grid [on|off]: enable/disable grid drawing\n");
+printf("tex[ture] [on|off]: enable/disable OS texture preview\n");
+printf("contour: extrude current profile (made with middle mouse button)\n");
+printf("contour [circle (ray) [sub]|gather|reset]: see doc\n");
+printf("bind [erase] (file.tga): loads [or erase current texture whith] file.tga\n");
+printf("load (file.tri): loads from .tri file\n");
+printf("save (file.tri): saves to .tri file\n");
+printf("saveup (file.tri): saves to .tri file and upload to repository\n");
+printf("saveupall (file.tri): saves to .tri file and uploads to repository with dependencies\n");
+printf("upload (file): uploads file to repository\n");
+printf("uploadall (file): uploads file to repository with dependencies\n");
+printf("savea (file.tri): saves to .tri file, sorting alpha textures at the end of file\n");
+printf("move: move object by cursor position\n");
+printf("move x y z: move object by x, y and z\n");
+printf("rotate(x|y|z) angle: rotate object on x, y or z of angle\n");
+printf("resize [a | (x y z)] resize all by a or by x,y,z (scale factor)\n");
+printf("line [n]: change/reset line size\n");
+printf("mirror: mirror object\n");
+printf("size: return object sizes\n");
+printf("cam (cam.cam) draw cam path file\n");
+}
+
+
+void draw_texture(void)
+{
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current);
+//glColor4f(1.f,1.f,1.f,1.f);
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+glBegin(GL_QUADS);
+glTexCoord2f(0,1);
+glVertex3f(-modl_zoom,modl_zoom,0);
+glTexCoord2f(0,0);
+glVertex3f(-modl_zoom,modl_zoom-1,0);
+glTexCoord2f(1,0);
+glVertex3f(-modl_zoom+1,modl_zoom-1,0);
+glTexCoord2f(1,1);
+glVertex3f(-modl_zoom+1,modl_zoom,0);
+glEnd();
+raydium_rendering_internal_restore_render_state();
+}
+
+void draw_axes(void)
+{
+GLfloat size=modl_zoom/3;
+GLfloat font=modl_zoom/30;
+
+glBegin(GL_LINES);
+
+glVertex3f(0,0,0);
+glVertex3f(size,0,0);
+glVertex3f(size+font,-font,0);
+glVertex3f(size+font+font,font,0);
+glVertex3f(size+font,font,0);
+glVertex3f(size+font+font,-font,0);
+
+glVertex3f(0,0,0);
+glVertex3f(0,size,0);
+glVertex3f(0,size+font+(font/2),0);
+glVertex3f(0,size+font,0);
+glVertex3f(0,size+font+(font/2),0);
+glVertex3f(-font/2,size+font+font+(font/2),0);
+glVertex3f(0,size+font+(font/2),0);
+glVertex3f(font/2,size+font+font+(font/2),0);
+
+glVertex3f(0,0,0);
+glVertex3f(0,0,size);
+glVertex3f(0,font,size+font-(font/2));
+glVertex3f(0,font,size+font+(font/2));
+glVertex3f(0,-font,size+font-(font/2));
+glVertex3f(0,-font,size+font+(font/2));
+glVertex3f(0,font,size+font-(font/2));
+glVertex3f(0,-font,size+font+(font/2));
+
+
+glEnd();
+
+}
+
+
+void draw_grid(void)
+{
+GLfloat x;
+GLfloat y;
+GLfloat z;
+
+
+
+glBegin(GL_POINTS);
+for(x=-modl_zoom;x<=modl_zoom;x++)
+for(y=-modl_zoom;y<=modl_zoom;y++)
+for(z=-modl_zoom;z<=modl_zoom;z++)
+ {
+  if( (modl_view==VIEW_XY && z==pz) ||
+      (modl_view==VIEW_XZ && y==pz) ||
+      (modl_view==VIEW_ZY && x==pz) ) glColor3f(1,0,0); else glColor3f(0.5,0.5,0.5);
+ glVertex3f(x,y,z);
+ }
+
+glColor3f(0.7,0.7,0.7);
+//glColor3f(0.0,0.0,0.0);
+glEnd();
+}
+
+
+int cutcut(char *entry)
+{
+int i,j,n;
+
+for(i=0,j=0,n=0;i<=strlen(entry);i++)
+{
+if(entry[i]==' ' || entry[i]==0) { arg[n][j]=0; j=0; if(n<16) n++; }
+else arg[n][j++]=entry[i];
+}
+if(arg[0][0])
+return n; else return 0;
+}
+
+void prompt(char *entry)
+{
+int argc,i;
+
+//entry[strlen(entry)-1]=0;
+argc=cutcut(entry);
+if(!argc) return;
+
+
+if(!strcmp(arg[0],"quit")) modl_exit();
+if(!strcmp(arg[0],"help")) modl_help();
+/*
+if(!strcmp(arg[0],"map") && argc>=2)
+    if(!strcmp(arg[1],"u") && argc>=4) map_u(atof(arg[2]),atof(arg[3]));
+    else if(!strcmp(arg[1],"v") && argc>=4) map_v(atof(arg[2]),atof(arg[3]));
+*/    
+if(!strcmp(arg[0],"contour") && argc==1) generate_contour(CONTOUR_EXTRUDE);
+if(!strcmp(arg[0],"contour") && argc>=2)
+      if(!strcmp(arg[1],"gather")) generate_contour(CONTOUR_GATHER);
+if(!strcmp(arg[0],"contour") && argc>=2)
+      if(!strcmp(arg[1],"reset")) contour_index=0;
+if(!strcmp(arg[0],"contour") && argc>=2)
+      if(!strcmp(arg[1],"circle") && argc>=3)
+      {
+      if(argc==3) contour_circle(atof(arg[2]),defSUBDIV);
+      if(argc==4) contour_circle(atof(arg[2]),atof(arg[3]));
+      }
+if(!strcmp(arg[0],"light"))
+      if(argc>=2 && !strcmp(arg[1],"on")) modl_light=1; else modl_light=0;
+if(!strcmp(arg[0],"wire"))
+      if(argc>=2 && !strcmp(arg[1],"on")) modl_wire=1; else modl_wire=0;
+if(!strcmp(arg[0],"grid"))
+      if(argc>=2 && !strcmp(arg[1],"off")) modl_grid=0; else modl_grid=1;
+if(!strcmp(arg[0],"axe") || !strcmp(arg[0],"axes"))
+      if(argc>=2 && !strcmp(arg[1],"off")) modl_axes=0; else modl_axes=1;
+if(!strcmp(arg[0],"texture") || !strcmp(arg[0],"tex"))
+      if(argc>=2 && !strcmp(arg[1],"off")) modl_tex=0; else modl_tex=1;
+if(!strcmp(arg[0],"z") && argc==2) pz=atof(arg[1]);
+if(!strcmp(arg[0],"resize") && argc==2) resize(atof(arg[1]),atof(arg[1]),atof(arg[1]));
+if(!strcmp(arg[0],"resize") && argc==4) resize(atof(arg[1]),atof(arg[2]),atof(arg[3]));
+if(!strcmp(arg[0],"move") && argc==1) move();
+if(!strcmp(arg[0],"move") && argc==4) move_by(atof(arg[1]),atof(arg[2]),atof(arg[3]));
+if(!strcmp(arg[0],"size")) size();
+if(!strcmp(arg[0],"rotatex") && argc==2) rotatex(atof(arg[1]));
+if(!strcmp(arg[0],"rotatez") && argc==2) rotatez(atof(arg[1]));
+if(!strcmp(arg[0],"rotatey") && argc==2) rotatey(atof(arg[1]));
+if(!strcmp(arg[0],"mirror")) mirror();
+if(!strcmp(arg[0],"line")  && argc==1) glLineWidth(1.0);
+if(!strcmp(arg[0],"line")  && argc==2) glLineWidth(atof(arg[1]));
+if(!strcmp(arg[0],"save")  && argc==2) dump_vertex_to(arg[1]);
+if(!strcmp(arg[0],"saveup")&& argc==2) { dump_vertex_to(arg[1]); raydium_rayphp_repository_file_put(arg[1],0); }
+if(!strcmp(arg[0],"saveupall")&& argc==2) { dump_vertex_to(arg[1]); raydium_rayphp_repository_file_put(arg[1],1); }
+if(!strcmp(arg[0],"upload")&& argc==2) raydium_rayphp_repository_file_put(arg[1],0);
+if(!strcmp(arg[0],"uploadall")&& argc==2) raydium_rayphp_repository_file_put(arg[1],1);
+if(!strcmp(arg[0],"savea") && argc==2) dump_vertex_to_alpha(arg[1]);
+if(!strcmp(arg[0],"load")  && argc==2) read_vertex_from(arg[1]);
+if(!strcmp(arg[0],"bind")  && argc==2) raydium_texture_load(arg[1]); 
+if(!strcmp(arg[0],"bind")  && argc==3 && !strcmp(arg[1],"erase")) raydium_texture_load_erase(arg[2],raydium_texture_current); 
+if(!strcmp(arg[0],"cam") && argc==2) strcpy(cam_file,arg[1]);
+}
+
+
+
+void mouse_n_keys_event(void)
+{
+GLfloat rotx,roty;
+GLfloat x,y,z;
+if(raydium_key_last==1032) { map_uv(-modl_zoom,modl_zoom,-modl_zoom,modl_zoom,-modl_zoom,modl_zoom); }
+if(raydium_key_last==1045)  modl_zoom--;
+if(raydium_key_last==1043)  modl_zoom++;
+if(raydium_key_last==1027)  modl_exit();
+/*if(raydium_key_last==1)*/  
+//prompt();
+if(raydium_key_last==108) modl_view=VIEW_XY;
+if(raydium_key_last==106) modl_view=VIEW_ZY;
+if(raydium_key_last==1127) modl_view=VIEW_XZ;
+if(raydium_key_last==104) pz++;
+if(raydium_key_last==105) pz--;
+if(raydium_key_last==5 && raydium_texture_current>1) raydium_texture_current--;
+if(raydium_key_last==6 && raydium_texture_current<raydium_texture_index-1) raydium_texture_current++;
+if(raydium_key_last==1008 && raydium_vertex_index>=3) raydium_vertex_index-=3;
+if(raydium_key_last==8) raydium_normal_smooth_all();
+if(raydium_key_last==9) raydium_normal_regenerate_all();
+if(raydium_key_last==10) raydium_normal_restore_all();
+
+if(raydium_mouse_button[0]) 
+{
+rotx=((float)raydium_mouse_x-((float)raydium_window_tx/(float)2)) * ((float)360/(float)raydium_window_tx);
+roty=((float)raydium_mouse_y-((float)raydium_window_ty/(float)2)) * ((float)360/(float)raydium_window_ty);
+ if(modl_view==VIEW_XY)
+ {
+ glRotatef(roty,1,0,0);
+ glRotatef(rotx,0,1,0);
+ }
+ 
+ if(modl_view==VIEW_ZY)
+ {
+ glRotatef(roty,0,0,1);
+ glRotatef(rotx,0,1,0);
+ }
+
+ if(modl_view==VIEW_XZ)
+ {
+ glRotatef(roty,1,0,0);
+ glRotatef(rotx,0,0,1);
+ }
+
+//printf("-- %f %f %i\n",(raydium_mouse_x-(window_tx/2)),(window_tx/2),raydium_mouse_x);
+//printf("%i %i\n",raydium_mouse_x,mousey);
+}
+
+
+if(raydium_mouse_click==2)
+{
+screen_to_local(&x,&y,&z,modl_view);
+printf("vertex add at round(%f,%f,%f)\n",x,y,z);
+raydium_vertex_add(round(x),round(y),round(z));
+}
+
+if(raydium_mouse_click==3)
+{
+screen_to_local(&x,&y,&z,modl_view);
+printf("contour(%i) add at round(%f,%f,%f)\n",contour_index,x,y,z);
+contour_x[contour_index]=round(x);
+contour_y[contour_index]=round(y);
+contour_z[contour_index++]=round(z);
+}
+
+
+if(modl_zoom<1) modl_zoom=1;
+}
+
+
+
+void draw_contour(void)
+{
+GLuint i;
+
+glColor3f(0,1,0);
+glBegin(GL_LINE_LOOP);
+for(i=0;i<contour_index;i++)
+glVertex3f(contour_x[i],contour_y[i],contour_z[i]);
+
+glEnd();
+glColor3f(1,1,1);
+
+}
+
+
+void update_vars(void)
+{
+raydium_projection=RAYDIUM_PROJECTION_ORTHO;
+raydium_projection_near=-modl_zoom;
+raydium_projection_far=modl_zoom;
+raydium_projection_left=-modl_zoom;
+raydium_projection_right=modl_zoom;
+raydium_projection_bottom=-modl_zoom;
+raydium_projection_top=modl_zoom;
+raydium_window_resize_callback(raydium_window_tx,raydium_window_ty);
+//glutWarpPointer(0,0);
+}
+
+void light_update(void)
+{
+GLfloat lx,ly,lz;
+screen_to_local(&lx,&ly,&lz,modl_view);
+raydium_light_position[0][0]=lx;
+raydium_light_position[0][1]=ly;
+raydium_light_position[0][2]=lz;
+raydium_light_update_position(0);
+}
+
+
+
+void display(void)
+{
+raydium_clear_frame();
+
+glLoadIdentity();
+update_vars();
+light_update();
+
+if(modl_tex) draw_texture();
+if(modl_view==VIEW_ZY) glRotatef(90,0,1,0);
+if(modl_view==VIEW_XZ) glRotatef(-90,1,0,0);
+
+mouse_n_keys_event();
+//glRotatef(90,0,1,0);
+
+glDisable(GL_TEXTURE_2D);
+if(modl_grid) draw_grid();
+if(modl_axes) draw_axes();
+glColor3f(1.0,1.0,1.0);
+draw_contour();
+glEnable(GL_TEXTURE_2D);
+
+//glutSolidTeapot(1);
+if(modl_light) raydium_light_enable();
+if(modl_wire) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); }
+else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+//glEdgeFlag(GL_TRUE);
+raydium_rendering();
+
+if(cam_file[0]!=0)
+    raydium_camera_path_draw_name(cam_file);
+
+raydium_rendering_finish();
+raydium_light_disable();
+}
+
+
+
+int main(int argc, char **argv)
+{
+char window[256]="CQFD Corp. Raydium Modler";
+sprintf(window,"%s - %s",window,version);
+
+cam_file[0]=0;
+
+raydium_init_args(argc,argv);
+raydium_window_create(600,600,RAYDIUM_RENDERING_WINDOW,window);
+raydium_background_color_change(0,0,0,1);
+raydium_console_gets_callback=prompt;
+
+raydium_mouse_show();
+raydium_texture_filter=RAYDIUM_TEXTURE_FILTER_TRILINEAR;
+//raydium_texture_current=1;
+
+raydium_light_on(0);
+printf("Tip: Press key-below-esc to get prompt.\n");
+raydium_callback(&display);
+return(0);
+}
Index: train.c
===================================================================
--- train.c	(revision 0)
+++ train.c	(revision 1)
@@ -0,0 +1,134 @@
+#include "raydium/index.c"
+
+GLfloat cam_angle_x = 0;
+GLfloat cam_angle_y = 90;
+
+GLfloat cam_pos_x = 0;
+GLfloat cam_pos_y = 0;
+GLfloat cam_pos_z = 0;
+
+GLfloat speed = 0.1;
+GLint sensibilite = 3;
+
+GLint lacet = 0;
+float force=0;
+
+GLfloat light_color[] = {1.0, 0.9, 0.8, 1.0};
+
+
+void display(void)
+{
+    
+int delta_x, delta_y;
+// Touches
+raydium_joy_key_emul();
+
+cam_pos_z += (raydium_trigo_sin(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+cam_pos_x += (raydium_trigo_cos(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+cam_pos_y += (raydium_trigo_cos(90-cam_angle_y)*speed*raydium_joy_y);
+
+cam_pos_x -= (raydium_trigo_cos(cam_angle_x)*raydium_joy_x*speed);
+cam_pos_z -= (raydium_trigo_sin(cam_angle_x)*raydium_joy_x*speed);
+    
+if(raydium_key_last==1027)
+    exit(0);
+
+{
+float speed=0;
+if(raydium_key[GLUT_KEY_HOME]) speed=force;
+if(raydium_key[GLUT_KEY_END]) speed=-force;
+raydium_ode_motor_speed_name("train_moteur",speed);
+}
+
+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);
+
+
+if(raydium_key_last==1032)
+    {
+//    raydium_particle_generator_load("smoke.prt","smoke");
+//    raydium_particle_generator_load("clouds.prt","clouds");
+//    raydium_particle_generator_load("test.prt","durt_smoke");
+//    raydium_particle_generator_load("fountain.prt","fountain");
+//    raydium_particle_generator_load("explosion.prt","explo");
+//    raydium_particle_generator_load("explosmoke.prt","explo_smoke");
+    
+//    raydium_particle_generator_move_name_3f("explo",1,0,0);
+    raydium_php_exec("train.php");
+    }
+
+    
+delta_x = raydium_mouse_x - (raydium_window_tx/2);
+cam_angle_x += (delta_x*sensibilite*0.1f); 
+delta_y = raydium_mouse_y - (raydium_window_ty/2);
+cam_angle_y += (delta_y*sensibilite*0.1f); 
+
+raydium_mouse_move(raydium_window_tx/2, raydium_window_ty/2);
+    
+
+raydium_light_position[0][0]=100;
+raydium_light_position[0][1]=100;
+raydium_light_position[0][2]=100;
+raydium_light_position[0][3]=1.0;
+raydium_light_update_position(0); 
+
+raydium_background_color_change(light_color[0],light_color[1],light_color[2],light_color[3]);
+
+    
+raydium_clear_frame();
+
+raydium_camera_place(cam_pos_x,cam_pos_y,cam_pos_z,cam_angle_x,cam_angle_y,0);
+//raydium_ode_element_camera_inboard_name("train_train",0,1,0,-3,0,-0.5);
+//raydium_ode_element_camera_inboard_name("train_train",0,0.3,-0.3,-3,0,-0.5);
+raydium_camera_replace();
+raydium_object_draw_name("rail_world_background.tri");
+    
+raydium_ode_draw_all(0);
+if(raydium_key[GLUT_KEY_F1])
+    raydium_ode_draw_all(1);
+
+raydium_osd_logo("logo.tga");
+    
+raydium_rendering_finish();
+}
+
+
+
+
+int main(int argc, char **argv)
+{
+    raydium_init_args(argc,argv);
+    
+    raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"train's test");
+    raydium_texture_filter=RAYDIUM_TEXTURE_FILTER_TRILINEAR;
+    raydium_projection_near=0.01;
+    raydium_projection_far=2500;
+    raydium_projection_fov=60;
+    raydium_fog_disable();
+    raydium_window_view_update();
+    
+//    raydium_light_disable();
+    raydium_light_on(0);
+    memcpy(raydium_light_color[0],light_color,raydium_internal_size_vector_float_4);
+    raydium_light_intensity[0] = 1000000;
+    raydium_light_update_all(0);
+    
+//    raydium_osd_cursor_set("BOXcursor.tga",4,4);
+
+    raydium_window_view_update();
+
+    raydium_ode_ground_set_name("rail_world.tri");
+    raydium_register_variable(&force,RAYDIUM_REGISTER_FLOAT,"force");
+
+    // preload tri files and textures
+    raydium_object_find_load("train1.tri");
+    raydium_object_find_load("train_bw.tri");
+    raydium_object_find_load("wagon.tri");
+    raydium_object_find_load("train_a.tri");
+    raydium_php_exec("train.php");
+
+    raydium_callback(&display);
+    return(0);
+}
+// EOF
Index: willt5.c
===================================================================
--- willt5.c	(revision 0)
+++ willt5.c	(revision 1)
@@ -0,0 +1,107 @@
+#include "raydium/index.c"
+
+GLfloat cam_angle_x = 0;
+GLfloat cam_angle_y = 90;
+
+GLfloat cam_pos_x = 0;
+GLfloat cam_pos_y = 0;
+GLfloat cam_pos_z = 0;
+
+GLfloat speed = 0.1;
+GLint sensibilite = 3;
+
+GLint lacet = 0;
+
+GLfloat light_color[] = {1.0, 0.9, 0.8, 1.0};
+
+char draw_debug=1;
+
+void display(void)
+{
+    
+    int delta_x, delta_y;
+    raydium_joy_key_emul();
+
+    cam_pos_z += (raydium_trigo_sin(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+    cam_pos_x += (raydium_trigo_cos(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+    cam_pos_y += (raydium_trigo_cos(90-cam_angle_y)*speed*raydium_joy_y);
+    
+    cam_pos_x -= (raydium_trigo_cos(cam_angle_x)*raydium_joy_x*speed);
+    cam_pos_z -= (raydium_trigo_sin(cam_angle_x)*raydium_joy_x*speed);
+    
+    if(raydium_key_last==1027)
+	exit(0);
+
+    if(raydium_key_last==1032)
+	raydium_php_exec("test.php");
+
+    if(raydium_key_last==1116) draw_debug*=-1;
+    
+    delta_x = raydium_mouse_x - (raydium_window_tx/2);
+    cam_angle_x += (delta_x*sensibilite*0.1f); 
+
+    delta_y = raydium_mouse_y - (raydium_window_ty/2);
+    cam_angle_y += (delta_y*sensibilite*0.1f); 
+
+    raydium_mouse_move(raydium_window_tx/2, raydium_window_ty/2);
+    
+    raydium_light_position[0][0]=100;
+    raydium_light_position[0][1]=100;
+    raydium_light_position[0][2]=100;
+    raydium_light_position[0][3]=1.0;
+
+    raydium_background_color_change(light_color[0],light_color[1],light_color[2],light_color[3]);
+
+    
+    raydium_clear_frame();
+    raydium_camera_place(cam_pos_x,cam_pos_y,cam_pos_z,cam_angle_x,cam_angle_y,0);
+
+    raydium_camera_replace();
+    
+    raydium_ode_draw_all(0);
+    if(draw_debug>0)
+       raydium_ode_draw_all(1);
+
+    raydium_osd_logo("logo.tga");
+    
+    raydium_rendering_finish();
+    raydium_ode_network_element_send_iterative(5);
+}
+
+
+
+
+int main(int argc, char **argv)
+{
+    char server[128];
+    raydium_init_args(argc,argv);
+    
+    raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Test 5 network viewer");
+    raydium_texture_filter=RAYDIUM_TEXTURE_FILTER_TRILINEAR;
+    raydium_projection_near=0.01;
+    raydium_projection_far=2500;
+    raydium_projection_fov=60;
+    raydium_fog_disable();
+    raydium_window_view_update();
+    
+    raydium_light_on(0);
+    memcpy(raydium_light_color[0],light_color,raydium_internal_size_vector_float_4);
+    raydium_light_intensity[0] = 1000000;
+    raydium_light_update_all(0);
+    
+//    raydium_osd_cursor_set("BOXcursor.tga",4,4);
+
+    raydium_window_view_update();
+
+if(raydium_init_cli_option("server",server))
+     if(!raydium_network_client_connect_to(server)) 
+        exit(1);
+
+    raydium_ode_ground_set_name("a.tri");
+    raydium_ode_object_box_add("boite",0,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"crate.tri");
+    raydium_ode_element_move_name_3f("boite",10,10,10);
+
+    raydium_callback(&display);
+    return(0);
+}
+// EOF
Index: score.php
===================================================================
--- score.php	(revision 0)
+++ score.php	(revision 1)
@@ -0,0 +1,23 @@
+<?
+// this file is used by NewSkyDiver to upload
+// scores to CQFD Corp website.
+// See how it's easy to cheat ? ... No interest then ;)
+
+// $wind / $breaked_bones / $fly_time / $touching_steps / $score / $version / $name
+
+//die("score upload disabled in score.php !");
+
+$nameE=rawurlencode($name);
+$versionE=rawurlencode($version);
+
+$url="http://skydiver.cqfd-corp.org/score/?wind=$wind&breaked_bones=$breaked_bones&fly_time=$fly_time&touching_steps=$touching_steps&score=$score&name=$nameE&version=$versionE";
+$res=file($url);
+
+if($res[0]=="OK")
+    {
+    echo "Score successfuly posted to NewSkyDiver website";
+    echo "Visit http://skydiver.cqfd-corp.org/ to compare ;)";
+    }
+else raydium_log("^cScore posting failed ...."); // echo == raydium_log
+
+?>
\ No newline at end of file
Index: odyncomp.sh
===================================================================
--- odyncomp.sh	(revision 0)
+++ odyncomp.sh	(revision 1)
@@ -0,0 +1,7 @@
+ulimit -c 0
+make
+rm test
+gcc $1 -g -Wall -DFORCE_LIBRAYDIUM -o test libraydium.so -Iphp/ -Iphp/main/ -Iphp/Zend -Iphp/TSRM -Iode/include/
+sync
+export LD_LIBRARY_PATH=.
+./test $2 $3 $4 $5 $6

Property changes on: odyncomp.sh
___________________________________________________________________
Added: svn:executable
\ No newline at end of property
Index: train.php
===================================================================
--- train.php	(revision 0)
+++ train.php	(revision 1)
@@ -0,0 +1,86 @@
+<?
+
+function set_bog_slip($element)
+{
+raydium_ode_element_slip_name($element,10000);
+}
+
+function create_train()
+{
+$a=raydium_ode_object_create("TRAIN");
+
+// test if creation failed:
+if($a<0) return -1;
+
+
+raydium_ode_object_box_add("train_train",$a,1.5,-1,0,0,RAYDIUM_ODE_STANDARD,0,"train1.tri");
+
+raydium_ode_object_box_add("train_bog1",$a,0.5, 0.8,0.27,0.27,RAYDIUM_ODE_STANDARD,0,"train_bw.tri");
+set_bog_slip("train_bog1");
+raydium_ode_element_move_name_3f("train_bog1",0.65,0,-0.3);
+raydium_ode_joint_attach_hinge_name("train_atta1","train_train","train_bog1",0.65,0,-0.3,0,0,1);
+
+raydium_ode_object_box_add("train_bog2",$a,0.5, 0.8,0.27,0.27,RAYDIUM_ODE_STANDARD,0,"train_bw.tri");
+set_bog_slip("train_bog2");
+raydium_ode_element_move_name_3f("train_bog2",-0.65,0,-0.3);
+raydium_ode_joint_attach_hinge_name("train_atta2","train_train","train_bog2",-0.65,0,-0.3,0,0,1);
+
+
+raydium_ode_motor_create("train_moteur",$a,RAYDIUM_ODE_MOTOR_ROCKET);
+raydium_ode_motor_rocket_set_name("train_moteur","train_bog2",0,0,0);
+raydium_ode_motor_rocket_orientation_name("train_moteur",0,-90,0);
+
+return $a;
+}
+
+function create_wagon($train,$x,$attach_to)
+{
+if($train<0) return -1;
+
+$px=$x*2.95;
+
+raydium_ode_object_box_add("train_wagon_$x",$train,1.5,-1,0,0,RAYDIUM_ODE_STANDARD,0,"wagon.tri");
+raydium_ode_element_move_name_3f("train_wagon_$x",$px,0,0.1);
+
+raydium_ode_object_box_add("train_wagon_{$x}_bog1",$train,0.5, 0.8,0.27,0.27,RAYDIUM_ODE_STANDARD,0,"train_bw.tri");
+set_bog_slip("train_wagon_{$x}_bog1");
+raydium_ode_element_move_name_3f("train_wagon_{$x}_bog1",$px-1,0,-0.3);
+raydium_ode_joint_attach_hinge_name("train_wagon_{$x}_atta1","train_wagon_$x","train_wagon_{$x}_bog1",$px-1,0,-0.3,0,0,1);
+
+raydium_ode_object_box_add("train_wagon_{$x}_bog2",$train,0.5, 0.8,0.27,0.27,RAYDIUM_ODE_STANDARD,0,"train_bw.tri");
+set_bog_slip("train_wagon_{$x}_bog2");
+raydium_ode_element_move_name_3f("train_wagon_{$x}_bog2",$px+1,0,-0.3);
+raydium_ode_joint_attach_hinge_name("train_wagon_{$x}_atta2","train_wagon_$x","train_wagon_{$x}_bog2",$px+1,0,-0.3,0,0,1);
+
+
+raydium_ode_object_box_add("train_wagon_{$x}_inter",$train,0.1,-1,0,0,RAYDIUM_ODE_STANDARD,0,"train_a.tri");
+raydium_ode_element_move_name_3f("train_wagon_{$x}_inter",$px-1.46,0,-0.2);
+
+raydium_ode_joint_attach_hinge_name("train_wagon_{$x}_inter1","train_wagon_$x","train_wagon_{$x}_inter",$px-1.46+0.15,0,-0.2,0,0,1);
+//raydium_ode_joint_hinge_limits_name("train_wagon_{$x}_inter1",-1,1);
+raydium_ode_joint_attach_hinge_name("train_wagon_{$x}_inter2",$attach_to,"train_wagon_{$x}_inter",$px-1.46-0.15,0,-0.2,0,0,1);
+//raydium_ode_joint_hinge_limits_name("train_wagon_{$x}_inter2",-1,1);
+//raydium_ode_joint_suspension_name("train_wagon_{$x}_inter",9,0);
+
+return "train_wagon_$x";
+}
+
+
+echo "deleting old train (if any)...";
+raydium_ode_object_delete_name("TRAIN");
+
+echo "train building...";
+$train=create_train();
+$previous="train_train";
+for($i=1;$i<=2;$i++)
+    {
+    $previous=create_wagon($train,$i,$previous);
+    }
+$force=0.1;
+
+echo "train Ok.";
+raydium_ode_object_move_name_3f("TRAIN",2,0,0.3);
+
+//raydium_ode_time_change(0);
+
+?>
Index: rayphp/repositories.list
===================================================================
--- rayphp/repositories.list	(revision 0)
+++ rayphp/repositories.list	(revision 1)
@@ -0,0 +1,10 @@
+# This file lists data (tri, tga, wav, ogg, ...) repositories.
+# Listed servers must run R3S (Raydium Server Side Scripts) files.
+
+# you can only use http and https protocols:
+# http://host.tld/path
+
+# main:
+http://repository.cqfd-corp.org/raydium/
+
+# we needs "contrib" servers
Index: rayphp/getfile.php
===================================================================
--- rayphp/getfile.php	(revision 0)
+++ rayphp/getfile.php	(revision 1)
@@ -0,0 +1,76 @@
+<?
+// gets file from repositories listed in repositories.list
+
+// params: $filename (string, input), $force (integer, input),
+// 	   $status (integer, output)
+
+// This script must be placed in "rayphp" sub-directory.
+
+require("libfile.php");
+
+function getfile($file,$repos,$local)
+{
+global $force;
+
+//echo "trying: $repos/$file : ";
+$file=rawurlencode($file);
+
+$req="$repos?file=$file&type=getDate";
+$d=@file($req);
+if($d!=false) $d=$d[0];
+
+$ld=@filemtime($local);
+
+if($ld>=$d && !$force && $d!=false && $ld!=false)
+    {
+    echo "Local file is the same or newer, abording. ($repos)";
+    return false;
+    }
+
+$req="$repos?file=$file&type=getGzip";
+$data=@file($req);
+if($data==false)
+    return false;
+
+if(substr($data[0],0,6)=="FAILED")
+    {
+    echo $data[0]." ($repos)";
+    return false;
+    }
+
+$data=implode("",$data);
+echo "Found at '$repos'";
+return $data;
+}
+
+$status=0; // sets status to "error", by default
+
+
+filename_cut($filename,$file,$path);
+
+echo "Using repositories to get '$file' file:";
+
+$repos=read_repositories_file("rayphp/repositories.list");
+
+for($i=0;$i<count($repos);$i++)
+  {
+  $r=trim($repos[$i]);
+    if(valid_entry($r))
+	if( ($data=getfile($file,$r,$path.$file)) )
+	    {
+	    $status=-1;
+	    break;
+	    }
+  }
+	
+if($status==0)
+    die("No valid repository found for this file, abording.");
+
+$data=gzdecode($data);
+$fp=@fopen($path.$file,"wb");
+if(!$fp)
+    die("Cannot create output file '$path$file', abording.");
+fwrite($fp,$data);
+fclose($fp);
+$status=1;
+?>
\ No newline at end of file
Index: rayphp/r3s/index.php
===================================================================
--- rayphp/r3s/index.php	(revision 0)
+++ rayphp/r3s/index.php	(revision 1)
@@ -0,0 +1,137 @@
+<?
+// Raydium Server Side repository script
+// name this file "index.php", and place data in $data_dir directory.
+require("config.inc.php");
+
+
+function decompress_file($gz,$final)
+{
+$fp=gzopen($gz,"r");
+if(!$fp) die("FAILED: Cannot open gz file");
+while(!gzeof($fp))
+    {
+    $data.=gzread($fp,128);
+    }
+gzclose($fp);
+
+$fp=fopen($final,"wb");
+if(!$fp)
+    {
+    echo "FAILED: Cannot create file '$final' on this server";
+    return false;
+    }
+fwrite($fp,$data);
+fclose($fp);
+unlink($gz);
+return true;
+}
+
+function home()
+{
+global $data_dir,$upload_accept,$QUERY_STRING;
+
+echo "<h2>R3S Raydium data repository</h2>\n";
+echo "<h3>Available files:</h3>\n";
+echo "<table border=0 cellpadding=2>";
+
+ if ($dh = opendir($data_dir)) 
+ {
+    while (($file = readdir($dh)) !== false) 
+    {
+	if($file[0]==".") continue;
+	$size=filesize($data_dir.$file);
+	$total_size+=$size;
+	echo "<tr><td><b> $file </b></td><td align=right>$size byte(s)</td><td>&nbsp;</td><td>".date("Y-m-d H:i:s",filemtime($data_dir.$file))."</td></tr>";
+    }
+  closedir($dh);
+ }
+echo "<tr><td>&nbsp;</td></tr>";
+echo "<tr><td><b>Total size</b></td><td align=right>".sprintf("%.2f",$total_size/1024/1024)." MB</td></tr";
+echo "</table><br>";
+echo "You can add this URL in your <i>rayphp/repositories.*</i> files.<br>";
+if($upload_accept) $up="supports"; else $up="does not supports";
+echo "This server $up data uploading.<br><br>";
+echo "Yes, we needs a CSS file ;)<br>";
+echo "Note: files are not sorted.<br>";
+}
+
+
+
+function main($file,$type,$username,$password,$data)
+{
+global $data_dir,$upload,$upload_accept,$brute_force_delay;
+global $HTTP_POST_FILES;
+
+if($type=="")
+    {
+    home();
+    return;
+    }
+
+if($file=="") return;
+$file=rawurldecode($file);
+$file=str_replace("/","",$file);
+$file=$data_dir.$file;
+
+if($type=="putGzip")
+{
+if(!$upload_accept)
+    {
+    echo "FAILED: Upload is not activated on this server !";
+    return;
+    }
+
+sleep($brute_force_delay);
+
+$username=rawurldecode($username);
+$password=rawurldecode($password);
+
+if($username!=$upload["user"] || $password!=$upload["pass"])
+    {
+    echo "FAILED: invalid user/pass ($username/$password)";
+    return;
+    }
+$filegz=$file.".tmp.gz";
+if(file_exists($HTTP_POST_FILES["data"]["tmp_name"]))
+ {
+ move_uploaded_file($HTTP_POST_FILES["data"]["tmp_name"], $filegz);
+ }
+else die("FAILED: Cannot find data in this request");
+
+if(!decompress_file($filegz,$file)) return;
+chmod($file,0664);
+
+echo "+ SUCCESS: file uploaded";
+return;
+}
+
+if(!file_exists($file)) die("FAILED: file not found");
+
+if($type=="getGzip")
+{
+$fp=fopen($file,"rb");
+if(!$fp) die("FAILED: file not found");
+$data=fread($fp,filesize($file));
+fclose($fp);
+
+$tmp=tempnam("./","delme");
+$fp=gzopen($tmp,"wb");
+if(!$fp) return;
+gzwrite($fp,$data);
+gzclose($fp);
+//$dat=gzencode($data);
+//echo $dat;
+//echo date("s");
+readfile($tmp);
+unlink($tmp);
+//echo $tmp;
+}
+
+if($type=="getDate")
+{
+echo filemtime($file);
+}
+} // end main()
+
+main($file,$type,$username,$password,$data);
+?>
\ No newline at end of file
Index: rayphp/r3s/README
===================================================================
--- rayphp/r3s/README	(revision 0)
+++ rayphp/r3s/README	(revision 1)
@@ -0,0 +1,23 @@
+R3S: Raydium Server Side Scripts
+--------------------------------
+
+With this files and a HTTP/PHP server, you can build very
+quickly a data repository server, allowing clients to get new files
+(and refresh old ones) from this server.
+Files are all stored in the same directory, since
+the client will rebuilt directory structure by itself.
+
+R3S support uploading, but you can also use a FTP server since Raydium
+client applications allows this.
+
+With R3S, FTP is slower than HTTP since no compression is used (R3S protocol
+is using gzip with HTTP) but is the only correct solution with big files, since
+most HTTP servers and proxies limits requests size.
+
+See configuration file, and place data in $data_dir directory.
+
+Please, note that Apache (or any other HTTP server) must have write rights
+in $data_dir directory:
+# chgrp apache files/
+# chown g+w files/
+(You may have to change "apache" to "httpd", "www-data" or something else).
Index: rayphp/r3s/config.inc.php
===================================================================
--- rayphp/r3s/config.inc.php	(revision 0)
+++ rayphp/r3s/config.inc.php	(revision 1)
@@ -0,0 +1,16 @@
+<?
+// Raydium Server Side repository Scripts (R3S) configuration file.
+
+// files directory:
+$data_dir="files/";
+
+# Upload params:
+# Note: You can also use an FTP server.
+$upload_accept=true;
+$upload["user"]="anonymous";
+$upload["pass"]="nopass";
+
+// Minimum delay (in seconds) for each upload request:
+$brute_force_delay=1;
+
+?>
\ No newline at end of file
Index: rayphp/libdeps.php
===================================================================
--- rayphp/libdeps.php	(revision 0)
+++ rayphp/libdeps.php	(revision 1)
@@ -0,0 +1,83 @@
+<?
+
+// supported files : (depends_xxx style)
+
+function depends_tri($filename)
+{
+//$f=@file($filename);
+$fp=fopen($filename,"rt");
+if($fp==false)
+    {
+    echo "Cannot open $filename";
+    }
+
+fgets($fp, 4096); // skip first line (version number)
+
+while (!feof($fp)) 
+    {
+    $line = trim(fgets($fp, 4096));
+    $line=explode(" ",$line);
+    $tex=trim($line[count($line)-1]);
+    if(substr($tex,0,4)!="rgb(")
+	{
+	$tex=trim($tex);
+	$texs=explode(";",$tex);
+	if(strlen($texs[0])) $ret[]=$texs[0];
+	if(strlen($texs[1])) 
+	    {
+	    if(strpos($texs[1],"|")!==false)
+		{
+		$lm=explode("|",$texs[1]);
+		$ret[]=$lm[2];
+		}
+	    else
+		$ret[]=$texs[1];
+	    }
+	$ret=array_values(array_unique($ret));
+	}
+    }
+fclose($fp);
+$ret[]=$filename;
+
+return $ret;
+}
+
+function depends_prt($filename)
+{
+$f=@file($filename);
+for($i=0;$i<count($f);$i++)
+    {
+    $line=trim($f[$i]);
+    if($line[0]=='/' && $line[1]=='/') continue;
+    
+    if(strpos($line,"texture") === false) continue;
+
+    echo $line;
+    $t=explode('=',$line);
+    $t=trim($t[1]);
+    $t=str_replace('"',"",$t);
+    $t=str_replace(';',"",$t);
+    $ret[]=$t;
+    }
+
+$ret[]=$filename;
+return $ret;
+}
+
+
+// -----------------------------------------------
+
+function depends_find($filename)
+{
+$tbl=explode(".",$filename);
+$ext=trim($tbl[count($tbl)-1]);
+if($ext=="tri") return depends_tri($filename);
+if($ext=="prt") return depends_prt($filename);
+
+// else ..
+$ret[]=$filename;
+return $ret;
+}
+
+
+?>
Index: rayphp/repositories.upload
===================================================================
--- rayphp/repositories.upload	(revision 0)
+++ rayphp/repositories.upload	(revision 1)
@@ -0,0 +1,12 @@
+# This file lists all repositories used for uploading:
+# You can use http/https URL (R3S servers) or ftp/ftps servers (classic FTP).
+
+# Only first valid server will be used in this list.
+# No test is done to see if your file is newer than server side one.
+# Warning ! Be carefull with "/" at the end of urls since Raydium client
+# do not supports redirections !
+
+http://anonymous:nopass@repository.cqfd-corp.org/raydium/
+ftp://raydium:none@ftp.cqfd-corp.org:29/
+#http://anonymous:nopass@localhost/raydium/repository/
+#http://anonymous:nopass@localhost/
Index: rayphp/libfile.php
===================================================================
--- rayphp/libfile.php	(revision 0)
+++ rayphp/libfile.php	(revision 1)
@@ -0,0 +1,49 @@
+<?
+
+function read_repositories_file($repos)
+{
+$ret=@file($repos);
+if(count($ret)==0)
+    die("Cannot open $repos");
+
+// may make $ret array "uniq"
+
+return $ret;
+}
+
+
+function filename_cut($filename,&$file,&$path)
+{
+$t=explode("/",$filename);
+$file=$t[count($t)-1];
+$t[count($t)-1]="";
+$path=implode("/",$t);
+}
+
+function valid_entry($r)
+{
+if($r[0]!='#' && strlen(trim($r))>0)
+    return true;
+return false;
+}
+
+function gzdecode($in)
+{
+$tmp="tmp.tmp";
+$fp=fopen($tmp,"wb");
+if(!$fp) return false;
+fwrite($fp,$in);
+fclose($fp);
+
+$fp=gzopen($tmp,"rb");
+if(!$fp) return false;
+while(!gzeof($fp))
+    {
+    $data.=gzread($fp,128);
+    }
+gzclose($fp);
+unlink($tmp);
+return $data;
+}
+
+?>
\ No newline at end of file
Index: rayphp/README
===================================================================
--- rayphp/README	(revision 0)
+++ rayphp/README	(revision 1)
@@ -0,0 +1,4 @@
+This directory contains client PHP scripts for Raydium.
+
+Some of the most interesting files of this directory are "repositories.*" ones,
+describing wich data servers are available for your applications data.
Index: rayphp/putfile.php
===================================================================
--- rayphp/putfile.php	(revision 0)
+++ rayphp/putfile.php	(revision 1)
@@ -0,0 +1,206 @@
+<?
+// gets file from repositories listed in repositories.list
+
+// params: $filename (string, input), $depends (integer, input)
+// 	   $status (integer, output)
+
+// This script must be placed in "rayphp" sub-directory.
+
+require("libfile.php");
+require("libdeps.php");
+
+$status=0; // sets status to "error", by default
+
+//$filename="buggy.tri"; // used when debugging outside of Raydium
+
+// I use a "static" value for now, may randomly generate it in the future ...
+$boundary="BREAKmessageHEREthisISaBOUNDARY";
+
+
+// search first data line in $packer (HTTP server answer)
+function http_search_data($packet,&$first)
+{
+$data_start=1;
+$packet=explode("\n",$packet);
+
+$first=trim($packet[0]);
+for($i=0;$i<count($packet);$i++)
+    if(trim($packet[$i])=="")
+	break;
+
+for($j=0;$j<$i;$j++)
+    if(trim($packet[$j]) == "Transfer-Encoding: chunked")
+	$data_start=2;
+
+return trim($packet[$i+$data_start]);
+}
+
+function http_make_part($name,$value,$binary=false)
+{
+global $boundary;
+
+if($binary)
+    $filename="; filename=\"data.bin\"";
+else $filename="";
+
+$ret ="--$boundary\r\n";
+$ret.="Content-Disposition: form-data; name=\"$name\"$filename\r\n";
+if($binary)
+$ret.="Content-Type: application/octet-stream\r\n";
+$ret.="\r\n";
+$ret.="$value";
+$ret.="\r\n";
+
+return $ret;
+}
+
+function ftp_upload($repos,$local,$distant)
+{
+/*
+$ret=@copy($local,"$repos/$distant");
+if($ret==false)
+    {
+    echo "Failed contacting $repos";
+    return false;
+    }
+echo "$repos: SUCCESS";
+return true;
+*/
+$url=parse_url($repos);
+
+$conn_id = ftp_connect($url["host"],$url["port"]);
+$login_result = ftp_login($conn_id, $url["user"], $url["pass"]);
+ftp_pasv($conn_id, true);
+//echo ".";
+if (ftp_put($conn_id,$url["path"].$distant, $local, FTP_ASCII))
+ {
+ echo "$repos: SUCCESS";
+ return true;
+ }
+else
+ {
+ echo "Failed contacting $repos";
+ return false;
+ }
+ftp_close($conn_id);
+}
+
+function http_upload($repos,$local,$distant)
+{
+global $boundary,$depends;
+$data=@file($local);
+$data=implode("",$data);
+$data=gzencode($data);
+
+$url=parse_url($repos);
+$distant=rawurlencode($distant);
+$user=rawurlencode($url["user"]);
+$pass=rawurlencode($url["pass"]);
+
+$path=$url["path"];
+if($url["port"]=="") $url["port"]=80;
+$req="POST $path HTTP/1.1\r\n";
+
+$fp = @fsockopen($url["host"],$url["port"]);
+if(!$fp) 
+    {
+    echo "Failed contacting $repos";
+    return false;
+    }
+$ret="";
+fputs($fp,$req);
+fputs($fp,"Host: ".$url["host"]."\r\n");
+fputs($fp,"User-Agent: Raydium PHP Upload Script\r\n");
+
+fputs($fp,"Content-Type: multipart/form-data; boundary=$boundary\r\n");
+
+$packet =http_make_part("file",$distant);
+$packet.=http_make_part("type","putGzip");
+$packet.=http_make_part("data",$data,true);
+$packet.=http_make_part("username",$user);
+$packet.=http_make_part("password",$pass);
+
+$packet.="--$boundary--\r\n";
+
+$len=strlen($packet);
+fputs($fp,"Content-Length: $len\r\n");
+fputs($fp,"Connection: Close\r\n");
+fputs($fp,"\r\n");
+fputs($fp,$packet);
+
+while(!feof($fp)) 
+    {
+    $ret.=fgets($fp,128);
+    }
+fclose($fp);
+
+$ret=http_search_data($ret,$first);
+echo "$repos: $ret";
+if($ret[0]=='+') return true;
+echo "HTTP reply: $first";
+return false;
+}
+
+
+$repos=read_repositories_file("rayphp/repositories.upload");
+
+if($depends)
+$deps=depends_find($filename);
+else $deps[]=$filename;
+
+for($j=0;$j<count($deps);$j++)
+{
+filename_cut($deps[$j],$file,$path);
+
+if(!file_exists($path.$file) || !is_readable($path.$file))
+    {
+    echo "Cannot upload '$path$file': file not exists or invalid rights";
+    continue;
+    }
+
+echo "Using repositories to upload '$file' file:";
+
+ for($i=0;$i<count($repos);$i++)
+  {
+  $r=trim($repos[$i]);
+    if(valid_entry($r))
+	{
+	// http or ftp ?
+	$type=parse_url($r);
+	$type=$type["scheme"];
+	
+	if(($type=="ftp" ||
+	    $type=="ftps" )
+	    && ftp_upload($r,$file.$path,$file))
+	    {
+	    touch($path.$file);
+	    $status++;
+	    break;
+	    }
+	
+	if(($type=="http" ||
+	    $type=="https" )
+	&& http_upload($r,$file.$path,$file))
+	    {
+	    touch($path.$file);
+	    $status++;
+	    break;
+	    }	
+	}
+  }
+}
+
+if($status==count($deps))
+    {
+    echo "All files uploaded ($status)";
+    return;
+    }    
+
+if($status==0)
+    {
+    echo "No file uploaded";
+    return;
+    }    
+
+echo "Only $status/".count($deps)." file(s) uploaded";
+?>
Index: dist/COPYING
===================================================================
--- dist/COPYING	(revision 0)
+++ dist/COPYING	(revision 1)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: dist/makedist.sh
===================================================================
--- dist/makedist.sh	(revision 0)
+++ dist/makedist.sh	(revision 1)
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+# This script will build a release archive of Raydium
+
+APPS="test6.c raydium_modler.c willou.c willt5.c train.c
+train.php skydiver.c score.php playlist.php cam.c tests.c
+Makefile configure
+comp.sh ocomp.sh ostatcomp.sh odyncomp.sh
+"
+
+DIRS="raydium rayphp"
+
+
+if [ ! -d "build" ]; then
+    echo "creating build directory"
+    mkdir build
+fi
+
+
+# create names
+file="raydium-`date +%Y-%m-%d`"
+directory="build/$file"
+
+if [ -d "$directory" ]; then
+    echo "$directory already exists !"
+    exit 1
+fi
+
+echo "creating $directory ..."
+mkdir "$directory"
+
+if [ "$?" != "0" ]; then
+    echo "error creating $directory"
+    exit 1
+fi
+
+# cleaning Raydium
+cd ..
+make clean_f
+cd -
+
+# copy app files
+for i in $APPS; do
+    echo "file $i"
+    cp "../$i" "$directory"
+done
+
+# copy dirs
+for i in $DIRS; do
+    echo "directory $i"
+    cp -Rp "../$i" "$directory"
+done
+
+# regenerate "dist"
+echo "creating a new dist directory ..."
+mkdir "$directory/dist"
+
+if [ "$?" != "0" ]; then
+    echo "error creating $directory/dist"
+    exit 1
+fi
+
+for i in `ls`; do
+    if [ -f "$i" ]; then
+	echo "dist file $i"
+	cp "$i" "$directory/dist"
+    fi
+done
+
+# build archive
+cd build
+tar czf "$file.tar.gz" "$file"
+
+if [ "$?" != "0" ]; then
+    echo "error creating tar.gz archive"
+    exit 1
+fi
+
+echo "archive is ready in build directory"

Property changes on: dist/makedist.sh
___________________________________________________________________
Added: svn:executable
\ No newline at end of property
Index: dist/NEWS
===================================================================
--- dist/NEWS	(revision 0)
+++ dist/NEWS	(revision 1)
@@ -0,0 +1,2 @@
+No news no changelog yet.
+A Subversion repository will be available soon, with a complete changelog.
Index: dist/README
===================================================================
--- dist/README	(revision 0)
+++ dist/README	(revision 1)
@@ -0,0 +1,4 @@
+Raydium is a realtime 3D Game Engine, providing a powerfull but very simple API.
+
+Full description and a features list are available at:
+http://raydium.yoopla.org/wiki/RaydiumEn
Index: dist/INSTALL
===================================================================
--- dist/INSTALL	(revision 0)
+++ dist/INSTALL	(revision 1)
@@ -0,0 +1,2 @@
+Full building instructions are available at :
+http://raydium.yoopla.org/wiki/RaydiumInstallEn
Index: comp.sh
===================================================================
--- comp.sh	(revision 0)
+++ comp.sh	(revision 1)
@@ -0,0 +1,5 @@
+ulimit -c 0
+rm test
+gcc $1 -Wall -o test -L/usr/X11R6/lib/ -lGL -lglut -lGLU -lm -lopenal -lvorbis -logg -lvorbisfile -Iphp/ -Iphp/main/ -Iphp/Zend -Iphp/TSRM php/libs/libphp4.a -lresolv -lcrypt -lz
+sync
+./test $2 $3 $4 $5 $6

Property changes on: comp.sh
___________________________________________________________________
Added: svn:executable
\ No newline at end of property
Index: raydium/common.h
===================================================================
--- raydium/common.h	(revision 0)
+++ raydium/common.h	(revision 1)
@@ -0,0 +1,474 @@
+/*
+* Raydium - CQFD Corp.
+* http://raydium.cqfd-corp.org
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifdef WIN32
+#include "windows.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <GL/glut.h>
+#include <math.h>
+#include <time.h>
+#include <memory.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdarg.h>
+
+#include <AL/al.h>
+#include <AL/alut.h>
+#include <vorbis/vorbisfile.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+// need to separate LINUX & others, using glut for joystick..
+#ifndef WIN32
+#include <linux/joystick.h>
+#include <sys/ioctl.h>
+#include <linux/rtc.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h>
+#endif
+
+#include <errno.h>
+#include "config.h"
+
+#ifdef WIN32
+#include "glarb.h"
+#endif
+
+#ifdef GL_VERSION_1_4
+#define glActiveTextureARB glActiveTexture
+#define glMultiTexCoord2fARB glMultiTexCoord2f
+#endif
+
+#ifdef PHP_SUPPORT
+#ifdef WIN32
+#define PHP_WIN32
+#define ZTS
+#define ZEND_WIN32
+#endif
+#include "php.h"
+#include "php_version.h"
+#include "php_globals.h"
+#include "php_variables.h"
+#include "zend_modules.h"
+
+#include "SAPI.h"
+
+#include "php.h"
+//#include "build-defs.h"
+#include "zend.h"
+#include "zend_extensions.h"
+#include "php_ini.h"
+#include "php_globals.h"
+#include "php_main.h"
+#include "fopen_wrappers.h"
+#include "ext/standard/php_standard.h"
+#endif
+
+#define PI 					(3.1415926535f)
+
+#define RAYDIUM_MAX_VERTICES  			2000000
+#define RAYDIUM_MAX_TEXTURES    	   	256
+#define RAYDIUM_MAX_LIGHTS         	     	8
+#define RAYDIUM_MAX_NAME_LEN     	   	255
+#define RAYDIUM_MAX_OBJECTS		  	1024
+#define RAYDIUM_MAX_TIMECALLS 			16
+#define RAYDIUM_MAX_REG_VARIABLES  		256
+#define RAYDIUM_MAX_REG_FUNCTION		256
+#define RAYDIUM_MAX_LOG_FOPEN			256
+#define RAYDIUM_MAX_CAMERA_PATHS		16
+#define RAYDIUM_MAX_CAMERA_PATH_STEPS		512
+
+#define RAYDIUM_LIGHT_ON           	     	1
+#define RAYDIUM_LIGHT_BLINKING     	     	2
+#define RAYDIUM_LIGHT_OFF         	    	-1
+
+#define RAYDIUM_TEXTURE_FILTER_NONE	     	0
+#define RAYDIUM_TEXTURE_FILTER_BILINEAR	     	1
+#define RAYDIUM_TEXTURE_FILTER_TRILINEAR     	2
+
+// CUTOUT not used yet (soon !)
+#define RAYDIUM_TEXTURE_BLEND_NONE		0
+#define RAYDIUM_TEXTURE_BLEND_BLENDED		1
+#define RAYDIUM_TEXTURE_BLEND_CUTOUT		2 
+
+#define RAYDIUM_RENDERING_WINDOW      	    	0
+#define RAYDIUM_RENDERING_FULLSCREEN  	     	1
+#define RAYDIUM_RENDERING_NONE  	     	2
+
+#define RAYDIUM_PROJECTION_ORTHO       	     	0
+#define RAYDIUM_PROJECTION_PERSPECTIVE 	     	1
+
+#define RAYDIUM_KEYBOARD_SIZE	       	   	256
+#define RAYDIUM_BUTTONS_MAX_BUTTONS		4
+
+#define RAYDIUM_NETWORK_PORT			29104
+#define RAYDIUM_NETWORK_PACKET_SIZE		512
+#define RAYDIUM_NETWORK_TIMEOUT			10
+#define RAYDIUM_NETWORK_PACKET_OFFSET		4
+#define RAYDIUM_NETWORK_MAX_CLIENTS		8
+#define RAYDIUM_NETWORK_TX_QUEUE_SIZE		128
+#define RAYDIUM_NETWORK_MAX_TRIES		8
+#define RAYDIUM_NETWORK_MAX_NETCALLS 		32
+#define RAYDIUM_NETWORK_MAX_PROPAGS 		32
+#define RAYDIUM_NETWORK_ACK_DELAY_MAX		2
+#define RAYDIUM_NETWORK_PROPAG_HEAD		sizeof(int)
+#define RAYDIUM_NETWORK_MODE_NONE		0
+#define RAYDIUM_NETWORK_MODE_CLIENT		1
+#define RAYDIUM_NETWORK_MODE_SERVER		2
+//#define RAYDIUM_NETWORK_TCP			SOCK_STREAM
+#define RAYDIUM_NETWORK_UDP			SOCK_DGRAM
+#define RAYDIUM_NETWORK_DATA_OK			1
+#define RAYDIUM_NETWORK_DATA_NONE		0
+#define RAYDIUM_NETWORK_DATA_ERROR		-1
+
+#define RAYDIUM_NETWORK_PACKET_DATA			1
+#define RAYDIUM_NETWORK_PACKET_ERROR_NO_MORE_PLACE	2
+#define RAYDIUM_NETWORK_PACKET_ATTRIB_UID		3
+#define RAYDIUM_NETWORK_PACKET_REQUEST_UID		4
+#define RAYDIUM_NETWORK_PACKET_INFO_NAME		5
+#define RAYDIUM_NETWORK_PACKET_ACK			6
+#define RAYDIUM_NETWORK_PACKET_ODE_DATA			10
+#define RAYDIUM_NETWORK_PACKET_ODE_NEWELEM		11
+#define RAYDIUM_NETWORK_PACKET_ODE_REMELEM		12
+#define RAYDIUM_NETWORK_PACKET_ODE_NIDWHO		13
+#define RAYDIUM_NETWORK_PACKET_ODE_EXPLOSION		14
+#define	RAYDIUM_NETWORK_PACKET_BASE			20
+
+#define RAYDIUM_SOUND_NUM_BUFFERS 		30
+#define RAYDIUM_SOUND_NUM_SOURCES 		30
+#define SOUNDDATASIZE 				(4096*20)
+//#define RAYDIUM_SOUND_NUM_ENVIRONMENTS 		1
+
+#define RAYDIUM_CONSOLE_MAX_LINES		18
+#define RAYDIUM_CONSOLE_MAX_HISTORY		1000
+#define RAYDIUM_CONSOLE_FONT_SIZE		16
+#define RAYDIUM_CONSOLE_FONT_SPACER		0.5
+#define RAYDIUM_CONSOLE_MAX_COMPLETION		10
+
+#define RAYDIUM_TIMECALL_METHOD_NONE		0
+#define RAYDIUM_TIMECALL_METHOD_CLOCK		1
+#define RAYDIUM_TIMECALL_METHOD_DEVRTC 		2
+
+#define RAYDIUM_TIMECALL_FREQ_MIN 		100
+#define RAYDIUM_TIMECALL_FREQ_PREFERED 		8192
+#define RAYDIUM_TIMECALL_W32_MODULO_MIN		15
+
+#define RAYDIUM_REGISTER_INT    		1
+#define RAYDIUM_REGISTER_FLOAT  		2
+#define RAYDIUM_REGISTER_STR    		3
+#define RAYDIUM_REGISTER_ICONST			4
+#define RAYDIUM_REGISTER_FCONST			5
+
+#define RAYDIUM_PARSER_TYPE_EOF			0
+#define RAYDIUM_PARSER_TYPE_FLOAT		1
+#define RAYDIUM_PARSER_TYPE_STRING		2
+#define RAYDIUM_PARSER_TYPE_DEBUG		3
+#define RAYDIUM_PARSER_TYPE_RAWDATA		4
+
+#define RAYDIUM_OSD_FONT_SIZE_FACTOR		12
+
+#define RAYDIUM_RENDER_MULTITEX_AUTO_UV_FACT	50
+
+#ifdef MAIN_H
+#define __global extern
+#endif
+
+#ifdef MAIN_C
+#define __global
+#endif
+
+
+__global int 	 raydium_init_argc;
+__global char  **raydium_init_argv;
+
+__global int     raydium_key_last;
+__global char    raydium_key[RAYDIUM_KEYBOARD_SIZE];
+__global char    raydium_mouse_click;
+__global char    raydium_mouse_button[3];
+__global GLuint  raydium_mouse_x;
+__global GLuint  raydium_mouse_y;
+__global char    raydium_joy_button[RAYDIUM_BUTTONS_MAX_BUTTONS];
+__global char	 raydium_joy_click;
+__global GLfloat raydium_joy_x;
+__global GLfloat raydium_joy_y;
+__global GLfloat raydium_joy_z;
+__global int     raydium_joy;
+
+__global GLuint   raydium_texture_index;
+__global GLuint   raydium_texture_current;
+__global GLuint   raydium_texture_current_multi;
+__global GLfloat  raydium_texture_current_multi_u;
+__global GLfloat  raydium_texture_current_multi_v;
+__global char     raydium_texture_filter;
+__global GLuint	  raydium_texture_size_max;
+__global GLuint	  raydium_texture_units;
+__global GLuint   raydium_internal_size_vector_float_4;
+__global GLuint   raydium_texture_to_replace;
+__global GLfloat  raydium_texture_used_memory;
+
+__global char    raydium_projection;
+__global GLfloat raydium_projection_fov;  	// perspective only
+__global GLfloat raydium_projection_near; 	// perspective & ortho
+__global GLfloat raydium_projection_far; 	// perspective & ortho
+__global GLfloat raydium_projection_left; 	// ortho only
+__global GLfloat raydium_projection_right; 	// ortho only
+__global GLfloat raydium_projection_bottom; 	// ortho only
+__global GLfloat raydium_projection_top; 	// ortho only
+__global GLfloat raydium_background_color[4];
+__global char	 raydium_sky_force;
+
+__global GLsizei raydium_window_tx;
+__global GLsizei raydium_window_ty;
+__global char	 raydium_window_mode;
+
+__global GLuint  raydium_vertex_index;
+__global GLuint  raydium_vertex_counter;
+__global char    raydium_vertex_offset_triangle;
+
+__global GLfloat *raydium_vertex_x;
+__global GLfloat *raydium_vertex_y;
+__global GLfloat *raydium_vertex_z;
+__global GLfloat *raydium_vertex_normal_x;
+__global GLfloat *raydium_vertex_normal_y;
+__global GLfloat *raydium_vertex_normal_z;
+__global GLfloat *raydium_vertex_normal_visu_x; //
+__global GLfloat *raydium_vertex_normal_visu_y; // used for smoothing
+__global GLfloat *raydium_vertex_normal_visu_z; //
+__global GLfloat *raydium_vertex_texture_u;
+__global GLfloat *raydium_vertex_texture_v;
+__global GLuint  *raydium_vertex_texture;
+__global GLuint  *raydium_vertex_texture_multi;
+__global GLfloat *raydium_vertex_texture_multi_u;
+__global GLfloat *raydium_vertex_texture_multi_v;
+__global char	 *raydium_vertex_tag;
+__global char     raydium_texture_islightmap[RAYDIUM_MAX_TEXTURES];
+__global char     raydium_texture_blended[RAYDIUM_MAX_TEXTURES];
+__global char     raydium_texture_name[RAYDIUM_MAX_TEXTURES][RAYDIUM_MAX_NAME_LEN];
+__global GLfloat  raydium_texture_rgb[RAYDIUM_MAX_TEXTURES][4];
+
+__global GLuint	raydium_object_index;
+__global GLuint	raydium_object_start[RAYDIUM_MAX_OBJECTS];
+__global GLuint	raydium_object_end[RAYDIUM_MAX_OBJECTS];
+__global char	raydium_object_name[RAYDIUM_MAX_OBJECTS][RAYDIUM_MAX_NAME_LEN];
+
+__global int	 raydium_render_fps;
+__global GLfloat raydium_render_rgb_force[4];
+__global char	 raydium_render_rgb_force_tag;
+__global char	 raydium_render_displaylists_tag;
+
+__global char	 raydium_fog_enabled_tag;
+
+__global char	 raydium_light_enabled_tag;
+__global char    raydium_light_internal_state[RAYDIUM_MAX_LIGHTS];
+__global GLfloat raydium_light_position[RAYDIUM_MAX_LIGHTS][4];
+__global GLfloat raydium_light_color[RAYDIUM_MAX_LIGHTS][4];
+__global GLfloat raydium_light_intensity[RAYDIUM_MAX_LIGHTS];
+__global GLfloat raydium_light_blink_low[RAYDIUM_MAX_LIGHTS];
+__global GLfloat raydium_light_blink_high[RAYDIUM_MAX_LIGHTS];
+__global GLfloat raydium_light_blink_increment[RAYDIUM_MAX_LIGHTS];
+// TODO: light_spot
+
+__global char    raydium_internal_vertex_next_extras;
+__global GLfloat raydium_internal_vertex_next_u;
+__global GLfloat raydium_internal_vertex_next_v;
+__global GLfloat raydium_internal_vertex_next_nx;
+__global GLfloat raydium_internal_vertex_next_ny;
+__global GLfloat raydium_internal_vertex_next_nz;
+
+__global char	 raydium_frame_first_camera_pass;
+__global float	 raydium_frame_time;
+__global GLfloat raydium_camera_x;
+__global GLfloat raydium_camera_y; // read only, undocumented.
+__global GLfloat raydium_camera_z;
+__global char	 raydium_camera_pushed;
+__global GLfloat raydium_camera_cursor_place[3];
+__global GLfloat raydium_camera_look_at_roll;
+__global GLfloat raydium_camera_rumble_amplitude;
+__global GLfloat raydium_camera_rumble_evolution;
+__global GLfloat raydium_camera_rumble_remaining;
+
+typedef struct raydium_camera_Path
+    {
+    char    name[RAYDIUM_MAX_NAME_LEN];
+    GLfloat x[RAYDIUM_MAX_CAMERA_PATH_STEPS];
+    GLfloat y[RAYDIUM_MAX_CAMERA_PATH_STEPS];
+    GLfloat z[RAYDIUM_MAX_CAMERA_PATH_STEPS];
+    GLfloat zoom[RAYDIUM_MAX_CAMERA_PATH_STEPS];
+    GLfloat roll[RAYDIUM_MAX_CAMERA_PATH_STEPS];
+    int steps;
+    } raydium_camera_Path;
+__global raydium_camera_Path raydium_camera_path[RAYDIUM_MAX_CAMERA_PATHS];
+__global char raydium_camera_path_reset_flag;
+
+__global int 	raydium_network_socket;
+__global int 	raydium_network_uid;
+__global char	raydium_network_mode;
+__global char	raydium_network_client[RAYDIUM_NETWORK_MAX_CLIENTS];
+__global time_t raydium_network_start;
+__global struct sockaddr
+	raydium_network_client_addr[RAYDIUM_NETWORK_MAX_CLIENTS];
+__global time_t raydium_network_keepalive[RAYDIUM_NETWORK_MAX_CLIENTS];
+__global char   raydium_network_name_local[RAYDIUM_MAX_NAME_LEN];
+__global char   raydium_network_name[RAYDIUM_NETWORK_MAX_CLIENTS][RAYDIUM_MAX_NAME_LEN];
+__global int    raydium_network_netcall_type[RAYDIUM_NETWORK_MAX_NETCALLS];
+__global void * raydium_network_netcall_func[RAYDIUM_NETWORK_MAX_NETCALLS];
+__global char   raydium_network_netcall_tcp[RAYDIUM_NETWORK_MAX_NETCALLS];
+__global void * raydium_network_on_connect;
+__global void * raydium_network_on_disconnect;
+__global int    raydium_network_stat_rx;
+__global int    raydium_network_stat_tx;
+__global int    raydium_network_stat_reemitted;
+__global int    raydium_network_stat_double;
+__global int    raydium_network_stat_lost;
+__global int    raydium_network_stat_bogus_ack;
+
+typedef struct raydium_network_Tcp
+    {
+    char state;
+    unsigned short tcpid;
+    char packet[RAYDIUM_NETWORK_PACKET_SIZE];
+    unsigned long time;
+    unsigned short retries_left;
+    struct sockaddr to;
+    int to_player;
+    } raydium_network_Tcp;
+
+__global raydium_network_Tcp raydium_network_queue[RAYDIUM_NETWORK_TX_QUEUE_SIZE];
+__global int raydium_network_queue_index;
+
+__global unsigned short raydium_network_tcpid_i[RAYDIUM_NETWORK_TX_QUEUE_SIZE]; // ID
+__global int            raydium_network_tcpid_p[RAYDIUM_NETWORK_TX_QUEUE_SIZE]; // Player
+__global int		raydium_network_tcpid_index;
+
+__global unsigned long raydium_netwok_queue_ack_delay_client;
+__global unsigned long raydium_netwok_queue_ack_delay_server[RAYDIUM_NETWORK_MAX_CLIENTS];
+__global char	       raydium_network_write_notcp;
+
+typedef struct raydium_network_Propag
+    {
+    char state;
+    int type;
+    unsigned short size;
+    unsigned int version;
+    void *data;    
+    } raydium_network_Propag;
+
+__global raydium_network_Propag raydium_network_propag[RAYDIUM_NETWORK_MAX_PROPAGS];
+
+__global ALuint  raydium_sound_buffer[RAYDIUM_SOUND_NUM_BUFFERS];
+__global ALuint  raydium_sound_source[RAYDIUM_SOUND_NUM_SOURCES];
+__global ALfloat raydium_sound_DefaultReferenceDistance;
+__global int 	 raydium_sound;
+__global int 	 raydium_sound_top_buffer;
+__global char    raydium_sound_music_buf[SOUNDDATASIZE];
+__global FILE   *raydium_sound_music_file;
+__global OggVorbis_File raydium_sound_vf;
+__global vorbis_info   *raydium_sound_ogginfo;
+__global int 	(*raydium_sound_music_eof_callback)(char *);
+
+__global GLfloat raydium_osd_logo_angle;
+__global GLuint  raydium_osd_cursor_texture;
+__global GLfloat raydium_osd_cursor_xsize;
+__global GLfloat raydium_osd_cursor_ysize;
+__global GLfloat raydium_osd_color[4];
+#ifdef MAIN_C
+__global GLfloat raydium_osd_ega[]=
+         {
+         0.0f, 0.0f, 0.0f, // 0: black
+         0.0f, 0.0f, 0.6f, // 1: blue
+         0.0f, 0.6f, 0.0f, // 2: green
+         0.0f, 0.6f, 0.6f, // 3: cyan
+         0.6f, 0.0f, 0.0f, // 4: red
+         0.6f, 0.0f, 0.6f, // 5: purple
+         0.6f, 0.3f, 0.0f, // 6: brown
+         0.6f, 0.6f, 0.6f, // 7: white
+         0.3f, 0.3f, 0.3f, // 8: grey
+         0.3f, 0.3f, 1.0f, // 9: light blue
+         0.3f, 1.0f, 0.3f, // A: light green
+         0.3f, 1.0f, 1.0f, // B: light cyan
+         1.0f, 0.3f, 0.3f, // C: light red
+         1.0f, 0.3f, 1.0f, // D: light purple
+         1.0f, 1.0f, 0.3f, // E: light yellow
+         1.0f, 1.0f, 1.0f  // F: light white
+	 };
+#else
+__global GLfloat raydium_osd_ega[];
+#endif
+__global GLfloat raydium_osd_fade_color_timeleft;
+__global GLfloat raydium_osd_fade_color_increment[4];
+__global GLfloat raydium_osd_fade_color_current[4];
+__global void *  raydium_osd_fade_OnFadeEnd;
+
+__global GLfloat raydium_console_pos;
+__global GLfloat raydium_console_inc;
+__global GLfloat raydium_console_config_max;
+__global GLfloat raydium_console_config_speed;
+__global char    raydium_console_config_texture[RAYDIUM_MAX_NAME_LEN];
+__global char    raydium_console_config_font[RAYDIUM_MAX_NAME_LEN];
+__global char	 raydium_console_lines[RAYDIUM_CONSOLE_MAX_LINES][RAYDIUM_MAX_NAME_LEN];
+__global int	 raydium_console_line_last;
+__global char    raydium_console_get_string[RAYDIUM_MAX_NAME_LEN];
+__global char    raydium_console_get_string_last[RAYDIUM_MAX_NAME_LEN];
+__global void *	 raydium_console_gets_callback;
+__global char	 raydium_console_history[RAYDIUM_CONSOLE_MAX_HISTORY][RAYDIUM_MAX_NAME_LEN];
+__global int	 raydium_console_history_index; // store
+__global int	 raydium_console_history_index_current; // user
+__global char    raydium_console_history_filename[RAYDIUM_MAX_NAME_LEN];
+
+__global int		raydium_timecall_index;
+__global char          	raydium_timecall_method;
+__global unsigned long 	raydium_timecall_max_frequency;
+__global unsigned long 	raydium_timecall_clocks_per_sec;
+__global int           	raydium_timecall_devrtc_handle;
+__global unsigned long  raydium_timecall_devrtc_clocks;
+__global void *	      	raydium_timecall_funct[RAYDIUM_MAX_TIMECALLS];
+__global GLint 		raydium_timecall_soft_call[RAYDIUM_MAX_TIMECALLS];
+__global clock_t 	raydium_timecall_interval[RAYDIUM_MAX_TIMECALLS];
+__global clock_t 	raydium_timecall_next[RAYDIUM_MAX_TIMECALLS];
+__global int            raydium_timecall_w32_divmodulo;
+
+__global int    raydium_register_variable_index;
+__global int    raydium_register_function_index;
+__global char   raydium_register_variable_name[RAYDIUM_MAX_REG_VARIABLES][RAYDIUM_MAX_NAME_LEN];
+__global void * raydium_register_variable_addr[RAYDIUM_MAX_REG_VARIABLES];
+__global int    raydium_register_variable_type[RAYDIUM_MAX_REG_VARIABLES];
+#ifdef PHP_SUPPORT
+#define ZFE zend_function_entry
+#else
+#define ZFE void *
+#endif
+__global ZFE raydium_register_function_list[RAYDIUM_MAX_REG_FUNCTION];
+
+__global FILE *raydium_log_file;
+__global char raydium_file_log_fopen[RAYDIUM_MAX_LOG_FOPEN][RAYDIUM_MAX_NAME_LEN];
+__global int raydium_file_log_fopen_index;
+
+// EOF
Index: raydium/capture.c
===================================================================
--- raydium/capture.c	(revision 0)
+++ raydium/capture.c	(revision 1)
@@ -0,0 +1,88 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/capture.h"
+#endif 
+
+// Present capture code was inspired from various web files...
+// Not a pure CQFD Corp. production :)
+
+void raydium_capture_frame(char *filename)
+{
+unsigned char cGarbage = 0, type,mode,aux,bpp, *imageData;
+short int iGarbage = 0;
+GLuint i;
+GLuint size;
+FILE *file;
+
+mode=3; // RGB (Bpp)
+bpp=mode*8;
+type=2; // Color
+
+
+size=raydium_window_tx * raydium_window_ty * mode;
+imageData=malloc(size+1);
+
+glReadPixels(0, 0,raydium_window_tx,raydium_window_ty,GL_RGB,GL_UNSIGNED_BYTE,imageData);
+
+
+// open file and check for errors
+file = fopen(filename, "wb");
+if (file == NULL) { raydium_log("Error: capture: cannot open %s for writing",filename); return; }
+
+// write the header
+fwrite(&cGarbage, sizeof(unsigned char), 1, file);
+fwrite(&cGarbage, sizeof(unsigned char), 1, file);
+fwrite(&type, sizeof(unsigned char), 1, file);
+fwrite(&iGarbage, sizeof(short int), 1, file);
+fwrite(&iGarbage, sizeof(short int), 1, file);
+fwrite(&cGarbage, sizeof(unsigned char), 1, file);
+fwrite(&iGarbage, sizeof(short int), 1, file);
+fwrite(&iGarbage, sizeof(short int), 1, file);
+fwrite(&raydium_window_tx, sizeof(short int), 1, file);
+fwrite(&raydium_window_ty, sizeof(short int), 1, file);
+fwrite(&bpp, sizeof(unsigned char), 1, file);
+fwrite(&cGarbage, sizeof(unsigned char), 1, file);
+
+// convert the image data from RGB(a) to BGR(A)
+    for (i=0; i < size ; i+= mode) 
+    {
+    aux = imageData[i];
+    imageData[i] = imageData[i+2];
+    imageData[i+2] = aux;
+    }
+
+    // save the image data
+    fwrite(imageData, sizeof(unsigned char), size, file);
+    fclose(file);
+    // release the memory
+    free(imageData);
+    raydium_log("screenshot saved as %s",filename);
+}
+
+void raydium_capture_frame_auto(void)
+{
+static int cpt=0;
+char f[RAYDIUM_MAX_NAME_LEN];
+time_t rawtime;
+struct tm *ptm;
+    
+time(&rawtime);
+ptm=gmtime(&rawtime); // localtime() ?
+sprintf(f,"raycap%i-%02i-%02i-%02i%02i%02i-%02i.tga",
+	ptm->tm_year+1900,
+	ptm->tm_mon+1,
+	ptm->tm_mday,
+	ptm->tm_hour,
+	ptm->tm_min,
+	ptm->tm_sec,
+	cpt);
+raydium_capture_frame(f);
+cpt++;
+}
Index: raydium/particle.c
===================================================================
--- raydium/particle.c	(revision 0)
+++ raydium/particle.c	(revision 1)
@@ -0,0 +1,205 @@
+///////////////////////////////////////////////////////
+//
+// !!! THIS FILE IS OLD !!!
+// (used as a reference for new particle engine)
+//
+// See particle2.* files
+//
+///////////////////////////////////////////////////////
+
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+// proto
+void raydium_camera_replace(void);
+
+void raydium_particle_init(GLuint expl, GLuint part)
+{
+raydium_particle_ttl[expl][part]=0;
+}
+
+
+void raydium_explosion_reset(GLuint exp)
+{
+GLuint i;
+
+raydium_explosion_ttl[exp]=0;
+for(i=0;i< RAYDIUM_MAX_PARTICLES;i++)
+ raydium_particle_init(exp,i);
+
+}
+
+
+void raydium_explosion_add(GLfloat x, GLfloat y, GLfloat z, 
+			   GLfloat vx, GLfloat vy, GLfloat vz, 
+                           GLfloat dispersion, GLuint ttl, GLfloat dens_perc,
+			   GLfloat grav)
+{
+GLuint n=0; // gngngngngng ... debug !
+
+
+raydium_explosion_reset(n);
+raydium_explosion_ttl[n]=ttl;
+raydium_explosion_x[n]=x;
+raydium_explosion_y[n]=y;
+raydium_explosion_z[n]=z;
+raydium_explosion_vector_x[n]=vx;
+raydium_explosion_vector_y[n]=vy;
+raydium_explosion_vector_z[n]=vz;
+raydium_explosion_dispersion[n]=dispersion;
+raydium_explosion_gravity[n]=grav;
+// we need to know how many particles to generate per frame,
+// user gives us dens_perc, 0 < x < 100
+raydium_explosion_density_pf[n]=((float)RAYDIUM_MAX_PARTICLES*dens_perc)/(float)100;
+}
+
+
+char raydium_particle_life(GLuint expl, GLuint part, GLuint *created)
+{
+char ret=0;
+
+
+ if(raydium_particle_ttl[expl][part]<=0 &&
+    raydium_explosion_ttl[expl]>0 && 
+    (*created)<raydium_explosion_density_pf[expl]) /* explosion alive, we can regenerate particle */
+ {
+ (*created)++;
+ //ret=1;
+ raydium_particle_ttl[expl][part]=RAYDIUM_MAX_PARTICLES/raydium_explosion_density_pf[expl];
+ // set particle 
+ raydium_particle_x[expl][part]=raydium_explosion_x[expl];
+ raydium_particle_y[expl][part]=raydium_explosion_y[expl];
+ raydium_particle_z[expl][part]=raydium_explosion_z[expl];
+ 
+ // need to take direction vector
+ raydium_particle_ix[expl][part]=raydium_random_neg_pos_1()*raydium_explosion_dispersion[expl];
+ raydium_particle_iy[expl][part]=raydium_random_neg_pos_1()*raydium_explosion_dispersion[expl];
+ raydium_particle_iz[expl][part]=raydium_random_neg_pos_1()*raydium_explosion_dispersion[expl]; 
+ }
+
+
+ if(raydium_particle_ttl[expl][part]>0) // alive
+ {
+ ret=1;
+ // move particle
+ raydium_particle_x[expl][part]+=raydium_particle_ix[expl][part];
+ raydium_particle_y[expl][part]+=raydium_particle_iy[expl][part];
+ raydium_particle_z[expl][part]+=raydium_particle_iz[expl][part];
+
+ raydium_particle_iz[expl][part]-=raydium_explosion_gravity[expl];
+ raydium_particle_ttl[expl][part]--;
+ 
+ }
+
+return ret;
+}
+
+
+void raydium_explosion_life(GLuint expl)
+{
+GLuint i;
+char any_alive=0;
+GLuint created=0;
+
+for(i=0;i< RAYDIUM_MAX_PARTICLES;i++)
+ if(raydium_particle_life(expl,i,&created)) any_alive=1;
+
+if(raydium_explosion_ttl[expl]>0) raydium_explosion_ttl[expl]--;
+if(raydium_explosion_ttl[expl]==0 && any_alive) raydium_explosion_ttl[expl]=-1;
+if(raydium_explosion_ttl[expl]<0 && !any_alive) raydium_explosion_ttl[expl]=0;
+
+}
+
+
+void raydium_explosion_callback(void)
+{
+GLuint i;
+
+for(i=0;i< RAYDIUM_MAX_EXPLOSIONS;i++)
+ if(raydium_explosion_ttl[i]!=0)
+ raydium_explosion_life(i);
+}
+
+
+void raydium_explosion_draw_particles(GLuint expl)
+{
+GLuint i;
+#define TSIZE ((float)0.5)
+
+GLfloat modmat[16];
+GLfloat ux;
+GLfloat uy;
+GLfloat uz;
+GLfloat rx;
+GLfloat ry;
+GLfloat rz;
+
+glGetFloatv(GL_MODELVIEW_MATRIX,modmat);
+ux=modmat[0];
+uy=modmat[4];
+uz=modmat[8];
+ux*=TSIZE/2;
+uy*=TSIZE/2;
+uz*=TSIZE/2;
+
+rx=modmat[1];
+ry=modmat[5];
+rz=modmat[9];
+rx*=TSIZE/2;
+ry*=TSIZE/2;
+rz*=TSIZE/2;
+
+
+for(i=0;i< RAYDIUM_MAX_PARTICLES;i++)
+ if(raydium_particle_ttl[expl][i])
+ {
+  glBegin(GL_QUADS); // berk... but i'll switch to TRIANGLES one day ;)
+  glTexCoord2f(0.0f, 0.0f);
+  glVertex3f(raydium_particle_x[expl][i] + (-rx - ux),
+	     raydium_particle_y[expl][i] + (-ry - uy),
+	     raydium_particle_z[expl][i] + (-rz - uz));
+  glTexCoord2f(1.0f, 0.0f);
+  glVertex3f(raydium_particle_x[expl][i] + (rx - ux),
+	     raydium_particle_y[expl][i] + (ry - uy),
+	     raydium_particle_z[expl][i] + (rz - uz));
+  glTexCoord2f(1.0f, 1.0f);
+  glVertex3f(raydium_particle_x[expl][i] + (rx + ux),
+	     raydium_particle_y[expl][i] + (ry + uy),
+	     raydium_particle_z[expl][i] + (rz + uz));
+  glTexCoord2f(0.0f, 1.0f);
+  glVertex3f(raydium_particle_x[expl][i] + (ux - rx),
+	     raydium_particle_y[expl][i] + (uy - ry),
+	     raydium_particle_z[expl][i] + (uz - rz));
+  glEnd();
+ }
+}
+
+
+void raydium_explosion_draw_all(void)
+{
+GLuint i;
+GLuint texsave;
+char light;
+
+texsave=raydium_texture_current;
+light=raydium_light_enabled_tag;
+raydium_light_disable();
+if (raydium_camera_pushed) raydium_camera_replace(); // is it really our job to do it here ?
+//raydium_rendering_internal_restore_render_state();
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current_set_name("flare.tga"));
+glDepthMask(GL_FALSE);
+
+
+for(i=0;i< RAYDIUM_MAX_EXPLOSIONS;i++)
+ if(raydium_explosion_ttl[i]!=0)
+ raydium_explosion_draw_particles(i);
+
+glDepthMask(GL_TRUE);
+if(light) raydium_light_enable();
+
+raydium_texture_current_set(texsave);
+//raydium_rendering_internal_prepare_texture_render(texsave);
+}
Index: raydium/init.c
===================================================================
--- raydium/init.c	(revision 0)
+++ raydium/init.c	(revision 1)
@@ -0,0 +1,277 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/init.h"
+
+#endif 
+
+// proto
+void raydium_ode_init(void);
+void raydium_register_api(void);
+
+int raydium_init_cli_option(char *option, char *value)
+{
+int i;
+int found;
+char full_option[RAYDIUM_MAX_NAME_LEN];
+char head[3];
+
+strcpy(full_option  ,"--");
+strcpy(full_option+2,option);
+
+found=0;
+
+for(i=1;i<raydium_init_argc;i++)
+    if(!strcasecmp(full_option,raydium_init_argv[i]))
+	found=i;
+
+if(!found) return 0; 	// option not found
+
+if((found+1) >= raydium_init_argc)
+    {
+    if(value) strcpy(value,"");
+    return 1;	// found, no value (last option of cli)
+    }
+
+strncpy(head,raydium_init_argv[found+1],3);
+head[2]=0;
+
+if(!strcasecmp(head,"--"))
+    {
+    if(value) strcpy(value,"");
+    return 1;	// found, no value (value starts with -- : is a option)
+    }
+
+if(value) strcpy(value,raydium_init_argv[found+1]);
+return 1;
+}
+
+
+int raydium_init_cli_option_default(char *option, char *value, char *default_value)
+{
+if(!raydium_init_cli_option(option,value))
+    strcpy(value,default_value);
+return 1;
+}
+
+void raydium_init_lights(void)
+{
+GLuint i;
+
+for(i=0;i<RAYDIUM_MAX_LIGHTS;i++)
+raydium_light_reset(i);
+raydium_log("lights: OK");
+}
+
+void raydium_init_objects(void)
+{
+GLuint i;
+
+for(i=0;i<RAYDIUM_MAX_OBJECTS;i++)
+raydium_object_reset(i);
+raydium_log("objects: OK");
+}
+
+
+void raydium_init_key(void)
+{
+if(raydium_window_mode==RAYDIUM_RENDERING_NONE)
+    return;
+glutIgnoreKeyRepeat(1);
+memset(raydium_key,0,RAYDIUM_KEYBOARD_SIZE);
+raydium_key_last=0;
+raydium_log("keyboard: OK");
+}
+
+// NEVER tested as it should be ! (used once only for now)
+void raydium_init_reset(void)
+{
+GLuint i;
+
+/*
+for(i=1;i<raydium_texture_index;i++) // free all texture buffers
+free(raydium_texture_ptr[i]);
+*/
+
+raydium_init_lights();
+raydium_init_objects();
+raydium_network_init();
+raydium_timecall_init();
+raydium_particle_init();
+raydium_camera_path_init_all();
+raydium_osd_fade_init();
+raydium_console_init();
+raydium_gui_init();
+
+// Must find a way to delete textures from video card's memory, too...
+
+for(i=0;i<RAYDIUM_MAX_TEXTURES;i++) // reset all textures
+{
+ raydium_texture_name[i][0]=0;
+ raydium_texture_blended[i]=0;
+ raydium_texture_islightmap[i]=0;
+ raydium_texture_rgb[0][i]=-1.f;
+ raydium_texture_rgb[1][i]=-1.f;
+ raydium_texture_rgb[2][i]=-1.f;
+ raydium_texture_rgb[3][i]=1.f;
+}
+raydium_vertex_index=0;
+raydium_vertex_offset_triangle=0;
+
+strcpy(raydium_texture_name[0],"dummy.null");
+
+raydium_texture_index=1; // no more texture loaded (0 is not a texture)
+raydium_texture_current=0; // sets an "invalid" current texture
+raydium_texture_current_multi=0; // sets an "invalid" current texture
+raydium_texture_current_multi_u=0;
+raydium_texture_current_multi_v=0;
+raydium_texture_to_replace=0; // No texture to erase.. just load it :)
+raydium_texture_used_memory=0;
+//raydium_texture_filter=RAYDIUM_TEXTURE_FILTER_NONE;
+raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_NONE);
+raydium_rendering_rgb_normal();
+raydium_rendering_displaylists_enable();
+raydium_vertex_counter=0;
+raydium_projection=RAYDIUM_PROJECTION_PERSPECTIVE;
+raydium_projection_fov=60;
+raydium_projection_near=1;
+raydium_projection_far=1000;
+raydium_projection_left=0;
+raydium_projection_right=0;
+raydium_projection_bottom=0;
+raydium_projection_top=0;
+raydium_camera_pushed=0;
+raydium_camera_look_at_roll=0;
+raydium_camera_path_reset_flag=1;
+raydium_camera_rumble_amplitude=0;
+raydium_camera_rumble_evolution=0;
+raydium_camera_rumble_remaining=0;
+raydium_window_view_update();
+raydium_internal_vertex_next_extras=0;
+raydium_sky_force=0;
+raydium_osd_logo_angle=0;
+raydium_osd_cursor_texture=0;
+raydium_register_variable_index=0;
+raydium_register_function_index=0;
+raydium_file_log_fopen_index=0;
+raydium_frame_time=0;
+
+for(i=0;i<4;i++)
+raydium_osd_color[i]=1.f;
+
+raydium_background_color_change(1,1,1,1);
+raydium_fog_mode();
+raydium_fog_enable();
+
+glEnable(GL_TEXTURE_2D);
+glEnable(GL_DEPTH_TEST);
+glEnable(GL_COLOR_MATERIAL);
+glShadeModel(GL_SMOOTH);
+glDepthFunc(GL_LESS);
+glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+
+
+raydium_light_enable();
+glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);  // mmmmm...
+glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
+raydium_log("Raydium engine reseted to original state");
+}
+
+
+
+void raydium_init_engine(void)
+{
+char autoexec[RAYDIUM_MAX_NAME_LEN];
+
+raydium_signal_install_trap();
+#ifdef WIN32
+// init Win32 OpenGL ARB ext.
+raydium_arb_win32_init();
+#endif
+raydium_internal_size_vector_float_4 = sizeof(GLfloat) * 4;
+raydium_log("Platform \"4xfloat\" vector size is: %i byte(s) long",raydium_internal_size_vector_float_4);
+glGetIntegerv(GL_MAX_TEXTURE_SIZE, &raydium_texture_size_max);
+raydium_log("OpenGL implementation maximum texture size: %ix%i",raydium_texture_size_max,raydium_texture_size_max); 
+glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &raydium_texture_units);
+raydium_log("OpenGL hardware providing %i texture unit(s)",raydium_texture_units); 
+raydium_vertex_x=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_y=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_z=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_normal_x=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_normal_y=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_normal_z=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_normal_visu_x=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_normal_visu_y=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_normal_visu_z=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_texture_u=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_texture_v=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_texture=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLuint));
+raydium_vertex_texture_multi=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLuint));
+raydium_vertex_texture_multi_u=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_texture_multi_v=malloc(RAYDIUM_MAX_VERTICES*sizeof(GLfloat));
+raydium_vertex_tag=malloc(RAYDIUM_MAX_VERTICES);
+// must test more than just the last "big" malloc result..
+if(!raydium_vertex_texture) { raydium_log("Out of memory..."); exit(29); }
+raydium_log("vertex arrays memory: OK");
+raydium_random_randomize();
+raydium_init_key();
+raydium_mouse_init();
+raydium_joy_init(); // and not init_joy, since defined in joy.c, not init.c
+raydium_sound=0;
+raydium_sound_init();
+raydium_callback_set();
+#ifdef PHP_SUPPORT
+raydium_php_init();
+#endif
+
+atexit(raydium_sound_close);
+atexit(raydium_joy_close);
+atexit(raydium_network_close);
+atexit(raydium_internal_dump);
+atexit(raydium_console_history_save);
+raydium_log("atexit functions: OK");
+raydium_init_reset();
+#ifdef ODE_SUPPORT
+raydium_ode_init();
+#endif
+raydium_register_api();
+raydium_log("Engine is now ready.\n\t -----------------------------------------------------------");
+
+if(raydium_init_cli_option("autoexec",autoexec))
+    raydium_php_exec(autoexec);
+}
+
+
+void raydium_init_args(int argc, char **argv)
+{
+int i;
+char logfile[RAYDIUM_MAX_NAME_LEN];
+
+
+raydium_init_argc=argc;
+raydium_init_argv=malloc(argc*sizeof(char *));
+
+for(i=0;i<argc;i++)
+    {
+      raydium_init_argv[i]=malloc(strlen(argv[i])+1);
+      strcpy(raydium_init_argv[i],argv[i]);
+    }
+raydium_log("Using Raydium %s",raydium_version);
+
+if(raydium_init_cli_option("logfile",logfile))
+    {
+    raydium_log_file=fopen(logfile,"wt");
+    if(!raydium_log_file) raydium_log("init: Warning: cannot open logfile (%s) with rw mode",logfile);
+    }
+else raydium_log_file=NULL;
+
+raydium_log("command line args: OK");
+}
+
Index: raydium/rayphp.c
===================================================================
--- raydium/rayphp.c	(revision 0)
+++ raydium/rayphp.c	(revision 1)
@@ -0,0 +1,59 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/rayphp.h"
+#endif 
+
+int raydium_rayphp_repository_file_get(char *path)
+{
+int status;
+int force=0;
+char file[RAYDIUM_MAX_NAME_LEN];
+
+strcpy(file,path);
+
+if(raydium_init_cli_option("repository-force",NULL)) force=1;
+
+raydium_register_variable(file,RAYDIUM_REGISTER_STR,"filename");
+raydium_register_variable(&status,RAYDIUM_REGISTER_INT,"status");
+raydium_register_variable(&force,RAYDIUM_REGISTER_INT,"force");
+
+raydium_php_exec("rayphp/getfile.php");
+
+raydium_register_variable_unregister_last();
+raydium_register_variable_unregister_last();
+raydium_register_variable_unregister_last();
+
+if(status<0) status=0;
+
+return status;
+}
+
+
+// put "path" file (and dependencies, if asked)
+int raydium_rayphp_repository_file_put(char *path, int depends)
+{
+char file[RAYDIUM_MAX_NAME_LEN];
+int status;
+
+strcpy(file,path);
+raydium_register_variable(file,RAYDIUM_REGISTER_STR,"filename");
+raydium_register_variable(&status,RAYDIUM_REGISTER_INT,"status");
+raydium_register_variable(&depends,RAYDIUM_REGISTER_INT,"depends");
+
+raydium_php_exec("rayphp/putfile.php");
+
+raydium_register_variable_unregister_last();
+raydium_register_variable_unregister_last();
+raydium_register_variable_unregister_last();
+
+if(status<0) status=0;
+
+return status;
+}
Index: raydium/reg_api.c
===================================================================
--- raydium/reg_api.c	(revision 0)
+++ raydium/reg_api.c	(revision 1)
@@ -0,0 +1,340 @@
+#ifndef REG_API_C
+#define REG_API_C
+
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/reg_api.h"
+#endif
+
+
+#ifdef REG_API
+#ifdef PHP_SUPPORT
+
+// Part 1: create PHP wrappers
+// light.c
+PHP_v_v(raydium_light_enable)
+PHP_v_v(raydium_light_disable)
+PHP_v_i(raydium_light_on)
+PHP_v_i(raydium_light_off)
+PHP_v_i(raydium_light_switch)
+// fog.c
+PHP_v_v(raydium_fog_enable)
+PHP_v_v(raydium_fog_disable)
+// background.c
+PHP_v_ffff(raydium_background_color_change)
+// sound.c
+PHP_i_s(raydium_sound_load_music)
+PHP_i_if(raydium_sound_SetSourceGain)
+// render.c
+PHP_v_v(raydium_rendering_wireframe)
+PHP_v_v(raydium_rendering_normal)
+PHP_v_v(raydium_rendering_displaylists_enable)
+PHP_v_v(raydium_rendering_displaylists_disable)
+// window.c
+PHP_v_v(raydium_window_view_update)
+PHP_v_fff(raydium_window_view_perspective);
+// console.c
+PHP_v_s(raydium_console_exec_script)
+PHP_v_v(raydium_console_event)
+// log.c
+PHP_v_svaria(raydium_log)
+// capture.c
+PHP_v_s(raydium_capture_frame)
+// key.c
+PHP_i_i(raydium_key_pressed)
+// mouse.c
+PHP_i_i(raydium_mouse_button_pressed)
+// clear.c
+PHP_v_v(raydium_clear_frame);
+// camera.c
+PHP_v_v(raydium_camera_replace);
+// object.c
+PHP_v_s(raydium_object_draw_name);
+// particle2.c
+PHP_i_ss(raydium_particle_generator_load);
+PHP_v_s(raydium_particle_generator_delete_name);
+PHP_v_sfff(raydium_particle_generator_move_name_3f);
+PHP_i_s(raydium_particle_state_dump);
+PHP_i_s(raydium_particle_state_restore);
+
+#ifdef ODE_SUPPORT
+//ode.c
+PHP_v_v(raydium_ode_callback);
+PHP_v_i(raydium_ode_draw_all);
+PHP_v_sffffff(raydium_ode_element_camera_inboard_name);
+PHP_i_s(raydium_ode_element_find);
+PHP_i_ii(raydium_ode_element_delete);
+PHP_i_si(raydium_ode_element_delete_name);
+PHP_v_ii(raydium_ode_element_gravity);
+PHP_v_si(raydium_ode_element_gravity_name);
+//PHP_i_s(raydium_ode_element_ground_texture_get_name);
+PHP_i_sff(raydium_ode_element_material_name);
+PHP_v_sfff(raydium_ode_element_move_name_3f);
+PHP_v_sfff(raydium_ode_element_rotate_name_3f);
+PHP_v_ssi(raydium_ode_element_moveto_name);
+PHP_v_ss(raydium_ode_element_particle_name);
+PHP_i_sf(raydium_ode_element_player_angle_name);
+PHP_i_i(raydium_ode_element_player_get);
+PHP_v_si(raydium_ode_element_rotate_direction_name);
+//PHP_v_sf(raydium_ode_element_rotateq_name);
+PHP_i_sf(raydium_ode_element_rotfriction_name);
+//PHP_i_sf(raydium_ode_element_rotq_get_name);
+PHP_i_sf(raydium_ode_element_slip_name);
+PHP_v_ii(raydium_ode_element_sound_update);
+PHP_v_si(raydium_ode_element_sound_update_name);
+PHP_i_i(raydium_ode_element_tag_get);
+PHP_i_s(raydium_ode_element_touched_get_name);
+PHP_v_si(raydium_ode_element_ttl_set_name);
+PHP_v_s(raydium_ode_ground_set_name);
+PHP_i_sssffffff(raydium_ode_joint_attach_hinge_name);
+PHP_i_sssffffff(raydium_ode_joint_attach_hinge2_name);
+PHP_v_sf(raydium_ode_joint_break_force_name);
+PHP_v_sff(raydium_ode_joint_hinge_limits_name);
+PHP_v_si(raydium_ode_joint_hinge2_block_name);
+PHP_v_sff(raydium_ode_joint_suspension_name);
+PHP_i_ssffff(raydium_ode_launcher_name_3f);
+PHP_i_ssffff(raydium_ode_launcher_simple_name_3f);
+PHP_v_sf(raydium_ode_motor_angle_name);
+PHP_v_ssi(raydium_ode_motor_attach_name);
+PHP_i_sii(raydium_ode_motor_create);
+PHP_v_si(raydium_ode_motor_gear_change_name);
+PHP_v_sf(raydium_ode_motor_power_max_name);
+PHP_v_sfff(raydium_ode_motor_rocket_orientation_name);
+PHP_v_si(raydium_ode_motor_rocket_playermovement_name);
+PHP_v_ssfff(raydium_ode_motor_rocket_set_name);
+PHP_v_sf(raydium_ode_motor_speed_name);
+PHP_f_si(raydium_ode_motor_speed_get_name);
+PHP_v_ss(raydium_ode_name_auto);
+PHP_i_siffffiis(raydium_ode_object_box_add);
+PHP_i_s(raydium_ode_object_create);
+PHP_i_i(raydium_ode_object_delete);
+PHP_i_s(raydium_ode_object_delete_name);
+PHP_i_s(raydium_ode_object_find);
+PHP_v_sfff(raydium_ode_object_move_name_3f);
+PHP_i_siffiis(raydium_ode_object_sphere_add);
+PHP_v_f(raydium_ode_time_change);
+PHP_i_s(raydium_ode_capture_3d);
+
+// ode_net.c
+PHP_i_i(raydium_ode_network_element_isdistant);
+PHP_v_v(raydium_ode_network_element_send_all);
+PHP_v_i(raydium_ode_network_element_send_iterative);
+PHP_v_i(raydium_ode_network_element_send_random);
+#endif
+
+// gui.c
+PHP_i_s(raydium_gui_theme_load);
+PHP_v_v(raydium_gui_show);
+PHP_v_v(raydium_gui_hide);
+PHP_i_v(raydium_gui_isvisible);
+PHP_v_s(raydium_gui_window_delete_name);
+PHP_v_fff(raydium_gui_widget_sizes);
+PHP_i_sffff(raydium_gui_window_create);
+PHP_i_siffs(raydium_gui_button_create_simple);
+PHP_i_siffsfff(raydium_gui_label_create);
+PHP_i_siffiii(raydium_gui_track_create);
+PHP_i_siffs(raydium_gui_edit_create);
+PHP_i_siffsi(raydium_gui_check_create);
+PHP_i_siffsi(raydium_gui_combo_create);
+PHP_i_sss(raydium_gui_read_name);
+PHP_i_v(raydium_gui_button_clicked);
+
+// Part 2: register functions
+void raydium_register_api(void)
+{
+static int done=0;
+
+if(done)
+    {
+    raydium_log("RegAPI: PASSED (already done previously)");
+    return;
+    }
+
+// light.c
+raydium_register_function(C2PHP(raydium_light_enable),"raydium_light_enable");
+raydium_register_function(C2PHP(raydium_light_disable),"raydium_light_disable");
+raydium_register_function(C2PHP(raydium_light_on),"raydium_light_on");
+raydium_register_function(C2PHP(raydium_light_off),"raydium_light_off");
+raydium_register_function(C2PHP(raydium_light_switch),"raydium_light_switch");
+
+// fog.c
+raydium_register_function(C2PHP(raydium_fog_enable),"raydium_fog_enable");
+raydium_register_function(C2PHP(raydium_fog_disable),"raydium_fog_disable");
+
+// background.c
+raydium_register_function(C2PHP(raydium_background_color_change),"raydium_background_color_change");
+
+// sound.c
+raydium_register_function(C2PHP(raydium_sound_load_music),"raydium_sound_load_music");
+raydium_register_function(C2PHP(raydium_sound_SetSourceGain),"raydium_sound_setsourcegain");
+
+// render.c
+raydium_register_function(C2PHP(raydium_rendering_wireframe),"raydium_rendering_wireframe");
+raydium_register_function(C2PHP(raydium_rendering_normal),"raydium_rendering_normal");
+raydium_register_function(C2PHP(raydium_rendering_displaylists_enable),"raydium_rendering_displaylists_enable");
+raydium_register_function(C2PHP(raydium_rendering_displaylists_disable),"raydium_rendering_displaylists_disable");
+raydium_register_variable(&raydium_render_fps,RAYDIUM_REGISTER_INT,"raydium_render_fps");
+
+// window.c / projection
+raydium_register_function(C2PHP(raydium_window_view_perspective),"raydium_window_view_perspective");
+raydium_register_function(C2PHP(raydium_window_view_update),"raydium_window_view_update");
+
+// sky.c
+raydium_register_variable(&raydium_sky_force,RAYDIUM_REGISTER_INT,"raydium_sky_force");
+
+// console.c
+raydium_register_function(C2PHP(raydium_console_exec_script),"raydium_console_exec_script");
+raydium_register_function(C2PHP(raydium_console_event),"raydium_console_event");
+raydium_register_variable(raydium_console_config_texture,RAYDIUM_REGISTER_STR,"raydium_console_config_texture");
+
+// log.c
+raydium_register_function(C2PHP(raydium_log),"raydium_log");
+
+// capture.c
+raydium_register_function(C2PHP(raydium_capture_frame),"raydium_capture_frame");
+
+// key.c
+raydium_register_variable(&raydium_key_last,RAYDIUM_REGISTER_INT,"raydium_key_last");
+raydium_register_function(C2PHP(raydium_key_pressed),"raydium_key_pressed");
+
+// mouse.c
+raydium_register_variable(&raydium_mouse_x,RAYDIUM_REGISTER_INT,"raydium_mouse_x");
+raydium_register_variable(&raydium_mouse_y,RAYDIUM_REGISTER_INT,"raydium_mouse_y");
+raydium_register_variable(&raydium_mouse_click,RAYDIUM_REGISTER_INT,"raydium_mouse_click");
+raydium_register_function(C2PHP(raydium_mouse_button_pressed),"raydium_mouse_button_pressed");
+
+// clear.c
+raydium_register_function(C2PHP(raydium_clear_frame),"raydium_clear_frame");
+
+// camera.c
+raydium_register_function(C2PHP(raydium_camera_replace),"raydium_camera_replace");
+
+// object.c
+raydium_register_function(C2PHP(raydium_object_draw_name),"raydium_object_draw_name");
+
+// particle2.c
+raydium_register_function(C2PHP(raydium_particle_state_dump),"raydium_particle_state_dump");
+raydium_register_function(C2PHP(raydium_particle_state_restore),"raydium_particle_state_restore");
+raydium_register_function(C2PHP(raydium_particle_generator_load),"raydium_particle_generator_load");
+raydium_register_function(C2PHP(raydium_particle_generator_delete_name),"raydium_particle_generator_delete_name");
+raydium_register_function(C2PHP(raydium_particle_generator_move_name_3f),"raydium_particle_generator_move_name_3f");
+
+// gui.c
+raydium_register_function(C2PHP(raydium_gui_theme_load),"raydium_gui_theme_load");
+raydium_register_function(C2PHP(raydium_gui_show),"raydium_gui_show");
+raydium_register_function(C2PHP(raydium_gui_hide),"raydium_gui_hide");
+raydium_register_function(C2PHP(raydium_gui_isvisible),"raydium_gui_isvisible");
+raydium_register_function(C2PHP(raydium_gui_window_delete_name),"raydium_gui_window_delete_name");
+raydium_register_function(C2PHP(raydium_gui_widget_sizes),"raydium_gui_widget_sizes");
+raydium_register_function(C2PHP(raydium_gui_window_create),"raydium_gui_window_create");
+raydium_register_function(C2PHP(raydium_gui_button_create_simple),"raydium_gui_button_create_simple");
+raydium_register_function(C2PHP(raydium_gui_label_create),"raydium_gui_label_create");
+raydium_register_function(C2PHP(raydium_gui_track_create),"raydium_gui_track_create");
+raydium_register_function(C2PHP(raydium_gui_edit_create),"raydium_gui_edit_create");
+raydium_register_function(C2PHP(raydium_gui_check_create),"raydium_gui_check_create");
+raydium_register_function(C2PHP(raydium_gui_combo_create),"raydium_gui_combo_create");
+raydium_register_function(C2PHP(raydium_gui_read_name),"raydium_gui_read_name");
+raydium_register_function(C2PHP(raydium_gui_button_clicked),"raydium_gui_button_clicked");
+
+
+#ifdef ODE_SUPPORT
+// ode.c
+raydium_register_function(C2PHP(raydium_ode_callback),"raydium_ode_callback");
+raydium_register_function(C2PHP(raydium_ode_draw_all),"raydium_ode_draw_all");
+raydium_register_function(C2PHP(raydium_ode_element_camera_inboard_name),"raydium_ode_element_camera_inboard_name");
+raydium_register_function(C2PHP(raydium_ode_element_find),"raydium_ode_element_find");
+raydium_register_function(C2PHP(raydium_ode_element_delete),"raydium_ode_element_delete");
+raydium_register_function(C2PHP(raydium_ode_element_delete_name),"raydium_ode_element_delete_name");
+raydium_register_function(C2PHP(raydium_ode_element_gravity),"raydium_ode_element_gravity");
+raydium_register_function(C2PHP(raydium_ode_element_gravity_name),"raydium_ode_element_gravity_name");
+//raydium_register_function(C2PHP(raydium_ode_element_ground_texture_get_name),"raydium_ode_element_ground_texture_get_name");
+raydium_register_function(C2PHP(raydium_ode_element_material_name),"raydium_ode_element_material_name");
+raydium_register_function(C2PHP(raydium_ode_element_move_name_3f),"raydium_ode_element_move_name_3f");
+raydium_register_function(C2PHP(raydium_ode_element_rotate_name_3f),"raydium_ode_element_rotate_name_3f");
+raydium_register_function(C2PHP(raydium_ode_element_moveto_name),"raydium_ode_element_moveto_name");
+raydium_register_function(C2PHP(raydium_ode_element_particle_name),"raydium_ode_element_particle_name");
+raydium_register_function(C2PHP(raydium_ode_element_player_angle_name),"raydium_ode_element_player_angle_name");
+raydium_register_function(C2PHP(raydium_ode_element_player_get),"raydium_ode_element_player_get");
+raydium_register_function(C2PHP(raydium_ode_element_rotate_direction_name),"raydium_ode_element_rotate_direction_name");
+//raydium_register_function(C2PHP(raydium_ode_element_rotateq_name),"raydium_ode_element_rotateq_name");
+raydium_register_function(C2PHP(raydium_ode_element_rotfriction_name),"raydium_ode_element_rotfriction_name");
+//raydium_register_function(C2PHP(raydium_ode_element_rotq_get_name),"raydium_ode_element_rotq_get_name");
+raydium_register_function(C2PHP(raydium_ode_element_slip_name),"raydium_ode_element_slip_name");
+raydium_register_function(C2PHP(raydium_ode_element_sound_update),"raydium_ode_element_sound_update");
+raydium_register_function(C2PHP(raydium_ode_element_sound_update_name),"raydium_ode_element_sound_update_name");
+raydium_register_function(C2PHP(raydium_ode_element_tag_get),"raydium_ode_element_tag_get");
+raydium_register_function(C2PHP(raydium_ode_element_touched_get_name),"raydium_ode_element_touched_get_name");
+raydium_register_function(C2PHP(raydium_ode_element_ttl_set_name),"raydium_ode_element_ttl_set_name");
+raydium_register_function(C2PHP(raydium_ode_ground_set_name),"raydium_ode_ground_set_name");
+raydium_register_function(C2PHP(raydium_ode_joint_attach_hinge_name),"raydium_ode_joint_attach_hinge_name");
+raydium_register_function(C2PHP(raydium_ode_joint_attach_hinge2_name),"raydium_ode_joint_attach_hinge2_name");
+raydium_register_function(C2PHP(raydium_ode_joint_break_force_name),"raydium_ode_joint_break_force_name");
+raydium_register_function(C2PHP(raydium_ode_joint_hinge_limits_name),"raydium_ode_joint_hinge_limits_name");
+raydium_register_function(C2PHP(raydium_ode_joint_hinge2_block_name),"raydium_ode_joint_hinge2_block_name");
+raydium_register_function(C2PHP(raydium_ode_joint_suspension_name),"raydium_ode_joint_suspension_name");
+raydium_register_function(C2PHP(raydium_ode_launcher_name_3f),"raydium_ode_launcher_name_3f");
+raydium_register_function(C2PHP(raydium_ode_launcher_simple_name_3f),"raydium_ode_launcher_simple_name_3f");
+raydium_register_function(C2PHP(raydium_ode_motor_angle_name),"raydium_ode_motor_angle_name");
+raydium_register_function(C2PHP(raydium_ode_motor_attach_name),"raydium_ode_motor_attach_name");
+raydium_register_function(C2PHP(raydium_ode_motor_create),"raydium_ode_motor_create");
+raydium_register_function(C2PHP(raydium_ode_motor_gear_change_name),"raydium_ode_motor_gear_change_name");
+raydium_register_function(C2PHP(raydium_ode_motor_power_max_name),"raydium_ode_motor_power_max_name");
+raydium_register_function(C2PHP(raydium_ode_motor_rocket_orientation_name),"raydium_ode_motor_rocket_orientation_name");
+raydium_register_function(C2PHP(raydium_ode_motor_rocket_playermovement_name),"raydium_ode_motor_rocket_playermovement_name");
+raydium_register_function(C2PHP(raydium_ode_motor_rocket_set_name),"raydium_ode_motor_rocket_set_name");
+raydium_register_function(C2PHP(raydium_ode_motor_speed_name),"raydium_ode_motor_speed_name");
+raydium_register_function(C2PHP(raydium_ode_motor_speed_get_name),"raydium_ode_motor_speed_get_name");
+raydium_register_function(C2PHP(raydium_ode_name_auto),"raydium_ode_name_auto");
+raydium_register_function(C2PHP(raydium_ode_object_box_add),"raydium_ode_object_box_add");
+raydium_register_function(C2PHP(raydium_ode_object_create),"raydium_ode_object_create");
+raydium_register_function(C2PHP(raydium_ode_object_delete),"raydium_ode_object_delete");
+raydium_register_function(C2PHP(raydium_ode_object_delete_name),"raydium_ode_object_delete_name");
+raydium_register_function(C2PHP(raydium_ode_object_find),"raydium_ode_object_find");
+raydium_register_function(C2PHP(raydium_ode_object_move_name_3f),"raydium_ode_object_move_name_3f");
+raydium_register_function(C2PHP(raydium_ode_object_sphere_add),"raydium_ode_object_sphere_add");
+raydium_register_function(C2PHP(raydium_ode_time_change),"raydium_ode_time_change");
+raydium_register_function(C2PHP(raydium_ode_capture_3d),"raydium_ode_capture_3d");
+raydium_register_variable_const_i(RAYDIUM_ODE_AUTODETECT,"RAYDIUM_ODE_AUTODETECT");
+raydium_register_variable_const_i(RAYDIUM_ODE_STANDARD,"RAYDIUM_ODE_STANDARD");
+raydium_register_variable_const_i(RAYDIUM_ODE_STATIC,"RAYDIUM_ODE_STATIC");
+raydium_register_variable_const_i(RAYDIUM_ODE_FIXING,"RAYDIUM_ODE_FIXING");
+raydium_register_variable_const_i(RAYDIUM_ODE_MOTOR_ENGINE,"RAYDIUM_ODE_MOTOR_ENGINE");
+raydium_register_variable_const_i(RAYDIUM_ODE_MOTOR_ANGULAR,"RAYDIUM_ODE_MOTOR_ANGULAR");
+raydium_register_variable_const_i(RAYDIUM_ODE_MOTOR_ROCKET,"RAYDIUM_ODE_MOTOR_ROCKET");
+raydium_register_variable_const_f(RAYDIUM_ODE_SLIP_ICE,"RAYDIUM_ODE_SLIP_ICE");
+raydium_register_variable_const_f(RAYDIUM_ODE_SLIP_PLAYER,"RAYDIUM_ODE_SLIP_PLAYER");
+raydium_register_variable_const_f(RAYDIUM_ODE_SLIP_NORMAL,"RAYDIUM_ODE_SLIP_NORMAL");
+
+// ode_net.c
+raydium_register_function(C2PHP(raydium_ode_network_element_isdistant),"raydium_ode_network_element_isdistant");
+raydium_register_function(C2PHP(raydium_ode_network_element_send_all),"raydium_ode_netword_element_send_all");
+raydium_register_function(C2PHP(raydium_ode_network_element_send_iterative),"raydium_ode_network_element_send_iterative");
+raydium_register_function(C2PHP(raydium_ode_network_element_send_random),"raydium_ode_element_send_random");
+#endif
+raydium_log("RegAPI: OK");
+done=1;
+}
+
+#else
+void raydium_register_api(void) 
+{
+/* no PHP */
+raydium_log("RegAPI: DISABLED (No PHP support)");
+};
+#endif
+
+#else
+void raydium_register_api(void)
+{
+/* no REG_API */
+raydium_log("RegAPI: DISABLED (config.h: no REG_API symbol)");
+};
+#endif
+#endif
Index: raydium/object.c
===================================================================
--- raydium/object.c	(revision 0)
+++ raydium/object.c	(revision 1)
@@ -0,0 +1,176 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/object.h"
+#endif 
+
+GLint raydium_object_find(char *name)
+{
+GLint i;
+for(i=0;i<raydium_object_index;i++)
+if(!strcmp(raydium_object_name[i],name)) return i;
+
+return -1;
+}
+
+
+void raydium_object_reset(GLuint o)
+{
+raydium_object_name[o][0]=0;
+raydium_object_start[o]=0;
+raydium_object_end[o]=0;
+}
+
+
+int raydium_object_load(char *filename)
+{
+if(raydium_object_find(filename)>=0)
+    {
+    raydium_log("ERROR: object: %s already loaded",filename);
+    return -1;
+    }
+raydium_object_start[raydium_object_index]=raydium_vertex_index;
+read_vertex_from(filename);
+raydium_object_end[raydium_object_index]=raydium_vertex_index;
+strcpy(raydium_object_name[raydium_object_index],filename);
+return(raydium_object_index++);
+}
+
+GLint raydium_object_find_load(char *name)
+{
+int ret;
+
+ret=raydium_object_find(name);
+if(ret<0) return raydium_object_load(name);
+return ret;
+}
+
+
+void raydium_object_draw(GLuint o)
+{
+#ifndef DEBUG_RENDER_DISABLE_DISPLAYLISTS
+static GLuint dl[RAYDIUM_MAX_OBJECTS];
+static char dl_state[RAYDIUM_MAX_OBJECTS];
+static int first=0;
+int i;
+
+if(first)
+    for(i=0;i<RAYDIUM_MAX_OBJECTS;i++)
+	dl_state[i]=-1;
+
+
+if(raydium_render_displaylists_tag)
+{
+ if(!dl_state[o])
+    {
+    // build DL
+    dl_state[o]=1;
+    dl[o]=glGenLists(1);
+    raydium_log("Object: creating display list for object %s",raydium_object_name[o]);
+    glNewList(dl[o],GL_COMPILE);
+    raydium_rendering_from_to(raydium_object_start[o],raydium_object_end[o]);
+    glEndList();
+    }
+  glCallList(dl[o]);
+}
+else raydium_rendering_from_to(raydium_object_start[o],raydium_object_end[o]);
+
+#else
+// No display lists, draw 
+raydium_rendering_from_to(raydium_object_start[o],raydium_object_end[o]);
+#endif
+}
+
+void raydium_object_draw_name(char *name)
+{
+GLint i;
+
+i=raydium_object_find(name);
+
+if(i>=0) raydium_object_draw(i); 
+else 
+raydium_object_draw(raydium_object_load(name));
+}
+
+
+void raydium_object_deform(GLuint obj,GLfloat ampl)
+{
+GLuint i;
+
+
+for(i=raydium_object_start[obj];i<raydium_object_end[obj];i++)
+    {
+    raydium_vertex_x[i]+=raydium_random_neg_pos_1()*ampl;
+    raydium_vertex_y[i]+=raydium_random_neg_pos_1()*ampl;
+    raydium_vertex_z[i]+=raydium_random_neg_pos_1()*ampl;
+    }
+
+/*
+GLfloat ox,oy,oz;
+GLfloat nx,ny,nz;
+GLint j;
+
+for(i=raydium_object_start[obj];i<raydium_object_end[obj];i++)
+    {
+    ox=raydium_vertex_x[i];
+    oy=raydium_vertex_y[i];
+    oz=raydium_vertex_z[i];
+
+    nx=ox+raydium_random_neg_pos_1()*ampl;
+    ny=oy+raydium_random_neg_pos_1()*ampl;
+    nz=oz+raydium_random_neg_pos_1()*ampl;
+
+    for(j=i;j<raydium_object_end[obj];j++)
+	if(raydium_vertex_x[j]==ox && 
+	   raydium_vertex_y[j]==oy && 
+	   raydium_vertex_z[j]==oz)
+	{
+	raydium_vertex_x[j]=nx;
+	raydium_vertex_y[j]=ny;
+	raydium_vertex_z[j]=nz;
+	}
+    }*/
+}
+
+
+void raydium_object_deform_name(char *name,GLfloat ampl)
+{
+raydium_object_deform(raydium_object_find(name),ampl);
+}
+
+
+GLfloat raydium_object_find_dist_max(GLuint obj)
+{
+GLfloat max=0,val;
+int i;
+for(i=raydium_object_start[obj];i<raydium_object_end[obj];i++)
+    {
+    val=sqrt((raydium_vertex_x[i]*raydium_vertex_x[i])+
+	     (raydium_vertex_y[i]*raydium_vertex_y[i])+
+	    (raydium_vertex_z[i]*raydium_vertex_z[i]) );
+    if(val>max) max=val;
+    }
+return max;
+}
+
+void raydium_object_find_axes_max(GLuint obj, GLfloat *tx, GLfloat *ty, GLfloat *tz)
+{
+int i;
+*tx=*ty=*tz=0;
+
+for(i=raydium_object_start[obj];i<raydium_object_end[obj];i++)
+    {
+    if(raydium_trigo_abs(raydium_vertex_x[i])>*tx) *tx=raydium_trigo_abs(raydium_vertex_x[i]);
+    if(raydium_trigo_abs(raydium_vertex_y[i])>*ty) *ty=raydium_trigo_abs(raydium_vertex_y[i]);
+    if(raydium_trigo_abs(raydium_vertex_z[i])>*tz) *tz=raydium_trigo_abs(raydium_vertex_z[i]);
+    }
+*tx*=2;
+*ty*=2;
+*tz*=2;
+}
Index: raydium/config.h
===================================================================
--- raydium/config.h	(revision 0)
+++ raydium/config.h	(revision 1)
@@ -0,0 +1,54 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+// Raydium configuration file
+// For other options, see common.h
+
+// Enable PHP support
+#define PHP_SUPPORT
+#define PHP_INI_PATH "./"
+
+
+#ifndef NO_ODE_SUPPORT
+// Enable ODE physics support
+#define ODE_SUPPORT
+#define ODE_QUICKSTEP
+#define ODE_PREDICTION
+//#define ODE_NETWORK_GHOSTS
+#endif
+
+// RegApi Support (exports Raydium API to PHP)
+#define REG_API
+
+// enable profiling
+#define DEBUG_PROFILE
+
+// (link to OpenAL is always required !)
+//#define NO_SOUND_DEBUG
+
+// will highlight triangle with tag != 0 at render time :
+//#define RENDER_DEBUG_TAG
+
+// enable key traces
+//#define DEBUG_KEYS
+
+// disable clipping
+//#define RENDER_DEBUG_NO_CLIP
+
+// disable display list optims
+//#define DEBUG_RENDER_DISABLE_DISPLAYLISTS
+
+// debug network "tcp style" ACKs
+//#define DEBUG_NETWORK
+
+// debug ODE Network interface (verbose !)
+//#define DEBUG_ODENET
+
+// movie linear framerate (1/x sec) (starts recording, too)
+//#define DEBUG_MOVIE 2
+
+// allow vertex lighting for lightmaps textures
+//#define RENDER_ALLOW_LIGHTING_FOR_LIGHTMAPS
Index: raydium/fog.c
===================================================================
--- raydium/fog.c	(revision 0)
+++ raydium/fog.c	(revision 1)
@@ -0,0 +1,39 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/fog.h"
+
+#endif 
+
+void raydium_fog_enable(void)
+{
+glEnable(GL_FOG);
+raydium_fog_enabled_tag=1;
+}
+
+void raydium_fog_disable(void)
+{
+glDisable(GL_FOG);
+raydium_fog_enabled_tag=0;
+}
+
+void raydium_fog_color_update(void)
+{
+glFogfv(GL_FOG_COLOR,raydium_background_color);
+}
+
+// NOT A FINAL PROTOTYPE ! DO NOT USE BY YOURSELF ! (test only)
+// Note : i've removed args until final signature (if any)
+void raydium_fog_mode(void)
+{
+glFogi(GL_FOG_MODE,GL_LINEAR);
+glFogf(GL_FOG_START,raydium_projection_far/4); // hum...
+glFogf(GL_FOG_END,raydium_projection_far);
+raydium_fog_color_update();
+}
Index: raydium/ode_net.c
===================================================================
--- raydium/ode_net.c	(revision 0)
+++ raydium/ode_net.c	(revision 1)
@@ -0,0 +1,596 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+
+// This .c file is included from ode.c, so there's no includes here.
+
+void raydium_ode_network_element_new(int e);
+
+
+int raydium_ode_network_MaxElementsPerPacket(void)
+{
+return ((RAYDIUM_NETWORK_PACKET_SIZE-RAYDIUM_NETWORK_PACKET_OFFSET)/sizeof(raydium_ode_network_Event)-1);
+}
+
+
+int raydium_network_nid_element_find(int nid)
+{
+int i;
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state && raydium_ode_element[i].nid==nid)
+	return i;
+return -1;
+}
+
+void raydium_ode_network_newdel_event(int type,char *buff)
+{
+int id;
+int nid,dec,elem;
+int tag;
+dReal get[4];
+dReal default_pos[3]={0,0,9999};
+
+id=buff[1];
+if(id==raydium_network_uid) return; // do not update our elements
+//raydium_log("ode_net: new or del event received... (%i)",type);
+
+dec=RAYDIUM_NETWORK_PACKET_OFFSET;
+memcpy(&nid,buff+dec,sizeof(int));
+elem=raydium_network_nid_element_find(nid);
+dec+=sizeof(int);
+
+if(type==RAYDIUM_NETWORK_PACKET_ODE_NEWELEM)
+    {
+    int type;
+    char mesh[RAYDIUM_MAX_NAME_LEN];
+    char name[RAYDIUM_MAX_NAME_LEN];
+    int group;
+
+//    raydium_log("ode_net: NEWELEM event, from %i",buff[1]);
+    
+    // if we already have this element, refresh it
+    if(elem>=0) 
+	raydium_ode_element_delete(elem,1);
+    
+    memcpy(&type,buff+dec,sizeof(int));
+    dec+=sizeof(int);
+
+    memcpy(get,buff+dec,sizeof(dReal)*3);
+    dec+=(sizeof(dReal)*3);
+
+    memcpy(&tag,buff+dec,sizeof(int));
+    dec+=sizeof(int);
+
+    strcpy(mesh,buff+dec);
+    sprintf(name,"net_%i",nid); // may use the other side element name ?
+
+    group=raydium_ode_object_find("DISTANT");
+    switch(type)
+	{
+	case dSphereClass:
+	    raydium_ode_network_distant_create=1;
+	    elem=raydium_ode_object_sphere_add(name,group,1,get[0],RAYDIUM_ODE_STATIC,tag,mesh);
+	    break;
+	case dBoxClass:
+	    raydium_ode_network_distant_create=1;
+	    elem=raydium_ode_object_box_add(name,group,1,get[0],get[1],get[2],RAYDIUM_ODE_STATIC,tag,mesh);
+	    break;
+	}
+    raydium_ode_element[elem].distant_owner=buff[1];
+    raydium_ode_element[elem].nid=nid;
+    raydium_ode_element[elem].lastnetupdate=time(NULL);
+    raydium_ode_element_move(elem,default_pos);
+//    raydium_log("ode_net: ... new: %s",raydium_ode_element[elem].name);
+    }
+
+if(type==RAYDIUM_NETWORK_PACKET_ODE_REMELEM)
+    {
+    if(elem<0) return;
+    if(!raydium_ode_element[elem].distant) return;
+    raydium_ode_element_delete(elem,1);
+//    raydium_log("ode_net: ... delete: %s",raydium_ode_element[elem].name);
+    }
+
+}
+
+void raydium_ode_network_nidwho_event(int type,char *buff)
+{
+int nid,elem;
+memcpy(&nid,buff+RAYDIUM_NETWORK_PACKET_OFFSET,sizeof(int));
+elem=raydium_network_nid_element_find(nid);
+
+if(elem<0) return;
+
+// test if we are owner of elem
+if(!raydium_ode_element[elem].distant)
+    {
+    //raydium_log("ode_net: sending answer to nidwho request for %s",raydium_ode_element[elem].name);
+    raydium_ode_network_element_new(elem);
+    }
+}
+
+
+
+void raydium_ode_network_explosion_event(int type,char *buff)
+{
+raydium_ode_network_Explosion *exp;
+
+exp=(raydium_ode_network_Explosion *)(buff+RAYDIUM_NETWORK_PACKET_OFFSET);
+raydium_ode_network_explosion_create=1; // really create explosion
+
+if(exp->type==RAYDIUM_ODE_NETWORK_EXPLOSION_EXPL)
+    {
+    // needs to (automaticaly) generates a "name" for explosions
+    char name[RAYDIUM_MAX_NAME_LEN];
+    raydium_ode_name_auto("net_expl",name);
+    raydium_ode_explosion_create(name,exp->radius,exp->propag,exp->pos);
+    }
+
+if(exp->type==RAYDIUM_ODE_NETWORK_EXPLOSION_BLOW)
+    raydium_ode_explosion_blow(exp->radius,exp->force,exp->pos);
+
+// Useless, but...
+raydium_ode_network_explosion_create=0;
+}
+
+void raydium_ode_network_init(void)
+{
+char opt[128];
+raydium_ode_network_maxfreq=RAYDIUM_ODE_NETWORK_MAXFREQ;
+raydium_network_netcall_add(raydium_ode_network_newdel_event,RAYDIUM_NETWORK_PACKET_ODE_NEWELEM,1);
+raydium_network_netcall_add(raydium_ode_network_newdel_event,RAYDIUM_NETWORK_PACKET_ODE_REMELEM,1);
+raydium_network_netcall_add(raydium_ode_network_nidwho_event,RAYDIUM_NETWORK_PACKET_ODE_NIDWHO,1);
+raydium_network_netcall_add(raydium_ode_network_explosion_event,RAYDIUM_NETWORK_PACKET_ODE_EXPLOSION,1);
+if(raydium_init_cli_option("ode-rate",opt))
+    raydium_ode_network_maxfreq=atoi(opt);
+
+raydium_ode_object_create("DISTANT");
+raydium_ode_object_colliding_name("DISTANT",0);
+}
+
+
+char raydium_ode_network_TimeToSend(void)
+{
+static float time;
+
+time+=raydium_frame_time;
+
+if(time > (1.0/raydium_ode_network_maxfreq))
+    {
+    time=0;
+    return 1;
+    }
+return 0;
+}
+
+// Refresh elements pos/rot to network
+void raydium_ode_network_element_send(short nelems, int *e)
+{
+char data[RAYDIUM_NETWORK_PACKET_SIZE];
+raydium_ode_network_Event set;
+int dec;
+int i;
+short real=0;
+dReal q[4];
+dReal *p;
+
+if(raydium_network_mode!=RAYDIUM_NETWORK_MODE_CLIENT)
+    return;
+
+dec=RAYDIUM_NETWORK_PACKET_OFFSET;
+
+dec+=sizeof(nelems);
+
+for(i=0;i<nelems;i++)
+ {
+ if(!raydium_ode_element_isvalid(e[i])) continue;
+ if(raydium_ode_element[e[i]].nid<0) continue;
+ if(raydium_ode_element[e[i]].distant) continue;
+
+ set.nid=raydium_ode_element[e[i]].nid;
+
+ p=raydium_ode_element_pos_get(e[i]);
+ memcpy(set.pos,p,sizeof(dReal)*3);
+
+ raydium_ode_element_rotq_get(e[i],q);
+ memcpy(set.rot,q,sizeof(dReal)*4);
+
+ p=raydium_ode_element_linearvelocity_get(e[i]);
+ memcpy(set.vel,p,sizeof(dReal)*3);
+
+ memcpy(data+dec,&set,sizeof(set));
+ dec+=sizeof(set);
+ real++;
+ if(dec>=RAYDIUM_NETWORK_PACKET_SIZE)
+    {
+    raydium_log("ode_net: PACKET SIZE TOO SMALL !");
+    return;
+    }
+ }
+memcpy(data+RAYDIUM_NETWORK_PACKET_OFFSET,&real,sizeof(real));
+raydium_network_write(NULL,raydium_network_uid,RAYDIUM_NETWORK_PACKET_ODE_DATA,data);
+
+}
+
+void raydium_ode_network_element_send_all(void)
+{
+int i,n;
+int e[RAYDIUM_ODE_MAX_ELEMENTS];
+
+if(!raydium_ode_network_TimeToSend()) return;
+
+n=0;
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+ if(raydium_ode_element_isvalid(i) &&
+    raydium_ode_element[i].nid>=0 )
+	{
+	e[n]=i;
+	n++;
+	}
+raydium_ode_network_element_send(n,e);
+}
+
+
+void raydium_ode_network_element_send_random(int nelems)
+{
+int i=0;
+int n;
+int done[RAYDIUM_ODE_MAX_ELEMENTS];
+int e[RAYDIUM_ODE_MAX_ELEMENTS];
+int total=0;
+
+if(!raydium_ode_network_TimeToSend()) return;
+
+if(nelems==RAYDIUM_ODE_NETWORK_OPTIMAL)
+    nelems=raydium_ode_network_MaxElementsPerPacket();
+
+memset(done,0,RAYDIUM_ODE_MAX_ELEMENTS*sizeof(int));
+
+while(i<nelems)
+    {
+    n=raydium_random_i(0,RAYDIUM_ODE_MAX_ELEMENTS);
+    if(raydium_ode_element[n].state && raydium_ode_element[n].nid>=0 && !done[n])
+	{
+	done[n]=1;
+	e[i]=n;
+	i++;
+	}
+    total++;
+    if(total>RAYDIUM_ODE_MAX_ELEMENTS) break;
+    }
+raydium_ode_network_element_send(i,e);
+}
+
+
+void raydium_ode_network_element_send_iterative(int nelems)
+{
+static int curr=-1;
+int i=0;
+int e[RAYDIUM_ODE_MAX_ELEMENTS];
+int total=0;
+
+if(!raydium_ode_network_TimeToSend()) return;
+
+if(nelems==RAYDIUM_ODE_NETWORK_OPTIMAL)
+    nelems=raydium_ode_network_MaxElementsPerPacket();
+
+while(i<nelems)
+    {
+    curr++;
+    if(curr>=RAYDIUM_ODE_MAX_ELEMENTS) curr=0;
+    if(raydium_ode_element[curr].state && raydium_ode_element[curr].nid>=0)
+	{
+	e[i]=curr;
+	i++;
+	}
+    total++;
+    if(total>RAYDIUM_ODE_MAX_ELEMENTS) break;
+    }
+raydium_ode_network_element_send(i,e);
+}
+
+
+void raydium_ode_network_nidwho(int nid)
+{
+char data[RAYDIUM_NETWORK_PACKET_SIZE];
+
+// limit nidwho req freq
+if(!raydium_ode_network_TimeToSend()) return;
+
+memcpy(data+RAYDIUM_NETWORK_PACKET_OFFSET,&nid,sizeof(int));
+raydium_network_write(NULL,raydium_network_uid,RAYDIUM_NETWORK_PACKET_ODE_NIDWHO,data);
+}
+
+void raydium_ode_network_apply(raydium_ode_network_Event *ev)
+{
+int elem,i;
+unsigned long now;
+unsigned long before;
+dReal factor;
+dReal *pos;
+dReal Pcross[3];
+
+elem=raydium_network_nid_element_find(ev->nid);
+if(elem<0) 
+    {
+    // ask for this nid:
+    raydium_ode_network_nidwho(ev->nid);
+    return; // nid not found.. unknown element !
+    }
+
+raydium_ode_element[elem].lastnetupdate=time(NULL);
+
+// must test time modulo here !
+now=raydium_timecall_clock();
+before=raydium_ode_element[elem].net_last_time;
+raydium_ode_element[elem].net_last_interval=now-raydium_ode_element[elem].net_last_time;
+raydium_ode_element[elem].net_last_time=now;
+
+raydium_ode_element_rotateq(elem,ev->rot);
+
+if(!before || raydium_timecall_interval[raydium_ode_timecall]==0)
+{
+    raydium_ode_element_move(elem,ev->pos);
+    memcpy(raydium_ode_element[elem].netvel,ev->vel,sizeof(dReal)*3);
+#ifdef DEBUG_ODENET    
+    raydium_log("%i elem's first update (or 0 hz ODE callback)",elem);
+#endif
+}
+else
+{
+
+// we must modify "netvel" to force reconciliation
+pos=raydium_ode_element_pos_get(elem);
+factor=((raydium_ode_element[elem].net_last_interval/(float)raydium_timecall_clocks_per_sec)*(float)RAYDIUM_ODE_PHYSICS_FREQ)*RAYDIUM_ODE_TIMESTEP;
+#ifdef DEBUG_ODENET
+raydium_log("ODE 1 sec factor : %f",factor);
+#endif
+
+if(factor<0.01) // probably another packet from the same read loop
+    {
+    for(i=0;i<3;i++)
+	raydium_ode_element[elem].netvel[i]=0;
+    return;
+    }
+
+// 1 - determine probable next point (real and predi vectors cross point)
+for(i=0;i<3;i++)
+    Pcross[i]=ev->pos[i]+
+		(ev->vel[i] * factor);
+
+#ifdef DEBUG_ODENET
+raydium_log("pcross = %f %f %f | pos = %f %f %f",Pcross[0],Pcross[1],Pcross[2],pos[0],pos[1],pos[2]);
+#endif
+
+// 2 - determine vector to this point from estimated last prediction (pos)
+for(i=0;i<3;i++)
+    raydium_ode_element[elem].netvel[i]=(Pcross[i]-pos[i])/factor;
+
+
+#ifdef DEBUG_ODENET
+raydium_log("netvel = %f %f %f | org = %f %f %f",
+				raydium_ode_element[elem].netvel[0],
+				raydium_ode_element[elem].netvel[1],
+				raydium_ode_element[elem].netvel[2],
+				ev->vel[0],
+				ev->vel[1],
+				ev->vel[2]);
+raydium_log("---");
+#endif
+
+// start previ (client side)... (may be unused)
+//memcpy(raydium_ode_element[elem].net_last_pos2,raydium_ode_element[elem].net_last_pos1,sizeof(dReal)*3);
+//memcpy(raydium_ode_element[elem].net_last_pos1,ev->pos,sizeof(dReal)*3);
+// ... end previ
+}
+
+#ifndef ODE_PREDICTION
+raydium_ode_element_move(elem,ev->pos);
+raydium_ode_element_rotateq(elem,ev->rot);
+#endif
+
+#ifdef ODE_NETWORK_GHOSTS
+ {
+ // horrible... but usefull for debugging.
+ dMatrix3 R;
+ dQtoR(ev->rot,R);
+ ev->pos[0]+=0.01;
+ raydium_camera_replace_go(ev->pos,R);
+ raydium_object_draw(raydium_ode_element[elem].mesh);
+ //printf("ode_net: %s updated (packet usage: %i byte(s))\n", raydium_ode_element[elem].name,sizeof(*ev)+RAYDIUM_NETWORK_PACKET_OFFSET);
+ }
+#endif
+}
+
+
+// Read new packets (flushed read must be an option !)
+void raydium_ode_network_read(void)
+{
+char type;
+int id,i;
+short n;
+char data[RAYDIUM_NETWORK_PACKET_SIZE];
+raydium_ode_network_Event *get;
+
+
+if(raydium_network_mode!=RAYDIUM_NETWORK_MODE_CLIENT)
+    return;
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].nid>=0 && 
+       raydium_ode_element[i].distant &&
+       (time(NULL)>raydium_ode_element[i].lastnetupdate+RAYDIUM_NETWORK_TIMEOUT))
+    	    {
+	    raydium_ode_element_delete(i,1);
+	    //raydium_log("element %i deleted: timeout",i);
+	    }
+
+// read (flushed ?), and if RAYDIUM_NETWORK_PACKET_DATA, search nid and update pos/rot
+//if(raydium_network_read(&id,&type,data)!=RAYDIUM_NETWORK_DATA_OK)
+if(raydium_network_read_flushed(&id,&type,data)!=RAYDIUM_NETWORK_DATA_OK)
+    return;
+    
+#ifndef ODE_NETWORK_GHOSTS
+if(id==raydium_network_uid) 
+    return; // do not update our elements !
+#endif
+
+memcpy(&n,data+RAYDIUM_NETWORK_PACKET_OFFSET,sizeof(n));
+
+if(type==RAYDIUM_NETWORK_PACKET_ODE_DATA)
+ for(i=0;i<n;i++)
+    {
+    get=(raydium_ode_network_Event *)(data+RAYDIUM_NETWORK_PACKET_OFFSET+sizeof(n)+(i*sizeof(*get)));
+    raydium_ode_network_apply(get);
+    }
+
+}
+
+// Add new element to network
+void raydium_ode_network_element_new(int e)
+{
+char data[RAYDIUM_NETWORK_PACKET_SIZE];
+int dec,i;
+dReal set[3];
+
+if(raydium_network_mode!=RAYDIUM_NETWORK_MODE_CLIENT)
+    return;
+    
+if(!raydium_ode_element_isvalid(e)) return;
+if(raydium_ode_element[e].distant) return;
+
+raydium_ode_element[e].nid=(raydium_network_uid+1)*1000+e;
+
+dec=RAYDIUM_NETWORK_PACKET_OFFSET;
+memcpy(data+dec,&raydium_ode_element[e].nid,sizeof(int));
+dec+=sizeof(int);
+
+i=dGeomGetClass(raydium_ode_element[e].geom);
+memcpy(data+dec,&i,sizeof(int));
+dec+=sizeof(int);
+
+switch(i)
+    {
+    case dSphereClass:
+	set[0]=dGeomSphereGetRadius(raydium_ode_element[e].geom);
+	set[1]=set[2]=0;
+	break;
+    case dBoxClass:
+	dGeomBoxGetLengths(raydium_ode_element[e].geom,set);
+	break;
+    }
+memcpy(data+dec,set,sizeof(dReal)*3);
+dec+=(sizeof(dReal)*3);
+
+memcpy(data+dec,&raydium_ode_element[e].user_tag,sizeof(int));
+dec+=sizeof(int);
+
+strncpy(data+dec,raydium_object_name[raydium_ode_element[e].mesh],RAYDIUM_NETWORK_PACKET_SIZE-dec-1);
+data[RAYDIUM_NETWORK_PACKET_SIZE-1]='\0';
+raydium_network_write(NULL,raydium_network_uid,RAYDIUM_NETWORK_PACKET_ODE_NEWELEM,data);
+}
+
+void raydium_ode_network_element_delete(int e)
+{
+char data[RAYDIUM_NETWORK_PACKET_SIZE];
+int dec;
+
+if(raydium_network_mode!=RAYDIUM_NETWORK_MODE_CLIENT)
+    return;
+
+if(!raydium_ode_element_isvalid(e)) return;
+if(raydium_ode_element[e].nid<0) return;
+if(raydium_ode_element[e].distant) return;
+
+dec=RAYDIUM_NETWORK_PACKET_OFFSET;
+memcpy(data+dec,&raydium_ode_element[e].nid,sizeof(int));
+dec+=sizeof(int);
+
+raydium_network_write(NULL,raydium_network_uid,RAYDIUM_NETWORK_PACKET_ODE_REMELEM,data);
+}
+
+void raydium_ode_network_explosion_send(raydium_ode_network_Explosion *exp)
+{
+char data[RAYDIUM_NETWORK_PACKET_SIZE];
+memcpy(data+RAYDIUM_NETWORK_PACKET_OFFSET,exp,sizeof(raydium_ode_network_Explosion));
+raydium_network_write(NULL,raydium_network_uid,RAYDIUM_NETWORK_PACKET_ODE_EXPLOSION,data);
+}
+
+
+char raydium_ode_network_element_isdistant(int elem)
+{
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: cannot get element 'is distant' flag: invalid name/index");
+    return 0;
+    }
+
+return raydium_ode_element[elem].distant;
+}
+
+char raydium_ode_network_element_isdistant_name(char *elem)
+{
+return raydium_ode_network_element_isdistant(raydium_ode_element_find(elem));
+}
+
+char raydium_ode_network_element_distantowner(int elem)
+{
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: cannot get element 'distant owner': invalid name/index");
+    return 0;
+    }
+return raydium_ode_element[elem].distant_owner;
+}
+
+char raydium_ode_network_element_distantowner_name(char *elem)
+{
+return raydium_ode_network_element_distantowner(raydium_ode_element_find(elem));
+}
+
+
+void raydium_ode_network_element_trajectory_correct(int elem)
+{
+//dReal vector[3];
+dReal pos[3];
+dReal *cur;
+//unsigned long now;
+int i;
+raydium_ode_Element *e;
+
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: cannot correct trajectory: invalid name/index");
+    return;
+    }
+
+e=&raydium_ode_element[elem];
+//now=raydium_timecall_clock();
+
+// determine vector (last1 - last2)
+//for(i=0;i<3;i++)
+//    vector[i]=e->net_last_pos1[i]-e->net_last_pos2[i];
+
+// pos = last1 + ( vector * ( (now - last1) / interval ))
+//for(i=0;i<3;i++)
+//    pos[i]=e->net_last_pos1[i] + ( vector[i] * ( (now - e->net_last_time) / (dReal)(e->net_last_interval) ));
+
+
+// Use "dead reckoning" method :
+cur=raydium_ode_element_pos_get(elem);
+memcpy(pos,cur,sizeof(dReal)*3);
+for(i=0;i<3;i++)
+	pos[i]+=(e->netvel[i]*RAYDIUM_ODE_TIMESTEP);
+//	pos[i]+=(e->netvel[i]/RAYDIUM_ODE_PHYSICS_FREQ);
+
+//printf("cur = %f %f %f | next = %f %f %f (%f %f %f)\n",cur[0],cur[1],cur[2],pos[0],pos[1],pos[2],e->netvel[0],e->netvel[1],e->netvel[2]);
+
+#ifdef ODE_PREDICTION
+// pray.
+raydium_ode_element_move(elem,pos);
+#endif
+}
Index: raydium/vertex.c
===================================================================
--- raydium/vertex.c	(revision 0)
+++ raydium/vertex.c	(revision 1)
@@ -0,0 +1,105 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/vertex.h"
+#endif
+
+void raydium_vertex_add(GLfloat x, GLfloat y, GLfloat z/*, GLfloat nx, GLfloat ny, GLfloat nz*/)
+{
+
+raydium_vertex_x[raydium_vertex_index]=x;
+raydium_vertex_y[raydium_vertex_index]=y;
+raydium_vertex_z[raydium_vertex_index]=z;
+raydium_vertex_texture[raydium_vertex_index]=raydium_texture_current;
+raydium_vertex_texture_multi[raydium_vertex_index]=raydium_texture_current_multi;
+if(raydium_texture_current_multi)
+{
+    if(raydium_texture_current_multi_u==-99999 && 
+       raydium_texture_current_multi_v==-99999 )
+    {
+    raydium_vertex_texture_multi_u[raydium_vertex_index]=raydium_internal_vertex_next_u*RAYDIUM_RENDER_MULTITEX_AUTO_UV_FACT;
+    raydium_vertex_texture_multi_v[raydium_vertex_index]=raydium_internal_vertex_next_v*RAYDIUM_RENDER_MULTITEX_AUTO_UV_FACT;
+    }
+    else
+    {
+    raydium_vertex_texture_multi_u[raydium_vertex_index]=raydium_texture_current_multi_u;
+    raydium_vertex_texture_multi_v[raydium_vertex_index]=raydium_texture_current_multi_v;
+    }
+}
+else
+{
+raydium_vertex_texture_multi_u[raydium_vertex_index]=0;
+raydium_vertex_texture_multi_v[raydium_vertex_index]=0;
+}
+
+
+if(raydium_internal_vertex_next_extras)
+{
+ raydium_vertex_texture_u[raydium_vertex_index]=raydium_internal_vertex_next_u;
+ raydium_vertex_texture_v[raydium_vertex_index]=raydium_internal_vertex_next_v;
+}
+else 
+{
+ if(raydium_vertex_offset_triangle==0)
+ {
+ raydium_vertex_texture_u[raydium_vertex_index]=0.0;
+ raydium_vertex_texture_v[raydium_vertex_index]=0.0;
+ }
+
+ if(raydium_vertex_offset_triangle==1)
+ {
+ raydium_vertex_texture_u[raydium_vertex_index]=1.0;
+ raydium_vertex_texture_v[raydium_vertex_index]=0.0;
+ }
+
+ if(raydium_vertex_offset_triangle==2)
+ {
+ raydium_vertex_texture_u[raydium_vertex_index]=1.0;
+ raydium_vertex_texture_v[raydium_vertex_index]=1.0;
+ }
+}
+
+
+raydium_vertex_normal_visu_x[raydium_vertex_index]=raydium_internal_vertex_next_nx;
+raydium_vertex_normal_visu_y[raydium_vertex_index]=raydium_internal_vertex_next_ny;
+raydium_vertex_normal_visu_z[raydium_vertex_index]=raydium_internal_vertex_next_nz;
+
+raydium_vertex_index++;
+
+ if(++raydium_vertex_offset_triangle>=3)
+ {
+  if(raydium_internal_vertex_next_extras<2) raydium_normal_generate_lastest_triangle(1);
+  else raydium_normal_generate_lastest_triangle(0);
+  raydium_vertex_offset_triangle=0;
+ }
+
+ raydium_internal_vertex_next_extras=0;
+if(raydium_vertex_index>=RAYDIUM_MAX_VERTICES) {raydium_log("out of vertex table #%i!",raydium_texture_current); exit(29); }/* !!! TO CHANGE */
+}
+
+
+void raydium_vertex_uv_add(GLfloat x, GLfloat y, GLfloat z,GLfloat u, GLfloat v)
+{
+raydium_internal_vertex_next_extras=1;
+raydium_internal_vertex_next_u=u;
+raydium_internal_vertex_next_v=v;
+raydium_vertex_add(x,y,z);
+}
+
+void raydium_vertex_uv_normals_add(GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat u, GLfloat v)
+{
+raydium_internal_vertex_next_extras=2;
+raydium_internal_vertex_next_u=u;
+raydium_internal_vertex_next_v=v;
+
+raydium_internal_vertex_next_nx=nx;
+raydium_internal_vertex_next_ny=ny;
+raydium_internal_vertex_next_nz=nz;
+raydium_vertex_add(x,y,z);
+}
Index: raydium/background.c
===================================================================
--- raydium/background.c	(revision 0)
+++ raydium/background.c	(revision 1)
@@ -0,0 +1,22 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/background.h"
+#endif 
+
+void raydium_background_color_change(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+raydium_background_color[0]=r;
+raydium_background_color[1]=g;
+raydium_background_color[2]=b;
+raydium_background_color[3]=a;
+//glColor4fv(raydium_background_color);
+raydium_clear_color_update();
+raydium_fog_color_update();
+}
Index: raydium/log.c
===================================================================
--- raydium/log.c	(revision 0)
+++ raydium/log.c	(revision 1)
@@ -0,0 +1,33 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/log.h"
+#endif 
+
+#ifndef RAYDIUM_NETWORK_ONLY
+void raydium_console_line_add(char *format, ...);
+#endif
+
+// need to be secured
+void raydium_log(char *format, ...)
+{
+char str[RAYDIUM_MAX_NAME_LEN];
+va_list argptr;
+
+
+va_start(argptr,format);
+vsprintf(str,format,argptr);
+va_end(argptr);
+
+printf("Raydium: %s\n",str);
+if(raydium_log_file) fprintf(raydium_log_file,"%s\n",str);
+#ifndef RAYDIUM_NETWORK_ONLY
+raydium_console_line_add(str);
+#endif
+}
Index: raydium/gui.c
===================================================================
--- raydium/gui.c	(revision 0)
+++ raydium/gui.c	(revision 1)
@@ -0,0 +1,1978 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/gui.h"
+#endif 
+
+#include "gui.h"
+
+
+// Disclaimer ;)
+// Some part of this file are quite ugly, sorry about that.
+// (mainly for combos management [strings and double drawing])
+// There also a lot of duplicated code.
+// Needs some internal work, but API is quite stable, now.
+
+void raydium_gui_window_init(int window)
+{
+raydium_gui_Window *w;
+int i;
+
+w=&raydium_gui_windows[window];
+
+w->id=window;
+w->name[0]=0;
+w->pos[0]=w->pos[1]=0;
+w->size[0]=w->size[1]=0;
+w->focused_widget=-1;
+w->old_focused=-1;
+
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    {
+    w->widgets[i].id=i;
+    w->widgets[i].name[0]=0;
+    w->widgets[i].state=0;
+    w->widgets[i].window=window;
+    w->widgets[i].pos[0]=w->widgets[i].pos[1]=0;
+    w->widgets[i].size[0]=w->widgets[i].size[1]=0;
+    w->widgets[i].font_size=20;
+    if(w->widgets[i].widget!=NULL)
+	{
+	free(w->widgets[i].widget);
+	w->widgets[i].widget=NULL;
+	}
+    }
+}
+
+
+// "One time init"
+void raydium_gui_init(void)
+{
+int i,j;
+
+raydium_gui_visible=0;
+raydium_gui_window_focused=-1;
+raydium_gui_oldstate=0;
+raydium_gui_button_clicked_id=-1;
+raydium_gui_widget_sizes(15,5,16);
+raydium_gui_theme_init();
+
+// mark all windows's objetcs (widgets to NULL) ...
+for(i=0;i<RAYDIUM_GUI_MAX_WINDOWS;i++)
+    for(j=0;j<RAYDIUM_GUI_MAX_OBJECTS;j++)
+	{
+	raydium_gui_windows[i].widgets[j].state=0;
+	raydium_gui_windows[i].widgets[j].widget=NULL;
+	}
+
+// ... and then, get back to a regular init :
+for(i=0;i<RAYDIUM_GUI_MAX_WINDOWS;i++)
+    raydium_gui_window_init(i);
+}
+
+
+void raydium_gui_theme_init(void)
+{
+raydium_gui_theme_current.loaded=0;
+raydium_gui_theme_current.filename[0]=0;
+raydium_gui_theme_current.texture=0;
+raydium_gui_theme_current.texture_size[0]=1;
+raydium_gui_theme_current.texture_size[1]=1;
+memset(raydium_gui_theme_current.background_uv,0,sizeof(GLfloat)*4);
+}
+
+int raydium_gui_theme_load(char *filename)
+{
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+char done;
+
+fp=raydium_file_fopen(filename,"rt");
+if(!fp)
+ {
+ raydium_log("gui: ERROR: Cannot open %s theme file",filename);
+ return 0;
+ }
+
+raydium_gui_theme_init();
+strcpy(raydium_gui_theme_current.filename,filename);
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    done=0;
+
+    if(!strcasecmp(var,"texture"))
+	{
+	int t;
+	if(ret!=RAYDIUM_PARSER_TYPE_STRING)
+	    {
+	    raydium_log("gui: parser: texture: wrong type");
+	    continue;
+	    }
+	
+	t=raydium_texture_find_by_name(val_s);
+	if(!t)
+	    {
+	    fclose(fp);
+	    return 0;
+	    }
+	raydium_gui_theme_current.texture=t;
+	done=1;
+	}
+
+    if(!strcasecmp(var,"texture_size"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=2)
+	    {
+	    raydium_log("gui: parser: texture_size: wrong type");
+	    continue;
+	    }
+	// cast floats to ints
+	raydium_gui_theme_current.texture_size[0]=(int)val_f[0];
+	raydium_gui_theme_current.texture_size[1]=(int)val_f[1];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"background"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+	    {
+	    raydium_log("gui: parser: background: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_gui_theme_current.background_uv,val_f,sizeof(GLfloat)*4);
+	done=1;
+	}
+    /*
+    // We're only parsing "general" properties: no need to reports unknown ones
+    if(!done)
+	raydium_log("gui: parser: invalid or unsupported option '%s' (%s)",var,filename);
+    */    
+    }
+fclose(fp);
+raydium_gui_theme_current.loaded=1;
+return 1;
+}
+
+
+char raydium_gui_window_isvalid(int i)
+{
+if(i>=0 && i<RAYDIUM_GUI_MAX_WINDOWS &&
+   raydium_gui_windows[i].state)
+    return 1;
+return 0;
+}
+
+int raydium_gui_window_find(char *name)
+{
+int i;
+
+for(i=0;i<RAYDIUM_GUI_MAX_WINDOWS;i++)
+    if(!strcmp(name,raydium_gui_windows[i].name) && raydium_gui_window_isvalid(i))
+     return i;
+return -1;
+}
+
+
+char raydium_gui_widget_isvalid(int i, int window)
+{
+if(!raydium_gui_window_isvalid(window))
+    return 0;
+    
+if(i>=0 && i<RAYDIUM_GUI_MAX_WINDOWS &&
+   raydium_gui_windows[window].widgets[i].state)
+    return 1;
+return 0;
+}
+
+
+int raydium_gui_widget_find(char *name, int window)
+{
+int i;
+
+if(!raydium_gui_window_isvalid(window))
+    return -1;
+
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(!strcmp(name,raydium_gui_windows[window].widgets[i].name) && raydium_gui_widget_isvalid(i,window))
+     return i;
+return -1;
+}
+
+
+void raydium_gui_widget_next(void)
+{
+int i;
+raydium_gui_Window *w;
+
+if(!raydium_gui_window_isvalid(raydium_gui_window_focused))
+    return;
+w=&raydium_gui_windows[raydium_gui_window_focused];
+
+for(i=w->focused_widget+1;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(raydium_gui_widget_isvalid(i,raydium_gui_window_focused))
+	{
+	w->focused_widget=i;
+	return;
+	}
+
+// No found : rewind
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(raydium_gui_widget_isvalid(i,raydium_gui_window_focused))
+	{
+	w->focused_widget=i;
+	return;
+	}
+}
+
+
+void raydium_gui_widget_draw_internal(GLfloat *uv, GLfloat *xy)
+{
+raydium_osd_start();
+raydium_texture_current_set(raydium_gui_theme_current.texture);
+raydium_rendering_internal_prepare_texture_render(raydium_gui_theme_current.texture);
+
+glBegin(GL_QUADS);
+glTexCoord2f(uv[0],uv[1]);
+glVertex3f(xy[0],xy[3],0);
+glTexCoord2f(uv[2],uv[1]);
+glVertex3f(xy[2],xy[3],0);
+glTexCoord2f(uv[2],uv[3]);
+glVertex3f(xy[2],xy[1],0);
+glTexCoord2f(uv[0],uv[3]);
+glVertex3f(xy[0],xy[1],0);
+glEnd();
+
+raydium_osd_stop();
+}
+
+///////////////////////////
+// final Widgets drawing //
+///////////////////////////
+
+void raydium_gui_button_draw(int w, int window)
+{
+GLfloat uv[4];
+GLfloat xy[4];
+GLfloat fxy[2];
+GLfloat mxy[2];
+GLfloat wfactor[2];
+GLfloat *suv;
+GLfloat tmp;
+char style;
+raydium_gui_Button *b;
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+if(!raydium_gui_widget_isvalid(w,window))
+    return;
+
+b=raydium_gui_windows[window].widgets[w].widget;
+
+mxy[0]=    ((float)raydium_mouse_x/raydium_window_tx)*100;
+mxy[1]=100-((float)raydium_mouse_y/raydium_window_ty)*100;
+
+
+wfactor[0]=raydium_gui_windows[window].size[0]/100.;
+wfactor[1]=raydium_gui_windows[window].size[1]/100.;
+
+xy[0]=raydium_gui_windows[window].pos[0]+
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]);
+xy[1]=raydium_gui_windows[window].pos[1]+
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]);
+xy[2]=raydium_gui_windows[window].pos[0] +
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]) +
+      raydium_gui_windows[window].widgets[w].size[0];
+xy[3]=raydium_gui_windows[window].pos[1] +
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]) +
+      raydium_gui_windows[window].widgets[w].size[1];
+
+
+style=RAYDIUM_GUI_NORMAL;
+
+if(raydium_gui_windows[window].focused_widget==w)
+    style=RAYDIUM_GUI_FOCUS;
+
+if(raydium_gui_window_focused==window &&
+  (mxy[0]>=xy[0] && mxy[1]>=xy[1] &&
+   mxy[0]<=xy[2] && mxy[1]<=xy[3] ))
+	style=RAYDIUM_GUI_HOVER;
+
+// uv
+switch(style)
+    {
+    case RAYDIUM_GUI_NORMAL:
+	suv=b->uv_normal;
+	break;
+    case RAYDIUM_GUI_FOCUS:
+	suv=b->uv_focus;
+	break;
+    case RAYDIUM_GUI_HOVER:
+	suv=b->uv_hover;
+	break;
+    }
+
+uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];
+uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+
+raydium_gui_widget_draw_internal(uv,xy);
+
+if(strlen(b->caption)>0)
+{
+fxy[0]=xy[0]+(xy[2]-xy[0])/2;
+fxy[1]=xy[1]+(xy[3]-xy[1])/2;
+if(strlen(b->caption)>1)
+    {
+    tmp=raydium_gui_windows[window].widgets[w].font_size/RAYDIUM_OSD_FONT_SIZE_FACTOR;
+    tmp=((strlen(b->caption)-1)*tmp)/2;
+    }
+else
+    tmp=0;
+raydium_osd_color_change(b->font_color[0],b->font_color[1],b->font_color[2]);
+raydium_osd_printf(fxy[0]-tmp,fxy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","%s",b->caption);
+} // end caption drawing
+
+// Events management
+if( (style==RAYDIUM_GUI_HOVER && raydium_mouse_click==1)  ||
+    (style==RAYDIUM_GUI_FOCUS && raydium_key_last==1013) )
+    {
+    void (*f)(raydium_gui_Object *);
+    raydium_mouse_click=0;
+    raydium_gui_windows[window].focused_widget=w;
+    f=b->OnClick;
+    if(f)
+	f(&raydium_gui_windows[window].widgets[w]);
+    raydium_gui_button_clicked_id=window*1000+w;
+    }
+}
+
+void raydium_gui_track_draw(int w, int window)
+{
+GLfloat uv[4];
+GLfloat rxy[4];
+GLfloat cxy[4];
+GLfloat cdec[2];
+GLfloat mxy[2];
+GLfloat wfactor[2];
+GLfloat rcfactor[2];
+GLfloat *ruv;
+GLfloat *cuv;
+char style;
+raydium_gui_Track *t;
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+if(!raydium_gui_widget_isvalid(w,window))
+    return;
+
+t=raydium_gui_windows[window].widgets[w].widget;
+
+mxy[0]=    ((float)raydium_mouse_x/raydium_window_tx)*100;
+mxy[1]=100-((float)raydium_mouse_y/raydium_window_ty)*100;
+
+
+wfactor[0]=raydium_gui_windows[window].size[0]/100.;
+wfactor[1]=raydium_gui_windows[window].size[1]/100.;
+
+
+style=RAYDIUM_GUI_NORMAL;
+
+if(raydium_gui_windows[window].focused_widget==w)
+    style=RAYDIUM_GUI_FOCUS;
+
+// rule  ...
+rxy[0]=raydium_gui_windows[window].pos[0]+
+      (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]);
+rxy[1]=raydium_gui_windows[window].pos[1]+
+      (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]);
+rxy[2]=raydium_gui_windows[window].pos[0] +
+      (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]) +
+       raydium_gui_windows[window].widgets[w].size[0];
+rxy[3]=raydium_gui_windows[window].pos[1] +
+      (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]) +
+       raydium_gui_windows[window].widgets[w].size[1];
+// uv
+ruv=t->uv_rule;
+
+uv[0]=  ruv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-ruv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=  (ruv[0] + ruv[2]) / raydium_gui_theme_current.texture_size[0];
+uv[3]=1-(ruv[1] + ruv[3]) / raydium_gui_theme_current.texture_size[1];
+
+raydium_gui_widget_draw_internal(uv,rxy);
+// ... end rule
+
+// cursor  ...
+// uv
+switch(style)
+    {
+    case RAYDIUM_GUI_NORMAL:
+	cuv=t->uv_cursor_normal;
+	break;
+    case RAYDIUM_GUI_FOCUS:
+	cuv=t->uv_cursor_focus;
+	break;
+    }
+
+uv[0]=  cuv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-cuv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=  (cuv[0] + cuv[2]) / raydium_gui_theme_current.texture_size[0];
+uv[3]=1-(cuv[1] + cuv[3]) / raydium_gui_theme_current.texture_size[1];
+
+rcfactor[0]=cuv[2]/ruv[2];
+rcfactor[1]=cuv[3]/ruv[3];
+
+//raydium_log("%f %f",cuv[4],ruv[4]);
+
+cxy[0]=rxy[0];
+cxy[1]=rxy[1];
+cxy[2]=raydium_gui_windows[window].pos[0] +
+      (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]) +
+      (raydium_gui_windows[window].widgets[w].size[0]*rcfactor[0]);
+cxy[3]=raydium_gui_windows[window].pos[1] +
+      (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]) +
+      (raydium_gui_windows[window].widgets[w].size[1]*rcfactor[1]);
+
+cdec[0]=(rxy[2]-rxy[0]) * ((float)(t->current - t->min)/(t->max - t->min));
+cdec[0]-=(cxy[2]-cxy[0])/2;
+cdec[1]=(cxy[3]-cxy[1])/2 - (rxy[3]-rxy[1])/2;
+
+cxy[0]+=cdec[0];
+cxy[2]+=cdec[0];
+cxy[1]-=cdec[1];
+cxy[3]-=cdec[1];
+
+raydium_gui_widget_draw_internal(uv,cxy);
+// ... end cursor
+
+
+// Events management
+
+// hover
+if(raydium_gui_window_focused==window &&
+  (mxy[0]>=rxy[0] && mxy[1]>=rxy[1] &&
+   mxy[0]<=rxy[2] && mxy[1]<=rxy[3] ) &&
+   raydium_mouse_button[0])
+    {
+    GLfloat fact;
+    raydium_gui_windows[window].focused_widget=w;
+    fact=(mxy[0]-rxy[0])/(rxy[2]-rxy[0]);
+    
+    t->current= t->min + (fact*(t->max - t->min));
+    }
+
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==100)
+    t->current--;
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==102)
+    t->current++;
+
+
+if(t->current<t->min)
+    t->current=t->min;
+if(t->current>t->max)
+    t->current=t->max;
+}
+
+
+void raydium_gui_label_draw(int w, int window)
+{
+GLfloat xy[2];
+GLfloat wfactor[2];
+GLfloat tmp;
+raydium_gui_Label *l;
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+if(!raydium_gui_widget_isvalid(w,window))
+    return;
+
+l=raydium_gui_windows[window].widgets[w].widget;
+
+wfactor[0]=raydium_gui_windows[window].size[0]/100.;
+wfactor[1]=raydium_gui_windows[window].size[1]/100.;
+
+xy[0]=raydium_gui_windows[window].pos[0]+
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]);
+xy[1]=raydium_gui_windows[window].pos[1]+
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]);
+
+
+if(strlen(l->caption)>0)
+{
+if(strlen(l->caption)>1)
+    {
+    tmp=raydium_gui_windows[window].widgets[w].font_size/RAYDIUM_OSD_FONT_SIZE_FACTOR;
+    tmp=((strlen(l->caption)-1)*tmp)/2;
+    }
+else
+    tmp=0;
+raydium_osd_color_change(l->font_color[0],l->font_color[1],l->font_color[2]);
+raydium_osd_printf(xy[0]-tmp,xy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","%s",l->caption);
+} // end caption drawing
+}
+
+
+void raydium_gui_edit_draw(int w, int window)
+{
+GLfloat uv[4];
+GLfloat xy[4];
+GLfloat mxy[2];
+GLfloat wfactor[2];
+GLfloat *suv;
+char style;
+int len;
+raydium_gui_Edit *e;
+// ugly temp vars
+GLfloat fxy[2];
+GLfloat tmp,tmp2;
+char zone[RAYDIUM_MAX_NAME_LEN];
+
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+if(!raydium_gui_widget_isvalid(w,window))
+    return;
+
+e=raydium_gui_windows[window].widgets[w].widget;
+
+mxy[0]=    ((float)raydium_mouse_x/raydium_window_tx)*100;
+mxy[1]=100-((float)raydium_mouse_y/raydium_window_ty)*100;
+
+
+wfactor[0]=raydium_gui_windows[window].size[0]/100.;
+wfactor[1]=raydium_gui_windows[window].size[1]/100.;
+
+xy[0]=raydium_gui_windows[window].pos[0]+
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]);
+xy[1]=raydium_gui_windows[window].pos[1]+
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]);
+xy[2]=raydium_gui_windows[window].pos[0] +
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]) +
+      raydium_gui_windows[window].widgets[w].size[0];
+xy[3]=raydium_gui_windows[window].pos[1] +
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]) +
+      raydium_gui_windows[window].widgets[w].size[1];
+
+
+style=RAYDIUM_GUI_NORMAL;
+
+if(raydium_gui_windows[window].focused_widget==w)
+    style=RAYDIUM_GUI_FOCUS;
+
+// uv
+switch(style)
+    {
+    case RAYDIUM_GUI_NORMAL:
+	suv=e->uv_normal;
+	break;
+    case RAYDIUM_GUI_FOCUS:
+	suv=e->uv_focus;
+	break;
+    }
+
+uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];
+uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+
+raydium_gui_widget_draw_internal(uv,xy);
+
+len=strlen(e->text);
+
+fxy[0]=xy[0];
+fxy[1]=xy[1]+(xy[3]-xy[1])/2;
+tmp=raydium_gui_windows[window].widgets[w].font_size/RAYDIUM_OSD_FONT_SIZE_FACTOR;
+tmp2=(xy[2]-xy[0])-tmp;
+tmp2/=tmp;
+
+if(tmp2>250)
+    {
+    raydium_log("GUI: Error: edit zone is too long");
+    return;
+    }
+
+// asserts
+if(e->cursor>len)
+    e->cursor=len;
+if(e->cursor<0)
+    e->cursor=0;
+
+if(e->cursor-e->offset>tmp2)
+    e->offset=e->cursor-tmp2;
+if(e->cursor<e->offset)
+    e->offset=e->cursor;
+    
+strncpy(zone,e->text+e->offset,250);
+zone[(int)tmp2+1]=0;
+
+raydium_osd_color_change(e->font_color[0],e->font_color[1],e->font_color[2]);
+raydium_osd_printf(fxy[0]+tmp,fxy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","%s",zone);
+
+if(style==RAYDIUM_GUI_FOCUS)
+raydium_osd_printf(fxy[0]+tmp+(tmp*e->cursor)-(tmp/2)-(e->offset*tmp),fxy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","|");
+// end of "printf"
+
+// Events management
+
+if(raydium_gui_window_focused==window &&
+  (mxy[0]>=xy[0] && mxy[1]>=xy[1] &&
+   mxy[0]<=xy[2] && mxy[1]<=xy[3] ) &&
+   raydium_mouse_click==1)
+    {
+    GLfloat fact;
+    raydium_mouse_click=0;
+    raydium_gui_windows[window].focused_widget=w;
+    fact=(mxy[0]-xy[0])/(xy[2]-xy[0]);
+    e->cursor=(tmp2*fact)+(tmp/3.f)+e->offset; // need some work
+    }
+
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==100)
+    e->cursor--;
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==102)
+    e->cursor++;
+
+if(style==RAYDIUM_GUI_FOCUS && (raydium_key_last>=1032 && raydium_key_last<1127) &&
+		       len<(RAYDIUM_GUI_DATASIZE-1))
+    {
+    memmove(e->text+e->cursor+1,e->text+e->cursor,strlen(e->text+e->cursor)+1);
+    e->text[e->cursor]=raydium_key_last-1000;
+    e->cursor++;
+    }
+
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==1008 && len>0 && e->cursor>0)
+    {
+    memmove(e->text+e->cursor-1,e->text+e->cursor,strlen(e->text+e->cursor)+1);
+    e->cursor--;
+    }
+
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==1127 && e->cursor<len)
+    {
+    memmove(e->text+e->cursor,e->text+e->cursor+1,strlen(e->text+e->cursor)+1);
+    }
+
+
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==106)
+    e->cursor=0;
+if(style==RAYDIUM_GUI_FOCUS && raydium_key_last==107)
+    e->cursor=len;
+}
+
+
+void raydium_gui_check_draw(int w, int window)
+{
+GLfloat uv[4];
+GLfloat xy[4];
+GLfloat fxy[2];
+GLfloat mxy[2];
+GLfloat wfactor[2];
+GLfloat *suv;
+GLfloat *scol;
+char style;
+raydium_gui_Check *c;
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+if(!raydium_gui_widget_isvalid(w,window))
+    return;
+
+c=raydium_gui_windows[window].widgets[w].widget;
+
+mxy[0]=    ((float)raydium_mouse_x/raydium_window_tx)*100;
+mxy[1]=100-((float)raydium_mouse_y/raydium_window_ty)*100;
+
+
+wfactor[0]=raydium_gui_windows[window].size[0]/100.;
+wfactor[1]=raydium_gui_windows[window].size[1]/100.;
+
+xy[0]=raydium_gui_windows[window].pos[0]+
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]);
+xy[1]=raydium_gui_windows[window].pos[1]+
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]);
+xy[2]=raydium_gui_windows[window].pos[0] +
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]) +
+      raydium_gui_windows[window].widgets[w].size[0];
+xy[3]=raydium_gui_windows[window].pos[1] +
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]) +
+      raydium_gui_windows[window].widgets[w].size[1];
+
+
+style=RAYDIUM_GUI_NORMAL;
+
+if(raydium_gui_windows[window].focused_widget==w)
+    style=RAYDIUM_GUI_FOCUS;
+
+
+if(!c->checked)
+    suv=c->uv_normal;
+else
+    suv=c->uv_checked;
+
+if(style==RAYDIUM_GUI_NORMAL)
+    scol=c->font_color_normal;
+else
+    scol=c->font_color_focus;
+
+uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];
+uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+
+raydium_gui_widget_draw_internal(uv,xy);
+
+if(strlen(c->caption)>0)
+{
+fxy[0]=xy[0]+(xy[2]-xy[0]);
+fxy[1]=xy[1]+(xy[3]-xy[1])/2;
+raydium_osd_color_change(scol[0],scol[1],scol[2]);
+raydium_osd_printf(fxy[0],fxy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","%s",c->caption);
+} // end caption drawing
+
+if(raydium_gui_window_focused==window &&
+  (mxy[0]>=xy[0] && mxy[1]>=xy[1] &&
+   mxy[0]<=xy[2] && mxy[1]<=xy[3] ))
+    style=RAYDIUM_GUI_HOVER;
+
+// Events management
+if( (style==RAYDIUM_GUI_HOVER && raydium_mouse_click==1)  ||
+    (style==RAYDIUM_GUI_FOCUS && raydium_key_last==1013) )
+    {
+    raydium_mouse_click=0;
+    raydium_gui_windows[window].focused_widget=w;
+    c->checked=!c->checked;
+    }
+}
+
+
+void raydium_gui_combo_draw(int w, int window)
+{
+GLfloat uv[4];
+GLfloat xy[4];
+GLfloat fxy[2];
+GLfloat mxy[2];
+GLfloat wfactor[2];
+GLfloat *suv;
+GLfloat tmp,tmp2,tmp3;
+char style;
+raydium_gui_Combo *c;
+int nitems;
+int i;
+char str[RAYDIUM_MAX_NAME_LEN];
+int start,end,cpt;
+char arrow;
+int inc=0;
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+if(!raydium_gui_widget_isvalid(w,window))
+    return;
+
+c=raydium_gui_windows[window].widgets[w].widget;
+
+mxy[0]=    ((float)raydium_mouse_x/raydium_window_tx)*100;
+mxy[1]=100-((float)raydium_mouse_y/raydium_window_ty)*100;
+
+
+wfactor[0]=raydium_gui_windows[window].size[0]/100.;
+wfactor[1]=raydium_gui_windows[window].size[1]/100.;
+
+xy[0]=raydium_gui_windows[window].pos[0]+
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]);
+xy[1]=raydium_gui_windows[window].pos[1]+
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]);
+xy[2]=raydium_gui_windows[window].pos[0] +
+     (raydium_gui_windows[window].widgets[w].pos[0]*wfactor[0]) +
+      raydium_gui_windows[window].widgets[w].size[0];
+xy[3]=raydium_gui_windows[window].pos[1] +
+     (raydium_gui_windows[window].widgets[w].pos[1]*wfactor[1]) +
+      raydium_gui_windows[window].widgets[w].size[1];
+
+
+style=RAYDIUM_GUI_NORMAL;
+
+if(raydium_gui_windows[window].focused_widget==w)
+    style=RAYDIUM_GUI_FOCUS;
+
+/*
+if(raydium_gui_window_focused==window &&
+  (mxy[0]>=xy[0] && mxy[1]>=xy[1] &&
+   mxy[0]<=xy[2] && mxy[1]<=xy[3] ))
+	style=RAYDIUM_GUI_HOVER;
+*/
+
+// uv
+switch(style)
+    {
+    case RAYDIUM_GUI_NORMAL:
+	suv=c->uv_body_normal;
+	break;
+    case RAYDIUM_GUI_FOCUS:
+	suv=c->uv_body_focus;
+	break;
+    }
+
+uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];
+uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+
+raydium_gui_widget_draw_internal(uv,xy);
+
+// count items
+for(i=0,nitems=0;c->items[i];i++)
+    if(c->items[i]==RAYDIUM_GUI_ITEM_SEPARATOR)
+	nitems++;
+nitems++;
+
+
+if(c->current>=0 && c->current<nitems)
+{
+fxy[0]=xy[0];
+fxy[1]=xy[1]+(xy[3]-xy[1])/2;
+tmp=raydium_gui_windows[window].widgets[w].font_size/RAYDIUM_OSD_FONT_SIZE_FACTOR;
+tmp2=(xy[2]-xy[0])-tmp;
+tmp2/=tmp;
+
+// find current string
+str[0]=0;
+for(i=0,cpt=0,start=0;c->items[i];i++)
+    {
+    if(c->items[i]==RAYDIUM_GUI_ITEM_SEPARATOR || !c->items[i])
+	cpt++;
+    
+    if(cpt==c->current)
+	{
+	start=i+1;
+	break;
+	}
+    }
+
+for(end=start;c->items[end] && c->items[end]!=RAYDIUM_GUI_ITEM_SEPARATOR;end++)
+    {
+    // nothing ;)
+    }
+
+for(i=0;i<end-start;i++)
+    str[i]=c->items[i+start];
+str[end-start]=0;
+
+strcpy(c->current_str,str);
+
+
+// find body max str len (tmp3)
+tmp3=c->body_border_right*((xy[2]-xy[0])/(c->uv_body_normal[2]));
+tmp3=tmp2-(tmp3/tmp);
+
+// limit str size using tmp3
+if(tmp3 < strlen(str))
+    str[(int)tmp3]=0;
+
+raydium_osd_color_change(c->font_color[0],c->font_color[1],c->font_color[2]);
+raydium_osd_printf(fxy[0]+tmp,fxy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","%s",str);
+} // end caption drawing
+
+
+if(raydium_gui_windows[window].focused_widget!=w && c->expanded)
+    c->expanded=0;
+
+// Events management of body
+if(raydium_gui_window_focused==window &&
+   mxy[0]>=xy[0] && mxy[1]>=xy[1] &&
+   mxy[0]<=xy[2] && mxy[1]<=xy[3] &&
+   raydium_mouse_click==1 )
+    {
+    raydium_mouse_click=0;
+    c->expanded=!c->expanded;
+    raydium_gui_windows[window].focused_widget=w;
+    }
+
+if(raydium_gui_window_focused==window && 
+   style==RAYDIUM_GUI_FOCUS &&
+   raydium_key_last==1013)
+   {
+    raydium_key_last=0;
+    c->expanded=!c->expanded;
+   }
+
+
+// draw expanded part, if needed
+if(c->expanded && raydium_gui_windows[window].focused_widget==w)
+{
+if(raydium_key_last==101 && c->current>0)
+    {
+    c->current--;
+    raydium_key_last=0;
+    if(c->current < c->offset)
+	c->offset=c->current;
+    }
+if(raydium_key_last==103 && c->current<nitems-1)
+    {
+    c->current++;
+    raydium_key_last=0;
+    if(c->current >= c->offset+RAYDIUM_GUI_COMBO_LIST_HEIGHT)
+	c->offset=c->current-RAYDIUM_GUI_COMBO_LIST_HEIGHT+1;
+    }
+
+
+/*
+if(raydium_key_last==1032)
+    {
+    c->offset++;
+    raydium_key_last=0;
+    }
+*/
+
+if(c->offset<0)
+    c->offset=0;
+if(c->offset>nitems-RAYDIUM_GUI_COMBO_LIST_HEIGHT)
+    c->offset=nitems-RAYDIUM_GUI_COMBO_LIST_HEIGHT;
+
+
+// Apply offset (result's stored in 'i')
+for(i=0,cpt=0;i<strlen(c->items)+1;i++)
+    {
+    if(cpt==c->offset)
+	break;
+    if(c->items[i]==RAYDIUM_GUI_ITEM_SEPARATOR || !c->items[i])
+	cpt++;
+    }
+
+// foreach element
+    start=i;
+    cpt=0;
+    for(;i<strlen(c->items)+1;i++)
+	if(c->items[i]==RAYDIUM_GUI_ITEM_SEPARATOR || !c->items[i])
+	    {
+	    end=i;
+	    memcpy(str,c->items+start,end-start);
+	    str[end-start]=0;
+	    //raydium_log("%i %i -%s-",start,end,str);
+	    
+	    //	suv
+	    arrow=0;	    
+	    suv=c->uv_list_middle;
+	    if(cpt==0)
+		{
+		suv=c->uv_list_top;
+		arrow=-1;
+		}
+	    if(cpt==nitems-1 || cpt==RAYDIUM_GUI_COMBO_LIST_HEIGHT-1)
+		{
+		suv=c->uv_list_bottom;
+		arrow=1;
+		}
+
+	    uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+	    uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+	    uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];
+	    uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+
+	    xy[1]-=raydium_gui_windows[window].widgets[w].size[1];
+	    xy[3]-=raydium_gui_windows[window].widgets[w].size[1];
+	    //	draw
+	    raydium_gui_widget_draw_internal(uv,xy);
+
+	    //	test current
+	    //	    suv current and draw
+	    if(cpt+c->offset==c->current)
+		{
+		suv=c->uv_list_current;
+		uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+		uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+		uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];
+		uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+		raydium_gui_widget_draw_internal(uv,xy);		
+		}
+
+	    if(arrow)
+		{
+		GLfloat axy[4];
+		GLfloat sw;
+		suv=c->uv_arrow;
+		uv[0]=  suv[0]/raydium_gui_theme_current.texture_size[0];
+		uv[1]=1-suv[1]/raydium_gui_theme_current.texture_size[1];
+		uv[2]=  (suv[0] + suv[2]) / raydium_gui_theme_current.texture_size[0];		uv[3]=1-(suv[1] + suv[3]) / raydium_gui_theme_current.texture_size[1];
+		if(arrow<0)
+		    {
+		    sw=uv[1];
+		    uv[1]=uv[3];
+		    uv[3]=sw;
+		    }
+		axy[1]=xy[1];
+		axy[3]=xy[3];
+		axy[0]=xy[2];
+		axy[2]=xy[2]+(axy[3]-axy[1]);
+		raydium_gui_widget_draw_internal(uv,axy);
+		if(raydium_gui_window_focused==window &&
+		   mxy[0]>=axy[0] && mxy[1]>=axy[1] &&
+		   mxy[0]<=axy[2] && mxy[1]<=axy[3] &&
+		   raydium_mouse_click==1 )
+		    {
+	    	    raydium_mouse_click=0;
+	    	    raydium_gui_windows[window].focused_widget=w;
+		    inc=arrow;
+	    	    }
+		} // end if arrow
+
+	    fxy[0]=xy[0];
+	    fxy[1]=xy[1]+(xy[3]-xy[1])/2;
+	    tmp=raydium_gui_windows[window].widgets[w].font_size/RAYDIUM_OSD_FONT_SIZE_FACTOR;
+	    tmp2=(xy[2]-xy[0])-tmp;
+	    tmp2/=tmp;
+
+	    if(tmp2<strlen(str))
+	        str[(int)tmp2]=0;
+
+	    raydium_osd_color_change(c->font_color[0],c->font_color[1],c->font_color[2]);
+	    raydium_osd_printf(fxy[0]+tmp,fxy[1],
+		   raydium_gui_windows[window].widgets[w].font_size,
+		   0.5,"font2.tga","%s",str);
+
+	    //	events (change current ?)
+	    if(raydium_gui_window_focused==window &&
+	       mxy[0]>=xy[0] && mxy[1]>=xy[1] &&
+	       mxy[0]<=xy[2] && mxy[1]<=xy[3] &&
+	       raydium_mouse_click==1 )
+		{
+		c->current=cpt+c->offset;
+	        raydium_mouse_click=0;
+	        c->expanded=0;
+	        raydium_gui_windows[window].focused_widget=w;
+	        }
+
+	    if(cpt==RAYDIUM_GUI_COMBO_LIST_HEIGHT-1)
+		break;
+
+	    start=end+1;
+	    cpt++;
+	    } // end SEPARATOR
+} // end expanded
+
+c->offset+=inc;
+}
+
+
+void raydium_gui_window_draw(int window)
+{
+int i;
+GLfloat uv[4];
+GLfloat xy[4];
+
+if(!raydium_gui_window_isvalid(window))
+    return;
+
+uv[0]=  raydium_gui_theme_current.background_uv[0]/raydium_gui_theme_current.texture_size[0];
+uv[1]=1-raydium_gui_theme_current.background_uv[1]/raydium_gui_theme_current.texture_size[1];
+uv[2]=
+    (raydium_gui_theme_current.background_uv[0] +
+     raydium_gui_theme_current.background_uv[2] ) /
+     raydium_gui_theme_current.texture_size[0];
+uv[3]=1-
+    (raydium_gui_theme_current.background_uv[1] +
+     raydium_gui_theme_current.background_uv[3] ) /
+     raydium_gui_theme_current.texture_size[1];
+
+xy[0]=raydium_gui_windows[window].pos[0];
+xy[1]=raydium_gui_windows[window].pos[1];
+xy[2]=raydium_gui_windows[window].pos[0]+raydium_gui_windows[window].size[0];
+xy[3]=raydium_gui_windows[window].pos[1]+raydium_gui_windows[window].size[1];
+
+raydium_gui_widget_draw_internal(uv,xy);
+
+// draw combos, first pass (capture input events first)
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(raydium_gui_widget_isvalid(i,window))
+	switch(raydium_gui_windows[window].widgets[i].type)
+	{
+	case RAYDIUM_GUI_COMBO:
+	    raydium_gui_combo_draw(i,window);
+	    break;
+	}
+
+// draw other components
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(raydium_gui_widget_isvalid(i,window))
+	switch(raydium_gui_windows[window].widgets[i].type)
+	{
+	case RAYDIUM_GUI_BUTTON:
+	    raydium_gui_button_draw(i,window);
+	    break;
+	case RAYDIUM_GUI_LABEL:
+	    raydium_gui_label_draw(i,window);
+	    break;
+	case RAYDIUM_GUI_TRACK:
+	    raydium_gui_track_draw(i,window);
+	    break;
+	case RAYDIUM_GUI_EDIT:
+	    raydium_gui_edit_draw(i,window);
+	    break;
+	case RAYDIUM_GUI_CHECK:
+	    raydium_gui_check_draw(i,window);
+	    break;
+	}
+
+// draw combos last (overlay all components)
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(raydium_gui_widget_isvalid(i,window))
+	switch(raydium_gui_windows[window].widgets[i].type)
+	{
+	case RAYDIUM_GUI_COMBO:
+	    raydium_gui_combo_draw(i,window);
+	    break;
+	}
+
+// unfocus component
+if(raydium_mouse_click==1)
+    {
+    raydium_gui_windows[window].focused_widget=-1;
+    }
+}
+
+void raydium_gui_draw(void)
+{
+int i;
+
+if(!raydium_gui_visible)
+    return;
+if(!raydium_gui_theme_current.loaded)
+    return;
+
+if(!raydium_gui_window_isvalid(raydium_gui_window_focused))
+    raydium_gui_window_focused=-1;
+
+if(raydium_key_last==1009)
+    raydium_gui_widget_next();
+
+// non focused windows (~ creation order)
+for(i=0;i<RAYDIUM_GUI_MAX_WINDOWS;i++)
+    if(raydium_gui_windows[i].state && i!=raydium_gui_window_focused)
+	raydium_gui_window_draw(i);
+
+// focus window
+for(i=0;i<RAYDIUM_GUI_MAX_WINDOWS;i++)
+    if(raydium_gui_windows[i].state && i==raydium_gui_window_focused)
+	{
+	raydium_gui_window_draw(i);
+	break;
+	}
+
+raydium_osd_color_ega('f');
+}
+
+
+////////////////////////
+// Internal accessors //
+////////////////////////
+
+int raydium_gui_button_read(int window, int widget, char *str)
+{
+if(!raydium_gui_widget_isvalid(widget,window))
+    {
+    raydium_log("gui: error: cannot read widget value: invalid name or index");
+    return 0;
+    }
+// Nothing is readable on a button :
+str[0]=0;
+return 0;
+}
+
+int raydium_gui_label_read(int window, int widget, char *str)
+{
+if(!raydium_gui_widget_isvalid(widget,window))
+    {
+    raydium_log("gui: error: cannot read widget value: invalid name or index");
+    return 0;
+    }
+// Nothing is readable on a label :
+str[0]=0;
+return 0;
+}
+
+int raydium_gui_track_read(int window, int widget, char *str)
+{
+raydium_gui_Track *t;
+
+if(!raydium_gui_widget_isvalid(widget,window))
+    {
+    raydium_log("gui: error: cannot read widget value: invalid name or index");
+    return 0;
+    }
+t=raydium_gui_windows[window].widgets[widget].widget;
+// value|ratio|min|max
+sprintf(str,"%i|%f|%i|%i",t->current,
+			 (float)(t->current-t->min)/(float)(t->max-t->min),
+			 t->min,
+			 t->max);
+return t->current;
+}
+
+int raydium_gui_edit_read(int window, int widget, char *str)
+{
+raydium_gui_Edit *e;
+
+if(!raydium_gui_widget_isvalid(widget,window))
+    {
+    raydium_log("gui: error: cannot read widget value: invalid name or index");
+    return 0;
+    }
+e=raydium_gui_windows[window].widgets[widget].widget;
+strcpy(str,e->text);
+return strlen(e->text);
+}
+
+int raydium_gui_check_read(int window, int widget, char *str)
+{
+raydium_gui_Check *c;
+
+if(!raydium_gui_widget_isvalid(widget,window))
+    {
+    raydium_log("gui: error: cannot read widget value: invalid name or index");
+    return 0;
+    }
+c=raydium_gui_windows[window].widgets[widget].widget;
+sprintf(str,"%s",(c->checked?"true":"false"));
+return c->checked;
+}
+
+int raydium_gui_combo_read(int window, int widget, char *str)
+{
+raydium_gui_Combo *c;
+
+if(!raydium_gui_widget_isvalid(widget,window))
+    {
+    raydium_log("gui: error: cannot read widget value: invalid name or index");
+    return 0;
+    }
+c=raydium_gui_windows[window].widgets[widget].widget;
+strcpy(str,c->current_str);
+return c->current;
+}
+
+
+////////////////////////////
+// "public" GUI functions //
+////////////////////////////
+
+void raydium_gui_show(void)
+{
+raydium_gui_visible=1;
+if(!raydium_osd_cursor_texture)
+    {
+    raydium_gui_oldstate=raydium_mouse_isvisible();
+    raydium_mouse_show();
+    }
+}
+
+void raydium_gui_hide(void)
+{
+raydium_gui_visible=0;
+if(!raydium_osd_cursor_texture && !raydium_gui_oldstate)
+    {
+    raydium_mouse_hide();
+    raydium_gui_oldstate=0;
+    }
+}
+
+char raydium_gui_isvisible(void)
+{
+return raydium_gui_visible;
+}
+
+void raydium_gui_window_delete(int window)
+{
+if(!raydium_gui_window_isvalid(window))
+    {
+    raydium_log("GUI: Error: Cannot delete window: invalid window");
+    return;
+    }
+
+// focus another window
+raydium_gui_window_focused=raydium_gui_windows[window].old_focused;
+raydium_gui_window_init(window);
+}
+
+void raydium_gui_window_delete_name(char *window)
+{
+raydium_gui_window_delete(raydium_gui_window_find(window));
+}
+
+
+void raydium_gui_widget_sizes(GLfloat sizex, GLfloat sizey, GLfloat font_size)
+{
+raydium_gui_widget_sizes_default[0]=sizex;
+raydium_gui_widget_sizes_default[1]=sizey;
+raydium_gui_widget_sizes_default[2]=font_size;
+}
+
+int raydium_gui_window_create(char *name, GLfloat px, GLfloat py, GLfloat sizex, GLfloat sizey)
+{
+int i;
+
+if(raydium_gui_window_find(name)>=0)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" window: name already exists",name);
+    return -1;
+    }
+
+for(i=0;i<RAYDIUM_GUI_MAX_WINDOWS;i++)
+    if(!raydium_gui_windows[i].state)
+     {
+     strcpy(raydium_gui_windows[i].name,name);
+     raydium_gui_windows[i].state=1;
+     raydium_gui_windows[i].pos[0]=px;
+     raydium_gui_windows[i].pos[1]=py;
+     raydium_gui_windows[i].size[0]=sizex;
+     raydium_gui_windows[i].size[1]=sizey;
+     raydium_gui_windows[i].old_focused=raydium_gui_window_focused;
+     
+     raydium_gui_window_focused=i; // take focus
+     return i;
+     }
+raydium_log("GUI: Error: No more window slots ! aborting \"%s\" creation",name);
+return -1;
+}
+
+int raydium_gui_internal_object_create(char *name, int window, char type, GLfloat px, GLfloat py, GLfloat sizex, GLfloat sizey, GLfloat font_size)
+{
+int i;
+
+if(!raydium_gui_window_isvalid(window))
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" widget: invalid window",name);
+    return -1;
+    }
+
+if(raydium_gui_widget_find(name,window)>=0)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" widget: name already exists in this window",name);
+    return -1;
+    }
+
+for(i=0;i<RAYDIUM_GUI_MAX_OBJECTS;i++)
+    if(!raydium_gui_windows[window].widgets[i].state)
+     {
+     strcpy(raydium_gui_windows[window].widgets[i].name,name);
+     raydium_gui_windows[window].widgets[i].state=1;
+     raydium_gui_windows[window].widgets[i].type=type;
+     raydium_gui_windows[window].widgets[i].pos[0]=px;
+     raydium_gui_windows[window].widgets[i].pos[1]=py;
+     raydium_gui_windows[window].widgets[i].font_size=font_size;
+     raydium_gui_windows[window].widgets[i].size[0]=sizex;
+     raydium_gui_windows[window].widgets[i].size[1]=sizey;
+     return i;
+     }
+
+raydium_log("GUI: Error: Cannot create \"%s\" widget: no more slots",name);
+return -1;
+}
+
+int raydium_gui_button_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, void *OnClick)
+{
+int wid;
+raydium_gui_Button *b;
+GLfloat sx,sy,fs;
+// used for parsing
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+
+
+b=malloc(sizeof(raydium_gui_Button));
+if(!b)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" button: malloc failed",name);
+    return -1;
+    }
+
+fp=raydium_file_fopen(raydium_gui_theme_current.filename,"rt");
+if(!fp)
+    {
+    raydium_log("gui: ERROR: Cannot open current theme file");
+    return -1;
+    }
+
+sx=raydium_gui_widget_sizes_default[0];
+sy=raydium_gui_widget_sizes_default[1];
+fs=raydium_gui_widget_sizes_default[2];
+wid=raydium_gui_internal_object_create(name,window,RAYDIUM_GUI_BUTTON,px,py,sx,sy,fs);
+if(wid<0)
+    {
+    raydium_log("GUI: Error: early init failed for button '%s'",name);
+    return -1;
+    }
+
+strcpy(b->caption,caption);
+b->OnClick=OnClick;
+
+memset(b->uv_normal, 0,sizeof(GLfloat)*4);
+memset(b->uv_focus,  0,sizeof(GLfloat)*4);
+memset(b->uv_hover,  0,sizeof(GLfloat)*4);
+memset(b->font_color,0,sizeof(GLfloat)*3);
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)    
+    {
+    if(!strcasecmp(var,"button_normal"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: button_normal: wrong type");
+            continue;
+            }
+        memcpy(b->uv_normal,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"button_focus"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: button_focus: wrong type");
+            continue;
+            }
+        memcpy(b->uv_focus,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"button_hover"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: button_hover: wrong type");
+            continue;
+            }
+        memcpy(b->uv_hover,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"button_font"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+            {
+	    raydium_log("gui: parser: button_font: wrong type");
+            continue;
+            }
+        memcpy(b->font_color,val_f,sizeof(GLfloat)*3);
+        }
+    }
+fclose(fp);
+
+raydium_gui_windows[window].widgets[wid].widget=b;
+return wid;
+}
+
+
+int raydium_gui_button_create_simple(char *name, int window,  GLfloat px, GLfloat py, char *caption)
+{
+return raydium_gui_button_create(name,window,px,py,caption,NULL);
+}
+
+
+int raydium_gui_label_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, GLfloat r, GLfloat g, GLfloat b)
+{
+int wid;
+raydium_gui_Label *l;
+GLfloat fs;
+
+l=malloc(sizeof(raydium_gui_Label));
+if(!l)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" label: malloc failed",name);
+    return -1;
+    }
+
+fs=raydium_gui_widget_sizes_default[2];
+wid=raydium_gui_internal_object_create(name,window,RAYDIUM_GUI_LABEL,px,py,0,0,fs);
+if(wid<0)
+    {
+    raydium_log("GUI: Error: early init failed for label '%s'",name);
+    return -1;
+    }
+
+strcpy(l->caption,caption);
+l->font_color[0]=r;
+l->font_color[1]=g;
+l->font_color[2]=b;
+raydium_gui_windows[window].widgets[wid].widget=l;
+return wid;
+}
+
+
+int raydium_gui_track_create(char *name, int window,  GLfloat px, GLfloat py, int min, int max, int current)
+{
+int wid;
+raydium_gui_Track *t;
+GLfloat sx,sy,fs;
+// used for parsing
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+
+
+t=malloc(sizeof(raydium_gui_Track));
+if(!t)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" track: malloc failed",name);
+    return -1;
+    }
+
+fp=raydium_file_fopen(raydium_gui_theme_current.filename,"rt");
+if(!fp)
+    {
+    raydium_log("gui: ERROR: Cannot open current theme file");
+    return -1;
+    }
+
+sx=raydium_gui_widget_sizes_default[0];
+sy=raydium_gui_widget_sizes_default[1];
+fs=raydium_gui_widget_sizes_default[2];
+wid=raydium_gui_internal_object_create(name,window,RAYDIUM_GUI_TRACK,px,py,sx,sy,fs);
+if(wid<0)
+    {
+    raydium_log("GUI: Error: early init failed for track '%s'",name);
+    return -1;
+    }
+
+t->min=min;
+t->max=max;
+t->current=current;
+
+memset(t->uv_rule,0,sizeof(GLfloat)*4);
+memset(t->uv_cursor_normal,0,sizeof(GLfloat)*4);
+memset(t->uv_cursor_focus,0,sizeof(GLfloat)*4);
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    if(!strcasecmp(var,"track_rule"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: track_rule: wrong type");
+            continue;
+            }
+        memcpy(t->uv_rule,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"track_cursor_normal"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: track_cursor_normal: wrong type");
+            continue;
+            }
+        memcpy(t->uv_cursor_normal,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"track_cursor_focus"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: track_cursor_focus: wrong type");
+            continue;
+            }
+        memcpy(t->uv_cursor_focus,val_f,sizeof(GLfloat)*4);
+        }
+    }
+fclose(fp);
+
+raydium_gui_windows[window].widgets[wid].widget=t;
+return wid;
+}
+
+
+
+int raydium_gui_edit_create(char *name, int window,  GLfloat px, GLfloat py, char *default_text)
+{
+int wid;
+raydium_gui_Edit *e;
+GLfloat sx,sy,fs;
+// used for parsing
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+
+
+e=malloc(sizeof(raydium_gui_Edit));
+if(!e)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" edit: malloc failed",name);
+    return -1;
+    }
+
+fp=raydium_file_fopen(raydium_gui_theme_current.filename,"rt");
+if(!fp)
+    {
+    raydium_log("gui: ERROR: Cannot open current theme file");
+    return -1;
+    }
+
+sx=raydium_gui_widget_sizes_default[0];
+sy=raydium_gui_widget_sizes_default[1];
+fs=raydium_gui_widget_sizes_default[2];
+wid=raydium_gui_internal_object_create(name,window,RAYDIUM_GUI_EDIT,px,py,sx,sy,fs);
+if(wid<0)
+    {
+    raydium_log("GUI: Error: early init failed for edit '%s'",name);
+    return -1;
+    }
+
+e->offset=0;
+strcpy(e->text,default_text);
+e->cursor=strlen(e->text);
+//e->cursor=0;
+memset(e->uv_normal,0,sizeof(GLfloat)*4);
+memset(e->uv_focus,0,sizeof(GLfloat)*4);
+memset(e->font_color,0,sizeof(GLfloat)*3);
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    if(!strcasecmp(var,"edit_normal"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: edit_normal: wrong type");
+            continue;
+            }
+        memcpy(e->uv_normal,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"edit_focus"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: edit_focus: wrong type");
+            continue;
+            }
+        memcpy(e->uv_focus,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"font_color"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+            {
+	    raydium_log("gui: parser: font_color: wrong type");
+            continue;
+            }
+        memcpy(e->font_color,val_f,sizeof(GLfloat)*3);
+        }
+    }
+fclose(fp);
+
+raydium_gui_windows[window].widgets[wid].widget=e;
+return wid;
+}
+
+int raydium_gui_check_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, char checked)
+{
+int wid;
+raydium_gui_Check *c;
+GLfloat sx,sy,fs;
+// used for parsing
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+
+
+c=malloc(sizeof(raydium_gui_Check));
+if(!c)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" check: malloc failed",name);
+    return -1;
+    }
+
+fp=raydium_file_fopen(raydium_gui_theme_current.filename,"rt");
+if(!fp)
+    {
+    raydium_log("gui: ERROR: Cannot open current theme file");
+    return -1;
+    }
+
+sx=raydium_gui_widget_sizes_default[0];
+sy=raydium_gui_widget_sizes_default[1];
+fs=raydium_gui_widget_sizes_default[2];
+wid=raydium_gui_internal_object_create(name,window,RAYDIUM_GUI_CHECK,px,py,sx,sy,fs);
+if(wid<0)
+    {
+    raydium_log("GUI: Error: early init failed for check '%s'",name);
+    return -1;
+    }
+
+strcpy(c->caption,caption);
+c->checked=checked;
+memset(c->uv_normal,0,sizeof(GLfloat)*4);
+memset(c->uv_checked,0,sizeof(GLfloat)*4);
+memset(c->font_color_normal,0,sizeof(GLfloat)*3);
+memset(c->font_color_focus,0,sizeof(GLfloat)*3);
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    if(!strcasecmp(var,"check_normal"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: check_normal: wrong type");
+            continue;
+            }
+        memcpy(c->uv_normal,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"check_checked"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: check_checked: wrong type");
+            continue;
+            }
+        memcpy(c->uv_checked,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"font_color_normal"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+            {
+	    raydium_log("gui: parser: font_color_normal: wrong type");
+            continue;
+            }
+        memcpy(c->font_color_normal,val_f,sizeof(GLfloat)*3);
+        }
+
+    if(!strcasecmp(var,"font_color_focus"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+            {
+	    raydium_log("gui: parser: font_color_focus: wrong type");
+            continue;
+            }
+        memcpy(c->font_color_focus,val_f,sizeof(GLfloat)*3);
+        }
+    }
+fclose(fp);
+
+raydium_gui_windows[window].widgets[wid].widget=c;
+return wid;
+}
+
+int raydium_gui_combo_create(char *name, int window,  GLfloat px, GLfloat py, char *items, int current)
+{
+int wid;
+raydium_gui_Combo *c;
+GLfloat sx,sy,fs;
+// used for parsing
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+
+
+c=malloc(sizeof(raydium_gui_Combo));
+if(!c)
+    {
+    raydium_log("GUI: Error: Cannot create \"%s\" combo: malloc failed",name);
+    return -1;
+    }
+
+fp=raydium_file_fopen(raydium_gui_theme_current.filename,"rt");
+if(!fp)
+    {
+    raydium_log("gui: ERROR: Cannot open current theme file");
+    return -1;
+    }
+
+sx=raydium_gui_widget_sizes_default[0];
+sy=raydium_gui_widget_sizes_default[1];
+fs=raydium_gui_widget_sizes_default[2];
+wid=raydium_gui_internal_object_create(name,window,RAYDIUM_GUI_COMBO,px,py,sx,sy,fs);
+if(wid<0)
+    {
+    raydium_log("GUI: Error: early init failed for combo '%s'",name);
+    return -1;
+    }
+
+strcpy(c->items,items);
+c->current=current;
+c->expanded=0;
+c->offset=0;
+c->body_border_right=0;
+memset(c->uv_body_normal,0,sizeof(GLfloat)*4);
+memset(c->uv_body_focus,0,sizeof(GLfloat)*4);
+memset(c->uv_list_top,0,sizeof(GLfloat)*4);
+memset(c->uv_list_middle,0,sizeof(GLfloat)*4);
+memset(c->uv_list_bottom,0,sizeof(GLfloat)*4);
+memset(c->uv_list_current,0,sizeof(GLfloat)*4);
+memset(c->uv_arrow,0,sizeof(GLfloat)*4);
+memset(c->font_color,0,sizeof(GLfloat)*3);
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    if(!strcasecmp(var,"combo_body_normal"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_body_normal: wrong type");
+            continue;
+            }
+        memcpy(c->uv_body_normal,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"combo_body_focus"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_body_focus: wrong type");
+            continue;
+            }
+        memcpy(c->uv_body_focus,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"combo_body_border_right"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+            {
+	    raydium_log("gui: parser: combo_body_border_right: wrong type");
+            continue;
+            }
+        c->body_border_right=(int)val_f[0];
+        }
+
+
+    if(!strcasecmp(var,"combo_list_top"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_list_top: wrong type");
+            continue;
+            }
+        memcpy(c->uv_list_top,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"combo_list_middle"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_list_middle: wrong type");
+            continue;
+            }
+        memcpy(c->uv_list_middle,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"combo_list_bottom"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_list_bottom: wrong type");
+            continue;
+            }
+        memcpy(c->uv_list_bottom,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"combo_list_current"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_list_current: wrong type");
+            continue;
+            }
+        memcpy(c->uv_list_current,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"combo_arrow"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+            {
+	    raydium_log("gui: parser: combo_arrow: wrong type");
+            continue;
+            }
+        memcpy(c->uv_arrow,val_f,sizeof(GLfloat)*4);
+        }
+
+    if(!strcasecmp(var,"font_color"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+            {
+	    raydium_log("gui: parser: font_color: wrong type");
+            continue;
+            }
+        memcpy(c->font_color,val_f,sizeof(GLfloat)*3);
+        }
+    }
+fclose(fp);
+
+raydium_gui_windows[window].widgets[wid].widget=c;
+return wid;
+}
+
+
+// str may be big !
+int raydium_gui_read(int window, int widget, char *str)
+{
+    if(raydium_gui_widget_isvalid(widget,window))
+    {
+	switch(raydium_gui_windows[window].widgets[widget].type)
+	{
+	case RAYDIUM_GUI_BUTTON:
+	    return raydium_gui_button_read(window,widget,str);
+	case RAYDIUM_GUI_LABEL:
+	    return raydium_gui_label_read(window,widget,str);
+	case RAYDIUM_GUI_TRACK:
+	    return raydium_gui_track_read(window,widget,str);
+	case RAYDIUM_GUI_EDIT:
+	    return raydium_gui_edit_read(window,widget,str);
+	case RAYDIUM_GUI_CHECK:
+	    return raydium_gui_check_read(window,widget,str);
+	case RAYDIUM_GUI_COMBO:
+	    return raydium_gui_combo_read(window,widget,str);
+	}
+    }
+    else 
+	raydium_log("gui: error: cannot read widget value: invalid name or index");
+
+return 0;    
+}
+
+int raydium_gui_read_name(char *window, char *widget, char *str)
+{
+int w;
+w=raydium_gui_window_find(window);
+return raydium_gui_read(w,raydium_gui_widget_find(widget,w),str);
+}
+
+int raydium_gui_button_clicked(void)
+{
+int ret;
+ret=raydium_gui_button_clicked_id;
+raydium_gui_button_clicked_id=-1;
+return ret;
+}
Index: raydium/register.c
===================================================================
--- raydium/register.c	(revision 0)
+++ raydium/register.c	(revision 1)
@@ -0,0 +1,229 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/register.h"
+#endif 
+
+// script registering: varibles and functions
+
+int raydium_register_find_name(char *name)
+{
+int i;
+if(!strlen(name)) return -1;
+for(i=0;i<raydium_register_variable_index;i++)
+    if(!strcmp(name,raydium_register_variable_name[i]))
+        return i;
+// not found:
+return -1;
+}
+
+char raydium_register_name_isvalid(char *name)
+{
+int i;
+for(i=0;i<strlen(name);i++)
+    if(! ((name[i]>='a' && name[i]<='z') || 
+          (name[i]>='A' && name[i]<='Z') ||
+           name[i]=='_') )
+           return 0; // this char is not valid
+return 1;
+}
+
+// ex: int titi; ...(&titi,INT,"titi");
+int raydium_register_variable(void *addr, int type, char *name)
+{
+int i;
+
+
+if(raydium_register_variable_index==RAYDIUM_MAX_REG_VARIABLES)
+    {
+    raydium_log("register: ERROR: no more empty slots for variables",name);
+    return -1;
+    }
+
+if( type!=RAYDIUM_REGISTER_INT &&
+    type!=RAYDIUM_REGISTER_FLOAT &&
+    type!=RAYDIUM_REGISTER_STR)
+    {
+    raydium_log("register: ERROR: use 'raydium_register_variable_const_*' for constants",name);
+    return -1;
+    }
+
+if(!raydium_register_name_isvalid(name))
+    {
+    raydium_log("register: ERROR: \"%s\" is not a valid name",name);
+    return -1;
+    }
+if(raydium_register_find_name(name)>=0)
+    {
+    raydium_log("register: variable: ERROR: \"%s\" already registered",name);
+    return -1;
+    }
+
+i=raydium_register_variable_index++;
+strcpy(raydium_register_variable_name[i],name);
+raydium_register_variable_addr[i]=addr;
+raydium_register_variable_type[i]=type;
+return i;
+}
+
+int raydium_register_variable_const_i(int val, char *name)
+{
+int i;
+int type=RAYDIUM_REGISTER_ICONST;
+
+if(raydium_register_variable_index==RAYDIUM_MAX_REG_VARIABLES)
+    {
+    raydium_log("register: ERROR: no more empty slots for variables",name);
+    return -1;
+    }
+
+if(!raydium_register_name_isvalid(name))
+    {
+    raydium_log("register: \"%s\" is not a valid name",name);
+    return -1;
+    }
+if(raydium_register_find_name(name)>=0)
+    {
+    raydium_log("register: variable: ERROR: \"%s\" already registered",name);
+    return -1;
+    }
+
+i=raydium_register_variable_index++;
+strcpy(raydium_register_variable_name[i],name);
+raydium_register_variable_addr[i]=malloc(sizeof(val));
+(*(int *)raydium_register_variable_addr[i])=val;
+raydium_register_variable_type[i]=type;
+return i;
+}
+
+int raydium_register_variable_const_f(float val, char *name)
+{
+int i;
+int type=RAYDIUM_REGISTER_FCONST;
+
+if(raydium_register_variable_index==RAYDIUM_MAX_REG_VARIABLES)
+    {
+    raydium_log("register: ERROR: no more empty slots for variables",name);
+    return -1;
+    }
+
+if(!raydium_register_name_isvalid(name))
+    {
+    raydium_log("register: \"%s\" is not a valid name",name);
+    return -1;
+    }
+if(raydium_register_find_name(name)>=0)
+    {
+    raydium_log("register: variable: ERROR: \"%s\" already registered",name);
+    return -1;
+    }
+
+i=raydium_register_variable_index++;
+strcpy(raydium_register_variable_name[i],name);
+raydium_register_variable_addr[i]=malloc(sizeof(val));
+(*(float *)raydium_register_variable_addr[i])=val;
+raydium_register_variable_type[i]=type;
+return i;
+}
+
+
+
+
+void raydium_register_variable_unregister_last(void)
+{
+if(raydium_register_variable_index)
+    raydium_register_variable_index--;
+else
+    raydium_log("register: cannot unregister last variable: stack empty");
+}
+
+int raydium_register_modifiy(char *var, char *args)
+{
+int i;
+int *p_i;
+float *f_i;
+char *f_str;
+
+raydium_log("WARNING: raydium_register_modifiy is deprecated !");
+
+if(!raydium_register_name_isvalid(var))
+    {
+    raydium_log("register: modify: \"%s\" is not a valid name",var);
+    return -1;
+    }
+i=raydium_register_find_name(var);
+if(i<0)
+    {
+    raydium_log("register: modify: %s not found",var);
+    return -1;
+    }
+
+if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_INT)
+    {
+    p_i=raydium_register_variable_addr[i];
+    (*p_i)=atoi(args);
+    return i;
+    }
+
+if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_FLOAT)
+    {
+    float a;
+    f_i=raydium_register_variable_addr[i];
+    a=atof(args);
+    (*f_i)=a;
+    return i;
+    }
+
+if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_STR)
+    {
+    f_str=raydium_register_variable_addr[i];
+    strcpy(f_str,args);
+    return i;
+    }
+raydium_log("register: modify: unknown type (%i) for \"%s\"",raydium_register_variable_type[i],var);
+return -1;
+}
+
+void raydium_register_function(void *addr,char *name)
+{
+#ifdef PHP_SUPPORT
+char *str;
+str=malloc(strlen(name)+1);
+if(raydium_register_function_index+2>=RAYDIUM_MAX_REG_FUNCTION)
+    {
+    raydium_log("register function: ERROR: no more room");
+    return;
+    }
+strcpy(str,name);
+raydium_register_function_list[raydium_register_function_index].fname=str;
+raydium_register_function_list[raydium_register_function_index].handler=addr;
+raydium_register_function_list[raydium_register_function_index].func_arg_types=NULL;
+raydium_register_function_index++;
+raydium_register_function_list[raydium_register_function_index].fname=NULL;
+raydium_register_function_list[raydium_register_function_index].handler=NULL;
+raydium_register_function_list[raydium_register_function_index].func_arg_types=NULL;
+#else
+raydium_log("register function: ERROR: need PHP support");
+#endif
+}
+
+
+void raydium_register_dump(void)
+{
+int i;
+char type[6][16]={"","int ","float ","char *","cont int ","const float "};
+raydium_log("Registered data:");
+raydium_log("----------------");
+
+for(i=0;i<raydium_register_variable_index;i++)
+    raydium_log("var: %s%s;",type[raydium_register_variable_type[i]],raydium_register_variable_name[i]);
+
+for(i=0;i<raydium_register_function_index;i++)
+    raydium_log("func: %s();",raydium_register_function_list[i].fname);
+}
Index: raydium/osd.c
===================================================================
--- raydium/osd.c	(revision 0)
+++ raydium/osd.c	(revision 1)
@@ -0,0 +1,502 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/osd.h"
+#endif
+
+// need proto
+void raydium_camera_replace(void);
+
+// OSD color could be changed from one frame to the next one by Raydium
+// itself (console, internal uses, ...) so set your OSD color
+// in the display loop, no before.
+
+void raydium_osd_color_change(GLfloat r, GLfloat g, GLfloat b)
+{
+raydium_osd_color[0]=r;
+raydium_osd_color[1]=g;
+raydium_osd_color[2]=b;
+}
+
+void raydium_osd_alpha_change(GLfloat a)
+{
+raydium_osd_color[3]=a;
+}
+
+void raydium_osd_color_rgba(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+raydium_osd_color_change(r,g,b);
+raydium_osd_alpha_change(a);
+}
+
+void raydium_osd_color_ega(char hexa)
+{
+int i=15;
+
+if(hexa>='0' && hexa<='9') i=hexa - '0';
+if(hexa>='a' && hexa<='f') i=hexa - 'a'+10;
+if(hexa>='A' && hexa<='F') i=hexa - 'A'+10;
+i*=3;
+raydium_osd_color_change(raydium_osd_ega[i],raydium_osd_ega[i+1],raydium_osd_ega[i+2]);
+}
+
+void raydium_osd_start(void)
+{
+glMatrixMode(GL_PROJECTION);
+glLoadIdentity();
+
+//glViewport(0, 0, raydium_window_tx, raydium_window_ty);
+glOrtho(0,100, 0,100, -100,100);
+
+//glPushMatrix();
+raydium_rendering_internal_prepare_texture_render(0);
+glMatrixMode(GL_MODELVIEW);
+glLoadIdentity();
+glDisable(GL_DEPTH_TEST);
+glDepthMask(GL_FALSE);
+glDisable(GL_LIGHTING);
+glDisable(GL_FOG);
+glColor4f(1.f,1.f,1.f,1.f);
+}
+
+void raydium_osd_stop(void)
+{
+raydium_window_resize_callback(raydium_window_tx, raydium_window_ty);
+glEnable(GL_DEPTH_TEST);
+glDepthMask(GL_TRUE);
+if(raydium_light_enabled_tag) glEnable(GL_LIGHTING);
+if(raydium_fog_enabled_tag)   glEnable(GL_FOG);
+}
+
+
+void raydium_osd_draw(int tex ,GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+raydium_osd_start();
+
+raydium_texture_current_set(tex);
+raydium_rendering_internal_prepare_texture_render(tex);
+glColor4fv(raydium_osd_color);
+glBegin(GL_QUADS);
+glTexCoord2f(0,0);
+glVertex3f(x1,y1,0);
+glTexCoord2f(1,0);
+glVertex3f(x2,y1,0);
+glTexCoord2f(1,1);
+glVertex3f(x2,y2,0);
+glTexCoord2f(0,1);
+glVertex3f(x1,y2,0);
+glEnd();
+raydium_rendering_internal_restore_render_state();
+
+raydium_osd_stop();
+}
+
+void raydium_osd_draw_name(char *tex ,GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+raydium_osd_draw(raydium_texture_find_by_name(tex),x1,y1,x2,y2);
+}
+
+// need to be secured
+void raydium_osd_printf(GLfloat x, GLfloat y, GLfloat size, GLfloat spacer,char *texture, unsigned char *format, ...)
+{
+unsigned char str[RAYDIUM_MAX_NAME_LEN];
+va_list argptr;
+int i,texsave;
+GLfloat dx=0;
+unsigned char ligne,offset;
+GLfloat u,v;
+char c;
+
+
+size/=RAYDIUM_OSD_FONT_SIZE_FACTOR;
+va_start(argptr,format);
+vsprintf(str,format,argptr);
+va_end(argptr);
+
+raydium_osd_start();
+texsave=raydium_texture_current;
+raydium_texture_current_set_name(texture);
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+
+glTranslatef(x,y,0);
+
+// strlen is slooow :)
+for( i=0; str[i]; i++ )
+ {
+ if(str[i]=='\n' || str[i]=='\t') continue;
+ if(str[i]=='^' && i+1<RAYDIUM_MAX_NAME_LEN && str[i+1]!=0) {
+                 // oh ! ... you cannot draw '^' char since i'm
+		 // too lazy to code it for now :)
+                 raydium_osd_color_ega(str[++i]);
+		 continue;
+		 }
+ c=str[i]; // c=str[i]-32;
+ ligne=c/16;
+ offset=c-(ligne*16);
+ u=offset/16.f;
+ v=1-(ligne/16.f); // /*1-*/
+
+ glColor4fv(raydium_osd_color);
+ glBegin(GL_QUADS);
+ glTexCoord2f(u,v);
+ glVertex3f(-size+dx,size,0);
+ glTexCoord2f(u+(1/16.f),v);
+ glVertex3f(size+dx,size,0);
+ glTexCoord2f(u+(1/16.f),v-(1/16.f));
+ glVertex3f(size+dx,-size,0);
+ glTexCoord2f(u,v-(1/16.f));
+ glVertex3f(-size+dx,-size,0);
+ glEnd();
+ dx+=(size*2*spacer);
+
+ }
+
+//raydium_rendering_internal_restore_render_state();
+raydium_osd_stop();
+//raydium_texture_current_set(texsave);
+}
+
+
+void raydium_osd_printf_3D(GLfloat x, GLfloat y, GLfloat z, GLfloat size, GLfloat spacer,char *texture, unsigned char *format, ...)
+{
+unsigned char str[RAYDIUM_MAX_NAME_LEN];
+va_list argptr;
+
+GLdouble sx,sy,sz;
+GLdouble modelMatrix[16];
+GLdouble projectionMatrix[16];
+GLint   viewport[4];
+
+va_start(argptr,format);
+vsprintf(str,format,argptr);
+va_end(argptr);
+
+raydium_camera_replace();
+glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
+glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix);
+glGetIntegerv(GL_VIEWPORT, viewport);
+gluProject(x,y,z,modelMatrix,projectionMatrix,viewport,&sx,&sy,&sz);
+
+sx=sx/raydium_window_tx*100;
+sy=sy/raydium_window_ty*100;
+if(sz<=1.0) raydium_osd_printf(sx,sy,size,spacer,texture,str);
+}
+
+void raydium_osd_logo(char *texture)
+{
+//GLuint vertex_index_save;
+raydium_osd_start();
+raydium_texture_current_set_name(texture);
+
+glTranslatef(85,10,0);
+glRotatef(raydium_osd_logo_angle+=(raydium_frame_time*60),0,1,0); //must be callbacked !
+if(raydium_osd_logo_angle>90) raydium_osd_logo_angle=-90;
+
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+glBegin(GL_QUADS);
+glTexCoord2f(0,0);
+glVertex3f(-10,5,0);
+glTexCoord2f(1,0);
+glVertex3f(10,5,0);
+glTexCoord2f(1,1);
+glVertex3f(10,-5,0);
+glTexCoord2f(0,1);
+glVertex3f(-10,-5,0);
+glEnd();
+//raydium_rendering_internal_restore_render_state();
+
+raydium_osd_stop();
+}
+
+
+void raydium_osd_cursor_set(char *texture,GLfloat xsize, GLfloat ysize)
+{
+raydium_mouse_hide();
+raydium_osd_cursor_texture=raydium_texture_find_by_name(texture);
+raydium_osd_cursor_xsize=xsize;
+raydium_osd_cursor_ysize=ysize;
+}
+
+void raydium_osd_cursor_draw(void)
+{
+if(!raydium_osd_cursor_texture || !raydium_window_tx) return;
+
+raydium_osd_start();
+
+glTranslatef(((GLfloat)raydium_mouse_x/raydium_window_tx)*100.f,
+((GLfloat)(raydium_window_ty-raydium_mouse_y)/raydium_window_ty)*100.f,0);
+
+raydium_texture_current_set(raydium_osd_cursor_texture);
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+glBegin(GL_QUADS);
+glTexCoord2f(0,0);
+glVertex3f(0,0,0);
+glTexCoord2f(1,0);
+glVertex3f(raydium_osd_cursor_xsize,0,0);
+glTexCoord2f(1,1);
+glVertex3f(raydium_osd_cursor_xsize,-raydium_osd_cursor_ysize,0);
+glTexCoord2f(0,1);
+glVertex3f(0,-raydium_osd_cursor_ysize,0);
+glEnd();
+raydium_rendering_internal_restore_render_state();
+
+raydium_osd_stop();
+
+}
+
+void raydium_osd_internal_vertex(GLfloat x, GLfloat y, GLfloat top)
+{
+if(y>top) y=top;
+glVertex3f(x,y,0);
+}
+
+void raydium_osd_network_stat_draw(GLfloat px, GLfloat py, GLfloat size)
+{
+#define RAYDIUM_OSD_NET_SAMPLES		32
+#define RAYDIUM_OSD_NET_STEP		0.3
+static GLfloat past_delay[RAYDIUM_OSD_NET_SAMPLES];
+static GLfloat past_rx[RAYDIUM_OSD_NET_SAMPLES];
+static GLfloat past_tx[RAYDIUM_OSD_NET_SAMPLES];
+static GLfloat step=0;
+static int last_rx,last_tx;
+
+static GLfloat past_reemitted[RAYDIUM_OSD_NET_SAMPLES];
+static GLfloat past_double[RAYDIUM_OSD_NET_SAMPLES];
+static GLfloat past_lost[RAYDIUM_OSD_NET_SAMPLES];
+static GLfloat past_bogus[RAYDIUM_OSD_NET_SAMPLES];
+
+static GLfloat last_reemitted;
+static GLfloat last_double;
+static GLfloat last_lost;
+static GLfloat last_bogus;
+
+
+int i;
+GLfloat fact_x,fact_y_delay,fact_y_rxtx;
+
+fact_x=size/RAYDIUM_OSD_NET_SAMPLES;
+fact_y_delay=size/(RAYDIUM_NETWORK_ACK_DELAY_MAX*1000);
+fact_y_rxtx=size/50; // 50 KB
+step+=raydium_frame_time;
+
+if(step>=RAYDIUM_OSD_NET_STEP)
+    {
+    step=0;
+
+    // shift array to the left
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_delay[i-1]=past_delay[i];    
+    past_delay[RAYDIUM_OSD_NET_SAMPLES-1]=raydium_netwok_queue_ack_delay_client;
+
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_rx[i-1]=past_rx[i];    
+    past_rx[RAYDIUM_OSD_NET_SAMPLES-1]=(raydium_network_stat_rx-last_rx)/1024;
+    last_rx=raydium_network_stat_rx;
+
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_tx[i-1]=past_tx[i];    
+    past_tx[RAYDIUM_OSD_NET_SAMPLES-1]=(raydium_network_stat_tx-last_tx)/1024;
+    last_tx=raydium_network_stat_tx;
+
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_reemitted[i-1]=past_reemitted[i];    
+    past_reemitted[RAYDIUM_OSD_NET_SAMPLES-1]=(raydium_network_stat_reemitted-last_reemitted)*(size/10);
+    last_reemitted=raydium_network_stat_reemitted;
+
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_double[i-1]=past_double[i];
+    past_double[RAYDIUM_OSD_NET_SAMPLES-1]=(raydium_network_stat_double-last_double)*(size/10);
+    last_double=raydium_network_stat_double;
+
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_lost[i-1]=past_lost[i];
+    past_lost[RAYDIUM_OSD_NET_SAMPLES-1]=(raydium_network_stat_lost-last_lost)*(size/10);
+    last_lost=raydium_network_stat_lost;
+
+    for(i=1;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+	past_bogus[i-1]=past_bogus[i];
+    past_bogus[RAYDIUM_OSD_NET_SAMPLES-1]=(raydium_network_stat_bogus_ack-last_bogus)*(size/10);
+    last_bogus=raydium_network_stat_bogus_ack;
+
+    }
+
+// draw data
+raydium_osd_color_ega('0');
+raydium_osd_draw_name("rgb(0,0,0)",px,py,px+size,py+size);
+raydium_osd_start();
+
+raydium_osd_color_ega('9');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINE_STRIP);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+(past_delay[i]/(double)raydium_timecall_clocks_per_sec*1000*fact_y_delay),
+	py+size);
+    }
+glEnd();
+
+raydium_osd_color_ega('f');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINE_STRIP);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+(past_tx[i]*fact_y_rxtx),
+	py+size);
+    }
+glEnd();
+
+raydium_osd_color_ega('c');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINE_STRIP);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+(past_rx[i]*fact_y_rxtx),
+	py+size);
+    }
+glEnd();
+
+raydium_osd_color_ega('d');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINES);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py,
+	py+size);
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+past_reemitted[i],
+	py+size);
+    }
+glEnd();
+
+raydium_osd_color_ega('e');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINES);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py,
+	py+size);
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+past_double[i],
+	py+size);
+    }
+glEnd();
+
+raydium_osd_color_ega('a');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINES);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py,
+	py+size);
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+past_lost[i],
+	py+size);
+    }
+glEnd();
+
+raydium_osd_color_ega('b');
+glColor4fv(raydium_osd_color);
+glBegin(GL_LINES);
+for(i=0;i<RAYDIUM_OSD_NET_SAMPLES;i++)
+    {
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py,
+	py+size);
+    raydium_osd_internal_vertex(
+	px+(i*fact_x),
+	py+past_bogus[i],
+	py+size);
+    }
+glEnd();
+
+raydium_rendering_internal_restore_render_state();
+raydium_osd_stop();
+raydium_osd_color_ega('f');
+}
+
+void raydium_osd_mask(GLfloat *color4)
+{
+raydium_osd_start();
+
+// invalidate cache
+//raydium_texture_internal_loaded=0;
+raydium_rendering_internal_prepare_texture_render(0);
+glDisable(GL_TEXTURE_2D);
+glEnable(GL_BLEND);
+glDepthMask(GL_FALSE);
+glColor4f(color4[0],color4[1],color4[2],color4[3]);
+
+glBegin(GL_QUADS);
+glVertex3f(0,0,0);
+glVertex3f(100,0,0);
+glVertex3f(100,100,0);
+glVertex3f(0,100,0);
+glEnd();
+raydium_rendering_internal_restore_render_state();
+
+raydium_osd_stop();
+}
+
+void raydium_osd_fade_callback(void)
+{
+int i;
+void (*f)(void);
+
+if(raydium_osd_fade_color_timeleft>0)
+    {
+    raydium_osd_fade_color_timeleft-=raydium_frame_time;
+    for(i=0;i<4;i++)
+	raydium_osd_fade_color_current[i]+=
+	    raydium_osd_fade_color_increment[i]*raydium_frame_time;
+    
+    raydium_osd_mask(raydium_osd_fade_color_current);
+    if(raydium_osd_fade_color_timeleft<=0 && raydium_osd_fade_OnFadeEnd)
+	{
+	f=raydium_osd_fade_OnFadeEnd;
+	f();
+	return; // fade may have changed during playback ...
+	}
+    }
+}
+
+
+void raydium_osd_fade_init(void)
+{
+raydium_osd_fade_color_timeleft=-1;
+memset(raydium_osd_fade_color_increment,0,raydium_internal_size_vector_float_4);
+memset(raydium_osd_fade_color_current,0,raydium_internal_size_vector_float_4);
+raydium_osd_fade_OnFadeEnd=NULL;
+}
+
+void raydium_osd_fade_from(GLfloat *from4, GLfloat *to4, GLfloat time_len, void *OnFadeEnd)
+{
+int i;
+
+raydium_osd_fade_color_timeleft=time_len;
+memcpy(raydium_osd_fade_color_current,from4,raydium_internal_size_vector_float_4);
+raydium_osd_fade_OnFadeEnd=OnFadeEnd;
+for(i=0;i<4;i++)
+    raydium_osd_fade_color_increment[i]=(to4[i]-from4[i])/time_len; // per sec
+}
Index: raydium/particle2.c
===================================================================
--- raydium/particle2.c	(revision 0)
+++ raydium/particle2.c	(revision 1)
@@ -0,0 +1,997 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/particle2.h"
+#endif 
+
+// Raydium Particle Engine, version 2
+
+// TODO:
+// relative texture filename (as for include statement) ?
+// multiple file loading (composite generators)
+// rotation
+
+#include "particle2.h"
+
+void raydium_particle_name_auto(char *prefix, char *dest)
+{
+static int counter;
+sprintf(dest,"%s_particle_%i",prefix,counter);
+counter++;
+}
+
+
+
+void raydium_particle_init(void)
+{
+int i;
+
+raydium_particle_time_factor=1;
+
+for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
+    {
+    raydium_particle_generators[i].state=0;
+    raydium_particle_generators[i].id=i;
+    }
+
+for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
+    raydium_particle_particles[i]=NULL;
+    
+raydium_log("particle: OK");
+}
+
+char raydium_particle_generator_isvalid(int g)
+{
+if(g>=0 && g<RAYDIUM_MAX_GENERATORS && raydium_particle_generators[g].state)
+    return 1;
+return 0;
+}
+
+int raydium_particle_generator_find(char *name)
+{
+int i;
+                                                                                
+for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
+    if(!strcmp(name,raydium_particle_generators[i].name) && raydium_particle_generator_isvalid(i))
+     return i;
+return -1;
+}
+
+int raydium_particle_find_free(void)
+{
+int i;
+
+for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
+    if(raydium_particle_particles[i]==NULL)
+     return i;
+return -1;
+}
+
+
+void raydium_particle_generator_delete(int gen)
+{
+if(!raydium_particle_generator_isvalid(gen))
+    {
+    raydium_log("particle: cannot delete generator: invalid name or index");
+    return;
+    }
+raydium_particle_generators[gen].state=0;
+}
+
+void raydium_particle_generator_delete_name(char *gen)
+{
+raydium_particle_generator_delete(raydium_particle_generator_find(gen));
+}
+
+void raydium_particle_generator_enable(int gen, char enabled)
+{
+if(!raydium_particle_generator_isvalid(gen))
+    {
+    raydium_log("particle: cannot enable/disable generator: invalid name or index");
+    return;
+    }
+raydium_particle_generators[gen].enabled=enabled;
+}
+
+void raydium_particle_generator_enable_name(char *gen, char enable)
+{
+raydium_particle_generator_enable(raydium_particle_generator_find(gen),enable);
+}
+
+void raydium_particle_preload(char *filename)
+{
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+
+
+fp=raydium_file_fopen(filename,"rt"); // idem ("rb" ?)
+if(!fp)
+ {
+ raydium_log("particle: ERROR: Cannot open %s particle file for preloading",filename);
+ return;
+ }
+
+// parse (and cache) file
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    if(!strcasecmp(var,"include"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_STRING)
+	    {
+	    raydium_log("particle: parser: include: wrong type");
+	    continue;
+	    }
+	raydium_particle_preload(val_s);
+	}
+
+    if(!strcasecmp(var,"texture"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_STRING)
+	    {
+	    raydium_log("particle: parser: texture: wrong type");
+	    continue; // in case of multiple textures ? (degenarated file)
+	    }
+	// cache texture
+	raydium_texture_current_set_name(val_s);
+	}
+    }
+fclose(fp);
+}
+
+
+void raydium_particle_generator_load_internal(int generator,FILE *fp, char *filename)
+{
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[4];
+int size;
+char done;
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    done=0;
+
+    if(!strcasecmp(var,"include"))
+	{
+	FILE *sub;
+	char dir[RAYDIUM_MAX_NAME_LEN];
+	
+	if(ret!=RAYDIUM_PARSER_TYPE_STRING)
+	    {
+	    raydium_log("particle: parser: include: wrong type");
+	    continue;
+	    }
+	raydium_file_dirname(dir,filename);
+	strcat(dir,val_s);
+	strcpy(val_s,dir);
+	sub=raydium_file_fopen(val_s,"rt"); // idem
+	if(!sub)
+	 {
+	 raydium_log("particle: ERROR: %s cannot open %s particle subfile",filename,val_s);
+	 continue;
+	 }
+        raydium_particle_generator_load_internal(generator,sub,val_s);
+	fclose(sub);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"position"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: position: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].position,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"position_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: position_random: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].position_random,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"ttl_generator"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: ttl_generator: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].ttl_generator=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"ttl_particles"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: ttl_particles: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].ttl_particles=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"ttl_particles_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: ttl_particles_random: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].ttl_particles_random=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"particles_per_second"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: particles_per_second: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].particles_per_second=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"texture"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_STRING)
+	    {
+	    raydium_log("particle: parser: texture: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].texture=
+	    raydium_texture_find_by_name(val_s);
+	done=1;
+	}
+
+
+    if(!strcasecmp(var,"size"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: size: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].size=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"size_inc_per_sec"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: size_inc_per_sec: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].size_inc_per_sec=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"size_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: size_random: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].size_random=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"size_limit"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: size_limit: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].size_limit=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"gravity"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: gravity: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].gravity,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"vector"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: vector: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].vector,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"vector_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: vector_random: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].vector_random,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"vector_sphere_angles"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: vector_sphere_angles: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].vector_sphere_angles,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"vector_sphere_angles_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=3)
+	    {
+	    raydium_log("particle: parser: vector_sphere_angles_random: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].vector_sphere_angles_random,val_f,sizeof(GLfloat)*3);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"vector_sphere_force"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: vector_sphere_force: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].vector_sphere_force=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"vector_sphere_force_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: vector_sphere_force_random: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].vector_sphere_force_random=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"rotation_speed"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: rotation_speed: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].rotation_speed=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"rotation_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: rotation_random: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].rotation_random=val_f[0];
+	done=1;
+	}
+
+    if(!strcasecmp(var,"color_start"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+	    {
+	    raydium_log("particle: parser: color_start: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].color_start,val_f,sizeof(GLfloat)*4);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"color_start_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+	    {
+	    raydium_log("particle: parser: color_start_random: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].color_start_random,val_f,sizeof(GLfloat)*4);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"color_end"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+	    {
+	    raydium_log("particle: parser: color_end: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].color_end,val_f,sizeof(GLfloat)*4);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"color_end_random"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=4)
+	    {
+	    raydium_log("particle: parser: color_end_random: wrong type");
+	    continue;
+	    }
+	memcpy(raydium_particle_generators[generator].color_end_random,val_f,sizeof(GLfloat)*4);
+	done=1;
+	}
+
+    if(!strcasecmp(var,"visibility"))
+	{
+	if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=1)
+	    {
+	    raydium_log("particle: parser: visibility: wrong type");
+	    continue;
+	    }
+	raydium_particle_generators[generator].visibility=val_f[0];
+	done=1;
+	}
+
+    if(!done)
+	raydium_log("particle: parser: invalid or unsupported option '%s' (%s)",var,filename);
+    }
+}
+
+int raydium_particle_generator_load(char *filename,char *name)
+{
+FILE *fp;
+int generator;
+int i;
+
+
+if(raydium_particle_generator_find(name)>=0)
+    {
+    raydium_log("particle: Cannot load \"%s\": '%s' already exists",filename,name);
+    return -1;    
+    }
+
+fp=raydium_file_fopen(filename,"rt"); // rb ? must test under win32
+if(!fp)
+ {
+ raydium_log("particle: ERROR: Cannot open %s particle file",filename);
+ return -1;
+ }
+
+for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
+    if(raydium_particle_generators[i].state==0)
+	break;
+	
+if(i==RAYDIUM_MAX_GENERATORS)
+    {
+    raydium_log("particle: no more available slots !");
+    fclose(fp);
+    return -1;
+    }
+generator=i;
+
+raydium_particle_generators[generator].state=1;
+raydium_particle_generators[generator].enabled=1;
+strcpy(raydium_particle_generators[generator].name,name);
+raydium_particle_generators[generator].position[0]=0;
+raydium_particle_generators[generator].position[1]=0;
+raydium_particle_generators[generator].position[2]=0;
+raydium_particle_generators[generator].position_random[0]=0;
+raydium_particle_generators[generator].position_random[1]=0;
+raydium_particle_generators[generator].position_random[2]=0;
+raydium_particle_generators[generator].position_user[0]=0;
+raydium_particle_generators[generator].position_user[1]=0;
+raydium_particle_generators[generator].position_user[2]=0;
+raydium_particle_generators[generator].ttl_generator=1;
+raydium_particle_generators[generator].ttl_particles=1;
+raydium_particle_generators[generator].particles_per_second=100;
+raydium_particle_generators[generator].texture=0;
+raydium_particle_generators[generator].size=1;
+raydium_particle_generators[generator].size_inc_per_sec=0;
+raydium_particle_generators[generator].size_random=0;
+raydium_particle_generators[generator].size_limit=-1;
+raydium_particle_generators[generator].gravity[0]=0;
+raydium_particle_generators[generator].gravity[1]=0;
+raydium_particle_generators[generator].gravity[2]=0;
+raydium_particle_generators[generator].vector[0]=0;
+raydium_particle_generators[generator].vector[1]=0;
+raydium_particle_generators[generator].vector[2]=0;
+raydium_particle_generators[generator].vector_random[0]=0;
+raydium_particle_generators[generator].vector_random[1]=0;
+raydium_particle_generators[generator].vector_random[2]=0;
+raydium_particle_generators[generator].vector_sphere_angles[0]=0;
+raydium_particle_generators[generator].vector_sphere_angles[1]=0;
+raydium_particle_generators[generator].vector_sphere_angles[2]=0;
+raydium_particle_generators[generator].vector_sphere_angles_random[0]=0;
+raydium_particle_generators[generator].vector_sphere_angles_random[1]=0;
+raydium_particle_generators[generator].vector_sphere_angles_random[2]=0;
+raydium_particle_generators[generator].vector_sphere_force=0;
+raydium_particle_generators[generator].vector_sphere_force_random=0;
+// velocity_limit
+raydium_particle_generators[generator].rotation_speed=45;
+raydium_particle_generators[generator].rotation_random=0;
+raydium_particle_generators[generator].color_start[0]=1;
+raydium_particle_generators[generator].color_start[1]=1;
+raydium_particle_generators[generator].color_start[2]=1;
+raydium_particle_generators[generator].color_start[3]=1;
+raydium_particle_generators[generator].color_start_random[0]=0;
+raydium_particle_generators[generator].color_start_random[1]=0;
+raydium_particle_generators[generator].color_start_random[2]=0;
+raydium_particle_generators[generator].color_start_random[3]=0;
+raydium_particle_generators[generator].color_end[0]=1;
+raydium_particle_generators[generator].color_end[1]=1;
+raydium_particle_generators[generator].color_end[2]=1;
+raydium_particle_generators[generator].color_end[3]=1;
+raydium_particle_generators[generator].color_end_random[0]=0;
+raydium_particle_generators[generator].color_end_random[1]=0;
+raydium_particle_generators[generator].color_end_random[2]=0;
+raydium_particle_generators[generator].color_end_random[3]=0;
+raydium_particle_generators[generator].visibility=1;
+raydium_particle_generators[generator].OnDeleteParticle=NULL;
+
+// transform
+raydium_particle_generator_load_internal(generator,fp,filename);
+
+fclose(fp);
+return generator;
+}
+
+
+void raydium_particle_generator_update(int g,GLfloat step)
+{
+int i,j,p,to_create;
+raydium_particle_Generator *gen;
+raydium_particle_Particle *part;
+
+/*
+if(!raydium_particle_generators[g].state) 
+    {
+    raydium_log("particle: Cannot update generator: invalid index");
+    return;
+    }
+*/
+
+gen=&raydium_particle_generators[g];
+
+// This +1 is bad, must use a "float" counter on generator
+to_create=(step*gen->particles_per_second)+1;
+//raydium_log("will create %i particles for %s (%i)",to_create,gen->name,g);
+
+if(!gen->enabled) to_create=0;
+
+for(i=0;i<to_create;i++)
+    {
+    p=raydium_particle_find_free();
+    if(p<0)
+	{
+	//raydium_log("particle: No more particle slots !");
+	break;
+	}
+
+    raydium_particle_particles[p]=malloc(sizeof(raydium_particle_Particle));
+    if(!raydium_particle_particles[p])
+	{
+	raydium_log("particle: ERROR: malloc failed !");
+	return;
+	}
+
+
+    part=raydium_particle_particles[p];
+
+    part->ttl_init=raydium_random_f(gen->ttl_particles-gen->ttl_particles_random,gen->ttl_particles+gen->ttl_particles_random);
+    part->ttl=part->ttl_init;
+    part->texture=gen->texture;
+
+    memcpy(part->position,gen->position,sizeof(GLfloat)*3);
+    for(j=0;j<3;j++)
+	part->position[j]+=raydium_random_f(-gen->position_random[j],gen->position_random[j]);
+
+    for(j=0;j<3;j++)
+	part->position[j]+=gen->position_user[j];
+
+    part->size=raydium_random_f(gen->size-gen->size_random,gen->size+gen->size_random);
+    part->size_inc_per_sec=gen->size_inc_per_sec;
+    part->size_limit=gen->size_limit;
+
+    memcpy(part->gravity,gen->gravity,sizeof(GLfloat)*3);
+
+
+    if(gen->vector_sphere_force==0 && gen->vector_sphere_force_random==0) 
+    { 
+     // ortho
+     memcpy(part->vel,gen->vector,sizeof(GLfloat)*3);
+     for(j=0;j<3;j++)
+	part->vel[j]+=raydium_random_f(-gen->vector_random[j],gen->vector_random[j]);
+    }
+    else 
+    {
+    // spherical
+    GLfloat def_angles[3]={0,0,1};
+    GLfloat angles[3];
+    GLfloat force;
+
+    memcpy(angles,gen->vector_sphere_angles,sizeof(GLfloat)*3);
+    for(j=0;j<3;j++)
+	angles[j]+=raydium_random_f(-gen->vector_sphere_angles_random[j],gen->vector_sphere_angles_random[j]);
+
+    
+    force=gen->vector_sphere_force
+         +raydium_random_f(-gen->vector_sphere_force_random,
+			    gen->vector_sphere_force_random);
+    for(j=0;j<3;j++)
+	def_angles[j]*=force;
+    
+    raydium_trigo_rotate(def_angles,angles[0],angles[1],angles[2],part->vel);
+    }
+
+    memcpy(part->color_start,gen->color_start,sizeof(GLfloat)*4);
+    for(j=0;j<4;j++)
+	part->color_start[j]+=raydium_random_f(-gen->color_start_random[j],gen->color_start_random[j]);
+
+    memcpy(part->color_end,gen->color_end,sizeof(GLfloat)*4);
+    for(j=0;j<4;j++)
+	part->color_end[j]+=raydium_random_f(-gen->color_end_random[j],gen->color_end_random[j]);
+
+    part->rotation_speed=raydium_random_f(gen->rotation_speed-gen->rotation_random,
+					  gen->rotation_speed+gen->rotation_random);
+
+    part->visibility=gen->visibility;
+    part->OnDelete=gen->OnDeleteParticle;
+    }
+
+
+if(gen->ttl_generator==0) 
+    return; // infinite generator
+
+gen->ttl_generator-=step;
+if(gen->ttl_generator<=0) 
+    {
+    // we've a OnDelete callback for particles and not for
+    // generators ... 'must code it.
+    gen->state=0; // delete generator
+    }
+}
+
+void raydium_particle_update(int part, GLfloat step)
+{
+int i;
+GLfloat age,age_factor;
+raydium_particle_Particle *p;
+
+p=raydium_particle_particles[part];
+// ttl
+if(p->ttl!=0) // if not an infinite particle
+{
+ p->ttl-=step;
+ if(p->ttl<=0) // "timeout" ...
+    {
+    void (*f)(raydium_particle_Particle *);
+    
+    f=p->OnDelete;
+    if(f) f(p);
+    
+    free(p);
+    raydium_particle_particles[part]=NULL;
+    return;
+    }
+}
+
+age=(p->ttl_init-p->ttl);
+if(p->ttl_init)
+    age_factor=age/p->ttl_init;
+else
+    age_factor=0;
+
+// pos
+for(i=0;i<3;i++)
+    p->position[i]+=(p->vel[i]*step);
+
+// vel
+for(i=0;i<3;i++)
+    p->vel[i]+=(p->gravity[i]*step);
+
+// size
+p->size+=(p->size_inc_per_sec*step);
+if(p->size<0) p->size=0;
+if(p->size>p->size_limit && p->size_limit>0) p->size=p->size_limit;
+
+// color
+for(i=0;i<4;i++)
+    p->current_color[i]=(p->color_end[i]-p->color_start[i])*age_factor+p->color_start[i];
+
+// rotation
+p->current_rotation=age*p->rotation_speed;
+
+}
+
+void raydium_particle_callback(void)
+{
+int i;
+
+//raydium_profile_start();
+
+for(i=0;i<RAYDIUM_MAX_GENERATORS;i++)
+    if(raydium_particle_generators[i].state)
+	raydium_particle_generator_update(i,raydium_frame_time*raydium_particle_time_factor);
+
+for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
+    if(raydium_particle_particles[i])
+	raydium_particle_update(i,raydium_frame_time*raydium_particle_time_factor);
+
+//raydium_profile_end("particles updating");
+}
+
+
+int raydium_particle_state_dump(char *filename)
+{
+FILE *fp;
+int i;
+int cpt=0;
+raydium_particle_Particle *p;
+
+fp=fopen(filename,"wt");
+if(!fp)
+    {
+    raydium_log("particle: ERROR: cannot create '%s' filename",filename);
+    return 0;
+    }
+
+fprintf(fp,"0\n");
+
+for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
+    if(raydium_particle_particles[i])
+	{
+	cpt++;
+	p=raydium_particle_particles[i];
+	fprintf(fp,"%f %f %f %f %f %f %f %f %f %s\n",
+		p->position[0],
+		p->position[1],
+		p->position[2],
+		p->size,
+		p->current_color[0],
+		p->current_color[1],
+		p->current_color[2],
+		p->current_color[3],
+		p->visibility,
+		raydium_texture_name[p->texture]);	
+	}
+fclose(fp);
+raydium_log("particle: %i particle(s) dumped",cpt);
+return 1;
+}
+
+int raydium_particle_state_restore(char *filename)
+{
+FILE *fp;
+int p,visu,cpt=0;
+raydium_particle_Particle *part;
+GLfloat pos[3],color[4],size,visibility;
+char texture[RAYDIUM_MAX_NAME_LEN];
+
+fp=raydium_file_fopen(filename,"rt");
+if(!fp) 
+    { 
+    raydium_log("particle: ERROR: cannot read from file '%s'",filename);
+    return 0; 
+    }
+fscanf(fp,"%i\n",&visu);
+
+if(visu!=0)
+    { 
+    raydium_log("particle: ERROR: '%s' file must be 'version 0'",filename);
+    return 0; 
+    }
+
+
+while( fscanf(fp,"%f %f %f %f %f %f %f %f %f %s\n",
+    &pos[0],
+    &pos[1],
+    &pos[2],
+    &size,
+    &color[0],
+    &color[1],
+    &color[2],
+    &color[3],
+    &visibility,
+    texture)!=EOF )
+    {
+    cpt++;
+    p=raydium_particle_find_free();
+    if(p<0)
+	{
+	raydium_log("particle: No more particle slots !");
+	return -1;
+	}
+
+    raydium_particle_particles[p]=malloc(sizeof(raydium_particle_Particle));
+    if(!raydium_particle_particles[p])
+	{
+	raydium_log("particle: ERROR: malloc failed !");
+	return 0;
+	}
+
+
+    part=raydium_particle_particles[p];
+
+    part->ttl_init=0;
+    part->ttl=part->ttl_init;
+    part->texture=raydium_texture_find_by_name(texture);
+
+    memcpy(part->position,pos,sizeof(GLfloat)*3);
+
+    part->size=size;
+    part->size_inc_per_sec=0;
+    part->size_limit=size+1;
+
+    part->gravity[0]=part->gravity[1]=part->gravity[2]=0;
+
+    part->vel[0]=part->vel[1]=part->vel[2]=0;
+    
+    memcpy(part->color_start,   color,sizeof(GLfloat)*4);
+    memcpy(part->color_end,     color,sizeof(GLfloat)*4);
+    memcpy(part->current_color, color,sizeof(GLfloat)*4);
+
+    part->rotation_speed=0;
+    part->visibility=visibility;
+    part->OnDelete=NULL;
+    }
+fclose(fp);
+raydium_log("particle: %i infinite particle(s) created",cpt);
+return 1;
+}
+
+
+void raydium_particle_draw(raydium_particle_Particle *p,GLfloat ux, GLfloat uy, GLfloat uz, GLfloat rx, GLfloat ry, GLfloat rz)
+{
+GLfloat TSIZE;
+
+if(!raydium_random_proba(p->visibility))
+    return;
+
+// need to order drawing by texture id
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current_set(p->texture));
+glColor4fv(p->current_color);
+TSIZE=p->size;
+
+ux*=TSIZE/2;
+uy*=TSIZE/2;
+uz*=TSIZE/2;
+
+rx*=TSIZE/2;
+ry*=TSIZE/2;
+rz*=TSIZE/2;
+
+// p->rotation
+
+  glBegin(GL_QUADS); // berk... but i'll switch to triangles one day ;)
+  glTexCoord2f(1.0f, 0.0f);
+  glVertex3f(p->position[0] + (-rx - ux),
+	     p->position[1] + (-ry - uy),
+	     p->position[2] + (-rz - uz));
+  glTexCoord2f(1.0f, 1.0f);
+  glVertex3f(p->position[0] + (rx - ux),
+	     p->position[1] + (ry - uy),
+	     p->position[2] + (rz - uz));
+  glTexCoord2f(0.0f, 1.0f);
+  glVertex3f(p->position[0] + (rx + ux),
+	     p->position[1] + (ry + uy),
+	     p->position[2] + (rz + uz));
+  glTexCoord2f(0.0f, 0.0f);
+  glVertex3f(p->position[0] + (ux - rx),
+	     p->position[1] + (uy - ry),
+	     p->position[2] + (uz - rz));
+  glEnd();
+}
+
+void raydium_particle_draw_all(void)
+{
+GLuint i;
+GLuint texsave;
+char light;
+GLfloat modmat[16];
+GLfloat ux;
+GLfloat uy;
+GLfloat uz;
+GLfloat rx;
+GLfloat ry;
+GLfloat rz;
+
+//raydium_profile_start();
+
+texsave=raydium_texture_current;
+light=raydium_light_enabled_tag;
+raydium_light_disable();
+if (raydium_camera_pushed) raydium_camera_replace(); // is it really our job to do it here ?
+//raydium_rendering_internal_restore_render_state();
+
+glGetFloatv(GL_MODELVIEW_MATRIX,modmat);
+ux=modmat[0];
+uy=modmat[4];
+uz=modmat[8];
+rx=modmat[1];
+ry=modmat[5];
+rz=modmat[9];
+
+glDepthMask(GL_FALSE);
+
+for(i=0;i<RAYDIUM_MAX_PARTICLES;i++)
+    if(raydium_particle_particles[i])
+	raydium_particle_draw(raydium_particle_particles[i],ux,uy,uz,rx,ry,rz);
+
+glDepthMask(GL_TRUE);
+if(light) raydium_light_enable();
+
+raydium_texture_current_set(texsave);
+//raydium_rendering_internal_prepare_texture_render(texsave);
+//raydium_profile_end("particles drawing");
+}
+
+
+void raydium_particle_generator_move(int gen, GLfloat *pos)
+{
+if(!raydium_particle_generator_isvalid(gen))
+    {
+    raydium_log("particle: cannot move generator: invalid name or index");
+    return;
+    }
+memcpy(raydium_particle_generators[gen].position_user,pos,sizeof(GLfloat)*3);
+}
+
+void raydium_particle_generator_move_name(char *gen, GLfloat *pos)
+{
+raydium_particle_generator_move(raydium_particle_generator_find(gen),pos);
+}
+
+void raydium_particle_generator_move_name_3f(char *gen, GLfloat x, GLfloat y, GLfloat z)
+{
+GLfloat tmp[3];
+tmp[0]=x;
+tmp[1]=y;
+tmp[2]=z;
+raydium_particle_generator_move_name(gen,tmp);
+}
+
+void raydium_particle_generator_particles_OnDelete(int gen, void *OnDelete)
+{
+if(!raydium_particle_generator_isvalid(gen))
+    {
+    raydium_log("particle: cannot set OnDelete: invalid name or index");
+    return;
+    }
+raydium_particle_generators[gen].OnDeleteParticle=OnDelete;
+}
+
+void raydium_particle_generator_particles_OnDelete_name(char *gen, void *OnDelete)
+{
+raydium_particle_generator_particles_OnDelete(raydium_particle_generator_find(gen),OnDelete);
+}
Index: raydium/clear.c
===================================================================
--- raydium/clear.c	(revision 0)
+++ raydium/clear.c	(revision 1)
@@ -0,0 +1,26 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/clear.h"
+#endif 
+
+void raydium_clear_frame(void)
+{
+glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+raydium_frame_first_camera_pass=1;
+raydium_vertex_counter=0;
+}
+
+void raydium_clear_color_update(void)
+{
+glClearColor(raydium_background_color[0],
+	     raydium_background_color[1],
+	     raydium_background_color[2],
+	     raydium_background_color[3]);
+}
Index: raydium/mouse.c
===================================================================
--- raydium/mouse.c	(revision 0)
+++ raydium/mouse.c	(revision 1)
@@ -0,0 +1,61 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/mouse.h"
+#endif 
+
+/*
+#define raydium_mouse_hide() glutSetCursor(GLUT_CURSOR_NONE);
+#define raydium_mouse_show() glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
+#define raydium_mouse_move(x,y) glutWarpPointer(x,y)
+*/
+
+char raydium_mouse_isvisible(void)
+{
+int ret;
+ret=glutGet(GLUT_WINDOW_CURSOR);
+return (ret==GLUT_CURSOR_NONE?0:1);
+}
+
+void raydium_mouse_init(void)
+{
+if(raydium_window_mode==RAYDIUM_RENDERING_NONE)
+    return;
+memset(raydium_mouse_button,0,3);
+raydium_mouse_click=0;
+raydium_mouse_x=raydium_mouse_y=raydium_window_ty=0;
+raydium_log("mouse: OK");
+raydium_mouse_hide();
+}
+
+
+void raydium_mouse_click_callback(int but,int state,int x,int y)
+{
+unsigned char n=0,s=0;
+
+if(but==GLUT_LEFT_BUTTON) n=0;
+if(but==GLUT_RIGHT_BUTTON) n=1;
+if(but==GLUT_MIDDLE_BUTTON) n=2;
+if(state==GLUT_DOWN) s=1;
+if(state==GLUT_UP) s=0;
+if(s) raydium_mouse_click=n+1;
+raydium_mouse_button[n]=s;
+}
+
+
+void raydium_mouse_move_callback(int x, int y)
+{
+if(x>=0 && x<raydium_window_tx) raydium_mouse_x=x;
+if(y>=0 && y<raydium_window_ty) raydium_mouse_y=y;
+}
+
+int raydium_mouse_button_pressed(int button)
+{
+return raydium_mouse_button[button];
+}
Index: raydium/key.c
===================================================================
--- raydium/key.c	(revision 0)
+++ raydium/key.c	(revision 1)
@@ -0,0 +1,118 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/key.h"
+#endif
+
+
+// proto
+void raydium_console_event(void);
+void raydium_console_line_add(char *format, ...);
+void raydium_console_exec_last_command(void);
+void raydium_console_complete(char *str);
+void raydium_console_history_previous(void);
+void raydium_console_history_next(void);
+
+
+void raydium_key_normal_callback(GLuint key, int x, int y)
+{
+int i;
+key%=65536;
+if(key==178) raydium_console_event();
+if(key==126) raydium_capture_frame_auto(); // glut@w32 won't return this key...
+
+if(raydium_console_pos && ( (key>=32 && key<127) 
+		       || key==8 
+		       || key==9 
+		       || key==13) )
+ {
+ i=strlen(raydium_console_get_string);
+// printf("%s\n",raydium_console_get_string);
+
+ if(key==13)
+  {
+  if(!i) return;
+  raydium_console_get_string[i]=key; // lag from last frame...
+  raydium_console_get_string[i+1]=0;
+  // there is a bug: raydium_console_get_string '\n' is cleaned, but
+  // after being copied into raydium_console_get_string_last.
+  // Must take some time to clean all this (key, console, test4 and modler)
+  strcpy(raydium_console_get_string_last,raydium_console_get_string);
+  raydium_console_get_string[i]=0;
+  raydium_console_line_add("%s",raydium_console_get_string);
+  raydium_console_get_string[0]=0;
+  raydium_console_exec_last_command();
+  return;
+  }
+ 
+ if(key==8) // delete last char
+    { 
+    if(i>0) i--; 
+    key=0;
+    }
+
+ if(key==9) // completion
+    {
+    raydium_console_complete(raydium_console_get_string);
+    return;
+    }
+
+ if(i<RAYDIUM_MAX_NAME_LEN-3)
+  {
+  raydium_console_get_string[i]=key;
+  raydium_console_get_string[i+1]=0; 
+  }
+ }
+else
+ {
+ raydium_key_last=key+1000;
+#ifdef DEBUG_KEYS
+ raydium_log("normal key %i pressed",key+1000);
+#endif
+ }
+
+}
+
+void raydium_key_special_callback(GLuint key, int x, int y)
+{
+
+if(raydium_console_pos && key==GLUT_KEY_UP)
+    {
+    raydium_console_history_previous();
+    return;
+    }
+
+if(raydium_console_pos && key==GLUT_KEY_DOWN)
+    {
+    raydium_console_history_next();
+    return;
+    }
+
+key%=65536;
+raydium_key[key]=2;
+raydium_key_last=key;
+#ifdef DEBUG_KEYS
+raydium_log("special key %i down (normal key updated too)",key);
+#endif
+}
+
+void raydium_key_special_up_callback(GLuint key, int x, int y)
+{
+key%=65536;
+raydium_key[key]=0;
+#ifdef DEBUG_KEYS
+raydium_log("special key %i up",key);
+#endif
+}
+
+// moslty used for php
+int raydium_key_pressed(GLuint key)
+{
+return raydium_key[key];
+}
Index: raydium/gui.h
===================================================================
--- raydium/gui.h	(revision 0)
+++ raydium/gui.h	(revision 1)
@@ -0,0 +1,142 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+// window borders & moves
+// multiple windows tests
+// modal windows
+
+#ifndef RAY_GUI_H
+#define RAY_GUI_H
+
+#define RAYDIUM_GUI_MAX_OBJECTS		64
+#define RAYDIUM_GUI_MAX_WINDOWS		16
+
+#define RAYDIUM_GUI_BUTTON	1
+#define RAYDIUM_GUI_LABEL	2
+#define RAYDIUM_GUI_TRACK	3
+#define RAYDIUM_GUI_EDIT	4
+#define RAYDIUM_GUI_CHECK	5
+#define RAYDIUM_GUI_COMBO	6
+
+#define RAYDIUM_GUI_NORMAL	1
+#define RAYDIUM_GUI_FOCUS	2
+#define RAYDIUM_GUI_HOVER	3
+
+#define RAYDIUM_GUI_DATASIZE	4096
+
+#define RAYDIUM_GUI_ITEM_SEPARATOR	'\n'
+#define RAYDIUM_GUI_COMBO_LIST_HEIGHT	5
+
+typedef struct raydium_gui_Button
+{
+    void *   OnClick;
+    char     caption[RAYDIUM_MAX_NAME_LEN];
+    GLfloat  uv_normal[4];
+    GLfloat  uv_focus[4];
+    GLfloat  uv_hover[4];
+    GLfloat  font_color[3];
+} raydium_gui_Button;
+
+typedef struct raydium_gui_Label
+{
+    char     caption[RAYDIUM_MAX_NAME_LEN];
+    GLfloat  font_color[3];
+} raydium_gui_Label;
+
+typedef struct raydium_gui_Track
+{
+    GLfloat  uv_rule[4];
+    GLfloat  uv_cursor_normal[4];
+    GLfloat  uv_cursor_focus[4];
+    int	     min;
+    int      max;
+    int      current;
+} raydium_gui_Track;
+
+typedef struct raydium_gui_Edit
+{
+    char     text[RAYDIUM_GUI_DATASIZE];
+    GLfloat  uv_normal[4];
+    GLfloat  uv_focus[4];
+    GLfloat  font_color[3];
+    int      cursor;
+    int      offset;
+} raydium_gui_Edit;
+
+typedef struct raydium_gui_Check
+{
+    char     caption[RAYDIUM_MAX_NAME_LEN];
+    char     checked;
+    GLfloat  uv_normal[4];
+    GLfloat  uv_checked[4];
+    GLfloat  font_color_normal[3];
+    GLfloat  font_color_focus[3];
+} raydium_gui_Check;
+
+typedef struct raydium_gui_Combo
+{
+    char     items[RAYDIUM_GUI_DATASIZE];
+    int      current;
+    char     current_str[RAYDIUM_GUI_DATASIZE]; // provided as a "bonus"
+    char     expanded;
+    int      offset;
+    GLfloat  uv_body_normal[4];
+    GLfloat  uv_body_focus[4];
+    int      body_border_right;
+    GLfloat  uv_list_top[4];
+    GLfloat  uv_list_middle[4];
+    GLfloat  uv_list_bottom[4];
+    GLfloat  uv_list_current[4];
+    GLfloat  uv_arrow[4];
+    GLfloat  font_color[3];
+} raydium_gui_Combo;
+
+// Parent of all widgets
+typedef struct raydium_gui_Object
+{
+    int      id;
+    char     name[RAYDIUM_MAX_NAME_LEN];
+    char     state;
+    char     type;
+    int      window;
+    GLfloat  pos[2];
+    GLfloat  size[2];
+    GLfloat  font_size;
+    void *   widget;
+} raydium_gui_Object;
+
+
+typedef struct raydium_gui_Window
+{
+    int      id;
+    char     name[RAYDIUM_MAX_NAME_LEN];
+    char     state;
+    GLfloat  pos[2];
+    GLfloat  size[2];
+    raydium_gui_Object widgets[RAYDIUM_GUI_MAX_OBJECTS];
+    int      focused_widget;
+    int	     old_focused;
+} raydium_gui_Window;
+
+
+typedef struct raydium_gui_Theme
+{
+    char     loaded;
+    char     filename[RAYDIUM_MAX_NAME_LEN];
+    int      texture;
+    int      texture_size[2];
+    GLfloat  background_uv[4];
+} raydium_gui_Theme;
+
+raydium_gui_Theme  raydium_gui_theme_current;
+raydium_gui_Window raydium_gui_windows[RAYDIUM_GUI_MAX_WINDOWS];
+char               raydium_gui_visible;
+int                raydium_gui_window_focused;
+char		   raydium_gui_oldstate;
+GLfloat		   raydium_gui_widget_sizes_default[3];
+int		   raydium_gui_button_clicked_id;
+
+#endif
Index: raydium/headers/rayphp.h
===================================================================
--- raydium/headers/rayphp.h	(revision 0)
+++ raydium/headers/rayphp.h	(revision 1)
@@ -0,0 +1,29 @@
+#ifndef _RAYPHP_H
+#define _RAYPHP_H
+
+/*=
+RayPHP (internals)
+3600
+**/
+
+// Introduction
+/**
+Raydium also use RayPHP (Raydium/PHP interface) for its own needs.
+For PHP part of these functions, see "rayphp/" directory.
+So far, RayPHP is dedicated to R3S (Raydium Server Side Scripts) access.
+All this is mostly usefull for internal uses, since Raydium provides ##fopen##
+wrappers, thru ##raydium_file_fopen##.
+**/
+
+extern int raydium_rayphp_repository_file_get (char *path);
+/**
+Will contact R3S servers for downloading ##path## file.
+**/
+
+extern int raydium_rayphp_repository_file_put (char *path, int depends);
+/**
+Will contact R3S servers for uploading ##path## file. Set ##depends## to
+true (1) if you also want to upload dependencies, false (0) otherwise.
+**/
+
+#endif
Index: raydium/headers/init.h
===================================================================
--- raydium/headers/init.h	(revision 0)
+++ raydium/headers/init.h	(revision 1)
@@ -0,0 +1,80 @@
+#ifndef _INIT_H
+#define _INIT_H
+/*=
+Initialization
+2400
+**/
+
+// Introduction
+/**
+This file is mainly designed for internal uses, but there's anyway 
+some interesting functions. 
+**/
+
+extern int raydium_init_cli_option (char *option, char *value);
+/**
+This function will search command line ##option##.
+If this option is found, the functions stores any argument to ##value## and
+returns 1.
+The function will return 0 if ##option## is not found.
+
+Example (search for: ##--ground##)
+%%(c)
+char ground[RAYDIUM_MAX_NAME_LEN];
+if(raydium_init_cli_option("ground",model))
+    {
+    setground(model);
+    }
+%%
+**/
+
+extern int raydium_init_cli_option_default (char *option, char *value, char *default_value);
+/**
+Same as above, but allows you to provide a default value (##default##) if
+the ##option## is not found on command line.
+**/
+
+extern void raydium_init_lights (void);
+/**
+Internal use. Must be moved to light.c.
+**/
+
+extern void raydium_init_objects (void);
+/**
+Internal use. Must be moved to object.c.
+**/
+
+extern void raydium_init_key (void);
+/**
+Internal use. Must be moved to key.c.
+**/
+
+extern void raydium_init_reset (void);
+/**
+This function is supposed to reset the whole Raydium engine: 
+textures, vertices, lights, objects, ...
+Never tested yet, and probaly fails for many reasons when called more than
+one time.
+**/
+
+extern void raydium_init_engine (void);
+/**
+Internal use. **Never** call this function by yourself, it may cause
+huge memory leaks.
+**/
+
+extern void raydium_init_args (int argc, char **argv);
+/**
+You must use this function, wich send application arguments to Raydium 
+and external libs (GLUT, OpenAL, ...).
+This must be done **before** any other call to Raydium.
+Example:
+%%(c)
+int main(int argc, char **argv)
+{
+raydium_init_args(argc,argv);
+[...]
+%%
+**/
+
+#endif
Index: raydium/headers/object.h
===================================================================
--- raydium/headers/object.h	(revision 0)
+++ raydium/headers/object.h	(revision 1)
@@ -0,0 +1,69 @@
+#ifndef _OBJECT_H
+#define _OBJECT_H
+/*=
+Objects
+2300
+**/
+
+// Introduction
+/**
+With the following functions, you can easily draw and manage
+mesh objects (.tri file).
+**/
+
+extern GLint raydium_object_find (char *name);
+/**
+Lookups an object by his ##name##. This function will return -1 if the
+object's not found, and will not try to load the .tri file.
+**/
+
+extern GLint raydium_object_find_load (char *name);
+/**
+Same as above (##raydium_object_load##), but will try to load object
+**/
+
+extern void raydium_object_reset (GLuint o);
+/**
+Internal use. Do not call.
+**/
+
+extern int raydium_object_load (char *filename);
+/**
+Load ##filename## as a .tri file, and returns corresponding id, or
+-1 in case of error.
+**/
+
+extern void raydium_object_draw (GLuint o);
+/**
+Draws ##o## (index) object, using current matrixes.
+**/
+
+extern void raydium_object_draw_name (char *name);
+/**
+Same as above, but you only have to provide object's ##name## (".tri file"). 
+If this object was not already loaded, this function will do it for you.
+**/
+
+extern void raydium_object_deform (GLuint obj, GLfloat ampl);
+/**
+Early devel state. Useless as is.
+**/
+
+extern void raydium_object_deform_name (char *name, GLfloat ampl);
+/**
+Early devel state. Useless as is.
+**/
+
+extern GLfloat raydium_object_find_dist_max (GLuint obj);
+/**
+This function will return will return the distance form (0,0,0) 
+to the farest point of ##obj## object.
+**/
+
+extern void raydium_object_find_axes_max (GLuint obj, GLfloat * tx, GLfloat * ty, GLfloat * tz);
+/**
+This function returns the (maximum) size of the bounding box 
+of ##obj## (relative to (0,0,0)).
+**/
+
+#endif
Index: raydium/headers/sky.h
===================================================================
--- raydium/headers/sky.h	(revision 0)
+++ raydium/headers/sky.h	(revision 1)
@@ -0,0 +1,33 @@
+#ifndef _SKY_H
+#define _SKY_H
+
+/*=
+Sky and environement boxes
+1900
+**/
+
+// Introduction
+/**
+Skyboxes are mostly automated.
+
+For now, Raydium will use ##BOXfront.tga##, ##BOXback.tga##, ##BOXleft.tga##,
+##BOXright.tga##, ##BOXbottom.tga## and ##BOXtop.tga## and will draw a 
+skybox only if fog is disabled (this is not for technical reasons, 
+but only for realism, just think about it ;)... but you can force 
+skybox with fog using ##raydium_sky_force## if you really want).
+**/
+
+
+extern void raydium_sky_box_cache (void);
+/**
+As skybox texture are sometimes large files, you can pre-load skybox
+with this function. If you don't do it, Raydium will load textures 
+during the first frame of your application.
+**/
+
+extern void raydium_sky_box_render (GLfloat x, GLfloat y, GLfloat z);
+/**
+Internal use.
+**/
+
+#endif
Index: raydium/headers/ode.h
===================================================================
--- raydium/headers/ode.h	(revision 0)
+++ raydium/headers/ode.h	(revision 1)
@@ -0,0 +1,197 @@
+#ifndef _ODE_H
+#define _ODE_H
+#include "../ode.h"
+extern void raydium_ode_name_auto (char *prefix, char *dest);
+extern void raydium_ode_init_object (int i);
+extern void raydium_ode_init_element (int i);
+extern void raydium_ode_init_joint (int i);
+extern void raydium_ode_init_motor (int i);
+extern void raydium_ode_init_explosion (int e);
+extern void raydium_ode_init (void);
+extern char raydium_ode_object_isvalid (int i);
+extern char raydium_ode_element_isvalid (int i);
+extern char raydium_ode_joint_isvalid (int i);
+extern char raydium_ode_motor_isvalid (int i);
+extern char raydium_ode_explosion_isvalid (int i);
+extern void raydium_ode_ground_dTriArrayCallback (dGeomID TriMesh, dGeomID RefObject, const int *TriIndices, int TriCount);
+extern int raydium_ode_ground_dTriCallback (dGeomID TriMesh, dGeomID RefObject, int TriangleIndex);
+extern void raydium_ode_ground_set_name (char *name);
+extern int raydium_ode_object_find (char *name);
+extern int raydium_ode_element_find (char *name);
+extern int raydium_ode_joint_find (char *name);
+extern int raydium_ode_motor_find (char *name);
+extern int raydium_ode_explosion_find (char *name);
+extern int raydium_ode_object_create (char *name);
+extern char raydium_ode_object_rename (int o, char *newname);
+extern char raydium_ode_object_rename_name (char *o, char *newname);
+extern char raydium_ode_object_colliding (int o, char colliding);
+extern char raydium_ode_object_colliding_name (char *o, char colliding);
+extern void raydium_ode_object_linearvelocity_set (int o, dReal * vect);
+extern void raydium_ode_object_linearvelocity_set_name (char *o, dReal * vect);
+extern void raydium_ode_object_linearvelocity_set_name_3f (char *o, dReal vx, dReal vy, dReal vz);
+extern void raydium_ode_object_addforce (int o, dReal * vect);
+extern void raydium_ode_object_addforce_name (char *o, dReal * vect);
+extern void raydium_ode_object_addforce_name_3f (char *o, dReal vx, dReal vy, dReal vz);
+extern void raydium_ode_element_addforce (int e, dReal * vect);
+extern void raydium_ode_element_addforce_name (char *e, dReal * vect);
+extern void raydium_ode_element_addforce_name_3f (char *e, dReal vx, dReal vy, dReal vz);
+extern void raydium_ode_element_addtorque (int e, dReal * vect);
+extern void raydium_ode_element_addtorque_name (char *e, dReal * vect);
+extern void raydium_ode_element_addtorque_name_3f (char *e, dReal vx, dReal vy, dReal vz);
+extern char raydium_ode_element_material (int e, dReal erp, dReal cfm);
+extern char raydium_ode_element_material_name (char *name, dReal erp, dReal cfm);
+extern char raydium_ode_element_slip (int e, dReal slip);
+extern char raydium_ode_element_slip_name (char *e, dReal slip);
+extern char raydium_ode_element_rotfriction (int e, dReal rotfriction);
+extern char raydium_ode_element_rotfriction_name (char *e, dReal rotfriction);
+extern dReal *raydium_ode_element_linearvelocity_get (int e);
+extern dReal *raydium_ode_element_linearvelocity_get_name (char *e);
+extern void raydium_ode_element_OnBlow (int e, void *OnBlow);
+extern void raydium_ode_element_OnBlow_name (char *e, void *OnBlow);
+extern void raydium_ode_element_OnDelete (int e, void *OnDelete);
+extern void raydium_ode_element_OnDelete_name (char *e, void *OnDelete);
+extern void raydium_ode_element_gravity (int e, char enable);
+extern void raydium_ode_element_gravity_name (char *e, char enable);
+extern void raydium_ode_element_ttl_set (int e, int ttl);
+extern void raydium_ode_element_ttl_set_name (char *e, int ttl);
+extern char raydium_ode_element_aabb_get (int element, dReal * aabb);
+extern char raydium_ode_element_aabb_get_name (char *element, dReal * aabb);
+extern int raydium_ode_element_touched_get (int e);
+extern int raydium_ode_element_touched_get_name (char *e);
+extern char raydium_ode_element_player_set (int e, char isplayer);
+extern char raydium_ode_element_player_set_name (char *name, char isplayer);
+extern char raydium_ode_element_player_get (int e);
+extern char raydium_ode_element_player_get_name (char *name);
+extern char raydium_ode_element_player_angle (int e, dReal angle);
+extern char raydium_ode_element_player_angle_name (char *e, dReal angle);
+extern int raydium_ode_element_ground_texture_get (int e);
+extern int raydium_ode_element_ground_texture_get_name (char *e);
+extern int raydium_ode_element_object_get (int e);
+extern int raydium_ode_element_object_get_name (char *e);
+extern int raydium_ode_object_sphere_add (char *name, int group, dReal mass, dReal radius, char type, int tag, char *mesh);
+extern int raydium_ode_object_box_add (char *name, int group, dReal mass, dReal tx, dReal ty, dReal tz, char type, int tag, char *mesh);
+extern int raydium_ode_element_fix (char *name, int *elem, int nelems, char keepgeoms);
+extern void raydium_ode_element_unfix (int e);
+extern void raydium_ode_element_move (int elem, dReal * pos);
+extern void raydium_ode_element_move_3f(int elem, dReal x,dReal y, dReal z);
+extern void raydium_ode_element_move_name (char *name, dReal * pos);
+extern void raydium_ode_element_move_name_3f (char *name, dReal x, dReal y, dReal z);
+extern void raydium_ode_element_rotate (int elem, dReal * rot);
+extern void raydium_ode_element_rotate_3f (int elem, dReal rx, dReal ry, dReal rz);
+extern void raydium_ode_element_rotate_name (char *name, dReal * rot);
+extern void raydium_ode_element_rotateq (int elem, dReal * rot);
+extern void raydium_ode_element_rotateq_name (char *name, dQuaternion rot);
+extern void raydium_ode_element_rotate_name_3f (char *name, dReal rx, dReal ry, dReal rz);
+extern void raydium_ode_object_rotate(int obj, dReal *rot);
+extern void raydium_ode_object_rotate_name(char *obj, dReal *rot);
+extern void raydium_ode_object_rotate_name_3f(char *obj, dReal rx, dReal ry, dReal rz);
+extern void raydium_ode_element_rotate_direction (int elem, char Force0OrVel1);
+extern void raydium_ode_element_rotate_direction_name (char *e, char Force0OrVel1);
+extern void raydium_ode_element_data_set (int e, void *data);
+extern void raydium_ode_element_data_set_name (char *e, void *data);
+extern void *raydium_ode_element_data_get (int e);
+extern void *raydium_ode_element_data_get_name (char *e);
+extern int raydium_ode_element_tag_get (int e);
+extern int raydium_ode_element_tag_get_name (char *e);
+extern void raydium_ode_object_move (int obj, dReal * pos);
+extern void raydium_ode_object_move_name (char *name, dReal * pos);
+extern void raydium_ode_object_move_name_3f (char *name, dReal x, dReal y, dReal z);
+extern void raydium_ode_object_rotateq (int obj, dReal * rot);
+extern void raydium_ode_object_rotateq_name (char *obj, dReal * rot);
+extern void raydium_ode_joint_suspension (int j, dReal erp, dReal cfm);
+extern void raydium_ode_joint_suspension_name (char *j, dReal erp, dReal cfm);
+extern int raydium_ode_joint_attach_hinge2 (char *name, int elem1, int elem2, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z);
+extern int raydium_ode_joint_attach_hinge2_name (char *name, char *elem1, char *elem2, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z);
+extern int raydium_ode_joint_attach_universal (char *name, int elem1, int elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z);
+extern int raydium_ode_joint_attach_universal_name (char *name, char *elem1, char *elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z);
+extern int raydium_ode_joint_attach_hinge (char *name, int elem1, int elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z);
+extern int raydium_ode_joint_attach_hinge_name (char *name, char *elem1, char *elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z);
+extern int raydium_ode_joint_attach_fixed (char *name, int elem1, int elem2);
+extern int raydium_ode_joint_attach_fixed_name (char *name, char *elem1, char *elem2);
+extern void raydium_ode_joint_hinge_limits (int j, dReal lo, dReal hi);
+extern void raydium_ode_joint_hinge_limits_name (char *j, dReal lo, dReal hi);
+extern void raydium_ode_joint_universal_limits (int j, dReal lo1, dReal hi1, dReal lo2, dReal hi2);
+extern void raydium_ode_joint_universal_limits_name (char *j, dReal lo1, dReal hi1, dReal lo2, dReal hi2);
+extern void raydium_ode_joint_hinge2_block (int j, char block);
+extern void raydium_ode_joint_hinge2_block_name (char *name, char block);
+extern void raydium_ode_joint_delete_callback (int j, void (*f) (int));
+extern void raydium_ode_joint_delete_callback_name (char *name, void (*f) (int));
+extern void raydium_ode_joint_break_force (int j, dReal maxforce);
+extern void raydium_ode_joint_break_force_name (char *name, dReal maxforce);
+extern void raydium_ode_joint_elements_get (int j, int *e1, int *e2);
+extern void raydium_ode_joint_elements_get_name (char *j, int *e1, int *e2);
+extern void raydium_ode_motor_update_joints_data_internal (int j);
+extern void raydium_ode_motor_speed (int j, dReal force);
+extern void raydium_ode_motor_speed_name (char *name, dReal force);
+extern void raydium_ode_motor_power_max (int j, dReal power);
+extern void raydium_ode_motor_power_max_name (char *name, dReal power);
+extern void raydium_ode_motor_angle (int j, dReal angle);
+extern void raydium_ode_motor_angle_name (char *motor, dReal angle);
+extern void raydium_ode_motor_gears_set (int m, dReal * gears, int n_gears);
+extern void raydium_ode_motor_gears_set_name (char *m, dReal * gears, int n_gears);
+extern void raydium_ode_motor_gear_change (int m, int gear);
+extern void raydium_ode_motor_gear_change_name (char *m, int gear);
+extern dReal *raydium_ode_element_pos_get (int j);
+extern dReal *raydium_ode_element_pos_get_name (char *name);
+extern char raydium_ode_element_rotq_get (int j, dQuaternion res);
+extern char raydium_ode_element_rotq_get_name (char *name, dQuaternion res);
+extern char raydium_ode_element_rot_get (int e, dReal * rx, dReal * ry, dReal * rz);
+extern char raydium_ode_element_rot_get_name (char *e, dReal * rx, dReal * ry, dReal * rz);
+extern void raydium_ode_element_sound_update (int e, int source);
+extern void raydium_ode_element_sound_update_name (char *e, int source);
+extern void raydium_ode_element_RelPointPos (int e, dReal px, dReal py, dReal pz, dReal * res);
+extern void raydium_ode_element_RelPointPos_name (char *e, dReal px, dReal py, dReal pz, dReal * res);
+extern int raydium_ode_motor_create (char *name, int obj, char type);
+extern void raydium_ode_motor_attach (int motor, int joint, int joint_axe);
+extern void raydium_ode_motor_attach_name (char *motor, char *joint, int joint_axe);
+extern dReal raydium_ode_motor_speed_get (int m, int gears);
+extern dReal raydium_ode_motor_speed_get_name (char *name, int gears);
+extern void raydium_ode_motor_rocket_set (int m, int element, dReal x, dReal y, dReal z);
+extern void raydium_ode_motor_rocket_set_name (char *motor, char *element, dReal x, dReal y, dReal z);
+extern void raydium_ode_motor_rocket_orientation (int m, dReal rx, dReal ry, dReal rz);
+extern void raydium_ode_motor_rocket_orientation_name (char *name, dReal rx, dReal ry, dReal rz);
+extern void raydium_ode_motor_rocket_playermovement (int m, char isplayermovement);
+extern void raydium_ode_motor_rocket_playermovement_name (char *m, char isplayermovement);
+extern char raydium_ode_motor_delete (int e);
+extern char raydium_ode_motor_delete_name (char *name);
+extern char raydium_ode_joint_delete (int joint);
+extern char raydium_ode_joint_delete_name (char *name);
+extern char raydium_ode_element_delete (int e, char deletejoints);
+extern char raydium_ode_element_delete_name (char *name, char deletejoints);
+extern char raydium_ode_object_delete (int obj);
+extern char raydium_ode_object_delete_name (char *name);
+extern char raydium_ode_explosion_delete (int e);
+extern char raydium_ode_element_moveto (int element, int object, char deletejoints);
+extern char raydium_ode_element_moveto_name (char *element, char *object, char deletejoints);
+extern void raydium_ode_joint_break (int j);
+extern char raydium_ode_launcher (int element, int from_element, dReal * rot, dReal force);
+extern char raydium_ode_launcher_name (char *element, char *from_element, dReal * rot, dReal force);
+extern char raydium_ode_launcher_name_3f (char *element, char *from_element, dReal rx, dReal ry, dReal rz, dReal force);
+extern char raydium_ode_launcher_simple (int element, int from_element, dReal * lrot, dReal force);
+extern char raydium_ode_launcher_simple_name (char *element, char *from_element, dReal * rot, dReal force);
+extern char raydium_ode_launcher_simple_name_3f (char *element, char *from_element, dReal rx, dReal ry, dReal rz, dReal force);
+extern void raydium_ode_explosion_blow (dReal radius, dReal max_force, dReal * pos);
+extern void raydium_ode_explosion_blow_3f (dReal radius, dReal max_force, dReal px, dReal py, dReal pz);
+extern int raydium_ode_explosion_create (char *name, dReal final_radius, dReal propag, dReal * pos);
+extern void raydium_ode_element_camera_inboard (int e, dReal px, dReal py, dReal pz, dReal lookx, dReal looky, dReal lookz);
+extern void raydium_ode_element_camera_inboard_name (char *name, dReal px, dReal py, dReal pz, dReal lookx, dReal looky, dReal lookz);
+extern void raydium_ode_draw_all (char names);
+extern void raydium_ode_near_callback (void *data, dGeomID o1, dGeomID o2);
+extern void raydium_ode_callback (void);
+extern void raydium_ode_time_change (GLfloat perc);
+extern void raydium_ode_element_particle (int elem, char *filename);
+extern void raydium_ode_element_particle_name (char *elem, char *filename);
+extern void raydium_ode_element_particle_offset (int elem, char *filename, dReal * offset);
+extern void raydium_ode_element_particle_offset_name (char *elem, char *filename, dReal * offset);
+extern void raydium_ode_element_particle_offset_name_3f (char *elem, char *filename, dReal ox, dReal oy, dReal oz);
+extern void raydium_ode_element_particle_point (int elem, char *filename);
+extern void raydium_ode_element_particle_point_name (char *elem, char *filename);
+extern void raydium_camera_smooth_path_to_element (char *path, int element, GLfloat path_step, GLfloat smooth_step);
+extern void raydium_camera_smooth_path_to_element_name (char *path, char *element, GLfloat path_step, GLfloat smooth_step);
+extern void raydium_camera_smooth_element_to_path_offset (int element, GLfloat offset_x, GLfloat offset_y, GLfloat offset_z, char *path, GLfloat path_step, GLfloat smooth_step);
+extern void raydium_camera_smooth_element_to_path_offset_name (char *element, GLfloat offset_x, GLfloat offset_y, GLfloat offset_z, char *path, GLfloat path_step, GLfloat smooth_step);
+extern void raydium_camera_smooth_element_to_path_name (char *element, char *path, GLfloat path_step, GLfloat smooth_step);
+extern int raydium_ode_capture_3d(char *filename);
+extern int raydium_ode_orphans_check(void);
+#include "ode_net.h"
+#endif
Index: raydium/headers/light.h
===================================================================
--- raydium/headers/light.h	(revision 0)
+++ raydium/headers/light.h	(revision 1)
@@ -0,0 +1,106 @@
+#ifndef _LIGHT_H
+#define _LIGHT_H
+/*=
+Lights
+900
+**/
+
+// Introduction to Raydium light system
+/**
+When we starts Raydium development, the main idea was to use native OpenGL
+lights, and not lightmaps or another method.
+
+This method (native lights) provides 8 simultaneous movable lights, 
+and is quite effective with recent OpenGL hardware.
+
+You can modify intensity, position, color, you can turn on any light at 
+any time, make them blinking... Mixing all theses features can result 
+many effects, as realtime sunset, flashing lights for cars, explosions, ...
+
+Usage is very easy: no need to create lights, just turn them on. 
+
+See also: LightMaps
+**/
+
+extern void raydium_light_enable (void);
+/**
+Obvious.
+**/
+
+extern void raydium_light_disable (void);
+/**
+Obvious.
+**/
+
+extern GLuint raydium_light_to_GL_light (GLuint l);
+/**
+Probably useless for end user. (internal uses)
+**/
+
+extern void raydium_light_on (GLuint l);
+/**
+Turns ##l## light on ( 0 <= l <= RAYDIUM_MAX_LIGHTS )
+**/
+
+extern void raydium_light_off (GLuint l);
+/**
+Turns ##l## light off
+**/
+
+extern void raydium_light_switch (GLuint l);
+/**
+Will swith ##l## light state (from "on" to "off", for example).
+**/
+
+extern void raydium_light_update_position (GLuint l);
+/**
+Updates ##raydium_light_position[l]## array changes to hardware.
+This function is now used internaly by Raydium,
+so you have no reasons to call it by yourself.
+**/
+
+extern void raydium_light_update_position_all (void);
+/**
+See above.
+**/
+
+extern void raydium_light_update_intensity (GLuint l);
+/**
+See above.
+**/
+
+extern void raydium_light_update_all (GLuint l);
+/**
+See above.
+**/
+
+extern void raydium_light_move (GLuint l, GLfloat * vect);
+/**
+Moves light to position ##vect## for light ##l## (vect is GLfloat[4]: x,y,z,dummy).
+
+Just move your lights before camera placement, or your changes 
+will be applied to the next frame only.
+**/
+
+extern void raydium_light_reset (GLuint l);
+/**
+This function will restore all defaults for ##l## light.
+**/
+
+extern void raydium_light_blink_internal_update (GLuint l);
+/**
+Useless for end-user.
+**/
+
+extern void raydium_light_blink_start (GLuint l, int fpc);
+/**
+Makes ##l## light blinking at ##fpc## (frames per cycle) rate.
+This function will use timecalls soon ("fpc" -> "hertz")
+**/
+
+extern void raydium_light_callback (void);
+/**
+Useless for end-user.
+**/
+
+#endif
Index: raydium/headers/vertex.h
===================================================================
--- raydium/headers/vertex.h	(revision 0)
+++ raydium/headers/vertex.h	(revision 1)
@@ -0,0 +1,32 @@
+#ifndef _VERTEX_H
+#define _VERTEX_H
+
+/*=
+vertices
+1700
+**/
+
+// Introduction
+/**
+You can create objets at runtime, if needed, using the following functions.
+Each of theses functions adds only one vertex so, obviously, you need to 
+call three time the same function to add one triangle. 
+**/
+
+
+extern void raydium_vertex_add (GLfloat x, GLfloat y, GLfloat z);
+/**
+Adds a vertex at (##x,y,z##).
+**/
+
+extern void raydium_vertex_uv_add (GLfloat x, GLfloat y, GLfloat z, GLfloat u, GLfloat v);
+/**
+Same as above, but providing texture mapping informations with ##u## and ##v##.
+**/
+
+extern void raydium_vertex_uv_normals_add (GLfloat x, GLfloat y, GLfloat z, GLfloat nx, GLfloat ny, GLfloat nz, GLfloat u, GLfloat v);
+/**
+Same as above, giving vertex's normal with (##nx,ny,nz##).
+**/
+
+#endif
Index: raydium/headers/background.h
===================================================================
--- raydium/headers/background.h	(revision 0)
+++ raydium/headers/background.h	(revision 1)
@@ -0,0 +1,14 @@
+#ifndef _BACKGROUND_H
+#define _BACKGROUND_H
+/*=
+Background
+800
+**/
+
+extern void raydium_background_color_change (GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+/**
+Will change ##raydium_background_color## array and apply this modification.
+(will update fog color, obviously).
+**/
+
+#endif
Index: raydium/headers/register.h
===================================================================
--- raydium/headers/register.h	(revision 0)
+++ raydium/headers/register.h	(revision 1)
@@ -0,0 +1,73 @@
+#ifndef _REGISTER_H
+#define _REGISTER_H
+
+/*=
+Data registration
+3400
+**/
+
+// Introduction
+/**
+Raydium supports scripting, for example using PHP in the current implementation.
+All ##raydium_register_*## functions are provided as a "bridge" between
+your applications and PHP scripts, allowing you to "export" native variables 
+and functions to PHP scripts.
+For more informations, see PHP chapters.
+**/
+
+extern int raydium_register_find_name (char *name);
+/**
+Lookups a **variable** by ##name##. Search is not possible (yet) for
+registered functions.
+Mostly used internally.
+**/
+
+extern char raydium_register_name_isvalid (char *name);
+/**
+Tests ##name##, and returns his viability as a boolean.
+Accepted intervals for variables and functions: [a-z], [A-Z] and '_'
+Numerics are not allowed.
+**/
+
+extern int raydium_register_variable (void *addr, int type, char *name);
+/**
+Will register a new variable. You must provide variable's address (##addr##), 
+##type## and ##name##.
+Current available types are: ##RAYDIUM_REGISTER_INT##, ##RAYDIUM_REGISTER_FLOAT##,
+and ##RAYDIUM_REGISTER_STR##.
+**/
+
+extern int raydium_register_variable_const_f(float val, char *name);
+/**
+Will register a new ##float## constant.
+**/
+
+extern int raydium_register_variable_const_i(int val, char *name);
+/**
+Will register a new ##int## constant.
+**/
+
+extern void raydium_register_variable_unregister_last (void);
+/**
+Variable are registered on a stack. As you may want to create "temporary"
+variables (usefull for building script's arguments, for example), this function
+allows you to unregister last registered variable. Multiple calls are possible.
+**/
+
+extern int raydium_register_modifiy (char *var, char *args);
+/**
+Deprecated.
+**/
+
+extern void raydium_register_function (void *addr, char *name);
+/**
+Will register a function. You only need to provide an address (##addr##)
+and a name.
+**/
+
+extern void raydium_register_dump (void);
+/**
+Will dump to console all registered variables and functions.
+**/
+
+#endif
Index: raydium/headers/trigo.h
===================================================================
--- raydium/headers/trigo.h	(revision 0)
+++ raydium/headers/trigo.h	(revision 1)
@@ -0,0 +1,71 @@
+#ifndef _TRIGO_H
+#define _TRIGO_H
+
+/*=
+Maths
+200
+*/
+
+// Little introduction to trigo.c
+/**
+This section is mostly designed for internal uses, but provides some
+usefull maths functions.
+**/
+
+extern GLfloat raydium_trigo_cos (GLfloat i);
+/**
+Obvious (degrees)
+**/
+
+extern GLfloat raydium_trigo_sin (GLfloat i);
+/**
+Obvious (degrees)
+**/
+
+extern GLfloat raydium_trigo_cos_inv (GLfloat i);
+/**
+Obvious (degrees)
+**/
+
+extern GLfloat raydium_trigo_sin_inv (GLfloat i);
+/**
+Obvious (degrees)
+**/
+
+#define raydium_trigo_abs(a) ( (a) < (0) ? (-a) : (a) )
+/**
+Obvious
+**/
+
+#define raydium_trigo_min(a,b) ( (a) < (b) ? (a) : (b) )
+/**
+Obvious
+**/
+
+#define raydium_trigo_max(a,b) ( (a) > (b) ? (a) : (b) )
+/**
+Obvious
+**/
+
+#define raydium_trigo_isfloat(a) ( (!isnan(a) && !isinf(a)) ? 1 : 0)
+/**
+Test two cases : "Not a Number" and "Infinite"
+**/
+
+extern void raydium_trigo_rotate (GLfloat * p, GLfloat rx, GLfloat ry, GLfloat rz, GLfloat * res);
+/**
+Rotate p (GLfloat * 3) by (rx,ry,rx) angles (degrees).
+Result is stored in res (GLfloat * 3)
+**/
+
+extern void raydium_trigo_pos_to_matrix (GLfloat * pos, GLfloat * m);
+/**
+Generates a ODE style matrix (16 Glfloat) from pos (GLfloat * 3)
+**/
+
+extern void raydium_trigo_pos_get_modelview (GLfloat * res);
+/**
+Stores the current OpenGL MODELVIEW matrix in res (16 GLfloat)
+**/
+
+#endif
Index: raydium/headers/php.h
===================================================================
--- raydium/headers/php.h	(revision 0)
+++ raydium/headers/php.h	(revision 1)
@@ -0,0 +1,57 @@
+#ifndef _PHP_H
+#define _PHP_H
+// PHP support for Raydium
+// Known bug: recursive Ray/PHP calls are fatal (segfault in zend core).
+
+#include "../php_wrappers.c"
+// use this macro when registering your functions
+#define C2PHP ZEND_FN
+
+
+// Dirty globals... (needed for WIN32 PHP support)
+#ifdef ZTS
+extern zend_compiler_globals *compiler_globals;
+extern zend_executor_globals *executor_globals;
+extern php_core_globals *core_globals;
+extern sapi_globals_struct *sapi_globals;
+extern void ***tsrm_ls;
+#endif
+extern int raydium_init_cli_option (char *option, char *value);;
+// { // Unrecognized
+//   return SAPI_HEADER_SENT_SUCCESSFULLY; // Unrecognized
+// } // Unrecognized
+// { // Unrecognized
+// } // Unrecognized
+// { // Unrecognized
+//   return SUCCESS; // Unrecognized
+// } // Unrecognized
+extern void raydium_php_error (int type, const char *msg, ...);
+extern int raydium_php_uwrite (const char *str, uint str_length TSRMLS_DC);
+//   "RayHandler", // Unrecognized
+//   "Raydium PHP Handler", // Unrecognized
+//   php_dummy, // Unrecognized
+//   php_dummy, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   raydium_php_uwrite, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   raydium_php_error, // Unrecognized
+//   NULL, // Unrecognized
+//   sapi_raydium_send_headers, // Unrecognized
+//   sapi_raydium_send_header, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   NULL, // Unrecognized
+//   STANDARD_SAPI_MODULE_PROPERTIES // Unrecognized
+// }; // Unrecognized
+extern void raydium_php_init_request (char *filename);
+extern int raydium_php_exec (char *name);
+extern void raydium_php_close (void);
+extern void raydium_php_init (void);
+#endif
Index: raydium/headers/sound.h
===================================================================
--- raydium/headers/sound.h	(revision 0)
+++ raydium/headers/sound.h	(revision 1)
@@ -0,0 +1,249 @@
+#ifndef _SOUND_H
+#define _SOUND_H
+/*=
+Sound and music
+2600
+**/
+
+// Introduction
+/**
+The Raydium sound API is pretty easy to use and there's only need to use a 
+few functions to make your program ouput sounds or music.
+
+On top of this, there are a bunch of functions to modify the sound behavior.
+
+Raydium uses OpenAL and OggVorbis? for its sounds and musics, for a basic 
+use of our sound API you only need to know one thing: OpenAL uses buffers 
+for its sounds and you need to be able to address the sounds separately.
+For this we use ALuint in our code. Each buffer is associated to a source,
+we have an array of all available sources and then, you only need to have 
+a simple int that acts as an index in this array. See below for more
+informations.
+
+Music is readed thru libogg, streamed from disk. If you want to play an
+OGG audio track, the only thing you've to do is to call the suitable function.
+You can use ##raydium_sound_music_eof_callback## if needed. This event is
+fired when sound track ends, allowing you to switch to another file.
+Prototype for this callback is ##int callback(char *new_track)##, allowing
+you to do something like ##strcpy(new_track,"foobar.ogg"); return 1;##.
+Return 0 if you do not want to switch to another audio file (this will stops
+music playback).
+
+This document is not an alternative to OpenAL papers, and only provides
+informations about Raydium's interface to OpenAL.
+See specifications here: http://www.openal.org/documentation.html
+**/
+
+extern void raydium_sound_verify (char *caller);
+/**
+This functions checks if any error occured during last OpenAL operation.
+You don't have to call this function by yourself, since every function of
+this API will do it.
+**/
+
+extern int raydium_sound_Array3IsValid(ALfloat *a);
+/**
+Since OpenAL is very sensitive to malformed values, this function is used
+internally to check consistency of provided ALfloat arrays.
+**/
+
+extern void raydium_sound_InitSource (int src);
+/**
+Internal use.
+**/
+
+extern int raydium_sound_LoadWav (const char *fname);
+/**
+This function tries to load the ##fname## wav file into a buffer, if 
+successful, it returns the source id, else 0.
+**/
+
+extern int raydium_sound_SourceVerify (int src);
+/**
+Internal id checks.
+**/
+
+extern int raydium_sound_SetSourceLoop (int src, char loop);
+/**
+Modifies the ##loop## property of the ##src## source (loops if loop is non-zero, 
+default value for a source is "true").
+Returns 0 if ok, -1 if error.
+**/
+
+extern int raydium_sound_GetSourcePitch (int src, ALfloat * p);
+/**
+Returns current pitch for ##src## source.
+**/
+
+extern int raydium_sound_SetSourcePitch (int src, ALfloat p);
+/**
+Sets pitch for ##src## source.
+Current OpenAL spec is not clear about pitch's limits. Raydium will 
+clamp values to to ]0,2] interval.
+**/
+
+extern int raydium_sound_GetSourceGain (int src, ALfloat * g);
+/**
+Returns current gain ("volume") for ##src## source.
+**/
+
+extern int raydium_sound_SetSourceGain (int src, ALfloat g);
+/**
+Sets gain ("volume") for ##src## source.
+Current OpenAL spec is not clear about pitch's limits. Raydium do not allows
+negative values, but no upper limit is set.
+Warning: some OpenAL implementations will provide strange gain curves. More
+work is needed on this issue.
+**/
+
+extern int raydium_sound_SetSourcePos (int src, ALfloat Pos[]);
+/**
+Sets 3D position of ##src## source.
+##Pos## is a 3 * ALfloat array.
+**/
+
+extern int raydium_sound_SetSourcePosCamera(int src);
+/**
+Sets 3D position of ##src## source on the current camera position.
+**/
+
+extern int raydium_sound_GetSourcePos (int src, ALfloat * Pos[]);
+/**
+Returns current 3D position of ##src## source.
+##Pos## is a 3 * ALfloat array.
+**/
+
+extern int raydium_sound_SetSourceDir (int src, ALfloat Dir[]);
+/**
+Sets 3D direction of ##src## source.
+##Dir## is a 3 * ALfloat array.
+**/
+
+extern int raydium_sound_GetSourceDir (int src, ALfloat * Dir[]);
+/**
+Returns current 3D direction of ##src## source.
+##Dir## is a 3 * ALfloat array.
+**/
+
+extern int raydium_sound_SetSourceVel (int src, ALfloat Vel[]);
+/**
+Sets 3D velocity of ##src## source.
+##Vel## is a 3 * ALfloat array.
+**/
+
+extern int raydium_sound_GetSourceVel (int src, ALfloat * Vel[]);
+/**
+Returns current 3D velocity of ##src## source.
+##Vel## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_SetListenerPos (ALfloat Pos[]);
+/**
+Sets 3D position of listener.
+This is done automatically by Raydium, each frame, using camera informations
+##Pos## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_GetListenerPos (ALfloat * Pos[]);
+/**
+Returns current 3D position of listener.
+##Pos## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_SetListenerOr (ALfloat Or[]);
+/**
+Sets 3D orientation of listener.
+This is done automatically by Raydium, each frame, using camera informations
+##Or## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_GetListenerOr (ALfloat * Or[]);
+/**
+Returns current 3D orientation of listener.
+##Or## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_SetListenerVel (ALfloat Vel[]);
+/**
+Sets 3D velocity of Listener.
+##Vel## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_GetListenerVel (ALfloat * Vel[]);
+/**
+Returns current 3D velocity of Listener.
+##Vel## is a 3 * ALfloat array.
+**/
+
+extern void raydium_sound_init (void);
+/**
+Internal use.
+**/
+
+extern int raydium_sound_SourcePlay (int src);
+/**
+Plays the ##src## source.
+If ##src## was already in "play" state, the buffer is rewinded.
+Returns 0 if ok, -1 if error.
+**/
+
+extern int raydium_sound_SourceStop (int src);
+/**
+Stops the ##src## source.
+Returns 0 if ok, -1 if error.
+**/
+
+extern int raydium_sound_SourcePause (int src);
+/**
+Will pause the ##src## source.
+Returns 0 if ok, -1 if error.
+**/
+
+extern int raydium_sound_SourceUnpause (int src);
+/**
+##src## will restart playback after being paused.
+Returns 0 if ok, -1 if error.
+**/
+
+extern void raydium_sound_close (void);
+/**
+Internal use.
+**/
+
+extern int BufferData (ALuint buffer, OggVorbis_File * file, vorbis_info * ogginfo);
+extern void raydium_sound_internal_cleanstreambuffs (void);
+extern int StartMusic (ALuint musicsource, ALuint * buffers, OggVorbis_File * file, vorbis_info * ogginfo);
+extern int raydium_sound_load_music (char *fname);
+/**
+Opens fname **OGG** music file and prepairs Raydium for playing it.
+The music will be automatically played after a call to this function.
+This function will use R3S (data repositories) if needed.
+To switch to another audio track, simply call again this function.
+Send ##NULL## or an empty string to cancel music playback.
+Returns 0 if ok, -1 if error
+
+See also ##raydium_sound_music_eof_callback## at the top of this chapter.
+**/
+
+extern void raydium_sound_music_callback (void);
+/**
+Internal use.
+**/
+
+extern void raydium_sound_callback (void);
+/**
+Internal use.
+**/
+
+// Example
+/**
+%%(c)
+int sound;
+sound=raydium_sound_LoadWav("explo.wav");
+raydium_sound_SetSourceLoop(sound,0);
+[...]
+if(explosion) raydium_sound_SourcePlay(sound);
+%%
+**/
+
+#endif
Index: raydium/headers/network.h
===================================================================
--- raydium/headers/network.h	(revision 0)
+++ raydium/headers/network.h	(revision 1)
@@ -0,0 +1,396 @@
+#ifndef _NETWORK_H
+#define _NETWORK_H
+/*=
+Network
+2800
+**/
+
+// Bases of Raydium's networking API
+/**
+Raydium supports networking via UDP/IP, providing high level functions 
+for multiplayer game development.
+Raydium servers are limited to 256 clients for now.
+
+You will find in network.c a set of functions and vars dedicated to 
+networked games: players names, event callbacks, UDP sockets, 
+broadcasts, ... 
+All this is ready to use. As it's not done in the introduction of this 
+guide, We will explain here some variables defined in common.c.
+
+%%(c)
+#define RAYDIUM_NETWORK_PORT          29104
+#define RAYDIUM_NETWORK_PACKET_SIZE   230
+#define RAYDIUM_NETWORK_TIMEOUT       5
+#define RAYDIUM_NETWORK_PACKET_OFFSET 4
+#define RAYDIUM_NETWORK_MAX_CLIENTS   8
+#define RAYDIUM_NETWORK_MODE_NONE     0
+#define RAYDIUM_NETWORK_MODE_CLIENT   1
+#define RAYDIUM_NETWORK_MODE_SERVER   2
+%%
+
+Here, we can find network port declaration (Raydium will use only one 
+port, allowing easy port forwarding management, if needed), default timeout 
+(unit: second), and the three mode possible for a Raydium application.
+
+But there is also two other very important defines: packet size 
+(unit: byte) and max number of clients.. This is important because 
+Raydium uses UDP sockets, and UDP sockets required fixed 
+length packets, and as you need to set packet size as small as possible 
+(for obvious speed reasons), you must calculate you maximum 
+information packet size (players position, for example), multiply 
+it by ##RAYDIUM_NETWORK_MAX_CLIENTS##,and add ##RAYDIUM_NETWORK_PACKET_OFFSET##
+wich represent the required header of the packet.
+
+It's more easy than it seems, look:
+//
+My game will support 8 players.
+I will send players state with 3 floats (x,y,z).
+My packet size must be: 8*3*sizeof(float)+RAYDIUM_NETWORK_PACKET_OFFSET = 100 bytes.
+//
+Please, do not change packet offset size, since Raydium will use it
+for packet header.
+
+%%(c)
+#define RAYDIUM_NETWORK_DATA_OK     1
+#define RAYDIUM_NETWORK_DATA_NONE   0
+#define RAYDIUM_NETWORK_DATA_ERROR -1
+%%
+
+This three defines are used as network functions result:
+
+%%(c)
+if(raydium_network_read_flushed(&id,&type,buff)==RAYDIUM_NETWORK_DATA_OK)
+{
+...
+%%
+
+%%(c) #define RAYDIUM_NETWORK_PACKET_BASE 20 %%
+
+In most network functions, you will find a "type" argument, used to 
+determine packet goal. This type is 8 bits long (256 possible values), 
+but Raydium is already using some of them. So you can use 
+##RAYDIUM_NETWORK_PACKET_BASE## as a base for your own types:
+
+%%(c)
+#define NORMAL_DATA RAYDIUM_NETWORK_PACKET_BASE
+#define BALL_TAKEN (NORMAL_DATA+1)
+#define SCORE_INFO (NORMAL_DATA+2)
+#define HORN (NORMAL_DATA+3)
+...
+%%
+
+===Variables:===
+
+Your own player id (0<= id < RAYDIUM_NETWORK_MAX_CLIENTS),
+read only: ##int raydium_network_uid;##
+Special value "-1" means that you're not connected (see below).
+
+Current network mode (none, client, server),
+read only: ##char raydium_network_mode;##
+
+Boolean used to determine client state (connected or not), read only:
+##char raydium_network_client[RAYDIUM_NETWORK_MAX_CLIENTS];##
+
+example: 
+%%(c)
+if(raydium_network_client[4])
+    draw_player(4);
+%%
+
+Can be used by a server to send data to his clients. Read only:
+##struct sockaddr raydium_network_client_addr[RAYDIUM_NETWORK_MAX_CLIENTS];##
+
+Players names, read only:
+##char raydium_network_name[RAYDIUM_NETWORK_MAX_CLIENTS][RAYDIUM_MAX_NAME_LEN];##
+
+##OnConnect## and ##OnDisconnect## events (server only):
+##void * raydium_network_on_connect;
+void * raydium_network_on_disconnect;##
+
+You can place your owns callbacks (##void(int)##) on these events, as in 
+this example:
+
+%%(c)
+void new_client(int client)
+{
+raydium_log("New player: %s", raydium_network_nameclient);
+}
+
+...
+
+int main(int argc, char **argv)
+{
+...
+raydium_network_on_connect=new_client;
+...
+%%
+**/
+
+// Reliablility versus Speed
+/**
+As explained above, Raydium is using UDP network packets, and as 
+you may know, UDP is not a reliable protocol, aiming speed before all.
+This system is interesting for sending non-sensible data, as player positions,
+for example.
+But Raydium's can handle more important data, using some of methods of TCP
+protocol, as Timeouts, ACK, resending, ...
+This TCP style packets are available thru "Netcalls".
+**/
+
+// High level API: "Netcalls" and "Propags"
+/**
+Netcalls provides you a good way to handle network exchanges using
+callbacks functions, like a simple RPC system.
+The idea is simple, built over the notion of "type". See suitable functions for
+more information about this system.
+
+Another available mechanism is called Propags, and allows you to "share"
+variables over the network (scores, game state, ...) in a very few steps.
+You only need to "create" a type, and link a variable to it (any C type or
+structure is allowed). After each modification of this (local copy of the) 
+variable, just call ##raydium_network_propag_refresh*## and that's it. If 
+any other client (or the server) is applying a modification to this "type", 
+your local copy is automatically updated.
+**/
+
+extern int raydium_network_propag_find (int type);
+/**
+Lookups a "propag" by his ##type##. Returns -1 is no propag is found.
+**/
+
+extern void raydium_network_propag_recv (int type, char *buff);
+/**
+Internal callback for "propag" receiving.
+**/
+
+extern void raydium_network_propag_refresh_id (int i);
+/**
+Will refresh a propag by his ##id##.
+**/
+
+extern void raydium_network_propag_refresh (int type);
+/**
+Will refresh a propag by his ##type##.
+**/
+
+extern void raydium_network_propag_refresh_all (void);
+/**
+Will refresh all propags
+**/
+
+extern int raydium_network_propag_add (int type, void *data, int size);
+/**
+This function will "register" a new propag. You need to provide the address
+of your variable/structure (##data##), ans its ##size##. A dedicated ##type##
+is also required (see at the top of this chapter).
+**/
+
+extern void raydium_network_queue_element_init (raydium_network_Tcp * e);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern unsigned short raydium_network_queue_tcpid_gen (void);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern void raydium_network_queue_tcpid_known_add (int tcpid, int player);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern char raydium_network_queue_tcpid_known (unsigned short tcpid, unsigned short player);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern char raydium_network_queue_is_tcpid (int type);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern void raydium_network_queue_element_add (char *packet, struct sockaddr *to);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern unsigned long *raydium_network_internal_find_delay_addr (int player);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern void raydium_network_queue_check_time (void);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern void raydium_network_queue_ack_send (unsigned short tcpid, struct sockaddr *to);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern void raydium_network_queue_ack_recv (int type, char *buff);
+/**
+Internal use. (TCP style packets)
+**/
+
+extern void raydium_network_player_name (char *str);
+/**
+This function will returns the current player name.
+Raydium will ask the OS for "current logged user", but player name may
+be provided thru ##--name## command line argument.
+**/
+
+extern char raydium_network_set_socket_block (int block);
+/**
+This function will sets ##block## (true or false) status to the network stack.
+A blocking socket will wait indefinitely an incoming packet. A non blocking one
+will return "no data" instead.
+You've almost no reason to call this function by yourself.
+**/
+
+extern char raydium_network_netcall_add (void *ptr, int type, char tcp);
+/**
+This function will register a new Network Callback ("netcall").
+With Raydium, you can read the main data stream with 
+##raydium_network_read_flushed()##, and configure netcalls on random 
+events (using packet type).
+
+Netcalls signature is: ##void(int type, char *buff)##
+
+As you may configure the same callback function for multiples packet types,
+this type is passed to your function, with the temporary ##buff## buffer.
+You can extract from field from packet if needed.
+
+If you sets the ##tcp## flag to true (1), your packet will use "TCP style"
+network protocol (see a the top of this chapter).
+**/
+
+extern void raydium_network_netcall_exec (int type, char *buff);
+/**
+Internal callback for "netcall" receiving.
+**/
+
+extern char raydium_network_timeout_check (void);
+/**
+Internal use.
+**/
+
+extern char raydium_network_init (void);
+/**
+Nothing interesting unless you're creating a console server (using the
+##RAYDIUM_NETWORK_ONLY## directive), since in this case you must do all
+inits by yourself...
+example :
+%%(c)
+#define RAYDIUM_NETWORK_ONLY
+#include "raydium/index.c"
+
+...
+
+int main(int argc, char **argv)
+{
+setbuf(stdout,NULL);
+signal(SIGINT,quit);
+raydium_php_init(); // only if you need PHP support
+raydium_network_init();
+raydium_network_server_create();
+...
+%%
+**/
+
+extern void raydium_network_write (struct sockaddr *to, int from, char type, char *buff);
+/**
+Obviously, this function will send data.
+If you're a client, you don't need to determine to field, as the only 
+destination is the server, so you can use ##NULL##, for example. If you're 
+a server, you can use ##raydium_network_client_addr[]## array.
+
+As a client, ##from## argument is generally your own uid (##raydium_network_uid##),
+but you can use any other player number if needed.
+As a server, ##from## field is useless, since you are the only machine able 
+to send data to clients.
+
+As you may expect, ##type## field is used to determine packet's type.
+You can use any (8 bits) value greater or equal to ##RAYDIUM_NETWORK_PACKET_BASE##.
+
+Finally, ##buff## is a pointer to data's buffer. This buffer 
+must be ##RAYDIUM_NETWORK_PACKET_SIZE## long, and can be cleared 
+or re-used after this call.
+**/
+
+extern void raydium_network_broadcast (char type, char *buff);
+/**
+Sends data over network.
+Obviously, from network point of vue, only a server can broadcast 
+(to his clients).
+
+When a client needs to broadcast (from the game point of vue) some 
+informations (his own position, for example), he must send this information
+to server, and the server will broadcast it.
+
+This function uses the same arguments as previous one, except ##to## and 
+##from##, not needed here.
+**/
+
+extern char raydium_network_read (int *id, char *type, char *buff);
+/**
+Reads next packet from network (FIFO) stack.
+This function uses the same arguments as previous ones, and returns 
+data availability: ##RAYDIUM_NETWORK_DATA_OK##, ##RAYDIUM_NETWORK_DATA_NONE##
+or ##RAYDIUM_NETWORK_DATA_ERROR##.
+**/
+
+extern char raydium_network_read_flushed (int *id, char *type, char *buff);
+/**
+Reads last packet from network stack.
+All previous packets will be ignored, only the newest packet will
+be read (if any).
+
+As you may miss some important informations, you can use netcalls 
+(see above) if you want to capture packets with a particular 
+type, even with flushed reading.
+**/
+
+extern char raydium_network_server_create (void);
+/**
+Will transform you application into a server, accepting new clients 
+instantaneously.
+See also the ##RAYDIUM_NETWORK_ONLY## directive if you want to create console
+servers.
+**/
+
+extern char raydium_network_client_connect_to (char *server);
+/**
+This function will try to connect your application to ##server## (hostname or 
+ip address).
+WARNING: For now, this call could be endless ! (server failure while connecting).
+This function will succed returning 1 or 0 otherwise.
+You are connected instantaneously, and you must start sending data 
+before server timeout (defined by ##RAYDIUM_NETWORK_TIMEOUT##).
+You player number can be found with ##raydium_network_uid## variable, 
+as said before.
+**/
+
+extern char raydium_server_accept_new (struct sockaddr *from, char *name);
+/**
+Internal server callback for new clients.
+**/
+
+extern void raydium_network_close (void);
+/**
+Obvious. Raydium will do it for you, anyway.
+**/
+
+extern void raydium_network_internal_server_delays_dump (void);
+/**
+Dumps "TCP Style" timeouts for all clients to console.
+**/
+
+extern void raydium_network_internal_dump (void);
+/**
+Dumps various stats about network stack to console.
+**/
+
+#endif
Index: raydium/headers/timecall.h
===================================================================
--- raydium/headers/timecall.h	(revision 0)
+++ raydium/headers/timecall.h	(revision 1)
@@ -0,0 +1,146 @@
+#ifndef _TIMECALL_H
+#define _TIMECALL_H
+/*=
+Timecalls
+2700
+**/
+
+// Concept
+/**
+As you may already know, in a real time application (as a game), you need 
+to control in-game time evolution.
+For example, you cannot increment a car position by 1 at each frame since 
+it will generate an irregular scrolling (a frame is never rendered within 
+the same time as the previous or the next one).
+
+Raydium supports timecalls, wich are a great solution for this problem. 
+Usage is very simple: write a simple function, and ask Raydium to call it 
+at the desired rate.
+**/
+
+// Constraints
+/**
+There is an important risk with timecalls: infinite loops.
+If a callback is long, it may take more CPU time than he would, as in this
+very simple example:
+
+foo() is a function, taking 200 ms for his own execution. If you ask for 
+a 6 Hz execution, Raydium will execute foo() six times on the first frame, 
+taking 1200 ms. On the next frame, Raydium will need to execute foo() 7 
+times (the asked 6 times, and one more for the 200 ms lost during the last 
+frame), taking 1400 ms, so 8 times will be needed for the next frame, then 9, ...
+
+So you need to create callbacks as short as possible, since long callbacks 
+may cause a game freeze on slower machines than yours. (1 FPS syndrom)
+**/
+
+// Hardware devices and methods
+/**
+Raydium must use a very accurate system timer, and will try many methods:
+##/dev/rtc## , ##gettimeofday()## (Linux only) and 
+##QueryPerformanceCounter## for win32.
+
+##gettimeofday()## will use a CPU counter and is extremely accurate. 
+It's far the best method. (0.001 ms accuracy is possible)
+
+##/dev/rtc## is quite good, and Raydium will try to configure RTC at 
+##RAYDIUM_TIMECALL_FREQ_PREFERED## rate (8192 Hz by default), but may 
+require a "##/proc/sys/dev/rtc/max-user-freq##" modification:
+##echo 8192 > /proc/sys/dev/rtc/max-user-freq##
+
+You may want to look at common.c for interesting defines about timecalls. 
+**/
+
+#ifdef WIN32
+#define __GETTIMEOFDAY_USEC 1000
+#else
+#define __GETTIMEOFDAY_USEC 1000000
+#endif
+extern void raydium_timecall_raydium (GLfloat step);
+/**
+Internal Raydium callback.
+**/
+
+#ifdef WIN32
+extern float raydium_timecall_internal_w32_detect_modulo(int div);
+/**
+Internal, WIN32 only: Returns timer resolution for ##div## divisor.
+**/
+
+extern int raydium_timecall_internal_w32_divmodulo_find(void);
+/**
+Internal, WIN32 only: Detects the best timer divisor for the current CPU.
+**/
+
+#endif
+extern unsigned long raydium_timecall_devrtc_clock (void);
+/**
+Internal, Linux only: Reads and return RTC clock.
+**/
+
+extern unsigned long raydium_timecall_clock (void);
+/**
+Returns current "time".
+**/
+
+extern char raydium_timecall_devrtc_rate_change (unsigned long new);
+/**
+Internal, Linux only: Modifies RTC clock rate.
+**/
+
+extern void raydium_timecall_devrtc_close (void);
+/**
+Internal, Linux only: Will close RTC clock.
+**/
+
+extern unsigned long raydium_timecall_devrtc_init (void);
+/**
+Internal, Linux only: Will open RTC clock.
+**/
+
+extern int raydium_timecall_detect_frequency (void);
+/**
+Internal: This function will find the best timer available for current
+platform, and adjust properties to your hardware (rate, divisor, ...).
+**/
+
+extern void raydium_timecall_init (void);
+/**
+Internal use.
+**/
+
+
+extern int raydium_timecall_add (void *funct, GLint hz);
+/**
+There is two sort of timecalls with Raydium:
+
+1. Standard ones:
+%%(c)
+raydium_timecall_add(function,800);
+%%
+##void function(void)## will be called 800 times per second.
+
+2. Elastic timed ones:
+%%(c)
+raydium_timecall_add(function,-80);
+%%
+##void function(float step)## will be called for each frame, with a 
+"##step## factor" as argument. In the above example, a 160 Hz game will call 
+function with step = 0.5, but step = 2.0 for a 40 Hz game.
+
+A standard timecall will use ##void(void)## function and a positive ##hertz##
+argument, as an elasitc one will use ##void(float)## and negative ##hertz## argument.
+**/
+
+extern void raydium_timecall_freq_change (int callback, GLint hz);
+/**
+This function changes the ##callback## frequency. See above for possibles
+values of ##hz## (negative and positive values).
+**/
+
+extern void raydium_timecall_callback (void);
+/**
+Internal use (frame fired callback).
+**/
+
+#endif
Index: raydium/headers/capture.h
===================================================================
--- raydium/headers/capture.h	(revision 0)
+++ raydium/headers/capture.h	(revision 1)
@@ -0,0 +1,26 @@
+#ifndef _CAPTURE_H
+#define _CAPTURE_H
+/*=
+Capture (2D)
+700
+**/
+
+// Quickview
+/**
+Captures are made in TGA format (without RLE compression) and saved into
+the current directory.
+This function may fail (garbage in resulting capture) if frame size if 
+not "standard", mostly after a window resize.
+**/
+
+extern void raydium_capture_frame(char *filename);
+/**
+Capture current frame to ##filename##.
+**/
+
+extern void raydium_capture_frame_auto(void);
+/**
+Same as above, but to an auto-generated filename (raycap*).
+**/
+
+#endif
Index: raydium/headers/reg_api.h
===================================================================
--- raydium/headers/reg_api.h	(revision 0)
+++ raydium/headers/reg_api.h	(revision 1)
@@ -0,0 +1,6 @@
+#ifndef _REGAPI_H
+#define _REGAPI_H
+
+void raydium_register_api(void);
+
+#endif
Index: raydium/headers/window.h
===================================================================
--- raydium/headers/window.h	(revision 0)
+++ raydium/headers/window.h	(revision 1)
@@ -0,0 +1,52 @@
+#ifndef _WINDOW_H
+#define _WINDOW_H
+/*=
+Window management
+600
+**/
+
+// Introduction
+/**
+Some important functions, used for window creation and managment.
+**/
+
+extern void raydium_window_close (void);
+/**
+This function is called by Raydium, do not use.
+**/
+
+extern void raydium_window_create (GLuint tx, GLuint ty, char rendering, char *name);
+/**
+You must call this function once in your program, with following arguments:
+
+1. ##tx##, ##ty##: window size, in pixel
+2. ##rendering##: window mode: ##RAYDIUM_RENDERING_*## (NONE, WINDOW, FULLSCREEN)
+3. ##name##: window's name
+
+Raydium is using GLUT for window management, and GLUT fullscreen is not 
+the same between various implementations, and can fail, 
+so use a standard window size (640x480, 800x600, ...) for fullscreen mode.
+
+Note that user can force fullscreen using ##--fullscreen## on the command line.
+**/
+
+extern void raydium_window_resize_callback (GLsizei Width, GLsizei Height);
+/**
+This function is automaticaly called during a window resize, 
+and resize OpenGL rendering space.
+
+There is almost no reason to call this function by yourself.
+**/
+
+extern void raydium_window_view_update (void);
+/**
+If you've changed 3D window size (clipping: raydium_projection_*),
+apply to hardware with this fonction. 
+**/
+
+extern void raydium_window_view_perspective(GLfloat fov, GLfloat fnear, GLfloat ffar);
+/**
+All-in-one function: sets all "perspective" variables, and updates.
+**/
+
+#endif
Index: raydium/headers/fog.h
===================================================================
--- raydium/headers/fog.h	(revision 0)
+++ raydium/headers/fog.h	(revision 1)
@@ -0,0 +1,42 @@
+#ifndef _FOG_H
+#define _FOG_H
+/*=
+Fog
+500
+**/
+
+// Introduction
+/**
+Fog is usefull for two major reasons:
+
+1. Realism: Just try, and you'll understand: 
+amazing depth impression, no ?
+
+2. Speed: For a correct fog effect (i'm talking 
+about estetic aspect), you must bring near_clipping to a closer value,
+reducing the overall number of triangles displayed at the same time. 
+**/
+
+extern void raydium_fog_enable (void);
+/**
+Obvious
+**/
+
+extern void raydium_fog_disable (void);
+/**
+Obvious
+**/
+
+extern void raydium_fog_color_update (void);
+/**
+If you have modified ##raydium_background_color## array, you must 
+call this function, applying the specified color to hardware.
+See also: ##raydium_background_color_change##
+**/
+
+extern void raydium_fog_mode (void);
+/**
+Do not use. Instable prototype.
+**/
+
+#endif
Index: raydium/headers/internal.h
===================================================================
--- raydium/headers/internal.h	(revision 0)
+++ raydium/headers/internal.h	(revision 1)
@@ -0,0 +1,26 @@
+#ifndef _INTERNAL_H
+#define _INTERNAL_H
+
+/*=
+"Internal" informations access
+2000
+**/
+
+extern void raydium_internal_dump (void);
+/**
+This function is now systematically called by Raydium at application's exit,
+displaying some informations about loaded textures, objects, registered data,
+network statistics.
+**/
+
+extern void raydium_internal_dump_matrix (int n);
+/**
+Dumps matrix to console.
+##n## values are:
+%%
+0 for GL_PROJECTION_MATRIX
+1 for GL_MODELVIEW_MATRIX
+%%
+**/
+
+#endif
Index: raydium/headers/ode_net.h
===================================================================
--- raydium/headers/ode_net.h	(revision 0)
+++ raydium/headers/ode_net.h	(revision 1)
@@ -0,0 +1,25 @@
+#ifndef _ODE_NET_H
+#define _ODE_NET_H
+extern int raydium_ode_network_MaxElementsPerPacket (void);
+extern int raydium_network_nid_element_find (int nid);
+extern void raydium_ode_network_newdel_event (int type, char *buff);
+extern void raydium_ode_network_nidwho_event (int type, char *buff);
+extern void raydium_ode_network_explosion_event (int type, char *buff);
+extern void raydium_ode_network_init (void);
+extern char raydium_ode_network_TimeToSend (void);
+extern void raydium_ode_network_element_send (short nelems, int *e);
+extern void raydium_ode_network_element_send_all (void);
+extern void raydium_ode_network_element_send_random (int nelems);
+extern void raydium_ode_network_element_send_iterative (int nelems);
+extern void raydium_ode_network_nidwho (int nid);
+extern void raydium_ode_network_apply (raydium_ode_network_Event * ev);
+extern void raydium_ode_network_read (void);
+extern void raydium_ode_network_element_new (int e);
+extern void raydium_ode_network_element_delete (int e);
+extern void raydium_ode_network_explosion_send (raydium_ode_network_Explosion * exp);
+extern char raydium_ode_network_element_isdistant (int elem);
+extern char raydium_ode_network_element_isdistant_name (char *elem);
+extern char raydium_ode_network_element_distantowner(int elem);
+extern char raydium_ode_network_element_distantowner_name(char *elem);
+extern void raydium_ode_network_element_trajectory_correct (int elem);
+#endif
Index: raydium/headers/signal.h
===================================================================
--- raydium/headers/signal.h	(revision 0)
+++ raydium/headers/signal.h	(revision 1)
@@ -0,0 +1,17 @@
+#ifndef _HEADERS_SIGNAL_H
+#define _HEADERS_SIGNAL_H
+/*=
+Signals
+2500
+**/
+
+// Quickview
+/**
+There almost nothing to said about signals management, except that Raydium 
+will try to catch SIGINT signal (sended by CTRL+C sequence, for example).
+There's nothing else for now, but we plan a user callback for this signal. 
+**/
+
+extern void raydium_signal_handler (int sig);
+extern void raydium_signal_install_trap (void);
+#endif
Index: raydium/headers/land.h
===================================================================
--- raydium/headers/land.h	(revision 0)
+++ raydium/headers/land.h	(revision 1)
@@ -0,0 +1,19 @@
+#ifndef _LAND_H
+#define _LAND_H
+
+/*=
+Land
+1800
+**/
+
+// Introduction
+/**
+Historically, this file was quite complex, since Raydium was using
+his own physic. Now, this file is almost empty, since ODE integration
+now provides new landscape functions.
+**/
+
+extern GLfloat raydium_land_internal_landtmp (GLfloat x, GLfloat y, GLfloat phase, GLfloat ampl, GLfloat periode);
+extern void raydium_land_draw_water (GLfloat phase, GLfloat ampl, GLfloat periode, int sub, GLfloat pas, char *texture);
+extern GLfloat raydium_land_surface (GLfloat x, GLfloat y, GLfloat * nx, GLfloat * ny, GLfloat * nz);
+#endif
Index: raydium/headers/file.h
===================================================================
--- raydium/headers/file.h	(revision 0)
+++ raydium/headers/file.h	(revision 1)
@@ -0,0 +1,93 @@
+#ifndef _FILE_H
+#define _FILE_H
+/*=
+Files
+2100
+**/
+
+// Warning
+/**
+It's important to use only functions with ##raydium_file_*## prefix.
+All other functions may change or disappear. Upper level functions are
+available (see ##object.c##).
+**/
+
+// Introduction
+/**
+##file.c## use .tri mesh files (text), available in 3 versions:
+
+1. version 1: providing normals and uv texture mapping informations.
+2. version 0: providing normals.
+3. version -1: only providing vertices. 
+	 
+Version 1 example file:
+%%
+1
+5.1 15.75 -3.82 0.0000 0.0000 -1.0000 0.5158 0.5489 rgb(0.5,0.5,0.5)
+6.3 11.75 -3.82 0.0000 0.0000 -1.0000 0.5196 0.5365 rgb(0.5,0.5,0.5)
+5.0 11.75 -3.82 0.0000 0.0000 -1.0000 0.5158 0.5365 rgb(0.5,0.5,0.5)
+...
+%%
+	      
+You can find the file version on first line, and then data.
+Next lines: vertex position (x,y,z), normal (x,y,z), texture mapping (u,v)
+and texture (string). 
+**/
+
+
+#define DONT_SAVE_DUMMY_TEXTURE
+extern void raydium_file_dirname(char *dest,char *from);
+/**
+Reliable and portable version of libc's ##dirname## function.
+This function extracts directory from ##from## filename, and writes it
+to ##dest##.
+No memory allocation will be done by the function.
+**/
+
+extern void raydium_file_log_fopen_display(void);
+/**
+Display (console) all filenames that were opened before the call.
+##--files## command line option will call this function at the application's
+exit, closed or not.
+**/
+
+extern FILE *raydium_file_fopen(char *file, char *mode);
+/**
+Raydium wrapper to libc's ##fopen## function.
+This function will:
+- Update some stats
+- Try to download the file from repositories if no local version is found, or
+will try to update the file if asked (##--repository-refresh## or 
+##repository-force##). See R3S on Raydium's Wiki.
+**/
+
+#ifdef PHP_SUPPORT
+extern int raydium_rayphp_repository_file_get(char *file);
+#else
+#define raydium_php_repository_file_get fopen
+#endif
+extern void dump_vertex_to (char *filename);
+/**
+This function save all scene to filename (.tri file) in version 1.
+Vertice may be sorted.
+Please, try to do not use this function.
+**/
+
+extern void dump_vertex_to_alpha (char *filename);
+/**
+Now useless and deprecated.
+**/
+
+extern int raydium_file_set_textures (char *name);
+/**
+Internal use.
+This function analyze texture filename, and search for extended multitexturing
+informations (u,v and another texture).
+**/
+
+extern void read_vertex_from (char *filename);
+/**
+Loads filename. Again, avoid use of this function.
+**/
+
+#endif
Index: raydium/headers/render.h
===================================================================
--- raydium/headers/render.h	(revision 0)
+++ raydium/headers/render.h	(revision 1)
@@ -0,0 +1,88 @@
+#ifndef _RENDER_H
+#define _RENDER_H
+/*=
+Rendering
+1300
+**/
+
+// Introduction
+/*=
+render.c contains Raydium rendering core, so only "public" and 
+interesting function will be documented.
+
+It' obvious for me that many parts of this code have to be 
+rewritten (tips: slow, buggy, old, ... :) 
+**/
+
+
+extern int  raydium_rendering_prepare_texture_unit (GLenum tu, GLuint tex);
+/**
+This function will "prepare" hardawre texture unit ##tu## to render ##tex## texture.
+There almost no reason to call this function by yourself.
+**/
+
+extern void raydium_rendering_internal_prepare_texture_render (GLuint tex);
+/**
+Same as above, but for texture unit #0 only.
+**/
+
+extern void raydium_rendering_internal_restore_render_state (void);
+/**
+Internal. Deprecated.
+**/
+
+// DO NOT DOCUMENT THIS ... THING !
+extern char infov (GLfloat x, GLfloat y);
+
+extern void raydium_rendering_from_to (GLuint from, GLuint to);
+/**
+Renders vertices from ##from## to ##to##.
+Using object management functions is a better idea.
+**/
+
+extern void raydium_rendering (void);
+/**
+Renders all vertices (probably useless, now).
+**/
+
+extern void raydium_rendering_finish (void);
+/**
+You must call this function at the end of each frame. This will flush all
+commands to hardware, fire a lot off callbacks, and prepare next frame.
+**/
+
+extern void raydium_rendering_wireframe (void);
+/**
+Switch to wireframe rendering.
+**/
+
+extern void raydium_rendering_normal (void);
+/**
+Switch back to standard rendering.
+**/
+
+extern void raydium_rendering_rgb_force (GLfloat r, GLfloat g, GLfloat b);
+/**
+Force all RGB colored vertices to take ##(r,g,b)## color. One example of this
+use is for making "team colored" cars : Do not apply textures to some faces
+while modelling, and force to team color each time you render a car.
+**/
+
+extern void raydium_rendering_rgb_normal (void);
+/**
+Disable "rgb force" state. See above.
+**/
+
+extern void raydium_rendering_displaylists_disable(void);
+/**
+Disable display lists usage.
+Some old video cards and broken drivers may get better performances WITHOUT
+display lists (on large objects, mainly).
+**/
+
+extern void raydium_rendering_displaylists_enable(void);
+/**
+Enable display lists usage. default state.
+**/
+
+#endif
Index: raydium/headers/random.h
===================================================================
--- raydium/headers/random.h	(revision 0)
+++ raydium/headers/random.h	(revision 1)
@@ -0,0 +1,52 @@
+#ifndef _RANDOM_H
+#define _RANDOM_H
+/*=
+Random
+400
+**/
+
+// Introduction
+/**
+These functions deals with random numbers generation.
+**/
+
+extern void raydium_random_randomize (void);
+/**
+This function initialize the random number generator 
+with current time for seed.
+**Note: ** You are not supposed to use this function.
+**/
+
+extern GLfloat raydium_random_pos_1 (void);
+/**
+"positive, to one": 0 <= res <= 1
+**/
+
+extern GLfloat raydium_random_neg_pos_1 (void);
+/**
+"negative and positive, one as absolute limit": -1 <= res <= 1
+**/
+
+extern GLfloat raydium_random_0_x (GLfloat i);
+/**
+"zero to x": 0 <= res <= x
+**/
+
+extern GLfloat raydium_random_f (GLfloat min, GLfloat max);
+/**
+min <= res <= max (float)
+**/
+
+extern int raydium_random_i (int min, int max);
+/**
+min <= res <= max (integer)
+**/
+
+extern char raydium_random_proba (GLfloat proba);
+/**
+Returns true or false (0 or 1) depending of "proba" factor.
+##proba## must be: 0 <= proba <=1
+ex: 50% = 0.5
+**/
+
+#endif
Index: raydium/headers/raydoc.php
===================================================================
--- raydium/headers/raydoc.php	(revision 0)
+++ raydium/headers/raydoc.php	(revision 1)
@@ -0,0 +1,256 @@
+#!/usr/bin/php
+<?
+
+// This script generates a Wiki(ni) style documentation from comments of
+// all header files of Raydium (raydium/header/*.h)
+
+$page="http://raydium.yoopla.org/wiki/RaydiumApiReference";
+
+$intro="
+======Raydium API Reference======
+
+=====CQFD Corp.=====
+
+This document is the most up-to-date version. **This is a work in progress**:
+only the core of Raydium is described here, and there's again some 
+errors and wrong informations. Try, wait, or contribute ;)
+
+\"\"<a href=$page#index>Index of all Raydium functions</a>\"\"
+
+----
+This document is autogenerated, any change will be lost,
+use RaydiumApiReferenceComments for any need.
+{DATE}, for Raydium **{VERSION}**
+----
+";
+
+
+
+function getTagLine($tag,$lines,$from=0)
+{
+for($i=$from;$i<count($lines);$i++)
+    {
+    $l=$lines[$i];
+    if(substr(trim($l),0,strlen($tag))==$tag)
+	return $i;
+    }
+return -1;
+}
+
+function getVersion()
+{
+$file="../main.c";
+$f=file($file);
+$l=getTagLine("char *raydium_version",$f);
+$v=explode('"',trim($f[$l]));
+return $v[1];
+}
+
+function getMain($filename,$offset)
+{
+$f=file($filename);
+$l=getTagLine("/*=",$f);
+if($l==-1)
+    return -1;
+$res=trim($f[$l+$offset]);
+return $res;
+}
+
+function getPriority($filename)
+{
+$res=trim(getMain($filename,2));
+if(is_numeric($res))
+    return $res;
+else
+    return -1;
+}
+
+function getTitle($filename)
+{
+return trim(getMain($filename,1));
+}
+
+
+
+function getHeaders($directory)
+{
+$res=array();
+if (is_dir($directory)) 
+    {
+	if ($dh = opendir($directory)) 
+	{
+	    while (($file = readdir($dh)) !== false) 
+	    {
+		if(substr($file,-2)==".h")
+		{
+		    $res[]=$file;
+		}
+	    }
+	closedir($dh);
+	}
+    }
+    else echo "'$directory' is not a directory";
+return $res;
+}
+
+
+function h1($str)
+{
+echo "\n=====$str:=====\n";
+}
+
+function h2($str)
+{
+echo "====$str:====\n";
+}
+
+function body($str)
+{
+echo $str."\n\n";
+}
+
+function intro($str)
+{
+$str=str_replace("{DATE}","Generated: ".date("Y-m-d H:i:s"),$str);
+$str=str_replace("{VERSION}",getVersion(),$str);
+echo $str;
+}
+
+$index=array();
+function addToIndex($f)
+{
+static $i=0;
+global $index;
+
+$p=strpos($f,"raydium_");
+if($p!==false)
+    $f=substr($f,$p);
+
+$index[$i]=$f."|$i";
+return $i++;
+}
+
+// Main
+
+$files=getHeaders(".");
+//var_dump($files);
+if($files==-1)
+    die("No header found");
+
+unset($sorted);
+for($i=0;$i<count($files);$i++)
+    {
+    $file=$files[$i];
+    $p=getPriority($file);
+    if($p==-1)
+	$p=999000+$i;
+	
+    while(isset($sorted[$p]))
+	$p++;
+    $sorted[$p]=$file;
+    }
+ksort($sorted);
+$sorted=array_values($sorted);
+//var_dump($sorted);
+
+// Files are sorted, now
+
+intro($intro);
+
+for($i=0;$i<count($sorted);$i++)
+    {
+    $file=$sorted[$i];
+    $title=getTitle($file);
+
+    if($title==-1) 
+	{
+	h1(($i+1)." no documentation for $file");
+	continue;
+	}
+    
+    h1(($i+1)." $title");
+    
+    $f=file($file);
+    $last=0;
+    $n=0;
+    while(($l=getTagLine("/**",$f,$last))!=-1)
+	{
+	$title=trim($f[$l-1]);
+	if($title=="")
+	    $title="// unknown item";
+	    
+	// types:
+	// 1 - Comment (//)
+	// 2 - Macro (#)
+	// 3 - Code (...)
+	$type=3;
+	if($title[0]=="/")
+	    {
+	    $type=1;
+	    $title=trim(substr($title,2));
+	    }
+
+	if($title[0]=="#")
+	    {
+	    $type=2;
+	    $pos=strpos($title,")");
+	    if($pos)
+		{
+		$title=substr($title,0,$pos+1);
+		}
+	    $title=trim(str_replace("#define ","",$title))." (macro)";
+	    
+	    }
+
+	if($type==3)
+	    {
+	    if(substr($title,0,7)=="extern ")
+		$title=trim(substr($title,7));
+	    if($title[strlen($title)-1]==";")
+		$title=substr($title,0,-1);
+	    $title=trim(str_replace("**","* *",$title));
+	    }
+	
+	if($type==2 || $type==3)
+	    $id=addToIndex($title);
+	
+	h2('""'."<a name=$id></a>".'""'.($i+1).".".($n+1)." $title");
+	
+	$last=$l+1;
+	$end=getTagLine("**/",$f,$last);
+	if($end==-1)
+	    die("expected '**/' (started line $l)");
+	
+	unset($body);
+/*	for($j=$l+1;$j<$end;$j++)
+	    {
+	    $lj=trim($f[$j]);
+	    if($lj=="") 
+		$lj="\n\n";
+	    else
+		$lj.=" ";
+	    $body[]=$lj;
+	    }
+	$str=implode("",$body);*/
+	for($j=$l+1;$j<$end;$j++)
+	    {
+	    $lj=trim($f[$j]);
+	    $body[]=$lj;
+	    }
+	$str=@implode("\n",$body);
+	body($str);
+	
+	$last=$end+1;
+	$n++;
+	}
+    }
+
+sort($index);
+h1('""<a name=index></a>""Index');
+for($i=0;$i<count($index);$i++)
+    {
+    $j=explode("|",$index[$i]);
+    $k=$j[0];
+    $l=$j[1];
+    echo '""'."<a href=$page#$l><tt>$k</tt></a>".'""'."\n";
+    }

Property changes on: raydium/headers/raydoc.php
___________________________________________________________________
Added: svn:executable
\ No newline at end of property
Index: raydium/headers/log.h
===================================================================
--- raydium/headers/log.h	(revision 0)
+++ raydium/headers/log.h	(revision 1)
@@ -0,0 +1,31 @@
+#ifndef _LOG_H
+#define _LOG_H
+
+/*=
+Logging
+300
+**/
+
+// Introduction to log.c
+/**
+Raydium uses and provides his own logging system, 
+hidden behind a single function, as shown below.
+**/
+
+#ifndef RAYDIUM_NETWORK_ONLY
+extern void raydium_console_line_add (char *format, ...);
+#endif
+extern void raydium_log (char *format, ...);
+/**
+This function must be used like "printf", using a format 
+("%s, %i, %x, ...") and then, suitable variables, 
+but without the end-line char ('\n')
+
+%%(c)
+raydium_log("You are player %i, %s",player_number,player_name);
+%%
+ 
+For now, this function writes to the parent terminal and the in-game console, with "Raydium: " string prefix.
+The user can force logging to a file, using ##--logfile## command line switch.
+**/
+#endif
Index: raydium/headers/main.h
===================================================================
--- raydium/headers/main.h	(revision 0)
+++ raydium/headers/main.h	(revision 1)
@@ -0,0 +1,363 @@
+#define		HEADER_MAIN
+#include	"../main.h"
+
+/*=
+Introduction to Raydium
+100
+**/
+
+// About
+/**
+Well, first of all, let me talk about [[Raydium]] goals: this project 
+aims to be simple, easy to use, portable, and quite fast.
+
+[[Raydium]] is a C written abstract layer, on top of OpenGL, 
+[[GLU]] and [[GLUT]]: this means you can write an entire 3D 
+application without calling any OpenGL function. 
+Want to draw an object ? call the suitable [[Raydium]] function, 
+and all textures and vertices will be loaded, and your object drawn.
+Want to make an explosion ? Same thing: call the right function.
+Note that you can call OpenGL functions anyway, if necessary.
+
+About portability, I can say a few things: [[Raydium]] was initially 
+planned for linux only, but with an "clean" (nearly [[ANSI]]) code,
+and, in facts, we have been able to compile Raydium under VC6 (Windows)
+and mingw with a very few modifications.
+So you can expect a correct result on any system providing 
+OpenGL (at least 1.2), [[GLU]], [[GLUT]] and a C compiler.
+
+As we ([[CQFD Corp]].) needed a library for our own games, demos,
+and... and things like that, and as I was interested by OpenGL,
+I starts to write [[Raydium]].
+
+Raydium is perfect for outdoors spaces, integrating a landscape engine,
+with suitable physic, supports dynamic lighting, fog, blending, water and
+waves, terraforming, and more.
+
+This features list will probably grow up during Raydium developpement.
+
+You'll find, in this document, a list of many functions and possibilities 
+of [[Raydium]].
+
+After this short introduction, let's talk about the [[API]] itself, 
+starting with the main file (from the programmer's point of vue) 
+of [[Raydium]]: common.c
+**/
+
+
+// Defines
+/**
+As mentioned above, the file common.c is quite interesting, 
+for several reasons: first, as this file includes all others [[Raydium]]'s
+files, you can have an overview of the whole project, just by looking at this.
+
+It can also be used as a "quick help", since all variables are declared 
+here, and not in the corresponding files. I mean, for example, 
+that "##raydium_light_intensity...##" will be declared in common.c, 
+not in light.c . There's many reasons for using such "style",
+but you must only retain that it is simpler for you :)
+
+Ok, after this little disclaimer, we can have a look to the first part
+of our file.
+
+After usual #include (nothing interesting here), we find some #defines.
+
+===generic limits===
+
+The first #define block determine limits of your application,
+and here you are the actual values for basic defines:
+%%(c)
+#define RAYDIUM_MAX_VERTICES 500000
+#define RAYDIUM_MAX_TEXTURES 256
+#define RAYDIUM_MAX_LIGHTS 8
+#define RAYDIUM_MAX_NAME_LEN 255
+#define RAYDIUM_MAX_OBJECTS 1024
+%%
+
+- As you may expect, ##MAX_VERTICES## defines the amount of memory you'll
+waste with vertex tables. These tables will contain all loaded objects, 
+then remember each time you draw something (object), 
+[[Raydium]] loads it (if not already done). Currently, there is no "delete"
+mechanism implemented (except by deleting all objects). 
+Let me give you a scale: with an Athlon XP1900+, [[GeForce]] 3, 
+actual [[Raydium]] devel. version 0.31, with around 100 000 vertices, 
+losts of options (sky, blending, 2 lights, 15 textures, ...), 
+Raydium renders ~ 45 FPS. Beyond this, a very correct object uses less
+than 10 000 vertices. So 500 000 vertices, the actual default, 
+is quite large. It's also important to talk about memory: Linux is 
+very efficient on this point, and allocates only "really used" memory. 
+Under Linux, with the above scene, Raydium used about 20 MB (data only), 
+instead of "much more" (~ 5x). I haven't made any test about this under 
+Windows, but we can expect worse results.
+ 
+- There's nothing really important to say about ##MAX_TEXTURES##,
+since that doesn't influence the amount of memory used. You are not 
+limited to 8 bits values, but 256 seems very comfortable (and you must
+pay attention to the capacities of your 3D hardware !)
+ 
+- The next define, ##MAX_LIGHTS## is very important: OpenGL, for now 
+(version 1.3 and lower), impose 8 lights at least, and all current 
+hardware doesn't manage more. If this situation is likely to evolve, 
+we will move this #define to a variable, and will ask hardware for its 
+capacities at initialization, but, for the moment, do not exceed 8.
+ 
+- Next, ##NAME_LEN##, limits the maximum length of strings (textures and 
+objects names) used by Raydium. Default value should be perfect. 
+(avoid higher values, since it could slow down name searches)
+ 
+- ##MAX_OBJECTS## use the same mechanism as ##MAX_TEXTURES##, and addition 
+with the fact that hardware is not concerned, it can be ignored. 
+     
+===Options and parameters===
+     
+This is the next part of our #define section, I will not explain these
+constants here, but in respective sections, so you'll have just you to
+remember they're declared here.
+**/     
+
+// Basic vars
+/**
+
+This section aims to describe each variable [[Raydium]] use, one by one. 
+Some (most ?) of them are used internaly only, but you could need to access 
+it. Moreover, you'll better understand how Raydium works by looking at 
+these variables.
+
+===Keyboard input===
+
+Following variables can be found:
+
+##raydium_key_last## will always contains the last key (normal or special) 
+pressed down. You'll find a explanation about normal and special keys above.
+
+##raydium_key[]## hosts all special keys state. Currently, you must use 
+[[GLUT]] define's (Raydium aliases will come soon), limited to
+following keys:
+
+- ##GLUT_KEY_F1## to ##GLUT_KEY_F12##
+- ##GLUT_KEY_LEFT##, ##GLUT_KEY_RIGHT##, ##GLUT_KEY_UP##, ##GLUT_KEY_DOWN##
+- ##GLUT_KEY_PAGE_UP##, ##GLUT_KEY_PAGE_DOWN##
+- ##GLUT_KEY_HOME##, ##GLUT_KEY_END##, ##GLUT_KEY_INSERT##
+    
+These are "special" keys: they have 2 states. released (0), 
+and pressed (non zero). It means you can do something
+(move an object, turn on a light) **UNTIL** user stops to press the key. 
+"Normal" keys have a different behavior: you can do something **IF** user 
+press a key (exit from application if ESC is pressed, for example).
+You'll have no information about key's release.
+    
+A normal key is sent through ##raydium_key_last##, a special one through 
+##raydium_key[]## AND ##raydium_key_last##.
+    
+You must see ##raydium_key_last## as an "event", fired when the user press 
+a key (ANY key: special or not). When a normal key is pressed, you'll get
+the ASCII value + 1000 assigned to ##raydium_key_last##. (1027 for "ESC", for 
+example)
+    
+Here is a method to use special keys: 
+%%(c) if(raydium_key[GLUT_KEY_UP]) move_car(); %%
+    
+Yes, it's easy. You can also use 
+%%(c) if(raydium_key_last""==""GLUT_KEY_UP) explose(); %%
+for example, if you need to carry out a specific action.
+    
+It's ok for you ? use ##raydium_key[]## to keep the car moving until 
+user release UP key, or use ##raydium_key_last## to explode the car 
+when the user tries to start it :)
+    
+===Mouse input===
+    
+Easy.
+    
+You can get actual mouse position on the window (relative to window's
+position on screen, I mean) with ##raydium_mouse_x## and ##raydium_mouse_y##
+(GLuint), starting at (0,0) for upper left 
+(Warning: some [[GLUT]] implementations can give mouse position even 
+when mouse is out of the window ! Check boundaries before using these values).
+    
+Raydium use: 1 for left button, 2 for right button, and 3 for 
+middle button (0 for none) with ##raydium_mouse_clic## for the last clic 
+value. (generated one time per clic)
+    
+You can permanently get a button's state, up (0) or down (non zero), 
+using ##raydium_mouse_button[x]##, where x is 0 for left button, 1 for right 
+one, and 2 for middle button.
+    
+===Textures===
+    
+##raydium_texture_index## and ##raydium_texture_current## (GLuint) are used
+internaly to determine repectively how many textures are loaded,
+wich is the current one.
+    
+The next variable, ##raydium_texture_filter##, is very important. You can
+assign ##RAYDIUM_TEXTURE_FILTER_NONE## (default), ##RAYDIUM_TEXTURE_FILTER_BILINEAR##
+or ##RAYDIUM_TEXTURE_FILTER_TRILINEAR## (recommended).
+    
+Using no texture filter can gives you higher framerate on old 3D hardware,
+but this is quite ugly.
+    
+You can activate bilinear filtering without any framerate impact on
+most recent video cards, and get a much more attractive rendering.
+    
+Trilinear filtering uses Bilinear filtering and MipMaps. A MipMaped
+texture is a duplicated texture (3 times, with Raydium), but at different 
+sizes. A 512x512 texture will generate, for example, a (smoothed) 
+256x256 texture, and a (smoothed) 128x128 one. Your video card will 
+use these textures according to distance from POV (point of vue),
+reducing flickering effect.
+    
+This is the best filtering Raydium can use, for a great rendering quality.
+Good and recent 3D hardware can do trilinear filtering in a single pass, 
+so it must be the default setting for your application.
+    
+About ##raydium_texture_filter## itself: changing this variable will not modify
+the rendering, but the way to load textures. It means you can (for example)
+use trilinear only for landscape textures, and bilinear for others.
+It also means you must reload (erase) a texture to change it's filter.
+    
+Note that Raydium will never use trilinear filter with blended (transparent)
+textures, for good reasons :)
+    
+Let's talk quickly about next (internal) texture variables:
+##raydium_texture_blended[]## is a flag table, where each element is
+non zero for a blended (RGBA) texture, and 0 for an RGB one.
+    
+For Raydium, when a texture does not contain a "bitmap" (texture file, 
+for example), it contains a plain color, and this color is stored in 
+##raydium_texture_rgb[][4]## (4 is for RGBA, values between 0 and 1).
+You can load an rgb texture with "rgb" keyword. For example, instead of 
+loading "red.tga", you can load "rgb(0.8,0.1,0.1)".
+    
+##raydium_texture_name[]## table simply contains texture filenames.
+    
+Last thing, ##raydium_texture_to_replace##,
+can be used to erase an already loaded texture. 
+Set the variable to n, and load a new texture: texture number "n" will be
+replaced in memory.
+    
+===Projection===
+    
+Raydium supports 2 types of projection: ##RAYDIUM_PROJECTION_ORTHO##
+(orthographic) and ##RAYDIUM_PROJECTION_PERSPECTIVE##.
+
+First of all, let us point out what "projection" is. Using a "perspective" 
+projection, closest objects will looks larger than the orthers. It is 
+typically used in video games (since human eye runs like that), 
+by opposition to orthographic projection, wich is mostly used by 3D 
+modeling tools. The principle is simple, discover it by yourself :)
+    
+Raydium reads ##raydium_projection## to determine wich method to use. 
+Each projection is configured with ##raydium_projection_*## variables. 
+Some of these variables are used both by "perspective" and "orthographic" 
+projections.
+    
+Here is what common.c says:
+    
+%%(c)
+GLFLOAT RAYDIUM_PROJECTION_FOV; // PERSPECTIVE ONLY
+GLFLOAT RAYDIUM_PROJECTION_NEAR; // PERSPECTIVE & ORTHO
+GLFLOAT RAYDIUM_PROJECTION_FAR; // PERSPECTIVE & ORTHO
+GLFLOAT RAYDIUM_PROJECTION_LEFT; // ORTHO ONLY
+GLFLOAT RAYDIUM_PROJECTION_RIGHT; // ORTHO ONLY
+GLFLOAT RAYDIUM_PROJECTION_BOTTOM; // ORTHO ONLY
+GLFLOAT RAYDIUM_PROJECTION_TOP; // ORTHO ONLY
+%%
+    
+You've probably noticed that orthographic projection defines a "box" 
+with your screen: near, far, left, right, bottom. Everything out ouf 
+this box will never be displayed.
+    
+Perspective projection is based on FOV: Field Of Vision, given in degrees. 
+"near" and "far" are used for many things: Z-Buffer precision is affected, 
+and clipping too: as with "orthographic", nothing will be displayed beyond 
+"far", and fog, if enabled, will hide this "limit". This is right for "near",
+too, but without fog, obviously :)
+    
+Also remember that decreasing FOV will zoom in.
+    
+You must call ##raydium_window_view_update()## after any modification on one
+(or more) of these variables (see "Window Managment" section for more
+information)
+    
+===Frame size and color===
+    
+##raydium_window_tx## and ##raydium_window_ty## are read-only variables,
+providing you actual frame size.
+    
+##raydium_background_color[4]## is a RGBA table, and will be used for
+frame clearing, and fog color. You can change this variable, and call 
+respective update functions (frame and fog), or simply use 
+##raydium_background_color_change(GLfloat r, GLfloat g, GLfloat b, GLfloat a)##.
+    
+More informations in corresponding sections.
+    
+===Vertices===
+    
+Vertices data structure is distributed in 4 parts:
+    
+- ##raydium_vertex_*## : these tables will simply contains vertices coordinates
+
+- ##raydium_vertex_normal_*## : vertices normals. Raydium will maintain 
+two distinct normal tables, and this one will be used for calculations.
+
+- ##raydium_vertex_normal_visu_*## : the other normal table, used for 
+lighting. Smoothing "visu" normals will provides a better rendering, and Raydium includes 
+all necessary functions to automate this task.
+
+- ##raydium_vertex_texture_u##, ##*raydium_vertex_texture_v##, 
+##*raydium_vertex_texture## contains, for each vertex stored 
+in the vertices data structure, u and v mapping information, 
+and associated texture number. U and V are texture mapping coordinates. 
+	
+Raydium can automatically generates some of these data 
+(normals and uv coords, that is), Read "Vertices" section above 
+for more information.
+	
+PLEASE, do not write directly in these tables, use dedicated functions.
+	
+===Objects===
+	
+Objects are loaded in Vertices stream, identified by a "start" and an "end" 
+(##raydium_object_start[]## and ##raydium_object_end[]##) in this stream.
+An index is incremented each time you load an object 
+(##GLuint raydium_object_index##). Filename is also stored in 
+##raydium_object_name[][]##. Go to "Objects" section to know more.
+	
+===Lights===
+	
+First of all, ##raydium_light_enabled_tag## contains 0 when light is
+disabled, non-zero otherwise. This is a read-only variable, so use 
+suitable functions.
+	
+Currently, for Raydium, a light can have 3 states: on, off, or blinking.
+##raydium_light_internal_state[]## stores this.
+	
+Next comes all light's features: position, color, intensity. You can 
+modify directly these variables, and call update fonctions, 
+if needed (not recommended).
+	
+Next, ##raydium_light_blink_*## are used internaly for blinking lights, 
+setting lowest, higher light intensity, and blinking speed. 
+Do noy modify these variables, use suitable functions.
+	
+You should read the chapter dedicated to lights for more information.
+	
+===Fog===
+	
+Only one variable, here: ##raydium_fog_enabled_tag##, switching from zero 
+to non zero if fog is enabled. Do NOT use this variable to enable or 
+disable fog, but suitable functions, this variable is just a tag.
+	
+===Camera===
+	
+Since many calls to camera functions are done during one frame,
+Raydium must track if any call to these functions was already done, 
+using ##raydium_frame_first_camera_pass## boolean.
+	
+##raydium_camera_pushed##, also used as a boolean, stores stack state. 
+When you place your camera in the scene with Raydium, it pushes matrix 
+on top of the stack, so you can modify it (the matrix), placing an object
+for example, an restore it quickly after, by popping matrix off.
+
+**/
Index: raydium/headers/gui.h
===================================================================
--- raydium/headers/gui.h	(revision 0)
+++ raydium/headers/gui.h	(revision 1)
@@ -0,0 +1,318 @@
+#ifndef _GUI_H
+#define _GUI_H
+
+#include "../gui.h"
+
+/*=
+Graphic User Interfaces
+3200
+**/
+
+// Introduction
+/**
+Raydium provides a support for simple GUI definitions thru a set of
+functions (RayPHP interface is available).
+Raydium's GUI are themable, using ".gui" theme text files. A default "full"
+theme is provided as "theme-raydium2.gui" (and suitable ".tga" file) on the 
+data repository.
+Complete informations about theme building are readable in this file.
+**/
+
+// Vocabulary
+/**
+This API will allow declaeation of:
+- "widgets" (label, button, edit box, track bar, check box, combo box)
+- "windows" (containers for widgets)
+
+"Focus" is supported for windows and widgets. The final user will not have
+any control on windows focus. "Tab" key is used for widget focus cycling.
+
+Widgets and windows are identified by a name or by a unique numeric id.
+**/
+
+
+// Building
+/**
+The idea is simple: build a window (position and size), and create
+widgets over this window.
+All widgets are created using the current sizes (x,y and font). See 
+suitable function).
+Buttons provides a simple callback, and all other widgets (but label)
+provides an unified "read" function. Window deletion is also possible.
+
+You must set current theme before any of this operations (see below).
+**/
+
+void raydium_gui_window_init(int window);
+/**
+Internal use. Will reset ##window##.
+**/
+
+void raydium_gui_init(void);
+/**
+Internal use. Will init all GUI API. Called once by Raydium.
+**/
+
+void raydium_gui_theme_init(void);
+/**
+Internal use. Will init theme.
+**/
+
+int raydium_gui_theme_load(char *filename);
+/**
+This function will load and set current theme (".gui" files). You must load
+a theme by yourself, since Raydium will never do it for you.
+This function must be called before GUI building.
+**/
+
+char raydium_gui_window_isvalid(int i);
+/**
+Mostly internal. Will check if ##i## window is valid.
+**/
+
+int raydium_gui_window_find(char *name);
+/**
+Will search ##name## window's numeric id.
+**/
+
+char raydium_gui_widget_isvalid(int i, int window);
+/**
+Mostly internal. Will check if ##i## widget of ##window## is valid.
+**/
+
+int raydium_gui_widget_find(char *name, int window);
+/**
+Will search ##name## widget numeric id (for ##window##).
+**/
+
+void raydium_gui_widget_next(void);
+/**
+Mostly internal. Cycle focus.
+**/
+
+void raydium_gui_widget_draw_internal(GLfloat *uv, GLfloat *xy);
+/**
+Internal use. Generic drawing function.
+**/
+
+void raydium_gui_button_draw(int w, int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_track_draw(int w, int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_label_draw(int w, int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_edit_draw(int w, int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_check_draw(int w, int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_combo_draw(int w, int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_window_draw(int window);
+/**
+Internal use.
+**/
+
+void raydium_gui_draw(void);
+/**
+Internal use. GUI drawing callback.
+**/
+
+int raydium_gui_button_read(int window, int widget, char *str);
+/**
+Internal use. Button read accessor (dummy).
+**/
+
+int raydium_gui_label_read(int window, int widget, char *str);
+/**
+Internal use. Label read accessor (dummy).
+**/
+
+int raydium_gui_track_read(int window, int widget, char *str);
+/**
+Internal use. Track read accessor.
+**/
+
+int raydium_gui_edit_read(int window, int widget, char *str);
+/**
+Internal use. Edit read accessor.
+**/
+
+int raydium_gui_check_read(int window, int widget, char *str);
+/**
+Internal use. Check read accessor.
+**/
+
+int raydium_gui_combo_read(int window, int widget, char *str);
+/**
+Internal use. Combo read accessor.
+**/
+
+void raydium_gui_show(void);
+/**
+Will show current built GUI.
+**/
+
+void raydium_gui_hide(void);
+/**
+Will hide current built GUI. This is the default state.
+**/
+
+char raydium_gui_isvisible(void);
+/**
+Will return current visibility of GUI.
+**/
+
+void raydium_gui_window_delete(int window);
+/**
+Will delete ##window##. No further access to widgets is possible.
+**/
+
+void raydium_gui_window_delete_name(char *window);
+/**
+Same as above, but using ##window##'s name.
+**/
+
+void raydium_gui_widget_sizes(GLfloat sizex, GLfloat sizey, GLfloat font_size);
+/**
+Each widget is created using 3 size: X size, Y size and font size. This
+function will allow you to set all sizes for a widget or a group of widget.
+Unit: percents (screen)
+**/
+
+int raydium_gui_window_create(char *name, GLfloat px, GLfloat py, GLfloat sizex, GLfloat sizey);
+/**
+Obviously, this function will create a new window. This window will take focus
+and overlap any previous window.
+##px## and ##py## for X and Y position on the screen, and ##sizex## and ##sizey##
+for sizes, obviously.
+Unit: percents (screen)
+**/
+
+int raydium_gui_internal_object_create(char *name, int window, char type, GLfloat px, GLfloat py, GLfloat sizex, GLfloat sizey, GLfloat font_size);
+/**
+Internal use.
+**/
+
+int raydium_gui_button_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, void *OnClick);
+/**
+This function will create a new button, with ##name## and with ##window## for
+parent. 
+You need to provide a ##caption## ("title") and a OnClick callback function.
+This callback must follow this prototype:
+%%(c)void btnButtonClick(raydium_gui_Object *w)%%
+You can find ##raydium_gui_Object## structure declaration in ##raydium/gui.h##,
+if needed.
+
+Unit for position (##px## and ##py##): percents (**window**)
+**/
+
+int raydium_gui_button_create_simple(char *name, int window,  GLfloat px, GLfloat py, char *caption);
+/**
+Same as above, but no OnClick callback function is asked. This type of button 
+is "readable" thru ##raydium_gui_button_clicked##.
+**/
+
+
+int raydium_gui_label_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, GLfloat r, GLfloat g, GLfloat b);
+/**
+This function will create a new label, with ##name## and with ##window## for
+parent. 
+You need to provide a ##caption## ("title") and an RGB color (0..1 interval)
+
+Unit for position (##px## and ##py##): percents (**window**)
+**/
+
+int raydium_gui_track_create(char *name, int window,  GLfloat px, GLfloat py, int min, int max, int current);
+/**
+This function will create a new trackbar, with ##name## and with ##window## for
+parent. 
+You need to provide a ##min## interger value, a ##max## and ##current## value.
+
+Unit for position (##px## and ##py##): percents (**window**)
+**/
+
+int raydium_gui_edit_create(char *name, int window,  GLfloat px, GLfloat py, char *default_text);
+/**
+This function will create a new edit box, with ##name## and with ##window## 
+for parent. 
+You may provide a default text (or an empty string), if needed. Unless all
+others Raydium's data, max string length is ##RAYDIUM_GUI_DATASIZE## and
+not ##RAYDIUM_MAX_NAME_LEN##, since this component may handle bigger strings.
+See ##raydium/gui.h## for more informations.
+
+Unit for position (##px## and ##py##): percents (**window**)
+**/
+
+int raydium_gui_check_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, char checked);
+/**
+This function will create a new check box, with ##name## and with ##window## 
+for parent. 
+You need to provide a ##caption## ("title") and a boolean state (checked or not).
+
+Unit for position (##px## and ##py##): percents (**window**)
+**/
+
+int raydium_gui_combo_create(char *name, int window,  GLfloat px, GLfloat py, char *items, int current);
+/**
+This function will create a new edit box, with ##name## and with ##window## 
+for parent. 
+##items## is a string, using '\n' as a separator. It's allowed to create an
+empty item.
+##current## is the default selected item in ##items##. (first = 0)
+Unless all others Raydium's data, max string length is ##RAYDIUM_GUI_DATASIZE## 
+and not ##RAYDIUM_MAX_NAME_LEN##, since this component may handle bigger
+strings. See ##raydium/gui.h## for more informations.
+
+Unit for position (##px## and ##py##): percents (**window**)
+**/
+
+int raydium_gui_read(int window, int widget, char *str);
+/**
+Use this function to get ##widget##'s state (for ##window##).
+This function will always return this information thru two variable:
+an integer (returned value) and a string (##str##).
+This information is specific to ##widget##'s type (checked or not for a
+checkbox, current choice for a combo, current string for an edit box, ...)
+Please, note ##str## must be allocated before function call. This is also
+the case for PHP scripts :
+%%(php)
+$str=str_pad("",256); // "pre-alloc"
+$val=raydium_gui_read_name("main","track",$str);
+echo "value=$val, string='$str'";
+%%
+**/
+
+int raydium_gui_read_name(char *window, char *widget, char *str);
+/**
+Same as above, but ##window## and ##widget## are resolved thru names, and
+not numeric id.
+**/
+
+int raydium_gui_button_clicked(void);
+/**
+This function will return the id of the last clicked button,
+or -1 if none were clicked.
+The id is built like this : ##window * 1000 + widget_id##
+Usefull for PHP scripts, since it's not possible to create callback for
+buttons with RayPHP.
+**/
+
+#endif
Index: raydium/headers/osd.h
===================================================================
--- raydium/headers/osd.h	(revision 0)
+++ raydium/headers/osd.h	(revision 1)
@@ -0,0 +1,205 @@
+#ifndef _OSD_H
+#define _OSD_H
+/*=
+OSD (On Screen Display)
+2900
+**/
+
+// Introduction
+/**
+Raydium provides some high level function for "On Screen Display", 
+as string drawing (2D and 3D), application's logo, mouse cursor, and other
+various 2D displaying tools.
+
+In most cases, these functions must be called after any other object
+drawing function, to avoid overlapping problems.
+
+Most functions will use a percentage system, and origin is at lower-left corner.
+**/
+
+
+extern void raydium_osd_color_change (GLfloat r, GLfloat g, GLfloat b);
+/**
+This function will change the font color for the next ##raydium_osd_printf*## 
+calls.
+As usual: 0 <= (##r##,##g## and ##b##) <= 1.
+**/
+
+extern void raydium_osd_alpha_change (GLfloat a);
+/**
+Same as above, but will change font transparency.
+**/
+
+extern void raydium_osd_color_rgba (GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+/**
+This is a mix of ##raydium_osd_color_change## and ##raydium_osd_alpha_change##.
+**/
+
+extern void raydium_osd_color_ega (char hexa);
+/**
+This function will change font color with the corresponding 
+##hexa##decimal code (as a char: '0' to 'F') in the standard EGA palette.
+
+Here is this palette:
+""
+<div class="table" align="center">
+<table class="tableListing" summary=" " cellspacing="0" cellpadding="3" border="1">
+<tr class="wiki"><td class="wiki"> <b>Hexa</b> </td><td class="wiki"> <b>Color</b> </td></tr>
+<tr class="wiki"><td class="wiki"> 0 </td><td class="wiki"> Black </td></tr>
+<tr class="wiki"><td class="wiki"> 1 </td><td class="wiki"> Blue </td></tr>
+<tr class="wiki"><td class="wiki"> 2 </td><td class="wiki"> Green </td></tr>
+<tr class="wiki"><td class="wiki"> 3 </td><td class="wiki"> Cyan </td></tr>
+<tr class="wiki"><td class="wiki"> 4 </td><td class="wiki"> Red </td></tr>
+<tr class="wiki"><td class="wiki"> 5 </td><td class="wiki"> Purple </td></tr>
+<tr class="wiki"><td class="wiki"> 6 </td><td class="wiki"> Brown </td></tr>
+<tr class="wiki"><td class="wiki"> 7 </td><td class="wiki"> White </td></tr>
+<tr class="wiki"><td class="wiki"> 8 </td><td class="wiki"> Grey </td></tr>
+<tr class="wiki"><td class="wiki"> 9 </td><td class="wiki"> Light Blue </td></tr>
+<tr class="wiki"><td class="wiki"> A </td><td class="wiki"> Light Green </td></tr>
+<tr class="wiki"><td class="wiki"> B </td><td class="wiki"> Light Cyan </td></tr>
+<tr class="wiki"><td class="wiki"> C </td><td class="wiki"> Light Red </td></tr>
+<tr class="wiki"><td class="wiki"> D </td><td class="wiki"> Light Purple </td></tr>
+<tr class="wiki"><td class="wiki"> E </td><td class="wiki"> Light Yellow </td></tr>
+<tr class="wiki"><td class="wiki"> F </td><td class="wiki"> Light White </td></tr>
+</table>
+</div>
+""
+**/
+
+extern void raydium_osd_start (void);
+/**
+Mostly for internal uses. (will configure screen for OSD operations)
+**/
+
+extern void raydium_osd_stop (void);
+/**
+Mostly for internal uses. (see above)
+**/
+
+extern void raydium_osd_draw (int tex, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+/**
+Will draw ##tex## texture using (##x1##,##y1##) and (##x2##,##y2##) points.
+**/
+
+extern void raydium_osd_draw_name (char *tex, GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2);
+/**
+Same as above, but using texture filename.
+**/
+
+extern void raydium_osd_printf (GLfloat x, GLfloat y, GLfloat size, GLfloat spacer, char *texture, unsigned char *format, ...);
+/**
+This function is an OpenGL equivalent to the standard "printf" C function.
+
+- (##x##,##y##) is the position of the text's beginning, as a screen 
+percentage, with origin at lower left.
+
+- ##size## is the font size, using an arbitrary unit. This size is always 
+proportionnal to frame size (font size will grow up with screen size,
+in other words).
+
+- ##spacer## is the factor of spacing between 2 consecutive letters. With 
+standard fonts, 0.5 is a correct value (relatively condensed text).
+
+- ##texture## is obviously the texture filename to use (font*.tga are 
+often provided with Raydium distribution, and by R3S).
+
+- ##format## is the standard printf format string, followed by 
+corresponding arguments: ##"^9Player ^Fname is: %10s", player_name##
+This format can use '^' char to change color text, followed by a color, 
+indicated by a hexadecimal letter (EGA palette). See ##raydium_osd_color_ega##
+function, above.
+
+Here you are a simple example:
+
+%%(c)
+strcpy(version,"^Ctest 0.1^F");
+raydium_osd_printf(2,98,16,0.5,"font2.tga","- %3i FPS - tech demo %s for Raydium %s, CQFD Corp.",
+                   raydium_render_fps,version,raydium_version);
+%%
+**/
+
+extern void raydium_osd_printf_3D (GLfloat x, GLfloat y, GLfloat z, GLfloat size, GLfloat spacer, char *texture, unsigned char *format, ...);
+/**
+Same as above, but you can place your text in your application 3D space, 
+using ##x##, ##y## and ##z## values.
+**/
+
+extern void raydium_osd_logo (char *texture);
+/**
+Will draw a logo for the current frame with texture filename.
+For now, you've no control over rotation speed of the logo.
+**/
+
+extern void raydium_osd_cursor_set (char *texture, GLfloat xsize, GLfloat ysize);
+/**
+This function will set mouse cursor with texture filename and 
+with (##xsize##,##ysize##) size (percent of screen size).
+You should use a RGB**A** texture for better results.
+example:
+%%(c)
+raydium_osd_cursor_set("BOXcursor.tga",4,4);
+%%
+**/
+
+extern void raydium_osd_cursor_draw (void);
+/**
+Internal use.
+**/
+
+extern void raydium_osd_internal_vertex (GLfloat x, GLfloat y, GLfloat top);
+/**
+Internal use.
+**/
+
+extern void raydium_osd_network_stat_draw (GLfloat px, GLfloat py, GLfloat size);
+/**
+Will draw network stats (if available) in a box.
+%%(c) raydium_osd_network_stat_draw(5,30,20); %%
+**/
+
+extern void raydium_osd_mask (GLfloat * color4);
+/**
+Will draw a uniform mask using ##color4## (RGBA color) for this frame.
+**/
+
+extern void raydium_osd_fade_callback (void);
+/**
+Internal use.
+**/
+
+extern void raydium_osd_fade_init (void);
+/**
+Internal use.
+**/
+
+extern void raydium_osd_fade_from (GLfloat * from4, GLfloat * to4, GLfloat time_len, void *OnFadeEnd);
+/**
+This function will configure a fading mask from ##from4## color to ##to4##.
+This fade will last ##time_len## seconds, and will call ##OnFadeEnd## callback
+when finished.
+This callback signature must be ##void callback(void)##.
+
+A standard fade-to-black-and-restore example:
+%%(c)
+// back to normal rendering
+void restorefade(void)
+{
+   GLfloat from[4]={0,0,0,2};
+   GLfloat to[4]={0,0,0,0};
+   raydium_osd_fade_from(from,to,1,NULL);
+   // do things (like moving camera to another place, for example).
+}
+				
+...
+
+// If space key : fade to black
+if(raydium_key_last==1032)
+    {
+    GLfloat from[4]={0,0,0,0};
+    GLfloat to[4]={0,0,0,1};
+    raydium_osd_fade_from(from,to,0.3,restorefade);
+    }
+%%				 
+**/
+
+#endif
Index: raydium/headers/particle2.h
===================================================================
--- raydium/headers/particle2.h	(revision 0)
+++ raydium/headers/particle2.h	(revision 1)
@@ -0,0 +1,183 @@
+#ifndef _PARTICLE__H
+#define _PARTICLE__H
+#include "../particle2.h"
+
+/*=
+Particle engine
+1400
+**/
+
+// Introduction
+/**
+This is the second version of Raydium's particle engine. This engine is build
+on top of a dedicated file format (.prt and .sprt files), describing most 
+(up to all, in facts) properties of generators.
+It probably better to start by an example (fountain.prt) :
+%%(c)
+// Simple blue fountain (change 'vector' if needed)
+ttl_generator=5;
+ttl_particles=1.5;
+ttl_particles_random=0;
+
+particles_per_second=200;
+
+texture="flare_nb.tga";
+
+size=0.1;
+size_inc_per_sec=0.1;
+
+gravity={0,0,-5};
+vector={0,0,4};
+vector_random={0.2,0.2,0.2};
+
+// RGBA
+color_start={0.6,0.6,1,0.5};
+color_start_random={0,0,0.2,0};
+color_end={1,1,1,0.1};
+
+// end of file.
+%%
+
+.prt files are readed using parsing functions (see appropriate chapter, if
+needed), and the list of all available properties can be found in particle2.c
+source file. A full toturial is also available on Raydium's Wiki.
+
+Once the particle file is written, you only need to load the file using the
+suitable function (see below). Some anchor are available to link generators to
+physic entities, if needed, as callbacks for a few events (one, for now).
+
+.sprt files are used to create a "snapshot" of particles, used for example by
+3D captures, and are not meant to be edited by hand.
+**/
+
+extern void raydium_particle_name_auto (char *prefix, char *dest);
+/**
+Will generate a unique string using ##prefix##. The string is created using
+space provided by ##dest##.
+You can use this function when building a new generator.
+**/
+
+extern void raydium_particle_init (void);
+/**
+Internal use.
+**/
+
+extern char raydium_particle_generator_isvalid (int g);
+/**
+Internal use, but you can call this function if you want to verify if a
+generator's id is valid (in bounds, and loaded).
+**/
+
+extern int raydium_particle_generator_find (char *name);
+/**
+Lookups a generator using is name. Returns -1 if ##name## is not found.
+**/
+
+extern int raydium_particle_find_free (void);
+/**
+Finds a free **particle** slot.
+**/
+
+extern void raydium_particle_generator_delete (int gen);
+/**
+Deletes a generator.
+**/
+
+extern void raydium_particle_generator_delete_name (char *gen);
+/**
+Same as above, but using generator's name.
+**/
+
+extern void raydium_particle_generator_enable (int gen, char enabled);
+/**
+Activate a disabled generator (see below).
+**/
+
+extern void raydium_particle_generator_enable_name (char *gen, char enable);
+/**
+Disable a generator (TTL is still decremented).
+**/
+
+extern void raydium_particle_preload (char *filename);
+/**
+Loads .prt file and associated textures into suitable caches.
+Call this function if you want to avoid (small) jerks caused by "live"
+loading a generator.
+**/
+
+extern void raydium_particle_generator_load_internal (int generator, FILE * fp, char *filename);
+/**
+Internal use.
+**/
+
+extern int raydium_particle_generator_load (char *filename, char *name);
+/**
+Loads generator from ##filename## as ##name##. This ##name## will be used for
+future references to this generator, as the returned interger id.
+**/
+
+extern void raydium_particle_generator_update (int g, GLfloat step);
+/**
+Internal use.
+**/
+
+extern void raydium_particle_update (int part, GLfloat step);
+/**
+Internal use.
+**/
+
+extern void raydium_particle_callback (void);
+/**
+Internal use.
+**/
+
+extern int raydium_particle_state_dump(char *filename);
+/**
+Dumped current particles to ##filename## (.sprt [static particles]).
+**/
+
+extern int raydium_particle_state_restore(char *filename);
+/**
+Append .sprt ##filename## to current scene.
+**/
+
+extern void raydium_particle_draw (raydium_particle_Particle * p, GLfloat ux, GLfloat uy, GLfloat uz, GLfloat rx, GLfloat ry, GLfloat rz);
+/**
+Internal use.
+**/
+
+extern void raydium_particle_draw_all (void);
+/**
+Internal use.
+**/
+
+extern void raydium_particle_generator_move (int gen, GLfloat * pos);
+/**
+Moves ##gen## generator to ##pos## position (3 * GLfloat array).
+**/
+
+extern void raydium_particle_generator_move_name (char *gen, GLfloat * pos);
+/**
+Same as above, but using generator's name.
+**/
+
+extern void raydium_particle_generator_move_name_3f (char *gen, GLfloat x, GLfloat y, GLfloat z);
+/**
+Same as above, using 3 different GLfloat values.
+**/
+
+extern void raydium_particle_generator_particles_OnDelete (int gen, void *OnDelete);
+/**
+Sets a callback for ##gen##, fired when any particle of this generator is
+deleted, providing a easy way to create "cascading" generators.
+The callback must respect the following prototype:
+%%(c) void cb(raydium_particle_Particle *) %%
+Do not free the provided particle.
+**/
+
+extern void raydium_particle_generator_particles_OnDelete_name (char *gen, void *OnDelete);
+/**
+Same as above, but using generator's name.
+**/
+
+#endif
Index: raydium/headers/clear.h
===================================================================
--- raydium/headers/clear.h	(revision 0)
+++ raydium/headers/clear.h	(revision 1)
@@ -0,0 +1,17 @@
+#ifndef _CLEAR_H
+#define _CLEAR_H
+/*=
+Frame clearing
+801
+**/
+
+extern void raydium_clear_frame (void);
+/**
+You need to call this function every frame to clear all hardware buffers.
+**/
+
+extern void raydium_clear_color_update (void);
+/**
+Will apply background color modification. Probably useless for you.
+**/
+#endif
Index: raydium/headers/normal.h
===================================================================
--- raydium/headers/normal.h	(revision 0)
+++ raydium/headers/normal.h	(revision 1)
@@ -0,0 +1,40 @@
+#ifndef _NORMAL_H
+#define _NORMAL_H
+
+/*=
+Normals
+1600
+**/
+
+// Introduction
+/**
+This file provides some usefull functions for normal generation and smoothing.
+You can find some more informations about normals at the top of this guide. 
+**/
+
+
+extern void raydium_normal_generate_lastest_triangle (int default_visu);
+/**
+Generate normal for the last created triangle (see ##raydium_vertex_index##)
+if ##default_visu## is true ( != 0 ), this function will restore "visu" 
+normals too.
+**/
+
+extern void raydium_normal_restore_all (void);
+/**
+This function restore visu normals with standard ones (##raydium_vertex_normal_*##)
+**/
+
+extern void raydium_normal_regenerate_all (void);
+/**
+This function will regenerate standard and visu normals for the whole 
+scene (ground, objects, ...).
+**/
+
+extern void raydium_normal_smooth_all (void);
+/**
+This function will smooth the whole scene, using adjacent vertices.
+Note this function can take a lot of time.
+**/
+
+#endif
Index: raydium/headers/camera.h
===================================================================
--- raydium/headers/camera.h	(revision 0)
+++ raydium/headers/camera.h	(revision 1)
@@ -0,0 +1,173 @@
+#ifndef _CAMERA_H
+#define _CAMERA_H
+
+/*=
+Camera
+2200
+**/
+
+// Introduction
+/**
+Raydium provides camera management functions, allowing the coder to
+move camera with very simple functions, even for complex moves.
+You have to place your camera once per frame (not more, not less).
+
+"look_at" style functions can be affected by ##raydium_camera_look_at_roll##
+global variable, if needed.
+
+A few words about camera path: Take a look to a .cam file if you want to
+understand this simple file format, but you probably only need the ##cam.c##
+application, dedicated to camera path creation.
+
+Some camera functions are provided by physics module, see suitable chapter.
+**/
+
+
+extern void raydium_camera_vectors (GLfloat * res3);
+/**
+This function will return two vectors (2 * 3 * GLfloat), giving the camera 
+orientation (front vector and up vector). At this day, the up vector is 
+always the same as the world up vector, even if the camera is rotated 
+or upside down (and yes, this MUST be corrected :).
+
+Designed for internal uses, before all.
+**/
+
+extern void raydium_camera_internal_prepare(void);
+/**
+Internal use. (pre)
+**/
+
+extern void raydium_camera_internal (GLfloat x, GLfloat y, GLfloat z);
+/**
+Internal use. (post)
+**/
+
+extern void raydium_camera_place (GLfloat x, GLfloat y, GLfloat z, GLfloat lacet, GLfloat tangage, GLfloat roulis);
+/**
+Sets the camera at (x,y,z) position, and using (lacet,tangage,roulis) 
+as rotation angles.
+**/
+
+extern void raydium_camera_look_at (GLfloat x, GLfloat y, GLfloat z, GLfloat x_to, GLfloat y_to, GLfloat z_to);
+/**
+Sets the camera at (x,y,z) position, and looks at (x_to,y_to,z_to).
+**/
+
+extern void raydium_camera_replace (void);
+/**
+You'll need to reset camera position and orientation after each object drawing.
+If this is unclear to you, read the "example" section, below.
+
+You will need to make your own 3D transformations (GLRotate, GLTranslate, 
+...) to draw your objects, or you can use the following function.
+**/
+
+extern void raydium_camera_replace_go (GLfloat * pos, GLfloat * R);
+/**
+This function will replace the camera, as ##raydium_camera_replace()##,
+but will place "3D drawing cursor" at position ##pos## (3 GLfloat) with 
+rotation ##R## (4 GLfloat quaternion).
+
+No eulers (rotx, roty, rotz) version of this function is provided for now.. 
+Do you really need it ?
+**/
+
+// Example of camera use
+/**
+1. place camera
+2. move "drawing cursor" to object's place
+3. draw object
+4. reset camera to initial place (the one given at step 1)
+5. move "drawing cursor" to another object's place
+6. draw another object
+7. [...]
+
+Steps 4 and 5 can be done with raydium_camera_replace_go().
+**/
+
+void raydium_camera_rumble(GLfloat amplitude, GLfloat ampl_evo, GLfloat secs);
+/**
+Camera (any type) will rumble for ##secs## seconds, with ##amplitude## (radians).
+This ##amplitude## will be incremented of ##ampl_evo## every second (negative
+values are allowed).
+An ##amplitude## is always positive.
+**/
+
+extern void raydium_camera_smooth (GLfloat px, GLfloat py, GLfloat pz, GLfloat lx, GLfloat ly, GLfloat lz, GLfloat zoom, GLfloat roll, GLfloat step);
+/**
+Smooth style clone of ##raydium_camera_look_at##.
+Roll is given by ##roll## and not global variable ##raydium_camera_look_at_roll##
+as for regular look_at function.
+##zoom## is the requested FOV.
+Play with step to modify smoothing level of the movement. A good way to use
+this function is the following usage :
+%%(c) raydium_camera_smooth(cam[0],cam[1],cam[2],pos[1],-pos[2],pos[0],70,0,raydium_frame_time*3); %%
+**/
+
+extern void raydium_camera_path_init (int p);
+/**
+Internal use.
+**/
+
+extern void raydium_camera_path_init_all (void);
+/**
+Internal use.
+**/
+
+extern int raydium_camera_path_find (char *name);
+/**
+Lookups path's id using filename ##name##.
+This function will not try to load a camera path if it's not found, and
+will return -1.
+**/
+
+extern int raydium_camera_path_load (char *filename);
+/**
+Obvious : use this function to load a camera path.
+**/
+
+extern void raydium_camera_path_draw (int p);
+/**
+Draws ##p## camera path, as red lines. This must be done at each frame. 
+**/
+
+extern void raydium_camera_path_draw_name (char *path);
+/**
+Same as above, but using camera path's name.
+**/
+
+extern char raydium_camera_smooth_path (char *path, GLfloat step, GLfloat * x, GLfloat * y, GLfloat * z, GLfloat * zoom, GLfloat * roll);
+/**
+Returns the (##x,y,z##) point of the camera path for step ##step##, using
+provided ##zoom## (FOV) and ##roll## angle.
+It's important to note that ##step## is a float.
+Mostly for internal use.
+**/
+
+extern void raydium_camera_path_reset(void);
+/**
+Next smooth call will be instantaneous.
+**/
+
+extern void raydium_camera_smooth_path_to_pos (char *path, GLfloat lx, GLfloat ly, GLfloat lz, GLfloat path_step, GLfloat smooth_step);
+/**
+"Camera on path looking to a point"
+simple ##raydium_camera_smooth## version:
+Give a path name, a "look_at" point (##lx,ly,lz##), a current ##step##, and
+a ##smooth_step## time factor (see ##raydium_camera_smooth## example above).
+**/
+
+extern void raydium_camera_smooth_pos_to_path (GLfloat lx, GLfloat ly, GLfloat lz, char *path, GLfloat path_step, GLfloat smooth_step);
+/**
+"Camera on point looking at a path"
+Same style as previous function.
+**/
+
+extern void raydium_camera_smooth_path_to_path (char *path_from, GLfloat path_step_from, char *path_to, GLfloat path_step_to, GLfloat smooth_step);
+/**
+"Camera on a path looking at another path"
+Same style as previous functions.
+**/
+
+#endif
Index: raydium/headers/key.h
===================================================================
--- raydium/headers/key.h	(revision 0)
+++ raydium/headers/key.h	(revision 1)
@@ -0,0 +1,36 @@
+#ifndef _KEY_H
+#define _KEY_H
+/*=
+Keyboard & keys
+1000
+**/
+
+// Introduction
+/*=
+Keyboard API is already described at the top of this guide,
+see section "keyboard input".
+**/
+
+extern void raydium_key_normal_callback (GLuint key, int x, int y);
+/**
+Internal callback.
+**/
+
+extern void raydium_key_special_callback (GLuint key, int x, int y);
+/**
+Internal callback.
+**/
+
+extern void raydium_key_special_up_callback (GLuint key, int x, int y);
+/**
+Internal callback.
+**/
+
+extern int raydium_key_pressed (GLuint key);
+/**
+Will return state of ##key## in the ##raydium_keys[]## array.
+This function is usefull to test keyboard from PHP, since RayPHP doest not
+support array for now.
+**/
+
+#endif
Index: raydium/headers/mouse.h
===================================================================
--- raydium/headers/mouse.h	(revision 0)
+++ raydium/headers/mouse.h	(revision 1)
@@ -0,0 +1,58 @@
+#ifndef _MOUSE_H
+#define _MOUSE_H
+/*=
+Mouse
+1100
+**/
+
+// Introduction
+/**
+Mouse API is almost explainded at the top of this guide, but here it 
+is some other usefull functions (macros, in facts)
+**/
+
+
+#define raydium_mouse_hide() glutSetCursor(GLUT_CURSOR_NONE);
+/**
+Hides mouse cursor.
+**/
+
+#define raydium_mouse_show() glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
+/**
+Shows mouse cursor.
+**/
+
+#define raydium_mouse_move(x,y) glutWarpPointer((x),(y))
+/**
+Moves cursor to (##x##,##y##) position (in pixel).
+Example if you want to move cursor at window's center: 
+%%(c)raydium_mouse_move(raydium_window_tx/2, raydium_window_ty/2);%%
+**/
+
+char raydium_mouse_isvisible(void);
+/**
+Returns true or false (0 or 1), if the mouse is visible or not.
+See ##raydium_mouse_show()## and ##raydium_mouse_hide()## above.
+**/
+
+extern void raydium_mouse_init (void);
+/**
+Internal use.
+**/
+
+extern void raydium_mouse_click_callback (int but, int state, int x, int y);
+/**
+Internal callback.
+**/
+
+extern void raydium_mouse_move_callback (int x, int y);
+/**
+Internal callback.
+**/
+
+extern int raydium_mouse_button_pressed (int button);
+/**
+returns ##button## state. (See first part of this document)
+**/
+
+#endif
Index: raydium/headers/misc.h
===================================================================
--- raydium/headers/misc.h	(revision 0)
+++ raydium/headers/misc.h	(revision 1)
@@ -0,0 +1,63 @@
+// This file is a footer for Raydium documention
+// No compilation is required.
+
+/*=
+Miscalleneous
+9000
+**/
+
+// License
+/**
+Raydium engine and provided applications are released under GPL version 2. 
+You can found the original text of this license here : 
+http://www.gnu.org/licenses/gpl.txt
+**/
+
+// About CQFD Corp Raydium Team
+/**
+Alphabetical order:
+batcox, Blue Prawn, Cocorobix, FlexH, Jimbo, manproc, Mildred, neub, RyLe,
+whisky, willou, Xfennec, Yoltie
+**/
+
+// Todo
+/**
+No particular order:
+- rendering core rewrite
+- self-running demo
+- (idea from RyLe) 'rayphp/' scripts integration into the binary (and why 
+not, a "PACK style" support).
+- more network stack optimisations ?
+- more and more and even more ODE features
+- doc for new features (physics, network, scripting, ...)
+- (idea from FlexH) ./configure.sh type script for dependencies check 
+and auto-configuration
+- better organisation of comp.sh and ocomp.sh files (separate options 
+and build process)
+
+Please, if you start working on a feature, remove it from the list (and 
+restore it if you failed)
+**/
+
+// Links
+/**
+http://raydium.cqfd-corp.org (Raydium home)
+http://wvs.cqfd-corp.org (Web Version System: public mini CVS like for Raydium)
+http://memak.cqfd-corp.org (MeMak forum: "a game using Raydium", french)
+http://www.cqfd-corp.org (CQFD homesite)
+mailto:cqfd@cqfd-corp.org
+mailto:xfennec@cqfd-corp.org
+**/
+
+// Greets
+/**
+**RyLe**: original implementation of sound.c (OpenAL core sound API)
+
+**BatcoX**: export of RayODE functions into RayPHP (reg_api.c) 
+and additional PHP wrappers (wrappers.c)
+
+**Mildred**: header and Makefile generator, dynamic version of 
+Raydium (.so and .a) for Linux.
+**/
+
+// The end !
Index: raydium/headers/callback.h
===================================================================
--- raydium/headers/callback.h	(revision 0)
+++ raydium/headers/callback.h	(revision 1)
@@ -0,0 +1,34 @@
+#ifndef _CALLBACK_H
+#define _CALLBACK_H
+
+/*=
+Callbacks
+1500
+**/
+
+// Introduction
+/**
+This file contains many initializations, a few internal callbacks, but 
+will provides a very important function for end-user, wich will 
+gives user display function to Raydium: see below
+**/
+
+
+extern void raydium_callback_image (void);
+/**
+Internal use.
+**/
+
+extern void raydium_callback_set (void);
+/**
+Internal use.
+**/
+
+extern void raydium_callback (void (*loop));
+/**
+This function will loop over the provided display function, indefinitely.
+"loop" must be: 
+%%(c) void loop(void) %%
+**/
+
+#endif
Index: raydium/headers/parser.h
===================================================================
--- raydium/headers/parser.h	(revision 0)
+++ raydium/headers/parser.h	(revision 1)
@@ -0,0 +1,94 @@
+#ifndef _PARSER_H
+#define _PARSER_H
+
+/*=
+Text file parsing
+3700
+**/
+
+// Introduction
+/**
+Raydium provides a set of functions dedicated to text files parsing. These
+files must follow a simple syntax:
+%%(c)
+// strings
+variable_s="string value";
+
+// float (or integer, i.e.)
+variable_f=10.5;
+
+// float array
+variable_a={1,2,10.5,};
+
+// raw data
+variable_r=[
+xxxxxxxx
+#  oo  #
+#      #
+#  oo  #
+xxxxxxxx
+];
+%%
+Semi-colon are purely esthetic.
+**/
+
+extern void raydium_parser_trim (char *org);
+/**
+Strip whitespace (or other characters) from the beginning and end of a string.
+So far, ' ', '\n' and ';' are deleted.
+**/
+
+extern char raydium_parser_isdata (char *str);
+/**
+Returns true (1) if ##str## contains data, false (0) otherwise (comments and
+blank lines).
+**/
+
+extern char raydium_parser_cut (char *str, char *part1, char *part2, char separator);
+/**
+This function will cut ##str## in two parts (##part1## and ##part2##) on
+##separator##. No memory allocation will be done by this functions.
+First occurence of ##separator## is used (left cut).
+Return true (1) if ##str## was cut.
+**/
+
+extern void raydium_parser_replace (char *str, char what, char with);
+/**
+Will replace all occurence of ##what## with ##with##.
+**/
+
+extern int raydium_parser_read (char *var, char *val_s, GLfloat *val_f, int *size, FILE *fp);
+/**
+Reads a new data line in ##fp##.
+##var## will contain variable name. You'll find associated value in ##val_s##
+if it's a string, or ##val_f## if it's a float (or a float array). In this last
+case, ##size## will return the number of elements if the array.
+%%(c)
+FILE *fp;
+int ret;
+char var[RAYDIUM_MAX_NAME_LEN];
+char val_s[RAYDIUM_MAX_NAME_LEN];
+GLfloat val_f[MY_ARRAY_SIZE];
+int size;
+
+fp=raydium_file_fopen("foobar.txt","rt");
+
+while( (ret=raydium_parser_read(var,val_s,val_f,&size,fp))!=RAYDIUM_PARSER_TYPE_EOF)
+    {
+    if(!strcasecmp(var,"foobar_variable"))
+        {
+        if(ret!=RAYDIUM_PARSER_TYPE_FLOAT || size!=2)
+            {
+	    raydium_log("error: foobar_variable is not float array");
+            continue;
+            }
+        memcpy(...);
+        }
+
+    ...
+
+    }
+%%
+**/
+
+#endif
Index: raydium/headers/texture.h
===================================================================
--- raydium/headers/texture.h	(revision 0)
+++ raydium/headers/texture.h	(revision 1)
@@ -0,0 +1,83 @@
+#ifndef _TEXTURE_H
+#define _TEXTURE_H
+/*=
+Textures
+1200
+**/
+
+// Introduction
+/**
+For now, Raydium only handles TGA uncompressed texture.
+As explainded in the first part of this guide, Raydium provides three 
+texture filters (none, bilinear, trilinear using MipMaps ).
+
+Texture sizes must be a power of two, 8 (alpha mask), 24 (RGB) or 32 (RGBA) bits.
+
+Raydium now supports materials with a simple "rgb(r,g,b)" string 
+as texture name, where r, g and b are 0 <= x <= 1 (floats).
+Texture clamping and multitexturing are supported by Raydium, but not
+documented here for now. If you're interested, have a look to source code, or
+take a look to the Wiki.
+
+Tips: "BOX_", ";", "|".
+**/
+
+
+extern char raydium_texture_size_is_correct (GLuint size);
+/**
+Returns true if ##size## is a correct texture size, depending of
+hardware capacities and "power of 2" constraint.
+**/
+
+extern GLuint raydium_texture_load_internal (char *filename, char *as);
+/**
+Internal use.
+**/
+
+extern GLuint raydium_texture_load (char *filename);
+/**
+Loads "filename" texture into hardware memory. Function results 
+texture index, but in most cases, you can identify later a texture 
+by his name, without providing his index, so you can probably ignore 
+this value.
+
+0 is returned if texture loading have failed.
+**/
+
+extern GLuint raydium_texture_load_erase (char *filename, GLuint to_replace);
+/**
+Same as above, but ##to_replace## texture (index) is erased with ##filename##.
+**/
+
+extern char raydium_texture_current_set (GLuint current);
+/**
+Switch active texture to "current" index. Mostly used for runtime object 
+creation:
+"set current texture, add vertices, set another texture, 
+add vertices, ... and save all to an objet" 
+(see below for vertices management).
+**/
+
+extern char raydium_texture_current_set_name (char *name);
+/**
+Same as above, but using texture name. This function will load ##name## 
+if not alread done.
+**/
+
+extern GLuint raydium_texture_find_by_name (char *name);
+/**
+Returns index for texture "name", and load it if not already done.
+**/
+
+extern void raydium_texture_filter_change (GLuint filter);
+/**
+
+This function will change all filters at anytime.
+Please note that this function will reload all textures and can be very slow.
+
+%%(c)
+// will switch all textures to bilinear filter.
+raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_BILINEAR)%%
+**/
+
+#endif
Index: raydium/headers/profile.h
===================================================================
--- raydium/headers/profile.h	(revision 0)
+++ raydium/headers/profile.h	(revision 1)
@@ -0,0 +1,29 @@
+#ifndef _PROFILE_H
+#define _PROFILE_H
+#ifdef DEBUG_PROFILE
+
+/*=
+Profiling (sort of ...)
+3500
+**/
+
+// Introduction
+/**
+You will find here a few functions for a **very simple** profiling.
+For anything else than a quick time measure, use real profiling tools.
+Note: Use only one "profiler" at a time.
+**/
+
+extern unsigned long raydium_profile_timer;
+extern void raydium_profile_start(void);
+/**
+Starts measure.
+**/
+
+extern void raydium_profile_end(char *tag);
+/**
+Stops measure and displays result using ##tag## string.
+**/
+
+#endif
+#endif
Index: raydium/headers/joy.h
===================================================================
--- raydium/headers/joy.h	(revision 0)
+++ raydium/headers/joy.h	(revision 1)
@@ -0,0 +1,62 @@
+#ifndef _JOY_H
+#define _JOY_H
+/*=
+Joysticks, pads and force feedback
+3100
+**/
+
+// Introduction
+/**
+Raydium supports Joysticks, joypads, steering wheels, force feedback devices, 
+keyboard emulation, for Linux only.
+
+Since API could change during Win32 integration, there is no particular 
+documentation about this subject.
+
+Interesting variables:
+%%(c)
+char raydium_joy_button[RAYDIUM_BUTTONS_MAX_BUTTONS];
+GLfloat raydium_joy_x;
+GLfloat raydium_joy_y;
+GLfloat raydium_joy_z;
+int raydium_joy;
+%%
+Buttons are booleans, joy x,y and z are -1 <= (x,y,z) <= 1 and 0 means "center".
+**/
+
+#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
+#define JS_EVENT_AXIS           0x02    /* joystick moved */
+#define JS_EVENT_INIT           0x80    /* initial state of device */
+extern char number_of_axes, number_of_buttons;
+extern int raydium_joy_event_handle;
+#ifndef WIN32
+struct ff_effect effect_tremble;
+#endif
+extern struct ff_effect effect_tremble;
+extern char effect_tremble_state;
+extern clock_t last_event;
+extern void raydium_joy_init_vars (void);
+extern void raydium_joy_key_emul (void);
+/**
+Emulate keyboard (directional pad) with joy, if any.
+**/
+
+#ifndef WIN32
+extern int raydium_joy_process_event (struct js_event e);
+#endif
+extern void raydium_joy_callback (void);
+extern void raydium_joy_ff_autocenter (int perc);
+/**
+Set Force Feedback autocenter factor.
+**/
+
+extern void raydium_joy_init (void);
+extern void raydium_joy_close (void);
+extern void raydium_joy_ff (void);
+extern void raydium_joy_ff_tremble_set (GLfloat period, GLfloat force);
+/**
+Send tremble effect to Force Feedback device for a determined period, 
+at a particular force. (no units yet).
+**/
+
+#endif
Index: raydium/headers/console.h
===================================================================
--- raydium/headers/console.h	(revision 0)
+++ raydium/headers/console.h	(revision 1)
@@ -0,0 +1,106 @@
+#ifndef _CONSOLE_H
+#define _CONSOLE_H
+/*=
+In-game console
+3000
+**/
+
+// Introduction
+/**
+This chapter introduce Raydium console, allowing applications to take 
+user keyboard input (game commands, chat, ...) and to send informations 
+to this console.
+The end user can call the console using "the key below esc". 
+
+By default, if PHP support is enabled, all user commands will be redirected
+to PHP engine. Each command will get his own context, don't expect to create
+anything else than "single line PHP scripts" with the console. See PHP chapter
+for more informations.
+The console allows the user to prefix command with the following characters:
+
+- ##/##: Non PHP command. The command will be sent to application (see
+##raydium_console_gets_callback##, below.
+
+- ##>##: Will launch argument as a PHP script (identical to ##include("...")##)
+
+- ##!##: Will launch argument as a sequence script
+
+Command history is saved to ##raydium_history## file when application exits.
+
+You can use a ##void prompt(char *)## callback to get user commands. Your
+callback must be registered thru ##raydium_console_gets_callback##:
+%%(c) raydium_console_gets_callback=prompt; %%
+
+This console provides auto-completion of register functions and variables.
+See the suitable chapter for more information.
+**/
+
+extern void raydium_console_init (void);
+/**
+Internal use.
+**/
+
+extern void raydium_console_history_save (void);
+/**
+Internal use (will flush console history to disk).
+You can call it by yourself if needed.
+**/
+
+extern int raydium_console_gets (char *where);
+/**
+**DISABLED**.
+Use ##raydium_console_gets_callback## function pointer instead.
+**/
+
+extern void raydium_console_history_previous (void);
+/**
+Internal use.
+**/
+
+extern void raydium_console_history_next (void);
+/**
+Internal use.
+**/
+
+extern void raydium_console_history_add (char *str);
+/**
+Internal use.
+**/
+
+extern void raydium_console_exec_script (char *file);
+/**
+Internal use.
+**/
+
+extern void raydium_console_exec_last_command (void);
+/**
+Internal use.
+**/
+
+extern void raydium_console_line_add (char *format, ...);
+/**
+Mostly reserved for internal use, but unless ##raydium_log##, this function will
+add the provided data only to ingame console, and not to "native" console.
+**/
+
+extern void raydium_console_event (void);
+/**
+Internal use. Will switch console up and down.
+**/
+
+extern void raydium_console_draw (void);
+/**
+Internal use.
+**/
+
+extern int raydium_console_internal_isalphanumuscore (char c);
+/**
+Internal use.
+**/
+
+extern void raydium_console_complete (char *str);
+/**
+Internal use.
+**/
+
+#endif
Index: raydium/particle2.h
===================================================================
--- raydium/particle2.h	(revision 0)
+++ raydium/particle2.h	(revision 1)
@@ -0,0 +1,83 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+// Raydium Particle Engine, version 2
+
+#ifndef PARTICLE2_H
+#define PARTICLE2_H
+
+#define RAYDIUM_MAX_PARTICLES	8192
+#define RAYDIUM_MAX_GENERATORS	16
+
+typedef struct raydium_particle_Generator
+{
+ int      id;
+ char	  state;
+ char	  enabled;
+ char     name[RAYDIUM_MAX_NAME_LEN];
+ GLfloat  position[3];
+ GLfloat  position_random[3];
+ GLfloat  position_user[3];
+ GLfloat  ttl_generator;
+ GLfloat  ttl_particles;
+ GLfloat  ttl_particles_random;
+ GLfloat  particles_per_second;
+ int	  texture;
+ GLfloat  size;
+ GLfloat  size_random;
+ GLfloat  size_inc_per_sec;
+ GLfloat  size_limit;
+ GLfloat  gravity[3];
+ GLfloat  vector[3];
+ GLfloat  vector_random[3];
+ GLfloat  vector_sphere_angles[3];
+ GLfloat  vector_sphere_angles_random[3];
+ GLfloat  vector_sphere_force;
+ GLfloat  vector_sphere_force_random;
+// GLfloat  velocity_limit[3];
+ GLfloat  rotation_speed;
+ GLfloat  rotation_random;
+ GLfloat  color_start[4];
+ GLfloat  color_start_random[4];
+ GLfloat  color_end[4];
+ GLfloat  color_end_random[4];
+// char     transform[RAYDIUM_MAX_NAME_LEN];
+ GLfloat  visibility;
+ void *   OnDeleteParticle;
+} raydium_particle_Generator;
+
+typedef struct raydium_particle_Particle
+{
+ GLfloat ttl_init;
+ GLfloat ttl; // is updated over time
+ int	 texture;
+ GLfloat  size;
+ GLfloat  size_inc_per_sec;
+ GLfloat  size_limit;
+ GLfloat position[3];
+ GLfloat vel[3]; // is updated over time
+ GLfloat gravity[3];
+// GLfloat velocity_limit[3];
+ GLfloat color_start[4]; // will use ttl to determine current color
+ GLfloat color_end[4];   // use ttl too
+ GLfloat rotation_speed; // use ttl too
+ GLfloat visibility;
+ void *  OnDelete; 
+ 
+// --- Current resulting data
+ GLfloat current_color[4];
+ GLfloat current_rotation;
+} raydium_particle_Particle;
+
+raydium_particle_Generator raydium_particle_generators[RAYDIUM_MAX_GENERATORS];
+raydium_particle_Particle *raydium_particle_particles[RAYDIUM_MAX_PARTICLES];
+GLfloat raydium_particle_time_factor;
+
+// proto
+void raydium_camera_replace(void);
+void raydium_file_dirname(char *dest,char *from);
+
+#endif
Index: raydium/timecall.c
===================================================================
--- raydium/timecall.c	(revision 0)
+++ raydium/timecall.c	(revision 1)
@@ -0,0 +1,419 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/timecall.h"
+#endif
+
+#ifdef WIN32
+#define __GETTIMEOFDAY_USEC 1000
+#else
+#define __GETTIMEOFDAY_USEC 1000000
+#endif
+
+// needed proto
+int raydium_timecall_add(void *funct, GLint hz);
+
+
+void raydium_timecall_raydium(GLfloat step)
+{
+raydium_frame_time=step;
+}
+
+#ifdef WIN32
+float raydium_timecall_internal_w32_detect_modulo(int div)
+{
+ LARGE_INTEGER t;
+ unsigned long mx;
+ 
+ QueryPerformanceFrequency(&t);
+ t.QuadPart >>= div;
+ mx=(0xFFFFFFFF / t.LowPart); 
+ return mx/60.f;
+}
+
+
+int raydium_timecall_internal_w32_divmodulo_find(void)
+{
+float modulo_time;
+int div;
+
+div=-1;
+do{
+div++;
+modulo_time=raydium_timecall_internal_w32_detect_modulo(div);
+}while(modulo_time<RAYDIUM_TIMECALL_W32_MODULO_MIN);
+
+raydium_log("timecall: win32 modulo every %.2f minutes, modulodiv is 2^%i",modulo_time,div);
+return div;
+}
+#endif
+
+
+unsigned long raydium_timecall_devrtc_clock(void)
+{
+#ifndef WIN32
+struct timeval tv={0, 0};
+fd_set readfds;
+int ret;
+unsigned long data,missed;
+
+FD_ZERO(&readfds);
+FD_SET(raydium_timecall_devrtc_handle, &readfds);
+if( (ret=select(raydium_timecall_devrtc_handle+1, &readfds, NULL, NULL, &tv)) == -1)
+    {
+    raydium_log("timecall: ERROR: selecting /dev/rtc failed at runtime");
+    perror("system");
+    }
+
+// IRQ fired !
+if(ret>0)
+ {
+        if( read(raydium_timecall_devrtc_handle, &data, sizeof(unsigned long)) == -1)
+	{
+	raydium_log("timecall: ERROR: reading /dev/rtc failed at runtime");
+        perror("system");
+        }
+	else 
+	{
+	// read first 3 bytes only
+	missed=(data & 0xffffff00UL)>>8;
+	raydium_timecall_devrtc_clocks+=missed;
+//	raydium_log("%i",raydium_timecall_devrtc_clocks);
+	}
+ }
+ 
+return raydium_timecall_devrtc_clocks;
+#else
+return 0;
+#endif
+}
+
+unsigned long raydium_timecall_clock(void)
+{
+struct timeval tv;
+if(raydium_timecall_method==RAYDIUM_TIMECALL_METHOD_CLOCK)
+ {
+ #ifdef WIN32
+  {
+// return GetTickCount();
+    LARGE_INTEGER t;
+    QueryPerformanceCounter(&t);
+    t.QuadPart>>=raydium_timecall_w32_divmodulo;
+    return t.LowPart;
+  }
+ #else
+ gettimeofday(&tv,NULL);
+ return (tv.tv_sec*1000000 + tv.tv_usec);
+ #endif
+ //return clock();
+ }
+//else if(raydium_timecall_method==RAYDIUM_TIMECALL_METHOD_DEVRTC)
+ return raydium_timecall_devrtc_clock();
+}
+
+char raydium_timecall_devrtc_rate_change(unsigned long new)
+{
+#ifndef WIN32
+        if(ioctl(raydium_timecall_devrtc_handle, RTC_IRQP_SET, new)==-1)
+	{
+		raydium_log("timecall: ERROR: changing /dev/rtc rate to %lu Hz failed !",new);
+		raydium_log("timecall: is /proc/sys/dev/rtc/max-user-freq correct for this value ?");
+                perror("system");
+//                exit(errno);
+                return 0;
+        }
+	raydium_log("timecall: /dev/rtc rate changed to %lu Hz",new);
+	return 1;
+#else
+return 0;
+#endif
+}
+
+void raydium_timecall_devrtc_close(void)
+{
+#ifndef WIN32
+        if(ioctl(raydium_timecall_devrtc_handle, RTC_PIE_OFF, 0) == -1)
+	{
+		raydium_log("timecall: ERROR disabling /dev/rtc periodic interrupts");
+                perror("system");
+//                exit(errno);
+        }
+close(raydium_timecall_devrtc_handle);
+#endif
+}
+
+
+unsigned long raydium_timecall_devrtc_init(void)
+{
+#ifndef WIN32
+ unsigned long freq;
+ raydium_timecall_devrtc_clocks=0;
+ 
+ if((raydium_timecall_devrtc_handle = open ("/dev/rtc", O_RDONLY)) == -1 )
+ {
+  raydium_log("timecall: ERROR: /dev/rtc unavailable ! (chmod a+rx /dev/rtc ?)");
+  perror("system");
+//  exit(errno);
+  return 0;
+ }
+
+ // ok, it's now open, so let's read actual rate
+ if (ioctl(raydium_timecall_devrtc_handle, RTC_IRQP_READ, &freq) == -1 )
+ {
+  raydium_log("timecall: ERROR reading /dev/rtc rate");
+  perror("system");
+//  exit(errno);
+  return 0;
+ }
+ raydium_log("timecall: /dev/rtc rate is %lu Hz",freq);
+
+ if(freq<RAYDIUM_TIMECALL_FREQ_MIN)
+  {
+   raydium_log("timecall: /dev/rtc rate (%i Hz) too low (min: %i)",freq,RAYDIUM_TIMECALL_FREQ_MIN);
+   if(!raydium_timecall_devrtc_rate_change(RAYDIUM_TIMECALL_FREQ_PREFERED)) return 0;
+   else freq=RAYDIUM_TIMECALL_FREQ_PREFERED; // need to verify this new value ?
+  }
+ 
+ if(freq<RAYDIUM_TIMECALL_FREQ_PREFERED)
+  {
+   raydium_log("timecall: /dev/rtc rate (%i Hz) is low (prefered: %i)",freq,RAYDIUM_TIMECALL_FREQ_PREFERED);
+   if(raydium_timecall_devrtc_rate_change(RAYDIUM_TIMECALL_FREQ_PREFERED)) 
+      freq=RAYDIUM_TIMECALL_FREQ_PREFERED; // need to verify this new value ?
+  }
+
+    // Enable periodic interrupts
+    if(ioctl(raydium_timecall_devrtc_handle, RTC_PIE_ON, 0) == -1)
+    {
+	    raydium_log("timecall: ERROR enabling /dev/rtc periodic interrupts !");
+	    raydium_log("timecall: is /proc/sys/dev/rtc/max-user-freq allowing %lu Hz ?",freq);
+            perror("system");
+//            exit(errno);
+	    return 0;
+    }
+
+atexit(raydium_timecall_devrtc_close);
+return freq;
+#else
+raydium_log("timecall: FAILED: /dev/rtc only available for Linux");
+return 0;
+#endif
+}
+
+/*
+int raydium_timecall_detect_max_clock_frequency(void)
+{
+int i;
+clock_t first,second;
+float accu,max;
+
+first=second=clock();
+while(first==second)
+{
+i++;
+second=clock();
+}
+
+accu=((second-first)/(float)CLOCKS_PER_SEC)*1000;
+max=1.0/(accu/1000);
+raydium_log("timecall: clock() accuracy = %.2f ms (%.2f Hz)",accu,max);
+return (int)max;
+}
+*/
+
+int raydium_timecall_detect_frequency(void)
+{
+int i;
+unsigned long first,second;
+float accu,max;
+
+first=second=raydium_timecall_clock();
+while(first==second)
+{
+i++;
+second=raydium_timecall_clock();
+}
+
+raydium_log("timer: detection: %i iterations: diff: %li steps (%li/sec)",i,second-first,raydium_timecall_clocks_per_sec);
+accu=((second-first)/(float)raydium_timecall_clocks_per_sec)*1000;
+max=1.0/(accu/1000);
+raydium_log("timecall: method accuracy = %.3f ms (%.2f Hz)",accu,max);
+return (int)max;
+}
+
+
+void raydium_timecall_init(void)
+{
+int i;
+unsigned long tmp;
+#ifdef WIN32
+LARGE_INTEGER t;
+#endif
+
+//default
+raydium_timecall_method=RAYDIUM_TIMECALL_METHOD_CLOCK;
+raydium_timecall_clocks_per_sec=__GETTIMEOFDAY_USEC;
+
+#ifdef WIN32
+raydium_timecall_w32_divmodulo=raydium_timecall_internal_w32_divmodulo_find();
+QueryPerformanceFrequency(&t);
+t.QuadPart>>=raydium_timecall_w32_divmodulo;
+raydium_timecall_clocks_per_sec=t.LowPart;
+#endif
+
+raydium_timecall_max_frequency=raydium_timecall_detect_frequency();
+
+
+if(raydium_timecall_max_frequency<RAYDIUM_TIMECALL_FREQ_PREFERED)
+{
+raydium_log("timecall: basic method accuracy is low , trying /dev/rtc ...");
+tmp=raydium_timecall_devrtc_init();
+if(tmp) {
+	raydium_timecall_method=RAYDIUM_TIMECALL_METHOD_DEVRTC;
+	raydium_timecall_max_frequency=tmp;
+	}
+}
+
+if(raydium_timecall_method==RAYDIUM_TIMECALL_METHOD_CLOCK)
+{
+raydium_log("timecall: Using basic gettimeofday() method");
+raydium_timecall_clocks_per_sec=__GETTIMEOFDAY_USEC;
+#ifdef WIN32
+//QueryPerformanceFrequency(&t);
+raydium_timecall_clocks_per_sec=t.LowPart;
+//printf("%i %i %i\n",t.LowPart,t.HighPart,t.QuadPart);
+#endif
+
+}
+
+if(raydium_timecall_method==RAYDIUM_TIMECALL_METHOD_DEVRTC)
+{
+raydium_log("timecall: Using /dev/rtc method");
+raydium_timecall_clocks_per_sec=raydium_timecall_max_frequency;
+//raydium_timecall_method_test();
+}
+
+raydium_timecall_index=0;
+for(i=0;i<RAYDIUM_MAX_TIMECALLS;i++)
+    {
+    raydium_timecall_funct[i]=NULL;
+    raydium_timecall_soft_call[i]=0;
+    raydium_timecall_interval[i]=0;
+    raydium_timecall_next[i]=0;
+    }
+raydium_log("timecall: OK (%lu Hz)",raydium_timecall_max_frequency);
+raydium_timecall_add(raydium_timecall_raydium,-1);
+}
+
+
+// Utility function only: No test is done here, please, secure your calls
+void raydium_timecall_freq_change(int callback, GLint hz)
+{
+if(!hz)
+ {
+ raydium_log("timecall: WARNING ! 0 Hz callback (num %i)",callback);
+ raydium_timecall_interval[callback]=0;
+ }
+else
+ raydium_timecall_interval[callback]=raydium_timecall_clocks_per_sec/abs(hz);
+
+raydium_timecall_soft_call[callback]=(hz<0);
+raydium_timecall_next[callback]=raydium_timecall_clock();
+
+if(abs(hz)>raydium_timecall_max_frequency && hz>0)
+ raydium_log("timecall: WARNING ! this callback refresh rate (%i Hz) is probably too high for this system clock (detected at %i Hz)",hz,raydium_timecall_max_frequency);
+
+if(hz>0)
+ raydium_log("timecall: callback %i: %i Hz (%i clocks interval)",callback,hz,raydium_timecall_interval[callback]);
+
+if(hz<0)
+ raydium_log("timecall: softcall %i: %i Hz (%i clocks interval)",callback,-hz,raydium_timecall_interval[callback]);
+}
+
+int raydium_timecall_add(void *funct, GLint hz)
+{
+if(raydium_timecall_index>=RAYDIUM_MAX_TIMECALLS)
+    {
+    raydium_log("timecall: ERROR ! Too much timecalls, exiting.");
+    exit(29);
+    }
+
+raydium_timecall_funct[raydium_timecall_index]=funct;
+raydium_timecall_freq_change(raydium_timecall_index,hz);
+return raydium_timecall_index++;
+}
+
+
+
+void raydium_timecall_callback(void)
+{
+int i,j,steps;
+GLfloat stepsf;
+unsigned long now,phase;
+static unsigned long last;
+void (*f)();
+void (*ff)(GLfloat);
+
+// workaround for time modulos
+now=raydium_timecall_clock();
+if(last>now)
+    {
+    raydium_log("timecall: warning: time modulo detected: workarounding");
+    for(i=0;i<raydium_timecall_index;i++)
+        if(!raydium_timecall_soft_call[i] && 
+            raydium_timecall_interval[i])
+            {
+              // reset timecall next value
+              raydium_timecall_next[i]=now+raydium_timecall_interval[i];
+            }
+    }
+last=now;
+// end of workaround
+
+
+for(i=0;i<raydium_timecall_index;i++)
+ {
+ now=raydium_timecall_clock();
+
+   if(!raydium_timecall_soft_call[i] && now>=raydium_timecall_next[i] && raydium_timecall_interval[i])
+    {
+    steps=((now-raydium_timecall_next[i])/raydium_timecall_interval[i])+1;
+    phase=(now-raydium_timecall_next[i])-((steps-1)*raydium_timecall_interval[i]);
+    //raydium_log("current phase overload for timecall %i: %i (total interval = %i",i,phase,raydium_timecall_interval[i]);
+    raydium_timecall_next[i]=now+raydium_timecall_interval[i]-phase;
+
+#ifdef DEBUG_MOVIE
+    steps=(float)raydium_timecall_interval[i]/((float)raydium_timecall_interval[i]*(1/(float)DEBUG_MOVIE));
+#endif
+
+    if(steps>1000) { // DEBUG ! need to calculate this value
+		    steps=100;
+		    raydium_log("WARNING: timecall's too long");
+		 }    
+    
+//    raydium_log("debug: need %i steps",steps);
+    f=raydium_timecall_funct[i];
+
+    for(j=0;j<steps;j++)
+     f();
+    }
+    else if(raydium_timecall_soft_call[i]) // this an "elastic-timed" callback
+    {
+     stepsf=(now-raydium_timecall_next[i])/(GLfloat)raydium_timecall_interval[i];
+     ff=raydium_timecall_funct[i];
+     raydium_timecall_next[i]=raydium_timecall_clock();
+     //raydium_log("debug: soft call: step factor: %.2f",stepsf);
+
+#ifdef DEBUG_MOVIE
+    stepsf=((float)raydium_timecall_interval[i]*(1/(float)DEBUG_MOVIE))/(float)raydium_timecall_interval[i];
+#endif
+
+     ff(stepsf);
+    }
+ }
+}
Index: raydium/render.c.old
===================================================================
--- raydium/render.c.old	(revision 0)
+++ raydium/render.c.old	(revision 1)
@@ -0,0 +1,248 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/render.h"
+#endif 
+
+void raydium_callback_image(void);
+void raydium_timecall_callback(void);
+
+// EARLY devel stage !
+void raydium_rendering_prepare_texture_unit(GLenum tu,GLuint tex)
+{
+glActiveTextureARB(tu);
+ if(tex)
+ {
+  glEnable(GL_TEXTURE_2D);
+  glBindTexture(GL_TEXTURE_2D,tex);
+//  glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+  glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT);
+  glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2);
+ } 
+ else 
+ {
+ glDisable(GL_TEXTURE_2D);
+// glBindTexture(GL_TEXTURE_2D,0); 
+ }
+
+glActiveTextureARB(GL_TEXTURE0_ARB);
+}
+
+void raydium_rendering_internal_prepare_texture_render(GLuint tex)
+{
+//#define ONE 0.8 // default (according GL specs) DIFFUSE value.
+GLfloat one[]={0.8f, 0.8f, 0.8f, 1.f};
+GLfloat zero[]={0.0,0.0,0.0,0.0};
+GLfloat *rgb;
+
+glColor4f(1.f,1.f,1.f,1.f);
+
+
+// "cache"
+if(tex==raydium_texture_internal_loaded) return;
+raydium_texture_internal_loaded=tex;
+
+  if(raydium_texture_blended[tex]==1)
+  {
+  glEnable(GL_BLEND);
+  glDepthMask(GL_FALSE);
+  glDisable(GL_ALPHA_TEST);
+//  glDisable(GL_FOG);
+  }
+
+  if(raydium_texture_blended[tex]==2)
+  {
+  glEnable(GL_BLEND);
+  glDepthMask(GL_TRUE);
+  glAlphaFunc(GL_GREATER,0);
+  glEnable (GL_ALPHA_TEST);
+//  glDisable(GL_FOG);
+  }
+
+  if(raydium_texture_blended[tex]==0)
+  {
+  glDisable(GL_BLEND);
+  glDepthMask(GL_TRUE);
+  glDisable(GL_ALPHA_TEST);
+//  glEnable(GL_FOG);
+  }
+
+  if(raydium_texture_rgb[tex][0]>=0)
+  {
+  if(raydium_render_rgb_force_tag)
+    rgb=raydium_render_rgb_force;
+  else
+    rgb=raydium_texture_rgb[tex];
+  
+  glDisable(GL_TEXTURE_2D);
+  glColor4f(rgb[0],rgb[1],rgb[2],1.f);
+   if(raydium_light_enabled_tag)
+   {
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, rgb);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, rgb);
+   }
+  }
+  else 
+  {
+  glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, one);
+  glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, zero);
+  glEnable(GL_TEXTURE_2D);
+  glBindTexture(GL_TEXTURE_2D,tex);
+  }
+}
+
+void raydium_rendering_internal_restore_render_state(void)
+{
+//#define ONE 0.8 // default DIFFUSE value.
+GLfloat one[]={0.8f, 0.8f, 0.8f, 1.f};
+
+//return; // make no sens to restore state since next texture will reset it
+
+glDisable(GL_BLEND);
+glDepthMask(GL_TRUE);
+glEnable(GL_TEXTURE_2D);
+glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, one);
+}
+
+// 2D quick 'n ugly clipping test
+char infov(GLfloat x, GLfloat y)
+{
+#ifdef RENDER_DEBUG_NO_CLIP
+return 1;
+#endif
+if((x+raydium_camera_cursor_place[0])>(raydium_camera_x-raydium_projection_far) &&
+   (x+raydium_camera_cursor_place[0])<(raydium_camera_x+raydium_projection_far) &&
+   (y+raydium_camera_cursor_place[1])>(raydium_camera_y-raydium_projection_far) &&
+   (y+raydium_camera_cursor_place[1])<(raydium_camera_y+raydium_projection_far) ) return 1; else return 0;
+}
+
+void raydium_rendering_from_to(GLuint from, GLuint to)
+{
+GLuint tex,i,j;
+char toload;
+
+
+for(tex=1;tex<raydium_texture_index;tex++)
+{
+  toload=tex;
+  
+  for(i=from,j=0;i<to;i+=3)
+  if(raydium_vertex_texture[i]==tex)
+  {
+   if(infov(raydium_vertex_x[i  ],raydium_vertex_y[i  ]) ||
+      infov(raydium_vertex_x[i+1],raydium_vertex_y[i+1]) ||
+      infov(raydium_vertex_x[i+2],raydium_vertex_y[i+2]) )
+   {
+    if(toload) 
+    { 
+      raydium_rendering_internal_prepare_texture_render(toload);
+      raydium_rendering_prepare_texture_unit(GL_TEXTURE1_ARB,raydium_vertex_texture_multi[i]);
+#ifndef LIMIT_TO_2_TEXUNITS_DEBUG      
+      raydium_rendering_prepare_texture_unit(GL_TEXTURE2_ARB,raydium_vertex_texture_multi[i]);
+#endif
+      toload=0; 
+      glBegin(GL_TRIANGLES);
+    }
+    
+#ifdef RENDER_DEBUG_TAG
+    if(raydium_vertex_tag[i  ] ||
+       raydium_vertex_tag[i+1] ||
+       raydium_vertex_tag[i+2] )
+	glColor4f(1.f,0.f,1.f,1.f);
+	else
+	glColor4f(1.f,1.f,1.f,1.f);
+#endif    
+    
+    for(j=0;j<3;j++)
+    {
+    glNormal3f(raydium_vertex_normal_visu_x[i+j],raydium_vertex_normal_visu_y[i+j],raydium_vertex_normal_visu_z[i+j]);
+  //glTexCoord2f(raydium_vertex_texture_u[i+j],raydium_vertex_texture_v[i+j]);
+    glMultiTexCoord2fARB(GL_TEXTURE0_ARB,raydium_vertex_texture_u[i+j],raydium_vertex_texture_v[i+j]);
+#define MULTF2 500.f
+//#define MULTF 3000.f
+#define MULTF 50.f
+    glMultiTexCoord2fARB(GL_TEXTURE1_ARB,raydium_vertex_texture_u[i+j]*MULTF,raydium_vertex_texture_v[i+j]*MULTF);
+
+#ifndef LIMIT_TO_2_TEXUNITS_DEBUG      
+    glMultiTexCoord2fARB(GL_TEXTURE2_ARB,raydium_vertex_texture_u[i+j]*MULTF2,raydium_vertex_texture_v[i+j]*MULTF2);
+#endif    
+    glVertex3f(raydium_vertex_x[i+j], raydium_vertex_y[i+j], raydium_vertex_z[i+j]);
+    raydium_vertex_counter++;
+    }
+   }
+  }
+  if(!toload) glEnd();
+ }
+}
+
+void raydium_rendering(void)
+{
+raydium_rendering_from_to(0,raydium_vertex_index);
+}
+
+void raydium_rendering_finish(void)
+{
+static int fps=0;
+static clock_t last=0;
+fps++;
+if(!last) last=clock();
+
+raydium_callback_image();
+glFlush();
+raydium_rendering_internal_restore_render_state();
+//glutPostRedisplay();
+
+#ifdef DEBUG_MOVIE
+{
+char name[128];
+static int frame;
+sprintf(name,"movie/frame%04d.tga",frame);
+raydium_capture_frame(name);
+frame++;
+}
+#endif
+
+glutSwapBuffers();
+//raydium_timecall_callback();
+raydium_key_last=0;
+raydium_mouse_clic=0;
+raydium_camera_pushed=0; 
+glPopMatrix();
+raydium_texture_internal_loaded=0;
+if(clock() > last + CLOCKS_PER_SEC)
+    {
+    last=clock();
+    raydium_render_fps=fps;
+    fps=0;
+    }
+}
+
+void raydium_rendering_wireframe(void)
+{
+glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+}
+
+void raydium_rendering_normal(void)
+{
+glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void raydium_rendering_rgb_force(GLfloat r, GLfloat g, GLfloat b)
+{
+raydium_render_rgb_force_tag=1;
+raydium_render_rgb_force[0]=r;
+raydium_render_rgb_force[1]=g;
+raydium_render_rgb_force[2]=b;
+raydium_render_rgb_force[3]=1.0;
+}
+
+void raydium_rendering_rgb_normal(void)
+{
+raydium_render_rgb_force_tag=0;
+}
Index: raydium/texture.c
===================================================================
--- raydium/texture.c	(revision 0)
+++ raydium/texture.c	(revision 1)
@@ -0,0 +1,307 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/texture.h"
+#endif
+
+// proto
+int raydium_init_cli_option(char *option, char *value);
+FILE *raydium_file_fopen(char *path, char *mode);
+
+
+char raydium_texture_size_is_correct(GLuint size)
+{
+int i;
+
+if(raydium_window_mode==RAYDIUM_RENDERING_NONE)
+    return 1;
+
+// must be a power of 2 and <= to raydium_texture_size_max
+if(size==1) return 1;
+for(i=2;i<=raydium_texture_size_max;i*=2)
+    if(i==size) return 1;
+return 0;
+}
+
+GLuint raydium_texture_load_internal(char *filename, char *as)
+{
+FILE *file;
+unsigned char temp[RAYDIUM_MAX_NAME_LEN];
+unsigned char *data;
+GLuint tx,ty,bpp,id;
+GLuint i,j,k,GLbpp=0,GLbppi;
+GLuint texsize=0;
+char blended=0,filter=0,cutout=0;
+char rgb;
+GLfloat r,g,b;
+
+
+/* is RGB color ? (or texture) */
+strcpy(temp,filename);
+temp[4]=0;
+if(!strcmp("rgb(",temp)) rgb=1; else rgb=0;
+
+if(!rgb)
+{
+ file=raydium_file_fopen(filename,"rb");
+ if(!file)
+  {
+    raydium_log("Cannot open %s texture",filename);
+    return 0;
+  }
+
+ fread(temp,1,12,file);
+ if(temp[2]!=2 && temp[2]!=3) 
+ { 
+ fclose(file); 
+ raydium_log("%s is not an uncompressed TGA RGB or grayscale file (type %i)",filename,temp[2]);
+ return 0; //not a: uncompressed TGA RGB file
+ } 
+
+ fread(temp,1,6,file);
+
+ tx = temp[1] * 256 + temp[0]; // highbyte*256+lowbyte
+ ty = temp[3] * 256 + temp[2]; // highbyte*256+lowbyte
+
+ if( !raydium_texture_size_is_correct(tx) || !raydium_texture_size_is_correct(ty) )
+ {
+ raydium_log("texture: ERROR: cannot load %s: invalid size %ix%i (must be a power of two and inferior to your max hardware size: %i)",filename,tx,ty,raydium_texture_size_max);
+ raydium_log("texture: I will fake this texture.");
+ tx=ty=1;
+ }
+ bpp= temp[4] / 8;
+ texsize = tx * ty * bpp;
+
+ data=malloc(texsize);
+ if(!data) { 
+ fclose(file); 
+ raydium_log("texture: ERROR ! malloc for %s failed ! (%i bytes needed)",filename,tx*ty*bpp);
+ return 0; }
+
+ for(j=0; j<ty; j++)
+ for(i=0; i<tx; i++)
+ {
+ if(fread(temp,1,bpp,file)!=bpp) 
+ { free(data); fclose(file); 
+ raydium_log("Invalid data in %s",filename);
+ return 0; }
+ k=(( (ty-j-1) *tx)+i)*bpp;
+ if(bpp == 1) data[k]=temp[0];
+ else // no greyscale
+  {
+   data[k]=temp[2];
+   data[k+1]=temp[1];
+   data[k+2]=temp[0];
+   if(bpp == 4) 
+    { 
+    data[k+3]=temp[3]; 
+    if(temp[3]>0 && temp[3]<255)
+	blended=1;
+    if(temp[3]==0)
+	cutout=1;
+    }
+  }
+ }
+
+ fclose(file);
+ glPixelStorei(GL_UNPACK_ALIGNMENT,1); //TEMPO
+} //end !rgb
+
+
+
+if(raydium_texture_to_replace)
+ { id=raydium_texture_to_replace; raydium_texture_to_replace=0; }
+ else
+ id=raydium_texture_index++;
+ 
+if(raydium_texture_index>RAYDIUM_MAX_TEXTURES) 
+    { 
+    raydium_log("texture: No more texture slots left ! (%i max)",
+		RAYDIUM_MAX_TEXTURES); 
+    return 0; 
+    }
+
+strcpy(raydium_texture_name[id],as);
+
+if(!rgb)
+{
+ if(bpp==1) 
+    { 
+    GLbpp=GL_ALPHA;
+    GLbppi=GL_ALPHA8;
+    blended=1; 
+    }
+
+ if(bpp==3) 
+    {
+    GLbpp=GL_RGB;
+    GLbppi=GL_RGBA8; // force RGBA (since ATI cards needs it)
+    texsize += tx * ty;
+    }
+    
+ if(bpp==4) 
+    {
+    GLbpp=GL_RGBA;
+    GLbppi=GL_RGBA8;
+    }
+
+ raydium_texture_blended[id]=0;
+ if(blended)
+    raydium_texture_blended[id]=1;
+
+ if(cutout && !blended)
+    {
+    raydium_texture_blended[id]=2;
+    blended=2;
+    }
+
+
+ raydium_texture_used_memory+=texsize;
+ if(raydium_texture_filter==RAYDIUM_TEXTURE_FILTER_TRILINEAR)
+    raydium_texture_used_memory+=(texsize/3); // mipmaps
+
+ glBindTexture(GL_TEXTURE_2D,id);
+
+
+ if(strstr(filename,".tri."))
+    raydium_texture_islightmap[id]=1;
+
+ memcpy(temp,filename,3);						// TEMP !!
+ temp[3]=0;								// TEMP !!
+ if(!strcmp("BOX",temp))						// TEMP !!
+ {									// TEMP !!
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);		// TEMP !!
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);		// TEMP !!
+ }									// TEMP !!
+ else
+ {
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
+ }
+
+ filter=raydium_texture_filter;
+ if(filter==RAYDIUM_TEXTURE_FILTER_TRILINEAR && blended)
+ filter=RAYDIUM_TEXTURE_FILTER_BILINEAR;
+
+  if(filter==RAYDIUM_TEXTURE_FILTER_NONE)
+  {
+  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); 
+  glTexImage2D(GL_TEXTURE_2D,0,GLbppi,tx,ty,0,GLbpp,GL_UNSIGNED_BYTE,data);
+  }
+
+  if(filter==RAYDIUM_TEXTURE_FILTER_BILINEAR)
+  {
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexImage2D(GL_TEXTURE_2D,0,GLbppi,tx,ty,0,GLbpp,GL_UNSIGNED_BYTE,data);
+  }
+
+  if(filter==RAYDIUM_TEXTURE_FILTER_TRILINEAR)
+  {
+  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
+  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); // Trilinear filtering
+  gluBuild2DMipmaps(GL_TEXTURE_2D, GLbppi, tx, ty, GLbpp, GL_UNSIGNED_BYTE, data);
+  }
+
+ raydium_log("Texture num %i (%s) loaded: %ix%i, %i bpp (b%i lm%i)",
+	     id,raydium_texture_name[id],tx,ty,bpp,
+	     blended,raydium_texture_islightmap[id]);
+ free(data);
+} else /* is rgb color */
+{
+ sscanf(filename,"rgb(%f,%f,%f)",&r,&g,&b);
+ raydium_texture_rgb[id][0]=r;
+ raydium_texture_rgb[id][1]=g;
+ raydium_texture_rgb[id][2]=b;
+ raydium_texture_rgb[id][3]=1.f;
+ raydium_texture_blended[id]=0;
+ raydium_log("Texture num %i, rgb(%f,%f,%f) is RGB Color",id,r,g,b);
+}
+ 
+return id;
+}
+
+GLuint raydium_texture_load(char *filename)
+{
+GLuint res;
+res=raydium_texture_load_internal(filename,filename);
+if(res<=0)
+    {
+    raydium_log("texture: faking '%s' with pink color");
+    res=raydium_texture_load_internal("rgb(1,0,1)",filename);
+    }
+return res;
+}
+
+
+GLuint raydium_texture_load_erase(char *filename, GLuint to_replace)
+{
+if(to_replace<=0) return 0;
+raydium_texture_to_replace=to_replace;
+return raydium_texture_load(filename);
+}
+
+
+char raydium_texture_current_set(GLuint current)
+{
+if(current<RAYDIUM_MAX_TEXTURES)
+{ raydium_texture_current=current; return current; }
+return 0;
+}
+
+GLuint raydium_texture_find_by_name(char *name)
+{
+GLuint i;
+char flag=0;
+GLuint ret=0;
+
+for(i=0;i<raydium_texture_index;i++)
+if(!strcmp(raydium_texture_name[i],name)) { flag++; ret=i; }
+
+if(!flag) ret=raydium_texture_load(name);
+return ret;
+}
+
+
+char raydium_texture_current_set_name(char *name)
+{
+/*
+GLuint i;
+char flag=0;
+char ret=0;
+
+for(i=0;i<raydium_texture_index;i++)
+if(!strcmp(raydium_texture_name[i],name)) { flag++; raydium_texture_current_set(i); ret=i; }
+
+if(!flag) ret=raydium_texture_current_set(raydium_texture_load(name));
+*/
+return raydium_texture_current_set(raydium_texture_find_by_name(name));
+}
+
+
+void raydium_texture_filter_change(GLuint filter)
+{
+GLuint i;
+char force[RAYDIUM_MAX_NAME_LEN];
+
+if(raydium_init_cli_option("filter",force))
+    {
+    if(!strcmp(force,"none")) filter=RAYDIUM_TEXTURE_FILTER_NONE;
+    if(!strcmp(force,"bilinear")) filter=RAYDIUM_TEXTURE_FILTER_BILINEAR;
+    if(!strcmp(force,"trilinear")) filter=RAYDIUM_TEXTURE_FILTER_TRILINEAR;
+    }
+
+raydium_texture_filter=filter;
+
+for(i=0;i<raydium_texture_index;i++)
+    raydium_texture_load_erase(raydium_texture_name[i],i);
+
+}
+
Index: raydium/profile.c
===================================================================
--- raydium/profile.c	(revision 0)
+++ raydium/profile.c	(revision 1)
@@ -0,0 +1,40 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/profile.h"
+#endif
+
+// Simple "profiling" functions
+// Only one profiler can be used a the same time
+
+#ifdef DEBUG_PROFILE
+
+unsigned long raydium_profile_timer;
+
+void raydium_profile_start(void)
+{
+raydium_profile_timer=raydium_timecall_clock();
+}
+
+
+void raydium_profile_end(char *tag)
+{
+unsigned long del;
+del=raydium_timecall_clock()-raydium_profile_timer;
+
+printf("*** profiler: %40s | %.4f ms\n",tag,del/(double)raydium_timecall_clocks_per_sec*1000);
+}
+
+
+#else
+
+#define raydium_profile_start()
+#define raydium_profile_end(a)
+
+#endif
Index: raydium/joy.c
===================================================================
--- raydium/joy.c	(revision 0)
+++ raydium/joy.c	(revision 1)
@@ -0,0 +1,360 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/joy.h"
+#endif 
+
+// proto
+int raydium_init_cli_option_default(char *option, char *value, char *default_value);
+
+// This file needs a lot of work, again ...
+// (will use Glut for windows joy support soon ...)
+
+//#define joy_debug 1			//do we display debug infos ?
+
+#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
+#define JS_EVENT_AXIS           0x02    /* joystick moved */
+#define JS_EVENT_INIT           0x80    /* initial state of device */
+/*
+			// function                     3rd arg
+#define JSIOCGAXES      // get number of axes           char
+#define JSIOCGBUTTONS   // get number of buttons        char
+#define JSIOCGVERSION   // get driver version           int
+#define JSIOCGNAME(len) // get identifier string        char
+#define JSIOCSCORR      // set correction values        &js_corr
+#define JSIOCGCORR      // get correction values        &js_corr
+*/
+
+//int joy;				//file handle
+char number_of_axes,number_of_buttons;	//self explaining ;)
+
+//struct input_event play;
+//struct input_event stop;
+//struct ff_effect effect;
+int raydium_joy_event_handle;
+#ifndef WIN32
+struct ff_effect effect_tremble;
+#endif
+char effect_tremble_state=0;
+clock_t last_event;
+
+
+void raydium_joy_init_vars(void)
+{
+memset(raydium_joy_button,0,RAYDIUM_BUTTONS_MAX_BUTTONS);
+raydium_joy_x=raydium_joy_y=raydium_joy_z=0.f;
+raydium_joy_click=0;
+}
+
+
+void raydium_joy_key_emul(void)
+{
+if(raydium_joy) return;
+
+if(raydium_key[GLUT_KEY_UP]) raydium_joy_y=1.f;
+if(raydium_key[GLUT_KEY_DOWN]) raydium_joy_y=-1.f;
+
+if(raydium_key[GLUT_KEY_LEFT]) raydium_joy_x=-1.f;
+if(raydium_key[GLUT_KEY_RIGHT]) raydium_joy_x=1.f;
+
+//buttons
+}
+
+#ifndef WIN32
+int raydium_joy_process_event(struct js_event e)
+{
+    switch(e.type)
+    {
+        case JS_EVENT_BUTTON:
+		    if(e.value==1)
+		    {
+			raydium_joy_click=e.number+1;
+			raydium_joy_button[e.number]=e.value;
+			#ifdef joy_debug
+			raydium_log("Button %d pushed",e.number);
+			#endif
+		    }
+		    else
+		    {
+			raydium_joy_button[e.number]=e.value;
+		    }
+        	    break;
+        case JS_EVENT_AXIS:
+		    #ifdef joy_debug
+		    raydium_log("Axis Moved: %i",e.value);
+		    #endif
+		    //here we invert values from the y axis: we want 
+		    //1 for up and -1 for down
+			if(e.value<0)
+			{
+		          #ifdef joy_debug
+			   if(e.number==1)raydium_log("Up");
+			   if(e.number==0)raydium_log("Left");
+			  #endif
+			  if(e.number==2)
+			  {
+			   raydium_joy_z=e.value/(float)32767*-1;
+			  }
+			  if(e.number==1)
+			  {
+			   raydium_joy_y=e.value/(float)32767*-1;
+			  }
+			  if(e.number==0)
+			  {
+			   raydium_joy_x=e.value/(float)32767;
+			  }
+			}
+			if(e.value>0)
+			{
+			  #ifdef joy_debug
+			   if(e.number==1)raydium_log("Down");
+			   if(e.number==0)raydium_log("Right");
+			  #endif
+			  if(e.number==2)
+			  {
+			   raydium_joy_z=e.value/(float)32767*-1;
+			  }
+			  if(e.number==1)
+			  {
+			   raydium_joy_y=e.value/(float)32767*-1;
+			  }
+			  if(e.number==0)
+			  {
+			   raydium_joy_x=e.value/(float)32767;
+			  }
+			}
+			if(e.value==0)
+			{
+			  if(e.number==1)
+			  {
+			   raydium_joy_y=0.0;
+			  }
+			  if(e.number==0)
+			  {
+			   raydium_joy_x=0.0;
+			  }
+		 	}
+		    break;
+        case JS_EVENT_INIT:
+		    //raydium_log("Joystick returned its initial state\n");
+        	    break;
+
+    }
+    return(e.type);
+}
+#endif
+
+void raydium_joy_callback(void)
+{
+#ifndef WIN32
+ struct js_event e;			//structure for storing an event
+ 
+	if(!raydium_joy) { raydium_joy_init_vars(); return; }
+
+	raydium_joy_click=0;	
+	while (read (raydium_joy, &e, sizeof(struct js_event)) > 0)
+	{
+            raydium_joy_process_event (e);
+	    //raydium_log("joy_DEBUG number:%d, value:%d",e.number,e.value);
+        }
+#else
+raydium_joy_init_vars();
+#endif
+}
+
+void raydium_joy_ff_autocenter(int perc)
+{
+#ifndef WIN32
+struct input_event ie;
+
+if(raydium_joy_event_handle<0) return;
+
+ie.type = EV_FF;
+ie.code = FF_AUTOCENTER;
+ie.value = 0xFFFFUL * perc / 100;
+
+if (write(raydium_joy_event_handle, &ie, sizeof(ie)) == -1)
+        perror("set auto-center");
+
+#endif
+}
+
+
+void raydium_joy_init(void)
+{
+ int ret;					//test var for ioctls
+ char name[128];				//driver String (and temp things)
+
+int autocenter=5;         /* default value. between 0 and 100 */
+
+	raydium_joy_init_vars();
+#ifndef WIN32
+	raydium_init_cli_option_default("joydev",name,"/dev/js0");
+	    
+	raydium_joy=open(name,O_RDONLY|O_NONBLOCK);
+
+	raydium_init_cli_option_default("evdev",name,"/dev/input/event0");
+	    
+	raydium_joy_event_handle = open(name, O_RDWR);
+	if(raydium_joy_event_handle==-1) 
+	  raydium_log("%s: cannot open (rw), no Force Feedback.",name);
+	last_event=clock();
+
+	raydium_joy_ff_autocenter(autocenter);
+	
+	if(raydium_joy==-1)
+	{
+		raydium_log("joy: FAILED\n\t ERROR opening /dev/js0");
+		raydium_joy=0;
+	}
+	else
+	{
+		raydium_log("joy: OK\n\t Cool, we have a joystick");
+		//raydium_joy=1;
+	}
+
+	if(raydium_joy)
+	{
+		ret=ioctl (raydium_joy,JSIOCGNAME(sizeof(name)),name);
+		if(ret==-1)
+		{
+	    		raydium_log("Error reading joystick driver's signature");
+	    		strncpy(name,"Unknown",sizeof(name));
+		}
+		else
+		{
+		    	raydium_log("Joystick driver's signature: %s",name);
+		}
+
+		ret=ioctl (raydium_joy,JSIOCGAXES,&number_of_axes);
+		if(ret==-1)
+		{
+	    		raydium_log("Error reading number of axes");
+		}
+		else
+		{
+	    		raydium_log("This joystick has %d axes",number_of_axes);
+		}
+
+		ret=ioctl (raydium_joy,JSIOCGBUTTONS,&number_of_buttons);
+		if(ret==-1)
+		{
+	    		raydium_log("Error reading number of buttons");
+		}
+		else
+		{
+	    		raydium_log("This joystick has %d buttons",number_of_buttons);
+		}
+	}
+#else
+    raydium_log("joy: FAILED\n\t No Joy support under Win32 yet");
+#endif
+}
+
+void raydium_joy_close(void)
+{
+	if(raydium_joy)	close(raydium_joy);
+}
+
+void raydium_joy_ff(void)
+{
+//memset(&effect,0,sizeof(struct ff_effect));
+// effect.type=FF_CONSTANT;
+// effect.u.constant.level=0xEFF0;
+// effect.u.constant.direction=0x2000;
+// effect.replay.length=65535;
+// effect.u.constant.shape.attack_length=40000;
+// effect.u.constant.shape.attack_level=0x8888;
+// effect.u.constant.shape.fade_length=20000;
+// effect.u.constant.shape.fade_level=0x2222;
+/*	effect.type = FF_SPRING;
+	effect.u.interactive.direction=0x4000;
+	effect.u.interactive.right_saturation = 32767;
+	effect.u.interactive.left_saturation = 32767;
+	effect.u.interactive.right_coeff = 32767;
+	effect.u.interactive.left_coeff = 32767;
+	effect.u.interactive.deadband = 0x0;
+	effect.u.interactive.center = 0x0;*/
+//    effect.type = FF_PERIODIC;
+/*
+#define FF_SQUARE	0x58
+#define FF_TRIANGLE	0x59
+#define FF_SINE		0x5a
+#define FF_SAW_UP	0x5b
+#define FF_SAW_DOWN	0x5c
+#define FF_CUSTOM	0x5d
+*/
+/*    effect.u.periodic.waveform=FF_TRIANGLE;
+    effect.u.periodic.period=50;
+    effect.u.periodic.magnitude=16000;
+    effect.u.periodic.direction=0x4000;*/
+    
+	
+
+
+
+
+// raydium_log("upload effect valeur=%d", ioctl(fd, EVIOCSFF, &effect));
+// perror("merde:");
+
+// play.type = EV_FF;
+// play.code = effect.id;
+//raydium_log("effect_id=%d",effect.id);
+// play.value = 10000;
+// write(fd, (const void*) &play, sizeof(play));
+
+/* stop.type = EV_FF;
+ stop.code = effect.id;
+ stop.value = 0;
+
+ write(fd, (const void*) &play, sizeof(stop));*/
+//raydium_log("remove effectvaleur=%d", ioctl(fd, EVIOCRMFF, effect.id));
+}
+
+void raydium_joy_ff_tremble_set(GLfloat period, GLfloat force)
+{
+#ifndef WIN32
+struct input_event play;
+struct input_event stop;
+
+if (clock() < last_event + CLOCKS_PER_SEC/10)
+return;
+
+
+if(effect_tremble_state)
+{
+ stop.type = EV_FF;
+ stop.code = effect_tremble.id;
+ stop.value = 0;
+ write(raydium_joy_event_handle, (const void*) &stop, sizeof(stop));
+// perror("ff: stop tremble");
+ ioctl(raydium_joy_event_handle, EVIOCRMFF, effect_tremble.id);
+// perror("ff: free tremble");
+}
+
+memset(&effect_tremble,0,sizeof(struct ff_effect));
+effect_tremble.type = FF_PERIODIC;
+effect_tremble.u.periodic.waveform=FF_TRIANGLE;
+effect_tremble.u.periodic.period=period;
+effect_tremble.u.periodic.magnitude=force;
+//effect_tremble.u.periodic.direction=0x4000; // NEED SOME WORK HERE !!
+effect_tremble.replay.length=65535;
+ioctl(raydium_joy_event_handle, EVIOCSFF, &effect_tremble);
+//perror("ff: upload tremble");
+play.type = EV_FF;
+play.code = effect_tremble.id;
+play.value = 1;
+write(raydium_joy_event_handle, (const void*) &play, sizeof(play));
+//perror("ff: play tremble");
+effect_tremble_state=1;
+last_event=clock();
+//printf("ff event refreshed\n");
+#endif
+}
+
Index: raydium/console.c
===================================================================
--- raydium/console.c	(revision 0)
+++ raydium/console.c	(revision 1)
@@ -0,0 +1,440 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/console.h"
+#endif 
+
+// proto
+void raydium_console_exec_last_command(void);
+void raydium_console_history_add(char *str);
+
+
+void raydium_console_init(void)
+{
+int i;
+FILE *fp;
+char line[RAYDIUM_MAX_NAME_LEN];
+
+raydium_console_pos=0;
+raydium_console_inc=0;
+raydium_console_config_max=50;
+raydium_console_config_speed=3;
+raydium_init_cli_option_default("consoletexture",raydium_console_config_texture,"rgb(0.2,0.2,0.2)");
+raydium_init_cli_option_default("consolefont",raydium_console_config_font,"font2.tga");
+raydium_console_line_last=-1;
+for(i=0;i<RAYDIUM_CONSOLE_MAX_LINES;i++)
+ raydium_console_lines[i][0]=0;
+raydium_console_get_string[0]=0;
+raydium_console_get_string_last[0]=0;
+
+raydium_init_cli_option_default("history",raydium_console_history_filename,"raydium_history");
+for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY;i++)
+    raydium_console_history[i][0]=0;
+raydium_console_history_index_current=-1;
+raydium_console_history_index=0;
+
+fp=fopen(raydium_console_history_filename,"rt");
+if(fp)
+    {
+    while(fgets(line,RAYDIUM_MAX_NAME_LEN,fp))
+	{
+	line[strlen(line)-1]=0;
+	raydium_console_history_add(line);
+        }
+    fclose(fp);
+    }
+}
+
+
+void raydium_console_history_save(void)
+{
+int i;
+FILE *fp;
+char last[RAYDIUM_MAX_NAME_LEN];
+
+last[0]=0;
+
+fp=fopen(raydium_console_history_filename,"wt");
+if(!fp)
+    {
+    raydium_log("console: error: cannot save history file ('%s')",raydium_console_history_filename);
+    return;
+    }
+
+for(i=0;i<raydium_console_history_index;i++)
+    if(strcmp(raydium_console_history[i],last))
+	{
+	strcpy(last,raydium_console_history[i]);
+	fprintf(fp,"%s\n",raydium_console_history[i]);
+	}
+fclose(fp);
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Now DISABLED, 
+// use raydium_console_gets_callback fptr instead.
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+int raydium_console_gets(char *where)
+{
+// always here for compat' only, do not use.
+/*if(strlen(raydium_console_get_string_last))
+ {
+ strcpy(where,raydium_console_get_string_last);
+ raydium_console_get_string_last[0]=0;
+ return 1;
+ } else*/ return 0;
+}
+
+
+
+void raydium_console_history_previous(void)
+{
+raydium_console_history_index_current--;
+
+if(raydium_console_history_index_current<0) 
+    {
+    raydium_console_history_index_current=0;
+    return;
+    }
+strcpy(raydium_console_get_string,raydium_console_history[raydium_console_history_index_current]);
+}
+
+void raydium_console_history_next(void)
+{
+raydium_console_history_index_current++;
+
+if(raydium_console_history_index_current>=raydium_console_history_index)
+    {
+    raydium_console_history_index_current=raydium_console_history_index;
+    strcpy(raydium_console_get_string,"");
+    return;
+    }
+strcpy(raydium_console_get_string,raydium_console_history[raydium_console_history_index_current]);
+}
+
+
+void raydium_console_history_add(char *str)
+{
+int i;
+
+
+if(raydium_console_history_index==RAYDIUM_CONSOLE_MAX_HISTORY)
+    {
+    raydium_console_history_index_current=raydium_console_history_index;
+    /*
+    printf("-----\n");
+    for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY;i++)
+	printf("%s\n",raydium_console_history[i]);
+    */
+
+    for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY-1;i++)
+	strcpy(raydium_console_history[i],raydium_console_history[i+1]);
+
+    strcpy(raydium_console_history[RAYDIUM_CONSOLE_MAX_HISTORY-1],str);
+    /*
+    printf("-----\n");
+    for(i=0;i<RAYDIUM_CONSOLE_MAX_HISTORY;i++)
+	printf("%s\n",raydium_console_history[i]);
+    */
+    return;
+    }
+raydium_console_history_index_current=raydium_console_history_index+1;
+strcpy(raydium_console_history[raydium_console_history_index],str);
+raydium_console_history_index++;
+}
+
+
+void raydium_console_exec_script(char *file)
+{
+FILE *fp;
+char command[RAYDIUM_MAX_NAME_LEN];
+
+if(!raydium_console_gets_callback)
+    {
+    raydium_log("ERROR: console: script: no command callback is defined, aborded.");
+    return;
+    }
+
+fp=raydium_file_fopen(file,"rt");
+if(!fp)
+    {
+    raydium_log("ERROR: console: script: file not found \"%s\"",file);
+    return;
+    }
+while(fgets(command,RAYDIUM_MAX_NAME_LEN,fp))
+    {
+    strcpy(raydium_console_get_string_last,command);
+    raydium_console_exec_last_command();
+    }
+
+fclose(fp);
+}
+
+
+void raydium_console_exec_last_command(void)
+{
+int treated=0;
+void (*f)(char *);
+char temp[RAYDIUM_MAX_NAME_LEN];
+
+raydium_console_get_string_last[strlen(raydium_console_get_string_last)-1]=0;
+raydium_console_history_add(raydium_console_get_string_last);
+
+if(raydium_console_get_string_last[0]=='!')
+    {
+    treated=1;
+    raydium_console_exec_script(raydium_console_get_string_last+1);
+    }
+
+if(raydium_console_get_string_last[0]=='>')
+    {
+    treated=1;
+#ifdef PHP_SUPPORT
+    raydium_php_exec(raydium_console_get_string_last+1);
+#else
+    raydium_log("ERROR: No PHP support compiled");
+#endif
+    }
+
+if(raydium_console_get_string_last[0]!='/' && !treated)
+{
+#ifdef PHP_SUPPORT
+#define TEMPFILE "temp.delme.php"
+FILE *fp;
+fp=fopen(TEMPFILE,"wt");
+if(!fp) { raydium_log("console: php call: cannot create %s temporary file",TEMPFILE); return; }
+fprintf(fp,"<? %s; ?>",raydium_console_get_string_last);
+fclose(fp);
+raydium_php_exec(TEMPFILE);
+treated=1; // all is sended to PHP for now
+#endif
+}
+
+
+if(!treated && raydium_console_gets_callback)
+    {
+    f=raydium_console_gets_callback;
+    strcpy(temp,raydium_console_get_string_last+1);
+    f(temp);
+    }
+
+}
+
+// need to secure this one too
+void raydium_console_line_add(char *format, ...)
+{
+unsigned char str[RAYDIUM_MAX_NAME_LEN];
+va_list argptr;
+va_start(argptr,format);
+vsprintf(str,format,argptr);
+va_end(argptr);
+
+raydium_console_line_last++;
+if(raydium_console_line_last>=RAYDIUM_CONSOLE_MAX_LINES)
+   raydium_console_line_last=0;
+
+strcpy(raydium_console_lines[raydium_console_line_last],str);
+}
+
+void raydium_console_event(void)
+{
+if(raydium_console_inc!=0) raydium_console_inc*=-1;
+else {
+	if(raydium_console_pos==0) raydium_console_inc=raydium_console_config_speed;
+	else raydium_console_inc=-raydium_console_config_speed;
+     }
+}
+
+void raydium_console_draw(void)
+{
+GLfloat y;
+int i,start;
+int texsave;
+raydium_console_pos+=raydium_console_inc*(raydium_frame_time*100);
+
+if(raydium_console_pos<0)
+ {
+ raydium_console_pos=0;
+ raydium_console_inc=0;
+ }
+ 
+if(raydium_console_pos>raydium_console_config_max)
+ {
+ raydium_console_pos=raydium_console_config_max;
+ raydium_console_inc=0;
+ }
+
+if(!raydium_console_pos) return;
+
+raydium_osd_start();
+texsave=raydium_texture_current;
+raydium_texture_current_set_name(raydium_console_config_texture);
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+
+glBegin(GL_QUADS);
+glTexCoord2f(0,0);
+glVertex3f(0,100-raydium_console_pos,0);
+glTexCoord2f(1,0);
+glVertex3f(100,100-raydium_console_pos,0);
+glTexCoord2f(1,1);
+glVertex3f(100,100,0);
+glTexCoord2f(0,1);
+glVertex3f(0,100,0);
+glEnd();
+
+raydium_osd_stop();
+
+y=100-raydium_console_pos+(RAYDIUM_CONSOLE_FONT_SIZE/6.f);
+
+raydium_osd_printf(1,y,RAYDIUM_CONSOLE_FONT_SIZE,RAYDIUM_CONSOLE_FONT_SPACER,raydium_console_config_font,"%s_",raydium_console_get_string);
+y+=(RAYDIUM_CONSOLE_FONT_SIZE/6.f);
+
+start=raydium_console_line_last;
+for(i=start;i>=0;i--)
+ {
+ raydium_osd_color_ega('f');
+ raydium_osd_printf(1,y,RAYDIUM_CONSOLE_FONT_SIZE,RAYDIUM_CONSOLE_FONT_SPACER,raydium_console_config_font,raydium_console_lines[i]);
+ y+=(RAYDIUM_CONSOLE_FONT_SIZE/6.f);
+ }
+
+for(i=RAYDIUM_CONSOLE_MAX_LINES-1;i>raydium_console_line_last;i--)
+ {
+ raydium_osd_color_ega('f');
+ raydium_osd_printf(1,y,RAYDIUM_CONSOLE_FONT_SIZE,RAYDIUM_CONSOLE_FONT_SPACER,raydium_console_config_font,raydium_console_lines[i]);
+ y+=(RAYDIUM_CONSOLE_FONT_SIZE/6.f);
+ }
+
+//raydium_texture_current_set(texsave); 
+//raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+}
+
+
+// is alpha, num or '_' ?
+int raydium_console_internal_isalphanumuscore(char c)
+{
+if(c=='_' || isalnum(c)) return 1;
+return 0;
+}
+
+
+// "str": RAYDIUM_MAX_NAME_LEN only
+
+void raydium_console_complete(char *str)
+{
+char candidates[RAYDIUM_CONSOLE_MAX_COMPLETION][RAYDIUM_MAX_NAME_LEN];
+char candidates_type[RAYDIUM_CONSOLE_MAX_COMPLETION];
+int n_candidates=0;
+char word[RAYDIUM_MAX_NAME_LEN];
+char candidate[RAYDIUM_MAX_NAME_LEN];
+int word_offset;
+int i,j;
+int len;
+int candidate_min_len;
+char c;
+
+// 0 - find last word, and store start offset
+len=strlen(str);
+//if(len==0) return;
+for(i=(len-1);i>=0;i--)
+    {
+    if(!raydium_console_internal_isalphanumuscore(str[i]))
+	{
+	i++;
+	break;
+	}
+    }
+if(i==-1) i=0; // first word of sentence
+
+//if(i<0 || !raydium_console_internal_isalphanumuscore(str[i])) 
+    //return; // empty word
+
+word_offset=i;
+strcpy(word,str+i);
+len=strlen(word);
+
+// 1 - build candidates list
+for(i=0;i<raydium_register_variable_index;i++)
+    {
+    strcpy(candidate,raydium_register_variable_name[i]);
+    candidate[len]=0;
+    if(!strcmp(candidate,word))
+	{
+	candidates_type[n_candidates]=0; // 0 = variable
+	strcpy(candidates[n_candidates++],raydium_register_variable_name[i]);
+	}
+    if(n_candidates==RAYDIUM_CONSOLE_MAX_COMPLETION) break;
+    }
+
+if(n_candidates<RAYDIUM_CONSOLE_MAX_COMPLETION)
+for(i=0;i<raydium_register_function_index;i++)
+    {
+    strcpy(candidate,raydium_register_function_list[i].fname);
+    candidate[len]=0;
+    if(!strcmp(candidate,word))
+	{
+	candidates_type[n_candidates]=1; // 1 = function
+	strcpy(candidates[n_candidates++],raydium_register_function_list[i].fname);
+	}
+    if(n_candidates==RAYDIUM_CONSOLE_MAX_COMPLETION) break;
+    }
+
+// 2 - no candidate ? only one ?
+if(!n_candidates)
+    return;
+
+if(n_candidates==1)
+    {
+    str[word_offset]=0;
+    if(strlen(str)+strlen(candidates[0]) >= (RAYDIUM_MAX_NAME_LEN-1))
+	return;	
+    strcat(str,candidates[0]);
+    if(candidates_type[0])
+	strcat(str,"(");
+    else
+	strcat(str," ");
+    return;
+    }
+    
+// 3 - more than one candidate : display candidates and find the common root
+raydium_console_line_add("> %s",str);
+
+// display
+for(i=0;i<n_candidates;i++)
+    {
+    if(candidates_type[i])
+	raydium_console_line_add("%s()",candidates[i]);
+    else
+	raydium_console_line_add("$%s",candidates[i]);
+    }
+if(n_candidates==RAYDIUM_CONSOLE_MAX_COMPLETION)
+    raydium_console_line_add("..."); // limited results
+
+// root: find shortest candidate
+candidate_min_len=RAYDIUM_MAX_NAME_LEN+1;
+for(i=0;i<n_candidates;i++)
+  if(strlen(candidates[i])<candidate_min_len)
+    candidate_min_len=strlen(candidates[i]);
+
+// root: find common chars
+for(i=strlen(word);i<=candidate_min_len;i++) // '\0' must be tested, too
+    {
+    c=candidates[0][i];
+    for(j=1;j<n_candidates;j++)
+      if(c!=candidates[j][i]) // last equiv
+	{
+	candidates[0][i]=0;
+	strcpy(candidate,candidates[0]);
+	str[word_offset]=0;
+	if(strlen(str)+strlen(candidate) >= (RAYDIUM_MAX_NAME_LEN-1))
+	    return;
+	strcat(str,candidate);
+	return;
+	}
+    }
+}
Index: raydium/sky.c
===================================================================
--- raydium/sky.c	(revision 0)
+++ raydium/sky.c	(revision 1)
@@ -0,0 +1,122 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/sky.h"
+#endif
+
+void raydium_sky_box_cache(void)
+{
+raydium_texture_current_set_name("BOXfront.tga");
+raydium_texture_current_set_name("BOXback.tga");
+raydium_texture_current_set_name("BOXleft.tga");
+raydium_texture_current_set_name("BOXright.tga");
+raydium_texture_current_set_name("BOXbottom.tga");
+raydium_texture_current_set_name("BOXtop.tga");
+}
+
+
+void raydium_sky_box_render(GLfloat x, GLfloat y, GLfloat z)
+{
+//GLfloat one[]={1.,1.,1.,1.};
+#define sizeb ((raydium_projection_far-raydium_projection_near)/2.f)
+/*
+GLfloat (x+size)=(x+5);
+GLfloat sizey=(x+5);
+GLfloat (z+size)=(x+5);
+GLfloat minv=(x-5);
+*/
+
+if(raydium_fog_enabled_tag && !raydium_sky_force) return;
+
+glDisable(GL_LIGHTING);
+glDisable(GL_FOG);
+//glColor4fv(raydium_background_color);
+//glColor4fv(one);
+
+raydium_texture_current_set_name("BOXfront.tga");
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current_set_name("BOXfront.tga"));
+glColor4fv(raydium_background_color);
+glDepthMask(GL_FALSE);
+glBegin(GL_QUADS);
+    glTexCoord2f(1.0f, 1.0f); glVertex3f((x+sizeb),(y-sizeb),(z-sizeb));
+    glTexCoord2f(0.0f, 1.0f); glVertex3f((x+sizeb),(y+sizeb),(z-sizeb));
+    glTexCoord2f(0.0f, 0.0f); glVertex3f((x+sizeb),(y+sizeb),(z+sizeb)); 
+    glTexCoord2f(1.0f, 0.0f); glVertex3f((x+sizeb),(y-sizeb),(z+sizeb));
+glEnd();
+
+				
+raydium_texture_current_set_name("BOXback.tga");
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current_set_name("BOXback.tga"));
+glColor4fv(raydium_background_color);
+glDepthMask(GL_FALSE);
+glBegin(GL_QUADS);
+    glTexCoord2f(0.0f, 1.0f); glVertex3f((x-sizeb),(y-sizeb),(z-sizeb));
+    glTexCoord2f(1.0f, 1.0f); glVertex3f((x-sizeb),(y+sizeb),(z-sizeb));
+    glTexCoord2f(1.0f, 0.0f); glVertex3f((x-sizeb),(y+sizeb),(z+sizeb)); 
+    glTexCoord2f(0.0f, 0.0f); glVertex3f((x-sizeb),(y-sizeb),(z+sizeb));
+glEnd();
+
+
+raydium_texture_current_set_name("BOXright.tga");
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current_set_name("BOXright.tga"));
+glColor4fv(raydium_background_color);
+glDepthMask(GL_FALSE);
+glBegin(GL_QUADS);
+    glTexCoord2f(0.0f, 1.0f); glVertex3f((x-sizeb),(y+sizeb),(z-sizeb));
+    glTexCoord2f(1.0f, 1.0f); glVertex3f((x+sizeb),(y+sizeb),(z-sizeb));
+    glTexCoord2f(1.0f, 0.0f); glVertex3f((x+sizeb),(y+sizeb),(z+sizeb)); 
+    glTexCoord2f(0.0f, 0.0f); glVertex3f((x-sizeb),(y+sizeb),(z+sizeb));
+glEnd();
+
+raydium_texture_current_set_name("BOXleft.tga");
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current_set_name("BOXleft.tga"));
+glColor4fv(raydium_background_color);
+glDepthMask(GL_FALSE);
+glBegin(GL_QUADS);
+    glTexCoord2f(1.0f, 1.0f); glVertex3f((x-sizeb),(y-sizeb),(z-sizeb));
+    glTexCoord2f(0.0f, 1.0f); glVertex3f((x+sizeb),(y-sizeb),(z-sizeb));
+    glTexCoord2f(0.0f, 0.0f); glVertex3f((x+sizeb),(y-sizeb),(z+sizeb)); 
+    glTexCoord2f(1.0f, 0.0f); glVertex3f((x-sizeb),(y-sizeb),(z+sizeb));
+glEnd();
+
+raydium_texture_current_set_name("BOXtop.tga");
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current_set_name("BOXtop.tga"));
+glColor4fv(raydium_background_color);
+glDepthMask(GL_FALSE);
+glBegin(GL_QUADS);
+    glTexCoord2f(0.0f, 0.0f); glVertex3f((x-sizeb),(y-sizeb),(z+sizeb));
+    glTexCoord2f(1.0f, 0.0f); glVertex3f((x+sizeb),(y-sizeb),(z+sizeb));
+    glTexCoord2f(1.0f, 1.0f); glVertex3f((x+sizeb),(y+sizeb),(z+sizeb)); 
+    glTexCoord2f(0.0f, 1.0f); glVertex3f((x-sizeb),(y+sizeb),(z+sizeb));
+glEnd();
+
+
+raydium_texture_current_set_name("BOXbottom.tga");
+raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+//glBindTexture(GL_TEXTURE_2D,raydium_texture_current_set_name("BOXbottom.tga"));
+glColor4fv(raydium_background_color);
+glDepthMask(GL_FALSE);
+glBegin(GL_QUADS);
+    glTexCoord2f(0.0f, 1.0f); glVertex3f((x-sizeb),(y-sizeb),(z-sizeb));
+    glTexCoord2f(1.0f, 1.0f); glVertex3f((x+sizeb),(y-sizeb),(z-sizeb));
+    glTexCoord2f(1.0f, 0.0f); glVertex3f((x+sizeb),(y+sizeb),(z-sizeb)); 
+    glTexCoord2f(0.0f, 0.0f); glVertex3f((x-sizeb),(y+sizeb),(z-sizeb));
+glEnd();
+
+
+if(raydium_light_enabled_tag) glEnable(GL_LIGHTING);
+if(raydium_fog_enabled_tag) glEnable(GL_FOG);
+glDepthMask(GL_TRUE);
+
+}
Index: raydium/window.c
===================================================================
--- raydium/window.c	(revision 0)
+++ raydium/window.c	(revision 1)
@@ -0,0 +1,117 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/window.h"
+#endif
+
+// proto
+void raydium_init_engine(void);
+int raydium_init_cli_option(char *option, char *value);
+
+void raydium_window_close(void)
+{
+//glutDestroyWindow(...);
+}
+
+// TODO: need to exit form game mode is enabled !
+
+void raydium_window_create(GLuint tx, GLuint ty,char rendering,char *name)
+{
+char mode[RAYDIUM_MAX_NAME_LEN];
+
+glutInit(&raydium_init_argc, raydium_init_argv);
+if(raydium_init_cli_option("fullscreen",NULL) && rendering!=RAYDIUM_RENDERING_NONE)
+    rendering=RAYDIUM_RENDERING_FULLSCREEN;
+
+raydium_window_mode=rendering;
+if(rendering==RAYDIUM_RENDERING_NONE) 
+    {
+    raydium_init_engine();
+    return;
+    }
+
+#ifndef WIN32
+// prefered under Linux
+glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+#else
+// seems to be the only way to get 24b zbuffer under win32
+glutInitDisplayString("rgb>=8 double depth>=16");
+#endif
+
+sprintf(mode,"%ix%i:32",tx,ty);
+raydium_log("Requesting %s mode",mode);
+ if(rendering==RAYDIUM_RENDERING_FULLSCREEN) 
+ {
+  glutGameModeString(mode);
+  if(!glutGameModeGet(GLUT_GAME_MODE_POSSIBLE)) raydium_log("cannot fullscreen to %s mode",mode);
+   glutEnterGameMode(); // GLUT will use a "fake" Fullscreen if real one's not possible
+ }
+ 
+ if(rendering==RAYDIUM_RENDERING_WINDOW)
+ {
+  glutInitWindowSize(tx,ty);
+  glutCreateWindow(name);
+ }
+
+raydium_log("Got %ix%i:%i mode",glutGet(GLUT_WINDOW_WIDTH),
+glutGet(GLUT_WINDOW_HEIGHT),
+glutGet(GLUT_WINDOW_DEPTH_SIZE));
+
+atexit(raydium_window_close);
+raydium_log("using %s, from %s (version %s)",glGetString(GL_RENDERER),glGetString(GL_VENDOR),glGetString(GL_VERSION));
+raydium_init_engine();
+raydium_mouse_x=tx/2;
+raydium_mouse_y=ty/2;
+}
+
+void raydium_window_resize_callback(GLsizei Width, GLsizei Height)
+{
+if(!Height) Height=1; // height=0 IS possible
+
+// called each frame !!
+//raydium_log("resized to %i %i\n",Width,Height);
+
+glMatrixMode(GL_PROJECTION);
+glLoadIdentity();
+glViewport(0, 0, Width, Height);
+
+raydium_window_tx=Width;
+raydium_window_ty=Height;
+
+
+if(raydium_projection==RAYDIUM_PROJECTION_ORTHO)
+glOrtho(raydium_projection_left,raydium_projection_right,
+        raydium_projection_bottom,raydium_projection_top,
+	raydium_projection_near,raydium_projection_far);
+
+if(raydium_projection==RAYDIUM_PROJECTION_PERSPECTIVE)
+gluPerspective(raydium_projection_fov,(GLfloat)Width/(GLfloat)Height,
+               raydium_projection_near,raydium_projection_far);
+
+
+glMatrixMode(GL_MODELVIEW);
+glLoadIdentity();
+}
+
+
+
+void raydium_window_view_update(void)
+{
+raydium_window_resize_callback(raydium_window_tx,raydium_window_ty);
+raydium_fog_mode();
+}
+
+void raydium_window_view_perspective(GLfloat fov, GLfloat fnear, GLfloat ffar)
+{
+raydium_projection=RAYDIUM_PROJECTION_PERSPECTIVE;
+if(fov>=0)  raydium_projection_fov =fov;
+if(fnear>=0) raydium_projection_near=fnear;
+if(ffar>=0)  raydium_projection_far =ffar;
+raydium_window_view_update();
+}
Index: raydium/ode.c
===================================================================
--- raydium/ode.c	(revision 0)
+++ raydium/ode.c	(revision 1)
@@ -0,0 +1,3755 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/ode.h"
+#endif 
+
+// TODO:
+// load object from file
+// delete callbaks (elements, motors, ... ?) (done for joints)
+// parametric frictions
+// other joints
+// allow full RayODE reset (almost done now)
+// multiple grounds
+// bugfix for rotation friction
+
+#include "ode.h"
+
+void raydium_ode_name_auto(char *prefix, char *dest)
+{
+static int counter;
+sprintf(dest,"%s_ode_%i",prefix,counter);
+counter++;
+}
+
+
+void raydium_ode_init_object(int i)
+{
+raydium_ode_object[i].id=i;
+raydium_ode_object[i].name[0]=0;
+raydium_ode_object[i].state=0;
+raydium_ode_object[i].colliding=0;
+raydium_ode_object[i].group=NULL;
+}
+
+
+void raydium_ode_init_element(int i)
+{
+int j;
+raydium_ode_element[i].id=i;
+raydium_ode_element[i].name[0]=0;
+raydium_ode_element[i].state=0;
+raydium_ode_element[i].object=-1;
+raydium_ode_element[i].mesh=-1;
+raydium_ode_element[i]._touched=0;
+raydium_ode_element[i]._movesfrom=-1;
+raydium_ode_element[i].isplayer=0;
+raydium_ode_element[i].playerangle=0;
+raydium_ode_element[i].slip=0;
+raydium_ode_element[i].rotfriction=0;
+raydium_ode_element[i].geom=NULL;
+raydium_ode_element[i].body=NULL;
+raydium_ode_element[i].erp=0;
+raydium_ode_element[i].cfm=0;
+raydium_ode_element[i].user_data=NULL;
+raydium_ode_element[i].user_tag=0;
+// I consider every fixed element is already free()
+for(j=0;j<RAYDIUM_ODE_ELEMENT_MAX_FIXING;j++)
+    raydium_ode_element[i].fixed_elements[j]=NULL;
+raydium_ode_element[i].nid=-1;
+raydium_ode_element[i].distant=0;
+raydium_ode_element[i].distant_owner=-1;
+raydium_ode_element[i].OnBlow=NULL;
+raydium_ode_element[i].OnDelete=NULL;
+raydium_ode_element[i].ttl=-1; // infinite
+raydium_ode_element[i].particle=-1;
+memset(raydium_ode_element[i].particle_offset,0,sizeof(dReal)*3);
+raydium_ode_element[i].ground_texture=0;
+memset(raydium_ode_element[i].net_last_pos1,0,sizeof(dReal)*3);
+memset(raydium_ode_element[i].net_last_pos2,0,sizeof(dReal)*3);
+//raydium_ode_element[i].net_last_time=raydium_timecall_clock();
+raydium_ode_element[i].net_last_time=0; // no previous update
+raydium_ode_element[i].net_last_interval=0;
+memset(raydium_ode_element[i].netvel,0,sizeof(dReal)*3);
+raydium_ode_element[i].marked_as_deleted=0;
+}
+
+void raydium_ode_init_joint(int i)
+{
+raydium_ode_joint[i].id=i;
+raydium_ode_joint[i].name[0]=0;
+raydium_ode_joint[i].state=0;
+raydium_ode_joint[i].mesh=-1;	    
+raydium_ode_joint[i].joint=NULL;
+//raydium_ode_joint[i].hinge2correct=0;
+raydium_ode_joint[i].breakableforce=0;
+raydium_ode_joint[i].breaking=0;
+raydium_ode_joint[i].OnDelete=NULL;
+}
+
+void raydium_ode_init_motor(int i)
+{
+int j;
+
+raydium_ode_motor[i].id=i;
+raydium_ode_motor[i].name[0]=0;
+raydium_ode_motor[i].state=0;
+raydium_ode_motor[i].object=-1;
+raydium_ode_motor[i].speed=0;
+raydium_ode_motor[i].force=0;
+raydium_ode_motor[i].angle=0;
+raydium_ode_motor[i].rocket_element=-1;
+raydium_ode_motor[i].rocket_playermovement=0;
+for(j=0;j<3;j++)
+    {
+    raydium_ode_motor[i].rocket_direction[j]=0;
+    raydium_ode_motor[i].rocket_position[j]=0;
+    raydium_ode_motor[i].rocket_orientation[j]=0;
+    }
+
+for(j=0;j<RAYDIUM_ODE_MOTOR_MAX_JOINTS;j++)
+    {
+    raydium_ode_motor[i].joints[j]=-1;
+    raydium_ode_motor[i].joints_axe[j]=0;
+    }
+raydium_ode_motor[i].gears[0]=1.f;
+raydium_ode_motor[i].gear=0;
+raydium_ode_motor[i].gear_max=0;
+}
+
+void raydium_ode_init_explosion(int e)
+{
+int j;
+raydium_ode_explosion[e].id=e;
+raydium_ode_explosion[e].name[0]=0;
+raydium_ode_explosion[e].state=0;
+raydium_ode_explosion[e].config_radius=0;
+raydium_ode_explosion[e].config_propag=0;
+raydium_ode_explosion[e].radius=0;
+raydium_ode_explosion[e].element=-1;
+for(j=0;j<3;j++)
+    raydium_ode_explosion[e].position[j]=0;
+}
+
+void raydium_ode_init(void)
+{
+int i;
+
+if(sizeof(dReal) != sizeof(float))
+    {
+    raydium_log("physics: FAILED");
+    raydium_log("physics: You need SINGLE precision for ODE");
+    exit(34);
+    }
+
+raydium_ode_ExplosionCallback=NULL;
+raydium_ode_CollideCallback=NULL;
+raydium_ode_StepCallback=NULL;
+raydium_ode_BeforeElementDrawCallback=NULL;
+raydium_ode_AfterElementDrawCallback=NULL;
+raydium_ode_ObjectNearCollide=NULL;
+raydium_ode_world=dWorldCreate();
+raydium_ode_space=dHashSpaceCreate(0);
+raydium_ode_contactgroup=dJointGroupCreate(0);
+dWorldSetGravity(raydium_ode_world,0,0,-1.0);
+raydium_ode_ground_mesh=-1;
+raydium_ode_network_distant_create=0;
+raydium_ode_network_next_local_only=0;
+raydium_ode_network_explosion_create=0;
+raydium_ode_element_delete_LOCK=0;
+
+for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
+    raydium_ode_init_object(i);
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    raydium_ode_init_element(i);
+    
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    raydium_ode_init_joint(i);
+
+for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    raydium_ode_init_motor(i);
+
+for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
+    raydium_ode_init_explosion(i);
+
+#ifndef ODE_MANUAL_CALLBACK
+raydium_ode_timecall=raydium_timecall_add(&raydium_ode_callback,RAYDIUM_ODE_PHYSICS_FREQ);
+#endif
+
+#ifdef ODE_QUICKSTEP
+dWorldSetQuickStepNumIterations (raydium_ode_world,10);
+//dWorldSetAutoDisableFlag (raydium_ode_world,1);
+//dWorldSetContactMaxCorrectingVel (raydium_ode_world,0.1);
+//dWorldSetContactSurfaceLayer (raydium_ode_world,0.001);
+#endif
+
+// wow ! This is my first init dependance ;)
+raydium_ode_object_create("GLOBAL");
+raydium_ode_network_init();
+
+raydium_log("physics: ODE Net: %i element(s)/packet",raydium_ode_network_MaxElementsPerPacket());
+raydium_log("physics: OK");
+}
+
+
+char raydium_ode_object_isvalid(int i)
+{
+if(i>=0 && i<RAYDIUM_ODE_MAX_OBJECTS &&
+   raydium_ode_object[i].state)
+    return 1;
+return 0;
+}
+
+char raydium_ode_element_isvalid(int i)
+{
+if(i>=0 && i<RAYDIUM_ODE_MAX_ELEMENTS &&
+   raydium_ode_element[i].state)
+    return 1;
+return 0;
+}
+
+char raydium_ode_joint_isvalid(int i)
+{
+if(i>=0 && i<RAYDIUM_ODE_MAX_JOINTS &&
+   raydium_ode_joint[i].state)
+    return 1;
+return 0;
+}
+
+char raydium_ode_motor_isvalid(int i)
+{
+if(i>=0 && i<RAYDIUM_ODE_MAX_MOTORS &&
+   raydium_ode_motor[i].state)
+    return 1;
+return 0;
+}
+
+char raydium_ode_explosion_isvalid(int i)
+{
+if(i>=0 && i<RAYDIUM_ODE_MAX_EXPLOSIONS &&
+   raydium_ode_explosion[i].state)
+    return 1;
+return 0;
+}
+
+
+void raydium_ode_ground_dTriArrayCallback (
+	dGeomID TriMesh, dGeomID RefObject,
+        const int* TriIndices, int TriCount)
+{
+int offset;
+int max_index;
+GLfloat max_val,tmp;
+dReal *pos;
+int i;
+raydium_ode_Element *e;
+
+e=dGeomGetData(RefObject);
+pos=(dReal *)dGeomGetPosition(RefObject);
+
+if(!e) return;
+// add ground object offset:
+offset=raydium_object_start[raydium_ode_ground_mesh];
+//one=0;
+//one+=(TriIndices[0]*3);
+//printf("%i %s\n",TriCount,e->name);
+//printf("%i\n",one);
+//e->ground_texture=raydium_vertex_texture[one];
+
+max_val=
+    ((pos[0]-raydium_vertex_x[TriIndices[0]*3+offset]) +
+     (pos[1]-raydium_vertex_y[TriIndices[0]*3+offset]) +
+     (pos[2]-raydium_vertex_z[TriIndices[0]*3+offset]) );
+max_index=0;
+
+for(i=1;i<TriCount;i++)
+    {
+    tmp=
+    ((pos[0]-raydium_vertex_x[TriIndices[i]*3+offset]) +
+     (pos[1]-raydium_vertex_y[TriIndices[i]*3+offset]) +
+     (pos[2]-raydium_vertex_z[TriIndices[i]*3+offset]) );
+    if(tmp<=max_val)
+	{
+	max_index=i;
+	max_val=tmp;
+	}    
+    }
+
+//printf("%i %s %i %i\n",TriCount,e->name,TriIndices[0],TriIndices[1]);
+e->ground_texture=raydium_vertex_texture[TriIndices[max_index]*3+offset];
+raydium_vertex_tag[TriIndices[max_index]*3+offset]=1;
+}
+
+
+int raydium_ode_ground_dTriCallback(
+		dGeomID TriMesh,
+		dGeomID RefObject,
+		int TriangleIndex)
+{
+//printf("%i\n",TriangleIndex);
+raydium_vertex_tag[TriangleIndex*3]=1;
+return 1;
+}
+
+void raydium_ode_ground_set_name(char *name)
+{
+int i,j,k;
+int obj,size;
+
+static dTriMeshDataID Data;
+static int *Indices;
+static dReal *Vertices;
+static dGeomID geom;
+
+int global;
+char replace=0;
+
+
+if(raydium_ode_ground_mesh>=0)
+    {
+    //raydium_log("ODE: Error: Cannot change ground at runtime");
+    //return;
+    // OR
+    replace=1;
+    dGeomDestroy(geom);
+    dGeomTriMeshDataDestroy(Data);
+    /*
+    Data=dGeomTriMeshDataCreate();
+     dGeomTriMeshDataBuildSingle(Data,&Vertices[0],sizeof(dReal)*3,size,&Indices[0],size,3*sizeof(int));
+    geom=dCreateTriMesh(raydium_ode_space, Data, 0, 0, 0);
+    */
+    free(Indices);
+    free(Vertices);
+    }
+
+obj=raydium_object_find_load(name);
+if(obj<0)
+    {
+    raydium_log("ODE: Error: cannot load ground (%s)",name);
+    return;
+    }
+
+// let's transform tri file format to ODE format ...
+size=raydium_object_end[obj]-raydium_object_start[obj];
+Indices=malloc(size*sizeof(int));
+Vertices=malloc(size*sizeof(dReal)*3);
+raydium_ode_ground_mesh=obj;
+
+for(i=raydium_object_start[obj],j=k=0;i<raydium_object_end[obj];i+=3,j+=3)
+{
+Indices[j]=j;
+Vertices[k++]=raydium_vertex_x[i];
+Vertices[k++]=raydium_vertex_y[i];
+Vertices[k++]=raydium_vertex_z[i];
+
+Indices[j+1]=j+1;
+Vertices[k++]=raydium_vertex_x[i+1];
+Vertices[k++]=raydium_vertex_y[i+1];
+Vertices[k++]=raydium_vertex_z[i+1];
+
+Indices[j+2]=j+2;
+Vertices[k++]=raydium_vertex_x[i+2];
+Vertices[k++]=raydium_vertex_y[i+2];
+Vertices[k++]=raydium_vertex_z[i+2];
+}
+
+// There is NO way to delete the ground, yet ...
+Data=dGeomTriMeshDataCreate();
+
+// with newer ODE versions, use the following:
+dGeomTriMeshDataBuildSingle(Data,&Vertices[0],sizeof(dReal)*3,size,&Indices[0],size,3*sizeof(int));
+// and the following with ODE .039:
+//dGeomTriMeshDataBuild(Data,&Vertices[0],sizeof(dReal)*3,size,&Indices[0], size, 3*sizeof(int));
+
+geom=dCreateTriMesh(raydium_ode_space, Data, 0, 0, 0);
+
+//if(!replace)
+//    global=raydium_ode_object_create("GLOBAL");
+//else
+global=raydium_ode_object_find("GLOBAL");
+
+raydium_ode_object_colliding(global,1);
+
+raydium_ode_init_element(0);
+raydium_ode_element[0].object=global;
+strcpy(raydium_ode_element[0].name,"ground");
+raydium_ode_element[0].state=RAYDIUM_ODE_STATIC;
+raydium_ode_element[0].mesh=obj;
+raydium_ode_element[0].geom=geom;
+raydium_ode_element[0].user_tag=RAYDIUM_ODE_TAG_GROUND;
+raydium_ode_element_material(0,RAYDIUM_ODE_MATERIAL_DEFAULT);
+raydium_ode_element_slip(0,RAYDIUM_ODE_SLIP_DEFAULT);
+dGeomSetData(geom,&raydium_ode_element[0]);
+
+// sets Tri[Array]Callback: (no usable yet !)
+//dGeomTriMeshSetArrayCallback(geom,raydium_ode_ground_dTriArrayCallback);
+//dGeomTriMeshSetCallback(geom,raydium_ode_ground_dTriCallback);
+}
+
+
+int raydium_ode_object_find(char *name)
+{
+int i;
+
+for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
+    if(!strcmp(name,raydium_ode_object[i].name) && raydium_ode_object_isvalid(i))
+     return i;
+return -1;
+}
+
+
+int raydium_ode_element_find(char *name)
+{
+int i;
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(!strcmp(name,raydium_ode_element[i].name) && raydium_ode_element_isvalid(i))
+     return i;
+return -1;
+}
+
+int raydium_ode_joint_find(char *name)
+{
+int i;
+
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(!strcmp(name,raydium_ode_joint[i].name) && raydium_ode_joint_isvalid(i))
+     return i;
+return -1;
+}
+
+int raydium_ode_motor_find(char *name)
+{
+int i;
+
+for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    if(!strcmp(name,raydium_ode_motor[i].name) && raydium_ode_motor_isvalid(i))
+     return i;
+return -1;
+}
+
+int raydium_ode_explosion_find(char *name)
+{
+int i;
+
+for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
+    if(!strcmp(name,raydium_ode_explosion[i].name))
+     return i;
+return -1;
+}
+
+int raydium_ode_object_create(char *name)
+{
+int i;
+
+if(raydium_ode_object_find(name)>=0)
+    {
+    raydium_log("ODE: Error: Cannot add object \"%s\": name already exists",name);
+    return -1;
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
+    if(!raydium_ode_object[i].state)
+     {
+     strcpy(raydium_ode_object[i].name,name);
+     raydium_ode_object[i].state=1;
+     // raydium_ode_object[i].group=dCreateGeomGroup(raydium_ode_space);
+     raydium_ode_object[i].group=dSimpleSpaceCreate(raydium_ode_space);
+     dSpaceSetCleanup(raydium_ode_object[i].group,0);
+     dGeomSetData((dGeomID)raydium_ode_object[i].group,&raydium_ode_object[i]);
+     return i;
+     }
+raydium_log("ODE: Error: No more object slots ! aborting \"%s\" creation",name);
+return -1;
+}
+
+
+char raydium_ode_object_rename(int o, char *newname)
+{
+int elem;
+
+if(!raydium_ode_object_isvalid(o))
+    {
+    raydium_log("ODE: Error: cannot rename object: invalid name or index");
+    return 0;
+    }
+
+elem=raydium_ode_object_find(newname);
+if(elem>=0)
+    {
+    raydium_log("ODE: Error: cannot rename '%s' to '%s': name already exists");
+    return 0;
+    }
+
+strcpy(raydium_ode_object[o].name,newname);
+return 1;
+}
+
+char raydium_ode_object_rename_name(char *o, char *newname)
+{
+return raydium_ode_object_rename(raydium_ode_object_find(o),newname);
+}
+
+
+char raydium_ode_object_colliding(int o, char colliding)
+{
+if(!raydium_ode_object_isvalid(o))
+    {
+    raydium_log("ODE: Error: cannot set object internal colliding flag: invalid name or index");
+    return 0;
+    }
+raydium_ode_object[o].colliding=colliding;
+return 1;
+}
+
+
+char raydium_ode_object_colliding_name(char *o, char colliding)
+{
+return raydium_ode_object_colliding(raydium_ode_object_find(o),colliding);
+}
+
+
+
+void raydium_ode_object_linearvelocity_set(int o, dReal *vect)
+{
+int i;
+if(!raydium_ode_object_isvalid(o))
+    {
+    raydium_log("ODE: Error: cannot set object linear velocity: invalid name or index");
+    return;
+    }
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if( (raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD ||
+         raydium_ode_element[i].state==RAYDIUM_ODE_STATIC) &&
+         raydium_ode_element[i].object==o)
+	    dBodySetLinearVel(raydium_ode_element[i].body,vect[0],vect[1],vect[2]);
+}
+
+void raydium_ode_object_linearvelocity_set_name(char *o, dReal *vect)
+{
+raydium_ode_object_linearvelocity_set(raydium_ode_object_find(o),vect);
+}
+
+void raydium_ode_object_linearvelocity_set_name_3f(char *o, dReal vx, dReal vy, dReal vz)
+{
+dReal vect[3];
+vect[0]=vx;
+vect[1]=vy;
+vect[2]=vz;
+raydium_ode_object_linearvelocity_set_name(o,vect);
+}
+
+void raydium_ode_object_addforce(int o, dReal *vect)
+{
+int i;
+if(!raydium_ode_object_isvalid(o))
+    {
+    raydium_log("ODE: Error: cannot add force to object: invalid name or index");
+    return;
+    }
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if( raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD &&
+        raydium_ode_element[i].object==o)
+	    dBodyAddForce(raydium_ode_element[i].body,vect[0],vect[1],vect[2]);
+}
+
+void raydium_ode_object_addforce_name(char *o, dReal *vect)
+{
+raydium_ode_object_addforce(raydium_ode_object_find(o),vect);
+}
+
+void raydium_ode_object_addforce_name_3f(char *o, dReal vx, dReal vy, dReal vz)
+{
+dReal vect[3];
+vect[0]=vx;
+vect[1]=vy;
+vect[2]=vz;
+raydium_ode_object_addforce_name(o,vect);
+}
+
+void raydium_ode_element_addforce(int e, dReal *vect)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot add force to element: invalid name or index");
+    return;
+    }
+if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
+    {
+    raydium_log("ODE: Error: cannot add force to a static element");
+    return;
+    }
+		
+dBodyAddForce(raydium_ode_element[e].body,vect[0],vect[1],vect[2]);
+}
+
+void raydium_ode_element_addforce_name(char *e, dReal *vect)
+{
+raydium_ode_element_addforce(raydium_ode_element_find(e),vect);
+}
+
+void raydium_ode_element_addforce_name_3f(char *e, dReal vx, dReal vy, dReal vz)
+{
+dReal vect[3];
+vect[0]=vx;
+vect[1]=vy;
+vect[2]=vz;
+raydium_ode_element_addforce_name(e,vect);
+}
+
+void raydium_ode_element_addtorque(int e, dReal *vect)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot add torque to element: invalid name or index");
+    return;
+    }
+if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
+    {
+    raydium_log("ODE: Error: cannot add torque to a static element");
+    return;
+    }
+		
+dBodyAddTorque(raydium_ode_element[e].body,vect[0],vect[1],vect[2]);
+}
+
+void raydium_ode_element_addtorque_name(char *e, dReal *vect)
+{
+raydium_ode_element_addtorque(raydium_ode_element_find(e),vect);
+}
+
+void raydium_ode_element_addtorque_name_3f(char *e, dReal vx, dReal vy, dReal vz)
+{
+dReal vect[3];
+vect[0]=vx;
+vect[1]=vy;
+vect[2]=vz;
+raydium_ode_element_addtorque_name(e,vect);
+}
+
+
+char raydium_ode_element_material(int e, dReal erp, dReal cfm)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set element material: invalid name or index");
+    return 0;
+    }
+raydium_ode_element[e].erp=erp;
+raydium_ode_element[e].cfm=cfm;
+return 1;
+}
+
+char raydium_ode_element_material_name(char *name, dReal erp, dReal cfm)
+{
+return raydium_ode_element_material(raydium_ode_element_find(name),erp,cfm);
+}
+
+
+char raydium_ode_element_slip(int e, dReal slip)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set element slip coef: invalid name or index");
+    return 0;
+    }
+raydium_ode_element[e].slip=slip;
+return 1;
+}
+
+char raydium_ode_element_slip_name(char *e, dReal slip)
+{
+return raydium_ode_element_slip(raydium_ode_element_find(e),slip);
+}
+
+char raydium_ode_element_rotfriction(int e, dReal rotfriction)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set element rotation friction: invalid name or index");
+    return 0;
+    }
+raydium_ode_element[e].rotfriction=rotfriction;
+return 1;
+}
+
+char raydium_ode_element_rotfriction_name(char *e, dReal rotfriction)
+{
+return raydium_ode_element_rotfriction(raydium_ode_element_find(e),rotfriction);
+}
+
+dReal *raydium_ode_element_linearvelocity_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot get element linear velocity: invalid name or index");
+    return NULL;
+    }
+if(raydium_ode_element[e].state!=RAYDIUM_ODE_STANDARD)
+    {
+    raydium_log("ODE: Error: cannot get element linear velocity: not a standard object");
+    return NULL;
+    }
+return (dReal *)dBodyGetLinearVel(raydium_ode_element[e].body);
+}
+
+dReal *raydium_ode_element_linearvelocity_get_name(char *e)
+{
+return raydium_ode_element_linearvelocity_get(raydium_ode_element_find(e));
+}
+
+void raydium_ode_element_OnBlow(int e, void *OnBlow)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set OnBlow callback: invalid name or index");
+    return;
+    }
+raydium_ode_element[e].OnBlow=OnBlow;
+}
+
+void raydium_ode_element_OnBlow_name(char *e, void *OnBlow)
+{
+raydium_ode_element_OnBlow(raydium_ode_element_find(e),OnBlow);
+}
+
+void raydium_ode_element_OnDelete(int e, void *OnDelete)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set OnDelete callback: invalid name or index");
+    return;
+    }
+raydium_ode_element[e].OnDelete=OnDelete;
+}
+
+void raydium_ode_element_OnDelete_name(char *e, void *OnDelete)
+{
+raydium_ode_element_OnDelete(raydium_ode_element_find(e),OnDelete);
+}
+
+void raydium_ode_element_gravity(int e, char enable)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set gravity mode: invalid name or index");
+    return;
+    }
+
+if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
+    {
+    raydium_log("ODE: Error: cannot set gravity mode on a static element");
+    return;
+    }
+
+dBodySetGravityMode(raydium_ode_element[e].body,enable);
+}
+
+void raydium_ode_element_gravity_name(char *e, char enable)
+{
+raydium_ode_element_gravity(raydium_ode_element_find(e),enable);
+}
+
+void raydium_ode_element_ttl_set(int e, int ttl)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set ttl: invalid name or index");
+    return;
+    }
+raydium_ode_element[e].ttl=ttl;
+}
+
+void raydium_ode_element_ttl_set_name(char *e, int ttl)
+{
+raydium_ode_element_ttl_set(raydium_ode_element_find(e),ttl);
+}
+
+
+// aabb is dReal[6]
+char raydium_ode_element_aabb_get(int element, dReal *aabb)
+{
+if(!raydium_ode_element_isvalid(element))
+    {
+    raydium_log("ODE: Error: cannot get AABB: invalid name or index");
+    return 0;
+    }
+dGeomGetAABB(raydium_ode_element[element].geom,aabb);
+return 1;
+}
+
+char raydium_ode_element_aabb_get_name(char *element, dReal *aabb)
+{
+return raydium_ode_element_aabb_get(raydium_ode_element_find(element),aabb);
+}
+
+int raydium_ode_element_touched_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot get 'touched' flag: invalid name or index");
+    return 0;
+    }
+return raydium_ode_element[e]._touched;
+}
+
+int raydium_ode_element_touched_get_name(char *e)
+{
+return raydium_ode_element_touched_get(raydium_ode_element_find(e));
+}
+
+char raydium_ode_element_player_set(int e, char isplayer)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set player flag: invalid name or index");
+    return 0;
+    }
+raydium_ode_element[e].isplayer=isplayer;
+if(isplayer)
+    raydium_ode_element_slip(e,RAYDIUM_ODE_SLIP_PLAYER);
+else
+    raydium_ode_element_slip(e,RAYDIUM_ODE_SLIP_DEFAULT);
+
+return 1;
+}
+
+char raydium_ode_element_player_set_name(char *name, char isplayer)
+{
+return raydium_ode_element_player_set(raydium_ode_element_find(name),isplayer);
+}
+
+char raydium_ode_element_player_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot get player flag: invalid name or index");
+    return 0;
+    }
+return raydium_ode_element[e].isplayer;
+}
+
+char raydium_ode_element_player_get_name(char *name)
+{
+return raydium_ode_element_player_get(raydium_ode_element_find(name));
+}
+
+char raydium_ode_element_player_angle(int e, dReal angle)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set player angle: invalid name or index");
+    return 0;
+    }
+raydium_ode_element[e].playerangle=angle;
+return 1;
+}
+
+char raydium_ode_element_player_angle_name(char *e, dReal angle)
+{
+return raydium_ode_element_player_angle(raydium_ode_element_find(e),angle);
+}
+
+
+int raydium_ode_element_ground_texture_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot get ground texture: invalid name or index");
+    return 0;
+    }
+return raydium_ode_element[e].ground_texture;
+}
+
+int raydium_ode_element_ground_texture_get_name(char *e)
+{
+return raydium_ode_element_ground_texture_get(raydium_ode_element_find(e));
+}
+
+int raydium_ode_element_object_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot get element's owner: invalid name or index");
+    return 0;
+    }
+return raydium_ode_element[e].object;
+}
+
+int raydium_ode_element_object_get_name(char *e)
+{
+return raydium_ode_element_object_get(raydium_ode_element_find(e));
+}
+
+int raydium_ode_object_sphere_add(char *name, int group, dReal mass, dReal radius, char type, int tag, char *mesh)
+{
+int i;
+dMass m;
+
+if(raydium_ode_element_find(name)>=0)
+    {
+    raydium_log("ODE: Error: Cannot add element \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_object_isvalid(group))
+    {
+    raydium_log("ODE: Error: object not found while adding \"%s\"",name);
+    return -1;
+    }
+
+if(tag<0)
+    {
+    raydium_log("ODE: Error: Element creation failed: negative tags are forbidden");
+    return -1;
+    }
+
+// First element is reserved
+for(i=1;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(!raydium_ode_element[i].state)
+     {
+     strcpy(raydium_ode_element[i].name,name);
+     raydium_ode_element[i].object=group;
+     raydium_ode_element[i].user_tag=tag;
+     if(strlen(mesh))
+     {
+      raydium_ode_element[i].mesh=raydium_object_find_load(mesh);
+      if(radius<0) // AUTODETECT
+         radius=raydium_object_find_dist_max(raydium_ode_element[i].mesh)*-radius;
+     }
+
+     if(type==RAYDIUM_ODE_STANDARD)
+     {
+        raydium_ode_element[i].body=dBodyCreate(raydium_ode_world);
+        dMassSetSphere(&m,1,radius);
+	dMassAdjust(&m,mass);
+        dBodySetMass(raydium_ode_element[i].body,&m);
+        dBodySetData(raydium_ode_element[i].body,&raydium_ode_element[i]);
+//	dBodySetAutoDisableSF1(raydium_ode_element[i].body,1);
+     }  
+     else raydium_ode_element[i].body=0;
+
+     raydium_ode_element[i].geom=dCreateSphere(0,radius);
+     raydium_ode_element[i].state=type;
+     dGeomSetBody(raydium_ode_element[i].geom,raydium_ode_element[i].body);
+     dGeomSetData(raydium_ode_element[i].geom,&raydium_ode_element[i]);
+     dSpaceAdd(raydium_ode_object[group].group,raydium_ode_element[i].geom);
+     raydium_ode_element_material(i,RAYDIUM_ODE_MATERIAL_DEFAULT);
+     raydium_ode_element_slip(i,RAYDIUM_ODE_SLIP_DEFAULT);
+     raydium_ode_element[i].distant=raydium_ode_network_distant_create;
+     raydium_ode_network_distant_create=0;
+     if(!raydium_ode_network_next_local_only)
+        raydium_ode_network_element_new(i);
+     raydium_ode_network_next_local_only=0;
+     return i;
+     }
+raydium_log("ODE: No more element slots ! aborting \"%s\" creation",name);
+return -1;
+
+}
+
+int raydium_ode_object_box_add(char *name, int group, dReal mass, dReal tx, dReal ty, dReal tz, char type, int tag, char *mesh)
+{
+int i;
+dMass m;
+
+if(raydium_ode_element_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add element \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_object_isvalid(group))
+    {
+    raydium_log("ODE: Error: object not found while adding \"%s\"",name);
+    return -1;
+    }
+
+if(tag<0)
+    {
+    raydium_log("ODE: Error: Element creation failed: negative tags are forbidden");
+    return -1;
+    }
+
+// First element is reserved
+for(i=1;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(!raydium_ode_element[i].state)
+     {
+     strcpy(raydium_ode_element[i].name,name);
+     raydium_ode_element[i].object=group;
+     raydium_ode_element[i].user_tag=tag;
+     if(strlen(mesh))
+     {
+      raydium_ode_element[i].mesh=raydium_object_find_load(mesh);
+      if(tx<0) // AUTODETECT
+         {
+	 int ratio=tx;
+         raydium_object_find_axes_max(raydium_ode_element[i].mesh,&tx,&ty,&tz);
+	 tx*=(-ratio);
+	 ty*=(-ratio);
+	 tz*=(-ratio);
+	 }
+     }
+
+     if(type==RAYDIUM_ODE_STANDARD)
+     {
+        raydium_ode_element[i].body=dBodyCreate(raydium_ode_world);
+        dMassSetBox(&m,1,tx,ty,tz);
+	dMassAdjust(&m,mass);
+        dBodySetMass(raydium_ode_element[i].body,&m);
+        dBodySetData(raydium_ode_element[i].body,&raydium_ode_element[i]);
+//	dBodySetAutoDisableSF1(raydium_ode_element[i].body,1);
+     } 
+     else raydium_ode_element[i].body=0;
+
+     raydium_ode_element[i].geom=dCreateBox(0,tx,ty,tz);
+     raydium_ode_element[i].state=type;
+     dGeomSetBody(raydium_ode_element[i].geom,raydium_ode_element[i].body);
+     dGeomSetData(raydium_ode_element[i].geom,&raydium_ode_element[i]);
+     dSpaceAdd(raydium_ode_object[group].group,raydium_ode_element[i].geom);
+     raydium_ode_element_material(i,RAYDIUM_ODE_MATERIAL_DEFAULT);
+     raydium_ode_element_slip(i,RAYDIUM_ODE_SLIP_DEFAULT);
+     raydium_ode_element[i].distant=raydium_ode_network_distant_create;
+     raydium_ode_network_distant_create=0;
+     if(!raydium_ode_network_next_local_only)
+        raydium_ode_network_element_new(i);
+     raydium_ode_network_next_local_only=0;
+     return i;
+     }
+raydium_log("ODE: No more element slots ! aborting \"%s\" creation",name);
+return -1;
+
+}
+
+int raydium_ode_element_fix(char *name, int *elem, int nelems, char keepgeoms)
+{
+dReal aabb[6];
+dReal aabbR[6];
+dReal bounding[3];
+dReal position[3];
+int group;
+int elemN;
+int i,j;
+int done;
+dReal *data;
+dMass m;
+dReal mass;
+
+
+if(keepgeoms)
+    raydium_log("ODE: element_fix: keepgeoms not implemented yet !");
+
+if(raydium_ode_element_find(name)>=0)
+    {
+    raydium_log("ODE: Error: Cannot fix elements as \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(nelems<1)
+    {
+    raydium_log("ODE: Error: Must fix at least one element");
+    return -1;    
+    }
+
+for(i=0;i<nelems;i++)
+ if(!raydium_ode_element_isvalid(elem[i]))
+    {
+    raydium_log("ODE: Error: Cannot fix elements: one element is not valid");
+    return -1;
+    }
+
+for(i=0;i<nelems;i++)
+ if(raydium_ode_element[elem[i]].state!=RAYDIUM_ODE_STANDARD)
+    {
+    raydium_log("ODE: Error: Cannot fix non standard elements");
+    return -1;
+    }
+
+
+group=raydium_ode_element[elem[0]].object;
+for(i=1;i<nelems;i++)
+ if(raydium_ode_element[elem[i]].object!=group)
+    {
+    raydium_log("ODE: Error: Cannot fix elements: not owned by the same object");
+    return -1;
+    }
+
+// 2 - create new element (using AABB from elements)
+dGeomGetAABB(raydium_ode_element[elem[0]].geom,aabbR);
+    
+for(i=1;i<nelems;i++)
+    {
+    dGeomGetAABB(raydium_ode_element[elem[i]].geom,aabb);
+    for(j=0;j<6;j+=2)
+	{
+	aabbR[j  ]=raydium_trigo_min(aabb[j  ],aabbR[j  ]);
+	aabbR[j+1]=raydium_trigo_max(aabb[j+1],aabbR[j+1]);
+	}
+    }
+
+bounding[0]=aabbR[1]-aabbR[0];
+bounding[1]=aabbR[3]-aabbR[2];
+bounding[2]=aabbR[5]-aabbR[4];
+
+position[0]=aabbR[0]+(bounding[0]/2.f);
+position[1]=aabbR[2]+(bounding[1]/2.f);
+position[2]=aabbR[4]+(bounding[2]/2.f);
+
+// Now, we can create an new box element with some dummy values:
+elemN=raydium_ode_object_box_add(name,group,0.f,bounding[0],bounding[1],bounding[2],RAYDIUM_ODE_STANDARD,0,"");
+raydium_ode_element[elemN].state=RAYDIUM_ODE_FIXING;
+raydium_ode_element_move(elemN,position);
+
+// 3 - save elements to new element
+done=0;
+mass=0;
+for(i=0;i<nelems;i++)
+ for(j=0;j<RAYDIUM_ODE_ELEMENT_MAX_FIXING;j++)
+    if(raydium_ode_element[elemN].fixed_elements[j]==NULL)
+	{
+	raydium_ode_element[elemN].fixed_elements[j]=malloc(sizeof(raydium_ode_ElementInternalSave));
+	strcpy(raydium_ode_element[elemN].fixed_elements[j]->name,raydium_ode_element[elem[i]].name);
+	raydium_ode_element[elemN].fixed_elements[j]->type=dGeomGetClass(raydium_ode_element[elem[i]].geom);
+	dGeomBoxGetLengths(raydium_ode_element[elem[i]].geom,raydium_ode_element[elemN].fixed_elements[j]->box_sizes);
+	raydium_ode_element[elemN].fixed_elements[j]->sphere_radius=dGeomSphereGetRadius(raydium_ode_element[elem[i]].geom);
+	dBodyGetMass(raydium_ode_element[elem[i]].body,&m);
+	raydium_ode_element[elemN].fixed_elements[j]->mass=m.mass;
+	raydium_ode_element[elemN].fixed_elements[j]->object=raydium_ode_element[elem[i]].object;
+	raydium_ode_element[elemN].fixed_elements[j]->mesh=raydium_ode_element[elem[i]].mesh;
+	raydium_ode_element[elemN].fixed_elements[j]->slip=raydium_ode_element[elem[i]].slip;
+	raydium_ode_element[elemN].fixed_elements[j]->cfm=raydium_ode_element[elem[i]].cfm;
+	raydium_ode_element[elemN].fixed_elements[j]->erp=raydium_ode_element[elem[i]].erp;
+
+	data=(dReal *)dGeomGetPosition(raydium_ode_element[elem[i]].geom);
+	memcpy(raydium_ode_element[elemN].fixed_elements[j]->rel_pos,data,sizeof(dReal)*3);
+	raydium_ode_element[elemN].fixed_elements[j]->rel_pos[0]-=position[0];
+	raydium_ode_element[elemN].fixed_elements[j]->rel_pos[1]-=position[1];
+	raydium_ode_element[elemN].fixed_elements[j]->rel_pos[2]-=position[2];
+	dGeomGetQuaternion(raydium_ode_element[elem[i]].geom,raydium_ode_element[elemN].fixed_elements[j]->rel_rot);
+	raydium_ode_element[elemN].fixed_elements[j]->user_data=raydium_ode_element[elem[i]].user_data;
+	raydium_ode_element[elemN].fixed_elements[j]->user_tag=raydium_ode_element[elem[i]].user_tag;
+	dBodyGetMass(raydium_ode_element[elem[i]].body,&m);
+	raydium_ode_element[elemN].fixed_elements[j]->OnBlow=raydium_ode_element[elem[i]].OnBlow;
+	raydium_ode_element[elemN].fixed_elements[j]->OnDelete=raydium_ode_element[elem[i]].OnDelete;
+	mass+=m.mass;
+	done++;
+	j=RAYDIUM_ODE_ELEMENT_MAX_FIXING; // jump to next element to save
+	}
+
+if(done!=nelems)
+    raydium_log("ODE: Error: only %i/%i elems were fixed to %s ! Continue anyway...",done,nelems,name);
+
+// 4 - delete elements
+for(i=0;i<nelems;i++)
+    raydium_ode_element_delete(elem[i],1); // delete joints, too /!\ (must fix this)
+
+// 5 - compute new mass
+dMassSetBox(&m,1,bounding[0],bounding[1],bounding[2]);
+dMassAdjust(&m,mass);
+dBodySetMass(raydium_ode_element[elemN].body,&m);
+
+return elemN;
+}
+
+void raydium_ode_element_unfix(int e)
+{
+int i;
+
+raydium_log("ODE: unfix unimplemented !");
+return;
+
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot unfix element: element is not valid");
+    return;
+    }
+
+if(raydium_ode_element[e].state!=RAYDIUM_ODE_FIXING)
+    {
+    raydium_log("ODE: Error: Cannot unfix a non-fixing element");
+    return;
+    }
+
+
+for(i=0;i<RAYDIUM_ODE_ELEMENT_MAX_FIXING;i++)
+    if(raydium_ode_element[e].fixed_elements[i])
+	{
+	// TODO:
+	// test type
+	// create element (using name)
+	// move/rotate
+	// restor params (erp, cfm, ...)
+	}
+
+raydium_ode_element_delete(e,1);
+}
+
+void raydium_ode_element_move(int elem, dReal *pos)
+{
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot move element: invalid index or name");
+    return;
+    }
+dGeomSetPosition(raydium_ode_element[elem].geom,pos[0],pos[1],pos[2]);
+}
+
+void raydium_ode_element_move_3f(int elem, dReal x,dReal y, dReal z)
+{
+dReal pos[3];
+pos[0]=x;
+pos[1]=y;
+pos[2]=z;
+raydium_ode_element_move(elem,pos);
+}
+
+void raydium_ode_element_move_name(char *name, dReal *pos)
+{
+raydium_ode_element_move(raydium_ode_element_find(name),pos);
+}
+
+void raydium_ode_element_move_name_3f(char *name, dReal x,dReal y, dReal z)
+{
+raydium_ode_element_move_3f(raydium_ode_element_find(name),x,y,z);
+}
+
+void raydium_ode_element_rotate(int elem, dReal *rot)
+{
+dMatrix3 R;
+
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot rotate element: invalid index or name");
+    return;
+    }
+dRFromEulerAngles(R,rot[0],rot[1],rot[2]);
+dGeomSetRotation(raydium_ode_element[elem].geom,R);
+}
+
+void raydium_ode_element_rotate_3f(int elem, dReal rx, dReal ry, dReal rz)
+{
+dReal rot[3];
+rot[0]=rx;
+rot[1]=ry;
+rot[2]=rz;
+raydium_ode_element_rotate(elem,rot);
+}
+
+void raydium_ode_element_rotate_name(char *name, dReal *rot)
+{
+raydium_ode_element_rotate(raydium_ode_element_find(name),rot);
+}
+
+
+void raydium_ode_element_rotateq(int elem, dReal *rot)
+{
+
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot rotate element: invalid index or name");
+    return;
+    }
+dGeomSetQuaternion(raydium_ode_element[elem].geom,rot);
+}
+
+void raydium_ode_element_rotateq_name(char *name, dQuaternion rot)
+{
+raydium_ode_element_rotateq(raydium_ode_element_find(name),rot);
+}
+
+void raydium_ode_element_rotate_name_3f(char *name, dReal rx, dReal ry, dReal rz)
+{
+raydium_ode_element_rotate_3f(raydium_ode_element_find(name),rx,ry,rz);
+}
+
+void raydium_ode_element_rotate_direction(int elem, char Force0OrVel1)
+{
+dReal *vel;
+dMatrix3 R;
+
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot align element: invalid index or name");
+    return;
+    }
+
+if(raydium_ode_element[elem].state==RAYDIUM_ODE_STATIC)
+    {
+    raydium_log("ODE: Error: Cannot align a static element");
+    return;
+    }
+
+
+if(!Force0OrVel1)
+ vel=(dReal *)dBodyGetForce(raydium_ode_element[elem].body);
+else
+ vel=(dReal *)dBodyGetLinearVel(raydium_ode_element[elem].body);
+
+dRFrom2Axes(R,vel[0],vel[1],vel[2], vel[0],vel[1],vel[2]*0); // 1 0 0
+dBodySetRotation(raydium_ode_element[elem].body,R);
+}
+
+void raydium_ode_element_rotate_direction_name(char *e, char Force0OrVel1)
+{
+raydium_ode_element_rotate_direction(raydium_ode_element_find(e),Force0OrVel1);
+}
+
+void raydium_ode_element_data_set(int e, void *data)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot set element data: invalid index or name");
+    return;
+    }
+raydium_ode_element[e].user_data=data;
+}
+
+void raydium_ode_element_data_set_name(char *e, void *data)
+{
+raydium_ode_element_data_set(raydium_ode_element_find(e),data);
+}
+
+void *raydium_ode_element_data_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot get element data: invalid index or name");
+    return NULL;
+    }
+return raydium_ode_element[e].user_data;
+}
+
+void *raydium_ode_element_data_get_name(char *e)
+{
+return raydium_ode_element_data_get(raydium_ode_element_find(e));
+}
+
+int raydium_ode_element_tag_get(int e)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot get element tag: invalid index or name");
+    return 0;
+    }
+return raydium_ode_element[e].user_tag;
+}
+
+int raydium_ode_element_tag_get_name(char *e)
+{
+return raydium_ode_element_tag_get(raydium_ode_element_find(e));
+}
+
+// move object elements to pos (pos is used for the LAST element of your object)
+void raydium_ode_object_move(int obj, dReal *pos)
+{
+
+int i,n;
+raydium_ode_Element *e;
+dReal *refp;
+dReal *act;
+dReal diff[3];
+dReal ref[3];
+
+if(!raydium_ode_object_isvalid(obj))
+    {
+    raydium_log("ODE: Error: Cannot move object: invalid index or name");
+    return;
+    }
+
+//n=dGeomGroupGetNumGeoms(raydium_ode_object[obj].group);
+n=dSpaceGetNumGeoms(raydium_ode_object[obj].group);
+if(!n) return;
+
+//refp=(dReal *)dGeomGetPosition(dGeomGroupGetGeom(raydium_ode_object[obj].group,0));
+refp=(dReal *)dGeomGetPosition(dSpaceGetGeom(raydium_ode_object[obj].group,0));
+ref[0]=refp[0];
+ref[1]=refp[1];
+ref[2]=refp[2];
+e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,0));
+raydium_ode_element_move(e->id,pos);
+
+for(i=1;i<n;i++)
+    {
+    act=(dReal *)dGeomGetPosition(dSpaceGetGeom(raydium_ode_object[obj].group,i));
+    diff[0]=pos[0]+(act[0]-ref[0]);
+    diff[1]=pos[1]+(act[1]-ref[1]);
+    diff[2]=pos[2]+(act[2]-ref[2]);
+    //raydium_log("%f %f %f",act[0],act[1],act[2]);
+    e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,i));
+    raydium_ode_element_move(e->id,diff);
+    }
+
+
+}
+
+void raydium_ode_object_move_name(char *name, dReal *pos)
+{
+raydium_ode_object_move(raydium_ode_object_find(name),pos);
+}
+
+void raydium_ode_object_move_name_3f(char *name, dReal x,dReal y, dReal z)
+{
+dReal pos[3];
+pos[0]=x;
+pos[1]=y;
+pos[2]=z;
+raydium_ode_object_move_name(name,pos);
+}
+
+// rotate object (rotation is done around LAST element of obj)
+void raydium_ode_object_rotateq(int obj, dReal *rot)
+{
+int i,n;
+raydium_ode_Element *e;
+raydium_ode_Element *ref;
+dBodyID body;
+dReal *pos;
+dReal *epos;
+//dReal vect[3];
+dVector3 res;
+
+//raydium_log("obj rotate unimplemented"); return;
+
+if(!raydium_ode_object_isvalid(obj))
+    {
+    raydium_log("ODE: Error: Cannot rotateq object: invalid index or name");
+    return;
+    }
+
+n=dSpaceGetNumGeoms(raydium_ode_object[obj].group);
+if(!n) return;
+
+// 1 - rotate elements (THIS IS NOT THE CORRECT WAY TO DO IT !)
+for(i=1;i<n;i++)
+    {
+    e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,i));
+    raydium_ode_element_rotateq(e->id,rot);
+    }
+
+// 2 - create a temporary body (based on reference element)
+body=dBodyCreate(raydium_ode_world);
+ref=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,0));
+pos=raydium_ode_element_pos_get(ref->id);
+dBodySetPosition(body,pos[0],pos[1],pos[2]);
+dBodySetQuaternion(body,rot);
+
+// 3 - replace rotated elements
+for(i=1;i<n;i++)
+    {
+    // 3 - 1 - Get relative point from real body
+    e=dGeomGetData(dSpaceGetGeom(raydium_ode_object[obj].group,i));
+    epos=raydium_ode_element_pos_get(e->id);
+    dBodyGetPosRelPoint(ref->body,epos[0],epos[1],epos[2],res);
+    //printf("---> %s %f %f %f\n",e->name,res[0],res[1],res[2]);
+    // 3 - 2 - Apply relative point to world with "fake" body
+    dBodyGetRelPointPos(body,res[0],res[1],res[2],epos);
+    // 3 - 3 - Change position
+    raydium_ode_element_move(e->id,epos);
+    }
+
+dBodyDestroy(body);
+raydium_ode_element_rotateq(ref->id,rot);
+}
+
+void raydium_ode_object_rotateq_name(char *obj, dReal *rot)
+{
+raydium_ode_object_rotateq(raydium_ode_object_find(obj),rot);
+}
+
+void raydium_ode_object_rotate(int obj, dReal *rot)
+{
+dMatrix3 R;
+dQuaternion Q;
+dRFromEulerAngles(R,rot[0],rot[1],rot[2]);
+dRtoQ(R,Q);
+raydium_ode_object_rotateq(obj,Q);
+}
+
+void raydium_ode_object_rotate_name(char *obj, dReal *rot)
+{
+raydium_ode_object_rotate(raydium_ode_object_find(obj),rot);
+}
+
+void raydium_ode_object_rotate_name_3f(char *obj, dReal rx, dReal ry, dReal rz)
+{
+dReal r[3];
+r[0]=rx;
+r[1]=ry;
+r[2]=rz;
+raydium_ode_object_rotate_name(obj,r);
+}
+
+
+void raydium_ode_joint_suspension(int j, dReal erp, dReal cfm)
+{
+void (*f)(dJointID,int,dReal);
+int type;
+
+if(!raydium_ode_joint_isvalid(j))
+    {
+    raydium_log("ODE: Cannot set ERP and CFM for this joint: invalid name or index");
+    return;
+    }
+
+type=dJointGetType(raydium_ode_joint[j].joint);
+switch(type)
+    {
+    case dJointTypeHinge2:
+	f=dJointSetHinge2Param;
+	break;
+    case dJointTypeHinge:
+	f=dJointSetHingeParam;
+	break;
+    default: raydium_log("ODE: ERROR: suspension: joint type not supported!");
+    }
+f(raydium_ode_joint[j].joint,dParamSuspensionERP,erp);
+f(raydium_ode_joint[j].joint,dParamSuspensionCFM,cfm);
+}
+
+void raydium_ode_joint_suspension_name(char *j, dReal erp, dReal cfm)
+{
+raydium_ode_joint_suspension(raydium_ode_joint_find(j),erp,cfm);
+}
+
+int raydium_ode_joint_attach_hinge2(char *name, int elem1, int elem2, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
+{
+int i;
+const dReal *a;
+
+if(raydium_ode_joint_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add (hinge2) joint \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
+    {
+    raydium_log("ODE: Error: Cannot attach hinge2: one element is not valid");
+    return -1;
+    }
+
+if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
+    raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
+    {
+    raydium_log("ODE: Error: Cannot attach a static element");
+    return -1;    
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(!raydium_ode_joint[i].state)
+     {
+     dJointFeedback *jf;
+     strcpy(raydium_ode_joint[i].name,name);
+     raydium_ode_joint[i].joint=dJointCreateHinge2(raydium_ode_world,0);
+     dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
+     a=dBodyGetPosition(raydium_ode_element[elem2].body);
+     dJointSetHinge2Anchor(raydium_ode_joint[i].joint,a[0],a[1],a[2]);
+     dJointSetHinge2Axis1(raydium_ode_joint[i].joint,axe1x,axe1y,axe1z);
+     dJointSetHinge2Axis2(raydium_ode_joint[i].joint,axe2x,axe2y,axe2z);
+     dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
+     jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
+     dJointSetFeedback(raydium_ode_joint[i].joint,jf);
+     raydium_ode_joint[i].state=1;
+     dJointSetHinge2Param (raydium_ode_joint[i].joint,dParamSuspensionERP,0.1);
+     dJointSetHinge2Param (raydium_ode_joint[i].joint,dParamSuspensionCFM,0.9);
+     return i;
+     }
+raydium_log("ODE: No more joint slots ! aborting \"%s\" (hinge2) creation",name);
+return -1;
+}
+
+int raydium_ode_joint_attach_hinge2_name(char *name, char *elem1, char *elem2, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
+{
+int e1,e2;
+e1=raydium_ode_element_find(elem1);
+e2=raydium_ode_element_find(elem2);
+return raydium_ode_joint_attach_hinge2(name,e1,e2,axe1x,axe1y,axe1z,axe2x,axe2y,axe2z);
+}
+
+
+int raydium_ode_joint_attach_universal(char *name, int elem1, int elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
+{
+int i;
+
+if(raydium_ode_joint_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add (universal) joint \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
+    {
+    raydium_log("ODE: Error: Cannot attach universal: one element is not valid");
+    return -1;
+    }
+
+if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
+    raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
+    {
+    raydium_log("ODE: Error: Cannot attach a static element");
+    return -1;    
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(!raydium_ode_joint[i].state)
+     {
+     dJointFeedback *jf;
+     strcpy(raydium_ode_joint[i].name,name);
+     raydium_ode_joint[i].joint=dJointCreateUniversal(raydium_ode_world,0);
+     dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
+     dJointSetUniversalAnchor(raydium_ode_joint[i].joint,posx,posy,posz);
+     dJointSetUniversalAxis1(raydium_ode_joint[i].joint,axe1x,axe1y,axe1z);
+     dJointSetUniversalAxis2(raydium_ode_joint[i].joint,axe2x,axe2y,axe2z);
+     dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
+     jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
+     dJointSetFeedback(raydium_ode_joint[i].joint,jf);
+     raydium_ode_joint[i].state=1;
+     return i;
+     }
+raydium_log("ODE: No more joint slots ! aborting \"%s\" (universal) creation",name);
+return -1;
+}
+
+int raydium_ode_joint_attach_universal_name(char *name, char *elem1, char *elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z, dReal axe2x, dReal axe2y, dReal axe2z)
+{
+int e1,e2;
+e1=raydium_ode_element_find(elem1);
+e2=raydium_ode_element_find(elem2);
+return raydium_ode_joint_attach_universal(name,e1,e2,posx,posy,posz,axe1x,axe1y,axe1z,axe2x,axe2y,axe2z);
+}
+
+
+int raydium_ode_joint_attach_hinge(char *name, int elem1, int elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z)
+{
+int i;
+
+if(raydium_ode_joint_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add (hinge) joint \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
+    {
+    raydium_log("ODE: Error: Cannot attach hinge: one element is not valid");
+    return -1;
+    }
+
+if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
+    raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
+    {
+    raydium_log("ODE: Error: Cannot attach a static element");
+    return -1;    
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(!raydium_ode_joint[i].state)
+     {
+     dJointFeedback *jf;
+     strcpy(raydium_ode_joint[i].name,name);
+     raydium_ode_joint[i].joint=dJointCreateHinge(raydium_ode_world,0);
+     dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
+     dJointSetHingeAnchor(raydium_ode_joint[i].joint,posx,posy,posz);
+     dJointSetHingeAxis(raydium_ode_joint[i].joint,axe1x,axe1y,axe1z);
+     dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
+     jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
+     dJointSetFeedback(raydium_ode_joint[i].joint,jf);
+     raydium_ode_joint[i].state=1;
+     return i;
+     }
+raydium_log("ODE: No more joint slots ! aborting \"%s\" (hinge) creation",name);
+return -1;
+}
+
+int raydium_ode_joint_attach_hinge_name(char *name, char *elem1, char *elem2, dReal posx, dReal posy, dReal posz, dReal axe1x, dReal axe1y, dReal axe1z)
+{
+int e1,e2;
+e1=raydium_ode_element_find(elem1);
+e2=raydium_ode_element_find(elem2);
+return raydium_ode_joint_attach_hinge(name,e1,e2,posx,posy,posz,axe1x,axe1y,axe1z);
+}
+
+int raydium_ode_joint_attach_fixed(char *name, int elem1, int elem2)
+{
+int i;
+
+if(raydium_ode_joint_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add (fixed) joint \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_element_isvalid(elem1) || !raydium_ode_element_isvalid(elem2))
+    {
+    raydium_log("ODE: Error: Cannot attach fixed: one element is not valid");
+    return -1;
+    }
+
+if( raydium_ode_element[elem1].state==RAYDIUM_ODE_STATIC ||
+    raydium_ode_element[elem2].state==RAYDIUM_ODE_STATIC )
+    {
+    raydium_log("ODE: Error: Cannot attach a static element");
+    return -1;    
+    }
+
+//raydium_log("ODE: Warning: fixed joint slows down physics !");
+
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(!raydium_ode_joint[i].state)
+     {
+     dJointFeedback *jf;
+     strcpy(raydium_ode_joint[i].name,name);
+     raydium_ode_joint[i].joint=dJointCreateFixed(raydium_ode_world,0);
+     dJointAttach(raydium_ode_joint[i].joint,raydium_ode_element[elem1].body,raydium_ode_element[elem2].body);
+     dJointSetFixed(raydium_ode_joint[i].joint);
+     dJointSetData(raydium_ode_joint[i].joint,&raydium_ode_joint[i]);
+     jf=(dJointFeedback *)malloc(sizeof(dJointFeedback));
+     dJointSetFeedback(raydium_ode_joint[i].joint,jf);
+     raydium_ode_joint[i].state=1;
+     return i;
+     }
+raydium_log("ODE: No more joint slots ! aborting \"%s\" (fixed) creation",name);
+return -1;
+}
+
+int raydium_ode_joint_attach_fixed_name(char *name, char *elem1, char *elem2)
+{
+return raydium_ode_joint_attach_fixed(name,raydium_ode_element_find(elem1),raydium_ode_element_find(elem2));
+}
+
+void raydium_ode_joint_hinge_limits(int j, dReal lo, dReal hi)
+{
+if(raydium_ode_joint_isvalid(j))
+    {
+    dJointSetHingeParam(raydium_ode_joint[j].joint,dParamLoStop,lo);
+    dJointSetHingeParam(raydium_ode_joint[j].joint,dParamHiStop,hi);
+    dJointSetHingeParam(raydium_ode_joint[j].joint,dParamLoStop,lo); // ODE "feature" :)
+    return;
+    }
+raydium_log("ODE: Error: cannot set joint limits: invalid index or name");
+}
+
+void raydium_ode_joint_hinge_limits_name(char *j, dReal lo, dReal hi)
+{
+return raydium_ode_joint_hinge_limits(raydium_ode_joint_find(j),lo,hi);
+}
+
+void raydium_ode_joint_universal_limits(int j, dReal lo1, dReal hi1, dReal lo2, dReal hi2)
+{
+if(raydium_ode_joint_isvalid(j))
+    {
+    dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop ,lo1);
+    dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamHiStop ,hi1);
+    dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop ,lo1);
+
+    dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop2,lo2);
+    dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamHiStop2,hi2);
+    dJointSetUniversalParam(raydium_ode_joint[j].joint,dParamLoStop2,lo2);
+    return;
+    }
+raydium_log("ODE: Error: cannot set joint limits: invalid index or name");
+}
+
+void raydium_ode_joint_universal_limits_name(char *j, dReal lo1, dReal hi1, dReal lo2, dReal hi2)
+{
+return raydium_ode_joint_universal_limits(raydium_ode_joint_find(j),lo1,hi1,lo2,hi2);
+}
+
+
+void raydium_ode_joint_hinge2_block(int j, char block)
+{
+// TODO: test if joint is hinge2 type
+if(raydium_ode_joint_isvalid(j))
+    {
+//    raydium_ode_joint[j].hinge2correct=block;
+    if(!block)
+	{
+        dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,-dInfinity);
+	dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamHiStop,dInfinity);
+        dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,-dInfinity);
+	}
+    else
+	{
+        dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,0);
+	dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamHiStop,0);
+        dJointSetHinge2Param(raydium_ode_joint[j].joint,dParamLoStop,0);
+	}
+    return;
+    }
+raydium_log("ODE: Error: cannot block: invalid index or name");
+}
+
+
+
+void raydium_ode_joint_hinge2_block_name(char *name, char block)
+{
+raydium_ode_joint_hinge2_block(raydium_ode_joint_find(name),block);
+}
+
+void raydium_ode_joint_delete_callback(int j, void (*f)(int))
+{
+if(!raydium_ode_joint_isvalid(j))
+    {
+    raydium_log("ODE: Error: Cannot set joint \"OnDelete\" callback: invalid index/name");
+    return;
+    }
+raydium_ode_joint[j].OnDelete=f;
+}
+
+void raydium_ode_joint_delete_callback_name(char *name, void (*f)(int))
+{
+raydium_ode_joint_delete_callback(raydium_ode_joint_find(name),f);
+}
+
+void raydium_ode_joint_break_force(int j, dReal maxforce)
+{
+if(!raydium_ode_joint_isvalid(j))
+    {
+    raydium_log("ODE: Error: Cannot set break limit force: invalid index/name");
+    return;
+    }
+raydium_ode_joint[j].breakableforce=maxforce;
+}
+
+void raydium_ode_joint_break_force_name(char *name, dReal maxforce)
+{
+raydium_ode_joint_break_force(raydium_ode_joint_find(name),maxforce);
+}
+
+
+void raydium_ode_joint_elements_get(int j, int *e1, int *e2)
+{
+raydium_ode_Element *elem1;
+raydium_ode_Element *elem2;
+
+if(!raydium_ode_joint_isvalid(j))
+    {
+    raydium_log("ODE: Error: Cannot get joint's attached elements: invalid index/name");
+    return;
+    }
+
+// may crash if joint is disconnected at one of his ends !
+elem1=dBodyGetData(dJointGetBody(raydium_ode_joint[j].joint,0));
+elem2=dBodyGetData(dJointGetBody(raydium_ode_joint[j].joint,1));
+    
+*e1=elem1->id;
+*e2=elem2->id;
+}
+
+void raydium_ode_joint_elements_get_name(char *j, int *e1, int *e2)
+{
+raydium_ode_joint_elements_get(raydium_ode_joint_find(j),e1,e2);
+}
+
+void raydium_ode_motor_update_joints_data_internal(int j)
+{
+int i;
+
+if(raydium_ode_motor_isvalid(j))
+    {
+    if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ROCKET)
+    {
+    dReal speed;
+    // test if element is attached:
+    if(raydium_ode_motor[j].rocket_element<0)
+	return;
+	
+    speed=raydium_ode_motor[j].speed;
+    if(raydium_ode_motor[j].rocket_playermovement &&
+       !raydium_ode_element[raydium_ode_motor[j].rocket_element]._touched )
+       speed=0;
+
+    if(speed!=0.f)
+    dBodyAddRelForceAtRelPos(raydium_ode_element[raydium_ode_motor[j].rocket_element].body,
+			     raydium_ode_motor[j].rocket_direction[0],
+			     raydium_ode_motor[j].rocket_direction[1],
+			     raydium_ode_motor[j].rocket_direction[2],
+			     raydium_ode_motor[j].rocket_position[0],
+			     raydium_ode_motor[j].rocket_position[1],
+			     raydium_ode_motor[j].rocket_position[2]);
+    return;
+    }        
+    // if motor is anything else than a rocket:
+    for(i=0;i<RAYDIUM_ODE_MOTOR_MAX_JOINTS;i++)
+	if(raydium_ode_motor[j].joints[i]>=0)
+	{
+	void (*SetParam)(dJointID,int,dReal);
+	dReal (*GetAngle)(dJointID);
+	int vel;
+	int fmax;
+	int type;
+	char cancel=0;
+	
+	switch(raydium_ode_motor[j].joints_axe[i])
+	    {
+	    case 0:
+		vel=dParamVel;
+		fmax=dParamFMax;
+		break;
+	    case 1:
+		vel=dParamVel2;
+		fmax=dParamFMax2;
+		break;
+	    case 2:
+		vel=dParamVel3;
+		fmax=dParamFMax3;
+		break;
+	    default:
+		cancel=1;
+		raydium_log("ODE: Motor: Invalid axe for this joint (%s, motor is %s)",raydium_ode_joint[raydium_ode_motor[j].joints[i]].name,raydium_ode_motor[j].name);
+	    }
+	
+	type=dJointGetType(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint);
+    	    
+	switch(type)
+	    {
+	    case dJointTypeHinge2:
+		SetParam=dJointSetHinge2Param;
+		GetAngle=dJointGetHinge2Angle1;
+		if(raydium_ode_motor[j].joints_axe[i]!=0 && raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ANGULAR)
+		    {
+		    cancel=1;
+		    raydium_log("ODE: Only axe Hinge2 axe 0 is supported with angular motors (%s, motor is %s)",raydium_ode_joint[raydium_ode_motor[j].joints[i]].name,raydium_ode_motor[j].name);
+		    }
+		break;
+	    case dJointTypeHinge:
+		SetParam=dJointSetHingeParam;
+		GetAngle=dJointGetHingeAngle;
+		break;
+	    default:
+		cancel=1;
+		raydium_log("ODE: Motor: Invalid joint type (%s, motor is %s)",raydium_ode_joint[raydium_ode_motor[j].joints[i]].name,raydium_ode_motor[j].name);
+	    }
+	    
+	
+	if(cancel) continue; // previous tests failed
+	
+	if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ENGINE)
+		{
+		dReal speed;
+		dReal force;
+		speed=raydium_ode_motor[j].speed*raydium_ode_motor[j].gears[raydium_ode_motor[j].gear];
+		
+		if(raydium_ode_motor[j].gears[raydium_ode_motor[j].gear]==0.0)
+		    force=0;
+		else
+		    force=raydium_ode_motor[j].force*(1/raydium_ode_motor[j].gears[raydium_ode_motor[j].gear]);
+		
+//		force=raydium_ode_motor[j].force;
+//		raydium_log("speed=%f force=%f",speed,force);
+		SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,vel,speed);
+		SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,fmax,force);
+		}
+		
+	if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ANGULAR)
+	    {
+		dReal v;
+		SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,fmax,raydium_ode_motor[j].force);
+		v = raydium_ode_motor[j].angle - 
+		    GetAngle(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint);
+		SetParam(raydium_ode_joint[raydium_ode_motor[j].joints[i]].joint,vel,v*10);
+	    }	    	
+	}
+    return;
+    }
+raydium_log("ODE: Error (internal): motor update failed: not found");
+}
+
+void raydium_ode_motor_speed(int j, dReal force)
+{
+if(raydium_ode_motor_isvalid(j))
+    {
+    raydium_ode_motor[j].speed=force;
+    // refresh direction using direction and speed:
+    if(raydium_ode_motor[j].state==RAYDIUM_ODE_MOTOR_ROCKET)
+	raydium_ode_motor_rocket_orientation(j,raydium_ode_motor[j].rocket_orientation[0],raydium_ode_motor[j].rocket_orientation[1],raydium_ode_motor[j].rocket_orientation[2]);
+    return;
+    }
+raydium_log("ODE: Error: cannot set motor's speed: invalid index or name");
+}
+
+void raydium_ode_motor_speed_name(char *name, dReal force)
+{
+raydium_ode_motor_speed(raydium_ode_motor_find(name),force);
+}
+
+// power = 0 means motor has no effect on joints (free moves)
+void raydium_ode_motor_power_max(int j, dReal power)
+{
+if(raydium_ode_motor_isvalid(j))
+    {
+    raydium_ode_motor[j].force=power;
+    return;
+    }
+raydium_log("ODE: Error: cannot set max motor's power: invalid index or name");
+}
+
+void raydium_ode_motor_power_max_name(char *name, dReal power)
+{
+raydium_ode_motor_power_max(raydium_ode_motor_find(name),power);
+}
+
+
+void raydium_ode_motor_angle(int j, dReal angle)
+{
+if(raydium_ode_motor_isvalid(j))
+    {
+    raydium_ode_motor[j].angle=angle;
+    return;
+    }
+raydium_log("ODE: Error: cannot set motor's angle: invalid index or name");
+}
+
+void raydium_ode_motor_angle_name(char *motor, dReal angle)
+{
+raydium_ode_motor_angle(raydium_ode_motor_find(motor),angle);
+}
+
+
+void raydium_ode_motor_gears_set(int m,dReal *gears, int n_gears)
+{
+if(raydium_ode_motor_isvalid(m))
+    {
+    if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ENGINE)
+	{
+	raydium_log("ODE: Error: cannot use a gearbox with a non-engine motor");
+	return;
+	}
+    memcpy(raydium_ode_motor[m].gears,gears,sizeof(dReal)*n_gears);
+    raydium_ode_motor[m].gear_max=n_gears-1;
+    return;
+    }
+raydium_log("ODE: Error: cannot configure motor's gears: invalid index or name");
+}
+
+void raydium_ode_motor_gears_set_name(char *m,dReal *gears,int n_gears)
+{
+raydium_ode_motor_gears_set(raydium_ode_motor_find(m),gears,n_gears);
+}
+
+void raydium_ode_motor_gear_change(int m, int gear)
+{
+if(raydium_ode_motor_isvalid(m))
+    {
+    if(gear<0 || gear>raydium_ode_motor[m].gear_max)
+	{
+	raydium_log("ODE: Error: invalid gear (%i)",gear);
+	return;
+	}
+    raydium_ode_motor[m].gear=gear;
+    return;
+    }
+raydium_log("ODE: Error: cannot set motor's gear: invalid index or name");
+}
+
+void raydium_ode_motor_gear_change_name(char *m, int gear)
+{
+raydium_ode_motor_gear_change(raydium_ode_motor_find(m),gear);
+}
+
+dReal *raydium_ode_element_pos_get(int j)
+{
+if(raydium_ode_element_isvalid(j))
+    {
+    return (dReal *)dGeomGetPosition(raydium_ode_element[j].geom);
+    }
+raydium_log("ODE: Error: cannot get element position: invalid index or name");
+return NULL;
+}
+
+dReal *raydium_ode_element_pos_get_name(char *name)
+{
+return raydium_ode_element_pos_get(raydium_ode_element_find(name));
+}
+
+
+char raydium_ode_element_rotq_get(int j, dQuaternion res)
+{
+if(raydium_ode_element_isvalid(j))
+    {
+    dGeomGetQuaternion(raydium_ode_element[j].geom,res);
+    return 1;
+    }
+raydium_log("ODE: Error: cannot get element rotation (quaternion): invalid index or name");
+return 0;
+}
+
+char raydium_ode_element_rotq_get_name(char *name, dQuaternion res)
+{
+return raydium_ode_element_rotq_get(raydium_ode_element_find(name),res);
+}
+/*
+char raydium_ode_element_rot_get(int e, dReal *rx, dReal *ry, dReal *rz)
+{
+// From Andrzej Szombierski <qq@kuku.eu.org> (ODE ML)
+// patched by Daniel Monteiro Basso <dmbasso@inf.ufrgs.br> (ODE ML)
+// but it's not what i want, again.. arrrgh ;)
+const dReal epsilon=0.0000001;
+dReal *matrix;
+dReal c;
+
+if(raydium_ode_element_isvalid(e))
+    {
+    matrix=(dReal *)dGeomGetRotation(raydium_ode_element[e].geom);
+    
+    if(matrix[2] < 1-epsilon && matrix[2] > -1+epsilon)
+    {
+	*ry=-asin(matrix[2]);
+	c=cos(*ry);
+	*rx= atan2(matrix[6]/c,matrix[10]/c);
+	*rz= atan2(matrix[1]/c,matrix[0]/c);
+    } 
+    else 
+    {       
+	*rz=0;   
+	*ry=-atan2(matrix[2],0);
+	*rx= atan2(-matrix[9],matrix[5]);
+    }
+    // rad to deg
+    //(*rx)*=180/PI;
+    //(*ry)*=180/PI;
+    //(*rz)*=180/PI;
+    return 1;
+    }
+raydium_log("ODE: Error: cannot get element rotation (3f): invalid index or name");
+return 0;
+}
+*/
+
+char raydium_ode_element_rot_get(int e, dReal *rx, dReal *ry, dReal *rz)
+{
+// From Andrzej Szombierski <qq@kuku.eu.org> (ODE ML)
+// Original code version: "absolute" angles
+// Do not apply back returned angles ! (not ODE "formated")
+const dReal epsilon=0.0000001;
+dReal *matrix;
+dReal c;
+
+if(raydium_ode_element_isvalid(e))
+    {
+    matrix=(dReal *)dGeomGetRotation(raydium_ode_element[e].geom);
+    
+    if(matrix[8] < 1-epsilon && matrix[8] > -1+epsilon)
+    {
+	*ry=-asin(matrix[8]);
+	c=cos(*ry);
+	*rx= atan2(matrix[9]/c,matrix[10]/c);
+	*rz= atan2(matrix[4]/c,matrix[0]/c);
+    }       
+    else    
+    {       
+	*rz=0;   
+	*ry=-atan2(matrix[8],0);
+	*rx= atan2(-matrix[6],matrix[5]);
+    }       
+
+    // rad to deg
+    //(*rx)*=180/PI;
+    //(*ry)*=180/PI;
+    //(*rz)*=180/PI;
+    return 1;
+    }
+raydium_log("ODE: Error: cannot get element rotation (3f): invalid index or name");
+return 0;
+}
+
+
+char raydium_ode_element_rot_get_name(char *e, dReal *rx, dReal *ry, dReal *rz)
+{
+return raydium_ode_element_rot_get(raydium_ode_element_find(e),rx,ry,rz);
+}
+
+void raydium_ode_element_sound_update(int e, int source)
+{
+if(raydium_ode_element_isvalid(e))
+    {
+    dReal *pos;
+    pos=raydium_ode_element_pos_get(e);
+    raydium_sound_SetSourcePos(source,pos);
+    return;
+    }
+raydium_log("ODE: Error: cannot update source: invalid index or name");
+return;
+}
+
+void raydium_ode_element_sound_update_name(char *e, int source)
+{
+raydium_ode_element_sound_update(raydium_ode_element_find(e),source);
+}
+
+void raydium_ode_element_RelPointPos(int e, dReal px, dReal py, dReal pz, dReal *res)
+{
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot get RelPointPos: invalid index or name");
+    return;    
+    }
+
+if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
+    {
+    raydium_log("ODE: Error: Cannot get RelPointPos on a static element");
+    return;
+    }
+
+dBodyGetRelPointPos(raydium_ode_element[e].body,px,py,pz,res);
+}
+
+
+void raydium_ode_element_RelPointPos_name(char *e, dReal px, dReal py, dReal pz, dReal *res)
+{
+raydium_ode_element_RelPointPos(raydium_ode_element_find(e),px,py,pz,res);
+}
+
+int raydium_ode_motor_create(char *name, int obj, char type)
+{
+int i;
+
+if(raydium_ode_motor_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add motor \"%s\": name already exists",name);
+    return -1;
+    }
+
+if(!raydium_ode_object_isvalid(obj))
+    {
+    raydium_log("ODE: Cannot add motor \"%s\": parent object is invalid",name);
+    return -1;    
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    if(!raydium_ode_motor[i].state)
+     {
+     strcpy(raydium_ode_motor[i].name,name);
+     raydium_ode_motor[i].state=type;
+     raydium_ode_motor[i].object=obj;     
+     return i;
+     }
+raydium_log("ODE: No more motor slots ! aborting \"%s\" creation",name);
+return -1;
+}
+
+
+void raydium_ode_motor_attach(int motor, int joint, int joint_axe)
+{
+int i;
+int e1,e2;
+raydium_ode_Element *elem1;
+raydium_ode_Element *elem2;
+
+if(raydium_ode_motor_isvalid(motor) && raydium_ode_joint_isvalid(joint))
+    {
+    // may crash if joint is disconnected at one of its ends !
+    elem1=dBodyGetData(dJointGetBody(raydium_ode_joint[joint].joint,0));
+    elem2=dBodyGetData(dJointGetBody(raydium_ode_joint[joint].joint,1));
+    
+    e1=elem1->id;
+    e2=elem2->id;
+    
+    if(raydium_ode_motor[motor].object!=raydium_ode_element[e1].object &&
+       raydium_ode_motor[motor].object!=raydium_ode_element[e2].object )
+        {
+	raydium_log("ODE: Cannot attach motor: joint must be attached to at least one element from motor's object");
+	return;
+	}	
+    
+    for(i=0;i<RAYDIUM_ODE_MOTOR_MAX_JOINTS;i++)
+	if(raydium_ode_motor[motor].joints[i]<0)
+	    {
+	    raydium_ode_motor[motor].joints[i]=joint;
+	    raydium_ode_motor[motor].joints_axe[i]=joint_axe;
+	    return;
+	    }
+    raydium_log("ODE: Error: no more joint slots for motor \"%s\" (while adding %s)", raydium_ode_motor[motor].name,raydium_ode_joint[joint].name);
+    return;
+    }
+raydium_log("ODE: Error: cannot attach joint to motor: invalid index or name");
+}
+
+void raydium_ode_motor_attach_name(char *motor, char *joint, int joint_axe)
+{
+raydium_ode_motor_attach(raydium_ode_motor_find(motor),raydium_ode_joint_find(joint),joint_axe);
+}
+
+dReal raydium_ode_motor_speed_get(int m, int gears)
+{
+dReal *vel;
+dReal velf=0;
+int i,n=0;
+dBodyID body;
+
+if(!raydium_ode_motor_isvalid(m))
+    {
+    raydium_log("ODE: Error: Cannot get motor speed: invalid name or index");
+    return 0;
+    }
+
+if(raydium_ode_motor[m].state==RAYDIUM_ODE_MOTOR_ROCKET)
+    return raydium_ode_motor[m].speed;
+
+for(i=0;i<RAYDIUM_ODE_MOTOR_MAX_JOINTS;i++)
+    if(raydium_ode_motor[m].joints[i]>=0)
+	{
+	body=dJointGetBody(raydium_ode_joint[raydium_ode_motor[m].joints[i]].joint,raydium_ode_motor[m].joints_axe[i]);
+	vel=(dReal *)dBodyGetAngularVel(body);
+	velf+=sqrt(vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2]);
+	n++;
+	}
+if(n) 
+    {
+    velf/=n;
+    if(gears) velf*=(1/raydium_trigo_abs(raydium_ode_motor[m].gears[raydium_ode_motor[m].gear]));
+    }
+else velf=0;
+return velf;
+}
+
+dReal raydium_ode_motor_speed_get_name(char *name, int gears)
+{
+return raydium_ode_motor_speed_get(raydium_ode_motor_find(name),gears);
+}
+
+
+void raydium_ode_motor_rocket_set(int m, int element, dReal x, dReal y, dReal z)
+{
+if(!raydium_ode_motor_isvalid(m) || !raydium_ode_element_isvalid(element))
+    {
+    raydium_log("ODE: Error: Cannot set rocket element: invalid name or index");
+    return;
+    }
+
+if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ROCKET)
+    {
+    raydium_log("ODE: Error: Cannot set rocket element: motor is not a rocket");
+    return;
+    }
+    
+raydium_ode_motor[m].rocket_element=element;
+raydium_ode_motor[m].rocket_position[0]=x;
+raydium_ode_motor[m].rocket_position[1]=y;
+raydium_ode_motor[m].rocket_position[2]=z;
+}
+
+void raydium_ode_motor_rocket_set_name(char *motor,char *element, dReal x, dReal y, dReal z)
+{
+raydium_ode_motor_rocket_set(raydium_ode_motor_find(motor),raydium_ode_element_find(element),x,y,z);
+}
+
+void raydium_ode_motor_rocket_orientation(int m, dReal rx, dReal ry, dReal rz)
+{
+GLfloat res[3];
+GLfloat dir[3]={0,0,1};
+if(!raydium_ode_motor_isvalid(m))
+    {
+    raydium_log("ODE: Error: Cannot set rocket orientation: invalid name or index");
+    return;
+    }
+if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ROCKET)
+    {
+    raydium_log("ODE: Error: Cannot set rocket orientation: motor is not a rocket");
+    return;
+    }
+
+raydium_ode_motor[m].rocket_orientation[0]=rx;
+raydium_ode_motor[m].rocket_orientation[1]=ry;
+raydium_ode_motor[m].rocket_orientation[2]=rz;
+raydium_trigo_rotate(dir,rx,ry,rz,res);
+res[0]*=raydium_ode_motor[m].speed;
+res[1]*=raydium_ode_motor[m].speed;
+res[2]*=raydium_ode_motor[m].speed;
+raydium_ode_motor[m].rocket_direction[0]=res[0];
+raydium_ode_motor[m].rocket_direction[1]=res[1];
+raydium_ode_motor[m].rocket_direction[2]=res[2];
+}
+
+void raydium_ode_motor_rocket_orientation_name(char *name, dReal rx, dReal ry, dReal rz)
+{
+raydium_ode_motor_rocket_orientation(raydium_ode_motor_find(name),rx,ry,rz);
+}
+
+
+void raydium_ode_motor_rocket_playermovement(int m, char isplayermovement)
+{
+if(!raydium_ode_motor_isvalid(m))
+    {
+    raydium_log("ODE: Error: Cannot set rocket type (player movement): invalid name or index");
+    return;
+    }
+if(raydium_ode_motor[m].state!=RAYDIUM_ODE_MOTOR_ROCKET)
+    {
+    raydium_log("ODE: Error: Cannot set rocket type (player movement): motor is not a rocket");
+    return;
+    }
+raydium_ode_motor[m].rocket_playermovement=isplayermovement;
+}
+
+void raydium_ode_motor_rocket_playermovement_name(char *m, char isplayermovement)
+{
+return raydium_ode_motor_rocket_playermovement(raydium_ode_motor_find(m),isplayermovement);
+}
+
+char raydium_ode_motor_delete(int e)
+{
+if(!raydium_ode_motor_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot delete motor: invalid name or index");
+    return 0;
+    }
+raydium_ode_init_motor(e);
+return 1;
+}
+
+char raydium_ode_motor_delete_name(char *name)
+{
+return raydium_ode_motor_delete(raydium_ode_motor_find(name));
+}
+
+
+char raydium_ode_joint_delete(int joint)
+{
+int i,j;
+void (*f)(int);
+
+if(!raydium_ode_joint_isvalid(joint))
+    {
+    raydium_log("ODE: Error: Cannot delete joint: invalid name or index");
+    return 0;
+    }
+for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    for(j=0;j<RAYDIUM_ODE_MOTOR_MAX_JOINTS;j++)
+	if(raydium_ode_motor[i].joints[j]==joint)
+	{
+	raydium_ode_motor[i].joints[j]=-1;
+	raydium_ode_motor[i].joints_axe[j]=0;
+	}
+
+free(dJointGetFeedback(raydium_ode_joint[joint].joint));
+dJointDestroy(raydium_ode_joint[joint].joint);
+
+f=raydium_ode_joint[joint].OnDelete;
+if(f) f(joint);
+raydium_ode_init_joint(joint);
+return 1;
+}
+
+char raydium_ode_joint_delete_name(char *name)
+{
+return raydium_ode_joint_delete(raydium_ode_joint_find(name));
+}
+
+
+char raydium_ode_element_delete(int e, char deletejoints)
+{
+int i;
+int (*f)(int);
+
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot delete element: invalid name or index");
+    return 0;
+    }
+
+
+
+
+// Only for "first pass"
+if(!raydium_ode_element[e].marked_as_deleted)
+{
+    f=raydium_ode_element[e].OnDelete;
+    if(f && !f(e)) return 0; // user cancel
+}
+
+if(raydium_ode_element_delete_LOCK)
+    {
+    //raydium_log("ODE: Warning: deleting of elements is locked !");
+    // element will be delete at the end of the current collide test loop (but
+    // is ignored for all future collisions in this test)
+    raydium_ode_element[e].marked_as_deleted=1;
+    return 1;
+    }
+
+
+// verify element state after user callback (element may be already deleted ! :)
+// note : this test is bad.. an new element may have taken the free slot ...
+// in facts, a user must not delete an element during his own OnDelete callback
+if(!raydium_ode_element_isvalid(e)) 
+    return 1; // delete is successfull thru user callback
+
+
+raydium_ode_network_element_delete(e);
+
+if(deletejoints && raydium_ode_element[e].state!=RAYDIUM_ODE_STATIC)
+    {
+    raydium_ode_Joint *j;
+    int *to_delete;
+    int n_joints;
+
+    n_joints=dBodyGetNumJoints(raydium_ode_element[e].body);
+    if(n_joints)
+     {
+	// create a list of joint to delete ...
+	to_delete=malloc(n_joints*sizeof(int));
+	for(i=0;i<n_joints;i++)
+	    {
+	    j=dJointGetData(dBodyGetJoint(raydium_ode_element[e].body,i));
+	    if(j)
+		to_delete[i]=j->id; 
+	    else 
+		to_delete[i]=-1;
+	    }    
+	// ... and delete joints
+	for(i=0;i<n_joints;i++)
+	  if(to_delete[i]>=0)
+	    raydium_ode_joint_delete(to_delete[i]);
+
+	free(to_delete);
+     }
+    }
+
+dGeomSetData(raydium_ode_element[e].geom,NULL); // no more linked to this structure
+dGeomDestroy(raydium_ode_element[e].geom);
+if(raydium_ode_element[e].body)
+ dBodyDestroy(raydium_ode_element[e].body);
+
+for(i=0;i<RAYDIUM_ODE_ELEMENT_MAX_FIXING;i++)
+    if(raydium_ode_element[e].fixed_elements[i])
+	{
+	free(raydium_ode_element[e].fixed_elements[i]);
+	raydium_ode_element[e].fixed_elements[i]=NULL;
+	}
+
+if(raydium_ode_element[e].particle>=0)
+    raydium_particle_generator_delete(raydium_ode_element[e].particle);
+
+raydium_ode_init_element(e);
+return 1;
+}
+
+char raydium_ode_element_delete_name(char *name, char deletejoints)
+{
+return raydium_ode_element_delete(raydium_ode_element_find(name),deletejoints);
+}
+
+
+char raydium_ode_object_delete(int obj)
+{
+int i;
+//raydium_ode_Element *e;
+
+if(!raydium_ode_object_isvalid(obj))
+    {
+    raydium_log("ODE: Error: Cannot delete object: invalid name or index");
+    return 0;
+    }
+
+if(obj == raydium_ode_object_find("GLOBAL"))
+    {
+    raydium_log("ODE: Error: Cannot delete special \"GLOBAL\" object");
+    return 0;
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    if(raydium_ode_motor[i].object==obj)
+	raydium_ode_motor_delete(i);	
+    
+// Wow... group indices are unstable while deleting group's bodies !
+//for(i=0;i<dGeomGroupGetNumGeoms(raydium_ode_object[obj].group);i++)
+//    {
+//    e=dGeomGetData(dGeomGroupGetGeom(raydium_ode_object[obj].group,i));
+//    raydium_ode_element_delete(e->id,1);
+//    }
+// So i'll search for bodies in my own structures
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].object==obj)
+	raydium_ode_element_delete(i,1);
+
+dSpaceDestroy(raydium_ode_object[obj].group);
+raydium_ode_init_object(obj);
+return 1;
+}
+
+char raydium_ode_object_delete_name(char *name)
+{
+return raydium_ode_object_delete(raydium_ode_object_find(name));
+}
+
+char raydium_ode_explosion_delete(int e)
+{
+if(!raydium_ode_explosion_isvalid(e))
+    {
+    raydium_log("ODE: Error: Cannot delete explosion: invalid name or index");
+    return 0;
+    }
+if(raydium_ode_explosion[e].element>=0)
+    raydium_ode_element_delete(raydium_ode_explosion[e].element,0);
+raydium_ode_init_explosion(e);
+return 1;
+}
+
+
+char raydium_ode_element_moveto(int element, int object, char deletejoints)
+{
+int i;
+raydium_ode_Joint *j;
+dBodyID e1,e2;
+
+if(!raydium_ode_element_isvalid(element) ||
+   !raydium_ode_object_isvalid(object) )
+   {
+   raydium_log("ODE: Error: Cannot move element to object: invalid index/name");
+   return 0;
+   }
+
+for(i=0;i<dBodyGetNumJoints(raydium_ode_element[element].body);i++)
+    {
+    j=dJointGetData(dBodyGetJoint(raydium_ode_element[element].body,i));
+    if(deletejoints)
+	raydium_ode_joint_delete(j->id);
+    else
+	{
+	e1=dJointGetBody(j->joint,0);
+	e2=dJointGetBody(j->joint,1);
+	if(e1==raydium_ode_element[element].body) e1=0;
+	if(e2==raydium_ode_element[element].body) e2=0;
+	dJointAttach(j->joint,e1,e2);	
+	}
+    }
+// Well well well.. donno if dGeomGroupAdd removes body from previous
+// GeomGroup, so i do it myself.
+raydium_ode_element[element]._movesfrom=raydium_ode_element[element].object;
+dSpaceRemove(raydium_ode_object[raydium_ode_element[element].object].group,
+	     raydium_ode_element[element].geom);
+raydium_ode_element[element].object=object;
+dSpaceAdd(raydium_ode_object[raydium_ode_element[element].object].group,
+	     raydium_ode_element[element].geom);
+
+return 1;
+}
+
+
+char raydium_ode_element_moveto_name(char *element, char *object, char deletejoints)
+{
+return raydium_ode_element_moveto(raydium_ode_element_find(element),raydium_ode_object_find(object),deletejoints);
+}
+
+
+void raydium_ode_joint_break(int j)
+{
+dJointFeedback *jf;
+dReal force=0;
+if(!raydium_ode_joint[j].breakableforce) return;
+
+if(!raydium_ode_joint_isvalid(j))
+    {
+    raydium_log("ODE: Error: cannot test joint breaking: invalid index/name");
+    return;
+    }
+jf=dJointGetFeedback(raydium_ode_joint[j].joint);
+if(!jf) return;
+force+=raydium_trigo_abs(jf->f1[0]);
+force+=raydium_trigo_abs(jf->f1[1]);
+force+=raydium_trigo_abs(jf->f1[2]);
+force+=raydium_trigo_abs(jf->f2[0]);
+force+=raydium_trigo_abs(jf->f2[1]);
+force+=raydium_trigo_abs(jf->f2[2]);
+//raydium_log("%f %s",force,raydium_ode_joint[j].name);
+if(force>raydium_ode_joint[j].breakableforce)
+    {
+    raydium_ode_joint[j].breaking=1;
+    raydium_ode_joint_delete(j);
+    }
+}
+
+char raydium_ode_launcher(int element, int from_element, dReal *rot, dReal force)
+{
+dReal res[3];
+dReal *initial;
+dVector3 final;
+dReal dir[3]={0,0,1};
+
+if(!raydium_ode_element_isvalid(element) ||
+   !raydium_ode_element_isvalid(from_element) )
+    {
+    raydium_log("ODE: Cannot launch element: invalid name or index");
+    return 0;
+    }
+
+if( raydium_ode_element[from_element].state==RAYDIUM_ODE_STATIC ||
+    raydium_ode_element[element].state==RAYDIUM_ODE_STATIC )
+    {
+    raydium_log("ODE: Cannot launch element: you must use non-static elements");
+    return 0;
+    }
+
+raydium_trigo_rotate(dir,rot[0],rot[1],rot[2],res);
+res[0]*=force;
+res[1]*=force;
+res[2]*=force;
+dBodyVectorToWorld(raydium_ode_element[from_element].body,res[0],res[1],res[2],final);
+initial=(dReal *)dBodyGetLinearVel(raydium_ode_element[from_element].body);
+final[0]+=initial[0];
+final[1]+=initial[1];
+final[2]+=initial[2];
+dBodyAddForce(raydium_ode_element[element].body,final[0],final[1],final[2]);
+return 1;
+}
+
+char raydium_ode_launcher_name(char *element, char *from_element, dReal *rot, dReal force)
+{
+return raydium_ode_launcher(raydium_ode_element_find(element),raydium_ode_element_find(from_element),rot,force);
+}
+
+char raydium_ode_launcher_name_3f(char *element, char *from_element, dReal rx, dReal ry, dReal rz, dReal force)
+{
+dReal tmp[3];
+tmp[0]=rx;
+tmp[1]=ry;
+tmp[2]=rz;
+return raydium_ode_launcher_name(element,from_element,tmp,force);
+}
+
+
+char raydium_ode_launcher_simple(int element, int from_element, dReal *lrot, dReal force)
+{
+dReal *pos;
+dQuaternion rot;
+
+if(!raydium_ode_element_isvalid(element) ||
+   !raydium_ode_element_isvalid(from_element) )
+    {
+    raydium_log("ODE: Cannot (simple) launch element: invalid name or index");
+    return 0;
+    }
+
+// test if element and from_element are from the same objet
+if(raydium_ode_element[element].object!=raydium_ode_element[from_element].object)
+    {
+    raydium_log("ODE: Cannot (simple) launch element: element and from_element are not from the same object");
+    return 0;
+    }
+
+pos=raydium_ode_element_pos_get(from_element);
+raydium_ode_element_rotq_get(from_element,rot);
+raydium_ode_element_move(element,pos);
+raydium_ode_element_rotateq(element,rot);
+raydium_ode_launcher(element,from_element,lrot,force);
+raydium_ode_element_moveto(element,raydium_ode_object_find("GLOBAL"),0);
+return 1;
+}
+
+char raydium_ode_launcher_simple_name(char *element, char *from_element, dReal *rot, dReal force)
+{
+return raydium_ode_launcher_simple(raydium_ode_element_find(element),raydium_ode_element_find(from_element),rot,force);
+}
+
+char raydium_ode_launcher_simple_name_3f(char *element, char *from_element, dReal rx, dReal ry, dReal rz, dReal force)
+{
+dReal tmp[3];
+tmp[0]=rx;
+tmp[1]=ry;
+tmp[2]=rz;
+return raydium_ode_launcher_simple_name(element,from_element,tmp,force);
+}
+
+
+void raydium_ode_explosion_blow(dReal radius, dReal max_force, dReal *pos)
+{
+int i;
+void (*f)(char, dReal, dReal, dReal *);
+void (*g)(int, dReal, dReal);
+
+if(raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT && !raydium_ode_network_explosion_create)
+{
+// propag over network
+raydium_ode_network_Explosion exp;
+exp.type=RAYDIUM_ODE_NETWORK_EXPLOSION_BLOW;
+exp.radius=radius;
+memcpy(exp.pos,pos,sizeof(dReal)*3);
+exp.force=max_force;
+raydium_ode_network_explosion_send(&exp);
+return;
+}
+raydium_ode_network_explosion_create=0;
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD)
+	{
+	dReal vect[3];
+	dReal *elp;
+	dReal len;
+	dReal force;
+	elp=(dReal *)dGeomGetPosition(raydium_ode_element[i].geom);
+	
+	//raydium_log("Blow: %s",raydium_ode_element[i].name);
+	
+	// explosion to element vector
+	vect[0]=elp[0]-pos[0];
+	vect[1]=elp[1]-pos[1];
+	vect[2]=elp[2]-pos[2];
+	// distance from explosion
+	len=sqrt(vect[0]*vect[0] + vect[1]*vect[1] + vect[2]*vect[2]);
+	
+	if(len==0.f) continue;
+//	raydium_log("dist from core: %f (radius=%f)",len,radius);
+	// normalize vector
+	vect[0]/=len;
+	vect[1]/=len;
+	vect[2]/=len;
+	
+	if(len>radius) continue;
+	force = ((radius*radius) - (len*len)) / (radius * radius) * max_force;
+//	raydium_log("resulting force: %f (max force at core=%f)",force,max_force);
+	vect[0]*=force;
+	vect[1]*=force;
+	vect[2]*=force;
+//	raydium_log("resulting impulse vector: [%f %f %f]",vect[0],vect[1],vect[2]);
+	dBodyAddForce(raydium_ode_element[i].body,vect[0],vect[1],vect[2]);
+	g=raydium_ode_element[i].OnBlow;
+	if(g) g(i,force,max_force);
+	}
+f=raydium_ode_ExplosionCallback;
+if(f)
+    f(RAYDIUM_ODE_NETWORK_EXPLOSION_BLOW,radius,max_force,pos);
+}
+
+
+void raydium_ode_explosion_blow_3f(dReal radius, dReal max_force, dReal px, dReal py, dReal pz)
+{
+dReal pos[3];
+pos[0]=px;
+pos[1]=py;
+pos[2]=pz;
+raydium_ode_explosion_blow(radius,max_force,pos);
+}
+
+int raydium_ode_explosion_create(char *name, dReal final_radius, dReal propag, dReal *pos)
+{
+int i;
+void (*f)(char, dReal, dReal, dReal *);
+
+if(raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT && !raydium_ode_network_explosion_create)
+{
+// propag over network
+raydium_ode_network_Explosion exp;
+exp.type=RAYDIUM_ODE_NETWORK_EXPLOSION_EXPL;
+exp.radius=final_radius;
+memcpy(exp.pos,pos,sizeof(dReal)*3);
+exp.propag=propag;
+raydium_ode_network_explosion_send(&exp);
+return -1; // WARNING: During networked games, this function always returns -1
+}
+raydium_ode_network_explosion_create=0;
+
+
+if(raydium_ode_explosion_find(name)>=0)
+    {
+    raydium_log("ODE: Cannot add explosion \"%s\": name already exists",name);
+    return -1;
+    }
+
+for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
+    if(!raydium_ode_explosion[i].state)
+     {
+     strcpy(raydium_ode_explosion[i].name,name);
+     raydium_ode_explosion[i].state=1;
+     raydium_ode_explosion[i].config_radius=final_radius;
+     raydium_ode_explosion[i].config_propag=propag;
+     raydium_ode_explosion[i].radius=0;
+     memcpy(raydium_ode_explosion[i].position,pos,sizeof(dReal)*3);
+     
+     f=raydium_ode_ExplosionCallback;
+     if(f)
+	f(RAYDIUM_ODE_NETWORK_EXPLOSION_EXPL,final_radius,propag,pos);
+
+     return i;
+     }
+raydium_log("ODE: No more explosion slots ! aborting \"%s\" creation",name);
+return -1;
+}
+
+
+// load object from disk
+// raydium_ode_object_load(char *filename, char *suffix)
+
+////////
+
+
+void raydium_ode_element_camera_inboard(int e, dReal px, dReal py, dReal pz, dReal lookx, dReal looky, dReal lookz)
+{
+dBodyID body;
+dVector3 face,up,cam;
+if(!raydium_ode_element_isvalid(e))
+    {
+    raydium_log("ODE: Error: cannot set camera on element: invalid name or index");
+    return;
+    }
+
+if(raydium_ode_element[e].state==RAYDIUM_ODE_STATIC)
+    {
+    raydium_log("ODE: Error: cannot put camera on a static element");
+    return;
+    }
+//glLoadIdentity();
+raydium_camera_internal_prepare();
+body=raydium_ode_element[e].body;
+dBodyGetRelPointPos(body,px,py,pz,cam);
+dBodyGetRelPointPos(body,lookx,looky,lookz,face);
+dBodyVectorToWorld (body,0,0,1,up);
+gluLookAt(cam[0],cam[1],cam[2],face[0],face[1],face[2],up[0],up[1],up[2]);
+raydium_camera_internal(cam[0], cam[1], cam[2]);
+}
+
+
+void raydium_ode_element_camera_inboard_name(char *name, dReal px, dReal py, dReal pz, dReal lookx, dReal looky, dReal lookz)
+{
+raydium_ode_element_camera_inboard(raydium_ode_element_find(name),px,py,pz,lookx,looky,lookz);
+}
+
+
+void raydium_ode_draw_all(char names)
+{
+int i,j;
+char (*bef)(int);
+void (*aft)(int);
+
+bef=raydium_ode_BeforeElementDrawCallback;
+aft=raydium_ode_AfterElementDrawCallback;
+
+if(names==1)
+ for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    if(raydium_ode_motor[i].state==RAYDIUM_ODE_MOTOR_ROCKET)
+     {
+     int j;
+     j=raydium_ode_motor[i].rocket_element;
+     raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[j].geom), (dReal *)dGeomGetRotation(raydium_ode_element[j].geom));
+     glDisable(GL_LIGHTING);
+     raydium_texture_current_set_name("rgb(1,0,0)");
+     raydium_rendering_internal_prepare_texture_render(raydium_texture_current);     
+     glLineWidth(1.f);
+     glBegin(GL_LINES);
+     glVertex3f(raydium_ode_motor[i].rocket_position[0],raydium_ode_motor[i].rocket_position[1],raydium_ode_motor[i].rocket_position[2]);
+     glVertex3f(raydium_ode_motor[i].rocket_position[0]+raydium_ode_motor[i].rocket_direction[0],
+    		raydium_ode_motor[i].rocket_position[1]+raydium_ode_motor[i].rocket_direction[1],
+		raydium_ode_motor[i].rocket_position[2]+raydium_ode_motor[i].rocket_direction[2]);
+     glEnd();
+     if(raydium_light_enabled_tag)
+        glEnable(GL_LIGHTING);
+     }
+
+if(names==1)
+ for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
+    if(raydium_ode_explosion[i].state)
+	{
+	int j;
+	j=raydium_ode_explosion[i].element;
+    	raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[j].geom), (dReal *)dGeomGetRotation(raydium_ode_element[j].geom));
+	glutWireSphere(raydium_ode_explosion[i].radius,10,10);
+	}
+
+
+if(names==1)
+ for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(raydium_ode_joint[i].state)
+    {
+    void (*f1)(dJointID,dVector3);
+    void (*f2)(dJointID,dVector3);
+    dVector3 res1;
+    dVector3 res2;
+    dMatrix3 r;
+    int type;
+    char col;
+    dRSetIdentity(r);
+    type=dJointGetType(raydium_ode_joint[i].joint);
+    switch(type)
+	{
+	case dJointTypeHinge2:
+	    f1=dJointGetHinge2Anchor;
+	    f2=dJointGetHinge2Anchor2;
+	    col='3';
+	    break;
+	case dJointTypeUniversal:
+	    f1=dJointGetUniversalAnchor;
+	    f2=dJointGetUniversalAnchor2;
+	    col='5';
+	    break;
+	case dJointTypeHinge:
+	    f1=dJointGetHingeAnchor;
+	    f2=dJointGetHingeAnchor2;
+	    col='2';
+	    break;
+	case dJointTypeFixed:
+	    f1=NULL;
+	    f2=NULL;
+	    col='0';
+	    break;
+	default: raydium_log("ODE: ERROR: draw_all: invalid joint type !");
+	}
+
+     if(f1 && f2)
+     {
+      f1(raydium_ode_joint[i].joint,res1);
+      f2(raydium_ode_joint[i].joint,res2);
+      raydium_texture_current_set_name("rgb(1,0,0)");
+      raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+      raydium_camera_replace_go(res1,r);
+      glutWireSphere(0.05,5,5);
+      raydium_camera_replace_go(res2,r);
+      glutWireSphere(0.05,5,5);
+      raydium_osd_color_ega(col);
+      raydium_osd_printf_3D(res1[0],res1[1],res1[2],12,0.6,"font2.tga","<%s>",raydium_ode_joint[i].name);
+     }
+    }
+     
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state)
+     {
+	
+     if(!names)
+        {
+	
+	if(bef && !bef(i))
+    	    continue;
+    	raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[i].geom), (dReal *)dGeomGetRotation(raydium_ode_element[i].geom));
+	if(raydium_ode_element[i].mesh>=0)
+    	   raydium_object_draw(raydium_ode_element[i].mesh);
+	if(aft) aft(i);
+
+	if(raydium_ode_element[i].particle>=0)
+	    {
+	    dVector3 res;
+
+	    // if element is static, fake a temporary body
+	    if(raydium_ode_element[i].state==RAYDIUM_ODE_STATIC)
+	    {
+	     dBodyID body;
+	     dReal *pos;
+	     dQuaternion rot;
+	     body=dBodyCreate(raydium_ode_world);
+	     pos=raydium_ode_element_pos_get(i);
+	     raydium_ode_element_rotq_get(i,rot);
+	     dBodySetPosition(body,pos[0],pos[1],pos[2]);
+	     dBodySetQuaternion(body,rot);
+	     dBodyGetRelPointPos(body,
+				raydium_ode_element[i].particle_offset[0],
+				raydium_ode_element[i].particle_offset[1],
+				raydium_ode_element[i].particle_offset[2],	    
+				res);
+	     dBodyDestroy(body);
+	    }
+	    else
+	    if(raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD)
+	    {
+	     dBodyGetRelPointPos(raydium_ode_element[i].body,
+				raydium_ode_element[i].particle_offset[0],
+				raydium_ode_element[i].particle_offset[1],
+				raydium_ode_element[i].particle_offset[2],	    
+				res);	    
+	    }
+	    
+	    raydium_particle_generator_move(
+		raydium_ode_element[i].particle,res);
+	    }
+	   
+	for(j=0;j<RAYDIUM_ODE_ELEMENT_MAX_FIXING;j++)
+	  if(raydium_ode_element[i].fixed_elements[j])
+	    {
+	    glPushMatrix();
+	    glTranslatef(raydium_ode_element[i].fixed_elements[j]->rel_pos[0],
+			 raydium_ode_element[i].fixed_elements[j]->rel_pos[1],
+			 raydium_ode_element[i].fixed_elements[j]->rel_pos[2]);
+	    {
+	    dMatrix3 R;
+	    GLfloat matrix[16];
+	    dQtoR(raydium_ode_element[i].fixed_elements[j]->rel_rot,R);
+	    matrix[0]=R[0];
+	    matrix[1]=R[4];
+	    matrix[2]=R[8];
+	    matrix[3]=0;
+	    matrix[4]=R[1];
+	    matrix[5]=R[5];
+	    matrix[6]=R[9];
+	    matrix[7]=0;
+	    matrix[8]=R[2];
+	    matrix[9]=R[6];
+	    matrix[10]=R[10];
+	    matrix[11]=0;
+	    matrix[12]=0;
+	    matrix[13]=0;
+	    matrix[14]=0;
+	    matrix[15]=1;
+	    glMultMatrixf (matrix);
+	    }
+	    raydium_object_draw(raydium_ode_element[i].fixed_elements[j]->mesh);
+	    glPopMatrix();
+	    }
+	}
+     else
+        {
+	const dReal *p;
+
+	
+	if(names==1) // draw shape
+	    {
+	    raydium_rendering_internal_prepare_texture_render(0); // !!!
+    	    raydium_texture_current_set_name("rgb(1,0,0)");
+	    raydium_camera_replace_go((dReal *)dGeomGetPosition(raydium_ode_element[i].geom), (dReal *)dGeomGetRotation(raydium_ode_element[i].geom));
+	    raydium_rendering_internal_prepare_texture_render(raydium_texture_current);     
+
+	    if(dGeomGetClass(raydium_ode_element[i].geom)==dBoxClass)
+		{
+		dVector3 sides;
+		float lx;
+		float ly;
+		float lz;
+		dGeomBoxGetLengths(raydium_ode_element[i].geom,sides);
+		lx = sides[0]*0.5f;
+		ly = sides[1]*0.5f;
+		lz = sides[2]*0.5f;
+		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+		// sides
+		glBegin (GL_TRIANGLE_STRIP);
+		glNormal3f (-1,0,0);
+		glVertex3f (-lx,-ly,-lz);
+		glVertex3f (-lx,-ly,lz);
+		glVertex3f (-lx,ly,-lz);
+		glVertex3f (-lx,ly,lz);
+		glNormal3f (0,1,0);
+		glVertex3f (lx,ly,-lz);
+		glVertex3f (lx,ly,lz);
+		glNormal3f (1,0,0);
+		glVertex3f (lx,-ly,-lz);
+		glVertex3f (lx,-ly,lz);
+		glNormal3f (0,-1,0);
+		glVertex3f (-lx,-ly,-lz);
+		glVertex3f (-lx,-ly,lz);
+		glEnd();
+	    
+    	        // top face
+	        glBegin (GL_TRIANGLE_FAN);
+	        glNormal3f (0,0,1);
+	        glVertex3f (-lx,-ly,lz);
+	        glVertex3f (lx,-ly,lz);
+	        glVertex3f (lx,ly,lz);
+	        glVertex3f (-lx,ly,lz);
+	        glEnd();
+
+	        // bottom face
+	        glBegin (GL_TRIANGLE_FAN);
+	        glNormal3f (0,0,-1);
+	        glVertex3f (-lx,-ly,-lz);
+	        glVertex3f (-lx,ly,-lz);
+	        glVertex3f (lx,ly,-lz);
+	        glVertex3f (lx,-ly,-lz);
+	        glEnd();
+	        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);	    
+	        }
+		else // dSphereClass
+		{
+	        glutWireSphere(dGeomSphereGetRadius(raydium_ode_element[i].geom),10,10);
+	        }
+	
+	    p=dGeomGetPosition(raydium_ode_element[i].geom);
+	    if(raydium_ode_element[i]._touched)
+		raydium_osd_color_ega('c');
+	    else
+		raydium_osd_color_ega('f');
+		
+	    if(raydium_ode_element[i]._avoidedcol)
+		raydium_osd_color_ega('d');
+	
+	    if(!dGeomIsEnabled(raydium_ode_element[i].geom))
+		raydium_osd_color_ega('a');
+
+	    if( raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD &&
+		!dBodyIsEnabled(raydium_ode_element[i].body) )
+		    raydium_osd_color_ega('0');
+	
+	    raydium_osd_printf_3D(p[0],p[1],p[2],12,0.6,"font2.tga","%i %s (%s) @ %i",i,raydium_ode_element[i].name,raydium_ode_object[raydium_ode_element[i].object].name,raydium_ode_element[i].distant_owner);
+	    }
+
+	    if(names==2) // draw AABB
+	    {
+	    dReal aabb[6];
+
+	    raydium_camera_replace();
+	    raydium_rendering_internal_prepare_texture_render(0); // !!
+	    raydium_texture_current_set_name("rgb(0,0,1)");
+	    raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+	    dGeomGetAABB(raydium_ode_element[i].geom,aabb);
+	    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+	    // sides
+	    glBegin (GL_TRIANGLE_STRIP);
+	    glNormal3f (-1,0,0);
+	    glVertex3f (aabb[0],aabb[2],aabb[4]);
+	    glVertex3f (aabb[0],aabb[2],aabb[5]);
+	    glVertex3f (aabb[0],aabb[3],aabb[4]);
+	    glVertex3f (aabb[0],aabb[3],aabb[5]);
+
+	    glNormal3f (0,1,0);
+	    glVertex3f (aabb[1],aabb[3],aabb[4]);
+	    glVertex3f (aabb[1],aabb[3],aabb[5]);
+
+	    glNormal3f (1,0,0);
+	    glVertex3f (aabb[1],aabb[2],aabb[4]);
+	    glVertex3f (aabb[1],aabb[2],aabb[5]);
+
+	    glNormal3f (0,-1,0);
+	    glVertex3f (aabb[0],aabb[2],aabb[4]);
+	    glVertex3f (aabb[0],aabb[2],aabb[5]);
+	    glEnd();
+	    
+    	    // top face
+	    glBegin (GL_TRIANGLE_FAN);
+	    glNormal3f (0,0,1);
+	    glVertex3f (aabb[0],aabb[2],aabb[5]);
+	    glVertex3f (aabb[1],aabb[2],aabb[5]);
+	    glVertex3f (aabb[1],aabb[3],aabb[5]);
+	    glVertex3f (aabb[0],aabb[3],aabb[5]);
+	    glEnd();
+
+	    // bottom face
+	    glBegin (GL_TRIANGLE_FAN);
+	    glNormal3f (0,0,-1);
+	    glVertex3f (aabb[0],aabb[2],aabb[4]);
+	    glVertex3f (aabb[0],aabb[3],aabb[4]);
+	    glVertex3f (aabb[1],aabb[3],aabb[4]);
+	    glVertex3f (aabb[1],aabb[2],aabb[4]);
+	    glEnd();
+	    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+	    }
+	}
+     }
+}
+
+
+void raydium_ode_near_callback(void *data, dGeomID o1, dGeomID o2)
+{
+int i,n;
+// dirty, but...
+#define N 400
+static  dContact contact[N];
+dJointID c;
+raydium_ode_Element *e1, *e2;
+int ground_elem_id,distan_obj_id;
+dReal erp=0;
+dReal cfm=0;
+dReal slip=0;
+int count=0;
+char (*f)(int,int, dContact *);
+f=raydium_ode_CollideCallback;
+
+ground_elem_id=raydium_ode_element_find("ground");
+distan_obj_id=raydium_ode_object_find("DISTANT");
+
+if(dGeomIsSpace (o1) || dGeomIsSpace (o2)) 
+    {
+    raydium_ode_Object *oo1, *oo2;
+    char (*g)(int,int);
+    oo1=dGeomGetData(o1);
+    oo2=dGeomGetData(o2);
+    g=raydium_ode_ObjectNearCollide;
+    if(g && !g(oo1->id,oo2->id)) return;
+    dSpaceCollide2 (o1,o2,data,&raydium_ode_near_callback);
+    return;
+    }
+
+
+  e1=dGeomGetData(o1);
+  e2=dGeomGetData(o2);
+
+/*
+  // avoid "ground - distant elements" contacts (may do it for all static-static contacts ?)
+  if(e1->id == ground_elem_id && e2->object == distan_obj_id)
+    return;
+  if(e2->id == ground_elem_id && e1->object == distan_obj_id)
+    return;
+  // .
+*/
+
+  // As said above, we will avoid all static-statics contacts.
+  // I think we must provide a "pre-filter" callback, since the user
+  // may need this contact infos
+
+  if(e1->state==RAYDIUM_ODE_STATIC && e2->state==RAYDIUM_ODE_STATIC)
+    return;
+
+  n = dCollide (o1,o2,N,&contact[0].geom,sizeof(dContact));
+  if(n>=N-1)
+    raydium_log("ODE: WARNING ! Not enought contact points available ! (%i max)",N);
+  if (n > 0) 
+  {
+  
+    for (i=0; i<n; i++) 
+	{	
+	e1=dGeomGetData(contact[i].geom.g1);
+	e2=dGeomGetData(contact[i].geom.g2);
+	
+	if(e1==NULL || e2==NULL)
+	    continue; // Deleted, or not one of our elements
+
+	if(e1 && e1->marked_as_deleted)
+	    return;
+	if(e2 && e2->marked_as_deleted)
+	    return;
+
+	if( e1 && e2 && e1->_movesfrom>=0 &&
+	    e1->_movesfrom==e2->object)
+		{
+		e1->_avoidedcol=1;
+		continue; // avoid collision ! (where are moving from this object)
+		}
+
+	if( e1 && e2 && e2->_movesfrom>=0 &&
+	    e2->_movesfrom==e1->object)
+		{
+		e2->_avoidedcol=1;
+		continue; // avoid collision ! (where are moving from this object)
+		}
+	
+	erp=cfm=slip=0;
+
+	if(e1)
+	    {
+	    erp=e1->erp;
+	    cfm=e1->cfm;
+	    slip=e1->slip;
+	    count=1;
+	    }
+	    
+	if(e2)
+	    {
+	    erp+=e2->erp;
+	    cfm+=e2->cfm;
+	    slip+=e2->slip;
+	    count++;
+	    }
+	    
+	if(count)
+	    {
+	    erp/=count;
+	    cfm/=count;
+	    slip/=count;
+	    }
+	    
+	contact[i].surface.mode = dContactSlip1 | dContactSlip2 |
+	dContactSoftERP | dContactSoftCFM | dContactApprox1;
+	contact[i].surface.mu = dInfinity;
+
+	contact[i].surface.slip1 = slip;
+	contact[i].surface.slip2 = slip;
+	
+	contact[i].surface.soft_erp = erp;
+	contact[i].surface.soft_cfm = cfm;
+
+	if(f)
+	    {
+	    int id1,id2;
+	    id1=id2=-1;
+	    if(e1) id1=e1->id;
+	    if(e2) id2=e2->id;
+	    if(!f(id1,id2,&contact[i])) continue;
+	    }
+
+	if(e1) e1->_touched=1; // may use it as a counter ?
+	if(e2) e2->_touched=1; // same as above
+
+	c = dJointCreateContact (raydium_ode_world,raydium_ode_contactgroup,&contact[i]);
+	dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2));
+    }
+  }
+}
+
+
+void raydium_ode_callback(void)
+{
+int i;
+void (*f)(void);
+f=raydium_ode_StepCallback;
+
+raydium_ode_network_read();
+
+if(f) f();
+
+/*
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(raydium_ode_joint[i].state)
+	{
+	if(raydium_ode_joint[i].hinge2correct)
+	    {
+	    //dJointCorrectHinge2(raydium_ode_joint[i].joint);
+	    }
+	}
+*/
+
+for(i=0;i<RAYDIUM_ODE_MAX_MOTORS;i++)
+    if(raydium_ode_motor[i].state)
+	raydium_ode_motor_update_joints_data_internal(i);
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state)
+	{
+	// init per_step variables
+	raydium_ode_element[i]._touched=0;
+	raydium_ode_element[i]._avoidedcol=0;
+	raydium_ode_element[i].ground_texture=0;
+	// test for damping effect:
+	if( raydium_ode_element[i].state==RAYDIUM_ODE_STANDARD &&
+	    raydium_ode_element[i].rotfriction!=0.f)
+	    {
+	    dReal *torque;
+	    dReal torqueinv[3];
+	    // may use element size, too ...
+	    torque=(dReal *)dBodyGetAngularVel(raydium_ode_element[i].body);
+	    torqueinv[0]=torque[0]*-raydium_ode_element[i].rotfriction;
+	    torqueinv[1]=torque[1]*-raydium_ode_element[i].rotfriction;
+	    torqueinv[2]=torque[2]*-raydium_ode_element[i].rotfriction;
+	    dBodyAddTorque(raydium_ode_element[i].body,torqueinv[0],torqueinv[1],torqueinv[2]);
+	    }
+	}
+
+for(i=0;i<RAYDIUM_ODE_MAX_EXPLOSIONS;i++)
+    if(raydium_ode_explosion[i].state)
+	{
+	// tag
+	
+	// 1 - check if radius > config_radius (and then delete explosion)
+	if(raydium_ode_explosion[i].radius>raydium_ode_explosion[i].config_radius)
+	    raydium_ode_explosion_delete(i);
+	else
+	 {	
+	 // 2 - increment radius
+	 raydium_ode_explosion[i].radius+=raydium_ode_explosion[i].config_propag;
+	 
+	 // 3 - delete previous element if exists
+	 if(raydium_ode_explosion[i].element>=0)
+	    raydium_ode_element_delete(raydium_ode_explosion[i].element,0);
+
+	 // 4 - create new element
+	 // (not really a distant element, but we don't want progap' ...)
+	 raydium_ode_network_distant_create=1;
+	 raydium_ode_explosion[i].element=
+	 raydium_ode_object_sphere_add(raydium_ode_explosion[i].name,
+	                               raydium_ode_object_find("GLOBAL"),
+				       0,
+				       raydium_ode_explosion[i].radius,
+				       RAYDIUM_ODE_STATIC,
+				       0, /* see below */
+				       "");
+	 raydium_ode_element[raydium_ode_explosion[i].element].user_tag=RAYDIUM_ODE_TAG_EXPLOSION;
+	 raydium_ode_element_material(raydium_ode_explosion[i].element,RAYDIUM_ODE_MATERIAL_SOFT2);
+	 raydium_ode_element_move(raydium_ode_explosion[i].element,raydium_ode_explosion[i].position);
+	 }
+	}
+
+
+raydium_ode_element_delete_LOCK=1;
+//raydium_profile_start();
+dSpaceCollide (raydium_ode_space,0,&raydium_ode_near_callback);
+for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
+    if(raydium_ode_object[i].state && raydium_ode_object[i].colliding)
+	dSpaceCollide ((dSpaceID)raydium_ode_object[i].group,0,&raydium_ode_near_callback);
+//raydium_profile_end("collision detection");
+raydium_ode_element_delete_LOCK=0;
+
+
+
+//raydium_profile_start();
+#ifdef ODE_QUICKSTEP
+dWorldQuickStep(raydium_ode_world,RAYDIUM_ODE_TIMESTEP);
+#else
+dWorldStep(raydium_ode_world,RAYDIUM_ODE_TIMESTEP);
+#endif
+//raydium_profile_end("world stepping");
+
+
+dJointGroupEmpty (raydium_ode_contactgroup);
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state  && 
+       raydium_ode_element[i].marked_as_deleted)
+	    raydium_ode_element_delete(i,1);
+    	    
+
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state  	    && 
+       raydium_ode_element[i]._movesfrom>=0 &&
+       !raydium_ode_element[i]._avoidedcol  )
+    	    raydium_ode_element[i]._movesfrom=-1;
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state   && 
+       raydium_ode_element[i].isplayer )
+        {
+	dMatrix3 R;
+	dRFromEulerAngles(R,0,0,raydium_ode_element[i].playerangle);
+	dBodySetRotation(raydium_ode_element[i].body,R);
+	dBodySetAngularVel(raydium_ode_element[i].body,0,0,0);
+	}
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state  &&
+       raydium_ode_element[i].ttl!=-1 )
+	{
+        if(raydium_ode_element[i].ttl==0)
+	    raydium_ode_element_delete(i,1);
+	else
+    	    raydium_ode_element[i].ttl--;	
+	}
+
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state  &&
+       raydium_ode_element[i].nid>=0  &&
+       raydium_ode_element[i].distant)
+	    raydium_ode_network_element_trajectory_correct(i);
+
+
+for(i=0;i<RAYDIUM_ODE_MAX_JOINTS;i++)
+    if(raydium_ode_joint[i].state)
+	raydium_ode_joint_break(i);
+
+}
+
+void raydium_ode_time_change(GLfloat perc)
+{
+raydium_timecall_freq_change(raydium_ode_timecall,(RAYDIUM_ODE_PHYSICS_FREQ*perc)/100.f);
+raydium_particle_time_factor=perc/100.f;
+}
+
+void raydium_ode_element_particle(int elem, char *filename)
+{
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot attach particle generator: invalid index or name");
+    return;
+    }
+raydium_ode_element[elem].particle=raydium_particle_generator_load(filename,raydium_ode_element[elem].name);
+memset(raydium_ode_element[elem].particle_offset,0,sizeof(dReal)*3);
+}
+
+void raydium_ode_element_particle_name(char *elem, char *filename)
+{
+raydium_ode_element_particle(raydium_ode_element_find(elem),filename);
+}
+
+void raydium_ode_element_particle_offset(int elem, char *filename, dReal *offset)
+{
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot attach particle generator (offset): invalid index or name");
+    return;
+    }
+raydium_ode_element[elem].particle=raydium_particle_generator_load(filename,raydium_ode_element[elem].name);
+memcpy(raydium_ode_element[elem].particle_offset,offset,sizeof(dReal)*3);
+}
+
+void raydium_ode_element_particle_offset_name(char *elem, char *filename, dReal *offset)
+{
+raydium_ode_element_particle_offset(raydium_ode_element_find(elem),filename,offset);
+}
+
+void raydium_ode_element_particle_offset_name_3f(char *elem, char *filename, dReal ox, dReal oy, dReal oz)
+{
+dReal offset[3];
+offset[0]=ox;
+offset[1]=oy;
+offset[2]=oz;
+raydium_ode_element_particle_offset(raydium_ode_element_find(elem),filename,offset);
+}
+
+
+// no offset provided yet for particle_point ... (easy to write, indeed)
+void raydium_ode_element_particle_point(int elem, char *filename)
+{
+char n[RAYDIUM_MAX_NAME_LEN];
+int p;
+dReal *pos;
+
+if(!raydium_ode_element_isvalid(elem))
+    {
+    raydium_log("ODE: Error: Cannot attach particle genrator: invalid index or name");
+    return;
+    }
+raydium_particle_name_auto(raydium_ode_element[elem].name,n);
+p=raydium_particle_generator_load(filename,n);
+if(p<0) return;
+pos=raydium_ode_element_pos_get(elem);
+raydium_particle_generator_move(p,pos);
+}
+
+void raydium_ode_element_particle_point_name(char *elem, char *filename)
+{
+raydium_ode_element_particle_point(raydium_ode_element_find(elem),filename);
+}
+
+// smooth camera related functions
+
+void raydium_camera_smooth_path_to_element(char *path, int element, GLfloat path_step, GLfloat smooth_step)
+{
+GLfloat x,y,z,zoom,roll;
+GLfloat *pos;
+
+pos=raydium_ode_element_pos_get(element);
+
+if(raydium_camera_smooth_path(path,path_step,&x,&y,&z,&zoom,&roll)==-1)
+    raydium_log("camera path error with '%s'",path);
+
+raydium_camera_smooth(x,y,z,pos[1],-pos[2],pos[0],zoom,roll,smooth_step);
+}
+
+void raydium_camera_smooth_path_to_element_name(char *path,char *element, GLfloat path_step, GLfloat smooth_step)
+{
+raydium_camera_smooth_path_to_element(path,raydium_ode_element_find(element),path_step,smooth_step);
+}
+
+
+void raydium_camera_smooth_element_to_path_offset(int element, GLfloat offset_x, GLfloat offset_y, GLfloat offset_z, char *path, GLfloat path_step, GLfloat smooth_step)
+{
+GLfloat x,y,z,zoom,roll;
+GLfloat *pos;
+GLfloat offset[3];
+
+pos=raydium_ode_element_pos_get(element);
+
+if(raydium_camera_smooth_path(path,path_step,&x,&y,&z,&zoom,&roll)==-1)
+    raydium_log("camera path error with '%s'",path);
+
+// static elems are not supported
+dBodyVectorToWorld(raydium_ode_element[element].body,offset_x,offset_y,offset_z,offset);
+
+raydium_camera_smooth(pos[0]+offset[0],pos[1]+offset[1],pos[2]+offset[2],y,-z,x,zoom,roll,smooth_step);
+}
+
+void raydium_camera_smooth_element_to_path_offset_name(char *element, GLfloat offset_x, GLfloat offset_y, GLfloat offset_z, char *path, GLfloat path_step, GLfloat smooth_step)
+{
+raydium_camera_smooth_element_to_path_offset(raydium_ode_element_find(element),offset_x,offset_y,offset_z,path,path_step,smooth_step);
+}
+
+void raydium_camera_smooth_element_to_path_name(char *element, char *path, GLfloat path_step, GLfloat smooth_step)
+{
+raydium_camera_smooth_element_to_path_offset(raydium_ode_element_find(element),0,0,0,path,path_step,smooth_step);
+}
+
+
+// This function is provided "for fun" only. Not all effects are dumped :
+// Missing : particles, shadows, forced colors, before/after callbacks, 
+// fixed elements, ...
+// Some code is pasted from file.c (and this is BAD ! :)
+
+int raydium_ode_capture_3d(char *filename)
+{
+int i,j,k;
+FILE *fp;
+dVector3 res,norm;
+char text[256];
+char sprt[256];
+
+
+fp=fopen(filename,"wt");
+if(!fp)
+    {
+    raydium_log("ERROR : failed to create 3D capture file '%s'",filename);
+    return 0;
+    }
+fprintf(fp,"1\n");
+
+for(i=0;i<RAYDIUM_ODE_MAX_ELEMENTS;i++)
+    if(raydium_ode_element[i].state && raydium_ode_element[i].mesh>=0)
+     {
+        dBodyID body;
+	dReal *pos;
+	dQuaternion rot;
+	body=dBodyCreate(raydium_ode_world);
+	pos=raydium_ode_element_pos_get(i);
+	raydium_ode_element_rotq_get(i,rot);
+	dBodySetPosition(body,pos[0],pos[1],pos[2]);
+	dBodySetQuaternion(body,rot);
+	k=raydium_ode_element[i].mesh;
+	
+	for(j=raydium_object_start[k];j<raydium_object_end[k];j++)
+	{
+	  if(raydium_vertex_texture_multi[j])
+	    {
+	    sprintf(text,"%s;%f|%f|%s",raydium_texture_name[raydium_vertex_texture[j]],
+	                               raydium_vertex_texture_multi_u[j],
+	                               raydium_vertex_texture_multi_v[j],
+	                               raydium_texture_name[raydium_vertex_texture_multi[j]]);
+	    }
+	else
+	    strcpy(text,raydium_texture_name[raydium_vertex_texture[j]]);
+													       
+	dBodyGetRelPointPos(body,
+                        	raydium_vertex_x[j],
+                        	raydium_vertex_y[j],
+                        	raydium_vertex_z[j],
+                        	res);
+				
+	dBodyVectorToWorld(body,
+				raydium_vertex_normal_visu_x[j],
+				raydium_vertex_normal_visu_y[j],
+				raydium_vertex_normal_visu_z[j],
+				norm);
+	
+	fprintf(fp,"%f %f %f %f %f %f %f %f %s\n",
+					res[0],
+					res[1],
+					res[2],
+					norm[0],
+					norm[1],
+					norm[2],
+					raydium_vertex_texture_u[j],
+					raydium_vertex_texture_v[j],
+					text);
+	}
+
+	dBodyDestroy(body);
+    	// raydium_ode_element[i].mesh
+     }
+fclose(fp);
+raydium_log("3D capture saved to '%s'",filename);
+sprintf(sprt,"%s.sprt",filename);
+raydium_particle_state_dump(sprt);
+return 1;
+}
+
+
+int raydium_ode_orphans_check(void)
+{
+int i,j,k,n;
+dGeomID g;
+int cpt=0;
+
+for(i=0;i<RAYDIUM_ODE_MAX_OBJECTS;i++)
+    if(raydium_ode_object[i].state)
+    {
+    n=dSpaceGetNumGeoms(raydium_ode_object[i].group);
+    if(!n) continue;
+
+    for(j=0;j<n;j++)
+	{
+	g=dSpaceGetGeom(raydium_ode_object[i].group,j);
+	for(k=0;k<RAYDIUM_ODE_MAX_ELEMENTS;k++)
+	    if(raydium_ode_element[k].state)
+		if(raydium_ode_element[k].geom)
+		    break;
+	
+	if(k==RAYDIUM_ODE_MAX_ELEMENTS)
+	    {
+	    cpt++;
+	    raydium_log("new orphan in '%s'",raydium_ode_object[i].name);
+	    }
+	}
+    }
+return cpt;
+}
+
+
+#include "ode_net.c"
Index: raydium/light.c
===================================================================
--- raydium/light.c	(revision 0)
+++ raydium/light.c	(revision 1)
@@ -0,0 +1,151 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/light.h"
+#endif 
+
+void raydium_light_enable(void)
+{
+glEnable(GL_LIGHTING);
+raydium_light_enabled_tag=1;
+}
+
+void raydium_light_disable(void)
+{
+glDisable(GL_LIGHTING);
+raydium_light_enabled_tag=0;
+}
+
+
+GLuint raydium_light_to_GL_light(GLuint l)
+{
+return GL_LIGHT0+l;
+}
+
+void raydium_light_on(GLuint l)
+{
+raydium_light_internal_state[l]=RAYDIUM_LIGHT_ON;
+glEnable(raydium_light_to_GL_light(l));
+}
+
+void raydium_light_off(GLuint l)
+{
+raydium_light_internal_state[l]=RAYDIUM_LIGHT_OFF;
+glDisable(raydium_light_to_GL_light(l));
+}
+
+void raydium_light_switch(GLuint l)
+{
+if(raydium_light_internal_state[l]<0)
+raydium_light_on(l);
+else
+raydium_light_off(l);
+}
+
+
+void raydium_light_update_position(GLuint l)
+{
+glLightfv(raydium_light_to_GL_light(l),GL_POSITION,raydium_light_position[l]);
+}
+
+void raydium_light_update_position_all(void)
+{
+int i;
+for(i=0;i<RAYDIUM_MAX_LIGHTS;i++)
+    if(raydium_light_internal_state[i]!=RAYDIUM_LIGHT_OFF)
+        raydium_light_update_position(i); 
+}
+
+
+void raydium_light_update_intensity(GLuint l)
+{
+glLightf(raydium_light_to_GL_light(l),GL_QUADRATIC_ATTENUATION,1.0/raydium_light_intensity[l]);
+}
+
+
+void raydium_light_update_all(GLuint l)
+{
+GLuint GLl=raydium_light_to_GL_light(l);
+//GLfloat zero[4]={0.0,0.0,0.0,1.0};
+//GLfloat one[4]={0.3,0.3,0.3,1.};
+//glLightfv(GLl,GL_AMBIENT, /*raydium_light_color[l]*//*zero*/one);
+glLightfv(GLl,GL_DIFFUSE, raydium_light_color[l]);
+glLightfv(GLl,GL_SPECULAR,raydium_light_color[l]);
+
+raydium_light_update_intensity(l);
+raydium_light_update_position(l);
+
+}
+
+
+
+void raydium_light_move(GLuint l,GLfloat *vect)
+{
+memcpy(raydium_light_position[l],vect,raydium_internal_size_vector_float_4);
+//raydium_light_update_position(l);
+}
+
+
+
+void raydium_light_reset(GLuint l)
+{
+GLfloat pos[]={0,0,0,1};
+GLfloat color[]={1.0, 1.0, 1.0, 1.0};
+GLfloat intensity=10000000;
+
+memcpy(raydium_light_position[l],pos,raydium_internal_size_vector_float_4);
+memcpy(raydium_light_color[l],color,raydium_internal_size_vector_float_4);
+raydium_light_intensity[l]=intensity;
+raydium_light_off(l);
+raydium_light_update_all(l);
+}
+
+
+void raydium_light_blink_internal_update(GLuint l)
+{
+raydium_light_intensity[l]+=raydium_light_blink_increment[l];
+
+if(raydium_light_intensity[l]>raydium_light_blink_high[l])
+ { 
+ raydium_light_intensity[l]=raydium_light_blink_high[l];
+ raydium_light_blink_increment[l]*=-1.0;
+ }
+
+if(raydium_light_intensity[l]<raydium_light_blink_low[l])
+ { 
+ raydium_light_intensity[l]=raydium_light_blink_low[l];
+ raydium_light_blink_increment[l]*=-1.0;
+ }
+
+raydium_light_update_intensity(l);
+}
+
+
+void raydium_light_blink_start(GLuint l,int fpc)
+{
+raydium_light_on(l);
+raydium_light_internal_state[l]=RAYDIUM_LIGHT_BLINKING;
+//fpc = frames per cycle
+fpc/=2;
+raydium_light_blink_low[l]=raydium_light_intensity[l]/fpc;
+raydium_light_blink_high[l]=raydium_light_intensity[l];
+raydium_light_blink_increment[l]=raydium_light_intensity[l]/fpc;
+raydium_light_blink_internal_update(l);
+}
+
+
+void raydium_light_callback(void)
+{
+GLuint i;
+
+for(i=0;i<RAYDIUM_MAX_LIGHTS;i++)
+ if(raydium_light_internal_state[i]==RAYDIUM_LIGHT_BLINKING) 
+  raydium_light_blink_internal_update(i);
+}
+
Index: raydium/index.c
===================================================================
--- raydium/index.c	(revision 0)
+++ raydium/index.c	(revision 1)
@@ -0,0 +1,94 @@
+#ifndef FORCE_LIBRAYDIUM
+/*
+* Raydium - CQFD Corp.
+* http://raydium.cqfd-corp.org
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+// Include this file if you want to use "[o]comp*.sh" scripts, for
+// a full compilation + run.
+// Define "FORCE_LIBRAYDIUM" (-DFORCE_LIBRAYDIUM) if you want to
+// force index.h (see dyncomp.sh).
+
+#define DONT_INCLUDE_HEADERS 
+
+#include "main.c"
+
+// let's start "compile time static linking" ;)
+#ifndef RAYDIUM_NETWORK_ONLY
+#include "log.c"
+#include "signal.c"
+#include "trigo.c"
+#include "random.c"
+#include "timecall.c"
+#include "profile.c"
+#include "parser.c"
+#include "fog.c"
+#include "window.c"
+#include "capture.c"
+#include "clear.c"
+#include "background.c"
+#include "light.c"
+#include "key.c"
+#include "mouse.c"
+#include "joy.c"
+#include "texture.c"
+#include "render.c"
+#include "particle2.c"
+#include "sound.c"
+#include "callback.c"
+#include "normal.c"
+#include "vertex.c"
+#include "osd.c"
+#include "register.c"
+#ifdef PHP_SUPPORT
+#include "php.c"
+#include "rayphp.c"
+#endif
+#include "console.c"
+#include "gui.c"
+#include "land.c"
+#include "sky.c"
+#include "internal.c"
+#include "file.c"
+#include "camera.c"
+#include "object.c"
+#include "network.c"
+#include "init.c"
+#ifdef ODE_SUPPORT
+#include "ode.c"
+#endif
+#include "reg_api.c"
+
+#else
+
+#include "log.c"
+#include "trigo.c"
+#include "random.c"
+#include "timecall.c"
+#include "parser.c"
+#include "network.c"
+#include "register.c"
+#ifdef PHP_SUPPORT
+#include "php.c"
+#endif
+#endif
+
+#else
+// FORCE_LIBRAYDIUM is defined
+#include "index.h"
+#endif
+// EOF
Index: raydium/php_wrappers.c
===================================================================
--- raydium/php_wrappers.c	(revision 0)
+++ raydium/php_wrappers.c	(revision 1)
@@ -0,0 +1,523 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+// C prototype to PHP function wrappers:
+// PHP_ReturnType_Arg1TypeArg2Type...(function to wrap)
+// v stands for: void
+// i stands for: int
+// f stands for: float
+// s stands for: char *
+// svaria stands for: (char *, ...)
+// Don't forget to register your functions, too ! (see register.c or docs)
+
+// void f(void)
+#define PHP_v_v(fname)\
+ZEND_FUNCTION(fname)\
+{\
+fname();\
+}
+
+// void f(int)
+#define PHP_v_i(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long a;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "l", &a) == FAILURE)  return;\
+fname(a);\
+}
+
+// void f(float)
+#define PHP_v_f(fname)\
+ZEND_FUNCTION(fname)\
+{\
+double a;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "d", &a) == FAILURE)  return;\
+fname(a);\
+}
+
+// int f(void)
+#define PHP_i_v(fname)\
+ZEND_FUNCTION(fname)\
+{\
+RETURN_LONG(fname());\
+}
+
+// int f(int)
+#define PHP_i_i(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long a;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "l", &a) == FAILURE)  return;\
+RETURN_LONG(fname(a));\
+}
+
+// int f(int, int)
+#define PHP_i_ii(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long a,b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ll", &a, &b) == FAILURE)  return;\
+RETURN_LONG(fname(a,b));\
+}
+
+// void f(int, int)
+#define PHP_v_ii(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long a,b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ll", &a, &b) == FAILURE)  return;\
+fname(a,b);\
+}
+
+// int f(int,float)
+#define PHP_i_if(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long a;\
+double b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ld", &a, &b) == FAILURE)  return;\
+RETURN_LONG(fname(a,b));\
+}
+  
+// void f(float, float, float) - double, too
+#define PHP_v_fff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+double a,b,c;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+    "ddd", &a, &b, &c) == FAILURE)  return;\
+fname(a,b,c);\
+}
+
+// void f(float, float, float, float)
+#define PHP_v_ffff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+double a,b,c,d;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+    "dddd", &a, &b, &c, &d) == FAILURE)  return;\
+fname(a,b,c,d);\
+}
+
+// int f(char *)
+#define PHP_i_s(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "s", &a, &s_len) == FAILURE)  return;\
+RETURN_LONG(fname(a));\
+}
+
+// int f(char *, char*)
+#define PHP_i_ss(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+char *b;\
+long s_len;\
+long s_len2;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ss", &a, &s_len, &b, &s_len2) == FAILURE)  return;\
+RETURN_LONG(fname(a,b));\
+}
+
+// float f(char *, int)
+#define PHP_f_si(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+long b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sl", &a, &s_len, &b) == FAILURE)  return;\
+RETURN_DOUBLE(fname(a,b));\
+}
+
+// int f(char *, int)
+#define PHP_i_si(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+long b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sl", &a, &s_len, &b) == FAILURE)  return;\
+RETURN_LONG(fname(a,b));\
+}
+
+// int f(char *, int, int)
+#define PHP_i_sii(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+long b,c;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sll", &a, &s_len, &b, &c) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c));\
+}
+
+
+// void f(char *)
+#define PHP_v_s(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "s", &a, &s_len) == FAILURE)  return;\
+fname(a);\
+}
+
+// int f(char *, char*, char *)
+#define PHP_i_sss(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+char *b;\
+char *c;\
+long s_len;\
+long s_len2;\
+long s_len3;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sss", &a, &s_len, &b, &s_len2, &c, &s_len3) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c));\
+}
+
+// void f(char *, char*, char *)
+#define PHP_v_sss(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+char *b;\
+char *c;\
+long s_len;\
+long s_len2;\
+long s_len3;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sss", &a, &s_len, &b, &s_len2, &c, &s_len3) == FAILURE)  return;\
+fname(a,b,c));\
+}
+
+// void f(char *, ...) - (printf style)
+#define PHP_v_svaria(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "s", &a, &s_len) == FAILURE)  return;\
+fname("%s",a);\
+}
+
+
+// int f(char *, int, float, float, char *)
+#define PHP_i_siffs(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long s_len1;\
+long s_len2;\
+char *a;\
+long b;\
+double c,d;\
+char *e;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sldds", &a, &s_len1, &b, &c, &d, &e, &s_len2) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e));\
+}
+
+// int f(char *, int, float, float, char *, int)
+#define PHP_i_siffsi(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long s_len1;\
+long s_len2;\
+char *a;\
+long b;\
+double c,d;\
+char *e;\
+long f;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "slddsl", &a, &s_len1, &b, &c, &d, &e, &s_len2, &f) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f));\
+}
+
+// int f(char *, int, float, float, char *, float, float, float)
+#define PHP_i_siffsfff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long s_len1;\
+long s_len2;\
+char *a;\
+long b;\
+double c,d;\
+char *e;\
+double f,g,h;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "slddsddd", &a, &s_len1, &b, &c, &d, &e, &s_len2, &f, &g, &h) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f,g,h));\
+}
+
+
+// int f(char *, int, float, float, int, int, char *)
+#define PHP_i_siffiis(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long s_len1;\
+long s_len2;\
+char *a;\
+long b;\
+double c,d;\
+long e,f;\
+char *g;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "slddlls", &a, &s_len1, &b, &c, &d, &e, &f, &g, &s_len2) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f,g));\
+}
+
+#define PHP_i_siffiii(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long s_len1;\
+char *a;\
+long b;\
+double c,d;\
+long e,f;\
+long g;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "slddlll", &a, &s_len1, &b, &c, &d, &e, &f, &g) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f,g));\
+}
+
+// int f(char *, int, float, float, float, float, int, int, char *)
+#define PHP_i_siffffiis(fname)\
+ZEND_FUNCTION(fname)\
+{\
+long s_len1;\
+long s_len2;\
+char *a;\
+long b;\
+double c,d,e,f;\
+long g,h;\
+char *i;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "slddddlls", &a, &s_len1, &b, &c, &d, &e, &f, &g, &h, &i, &s_len2) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f,g,h,i));\
+}
+
+
+// void f(char *, int)
+#define PHP_v_si(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+long b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sl", &a, &s_len, &b) == FAILURE)  return;\
+fname(a,b);\
+}
+
+// int f(char *, float)
+#define PHP_i_sf(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+double b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sd", &a, &s_len, &b) == FAILURE)  return;\
+RETURN_LONG(fname(a,b));\
+}
+
+
+// int f(char *, float, float)
+#define PHP_i_sff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+double b,c;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sdd", &a, &s_len, &b, &c) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c));\
+}
+
+// void f(char *, float, float)
+#define PHP_v_sff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+double b,c;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sdd", &a, &s_len, &b, &c) == FAILURE)  return;\
+fname(a,b,c);\
+}
+
+// void f(char *, float, float, float)
+#define PHP_v_sfff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+double b,c,d;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sddd", &a, &s_len, &b, &c, &d) == FAILURE)  return;\
+fname(a,b,c,d);\
+}
+
+// void f(char *, float, float, float, float, float, float)
+#define PHP_v_sffffff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len;\
+double b,c,d;\
+double e,f,g;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sdddddd", &a, &s_len, &b, &c, &d, &e, &f, &g) == FAILURE)  return;\
+fname(a,b,c,d,e,f,g);\
+}
+
+
+// void f(char *, char *, int)
+#define PHP_v_ssi(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+long c;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ssl", &a, &s_len1, &b, &s_len2, &c) == FAILURE)  return;\
+fname(a,b,c);\
+}
+
+// void f(char *, char *, float)
+#define PHP_v_ssf(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+double c;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ssd", &a, &s_len1, &b, &s_len2, &b, &c) == FAILURE)  return;\
+fname(a,b,c);\
+}
+
+// void f(char *, char *, float, float, float)
+#define PHP_v_ssfff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+double c,d,e;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ssddd", &a, &s_len1, &b, &s_len2, &c, &d, &e) == FAILURE)  return;\
+fname(a,b,c,d,e);\
+}
+
+
+// void f(char *, char *)
+#define PHP_v_ss(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ss", &a, &s_len1, &b, &s_len2, &b) == FAILURE)  return;\
+fname(a,b);\
+}
+
+
+// void f(char *, float)
+#define PHP_v_sf(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+double b;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sd", &a, &s_len1, &b) == FAILURE)  return;\
+fname(a,b);\
+}
+
+// int f(char *, char *, char *, float, float, float, float, float, float)
+#define PHP_i_sssffffff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+char *c;\
+long s_len3;\
+double d,e,f;\
+double g,h,i;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sssdddddd", &a, &s_len1, &b, &s_len2,&c, &s_len3, &d, &e ,&f, &g, &h, &i) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f,g,h,i));\
+}
+
+// int f(char *, float, float, float, float)
+#define PHP_i_sffff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+double b,c,d,e;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sdddd", &a, &s_len1, &b, &c, &d, &e) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e));\
+}
+
+// int f(char *, char *, float, float, float, float)
+#define PHP_i_ssffff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+double c,d,e,f;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "ssdddd", &a, &s_len1, &b, &s_len2, &c, &d, &e ,&f) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f));\
+}
+
+// int f(char *, char *, float, float, float, float)
+#define PHP_i_sssffff(fname)\
+ZEND_FUNCTION(fname)\
+{\
+char *a;\
+long s_len1;\
+char *b;\
+long s_len2;\
+char *c;\
+long s_len3;\
+double d,e,f;\
+double g;\
+if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,\
+  "sssdddd", &a, &s_len1, &b, &s_len2,&c, &s_len3, &d, &e ,&f, &g) == FAILURE)  return;\
+RETURN_LONG(fname(a,b,c,d,e,f,g));\
+}
+
Index: raydium/internal.c
===================================================================
--- raydium/internal.c	(revision 0)
+++ raydium/internal.c	(revision 1)
@@ -0,0 +1,75 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/internal.h"
+#endif 
+
+void raydium_file_log_fopen_display(void);
+void raydium_network_internal_dump(void);
+
+void raydium_internal_dump(void)
+{
+GLuint i,j,a;
+
+if(raydium_init_cli_option("regs",NULL))
+    raydium_register_dump();
+
+raydium_log("Internal buffers:");
+raydium_log("-----------------");
+raydium_log("Total of %i vertex(s) loaded:",raydium_vertex_index);
+for(i=0;i<raydium_texture_index;i++)
+    {
+    for(j=0,a=0;j<raydium_vertex_index;j++)
+	if(raydium_vertex_texture[j]==i) a++;
+	    raydium_log("Texture num %i: %i vertex(s) - loaded as \"%s\"",i,a,raydium_texture_name[i]);
+    }
+raydium_log("Estimated total: %.2f MB used for textures.",raydium_texture_used_memory/1024.f/1024.f);
+
+raydium_log("Using %i object(s):",raydium_object_index);
+for(i=0;i<raydium_object_index;i++)
+    {
+    a=raydium_object_end[i]-raydium_object_start[i];
+    raydium_log("Object num %i: %i vertex(s) - loaded as \"%s\"",i,a,raydium_object_name[i]);
+    }
+
+if(raydium_network_mode!=RAYDIUM_NETWORK_MODE_NONE)
+    raydium_network_internal_dump();
+
+if(raydium_init_cli_option("files",NULL)) raydium_file_log_fopen_display();
+
+// raydium_log(".end of dump");
+}
+
+// 0 : Projection
+// 1 : Model
+void raydium_internal_dump_matrix(int n)
+{
+GLfloat tmp[16];
+char str[80];
+char str2[80];
+int i,j;
+
+if(n==0) glGetFloatv(GL_PROJECTION_MATRIX,tmp);
+if(n==1) glGetFloatv(GL_MODELVIEW_MATRIX,tmp);
+
+raydium_log("Matrix [4x4] :");
+str[0]=0;
+for(i=j=0;i<16;i++,j++)
+ {
+  sprintf(str2,"| % 10.2f ",tmp[i]);
+  strcat(str,str2);
+  if(j>=3)
+   {
+   j=-1;
+   raydium_log("%s",str);
+   str[0]=0;
+   }
+ }
+raydium_log(".end");
+}
Index: raydium/ode.h
===================================================================
--- raydium/ode.h	(revision 0)
+++ raydium/ode.h	(revision 1)
@@ -0,0 +1,240 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef RAY_ODE_H
+#define RAY_ODE_H
+#include "../ode/include/ode/ode.h"
+
+#define RAYDIUM_ODE_MAX_OBJECTS			64
+#define RAYDIUM_ODE_MAX_ELEMENTS		256
+#define RAYDIUM_ODE_MAX_JOINTS			256
+#define RAYDIUM_ODE_MAX_MOTORS			64
+#define RAYDIUM_ODE_MAX_EXPLOSIONS		32
+#define	RAYDIUM_ODE_MOTOR_MAX_JOINTS		10
+#define	RAYDIUM_ODE_MOTOR_MAX_GEARS		10
+#define	RAYDIUM_ODE_ELEMENT_MAX_FIXING		10
+
+
+#define RAYDIUM_ODE_PHYSICS_FREQ		400
+#define	RAYDIUM_ODE_TIMESTEP			(0.006f)
+
+#define RAYDIUM_ODE_AUTODETECT			-1
+#define RAYDIUM_ODE_STANDARD			1
+#define RAYDIUM_ODE_STATIC			2
+#define RAYDIUM_ODE_FIXING			3
+#define RAYDIUM_ODE_MOTOR_ENGINE		1
+#define RAYDIUM_ODE_MOTOR_ANGULAR		2
+#define RAYDIUM_ODE_MOTOR_ROCKET		3
+
+#define RAYDIUM_ODE_JOINT_AXE_X			1,0,0
+#define RAYDIUM_ODE_JOINT_AXE_Y			0,1,0
+#define RAYDIUM_ODE_JOINT_AXE_Z			0,0,1
+#define RAYDIUM_ODE_JOINT_SUSP_DEFAULT_AXES	RAYDIUM_ODE_JOINT_AXE_Z,RAYDIUM_ODE_JOINT_AXE_Y
+
+#define RAYDIUM_ODE_MATERIAL_HARD		0.9,0.1
+#define RAYDIUM_ODE_MATERIAL_MEDIUM		0.5,0.5
+#define RAYDIUM_ODE_MATERIAL_SOFT		0.1,0.9
+#define RAYDIUM_ODE_MATERIAL_SOFT2		0.0,0.9
+#define RAYDIUM_ODE_MATERIAL_DEFAULT		RAYDIUM_ODE_MATERIAL_HARD
+
+#define RAYDIUM_ODE_SLIP_ICE			5.f
+#define RAYDIUM_ODE_SLIP_PLAYER			10.f
+#define RAYDIUM_ODE_SLIP_NORMAL			0.4f		
+#define RAYDIUM_ODE_SLIP_DEFAULT		RAYDIUM_ODE_SLIP_NORMAL
+
+#define RAYDIUM_ODE_TAG_EXPLOSION		-1
+#define RAYDIUM_ODE_TAG_GROUND			-2
+
+#define RAYDIUM_ODE_NETWORK_OPTIMAL		-1
+#define RAYDIUM_ODE_NETWORK_MAXFREQ		20
+
+#define RAYDIUM_ODE_NETWORK_EXPLOSION_EXPL	1
+#define RAYDIUM_ODE_NETWORK_EXPLOSION_BLOW	2
+
+
+dWorldID 	raydium_ode_world;
+dSpaceID 	raydium_ode_space;
+dJointGroupID 	raydium_ode_contactgroup;
+int		raydium_ode_ground_mesh;
+GLint		raydium_ode_timecall; // read only (timecall index for ode callback)
+void *		raydium_ode_CollideCallback; // char f(int,int,dContact*)
+void *		raydium_ode_StepCallback; // void f(void)
+void *		raydium_ode_ObjectNearCollide; // char f(int,int)
+char		raydium_ode_network_distant_create;
+char		raydium_ode_network_next_local_only;
+char		raydium_ode_network_explosion_create;
+int		raydium_ode_network_maxfreq;
+void *		raydium_ode_ExplosionCallback; // void f(char,dReal,dReal,dReal *)
+void *		raydium_ode_BeforeElementDrawCallback;
+void *		raydium_ode_AfterElementDrawCallback;
+char	  	raydium_ode_element_delete_LOCK;
+
+typedef struct raydium_ode_Explosion // used for "blowing" explosions
+{
+    int   id;
+    char  name[RAYDIUM_MAX_NAME_LEN];
+    char  state;
+    dReal config_radius; // desired radius
+    dReal config_propag; // propagation speed (increment to config_radius)
+    dReal radius; // current radius
+    int   element;
+    dReal position[3];
+} raydium_ode_Explosion;
+
+typedef struct raydium_ode_Joint
+{
+    int      id;
+    char     name[RAYDIUM_MAX_NAME_LEN];
+    char     state;
+    int      mesh; // not used for joints, yet
+    char     hinge2correct; // this hinge2 needs to be re-aligned each timestep
+    char     motored; // powered by a motor ?
+    dReal    motorforce;
+    dReal    breakableforce; // is breakable ? (max force without braking)
+    char     breaking; // is currently breaking (used as a tag for OnDelete)
+    dJointID joint;
+    void *   OnDelete; // pointer to OnDelete user callback
+} raydium_ode_Joint;
+
+typedef struct raydium_ode_Motor
+{
+    int   id;
+    char  name[RAYDIUM_MAX_NAME_LEN];
+    char  state;
+    int   object; // owner
+    int   joints[RAYDIUM_ODE_MOTOR_MAX_JOINTS];      // attached to ... (joints)
+    int	  joints_axe[RAYDIUM_ODE_MOTOR_MAX_JOINTS];  // wich axe ? (joint relative)
+    int   rocket_element; // rocket only: attached to this element
+    dReal rocket_direction[3]; // rocket only (relative to element)
+    dReal rocket_orientation[3]; // rocket only (relative to element)
+    dReal rocket_position[3]; // rocket only (relative to element)
+    char  rocket_playermovement; // this rocket is used for a FPS player
+    dReal speed; // "engine style" motor: desired speed
+    dReal angle; // "angular style" motor: desired angle
+    dReal force; // all styles (engine, angular and rocket)
+    dReal gears[RAYDIUM_ODE_MOTOR_MAX_GEARS]; // gear box factors
+    int   gear; // current gear
+    int   gear_max; // max gear
+} raydium_ode_Motor;
+
+typedef struct raydium_ode_ElementInternalSave
+{
+    char  name[RAYDIUM_MAX_NAME_LEN];
+    int	  type; // ODE geom type
+    dReal sphere_radius;
+    dReal box_sizes[3];
+    dReal mass;
+    int   object;
+    int   mesh;
+    dReal slip;
+    dReal cfm;
+    dReal erp;
+    dReal rel_pos[3];
+    dReal rel_rot[4];
+    void *user_data;
+    int   user_tag;
+    void *OnBlow;
+    void *OnDelete;
+} raydium_ode_ElementInternalSave;
+
+typedef struct raydium_ode_Element
+{
+    int     id;
+    char    name[RAYDIUM_MAX_NAME_LEN];
+    char    state;
+    int     object;
+    int     mesh;
+    char    _touched;	// touched during very last timestep
+    char    _movesfrom;	// is leaving this object to "object" member
+    char    _avoidedcol;	// is any collision was avoided because of this move ?
+    char    isplayer;	// is this element an FPS player ? ("standing elem")
+    dReal   playerangle; // FPS player angle
+    dReal   slip;	// slipping factor
+    dReal   rotfriction; // rotation friction factor (avoid infinite rolling spheres)
+    dGeomID geom;
+    dBodyID body;
+    dReal   erp;
+    dReal   cfm;    
+    void *  user_data; // point to user data
+    int	    user_tag; // tag reseverd to user (this tag is networked)
+    raydium_ode_ElementInternalSave *fixed_elements[RAYDIUM_ODE_ELEMENT_MAX_FIXING];
+    int	    nid; //  network ID
+    char    distant; // owned by a distant machine
+    int     distant_owner;
+    time_t  lastnetupdate;
+    void *  OnBlow; // when touched by a blowing explosion void (*f)(int,dReal,dReal)
+    void *  OnDelete; // int (*f)(int)
+    int	    ttl; // time to live, -1 for infinite (default)
+    int	    particle;
+    dReal   particle_offset[3];
+    unsigned long net_last_time;
+    dReal         net_last_pos1[3];
+    dReal         net_last_pos2[3];
+    dReal         netvel[3]; // test
+    unsigned long net_last_interval;
+    int		  ground_texture;
+    char	  marked_as_deleted;
+} raydium_ode_Element;
+
+
+typedef struct raydium_ode_Object
+{
+    int      id;
+    char     name[RAYDIUM_MAX_NAME_LEN];
+    char     state;
+    char     colliding; // elements of this objet can collide each other
+    dSpaceID group;
+//    dGeomID group;
+} raydium_ode_Object;
+
+
+typedef struct raydium_ode_network_Event
+{
+    int nid;
+    dReal pos[3];
+    dReal rot[4];
+    dReal vel[3]; // test
+} raydium_ode_network_Event;
+
+typedef struct raydium_ode_network_Explosion
+{
+    char type; // RAYDIUM_ODE_NETWORK_EXPLOSION_* (EXPL or BLOW)
+    dReal pos[3];
+    dReal radius;
+    dReal force; // BLOW only
+    dReal propag; // EXPL only
+} raydium_ode_network_Explosion;
+
+
+raydium_ode_Object    raydium_ode_object[RAYDIUM_ODE_MAX_OBJECTS];
+raydium_ode_Element   raydium_ode_element[RAYDIUM_ODE_MAX_ELEMENTS];
+raydium_ode_Joint     raydium_ode_joint[RAYDIUM_ODE_MAX_JOINTS];
+raydium_ode_Motor     raydium_ode_motor[RAYDIUM_ODE_MAX_MOTORS];
+raydium_ode_Explosion raydium_ode_explosion[RAYDIUM_ODE_MAX_EXPLOSIONS];
+
+void raydium_ode_callback(void);
+int  raydium_ode_object_create(char *);
+void raydium_ode_motor_rocket_orientation(int m, dReal rx, dReal ry, dReal rz);
+int  raydium_ode_object_find(char *name);
+char raydium_ode_element_material(int e, dReal erp, dReal cfm);
+char raydium_ode_element_slip(int e, dReal slip);
+char raydium_ode_object_colliding(int o, char colliding);
+char raydium_ode_element_delete(int e, char deletejoints);
+void raydium_ode_element_move(int elem, dReal *pos);
+dReal *raydium_ode_element_pos_get(int j);
+
+void raydium_ode_network_init(void);
+void raydium_ode_network_element_delete(int e);
+void raydium_ode_network_element_new(int e);
+void raydium_ode_network_read(void);
+int  raydium_network_nid_element_find(int nid);
+int  raydium_ode_network_MaxElementsPerPacket(void);
+void raydium_ode_network_explosion_send(raydium_ode_network_Explosion *exp);
+void raydium_ode_network_element_trajectory_correct(int elem);
+
+// (#ifdef RAY_ODE_H)
+#endif
+
Index: raydium/index.h
===================================================================
--- raydium/index.h	(revision 0)
+++ raydium/index.h	(revision 1)
@@ -0,0 +1,84 @@
+/*
+* Raydium - CQFD Corp.
+* http://raydium.cqfd-corp.org
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+// Include this file if you want to use Makefile and libraydium, for
+// a quick compilation (use odyncomp.sh script, for example)
+
+#include "headers/main.h"
+
+#ifndef RAYDIUM_NETWORK_ONLY
+#include "headers/log.h"
+#include "headers/signal.h"
+#include "headers/trigo.h"
+#include "headers/random.h"
+#include "headers/timecall.h"
+#include "headers/profile.h"
+#include "headers/parser.h"
+#include "headers/fog.h"
+#include "headers/window.h"
+#include "headers/capture.h"
+#include "headers/clear.h"
+#include "headers/background.h"
+#include "headers/light.h"
+#include "headers/key.h"
+#include "headers/mouse.h"
+#include "headers/joy.h"
+#include "headers/texture.h"
+#include "headers/render.h"
+#include "headers/particle2.h"
+#include "headers/sound.h"
+#include "headers/callback.h"
+#include "headers/normal.h"
+#include "headers/vertex.h"
+#include "headers/osd.h"
+#include "headers/register.h"
+#ifdef PHP_SUPPORT
+#include "headers/php.h"
+#include "headers/rayphp.h"
+#endif
+#include "headers/console.h"
+#include "headers/gui.h"
+#include "headers/land.h"
+#include "headers/sky.h"
+#include "headers/internal.h"
+#include "headers/file.h"
+#include "headers/camera.h"
+#include "headers/object.h"
+#include "headers/network.h"
+#include "headers/init.h"
+#ifdef ODE_SUPPORT
+#include "headers/ode.h"
+#endif
+#include "headers/reg_api.h"
+
+#else
+
+#warning "unless you know what you're doing, RAYDIUM_NETWORK_ONLY with \
+dynamic linking is a bad idea. Use static linking instead (ex: comp.sh)"
+#include "headers/log.h"
+#include "headers/trigo.h"
+#include "headers/random.h"
+#include "headers/timecall.h"
+#include "headers/parser.h"
+#include "headers/network.h"
+#include "headers/register.h"
+#ifdef PHP_SUPPORT
+#include "headers/php.h"
+#endif
+#endif
Index: raydium/signal.c
===================================================================
--- raydium/signal.c	(revision 0)
+++ raydium/signal.c	(revision 1)
@@ -0,0 +1,25 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/signal.h"
+#endif
+
+void raydium_signal_handler(int sig)
+{
+raydium_log("SIGINT disabled.",sig); // sig not used (compilo warning)
+}
+
+void raydium_signal_install_trap(void)
+{
+
+if(signal(SIGINT,raydium_signal_handler)==SIG_ERR)
+    raydium_log("Signal Handler: FAILED !");
+else
+    raydium_log("Signal Handler: OK");
+}
Index: raydium/land.c
===================================================================
--- raydium/land.c	(revision 0)
+++ raydium/land.c	(revision 1)
@@ -0,0 +1,131 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/land.h"
+#endif
+
+// mostly unusable functions (old Raydium's core) ...
+
+GLfloat raydium_land_internal_landtmp(GLfloat x,GLfloat y,GLfloat phase,GLfloat ampl, GLfloat periode)
+{
+GLfloat a,b;
+
+a=(x/periode)*360;
+b=(y/periode)*360;
+a+=phase;
+b+=phase;
+
+while(a>=360) a-=360;
+while(b>=360) b-=360;
+
+a=raydium_trigo_cos(a);
+b=raydium_trigo_cos(b);
+
+b=b*a;
+b*=ampl;
+
+return(b);
+}
+
+// must recode all this function
+void raydium_land_draw_water(GLfloat phase, GLfloat ampl, GLfloat periode,
+                                 int sub, GLfloat pas, char *texture)
+{
+int ix,iy;
+//GLfloat pas;
+//GLfloat wpas,border,dep=0;
+GLfloat x1,x2,y1,y2;
+GLuint vertex_index_save;
+
+//pas=(SUBDIV*FACT)/sub;
+
+
+raydium_texture_current_set_name(texture);
+vertex_index_save=raydium_vertex_index;
+
+// angle=(x*ampl)/360
+
+for(iy=0;iy<sub;iy++)
+for(ix=0;ix<sub;ix++)
+{
+
+x1=(GLfloat)(ix)*pas;
+x2=(GLfloat)(ix+1)*pas;
+y1=(GLfloat)(iy)*pas;
+y2=(GLfloat)(iy+1)*pas;
+
+//#define FACTW (FACT/2)
+#define FACTW 10
+
+raydium_vertex_uv_add(x1,y1, raydium_land_internal_landtmp(x1,y1,phase,ampl,periode), 0,0);
+raydium_vertex_uv_add(x2,y1, raydium_land_internal_landtmp(x2,y1,phase,ampl,periode), FACTW,0);
+raydium_vertex_uv_add(x2,y2, raydium_land_internal_landtmp(x2,y2,phase,ampl,periode), FACTW,FACTW);
+
+raydium_vertex_uv_add(x2,y2, raydium_land_internal_landtmp(x2,y2,phase,ampl,periode), FACTW,FACTW);
+raydium_vertex_uv_add(x1,y2, raydium_land_internal_landtmp(x1,y2,phase,ampl,periode), 0,FACTW);
+raydium_vertex_uv_add(x1,y1, raydium_land_internal_landtmp(x1,y1,phase,ampl,periode), 0,0);
+
+}
+
+/*
+// expand water space
+#define EXPAND 5000.f
+#define EX_Z (-ampl)
+border=SUBDIV*FACT;
+
+
+raydium_vertex_uv_add(0,-EXPAND,EX_Z, 0,0);
+raydium_vertex_uv_add(0,border+EXPAND,EX_Z, 0,(EXPAND*2+border)/FACT);
+raydium_vertex_uv_add(-EXPAND,border+EXPAND,EX_Z, -EXPAND/FACT,(EXPAND*2+border)/FACT);
+*/
+
+raydium_rendering_from_to(vertex_index_save,raydium_vertex_index);
+raydium_vertex_index=vertex_index_save;
+}
+
+
+// unsable
+GLfloat raydium_land_surface(GLfloat x, GLfloat y, GLfloat *nx, GLfloat *ny, GLfloat *nz)
+{
+//int cx,cy;
+GLint n;
+GLfloat dx,dy;
+GLfloat a,b,c,d;
+//cx=x/FACT;
+//cy=y/FACT;
+//n=((cx*(SUBDIV-1))+cy)*6;
+
+//dy=x-(float)(cx*FACT);
+//dx=y-(float)(cy*FACT);
+
+if(dy>=dx) n+=3;
+
+#define Ax raydium_vertex_x[n]
+#define Bx raydium_vertex_x[n+1]
+#define Cx raydium_vertex_x[n+2]
+
+#define Ay raydium_vertex_y[n]
+#define By raydium_vertex_y[n+1]
+#define Cy raydium_vertex_y[n+2]
+
+#define Az raydium_vertex_z[n]
+#define Bz raydium_vertex_z[n+1]
+#define Cz raydium_vertex_z[n+2]
+
+a = ((Az - Bz) * (Ay - Cy)) + ((Az - Cz) * (By - Ay));
+b = ((Ax - Bx) * (Az - Cz)) + ((Ax - Cx) * (Bz - Az));
+c = ((Bx - Ax) * (Ay - Cy)) + ((Ax - Cx) * (Ay - By));
+d = - a*Ax - b*Ay - c*Az;
+
+*nx=raydium_vertex_normal_x[n];
+*ny=raydium_vertex_normal_y[n];
+*nz=raydium_vertex_normal_z[n];
+
+return(-(a*y+b*x+d)/c);
+}
Index: raydium/file.c
===================================================================
--- raydium/file.c	(revision 0)
+++ raydium/file.c	(revision 1)
@@ -0,0 +1,292 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/file.h"
+#endif 
+
+// WARNING: most functions of this file are not part of Raydium yet !
+// So, be carefull with functions without "raydium_file" prefix.
+
+
+#define DONT_SAVE_DUMMY_TEXTURE
+
+
+// far better than glibc's 'dirname' (and portable)
+void raydium_file_dirname(char *dest,char *from)
+{
+char *c;
+int n;
+
+c=strrchr(from,'/');
+if(!c)
+    {
+    strcpy(dest,"./");
+    return;
+    }
+n=c-from;
+memcpy(dest,from,n+1);
+dest[n+1]=0;
+}
+
+
+void raydium_file_log_fopen_display(void)
+{
+int i;
+
+raydium_log("List of all opended files:");
+
+for(i=0;i<raydium_file_log_fopen_index;i++)
+    raydium_log("%s",raydium_file_log_fopen[i]);
+
+}
+
+#ifdef PHP_SUPPORT
+FILE *raydium_file_fopen(char *file, char *mode)
+{
+FILE *fp;
+int i;
+char found=0;
+
+if(!file || !strlen(file))
+    return NULL;
+
+for(i=0;i<raydium_file_log_fopen_index;i++)
+    if(!strcmp(raydium_file_log_fopen[i],file))
+	{
+	found=1;
+	break;
+	}
+
+if(!found) strcpy(raydium_file_log_fopen[raydium_file_log_fopen_index++],file);
+
+if(strchr(mode,'w') || raydium_init_cli_option("repository-disable",NULL))
+    {
+    return fopen(file,mode);
+    }
+
+if( !raydium_init_cli_option("repository-refresh",NULL) && 
+    !raydium_init_cli_option("repository-force",NULL) )
+{
+ fp=fopen(file,mode);
+ if(fp) return fp;
+}
+raydium_rayphp_repository_file_get(file);
+fp=fopen(file,mode);
+
+return fp;
+}
+#endif
+
+void dump_vertex_to(char *filename)
+{
+FILE *fp;
+//GLuint tex;
+GLuint i;
+char text[256];
+char bl;
+
+fp=fopen(filename,"wt");
+if(!fp) { printf("cannot write to file \"%s\", fopen() failed\n",filename); return; }
+fprintf(fp,"1\n");
+/*
+for(tex=0;tex<raydium_texture_index;tex++)
+{
+// fprintf(fp,"%s\n",raydium_texture_name[tex]);
+// fprintf(fp,"%i\n",j);
+ for(i=0;i<raydium_vertex_index;i++)
+  if(raydium_vertex_texture[i]==tex)
+  fprintf(fp,"%f %f %f %f %f %s\n",
+  raydium_vertex_x[i],raydium_vertex_y[i],raydium_vertex_z[i],
+  raydium_vertex_texture_u[i],raydium_vertex_texture_v[i],raydium_texture_name[tex]);
+}
+*/
+for(bl=0;bl<2;bl++)
+{
+ for(i=0;i<raydium_vertex_index;i++)
+ if( (raydium_texture_blended[raydium_vertex_texture[i]]?1:0) == bl)
+ {
+  if(raydium_vertex_texture_multi[i])
+  {
+   sprintf(text,"%s;%f|%f|%s",raydium_texture_name[raydium_vertex_texture[i]],
+			      raydium_vertex_texture_multi_u[i],
+			      raydium_vertex_texture_multi_v[i],
+			      raydium_texture_name[raydium_vertex_texture_multi[i]]);
+  }
+  else
+  strcpy(text,raydium_texture_name[raydium_vertex_texture[i]]);
+
+#ifdef DONT_SAVE_DUMMY_TEXTURE 
+  if(raydium_vertex_texture[i]) 
+#endif
+  fprintf(fp,"%f %f %f %f %f %f %f %f %s\n",
+  raydium_vertex_x[i],raydium_vertex_y[i],raydium_vertex_z[i],
+  raydium_vertex_normal_visu_x[i], raydium_vertex_normal_visu_y[i], raydium_vertex_normal_visu_z[i],
+  raydium_vertex_texture_u[i],raydium_vertex_texture_v[i],
+  text);
+ }
+}
+
+fclose(fp);
+printf("saved.\n");
+}
+
+// sorts alpha textures
+void dump_vertex_to_alpha(char *filename)
+{
+FILE *fp;
+GLuint tex;
+GLuint i;
+char text[256];
+int bl;
+
+
+raydium_log("WARNING: 'dump_vertex_to_alpha' function is deprecated, since regular 'dump_vertex_to' function now sorts alpha textures");
+
+
+fp=fopen(filename,"wt");
+if(!fp) { printf("cannot write to file \"%s\", fopen() failed\n",filename); return; }
+fprintf(fp,"1\n");
+
+for(bl=0;bl<2;bl++)
+{
+for(tex=0;tex<raydium_texture_index;tex++)
+if( (raydium_texture_blended[tex]?1:0) == bl)
+{
+  printf("%s\n",raydium_texture_name[tex]);
+  strcpy(text,raydium_texture_name[tex]);
+// fprintf(fp,"%i\n",j);
+ for(i=0;i<raydium_vertex_index;i++)
+  if(raydium_vertex_texture[i]==tex )
+  fprintf(fp,"%f %f %f %f %f %f %f %f %s\n",
+  raydium_vertex_x[i],raydium_vertex_y[i],raydium_vertex_z[i],
+  raydium_vertex_normal_visu_x[i], raydium_vertex_normal_visu_y[i], raydium_vertex_normal_visu_z[i],
+  raydium_vertex_texture_u[i],raydium_vertex_texture_v[i],
+  text);
+}
+printf("----\n");
+}
+
+
+fclose(fp);
+printf("saved.\n");
+}
+
+
+#define MULTI_SEP ';'
+#define MULTI_UVSEP '|'
+int raydium_file_set_textures(char *name)
+{
+char *sep;
+char *sep2=NULL;
+char texname[RAYDIUM_MAX_NAME_LEN];
+
+sep  = strchr(name,MULTI_SEP);
+if(sep) sep2 = strchr(sep+1,MULTI_UVSEP);
+
+
+// 2 textures + 1 uv
+if(sep && sep2)
+{
+  sscanf(sep+1,"%f|%f|%s\n", &raydium_texture_current_multi_u,
+			    &raydium_texture_current_multi_v,
+			    texname);
+  raydium_texture_current_multi=raydium_texture_find_by_name(texname);
+  *sep=0;
+  raydium_texture_current_set_name(name);
+  *sep=MULTI_SEP;
+  return 2;
+} 
+ 
+
+// 2 textures, but 0 uv
+if(sep && !sep2)
+{
+  raydium_texture_current_multi=raydium_texture_find_by_name(sep+1);
+  *sep=0;
+  raydium_texture_current_set_name(name);
+  *sep=MULTI_SEP;
+  raydium_texture_current_multi_u=-99999;
+  raydium_texture_current_multi_v=-99999;
+  return 1;
+} 
+  
+// 1 texture and 0 uv
+if(!sep && !sep2)
+{ 
+  raydium_texture_current_multi=0;
+  raydium_texture_current_set_name(name);
+  return 0;
+}
+
+return -1; // should never reach this
+}
+
+
+
+void read_vertex_from(char *filename)
+{
+GLfloat x,y,z,nx,ny,nz,u,v;
+int i;
+GLuint save;
+GLint visu;
+FILE *fp;
+char name[RAYDIUM_MAX_NAME_LEN];
+
+fp=raydium_file_fopen(filename,"rt");
+if(!fp) { printf("cannot read from file \"%s\", fopen() failed\n",filename); return; }
+fscanf(fp,"%i\n",&visu);
+
+
+raydium_log("Object: loading \"%s\", version %i",filename,visu);
+
+save=raydium_texture_current;
+i=0;
+
+if(visu>0)
+{
+ while( fscanf(fp,"%f %f %f %f %f %f %f %f %s\n",&x,&y,&z,&nx,&ny,&nz,&u,&v,name)!=EOF )
+ {
+  raydium_file_set_textures(name);
+  raydium_vertex_uv_normals_add(x,y,z,nx,ny,nz,u,v);
+  i++;
+ }
+}
+else if(visu==0)
+{
+ while( fscanf(fp,"%f %f %f %f %f %s\n",&x,&y,&z,&u,&v,name)!=EOF )
+ {
+  raydium_file_set_textures(name);
+  raydium_vertex_uv_add(x,y,z,u,v);
+  i++;
+ }
+}
+else if(visu<0)
+{
+ while( fscanf(fp,"%f %f %f %s\n",&x,&y,&z,name)!=EOF )
+ {
+  raydium_file_set_textures(name);
+  raydium_vertex_add(x,y,z);
+  i++;
+ }
+
+}
+
+if(i%3) 
+    {
+    printf("ERROR with object %s ... must be *3 !",filename);
+    // and generate dummy vertices ?
+    }
+
+fclose(fp);
+
+raydium_texture_current_multi=0;
+raydium_texture_current_set(save);
+//printf("loaded.\n");
+}
+
Index: raydium/render.c
===================================================================
--- raydium/render.c	(revision 0)
+++ raydium/render.c	(revision 1)
@@ -0,0 +1,336 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/render.h"
+#endif 
+
+void raydium_callback_image(void);
+void raydium_timecall_callback(void);
+
+
+// let's keep this define here, until full tests
+#define RAYDIUM_RENDER_MAX_TEXUNITS 2
+int raydium_rendering_prepare_texture_unit(GLenum tu,GLuint tex)
+{
+// cache state of each texunit
+static GLuint texunit_state[RAYDIUM_RENDER_MAX_TEXUNITS];
+static int first=1;
+int tui;
+
+if(first)
+    {
+    int i;
+    for(i=0;i<RAYDIUM_RENDER_MAX_TEXUNITS;i++)
+	texunit_state[i]=0;    
+    }
+first=0;
+
+tui=tu-GL_TEXTURE0_ARB;
+
+if(tui>=RAYDIUM_RENDER_MAX_TEXUNITS)
+    {
+    raydium_log("render: texture unit %i is invalid (%i max, see RAYDIUM_RENDER_MAX_TEXUNITS",
+    tui,RAYDIUM_RENDER_MAX_TEXUNITS);
+    return 0;
+    }
+
+if(texunit_state[tui]==tex)
+    return 0;
+
+texunit_state[tui]=tex;
+
+//printf("preparing texunut %i with %s\n",tui,raydium_texture_name[tex]);
+
+// prepare "lightmaps" texture units
+if(tui>0)
+{
+ glEnd(); // ugly, but we must close all shapes, if any
+ glActiveTextureARB(tu);
+ 
+#ifndef RENDER_ALLOW_LIGHTING_FOR_LIGHTMAPS
+ if(raydium_texture_islightmap[tex])
+ {
+ glDisable(GL_LIGHTING); 
+ }
+ else if(raydium_light_enabled_tag)
+	glEnable(GL_LIGHTING);
+#endif 
+ 
+ if(tex)
+ {
+  glEnable(GL_TEXTURE_2D);
+  glBindTexture(GL_TEXTURE_2D,tex);
+
+  if(raydium_texture_islightmap[tex])
+  {
+    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
+  }
+  else
+  {
+    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE_EXT);
+    glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2);
+  } 
+ } 
+ else 
+ {
+ glDisable(GL_TEXTURE_2D);
+// glBindTexture(GL_TEXTURE_2D,0); 
+ }
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+}
+else // "standard" textunit
+{
+  //#define ONE 0.8 // default (according GL specs) DIFFUSE value.
+  GLfloat one[]={0.8f, 0.8f, 0.8f, 1.f};
+  GLfloat zero[]={0.0,0.0,0.0,0.0};
+  GLfloat *rgb;
+
+  glColor4f(1.f,1.f,1.f,1.f);
+
+  if(raydium_texture_blended[tex]==1)
+  {
+  glEnable(GL_BLEND);
+  glDepthMask(GL_FALSE);
+  glDisable(GL_ALPHA_TEST);
+//  glDisable(GL_FOG);
+  }
+
+  if(raydium_texture_blended[tex]==2)
+  {
+  glEnable(GL_BLEND);
+  glDepthMask(GL_TRUE);
+  glAlphaFunc(GL_GREATER,0);
+  glEnable (GL_ALPHA_TEST);
+//  glDisable(GL_FOG);
+  }
+
+  if(raydium_texture_blended[tex]==0)
+  {
+  glDisable(GL_BLEND);
+  glDepthMask(GL_TRUE);
+  glDisable(GL_ALPHA_TEST);
+//  glEnable(GL_FOG);
+  }
+
+  if(raydium_texture_rgb[tex][0]>=0)
+  {
+  if(raydium_render_rgb_force_tag)
+    rgb=raydium_render_rgb_force;
+  else
+    rgb=raydium_texture_rgb[tex];
+  
+  glDisable(GL_TEXTURE_2D);
+  glColor4f(rgb[0],rgb[1],rgb[2],1.f);
+   if(raydium_light_enabled_tag)
+   {
+    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, rgb);
+    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, rgb);
+   }
+  }
+  else 
+  {
+  glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, one);
+  glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, zero);
+  glEnable(GL_TEXTURE_2D);
+  glBindTexture(GL_TEXTURE_2D,tex);
+  //printf("%s\n",raydium_texture_name[tex]);
+  }
+} // end "standard" texture
+return 1;
+}
+
+
+void raydium_rendering_internal_prepare_texture_render(GLuint tex)
+{
+raydium_rendering_prepare_texture_unit(GL_TEXTURE0_ARB,tex);
+}
+
+void raydium_rendering_internal_restore_render_state(void)
+{
+//#define ONE 0.8 // default DIFFUSE value.
+GLfloat one[]={0.8f, 0.8f, 0.8f, 1.f};
+
+//return; // make no sens to restore state since next texture will reset it
+
+glDisable(GL_BLEND);
+glDepthMask(GL_TRUE);
+glEnable(GL_TEXTURE_2D);
+glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, one);
+}
+
+// 2D quick 'n ugly clipping test
+char infov(GLfloat x, GLfloat y)
+{
+#ifdef RENDER_DEBUG_NO_CLIP
+return 1;
+#endif
+if((x+raydium_camera_cursor_place[0])>(raydium_camera_x-raydium_projection_far) &&
+   (x+raydium_camera_cursor_place[0])<(raydium_camera_x+raydium_projection_far) &&
+   (y+raydium_camera_cursor_place[1])>(raydium_camera_y-raydium_projection_far) &&
+   (y+raydium_camera_cursor_place[1])<(raydium_camera_y+raydium_projection_far) ) return 1; else return 0;
+}
+
+void raydium_rendering_from_to(GLuint from, GLuint to)
+{
+GLuint tex,i,j;
+int multi_prepared=0;
+
+
+for(tex=1;tex<raydium_texture_index;tex++)
+{
+  // prepare first texture unit
+  raydium_rendering_prepare_texture_unit(GL_TEXTURE0_ARB,tex);
+
+  glBegin(GL_TRIANGLES);
+  
+
+  for(i=from,j=0;i<to;i+=3)
+  if(raydium_vertex_texture[i]==tex)
+  {
+#ifdef DEBUG_RENDER_DISABLE_DISPLAYLISTS
+   if(!infov(raydium_vertex_x[i  ],raydium_vertex_y[i  ]) &&
+      !infov(raydium_vertex_x[i+1],raydium_vertex_y[i+1]) &&
+      !infov(raydium_vertex_x[i+2],raydium_vertex_y[i+2]) )
+        continue;
+#endif
+
+    
+#ifdef RENDER_DEBUG_TAG
+    if(raydium_vertex_tag[i  ] ||
+       raydium_vertex_tag[i+1] ||
+       raydium_vertex_tag[i+2] )
+	glColor4f(1.f,0.f,1.f,1.f);
+    else
+	glColor4f(1.f,1.f,1.f,1.f);
+#endif    
+
+    if(raydium_vertex_texture_multi[i])
+    {
+	if(raydium_rendering_prepare_texture_unit(GL_TEXTURE1_ARB,raydium_vertex_texture_multi[i]))
+	    {
+	    //glEnd(); // done by "prepare_texture_multi"
+	    glBegin(GL_TRIANGLES);
+	    multi_prepared=1;
+	    }
+
+	// THIS CODE IS DUPLICATED FOR SPEED REASON (1)
+	for(j=0;j<3;j++)
+	{
+	glNormal3f(raydium_vertex_normal_visu_x[i+j],raydium_vertex_normal_visu_y[i+j],raydium_vertex_normal_visu_z[i+j]);
+	glMultiTexCoord2fARB(GL_TEXTURE0_ARB,raydium_vertex_texture_u[i+j],raydium_vertex_texture_v[i+j]);
+	glMultiTexCoord2fARB(GL_TEXTURE1_ARB,raydium_vertex_texture_multi_u[i+j],raydium_vertex_texture_multi_v[i+j]);
+	//printf("%f %f\n",raydium_vertex_texture_multi_u[i+j],raydium_vertex_texture_multi_v[i+j]);
+	glVertex3f(raydium_vertex_x[i+j], raydium_vertex_y[i+j], raydium_vertex_z[i+j]);
+	raydium_vertex_counter++;
+	}
+    }
+    else
+    {
+	// cancel previous multitexturing activation    
+	if(multi_prepared)
+	    {
+	    raydium_rendering_prepare_texture_unit(GL_TEXTURE1_ARB,0);
+	    multi_prepared=0;
+	    glBegin(GL_TRIANGLES);
+	    }
+
+	// THIS CODE IS DUPLICATED FOR SPEED REASON (2)
+	for(j=0;j<3;j++)
+	{
+	glNormal3f(raydium_vertex_normal_visu_x[i+j],raydium_vertex_normal_visu_y[i+j],raydium_vertex_normal_visu_z[i+j]);
+	glMultiTexCoord2fARB(GL_TEXTURE0_ARB,raydium_vertex_texture_u[i+j],raydium_vertex_texture_v[i+j]);
+	glVertex3f(raydium_vertex_x[i+j], raydium_vertex_y[i+j], raydium_vertex_z[i+j]);
+	raydium_vertex_counter++;
+	}
+    }
+  }
+  glEnd();
+} // end for "all textures"
+
+raydium_rendering_prepare_texture_unit(GL_TEXTURE1_ARB,0);
+}
+
+
+
+void raydium_rendering(void)
+{
+raydium_rendering_from_to(0,raydium_vertex_index);
+}
+
+void raydium_rendering_finish(void)
+{
+static int fps=0;
+static clock_t last=0;
+fps++;
+if(!last) last=clock();
+
+raydium_callback_image();
+glFlush();
+raydium_rendering_internal_restore_render_state();
+//glutPostRedisplay();
+
+#ifdef DEBUG_MOVIE
+{
+char name[128];
+static int frame;
+sprintf(name,"movie/frame%04d.tga",frame);
+raydium_capture_frame(name);
+frame++;
+}
+#endif
+
+glutSwapBuffers();
+//raydium_timecall_callback();
+raydium_key_last=0;
+raydium_mouse_click=0;
+raydium_camera_pushed=0; 
+glPopMatrix();
+//raydium_texture_internal_loaded=0;
+if(clock() > last + CLOCKS_PER_SEC)
+    {
+    last=clock();
+    raydium_render_fps=fps;
+    fps=0;
+    }
+}
+
+void raydium_rendering_wireframe(void)
+{
+glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+}
+
+void raydium_rendering_normal(void)
+{
+glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+void raydium_rendering_rgb_force(GLfloat r, GLfloat g, GLfloat b)
+{
+raydium_render_rgb_force_tag=1;
+raydium_render_rgb_force[0]=r;
+raydium_render_rgb_force[1]=g;
+raydium_render_rgb_force[2]=b;
+raydium_render_rgb_force[3]=1.0;
+}
+
+void raydium_rendering_rgb_normal(void)
+{
+raydium_render_rgb_force_tag=0;
+}
+
+
+void raydium_rendering_displaylists_enable(void)
+{
+raydium_render_displaylists_tag=1;
+}
+
+void raydium_rendering_displaylists_disable(void)
+{
+raydium_render_displaylists_tag=0;
+}
Index: raydium/gpl.txt
===================================================================
--- raydium/gpl.txt	(revision 0)
+++ raydium/gpl.txt	(revision 1)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: raydium/random.c
===================================================================
--- raydium/random.c	(revision 0)
+++ raydium/random.c	(revision 1)
@@ -0,0 +1,54 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/random.h"
+#endif 
+
+void raydium_random_randomize(void)
+{
+srand(time(NULL));
+}
+
+GLfloat raydium_random_pos_1(void)
+{
+return (GLfloat) rand() / (GLfloat) RAND_MAX;
+}
+
+/* de -1.0 a 1.0 */
+GLfloat raydium_random_neg_pos_1(void)
+{
+return (2.f * raydium_random_pos_1()) - 1.f;
+}
+
+GLfloat raydium_random_0_x(GLfloat i)
+{
+return(raydium_random_pos_1() * i);
+}
+
+GLfloat raydium_random_f(GLfloat min, GLfloat max)
+{
+return( (raydium_random_pos_1() * (max-min)) + min);
+}
+
+int raydium_random_i(int min, int max)
+{
+return (rand()%(max-min+1))+min;
+}
+
+
+char raydium_random_proba(GLfloat proba)
+{
+GLfloat min;
+GLfloat max;
+
+max=2*proba;
+min=max-2;
+
+return raydium_random_f(min,max)>=0;
+}
Index: raydium/main.c
===================================================================
--- raydium/main.c	(revision 0)
+++ raydium/main.c	(revision 1)
@@ -0,0 +1,25 @@
+/*
+* Raydium - CQFD Corp.
+* http://raydium.cqfd-corp.org
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+char *raydium_version="0.642";
+
+#define MAIN_C
+#include "common.h"
+
+// EOF
Index: raydium/trigo.c
===================================================================
--- raydium/trigo.c	(revision 0)
+++ raydium/trigo.c	(revision 1)
@@ -0,0 +1,91 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/trigo.h"
+#endif 
+
+GLfloat raydium_trigo_cos(GLfloat i)
+{
+return( (GLfloat)cos(i*PI/180) );
+}
+
+GLfloat raydium_trigo_sin(GLfloat i)
+{
+return( (GLfloat)sin(i*PI/180) );
+}
+
+GLfloat raydium_trigo_cos_inv(GLfloat i)
+{
+return(acos(i)*180/PI);
+}
+
+GLfloat raydium_trigo_sin_inv(GLfloat i)
+{
+return(asin(i)*180/PI);
+}
+
+void raydium_trigo_rotate(GLfloat *p, GLfloat rx, GLfloat ry, GLfloat rz, GLfloat *res)
+{
+res[0]= (p[0]*raydium_trigo_cos(ry)+(p[2]*raydium_trigo_cos(rx)+p[1]*raydium_trigo_sin(rx))*raydium_trigo_sin(ry))*raydium_trigo_cos(rz) + (p[1]*raydium_trigo_cos(rx)-p[2]*raydium_trigo_sin(rx))*raydium_trigo_sin(rz);
+res[1]=-(p[0]*raydium_trigo_cos(ry)+(p[2]*raydium_trigo_cos(rx)+p[1]*raydium_trigo_sin(rx))*raydium_trigo_sin(ry))*raydium_trigo_sin(rz) + (p[1]*raydium_trigo_cos(rx)-p[2]*raydium_trigo_sin(rx))*raydium_trigo_cos(rz);
+res[2]= (p[2]*raydium_trigo_cos(rx)+ p[1]*raydium_trigo_sin(rx))*raydium_trigo_cos(ry)-p[0]*raydium_trigo_sin(ry);
+}
+
+
+// pos: GLfloat[3], m: GLfloat[16]
+void raydium_trigo_pos_to_matrix(GLfloat *pos, GLfloat *m)
+{
+m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = pos[0];
+m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = pos[1];
+m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = pos[2];
+m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
+}
+
+// res: GLfloat[3]
+void raydium_trigo_pos_get_modelview(GLfloat *res)
+{
+GLfloat tmp[16];
+glGetFloatv(GL_MODELVIEW_MATRIX,tmp);
+res[0]=tmp[12];
+res[1]=tmp[13];
+res[2]=tmp[14];
+}
+
+/* Unfinished !
+// pos == res is safe
+void raydium_trigo_carth_to_sphere(GLfloat *pos, GLfloat *res)
+{
+GLfloat r,G,T;
+
+r=sqrt(pos[0]*pos[0] + pos[1]*pos[1] + pos[2]*pos[2]);
+G=atan(pos[1]/pos[0]);
+T=acos(pos[2]/r);
+
+//printf("%f\n",r);
+r=1;
+
+if(pos[0]<0)
+    res[0]=-r*cos(G);
+else
+    res[0]=+r*cos(G);
+
+//res[1]=r*sin(G);
+if(pos[0]<0)
+    res[0]=-r*sin(T)*cos(G);
+else
+    res[0]=r*sin(T)*cos(G);
+res[1]=r*sin(G)*cos(G);
+res[2]=r*cos(T);
+
+if(isnan(res[0])) res[0]=0;
+if(isnan(res[1])) res[1]=0;
+if(isnan(res[2])) res[2]=0;
+
+}
+*/
Index: raydium/php.c
===================================================================
--- raydium/php.c	(revision 0)
+++ raydium/php.c	(revision 1)
@@ -0,0 +1,302 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/php.h"
+#endif 
+
+// PHP support for Raydium
+// Known bug: recursive Ray/PHP calls are fatal (segfault in zend core).
+
+#include "php_wrappers.c"
+// use this macro when registering your functions
+#define C2PHP ZEND_FN
+
+
+#ifdef RAYDIUM_NETWORK_ONLY
+#define raydium_file_fopen fopen
+#endif
+
+// Dirty globals... (needed for WIN32 PHP support)
+#ifdef ZTS
+zend_compiler_globals *compiler_globals;
+zend_executor_globals *executor_globals;
+php_core_globals *core_globals;
+sapi_globals_struct *sapi_globals;
+void ***tsrm_ls;
+#endif
+
+static int sapi_raydium_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
+{
+return SAPI_HEADER_SENT_SUCCESSFULLY;
+}
+ 
+static void sapi_raydium_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC)
+{
+}
+
+
+static int php_dummy(sapi_module_struct *sapi_module)
+{
+return SUCCESS;
+}
+
+void raydium_php_error(int type, const char *msg, ...)
+{
+raydium_log("^cERROR type %i",type);
+}
+
+int raydium_php_uwrite(const char *str, uint str_length TSRMLS_DC)  
+{
+ if(str_length>=RAYDIUM_MAX_NAME_LEN-15)
+    {
+    raydium_log("PHP output is to long ! : redirected to stdout");
+    printf("%s",str);
+    }
+ else
+    raydium_log("%s",str);
+ return SUCCESS;
+}
+
+static sapi_module_struct raydium_sapi_module = 
+{
+	"RayHandler",                   /* name */
+	"Raydium PHP Handler",          /* pretty name */
+									
+// Since PHP@Win32 is dirty... :
+	php_dummy,             /* startup */
+	php_dummy,	       /* shutdown */
+
+	NULL,				/* activate */
+	NULL,				/* deactivate */
+
+	raydium_php_uwrite,           	/* unbuffered write */
+	NULL,                 		/* flush */
+	NULL,                         	/* get uid */
+	NULL,                         	/* getenv */
+
+	raydium_php_error,          	/* error handler */
+
+	NULL,                         	/* header handler */
+	sapi_raydium_send_headers,      /* send headers handler */
+	sapi_raydium_send_header,       /* send header handler */
+
+	NULL,                		/* read POST data */
+	NULL,             		/* read Cookies */
+	NULL,
+
+	NULL,				/* register server variables */
+	NULL,              		/* Log message */
+
+	NULL,				/* Block interruptions */
+	NULL,				/* Unblock interruptions */
+
+	STANDARD_SAPI_MODULE_PROPERTIES
+};
+
+
+void raydium_php_init_request(char *filename)
+{
+//Must allocate memory for those 3 ones :
+//SG(request_info).request_method = "GET";
+//SG(request_info).query_string = "";
+//SG(request_info).content_type = "text/html";
+
+SG(request_info).request_method = NULL;
+SG(request_info).query_string = NULL;
+SG(request_info).content_type = NULL;
+SG(request_info).request_uri = filename;
+SG(request_info).path_translated = filename;
+SG(request_info).content_length = 0;
+SG(sapi_headers).http_response_code = 200;
+SG(server_context) = NULL;
+}
+
+
+int raydium_php_exec(char *name)  
+{
+    FILE *fp;
+    char prefix[32];
+    zval *vars[RAYDIUM_MAX_REG_VARIABLES]; 
+    zend_file_handle file_handle;
+    zend_llist global_vars;
+    int i,nvars;
+
+
+    // Do not use rayphp auto-downloading for rayphp/* files ! :)
+    strncpy(prefix,name,7);
+    prefix[7]=0;
+    if(strcasecmp(prefix,"rayphp/"))
+    {
+	fp=raydium_file_fopen(name,"rb");
+	if(!fp)
+	    {
+	    raydium_log("php: ERROR: cannot pre-open '%s' file",name);
+	    return 0;
+	    }
+	fclose(fp);
+    }
+
+
+// PHP_ MAJOR and MINOR _VERSION **seems** to be introduced with PHP 4.3
+#ifdef PHP_MAJOR_VERSION
+    // >= 4.3
+    if(php_module_startup(&raydium_sapi_module,NULL,0) == FAILURE)
+#else
+    if(php_module_startup(&raydium_sapi_module) == FAILURE)
+#endif
+    {
+        return FAILURE;
+    }
+    raydium_php_init_request(name);
+
+    zend_llist_init(&global_vars, sizeof(char *), NULL, 0);
+    zend_alter_ini_entry("html_errors", 12, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+    zend_alter_ini_entry("max_execution_time", 19, "0", 1, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+/*
+    file_handle.type = ZEND_HANDLE_FILENAME;
+    file_handle.filename = SG(request_info).path_translated;
+    file_handle.free_filename = 0;
+    file_handle.opened_path = NULL;
+*/
+
+    file_handle.handle.fp=VCWD_FOPEN(name,"rb");
+    if(!file_handle.handle.fp)
+	{
+	raydium_log("php: ERROR: cannot post-open '%s' file",name);
+	return 0;
+	}
+    file_handle.filename=name;
+    file_handle.type = ZEND_HANDLE_FP;
+    file_handle.free_filename = 0;
+    file_handle.opened_path = NULL;
+    
+
+//    if(php_request_startup(CLS_C ELS_CC PLS_CC SLS_CC) == FAILURE) {
+    if(php_request_startup(TSRMLS_C) == FAILURE) {
+        php_module_shutdown(TSRMLS_C);
+        return FAILURE;
+    }
+
+    SG(headers_sent) = 1;
+    SG(request_info).no_headers = 1;
+
+ // i save "raydium_register_variable_index" here since it may change during script exec
+ nvars=raydium_register_variable_index;
+ for(i=0;i<nvars;i++)
+    {
+    if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_INT)
+	{
+        MAKE_STD_ZVAL(vars[i]); // init
+	ZVAL_LONG(vars[i],(*(int *)raydium_register_variable_addr[i]));
+	ZEND_SET_SYMBOL(&EG(symbol_table), raydium_register_variable_name[i], vars[i]);
+	}
+
+    if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_FLOAT)
+	{
+        MAKE_STD_ZVAL(vars[i]); // init
+	ZVAL_DOUBLE(vars[i],(*(float *)raydium_register_variable_addr[i]));
+	ZEND_SET_SYMBOL(&EG(symbol_table), raydium_register_variable_name[i], vars[i]);
+	}
+
+    if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_STR)
+	{
+        MAKE_STD_ZVAL(vars[i]); // init
+	ZVAL_STRING(vars[i],(char *)raydium_register_variable_addr[i],1); // 1 means "duplicate string"
+	ZEND_SET_SYMBOL(&EG(symbol_table), raydium_register_variable_name[i], vars[i]);
+	}
+     
+    if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_ICONST)
+	{
+	zend_register_long_constant(raydium_register_variable_name[i],
+				    strlen(raydium_register_variable_name[i])+1,
+				    (*(int *)raydium_register_variable_addr[i]),
+				    CONST_CS,
+				    0 TSRMLS_CC);
+	}
+
+    if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_FCONST)
+	{
+	zend_register_double_constant(raydium_register_variable_name[i],
+				      strlen(raydium_register_variable_name[i])+1,
+				      (*(float *)raydium_register_variable_addr[i]),
+				      CONST_CS,
+				      0 TSRMLS_CC);
+	}
+    }
+
+#ifdef WIN32
+ zend_register_functions(raydium_register_function_list,CG(function_table), MODULE_PERSISTENT,TSRMLS_C);
+ php_execute_script(&file_handle,TSRMLS_C);
+#else
+ zend_register_functions(raydium_register_function_list,CG(function_table), MODULE_PERSISTENT);
+ php_execute_script(&file_handle CLS_CC ELS_CC PLS_CC);
+#endif
+
+ // now get back variable values
+ for(i=0;i<nvars;i++)
+    {
+        if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_INT)
+	 {
+	    if(vars[i]->type == IS_LONG)
+		*(int *)raydium_register_variable_addr[i]=vars[i]->value.lval;
+	    else raydium_log("php: (int)%s type have changed ! Cannot read new value.",raydium_register_variable_name[i]);
+	 }
+
+        if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_FLOAT)
+	 {
+	    if(vars[i]->type == IS_DOUBLE)
+		*(float *)raydium_register_variable_addr[i]=vars[i]->value.dval;
+	    else if(vars[i]->type == IS_LONG)
+		*(float *)raydium_register_variable_addr[i]=vars[i]->value.lval;		
+	    else raydium_log("php: (float)%s type have changed ! Cannot read new value.",raydium_register_variable_name[i]);
+	 }
+
+        if(raydium_register_variable_type[i]==RAYDIUM_REGISTER_STR)
+	 {
+	    if(vars[i]->type == IS_STRING)
+		strcpy(raydium_register_variable_addr[i],vars[i]->value.str.val);
+	    else if(vars[i]->type == IS_DOUBLE)
+		sprintf(raydium_register_variable_addr[i],"%f",vars[i]->value.dval);
+	    else if(vars[i]->type == IS_LONG)
+		sprintf(raydium_register_variable_addr[i],"%li",vars[i]->value.lval);
+	    else raydium_log("php: (char *)%s type have changed ! Cannot read new value.",raydium_register_variable_name[i]);
+	 }
+        
+    }
+
+ php_request_shutdown(NULL);
+ raydium_sapi_module.shutdown(&raydium_sapi_module);
+ return 1;
+}
+
+
+void raydium_php_close(void)
+{
+sapi_shutdown();
+}
+
+void raydium_php_init(void)
+{
+char *path;
+#ifdef ZTS
+tsrm_startup(1, 1, 0, NULL);
+compiler_globals = ts_resource(compiler_globals_id);
+executor_globals = ts_resource(executor_globals_id);
+core_globals = ts_resource(core_globals_id);
+sapi_globals = ts_resource(sapi_globals_id);
+tsrm_ls = ts_resource(0);
+#endif
+raydium_sapi_module.phpinfo_as_text=1;
+path=malloc(strlen(PHP_INI_PATH));
+strcpy(path,PHP_INI_PATH);
+raydium_sapi_module.php_ini_path_override=path;
+sapi_startup(&raydium_sapi_module);
+atexit(raydium_php_close);
+raydium_log("PHP support: OK");
+}
Index: raydium/normal.c
===================================================================
--- raydium/normal.c	(revision 0)
+++ raydium/normal.c	(revision 1)
@@ -0,0 +1,160 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/normal.h"
+#endif 
+
+void raydium_normal_generate_lastest_triangle(int default_visu)
+{
+GLfloat vect[2][3];
+GLfloat norm[3];
+GLfloat len;
+int i;
+GLuint index=raydium_vertex_index;
+
+// let's find "vectors" of the triangle's plane ...
+vect[0][0]=
+ raydium_vertex_x[index-1] -
+ raydium_vertex_x[index-2] ;
+vect[0][1]=
+ raydium_vertex_y[index-1] -
+ raydium_vertex_y[index-2] ;
+vect[0][2]=
+ raydium_vertex_z[index-1] -
+ raydium_vertex_z[index-2] ;
+
+vect[1][0]=
+ raydium_vertex_x[index-1] -
+ raydium_vertex_x[index-3] ;
+vect[1][1]=
+ raydium_vertex_y[index-1] -
+ raydium_vertex_y[index-3] ;
+vect[1][2]=
+ raydium_vertex_z[index-1] -
+ raydium_vertex_z[index-3] ;
+
+// ... and now, the normal ...
+
+norm[0]=vect[0][1]*vect[1][2] - vect[0][2]*vect[1][1];
+norm[1]=vect[0][2]*vect[1][0] - vect[0][0]*vect[1][2];
+norm[2]=vect[0][0]*vect[1][1] - vect[0][1]*vect[1][0];
+
+// ... wich we normalize.
+
+len=sqrt(norm[0]*norm[0] + norm[1]*norm[1] + norm[2]*norm[2]);
+
+for(i=1;i<=3;i++) 
+{ 
+raydium_vertex_normal_x[index-i]=-norm[0]/len;
+if(default_visu) raydium_vertex_normal_visu_x[index-i]=raydium_vertex_normal_x[index-i];
+}
+
+for(i=1;i<=3;i++) 
+{
+raydium_vertex_normal_y[index-i]=-norm[1]/len;
+if(default_visu) raydium_vertex_normal_visu_y[index-i]=raydium_vertex_normal_y[index-i];
+}
+
+for(i=1;i<=3;i++)
+{
+raydium_vertex_normal_z[index-i]=-norm[2]/len;
+if(default_visu) raydium_vertex_normal_visu_z[index-i]=raydium_vertex_normal_z[index-i];
+}
+
+//raydium_log("norm [%f,%f,%f]/%f",norm[0],norm[1],norm[2],len);
+}
+
+
+void raydium_normal_restore_all(void)
+{
+GLuint i;
+for(i=0;i<raydium_vertex_index;i++)
+ {
+ raydium_vertex_normal_visu_x[i]=raydium_vertex_normal_x[i];
+ raydium_vertex_normal_visu_y[i]=raydium_vertex_normal_y[i];
+ raydium_vertex_normal_visu_z[i]=raydium_vertex_normal_z[i];
+ }
+raydium_log("normal: Normals restaured.");
+}
+
+void raydium_normal_regenerate_all(void)
+{
+GLuint save=raydium_vertex_index;
+
+if(save<3) return;
+
+for(raydium_vertex_index=3;raydium_vertex_index<=save;raydium_vertex_index+=3)
+    raydium_normal_generate_lastest_triangle(1);
+
+raydium_vertex_index=save;
+raydium_log("normal: Normals regenerated.");
+}
+
+
+void raydium_normal_smooth_all(void)
+{
+GLuint i,j;
+GLfloat x,y,z;
+GLfloat sum_x;
+GLfloat sum_y;
+GLfloat sum_z;
+GLuint n;
+GLuint debug_time;
+char *tag; // 1 means "already done", 2 means "used for last normals search"
+
+
+tag=malloc(RAYDIUM_MAX_VERTICES);
+if(!tag) { raydium_log("normal: Not enought memory for normal smoothing, giving up."); return; }
+memset(tag,0,RAYDIUM_MAX_VERTICES);
+
+debug_time=0;
+
+for(i=0;i<raydium_vertex_index;i++)
+{
+if(tag[i]) continue;
+x=raydium_vertex_x[i];
+y=raydium_vertex_y[i];
+z=raydium_vertex_z[i];
+sum_x=0;
+sum_y=0;
+sum_z=0;
+n=0;
+
+for(j=0;j<raydium_vertex_index;j++)
+ {
+ if(raydium_vertex_x[j]==x && raydium_vertex_y[j]==y && raydium_vertex_z[j]==z)
+  { 
+  sum_x+=raydium_vertex_normal_x[i];
+  sum_y+=raydium_vertex_normal_y[i];
+  sum_z+=raydium_vertex_normal_z[i];
+  n++;
+  tag[j]=2;  
+  }
+ }
+sum_x/=(GLfloat)n;
+sum_y/=(GLfloat)n;
+sum_z/=(GLfloat)n;
+
+for(j=0;j<raydium_vertex_index;j++)
+if(tag[j]==2)
+ {
+ raydium_vertex_normal_visu_x[j]=sum_x;
+ raydium_vertex_normal_visu_y[j]=sum_y;
+ raydium_vertex_normal_visu_z[j]=sum_z;
+ tag[j]=1;
+ }
+
+
+debug_time++;
+if(debug_time>100) { raydium_log("normal: smoothing: %i/%i",i,raydium_vertex_index); debug_time=0; }
+}
+
+free(tag);
+raydium_log("normal: smoothing done.");
+}
Index: raydium/camera.c
===================================================================
--- raydium/camera.c	(revision 0)
+++ raydium/camera.c	(revision 1)
@@ -0,0 +1,446 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/camera.h"
+#endif 
+
+// res3 is GLfloat[3]
+void raydium_camera_vectors(GLfloat *res3)
+{
+GLfloat m[16];
+GLfloat front[3]={1,0,0};
+//GLfloat up[3]={0,0,1};
+GLfloat res1[3];
+GLfloat res2[3];
+
+
+raydium_trigo_pos_get_modelview(res1); // get current position
+raydium_trigo_pos_to_matrix(front,m); // create matrix using front
+glPushMatrix();
+glMultMatrixf(m); // project front
+raydium_trigo_pos_get_modelview(res2); // get new position
+glPopMatrix();
+
+// create front vector
+res3[1]=-(res1[0]-res2[0]); // x
+res3[2]=(res1[1]-res2[1]); // y
+res3[0]=(res1[2]-res2[2]); // z
+
+// create up vector
+
+// fallback
+res3[3]=res3[4]=0;
+res3[5]=1;
+
+/*
+raydium_trigo_pos_get_modelview(res1); // get current position
+raydium_trigo_pos_to_matrix(up,m); // create matrix using front
+glPushMatrix();
+glMultMatrixf(m); // project front
+raydium_trigo_pos_get_modelview(res2); // get new position
+glPopMatrix();
+res3[4]=(res1[0]-res2[0]); // x
+res3[5]=-(res1[1]-res2[1]); // y
+res3[3]=-(res1[2]-res2[2]); // z
+*/
+
+//raydium_log("%f %f %f",res3[3],res3[4],res3[5]);
+}
+
+
+void raydium_camera_internal_prepare(void)
+{
+GLfloat x,y,z;
+
+glLoadIdentity();
+
+if(raydium_camera_rumble_remaining>0)
+    {
+    x=raydium_random_f(-raydium_camera_rumble_amplitude,raydium_camera_rumble_amplitude);
+    y=raydium_random_f(-raydium_camera_rumble_amplitude,raydium_camera_rumble_amplitude);
+    z=raydium_random_f(-raydium_camera_rumble_amplitude,raydium_camera_rumble_amplitude);
+
+    glRotatef(z,0,0,1);
+    glRotatef(x,1,0,0);
+    glRotatef(y,0,1,0);
+
+    raydium_camera_rumble_remaining-=raydium_frame_time;
+    raydium_camera_rumble_amplitude+=(raydium_camera_rumble_evolution*raydium_frame_time);
+    if(raydium_camera_rumble_amplitude<=0)
+	{
+	raydium_camera_rumble_amplitude=0;
+	raydium_camera_rumble_remaining=0;
+	}
+    }
+    else raydium_camera_rumble_remaining=0;
+}
+
+void raydium_camera_internal(GLfloat x, GLfloat y, GLfloat z)
+{
+ if(raydium_frame_first_camera_pass)
+ {
+ float pos[3];
+ float or[6];
+ pos[0]=x;
+ pos[1]=y;
+ pos[2]=z;
+ if(raydium_sound) 
+    {
+    raydium_camera_vectors(or); // get vectors
+    raydium_sound_SetListenerPos(pos);
+    raydium_sound_SetListenerOr(or);
+    }
+ raydium_sky_box_render(x,y,z);
+ raydium_frame_first_camera_pass=0;
+ raydium_light_update_position_all();
+ }
+
+ if(!raydium_camera_pushed)
+ {
+ raydium_camera_pushed=1;
+ raydium_camera_x=x; 
+ raydium_camera_y=y;
+ raydium_camera_z=z;
+
+ glPushMatrix();
+ memset(raydium_camera_cursor_place,0,3*sizeof(GLfloat));
+ }
+ else raydium_log("Warning: too many calls to camera_* ! (matrix already pushed)");
+
+}
+
+
+void raydium_camera_place(GLfloat x, GLfloat y, GLfloat z,
+			  GLfloat lacet, GLfloat tangage, GLfloat roulis)
+{
+//glLoadIdentity();
+raydium_camera_internal_prepare();
+glRotatef(roulis,0,0,1);
+glRotatef(tangage,1,0,0);
+glRotatef(lacet,0,1,0);
+glTranslatef(x, y, z);
+glRotatef(90,0,0,1);
+glRotatef(90,0,1,0);
+raydium_camera_internal(z,x,-y);
+}
+
+
+void raydium_camera_look_at(GLfloat x, GLfloat y, GLfloat z,
+			  GLfloat x_to, GLfloat y_to, GLfloat z_to)
+{
+//glLoadIdentity();
+raydium_camera_internal_prepare();
+glRotatef(raydium_camera_look_at_roll,0,0,1);
+raydium_camera_look_at_roll=0;
+gluLookAt(x,y,z,z_to,x_to,-y_to,0.,0.,1.);
+raydium_camera_internal(x,y,z);
+}
+
+void raydium_camera_replace(void)
+{
+ if(!raydium_camera_pushed)
+ raydium_log("Warning: no camera to replace (matrix stack's empty)");
+ else
+ {
+ glPopMatrix();
+ glPushMatrix();
+ memset(raydium_camera_cursor_place,0,3*sizeof(GLfloat));
+
+ }
+}
+
+void raydium_camera_replace_go(GLfloat *pos, GLfloat *R)
+{
+// pos[3], R[3*3]
+
+GLfloat matrix[16];
+
+raydium_camera_replace();
+matrix[0]=R[0];
+matrix[1]=R[4];
+matrix[2]=R[8];
+matrix[3]=0;
+matrix[4]=R[1];
+matrix[5]=R[5];
+matrix[6]=R[9];
+matrix[7]=0;
+matrix[8]=R[2];
+matrix[9]=R[6];
+matrix[10]=R[10];
+matrix[11]=0;
+matrix[12]=pos[0];
+matrix[13]=pos[1];
+matrix[14]=pos[2];
+matrix[15]=1;
+glMultMatrixf(matrix);
+memcpy(raydium_camera_cursor_place,pos,3*sizeof(GLfloat));
+}
+
+
+void raydium_camera_rumble(GLfloat amplitude, GLfloat ampl_evo, GLfloat secs)
+{
+raydium_camera_rumble_amplitude=amplitude;
+raydium_camera_rumble_evolution=ampl_evo;
+raydium_camera_rumble_remaining=secs;
+}
+
+void raydium_camera_path_reset(void)
+{
+raydium_camera_path_reset_flag=1;
+}
+
+// if step is <= 0, moves will be instaneous
+// camera will be placed only if step is >=0 (negative steps are used
+// only to change internal vars)
+void raydium_camera_smooth(GLfloat px, GLfloat py, GLfloat pz, 
+			   GLfloat lx, GLfloat ly, GLfloat lz, 
+			   GLfloat zoom, GLfloat roll, GLfloat step)
+{
+static GLfloat opx,opy,opz;
+static GLfloat olx,oly,olz;
+static GLfloat ozoom=90;
+static GLfloat oroll=0;
+
+//ydium_log("camera smooth (asked): %.2f %.2f %.2f | %.2f %.2f %.2f | %.2f %.2f",px,py,pz,lx,ly,lz,zoom,step);
+    
+if(step<=0 || // wow.. smells inf, do a instantaneous step. (and don't place cam)
+   raydium_camera_path_reset_flag)
+{
+    opx=px;
+    opy=py;
+    opz=pz;
+    olx=lx;
+    oly=ly;
+    olz=lz;
+    ozoom=zoom;
+    oroll=roll;
+    raydium_camera_path_reset_flag=0;
+}
+else
+{
+    opx+=(px-opx)*step;
+    opy+=(py-opy)*step;
+    opz+=(pz-opz)*step;
+    olx+=(lx-olx)*step;
+    oly+=(ly-oly)*step;
+    olz+=(lz-olz)*step;
+    ozoom+=(zoom-ozoom)*step;
+    oroll+=(roll-oroll)*step;
+
+    if(ozoom<0) ozoom=0;
+    if(ozoom>180) ozoom=270;
+
+    if(ozoom!=raydium_projection_fov)
+        {
+        raydium_projection_fov=ozoom;
+        raydium_window_view_update();
+        }
+}
+
+raydium_camera_look_at_roll=oroll;
+
+if(step>=0)
+    raydium_camera_look_at(opx,opy,opz,olx,oly,olz);
+//raydium_log("camera smooth (result): %.2f %.2f %.2f | %.2f %.2f %.2f | %.2f | %.2f",opx,opy,opz,olx,oly,olz,ozoom,step);
+}
+
+
+void raydium_camera_path_init(int p)
+{
+int i;
+raydium_camera_path[p].name[0]=0;
+raydium_camera_path[p].steps=-1;
+for(i=0;i<RAYDIUM_MAX_CAMERA_PATH_STEPS;i++)
+    {
+    raydium_camera_path[p].x[i]=0;
+    raydium_camera_path[p].y[i]=0;
+    raydium_camera_path[p].z[i]=0;
+    raydium_camera_path[p].zoom[i]=0;
+    raydium_camera_path[p].roll[i]=0;
+    }
+}
+
+void raydium_camera_path_init_all(void)
+{
+int i;
+for(i=0;i<RAYDIUM_MAX_CAMERA_PATHS;i++)
+    raydium_camera_path_init(i);
+}
+
+
+int raydium_camera_path_find(char *name)
+{
+int i;
+for(i=0;i<RAYDIUM_MAX_CAMERA_PATHS;i++)
+    if(!strcmp(raydium_camera_path[i].name,name) && raydium_camera_path[i].steps>-1)
+	return i;
+return -1;
+}
+
+
+int raydium_camera_path_load(char *filename)
+{
+FILE *fp;
+int i=0;
+GLfloat x,y,z,zoom,roll;
+int p;
+
+fp=raydium_file_fopen(filename,"rt");
+if(!fp)
+    {
+    raydium_log("camera: cannot open camera path '%s'",filename);
+    return -1;
+    }
+
+for(p=0;p<RAYDIUM_MAX_CAMERA_PATHS;p++)
+    if(raydium_camera_path[p].steps==-1)
+	break;
+
+if(p==RAYDIUM_MAX_CAMERA_PATHS)
+    {
+    raydium_log("camera: cannot find any free slot !",filename);
+    return -1;
+    }
+
+strcpy(raydium_camera_path[p].name,filename);
+
+while( fscanf(fp,"%f %f %f %f %f\n",&x,&y,&z,&zoom,&roll)!=EOF )
+ {
+  raydium_camera_path[p].x[i]=x;
+  raydium_camera_path[p].y[i]=y;
+  raydium_camera_path[p].z[i]=z;
+  raydium_camera_path[p].zoom[i]=zoom;
+  raydium_camera_path[p].roll[i]=roll;
+  i++;
+ }
+
+raydium_camera_path[p].steps=i;
+raydium_log("camera path '%s' loaded (slot %i, %i steps)",filename,p,i);
+return p;
+}
+
+
+void raydium_camera_path_draw(int p)
+{
+int i;
+
+if(p>=0 && p<RAYDIUM_MAX_CAMERA_PATHS)
+    {
+    glDisable(GL_LIGHTING);
+    raydium_texture_current_set_name("rgb(1,0,0)");
+    raydium_rendering_internal_prepare_texture_render(raydium_texture_current);
+    glLineWidth(1.f);
+    glBegin(GL_LINE_LOOP);
+
+    for(i=0;i<raydium_camera_path[p].steps;i++)
+	{
+	glVertex3f(
+		raydium_camera_path[p].x[i],
+		raydium_camera_path[p].y[i],
+		raydium_camera_path[p].z[i]);
+	}
+
+    glEnd();
+    if(raydium_light_enabled_tag)
+	glEnable(GL_LIGHTING);
+	     
+    return;
+    }
+raydium_log("camera path draw failed : invalid index");
+}
+
+void raydium_camera_path_draw_name(char *path)
+{
+int p;
+
+p=raydium_camera_path_find(path);
+if(p==-1) p=raydium_camera_path_load(path);
+
+raydium_camera_path_draw(p);
+}
+
+
+char raydium_camera_smooth_path(char *path, GLfloat step, GLfloat *x, GLfloat *y, GLfloat *z, GLfloat *zoom, GLfloat *roll)
+{
+int p;
+int step1,step2;
+GLfloat vx,vy,vz,vzoom,vroll;
+GLfloat diff;
+
+p=raydium_camera_path_find(path);
+
+if(p==-1)
+    p=raydium_camera_path_load(path);
+    
+if(p==-1)
+    return 0;
+
+step1=(int)step;
+step2=step1+1;
+diff=step-step1;
+
+while(step1>=raydium_camera_path[p].steps)
+    {
+    step1-=raydium_camera_path[p].steps;
+    }
+
+while(step2>=raydium_camera_path[p].steps)
+    {
+    step2-=raydium_camera_path[p].steps;
+    }
+
+vx=raydium_camera_path[p].x[step2]-raydium_camera_path[p].x[step1];
+vy=raydium_camera_path[p].y[step2]-raydium_camera_path[p].y[step1];
+vz=raydium_camera_path[p].z[step2]-raydium_camera_path[p].z[step1];
+vzoom=raydium_camera_path[p].zoom[step2]-raydium_camera_path[p].zoom[step1];
+vroll=raydium_camera_path[p].roll[step2]-raydium_camera_path[p].roll[step1];
+
+*x=raydium_camera_path[p].x[step1]+(vx*diff);
+*y=raydium_camera_path[p].y[step1]+(vy*diff);
+*z=raydium_camera_path[p].z[step1]+(vz*diff);
+*zoom=raydium_camera_path[p].zoom[step1]+(vzoom*diff);
+*roll=raydium_camera_path[p].roll[step1]+(vroll*diff);
+
+return 1;
+}
+
+
+void raydium_camera_smooth_path_to_pos(char *path, GLfloat lx, GLfloat ly, GLfloat lz, GLfloat path_step, GLfloat smooth_step)
+{
+GLfloat x,y,z,zoom,roll;
+
+if(raydium_camera_smooth_path(path,path_step,&x,&y,&z,&zoom,&roll)==-1)
+    raydium_log("camera path error with '%s'",path);
+
+raydium_camera_smooth(x,y,z,ly,-lz,lx,zoom,roll,smooth_step);
+}
+
+void raydium_camera_smooth_pos_to_path(GLfloat lx, GLfloat ly, GLfloat lz, char *path, GLfloat path_step, GLfloat smooth_step)
+{
+GLfloat x,y,z,zoom,roll;
+
+if(raydium_camera_smooth_path(path,path_step,&x,&y,&z,&zoom,&roll)==-1)
+    raydium_log("camera path error with '%s'",path);
+
+raydium_camera_smooth(lx,ly,lz,y,-z,x,zoom,roll,smooth_step);
+}
+
+void raydium_camera_smooth_path_to_path(char *path_from, GLfloat path_step_from, char *path_to, GLfloat path_step_to, GLfloat smooth_step)
+{
+GLfloat fx,fy,fz,fzoom,froll;
+GLfloat tx,ty,tz,tzoom,troll;
+
+if(raydium_camera_smooth_path(path_from,path_step_from,&fx,&fy,&fz,&fzoom,&froll)==-1)
+    raydium_log("camera path error with '%s' (from)",path_from);
+
+if(raydium_camera_smooth_path(path_to,path_step_to,&tx,&ty,&tz,&tzoom,&troll)==-1)
+    raydium_log("camera path error with '%s' (to)",path_to);
+
+raydium_camera_smooth(fx,fy,fz, ty,-tz,tx,fzoom,froll,smooth_step);
+}
Index: raydium/sound.c
===================================================================
--- raydium/sound.c	(revision 0)
+++ raydium/sound.c	(revision 1)
@@ -0,0 +1,653 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/sound.h"
+#endif
+
+// IMPORTANT ! USE A  R E C E N T  RELEASE OF OPENAL (0.0.6)
+
+//VERIFIES THAT THE LAST OPERATION DID NOT MAKE ANY ERROR
+//IF AN ERROR IS DETECTED IT PRINTS THE caller NAME
+void raydium_sound_verify(char *caller)
+{
+ int error;
+ if ((error = alGetError()) != AL_NO_ERROR)
+ {
+  raydium_log("sound: ERROR : %s :%d",caller,error);
+//  raydium_log("sound: Deleting buffers");
+//   alDeleteBuffers(RAYDIUM_SOUND_NUM_BUFFERS,raydium_sound_buffer);
+//  raydium_log("sound: Releasing OpenAL");
+//   alutExit();
+//   exit(1);
+ }
+}
+
+int raydium_sound_Array3IsValid(ALfloat *a)
+{
+if( !raydium_trigo_isfloat(a[0]) ||
+    !raydium_trigo_isfloat(a[1]) ||
+    !raydium_trigo_isfloat(a[2]) )
+	{
+	raydium_log("sound : ERROR: invalid 3xALfloat array provided");
+	return 0;
+	}
+return 1;
+}
+
+//INITS A SOURCE WITH DEFAULT VALUES
+//TAKES A SOURCE NUMBER
+void raydium_sound_InitSource(int src)
+{
+ ALfloat srcPos[]={ 0.0, 0.0, 0.0};
+ ALfloat srcVel[]={ 0.0, 0.0, 0.0};
+
+ alSourcef(raydium_sound_source[src],AL_PITCH,1.0f);                //SETS SOURCE PITCH
+   raydium_sound_verify("setting source pitch");
+ alSourcef(raydium_sound_source[src],AL_GAIN,1.0f);                 //SETS SOURCE GAIN
+   raydium_sound_verify("setting source gain");
+ alSourcef(raydium_sound_source[src],AL_REFERENCE_DISTANCE,raydium_sound_DefaultReferenceDistance);
+   raydium_sound_verify("setting source reference distance");
+ alSourcefv(raydium_sound_source[src],AL_POSITION,srcPos);          //SETS SOURCE POSITION
+   raydium_sound_verify("setting source position");
+ alSourcefv(raydium_sound_source[src],AL_VELOCITY,srcVel);          //SETS SOURCE VELOCITY
+   raydium_sound_verify("setting source velocity");
+ alSourcei(raydium_sound_source[src],AL_BUFFER,raydium_sound_buffer[src]);               //ATTACHS A SOURCE TO A BUFFER
+   raydium_sound_verify("attaching source to buffer");
+ alSourcei(raydium_sound_source[src],AL_LOOPING,AL_TRUE);           //SETS SOURCE LOOPING TO TRUE
+   raydium_sound_verify("setting source loop state");
+}
+
+
+//LOADS A WAV FILE
+//RETURNS THE SOURCE NUMBER OR -1 IF IT FAILS
+int raydium_sound_LoadWav(const char *fname)
+{
+ int snum;
+ ALsizei size,freq;
+ ALenum format;
+ ALvoid *data;
+ FILE *fp;
+//#ifdef WIN32
+ ALboolean bool;
+//#endif
+
+ if(raydium_sound_top_buffer==RAYDIUM_SOUND_NUM_BUFFERS)
+ {
+  raydium_log("sound: ERROR loading %s no more buffers available",fname);
+//  exit(1);
+  return -1;
+ }
+ else
+ {
+  snum=raydium_sound_top_buffer;
+ }
+
+ fp=raydium_file_fopen((char *)fname,"r");
+ if(fp==NULL)
+ {
+  raydium_log("sound: ERROR opening file %s",fname);
+  return -1;
+  //exit(1);
+ }
+ fclose(fp);
+
+  alutLoadWAVFile((ALbyte *)fname,&format,&data,&size,&freq,&bool);
+     raydium_sound_verify("alutLoadWAVFile");
+
+ alBufferData(raydium_sound_buffer[snum],format,data,size,freq);
+     raydium_sound_verify("alBufferData");
+
+ alutUnloadWAV(format,data,size,freq);
+     raydium_sound_verify("alutUnloadWAV");
+
+ raydium_sound_top_buffer++;
+ raydium_sound_InitSource(snum);
+  return(snum);
+}
+
+
+//VERIFIES THAT THE SOURCE IS IN THE SOURCE ARRAY
+//RETURNS 0 IF OK, -1 IF THERE'S AN ERROR
+int raydium_sound_SourceVerify(int src)
+{
+ if(src<0 || src>=raydium_sound_top_buffer)
+ {
+  raydium_log("sound: source %d doesn't exist !",src);
+  return(-1);
+ }
+ return(0);
+}
+
+//SETS THE LOOP ATTRIBUTE OF A SOURCE
+int raydium_sound_SetSourceLoop(int src, char loop)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alSourcei(raydium_sound_source[src],AL_LOOPING,(loop?AL_TRUE:AL_FALSE));
+  raydium_sound_verify("setting source loop");
+ }
+ return(result);
+}
+
+//GETS SOURCE PITCH
+//TAKES A SOURCE NUMBER
+//GIVES AN ALfloat
+int raydium_sound_GetSourcePitch(int src, ALfloat *p)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alGetSourcef(raydium_sound_source[src],AL_PITCH,p);
+  raydium_sound_verify("getting source pitch");
+ }
+ return(result);
+}
+
+
+//SETS SOURCE PITCH
+//TAKES A SOURCE NUMBER AND AN ALfloat
+int raydium_sound_SetSourcePitch(int src, ALfloat p)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  if(p>2.0)
+  {
+   p=2.0;//CLIPPING
+   raydium_log("sound: Pitch Overflow , clipped to 2");
+  }
+  if(p<=0.0)
+  {
+   p=0.1; // Seems ok :)
+   raydium_log("sound: Tried to set negative or 0 Pitch , clipped to 0.1");
+  }
+  alSourcef(raydium_sound_source[src],AL_PITCH,p);
+  raydium_sound_verify("setting source pitch");
+ }
+ return(result);
+}
+
+
+//GETS SOURCE GAIN
+//TAKES A SOURCE NUMBER
+//GIVES AN ALfloat
+int raydium_sound_GetSourceGain(int src, ALfloat *g)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alGetSourcef(raydium_sound_source[src],AL_GAIN,g);
+  raydium_sound_verify("getting source gain");
+ }
+ return(result);
+}
+
+
+//SETS SOURCE GAIN
+//TAKES A SOURCE NUMBER AND AN ALfloat
+int raydium_sound_SetSourceGain(int src, ALfloat g)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  if(g<0.0)
+  {
+   g=0.0;
+   raydium_log("sound: Tried to set negative Gain , clipped to 0");
+  }
+  alSourcef(raydium_sound_source[src],AL_GAIN,g);
+  raydium_sound_verify("setting source gain");
+ }
+ return(result);
+}
+
+//SETS SOURCE POSITION
+//TAKES A SOURCE NUMBER AND AN ALfloat ARRAY {x,y,z}
+int raydium_sound_SetSourcePos(int src, ALfloat Pos[])
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0 && raydium_sound_Array3IsValid(Pos))
+ {
+  alSourcefv(raydium_sound_source[src],AL_POSITION,Pos);
+  raydium_sound_verify("setting source position");
+ }
+ return(result);
+}
+
+
+int raydium_sound_SetSourcePosCamera(int src)
+{
+ALfloat p[3];
+p[0]=raydium_camera_x;
+p[1]=raydium_camera_y;
+p[2]=raydium_camera_z;
+return raydium_sound_SetSourcePos(src,p);
+}
+
+//GETS SOURCE POSITION
+//TAKES A SOURCE NUMBER
+//GIVES AN ALfloat ARRAY {x,y,z}
+int raydium_sound_GetSourcePos(int src, ALfloat *Pos[] )
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alGetSourcefv(raydium_sound_source[src],AL_POSITION,(ALfloat *)&(*Pos));
+  raydium_sound_verify("getting source position");
+ }
+ return(result);
+}
+
+
+//SETS SOURCE DIRECTION
+//TAKES A SOURCE NUMBER AND AN ALfloat ARRAY {x,y,z}
+int raydium_sound_SetSourceDir(int src, ALfloat Dir[])
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0 && raydium_sound_Array3IsValid(Dir))
+ {
+  alSourcefv(raydium_sound_source[src],AL_DIRECTION,Dir);
+  raydium_sound_verify("setting source direction");
+ }
+ return(result);
+}
+
+//GETS SOURCE DIRECTION
+//TAKES A SOURCE NUMBER
+//GIVES AN ALfloat ARRAY {x,y,z}
+int raydium_sound_GetSourceDir(int src, ALfloat *Dir[] )
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alGetSourcefv(raydium_sound_source[src],AL_DIRECTION,(ALfloat *)&(*Dir));
+  raydium_sound_verify("getting source direction");
+ }
+ return(result);
+}
+
+
+//SETS SOURCE VELOCITY
+//TAKES A SOURCE NUMBER AND AN ALfloat ARRAY {x,y,z}
+int raydium_sound_SetSourceVel(int src, ALfloat Vel[])
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0 && raydium_sound_Array3IsValid(Vel))
+ {
+  alSourcefv(raydium_sound_source[src],AL_VELOCITY,Vel);
+  raydium_sound_verify("setting source velocity");
+ }
+ return(result);
+}
+
+//GETS SOURCE VELOCITY
+//TAKES A SOURCE NUMBER
+//GIVES AN ALfloat ARRAY {x,y,z}
+int raydium_sound_GetSourceVel(int src, ALfloat *Vel[] )
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alGetSourcefv(raydium_sound_source[src],AL_VELOCITY,(ALfloat *)&(*Vel));
+  raydium_sound_verify("getting source velocity");
+ }
+ return(result);
+}
+
+
+
+//SETS LISTENER POSITION
+//TAKES AN ALfloat ARRAY {x,y,z}
+void raydium_sound_SetListenerPos(ALfloat Pos[])
+{
+ if(!raydium_sound_Array3IsValid(Pos)) return;
+ 
+ alListenerfv(AL_POSITION,Pos);
+   raydium_sound_verify("setting listener position");
+}
+
+//GETS LISTENER POSITION
+//GIVES AN ALfloat ARRAY {x,y,z}
+void raydium_sound_GetListenerPos(ALfloat *Pos[] )
+{
+ alGetListenerfv(AL_POSITION,(ALfloat *)&(*Pos));
+   raydium_sound_verify("getting listener position");
+}
+
+//SETS LISTENER ORIENTATION
+//TAKES AN ALfloat ARRAY {x,y,z,x2,y2,z2}
+//                        ATvector UPvector
+void raydium_sound_SetListenerOr(ALfloat Or[])
+{
+ if(!raydium_sound_Array3IsValid(Or)) return;
+ if(!raydium_sound_Array3IsValid(Or+3)) return;
+ 
+ alListenerfv(AL_ORIENTATION,Or);
+   raydium_sound_verify("setting listener orientation");
+}
+
+//GETS LISTENER ORIENTATION
+//GIVES AN ALfloat ARRAY {x,y,z,x2,y2,z2}
+//                        ATvector UPvector
+void raydium_sound_GetListenerOr(ALfloat *Or[] )
+{
+ 
+ alGetListenerfv(AL_ORIENTATION,(ALfloat *)&(*Or));
+   raydium_sound_verify("getting listener orientation");
+}
+
+//SETS LISTENER VELOCITY
+//TAKES AN ALfloat ARRAY {x,y,z}
+void raydium_sound_SetListenerVel(ALfloat Vel[])
+{
+if(!raydium_sound_Array3IsValid(Vel)) return;
+
+ alListenerfv(AL_VELOCITY,Vel);
+   raydium_sound_verify("setting listener velocity");
+}
+
+//GETS LISTENER VELOCITY
+//GIVES AN ALfloat ARRAY {x,y,z}
+void raydium_sound_GetListenerVel(ALfloat *Vel[] )
+{
+ alGetListenerfv(AL_VELOCITY,(ALfloat *)&(*Vel));
+   raydium_sound_verify("getting listener velocity");
+}
+
+
+//INITIALISATION
+void raydium_sound_init(void)
+{
+ ALfloat listenerPos[]={-10.0,0.0,0.0};
+ ALfloat listenerVel[]={0.0,0.0,0.0};
+// ALfloat back[] ={ 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f };
+ ALfloat front[]={ 1.0f, 0.0f,  1.0f, 0.0f, 0.0f, 1.0f };
+
+#ifdef NO_SOUND_DEBUG
+return;
+#endif
+
+ alutInit(&raydium_init_argc, raydium_init_argv);
+//alutInit(0, NULL) ;
+ alGetError();
+
+ alListenerfv(AL_POSITION,listenerPos);
+ alListenerfv(AL_VELOCITY,listenerVel);
+ alListenerfv(AL_ORIENTATION,front);
+ alDistanceModel(AL_INVERSE_DISTANCE);
+//#ifdef __linux
+ alGetError(); /* clear error */
+ alGenBuffers(RAYDIUM_SOUND_NUM_BUFFERS, raydium_sound_buffer);
+ raydium_sound_verify("alGenBuffers");
+//#else
+//alGenBuffers(RAYDIUM_SOUND_NUM_BUFFERS,raydium_sound_buffer);
+// if (!raydium_sound_buffer)
+// {
+//  raydium_log("sound: Error creating buffers !!");
+//  exit(1);
+// }
+//#endif
+
+ raydium_log("sound: Buffer creation successfull");
+
+//#ifdef __linux
+ alGetError(); /* clear error */
+ alGenSources(RAYDIUM_SOUND_NUM_SOURCES, raydium_sound_source);
+ raydium_sound_verify("alGenSources");
+//#else
+// raydium_sound_verify("alGenSources");
+//#endif
+ raydium_sound_top_buffer=2; //first available buffer (2 first are used by music)
+ raydium_sound=1;
+ raydium_sound_music_file=NULL;
+ raydium_sound_DefaultReferenceDistance=50.f; // default distance where the source sound is half volume
+ raydium_sound_music_eof_callback=NULL;
+ raydium_log("sound: OK");
+ 
+}
+
+//PLAYS A SOURCE
+int raydium_sound_SourcePlay(int src)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alSourcePlay(raydium_sound_source[src]);
+ }
+ return(result);
+}
+
+//STOPS A SOURCE
+int raydium_sound_SourceStop(int src)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alSourceStop(raydium_sound_source[src]);
+ }
+ return(result);
+}
+
+//PAUSE A SOURCE
+int raydium_sound_SourcePause(int src)
+{
+ int result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alSourcePause(raydium_sound_source[src]);
+ }
+ return(result);
+}
+
+//UNPAUSE A SOURCE
+int raydium_sound_SourceUnpause(int src)
+{
+ int result;
+ int state;
+ result=raydium_sound_SourceVerify(src);
+ if(result==0)
+ {
+  alGetSourcei(raydium_sound_source[src], AL_SOURCE_STATE, &state);
+  if(state==AL_PAUSED)
+    alSourcePlay(raydium_sound_source[src]);
+ }
+ return(result);
+}
+
+
+//THINGS TO DO WHEN EXITING
+void raydium_sound_close(void)
+{
+int i;
+ if(raydium_sound==1) // WE DO THESE THINGS ONLY IF OPEN AL INIT WAS OK
+ {
+  for(i=0;i<raydium_sound_top_buffer;i++)
+    raydium_sound_SourceStop(i);
+  raydium_log("sound: Deleting sources");
+   alDeleteSources(RAYDIUM_SOUND_NUM_SOURCES,raydium_sound_source);
+  raydium_log("sound: Deleting buffers");
+   alDeleteBuffers(RAYDIUM_SOUND_NUM_BUFFERS,raydium_sound_buffer);
+  raydium_log("sound: Releasing OpenAL");
+   alutExit();
+ }
+}
+
+
+int BufferData(ALuint buffer,OggVorbis_File *file,vorbis_info *ogginfo) 
+{
+  unsigned int count=0;
+  int stream;
+  int amt;
+  ALint format;
+
+  while(count<SOUNDDATASIZE)
+  {
+    amt=ov_read(file,&(raydium_sound_music_buf[count]),
+          SOUNDDATASIZE-count,
+          0,2,1,&stream);
+    if(amt<=0)
+    {
+//      if(amt<0)fprintf(stderr,"ov_read error: ");
+      raydium_log("sound: ov_read error");
+      break;
+    }
+    count+=amt;
+  }
+
+  if(!count)
+    return 0;
+
+  if(ogginfo->channels==1)
+    format=AL_FORMAT_MONO16;
+  else
+    format=AL_FORMAT_STEREO16;
+
+  alBufferData(buffer,format,raydium_sound_music_buf,count,ogginfo->rate);
+  return 1;
+}
+
+void raydium_sound_internal_cleanstreambuffs(void)
+{
+  ALint format;
+  vorbis_info *ogginfo;
+  
+  ogginfo=raydium_sound_ogginfo;
+  memset(raydium_sound_music_buf,0,SOUNDDATASIZE);
+
+  if(ogginfo->channels==1)
+    format=AL_FORMAT_MONO16;
+  else
+    format=AL_FORMAT_STEREO16;
+
+  alBufferData(raydium_sound_buffer[0],format,raydium_sound_music_buf,SOUNDDATASIZE,ogginfo->rate);
+  alBufferData(raydium_sound_buffer[1],format,raydium_sound_music_buf,SOUNDDATASIZE,ogginfo->rate);
+}
+
+
+int StartMusic(ALuint musicsource,ALuint *buffers,OggVorbis_File *file,
+      vorbis_info *ogginfo)
+{
+  int ok;
+  alSourceStop(musicsource);
+  memset(raydium_sound_music_buf,0,SOUNDDATASIZE);
+  ok=BufferData(raydium_sound_buffer[0],file,ogginfo) 
+     && BufferData(raydium_sound_buffer[1],file,ogginfo);
+  alSourceQueueBuffers(musicsource,2,raydium_sound_buffer);
+  alSourcePlay(musicsource);
+  return ok;
+} 
+
+
+
+//try to open music
+int raydium_sound_load_music(char *fname)
+{
+#ifdef NO_SOUND_DEBUG
+return -1;
+#endif
+
+ if(raydium_sound_music_file) fclose(raydium_sound_music_file);
+ raydium_sound_music_file=NULL;
+ 
+ if(fname==NULL || strlen(fname)==0)
+    return 0;
+ 
+ raydium_sound_music_file = raydium_file_fopen( fname, "rb" );
+ if(raydium_sound_music_file == NULL)
+ {
+  raydium_log("sound: Could not open %s", fname);
+  perror("raydium_sound_load_music");
+  return(-1);
+ }
+
+ alSourcei( raydium_sound_source[0], AL_SOURCE_RELATIVE, AL_TRUE );
+ alSourcei( raydium_sound_source[0], AL_LOOPING, AL_FALSE );
+
+ if(ov_open(raydium_sound_music_file, &raydium_sound_vf, NULL, 0) < 0)
+ {
+  raydium_log("ERROR: Failed to open %s as vorbis",fname);
+  return(-1);
+ }
+ raydium_sound_ogginfo=ov_info(&raydium_sound_vf,-1);
+ 
+// size = bits/8 * ov_info(&raydium_sound_vf, 0)->channels; 
+StartMusic(raydium_sound_source[0],raydium_sound_buffer,
+           &raydium_sound_vf,raydium_sound_ogginfo);
+ 
+return(0);
+}
+
+
+void raydium_sound_music_callback(void)
+{
+ALuint nprocessed;
+ALuint buffer;
+ALint sourcestate;
+char newfile[RAYDIUM_MAX_NAME_LEN];
+
+ if(raydium_sound_music_file==NULL) return;
+
+ if(feof(raydium_sound_music_file))
+    {
+    fseek(raydium_sound_music_file,0,SEEK_SET);//rewind in the file if we hit the end
+    raydium_log("sound: end of file reached");
+    if(raydium_sound_music_eof_callback && raydium_sound_music_eof_callback(newfile)>0)
+	{
+	if(strlen(newfile)) 
+	    raydium_sound_load_music(newfile);
+	else
+	    {
+	    // may cause glitches on next music.. ?
+	    //fclose(raydium_sound_music_file);
+	    //raydium_sound_music_file=NULL;
+	    raydium_sound_load_music(NULL);
+	    }
+	return ;
+	}
+    }
+
+ alGetSourcei(raydium_sound_source[0],AL_BUFFERS_PROCESSED,&nprocessed);
+ if(nprocessed) // or while...
+ {
+  static int last;
+  alSourceUnqueueBuffers(raydium_sound_source[0],1,&buffer);
+  if(buffer==last)
+    {
+    raydium_log("sound: OpenAL internal buffer mistake: cleaning buffers");
+    alSourceStop(raydium_sound_source[0]);
+    raydium_sound_internal_cleanstreambuffs();
+    alSourcePlay(raydium_sound_source[0]);
+    }
+    else  
+    {
+    last=buffer;
+    BufferData(buffer,&raydium_sound_vf,raydium_sound_ogginfo);
+    alSourceQueueBuffers(raydium_sound_source[0],1,&buffer);
+    nprocessed--;
+    }
+ } 
+
+ //restart playing if needed
+ alGetSourcei(raydium_sound_source[0],AL_SOURCE_STATE,&sourcestate);
+ if(sourcestate!=AL_PLAYING)
+ {
+  raydium_log("sound: music source stopped, back to play");
+  StartMusic(raydium_sound_source[0],raydium_sound_buffer,
+             &raydium_sound_vf,raydium_sound_ogginfo);
+ } 
+
+}
+
+//THINGS TO DO
+void raydium_sound_callback(void)
+{
+raydium_sound_music_callback();
+}
+
Index: raydium/main.h
===================================================================
--- raydium/main.h	(revision 0)
+++ raydium/main.h	(revision 1)
@@ -0,0 +1,25 @@
+/*
+* Raydium - CQFD Corp.
+* http://raydium.cqfd-corp.org
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+extern char *raydium_version;
+
+#define MAIN_H
+#include "common.h"
+
+// EOF
Index: raydium/network.c
===================================================================
--- raydium/network.c	(revision 0)
+++ raydium/network.c	(revision 1)
@@ -0,0 +1,939 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/network.h"
+#endif
+
+// Raydium low-level Network API.
+
+// TODO:
+// 1 - protection against duplicate data packets (how ?!)
+// 01/07/2004: done ? (need more tests)
+// 2 - per client delays for servers
+// end of 2004: done too (more test needed)
+
+// need proto
+char raydium_server_accept_new(struct sockaddr *from, char *name);
+void raydium_network_broadcast(char type,char *buff);
+void raydium_network_write(struct sockaddr *to, int from, char type,char *buff);
+char raydium_network_netcall_add(void *ptr, int type, char tcp);
+
+
+int raydium_network_propag_find(int type)
+{
+int i;
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_PROPAGS;i++)
+  if(raydium_network_propag[i].state && raydium_network_propag[i].type==type)
+	return i;
+return -1;
+}
+
+
+void raydium_network_propag_recv(int type, char *buff)
+{
+int dec;
+unsigned int version;
+int i;
+
+i=raydium_network_propag_find(type);
+if(i<0)
+    {
+    raydium_log("network: ERROR: received an invalid propag' type ! (%i)",type);
+    return;
+    }
+
+dec=RAYDIUM_NETWORK_PACKET_OFFSET;
+memcpy(&version,buff+dec,sizeof(int));
+if(version>raydium_network_propag[i].version) // this propag is newer than our
+    {
+    dec+=sizeof(int);    
+    raydium_network_propag[i].version=version;    
+    memcpy(raydium_network_propag[i].data,buff+dec,raydium_network_propag[i].size);
+    }
+}
+
+
+void raydium_network_propag_refresh_id(int i)
+{
+char buff[RAYDIUM_NETWORK_PACKET_SIZE];
+int dec;
+
+if(raydium_network_mode==RAYDIUM_NETWORK_MODE_NONE) return;
+
+if(i<0 || i>=RAYDIUM_NETWORK_MAX_PROPAGS || !raydium_network_propag[i].state)
+    {
+    raydium_log("network: ERROR: cannot refresh this propag': invalid id");
+    return;
+    }
+
+raydium_network_propag[i].version++;
+dec=RAYDIUM_NETWORK_PACKET_OFFSET;
+memcpy(buff+dec,&raydium_network_propag[i].version,sizeof(int));
+dec+=sizeof(int);
+memcpy(buff+dec,raydium_network_propag[i].data,raydium_network_propag[i].size);
+raydium_network_write(NULL,raydium_network_uid,raydium_network_propag[i].type,buff);
+}
+
+
+void raydium_network_propag_refresh(int type)
+{
+int i;
+
+i=raydium_network_propag_find(type);
+if(i<0)
+    {
+    raydium_log("network: ERROR: cannot refresh this propag': invalid type");
+    return;
+    }
+raydium_network_propag_refresh_id(i);
+}
+
+
+void raydium_network_propag_refresh_all(void)
+{
+int i;
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_PROPAGS;i++)
+  if(raydium_network_propag[i].state)
+    raydium_network_propag_refresh_id(i);
+}
+
+int raydium_network_propag_add(int type, void *data, int size)
+{
+int i;
+
+if(size>(RAYDIUM_NETWORK_PACKET_SIZE-RAYDIUM_NETWORK_PACKET_OFFSET-RAYDIUM_NETWORK_PROPAG_HEAD))
+    {
+    raydium_log("network: ERROR: propag' packet is too big for current network size");
+    return -1;
+    }
+
+if(raydium_network_propag_find(type)>=0)
+    {
+    raydium_log("network: ERROR: propag' type already added !");
+    return -1;
+    }
+    
+for(i=0;i<RAYDIUM_NETWORK_MAX_PROPAGS;i++)
+    if(!raydium_network_propag[i].state)
+	{
+	raydium_network_propag[i].state=1;
+	raydium_network_propag[i].version=0;
+	raydium_network_propag[i].type=type;
+	raydium_network_propag[i].size=size;
+	raydium_network_propag[i].data=data;
+	raydium_network_netcall_add(raydium_network_propag_recv,type,1);
+	return i;	
+	}
+raydium_log("network: ERROR: no more propag' slots !");
+return -1;
+}
+
+
+void raydium_network_queue_element_init(raydium_network_Tcp *e)
+{
+e->state=0;
+}
+
+
+unsigned short raydium_network_queue_tcpid_gen(void)
+{
+// not very important.. used for easy client/server tcpid identification
+//#ifdef RAYDIUM_NETWORK_ONLY_____
+static unsigned short gen=100;
+//#else
+//static unsigned short gen=1000;
+//#endif
+
+gen++;
+if(!gen) gen++;
+
+return gen;
+}
+
+
+void raydium_network_queue_tcpid_known_add(int tcpid, int player)
+{
+	raydium_network_tcpid_i[raydium_network_tcpid_index]=tcpid; // mark this TCP-ID as "known"
+	raydium_network_tcpid_p[raydium_network_tcpid_index]=player; // ... from this player
+#ifdef DEBUG_NETWORK
+	raydium_log("ACK adding tcpid=%i (player %i) to known packets",tcpid,player);
+#endif	
+	raydium_network_tcpid_index++;
+
+	if(raydium_network_tcpid_index==RAYDIUM_NETWORK_TX_QUEUE_SIZE)
+	    raydium_network_tcpid_index=0;
+}
+
+char raydium_network_queue_tcpid_known(unsigned short tcpid, unsigned short player)
+{
+int i;
+
+if(!tcpid) return 0;
+
+for(i=0;i<RAYDIUM_NETWORK_TX_QUEUE_SIZE;i++)
+  if(raydium_network_tcpid_i[i]==tcpid &&
+     raydium_network_tcpid_p[i]==player )
+    return i;
+
+return 0;
+}
+
+char raydium_network_queue_is_tcpid(int type)
+{
+int i=0;
+for(i=0;i<RAYDIUM_NETWORK_MAX_NETCALLS;i++)
+    if(raydium_network_netcall_type[i]==type && raydium_network_netcall_tcp[i])
+	return 1;
+return 0;
+}
+
+
+void raydium_network_queue_element_add(char *packet, struct sockaddr *to)
+{
+unsigned short tcpid;
+raydium_network_Tcp *e;
+memcpy(&tcpid,packet+2,sizeof(tcpid));
+
+
+e=&raydium_network_queue[raydium_network_queue_index];
+
+if(e->state)
+    {
+    raydium_network_queue_element_init(e);
+    raydium_network_stat_lost++; // we're erasing an old waiting packet !
+    }
+
+e->state=1;
+e->tcpid=tcpid;
+memcpy(e->packet,packet,RAYDIUM_NETWORK_PACKET_SIZE);
+e->time=raydium_timecall_clock();
+e->retries_left=RAYDIUM_NETWORK_MAX_TRIES;
+if(to) memcpy(&e->to,to,sizeof(struct sockaddr));
+e->to_player=-1;
+
+// if server mode, search for destination player
+if(raydium_network_mode==RAYDIUM_NETWORK_MODE_SERVER)
+    {
+    int i;
+    
+    for(i=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+	if(raydium_network_client[i] && &raydium_network_client_addr[i]==to)
+	    break;
+    
+    if(i==RAYDIUM_NETWORK_MAX_CLIENTS) // not found
+	{
+	raydium_log("ERROR: server: TCP style: cannot find client");
+	return;
+	}
+    e->to_player=i;
+    }
+
+raydium_network_queue_index++;
+if(raydium_network_queue_index==RAYDIUM_NETWORK_TX_QUEUE_SIZE)
+    raydium_network_queue_index=0;
+}
+
+
+unsigned long *raydium_network_internal_find_delay_addr(int player)
+{
+//if client
+if(raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT)
+    return &raydium_netwok_queue_ack_delay_client;
+else // (server)
+    {
+    if(player<0 || player>=RAYDIUM_NETWORK_MAX_CLIENTS)
+	{
+	raydium_log("ERROR: server: bad client id in resend queue ! SHOULD NEVER APPEND !");
+	return NULL; // eeeerk !
+	}
+    return &raydium_netwok_queue_ack_delay_server[player];
+    }
+}
+
+
+void raydium_network_queue_check_time(void)
+{
+unsigned long now;
+unsigned long *delay;
+raydium_network_Tcp *e;
+int i;
+
+
+// find current delay
+
+for(i=0;i<RAYDIUM_NETWORK_TX_QUEUE_SIZE;i++)
+  if(raydium_network_queue[i].state)
+    {
+    now=raydium_timecall_clock();
+    e=&raydium_network_queue[i];
+
+    delay=raydium_network_internal_find_delay_addr(e->to_player);
+    
+    // TCP style timeout: timeout=estimatedRTT*2
+    if( now>(e->time+(*delay)*2) || e->time>now )
+	{
+	// resend packet (and do not add this packet to queue again !)
+#ifdef DEBUG_NETWORK
+	raydium_log("ACK re-asking: tcpid=%i",e->tcpid);
+#endif
+	raydium_network_write_notcp=1;
+	raydium_network_write(&e->to,-1,e->packet[0],e->packet);
+	raydium_network_stat_reemitted++;
+	(*delay)*=2; // Karn/Partridge TCP algo
+        if((*delay)/(double)raydium_timecall_clocks_per_sec>RAYDIUM_NETWORK_ACK_DELAY_MAX)
+	    {
+#ifdef DEBUG_NETWORK
+	    raydium_log("ACK: slow network ! max ack delay reached");
+#endif
+	    (*delay)=raydium_timecall_clocks_per_sec*RAYDIUM_NETWORK_ACK_DELAY_MAX;
+	    }
+	e->retries_left--;
+	e->time=now;
+	if(e->retries_left==0) 
+	    {
+#ifdef DEBUG_NETWORK
+	    raydium_log("ACK: packet lost, too many retries: tcpid=%i",e->tcpid);
+#endif
+	    raydium_network_queue_element_init(e);
+	    raydium_network_stat_lost++;
+	    }
+	}
+    }
+}
+
+void raydium_network_queue_ack_send(unsigned short tcpid, struct sockaddr *to)
+{
+char buff[RAYDIUM_NETWORK_PACKET_SIZE];
+//unsigned short port;
+
+memcpy(buff+RAYDIUM_NETWORK_PACKET_OFFSET,&tcpid,sizeof(tcpid));
+raydium_network_write(to,raydium_network_uid,RAYDIUM_NETWORK_PACKET_ACK,buff);
+
+//memcpy(&port,&to->sa_data[0],sizeof(port));
+//raydium_log("ACK ---> %i.%i.%i.%i:%i",to->sa_data[2],to->sa_data[3],to->sa_data[4],to->sa_data[5],ntohs(port));
+}
+
+
+void raydium_network_queue_ack_recv(int type,char *buff)
+{
+unsigned short tcpid;
+int i;
+raydium_network_Tcp *e;
+unsigned long now;
+// TCP style weight average params
+const float a=0.85;
+const float b=0.15;
+
+memcpy(&tcpid,buff+RAYDIUM_NETWORK_PACKET_OFFSET,sizeof(tcpid));
+
+for(i=0;i<RAYDIUM_NETWORK_TX_QUEUE_SIZE;i++)
+    {
+    e=&raydium_network_queue[i];
+    if(e->state && e->tcpid==tcpid)
+	{
+	// ACK is correct, deleting packet from queue
+#ifdef DEBUG_NETWORK
+	raydium_log("ACK recv ok: tcpid=%i",tcpid);
+#endif
+	now=raydium_timecall_clock();
+	if(e->time<now)
+	    {
+	    unsigned long *delay;
+	    
+	    delay=raydium_network_internal_find_delay_addr(e->to_player);
+	    // Based on original TCP adaptative retransmission algorithm :
+	    *(delay)=a * (*delay) + b*(now - e->time);
+#ifdef DEBUG_NETWORK
+	    raydium_log("ACK delay re-eval: %.2f msec (inst=%.2f msec) (client %i)",(*delay)/(double)raydium_timecall_clocks_per_sec*1000,(now - e->time)/(double)raydium_timecall_clocks_per_sec*1000,e->to_player);
+#endif	
+	    }
+	raydium_network_queue_element_init(e);	    
+	return;
+	}    
+    }
+raydium_network_stat_bogus_ack++;
+#ifdef DEBUG_NETWORK
+raydium_log("ACK bogus (double ack, probably): tcpid=%i",tcpid);
+#endif
+}
+
+
+// -----------------------------------------------------------------------
+
+
+void raydium_network_player_name(char *str)
+{
+#ifndef WIN32
+{
+struct passwd *pn;
+pn=getpwuid(geteuid()); // ("old" kernels ok ?)
+strncpy(str,pn->pw_name,RAYDIUM_MAX_NAME_LEN-1);
+}
+#else
+{
+DWORD s;
+s=RAYDIUM_MAX_NAME_LEN-1;
+GetUserName(str,&s);
+}
+#endif
+
+if(!strlen(str))
+    gethostname(str,RAYDIUM_MAX_NAME_LEN-1);
+}
+
+char raydium_network_set_socket_block(int block)
+{
+int ret=-1;
+//int flags = fcntl(sock, F_GETFL); // bof... :)
+#ifndef WIN32
+if(!block) block=O_NONBLOCK; else block=0;
+ret=fcntl(raydium_network_socket, F_SETFL, block);
+#else
+if(!block) block=1; else block=0;
+ret = ioctlsocket(raydium_network_socket, FIONBIO, (unsigned long *)&block);
+if(ret) ret=-1;
+#endif
+
+if(ret==-1)
+    {
+    raydium_log("ERROR ! network: cannot block/unblock socket");
+    perror("System");
+    return(0);
+    }
+return(1);
+}
+
+//int raydium_network_get_socket_block(void)
+//{
+//return !( fcntl(raydium_network_socket, F_GETFL) & O_NONBLOCK );
+//}
+
+
+char raydium_network_netcall_add(void *ptr, int type, char tcp)
+{
+int i;
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_NETCALLS;i++)
+ if(raydium_network_netcall_type[i]<0)
+ {
+  raydium_network_netcall_func[i]=ptr;
+  raydium_network_netcall_type[i]=type;
+  raydium_network_netcall_tcp[i]=tcp;
+  break;
+ }
+
+if(i==RAYDIUM_NETWORK_MAX_NETCALLS)
+ {
+  raydium_log("network: ERROR: no more netcalls !");
+  return 0;
+ }
+
+return 1;
+}
+
+
+void raydium_network_netcall_exec(int type,char *buff)
+{
+char tmpbuff[RAYDIUM_NETWORK_PACKET_SIZE];
+int i;
+void (*f)(int, char*);
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_NETCALLS;i++)
+ if(raydium_network_netcall_type[i]==type)
+ {
+    memcpy(tmpbuff,buff,RAYDIUM_NETWORK_PACKET_SIZE);
+    f=raydium_network_netcall_func[i];
+    f(type,tmpbuff);
+ }
+}
+
+char raydium_network_timeout_check(void)
+{
+char str[RAYDIUM_NETWORK_PACKET_SIZE];
+int i,n;
+time_t now;
+void (*f)(int);
+
+time(&now);
+
+ if(raydium_network_mode==RAYDIUM_NETWORK_MODE_SERVER)
+ {
+  for(i=n=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+    if(raydium_network_client[i] && now>raydium_network_keepalive[i]+RAYDIUM_NETWORK_TIMEOUT)
+    {
+    raydium_log("network: TIMEOUT for client %i (%i sec): %s deleted !",i,RAYDIUM_NETWORK_TIMEOUT,raydium_network_name[i]);
+    raydium_network_client[i]=0;
+    if(raydium_network_on_disconnect)
+       {
+       f=raydium_network_on_disconnect;
+       f(i);
+       }
+    raydium_network_name[i][0]=0;
+    str[RAYDIUM_NETWORK_PACKET_OFFSET]=i;
+    str[RAYDIUM_NETWORK_PACKET_OFFSET+1]=0;
+    raydium_network_broadcast(RAYDIUM_NETWORK_PACKET_INFO_NAME,str);
+    n++;
+    }
+ return n;
+ }
+return 0;
+}
+
+char raydium_network_init(void)
+{
+int i;
+
+#ifdef WIN32
+int ret;
+WSADATA WSAData;
+ret = WSAStartup(MAKEWORD(1,1), &WSAData);
+if (ret) { raydium_log("network: FAILED ! (Winsock 2 Error: %i while asking for version 1.1)",ret); return(0); }
+#endif
+
+#ifdef RAYDIUM_NETWORK_ONLY
+// Do all needed inits for network only mode:
+raydium_timecall_init();
+#endif
+
+if(raydium_network_mode) close(raydium_network_socket);
+raydium_network_uid=-1;
+raydium_network_mode=RAYDIUM_NETWORK_MODE_NONE;
+raydium_network_socket=-1;
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+    {
+    raydium_network_client[i]=0;
+    raydium_network_name[i][0]=0;
+    }
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_NETCALLS;i++)
+    {
+    raydium_network_netcall_type[i]=-1;
+    raydium_network_netcall_func[i]=0;
+    raydium_network_netcall_tcp[i]=0;
+    }
+
+for(i=0;i<RAYDIUM_NETWORK_TX_QUEUE_SIZE;i++)
+    raydium_network_queue_element_init(&raydium_network_queue[i]);
+
+for(i=0;i<RAYDIUM_NETWORK_TX_QUEUE_SIZE;i++)
+    {
+    raydium_network_tcpid_i[i]=0;
+    raydium_network_tcpid_p[i]=0;
+    }
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_PROPAGS;i++)
+    raydium_network_propag[i].state=0;
+
+raydium_network_queue_index=0;
+raydium_network_tcpid_index=0;
+
+raydium_network_on_connect=raydium_network_on_disconnect=NULL;
+raydium_network_stat_rx=0;
+raydium_network_stat_tx=0;
+raydium_network_stat_lost=0;
+raydium_network_stat_double=0;
+raydium_network_stat_reemitted=0;
+raydium_network_stat_bogus_ack=0;
+raydium_network_netcall_add(raydium_network_queue_ack_recv,RAYDIUM_NETWORK_PACKET_ACK,0);
+raydium_netwok_queue_ack_delay_client=raydium_timecall_clocks_per_sec; // 1sec default delay
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+    raydium_netwok_queue_ack_delay_server[i]=raydium_timecall_clocks_per_sec; // 1sec default delay
+    
+raydium_network_write_notcp=0;
+
+raydium_network_name_local[0]=0;
+#ifndef RAYDIUM_NETWORK_ONLY
+if(raydium_init_cli_option("name",raydium_network_name_local))
+{
+    if(strlen(raydium_network_name_local)==0)
+	raydium_log("Warning: network: --name option needs an argument");
+}
+#endif
+
+if(strlen(raydium_network_name_local)==0)
+    raydium_network_player_name(raydium_network_name_local);
+
+
+raydium_log("network: OK");
+return(1);
+}
+
+// if from < 0, "from" field is not modified (used for broadcasts, mainly)
+void raydium_network_write(struct sockaddr *to, int from, char type,char *buff)
+{
+int ret=-1;
+unsigned short tcpid=0;
+
+buff[0]=type;
+
+if(from>=0)
+    buff[1]=(char)from; // 256 clients MAX for now.
+
+if(raydium_network_write_notcp==0 && raydium_network_queue_is_tcpid(type))
+    tcpid=raydium_network_queue_tcpid_gen();
+    
+if(raydium_network_write_notcp==0) // do not erase tcpid packet's element if it's a re-send
+    memcpy(buff+2,&tcpid,sizeof(unsigned short));
+
+raydium_network_write_notcp=0;
+
+raydium_network_stat_tx+=RAYDIUM_NETWORK_PACKET_SIZE;
+if(raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT)
+    ret=send(raydium_network_socket, buff, RAYDIUM_NETWORK_PACKET_SIZE, 0);
+
+else if(raydium_network_mode==RAYDIUM_NETWORK_MODE_SERVER)
+    ret=sendto(raydium_network_socket, buff, RAYDIUM_NETWORK_PACKET_SIZE, 0, to, sizeof(struct sockaddr));
+
+raydium_network_timeout_check();
+//raydium_log("send ret: %i",ret);
+if(ret<0)
+    {
+    raydium_log("network: ERROR sending ! (%i)",ret);
+    return;
+    }
+
+if(tcpid)
+    {
+    raydium_network_queue_element_add(buff,to);
+#ifdef DEBUG_NETWORK
+    raydium_log("ACK asking to peer: tcpid=%i type=%i",tcpid,type);
+#endif
+    }    
+}
+
+void raydium_network_broadcast(char type,char *buff)
+{
+int i;
+
+for(i=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+ if(raydium_network_client[i])
+  raydium_network_write(&raydium_network_client_addr[i],-1,type,buff);
+}
+
+// buff could be modified, even if return is RAYDIUM_NETWORK_DATA_NONE
+char raydium_network_read(int *id, char *type, char *buff)
+{
+int i;
+struct sockaddr from;
+socklen_t len;
+int ret;
+char dbl=0;
+
+raydium_network_timeout_check();
+raydium_network_queue_check_time();
+
+len=sizeof(struct sockaddr);
+ret=recvfrom(raydium_network_socket,buff,RAYDIUM_NETWORK_PACKET_SIZE,0,&from,&len);
+
+if(ret==RAYDIUM_NETWORK_PACKET_SIZE) 
+ {
+ unsigned short tcpid;
+ 
+ *type=buff[0];
+ *id=buff[1];
+ raydium_network_stat_rx+=RAYDIUM_NETWORK_PACKET_SIZE;
+
+
+ memcpy(&tcpid,buff+2,sizeof(unsigned short));
+ if(tcpid)
+    {
+#ifdef DEBUG_NETWORK
+    raydium_log("ACK read (and will send): tcpid=%i type=%i",tcpid,*type);
+#endif
+    if(raydium_network_queue_tcpid_known(tcpid,*id))
+	{
+	raydium_network_stat_double++;
+	dbl=1;
+#ifdef DEBUG_NETWORK
+	raydium_log("ACK double: tcpid=%i type=%i",tcpid,*type);
+#endif
+	}
+    /*else*/ raydium_network_queue_ack_send(tcpid,&from);
+     raydium_network_queue_tcpid_known_add(tcpid,buff[1]);
+    }
+ 
+ if(dbl) // discard double packet
+    return(RAYDIUM_NETWORK_DATA_NONE);
+ 
+ raydium_network_netcall_exec(*type,buff);
+ 
+ if( raydium_network_mode==RAYDIUM_NETWORK_MODE_SERVER && (*id>=0) && (*id<RAYDIUM_NETWORK_MAX_CLIENTS) )
+    time(&raydium_network_keepalive[(*id)]); // update keepalive
+ 
+ if(*type==RAYDIUM_NETWORK_PACKET_REQUEST_UID && raydium_network_mode==RAYDIUM_NETWORK_MODE_SERVER)
+    {
+    raydium_server_accept_new(&from,buff+RAYDIUM_NETWORK_PACKET_OFFSET);
+    return(RAYDIUM_NETWORK_DATA_NONE);
+    }
+
+ if(*type==RAYDIUM_NETWORK_PACKET_ACK)
+    return(RAYDIUM_NETWORK_DATA_NONE);
+
+ if(*type==RAYDIUM_NETWORK_PACKET_INFO_NAME && raydium_network_mode==RAYDIUM_NETWORK_MODE_CLIENT)
+    {
+    i=buff[RAYDIUM_NETWORK_PACKET_OFFSET];
+    strcpy(raydium_network_name[i],buff+RAYDIUM_NETWORK_PACKET_OFFSET+1);
+    raydium_log("network: client %i is %s",i,raydium_network_name[i]);
+    if(strlen(raydium_network_name[i]))
+	raydium_network_propag_refresh_all(); // spread propags to this new client
+    return(RAYDIUM_NETWORK_DATA_NONE);
+    }
+
+
+ return(RAYDIUM_NETWORK_DATA_OK);
+ }
+else if(errno==EAGAIN) return(RAYDIUM_NETWORK_DATA_NONE); // POSIX
+else { 
+#ifdef WIN32
+	ret=WSAGetLastError();
+	if(ret==WSAEWOULDBLOCK) return(RAYDIUM_NETWORK_DATA_NONE); // NON POSIX (GRRrrr)
+#else
+//	perror("System");	
+#endif
+//	raydium_log("ERROR ! network: error receiving ! (%i)",ret);
+	return(RAYDIUM_NETWORK_DATA_ERROR);
+     }
+}
+
+
+char raydium_network_read_flushed(int *id, char *type, char *buff)
+{
+char ret,data=0;
+char save_buff[RAYDIUM_NETWORK_PACKET_SIZE];
+int save_id;
+char save_type;
+
+do
+ {
+ // erreur !: meme si le retour est NONE, buff peut avoir ete modifie ! 
+ // (et donc, on le lit pas tt a fait le dernier paquet de donnes)
+ // solution: sauver buff avant et le restauter au final ? (lent ?)
+ // 13/04/2004: solution en question mise en place: en test, premier resultats
+ // probants
+ ret=raydium_network_read(id,type,buff);
+ if(ret==RAYDIUM_NETWORK_DATA_OK) 
+    {
+    data++;
+    memcpy(save_buff,buff,RAYDIUM_NETWORK_PACKET_SIZE);
+    save_id=*id;
+    save_type=*type;
+    }
+ }while(ret==RAYDIUM_NETWORK_DATA_OK);
+ 
+if(data) 
+    {
+    memcpy(buff,save_buff,RAYDIUM_NETWORK_PACKET_SIZE);
+    *id=save_id;
+    *type=save_type;
+    return RAYDIUM_NETWORK_DATA_OK;
+    }
+else return ret;
+}
+
+
+char raydium_network_server_create(void)
+{
+struct sockaddr_in sock;
+int ret;
+
+raydium_network_start=time(NULL);
+raydium_network_socket=socket(AF_INET,RAYDIUM_NETWORK_UDP,0);
+if(raydium_network_socket==-1)
+    {
+    raydium_log("ERROR ! network: cannot create server socket");
+    perror("System");
+    return(0);
+    }
+raydium_log("network: server socket created");
+
+sock.sin_family=AF_INET;
+sock.sin_addr.s_addr=htonl(INADDR_ANY);
+sock.sin_port=htons(RAYDIUM_NETWORK_PORT);
+ret=bind(raydium_network_socket,(struct sockaddr *)&sock,sizeof(sock));
+if(ret)
+    {
+    raydium_log("ERROR ! network: cannot open server socket (already used ?)");
+    perror("System");
+    return(0);
+    }
+
+raydium_log("network: server OK: waiting for clients (%i max) at udp port %i",RAYDIUM_NETWORK_MAX_CLIENTS,RAYDIUM_NETWORK_PORT);
+raydium_network_mode=RAYDIUM_NETWORK_MODE_SERVER;
+raydium_network_set_socket_block(0);
+return(1);
+}
+
+
+// will resolv "server" name
+char raydium_network_client_connect_to(char *server)
+{
+struct sockaddr_in sock;
+int ret,empty;
+char str[RAYDIUM_NETWORK_PACKET_SIZE];
+char type;
+struct hostent *server_addr;
+
+raydium_network_start=time(NULL);
+raydium_network_socket=socket(AF_INET,RAYDIUM_NETWORK_UDP,0);
+if(raydium_network_socket==-1)
+    {
+    raydium_log("ERROR ! network: cannot create client socket");
+    perror("System");
+    return(0);
+    }
+raydium_log("network: client socket created");
+
+
+server_addr = gethostbyname(server);
+if(!server_addr) 
+    {
+    raydium_log("ERROR ! DNS/resolv error with \"%s\"",server);
+    perror("System");
+    return(0);
+    }
+
+//inet_pton(AF_INET,server,&sock.sin_addr);
+memcpy((char*)(&(sock.sin_addr.s_addr)), server_addr->h_addr, server_addr->h_length);
+sock.sin_family=AF_INET;
+sock.sin_port=htons(RAYDIUM_NETWORK_PORT);
+
+ret=connect(raydium_network_socket,(struct sockaddr *)&sock,sizeof(sock));
+if(ret) 
+    {
+    raydium_log("ERROR ! local UDP socket error (contacting %s)",server);
+    perror("System");
+    return(0);
+    }
+raydium_log("network: connecting to %s and waiting UID...",server);
+raydium_network_set_socket_block(1);
+// needed now, because we use network_write
+raydium_network_mode=RAYDIUM_NETWORK_MODE_CLIENT;
+// we need to send request for uid (and send our name)
+strcpy(str+RAYDIUM_NETWORK_PACKET_OFFSET,raydium_network_name_local);
+raydium_network_write(NULL,-1,RAYDIUM_NETWORK_PACKET_REQUEST_UID,str);
+
+
+// probably needs timeouts, here ...
+if (raydium_network_read(&empty,&type,str)!=RAYDIUM_NETWORK_DATA_OK)
+    {
+    raydium_network_mode=RAYDIUM_NETWORK_MODE_NONE;
+    raydium_log("ERROR ! network: cannot connect to server %s",server);
+    perror("System");
+    return(0);
+    }
+
+if(type==RAYDIUM_NETWORK_PACKET_ATTRIB_UID)
+    {
+    raydium_network_uid=str[RAYDIUM_NETWORK_PACKET_OFFSET];
+    raydium_log("network: accepted as client %i",raydium_network_uid);
+    raydium_network_set_socket_block(0);
+    return(1);
+    }
+
+if(type==RAYDIUM_NETWORK_PACKET_ERROR_NO_MORE_PLACE)
+    {
+    raydium_network_mode=RAYDIUM_NETWORK_MODE_NONE;
+    raydium_log("ERROR ! network: no more room (server said: %s)",str+RAYDIUM_NETWORK_PACKET_OFFSET);
+    return(0);
+    }
+
+raydium_network_mode=RAYDIUM_NETWORK_MODE_NONE;
+raydium_log("ERROR ! network: unknow server message type (%i). abort.",type);
+return(0);
+
+}
+
+char raydium_server_accept_new(struct sockaddr *from, char *name)
+{
+int socklen,i,n;
+char str[RAYDIUM_NETWORK_PACKET_SIZE];
+void (*f)(int);
+
+socklen=sizeof(struct sockaddr);
+
+ for(i=0,n=-1;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+  if(!raydium_network_client[i]) {n=i; break;}
+
+ if(n<0) 
+    { 
+    // no more room in this server
+    sprintf(str+RAYDIUM_NETWORK_PACKET_OFFSET,"Server limited to %i client(s)",RAYDIUM_NETWORK_MAX_CLIENTS);
+    raydium_network_write(from,-1,RAYDIUM_NETWORK_PACKET_ERROR_NO_MORE_PLACE,str);
+    return(0);
+    }
+ 
+ memcpy(&raydium_network_client_addr[n],from,sizeof(struct sockaddr));
+ raydium_network_client[n]=1;
+ time(&raydium_network_keepalive[n]); // first keepalive
+ strcpy(raydium_network_name[n],name);
+ raydium_netwok_queue_ack_delay_server[n]=raydium_timecall_clocks_per_sec; // 1sec default delay
+ 
+ raydium_log("network: client %i connected as %s"/*,inet_ntoa(from->sin_addr)*/,n,name);
+ 
+ /* send uid to client */
+ str[RAYDIUM_NETWORK_PACKET_OFFSET]=n;
+ raydium_network_write(from,-1,RAYDIUM_NETWORK_PACKET_ATTRIB_UID,str);
+
+ // OnConnect:
+ for(i=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+    if(i!=n && raydium_network_client[i])
+    {
+    strcpy(str+RAYDIUM_NETWORK_PACKET_OFFSET+1,raydium_network_name[i]);
+    str[RAYDIUM_NETWORK_PACKET_OFFSET]=i;
+    raydium_network_write(from,i,RAYDIUM_NETWORK_PACKET_INFO_NAME,str);
+    }
+ strcpy(str+RAYDIUM_NETWORK_PACKET_OFFSET+1,raydium_network_name[n]); // send name to all others...
+ str[RAYDIUM_NETWORK_PACKET_OFFSET]=n;
+ raydium_network_broadcast(RAYDIUM_NETWORK_PACKET_INFO_NAME,str);    
+ 
+ if(raydium_network_on_connect)
+    {
+    f=raydium_network_on_connect;
+    f(n);
+    }
+    
+ return(n);
+}
+
+void raydium_network_close(void)
+{
+close(raydium_network_socket);
+#ifdef WIN32
+WSACleanup();
+#endif
+}
+
+
+void raydium_network_internal_server_delays_dump(void)
+{
+int i;
+
+raydium_log("Network server delays:");
+for(i=0;i<RAYDIUM_NETWORK_MAX_CLIENTS;i++)
+         if(raydium_network_client[i])
+	    raydium_log("player %i : %.2f msec (%s)",
+		i,
+		raydium_netwok_queue_ack_delay_server[i]/(double)raydium_timecall_clocks_per_sec*1000,
+		raydium_network_name[i]);
+}
+
+void raydium_network_internal_dump(void)
+{
+time_t diff;
+diff=time(NULL)-raydium_network_start;
+raydium_log("Network stats:");
+raydium_log("Rx: %i byte(s) / Tx: %i bytes(s) / %.2f min",raydium_network_stat_rx,raydium_network_stat_tx,diff/60.f);
+raydium_log("Transfert rates: Rx: %.2f KB/s / Tx: %.2f KB/s",raydium_network_stat_rx/(float)diff/1024.f,raydium_network_stat_tx/(float)diff/1024.f);
+raydium_log("Packets (err): Tx: %i re-emitted, Rx: %i doubles",raydium_network_stat_reemitted,raydium_network_stat_double);
+raydium_log("Packets (err): Tx: %i erased or lost, bogus ACK: %i",raydium_network_stat_lost,raydium_network_stat_bogus_ack);
+}
Index: raydium/callback.c
===================================================================
--- raydium/callback.c	(revision 0)
+++ raydium/callback.c	(revision 1)
@@ -0,0 +1,64 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/callback.h"
+#endif 
+
+void raydium_osd_cursor_draw(void);
+void raydium_console_draw(void);
+void raydium_gui_draw(void);
+void raydium_osd_fade_callback(void);
+int  raydium_php_exec(char *);
+#ifdef ODE_SUPPORT
+void raydium_ode_network_read(void);
+#endif
+
+void raydium_callback_image(void)
+{
+raydium_timecall_callback();
+raydium_light_callback();
+raydium_particle_draw_all();
+raydium_particle_callback();
+raydium_osd_fade_callback();
+raydium_gui_draw();
+raydium_console_draw();
+raydium_osd_cursor_draw();
+raydium_joy_callback();
+raydium_sound_callback();
+#ifdef ODE_SUPPORT
+// 0hz ODE callback workaround
+raydium_ode_network_read();
+#endif
+}
+
+
+void raydium_callback_set(void)
+{
+if(raydium_window_mode==RAYDIUM_RENDERING_NONE)
+    return;
+glutReshapeFunc(&raydium_window_resize_callback);
+glutKeyboardFunc((void *)raydium_key_normal_callback);
+glutSpecialUpFunc((void *)raydium_key_special_up_callback);
+glutSpecialFunc((void *)raydium_key_special_callback);
+glutMotionFunc((void *)raydium_mouse_move_callback);
+glutPassiveMotionFunc((void *)raydium_mouse_move_callback);
+glutMouseFunc((void *)raydium_mouse_click_callback);
+}
+
+
+void raydium_callback(void (*loop) )
+{
+char autoexec[RAYDIUM_MAX_NAME_LEN];
+
+if(raydium_init_cli_option("autoexec2",autoexec))
+    raydium_php_exec(autoexec);
+glutDisplayFunc(loop);
+glutIdleFunc(loop);
+glutMainLoop();
+}
Index: raydium/parser.c
===================================================================
--- raydium/parser.c	(revision 0)
+++ raydium/parser.c	(revision 1)
@@ -0,0 +1,150 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+#ifndef DONT_INCLUDE_HEADERS
+#include "index.h"
+#else
+#include "headers/parser.h"
+#endif
+
+// Trims string (left and right), removing ' ' and '\n' and ';'
+void raydium_parser_trim(char *org)
+{
+int i;
+char temp[RAYDIUM_MAX_NAME_LEN];
+strcpy(temp,org);
+
+for(i=0;i<strlen(temp);i++)
+    if(temp[i]!=' ')
+	break;
+strcpy(org,temp+i); // heading spaces: ok
+
+for(i=strlen(org);i>=0;i--)
+    if(org[i]!=' ' && org[i]!='\n' && org[i]!=0 && org[i]!=';')
+	break;
+
+org[i+1]=0; // tailing chars: ok
+}
+
+char raydium_parser_isdata(char *str)
+{
+if(strlen(str)==0) return 0;
+if(str[0]=='/' && str[1]=='/') return 0;
+return 1;
+}
+
+
+char raydium_parser_cut(char *str,char *part1, char *part2, char separator)
+{
+// strstr, strok and strsep aren't that good ;)
+int i;
+int len;
+
+len=strlen(str);
+
+for(i=0;i<len;i++)
+    if(str[i]==separator)
+	break;
+
+if(i==len) return 0; // not found
+
+strcpy(part2,str+i+1);
+strcpy(part1,str);
+part1[i]=0;
+raydium_parser_trim(part1);
+raydium_parser_trim(part2);
+return 1;
+}
+
+void raydium_parser_replace(char *str,char what, char with)
+{
+int len,i;
+
+len=strlen(str);
+
+for(i=0;i<len;i++)
+    if(str[i]==what)
+	str[i]=with;
+
+}
+
+
+int raydium_parser_read(char *var, char *val_s, GLfloat *val_f, int *size, FILE *fp)
+{
+char str[RAYDIUM_MAX_NAME_LEN];
+char *ret;
+
+do {
+str[0]=0;
+ret=fgets(str,RAYDIUM_MAX_NAME_LEN-1,fp);
+raydium_parser_trim(str);
+} while(ret!=NULL && !raydium_parser_isdata(str));
+
+if(ret==NULL)
+    {
+    *size=0;
+    return RAYDIUM_PARSER_TYPE_EOF;
+    }
+
+raydium_parser_cut(str,var,val_s,'=');
+
+if(val_s[0]=='[') // is raw data (RAYDIUM_MAX_NAME_LEN limit !)
+    {
+    int offset=0;
+    int len;
+    
+    do {
+	str[0]=0;
+	ret=fgets(str,RAYDIUM_MAX_NAME_LEN-1,fp);
+	if(ret==NULL)
+	    break;
+	if(strlen(str)>=1 && str[0]==']') // bad idea, but ... no time for now
+	    break;
+	len=strlen(str);
+	memcpy(val_s+offset,str,len);
+	offset+=len;
+    } while(1);
+    
+    val_s[offset]=0;
+    *size=offset;
+    return RAYDIUM_PARSER_TYPE_RAWDATA;
+    }
+
+if(val_s[0]=='"') // is a string
+    {
+    raydium_parser_replace(val_s,'"',' ');    
+    raydium_parser_trim(val_s);
+    *size=strlen(val_s);
+    return RAYDIUM_PARSER_TYPE_STRING;
+    }
+
+if(val_s[0]=='{') // is a float array
+    {
+    char extracted[RAYDIUM_MAX_NAME_LEN];
+    char next[RAYDIUM_MAX_NAME_LEN];
+    
+    *size=0;
+    raydium_parser_replace(val_s,'{',' ');
+    raydium_parser_trim(val_s);
+
+    while(raydium_parser_cut(val_s,extracted,next,','))
+	{
+	val_f[*size]=atof(extracted);
+	(*size)++;
+	strcpy(val_s,next);
+	}
+    val_f[*size]=atof(next);
+    (*size)++;
+    val_s[0]=0;
+    return RAYDIUM_PARSER_TYPE_FLOAT;    
+    }
+
+// is a float
+*val_f=atof(val_s);
+*size=1;
+return RAYDIUM_PARSER_TYPE_FLOAT;    
+
+}
Index: raydium/glarb.h
===================================================================
--- raydium/glarb.h	(revision 0)
+++ raydium/glarb.h	(revision 1)
@@ -0,0 +1,40 @@
+/*
+    Raydium - CQFD Corp.
+    http://raydium.cqfd-corp.org
+    License: GPL - GNU General Public License, see "gpl.txt" file.
+*/
+
+/* OpenGL ARB ext (only needed) for WIN32 and OpenGL <= 1.1 */
+
+// We need a few #ifdef here, since newer versions of DevCPP
+// seems to provides GL > 1.1
+
+#define GL_ACTIVE_TEXTURE_ARB               0x84E0
+#define GL_MAX_TEXTURE_UNITS_ARB	    0x84E2
+#define GL_TEXTURE0_ARB                     0x84C0
+#define GL_TEXTURE1_ARB                     0x84C1
+#define GL_TEXTURE2_ARB                     0x84C2
+#define GL_TEXTURE3_ARB                     0x84C3
+#define GL_TEXTURE4_ARB                     0x84C4
+#define GL_TEXTURE5_ARB                     0x84C5
+#define GL_TEXTURE6_ARB                     0x84C6
+#define GL_TEXTURE7_ARB                     0x84C7
+#define GL_TEXTURE8_ARB                     0x84C8
+#define GL_COMBINE_EXT			    0x8570
+#define GL_RGB_SCALE_EXT                    0x8573
+#define GL_LIGHT_MODEL_COLOR_CONTROL        0x81F8
+#define GL_SEPARATE_SPECULAR_COLOR          0x81FA
+#define GL_CLAMP_TO_EDGE		    0x812F
+
+// You can comment thoses two lines if any problem
+typedef void (APIENTRY * PFNGLACTIVETEXTUREARBPROC) (GLenum texture);
+typedef void (APIENTRY * PFNGLMULTITEXCOORD2FARBPROC) (GLenum texture, GLfloat s, GLfloat t);
+
+PFNGLACTIVETEXTUREARBPROC       glActiveTextureARB     = NULL;
+PFNGLMULTITEXCOORD2FARBPROC     glMultiTexCoord2fARB   = NULL;
+
+void raydium_arb_win32_init(void)
+{
+glActiveTextureARB=(PFNGLACTIVETEXTUREARBPROC) 		wglGetProcAddress( "glActiveTextureARB" );
+glMultiTexCoord2fARB=(PFNGLMULTITEXCOORD2FARBPROC)   	wglGetProcAddress( "glMultiTexCoord2fARB" );
+}
Index: Makefile
===================================================================
--- Makefile	(revision 0)
+++ Makefile	(revision 1)
@@ -0,0 +1,300 @@
+## auto-generated Makefile
+EXT_H = .h
+ROOT = ./
+RAYDIUM_DIR = raydium/
+HEADERS_DIR = raydium/headers/
+COMPILE_DIR = raydium/compile/
+CC = gcc
+AR = ar
+RANLIB = ranlib
+LOG_FILE = compile.log
+SYSTEM_LIBS =  -lGL -lglut -lGLU -lm -lopenal -lvorbis -lvorbisfile -logg -lresolv -lcrypt -lz
+OTHER_LIBS =  ode/lib/libode.a php/libs/libphp4.a
+INCLUDE_PATH =  -Iode/include/ -Iphp/ -Iphp/include -Iphp/main/ -Iphp/Zend -Iphp/TSRM
+LIBS_PATH =  -L/usr/X11R6/lib/
+
+CFLAGS=-Wall
+COMPILE_OPTIONS=-g
+LDFLAGS=
+LINKING_OPTIONS=-Wl,-soname,libraydium.so.0
+AR_OPTIONS=
+
+VER=0.0
+VER1=0
+VER2=0.0
+
+
+default: all
+
+all: libraydium.a libraydium.so
+	@echo "Files created: $+"
+
+help:
+	@echo "Help compiling raydium"
+	@echo "	make help	this"
+	@echo "	make default	make all"
+	@echo "	make all	create libraries"
+	@echo "	make clean	remove compilation objects and libraries"
+	@echo "	make clean_f	remove without confirmation"
+
+################################################################################
+# Create libraries
+################################################################################
+
+
+libraydium.so.0.0:  raydium/compile/background.o raydium/compile/callback.o raydium/compile/camera.o raydium/compile/capture.o raydium/compile/clear.o raydium/compile/console.o raydium/compile/file.o raydium/compile/fog.o raydium/compile/init.o raydium/compile/internal.o raydium/compile/joy.o raydium/compile/key.o raydium/compile/land.o raydium/compile/light.o raydium/compile/log.o raydium/compile/main.o raydium/compile/mouse.o raydium/compile/network.o raydium/compile/normal.o raydium/compile/object.o raydium/compile/ode.o raydium/compile/osd.o raydium/compile/parser.o raydium/compile/particle2.o raydium/compile/php.o raydium/compile/profile.o raydium/compile/random.o raydium/compile/rayphp.o raydium/compile/register.o raydium/compile/render.o raydium/compile/signal.o raydium/compile/sky.o raydium/compile/sound.o raydium/compile/texture.o raydium/compile/timecall.o raydium/compile/trigo.o raydium/compile/vertex.o raydium/compile/window.o raydium/compile/reg_api.o raydium/compile/gui.o
+	@echo "Creating $@" >> $(LOG_FILE)
+	gcc $(LDFLAGS) $(LINKING_OPTIONS) -o $@ -shared $+ $(LIBS_PATH) $(OTHER_LIBS) $(SYSTEM_LIBS)
+	@echo "File created: $@"
+
+libraydium.so.0: libraydium.so.0.0
+	ln -s $< $@ || true
+
+libraydium.so: libraydium.so.0
+	ln -s $< $@ || true
+
+libraydium.a.0.0:  raydium/compile/background.o raydium/compile/callback.o raydium/compile/camera.o raydium/compile/capture.o raydium/compile/clear.o raydium/compile/console.o raydium/compile/file.o raydium/compile/fog.o raydium/compile/init.o raydium/compile/internal.o raydium/compile/joy.o raydium/compile/key.o raydium/compile/land.o raydium/compile/light.o raydium/compile/log.o raydium/compile/main.o raydium/compile/mouse.o raydium/compile/network.o raydium/compile/normal.o raydium/compile/object.o raydium/compile/ode.o raydium/compile/osd.o raydium/compile/parser.o raydium/compile/particle2.o raydium/compile/php.o raydium/compile/profile.o raydium/compile/random.o raydium/compile/rayphp.o raydium/compile/register.o raydium/compile/render.o raydium/compile/signal.o raydium/compile/sky.o raydium/compile/sound.o raydium/compile/texture.o raydium/compile/timecall.o raydium/compile/trigo.o raydium/compile/vertex.o raydium/compile/window.o raydium/compile/reg_api.o raydium/compile/gui.o
+	$(AR) $(AR_OPTIONS) -crv $@ $+
+	$(RANLIB) $@ || true
+	@echo "File created: $@"
+
+libraydium.a.0: libraydium.a.0.0
+	ln -s $< $@ || true
+
+libraydium.a: libraydium.a.0
+	ln -s $< $@ || true
+
+
+################################################################################
+# Other rules
+################################################################################
+
+
+headers:  raydium/headers/background.h raydium/headers/callback.h raydium/headers/camera.h raydium/headers/capture.h raydium/headers/clear.h raydium/headers/console.h raydium/headers/file.h raydium/headers/fog.h raydium/headers/init.h raydium/headers/internal.h raydium/headers/joy.h raydium/headers/key.h raydium/headers/land.h raydium/headers/light.h raydium/headers/log.h raydium/headers/main.h raydium/headers/mouse.h raydium/headers/network.h raydium/headers/normal.h raydium/headers/object.h raydium/headers/ode.h raydium/headers/osd.h raydium/headers/parser.h raydium/headers/particle2.h raydium/headers/php.h raydium/headers/profile.h raydium/headers/random.h raydium/headers/rayphp.h raydium/headers/register.h raydium/headers/render.h raydium/headers/signal.h raydium/headers/sky.h raydium/headers/sound.h raydium/headers/texture.h raydium/headers/timecall.h raydium/headers/trigo.h raydium/headers/vertex.h raydium/headers/window.h raydium/headers/reg_api.h raydium/headers/gui.h
+	touch $@
+	@echo "Headers found: $+"
+
+compile:  raydium/compile/background.o raydium/compile/callback.o raydium/compile/camera.o raydium/compile/capture.o raydium/compile/clear.o raydium/compile/console.o raydium/compile/file.o raydium/compile/fog.o raydium/compile/init.o raydium/compile/internal.o raydium/compile/joy.o raydium/compile/key.o raydium/compile/land.o raydium/compile/light.o raydium/compile/log.o raydium/compile/main.o raydium/compile/mouse.o raydium/compile/network.o raydium/compile/normal.o raydium/compile/object.o raydium/compile/ode.o raydium/compile/osd.o raydium/compile/parser.o raydium/compile/particle2.o raydium/compile/php.o raydium/compile/profile.o raydium/compile/random.o raydium/compile/rayphp.o raydium/compile/register.o raydium/compile/render.o raydium/compile/signal.o raydium/compile/sky.o raydium/compile/sound.o raydium/compile/texture.o raydium/compile/timecall.o raydium/compile/trigo.o raydium/compile/vertex.o raydium/compile/window.o raydium/headers/reg_api.o raydium/headers/gui.o
+	touch $@
+	@echo "Files created: $+"
+
+
+################################################################################
+# Cleaning rules
+################################################################################
+
+
+clean:
+	rm -ri $(COMPILE_DIR)	|| true
+	rm -i libraydium.so*	|| true
+	rm -i libraydium.a*	|| true
+
+clean_f:
+	rm -r $(COMPILE_DIR)	|| true
+	rm libraydium.so*	|| true
+	rm libraydium.a*	|| true
+
+
+################################################################################
+# All files
+################################################################################
+
+raydium/compile/background.o: raydium/background.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/callback.o: raydium/callback.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/camera.o: raydium/camera.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/capture.o: raydium/capture.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/clear.o: raydium/clear.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/console.o: raydium/console.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/file.o: raydium/file.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/fog.o: raydium/fog.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/init.o: raydium/init.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/internal.o: raydium/internal.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/joy.o: raydium/joy.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/key.o: raydium/key.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/land.o: raydium/land.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/light.o: raydium/light.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/log.o: raydium/log.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/main.o: raydium/main.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/mouse.o: raydium/mouse.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/network.o: raydium/network.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/normal.o: raydium/normal.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/object.o: raydium/object.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/ode.o: raydium/ode.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/osd.o: raydium/osd.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/parser.o: raydium/parser.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/particle2.o: raydium/particle2.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/php.o: raydium/php.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/profile.o: raydium/profile.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/random.o: raydium/random.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/rayphp.o: raydium/rayphp.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/register.o: raydium/register.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/render.o: raydium/render.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/signal.o: raydium/signal.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/sky.o: raydium/sky.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/sound.o: raydium/sound.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/texture.o: raydium/texture.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/timecall.o: raydium/timecall.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/trigo.o: raydium/trigo.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/vertex.o: raydium/vertex.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/window.o: raydium/window.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/reg_api.o: raydium/reg_api.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
+
+raydium/compile/gui.o: raydium/gui.c headers
+	@mkdir -p $(COMPILE_DIR)
+	@echo "Creating: $@"
+	$(CC) $(COMPILE_OPTIONS) $(CFLAGS) -o $@ -c $< $(INCLUDE_PATH) 2>> $(LOG_FILE)
Index: skydiver.c
===================================================================
--- skydiver.c	(revision 0)
+++ skydiver.c	(revision 1)
@@ -0,0 +1,739 @@
+// TODO:
+// - Blood (red particules)
+// - Update this game to use all last Raydium ODE integrations
+
+/*
+    Xfennec - CQFD Corp.
+    NewSkyDiver (Atari "Sky Diver" clone)
+    CQFD Corp.
+*/
+
+char *version="version 0.96";
+
+//#define ODE_MANUAL_CALLBACK
+
+#include "raydium/index.c"
+
+
+#define DEFAULT_ZOOM		20
+#define DEFAULT_CAMX		0
+#define DEFAULT_CAMY		-100
+#define DEFAULT_CAMZ		5
+#define PLANE_PLACE		30
+#define PARACHUTE_PORTANCE 	0.1
+#define MAX_TOUCH_TIME		5
+
+
+GLfloat sun[]={1.0,0.9,0.5,1.0};
+GLfloat amb[]={1.0,0.0,0.0,1.0};
+GLfloat tmp2[]={1.0,1.0,1.0,1.0};
+GLfloat zero[]={0.0,0.0,0.0,0.0};
+
+GLfloat camx=DEFAULT_CAMX;
+GLfloat camy=DEFAULT_CAMY;
+GLfloat camz=DEFAULT_CAMZ;
+GLfloat camzoom=DEFAULT_ZOOM;
+dReal wind;
+dReal move=0;
+char para_open;
+char touching;
+int touching_steps;
+float fly_time;
+float dist_from_center;
+int breaked_bones;
+int best_score=0;
+int plane_touched;
+char cam[RAYDIUM_MAX_NAME_LEN];
+GLfloat last_frame_step;
+char tips[6][128]={"^dPress ^fSPACE^d to jump, ^fBACKSPACE^d to restart a game, ^fF1^d for dynamic view.","^cPress ^fSPACE^c to open parachute !","^aUse ^fLEFT^a and ^fRIGHT^a arrows (or joystick/joypad) to move ...","^eUse ^fBACKSPACE^e to try again !","^dBye ! ...",""};
+char player_name[RAYDIUM_MAX_NAME_LEN];
+int tip=0;
+dReal score_timer;
+char fp_view=-1;
+
+#define GAME_PART_PLANE    0
+#define GAME_PART_JUMP     1
+#define GAME_PART_PARA     2
+#define GAME_PART_TOUCHED  3
+#define GAME_PART_SCORE	   4
+#define GAME_PART_QUIT     5
+int game_part=-1;
+
+int S_plane;
+int S_hurt[4];
+int S_plane_fall;
+
+// type_* are used as address tag
+char type_lander;
+char type_para;
+char type_plane;
+
+int music_change(char *newfile)
+{
+raydium_register_variable(newfile,RAYDIUM_REGISTER_STR,"raydium_ogg_file");
+raydium_php_exec("playlist.php");
+raydium_register_variable_unregister_last();
+return strlen(newfile)!=0;
+}
+
+
+int get_score(char growing_fx)
+{
+// - Scoring (breaked bones, flying time, lander-touching time, wind)
+GLfloat score,tmp,w;
+
+w=wind;
+
+if(breaked_bones) return 0;
+if(!touching_steps) return 0;
+if(w>0) w*=2; // positive wind is harder
+score=touching_steps*raydium_trigo_abs(w); // 2000 max
+
+tmp=3.f-fly_time; // fly time
+if(tmp<0) tmp=0;
+score+=400*tmp;
+
+tmp=0.5f-dist_from_center; // fly time
+if(tmp<0) tmp=0;
+score+=4000*tmp;
+
+tmp=score_timer/2;
+if(tmp>1 || !growing_fx) tmp=1;
+if(score>best_score) best_score=score;
+return score*tmp;
+}
+
+
+void post_score(void)
+{
+int score=get_score(0);
+char lversion[RAYDIUM_MAX_NAME_LEN];
+
+if(!score) return;
+
+strcpy(lversion,version); // since PHP will write to variables ..
+
+raydium_register_variable(&wind,RAYDIUM_REGISTER_FLOAT,"wind");
+raydium_register_variable(&breaked_bones,RAYDIUM_REGISTER_INT,"breaked_bones");
+raydium_register_variable(&fly_time,RAYDIUM_REGISTER_FLOAT,"fly_time");
+raydium_register_variable(&touching_steps,RAYDIUM_REGISTER_INT,"touching_steps");
+raydium_register_variable(&score,RAYDIUM_REGISTER_INT,"score");
+raydium_register_variable(player_name,RAYDIUM_REGISTER_STR,"name");
+raydium_register_variable(lversion,RAYDIUM_REGISTER_STR,"version");
+
+raydium_php_exec("score.php");
+
+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();
+}
+
+
+void play_hurt_sound(void)
+{
+raydium_sound_SourcePlay(S_hurt[rand()%4]);
+}
+
+void frame_step(GLfloat step)
+{
+last_frame_step=step;
+if(game_part==GAME_PART_SCORE)
+    score_timer+=(step/60);
+}
+
+void bone_break(int j)
+{
+play_hurt_sound();
+breaked_bones++;
+}
+
+void camera(GLfloat px, GLfloat py, GLfloat pz, GLfloat lx, GLfloat ly, GLfloat lz, GLfloat zoom)
+{
+#define SLOW_FACT 30
+static GLfloat opx,opy,opz;
+static GLfloat olx,oly,olz;
+static GLfloat ozoom=DEFAULT_ZOOM;
+ALfloat pos[3];
+ALfloat or[6];
+
+//raydium_log("<%f (asked=%f real=%f step=%f)",ozoom,zoom,raydium_projection_fov,last_frame_step);
+
+opx+=(px-opx)/SLOW_FACT*last_frame_step;
+opy+=(py-opy)/SLOW_FACT*last_frame_step;
+opz+=(pz-opz)/SLOW_FACT*last_frame_step;
+olx+=(lx-olx)/SLOW_FACT*last_frame_step;
+oly+=(ly-oly)/SLOW_FACT*last_frame_step;
+olz+=(lz-olz)/SLOW_FACT*last_frame_step;
+ozoom+=(zoom-ozoom)/SLOW_FACT*last_frame_step;
+
+//raydium_log(">%f",ozoom);
+
+if(ozoom!=raydium_projection_fov)
+    {
+    raydium_projection_fov=ozoom;
+    raydium_window_view_update();
+    }
+
+raydium_camera_look_at(opx,opy,opz,olx,oly,olz);
+pos[0]=opx;
+pos[1]=opy;
+pos[2]=opz;
+raydium_sound_SetListenerPos(pos);
+or[0]=olx-opx;
+or[1]=oly-opy;
+or[2]=olz-opz;
+or[3]=or[4]=0;
+or[5]=1;
+raydium_sound_SetListenerOr(or);
+}
+
+
+char collide(int e1, int e2, dContact *n)
+{
+char *c1,*c2;
+
+c1=raydium_ode_element_data_get(e1);
+c2=raydium_ode_element_data_get(e2);
+
+    if(((c1==&type_para && c2==&type_lander) || 
+        (c2==&type_para && c1==&type_lander)  ) && game_part<GAME_PART_SCORE)
+	{
+	touching=1;
+	}
+
+if((c1==&type_para || c2==&type_para) && (game_part==GAME_PART_PARA || game_part==GAME_PART_JUMP)) 
+{
+dReal *pos;
+para_open=0;
+game_part=GAME_PART_TOUCHED;
+pos=raydium_ode_element_pos_get_name("body");
+dist_from_center=raydium_trigo_abs(pos[0]);
+}
+
+if(c1==&type_plane || c2==&type_plane)
+    {
+     if(!plane_touched)
+        {
+	raydium_sound_SourceStop(S_plane);
+	play_hurt_sound();
+	plane_touched++;
+	}
+    }
+
+return 1;
+}
+
+void step(void)
+{
+
+if(touching) touching_steps++;
+touching=0;
+// if parachute is open... :
+if(para_open)
+ raydium_ode_object_addforce_name_3f("RAGDOLL",move+(wind*0.1),0,PARACHUTE_PORTANCE);
+
+if(game_part>=GAME_PART_JUMP && game_part<GAME_PART_TOUCHED)
+    fly_time+=(1/400.f);
+
+{
+int i;
+dJointID joint;
+
+i=raydium_ode_joint_find("shoulder");
+if(i<0) 
+    {
+    //raydium_log("not found");
+    return;
+    }
+joint=raydium_ode_joint[i].joint;
+if(raydium_key[GLUT_KEY_F2])
+    {
+    dJointSetHingeParam(joint,dParamVel,10);
+    dJointSetHingeParam(joint,dParamFMax,0.2);
+    }
+else
+    {
+    dJointSetHingeParam(joint,dParamVel, 0);
+    dJointSetHingeParam(joint,dParamFMax,0);
+    }
+}
+
+}
+
+void create_landing(dReal px, dReal py, dReal pz)
+{
+int a;
+a=raydium_ode_object_create("LANDER");
+  raydium_ode_object_box_add("lander",a,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STATIC,0,"landing.tri");
+  raydium_ode_element_move_name_3f("lander",pz,py,pz);
+  raydium_ode_element_data_set_name("lander",&type_lander);
+}
+
+
+void create_plane(int num)
+{
+int a;
+char obj[128];
+char ele[128];
+
+sprintf(obj,"PLANE %i",num);
+sprintf(ele,"plane %i",num);
+a=raydium_ode_object_create(obj);
+  raydium_ode_object_box_add(ele,a,1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"plane.tri");
+  raydium_ode_element_move_name_3f(ele,-PLANE_PLACE,0,10);
+  raydium_ode_element_data_set_name(ele,&type_plane);
+  // hey ... we shouldn't call ODE directly !
+  dBodyAddForce(raydium_ode_element[raydium_ode_element_find(ele)].body,500,0,0);
+  dBodySetGravityMode(raydium_ode_element[raydium_ode_element_find(ele)].body,0);
+  raydium_sound_SourcePlay(S_plane);
+}
+
+
+void create_para(char *plane)
+{
+#define BONE_BREAK 40
+dReal *pos;
+dReal mypos[3];
+int a;
+
+    a=raydium_ode_object_create("RAGDOLL");
+    raydium_ode_object_sphere_add("head",a,0.1,RAYDIUM_ODE_AUTODETECT,RAYDIUM_ODE_STANDARD,0,"p_head.tri");
+    raydium_ode_element_data_set_name("head",&type_para);
+    raydium_ode_element_move_name_3f("head",5,0,1);
+    
+    raydium_ode_object_box_add("body",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_body.tri");
+    raydium_ode_element_data_set_name("body",&type_para);
+    raydium_ode_element_move_name_3f("body",5,0,0.66);
+    raydium_ode_joint_attach_hinge_name("neck","body","head",5,0,0.95,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("neck",-1,1);
+    raydium_ode_joint_break_force_name("neck",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("neck",bone_break);
+
+    raydium_ode_object_box_add("u_leg",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_u_leg.tri");
+    raydium_ode_element_data_set_name("u_leg",&type_para);
+    raydium_ode_element_move_name_3f("u_leg",4.9,0,0.26);
+    raydium_ode_element_rotate_name_3f("u_leg",0,-0.2,0);
+    raydium_ode_joint_attach_hinge_name("femur","body","u_leg",4.9,0,0.42,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("femur",-1,1);
+    raydium_ode_joint_break_force_name("femur",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("femur",bone_break);
+
+    raydium_ode_object_box_add("u_leg2",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_u_leg2.tri");
+    raydium_ode_element_data_set_name("u_leg2",&type_para);
+    raydium_ode_element_move_name_3f("u_leg2",5.1,0,0.26);
+    raydium_ode_element_rotate_name_3f("u_leg2",0,0.2,0);
+    raydium_ode_joint_attach_hinge_name("femur2","body","u_leg2",5.1,0,0.42,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("femur2",-1,1);
+    raydium_ode_joint_break_force_name("femur2",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("femur2",bone_break);
+
+
+    raydium_ode_object_box_add("l_leg",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_l_leg.tri");
+    raydium_ode_element_data_set_name("l_leg",&type_para);
+    raydium_ode_element_move_name_3f("l_leg",4.82,-0.02,-0.14);
+    raydium_ode_element_rotate_name_3f("l_leg",0,-0.1,0);
+    raydium_ode_joint_attach_hinge_name("knee","u_leg","l_leg",4.85,0,0.05,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("knee",-2,0);
+    raydium_ode_joint_break_force_name("knee",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("knee",bone_break);
+
+    raydium_ode_object_box_add("l_leg2",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_l_leg2.tri");
+    raydium_ode_element_data_set_name("l_leg2",&type_para);
+    raydium_ode_element_move_name_3f("l_leg2",5.18,-0.02,-0.14);
+    raydium_ode_element_rotate_name_3f("l_leg2",0,0.1,0);
+    raydium_ode_joint_attach_hinge_name("knee2","u_leg2","l_leg2",5.15,0,0.05,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("knee2",-2,0);
+    raydium_ode_joint_break_force_name("knee2",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("knee2",bone_break);
+
+    raydium_ode_object_box_add("u_arm",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_u_arm.tri");
+    raydium_ode_element_data_set_name("u_arm",&type_para);
+    raydium_ode_element_move_name_3f("u_arm",4.83,0,0.73);
+    raydium_ode_element_rotate_name_3f("u_arm",-0.1,-0.1,0);
+    raydium_ode_joint_attach_hinge_name("shoulder","body","u_arm",4.85,0,0.84,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_break_force_name("shoulder",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("shoulder",bone_break);
+//    raydium_ode_joint_hinge_limits_name("shoulder",-2,2);
+
+    raydium_ode_object_box_add("u_arm2",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_u_arm2.tri");
+    raydium_ode_element_data_set_name("u_arm2",&type_para);
+    raydium_ode_element_move_name_3f("u_arm2",5.17,0,0.73);
+    raydium_ode_element_rotate_name_3f("u_arm2",-0.1,0.1,0);
+    raydium_ode_joint_attach_hinge_name("shoulder2","body","u_arm2",5.15,0,0.84,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_break_force_name("shoulder2",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("shoulder2",bone_break);
+//    raydium_ode_joint_hinge_limits_name("shoulder2",-2,2);
+
+    raydium_ode_object_box_add("l_arm",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_l_arm.tri");
+    raydium_ode_element_data_set_name("l_arm",&type_para);
+    raydium_ode_element_move_name_3f("l_arm",4.80,-0.05,0.45);
+    raydium_ode_element_rotate_name_3f("l_arm",0.3,0,0);
+    raydium_ode_joint_attach_hinge_name("elbow","u_arm","l_arm",4.80,0,0.60,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("elbow",0,2);
+    raydium_ode_joint_break_force_name("elbow",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("elbow",bone_break);
+    
+    raydium_ode_object_box_add("l_arm2",a,0.1,RAYDIUM_ODE_AUTODETECT,0,0,RAYDIUM_ODE_STANDARD,0,"p_l_arm2.tri");
+    raydium_ode_element_data_set_name("l_arm2",&type_para);
+    raydium_ode_element_move_name_3f("l_arm2",5.20,-0.05,0.45);
+    raydium_ode_element_rotate_name_3f("l_arm2",0.3,0,0);
+    raydium_ode_joint_attach_hinge_name("elbow2","u_arm2","l_arm2",5.20,0,0.60,RAYDIUM_ODE_JOINT_AXE_X);
+    raydium_ode_joint_hinge_limits_name("elbow2",0,2);
+    raydium_ode_joint_break_force_name("elbow2",BONE_BREAK);
+    raydium_ode_joint_delete_callback_name("elbow2",bone_break);
+
+    pos=raydium_ode_element_pos_get_name(plane);
+    memcpy(mypos,pos,sizeof(dReal)*3);
+    mypos[2]-=2;
+    raydium_ode_object_move_name("RAGDOLL",mypos);
+    pos=(dReal *)dBodyGetLinearVel(raydium_ode_element[raydium_ode_element_find(plane)].body);
+    raydium_ode_object_linearvelocity_set_name("RAGDOLL",pos);
+}
+
+
+void create_game(void)
+{
+if(game_part==GAME_PART_SCORE) post_score();
+raydium_ode_object_delete_name("RAGDOLL");
+raydium_ode_object_delete_name("PLANE 1");
+raydium_ode_object_delete_name("LANDER");
+para_open=0;
+touching=0;
+touching_steps=0;
+if(game_part!=GAME_PART_PLANE)
+    wind=raydium_random_neg_pos_1();
+game_part=GAME_PART_PLANE;
+fly_time=0;
+dist_from_center=0;
+breaked_bones=0;
+plane_touched=0;
+create_plane(1);
+create_landing(0,0,0);
+}
+
+void name_change(char *name)
+{
+name[strlen(name)-1]=0;
+strcpy(player_name,name);
+raydium_log("Name changed to \"%s\"",player_name);
+raydium_console_event();
+}
+
+
+void display(void)
+{
+static GLfloat angle;
+dReal *tmp;
+
+angle+=last_frame_step/5;
+
+raydium_joy_key_emul();
+
+if(raydium_key_last==1027) 
+    game_part=GAME_PART_QUIT;
+
+if(raydium_key_last==1)
+    fp_view*=-1;
+
+//if(raydium_key[GLUT_KEY_F1]) camzoom/=(1.04);
+//if(raydium_key[GLUT_KEY_F2]) camzoom*=(1.04);
+
+move=raydium_joy_x*0.1;
+
+if(raydium_key_last==1008 && game_part!=GAME_PART_SCORE)
+    {
+    game_part=GAME_PART_SCORE;
+    score_timer=0;
+    raydium_key_last=0; // disable the following test
+    raydium_sound_SourcePlay(S_plane_fall);
+    }
+
+if((score_timer>30 || raydium_key_last==1008) && game_part==GAME_PART_SCORE)
+    create_game();
+
+if(raydium_key_last==1032)
+    {
+    if(game_part==GAME_PART_PLANE)
+	{
+	create_para("plane 1");
+	game_part=GAME_PART_JUMP;
+	}
+    else	
+    if(game_part==GAME_PART_JUMP)
+	{
+	para_open=1;
+	game_part=GAME_PART_PARA;
+	}
+    }
+
+if(touching_steps>=400*MAX_TOUCH_TIME && game_part==GAME_PART_TOUCHED)
+    {
+    touching_steps=400*MAX_TOUCH_TIME;
+    game_part=GAME_PART_SCORE;
+    raydium_sound_SourcePlay(S_plane_fall);
+    score_timer=0;
+    }
+
+
+raydium_background_color_change(sun[0],sun[1],sun[2],sun[3]);
+
+raydium_light_position[0][0]=50;
+raydium_light_position[0][1]=-150;
+raydium_light_position[0][2]=200;
+raydium_light_position[0][3]=1.0;
+
+raydium_clear_frame();
+
+switch(game_part)
+    {
+    case GAME_PART_PLANE:
+        camx=DEFAULT_CAMX;
+        camy=DEFAULT_CAMY;
+        camz=DEFAULT_CAMZ;
+	camzoom=20;
+	strcpy(cam,"ground");
+	tip=0;
+	break;
+    case GAME_PART_JUMP:
+	camzoom=5;
+	strcpy(cam,"body");
+	tip=1;
+	break;	
+    case GAME_PART_PARA:
+	camzoom=15;
+	strcpy(cam,"body");
+	tip=2;
+	break;
+    case GAME_PART_TOUCHED:
+	camzoom=6;
+	camz=50;
+	camx=raydium_trigo_cos(angle)*100;
+	camy=raydium_trigo_sin(angle)*100;
+	strcpy(cam,"head");
+	tip=3;
+	break;	
+    case GAME_PART_QUIT:
+	camx=camy=1;
+	camz+=(camz*last_frame_step)/60;
+	camzoom=70;
+	strcpy(cam,"ground");
+	tip=4;
+	if(camz>500) exit(0);
+	break;    
+    case GAME_PART_SCORE:
+	if(raydium_ode_object_find("PLANE 1")<0)
+	    create_plane(1);
+	dBodySetGravityMode(raydium_ode_element[raydium_ode_element_find("plane 1")].body,1);
+	camzoom=4;
+	camz=30;
+	camx=raydium_trigo_cos(-angle)*200;
+	camy=raydium_trigo_sin(-angle)*200;
+	strcpy(cam,"plane 1");
+	tip=3;
+	break;
+    }
+
+
+// test if plane is not too far ... : (and adjust his sound, too)
+if(raydium_ode_object_find("PLANE 1")>=0 && game_part<GAME_PART_SCORE)
+    {
+    ALfloat pos[3];
+    tmp=raydium_ode_element_pos_get_name("plane 1");
+    pos[0]=tmp[0];
+    pos[1]=tmp[1];
+    pos[2]=tmp[2];
+    raydium_sound_SetSourcePos(S_plane,pos);
+    raydium_sound_SetSourcePos(S_plane_fall,pos);
+    if(tmp[0]>250)
+	{
+	score_timer=0;
+	game_part=GAME_PART_SCORE;
+	return;
+	}
+    }
+
+
+if(raydium_ode_element_find(cam)<0)
+    {
+    //raydium_log("Camera cannot find \"%s\", now looking ground...",cam);
+    strcpy(cam,"ground");
+    }
+
+// Test is "First Person" view is used
+if(fp_view>0 && game_part<GAME_PART_SCORE)
+{
+    int from,to;
+    dReal *from_p,*to_p;
+
+    raydium_projection_near=0.1;
+    raydium_projection_far=1000;
+
+    from=raydium_ode_element_find("body");
+    to=raydium_ode_element_find("ground");
+    if(from<0) from=raydium_ode_element_find("plane 1");
+    
+    from_p=raydium_ode_element_pos_get(from);
+    to_p=raydium_ode_element_pos_get(to);
+    
+    if(game_part>=GAME_PART_TOUCHED)
+	camera(to_p[0]-0.3,to_p[1]-0.3,to_p[2]+0.5,from_p[1],-from_p[2],from_p[0],80);
+    else
+	camera(from_p[0],from_p[1]-2,from_p[2]+1,to_p[0],to_p[1],to_p[2],80);
+//    raydium_projection_fov=90;
+//    raydium_window_view_update();
+//    raydium_ode_element_camera_inboard(from,0,-1,0,0,1,0);
+}
+else
+{
+    raydium_projection_near=5;
+    raydium_projection_far=3000;
+    tmp=raydium_ode_element_pos_get_name(cam);
+    camera(camx,camy,camz,tmp[1],-tmp[2],tmp[0],camzoom);
+}
+
+raydium_ode_draw_all(0);
+//raydium_ode_draw_all(1);
+
+if(para_open)
+    {
+    // All this to draw a simple static parachute...
+    dMatrix3 R;
+    dReal *pos;
+    dReal my_pos[3];
+    dRSetIdentity(R);
+    pos=raydium_ode_element_pos_get_name("head");
+    memcpy(my_pos,pos,sizeof(dReal)*3);
+    my_pos[2]+=1;
+    raydium_camera_replace_go(my_pos,R);
+    raydium_object_draw_name("parachute.tri");
+    }
+
+if(game_part==GAME_PART_SCORE)
+    {
+    raydium_osd_printf(20,45,40,0.8,"font2.tga","Score: %i",get_score(1));
+    }
+//else
+    {
+    raydium_osd_printf(5,13,16,0.5,"font2.tga","^cWind: %s %02.1f %% | Fly-Time: %.2f | Touch Time: %.2f",(wind<0?"<-":"->"),raydium_trigo_abs(wind*100),fly_time,touching_steps/400.f);
+    raydium_osd_printf(5,10,16,0.5,"font2.tga","^cCenter Distance: %.2f | Breaked Bones: %i",dist_from_center,breaked_bones);    
+    }
+
+raydium_osd_printf(75,95,16,0.5,"font2.tga","^fBest score: ^9% 5i",best_score);
+raydium_osd_printf(2,2,16,0.5,"font2.tga","%s",tips[tip]);
+raydium_osd_printf(2,98,16,0.5,"font2.tga","^f- %3i FPS - NewSkyDiver %s (Raydium %s) - CQFD Corp.",raydium_render_fps,version,raydium_version);
+raydium_osd_logo("logoc.tga");
+raydium_rendering_finish();
+
+raydium_ode_network_element_send_iterative(RAYDIUM_ODE_NETWORK_OPTIMAL);
+}
+
+int main(int argc, char **argv)
+{
+struct passwd *pn;
+char server[128];
+
+#ifndef WIN32
+pn=getpwuid(geteuid());
+strcpy(player_name,pn->pw_name);
+#else
+{
+DWORD s;
+s=RAYDIUM_MAX_NAME_LEN-1;
+GetUserName(player_name,&s);
+if(!strlen(player_name))
+    gethostname(player_name,RAYDIUM_MAX_NAME_LEN-1);
+}
+#endif
+
+raydium_init_args(argc,argv);
+raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,version);
+raydium_texture_filter_change(RAYDIUM_TEXTURE_FILTER_TRILINEAR);
+raydium_projection_near=5;
+raydium_projection_far=3000;
+raydium_projection_fov=DEFAULT_ZOOM;
+//raydium_light_disable();
+raydium_fog_disable();
+raydium_light_on(0);
+//raydium_light_on(1);
+memcpy(raydium_light_color[0],sun,raydium_internal_size_vector_float_4);
+//raydium_light_intensity[0]=400;
+raydium_light_intensity[0]=1000000;
+raydium_light_update_all(0);
+memcpy(raydium_light_color[1],amb,raydium_internal_size_vector_float_4);
+raydium_light_intensity[1]=10000;
+raydium_light_update_all(1);
+raydium_window_view_update();
+
+
+glMaterialfv( GL_FRONT, GL_DIFFUSE, tmp2);
+glMaterialfv( GL_FRONT, GL_AMBIENT, zero);
+glMaterialfv( GL_FRONT, GL_EMISSION, zero);
+glMaterialf( GL_FRONT, GL_SHININESS, 128.);
+
+
+// sounds loading :
+raydium_sound_DefaultReferenceDistance=100.f;
+
+S_plane=raydium_sound_LoadWav("plane.wav");
+raydium_sound_SetSourcePitch(S_plane,2);
+raydium_sound_SetSourceGain(S_plane,0.5);
+
+S_plane_fall=raydium_sound_LoadWav("planefall.wav");
+raydium_sound_SetSourceLoop(S_plane_fall,0);
+
+S_hurt[0]=raydium_sound_LoadWav("hurt4.wav");
+raydium_sound_SetSourceLoop(S_hurt[0],0);
+
+S_hurt[1]=raydium_sound_LoadWav("hurt2.wav");
+raydium_sound_SetSourceLoop(S_hurt[1],0);
+
+S_hurt[2]=raydium_sound_LoadWav("hurt3.wav");
+raydium_sound_SetSourceLoop(S_hurt[2],0);
+
+S_hurt[3]=raydium_sound_LoadWav("hurt1.wav");
+raydium_sound_SetSourceLoop(S_hurt[3],0);
+
+raydium_osd_cursor_set("BOXcursor.tga",4,4);
+strcpy(raydium_console_config_texture,"logo_console.tga");
+raydium_sky_box_cache();
+
+raydium_register_variable(&camx,RAYDIUM_REGISTER_FLOAT,"camx");
+raydium_register_variable(&camy,RAYDIUM_REGISTER_FLOAT,"camy");
+raydium_register_variable(&camz,RAYDIUM_REGISTER_FLOAT,"camz");
+raydium_register_variable(&camzoom,RAYDIUM_REGISTER_FLOAT,"camzoom");
+raydium_register_variable(&cam,RAYDIUM_REGISTER_STR,"cam");
+raydium_timecall_add(frame_step,-60);
+
+raydium_ode_ground_set_name("hills.tri");
+raydium_ode_CollideCallback=collide;
+raydium_ode_StepCallback=step;
+raydium_console_gets_callback=name_change;
+raydium_sound_music_eof_callback=music_change;
+
+{
+char file[RAYDIUM_MAX_NAME_LEN];
+music_change(file);
+raydium_sound_load_music(file);
+}
+
+raydium_log("Found player name: %s",player_name);
+raydium_log("use /xxx to change your player name");
+// cache data ... :
+create_plane(1);
+create_landing(0,0,0);
+create_para("plane 1");
+raydium_object_load("parachute.tri");
+// ... and start a new game :
+
+if(raydium_init_cli_option("server",server))
+     if(!raydium_network_client_connect_to(server)) 
+        exit(1);
+
+create_game();
+raydium_callback(&display);
+return 0;
+}
Index: cam.c
===================================================================
--- cam.c	(revision 0)
+++ cam.c	(revision 1)
@@ -0,0 +1,120 @@
+#define NO_ODE_SUPPORT
+#include "raydium/index.c"
+
+GLfloat cam_angle_x = 0;
+GLfloat cam_angle_y = 90;
+
+GLfloat cam_pos_x = 0;
+GLfloat cam_pos_y = 0;
+GLfloat cam_pos_z = 0;
+GLfloat roll = 0;
+
+GLfloat speed = 0.1;
+GLint sensibilite = 3;
+
+GLint lacet = 0;
+
+char model[RAYDIUM_MAX_NAME_LEN];
+
+GLfloat light_color[] = {1.0, 0.9, 0.8, 1.0};
+
+FILE *out;
+
+void display(void)
+{
+    
+int delta_x, delta_y;
+
+raydium_joy_key_emul();
+
+cam_pos_z += (raydium_trigo_sin(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+cam_pos_x += (raydium_trigo_cos(cam_angle_x+90)*raydium_joy_y*speed*raydium_trigo_sin(90-cam_angle_y));
+cam_pos_y += (raydium_trigo_cos(90-cam_angle_y)*speed*raydium_joy_y);
+    
+cam_pos_x -= (raydium_trigo_cos(cam_angle_x)*raydium_joy_x*speed);
+cam_pos_z -= (raydium_trigo_sin(cam_angle_x)*raydium_joy_x*speed);
+    
+if(raydium_key_last==1027)
+    exit(0);
+
+if(raydium_key[GLUT_KEY_F1]) { raydium_projection_fov/=(1.04); raydium_window_view_update(); }
+if(raydium_key[GLUT_KEY_F2]) { raydium_projection_fov*=(1.04); raydium_window_view_update(); }
+
+if(raydium_key[GLUT_KEY_F3]) roll--;
+if(raydium_key[GLUT_KEY_F4]) roll++;
+
+delta_x = raydium_mouse_x - (raydium_window_tx/2);
+cam_angle_x += (delta_x*sensibilite*0.1f); 
+
+delta_y = raydium_mouse_y - (raydium_window_ty/2);
+cam_angle_y += (delta_y*sensibilite*0.1f); 
+
+raydium_mouse_move(raydium_window_tx/2, raydium_window_ty/2);
+
+
+raydium_light_position[0][0]=100;
+raydium_light_position[0][1]=100;
+raydium_light_position[0][2]=100;
+raydium_light_position[0][3]=1.0;
+
+raydium_light_update_position(0); 
+
+raydium_background_color_change(light_color[0],light_color[1],light_color[2],light_color[3]);
+    
+raydium_clear_frame();
+raydium_camera_place(cam_pos_x,cam_pos_y,cam_pos_z,cam_angle_x,cam_angle_y,roll);
+
+raydium_camera_replace();
+raydium_object_draw_name(model);
+
+if(raydium_key_last==1032)
+    {
+    fprintf(out,"%f %f %f %f %f\n",cam_pos_z,cam_pos_x,-cam_pos_y,raydium_projection_fov,roll);
+    raydium_osd_printf(50,50,20,0.5,"font2.tga","^cADDED");
+//    raydium_log("Added a new pos to camera path file");
+    }
+
+raydium_osd_logo("logo.tga");
+raydium_osd_printf(2,98,16,0.48,"font2.tga","^fF1/F2: Zoom - F3/F4: Roll - Space: add path point - generates cam.cam file");
+    
+raydium_rendering_finish();
+}
+
+
+
+
+int main(int argc, char **argv)
+{
+    raydium_init_args(argc,argv);
+    
+    raydium_window_create(640,480,RAYDIUM_RENDERING_WINDOW,"Camera path maker (willou.c based)");
+    raydium_texture_filter=RAYDIUM_TEXTURE_FILTER_TRILINEAR;
+    raydium_projection_near=0.01;
+    raydium_projection_far=2500;
+    raydium_projection_fov=60;
+    raydium_fog_disable();
+    raydium_window_view_update();
+    
+    raydium_light_on(0);
+    memcpy(raydium_light_color[0],light_color,raydium_internal_size_vector_float_4);
+    raydium_light_intensity[0] = 1000000;
+    raydium_light_update_all(0);
+
+//    raydium_osd_cursor_set("BOXcursor.tga",4,4);
+
+    raydium_window_view_update();
+
+
+    strcpy(model,"a.tri");
+    raydium_init_cli_option("model",model);
+
+    out=fopen("cam.cam","wt");
+    if(!out)
+	{
+	raydium_log("cannot open cam.cam (w)");
+	return 1;
+	}
+    raydium_callback(&display);
+    return(0);
+}
+// EOF
Index: configure
===================================================================
--- configure	(revision 0)
+++ configure	(revision 1)
@@ -0,0 +1,299 @@
+#!/bin/sh
+
+# This script will configure Raydium and download, configure and build
+# dependencies if needed. See --help argument.
+
+# build file
+# $1 is file content
+# $2 is gcc's options
+test_build()
+{
+echo "$1" > configure.c
+gcc -g configure.c -Wall -o configure.bin $2 2> configure.log
+
+if [ "$?" != "0" ]; then
+    echo " build: failed"
+    return 1
+fi
+
+./configure.bin > configure.log
+ret=$?
+
+if [ "$ret" = "0" ]; then
+    echo " ok"
+fi
+
+if [ "$ret" != "0" ]; then
+    echo " run: failed"
+fi
+
+return $ret
+}
+
+
+# $1 is last returned code
+# $2 is error message
+exit_if_error()
+{
+if [ "$1" != "0" ]; then
+    echo "$2"
+    exit 1
+fi
+return 0
+}
+
+usage_print()
+{
+echo "Quick configure script for Raydium 3D Game Engine"
+echo "  --help               this text"
+echo "  --install-ode        ODE local auto-install"
+echo "  --install-php        PHP 4 local auto-install"
+exit 0
+}
+
+ode_install()
+{
+echo "ODE Auto local installation ..."
+if [ -d "ode" ]; then
+    echo "ODE (partial ?) install detected, abort (ode/)"
+    exit 1
+fi
+
+# download
+echo "Downloading from CVS ..."
+cvs -d:pserver:anonymous:@cvs.sourceforge.net:/cvsroot/opende login
+exit_if_error "$?" "No cvs client installed ?"
+cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/opende co -r UNSTABLE -P ode
+exit_if_error "$?" "CVS server error ? Try manual install (http://ode.org)"
+
+# configure (step 1)
+echo '
+# Raydium ODE autoconfig
+PLATFORM=unix-gcc
+PRECISION=SINGLE
+BUILD=release
+WINDOWS16=0
+OPCODE_DIRECTORY=OPCODE
+' > ode/config/user-settings
+
+# configure (step 2)
+echo "Configuring ... (ignore warnings)"
+cd ode
+make configure > ../configure.log
+ret=$?
+cd -
+exit_if_error "$?" "ODE configuration failed (see configure.log)"
+
+echo '
+#ifndef dEpsilon
+#define dEpsilon FLT_EPSILON
+#endif
+' >> ode/include/ode/config.h
+
+# build
+echo "Building ... (ignore warnings)"
+cd ode
+make > ../configure.log
+ret=$?
+cd -
+exit_if_error "$?" "ODE Build failed (see configure.log)"
+echo "- ODE seems ready -"
+}
+
+php_install()
+{
+echo "PHP4 Auto local installation ..."
+if [ -d "php" ]; then
+    echo "PHP (partial ?) install detected, abort (php/)"
+    exit 1
+fi
+
+# download
+echo "Downloading latest PHP4 ..."
+wget -O php4-last.tar.gz http://snaps.php.net/php4-STABLE-latest.tar.gz
+exit_if_error "$?" "wget not found, or network error"
+
+# uncompress
+echo "Uncompressing ..."
+tar xzf php4-last.tar.gz
+exit_if_error "$?" "tar not found, or corrupted archive"
+
+# rename
+php=`ls -dt php4-STABLE-*/`
+echo "Renaming $php to php/ ..."
+mv "$php" "php"
+exit_if_error "$?" "Is this script up to date ?"
+
+# configure
+echo "Configuring ..."
+cd php
+./configure --enable-embed=static --with-zlib --enable-ftp --enable-static=zlib > ../configure.log
+ret=$?
+cd -
+exit_if_error "$ret" "PHP configure failed (missing libs ?). See configure.log"
+
+# compile
+echo "Building ... (ignore warnings)"
+cd php
+make > ../configure.log
+ret=$?
+cd -
+exit_if_error "$ret" "PHP building failed, see configure.log"
+
+# deleting
+echo "Deleting tar.gz ..."
+rm -f php4-last.tar.gz
+
+echo "- PHP4 seems ready -"
+}
+
+
+####### Main
+
+for i in "$@"; do
+    if [ $i = "--help" ]; then
+    usage_print
+    fi
+done
+
+for i in "$@"; do
+    if [ $i = "--install-ode" ]; then
+    ode_install
+    fi
+done
+
+for i in "$@"; do
+    if [ $i = "--install-php" ]; then
+    php_install
+    fi
+done
+
+# Test compiler
+echo -n "* GCC :"
+file='int main(void) { return 0; }'
+test_build "$file" ""
+exit_if_error "$?" "GNU C Compiler (GCC) is missing"
+
+# Test OpenGL
+echo -n "* OpenGL lib :"
+
+file='#include <GL/gl.h>
+int main(void) { if(0) glVertex3f(0,0,0); return 0; }'
+test_build "$file" "-L/usr/X11R6/lib/ -lGL"
+exit_if_error "$?" "You must install opengl-devel package"
+
+# Test GLU
+echo -n "* GLU lib :"
+
+file='#include <GL/gl.h>
+#include <GL/glu.h>
+int main(void) { return 0; }'
+test_build "$file" "-L/usr/X11R6/lib/ -lGL -lGLU"
+exit_if_error "$?" "You must install glu-devel package"
+
+# Test GLUT
+echo -n "* GLUT lib :"
+
+file='#include <GL/glut.h>
+int main(void) { gluGetString(GLU_VERSION); return 0; }'
+test_build "$file" "-L/usr/X11R6/lib/ -lGL -lGLU -lglut"
+exit_if_error "$?" "You must install glut-devel package"
+
+# Full GL/GLU/Glut test, looking for hardware accel
+echo -n "* GL/GLU/GLUT and hardware support :"
+
+file='
+#include <stdio.h>
+#include <string.h>
+#include <GL/glut.h>
+int main(int argc, char **argv) { 
+char *r;
+glutInit(&argc,argv);
+glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
+glutInitWindowSize(320,240);
+glutCreateWindow("Test window");
+r=glGetString(GL_RENDERER);
+if(!strcmp(r,"Mesa GLX Indirect"))
+    {
+    fprintf(stderr,"WARNING ! Mesa Software renderer detected !");
+    fprintf(stdout,"WARNING ! Mesa Software renderer detected !");
+    }
+return 0; }
+'
+test_build "$file" "-L/usr/X11R6/lib/ -lGL -lglut -lGLU"
+exit_if_error "$?" "Full GL test faild, see configure.log"
+
+# OpenAL
+echo -n "* OpenAL :"
+file="
+#include <AL/al.h>
+#include <AL/alc.h>
+#include <AL/alut.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+int main(int argc, char **argv) {
+ALCdevice *dev;
+const ALubyte *initstr=(const ALubyte *) \"'( ( devices '( native null ) ) )\";
+dev=alcOpenDevice(initstr);
+sleep(1);
+alcCloseDevice(dev);
+return 0; }"
+test_build "$file" "-lopenal"
+exit_if_error "$?" "openal-devel is required. Official CVS may be a good idea"
+
+# OGG/Vorbis
+echo -n "* OGG/Vorbis :"
+file='
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <vorbis/codec.h>
+#include <vorbis/vorbisfile.h>
+int main(void){
+FILE *fp;
+OggVorbis_File vf;
+fp=fopen(".","r");
+if(ov_open(fp, &vf, NULL, 0) < 0) { exit(0); }
+// should never hit this !
+ov_clear(&vf);    
+return(0);
+}'
+# -logg seems useless ...
+test_build "$file" "-lvorbis -lvorbisfile -logg"
+exit_if_error "$?" "ogg and vorbis devels are required (libogg,libvorbis and libvorbisfile)"
+
+
+# ODE
+echo -n "* ODE (local) :"
+if [ -f "ode/lib/libode.a" ]; then
+    # found (0 = ok)
+    echo " ok"
+    ret=0
+else
+    echo " not found"
+    ret=1
+fi
+exit_if_error "$ret" "ODE is not installed (ODE must be local). Try --install-ode !"
+
+
+# PHP
+echo -n "* PHP 4 (local) :"
+if [ -f "php/libs/libphp4.a" ]; then
+    # found (0 = ok)
+    echo " ok"
+    ret=0
+else
+    echo " not found"
+    ret=1
+fi
+exit_if_error "$ret" "PHP 4 is not installed (PHP must be local). Try --install-php !"
+
+##### End of tests
+
+echo "- Build system seems ready -"
+echo "- Use \"make\" to build Raydium, and try: \"./odympcomp.sh test6.c\""
+echo "- You can also use \"./ocomp.sh test6.c\" for a quick direct test"

Property changes on: configure
___________________________________________________________________
Added: svn:executable
\ No newline at end of property