Fixes two major problems: time wrapping every 42 days, and timer

resolution getting poor after a couple days of play.

(for some value of "major")
This commit is contained in:
Glenn Maynard
2003-07-12 22:51:27 +00:00
parent cbfa6c72fc
commit fbcd804243
2 changed files with 87 additions and 59 deletions
+39 -43
View File
@@ -1,15 +1,4 @@
#include "global.h" #include "global.h"
/*
-----------------------------------------------------------------------------
File: RageTimer.cpp
Desc: See header.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
#include "RageTimer.h" #include "RageTimer.h"
#include "RageLog.h" #include "RageLog.h"
@@ -17,49 +6,56 @@
#include "SDL-1.2.5/include/SDL.h" #include "SDL-1.2.5/include/SDL.h"
#include "SDL-1.2.5/include/SDL_timer.h" #include "SDL-1.2.5/include/SDL_timer.h"
const float SECS_IN_DAY = 60*60*24; /* We only actually get 1000 using SDL. */
#define TIMESTAMP_RESOLUTION 1000000
/* XXX: SDL_GetTicks() wraps every month or so. Handle it. */ static RageTimer g_Start;
RageTimer::RageTimer()
float RageTimer::GetTimeSinceStart()
{ {
Init(); return g_Start.Ago();
GetDeltaTime(); /* so the next call to GetDeltaTime is from the construction of this object */
} }
void RageTimer::Init() void RageTimer::Touch()
{ {
/* unsigned ms = SDL_GetTicks();
This is needed for the "timer" system, not the "ticks" system; it often starts this->m_secs = ms / 1000;
a thread, so let's not do it--we don't need it. ms %= 1000;
static bool SDL_Initialized = false;
if(!SDL_Initialized) { unsigned mult = TIMESTAMP_RESOLUTION / 1000;
SDL_InitSubSystem(SDL_INIT_TIMER); this->m_us = ms*mult;
SDL_Initialized = true; }
}
*/ float RageTimer::Ago() const
{
const RageTimer Now;
return Difference(*this, Now);
} }
float RageTimer::GetDeltaTime() float RageTimer::GetDeltaTime()
{ {
/* Store the LDT in integral milliseconds, to avoid rounding error. */ const RageTimer Now;
int now = SDL_GetTicks(); const float diff = Difference( Now, *this );
int ret = now - m_iLastDeltaTime; *this = Now;
m_iLastDeltaTime = now; return diff;
return ret / 1000.f;
} }
float RageTimer::PeekDeltaTime() const float RageTimer::Difference(const RageTimer &lhs, const RageTimer &rhs)
{ {
return (SDL_GetTicks() - m_iLastDeltaTime) / 1000.f; int secs = lhs.m_secs - rhs.m_secs;
int us = lhs.m_us - rhs.m_us;
if( us < 0 )
{
us += TIMESTAMP_RESOLUTION;
--secs;
}
return float(secs) + float(us) / TIMESTAMP_RESOLUTION;
} }
float RageTimer::GetTimeSinceStart() /*
{ * Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
return SDL_GetTicks() / 1000.f; * Chris Danford
} * Glenn Maynard
*/
/* XXX: SDL_GetTicks() wraps every month or so. Handle it. */
unsigned int GetTicks()
{
return SDL_GetTicks();
}
+48 -16
View File
@@ -1,29 +1,61 @@
#ifndef RAGE_TIMER_H #ifndef RAGE_TIMER_H
#define RAGE_TIMER_H #define RAGE_TIMER_H
/* Timer services. */
/* /*
----------------------------------------------------------------------------- * This can be used in two ways: as a timestamp or as a timer.
File: RageTimer.h *
* As a timer,
Desc: Timer services. * RageTimer Timer;
* while(1) {
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved. * printf( "Will be approximately: %f", Timer.PeekDeltaTime()) ;
Chris Danford * float fDeltaTime = Timer.GetDeltaTime();
----------------------------------------------------------------------------- * }
*/ *
* or as a timestamp:
* void foo( RageTimer &timestamp ) {
* if( timestamp.IsZero() )
* printf( "The timestamp isn't set." );
* else
* printf( "The timestamp happened %f ago", timestamp.Ago() );
* timestamp.Touch();
* printf( "Near zero: %f", timestamp.Age() );
* }
*/
class RageTimer class RageTimer
{ {
public: public:
RageTimer(); RageTimer() { Touch(); }
unsigned int GetTicks();
float GetDeltaTime(); // time between last call to GetDeltaTime() /* Time ago this RageTimer represents. */
float PeekDeltaTime() const; float Ago() const;
inline void Touch();
inline bool IsZero() const { return m_secs == 0 && m_us == 0; }
inline void SetZero() { m_secs = m_us = 0; }
/* Time between last call to GetDeltaTime() (Ago() + Touch()): */
float GetDeltaTime();
/* (alias) */
float PeekDeltaTime() const { return Ago(); }
/* deprecated: */
static float GetTimeSinceStart(); // seconds since the program was started static float GetTimeSinceStart(); // seconds since the program was started
private: private:
static void Init(); static float Difference(const RageTimer &lhs, const RageTimer &rhs);
int m_iLastDeltaTime;
/* "float" is bad for a "time since start" RageTimer. If the game is running for
* several days, we'll lose a lot of resolution. I don't want to use double
* everywhere, since it's slow. I'd rather not use double just for RageTimers, since
* it's too easy to get a type wrong and end up with obscure resolution problems. */
unsigned m_secs, m_us;
}; };
#endif #endif
/*
* Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
* Chris Danford
* Glenn Maynard
*/