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"
|
#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
@@ -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 ×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
|
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
|
||||||
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user