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:
+39
-43
@@ -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
@@ -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 ×tamp ) {
|
||||
* 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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user