Merge pull request #1461 from colobot/AbigailBuccaneer-platform-independent
Merge PR#1141 "Use C++11 threading and timing constructs"fix-squashed-planets
commit
95579bbf1d
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 0ac8197b7a8a005c714b7696d36c642cf0e81474
|
||||
Subproject commit 21a45c0b8809accd142a83a81f1a3c92a327f319
|
|
@ -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
|
||||
|
|
|
@ -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 <libintl.h>
|
||||
#include <getopt.h>
|
||||
#include <localename.h>
|
||||
#include <thread>
|
||||
|
||||
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<int>(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<float>(numTickSlices));
|
||||
interpolatedTimeStamp = TimeUtils::Lerp(previousTimeStamp, currentTimeStamp, (tickSlice+1)/static_cast<float>(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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<std::mutex> 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<std::mutex> lock{m_mutex};
|
||||
|
||||
if (m_head == m_tail)
|
||||
{
|
||||
|
@ -673,7 +666,5 @@ Event CEventQueue::GetEvent()
|
|||
|
||||
}
|
||||
|
||||
SDL_UnlockMutex(*m_mutex);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
|
|
@ -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 <memory>
|
||||
#include <mutex>
|
||||
|
||||
/**
|
||||
\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;
|
||||
|
|
|
@ -23,10 +23,12 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
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<SystemTimeStamp*> CProfiler::m_runningPerformanceCounters;
|
||||
std::stack<TimeStamp> CProfiler::m_runningPerformanceCounters;
|
||||
std::stack<PerformanceCounter> 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)
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#pragma once
|
||||
|
||||
class CSystemUtils;
|
||||
struct SystemTimeStamp;
|
||||
|
||||
#include "common/system/system.h"
|
||||
#include <stack>
|
||||
|
||||
/**
|
||||
|
@ -73,7 +73,7 @@ private:
|
|||
|
||||
static long long m_performanceCounters[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;
|
||||
};
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
|
@ -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>();
|
||||
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<SystemTimeStamp>& 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});
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/timeutils.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -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<std::unique_ptr<SystemTimeStamp>> m_timeStamps;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -24,15 +24,8 @@
|
|||
|
||||
#include "common/system/system.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
//@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;
|
||||
};
|
||||
|
|
|
@ -140,8 +140,3 @@ bool CSystemUtilsMacOSX::OpenWebsite(const std::string& url)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CSystemUtilsMacOSX::Usleep(int usec)
|
||||
{
|
||||
usleep(usec);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Uint32>((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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<long long>((b->counterValue - a->counterValue) * static_cast<double>(i));
|
||||
}
|
||||
|
||||
long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
|
||||
{
|
||||
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));
|
||||
return static_cast<long long>(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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <SDL_thread.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* \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<typename Resource>
|
||||
class CResourceOwningThread
|
||||
{
|
||||
public:
|
||||
using ResourceUPtr = std::unique_ptr<Resource>;
|
||||
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<void*>(&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<ThreadData*>(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;
|
||||
};
|
|
@ -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 <SDL_thread.h>
|
||||
|
||||
/**
|
||||
* \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;
|
||||
};
|
|
@ -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 <SDL_thread.h>
|
||||
|
||||
/**
|
||||
* \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;
|
||||
};
|
|
@ -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 <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* \class CThread
|
||||
* \brief Wrapper for using SDL_thread with std::function
|
||||
*/
|
||||
class CThread
|
||||
{
|
||||
public:
|
||||
using ThreadFunctionPtr = std::function<void()>;
|
||||
|
||||
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<ThreadData> data = MakeUnique<ThreadData>();
|
||||
data->func = m_func;
|
||||
m_thread = MakeUnique<CResourceOwningThread<ThreadData>>(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<ThreadData> data)
|
||||
{
|
||||
data->func();
|
||||
}
|
||||
|
||||
std::unique_ptr<CResourceOwningThread<ThreadData>> m_thread;
|
||||
ThreadFunctionPtr m_func;
|
||||
std::string m_name;
|
||||
};
|
|
@ -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 <condition_variable>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
/**
|
||||
* \class CWorkerThread
|
||||
|
@ -39,27 +38,23 @@ public:
|
|||
using ThreadFunctionPtr = std::function<void()>;
|
||||
|
||||
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<std::mutex> 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<std::mutex> 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<std::mutex>(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<ThreadFunctionPtr> m_queue;
|
||||
};
|
||||
|
|
|
@ -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
|
|
@ -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 <iomanip>
|
||||
#include <SDL_surface.h>
|
||||
#include <SDL_thread.h>
|
||||
#include <thread>
|
||||
|
||||
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<WriteScreenShotData> thread(CEngine::WriteScreenShotThread, std::move(data), "WriteScreenShot thread");
|
||||
thread.Start();
|
||||
std::thread{&CEngine::WriteScreenShotThread, std::move(data)}.detach();
|
||||
}
|
||||
|
||||
void CEngine::WriteScreenShotThread(std::unique_ptr<WriteScreenShotData> 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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -32,8 +32,7 @@ CALSound::CALSound()
|
|||
m_musicVolume(1.0f),
|
||||
m_channelsLimit(2048),
|
||||
m_device{},
|
||||
m_context{},
|
||||
m_thread("Music loading thread")
|
||||
m_context{}
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<CApplicationWrapper> m_app;
|
||||
MockRepository m_mocks;
|
||||
CSystemUtils* m_systemUtils;
|
||||
std::vector<std::unique_ptr<FakeSystemTimeStamp>> 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<CApplicationWrapper>(m_systemUtils);
|
||||
}
|
||||
|
@ -121,31 +103,10 @@ void CApplicationUT::TearDown()
|
|||
m_app.reset();
|
||||
}
|
||||
|
||||
SystemTimeStamp* CApplicationUT::CreateTimeStamp()
|
||||
{
|
||||
auto stamp = MakeUnique<FakeSystemTimeStamp>(++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<FakeSystemTimeStamp*>(dst) = *static_cast<FakeSystemTimeStamp*>(src);
|
||||
}
|
||||
|
||||
void CApplicationUT::GetCurrentTimeStamp(SystemTimeStamp *stamp)
|
||||
{
|
||||
static_cast<FakeSystemTimeStamp*>(stamp)->time = m_currentTime;
|
||||
}
|
||||
|
||||
long long CApplicationUT::TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
|
||||
{
|
||||
return static_cast<FakeSystemTimeStamp*>(after)->time - static_cast<FakeSystemTimeStamp*>(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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <gtest/gtest.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <gtest/gtest.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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