Fixed timer functions on win32

* changed win32 implementation to QueryPerformaceTimer system function
 * refactored system utils code
 * proper tests for time utils and update event creation in application
 * should fix issue #134
dev-ui
Piotr Dziwinski 2013-03-24 00:03:37 +01:00
parent c211b001d2
commit 195d6cded0
27 changed files with 922 additions and 393 deletions

View File

@ -94,14 +94,6 @@ option(INSTALL_DOCS "Install Doxygen-generated documentation" OFF)
option(OPENAL_SOUND "Build openal sound support" OFF)
# Hacks for MSYS
if (MSYS)
set(COLOBOT_CXX_FLAGS "${COLOBOT_CXX_FLAGS} -U__STRICT_ANSI__") # fixes putenv()
set(USE_SDL_MAIN 1) # fixes SDL_main
set(DESKTOP OFF) # MSYS doesn't have the necessary tools
endif()
##
# Searching for packages
##
@ -131,35 +123,24 @@ if (${OPENAL_SOUND})
endif()
##
# Additional settings to use when cross-compiling with MXE (http://mxe.cc/)
##
include("${colobot_SOURCE_DIR}/cmake/mxe.cmake")
##
# Platform detection and some related checks
##
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
message(STATUS "Windows system detected")
set(PLATFORM_WINDOWS 1)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 0)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
message(STATUS "Linux system detected")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 1)
set(PLATFORM_OTHER 0)
else()
message(STATUS "Other system detected")
set(PLATFORM_WINDOWS 0)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 1)
endif()
if(NOT ${ASSERTS})
add_definitions(-DNDEBUG)
endif()
@ -171,6 +152,30 @@ else()
endif()
##
# Additional settings to use when cross-compiling with MXE (http://mxe.cc/)
##
include("${colobot_SOURCE_DIR}/cmake/mxe.cmake")
##
# Additional settings for MSYS
##
include("${colobot_SOURCE_DIR}/cmake/msys.cmake")
##
# Summary of detected things
##
if (${PLATFORM_WINDOWS})
message(STATUS "Build for Windows system")
elseif(${PLATFORM_LINUX})
message(STATUS "Build for Linux system")
else()
message(STATUS "Build for other system")
endif()
##
# Doxygen docs
##

12
cmake/msys.cmake Normal file
View File

@ -0,0 +1,12 @@
# Hacks for MSYS
if (MSYS AND (NOT MXE))
message(STATUS "Detected MSYS build")
set(PLATFORM_WINDOWS 1)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 0)
set(COLOBOT_CXX_FLAGS "${COLOBOT_CXX_FLAGS} -U__STRICT_ANSI__") # fixes putenv()
set(USE_SDL_MAIN 1) # fixes SDL_main
set(DESKTOP OFF) # MSYS doesn't have the necessary tools
endif()

View File

@ -4,6 +4,9 @@
if((${CMAKE_CROSSCOMPILING}) AND (DEFINED MSYS))
message(STATUS "Detected MXE build")
set(MXE 1)
set(PLATFORM_WINDOWS 1)
set(PLATFORM_LINUX 0)
set(PLATFORM_OTHER 0)
# Because some tests will not compile
set(TESTS OFF)
# All must be static, CBOT and GLEW too

View File

@ -52,9 +52,9 @@ if (${OPENAL_SOUND})
endif()
# Platform-dependent implementation of system.h
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if (${PLATFORM_WINDOWS})
set(SYSTEM_CPP_MODULE "system_windows.cpp")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
elseif(${PLATFORM_LINUX})
set(SYSTEM_CPP_MODULE "system_linux.cpp")
else()
set(SYSTEM_CPP_MODULE "system_other.cpp")

View File

