From fbcd8042436d3754f9cb368f39741a507e43f392 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sat, 12 Jul 2003 22:51:27 +0000 Subject: [PATCH] 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") --- stepmania/src/RageTimer.cpp | 82 ++++++++++++++++++------------------- stepmania/src/RageTimer.h | 64 +++++++++++++++++++++-------- 2 files changed, 87 insertions(+), 59 deletions(-) diff --git a/stepmania/src/RageTimer.cpp b/stepmania/src/RageTimer.cpp index bcbc0c43b2..b1a485bb00 100644 --- a/stepmania/src/RageTimer.cpp +++ b/stepmania/src/RageTimer.cpp @@ -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 + */ diff --git a/stepmania/src/RageTimer.h b/stepmania/src/RageTimer.h index bdea8d6839..a3d14fe7e0 100644 --- a/stepmania/src/RageTimer.h +++ b/stepmania/src/RageTimer.h @@ -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 + */