Ian Burgmyer
4 years ago
7 changed files with 174 additions and 2 deletions
@ -0,0 +1,18 @@
|
||||
/* Timer.h
|
||||
* |
||||
* Implements an interface for a high precision timer and stopwatch. |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
namespace PlipSdl { |
||||
class Timer { |
||||
public: |
||||
virtual void Nanosleep(long ns) = 0; |
||||
virtual void StopwatchStart() = 0; |
||||
virtual long StopwatchStop() = 0; |
||||
|
||||
protected: |
||||
Timer() = default; |
||||
}; |
||||
} |
@ -0,0 +1,30 @@
|
||||
/* TimerPosix.cpp
|
||||
*/ |
||||
|
||||
#include "TimerPosix.h" |
||||
|
||||
namespace PlipSdl { |
||||
#pragma clang diagnostic push |
||||
#pragma ide diagnostic ignored "cppcoreguidelines-pro-type-member-init" |
||||
void TimerPosix::Nanosleep(const long ns) { |
||||
const struct timespec req { // tv_nsec must be under 1 million
|
||||
.tv_sec = ns / 1000000000, |
||||
.tv_nsec = ns % 1000000000 |
||||
}; |
||||
struct timespec rem; // Populated by nanosleep().
|
||||
nanosleep(&req, nullptr); |
||||
} |
||||
|
||||
void TimerPosix::StopwatchStart() { |
||||
clock_gettime(CLOCK_MONOTONIC, &m_stopwatchVal); |
||||
} |
||||
|
||||
long TimerPosix::StopwatchStop() { |
||||
struct timespec end_val; |
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &end_val); |
||||
return ((end_val.tv_sec - m_stopwatchVal.tv_sec) * 1000000) |
||||
+ (end_val.tv_nsec - m_stopwatchVal.tv_nsec); |
||||
} |
||||
#pragma clang diagnostic pop |
||||
} |
@ -0,0 +1,24 @@
|
||||
/* TimerPosix.h
|
||||
* |
||||
* Uses the POSIX nanosleep function to maintain timing. |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <ctime> |
||||
|
||||
#include "Timer.h" |
||||
|
||||
namespace PlipSdl { |
||||
class TimerPosix : public Timer { |
||||
public: |
||||
TimerPosix() = default; |
||||
|
||||
void Nanosleep(long ns) override; |
||||
void StopwatchStart() override; |
||||
long StopwatchStop() override; |
||||
|
||||
private: |
||||
struct timespec m_stopwatchVal {}; |
||||
}; |
||||
} |
@ -0,0 +1,45 @@
|
||||
/* TimerSdl.h
|
||||
* |
||||
* Uses SDL's delay function to maintain timing. Since SDL's only supports |
||||
* millisecond accuracy, using the native OS timing functions is preferred |
||||
* where possible. |
||||
*/ |
||||
|
||||
#include "TimerSdl.h" |
||||
|
||||
#define MS_TO_NS(ms) ((ms) * 1000000) |
||||
#define NS_TO_MS(ns) ((ns) / 1000000) |
||||
|
||||
namespace PlipSdl { |
||||
void TimerSdl::Nanosleep(const long ns) { |
||||
// SDL2's timing functions are only precise to the millisecond, so we
|
||||
// save the lost precision and apply it to a future function call.
|
||||
// This method is not suitable for repeated short delays, but is
|
||||
// generally fine for maintaining timing.
|
||||
Uint32 waitTime = NS_TO_MS(ns); |
||||
m_sleepSkew += (float)ns / 1000000 - waitTime; |
||||
|
||||
if(m_sleepSkew >= 1) { |
||||
Uint32 skewAdd = (long)m_sleepSkew; |
||||
waitTime += skewAdd; |
||||
m_sleepSkew -= skewAdd; |
||||
} |
||||
|
||||
if(waitTime > 0) |
||||
SDL_Delay(waitTime); |
||||
} |
||||
|
||||
void TimerSdl::StopwatchStart() { |
||||
m_stopwatchVal = SDL_GetTicks(); |
||||
} |
||||
|
||||
long TimerSdl::StopwatchStop() { |
||||
Uint32 endVal = SDL_GetTicks(); |
||||
if(endVal >= m_stopwatchVal) |
||||
return MS_TO_NS(endVal - m_stopwatchVal); |
||||
|
||||
// The timer wraps around after 49 days. Try to cope with the stopwatch
|
||||
// running for that length of time. :'(
|
||||
return MS_TO_NS((UINT32_MAX - endVal) + m_stopwatchVal); |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
/* TimerSdl.h
|
||||
* |
||||
* Uses SDL's delay function to maintain timing. Since SDL's only supports |
||||
* millisecond accuracy, using the native OS timing functions is preferred |
||||
* where possible. |
||||
*/ |
||||
|
||||
#pragma once |
||||
|
||||
#include <SDL.h> |
||||
|
||||
#include "Timer.h" |
||||
|
||||
namespace PlipSdl { |
||||
class TimerSdl : public Timer { |
||||
public: |
||||
TimerSdl() = default; |
||||
|
||||
void Nanosleep(long ns) override; |
||||
void StopwatchStart() override; |
||||
long StopwatchStop() override; |
||||
|
||||
private: |
||||
float m_sleepSkew = 0; |
||||
Uint32 m_stopwatchVal = 0; |
||||
}; |
||||
} |
Loading…
Reference in new issue