@ -125,14 +125,14 @@ CApplication::CApplication()
m_absTime = 0.0f;
m_relTime = 0.0f;
m_baseTimeStamp = CreateTimeStamp();
m_curTimeStamp = CreateTimeStamp();
m_lastTimeStamp = CreateTimeStamp();
m_baseTimeStamp = GetSystemUtils()->CreateTimeStamp();
m_curTimeStamp = GetSystemUtils()->CreateTimeStamp();
m_lastTimeStamp = GetSystemUtils()->CreateTimeStamp();
for (int i = 0; i < PCNT_MAX; ++i)
{
m_performanceCounters[i][0] = CreateTimeStamp();
m_performanceCounters[i][1] = CreateTimeStamp();
m_performanceCounters[i][0] = GetSystemUtils()->CreateTimeStamp();
m_performanceCounters[i][1] = GetSystemUtils()->CreateTimeStamp();
}
m_joystickEnabled = false;
@ -177,14 +177,14 @@ CApplication::~CApplication()
delete m_iMan;
m_iMan = nullptr;
DestroyTimeStamp(m_baseTimeStamp);
DestroyTimeStamp(m_curTimeStamp);
DestroyTimeStamp(m_lastTimeStamp);
GetSystemUtils()->DestroyTimeStamp(m_baseTimeStamp);
GetSystemUtils()->DestroyTimeStamp(m_curTimeStamp);
GetSystemUtils()->DestroyTimeStamp(m_lastTimeStamp);
for (int i = 0; i < PCNT_MAX; ++i)
{
DestroyTimeStamp(m_performanceCounters[i][0]);
DestroyTimeStamp(m_performanceCounters[i][1]);
GetSystemUtils()->DestroyTimeStamp(m_performanceCounters[i][0]);
GetSystemUtils()->DestroyTimeStamp(m_performanceCounters[i][1]);
}
}
@ -199,8 +199,8 @@ CSoundInterface* CApplication::GetSound()
for (int i = 0; i < PCNT_MAX; ++i)
{
DestroyTimeStamp(m_performanceCounters[i][0]);
DestroyTimeStamp(m_performanceCounters[i][1]);
GetSystemUtils()->DestroyTimeStamp(m_performanceCounters[i][0]);
GetSystemUtils()->DestroyTimeStamp(m_performanceCounters[i][1]);
}
}
@ -607,7 +607,7 @@ bool CApplication::ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig)
std::string(SDL_GetError()) + std::string("\n") +
std::string("Previous mode will be restored");
GetLogger()->Error(error.c_str());
SystemDialog( SDT_ERROR, "COLOBT - Error", error);
GetSystemUtils()->SystemDialog( SDT_ERROR, "COLOBT - Error", error);
restore = true;
ChangeVideoConfig(m_lastDeviceConfig);
@ -620,7 +620,7 @@ bool CApplication::ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig)
std::string error = std::string("SDL error while restoring previous video mode:\n") +
std::string(SDL_GetError());
GetLogger()->Error(error.c_str());
SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", error);
GetSystemUtils()->SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", error);
// Fatal error, so post the quit event
@ -755,9 +755,9 @@ int CApplication::Run()
{
m_active = true;
GetCurrentTimeStamp(m_baseTimeStamp);
GetCurrentTimeStamp(m_lastTimeStamp);
GetCurrentTimeStamp(m_curTimeStamp);
GetSystemUtils()->GetCurrentTimeStamp(m_baseTimeStamp);
GetSystemUtils()->GetCurrentTimeStamp(m_lastTimeStamp);
GetSystemUtils()->GetCurrentTimeStamp(m_curTimeStamp);
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
@ -1109,49 +1109,49 @@ bool CApplication::ProcessEvent(const Event &event)
{
case EVENT_KEY_DOWN:
case EVENT_KEY_UP:
l->Info("EVENT_KEY_%s:\n", (event.type == EVENT_KEY_DOWN) ? "DOWN" : "UP");
l->Info(" virt = %s\n", (event.key.virt) ? "true" : "false");
l->Info(" key = %d\n", event.key.key);
l->Info(" unicode = 0x%04x\n", event.key.unicode);
l->Trace("EVENT_KEY_%s:\n", (event.type == EVENT_KEY_DOWN) ? "DOWN" : "UP");
l->Trace(" virt = %s\n", (event.key.virt) ? "true" : "false");
l->Trace(" key = %d\n", event.key.key);
l->Trace(" unicode = 0x%04x\n", event.key.unicode);
break;
case EVENT_MOUSE_MOVE:
l->Info("EVENT_MOUSE_MOVE:\n");
l->Trace("EVENT_MOUSE_MOVE:\n");
break;
case EVENT_MOUSE_BUTTON_DOWN:
case EVENT_MOUSE_BUTTON_UP:
l->Info("EVENT_MOUSE_BUTTON_%s:\n", (event.type == EVENT_MOUSE_BUTTON_DOWN) ? "DOWN" : "UP");
l->Info(" button = %d\n", event.mouseButton.button);
l->Trace("EVENT_MOUSE_BUTTON_%s:\n", (event.type == EVENT_MOUSE_BUTTON_DOWN) ? "DOWN" : "UP");
l->Trace(" button = %d\n", event.mouseButton.button);
break;
case EVENT_MOUSE_WHEEL:
l->Info("EVENT_MOUSE_WHEEL:\n");
l->Info(" dir = %s\n", (event.mouseWheel.dir == WHEEL_DOWN) ? "WHEEL_DOWN" : "WHEEL_UP");
l->Trace("EVENT_MOUSE_WHEEL:\n");
l->Trace(" dir = %s\n", (event.mouseWheel.dir == WHEEL_DOWN) ? "WHEEL_DOWN" : "WHEEL_UP");
break;
case EVENT_JOY_AXIS:
l->Info("EVENT_JOY_AXIS:\n");
l->Info(" axis = %d\n", event.joyAxis.axis);
l->Info(" value = %d\n", event.joyAxis.value);
l->Trace("EVENT_JOY_AXIS:\n");
l->Trace(" axis = %d\n", event.joyAxis.axis);
l->Trace(" value = %d\n", event.joyAxis.value);
break;
case EVENT_JOY_BUTTON_DOWN:
case EVENT_JOY_BUTTON_UP:
l->Info("EVENT_JOY_BUTTON_%s:\n", (event.type == EVENT_JOY_BUTTON_DOWN) ? "DOWN" : "UP");
l->Info(" button = %d\n", event.joyButton.button);
l->Trace("EVENT_JOY_BUTTON_%s:\n", (event.type == EVENT_JOY_BUTTON_DOWN) ? "DOWN" : "UP");
l->Trace(" button = %d\n", event.joyButton.button);
break;
case EVENT_ACTIVE:
l->Info("EVENT_ACTIVE:\n");
l->Info(" flags = 0x%x\n", event.active.flags);
l->Info(" gain = %s\n", event.active.gain ? "true" : "false");
l->Trace("EVENT_ACTIVE:\n");
l->Trace(" flags = 0x%x\n", event.active.flags);
l->Trace(" gain = %s\n", event.active.gain ? "true" : "false");
break;
default:
l->Info("Event type = %d:\n", static_cast<int>(event.type));
l->Trace("Event type = %d:\n", static_cast<int>(event.type));
break;
}
l->Info(" systemEvent = %s\n", event.systemEvent ? "true" : "false");
l->Info(" rTime = %f\n", event.rTime);
l->Info(" kmodState = %04x\n", event.kmodState);
l->Info(" trackedKeysState = %04x\n", event.trackedKeysState);
l->Info(" mousePos = %f, %f\n", event.mousePos.x, event.mousePos.y);
l->Info(" mouseButtonsState = %02x\n", event.mouseButtonsState);
l->Trace(" systemEvent = %s\n", event.systemEvent ? "true" : "false");
l->Trace(" rTime = %f\n", event.rTime);
l->Trace(" kmodState = %04x\n", event.kmodState);
l->Trace(" trackedKeysState = %04x\n", event.trackedKeysState);
l->Trace(" mousePos = %f, %f\n", event.mousePos.x, event.mousePos.y);
l->Trace(" mouseButtonsState = %02x\n", event.mouseButtonsState);
}
// By default, pass on all events
@ -1219,8 +1219,8 @@ void CApplication::ResumeSimulation()
{
m_simulationSuspended = false;
GetCurrentTimeStamp(m_baseTimeStamp);
CopyTimeStamp(m_curTimeStamp, m_baseTimeStamp);
GetSystemUtils()->GetCurrentTimeStamp(m_baseTimeStamp);
GetSystemUtils()->CopyTimeStamp(m_curTimeStamp, m_baseTimeStamp);
m_realAbsTimeBase = m_realAbsTime;
m_absTimeBase = m_exactAbsTime;
@ -1236,7 +1236,7 @@ void CApplication::SetSimulationSpeed(float speed)
{
m_simulationSpeed = speed;
GetCurrentTimeStamp(m_baseTimeStamp);
GetSystemUtils()->GetCurrentTimeStamp(m_baseTimeStamp);
m_realAbsTimeBase = m_realAbsTime;
m_absTimeBase = m_exactAbsTime;
@ -1248,18 +1248,31 @@ Event CApplication::CreateUpdateEvent()
if (m_simulationSuspended)
return Event(EVENT_NULL);
CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
GetCurrentTimeStamp(m_curTimeStamp);
GetSystemUtils()->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
GetSystemUtils()->GetCurrentTimeStamp(m_curTimeStamp);
long long absDiff = TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
m_realAbsTime = m_realAbsTimeBase + absDiff;
// m_baseTimeStamp is updated on simulation speed change, so this is OK
m_exactAbsTime = m_absTimeBase + m_simulationSpeed * absDiff;
m_absTime = (m_absTimeBase + m_simulationSpeed * absDiff) / 1e9f;
long long absDiff = GetSystemUtils()->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
long long newRealAbsTime = m_realAbsTimeBase + absDiff;
long long newRealRelTime = GetSystemUtils()->TimeStampExactDiff(m_lastTimeStamp, m_curTimeStamp);
m_realRelTime = TimeStampExactDiff(m_lastTimeStamp, m_curTimeStamp);
m_exactRelTime = m_simulationSpeed * m_realRelTime;
m_relTime = (m_simulationSpeed * m_realRelTime) / 1e9f;
if (newRealAbsTime < m_realAbsTime || newRealRelTime < 0)
{
GetLogger()->Error("Fatal error: got negative system counter difference!\n");
GetLogger()->Error("This should never happen. Please report this error.\n");
m_eventQueue->AddEvent(Event(EVENT_QUIT));
return Event(EVENT_NULL);
}
else
{
m_realAbsTime = newRealAbsTime;
// m_baseTimeStamp is updated on simulation speed change, so this is OK
m_exactAbsTime = m_absTimeBase + m_simulationSpeed * absDiff;
m_absTime = (m_absTimeBase + m_simulationSpeed * absDiff) / 1e9f;
m_realRelTime = newRealRelTime;
m_exactRelTime = m_simulationSpeed * m_realRelTime;
m_relTime = (m_simulationSpeed * m_realRelTime) / 1e9f;
}
Event frameEvent(EVENT_FRAME);
frameEvent.systemEvent = true;
@ -1651,12 +1664,12 @@ bool CApplication::GetLowCPU()
void CApplication::StartPerformanceCounter(PerformanceCounter counter)
{
GetCurrentTimeStamp(m_performanceCounters[counter][0]);
GetSystemUtils()->GetCurrentTimeStamp(m_performanceCounters[counter][0]);
}
void CApplication::StopPerformanceCounter(PerformanceCounter counter)
{
GetCurrentTimeStamp(m_performanceCounters[counter][1]);
GetSystemUtils()->GetCurrentTimeStamp(m_performanceCounters[counter][1]);
}
float CApplication::GetPerformanceCounterData(PerformanceCounter counter)
@ -1675,13 +1688,13 @@ void CApplication::ResetPerformanceCounters()
void CApplication::UpdatePerformanceCountersData()
{
long long sum = TimeStampExactDiff(m_performanceCounters[PCNT_ALL][0],
m_performanceCounters[PCNT_ALL][1]);
long long sum = GetSystemUtils()->TimeStampExactDiff(m_performanceCounters[PCNT_ALL][0],
m_performanceCounters[PCNT_ALL][1]);
for (int i = 0; i < PCNT_MAX; ++i)
{
long long diff = TimeStampExactDiff(m_performanceCounters[i][0],
m_performanceCounters[i][1]);
long long diff = GetSystemUtils()->TimeStampExactDiff(m_performanceCounters[i][0],
m_performanceCounters[i][1]);
m_performanceCountersData[static_cast<PerformanceCounter>(i)] =
static_cast<float>(diff) / static_cast<float>(sum);

View File

@ -352,7 +352,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
Event CreateUpdateEvent();
TEST_VIRTUAL Event CreateUpdateEvent();
//! Handles some incoming events
bool ProcessEvent(const Event& event);
//! Renders the image in window

View File

@ -76,40 +76,46 @@ extern "C"
int SDL_MAIN_FUNC(int argc, char *argv[])
{
CLogger logger; // Create the logger
CLogger logger; // single istance of logger
InitializeRestext(); // Initialize translation strings
InitializeRestext(); // init static translation strings
CSystemUtils* systemUtils = CSystemUtils::Create(); // platform-specific utils
systemUtils->Init();
logger.Info("Colobot starting\n");
CApplication app; // single instance of the application
CApplication* app = new CApplication(); // single instance of the application
ParseArgsStatus status = app.ParseArguments(argc, argv);
ParseArgsStatus status = app->ParseArguments(argc, argv);
if (status == PARSE_ARGS_FAIL)
{
SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n");
return app.GetExitCode();
systemUtils->SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", "Invalid commandline arguments!\n");
return app->GetExitCode();
}
else if (status == PARSE_ARGS_HELP)
{
return app.GetExitCode();
return app->GetExitCode();
}
int code = 0;
if (! app.Create())
if (! app->Create())
{
app.Destroy(); // ensure a clean exit
code = app.GetExitCode();
if ( code != 0 && !app.GetErrorMessage().empty() )
app->Destroy(); // ensure a clean exit
code = app->GetExitCode();
if ( code != 0 && !app->GetErrorMessage().empty() )
{
SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", app.GetErrorMessage());
systemUtils->SystemDialog(SDT_ERROR, "COLOBOT - Fatal Error", app->GetErrorMessage());
}
logger.Info("Didn't run main loop. Exiting with code %d\n", code);
return code;
}
code = app.Run();
code = app->Run();
delete app;
delete systemUtils;
logger.Info("Exiting with code %d\n", code);
return code;

View File

@ -22,75 +22,142 @@
#if defined(PLATFORM_WINDOWS)
#include "app/system_windows.h"
#include "app/system_windows.h"
#elif defined(PLATFORM_LINUX)
#include "app/system_linux.h"
#include "app/system_linux.h"
#else
#include "app/system_other.h"
#include "app/system_other.h"
#endif
#include <cassert>
#include <iostream>
/**
* Displays a system dialog with info, error, question etc. message.
*
* \param type type of dialog
* \param message text of message (in UTF-8)
* \param title dialog title (in UTF-8)
* \returns result (which button was clicked)
*/
SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
template<>
CSystemUtils* CSingleton<CSystemUtils>::m_instance = nullptr;
CSystemUtils::CSystemUtils()
{
#if defined(PLATFORM_WINDOWS)
return SystemDialog_Windows(type, title, message);
#elif defined(PLATFORM_LINUX)
return SystemDialog_Linux(type, title, message);
#else
return SystemDialog_Other(type, title, message);
#endif
}
SystemTimeStamp* CreateTimeStamp()
CSystemUtils* CSystemUtils::Create()
{
assert(m_instance == nullptr);
#if defined(PLATFORM_WINDOWS)
m_instance = new CSystemUtilsWindows();
#elif defined(PLATFORM_LINUX)
m_instance = new CSystemUtilsLinux();
#else
m_instance = new CSystemUtilsOther();
#endif
return m_instance;
}
SystemDialogResult CSystemUtils::ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
{
switch (type)
{
case SDT_INFO:
std::cout << "INFO: ";
break;
case SDT_WARNING:
std::cout << "WARNING:";
break;
case SDT_ERROR:
std::cout << "ERROR: ";
break;
case SDT_YES_NO:
case SDT_OK_CANCEL:
std::cout << "QUESTION: ";
break;
}
std::cout << message << std::endl;
std::string line;
SystemDialogResult result = SDR_OK;
bool done = false;
while (!done)
{
switch (type)
{
case SDT_INFO:
case SDT_WARNING:
case SDT_ERROR:
std::cout << "Press ENTER to continue";
break;
case SDT_YES_NO:
std::cout << "Type 'Y' for Yes or 'N' for No";
break;
case SDT_OK_CANCEL:
std::cout << "Type 'O' for OK or 'C' for Cancel";
break;
}
std::getline(std::cin, line);
switch (type)
{
case SDT_INFO:
case SDT_WARNING:
case SDT_ERROR:
done = true;
break;
case SDT_YES_NO:
if (line == "Y" || line == "y")
{
result = SDR_YES;
done = true;
}
else if (line == "N" || line == "n")
{
result = SDR_NO;
done = true;
}
break;
case SDT_OK_CANCEL:
if (line == "O" || line == "o")
{
done = true;
result = SDR_OK;
}
else if (line == "C" || line == "c")
{
done = true;
result = SDR_CANCEL;
}
break;
}
}
return result;
}
SystemTimeStamp* CSystemUtils::CreateTimeStamp()
{
return new SystemTimeStamp();
}
void DestroyTimeStamp(SystemTimeStamp *stamp)
void CSystemUtils::DestroyTimeStamp(SystemTimeStamp *stamp)
{
delete stamp;
}
void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
void CSystemUtils::CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
{
*dst = *src;
}
void GetCurrentTimeStamp(SystemTimeStamp *stamp)
float CSystemUtils::GetTimeStampResolution(SystemTimeUnit unit)
{
#if defined(PLATFORM_WINDOWS)
GetCurrentTimeStamp_Windows(stamp);
#elif defined(PLATFORM_LINUX)
GetCurrentTimeStamp_Linux(stamp);
#else
GetCurrentTimeStamp_Other(stamp);
#endif
}
float GetTimeStampResolution(SystemTimeUnit unit)
{
unsigned long long exact = 0;
#if defined(PLATFORM_WINDOWS)
exact = GetTimeStampExactResolution_Windows();
#elif defined(PLATFORM_LINUX)
exact = GetTimeStampExactResolution_Linux();
#else
exact = GetTimeStampExactResolution_Other();
#endif
unsigned long long exact = GetTimeStampExactResolution();
float result = 0.0f;
if (unit == STU_SEC)
result = exact * 1e-9;
@ -100,30 +167,14 @@ float GetTimeStampResolution(SystemTimeUnit unit)
result = exact * 1e-3;
else
assert(false);
return result;
}
long long GetTimeStampExactResolution()
float CSystemUtils::TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit)
{
#if defined(PLATFORM_WINDOWS)
return GetTimeStampExactResolution_Windows();
#elif defined(PLATFORM_LINUX)
return GetTimeStampExactResolution_Linux();
#else
return GetTimeStampExactResolution_Other();
#endif
}
long long exact = TimeStampExactDiff(before, after);
float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit)
{
long long exact = 0;
#if defined(PLATFORM_WINDOWS)
exact = TimeStampExactDiff_Windows(before, after);
#elif defined(PLATFORM_LINUX)
exact = TimeStampExactDiff_Linux(before, after);
#else
exact = TimeStampExactDiff_Other(before, after);
#endif
float result = 0.0f;
if (unit == STU_SEC)
result = exact * 1e-9;
@ -133,16 +184,6 @@ float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeU
result = exact * 1e-3;
else
assert(false);
return result;
}
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
{
#if defined(PLATFORM_WINDOWS)
return TimeStampExactDiff_Windows(before, after);
#elif defined(PLATFORM_LINUX)
return TimeStampExactDiff_Linux(before, after);
#else
return TimeStampExactDiff_Other(before, after);
#endif
}

View File

@ -22,12 +22,10 @@
#pragma once
#include "common/singleton.h"
#include <string>
/* Dialog utils */
/**
* \enum SystemDialogType
* \brief Type of system dialog
@ -60,12 +58,10 @@ enum SystemDialogResult
SDR_NO
};
//! Displays a system dialog
SystemDialogResult SystemDialog(SystemDialogType, const std::string &title, const std::string &message);
/* Time utils */
/**
* \enum SystemTimeUnit
* \brief Time unit
*/
enum SystemTimeUnit
{
//! seconds
@ -76,33 +72,67 @@ enum SystemTimeUnit
STU_USEC
};
/* Forward declaration of time stamp struct
* SystemTimeStamp should be used in a pointer context.
* The implementation details are hidden because of platform dependence. */
/*
* 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;
//! Creates a new time stamp object
SystemTimeStamp* CreateTimeStamp();
/**
* \class CSystemUtils
* \brief Platform-specific utils
*
* This class provides system-specific utilities like displaying user dialogs and
* querying system timers for exact timestamps.
*/
class CSystemUtils : public CSingleton<CSystemUtils>
{
protected:
CSystemUtils();
//! Destroys a time stamp object
void DestroyTimeStamp(SystemTimeStamp *stamp);
public:
//! Creates system utils for specific platform
static CSystemUtils* Create();
//! Copies the time stamp from \a src to \a dst
void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
//! Performs platform-specific initialization
virtual void Init() = 0;
//! Returns a time stamp associated with current time
void GetCurrentTimeStamp(SystemTimeStamp *stamp);
//! Displays a system dialog
virtual SystemDialogResult SystemDialog(SystemDialogType, const std::string &title, const std::string &message) = 0;
//! Returns the platform's expected time stamp resolution
float GetTimeStampResolution(SystemTimeUnit unit = STU_SEC);
//! Displays a fallback system dialog using console
TEST_VIRTUAL SystemDialogResult ConsoleSystemDialog(SystemDialogType type, const std::string& title, const std::string& message);
//! Returns the platform's exact (in nanosecond units) expected time stamp resolution
long long GetTimeStampExactResolution();
//! Creates a new time stamp object
TEST_VIRTUAL SystemTimeStamp* CreateTimeStamp();
//! Returns a difference between two timestamps in given time unit
/** The difference is \a after - \a before. */
float TimeStampDiff(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit = STU_SEC);
//! Destroys a time stamp object
TEST_VIRTUAL void DestroyTimeStamp(SystemTimeStamp *stamp);
//! Returns the exact (in nanosecond units) difference between two timestamps
/** The difference is \a after - \a before. */
long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after);
//! Copies the time stamp from \a src to \a dst
TEST_VIRTUAL void CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src);
//! Returns a time stamp associated with current time
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) = 0;
//! Returns the platform's expected time stamp resolution
TEST_VIRTUAL float GetTimeStampResolution(SystemTimeUnit unit = STU_SEC);
//! Returns the platform's exact (in nanosecond units) expected time stamp resolution
virtual long long GetTimeStampExactResolution() = 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;
};
//! Global function to get CSystemUtils instance
inline CSystemUtils* GetSystemUtils()
{
return CSystemUtils::GetInstancePointer();
}

