# Accurate event timer

This topic is 3576 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Haven't been around for a long time,since i was too busy with school&school projects. Now that im back , i decided to create something simple in my free time. Im trying to make something like a simple 3d demo(with sdl &opengl). I can hanlde most of the tasks(since i have old code that i can use) , but there is something really important that im not sure how to implement it. As title says ,im trying to create an accurate event timer, and in a demo , its REALLY important to be accurate, since the engine will execute a command set(like opcodes) based on time.. No , im not retard , i can calculate ms->secs->whatever, BUT , how can i make sure that it will be accurate on other machines,and the most part...it must be run on both linux & windows. A simple example would be more than helpful....

##### Share on other sites
I'm not sure what kind of accuracy you're looking for, but timing in a 3D application is usually done by calculating a timedelta value (the time it took to do one iteration of the game loop). Using the timedelta value you can compensate for slower or faster hardware (slower hardware <=> timedelta is larger, faster hardware <=> timedelta is smaller), by simply multiplying all your transformations with timedelta.

I assume you are going to need that value if you're going to have any animation in your demo and as far as my knowledge goes, you can calculate timedelta quite accurately on windows (I'm not sure about linux, I don't develop for that platform). You can use the QueryPerformanceCounter function to retrieve the number of processor 'ticks' and the QueryPerformanceFrequency function to get a rather accurate result (think nanoseconds, as opposed to getTickCount, or timeGetTime).

Knowing this, I am sure you can figure out a way to add these values to a 'totalTimePassed' variable to allow you to accurately post events at an interval rate set by you. Unfortunately, I can't help you with the linux part of things...

Regards,

Rogier

##### Share on other sites
I was learning to do this last night. I found this thread which gives an example of what rogierpennink is talking about:

[url]http://www.gamedev.net/community/forums/topic.asp?topic_id=113457&whichpage=1򕌅[/url]

As for the linux side, I have no idea.

##### Share on other sites

Sorry , let me explain what im asking more detailed.

First off- , im not asking how to implement frame independent movement.

//script class
typedef enum OP_LIST{OP_EXPL      	= 0,OP_CAMZOOMIN 	= 1,OP_CAMZOOMOUT	= 2,OP_QUIT         = 3,OP_UPDGFX       = 4};struct CscriptInfo{//commandunsigned int opcode;//will execute in defined timedouble   time;};Cscript::Cscript{        //command index        head=0;	//script size	bytes=0;}void Cscript::addTimerEvent(const unsigned int opcode,const double time){         //add event	m_Code.push_back( CscriptInfo(opcode,time) );        //update size 	bytes=m_Code.size();}void Cscript::next(){        //next code	head++;        //ensure script index is in valid range	assert(((head<bytes)&&(head>-1)));}double Cscript::getActiveEventTime() const;{        //get active script	const CscriptInfo* s = &m_Code[head];        //return time	return s.time;}void  Cscript::execute() {	use the op code...etc}

//Lets use the class..

        //create the script object	Cscript* script = new Cscript;        //memory allocated?	assert(script!=NULL);                //current time..        double currentTime=0.0;        //lets add a few events        //zoom camera after 500ms have passed	script->addTimerEvent(OP_CAMZOOMIN,500);	//make an explosion after 2000ms have passed	script->addTimerEvent(OP_EXPL,2000);        //our main loop	while(running)	{        //check if its about time to execute the active event	if(script->getActiveEventTime()==currentTime)        {        //yay! time to work..	//run the code 		script->execute();	//get next..	script->next();	}	currentTime+=1.0;	}        //release memory	delete script;        script = NULL;        //exit        return 0;

Now i think everyone's understand what i have in mind...right?

[Edited by - 3Dgonewild on February 29, 2008 8:51:52 AM]

##### Share on other sites
I think I see what you mean, but wouldn't the tools remain the same? I have unfortunately never implemented anything like what you describe, but considering you still need to use a rather accurate timer like window's high performance timer, it all boils down to simply adding the delta_time of each frame to a totalTimePassed value (in my eyes, I could be entirely wrong of course).

I think the easiest way to have your events happening at exactly the right time is to have them sorted in a container. Let's assume you use something as simple as a list (assuming it's sorted), you would only have to compare the first element of that list to the current totalTimePassed value and if it's equal or greater than you execute the event and remove it from the list. Then the first element of the list corresponds to the next event so you'll only ever have to check the first element...

