summaryrefslogtreecommitdiffstats
path: root/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/app')
-rw-r--r--src/app/app.cpp541
-rw-r--r--src/app/app.h171
-rw-r--r--src/app/main.cpp7
-rw-r--r--src/app/system_windows.h8
4 files changed, 612 insertions, 115 deletions
diff --git a/src/app/app.cpp b/src/app/app.cpp
index 00cd13d..23e6d9f 100644
--- a/src/app/app.cpp
+++ b/src/app/app.cpp
@@ -23,16 +23,24 @@
#include "common/logger.h"
#include "common/iman.h"
#include "common/image.h"
+#include "common/key.h"
#include "graphics/opengl/gldevice.h"
+#include "object/robotmain.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
-#include <stdio.h>
+#include <fstream>
+#include <stdlib.h>
+#include <libintl.h>
-template<> CApplication* CSingleton<CApplication>::mInstance = NULL;
+
+template<> CApplication* CSingleton<CApplication>::mInstance = nullptr;
+
+//! Static buffer for putenv locale
+static char S_LANGUAGE[50] = { 0 };
//! Interval of timer called to update joystick state
@@ -62,8 +70,8 @@ struct ApplicationPrivate
ApplicationPrivate()
{
memset(&currentEvent, 0, sizeof(SDL_Event));
- surface = NULL;
- joystick = NULL;
+ surface = nullptr;
+ joystick = nullptr;
joystickTimer = 0;
}
};
@@ -76,14 +84,10 @@ CApplication::CApplication()
m_iMan = new CInstanceManager();
m_eventQueue = new CEventQueue(m_iMan);
- m_engine = NULL;
- m_device = NULL;
- m_robotMain = NULL;
- m_sound = NULL;
-
- m_keyState = 0;
- m_axeKey = Math::Vector(0.0f, 0.0f, 0.0f);
- m_axeJoy = Math::Vector(0.0f, 0.0f, 0.0f);
+ m_engine = nullptr;
+ m_device = nullptr;
+ m_robotMain = nullptr;
+ m_sound = nullptr;
m_exitCode = 0;
m_active = false;
@@ -91,29 +95,57 @@ CApplication::CApplication()
m_windowTitle = "COLOBOT";
+ m_simulationSuspended = false;
+
+ m_simulationSpeed = 1.0f;
+
+ m_realAbsTimeBase = 0LL;
+ m_realAbsTime = 0LL;
+ m_realRelTime = 0LL;
+
+ m_absTimeBase = 0LL;
+ m_exactAbsTime = 0LL;
+ m_exactRelTime = 0LL;
+
+ m_absTime = 0.0f;
+ m_relTime = 0.0f;
+
+ m_baseTimeStamp = CreateTimeStamp();
+ m_curTimeStamp = CreateTimeStamp();
+ m_lastTimeStamp = CreateTimeStamp();
+
m_joystickEnabled = false;
+ m_kmodState = 0;
+ m_mouseButtonsState = 0;
+ m_trackedKeys = 0;
+
m_dataPath = "./data";
- ResetKey();
+ m_language = LANG_ENGLISH;
}
CApplication::~CApplication()
{
delete m_private;
- m_private = NULL;
+ m_private = nullptr;
delete m_eventQueue;
- m_eventQueue = NULL;
+ m_eventQueue = nullptr;
delete m_iMan;
- m_iMan = NULL;
+ m_iMan = nullptr;
+
+ DestroyTimeStamp(m_baseTimeStamp);
+ DestroyTimeStamp(m_curTimeStamp);
+ DestroyTimeStamp(m_lastTimeStamp);
}
-bool CApplication::ParseArguments(int argc, char *argv[])
+ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
{
bool waitDataDir = false;
bool waitLogLevel = false;
+ bool waitLanguage = false;
for (int i = 1; i < argc; ++i)
{
@@ -123,6 +155,7 @@ bool CApplication::ParseArguments(int argc, char *argv[])
{
waitDataDir = false;
m_dataPath = arg;
+ GetLogger()->Info("Using custom data dir: '%s'\n", m_dataPath.c_str());
continue;
}
@@ -142,7 +175,23 @@ bool CApplication::ParseArguments(int argc, char *argv[])
else if (arg == "none")
GetLogger()->SetLogLevel(LOG_NONE);
else
- return false;
+ return PARSE_ARGS_FAIL;
+ continue;
+ }
+
+ if (waitLanguage)
+ {
+ waitLanguage = false;
+ if (arg == "en")
+ m_language = LANG_ENGLISH;
+ else if (arg == "de")
+ m_language = LANG_GERMAN;
+ else if (arg == "fr")
+ m_language = LANG_FRENCH;
+ else if (arg == "pl")
+ m_language = LANG_POLISH;
+ else
+ return PARSE_ARGS_FAIL;
continue;
}
@@ -158,34 +207,95 @@ bool CApplication::ParseArguments(int argc, char *argv[])
{
waitDataDir = true;
}
+ else if (arg == "-language")
+ {
+ waitLanguage = true;
+ }
+ else if (arg == "-help")
+ {
+ GetLogger()->Message("\n");
+ GetLogger()->Message("COLOBOT GOLD pre-alpha\n");
+ GetLogger()->Message("\n");
+ GetLogger()->Message("List of available options:\n");
+ GetLogger()->Message(" -help this help\n");
+ GetLogger()->Message(" -datadir path set custom data directory path\n");
+ GetLogger()->Message(" -debug enable debug mode (more info printed in logs)\n");
+ GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n");
+ GetLogger()->Message(" -language lang set language (one of: en, de, fr, pl)\n");
+ return PARSE_ARGS_HELP;
+ }
else
{
m_exitCode = 1;
- return false;
+ return PARSE_ARGS_FAIL;
}
}
// Args not given?
- if (waitDataDir || waitLogLevel)
- return false;
+ if (waitDataDir || waitLogLevel || waitLanguage)
+ return PARSE_ARGS_FAIL;
- return true;
+ return PARSE_ARGS_OK;
}
bool CApplication::Create()
{
GetLogger()->Info("Creating CApplication\n");
- // TODO: verify that data directory exists
+ // I know, a primitive way to check for dir, but works
+ std::string readmePath = m_dataPath + "/README.txt";
+ std::ifstream testReadme;
+ testReadme.open(readmePath.c_str(), std::ios_base::in);
+ if (!testReadme.good())
+ {
+ GetLogger()->Error("Could not open test file in data dir: '%s'\n", readmePath.c_str());
+ m_errorMessage = std::string("Could not read from data directory:\n") +
+ std::string("'") + m_dataPath + std::string("'\n") +
+ std::string("Please check your installation, or supply a valid data directory by -datadir option.");
+ m_exitCode = 1;
+ return false;
+ }
+
+ /* Gettext initialization */
+
+ std::string locale = "C";
+ switch (m_language)
+ {
+ case LANG_ENGLISH:
+ locale = "en_US.utf8";
+ break;
+
+ case LANG_GERMAN:
+ locale = "de_DE.utf8";
+ break;
+
+ case LANG_FRENCH:
+ locale = "fr_FR.utf8";
+ break;
+
+ case LANG_POLISH:
+ locale = "pl_PL.utf8";
+ break;
+ }
+
+ std::string langStr = "LANGUAGE=";
+ langStr += locale;
+ strcpy(S_LANGUAGE, langStr.c_str());
+ putenv(S_LANGUAGE);
+ setlocale(LC_ALL, locale.c_str());
+
+ std::string trPath = m_dataPath + std::string("/i18n");
+ bindtextdomain("colobot", trPath.c_str());
+ bind_textdomain_codeset("colobot", "UTF-8");
+ textdomain("colobot");
+
+ GetLogger()->Debug("Testing gettext translation: '%s'\n", gettext("Colobot rules!"));
// Temporarily -- only in windowed mode
m_deviceConfig.fullScreen = false;
-/* // Create the sound instance.
- m_sound = new CSound(m_iMan);
-
- // Create the robot application.
- m_robotMain = new CRobotMain(m_iMan); */
+ // Create the sound instance.
+ m_sound = new CSoundInterface();
std::string standardInfoMessage =
@@ -218,7 +328,7 @@ bool CApplication::Create()
if (! CreateVideoSurface())
return false; // dialog is in function
- if (m_private->surface == NULL)
+ if (m_private->surface == nullptr)
{
m_errorMessage = std::string("SDL error while setting video mode:\n") +
std::string(SDL_GetError());
@@ -261,6 +371,11 @@ bool CApplication::Create()
return false;
}
+ // Create the robot application.
+ m_robotMain = new CRobotMain(m_iMan, this);
+
+ m_robotMain->ChangePhase(PHASE_WELCOME1);
+
GetLogger()->Info("CApplication created successfully\n");
return true;
@@ -269,7 +384,7 @@ bool CApplication::Create()
bool CApplication::CreateVideoSurface()
{
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
- if (videoInfo == NULL)
+ if (videoInfo == nullptr)
{
m_errorMessage = std::string("SDL error while getting video info:\n ") +
std::string(SDL_GetError());
@@ -321,44 +436,46 @@ bool CApplication::CreateVideoSurface()
void CApplication::Destroy()
{
- /*if (m_robotMain != NULL)
+ m_joystickEnabled = false;
+
+ if (m_robotMain != nullptr)
{
delete m_robotMain;
- m_robotMain = NULL;
+ m_robotMain = nullptr;
}
- if (m_sound != NULL)
+ if (m_sound != nullptr)
{
delete m_sound;
- m_sound = NULL;
- }*/
+ m_sound = nullptr;
+ }
- if (m_engine != NULL)
+ if (m_engine != nullptr)
{
m_engine->Destroy();
delete m_engine;
- m_engine = NULL;
+ m_engine = nullptr;
}
- if (m_device != NULL)
+ if (m_device != nullptr)
{
m_device->Destroy();
delete m_device;
- m_device = NULL;
+ m_device = nullptr;
}
- if (m_private->joystick != NULL)
+ if (m_private->joystick != nullptr)
{
SDL_JoystickClose(m_private->joystick);
- m_private->joystick = NULL;
+ m_private->joystick = nullptr;
}
- if (m_private->surface != NULL)
+ if (m_private->surface != nullptr)
{
SDL_FreeSurface(m_private->surface);
- m_private->surface = NULL;
+ m_private->surface = nullptr;
}
IMG_Quit();
@@ -383,7 +500,7 @@ bool CApplication::ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig)
return false;
}
- if (m_private->surface == NULL)
+ if (m_private->surface == nullptr)
{
if (! restore)
{
@@ -426,7 +543,7 @@ bool CApplication::OpenJoystick()
return false;
m_private->joystick = SDL_JoystickOpen(m_joystick.index);
- if (m_private->joystick == NULL)
+ if (m_private->joystick == nullptr)
return false;
m_joystick.axisCount = SDL_JoystickNumAxes(m_private->joystick);
@@ -437,7 +554,7 @@ bool CApplication::OpenJoystick()
m_joyButtonState = std::vector<bool>(m_joystick.buttonCount, false);
// Create a timer for polling joystick state
- m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, NULL);
+ m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, nullptr);
return true;
}
@@ -447,7 +564,7 @@ void CApplication::CloseJoystick()
// Timer will remove itself automatically
SDL_JoystickClose(m_private->joystick);
- m_private->joystick = NULL;
+ m_private->joystick = nullptr;
}
bool CApplication::ChangeJoystick(const JoystickDevice &newJoystick)
@@ -455,7 +572,7 @@ bool CApplication::ChangeJoystick(const JoystickDevice &newJoystick)
if ( (newJoystick.index < 0) || (newJoystick.index >= SDL_NumJoysticks()) )
return false;
- if (m_private->joystick != NULL)
+ if (m_private->joystick != nullptr)
CloseJoystick();
return OpenJoystick();
@@ -464,7 +581,7 @@ bool CApplication::ChangeJoystick(const JoystickDevice &newJoystick)
Uint32 JoystickTimerCallback(Uint32 interval, void *)
{
CApplication *app = CApplication::GetInstancePointer();
- if ((app == NULL) || (! app->GetJoystickEnabled()))
+ if ((app == nullptr) || (! app->GetJoystickEnabled()))
return 0; // don't run the timer again
app->UpdateJoystick();
@@ -540,6 +657,10 @@ int CApplication::Run()
{
m_active = true;
+ GetCurrentTimeStamp(m_baseTimeStamp);
+ GetCurrentTimeStamp(m_lastTimeStamp);
+ GetCurrentTimeStamp(m_curTimeStamp);
+
while (true)
{
// To be sure no old event remains
@@ -577,12 +698,24 @@ int CApplication::Run()
{
bool passOn = ProcessEvent(event);
- if (m_engine != NULL && passOn)
+ if (m_engine != nullptr && passOn)
passOn = m_engine->ProcessEvent(event);
if (passOn)
m_eventQueue->AddEvent(event);
}
+
+ Event virtualEvent = CreateVirtualEvent(event);
+ if (virtualEvent.type != EVENT_NULL)
+ {
+ bool passOn = ProcessEvent(virtualEvent);
+
+ if (m_engine != nullptr && passOn)
+ passOn = m_engine->ProcessEvent(virtualEvent);
+
+ if (passOn)
+ m_eventQueue->AddEvent(virtualEvent);
+ }
}
}
@@ -602,12 +735,12 @@ int CApplication::Run()
{
passOn = ProcessEvent(event);
- if (passOn && m_engine != NULL)
+ if (passOn && m_engine != nullptr)
passOn = m_engine->ProcessEvent(event);
}
- /*if (passOn && m_robotMain != NULL)
- m_robotMain->ProcessEvent(event); */
+ if (passOn && m_robotMain != nullptr)
+ m_robotMain->EventProcess(event);
}
/* Update mouse position explicitly right before rendering
@@ -616,6 +749,9 @@ int CApplication::Run()
// Update game and render a frame during idle time (no messages are waiting)
Render();
+
+ // Update simulation state
+ StepSimulation();
}
}
@@ -664,6 +800,7 @@ Event CApplication::ParseEvent()
else
event.type = EVENT_KEY_UP;
+ event.key.virt = false;
event.key.key = m_private->currentEvent.key.keysym.sym;
event.key.mod = m_private->currentEvent.key.keysym.mod;
event.key.state = TranslatePressState(m_private->currentEvent.key.state);
@@ -672,15 +809,32 @@ Event CApplication::ParseEvent()
else if ( (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN) ||
(m_private->currentEvent.type == SDL_MOUSEBUTTONUP) )
{
- if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
- event.type = EVENT_MOUSE_BUTTON_DOWN;
+ if ((m_private->currentEvent.button.button == SDL_BUTTON_WHEELUP) ||
+ (m_private->currentEvent.button.button == SDL_BUTTON_WHEELDOWN))
+ {
+ if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN) // ignore the following up event
+ {
+ event.type = EVENT_MOUSE_WHEEL;
+ if (m_private->currentEvent.button.button == SDL_BUTTON_WHEELDOWN)
+ event.mouseWheel.dir = WHEEL_DOWN;
+ else
+ event.mouseWheel.dir = WHEEL_UP;
+ event.mouseWheel.pos = m_engine->WindowToInterfaceCoords(
+ Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
+ }
+ }
else
- event.type = EVENT_MOUSE_BUTTON_UP;
+ {
+ if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
+ event.type = EVENT_MOUSE_BUTTON_DOWN;
+ else
+ event.type = EVENT_MOUSE_BUTTON_UP;
- event.mouseButton.button = m_private->currentEvent.button.button;
- event.mouseButton.state = TranslatePressState(m_private->currentEvent.button.state);
- event.mouseButton.pos = m_engine->WindowToInterfaceCoords(
- Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
+ event.mouseButton.button = m_private->currentEvent.button.button;
+ event.mouseButton.state = TranslatePressState(m_private->currentEvent.button.state);
+ event.mouseButton.pos = m_engine->WindowToInterfaceCoords(
+ Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
+ }
}
else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
{
@@ -725,18 +879,93 @@ Event CApplication::ParseEvent()
return event;
}
-/** Processes incoming events. It is the first function called after an event is captures.
- Function returns \c true if the event is to be passed on to other processing functions
- or \c false if not. */
-bool CApplication::ProcessEvent(const Event &event)
+/**
+ * Processes incoming events. It is the first function called after an event is captured.
+ * Event is modified, updating its tracked keys state and mouse position to current values.
+ * Function returns \c true if the event is to be passed on to other processing functions
+ * or \c false if not. */
+bool CApplication::ProcessEvent(Event &event)
{
CLogger *l = GetLogger();
+ event.trackedKeys = m_trackedKeys;
+ if (GetSystemMouseVisibile())
+ event.mousePos = m_systemMousePos;
+ else
+ event.mousePos = m_engine->GetMousePos();
+
if (event.type == EVENT_ACTIVE)
{
- m_active = event.active.gain;
if (m_debugMode)
- l->Info("Focus change: active = %s\n", m_active ? "true" : "false");
+ l->Info("Focus change: active = %s\n", event.active.gain ? "true" : "false");
+
+ /*if (m_active != event.active.gain)
+ {
+ m_active = event.active.gain;
+
+ if (m_active)
+ ResumeSimulation();
+ else
+ SuspendSimulation();
+ }*/
+ }
+ else if (event.type == EVENT_KEY_DOWN)
+ {
+ m_kmodState = event.key.mod;
+
+ if ((m_kmodState & KEY_MOD(SHIFT)) != 0)
+ m_trackedKeys |= TRKEY_SHIFT;
+ else if ((m_kmodState & KEY_MOD(CTRL)) != 0)
+ m_trackedKeys |= TRKEY_CONTROL;
+ else if (event.key.key == KEY(KP8))
+ m_trackedKeys |= TRKEY_NUM_UP;
+ else if (event.key.key == KEY(KP2))
+ m_trackedKeys |= TRKEY_NUM_DOWN;
+ else if (event.key.key == KEY(KP4))
+ m_trackedKeys |= TRKEY_NUM_LEFT;
+ else if (event.key.key == KEY(KP6))
+ m_trackedKeys |= TRKEY_NUM_RIGHT;
+ else if (event.key.key == KEY(KP_PLUS))
+ m_trackedKeys |= TRKEY_NUM_PLUS;
+ else if (event.key.key == KEY(KP_MINUS))
+ m_trackedKeys |= TRKEY_NUM_MINUS;
+ else if (event.key.key == KEY(PAGEUP))
+ m_trackedKeys |= TRKEY_PAGE_UP;
+ else if (event.key.key == KEY(PAGEDOWN))
+ m_trackedKeys |= TRKEY_PAGE_DOWN;
+ }
+ else if (event.type == EVENT_KEY_UP)
+ {
+ m_kmodState = event.key.mod;
+
+ if ((m_kmodState & KEY_MOD(SHIFT)) != 0)
+ m_trackedKeys &= ~TRKEY_SHIFT;
+ else if ((m_kmodState & KEY_MOD(CTRL)) != 0)
+ m_trackedKeys &= ~TRKEY_CONTROL;
+ else if (event.key.key == KEY(KP8))
+ m_trackedKeys &= ~TRKEY_NUM_UP;
+ else if (event.key.key == KEY(KP2))
+ m_trackedKeys &= ~TRKEY_NUM_DOWN;
+ else if (event.key.key == KEY(KP4))
+ m_trackedKeys &= ~TRKEY_NUM_LEFT;
+ else if (event.key.key == KEY(KP6))
+ m_trackedKeys &= ~TRKEY_NUM_RIGHT;
+ else if (event.key.key == KEY(KP_PLUS))
+ m_trackedKeys &= ~TRKEY_NUM_PLUS;
+ else if (event.key.key == KEY(KP_MINUS))
+ m_trackedKeys &= ~TRKEY_NUM_MINUS;
+ else if (event.key.key == KEY(PAGEUP))
+ m_trackedKeys &= ~TRKEY_PAGE_UP;
+ else if (event.key.key == KEY(PAGEDOWN))
+ m_trackedKeys &= ~TRKEY_PAGE_DOWN;
+ }
+ else if (event.type == EVENT_MOUSE_BUTTON_DOWN)
+ {
+ m_mouseButtonsState |= 1 << event.mouseButton.button;
+ }
+ else if (event.type == EVENT_MOUSE_BUTTON_UP)
+ {
+ m_mouseButtonsState &= ~(1 << event.mouseButton.button);
}
// Print the events in debug mode to test the code
@@ -747,6 +976,7 @@ 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 = %4x\n", event.key.key);
l->Info(" state = %s\n", (event.key.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
l->Info(" mod = %4x\n", event.key.mod);
@@ -764,6 +994,11 @@ bool CApplication::ProcessEvent(const Event &event)
l->Info(" state = %s\n", (event.mouseButton.state == STATE_PRESSED) ? "STATE_PRESSED" : "STATE_RELEASED");
l->Info(" pos = (%f, %f)\n", event.mouseButton.pos.x, event.mouseButton.pos.y);
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->Info(" pos = (%f, %f)\n", event.mouseWheel.pos.x, event.mouseWheel.pos.y);
+ break;
case EVENT_JOY_AXIS:
l->Info("EVENT_JOY_AXIS:\n");
l->Info(" axis = %d\n", event.joyAxis.axis);
@@ -789,6 +1024,48 @@ bool CApplication::ProcessEvent(const Event &event)
return true;
}
+
+Event CApplication::CreateVirtualEvent(const Event& sourceEvent)
+{
+ Event virtualEvent;
+ virtualEvent.systemEvent = true;
+
+ if ((sourceEvent.type == EVENT_KEY_DOWN) || (sourceEvent.type == EVENT_KEY_UP))
+ {
+ virtualEvent.type = sourceEvent.type;
+ virtualEvent.key = sourceEvent.key;
+ virtualEvent.key.virt = true;
+
+ if (sourceEvent.key.key == KEY(LCTRL) || sourceEvent.key.key == KEY(RCTRL))
+ virtualEvent.key.key = VIRTUAL_KMOD(CTRL);
+ else if (sourceEvent.key.key == KEY(LSHIFT) || sourceEvent.key.key == KEY(RSHIFT))
+ virtualEvent.key.key = VIRTUAL_KMOD(SHIFT);
+ else if (sourceEvent.key.key == KEY(LALT) || sourceEvent.key.key == KEY(RALT))
+ virtualEvent.key.key = VIRTUAL_KMOD(ALT);
+ else if (sourceEvent.key.key == KEY(LMETA) || sourceEvent.key.key == KEY(RMETA))
+ virtualEvent.key.key = VIRTUAL_KMOD(META);
+ else
+ virtualEvent.type = EVENT_NULL;
+ }
+ else if ((sourceEvent.type == EVENT_JOY_BUTTON_DOWN) || (sourceEvent.type == EVENT_JOY_BUTTON_UP))
+ {
+ if (sourceEvent.type == EVENT_JOY_BUTTON_DOWN)
+ virtualEvent.type = EVENT_KEY_DOWN;
+ else
+ virtualEvent.type = EVENT_KEY_UP;
+ virtualEvent.key.virt = true;
+ virtualEvent.key.key = VIRTUAL_JOY(sourceEvent.joyButton.button);
+ virtualEvent.key.mod = 0;
+ virtualEvent.key.unicode = 0;
+ }
+ else
+ {
+ virtualEvent.type = EVENT_NULL;
+ }
+
+ return virtualEvent;
+}
+
/** Renders the frame and swaps buffers as necessary */
void CApplication::Render()
{
@@ -798,9 +1075,101 @@ void CApplication::Render()
SDL_GL_SwapBuffers();
}
-void CApplication::StepSimulation(float rTime)
+void CApplication::SuspendSimulation()
{
- // TODO
+ m_simulationSuspended = true;
+ GetLogger()->Info("Suspend simulation\n");
+}
+
+void CApplication::ResumeSimulation()
+{
+ m_simulationSuspended = false;
+
+ GetCurrentTimeStamp(m_baseTimeStamp);
+ CopyTimeStamp(m_curTimeStamp, m_baseTimeStamp);
+ m_realAbsTimeBase = m_realAbsTime;
+ m_absTimeBase = m_exactAbsTime;
+
+ GetLogger()->Info("Resume simulation\n");
+}
+
+bool CApplication::GetSimulationSuspended()
+{
+ return m_simulationSuspended;
+}
+
+void CApplication::SetSimulationSpeed(float speed)
+{
+ m_simulationSpeed = speed;
+
+ GetCurrentTimeStamp(m_baseTimeStamp);
+ m_realAbsTimeBase = m_realAbsTime;
+ m_absTimeBase = m_exactAbsTime;
+
+ GetLogger()->Info("Simulation speed = %.2f\n", speed);
+}
+
+void CApplication::StepSimulation()
+{
+ if (m_simulationSuspended)
+ return;
+
+ CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
+ 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;
+
+ m_realRelTime = TimeStampExactDiff(m_lastTimeStamp, m_curTimeStamp);
+ m_exactRelTime = m_simulationSpeed * m_realRelTime;
+ m_relTime = (m_simulationSpeed * m_realRelTime) / 1e9f;
+
+
+ m_engine->FrameUpdate();
+ m_sound->FrameMove(m_relTime);
+
+
+ Event frameEvent(EVENT_FRAME);
+ frameEvent.rTime = m_relTime;
+ m_eventQueue->AddEvent(frameEvent);
+}
+
+float CApplication::GetSimulationSpeed()
+{
+ return m_simulationSpeed;
+}
+
+float CApplication::GetAbsTime()
+{
+ return m_absTime;
+}
+
+long long CApplication::GetExactAbsTime()
+{
+ return m_exactAbsTime;
+}
+
+long long CApplication::GetRealAbsTime()
+{
+ return m_realAbsTime;
+}
+
+float CApplication::GetRelTime()
+{
+ return m_relTime;
+}
+
+long long CApplication::GetExactRelTime()
+{
+ return m_exactRelTime;
+}
+
+long long CApplication::GetRealRelTime()
+{
+ return m_realRelTime;
}
Gfx::GLDeviceConfig CApplication::GetVideoConfig()
@@ -814,7 +1183,7 @@ VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntPoint
resolutions.clear();
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
- if (videoInfo == NULL)
+ if (videoInfo == nullptr)
return VIDEO_QUERY_ERROR;
Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
@@ -861,25 +1230,31 @@ bool CApplication::GetDebugMode()
return m_debugMode;
}
-void CApplication::FlushPressKey()
+int CApplication::GetKmods()
{
- // TODO
+ return m_kmodState;
}
-void CApplication::ResetKey()
+bool CApplication::GetKmodState(int kmod)
{
- // TODO
+ return (m_kmodState & kmod) != 0;
}
-void CApplication::SetKey(int keyRank, int option, int key)
+bool CApplication::GetTrackedKeyState(TrackedKey key)
{
- // TODO
+ return (m_trackedKeys & key) != 0;
}
-int CApplication::GetKey(int keyRank, int option)
+bool CApplication::GetMouseButtonState(int index)
{
- // TODO
- return 0;
+ return (m_mouseButtonsState & (1<<index)) != 0;
+}
+
+void CApplication::ResetKeyStates()
+{
+ m_trackedKeys = 0;
+ m_kmodState = 0;
+ m_robotMain->ResetKeyStates();
}
void CApplication::SetGrabInput(bool grab)
@@ -964,3 +1339,13 @@ std::string CApplication::GetDataFilePath(const std::string& dirName, const std:
{
return m_dataPath + "/" + dirName + "/" + fileName;
}
+
+Language CApplication::GetLanguage()
+{
+ return m_language;
+}
+
+void CApplication::SetLanguage(Language language)
+{
+ m_language = language;
+}
diff --git a/src/app/app.h b/src/app/app.h
index 7991177..33be5a5 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -22,8 +22,7 @@
#pragma once
-
-#include "common/misc.h"
+#include "common/global.h"
#include "common/singleton.h"
#include "graphics/core/device.h"
#include "graphics/engine/engine.h"
@@ -36,11 +35,12 @@
class CInstanceManager;
class CEvent;
class CRobotMain;
-class CSound;
+class CSoundInterface;
/**
- \struct JoystickDevice
- \brief Information about a joystick device */
+ * \struct JoystickDevice
+ * \brief Information about a joystick device
+ */
struct JoystickDevice
{
//! Device index (-1 = invalid device)
@@ -57,8 +57,9 @@ struct JoystickDevice
};
/**
- \enum VideoQueryResult
- \brief Result of querying for available video resolutions */
+ * \enum VideoQueryResult
+ * \brief Result of querying for available video resolutions
+ */
enum VideoQueryResult
{
VIDEO_QUERY_ERROR,
@@ -68,6 +69,35 @@ enum VideoQueryResult
};
+/**
+ * \enum TrackedKeys
+ * \brief Keys (or kmods) whose state (pressed/released) is tracked by CApplication
+ */
+enum TrackedKey
+{
+ TRKEY_SHIFT = (1<<0),
+ TRKEY_CONTROL = (1<<1),
+ TRKEY_NUM_UP = (1<<2),
+ TRKEY_NUM_DOWN = (1<<3),
+ TRKEY_NUM_LEFT = (1<<4),
+ TRKEY_NUM_RIGHT = (1<<5),
+ TRKEY_NUM_PLUS = (1<<6),
+ TRKEY_NUM_MINUS = (1<<7),
+ TRKEY_PAGE_UP = (1<<8),
+ TRKEY_PAGE_DOWN = (1<<9)
+};
+
+/**
+ * \enum ParseArgsStatus
+ * \brief State of parsing commandline arguments
+ */
+enum ParseArgsStatus
+{
+ PARSE_ARGS_OK = 1, //! < all ok
+ PARSE_ARGS_FAIL = 2, //! < invalid syntax
+ PARSE_ARGS_HELP = 3 //! < -help requested
+};
+
struct ApplicationPrivate;
/**
@@ -82,7 +112,7 @@ struct ApplicationPrivate;
* \section Creation Creation of other main objects
*
* The class creates the only instance of CInstanceManager, CEventQueue, CEngine,
- * CRobotMain and CSound classes.
+ * CRobotMain and CSoundInterface classes.
*
* \section Window Window management
*
@@ -123,7 +153,7 @@ public:
public:
//! Parses commandline arguments
- bool ParseArguments(int argc, char *argv[]);
+ ParseArgsStatus ParseArguments(int argc, char *argv[]);
//! Initializes the application
bool Create();
//! Main event loop
@@ -147,8 +177,37 @@ public:
//! Change the video mode to given mode
bool ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig);
+ //! Suspends animation (time will not be updated)
+ void SuspendSimulation();
+ //! Resumes animation
+ void ResumeSimulation();
+ //! Returns whether simulation is suspended
+ bool GetSimulationSuspended();
+
//! Updates the simulation state
- void StepSimulation(float rTime);
+ void StepSimulation();
+
+ //@{
+ //! Management of simulation speed
+ void SetSimulationSpeed(float speed);
+ float GetSimulationSpeed();
+ //@}
+
+ //! Returns the absolute time counter [seconds]
+ float GetAbsTime();
+ //! Returns the exact absolute time counter [nanoseconds]
+ long long GetExactAbsTime();
+
+ //! Returns the exact absolute time counter disregarding speed setting [nanoseconds]
+ long long GetRealAbsTime();
+
+ //! Returns the relative time since last update [seconds]
+ float GetRelTime();
+ //! Returns the exact realative time since last update [nanoseconds]
+ long long GetExactRelTime();
+
+ //! Returns the exact relative time since last update disregarding speed setting [nanoseconds]
+ long long GetRealRelTime();
//! Returns a list of available joystick devices
std::vector<JoystickDevice> GetJoystickList();
@@ -159,10 +218,11 @@ public:
//! Change the current joystick device
bool ChangeJoystick(const JoystickDevice &newJoystick);
- //! Enables/disables joystick
+ //! Management of joystick enable state
+ //@{
void SetJoystickEnabled(bool enable);
- //! Returns whether joystick is enabled
bool GetJoystickEnabled();
+ //@}
//! Polls the state of joystick axes and buttons
void UpdateJoystick();
@@ -170,42 +230,63 @@ public:
//! Updates the mouse position explicitly
void UpdateMouse();
- void FlushPressKey();
- void ResetKey();
- void SetKey(int keyRank, int option, int key);
- int GetKey(int keyRank, int option);
+ //! Returns the current key modifiers
+ int GetKmods();
+ //! Returns whether the given kmod is active
+ bool GetKmodState(int kmod);
+
+ //! Returns whether the tracked key is pressed
+ bool GetTrackedKeyState(TrackedKey key);
- //! Sets the grab mode for input (keyboard & mouse)
+ //! Returns whether the mouse button is pressed
+ bool GetMouseButtonState(int index);
+
+ //! Resets tracked key states and modifiers
+ void ResetKeyStates();
+
+ //! Management of the grab mode for input (keyboard & mouse)
+ //@{
void SetGrabInput(bool grab);
- //! Returns the grab mode
bool GetGrabInput();
+ //@}
- //! Sets the visiblity of system mouse cursor
+ //! Management of the visiblity of system mouse cursor
+ //@{
void SetSystemMouseVisible(bool visible);
- //! Returns the visiblity of system mouse cursor
bool GetSystemMouseVisibile();
+ //@}
- //! Sets the position of system mouse cursor (in interface coords)
+ //! Management of the position of system mouse cursor (in interface coords)
+ //@{
void SetSystemMousePos(Math::Point pos);
- //! Returns the position of system mouse cursor (in interface coords)
Math::Point GetSystemMousePos();
+ //@}
- //! Enables/disables debug mode (prints more info in logger)
+ //! Management of debug mode (prints more info in logger)
+ //@{
void SetDebugMode(bool mode);
- //! Returns whether debug mode is enabled
bool GetDebugMode();
+ //@}
//! Returns the full path to a file in data directory
std::string GetDataFilePath(const std::string &dirName, const std::string &fileName);
+ //! Management of language
+ //@{
+ Language GetLanguage();
+ void SetLanguage(Language language);
+ //@}
+
protected:
//! Creates the window's SDL_Surface
bool CreateVideoSurface();
//! Processes the captured SDL event to Event struct
Event ParseEvent();
+ //! If applicable, creates a virtual event to match the changed state as of new event
+ Event CreateVirtualEvent(const Event& sourceEvent);
//! Handles some incoming events
- bool ProcessEvent(const Event &event);
+ bool ProcessEvent(Event &event);
//! Renders the image in window
void Render();
@@ -226,7 +307,7 @@ protected:
//! Graphics device
Gfx::CDevice* m_device;
//! Sound subsystem
- CSound* m_sound;
+ CSoundInterface* m_sound;
//! Main class of the proper game engine
CRobotMain* m_robotMain;
@@ -248,13 +329,36 @@ protected:
//! Text set as window title
std::string m_windowTitle;
- int m_keyState;
- Math::Vector m_axeKey;
- Math::Vector m_axeJoy;
- Math::Point m_systemMousePos;
- long m_mouseWheel;
+ //! Animation time stamps, etc.
+ //@{
+ SystemTimeStamp* m_baseTimeStamp;
+ SystemTimeStamp* m_lastTimeStamp;
+ SystemTimeStamp* m_curTimeStamp;
- long m_key[50][2];
+ long long m_realAbsTimeBase;
+ long long m_realAbsTime;
+ long long m_realRelTime;
+
+ long long m_absTimeBase;
+ long long m_exactAbsTime;
+ long long m_exactRelTime;
+
+ float m_absTime;
+ float m_relTime;
+
+ float m_simulationSpeed;
+ bool m_simulationSuspended;
+ //@}
+
+ //! Current state of key modifiers (mask of SDLMod)
+ unsigned int m_kmodState;
+ //! Current state of some tracked keys (mask of TrackedKey)
+ unsigned int m_trackedKeys;
+ //! Current state of mouse buttons (mask of button indexes)
+ unsigned int m_mouseButtonsState;
+
+ //! Current system mouse position
+ Math::Point m_systemMousePos;
//! Info about current joystick device
JoystickDevice m_joystick;
@@ -267,5 +371,8 @@ protected:
//! Path to directory with data files
std::string m_dataPath;
+
+ //! Application language
+ Language m_language;
};
diff --git a/src/app/main.cpp b/src/app/main.cpp
index 0d885f7..084ca30 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -78,11 +78,16 @@ int main(int argc, char *argv[])
CApplication app; // single instance of the application
- if (! 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();
}
+ else if (status == PARSE_ARGS_HELP)
+ {
+ return app.GetExitCode();
+ }
int code = 0;
diff --git a/src/app/system_windows.h b/src/app/system_windows.h
index 72d9f88..c9743e6 100644
--- a/src/app/system_windows.h
+++ b/src/app/system_windows.h
@@ -48,18 +48,18 @@ struct SystemTimeStamp
// Convert a wide Unicode string to an UTF8 string
std::string UTF8_Encode_Windows(const std::wstring &wstr)
{
- int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
+ 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], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), &strTo[0], size_needed, NULL, NULL);
return strTo;
}
// 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], (int)str.size(), NULL, 0);
+ 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], (int)str.size(), &wstrTo[0], size_needed);
+ MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), &wstrTo[0], size_needed);
return wstrTo;
}