View File

@ -17,11 +17,28 @@
#include "app/system_linux.h"
#include "common/logger.h"
#include <stdlib.h>
SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message)
void CSystemUtilsLinux::Init()
{
m_zenityAvailable = true;
if (system("zenity --version") != 0)
{
m_zenityAvailable = false;
GetLogger()->Warn("Zenity not available, will fallback to console users dialogs.\n");
}
}
SystemDialogResult CSystemUtilsLinux::SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
{
if (!m_zenityAvailable)
{
return ConsoleSystemDialog(type, title, message);
}
std::string options = "";
switch (type)
{
@ -62,17 +79,17 @@ SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string&
return result;
}
void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp)
void CSystemUtilsLinux::GetCurrentTimeStamp(SystemTimeStamp *stamp)
{
clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime);
}
long long GetTimeStampExactResolution_Linux()
long long CSystemUtilsLinux::GetTimeStampExactResolution()
{
return 1ll;
}
long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after)
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;

View File

@ -35,9 +35,17 @@ struct SystemTimeStamp
}
};
class CSystemUtilsLinux : public CSystemUtils
{
public:
virtual void Init() override;
SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message);
virtual SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp);
long long GetTimeStampExactResolution_Linux();
long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after);
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
virtual long long GetTimeStampExactResolution() override;
virtual long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
private:
bool m_zenityAvailable;
};

