Tutorial : Timing And Movement Part 1

A forum to store posts deemed exceptionally wise and useful

Did that tutorial help you ?

Yeah ! I liked it
18
62%
It was okay ...
7
24%
Leave me alone !
4
14%
 
Total votes: 29

eXodus
Posts: 320
Joined: Tue Jan 04, 2005 10:07 am
Location: Canada
Contact:

Post by eXodus »

This timer works #1, thanks for the work!
xhrit
Posts: 140
Joined: Mon Jun 14, 2004 8:54 am
Location: earth
Contact:

hack hack hack!!

Post by xhrit »

I used Serg's class! but (always a but!) someone told me the internal irrlicht time was not good enough. so I made some 'improvements.'. This clock should be accurate up to microseconds. It is not quite done - does someone want to help with the windows specific code? (fill in the blanks!!)

Code: Select all

#ifndef IRRTIMER_H
#define IRRTIMER_H

#include <irrlicht.h>
// #include "iosys.h"

#ifdef _WIN32
#include <windows.h> // ??
#endif

#ifdef  _POSIX
#include <sys/time.h>
#endif

using namespace irr;

class irrtimer {
	 public:
		IrrlichtDevice *m_device; // pointer to Irrlicht device

		irrtimer() {};
		irrtimer(IrrlichtDevice *device){
			m_device = device;
			Reset(); // init timer
		};

		// irrlicht built-in timer
		int m_Delta, m_Time;	// time since last clock update, current time
		float m_Factor;		// time factor

		#ifdef _WIN32 // win32 high-res timer
			// ??
		#endif

		#ifdef _POSIX // POSIX high-res timer ( Linux, BSD, Mac )
			struct timeval tv; //time since last clock update
			struct timeval ts; //time since last clock update
			float m_fDelta, m_fTime, m_fFactor;
			irr::f32 m_iFactor; // time factor
		#endif

		void Reset() {
			// irrlicht built in timer
			m_Time = m_device->getTimer()->getTime();
			
			#ifdef _WIN32 // win32 high-res timer
				// ??
			#endif

			#ifdef _POSIX // POSIX high-res timer
				gettimeofday( &ts, 0);
				gettimeofday( &tv, 0);
				m_fTime = ( tv.tv_sec * 1000) + ( tv.tv_usec / 1000 );
			#endif
		};

		void Update(){
			// irrlicht built in timer
			m_Delta = m_device->getTimer()->getTime() - m_Time;
			m_Time = m_Time + m_Delta;
			m_Factor = m_Delta * 0.001f;
			// cout << "irrlicht built in time :" << m_Factor << endl;

			#ifdef _WIN32 // win32 high-res timer
				// ??
			#endif

			#ifdef _POSIX // POSIX high-res timer
				gettimeofday(&tv, 0);
				m_fDelta = ( 	(( tv.tv_sec * 1000) + ( tv.tv_usec / 1000 )) -
						(( ts.tv_sec * 1000) + ( ts.tv_usec / 1000 )) -
						m_fTime);
				m_fTime =  m_fTime + m_fDelta;
				m_fFactor = m_fDelta * 0.001f;
				// cout << "POSIX high-res time :" << m_fFactor << endl;
			#endif
		};
};

#endif // IRRTIMER_H

Last edited by xhrit on Thu Apr 13, 2006 6:12 pm, edited 1 time in total.
Core2Duo E8400 3.0ghz - 2048mb DDR2 800 - geForce 9600 - Slackware12.1

Word-image-symbol programming limits, controls, and imprisons the individual.
Smash the control images, smash the control machine.
hybrid

Post by hybrid »

I don't see where you made a real progress compared to Irrlicht native Timer. You both use gettimeofday such that the base is the same. What's the puspose of your delta calculations then? Moreover, gettimeofday can give precision in microseconds, so why not use these values? On the other hand, having milliseconds allows for 1000 FPS if each cycle can be used, so what benefits would come from this?
xhrit
Posts: 140
Joined: Mon Jun 14, 2004 8:54 am
Location: earth
Contact:

...

Post by xhrit »

Here is how I am using it for fixed timestep.

Code: Select all

sim_timer->Update();
float delta = sim_timer->m_fFactor;

delta += accumulator;

if ( delta > step*5 ) { delta = step*5; }
if ( delta < step/5 ) { delta = step/5; }

for(; delta >= step; delta -= step){
	m_simsys.Update(keybuffer);
}
accumulator = delta;

uncomment the output lines and you will get something like this in the console window :

...
irrlicht built in time :0.021
POSIX high-res time :0.021
irrlicht built in time :0.02
POSIX high-res time :0.019
irrlicht built in time :0.019
POSIX high-res time :0.02
irrlicht built in time :0.02
POSIX high-res time :0.021
...

As you can see... they are not the same. what one is more accurate? I don't know. All I know was that someone in irc told me there are issues with the built in timer.

It has been brought to my attention that to get microsecond accuracy I needed to use a 64bit datatype to store the value in. How would I go about doing that?

>You both use gettimeofday such that the base is the same.
What do you mean?

>having milliseconds allows for 1000 FPS if each cycle can be used, so what benefits would come from this?
It is all about the accumulator and smoothing out the simulation. I find that overall there is less jitteryness on lower end systems with the high res timer.
Core2Duo E8400 3.0ghz - 2048mb DDR2 800 - geForce 9600 - Slackware12.1

Word-image-symbol programming limits, controls, and imprisons the individual.
Smash the control images, smash the control machine.
drac_gd
Posts: 132
Joined: Sun Apr 09, 2006 8:43 pm

Post by drac_gd »

