more precise timing

renamed Time::elapsed -> Time::seconds, change type to double
updated game to store ticks (microseconds) instead of milliseconds for better update precision
This commit is contained in:
Noel Berry 2021-02-06 00:13:50 -08:00
parent 2c2d668927
commit ac58379de8
13 changed files with 101 additions and 87 deletions

View File

@ -5,14 +5,20 @@ namespace Blah
{
struct Time
{
// uptime, in milliseconds
static uint64_t milliseconds;
// ticks per second (microseconds, in this case)
static constexpr uint64_t ticks_per_second = 1000000;
// uptime, in ticks
static uint64_t ticks;
// uptime, in seconds
static float elapsed;
static double seconds;
// previous frame uptime, in ticks
static uint64_t previous_ticks;
// previous frame uptime, in seconds
static float previous_elapsed;
static double previous_seconds;
// delta time from last frame
static float delta;
@ -21,10 +27,10 @@ namespace Blah
static float pause_timer;
// pauses the entire application for the given time
static void pause_for(float time);
static void pause_for(float duration);
// returns true on the given time interval
static bool on_interval(float time, float delta, float interval, float offset);
static bool on_interval(double time, float delta, float interval, float offset);
// returns true on the given time interval
static bool on_interval(float delta, float interval, float offset);
@ -33,10 +39,10 @@ namespace Blah
static bool on_interval(float interval, float offset = 0);
// returns true when the given timestamp is passed
static bool on_time(float time, float timestamp);
static bool on_time(double time, double timestamp);
// returns true between time intervals
static bool between_interval(float time, float interval, float offset);
static bool between_interval(double time, float interval, float offset);
// returns true between time intervals
static bool between_interval(float interval, float offset = 0);

View File

@ -61,9 +61,9 @@ namespace Blah
int m_last_value_i = 0;
bool m_pressed = false;
bool m_released = false;
float m_last_press_time = -1;
float m_last_release_time = -1;
float m_repeat_press_time = -1;
double m_last_press_time = -1;
double m_last_release_time = -1;
double m_repeat_press_time = -1;
public:
VirtualAxis& add_keys(Key negative, Key positive);

View File

@ -61,9 +61,9 @@ namespace Blah
bool m_down = false;
bool m_pressed = false;
bool m_released = false;
float m_last_press_time = -1;
float m_last_release_time = -1;
float m_repeat_press_time = -1;
double m_last_press_time = -1;
double m_last_release_time = -1;
double m_repeat_press_time = -1;
public:
VirtualButton& add_key(Key key);

View File

@ -70,9 +70,9 @@ namespace Blah
bool m_released = false;
float m_i_deadzone;
float m_last_press_time = -1;
float m_last_release_time = -1;
float m_repeat_press_time = -1;
double m_last_press_time = -1;
double m_last_release_time = -1;
double m_repeat_press_time = -1;
public:
VirtualStick();

View File

@ -6,13 +6,6 @@
using namespace Blah;
const uint16_t UTF8_LEAD_SURROGATE_MIN = 0xd800u;
const uint16_t UTF8_LEAD_SURROGATE_MAX = 0xdbffu;
const uint16_t UTF8_TRAIL_SURROGATE_MIN = 0xdc00u;
const uint16_t UTF8_TRAIL_SURROGATE_MAX = 0xdfffu;
const uint16_t UTF8_LEAD_OFFSET = UTF8_LEAD_SURROGATE_MIN - (0x10000 >> 10);
const uint32_t UTF8_SURROGATE_OFFSET = 0x10000u - (UTF8_LEAD_SURROGATE_MIN << 10) - UTF8_TRAIL_SURROGATE_MIN;
char Str::empty_buffer[1] = { '\0' };
bool Str::operator==(const Str& rhs) const
@ -217,24 +210,30 @@ Str& Str::append_fmt(const char* fmt, ...)
return *this;
}
Str& Str::append_utf16(const uint16_t* start, const uint16_t* end, bool swapEndian)
Str& Str::append_utf16(const uint16_t* start, const uint16_t* end, bool swap_endian)
{
// converts utf16 into utf8
// more info: https://en.wikipedia.org/wiki/UTF-16#Description
const uint16_t surrogate_min = 0xd800u;
const uint16_t surrogate_max = 0xdbffu;
while (start != end)
{
uint16_t next = (*start++);
if (swapEndian)
if (swap_endian)
next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8));
uint32_t cp = 0xffff & next;
if ((cp >= UTF8_LEAD_SURROGATE_MIN && cp <= UTF8_LEAD_SURROGATE_MAX))
if ((cp >= surrogate_min && cp <= surrogate_max))
{
next = (*start++);
if (swapEndian)
if (swap_endian)
next = ((next & 0xff) << 8 | ((next & 0xff00) >> 8));
uint32_t trail = 0xffff & next;
cp = (cp << 10) + trail + UTF8_SURROGATE_OFFSET;
cp = (cp << 10) + trail + 0x10000u - (surrogate_min << 10) - 0xdc00u;
}
append(cp);

View File

@ -48,8 +48,8 @@ namespace
// update at a fixed timerate
// TODO: allow a non-fixed step update?
{
uint64_t time_target = (uint64_t)((1.0f / app_config.target_framerate) * 1000);
uint64_t time_curr = PlatformBackend::time();
uint64_t time_target = (uint64_t)((1.0 / app_config.target_framerate) * Time::ticks_per_second);
uint64_t time_curr = PlatformBackend::ticks();
uint64_t time_diff = time_curr - time_last;
time_last = time_curr;
time_accumulator += time_diff;
@ -57,9 +57,10 @@ namespace
// do not let us run too fast
while (time_accumulator < time_target)
{
PlatformBackend::sleep((int)(time_target - time_accumulator));
int milliseconds = (int)(time_target - time_accumulator) / (Time::ticks_per_second / 1000);
PlatformBackend::sleep(milliseconds);
time_curr = PlatformBackend::time();
time_curr = PlatformBackend::ticks();
time_diff = time_curr - time_last;
time_last = time_curr;
time_accumulator += time_diff;
@ -81,15 +82,16 @@ namespace
if (Time::pause_timer > 0)
{
Time::pause_timer -= Time::delta;
if (Time::pause_timer <= -0.0001f)
if (Time::pause_timer <= -0.0001)
Time::delta = -Time::pause_timer;
else
continue;
}
Time::milliseconds += time_target;
Time::previous_elapsed = Time::elapsed;
Time::elapsed += Time::delta;
Time::previous_ticks = Time::ticks;
Time::ticks += time_target;
Time::previous_seconds = Time::seconds;
Time::seconds += Time::delta;
InputBackend::frame();
GraphicsBackend::frame();
@ -147,7 +149,7 @@ bool App::run(const Config* c)
if (app_config.on_startup != nullptr)
app_config.on_startup();
time_last = PlatformBackend::time();
time_last = PlatformBackend::ticks();
time_accumulator = 0;
// display window
@ -173,8 +175,11 @@ bool App::run(const Config* c)
// clear static state
app_is_running = false;
app_is_exiting = false;
Time::milliseconds = 0;
Time::elapsed = 0;
Time::ticks = 0;
Time::seconds = 0;
Time::previous_ticks = 0;
Time::previous_seconds = 0;
Time::delta = 0;
return true;

View File

@ -5,50 +5,51 @@ using namespace Blah;
namespace
{
float modf(float x, float m)
double modf(double x, double m)
{
return x - (int)(x / m) * m;
}
}
uint64_t Time::milliseconds = 0;
float Time::elapsed = 0;
uint64_t Time::ticks = 0;
uint64_t Time::previous_ticks = 0;
double Time::seconds = 0;
double Time::previous_seconds = 0;
float Time::delta = 0;
float Time::previous_elapsed = 0;
float Time::pause_timer = 0;
void Time::pause_for(float time)
void Time::pause_for(float duration)
{
if (time >= pause_timer)
pause_timer = time;
if (duration >= pause_timer)
pause_timer = duration;
}
bool Time::on_interval(float time, float delta, float interval, float offset)
bool Time::on_interval(double time, float delta, float interval, float offset)
{
return floor((time - offset - delta) / interval) < floor((time - offset) / interval);
}
bool Time::on_interval(float delta, float interval, float offset)
{
return Time::on_interval(Time::elapsed, delta, interval, offset);
return Time::on_interval(Time::seconds, delta, interval, offset);
}
bool Time::on_interval(float interval, float offset)
{
return Time::on_interval(Time::elapsed, Time::delta, interval, offset);
return Time::on_interval(Time::seconds, Time::delta, interval, offset);
}
bool Time::on_time(float time, float timestamp)
bool Time::on_time(double time, double timestamp)
{
return time >= timestamp && time - Time::delta < timestamp;
}
bool Time::between_interval(float time, float interval, float offset)
bool Time::between_interval(double time, float interval, float offset)
{
return modf(time - offset, interval * 2) >= interval;
}
bool Time::between_interval(float interval, float offset)
{
return between_interval(Time::elapsed, interval, offset);
return between_interval(Time::seconds, interval, offset);
}

View File

@ -93,7 +93,7 @@ void InputBackend::on_mouse_down(MouseButton button)
{
g_next_state.mouse.down[i] = true;
g_next_state.mouse.pressed[i] = true;
g_next_state.mouse.timestamp[i] = Time::milliseconds;
g_next_state.mouse.timestamp[i] = Time::ticks;
}
}
@ -114,7 +114,7 @@ void InputBackend::on_key_down(Key key)
{
g_next_state.keyboard.down[i] = true;
g_next_state.keyboard.pressed[i] = true;
g_next_state.keyboard.timestamp[i] = Time::milliseconds;
g_next_state.keyboard.timestamp[i] = Time::ticks;
}
}
@ -170,7 +170,7 @@ void InputBackend::on_button_down(int index, int button)
{
g_next_state.controllers[index].down[button] = 1;
g_next_state.controllers[index].pressed[button] = 1;
g_next_state.controllers[index].button_timestamp[button] = Time::milliseconds;
g_next_state.controllers[index].button_timestamp[button] = Time::ticks;
}
}
@ -194,7 +194,7 @@ void InputBackend::on_axis_move(int index, int axis, float value)
axis < g_next_state.controllers[index].axis_count)
{
g_next_state.controllers[index].axis[axis] = value;
g_next_state.controllers[index].axis_timestamp[axis] = Time::milliseconds;
g_next_state.controllers[index].axis_timestamp[axis] = Time::ticks;
}
}