View File

@ -18,105 +18,22 @@
#include "app/system_other.h"
SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message)
SystemDialogResult CSystemUtilsOther::SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
{
switch (type)
{
case SDT_INFO:
std::cout << "INFO: ";
break;
case SDT_WARNING:
std::cout << "WARNING:";
break;
case SDT_ERROR:
std::cout << "ERROR: ";
break;
case SDT_YES_NO:
case SDT_OK_CANCEL:
std::cout << "QUESTION: ";
break;
}
std::cout << message << std::endl;
std::string line;
SystemDialogResult result = SDR_OK;
bool done = false;
while (!done)
{
switch (type)
{
case SDT_INFO:
case SDT_WARNING:
case SDT_ERROR:
std::cout << "Press ENTER to continue";
break;
case SDT_YES_NO:
std::cout << "Type 'Y' for Yes or 'N' for No";
break;
case SDT_OK_CANCEL:
std::cout << "Type 'O' for OK or 'C' for Cancel";
break;
}
std::getline(std::cin, line);
switch (type)
{
case SDT_INFO:
case SDT_WARNING:
case SDT_ERROR:
done = true;
break;
case SDT_YES_NO:
if (line == "Y" || line == "y")
{
result = SDR_YES;
done = true;
}
else if (line == "N" || line == "n")
{
result = SDR_NO;
done = true;
}
break;
case SDT_OK_CANCEL:
if (line == "O" || line == "o")
{
done = true;
result = SDR_OK;
}
else if (line == "C" || line == "c")
{
done = true;
result = SDR_CANCEL;
}
break;
}
}
return result;
return ConsoleSystemDialog(type, title, message);
}
void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp)
void CSystemUtilsOther::GetCurrentTimeStamp(SystemTimeStamp* stamp)
{
stamp->sdlTicks = SDL_GetTicks();
}
long long GetTimeStampExactResolution_Other()
long long int CSystemUtilsOther::GetTimeStampExactResolution()
{
return 1000000ll;
}
long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after)
long long int CSystemUtilsOther::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after) const
{
return (after->sdlTicks - before->sdlTicks) * 1000000ll;
}

