I know there is some pretty horrid stuff happening in there, but it seems to do a reasonable job.
Comments, suggestions, criticisms welcome.
Code: Select all
// Filename: Timer.h
// Author: Caswal 'Zeussy' Parker
// Date: 11th June 2008
// License: Use as you want for what you want, just leave this documentation at the top of the file.
// I am not liable for any harm this may file may cause. Use at your own risk.
//
// Description: The ultimate time elapsed class for games and other time critical applications
// Has specific time elapsed calls as well as a general one
// Uses Singleton Design Patter so accessibly globally
// It can also callback functions and member functions of a class
//
// Usage: Above int main(int argc, char* argv[]) add INIT_TIMER
// float DT = Timer.getTimeElapsed();
// float DT = Timer.getTimeElasped("Player");
// float DT = Timer["Player"];
//
// Timer.addCallback( &func, 3 );
// Timer.addMemberCallback<bar>( &object, &bar::func, 5 );
//
// Timer.update(); //Must be called every so often, probably once an update/main loop
#ifndef __TIMER_H__
#define __TIMER_H__
#include <list>
#include <map>
#include <string>
#include <windows.h>
#define Timer (*CTimer::Instance())
#define PTimer (CTimer::Instance())
#define INIT_TIMER CTimer* CTimer::instance = 0;
class CTimer
{
//Keep these private, else we ain't no singleton
CTimer(void)
{
//Better restrict to 1 processor, for good ol Performance Counter
SetProcessAffinityMask( GetCurrentProcess(), 1L );
QueryPerformanceFrequency( &freq );
QueryPerformanceCounter( &prevTime );
}
virtual ~CTimer(void) {};
public:
//The instance function, if anyones cares to invoke it by hand
static CTimer* Instance()
{
if ( instance == 0 )
return instance = new CTimer();
return instance;
}
//Destroy function for the singleton
static void Destroy()
{
delete instance;
instance = 0;
}
//The lazy way of getting time elapsed for a specific timer
float operator[](const char* name)
{
return getTimeElapsed(name);
}
//The way of getting the generic time elapsed, or a specific
float getTimeElapsed(const char* name = 0)
{
LARGE_INTEGER CurrentTime;
if ( name )
{
if ( times[name].QuadPart == 0 )
{
QueryPerformanceCounter( ×[name] );
return 0.f;
} else
{
QueryPerformanceCounter( &CurrentTime );
LARGE_INTEGER Difference;
Difference.QuadPart = CurrentTime.QuadPart - times[name].QuadPart;
QueryPerformanceCounter( ×[name] );
return (float)Difference.QuadPart / (float)freq.QuadPart;
}
}
else
{
QueryPerformanceCounter( &CurrentTime );
LARGE_INTEGER Difference;
Difference.QuadPart = CurrentTime.QuadPart - prevTime.QuadPart;
QueryPerformanceCounter( &prevTime );
return (float)Difference.QuadPart / (float)freq.QuadPart;
}
}
//Function Pointer Typedef
typedef void (*fptr)(void);
//Add a simple void func(void) function to be called back later
void addCallback( fptr ptr, float timeToCallInSecs )
{
SCallback temp;
temp.func = ptr;
temp.timeToCall = timeToCallInSecs;
QueryPerformanceCounter( &(temp.startTime) );
callbacks.push_back(temp);
}
//Add a member void func(void) function of a class to be called back later
template <class T> void addMemberCallback(T *Object, void (T::*fmptr)(), float TimeToCall )
{
SMemberCallback tempCall;
tempCall.Object = Object;
tempCall.timeToCall = TimeToCall;
QueryPerformanceCounter( &(tempCall.startTime) );
typedef void (SMemberCallback::*cast)();
tempCall.fmptr = (cast)fmptr;
memberCallbacks.push_back(tempCall);
}
//For timed callbacks
//After enough time has elapsed, execure the callbacks
void update()
{
//Get the current time
LARGE_INTEGER CurrentTime;
QueryPerformanceCounter( &CurrentTime );
//Some more Local Scope
{
std::list<SCallback>::iterator iter = callbacks.begin();
//Loop through the callbacks, call and erase any callbacks thate are ready
while(iter != callbacks.end())
{
float diff = (float)(CurrentTime.QuadPart - prevTime.QuadPart) / (float)freq.QuadPart;
if ( diff > iter->timeToCall )
{
(*iter->func)();
iter = callbacks.erase(iter++);
}
else
iter++;
}
}
std::list<SMemberCallback>::iterator iter = memberCallbacks.begin();
//Loop through the member callbacks
while(iter != memberCallbacks.end())
{
float diff = (float)(CurrentTime.QuadPart - prevTime.QuadPart) / (float)freq.QuadPart;
if ( diff > iter->timeToCall )
{
//Omg it burns us!
//I am unsure if this is virtual safe?
//I would assume so as the function pointer originally passed
//Has to be from the type to be allowed to be passed as a parameter of addCallback
//The SMemberCallback* typecast is just to get around the problem that you cannot
//Invoke a function on a void datatype
//A few tests seem to indicate that this is fine
((SMemberCallback*)iter->Object->*iter->fmptr)();
iter = memberCallbacks.erase(iter++);
}
else
iter++;
}
}
private:
//Current Instance
static CTimer *instance;
//Map for all the specific time elapsed
std::map<std::string, LARGE_INTEGER> times;
//Generic timer stuff
LARGE_INTEGER prevTime;
LARGE_INTEGER freq;
//Callback vars and types
//Standard function callback
struct SCallback
{
fptr func;
float timeToCall;
LARGE_INTEGER startTime;
};
//Member function callback
struct SMemberCallback
{
void (SMemberCallback::*fmptr)(void);
void *Object;
float timeToCall;
LARGE_INTEGER startTime;
};
//The list of callback
std::list<SCallback> callbacks;
std::list<SMemberCallback> memberCallbacks;
};
#endif