Move time related functions out of CSystemUtils
GetCurrentTimeStamp() has not been moved because of CApplication unit tests.fix-squashed-planets
parent
5daaba6e64
commit
a69b88e09a
|
@ -83,6 +83,8 @@ add_library(colobotbase STATIC
|
||||||
common/singleton.h
|
common/singleton.h
|
||||||
common/stringutils.cpp
|
common/stringutils.cpp
|
||||||
common/stringutils.h
|
common/stringutils.h
|
||||||
|
common/timeutils.cpp
|
||||||
|
common/timeutils.h
|
||||||
common/thread/worker_thread.h
|
common/thread/worker_thread.h
|
||||||
graphics/core/color.cpp
|
graphics/core/color.cpp
|
||||||
graphics/core/color.h
|
graphics/core/color.h
|
||||||
|
|
|
@ -61,6 +61,9 @@
|
||||||
#include <localename.h>
|
#include <localename.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
using TimeUtils::TimeStamp;
|
||||||
|
using TimeUtils::TimeUnit;
|
||||||
|
|
||||||
char CApplication::m_languageLocale[] = { 0 };
|
char CApplication::m_languageLocale[] = { 0 };
|
||||||
|
|
||||||
|
|
||||||
|
@ -70,7 +73,6 @@ const int JOYSTICK_TIMER_INTERVAL = 1000/30;
|
||||||
//! Function called by the timer
|
//! Function called by the timer
|
||||||
Uint32 JoystickTimerCallback(Uint32 interval, void *);
|
Uint32 JoystickTimerCallback(Uint32 interval, void *);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \struct ApplicationPrivate
|
* \struct ApplicationPrivate
|
||||||
* \brief Private data of CApplication class
|
* \brief Private data of CApplication class
|
||||||
|
@ -1043,9 +1045,9 @@ int CApplication::Run()
|
||||||
|
|
||||||
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
|
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
|
||||||
|
|
||||||
SystemTimeStamp previousTimeStamp{};
|
TimeStamp previousTimeStamp{};
|
||||||
SystemTimeStamp currentTimeStamp{};
|
TimeStamp currentTimeStamp{};
|
||||||
SystemTimeStamp interpolatedTimeStamp{};
|
TimeStamp interpolatedTimeStamp{};
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -1153,7 +1155,7 @@ int CApplication::Run()
|
||||||
currentTimeStamp = m_systemUtils->GetCurrentTimeStamp();
|
currentTimeStamp = m_systemUtils->GetCurrentTimeStamp();
|
||||||
for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++)
|
for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++)
|
||||||
{
|
{
|
||||||
interpolatedTimeStamp = m_systemUtils->TimeStampLerp(previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
|
interpolatedTimeStamp = TimeUtils::Lerp(previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(numTickSlices));
|
||||||
Event event = CreateUpdateEvent(interpolatedTimeStamp);
|
Event event = CreateUpdateEvent(interpolatedTimeStamp);
|
||||||
if (event.type != EVENT_NULL && m_controller != nullptr)
|
if (event.type != EVENT_NULL && m_controller != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -1478,7 +1480,7 @@ void CApplication::Render()
|
||||||
void CApplication::RenderIfNeeded(int updateRate)
|
void CApplication::RenderIfNeeded(int updateRate)
|
||||||
{
|
{
|
||||||
m_manualFrameTime = m_systemUtils->GetCurrentTimeStamp();
|
m_manualFrameTime = m_systemUtils->GetCurrentTimeStamp();
|
||||||
long long diff = m_systemUtils->TimeStampExactDiff(m_manualFrameLast, m_manualFrameTime);
|
long long diff = TimeUtils::ExactDiff(m_manualFrameLast, m_manualFrameTime);
|
||||||
if (diff < 1e9f / updateRate)
|
if (diff < 1e9f / updateRate)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -1522,13 +1524,13 @@ void CApplication::StartLoadingMusic()
|
||||||
std::thread{[this]()
|
std::thread{[this]()
|
||||||
{
|
{
|
||||||
GetLogger()->Debug("Cache sounds...\n");
|
GetLogger()->Debug("Cache sounds...\n");
|
||||||
SystemTimeStamp musicLoadStart{m_systemUtils->GetCurrentTimeStamp()};
|
TimeStamp musicLoadStart{m_systemUtils->GetCurrentTimeStamp()};
|
||||||
|
|
||||||
m_sound->Reset();
|
m_sound->Reset();
|
||||||
m_sound->CacheAll();
|
m_sound->CacheAll();
|
||||||
|
|
||||||
SystemTimeStamp musicLoadEnd{m_systemUtils->GetCurrentTimeStamp()};
|
TimeStamp musicLoadEnd{m_systemUtils->GetCurrentTimeStamp()};
|
||||||
float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, SystemTimeUnit::MILLISECONDS);
|
float musicLoadTime = TimeUtils::Diff(musicLoadStart, musicLoadEnd, TimeUnit::MILLISECONDS);
|
||||||
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
|
GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime);
|
||||||
}}.detach();
|
}}.detach();
|
||||||
}
|
}
|
||||||
|
@ -1549,7 +1551,7 @@ void CApplication::SetSimulationSpeed(float speed)
|
||||||
GetLogger()->Info("Simulation speed = %.2f\n", speed);
|
GetLogger()->Info("Simulation speed = %.2f\n", speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
Event CApplication::CreateUpdateEvent(SystemTimeStamp newTimeStamp)
|
Event CApplication::CreateUpdateEvent(TimeStamp newTimeStamp)
|
||||||
{
|
{
|
||||||
if (m_simulationSuspended)
|
if (m_simulationSuspended)
|
||||||
return Event(EVENT_NULL);
|
return Event(EVENT_NULL);
|
||||||
|
@ -1557,9 +1559,9 @@ Event CApplication::CreateUpdateEvent(SystemTimeStamp newTimeStamp)
|
||||||
m_lastTimeStamp = m_curTimeStamp;
|
m_lastTimeStamp = m_curTimeStamp;
|
||||||
m_curTimeStamp = newTimeStamp;
|
m_curTimeStamp = newTimeStamp;
|
||||||
|
|
||||||
long long absDiff = m_systemUtils->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
|
long long absDiff = TimeUtils::ExactDiff(m_baseTimeStamp, m_curTimeStamp);
|
||||||
long long newRealAbsTime = m_realAbsTimeBase + absDiff;
|
long long newRealAbsTime = m_realAbsTimeBase + absDiff;
|
||||||
long long newRealRelTime = m_systemUtils->TimeStampExactDiff(m_lastTimeStamp, m_curTimeStamp);
|
long long newRealRelTime = TimeUtils::ExactDiff(m_lastTimeStamp, m_curTimeStamp);
|
||||||
|
|
||||||
if (newRealAbsTime < m_realAbsTime || newRealRelTime < 0)
|
if (newRealAbsTime < m_realAbsTime || newRealRelTime < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -297,7 +297,7 @@ protected:
|
||||||
//! If applicable, creates a virtual event to match the changed state as of new event
|
//! If applicable, creates a virtual event to match the changed state as of new event
|
||||||
Event CreateVirtualEvent(const Event& sourceEvent);
|
Event CreateVirtualEvent(const Event& sourceEvent);
|
||||||
//! Prepares a simulation update event
|
//! Prepares a simulation update event
|
||||||
TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp newTimeStamp);
|
TEST_VIRTUAL Event CreateUpdateEvent(TimeUtils::TimeStamp newTimeStamp);
|
||||||
//! Logs debug data for event
|
//! Logs debug data for event
|
||||||
void LogEvent(const Event& event);
|
void LogEvent(const Event& event);
|
||||||
|
|
||||||
|
@ -354,9 +354,9 @@ protected:
|
||||||
|
|
||||||
//! Animation time stamps, etc.
|
//! Animation time stamps, etc.
|
||||||
//@{
|
//@{
|
||||||
SystemTimeStamp m_baseTimeStamp;
|
TimeUtils::TimeStamp m_baseTimeStamp;
|
||||||
SystemTimeStamp m_lastTimeStamp;
|
TimeUtils::TimeStamp m_lastTimeStamp;
|
||||||
SystemTimeStamp m_curTimeStamp;
|
TimeUtils::TimeStamp m_curTimeStamp;
|
||||||
|
|
||||||
long long m_realAbsTimeBase;
|
long long m_realAbsTimeBase;
|
||||||
long long m_realAbsTime;
|
long long m_realAbsTime;
|
||||||
|
@ -373,8 +373,8 @@ protected:
|
||||||
bool m_simulationSuspended;
|
bool m_simulationSuspended;
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
SystemTimeStamp m_manualFrameLast;
|
TimeUtils::TimeStamp m_manualFrameLast;
|
||||||
SystemTimeStamp m_manualFrameTime;
|
TimeUtils::TimeStamp m_manualFrameTime;
|
||||||
|
|
||||||
//! Graphics device to use
|
//! Graphics device to use
|
||||||
bool m_graphicsOverride = false;
|
bool m_graphicsOverride = false;
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
using TimeUtils::TimeStamp;
|
||||||
|
|
||||||
CSystemUtils* CProfiler::m_systemUtils = nullptr;
|
CSystemUtils* CProfiler::m_systemUtils = nullptr;
|
||||||
long long CProfiler::m_performanceCounters[PCNT_MAX] = {0};
|
long long CProfiler::m_performanceCounters[PCNT_MAX] = {0};
|
||||||
long long CProfiler::m_prevPerformanceCounters[PCNT_MAX] = {0};
|
long long CProfiler::m_prevPerformanceCounters[PCNT_MAX] = {0};
|
||||||
std::stack<SystemTimeStamp> CProfiler::m_runningPerformanceCounters;
|
std::stack<TimeStamp> CProfiler::m_runningPerformanceCounters;
|
||||||
std::stack<PerformanceCounter> CProfiler::m_runningPerformanceCountersType;
|
std::stack<PerformanceCounter> CProfiler::m_runningPerformanceCountersType;
|
||||||
|
|
||||||
void CProfiler::SetSystemUtils(CSystemUtils* systemUtils)
|
void CProfiler::SetSystemUtils(CSystemUtils* systemUtils)
|
||||||
|
@ -39,7 +41,7 @@ void CProfiler::StartPerformanceCounter(PerformanceCounter counter)
|
||||||
if (counter == PCNT_ALL)
|
if (counter == PCNT_ALL)
|
||||||
ResetPerformanceCounters();
|
ResetPerformanceCounters();
|
||||||
|
|
||||||
SystemTimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
|
TimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
|
||||||
m_runningPerformanceCounters.push(timeStamp);
|
m_runningPerformanceCounters.push(timeStamp);
|
||||||
m_runningPerformanceCountersType.push(counter);
|
m_runningPerformanceCountersType.push(counter);
|
||||||
}
|
}
|
||||||
|
@ -49,8 +51,8 @@ void CProfiler::StopPerformanceCounter(PerformanceCounter counter)
|
||||||
assert(m_runningPerformanceCountersType.top() == counter);
|
assert(m_runningPerformanceCountersType.top() == counter);
|
||||||
m_runningPerformanceCountersType.pop();
|
m_runningPerformanceCountersType.pop();
|
||||||
|
|
||||||
SystemTimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
|
TimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp();
|
||||||
m_performanceCounters[counter] += m_systemUtils->TimeStampExactDiff(m_runningPerformanceCounters.top(), timeStamp);
|
m_performanceCounters[counter] += TimeUtils::ExactDiff(m_runningPerformanceCounters.top(), timeStamp);
|
||||||
m_runningPerformanceCounters.pop();
|
m_runningPerformanceCounters.pop();
|
||||||
|
|
||||||
if (counter == PCNT_ALL)
|
if (counter == PCNT_ALL)
|
||||||
|
|
|
@ -73,7 +73,7 @@ private:
|
||||||
|
|
||||||
static long long m_performanceCounters[PCNT_MAX];
|
static long long m_performanceCounters[PCNT_MAX];
|
||||||
static long long m_prevPerformanceCounters[PCNT_MAX];
|
static long long m_prevPerformanceCounters[PCNT_MAX];
|
||||||
static std::stack<SystemTimeStamp> m_runningPerformanceCounters;
|
static std::stack<TimeUtils::TimeStamp> m_runningPerformanceCounters;
|
||||||
static std::stack<PerformanceCounter> m_runningPerformanceCountersType;
|
static std::stack<PerformanceCounter> m_runningPerformanceCountersType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -143,38 +143,11 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemTimeStamp CSystemUtils::GetCurrentTimeStamp()
|
TimeUtils::TimeStamp CSystemUtils::GetCurrentTimeStamp()
|
||||||
{
|
{
|
||||||
return std::chrono::high_resolution_clock::now();
|
return std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemTimeStamp CSystemUtils::TimeStampLerp(SystemTimeStamp a, SystemTimeStamp b, float t)
|
|
||||||
{
|
|
||||||
return a + std::chrono::duration_cast<SystemTimeStamp::duration>((b - a) * t);
|
|
||||||
}
|
|
||||||
|
|
||||||
long long CSystemUtils::TimeStampExactDiff(SystemTimeStamp before, SystemTimeStamp after)
|
|
||||||
{
|
|
||||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(after - before).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
float CSystemUtils::TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after, SystemTimeUnit unit)
|
|
||||||
{
|
|
||||||
long long exact = TimeStampExactDiff(before, after);
|
|
||||||
|
|
||||||
float result = 0.0f;
|
|
||||||
if (unit == SystemTimeUnit::SECONDS)
|
|
||||||
result = exact * 1e-9;
|
|
||||||
else if (unit == SystemTimeUnit::MILLISECONDS)
|
|
||||||
result = exact * 1e-6;
|
|
||||||
else if (unit == SystemTimeUnit::MICROSECONDS)
|
|
||||||
result = exact * 1e-3;
|
|
||||||
else
|
|
||||||
assert(false);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CSystemUtils::GetBasePath()
|
std::string CSystemUtils::GetBasePath()
|
||||||
{
|
{
|
||||||
if (m_basePath.empty())
|
if (m_basePath.empty())
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
|
#include "common/timeutils.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -63,19 +64,6 @@ enum class SystemDialogResult
|
||||||
NO
|
NO
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* \enum SystemTimeUnit
|
|
||||||
* \brief Time unit
|
|
||||||
*/
|
|
||||||
enum class SystemTimeUnit
|
|
||||||
{
|
|
||||||
SECONDS,
|
|
||||||
MILLISECONDS,
|
|
||||||
MICROSECONDS
|
|
||||||
};
|
|
||||||
|
|
||||||
using SystemTimeStamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class CSystemUtils
|
* \class CSystemUtils
|
||||||
* \brief Platform-specific utils
|
* \brief Platform-specific utils
|
||||||
|
@ -101,18 +89,7 @@ public:
|
||||||
TEST_VIRTUAL SystemDialogResult ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message);
|
TEST_VIRTUAL SystemDialogResult ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message);
|
||||||
|
|
||||||
//! Returns a time stamp associated with current time
|
//! Returns a time stamp associated with current time
|
||||||
TEST_VIRTUAL SystemTimeStamp GetCurrentTimeStamp();
|
TEST_VIRTUAL TimeUtils::TimeStamp GetCurrentTimeStamp();
|
||||||
|
|
||||||
//! Linearly interpolates between two timestamps.
|
|
||||||
SystemTimeStamp TimeStampLerp(SystemTimeStamp a, SystemTimeStamp b, float t);
|
|
||||||
|
|
||||||
//! Returns a difference between two timestamps in given time unit
|
|
||||||
/** The difference is \a after - \a before. */
|
|
||||||
float TimeStampDiff(SystemTimeStamp before, SystemTimeStamp after, SystemTimeUnit unit = SystemTimeUnit::SECONDS);
|
|
||||||
|
|
||||||
//! Returns the exact (in nanosecond units) difference between two timestamps
|
|
||||||
/** The difference is \a after - \a before. */
|
|
||||||
long long TimeStampExactDiff(SystemTimeStamp before, SystemTimeStamp after);
|
|
||||||
|
|
||||||
//! Returns the path where the executable binary is located (ends with the path separator)
|
//! Returns the path where the executable binary is located (ends with the path separator)
|
||||||
virtual std::string GetBasePath();
|
virtual std::string GetBasePath();
|
||||||
|
@ -142,5 +119,4 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_basePath;
|
std::string m_basePath;
|
||||||
std::vector<std::unique_ptr<SystemTimeStamp>> m_timeStamps;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -83,17 +83,6 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp)
|
|
||||||
{
|
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
long long CSystemUtilsLinux::TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
|
|
||||||
{
|
|
||||||
return (after->clockTime.tv_nsec - before->clockTime.tv_nsec) +
|
|
||||||
(after->clockTime.tv_sec - before->clockTime.tv_sec) * 1000000000ll;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string CSystemUtilsLinux::GetSaveDir()
|
std::string CSystemUtilsLinux::GetSaveDir()
|
||||||
{
|
{
|
||||||
#if PORTABLE_SAVES || DEV_BUILD
|
#if PORTABLE_SAVES || DEV_BUILD
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/timeutils.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace TimeUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
TimeStamp Lerp(TimeStamp a, TimeStamp b, float t)
|
||||||
|
{
|
||||||
|
return a + std::chrono::duration_cast<TimeStamp::duration>((b - a) * t);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Diff(TimeStamp before, TimeStamp after, TimeUnit unit)
|
||||||
|
{
|
||||||
|
long long exact = ExactDiff(before, after);
|
||||||
|
|
||||||
|
float result = 0.0f;
|
||||||
|
if (unit == TimeUnit::SECONDS)
|
||||||
|
result = exact * 1e-9;
|
||||||
|
else if (unit == TimeUnit::MILLISECONDS)
|
||||||
|
result = exact * 1e-6;
|
||||||
|
else if (unit == TimeUnit::MICROSECONDS)
|
||||||
|
result = exact * 1e-3;
|
||||||
|
else
|
||||||
|
assert(false);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long ExactDiff(TimeStamp before, TimeStamp after)
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<std::chrono::nanoseconds>(after - before).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TimeUtils
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \file common/timeutils.h
|
||||||
|
* \brief Some useful cross-platform operations on timestamps
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace TimeUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class TimeUnit
|
||||||
|
{
|
||||||
|
SECONDS,
|
||||||
|
MILLISECONDS,
|
||||||
|
MICROSECONDS
|
||||||
|
};
|
||||||
|
|
||||||
|
using TimeStamp = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
||||||
|
|
||||||
|
//! Linearly interpolates between two timestamps.
|
||||||
|
TimeStamp Lerp(TimeStamp a, TimeStamp b, float t);
|
||||||
|
|
||||||
|
//! Returns a difference between two timestamps in given time unit
|
||||||
|
/** The difference is \a after - \a before. */
|
||||||
|
float Diff(TimeStamp before, TimeStamp after, TimeUnit unit = TimeUnit::SECONDS);
|
||||||
|
|
||||||
|
//! Returns the exact (in nanosecond units) difference between two timestamps
|
||||||
|
/** The difference is \a after - \a before. */
|
||||||
|
long long ExactDiff(TimeStamp before, TimeStamp after);
|
||||||
|
|
||||||
|
} // namespace TimeUtils
|
|
@ -63,6 +63,8 @@
|
||||||
#include <SDL_thread.h>
|
#include <SDL_thread.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
using TimeUtils::TimeUnit;
|
||||||
|
|
||||||
// Graphics module namespace
|
// Graphics module namespace
|
||||||
namespace Gfx
|
namespace Gfx
|
||||||
{
|
{
|
||||||
|
@ -3168,7 +3170,7 @@ void CEngine::Render()
|
||||||
m_fpsCounter++;
|
m_fpsCounter++;
|
||||||
|
|
||||||
m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp();
|
m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp();
|
||||||
float diff = m_systemUtils->TimeStampDiff(m_lastFrameTime, m_currentFrameTime, SystemTimeUnit::SECONDS);
|
float diff = TimeUtils::Diff(m_lastFrameTime, m_currentFrameTime, TimeUnit::SECONDS);
|
||||||
if (diff > 1.0f)
|
if (diff > 1.0f)
|
||||||
{
|
{
|
||||||
m_lastFrameTime = m_currentFrameTime;
|
m_lastFrameTime = m_currentFrameTime;
|
||||||
|
|
|
@ -1310,8 +1310,8 @@ protected:
|
||||||
//! Last encountered error
|
//! Last encountered error
|
||||||
std::string m_error;
|
std::string m_error;
|
||||||
|
|
||||||
SystemTimeStamp m_lastFrameTime;
|
TimeUtils::TimeStamp m_lastFrameTime;
|
||||||
SystemTimeStamp m_currentFrameTime;
|
TimeUtils::TimeStamp m_currentFrameTime;
|
||||||
int m_fpsCounter;
|
int m_fpsCounter;
|
||||||
float m_fps;
|
float m_fps;
|
||||||
|
|
||||||
|
|
|
@ -14,13 +14,12 @@ add_executable(colobot_ut
|
||||||
CBot/CBotToken_test.cpp
|
CBot/CBotToken_test.cpp
|
||||||
CBot/CBot_test.cpp
|
CBot/CBot_test.cpp
|
||||||
common/config_file_test.cpp
|
common/config_file_test.cpp
|
||||||
common/system/system_test.cpp
|
common/timeutils_test.cpp
|
||||||
graphics/engine/lightman_test.cpp
|
graphics/engine/lightman_test.cpp
|
||||||
math/func_test.cpp
|
math/func_test.cpp
|
||||||
math/geometry_test.cpp
|
math/geometry_test.cpp
|
||||||
math/matrix_test.cpp
|
math/matrix_test.cpp
|
||||||
math/vector_test.cpp
|
math/vector_test.cpp)
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(colobot_ut PRIVATE
|
target_include_directories(colobot_ut PRIVATE
|
||||||
common
|
common
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
using namespace HippoMocks;
|
using namespace HippoMocks;
|
||||||
namespace ph = std::placeholders;
|
namespace ph = std::placeholders;
|
||||||
|
using TimeUtils::TimeStamp;
|
||||||
|
|
||||||
class CApplicationWrapper : public CApplication
|
class CApplicationWrapper : public CApplication
|
||||||
{
|
{
|
||||||
|
@ -47,7 +48,7 @@ public:
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
Event CreateUpdateEvent(SystemTimeStamp timestamp) override
|
Event CreateUpdateEvent(TimeStamp timestamp) override
|
||||||
{
|
{
|
||||||
return CApplication::CreateUpdateEvent(timestamp);
|
return CApplication::CreateUpdateEvent(timestamp);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,7 @@ protected:
|
||||||
|
|
||||||
void NextInstant(long long diff);
|
void NextInstant(long long diff);
|
||||||
|
|
||||||
SystemTimeStamp GetCurrentTimeStamp();
|
TimeStamp GetCurrentTimeStamp();
|
||||||
|
|
||||||
void TestCreateUpdateEvent(long long relTimeExact, long long absTimeExact,
|
void TestCreateUpdateEvent(long long relTimeExact, long long absTimeExact,
|
||||||
float relTime, float absTime,
|
float relTime, float absTime,
|
||||||
|
@ -103,9 +104,9 @@ void CApplicationUT::TearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SystemTimeStamp CApplicationUT::GetCurrentTimeStamp()
|
TimeStamp CApplicationUT::GetCurrentTimeStamp()
|
||||||
{
|
{
|
||||||
return SystemTimeStamp{SystemTimeStamp::duration{m_currentTime}};
|
return TimeStamp{ TimeStamp::duration{m_currentTime}};
|
||||||
}
|
}
|
||||||
|
|
||||||
void CApplicationUT::NextInstant(long long diff)
|
void CApplicationUT::NextInstant(long long diff)
|
||||||
|
@ -117,7 +118,7 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs
|
||||||
float relTime, float absTime,
|
float relTime, float absTime,
|
||||||
long long relTimeReal, long long absTimeReal)
|
long long relTimeReal, long long absTimeReal)
|
||||||
{
|
{
|
||||||
SystemTimeStamp now = GetCurrentTimeStamp();
|
TimeStamp now = GetCurrentTimeStamp();
|
||||||
Event event = m_app->CreateUpdateEvent(now);
|
Event event = m_app->CreateUpdateEvent(now);
|
||||||
EXPECT_EQ(EVENT_FRAME, event.type);
|
EXPECT_EQ(EVENT_FRAME, event.type);
|
||||||
EXPECT_FLOAT_EQ(relTime, event.rTime);
|
EXPECT_FLOAT_EQ(relTime, event.rTime);
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of the Colobot: Gold Edition source code
|
|
||||||
* Copyright (C) 2018, Daniel Roux, EPSITEC SA & TerranovaTeam
|
|
||||||
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see http://gnu.org/licenses
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "common/system/system_other.h"
|
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
struct SystemTest : ::testing::Test
|
|
||||||
{
|
|
||||||
CSystemUtilsOther system;
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(SystemTest, TimeStampExactDiff)
|
|
||||||
{
|
|
||||||
auto epoch = SystemTimeStamp{};
|
|
||||||
EXPECT_EQ(system.TimeStampExactDiff(epoch, epoch), 0);
|
|
||||||
|
|
||||||
auto duration = std::chrono::microseconds{123456789L};
|
|
||||||
auto before = std::chrono::high_resolution_clock::now();
|
|
||||||
auto after = before + duration;
|
|
||||||
EXPECT_EQ(system.TimeStampExactDiff(before, after), std::chrono::nanoseconds{duration}.count());
|
|
||||||
EXPECT_EQ(system.TimeStampExactDiff(after, before), -std::chrono::nanoseconds{duration}.count());
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr auto TIMESTAMP_START = SystemTimeStamp{std::chrono::nanoseconds{300}};
|
|
||||||
constexpr auto TIMESTAMP_MID = SystemTimeStamp{std::chrono::nanoseconds{600}};
|
|
||||||
constexpr auto TIMESTAMP_END = SystemTimeStamp{std::chrono::nanoseconds{900}};
|
|
||||||
|
|
||||||
constexpr auto LERP_PARAM_ZERO = 0.0f;
|
|
||||||
constexpr auto LERP_PARAM_HALF = 0.5f;
|
|
||||||
constexpr auto LERP_PARAM_ONE = 1.0f;
|
|
||||||
|
|
||||||
TEST_F(SystemTest, TimeStampLerpReturnsStartWhenLerpParameterIsZero)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(TIMESTAMP_START, system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_ZERO));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SystemTest, TimeStampLerpReturnsEndWhenLerpParameterIsOne)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(TIMESTAMP_END, system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_ONE));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SystemTest, TimeStampLerpReturnsValueBetweenStartAndEndWhenLerpParameterIsBetweenZeroAndOne)
|
|
||||||
{
|
|
||||||
EXPECT_EQ(TIMESTAMP_MID, system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SystemTest, TimeStampLerpIsMonotonic)
|
|
||||||
{
|
|
||||||
constexpr auto deltaLerpParam = 0.1f;
|
|
||||||
auto earlierTimeStamp = system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF - deltaLerpParam);
|
|
||||||
auto laterTimeStamp = system.TimeStampLerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF + deltaLerpParam);
|
|
||||||
EXPECT_TRUE(earlierTimeStamp < laterTimeStamp);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(SystemTest, TimeStampLerpIsConsistent)
|
|
||||||
{
|
|
||||||
auto timeStamp = TIMESTAMP_START;
|
|
||||||
EXPECT_EQ(timeStamp, system.TimeStampLerp(timeStamp, timeStamp, LERP_PARAM_ZERO));
|
|
||||||
EXPECT_EQ(timeStamp, system.TimeStampLerp(timeStamp, timeStamp, LERP_PARAM_HALF));
|
|
||||||
EXPECT_EQ(timeStamp, system.TimeStampLerp(timeStamp, timeStamp, LERP_PARAM_ONE));
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the Colobot: Gold Edition source code
|
||||||
|
* Copyright (C) 2018-2021, Daniel Roux, EPSITEC SA & TerranovaTeam
|
||||||
|
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see http://gnu.org/licenses
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/timeutils.h"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace TimeUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
TEST(TimeUtilsExactDiffTest, ExactDiff)
|
||||||
|
{
|
||||||
|
auto epoch = TimeStamp{};
|
||||||
|
EXPECT_EQ(ExactDiff(epoch, epoch), 0);
|
||||||
|
|
||||||
|
auto duration = std::chrono::microseconds{123456789L};
|
||||||
|
auto before = std::chrono::high_resolution_clock::now();
|
||||||
|
auto after = before + duration;
|
||||||
|
EXPECT_EQ(ExactDiff(before, after), std::chrono::nanoseconds{duration}.count());
|
||||||
|
EXPECT_EQ(ExactDiff(after, before), -std::chrono::nanoseconds{duration}.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto TIMESTAMP_START = TimeStamp{std::chrono::nanoseconds{300}};
|
||||||
|
constexpr auto TIMESTAMP_MID = TimeStamp{std::chrono::nanoseconds{600}};
|
||||||
|
constexpr auto TIMESTAMP_END = TimeStamp{std::chrono::nanoseconds{900}};
|
||||||
|
|
||||||
|
constexpr auto LERP_PARAM_ZERO = 0.0f;
|
||||||
|
constexpr auto LERP_PARAM_HALF = 0.5f;
|
||||||
|
constexpr auto LERP_PARAM_ONE = 1.0f;
|
||||||
|
|
||||||
|
TEST(TimeUtilsLerpTest, LerpReturnsStartWhenLerpParameterIsZero)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(TIMESTAMP_START, Lerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_ZERO));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TimeUtilsLerpTest, LerpReturnsEndWhenLerpParameterIsOne)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(TIMESTAMP_END, Lerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_ONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TimeUtilsLerpTest, LerpReturnsValueBetweenStartAndEndWhenLerpParameterIsBetweenZeroAndOne)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(TIMESTAMP_MID, Lerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TimeUtilsLerpTest, LerpIsMonotonic)
|
||||||
|
{
|
||||||
|
constexpr auto deltaLerpParam = 0.1f;
|
||||||
|
auto earlierTimeStamp = Lerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF - deltaLerpParam);
|
||||||
|
auto laterTimeStamp = Lerp(TIMESTAMP_START, TIMESTAMP_END, LERP_PARAM_HALF + deltaLerpParam);
|
||||||
|
EXPECT_TRUE(earlierTimeStamp < laterTimeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TimeUtilsLerpTest, LerpIsConsistent)
|
||||||
|
{
|
||||||
|
auto timeStamp = TIMESTAMP_START;
|
||||||
|
EXPECT_EQ(timeStamp, Lerp(timeStamp, timeStamp, LERP_PARAM_ZERO));
|
||||||
|
EXPECT_EQ(timeStamp, Lerp(timeStamp, timeStamp, LERP_PARAM_HALF));
|
||||||
|
EXPECT_EQ(timeStamp, Lerp(timeStamp, timeStamp, LERP_PARAM_ONE));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace TimeUtils
|
Loading…
Reference in New Issue