View File

@ -37,9 +37,12 @@ struct SystemTimeStamp
}
};
class CSystemUtilsOther : public CSystemUtils
{
public:
virtual SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message);
void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp);
long long GetTimeStampExactResolution_Other();
long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after);
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
virtual long long GetTimeStampExactResolution() override;
virtual long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
};

View File

@ -17,30 +17,25 @@
#include "app/system_windows.h"
#include "common/logger.h"
// Convert a wide Unicode string to an UTF8 string
std::string UTF8_Encode_Windows(const std::wstring &wstr)
#include <windows.h>
void CSystemUtilsWindows::Init()
{
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), &strTo[0], size_needed, NULL, NULL);
return strTo;
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
m_counterFrequency = freq.QuadPart;
assert(m_counterFrequency != 0);
}
// Convert an UTF8 string to a wide Unicode String
std::wstring UTF8_Decode_Windows(const std::string &str)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), &wstrTo[0], size_needed);
return wstrTo;
}
SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message)
SystemDialogResult CSystemUtilsWindows::SystemDialog(SystemDialogType type, const std::string& title, const std::string& message)
{
unsigned int windowsType = 0;
std::wstring windowsMessage = UTF8_Decode_Windows(message);
std::wstring windowsTitle = UTF8_Decode_Windows(title);
std::wstring windowsMessage = UTF8_Decode(message);
std::wstring windowsTitle = UTF8_Decode(title);
switch (type)
{
@ -79,20 +74,39 @@ SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string
return SDR_OK;
}
void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp)
void CSystemUtilsWindows::GetCurrentTimeStamp(SystemTimeStamp* stamp)
{
GetSystemTimeAsFileTime(&stamp->fileTime);
LARGE_INTEGER value;
QueryPerformanceCounter(&value);
stamp->counterValue = value.QuadPart;
}
long long GetTimeStampExactResolution_Windows()
long long int CSystemUtilsWindows::GetTimeStampExactResolution()
{
return 100ll;
return 1000000000ll / m_counterFrequency;
}
long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after)
long long int CSystemUtilsWindows::TimeStampExactDiff(SystemTimeStamp* before, SystemTimeStamp* after)
{
long long tH = (1ll << 32) * (after->fileTime.dwHighDateTime - before->fileTime.dwHighDateTime);
long long tL = after->fileTime.dwLowDateTime - before->fileTime.dwLowDateTime;
return (tH + tL) * 100ll;
float floatValue = static_cast<double>(after->counterValue - before->counterValue) * (1e9 / static_cast<double>(m_counterFrequency));
return static_cast<long long>(floatValue);
}
//! Converts a wide Unicode string to an UTF8 string
std::string CSystemUtilsWindows::UTF8_Encode(const std::wstring& wstr)
{
int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), NULL, 0, NULL, NULL);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
//! Converts an UTF8 string to a wide Unicode String
std::wstring CSystemUtilsWindows::UTF8_Decode(const std::string& str)
{
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), NULL, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), &wstrTo[0], size_needed);
return wstrTo;
}

View File

@ -22,23 +22,32 @@
#include "app/system.h"
#include <windows.h>
struct SystemTimeStamp
{
FILETIME fileTime;
long long counterValue;
SystemTimeStamp()
{
fileTime.dwHighDateTime = fileTime.dwLowDateTime = 0;
counterValue = 0;
}
};
std::string UTF8_Encode_Windows(const std::wstring &wstr);
std::wstring UTF8_Decode_Windows(const std::string &str);
SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message);
class CSystemUtilsWindows : public CSystemUtils
{
public:
virtual void Init() override;
void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp);
long long GetTimeStampExactResolution_Windows();
long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after);
virtual SystemDialogResult SystemDialog(SystemDialogType type, const std::string& title, const std::string& message) override;
virtual void GetCurrentTimeStamp(SystemTimeStamp *stamp) override;
virtual long long GetTimeStampExactResolution() override;
virtual long long TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after) override;
private:
std::string UTF8_Encode(const std::wstring &wstr);
std::wstring UTF8_Decode(const std::string &str);
protected:
long long m_counterFrequency;
};

View File