I just happened to be searching and came across your post for windows specific timer.. here is a class I have used for a long time. Feel free to pick pieces out of it or use the whole thing :)

/*******************************************************************
* Copyright (C) 2003 Brett R. Jones issued to public domain
*********************************************************************/

#ifndef TIMER_H
#define TIMER_H

//=== VxTimer Class object ===//
//there are a couple of ways to use the timer
// any call to StartTime with any value sets the start time
// so that calls to ElapsedTime return the Time since last called StartTimer or timer was constucted,

// The second mode is StartTimer with a time till done
// Susequent calls to TimeDone return FALSE if the specified TimeTillDone has not been
// reached or TRUE if the time has expired
//
// NOTE: even after the TimerDone has expired, calls to ElapsedTimer are still valid
class VxTimer
{
private:
__int64 m_i64StartTick;
__int64 m_i64TimerFrequency;
double m_dInverseFrequency;
double m_dTimeTillDone;

public:
VxTimer(){Init();}
~VxTimer( void ){}
void Init( void );//this function only added for instances when constructor doesnt get called
double ElapsedSec( void ); //return the elapsed time in seconds since
//StartTimer was called or VxTimer was constructed...it doesnt mater if the time
//specified in the StartTimer parameter has elapsed or not
double ElapsedMilliSec( void ){return (ElapsedSec()*1000);}
double ElapsedMicroSec( void ){return (ElapsedSec()*1000000);};
//just sets start time for elapsed time
void StartTimer( void ){QueryPerformanceCounter((LARGE_INTEGER *) &m_i64StartTick );}
//starts a timer and sets time till TimerDone returns true
void StartTimer( double dSec );
void StartMilliTimer( double dMilliSec ){ StartTimer( dMilliSec * 1000.0 );}
void StartMicroTimer( double dMicoSec ){ StartTimer( dMicoSec * 1000000.0 );}
BOOL TimerDone( void ){return ElapsedSec() * 1000000 > m_dTimeTillDone?1:0;}

void WaitTime( double dMicroSec );

};
//declare one for global use
extern VxTimer g_gTimer;

#endif //TIMER_H

/*******************************************************************
* Copyright (C) 2003 Brett R. Jones issued to public domain
*********************************************************************/

#include <stdafx.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

//#define TEST_TIMER 1 //define this to use the test program
#include "util/VxTimer.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


VxTimer g_gTimer;//global declaration

void VxTimer::Init( void )
{
QueryPerformanceFrequency( (LARGE_INTEGER *) &m_i64TimerFrequency );
QueryPerformanceCounter( (LARGE_INTEGER *) &m_i64StartTick );
m_dInverseFrequency = (1.0 / ((double)m_i64TimerFrequency));
}

void VxTimer::StartTimer( double dSec )
{
//get current tick count
//currently the Counter Frequency for win95 intel is 1,193,180 Hz or approx .000000838 sec
//a 32 bit counter will rollover in 3600 seconds or 1 Hour
//the 64 bit counter will rollover in 4294967296 hours or 502,000 years
QueryPerformanceCounter( (LARGE_INTEGER *) &m_i64StartTick );
m_dTimeTillDone = dSec * 1000000;
}
void VxTimer::WaitTime( double dMicroSec )
{
//===for all other modes just loop and wait for time to run out ===//
StartMicroTimer( dMicroSec );
int iFirstTime = TRUE;
while(! TimerDone())
{
// we want to sleep as much as possible so we dont waist cpu cycles but we
// want to be awake when timer is done
if( iFirstTime )
{
iFirstTime = FALSE;
if( dMicroSec > 2000 )
Sleep((long)(( dMicroSec -2000 ) / 1000.0));//should wake up 2ms before timer is done
iFirstTime = 0;
}
}
}

double VxTimer::ElapsedSec( void )
{
__int64 i64EndTick;
QueryPerformanceCounter( (LARGE_INTEGER *) &i64EndTick);
return (double)( i64EndTick-m_i64StartTick) * m_dInverseFrequency;
}


#ifdef TEST_TIMER
int main(int argc, char *argv[])
{

VxTimer gTimer;
double dDelay;
long lLoopCnt;
long i;
while(TRUE)
{
printf("\n VxTimer Frequency = %lf", gTimer.GetTimerFrequency());
printf("\n Enter Time To Delay in Micro Seconds ");
scanf("%lf", &dDelay);
printf("\n Enter The Number of Times to Delay ");
scanf("%ld", &lLoopCnt);
printf("\nNow Executing using TimerDone function");
for(i = 0; i < lLoopCnt; i++)
{
gTimer.StartMicroTimer(dDelay);
while(FALSE == gTimer.TimerDone())
;
}
printf("\nNow Executing using Elapsed Time function");

for(i = 0; i < lLoopCnt; i++)
{
gTimer.StartMicroTimer(0);
while(dDelay > gTimer.ElapsedMicroSec())
;
}
printf("\n*****************Finished******************");
printf("\nPress X to exit or any other key to do again \n");
fflush(stdin);
int val = getch();
if('X' == val || 'x' == val)
return 0;
}
}

#endif //TEST_TIMER
Nox587
Posts: 12
Joined: Mon Jul 10, 2006 6:42 pm

Post by Nox587 »

This article may interest you for a good timer

http://www.gamedev.net/reference/progra ... es/timing/

I personally don't recommend using the irrlicht timer, I havn't had good experiences with it. The timer represented in that article seems to be a good start at the very least. I also like the platform independant timer that Ogre uses, it also represents a good starting point for someone, although Ogre does use a platform manager so it would require a bit more digging around to find its implementation.
Post Reply