Copyright (C) 2000-2012 |
GNU Info (xaos.info)timerlibThe timer library ================= Timer library is library I did for timming in XaoS. But I found it usefull in many other programs (like demonstrations, games, animation players and all other stuff that needs to be timed). So you should read this description and possibly use it in your application and save some coding time. There is many ways how to design of such timed aplicatioin (game) 1. read user input, move badies, display and again this way has one disadvantage. Speed of game depends on speed of computer. This was acceptable in old times where only processor was Z80 :) but now with wide variety of various hardwares such internal loop is unacceptable 2. read user input, measure time since last loop and caluclate step for badies, move badies for set step, display and again. This way fixes problem with speed. But moving badies just for caluclated step, that should differ a much is quite complex, usually introduces complex calculation, floating/fixedpoint math and other unnecesarry stuff that makes program long and introduces many bugs. 3. Set the fixed framerate that is high enought to make game smooth but low enought to do whole internal loop in time. So internal loop should look like: read user input, move badies, display, meausre time spent in loop an sleep rest of time until next frame. This is quite popular scheme but has another disadvantage -- game can not be designed to use whole cpu power since on slower computers internal loop should take longer time that is reserved for one frame. Game will run slowly again. 4. To take away disadvantage of previous methot, many games times just moving of badies and user input. Other stuff like displaying should be done in rest of time. In dos games moving and user input is often at asynchronous interrupt and drawing runs as main loop. This solves problem in case that drawing of game takes significantly longer time than moving of badies. This is quite usual so this scheme works well. 5. previous scheme still has one problem -- since timer interrupt works asynchronously, there should happend many race condition, in case moving takes longer time than time reserved from frame, computer can crash. So this scheme should be enhanced into synchronous one with exactly same result but avoiding problem with race condition: read user input, measure time spent by loop and caluclate how many simulated frame interrupts activated since last activation, if zero sleep until simulated interrupt, move badies as many times as required, display this is an combination of 4 and 3 and seems to be most confortable way for writing games but since main loop is now quite complex many games don't do that. 6. there is still one small problem. Method 5 expect that moving takes significantly lower time that displaying. This may not be truth. Simple work around is to write moving routine, that should move for x moves by faster way that calling move x times. This is often possible and makes easy extension to scheme 5. This scheme allows you to use very large maximal framerate (say 100FPS) and to have same results as method 2 (that is maximally exact method) As you can see, designing of main loop isn't so easy. This is just very simple example. More advanced aplication for example should want to move one set of badies at one framerate and other at different framerate. This requires two such timmings. Another complication is that there is many different ways to measure time exactly at different platforms. Under linux you can measure using gettimeofday but under DOS this is exact just to 1/18 of second and thats too low for smooth animation and so on. Thats why I decided to design portable easy to use timer library, that makes easy to implement all described method, combining of them and much more. During design I taken care at the following thinks: quality of timming, how easy to use it is, speed, portability and to minimalize inexpected situations (like race conditions in asynchronous interrupts and so on) What is what ------------ Timer library operates with "timers". They should be created, you should measuere time since last reset, pause them or set "handler" and "interval". But handler is not activat at gived interval yet. Since timer library is not asynchronous, you must activate them. For activating is used "groups". You should provess group at some place in your program. Then all timers in group are checked and their handlers activated if required. When time spent since last activation is higher than interval, handler is activated more times. Also interval to next invocation is calculated to keep freqency. Simple scheduling is performed at handler -- handler is activated just once and then all other timers are checked before it is activated again. You should also define an multihandler -- handler that is activated just once and receives argument how many intervals has left. There is two special groups -- `asyncgroup'. Timers in this group are activated asynchornously like from interrupt. It is not recomended to use it, since it brings many problems and usually isn't required. Also it does not work at many platforms. `Syncgroup' is the default group. Program is expected to process is quite often. In case you don't need to use more groups, you should use this one. Time in timerlib is bit strange, since it does not flow continuously but jumps. It is updated every time you call `tl_updatetime'. I used this way in order to minimize context switches but later I found this scheme very usefull, since you should lookup timer, do something and then reset it and don't wory about time spend between lookup and reset since it is 0 in case you did not called tl_updatetime. This helps to keep freqency of timers exact w/o any errors caused by such situations. At the other hand you need to call tl_updatetime at least once in your main loop. Maybe you don't know why to create more groups, but I found it quite usefull. For example an autopilot in XaoS has such special group -- I need to call it approx. every 1/20 of second but just at one place in program. Invoking of autopilot when caluclation is active should produce incorrect results, so I have special group for autopilot and process just at one place where I am sure it is safe. Timers should be also emulated. You should stop them and then control flow of time for given timer. This should be quite usefull for example when you want precalculate animation at given framerate. Time functions -------------- - Function: void tl_update_time (void) Update time used by timerlib. This must be called at least once in main loop otherwise time will not flow. See above. - Function: void tl_sleep (int TIME) Sleep given time. Similiar to usleep at POSIX. Group functions --------------- - Function: tl_group *tl_create_group (void) Allocate and initialize group header. Returns NULL when malloc fails. - Function: void tl_free_group (tl_group *GROUP) Free memory storage used by group structure - Function: int tl_process_group (tl_group *GROUP, int *ACTIVATED) Process timers in group and activates their handlers. Returns time until next invocation. Main loop should sleep returned time then. An ACTIVATED parameter sould be `NULL'. If it is non `NULL', variable is set to number of activated handlers. Timer functions --------------- - Function: tl_timer *tl_create_timer (void) Create timer structure. - Function: void tl_free_timer (tl_timer *TIMER) Free memory storage used by timer structure - Function: void tl_reset_timer (tl_timer *TIMER); Reset timer to current time. (time of last actication of `tl_update_time') - Function: int tl_lookup_timer (tl_timer *TIMER); Return time since last call of tl_reset_timer or last activation of handler. - Function: void tl_set_interval (tl_timer *TIMER, int INTERVAL); - Function: void tl_set_handler (tl_timer *TIMER, void (*HANDLER) (void *),void *userdata); - Function: void tl_set_multihandler (tl_timer *TIMER, void (*HANDLER) (void *,int),void *userdata); Handler, multihandler and interval control functions - Function: void tl_add_timer (tl_group *GROUP, tl_timer *TIMER) Add timer to given group. Timer should be added into just one group. - Function: void tl_stop_timer (tl_timer *TIMER) - Function: void tl_resume_timer (tl_timer *TIMER) Stop and resume timer. - Function: void tl_slowdown_timer (tl_timer *TIMER,int TIME) Time in timer is moved back for given time. Example main loop ----------------- while(1) { time=tl_process_group(syncgroup,activated); /*Call game control functions*/ update_keys(); if(activated) /*something changed*/ display(); else tl_sleep(time); } automatically generated by info2www version 1.2.2.9 |