@ -148,8 +148,8 @@ CEngine::CEngine(CApplication *app)
m_mouseType = ENG_MOUSE_NORM;
m_fpsCounter = 0;
m_lastFrameTime = CreateTimeStamp();
m_currentFrameTime = CreateTimeStamp();
m_lastFrameTime = GetSystemUtils()->CreateTimeStamp();
m_currentFrameTime = GetSystemUtils()->CreateTimeStamp();
m_defaultTexParams.format = TEX_IMG_AUTO;
m_defaultTexParams.mipmap = true;
@ -176,9 +176,9 @@ CEngine::~CEngine()
m_planet = nullptr;
m_terrain = nullptr;
DestroyTimeStamp(m_lastFrameTime);
GetSystemUtils()->DestroyTimeStamp(m_lastFrameTime);
m_lastFrameTime = nullptr;
DestroyTimeStamp(m_currentFrameTime);
GetSystemUtils()->DestroyTimeStamp(m_currentFrameTime);
m_currentFrameTime = nullptr;
}
@ -279,8 +279,8 @@ bool CEngine::Create()
params.mipmap = false;
m_miceTexture = LoadTexture("mouse.png", params);
GetCurrentTimeStamp(m_currentFrameTime);
GetCurrentTimeStamp(m_lastFrameTime);
GetSystemUtils()->GetCurrentTimeStamp(m_currentFrameTime);
GetSystemUtils()->GetCurrentTimeStamp(m_lastFrameTime);
return true;
}
@ -336,11 +336,11 @@ void CEngine::FrameUpdate()
{
m_fpsCounter++;
GetCurrentTimeStamp(m_currentFrameTime);
float diff = TimeStampDiff(m_lastFrameTime, m_currentFrameTime, STU_SEC);
GetSystemUtils()->GetCurrentTimeStamp(m_currentFrameTime);
float diff = GetSystemUtils()->TimeStampDiff(m_lastFrameTime, m_currentFrameTime, STU_SEC);
if (diff > 1.0f)
{
CopyTimeStamp(m_lastFrameTime, m_currentFrameTime);
GetSystemUtils()->CopyTimeStamp(m_lastFrameTime, m_currentFrameTime);
m_fps = m_fpsCounter / diff;
m_fpsCounter = 0;

View File

@ -3,9 +3,9 @@ set(SRC_DIR ${colobot_SOURCE_DIR}/src)
configure_file(${SRC_DIR}/common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
# Platform-dependent implementation of system.h
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if (${PLATFORM_WINDOWS})
set(SYSTEM_CPP_MODULE "system_windows.cpp")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
elseif(${PLATFORM_LINUX})
set(SYSTEM_CPP_MODULE "system_linux.cpp")
else()
set(SYSTEM_CPP_MODULE "system_other.cpp")

View File

@ -258,9 +258,9 @@ void Update()
{
const float TRANS_SPEED = 6.0f; // units / sec
GetCurrentTimeStamp(CURR_TIME);
float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
CopyTimeStamp(PREV_TIME, CURR_TIME);
GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME);
float timeDiff = GetSystemUtils()->TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
GetSystemUtils()->CopyTimeStamp(PREV_TIME, CURR_TIME);
CUBE_ORBIT += timeDiff * (Math::PI / 4.0f);
@ -365,11 +365,11 @@ int SDL_MAIN_FUNC(int argc, char *argv[])
{
CLogger logger;
PREV_TIME = CreateTimeStamp();
CURR_TIME = CreateTimeStamp();
PREV_TIME = GetSystemUtils()->CreateTimeStamp();
CURR_TIME = GetSystemUtils()->CreateTimeStamp();
GetCurrentTimeStamp(PREV_TIME);
GetCurrentTimeStamp(CURR_TIME);
GetSystemUtils()->GetCurrentTimeStamp(PREV_TIME);
GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME);
// Without any error checking, for simplicity
@ -459,8 +459,8 @@ int SDL_MAIN_FUNC(int argc, char *argv[])
SDL_Quit();
DestroyTimeStamp(PREV_TIME);
DestroyTimeStamp(CURR_TIME);
GetSystemUtils()->DestroyTimeStamp(PREV_TIME);
GetSystemUtils()->DestroyTimeStamp(CURR_TIME);
return 0;
}

View File

@ -153,9 +153,9 @@ void Update()
const float ROT_SPEED = 80.0f * Math::DEG_TO_RAD; // rad / sec
const float TRANS_SPEED = 3.0f; // units / sec
GetCurrentTimeStamp(CURR_TIME);
float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
CopyTimeStamp(PREV_TIME, CURR_TIME);
GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME);
float timeDiff = GetSystemUtils()->TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
GetSystemUtils()->CopyTimeStamp(PREV_TIME, CURR_TIME);
if (KEYMAP[K_RotYLeft])
ROTATION.y -= ROT_SPEED * timeDiff;
@ -265,11 +265,11 @@ int SDL_MAIN_FUNC(int argc, char *argv[])
{
CLogger logger;
PREV_TIME = CreateTimeStamp();
CURR_TIME = CreateTimeStamp();
PREV_TIME = GetSystemUtils()->CreateTimeStamp();
CURR_TIME = GetSystemUtils()->CreateTimeStamp();
GetCurrentTimeStamp(PREV_TIME);
GetCurrentTimeStamp(CURR_TIME);
GetSystemUtils()->GetCurrentTimeStamp(PREV_TIME);
GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME);
if (argc != 3)
{
@ -377,8 +377,8 @@ int SDL_MAIN_FUNC(int argc, char *argv[])
SDL_Quit();
DestroyTimeStamp(PREV_TIME);
DestroyTimeStamp(CURR_TIME);
GetSystemUtils()->DestroyTimeStamp(PREV_TIME);
GetSystemUtils()->DestroyTimeStamp(CURR_TIME);
return 0;
}

View File

@ -138,9 +138,9 @@ void Update()
{
const float TRANS_SPEED = 6.0f; // units / sec
GetCurrentTimeStamp(CURR_TIME);
float timeDiff = TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
CopyTimeStamp(PREV_TIME, CURR_TIME);
GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME);
float timeDiff = GetSystemUtils()->TimeStampDiff(PREV_TIME, CURR_TIME, STU_SEC);
GetSystemUtils()->CopyTimeStamp(PREV_TIME, CURR_TIME);
Math::Vector incTrans;
@ -243,11 +243,11 @@ int SDL_MAIN_FUNC(int argc, char *argv[])
{
CLogger logger;
PREV_TIME = CreateTimeStamp();
CURR_TIME = CreateTimeStamp();
PREV_TIME = GetSystemUtils()->CreateTimeStamp();
CURR_TIME = GetSystemUtils()->CreateTimeStamp();
GetCurrentTimeStamp(PREV_TIME);
GetCurrentTimeStamp(CURR_TIME);
GetSystemUtils()->GetCurrentTimeStamp(PREV_TIME);
GetSystemUtils()->GetCurrentTimeStamp(CURR_TIME);
// Without any error checking, for simplicity
@ -337,8 +337,8 @@ int SDL_MAIN_FUNC(int argc, char *argv[])
SDL_Quit();
DestroyTimeStamp(PREV_TIME);
DestroyTimeStamp(CURR_TIME);
GetSystemUtils()->DestroyTimeStamp(PREV_TIME);
GetSystemUtils()->DestroyTimeStamp(CURR_TIME);
return 0;
}

View File

@ -16,9 +16,9 @@ endif()
configure_file(${SRC_DIR}/common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h)
# Platform-dependent implementation of system.h
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
if (${PLATFORM_WINDOWS})
set(SYSTEM_CPP_MODULE "system_windows.cpp")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
elseif(${PLATFORM_LINUX})
set(SYSTEM_CPP_MODULE "system_linux.cpp")
else()
set(SYSTEM_CPP_MODULE "system_other.cpp")
@ -164,17 +164,16 @@ endif()
# Platform-dependent tests
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
#TODO: set(PLATFORM_TESTS app/system_windows_test.cpp)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if (${PLATFORM_WINDOWS})
set(PLATFORM_TESTS app/system_windows_test.cpp)
elseif(${PLATFORM_LINUX})
set(PLATFORM_TESTS app/system_linux_test.cpp)
else()
#TODO: set(PLATFORM_TESTS app/system_other_test.cpp)
endif()
# Tests
set(UT_SOURCES
main.cpp
app/app_test.cpp
graphics/engine/lightman_test.cpp
math/geometry_test.cpp
math/matrix_test.cpp

320
test/unit/app/app_test.cpp Normal file
View File

@ -0,0 +1,320 @@
#include "app/app.h"
#if defined(PLATFORM_WINDOWS)
#include "app/system_windows.h"
#elif defined(PLATFORM_LINUX)
#include "app/system_linux.h"
#else
#include "app/system_other.h"
#endif
#include "app/system_mock.h"
#include "common/logger.h"
#include <gtest/gtest.h>
using testing::_;
using testing::InSequence;
using testing::Return;
struct FakeSystemTimeStamp : public SystemTimeStamp
{
FakeSystemTimeStamp(int uid) : uid(uid), time(0) {}
int uid;
long long time;
};
class CApplicationWrapper : public CApplication
{
public:
virtual Event CreateUpdateEvent() override
{
return CApplication::CreateUpdateEvent();
}
};
class ApplicationUT : public testing::Test
{
protected:
ApplicationUT();
virtual void SetUp() override;
virtual void TearDown() override;
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);
void TestCreateUpdateEvent(long long relTimeExact, long long absTimeExact,
float relTime, float absTime,
long long relTimeReal, long long absTimeReal);
protected:
CLogger logger;
CApplicationWrapper* app;
CSystemUtilsMock* systemUtils;
private:
int m_stampUid;
long long m_currentTime;
};
ApplicationUT::ApplicationUT()
: m_stampUid(0)
, m_currentTime(0)
{}
void ApplicationUT::SetUp()
{
systemUtils = new CSystemUtilsMock();
ON_CALL(*systemUtils, CreateTimeStamp()).WillByDefault(Invoke(this, &ApplicationUT::CreateTimeStamp));
ON_CALL(*systemUtils, DestroyTimeStamp(_)).WillByDefault(Invoke(this, &ApplicationUT::DestroyTimeStamp));
ON_CALL(*systemUtils, CopyTimeStamp(_, _)).WillByDefault(Invoke(this, &ApplicationUT::CopyTimeStamp));
ON_CALL(*systemUtils, GetCurrentTimeStamp(_)).WillByDefault(Invoke(this, &ApplicationUT::GetCurrentTimeStamp));
ON_CALL(*systemUtils, TimeStampExactDiff(_, _)).WillByDefault(Invoke(this, &ApplicationUT::TimeStampExactDiff));
EXPECT_CALL(*systemUtils, CreateTimeStamp()).Times(3 + PCNT_MAX*2);
app = new CApplicationWrapper();
}
void ApplicationUT::TearDown()
{
EXPECT_CALL(*systemUtils, DestroyTimeStamp(_)).Times(3 + PCNT_MAX*2);
delete app;
app = nullptr;
delete systemUtils;
systemUtils = nullptr;
}
SystemTimeStamp* ApplicationUT::CreateTimeStamp()
{
return new FakeSystemTimeStamp(++m_stampUid);
}
void ApplicationUT::DestroyTimeStamp(SystemTimeStamp *stamp)
{
delete static_cast<FakeSystemTimeStamp*>(stamp);
}
void ApplicationUT::CopyTimeStamp(SystemTimeStamp *dst, SystemTimeStamp *src)
{
*static_cast<FakeSystemTimeStamp*>(dst) = *static_cast<FakeSystemTimeStamp*>(src);
}
void ApplicationUT::GetCurrentTimeStamp(SystemTimeStamp *stamp)
{
static_cast<FakeSystemTimeStamp*>(stamp)->time = m_currentTime;
}
long long ApplicationUT::TimeStampExactDiff(SystemTimeStamp *before, SystemTimeStamp *after)
{
return static_cast<FakeSystemTimeStamp*>(after)->time - static_cast<FakeSystemTimeStamp*>(before)->time;
}
void ApplicationUT::NextInstant(long long diff)
{
m_currentTime += diff;
}
void ApplicationUT::TestCreateUpdateEvent(long long relTimeExact, long long absTimeExact,
float relTime, float absTime,
long long relTimeReal, long long absTimeReal)
{
{
InSequence seq;
EXPECT_CALL(*systemUtils, CopyTimeStamp(_, _));
EXPECT_CALL(*systemUtils, GetCurrentTimeStamp(_));
EXPECT_CALL(*systemUtils, TimeStampExactDiff(_, _)).Times(2);
}
Event event = app->CreateUpdateEvent();
EXPECT_EQ(EVENT_FRAME, event.type);
EXPECT_FLOAT_EQ(relTime, event.rTime);
EXPECT_FLOAT_EQ(relTime, app->GetRelTime());
EXPECT_FLOAT_EQ(absTime, app->GetAbsTime());
EXPECT_EQ(relTimeExact, app->GetExactRelTime());
EXPECT_EQ(absTimeExact, app->GetExactAbsTime());
EXPECT_EQ(relTimeReal, app->GetRealRelTime());
EXPECT_EQ(absTimeReal, app->GetRealAbsTime());
}
TEST_F(ApplicationUT, UpdateEventTimeCalculation_SimulationSuspended)
{
app->SuspendSimulation();
Event event = app->CreateUpdateEvent();
EXPECT_EQ(EVENT_NULL, event.type);
}
TEST_F(ApplicationUT, UpdateEventTimeCalculation_NormalOperation)
{
// 1st update
long long relTimeExact = 1111;
long long absTimeExact = relTimeExact;
float relTime = relTimeExact / 1e9f;
float absTime = absTimeExact / 1e9f;
long long relTimeReal = relTimeExact;
long long absTimeReal = absTimeExact;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
// 2nd update
relTimeExact = 2222;
absTimeExact += relTimeExact;
relTime = relTimeExact / 1e9f;
absTime = absTimeExact / 1e9f;
relTimeReal = relTimeExact;
absTimeReal = absTimeExact;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
}
TEST_F(ApplicationUT, UpdateEventTimeCalculation_NegativeTimeOperation)
{
// 1st update
long long relTimeExact = 2222;
long long absTimeExact = relTimeExact;
float relTime = relTimeExact / 1e9f;
float absTime = absTimeExact / 1e9f;
long long relTimeReal = relTimeExact;
long long absTimeReal = absTimeExact;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
// 2nd update
NextInstant(-1111);
{
InSequence seq;
EXPECT_CALL(*systemUtils, CopyTimeStamp(_, _));
EXPECT_CALL(*systemUtils, GetCurrentTimeStamp(_));
EXPECT_CALL(*systemUtils, TimeStampExactDiff(_, _)).Times(2);
}
Event event = app->CreateUpdateEvent();
EXPECT_EQ(EVENT_NULL, event.type);
}
TEST_F(ApplicationUT, UpdateEventTimeCalculation_ChangingSimulationSpeed)
{
EXPECT_CALL(*systemUtils, GetCurrentTimeStamp(_));
app->SetSimulationSpeed(2.0f);
// 1st update -- speed 2x
long long relTimeReal = 100;
long long absTimeReal = relTimeReal;
long long relTimeExact = relTimeReal*2;
long long absTimeExact = absTimeReal*2;
float relTime = relTimeExact / 1e9f;
float absTime = absTimeExact / 1e9f;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
// 2nd update -- speed 2x
relTimeReal = 200;
absTimeReal += relTimeReal;
relTimeExact = relTimeReal*2;
absTimeExact += relTimeReal*2;
relTime = relTimeExact / 1e9f;
absTime = absTimeExact / 1e9f;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
// 3rd update -- speed 4x
EXPECT_CALL(*systemUtils, GetCurrentTimeStamp(_));
app->SetSimulationSpeed(4.0f);
relTimeReal = 300;
absTimeReal += relTimeReal;
relTimeExact = relTimeReal*4;
absTimeExact += relTimeReal*4;
relTime = relTimeExact / 1e9f;
absTime = absTimeExact / 1e9f;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
// 4th update -- speed 1x
EXPECT_CALL(*systemUtils, GetCurrentTimeStamp(_));
app->SetSimulationSpeed(1.0f);
relTimeReal = 400;
absTimeReal += relTimeReal;
relTimeExact = relTimeReal;
absTimeExact += relTimeReal;
relTime = relTimeExact / 1e9f;
absTime = absTimeExact / 1e9f;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
}
TEST_F(ApplicationUT, UpdateEventTimeCalculation_SuspendingAndResumingSimulation)
{
// 1st update -- simulation enabled
long long relTimeReal = 1000;
long long absTimeReal = relTimeReal;
long long relTimeExact = relTimeReal;
long long absTimeExact = absTimeReal;
float relTime = relTimeExact / 1e9f;
float absTime = absTimeExact / 1e9f;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
// 2nd update -- simulation suspended
app->SuspendSimulation();
long long suspensionTime = 5000;
NextInstant(suspensionTime);
// 3rd update -- simulation resumed
{
InSequence seq;
EXPECT_CALL(*systemUtils, GetCurrentTimeStamp(_));
EXPECT_CALL(*systemUtils, CopyTimeStamp(_, _));
}
app->ResumeSimulation();
relTimeReal = 200;
absTimeReal += relTimeReal;
relTimeExact = relTimeReal;
absTimeExact += relTimeReal;
relTime = relTimeExact / 1e9f;
absTime = absTimeExact / 1e9f;
NextInstant(relTimeReal);
TestCreateUpdateEvent(relTimeExact, absTimeExact, relTime, absTime, relTimeReal, absTimeReal);
}

View File

@ -3,10 +3,23 @@
#include <gtest/gtest.h>
TEST(SystemLinuxTest, TimeStampDiff)
class CSystemUtilsLinuxWrapper : public CSystemUtilsLinux
{
const long long SEC = 1000000000;
public:
CSystemUtilsLinuxWrapper() {}
};
class SystemUtilsLinuxUT : public testing::Test
{
protected:
static const long long SEC = 1000000000;
CSystemUtilsLinuxWrapper systemUtils;
};
TEST_F(SystemUtilsLinuxUT, TimeStampDiff)
{
SystemTimeStamp before, after;
before.clockTime.tv_sec = 1;
@ -15,10 +28,10 @@ TEST(SystemLinuxTest, TimeStampDiff)
after.clockTime.tv_sec = 1;
after.clockTime.tv_nsec = 900;
long long tDiff = TimeStampExactDiff_Linux(&before, &after);
long long tDiff = systemUtils.TimeStampExactDiff(&before, &after);
EXPECT_EQ( 800, tDiff);
tDiff = TimeStampExactDiff_Linux(&after, &before);
tDiff = systemUtils.TimeStampExactDiff(&after, &before);
EXPECT_EQ(-800, tDiff);
// -------
@ -29,10 +42,10 @@ TEST(SystemLinuxTest, TimeStampDiff)
after.clockTime.tv_sec = 3;
after.clockTime.tv_nsec = 500;
tDiff = TimeStampExactDiff_Linux(&before, &after);
tDiff = systemUtils.TimeStampExactDiff(&before, &after);
EXPECT_EQ( SEC + 300, tDiff);
tDiff = TimeStampExactDiff_Linux(&after, &before);
tDiff = systemUtils.TimeStampExactDiff(&after, &before);
EXPECT_EQ(-SEC - 300, tDiff);
// -------
@ -43,9 +56,9 @@ TEST(SystemLinuxTest, TimeStampDiff)
after.clockTime.tv_sec = 4;
after.clockTime.tv_nsec = 100;
tDiff = TimeStampExactDiff_Linux(&before, &after);
tDiff = systemUtils.TimeStampExactDiff(&before, &after);
EXPECT_EQ( SEC - 100, tDiff);
tDiff = TimeStampExactDiff_Linux(&after, &before);
tDiff = systemUtils.TimeStampExactDiff(&after, &before);
EXPECT_EQ(-SEC + 100, tDiff);
}

View File

@ -0,0 +1,48 @@
#pragma once
#include "app/system.h"
#include <gmock/gmock.h>
class CSystemUtilsMock : public CSystemUtils
{
public:
CSystemUtilsMock(bool defaultExpects = false)
{
if (defaultExpects)
SetDefaultExpects();
}
virtual ~CSystemUtilsMock() {}
void SetDefaultExpects()
{
using testing::_;
using testing::Return;
using testing::AnyNumber;
EXPECT_CALL(*this, CreateTimeStamp()).Times(AnyNumber()).WillRepeatedly(Return(nullptr));
EXPECT_CALL(*this, DestroyTimeStamp(_)).Times(AnyNumber());
EXPECT_CALL(*this, CopyTimeStamp(_, _)).Times(AnyNumber());
EXPECT_CALL(*this, GetCurrentTimeStamp(_)).Times(AnyNumber());
EXPECT_CALL(*this, GetTimeStampResolution(_)).Times(AnyNumber()).WillRepeatedly(Return(0.0f));
EXPECT_CALL(*this, GetTimeStampExactResolution()).Times(AnyNumber()).WillRepeatedly(Return(0ll));
EXPECT_CALL(*this, TimeStampDiff(_, _, _)).Times(AnyNumber()).WillRepeatedly(Return(0.0f));
EXPECT_CALL(*this, TimeStampExactDiff(_, _)).Times(AnyNumber()).WillRepeatedly(Return(0ll));
}
MOCK_METHOD0(Init, void());
MOCK_METHOD3(SystemDialog, SystemDialogResult(SystemDialogType, const std::string &title, const std::string &message));
MOCK_METHOD3(ConsoleSystemDialog, SystemDialogResult(SystemDialogType type, const std::string& title, const std::string& message));
MOCK_METHOD0(CreateTimeStamp, SystemTimeStamp*());
MOCK_METHOD1(DestroyTimeStamp, void (SystemTimeStamp *stamp));
MOCK_METHOD2(CopyTimeStamp, void (SystemTimeStamp *dst, SystemTimeStamp *src));
MOCK_METHOD1(GetCurrentTimeStamp, void (SystemTimeStamp *stamp));
MOCK_METHOD1(GetTimeStampResolution, float (SystemTimeUnit unit));
MOCK_METHOD0(GetTimeStampExactResolution, long long());
MOCK_METHOD3(TimeStampDiff, float(SystemTimeStamp *before, SystemTimeStamp *after, SystemTimeUnit unit));
MOCK_METHOD2(TimeStampExactDiff, long long(SystemTimeStamp *before, SystemTimeStamp *after));
};

View File

@ -0,0 +1,62 @@
#include "app/system.h"
#include "app/system_windows.h"
#include <gtest/gtest.h>
class CSystemUtilsWindowsWrapper : public CSystemUtilsWindows
{
public:
CSystemUtilsWindowsWrapper() {}
void SetFrequency(long long counterFrequency)
{
m_counterFrequency = counterFrequency;
}
};
class SystemUtilsWindowsUT : public testing::Test
{
protected:
static const long long SEC = 1000000000;
CSystemUtilsWindowsWrapper systemUtils;
};
TEST_F(SystemUtilsWindowsUT, TimerResolution)
{
systemUtils.SetFrequency(SEC);
EXPECT_EQ(1u, systemUtils.GetTimeStampExactResolution());
systemUtils.SetFrequency(SEC/3);
EXPECT_EQ(3u, systemUtils.GetTimeStampExactResolution());
}
TEST_F(SystemUtilsWindowsUT, TimeStampDiff)
{
systemUtils.SetFrequency(SEC);
SystemTimeStamp before, after;
before.counterValue = 100;
after.counterValue = 200;
long long tDiff = systemUtils.TimeStampExactDiff(&before, &after);
EXPECT_EQ( 100, tDiff);
tDiff = systemUtils.TimeStampExactDiff(&after, &before);
EXPECT_EQ(-100, tDiff);
// -------
systemUtils.SetFrequency(SEC/3);
before.counterValue = 200;
after.counterValue = 400;
tDiff = systemUtils.TimeStampExactDiff(&before, &after);
EXPECT_EQ( 200*3, tDiff);
tDiff = systemUtils.TimeStampExactDiff(&after, &before);
EXPECT_EQ(-200*3, tDiff);
}

View File

@ -1,5 +1,7 @@
#include "graphics/engine/lightman.h"
#include "app/system_mock.h"
#include "graphics/core/device_mock.h"
#include "graphics/engine/engine_mock.h"
@ -15,7 +17,8 @@ class LightManagerUT : public testing::Test
{
protected:
LightManagerUT()
: lightManager(&engine)
: systemUtils(true)
, lightManager(&engine)
{}
void PrepareLightTesting(int maxLights, Math::Vector eyePos);
@ -25,6 +28,7 @@ protected:
Math::Vector pos, EngineObjectType includeType, EngineObjectType excludeType);
CSystemUtilsMock systemUtils;
CLightManager lightManager;
CEngineMock engine;
CDeviceMock device;

View File

@ -40,3 +40,8 @@ std::string CApplication::GetDataDirPath()
{
return "";
}
Event CApplication::CreateUpdateEvent()
{
return Event(EVENT_NULL);
}