View File

@ -102,16 +102,16 @@ void VirtualAxis::update()
if (m_value_i != 0 && m_last_value_i != m_value_i)
{
m_pressed = true;
m_last_press_time = m_repeat_press_time = Time::elapsed;
m_last_press_time = m_repeat_press_time = Time::seconds;
}
else if (m_value_i == m_last_value_i && m_value_i != 0)
{
if (Time::elapsed - m_last_press_time <= m_press_buffer)
if (Time::seconds - m_last_press_time <= m_press_buffer)
m_pressed = true;
else if (m_repeat_interval > 0 && Time::elapsed >= m_repeat_press_time + m_repeat_delay)
else if (m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay)
{
int prev = (int)((Time::previous_elapsed - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int cur = (int)((Time::elapsed - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
m_pressed = prev < cur;
}
}
@ -120,9 +120,9 @@ void VirtualAxis::update()
if (m_last_value_i != 0 && m_value_i != m_last_value_i)
{
m_released = true;
m_last_release_time = Time::elapsed;
m_last_release_time = Time::seconds;
}
else if (Time::elapsed - m_last_release_time <= m_release_buffer)
else if (Time::seconds - m_last_release_time <= m_release_buffer)
m_released = true;
else
m_released = false;

View File

@ -68,7 +68,7 @@ void VirtualButton::update()
m_pressed = false;
m_released = false;
//Keys
// Keys
for (int i = 0; i < m_keys_len; i++)
{
m_keys[i].update();
@ -78,7 +78,7 @@ void VirtualButton::update()
m_released = m_released || m_keys[i].released;
}
//Buttons
// Buttons
for (int i = 0; i < m_buttons_len; i++)
{
m_buttons[i].update();
@ -88,7 +88,7 @@ void VirtualButton::update()
m_released = m_released || m_buttons[i].released;
}
//Axes
// Axes
for (int i = 0; i < m_axes_len; i++)
{
m_axes[i].update();
@ -98,27 +98,27 @@ void VirtualButton::update()
m_released = m_released || m_axes[i].released;
}
//pressed?
// pressed?
if (m_pressed)
{
m_repeat_press_time = m_last_press_time = Time::elapsed;
m_repeat_press_time = m_last_press_time = Time::seconds;
}
else if (Time::elapsed - m_last_press_time <= m_press_buffer)
else if (Time::seconds - m_last_press_time <= m_press_buffer)
{
m_pressed = true;
}
else if (m_down && m_repeat_interval > 0 && Time::elapsed >= m_repeat_press_time + m_repeat_delay)
else if (m_down && m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay)
{
int prev = (int)((Time::previous_elapsed - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int cur = (int)((Time::elapsed - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
m_pressed = prev < cur;
}
//released?
// released?
if (m_released)
m_last_release_time = Time::elapsed;
m_last_release_time = Time::seconds;
else
m_released = Time::elapsed - m_last_release_time <= m_release_buffer;
m_released = Time::seconds - m_last_release_time <= m_release_buffer;
}
void VirtualButton::KeyNode::init(Key key)

View File

@ -118,16 +118,16 @@ void VirtualStick::update()
if (m_value_i != Point::zero && m_last_value_i != m_value_i)
{
m_pressed = true;
m_last_press_time = m_repeat_press_time = Time::elapsed;
m_last_press_time = m_repeat_press_time = Time::seconds;
}
else if (m_value_i == m_last_value_i && m_value_i != Point::zero)
{
if (Time::elapsed - m_last_press_time <= m_press_buffer)
if (Time::seconds - m_last_press_time <= m_press_buffer)
m_pressed = true;
else if (m_repeat_interval > 0 && Time::elapsed >= m_repeat_press_time + m_repeat_delay)
else if (m_repeat_interval > 0 && Time::seconds >= m_repeat_press_time + m_repeat_delay)
{
int prev = (int)((Time::previous_elapsed - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int cur = (int)((Time::elapsed - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int prev = (int)((Time::previous_seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
int cur = (int)((Time::seconds - m_repeat_press_time - m_repeat_delay) / m_repeat_interval);
m_pressed = prev < cur;
}
}
@ -136,9 +136,9 @@ void VirtualStick::update()
if (m_last_value_i != Point::zero && m_value_i != m_last_value_i)
{
m_released = true;
m_last_release_time = Time::elapsed;
m_last_release_time = Time::seconds;
}
else if (Time::elapsed - m_last_release_time <= m_release_buffer)
else if (Time::seconds - m_last_release_time <= m_release_buffer)
m_released = true;
else
m_released = false;

View File

@ -21,8 +21,8 @@ namespace Blah
// Called during shutdown
void shutdown();
// The time, in milliseconds, since the Application was started
uint64_t time();
// The time, in ticks (microseconds) since the Application was started
uint64_t ticks();
// Called every frame
void frame();

View File

@ -7,6 +7,7 @@
#include <blah/core/app.h>
#include <blah/core/filesystem.h>
#include <blah/core/log.h>
#include <blah/core/time.h>
#include <SDL.h>
#include <SDL_vulkan.h>
@ -170,9 +171,11 @@ void PlatformBackend::shutdown()
SDL_Quit();
}
uint64_t PlatformBackend::time()
uint64_t PlatformBackend::ticks()
{
return (uint64_t)SDL_GetTicks();
auto counter = SDL_GetPerformanceCounter();
auto per_second = (double)SDL_GetPerformanceFrequency();
return (uint64_t)(counter * (Time::ticks_per_second / per_second));
}
// Macro defined by X11 conflicts with MouseButton enum