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"
/*
-----------------------------------------------------------------------------
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 "RageLog.h"
@@ -17,49 +6,56 @@
#include "SDL-1.2.5/include/SDL.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. */
RageTimer::RageTimer()
static RageTimer g_Start;
float RageTimer::GetTimeSinceStart()
{
Init();
GetDeltaTime(); /* so the next call to GetDeltaTime is from the construction of this object */
return g_Start.Ago();
}
void RageTimer::Init()
void RageTimer::Touch()
{
/*
This is needed for the "timer" system, not the "ticks" system; it often starts
a thread, so let's not do it--we don't need it.
static bool SDL_Initialized = false;
if(!SDL_Initialized) {
SDL_InitSubSystem(SDL_INIT_TIMER);
SDL_Initialized = true;
}
*/
unsigned ms = SDL_GetTicks();
this->m_secs = ms / 1000;
ms %= 1000;
unsigned mult = TIMESTAMP_RESOLUTION / 1000;
this->m_us = ms*mult;
}
float RageTimer::Ago() const
{
const RageTimer Now;
return Difference(*this, Now);
}
float RageTimer::GetDeltaTime()
{
/* Store the LDT in integral milliseconds, to avoid rounding error. */
int now = SDL_GetTicks();
int ret = now - m_iLastDeltaTime;
m_iLastDeltaTime = now;
return ret / 1000.f;
const RageTimer Now;
const float diff = Difference( Now, *this );
*this = Now;
return diff;
}
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()
{
return SDL_GetTicks() / 1000.f;
}
/* XXX: SDL_GetTicks() wraps every month or so. Handle it. */
unsigned int GetTicks()
{
return SDL_GetTicks();
}
/*
* Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
* Chris Danford
* Glenn Maynard
*/
+48 -16
View File
@@ -1,29 +1,61 @@
#ifndef RAGE_TIMER_H
#define RAGE_TIMER_H
/* Timer services. */
/*
-----------------------------------------------------------------------------
File: RageTimer.h
Desc: Timer services.
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
Chris Danford
-----------------------------------------------------------------------------
*/
* This can be used in two ways: as a timestamp or as a timer.
*
* As a timer,
* RageTimer Timer;
* while(1) {
* printf( "Will be approximately: %f", Timer.PeekDeltaTime()) ;
* 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
{
public:
RageTimer();
unsigned int GetTicks();
float GetDeltaTime(); // time between last call to GetDeltaTime()
float PeekDeltaTime() const;
RageTimer() { Touch(); }
/* Time ago this RageTimer represents. */
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
private:
static void Init();
int m_iLastDeltaTime;
static float Difference(const RageTimer &lhs, const RageTimer &rhs);
/* "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
/*
* Copyright (c) 2001-2003 by the person(s) listed below. All rights reserved.
* Chris Danford
* Glenn Maynard
*/