Again, I could be totally wrong, but this just seems the most sensible way of approaching what you're after....

Regards,

Rogier

##### Share on other sites
Quote:
 Original post by rogierpenninkI think I see what you mean, but wouldn't the tools remain the same? I have unfortunately never implemented anything like what you describe, but considering you still need to use a rather accurate timer like window's high performance timer, it all boils down to simply adding the delta_time of each frame to a totalTimePassed value (in my eyes, I could be entirely wrong of course).I think the easiest way to have your events happening at exactly the right time is to have them sorted in a container. Let's assume you use something as simple as a list (assuming it's sorted), you would only have to compare the first element of that list to the current totalTimePassed value and if it's equal or greater than you execute the event and remove it from the list. Then the first element of the list corresponds to the next event so you'll only ever have to check the first element...Again, I could be totally wrong, but this just seems the most sensible way of approaching what you're after....Regards,Rogier

I really appreciate your help so far.
I'll wait for some more ideas , and then i will decide which path to follow.

Actually , my main problem is the counter,which adds +1.0 ms on every frame, and i
have a feeling that it wont work well on every pc..

I also have another idea.

If i create something like an event editor(were you can place events etc), and update the counter on every frame , like this:

timepassed += 0.01

Then i could add each event on button press for example..

##### Share on other sites
Ah but that is where the timedelta comes in. You shouldn't add a fixed timevalue to the total time that has passed each frame, instead you should calculate how much time has passed since the previous frame and add that value to the total time that has passed. This is the essence of hardware-independent timing.

Let's just assume we have a function called 'getTime()' which returns the time that has passed since boot in nanoseconds:
total_time_passed = 0;previous_time = getTime();while ( running ){    if ( sorted_script_list.firstElement().time <= total_time_passed )        execute_script( sorted_script_list.firstElement() );    current_time = getTime();    timedelta = current_time - previous_time;    previous_time = current_time;    total_time_passed += timedelta;}

