diff --git a/data b/data index 0ac8197b..21a45c0b 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 0ac8197b7a8a005c714b7696d36c642cf0e81474 +Subproject commit 21a45c0b8809accd142a83a81f1a3c92a327f319 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 353d09ba..105bce70 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,10 +83,8 @@ add_library(colobotbase STATIC common/singleton.h common/stringutils.cpp common/stringutils.h - common/thread/resource_owning_thread.h - common/thread/sdl_cond_wrapper.h - common/thread/sdl_mutex_wrapper.h - common/thread/thread.h + common/timeutils.cpp + common/timeutils.h common/thread/worker_thread.h graphics/core/color.cpp graphics/core/color.h diff --git a/src/app/app.cpp b/src/app/app.cpp index 1e4515ed..9abd16f8 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -37,8 +37,6 @@ #include "common/system/system.h" -#include "common/thread/thread.h" - #include "graphics/core/nulldevice.h" #include "graphics/opengl/glutil.h" @@ -61,6 +59,10 @@ #include #include #include +#include + +using TimeUtils::TimeStamp; +using TimeUtils::TimeUnit; char CApplication::m_languageLocale[] = { 0 }; @@ -71,7 +73,6 @@ const int JOYSTICK_TIMER_INTERVAL = 1000/30; //! Function called by the timer Uint32 JoystickTimerCallback(Uint32 interval, void *); - /** * \struct ApplicationPrivate * \brief Private data of CApplication class @@ -138,13 +139,6 @@ CApplication::CApplication(CSystemUtils* systemUtils) m_absTime = 0.0f; m_relTime = 0.0f; - m_baseTimeStamp = m_systemUtils->CreateTimeStamp(); - m_curTimeStamp = m_systemUtils->CreateTimeStamp(); - m_lastTimeStamp = m_systemUtils->CreateTimeStamp(); - - m_manualFrameLast = m_systemUtils->CreateTimeStamp(); - m_manualFrameTime = m_systemUtils->CreateTimeStamp(); - m_joystickEnabled = false; @@ -162,13 +156,6 @@ CApplication::CApplication(CSystemUtils* systemUtils) CApplication::~CApplication() { - m_systemUtils->DestroyTimeStamp(m_baseTimeStamp); - m_systemUtils->DestroyTimeStamp(m_curTimeStamp); - m_systemUtils->DestroyTimeStamp(m_lastTimeStamp); - - m_systemUtils->DestroyTimeStamp(m_manualFrameLast); - m_systemUtils->DestroyTimeStamp(m_manualFrameTime); - m_joystickEnabled = false; m_controller.reset(); @@ -675,7 +662,7 @@ bool CApplication::Create() { GetLogger()->Error("Unknown graphics device: %s\n", graphics.c_str()); GetLogger()->Info("Changing to default device\n"); - m_systemUtils->SystemDialog(SDT_ERROR, "Graphics initialization error", "You have selected invalid graphics device with -graphics switch. Game will use default OpenGL device instead."); + m_systemUtils->SystemDialog(SystemDialogType::ERROR_MSG, "Graphics initialization error", "You have selected invalid graphics device with -graphics switch. Game will use default OpenGL device instead."); m_device = Gfx::CreateDevice(m_deviceConfig, "opengl"); } } @@ -1052,15 +1039,15 @@ int CApplication::Run() { m_active = true; - m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp); - m_systemUtils->GetCurrentTimeStamp(m_lastTimeStamp); - m_systemUtils->GetCurrentTimeStamp(m_curTimeStamp); + m_baseTimeStamp = m_systemUtils->GetCurrentTimeStamp(); + m_lastTimeStamp = m_systemUtils->GetCurrentTimeStamp(); + m_curTimeStamp = m_systemUtils->GetCurrentTimeStamp(); MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start - SystemTimeStamp *previousTimeStamp = m_systemUtils->CreateTimeStamp(); - SystemTimeStamp *currentTimeStamp = m_systemUtils->CreateTimeStamp(); - SystemTimeStamp *interpolatedTimeStamp = m_systemUtils->CreateTimeStamp(); + TimeStamp previousTimeStamp{}; + TimeStamp currentTimeStamp{}; + TimeStamp interpolatedTimeStamp{}; while (true) { @@ -1164,11 +1151,11 @@ int CApplication::Run() // If game speed is increased then we do extra ticks per loop iteration to improve physics accuracy. int numTickSlices = static_cast(GetSimulationSpeed()); if(numTickSlices < 1) numTickSlices = 1; - m_systemUtils->CopyTimeStamp(previousTimeStamp, m_curTimeStamp); - m_systemUtils->GetCurrentTimeStamp(currentTimeStamp); + previousTimeStamp = m_curTimeStamp; + currentTimeStamp = m_systemUtils->GetCurrentTimeStamp(); for(int tickSlice = 0; tickSlice < numTickSlices; tickSlice++) { - m_systemUtils->InterpolateTimeStamp(interpolatedTimeStamp, previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); + interpolatedTimeStamp = TimeUtils::Lerp(previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast(numTickSlices)); Event event = CreateUpdateEvent(interpolatedTimeStamp); if (event.type != EVENT_NULL && m_controller != nullptr) { @@ -1199,9 +1186,6 @@ int CApplication::Run() } end: - m_systemUtils->DestroyTimeStamp(previousTimeStamp); - m_systemUtils->DestroyTimeStamp(currentTimeStamp); - m_systemUtils->DestroyTimeStamp(interpolatedTimeStamp); return m_exitCode; } @@ -1495,13 +1479,13 @@ void CApplication::Render() void CApplication::RenderIfNeeded(int updateRate) { - m_systemUtils->GetCurrentTimeStamp(m_manualFrameTime); - long long diff = m_systemUtils->TimeStampExactDiff(m_manualFrameLast, m_manualFrameTime); + m_manualFrameTime = m_systemUtils->GetCurrentTimeStamp(); + long long diff = TimeUtils::ExactDiff(m_manualFrameLast, m_manualFrameTime); if (diff < 1e9f / updateRate) { return; } - m_systemUtils->CopyTimeStamp(m_manualFrameLast, m_manualFrameTime); + m_manualFrameLast = m_manualFrameTime; Render(); } @@ -1529,30 +1513,26 @@ void CApplication::ResetTimeAfterLoading() void CApplication::InternalResumeSimulation() { - m_systemUtils->GetCurrentTimeStamp(m_baseTimeStamp); - m_systemUtils->CopyTimeStamp(m_curTimeStamp, m_baseTimeStamp); + m_baseTimeStamp = m_systemUtils->GetCurrentTimeStamp(); + m_curTimeStamp = m_baseTimeStamp; m_realAbsTimeBase = m_realAbsTime; m_absTimeBase = m_exactAbsTime; } void CApplication::StartLoadingMusic() { - CThread musicLoadThread([this]() + std::thread{[this]() { GetLogger()->Debug("Cache sounds...\n"); - SystemTimeStamp* musicLoadStart = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(musicLoadStart); + TimeStamp musicLoadStart{m_systemUtils->GetCurrentTimeStamp()}; m_sound->Reset(); m_sound->CacheAll(); - SystemTimeStamp* musicLoadEnd = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(musicLoadEnd); - float musicLoadTime = m_systemUtils->TimeStampDiff(musicLoadStart, musicLoadEnd, STU_MSEC); + TimeStamp musicLoadEnd{m_systemUtils->GetCurrentTimeStamp()}; + float musicLoadTime = TimeUtils::Diff(musicLoadStart, musicLoadEnd, TimeUnit::MILLISECONDS); GetLogger()->Debug("Sound loading took %.2f ms\n", musicLoadTime); - }, - "Sound loading thread"); - musicLoadThread.Start(); + }}.detach(); } bool CApplication::GetSimulationSuspended() const @@ -1564,24 +1544,24 @@ void CApplication::SetSimulationSpeed(float speed) { m_simulationSpeed = speed; - m_systemUtils->CopyTimeStamp(m_baseTimeStamp, m_curTimeStamp); + m_baseTimeStamp = m_curTimeStamp; m_realAbsTimeBase = m_realAbsTime; m_absTimeBase = m_exactAbsTime; GetLogger()->Info("Simulation speed = %.2f\n", speed); } -Event CApplication::CreateUpdateEvent(SystemTimeStamp *newTimeStamp) +Event CApplication::CreateUpdateEvent(TimeStamp newTimeStamp) { if (m_simulationSuspended) return Event(EVENT_NULL); - m_systemUtils->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp); - m_systemUtils->CopyTimeStamp(m_curTimeStamp, newTimeStamp); + m_lastTimeStamp = m_curTimeStamp; + 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 newRealRelTime = m_systemUtils->TimeStampExactDiff(m_lastTimeStamp, m_curTimeStamp); + long long newRealRelTime = TimeUtils::ExactDiff(m_lastTimeStamp, m_curTimeStamp); if (newRealAbsTime < m_realAbsTime || newRealRelTime < 0) { diff --git a/src/app/app.h b/src/app/app.h index d238bde9..7160be54 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -27,6 +27,7 @@ #include "common/event.h" #include "common/language.h" #include "common/singleton.h" +#include "common/system/system.h" #include "graphics/core/device.h" @@ -46,7 +47,6 @@ class CModManager; class CPathManager; class CConfigFile; class CSystemUtils; -struct SystemTimeStamp; namespace Gfx { @@ -297,7 +297,7 @@ protected: //! If applicable, creates a virtual event to match the changed state as of new event Event CreateVirtualEvent(const Event& sourceEvent); //! Prepares a simulation update event - TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp); + TEST_VIRTUAL Event CreateUpdateEvent(TimeUtils::TimeStamp newTimeStamp); //! Logs debug data for event void LogEvent(const Event& event); @@ -354,9 +354,9 @@ protected: //! Animation time stamps, etc. //@{ - SystemTimeStamp* m_baseTimeStamp; - SystemTimeStamp* m_lastTimeStamp; - SystemTimeStamp* m_curTimeStamp; + TimeUtils::TimeStamp m_baseTimeStamp; + TimeUtils::TimeStamp m_lastTimeStamp; + TimeUtils::TimeStamp m_curTimeStamp; long long m_realAbsTimeBase; long long m_realAbsTime; @@ -373,8 +373,8 @@ protected: bool m_simulationSuspended; //@} - SystemTimeStamp* m_manualFrameLast; - SystemTimeStamp* m_manualFrameTime; + TimeUtils::TimeStamp m_manualFrameLast; + TimeUtils::TimeStamp m_manualFrameTime; //! Graphics device to use bool m_graphicsOverride = false; diff --git a/src/app/main.cpp b/src/app/main.cpp index 1cb8171a..7c6173b0 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -177,7 +177,7 @@ int main(int argc, char *argv[]) ParseArgsStatus status = app.ParseArguments(argc, argv); if (status == PARSE_ARGS_FAIL) { - systemUtils->SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n"); + systemUtils->SystemDialog(SystemDialogType::ERROR_MSG, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n"); return app.GetExitCode(); } else if (status == PARSE_ARGS_HELP) @@ -190,7 +190,7 @@ int main(int argc, char *argv[]) code = app.GetExitCode(); if (code != 0 && !app.GetErrorMessage().empty()) { - systemUtils->SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", app.GetErrorMessage()); + systemUtils->SystemDialog(SystemDialogType::ERROR_MSG, "COLOBOT - Fatal Error", app.GetErrorMessage()); } logger.Info("Didn't run main loop. Exiting with code %d\n", code); return code; diff --git a/src/app/signal_handlers.cpp b/src/app/signal_handlers.cpp index 1558f4be..f0e9f95e 100644 --- a/src/app/signal_handlers.cpp +++ b/src/app/signal_handlers.cpp @@ -162,7 +162,7 @@ void CSignalHandlers::ReportError(const std::string& errorMessage) std::cerr << std::endl << msg.str() << std::endl; - m_systemUtils->SystemDialog(SDT_ERROR, "Unhandled exception occurred!", msg.str()); + m_systemUtils->SystemDialog(SystemDialogType::ERROR_MSG, "Unhandled exception occurred!", msg.str()); if (canSave && !triedSaving) { @@ -172,13 +172,13 @@ void CSignalHandlers::ReportError(const std::string& errorMessage) msg << std::endl; msg << "Do you want to try saving now?"; - SystemDialogResult result = m_systemUtils->SystemDialog(SDT_YES_NO, "Try to save?", msg.str()); - if (result == SDR_YES) + SystemDialogResult result = m_systemUtils->SystemDialog(SystemDialogType::YES_NO, "Try to save?", msg.str()); + if (result == SystemDialogResult::YES) { triedSaving = true; CResourceManager::CreateNewDirectory("crashsave"); robotMain->IOWriteScene("crashsave/data.sav", "crashsave/cbot.run", "crashsave/screen.png", "Backup at the moment of a crash", true); - m_systemUtils->SystemDialog(SDT_INFO, "Try to save?", "Saving finished.\nPlease restart the game now"); + m_systemUtils->SystemDialog(SystemDialogType::INFO, "Try to save?", "Saving finished.\nPlease restart the game now"); } } diff --git a/src/common/event.cpp b/src/common/event.cpp index d75c8f9c..544428da 100644 --- a/src/common/event.cpp +++ b/src/common/event.cpp @@ -606,8 +606,7 @@ std::string ParseEventType(EventType eventType) CEventQueue::CEventQueue() - : m_mutex{}, - m_fifo(), + : m_fifo(), m_head{0}, m_tail{0}, m_total{0} @@ -625,15 +624,13 @@ bool CEventQueue::IsEmpty() Else, adds the event to the queue and returns \c true. */ bool CEventQueue::AddEvent(Event&& event) { - bool result{}; - - SDL_LockMutex(*m_mutex); + std::lock_guard lock{m_mutex}; if (m_total >= MAX_EVENT_QUEUE) { GetLogger()->Warn("Event queue flood!\n"); - result = false; + return false; } else { @@ -644,19 +641,15 @@ bool CEventQueue::AddEvent(Event&& event) m_total++; - result = true; + return true; } - - SDL_UnlockMutex(*m_mutex); - - return result; } Event CEventQueue::GetEvent() { Event event; - SDL_LockMutex(*m_mutex); + std::lock_guard lock{m_mutex}; if (m_head == m_tail) { @@ -673,7 +666,5 @@ Event CEventQueue::GetEvent() } - SDL_UnlockMutex(*m_mutex); - return event; } diff --git a/src/common/event.h b/src/common/event.h index aec48ecb..1b1bc1d3 100644 --- a/src/common/event.h +++ b/src/common/event.h @@ -27,12 +27,11 @@ #include "common/key.h" #include "common/make_unique.h" -#include "common/thread/sdl_mutex_wrapper.h" - #include "math/point.h" #include "math/vector.h" #include +#include /** \enum EventType @@ -932,7 +931,7 @@ public: Event GetEvent(); protected: - CSDLMutexWrapper m_mutex; + std::mutex m_mutex; Event m_fifo[MAX_EVENT_QUEUE]; int m_head; int m_tail; diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp index f20d3b06..56a5996d 100644 --- a/src/common/profiler.cpp +++ b/src/common/profiler.cpp @@ -23,10 +23,12 @@ #include +using TimeUtils::TimeStamp; + CSystemUtils* CProfiler::m_systemUtils = nullptr; long long CProfiler::m_performanceCounters[PCNT_MAX] = {0}; long long CProfiler::m_prevPerformanceCounters[PCNT_MAX] = {0}; -std::stack CProfiler::m_runningPerformanceCounters; +std::stack CProfiler::m_runningPerformanceCounters; std::stack CProfiler::m_runningPerformanceCountersType; void CProfiler::SetSystemUtils(CSystemUtils* systemUtils) @@ -39,8 +41,7 @@ void CProfiler::StartPerformanceCounter(PerformanceCounter counter) if (counter == PCNT_ALL) ResetPerformanceCounters(); - SystemTimeStamp* timeStamp = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(timeStamp); + TimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp(); m_runningPerformanceCounters.push(timeStamp); m_runningPerformanceCountersType.push(counter); } @@ -50,11 +51,8 @@ void CProfiler::StopPerformanceCounter(PerformanceCounter counter) assert(m_runningPerformanceCountersType.top() == counter); m_runningPerformanceCountersType.pop(); - SystemTimeStamp* timeStamp = m_systemUtils->CreateTimeStamp(); - m_systemUtils->GetCurrentTimeStamp(timeStamp); - m_performanceCounters[counter] += m_systemUtils->TimeStampExactDiff(m_runningPerformanceCounters.top(), timeStamp); - m_systemUtils->DestroyTimeStamp(timeStamp); - m_systemUtils->DestroyTimeStamp(m_runningPerformanceCounters.top()); + TimeStamp timeStamp = m_systemUtils->GetCurrentTimeStamp(); + m_performanceCounters[counter] += TimeUtils::ExactDiff(m_runningPerformanceCounters.top(), timeStamp); m_runningPerformanceCounters.pop(); if (counter == PCNT_ALL) diff --git a/src/common/profiler.h b/src/common/profiler.h index 5bef64ee..0c3da2b1 100644 --- a/src/common/profiler.h +++ b/src/common/profiler.h @@ -20,8 +20,8 @@ #pragma once class CSystemUtils; -struct SystemTimeStamp; +#include "common/system/system.h" #include /** @@ -73,7 +73,7 @@ private: static long long m_performanceCounters[PCNT_MAX]; static long long m_prevPerformanceCounters[PCNT_MAX]; - static std::stack m_runningPerformanceCounters; + static std::stack m_runningPerformanceCounters; static std::stack m_runningPerformanceCountersType; }; diff --git a/src/common/system/system.cpp b/src/common/system/system.cpp index b4893655..42242565 100644 --- a/src/common/system/system.cpp +++ b/src/common/system/system.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -60,17 +61,17 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons { switch (type) { - case SDT_INFO: + case SystemDialogType::INFO: std::cout << "INFO: "; break; - case SDT_WARNING: + case SystemDialogType::WARNING: std::cout << "WARNING:"; break; - case SDT_ERROR: + case SystemDialogType::ERROR_MSG: std::cout << "ERROR: "; break; - case SDT_YES_NO: - case SDT_OK_CANCEL: + case SystemDialogType::YES_NO: + case SystemDialogType::OK_CANCEL: std::cout << "QUESTION: "; break; } @@ -79,24 +80,24 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons std::string line; - SystemDialogResult result = SDR_OK; + auto result = SystemDialogResult::OK; bool done = false; while (!done) { switch (type) { - case SDT_INFO: - case SDT_WARNING: - case SDT_ERROR: + case SystemDialogType::INFO: + case SystemDialogType::WARNING: + case SystemDialogType::ERROR_MSG: std::cout << "Press ENTER to continue"; break; - case SDT_YES_NO: + case SystemDialogType::YES_NO: std::cout << "Type 'Y' for Yes or 'N' for No"; break; - case SDT_OK_CANCEL: + case SystemDialogType::OK_CANCEL: std::cout << "Type 'O' for OK or 'C' for Cancel"; break; } @@ -105,35 +106,35 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons switch (type) { - case SDT_INFO: - case SDT_WARNING: - case SDT_ERROR: + case SystemDialogType::INFO: + case SystemDialogType::WARNING: + case SystemDialogType::ERROR_MSG: done = true; break; - case SDT_YES_NO: + case SystemDialogType::YES_NO: if (line == "Y" || line == "y") { - result = SDR_YES; + result = SystemDialogResult::YES; done = true; } else if (line == "N" || line == "n") { - result = SDR_NO; + result = SystemDialogResult::NO; done = true; } break; - case SDT_OK_CANCEL: + case SystemDialogType::OK_CANCEL: if (line == "O" || line == "o") { done = true; - result = SDR_OK; + result = SystemDialogResult::OK; } else if (line == "C" || line == "c") { done = true; - result = SDR_CANCEL; + result = SystemDialogResult::CANCEL; } break; } @@ -142,39 +143,9 @@ SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, cons return result; } -SystemTimeStamp* CSystemUtils::CreateTimeStamp() +TimeUtils::TimeStamp CSystemUtils::GetCurrentTimeStamp() { - auto timeStamp = MakeUnique(); - SystemTimeStamp* timeStampPtr = timeStamp.get(); - m_timeStamps.push_back(std::move(timeStamp)); - return timeStampPtr; -} - -void CSystemUtils::DestroyTimeStamp(SystemTimeStamp *stamp) -{ - m_timeStamps.erase(std::remove_if(m_timeStamps.begin(), m_timeStamps.end(), [&](const std::unique_ptr& timeStamp) { return timeStamp.get() == stamp; })); -} - -void CSystemUtils::CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src) -{ - *dst = *src; -} - -float CSystemUtils::TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit) -{ - long long exact = TimeStampExactDiff(before, after); - - float result = 0.0f; - if (unit == STU_SEC) - result = exact * 1e-9; - else if (unit == STU_MSEC) - result = exact * 1e-6; - else if (unit == STU_USEC) - result = exact * 1e-3; - else - assert(false); - - return result; + return std::chrono::high_resolution_clock::now(); } std::string CSystemUtils::GetBasePath() @@ -225,3 +196,8 @@ bool CSystemUtils::OpenWebsite(const std::string& url) { return false; } + +void CSystemUtils::Usleep(int usecs) +{ + std::this_thread::sleep_for(std::chrono::microseconds{usecs}); +} diff --git a/src/common/system/system.h b/src/common/system/system.h index f20ee443..d5bf3d99 100644 --- a/src/common/system/system.h +++ b/src/common/system/system.h @@ -25,7 +25,9 @@ #pragma once #include "common/config.h" +#include "common/timeutils.h" +#include #include #include #include @@ -34,18 +36,18 @@ * \enum SystemDialogType * \brief Type of system dialog */ -enum SystemDialogType +enum class SystemDialogType { //! Information message - SDT_INFO, + INFO, //! Warning message - SDT_WARNING, + WARNING, //! Error message - SDT_ERROR, + ERROR_MSG, // windows.h defines ERROR which collides with the "ERROR" enum name //! Yes/No question - SDT_YES_NO, + YES_NO, //! Ok/Cancel question - SDT_OK_CANCEL + OK_CANCEL }; /** @@ -54,35 +56,14 @@ enum SystemDialogType * * Means which button was pressed. */ -enum SystemDialogResult +enum class SystemDialogResult { - SDR_OK, - SDR_CANCEL, - SDR_YES, - SDR_NO + OK, + CANCEL, + YES, + NO }; -/** - * \enum SystemTimeUnit - * \brief Time unit - */ -enum SystemTimeUnit -{ - //! seconds - STU_SEC, - //! milliseconds - STU_MSEC, - //! microseconds - STU_USEC -}; - -/* - * Forward declaration of time stamp struct - * SystemTimeStamp should only be used in a pointer context. - * The implementation details are hidden because of platform dependence. - */ -struct SystemTimeStamp; - /** * \class CSystemUtils * \brief Platform-specific utils @@ -107,28 +88,8 @@ public: //! Displays a fallback system dialog using console TEST_VIRTUAL SystemDialogResult ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message); - //! Creates a new time stamp object - TEST_VIRTUAL SystemTimeStamp* CreateTimeStamp(); - - //! Destroys a time stamp object - TEST_VIRTUAL void DestroyTimeStamp(SystemTimeStamp *stamp); - - //! Copies the time stamp from \a src to \a dst - TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src); - - //! Interpolates between two timestamps. If i=0 then dst=a. If i=1 then dst=b. If i=0.5 then dst is halfway between. - virtual void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) = 0; - //! Returns a time stamp associated with current time - virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0; - - //! Returns a difference between two timestamps in given time unit - /** The difference is \a after - \a before. */ - TEST_VIRTUAL float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit = STU_SEC); - - //! Returns the exact (in nanosecond units) difference between two timestamps - /** The difference is \a after - \a before. */ - virtual long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) = 0; + TEST_VIRTUAL TimeUtils::TimeStamp GetCurrentTimeStamp(); //! Returns the path where the executable binary is located (ends with the path separator) virtual std::string GetBasePath(); @@ -154,9 +115,8 @@ public: virtual bool OpenWebsite(const std::string& url); //! Sleep for given amount of microseconds - virtual void Usleep(int usecs) = 0; + void Usleep(int usecs); private: std::string m_basePath; - std::vector> m_timeStamps; }; diff --git a/src/common/system/system_linux.cpp b/src/common/system/system_linux.cpp index 2b7d99fa..0f9efeee 100644 --- a/src/common/system/system_linux.cpp +++ b/src/common/system/system_linux.cpp @@ -46,20 +46,20 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const std::string options = ""; switch (type) { - case SDT_INFO: + case SystemDialogType::INFO: default: options = "--info"; break; - case SDT_WARNING: + case SystemDialogType::WARNING: options = "--warning"; break; - case SDT_ERROR: + case SystemDialogType::ERROR_MSG: options = "--error"; break; - case SDT_YES_NO: + case SystemDialogType::YES_NO: options = "--question --ok-label=\"Yes\" --cancel-label=\"No\""; break; - case SDT_OK_CANCEL: + case SystemDialogType::OK_CANCEL: options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\""; break; } @@ -67,14 +67,14 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\""; int code = system(command.c_str()); - SystemDialogResult result = SDR_OK; + SystemDialogResult result = SystemDialogResult::OK; switch (type) { - case SDT_YES_NO: - result = code ? SDR_NO : SDR_YES; + case SystemDialogType::YES_NO: + result = code ? SystemDialogResult::NO : SystemDialogResult::YES; break; - case SDT_OK_CANCEL: - result = code ? SDR_CANCEL : SDR_OK; + case SystemDialogType::OK_CANCEL: + result = code ? SystemDialogResult::CANCEL : SystemDialogResult::OK; break; default: break; @@ -83,30 +83,6 @@ SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const return result; } -void CSystemUtilsLinux::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) -{ - long long delta = TimeStampExactDiff(a, b); - delta *= i; // truncates - dst->clockTime.tv_sec = a->clockTime.tv_sec + delta / 1000000000; - dst->clockTime.tv_nsec = a->clockTime.tv_nsec + delta % 1000000000; - if(dst->clockTime.tv_nsec >= 1000000000) - { - dst->clockTime.tv_nsec -= 1000000000; - dst->clockTime.tv_sec++; - } -} - -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() { #if PORTABLE_SAVES || DEV_BUILD @@ -172,7 +148,3 @@ bool CSystemUtilsLinux::OpenWebsite(const std::string& url) return true; } -void CSystemUtilsLinux::Usleep(int usec) -{ - usleep(usec); -} diff --git a/src/common/system/system_linux.h b/src/common/system/system_linux.h index 6607b150..8a1e60ec 100644 --- a/src/common/system/system_linux.h +++ b/src/common/system/system_linux.h @@ -24,15 +24,8 @@ #include "common/system/system.h" -#include - //@colobot-lint-exclude UndefinedFunctionRule -struct SystemTimeStamp -{ - timespec clockTime = {0, 0}; -}; - class CSystemUtilsLinux : public CSystemUtils { public: @@ -40,10 +33,6 @@ public: SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; - void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; - void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; - long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; - std::string GetSaveDir() override; std::string GetEnvVar(const std::string& name) override; @@ -51,8 +40,6 @@ public: bool OpenPath(const std::string& path) override; bool OpenWebsite(const std::string& url) override; - void Usleep(int usec) override; - private: bool m_zenityAvailable = false; }; diff --git a/src/common/system/system_macosx.cpp b/src/common/system/system_macosx.cpp index 72fa546c..8a20f7e2 100644 --- a/src/common/system/system_macosx.cpp +++ b/src/common/system/system_macosx.cpp @@ -140,8 +140,3 @@ bool CSystemUtilsMacOSX::OpenWebsite(const std::string& url) } return true; } - -void CSystemUtilsMacOSX::Usleep(int usec) -{ - usleep(usec); -} diff --git a/src/common/system/system_macosx.h b/src/common/system/system_macosx.h index 523e52e8..6ed4182b 100644 --- a/src/common/system/system_macosx.h +++ b/src/common/system/system_macosx.h @@ -41,8 +41,6 @@ public: bool OpenPath(const std::string& path) override; bool OpenWebsite(const std::string& url) override; - void Usleep(int usec) override; - private: std::string m_ASPath; std::string m_dataPath; diff --git a/src/common/system/system_other.cpp b/src/common/system/system_other.cpp index 865db847..f88def23 100644 --- a/src/common/system/system_other.cpp +++ b/src/common/system/system_other.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-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 @@ -29,22 +29,3 @@ SystemDialogResult CSystemUtilsOther::SystemDialog(SystemDialogType type, const return ConsoleSystemDialog(type, title, message); } -void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp) -{ - stamp->sdlTicks = SDL_GetTicks(); -} - -void CSystemUtilsOther::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) -{ - dst->sdlTicks = a->sdlTicks + static_cast((b->sdlTicks - a->sdlTicks) * i); -} - -long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) -{ - return (after->sdlTicks - before->sdlTicks) * 1000000ll; -} - -void CSystemUtilsOther::Usleep(int usec) -{ - SDL_Delay(usec / 1000); // close enough -} diff --git a/src/common/system/system_other.h b/src/common/system/system_other.h index 5964b585..4230e9ac 100644 --- a/src/common/system/system_other.h +++ b/src/common/system/system_other.h @@ -30,27 +30,11 @@ //@colobot-lint-exclude UndefinedFunctionRule -struct SystemTimeStamp -{ - Uint32 sdlTicks; - - SystemTimeStamp() - { - sdlTicks = 0; - } -}; - class CSystemUtilsOther : public CSystemUtils { public: void Init() override; SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; - - void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; - void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; - long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; - - void Usleep(int usec) override; }; //@end-colobot-lint-exclude diff --git a/src/common/system/system_windows.cpp b/src/common/system/system_windows.cpp index 989d359b..773bd62d 100644 --- a/src/common/system/system_windows.cpp +++ b/src/common/system/system_windows.cpp @@ -27,11 +27,6 @@ void CSystemUtilsWindows::Init() { - LARGE_INTEGER freq; - QueryPerformanceFrequency(&freq); - m_counterFrequency = freq.QuadPart; - - assert(m_counterFrequency != 0); } SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) @@ -42,20 +37,20 @@ SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, cons switch (type) { - case SDT_INFO: + case SystemDialogType::INFO: default: windowsType = MB_ICONINFORMATION|MB_OK; break; - case SDT_WARNING: + case SystemDialogType::WARNING: windowsType = MB_ICONWARNING|MB_OK; break; - case SDT_ERROR: + case SystemDialogType::ERROR_MSG: windowsType = MB_ICONERROR|MB_OK; break; - case SDT_YES_NO: + case SystemDialogType::YES_NO: windowsType = MB_ICONQUESTION|MB_YESNO; break; - case SDT_OK_CANCEL: + case SystemDialogType::OK_CANCEL: windowsType = MB_ICONWARNING|MB_OKCANCEL; break; } @@ -63,36 +58,18 @@ SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, cons switch (MessageBoxW(nullptr, windowsMessage.c_str(), windowsTitle.c_str(), windowsType)) { case IDOK: - return SDR_OK; + return SystemDialogResult::OK; case IDCANCEL: - return SDR_CANCEL; + return SystemDialogResult::CANCEL; case IDYES: - return SDR_YES; + return SystemDialogResult::YES; case IDNO: - return SDR_NO; + return SystemDialogResult::NO; default: break; } - return SDR_OK; -} - -void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp) -{ - LARGE_INTEGER value; - QueryPerformanceCounter(&value); - stamp->counterValue = value.QuadPart; -} - -void CSystemUtilsWindows::InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) -{ - dst->counterValue = a->counterValue + static_cast((b->counterValue - a->counterValue) * static_cast(i)); -} - -long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) -{ - float floatValue = static_cast(after->counterValue - before->counterValue) * (1e9 / static_cast(m_counterFrequency)); - return static_cast(floatValue); + return SystemDialogResult::OK; } //! Converts a wide Unicode string to an UTF8 string @@ -175,13 +152,3 @@ bool CSystemUtilsWindows::OpenWebsite(const std::string& url) return true; } -void CSystemUtilsWindows::Usleep(int usec) -{ - LARGE_INTEGER ft; - ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time - - HANDLE timer = CreateWaitableTimer(nullptr, TRUE, nullptr); - SetWaitableTimer(timer, &ft, 0, nullptr, nullptr, 0); - WaitForSingleObject(timer, INFINITE); - CloseHandle(timer); -} diff --git a/src/common/system/system_windows.h b/src/common/system/system_windows.h index 90ef6b91..c39285d5 100644 --- a/src/common/system/system_windows.h +++ b/src/common/system/system_windows.h @@ -26,11 +26,6 @@ //@colobot-lint-exclude UndefinedFunctionRule -struct SystemTimeStamp -{ - long long counterValue = 0; -}; - class CSystemUtilsWindows : public CSystemUtils { public: @@ -38,10 +33,6 @@ public: SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override; - void InterpolateTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *a, SystemTimeStamp *b, float i) override; - void GetCurrentTimeStamp(SystemTimeStamp *stamp) override; - long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override; - std::string GetSaveDir() override; std::string GetEnvVar(const std::string& name) override; @@ -49,14 +40,9 @@ public: bool OpenPath(const std::string& path) override; bool OpenWebsite(const std::string& url) override; - void Usleep(int usec) override; - public: static std::string UTF8_Encode(const std::wstring &wstr); static std::wstring UTF8_Decode(const std::string &str); - -protected: - long long m_counterFrequency = 0; }; //@end-colobot-lint-exclude diff --git a/src/common/thread/resource_owning_thread.h b/src/common/thread/resource_owning_thread.h deleted file mode 100644 index a6f515a3..00000000 --- a/src/common/thread/resource_owning_thread.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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 - */ - -#pragma once - -#include "common/thread/sdl_cond_wrapper.h" -#include "common/thread/sdl_mutex_wrapper.h" - -#include - -#include -#include - -/** - * \class CResourceOwningThread - * \brief Wrapper around SDL thread allowing passing of resources in safe manner - * - * This class is a workaround for passing ownership of resources in a safe - * manner to newly created threads. It takes a pointer to a function to call - * in new thread and a unique_ptr to resource which is to be passed to the new thread. - * - * This is how it works: - * - in main thread: create a new thread passing to it a special temporary context, - * - in main thread: wait for synchronization signal that the ownership was passed, - * - in new thread: acquire the resource from the context - * - in new thread: signal back to main thread that the resource was acquired, - * - in main thread: clean up temporary context and exit - * - in new thread: run the specified function with the acquired resource. - * - * It's a bit complicated, but that's the safe (thread-safe and exception-safe) - * way of doing this. - */ -template -class CResourceOwningThread -{ -public: - using ResourceUPtr = std::unique_ptr; - using ThreadFunctionPtr = void(*)(ResourceUPtr); - - CResourceOwningThread(ThreadFunctionPtr threadFunction, ResourceUPtr resource, std::string name = "") - : m_threadFunction(threadFunction), - m_resource(std::move(resource)), - m_name(name) - {} - - ~CResourceOwningThread() - { - SDL_DetachThread(m_thread); - } - - void Start() - { - CSDLMutexWrapper mutex; - CSDLCondWrapper cond; - bool condition = false; - - ThreadData data; - data.resource = std::move(m_resource); - data.threadFunction = m_threadFunction; - data.mutex = &mutex; - data.cond = &cond; - data.condition = &condition; - - SDL_LockMutex(*mutex); - - m_thread = SDL_CreateThread(Run, !m_name.empty() ? m_name.c_str() : nullptr, reinterpret_cast(&data)); - - while (!condition) - { - SDL_CondWait(*cond, *mutex); - } - - SDL_UnlockMutex(*mutex); - } - - void Join() - { - if (m_thread == nullptr) return; - SDL_WaitThread(m_thread, nullptr); - m_thread = nullptr; - } - -private: - static int Run(void* data) - { - ThreadFunctionPtr threadFunction = nullptr; - ResourceUPtr resource; - - ThreadData* threadData = reinterpret_cast(data); - SDL_LockMutex(**threadData->mutex); - - threadFunction = threadData->threadFunction; - resource = std::move(threadData->resource); - - *threadData->condition = true; - SDL_CondSignal(**threadData->cond); - SDL_UnlockMutex(**threadData->mutex); - - threadFunction(std::move(resource)); - return 0; - } - -private: - struct ThreadData - { - ResourceUPtr resource; - CSDLMutexWrapper* mutex = nullptr; - CSDLCondWrapper* cond = nullptr; - bool* condition = nullptr; - ThreadFunctionPtr threadFunction = nullptr; - }; - - ThreadFunctionPtr m_threadFunction; - ResourceUPtr m_resource; - std::string m_name; - SDL_Thread* m_thread = nullptr; -}; diff --git a/src/common/thread/sdl_cond_wrapper.h b/src/common/thread/sdl_cond_wrapper.h deleted file mode 100644 index 597e7fe7..00000000 --- a/src/common/thread/sdl_cond_wrapper.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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 - */ - -#pragma once - -#include "common/thread/sdl_mutex_wrapper.h" - -#include - -/** - * \class CSDLCondWrapper - * \brief Wrapper for safe creation/deletion of SDL_cond - */ -class CSDLCondWrapper -{ -public: - CSDLCondWrapper() - : m_cond(SDL_CreateCond()) - {} - - ~CSDLCondWrapper() - { - SDL_DestroyCond(m_cond); - } - - CSDLCondWrapper(const CSDLCondWrapper&) = delete; - CSDLCondWrapper& operator=(const CSDLCondWrapper&) = delete; - - SDL_cond* operator*() - { - return m_cond; - } - - void Signal() - { - SDL_CondSignal(m_cond); - } - - void Wait(SDL_mutex* mutex) - { - SDL_CondWait(m_cond, mutex); - } - -private: - SDL_cond* m_cond; -}; diff --git a/src/common/thread/sdl_mutex_wrapper.h b/src/common/thread/sdl_mutex_wrapper.h deleted file mode 100644 index 0c446010..00000000 --- a/src/common/thread/sdl_mutex_wrapper.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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 - */ - -#pragma once - -#include - -/** - * \class CSDLMutexWrapper - * \brief Wrapper for safe creation/deletion of SDL_mutex - */ -class CSDLMutexWrapper -{ -public: - CSDLMutexWrapper() - : m_mutex(SDL_CreateMutex()) - {} - - ~CSDLMutexWrapper() - { - SDL_DestroyMutex(m_mutex); - } - - CSDLMutexWrapper(const CSDLMutexWrapper&) = delete; - CSDLMutexWrapper& operator=(const CSDLMutexWrapper&) = delete; - - SDL_mutex* operator*() - { - return m_mutex; - } - - void Lock() - { - SDL_LockMutex(m_mutex); - } - - void Unlock() - { - SDL_UnlockMutex(m_mutex); - } - -private: - SDL_mutex* m_mutex; -}; diff --git a/src/common/thread/thread.h b/src/common/thread/thread.h deleted file mode 100644 index 12af2919..00000000 --- a/src/common/thread/thread.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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 - */ - -#pragma once - -#include "common/make_unique.h" - -#include "common/thread/resource_owning_thread.h" - -#include -#include -#include - -/** - * \class CThread - * \brief Wrapper for using SDL_thread with std::function - */ -class CThread -{ -public: - using ThreadFunctionPtr = std::function; - -private: - struct ThreadData - { - ThreadFunctionPtr func; - }; - -public: - CThread(ThreadFunctionPtr func, std::string name = "") - : m_func(std::move(func)) - , m_name(name) - {} - - void Start() - { - std::unique_ptr data = MakeUnique(); - data->func = m_func; - m_thread = MakeUnique>(Run, std::move(data), m_name); - m_thread->Start(); - } - - void Join() - { - if (!m_thread) return; - m_thread->Join(); - } - - CThread(const CThread&) = delete; - CThread& operator=(const CThread&) = delete; - -private: - static void Run(std::unique_ptr data) - { - data->func(); - } - - std::unique_ptr> m_thread; - ThreadFunctionPtr m_func; - std::string m_name; -}; diff --git a/src/common/thread/worker_thread.h b/src/common/thread/worker_thread.h index a877a754..01b4ec8f 100644 --- a/src/common/thread/worker_thread.h +++ b/src/common/thread/worker_thread.h @@ -21,13 +21,12 @@ #include "common/make_unique.h" -#include "common/thread/sdl_cond_wrapper.h" -#include "common/thread/sdl_mutex_wrapper.h" -#include "common/thread/thread.h" - +#include #include -#include +#include #include +#include +#include /** * \class CWorkerThread @@ -39,27 +38,23 @@ public: using ThreadFunctionPtr = std::function; public: - CWorkerThread(std::string name = "") - : m_thread(std::bind(&CWorkerThread::Run, this), name) - { - m_thread.Start(); - } + CWorkerThread() : m_thread{&CWorkerThread::Run, this} {} ~CWorkerThread() { - m_mutex.Lock(); - m_running = false; - m_cond.Signal(); - m_mutex.Unlock(); - m_thread.Join(); + { + std::lock_guard lock{m_mutex}; + m_running = false; + m_cond.notify_one(); + } + m_thread.join(); } - void Start(ThreadFunctionPtr func) + void Start(ThreadFunctionPtr&& func) { - m_mutex.Lock(); + std::lock_guard lock{m_mutex}; m_queue.push(func); - m_cond.Signal(); - m_mutex.Unlock(); + m_cond.notify_one(); } CWorkerThread(const CWorkerThread&) = delete; @@ -68,25 +63,21 @@ public: private: void Run() { - m_mutex.Lock(); + auto lock = std::unique_lock(m_mutex); while (true) { - while (m_queue.empty() && m_running) - { - m_cond.Wait(*m_mutex); - } + m_cond.wait(lock, [&]() { return !m_running || !m_queue.empty(); }); if (!m_running) break; - ThreadFunctionPtr func = m_queue.front(); + ThreadFunctionPtr func = std::move(m_queue.front()); m_queue.pop(); func(); } - m_mutex.Unlock(); } - CThread m_thread; - CSDLMutexWrapper m_mutex; - CSDLCondWrapper m_cond; + std::thread m_thread; + std::mutex m_mutex; + std::condition_variable m_cond; bool m_running = true; std::queue m_queue; }; diff --git a/src/common/timeutils.cpp b/src/common/timeutils.cpp new file mode 100644 index 00000000..96bcaa9c --- /dev/null +++ b/src/common/timeutils.cpp @@ -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 + +namespace TimeUtils +{ + +TimeStamp Lerp(TimeStamp a, TimeStamp b, float t) +{ + return a + std::chrono::duration_cast((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(after - before).count(); +} + +} // namespace TimeUtils diff --git a/src/common/timeutils.h b/src/common/timeutils.h new file mode 100644 index 00000000..5d67f4d7 --- /dev/null +++ b/src/common/timeutils.h @@ -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 + +namespace TimeUtils +{ + +enum class TimeUnit +{ + SECONDS, + MILLISECONDS, + MICROSECONDS +}; + +using TimeStamp = std::chrono::time_point; + +//! 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 diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index c146d767..f241f85d 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -32,8 +32,6 @@ #include "common/system/system.h" -#include "common/thread/resource_owning_thread.h" - #include "graphics/core/device.h" #include "graphics/core/framebuffer.h" @@ -63,6 +61,9 @@ #include #include #include +#include + +using TimeUtils::TimeUnit; // Graphics module namespace namespace Gfx @@ -218,8 +219,6 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) m_mouseType = ENG_MOUSE_NORM; m_fpsCounter = 0; - m_lastFrameTime = m_systemUtils->CreateTimeStamp(); - m_currentFrameTime = m_systemUtils->CreateTimeStamp(); m_shadowColor = 0.5f; @@ -243,10 +242,6 @@ CEngine::CEngine(CApplication *app, CSystemUtils* systemUtils) CEngine::~CEngine() { - m_systemUtils->DestroyTimeStamp(m_lastFrameTime); - m_lastFrameTime = nullptr; - m_systemUtils->DestroyTimeStamp(m_currentFrameTime); - m_currentFrameTime = nullptr; } void CEngine::SetDevice(CDevice *device) @@ -364,8 +359,8 @@ bool CEngine::Create() params.mipmap = false; m_miceTexture = LoadTexture("textures/interface/mouse.png", params); - m_systemUtils->GetCurrentTimeStamp(m_currentFrameTime); - m_systemUtils->GetCurrentTimeStamp(m_lastFrameTime); + m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp(); + m_lastFrameTime = m_systemUtils->GetCurrentTimeStamp(); return true; } @@ -503,8 +498,7 @@ void CEngine::WriteScreenShot(const std::string& fileName) data->fileName = fileName; - CResourceOwningThread thread(CEngine::WriteScreenShotThread, std::move(data), "WriteScreenShot thread"); - thread.Start(); + std::thread{&CEngine::WriteScreenShotThread, std::move(data)}.detach(); } void CEngine::WriteScreenShotThread(std::unique_ptr data) @@ -3175,11 +3169,11 @@ void CEngine::Render() { m_fpsCounter++; - m_systemUtils->GetCurrentTimeStamp(m_currentFrameTime); - float diff = m_systemUtils->TimeStampDiff(m_lastFrameTime, m_currentFrameTime, STU_SEC); + m_currentFrameTime = m_systemUtils->GetCurrentTimeStamp(); + float diff = TimeUtils::Diff(m_lastFrameTime, m_currentFrameTime, TimeUnit::SECONDS); if (diff > 1.0f) { - m_systemUtils->CopyTimeStamp(m_lastFrameTime, m_currentFrameTime); + m_lastFrameTime = m_currentFrameTime; m_fps = m_fpsCounter / diff; m_fpsCounter = 0; diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index aee24f34..db6eb8e1 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -25,6 +25,7 @@ #pragma once #include "common/singleton.h" +#include "common/system/system.h" #include "graphics/core/color.h" #include "graphics/core/material.h" @@ -50,7 +51,6 @@ class CApplication; class CSoundInterface; class CImage; class CSystemUtils; -struct SystemTimeStamp; struct Event; @@ -1310,8 +1310,8 @@ protected: //! Last encountered error std::string m_error; - SystemTimeStamp* m_lastFrameTime; - SystemTimeStamp* m_currentFrameTime; + TimeUtils::TimeStamp m_lastFrameTime; + TimeUtils::TimeStamp m_currentFrameTime; int m_fpsCounter; float m_fps; diff --git a/src/sound/oalsound/alsound.cpp b/src/sound/oalsound/alsound.cpp index 26006198..4a22d6b0 100644 --- a/src/sound/oalsound/alsound.cpp +++ b/src/sound/oalsound/alsound.cpp @@ -32,8 +32,7 @@ CALSound::CALSound() m_musicVolume(1.0f), m_channelsLimit(2048), m_device{}, - m_context{}, - m_thread("Music loading thread") + m_context{} { } diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 6121021e..b549229e 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,5 +1,3 @@ -# Test files - set(TEST_FILES common/colobot.ini ) @@ -16,19 +14,12 @@ add_executable(colobot_ut CBot/CBotToken_test.cpp CBot/CBot_test.cpp common/config_file_test.cpp + common/timeutils_test.cpp graphics/engine/lightman_test.cpp math/func_test.cpp math/geometry_test.cpp math/matrix_test.cpp - math/vector_test.cpp -) - -# Platform-dependent tests -if(PLATFORM_WINDOWS) - target_sources(colobot_ut PRIVATE common/system/system_windows_test.cpp) -elseif(PLATFORM_LINUX) - target_sources(colobot_ut PRIVATE common/system/system_linux_test.cpp) -endif() + math/vector_test.cpp) target_include_directories(colobot_ut PRIVATE common diff --git a/test/unit/app/app_test.cpp b/test/unit/app/app_test.cpp index aad94e39..549941c6 100644 --- a/test/unit/app/app_test.cpp +++ b/test/unit/app/app_test.cpp @@ -31,14 +31,7 @@ using namespace HippoMocks; namespace ph = std::placeholders; - -struct FakeSystemTimeStamp : public SystemTimeStamp -{ - FakeSystemTimeStamp(int uid) : uid(uid), time(0) {} - - int uid; - long long time; -}; +using TimeUtils::TimeStamp; class CApplicationWrapper : public CApplication { @@ -55,7 +48,7 @@ public: SDL_Quit(); } - Event CreateUpdateEvent(SystemTimeStamp *timestamp) override + Event CreateUpdateEvent(TimeStamp timestamp) override { return CApplication::CreateUpdateEvent(timestamp); } @@ -66,7 +59,6 @@ class CApplicationUT : public testing::Test protected: CApplicationUT() : m_systemUtils(nullptr), - m_stampUid(0), m_currentTime(0) {} @@ -78,11 +70,7 @@ protected: void NextInstant(long long diff); - SystemTimeStamp* CreateTimeStamp(); - void DestroyTimeStamp(SystemTimeStamp *stamp); - void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src); - void GetCurrentTimeStamp(SystemTimeStamp *stamp); - long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after); + TimeStamp GetCurrentTimeStamp(); void TestCreateUpdateEvent(long long relTimeExact, long long absTimeExact, float relTime, float absTime, @@ -92,10 +80,8 @@ protected: std::unique_ptr m_app; MockRepository m_mocks; CSystemUtils* m_systemUtils; - std::vector> m_timeStamps; private: - int m_stampUid; long long m_currentTime; }; @@ -107,11 +93,7 @@ void CApplicationUT::SetUp() m_mocks.OnCall(m_systemUtils, CSystemUtils::GetLangPath).Return(""); m_mocks.OnCall(m_systemUtils, CSystemUtils::GetSaveDir).Return(""); - m_mocks.OnCall(m_systemUtils, CSystemUtils::CreateTimeStamp).Do(std::bind(&CApplicationUT::CreateTimeStamp, this)); - m_mocks.OnCall(m_systemUtils, CSystemUtils::DestroyTimeStamp).Do(std::bind(&CApplicationUT::DestroyTimeStamp, this, ph::_1)); - m_mocks.OnCall(m_systemUtils, CSystemUtils::CopyTimeStamp).Do(std::bind(&CApplicationUT::CopyTimeStamp, this, ph::_1, ph::_2)); - m_mocks.OnCall(m_systemUtils, CSystemUtils::GetCurrentTimeStamp).Do(std::bind(&CApplicationUT::GetCurrentTimeStamp, this, ph::_1)); - m_mocks.OnCall(m_systemUtils, CSystemUtils::TimeStampExactDiff).Do(std::bind(&CApplicationUT::TimeStampExactDiff, this, ph::_1, ph::_2)); + m_mocks.OnCall(m_systemUtils, CSystemUtils::GetCurrentTimeStamp).Do(std::bind(&CApplicationUT::GetCurrentTimeStamp, this)); m_app = MakeUnique(m_systemUtils); } @@ -121,31 +103,10 @@ void CApplicationUT::TearDown() m_app.reset(); } -SystemTimeStamp* CApplicationUT::CreateTimeStamp() -{ - auto stamp = MakeUnique(++m_stampUid); - auto stampPtr = stamp.get(); - m_timeStamps.push_back(std::move(stamp)); - return stampPtr; -} -void CApplicationUT::DestroyTimeStamp(SystemTimeStamp *stamp) +TimeStamp CApplicationUT::GetCurrentTimeStamp() { -} - -void CApplicationUT::CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src) -{ - *static_cast(dst) = *static_cast(src); -} - -void CApplicationUT::GetCurrentTimeStamp(SystemTimeStamp *stamp) -{ - static_cast(stamp)->time = m_currentTime; -} - -long long CApplicationUT::TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) -{ - return static_cast(after)->time - static_cast(before)->time; + return TimeStamp{ TimeStamp::duration{m_currentTime}}; } void CApplicationUT::NextInstant(long long diff) @@ -157,8 +118,7 @@ void CApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long abs float relTime, float absTime, long long relTimeReal, long long absTimeReal) { - SystemTimeStamp *now = CreateTimeStamp(); - GetCurrentTimeStamp(now); + TimeStamp now = GetCurrentTimeStamp(); Event event = m_app->CreateUpdateEvent(now); EXPECT_EQ(EVENT_FRAME, event.type); EXPECT_FLOAT_EQ(relTime, event.rTime); @@ -175,9 +135,7 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_SimulationSuspended) { m_app->SuspendSimulation(); - SystemTimeStamp *now = CreateTimeStamp(); - GetCurrentTimeStamp(now); - Event event = m_app->CreateUpdateEvent(now); + Event event = m_app->CreateUpdateEvent(GetCurrentTimeStamp()); EXPECT_EQ(EVENT_NULL, event.type); } @@ -230,9 +188,7 @@ TEST_F(CApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation) NextInstant(-1111); - SystemTimeStamp *now = CreateTimeStamp(); - GetCurrentTimeStamp(now); - Event event = m_app->CreateUpdateEvent(now); + Event event = m_app->CreateUpdateEvent(GetCurrentTimeStamp()); EXPECT_EQ(EVENT_NULL, event.type); } diff --git a/test/unit/common/system/system_linux_test.cpp b/test/unit/common/system/system_linux_test.cpp deleted file mode 100644 index 6a503c18..00000000 --- a/test/unit/common/system/system_linux_test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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.h" -#include "common/system/system_linux.h" - -#include - -class CSystemUtilsLinuxUT : public testing::Test -{ -protected: - static const long long SEC = 1000000000; - - CSystemUtilsLinux m_systemUtils; -}; - - -TEST_F(CSystemUtilsLinuxUT, TimeStampDiff) -{ - SystemTimeStamp before, after; - - before.clockTime.tv_sec = 1; - before.clockTime.tv_nsec = 100; - - after.clockTime.tv_sec = 1; - after.clockTime.tv_nsec = 900; - - long long tDiff = m_systemUtils.TimeStampExactDiff(&before, &after); - EXPECT_EQ( 800, tDiff); - - tDiff = m_systemUtils.TimeStampExactDiff(&after, &before); - EXPECT_EQ(-800, tDiff); - - // ------- - - before.clockTime.tv_sec = 2; - before.clockTime.tv_nsec = 200; - - after.clockTime.tv_sec = 3; - after.clockTime.tv_nsec = 500; - - tDiff = m_systemUtils.TimeStampExactDiff(&before, &after); - EXPECT_EQ( SEC + 300, tDiff); - - tDiff = m_systemUtils.TimeStampExactDiff(&after, &before); - EXPECT_EQ(-SEC - 300, tDiff); - - // ------- - - before.clockTime.tv_sec = 3; - before.clockTime.tv_nsec = 200; - - after.clockTime.tv_sec = 4; - after.clockTime.tv_nsec = 100; - - tDiff = m_systemUtils.TimeStampExactDiff(&before, &after); - EXPECT_EQ( SEC - 100, tDiff); - - tDiff = m_systemUtils.TimeStampExactDiff(&after, &before); - EXPECT_EQ(-SEC + 100, tDiff); -} diff --git a/test/unit/common/system/system_windows_test.cpp b/test/unit/common/system/system_windows_test.cpp deleted file mode 100644 index eb959ff0..00000000 --- a/test/unit/common/system/system_windows_test.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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.h" -#include "common/system/system_windows.h" - -#include - -class CSystemUtilsWindowsWrapper : public CSystemUtilsWindows -{ -public: - void SetFrequency(long long frequency) - { - m_counterFrequency = frequency; - } -}; - -class CSystemUtilsWindowsUT : public testing::Test -{ -protected: - static const long long SEC = 1000000000; - - CSystemUtilsWindowsWrapper m_systemUtils; -}; - -TEST_F(CSystemUtilsWindowsUT, TimeStampDiff) -{ - m_systemUtils.SetFrequency(SEC); - - SystemTimeStamp before, after; - - before.counterValue = 100; - after.counterValue = 200; - - long long tDiff = m_systemUtils.TimeStampExactDiff(&before, &after); - EXPECT_EQ( 100, tDiff); - - tDiff = m_systemUtils.TimeStampExactDiff(&after, &before); - EXPECT_EQ(-100, tDiff); - - // ------- - - m_systemUtils.SetFrequency(SEC/3); - - before.counterValue = 200; - after.counterValue = 400; - - tDiff = m_systemUtils.TimeStampExactDiff(&before, &after); - EXPECT_EQ( 200*3, tDiff); - - tDiff = m_systemUtils.TimeStampExactDiff(&after, &before); - EXPECT_EQ(-200*3, tDiff); -} diff --git a/test/unit/common/timeutils_test.cpp b/test/unit/common/timeutils_test.cpp new file mode 100644 index 00000000..0f312a53 --- /dev/null +++ b/test/unit/common/timeutils_test.cpp @@ -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 + +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