Index: gui.h
===================================================================
--- gui.h	(revision 1214)
+++ gui.h	(revision 1215)
@@ -13,7 +13,7 @@
 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 
+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.
 **/
@@ -35,7 +35,7 @@
 /**
 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 
+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.
@@ -271,7 +271,7 @@
 __rayapi 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. 
+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)%%
@@ -283,7 +283,7 @@
 
 __rayapi 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 
+Same as above, but no OnClick callback function is asked. This type of button
 is "readable" thru ##raydium_gui_button_clicked()##.
 **/
 
@@ -291,7 +291,7 @@
 __rayapi 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. 
+parent.
 You need to provide a ##caption## ("title") and an RGB color (0..1 interval)
 
 Text is center on the given position. If you want to align the text on the
@@ -304,7 +304,7 @@
 __rayapi 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. 
+parent.
 You need to provide a ##min## interger value, a ##max## and ##current## value.
 
 Unit for position (##px## and ##py##): percents (**window**)
@@ -312,8 +312,8 @@
 
 __rayapi 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. 
+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.
@@ -324,8 +324,8 @@
 
 __rayapi int raydium_gui_check_create(char *name, int window,  GLfloat px, GLfloat py, char *caption, signed char checked);
 /**
-This function will create a new check box, with ##name## and with ##window## 
-for parent. 
+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**)
@@ -333,12 +333,12 @@
 
 __rayapi 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. 
+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## 
+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.
 
@@ -348,10 +348,10 @@
 __rayapi int raydium_gui_zone_create(char *name, int window,  GLfloat px, GLfloat py, GLfloat sx, GLfloat sy, int tag, void *OnClick);
 /**
 This function will create a "zone" with ##name## and with ##window## for
-parent. A zone will act like a button, but  will highlight a rectangular area 
+parent. A zone will act like a button, but  will highlight a rectangular area
 of the window.
 
-This widget will return its ##tag## when you'll read it, and will 
+This widget will return its ##tag## when you'll read it, and will
 update ##raydium_gui_button_clicked()## value when clicked.
 
 Unit for position/size (##px##, ##py##, ##sx## and ##sy##): percents (**window**)
@@ -392,15 +392,15 @@
 - With labels, you must use ##str## to change caption.
 - With tracks, you must use ##value## to change the current value.
 - With edits, you must use ##str## to change text.
-- With cheks, you must use ##value##: ##1## means "checked", ##0## "unchecked".
-- With combos, you must use ##value## as an ID to change wich entry is selected.
+- With checks, you must use ##value##: ##1## means "checked", ##0## "unchecked".
+- With combos, you must use ##value## as an ID to change witch entry is selected.
 
 Returns 1 when all is OK, 0 when it fails and -1 when nothing was changed.
 **/
 
 __rayapi int raydium_gui_write_name(char *window, char *widget, char *str, int value);
 /**
-Same as above, but ##window## and ##widget## are resolved thru names, and
+Same as above, but ##window## and ##widget## are resolved to names, and
 not numeric id.
 **/
 
ction: %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);
+    }
+ }
+}