Doing it this way will ensure that you always measure the correct amount of time that has passed. If you keep the list of scripts sorted based on the time values you will only ever have to check the first element (provided you throw away the first element after you've 'executed' it). Of course, other constructions are possible here, but I think this is the only reliable way to measure the real amount of time that has passed.

##### Share on other sites
Quote:
 Original post by rogierpenninkAh but that is where the timedelta comes in. You shouldn't add a fixed timevalue to the total time that has passed each frame, instead you should calculate how much time has passed since the previous frame and add that value to the total time that has passed. This is the essence of hardware-independent timing.Let's just assume we have a function called 'getTime()' which returns the time that has passed since boot in nanoseconds:total_time_passed = 0;previous_time = getTime();while ( running ){ if ( sorted_script_list.firstElement().time <= total_time_passed ) execute_script( sorted_script_list.firstElement() ); current_time = getTime(); timedelta = current_time - previous_time; previous_time = current_time; total_time_passed += timedelta;}Doing it this way will ensure that you always measure the correct amount of time that has passed. If you keep the list of scripts sorted based on the time values you will only ever have to check the first element (provided you throw away the first element after you've 'executed' it). Of course, other constructions are possible here, but I think this is the only reliable way to measure the real amount of time that has passed.

WOah , now thats something that i have to test out.

And as for sorting the list , its impossible , because it will mess the indexing.

For example , lets say that i have the following commands:

script->registerVariable("SOUND0","sample1.wav");//play sound #0 const std::string s = script->getVariable("SOUND0");//explosion animationscript->addcommand(OP_EXPL,2000);//play explosion sound after 2ms have passedscript->addcommandExt(OP_PLAYSOUND,s,1990);script->execute

Then , it will first play the sound, then the explosion..

##### Share on other sites
A priority queue data structure exists to do just that, C++ provides std::priority_queue.

On every tick, you dequeue all events that have expired. This means that all event executions will be late.

For accurate events, you'd need a real-time OS.

##### Share on other sites
I see, but remember that the list would be sorted. In other words, you could first add the explosion command, so the list would look like this:
+-------------+| EXPL - 2000 |+-------------+

Then you would add the sound command and notice that the first item in the list has a larger time value associated with it, so you insert the sound command in front of the explosion command:
+-------------+      +-------------+| SND - 1990  |      | EXPL - 2000 |+-------------+      +-------------+

However, for this to work well you would probably have to wrap your commands (and their possible parameters) into a class, so that you can just pass objects of that class into the list.

##### Share on other sites
Quote:
 Original post by rogierpenninkI see, but remember that the list would be sorted.

Yes. And typical priority queue offers O(log n) insertion and O(1) access to highest priority element.

Sorting is implied here, typically through use of heap for implementation.

##### Share on other sites
Quote:
 Original post by AntheusYes. And typical priority queue offers O(log n) insertion and O(1) access to highest priority element.Sorting is implied here, typically through use of heap for implementation.

I understand, I was replying to 3DGoneWild but you beat me to it, so it looks like I'm replying to your post now :P

Anyway, the usage of a list was merely an example; I am far from an expert in datastructures, I just wanted to express the importance of the event data being sorted by their time values so you can have O(1) access to the next event that is to take place.

##### Share on other sites
@antheus:

Thanks ,i'll check it out , but to be honest , itlooks kinda messy :)

Quote:
 Original post by rogierpennink However, for this to work well you would probably have to wrap your commands (and their possible parameters) into a class, so that you can just pass objects of that class into the list.

I lost you here...
You mean to replace OP code enumerator list , and create classes instead?

Something like:

class OP_SND{std::string file,name;unsigned int status,**more options**};class OP_3DBOX{std::string name;vector3 pos[4];};etc..?

But then how am i supposed to store them..??polymorphism..maybe?

##### Share on other sites
If you want to use any sort of data structure for your events, you will have to define a uniform event type. Since an event has a number of parameters you need to specify a 'holder' for those parameters or you can't put it in any type of container. You don't even need polymorphism for this (at least, judging by the code you've shown so far), even a simple struct would do:
struct Event{    int cmdType;    string name;    int numMilliSeconds;};

Now, Event is an entity that you can put in a container, and when you retrieve an Event object from your container (because it ought to be triggered), you can simply call your addCommandExt function, pass the variables in the struct to it as arguments, and call your script->execute function.

##### Share on other sites
Quote:
 Original post by rogierpenninkIf you want to use any sort of data structure for your events, you will have to define a uniform event type. Since an event has a number of parameters you need to specify a 'holder' for those parameters or you can't put it in any type of container. You don't even need polymorphism for this (at least, judging by the code you've shown so far), even a simple struct would do:struct Event{ int cmdType; string name; int numMilliSeconds;};Now, Event is an entity that you can put in a container, and when you retrieve an Event object from your container (because it ought to be triggered), you can simply call your addCommandExt function, pass the variables in the struct to it as arguments, and call your script->execute function.

Thank you , probably i will do something like this.

Can't find a clean way to do it with polymorphism.

Well , anyway , here's what i came up with(i can't figure out how to
call the commands from the "opcode" class):

***SORRY for the "dirty" code , but its just an example while im trying to figure how to follow the "polyMorphic way"..***

#include <iostream>#include <vector>class opcode{private:std::vector<opcode*> code;public:virtual void execute(){return;}virtual double getExecutionTime(){return (0.0);}void addCommand(opcode*op){code.push_back(op);}};class OP_NOP:public opcode{public:void execute(){} };class OP_PRINT:public opcode{private:std::string text;double time;public:OP_PRINT(std::string s,double t){text=s;time=t;}double getExecutionTime(){return time;}void execute(){std::cout<<text<<std::endl;}};int main(){opcode *script = new opcode;OP_PRINT p1("-3D Gone wild..",333),p2("-o'rly?..",339);script->addCommand(&p1);script->addCommand(&p2);script->execute();//<---DOES nothing -_-"p1.execute();p2.execute();delete script;script=NULL;return 0;}

##### Share on other sites
Thank you so much , your suggestion worked!
Well , i had to do some critical changes in the timer , but anyway, without your help probably i would had to search more on the subject.

Thanks again.

##### Share on other sites

This topic is 3576 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628706
• Total Posts
2984309

• 23
• 10
• 9
• 13
• 13