2012-06-22 14:31:55 +00:00
|
|
|
// * This file is part of the COLOBOT source code
|
|
|
|
// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch
|
|
|
|
// * Copyright (C) 2012, Polish Portal of Colobot (PPC)
|
|
|
|
// *
|
|
|
|
// * 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://www.gnu.org/licenses/.
|
|
|
|
|
2012-12-16 20:29:13 +00:00
|
|
|
#include "common/config.h"
|
2012-06-22 14:31:55 +00:00
|
|
|
|
|
|
|
#include "app/app.h"
|
|
|
|
|
2014-05-18 10:12:47 +00:00
|
|
|
#include "app/gamedata.h"
|
2012-06-25 17:59:17 +00:00
|
|
|
#include "app/system.h"
|
2012-09-20 18:37:37 +00:00
|
|
|
|
2012-07-04 17:56:22 +00:00
|
|
|
#include "common/logger.h"
|
2012-06-25 17:59:17 +00:00
|
|
|
#include "common/iman.h"
|
2012-07-22 20:05:12 +00:00
|
|
|
#include "common/image.h"
|
2012-09-19 16:32:18 +00:00
|
|
|
#include "common/key.h"
|
2013-06-16 19:39:21 +00:00
|
|
|
#include "common/stringutils.h"
|
2012-09-20 18:37:37 +00:00
|
|
|
|
2012-12-26 19:58:02 +00:00
|
|
|
#include "graphics/engine/modelmanager.h"
|
2012-06-30 23:37:30 +00:00
|
|
|
#include "graphics/opengl/gldevice.h"
|
2012-09-20 18:37:37 +00:00
|
|
|
|
2012-09-15 20:19:32 +00:00
|
|
|
#include "object/robotmain.h"
|
2012-06-22 14:31:55 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
#ifdef OPENAL_SOUND
|
|
|
|
#include "sound/oalsound/alsound.h"
|
|
|
|
#endif
|
|
|
|
|
2012-12-19 23:23:12 +00:00
|
|
|
#include <boost/filesystem.hpp>
|
2013-06-16 19:39:21 +00:00
|
|
|
#include <boost/tokenizer.hpp>
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2013-03-22 17:19:53 +00:00
|
|
|
#include <SDL.h>
|
|
|
|
#include <SDL_image.h>
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-09-13 21:28:06 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <libintl.h>
|
2012-09-20 18:37:37 +00:00
|
|
|
#include <unistd.h>
|
2013-03-10 14:44:21 +00:00
|
|
|
#include <getopt.h>
|
2013-06-24 11:07:33 +00:00
|
|
|
#include <localename.h>
|
2012-06-30 08:16:52 +00:00
|
|
|
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2013-02-16 21:37:43 +00:00
|
|
|
template<> CApplication* CSingleton<CApplication>::m_instance = nullptr;
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2012-09-19 16:32:18 +00:00
|
|
|
//! Static buffer for putenv locale
|
|
|
|
static char S_LANGUAGE[50] = { 0 };
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2012-06-30 10:26:40 +00:00
|
|
|
//! Interval of timer called to update joystick state
|
|
|
|
const int JOYSTICK_TIMER_INTERVAL = 1000/30;
|
|
|
|
|
|
|
|
//! Function called by the timer
|
|
|
|
Uint32 JoystickTimerCallback(Uint32 interval, void *);
|
|
|
|
|
|
|
|
|
2012-06-25 17:59:17 +00:00
|
|
|
/**
|
2012-06-26 20:50:55 +00:00
|
|
|
* \struct ApplicationPrivate
|
|
|
|
* \brief Private data of CApplication class
|
2012-06-25 17:59:17 +00:00
|
|
|
*
|
|
|
|
* Contains SDL-specific variables that should not be visible outside application module.
|
|
|
|
*/
|
|
|
|
struct ApplicationPrivate
|
|
|
|
{
|
2012-06-26 20:23:05 +00:00
|
|
|
//! Display surface
|
|
|
|
SDL_Surface *surface;
|
|
|
|
//! Currently handled event
|
|
|
|
SDL_Event currentEvent;
|
2012-09-22 15:36:10 +00:00
|
|
|
//! Mouse motion event to be handled
|
|
|
|
SDL_Event lastMouseMotionEvent;
|
2012-06-26 20:23:05 +00:00
|
|
|
//! Joystick
|
|
|
|
SDL_Joystick *joystick;
|
2012-06-30 10:26:40 +00:00
|
|
|
//! Id of joystick timer
|
|
|
|
SDL_TimerID joystickTimer;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
|
|
|
ApplicationPrivate()
|
|
|
|
{
|
|
|
|
memset(¤tEvent, 0, sizeof(SDL_Event));
|
2012-09-22 15:36:10 +00:00
|
|
|
memset(&lastMouseMotionEvent, 0, sizeof(SDL_Event));
|
2012-09-09 15:51:10 +00:00
|
|
|
surface = nullptr;
|
|
|
|
joystick = nullptr;
|
2012-06-30 10:26:40 +00:00
|
|
|
joystickTimer = 0;
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-06-30 10:26:40 +00:00
|
|
|
|
2012-06-25 17:59:17 +00:00
|
|
|
CApplication::CApplication()
|
|
|
|
{
|
2012-09-21 22:11:16 +00:00
|
|
|
m_private = new ApplicationPrivate();
|
|
|
|
m_iMan = new CInstanceManager();
|
2013-03-31 08:26:37 +00:00
|
|
|
m_objMan = new CObjectManager();
|
2013-02-16 21:37:43 +00:00
|
|
|
m_eventQueue = new CEventQueue();
|
2012-09-21 22:11:16 +00:00
|
|
|
m_profile = new CProfile();
|
2014-05-18 10:12:47 +00:00
|
|
|
m_gameData = new CGameData();
|
2012-06-29 22:12:04 +00:00
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
m_engine = nullptr;
|
|
|
|
m_device = nullptr;
|
2012-12-26 19:58:02 +00:00
|
|
|
m_modelManager = nullptr;
|
2012-09-09 15:51:10 +00:00
|
|
|
m_robotMain = nullptr;
|
|
|
|
m_sound = nullptr;
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
m_exitCode = 0;
|
|
|
|
m_active = false;
|
2013-06-16 19:39:21 +00:00
|
|
|
m_debugModes = 0;
|
2013-07-16 14:00:06 +00:00
|
|
|
m_customDataPath = false;
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2014-03-08 21:36:35 +00:00
|
|
|
m_windowTitle = "COLOBOT GOLD";
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-09-12 21:43:04 +00:00
|
|
|
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;
|
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
m_baseTimeStamp = GetSystemUtils()->CreateTimeStamp();
|
|
|
|
m_curTimeStamp = GetSystemUtils()->CreateTimeStamp();
|
|
|
|
m_lastTimeStamp = GetSystemUtils()->CreateTimeStamp();
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2012-10-25 21:29:49 +00:00
|
|
|
for (int i = 0; i < PCNT_MAX; ++i)
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
m_performanceCounters[i][0] = GetSystemUtils()->CreateTimeStamp();
|
|
|
|
m_performanceCounters[i][1] = GetSystemUtils()->CreateTimeStamp();
|
2012-10-25 21:29:49 +00:00
|
|
|
}
|
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
m_joystickEnabled = false;
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-09-20 18:37:37 +00:00
|
|
|
m_mouseMode = MOUSE_SYSTEM;
|
|
|
|
|
2012-09-12 21:43:04 +00:00
|
|
|
m_kmodState = 0;
|
|
|
|
m_mouseButtonsState = 0;
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys = 0;
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2013-10-31 09:08:32 +00:00
|
|
|
m_dataPath = GetSystemUtils()->GetDataPath();
|
2013-10-31 10:29:52 +00:00
|
|
|
m_langPath = GetSystemUtils()->GetLangPath();
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
m_runSceneName = "";
|
|
|
|
m_runSceneRank = 0;
|
2013-12-26 21:13:04 +00:00
|
|
|
|
|
|
|
m_sceneTest = false;
|
2013-06-16 19:39:21 +00:00
|
|
|
|
2012-12-14 10:17:42 +00:00
|
|
|
m_language = LANGUAGE_ENV;
|
2012-09-20 18:37:37 +00:00
|
|
|
|
|
|
|
m_lowCPU = true;
|
2012-09-22 12:40:13 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
m_protoMode = false;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CApplication::~CApplication()
|
|
|
|
{
|
2012-06-26 20:23:05 +00:00
|
|
|
delete m_private;
|
2012-09-09 15:51:10 +00:00
|
|
|
m_private = nullptr;
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2013-05-11 17:04:43 +00:00
|
|
|
delete m_objMan;
|
|
|
|
m_objMan = nullptr;
|
|
|
|
|
2012-06-29 22:12:04 +00:00
|
|
|
delete m_eventQueue;
|
2012-09-09 15:51:10 +00:00
|
|
|
m_eventQueue = nullptr;
|
2012-06-29 22:12:04 +00:00
|
|
|
|
2012-09-21 22:11:16 +00:00
|
|
|
delete m_profile;
|
2013-12-26 21:14:53 +00:00
|
|
|
m_profile = nullptr;
|
2012-09-21 22:11:16 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
delete m_iMan;
|
2012-09-09 15:51:10 +00:00
|
|
|
m_iMan = nullptr;
|
2014-06-26 19:37:38 +00:00
|
|
|
|
|
|
|
delete m_gameData;
|
|
|
|
m_gameData = nullptr;
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->DestroyTimeStamp(m_baseTimeStamp);
|
|
|
|
GetSystemUtils()->DestroyTimeStamp(m_curTimeStamp);
|
|
|
|
GetSystemUtils()->DestroyTimeStamp(m_lastTimeStamp);
|
2012-10-25 21:29:49 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < PCNT_MAX; ++i)
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->DestroyTimeStamp(m_performanceCounters[i][0]);
|
|
|
|
GetSystemUtils()->DestroyTimeStamp(m_performanceCounters[i][1]);
|
2012-10-25 21:29:49 +00:00
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-02-16 21:37:43 +00:00
|
|
|
CEventQueue* CApplication::GetEventQueue()
|
|
|
|
{
|
|
|
|
return m_eventQueue;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSoundInterface* CApplication::GetSound()
|
|
|
|
{
|
|
|
|
return m_sound;
|
|
|
|
}
|
|
|
|
|
2012-09-17 21:41:53 +00:00
|
|
|
ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2013-03-10 14:44:21 +00:00
|
|
|
enum OptionType
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2013-03-10 14:44:21 +00:00
|
|
|
OPT_HELP = 1,
|
|
|
|
OPT_DEBUG,
|
2013-06-16 19:39:21 +00:00
|
|
|
OPT_RUNSCENE,
|
2013-12-26 21:13:04 +00:00
|
|
|
OPT_SCENETEST,
|
2013-03-10 14:44:21 +00:00
|
|
|
OPT_LOGLEVEL,
|
|
|
|
OPT_LANGUAGE,
|
2013-06-16 19:39:21 +00:00
|
|
|
OPT_DATADIR,
|
2014-05-18 10:12:47 +00:00
|
|
|
OPT_MOD,
|
2013-03-28 14:59:13 +00:00
|
|
|
OPT_LANGDIR,
|
2013-12-27 19:36:11 +00:00
|
|
|
OPT_VBO
|
2013-03-10 14:44:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
option options[] =
|
|
|
|
{
|
|
|
|
{ "help", no_argument, nullptr, OPT_HELP },
|
2013-06-16 19:39:21 +00:00
|
|
|
{ "debug", required_argument, nullptr, OPT_DEBUG },
|
|
|
|
{ "runscene", required_argument, nullptr, OPT_RUNSCENE },
|
2013-12-26 21:13:04 +00:00
|
|
|
{ "scenetest", no_argument, nullptr, OPT_SCENETEST },
|
2013-03-10 14:44:21 +00:00
|
|
|
{ "loglevel", required_argument, nullptr, OPT_LOGLEVEL },
|
|
|
|
{ "language", required_argument, nullptr, OPT_LANGUAGE },
|
2013-06-16 19:39:21 +00:00
|
|
|
{ "datadir", required_argument, nullptr, OPT_DATADIR },
|
2014-05-18 10:12:47 +00:00
|
|
|
{ "mod", required_argument, nullptr, OPT_MOD },
|
2013-03-28 14:59:13 +00:00
|
|
|
{ "langdir", required_argument, nullptr, OPT_LANGDIR },
|
2013-06-16 19:39:21 +00:00
|
|
|
{ "vbo", required_argument, nullptr, OPT_VBO },
|
2013-05-26 08:23:30 +00:00
|
|
|
{ nullptr, 0, nullptr, 0}
|
2013-03-10 14:44:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
opterr = 0;
|
|
|
|
|
|
|
|
int c = 0;
|
|
|
|
int index = -1;
|
|
|
|
while ((c = getopt_long_only(argc, argv, "", options, &index)) != -1)
|
|
|
|
{
|
|
|
|
if (c == '?')
|
2012-08-31 18:55:16 +00:00
|
|
|
{
|
2013-03-10 14:44:21 +00:00
|
|
|
if (optopt == 0)
|
|
|
|
GetLogger()->Error("Invalid argument: %s\n", argv[optind-1]);
|
2012-08-31 18:55:16 +00:00
|
|
|
else
|
2013-03-10 14:44:21 +00:00
|
|
|
GetLogger()->Error("Expected argument for option: %s\n", argv[optind-1]);
|
2012-08-31 18:55:16 +00:00
|
|
|
|
2013-03-10 14:44:21 +00:00
|
|
|
m_exitCode = 1;
|
|
|
|
return PARSE_ARGS_FAIL;
|
2012-09-13 21:28:06 +00:00
|
|
|
}
|
|
|
|
|
2013-03-10 14:44:21 +00:00
|
|
|
index = -1;
|
|
|
|
|
|
|
|
switch (c)
|
2012-07-22 20:05:12 +00:00
|
|
|
{
|
2013-03-10 14:44:21 +00:00
|
|
|
case OPT_HELP:
|
|
|
|
{
|
|
|
|
GetLogger()->Message("\n");
|
|
|
|
GetLogger()->Message("Colobot %s (%s)\n", COLOBOT_CODENAME, COLOBOT_VERSION);
|
|
|
|
GetLogger()->Message("\n");
|
|
|
|
GetLogger()->Message("List of available options:\n");
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Message(" -help this help\n");
|
|
|
|
GetLogger()->Message(" -debug modes enable debug modes (more info printed in logs; see code for reference of modes)\n");
|
|
|
|
GetLogger()->Message(" -runscene sceneNNN run given scene on start\n");
|
2013-12-26 21:13:04 +00:00
|
|
|
GetLogger()->Message(" -scenetest win every mission right after it's loaded\n");
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n");
|
2013-11-25 23:29:03 +00:00
|
|
|
GetLogger()->Message(" -language lang set language (one of: en, de, fr, pl, ru)\n");
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Message(" -datadir path set custom data directory path\n");
|
2014-05-18 10:12:47 +00:00
|
|
|
GetLogger()->Message(" -mod path run mod\n");
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Message(" -langdir path set custom language directory path\n");
|
|
|
|
GetLogger()->Message(" -vbo mode set OpenGL VBO mode (one of: auto, enable, disable)\n");
|
2013-03-10 14:44:21 +00:00
|
|
|
return PARSE_ARGS_HELP;
|
|
|
|
}
|
|
|
|
case OPT_DEBUG:
|
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
if (optarg == nullptr)
|
|
|
|
{
|
|
|
|
m_debugModes = DEBUG_ALL;
|
|
|
|
GetLogger()->Info("All debug modes active\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int debugModes;
|
|
|
|
if (! ParseDebugModes(optarg, debugModes))
|
|
|
|
{
|
|
|
|
return PARSE_ARGS_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_debugModes = debugModes;
|
|
|
|
GetLogger()->Info("Active debug modes: %s\n", optarg);
|
|
|
|
}
|
2013-05-26 12:50:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-06-16 19:39:21 +00:00
|
|
|
case OPT_RUNSCENE:
|
2013-05-26 12:50:23 +00:00
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
std::string file = optarg;
|
|
|
|
m_runSceneName = file.substr(0, file.size()-3);
|
|
|
|
m_runSceneRank = StrUtils::FromString<int>(file.substr(file.size()-3, 3));
|
|
|
|
GetLogger()->Info("Running scene '%s%d' on start\n", m_runSceneName.c_str(), m_runSceneRank);
|
2013-05-26 12:50:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-12-26 21:13:04 +00:00
|
|
|
case OPT_SCENETEST:
|
|
|
|
{
|
|
|
|
m_sceneTest = true;
|
|
|
|
break;
|
|
|
|
}
|
2013-03-10 14:44:21 +00:00
|
|
|
case OPT_LOGLEVEL:
|
|
|
|
{
|
|
|
|
LogLevel logLevel;
|
|
|
|
if (! CLogger::ParseLogLevel(optarg, logLevel))
|
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Error("Invalid log level: '%s'\n", optarg);
|
2013-03-10 14:44:21 +00:00
|
|
|
return PARSE_ARGS_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetLogger()->Message("[*****] Log level changed to %s\n", optarg);
|
|
|
|
GetLogger()->SetLogLevel(logLevel);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case OPT_LANGUAGE:
|
|
|
|
{
|
|
|
|
Language language;
|
|
|
|
if (! ParseLanguage(optarg, language))
|
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Error("Invalid language: '%s'\n", optarg);
|
2013-03-10 14:44:21 +00:00
|
|
|
return PARSE_ARGS_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetLogger()->Info("Using language %s\n", optarg);
|
|
|
|
m_language = language;
|
|
|
|
break;
|
|
|
|
}
|
2013-06-16 19:39:21 +00:00
|
|
|
case OPT_DATADIR:
|
|
|
|
{
|
|
|
|
m_dataPath = optarg;
|
2013-07-16 14:00:06 +00:00
|
|
|
m_customDataPath = true;
|
2014-05-18 10:12:47 +00:00
|
|
|
GetLogger()->Info("Using datadir: '%s'\n", optarg);
|
2013-06-16 19:39:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-05-18 10:12:47 +00:00
|
|
|
case OPT_MOD:
|
2013-06-16 19:39:21 +00:00
|
|
|
{
|
2014-05-18 10:12:47 +00:00
|
|
|
m_gameData->AddMod(std::string(optarg));
|
|
|
|
GetLogger()->Info("Running mod from path: '%s'\n", optarg);
|
2013-06-16 19:39:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-05-18 10:12:47 +00:00
|
|
|
case OPT_LANGDIR:
|
2013-06-16 19:39:21 +00:00
|
|
|
{
|
2014-05-18 10:12:47 +00:00
|
|
|
m_langPath = optarg;
|
|
|
|
GetLogger()->Info("Using language dir: '%s'\n", m_langPath.c_str());
|
2013-06-16 19:39:21 +00:00
|
|
|
break;
|
|
|
|
}
|
2013-03-10 14:44:21 +00:00
|
|
|
case OPT_VBO:
|
|
|
|
{
|
|
|
|
std::string vbo;
|
|
|
|
vbo = optarg;
|
|
|
|
if (vbo == "auto")
|
|
|
|
m_deviceConfig.vboMode = Gfx::VBO_MODE_AUTO;
|
|
|
|
else if (vbo == "enable")
|
|
|
|
m_deviceConfig.vboMode = Gfx::VBO_MODE_ENABLE;
|
|
|
|
else if (vbo == "disable")
|
|
|
|
m_deviceConfig.vboMode = Gfx::VBO_MODE_DISABLE;
|
|
|
|
else
|
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
GetLogger()->Error("Invalid vbo mode: '%s'\n", optarg);
|
2013-03-10 14:44:21 +00:00
|
|
|
return PARSE_ARGS_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
assert(false); // should never get here
|
2012-07-22 20:05:12 +00:00
|
|
|
}
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
|
|
|
|
2012-09-17 21:41:53 +00:00
|
|
|
return PARSE_ARGS_OK;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CApplication::Create()
|
|
|
|
{
|
2013-05-03 19:34:10 +00:00
|
|
|
std::string path;
|
|
|
|
bool defaultValues = false;
|
|
|
|
|
2012-08-13 21:09:30 +00:00
|
|
|
GetLogger()->Info("Creating CApplication\n");
|
|
|
|
|
2014-08-12 19:24:33 +00:00
|
|
|
if (!GetProfile().Init())
|
2013-05-03 19:34:10 +00:00
|
|
|
{
|
|
|
|
GetLogger()->Warn("Config not found. Default values will be used!\n");
|
|
|
|
defaultValues = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-08-12 19:24:33 +00:00
|
|
|
if (!m_customDataPath && GetProfile().GetStringProperty("Resources", "Data", path))
|
2013-05-03 19:34:10 +00:00
|
|
|
m_dataPath = path;
|
|
|
|
}
|
|
|
|
|
2012-12-19 23:23:12 +00:00
|
|
|
boost::filesystem::path dataPath(m_dataPath);
|
|
|
|
if (! (boost::filesystem::exists(dataPath) && boost::filesystem::is_directory(dataPath)) )
|
2012-09-13 21:28:06 +00:00
|
|
|
{
|
2012-12-19 23:23:12 +00:00
|
|
|
GetLogger()->Error("Data directory '%s' doesn't exist or is not a directory\n", m_dataPath.c_str());
|
2012-09-13 21:28:06 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-05-18 10:12:47 +00:00
|
|
|
|
|
|
|
m_gameData->SetDataDir(std::string(m_dataPath));
|
|
|
|
m_gameData->Init();
|
2012-09-13 21:28:06 +00:00
|
|
|
|
2014-08-12 19:24:33 +00:00
|
|
|
if (GetProfile().GetStringProperty("Language", "Lang", path)) {
|
2013-12-31 16:20:03 +00:00
|
|
|
Language language;
|
|
|
|
if (ParseLanguage(path, language)) {
|
|
|
|
m_language = language;
|
2014-01-01 15:46:28 +00:00
|
|
|
GetLogger()->Info("Setting language '%s' from ini file\n", path.c_str());
|
2013-12-31 16:20:03 +00:00
|
|
|
} else {
|
|
|
|
GetLogger()->Error("Invalid language '%s' in ini file\n", path.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-12-28 21:31:47 +00:00
|
|
|
SetLanguage(m_language);
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-09-26 20:57:43 +00:00
|
|
|
//Create the sound instance.
|
2013-05-03 19:34:10 +00:00
|
|
|
#ifdef OPENAL_SOUND
|
|
|
|
m_sound = static_cast<CSoundInterface *>(new ALSound());
|
|
|
|
#else
|
|
|
|
GetLogger()->Info("No sound support.\n");
|
|
|
|
m_sound = new CSoundInterface();
|
|
|
|
#endif
|
|
|
|
|
2013-12-19 21:41:16 +00:00
|
|
|
m_sound->Create();
|
2014-05-18 10:12:47 +00:00
|
|
|
m_sound->CacheAll();
|
|
|
|
m_sound->AddMusicFiles();
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2013-05-03 19:34:10 +00:00
|
|
|
GetLogger()->Info("CApplication created successfully\n");
|
|
|
|
|
2012-08-13 21:09:30 +00:00
|
|
|
std::string standardInfoMessage =
|
|
|
|
"\nPlease see the console output or log file\n"
|
|
|
|
"to get more information on the source of error";
|
2012-06-29 22:12:04 +00:00
|
|
|
|
|
|
|
/* SDL initialization sequence */
|
|
|
|
|
|
|
|
|
2012-09-29 08:40:11 +00:00
|
|
|
Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_TIMER;
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
if (SDL_Init(initFlags) < 0)
|
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
m_errorMessage = std::string("SDL initialization error:\n") +
|
|
|
|
std::string(SDL_GetError());
|
|
|
|
GetLogger()->Error(m_errorMessage.c_str());
|
2012-07-04 17:56:22 +00:00
|
|
|
m_exitCode = 2;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-29 08:40:11 +00:00
|
|
|
// This is non-fatal and besides seems to fix some memory leaks
|
|
|
|
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
|
|
|
|
{
|
|
|
|
GetLogger()->Warn("Joystick subsystem init failed\nJoystick(s) will not be available\n");
|
|
|
|
}
|
|
|
|
|
2012-07-04 17:56:22 +00:00
|
|
|
if ((IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0)
|
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
m_errorMessage = std::string("SDL_Image initialization error:\n") +
|
|
|
|
std::string(IMG_GetError());
|
|
|
|
GetLogger()->Error(m_errorMessage.c_str());
|
2012-07-04 17:56:22 +00:00
|
|
|
m_exitCode = 3;
|
2012-06-26 20:23:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-03-10 14:44:21 +00:00
|
|
|
|
2012-12-25 20:36:50 +00:00
|
|
|
// load settings from profile
|
|
|
|
int iValue;
|
2014-08-12 19:24:33 +00:00
|
|
|
if ( GetProfile().GetIntProperty("Setup", "Resolution", iValue) )
|
2013-03-10 14:44:21 +00:00
|
|
|
{
|
|
|
|
std::vector<Math::IntPoint> modes;
|
|
|
|
GetVideoResolutionList(modes, true, true);
|
|
|
|
if (static_cast<unsigned int>(iValue) < modes.size())
|
|
|
|
m_deviceConfig.size = modes.at(iValue);
|
2012-12-25 20:36:50 +00:00
|
|
|
}
|
2013-03-10 14:44:21 +00:00
|
|
|
|
2014-08-12 19:24:33 +00:00
|
|
|
if ( GetProfile().GetIntProperty("Setup", "Fullscreen", iValue) )
|
2013-03-10 14:44:21 +00:00
|
|
|
{
|
|
|
|
m_deviceConfig.fullScreen = (iValue == 1);
|
2012-12-25 20:36:50 +00:00
|
|
|
}
|
2013-03-10 14:44:21 +00:00
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
if (! CreateVideoSurface())
|
|
|
|
return false; // dialog is in function
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_private->surface == nullptr)
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
m_errorMessage = std::string("SDL error while setting video mode:\n") +
|
|
|
|
std::string(SDL_GetError());
|
|
|
|
GetLogger()->Error(m_errorMessage.c_str());
|
|
|
|
m_exitCode = 4;
|
2012-06-26 20:23:05 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
SDL_WM_SetCaption(m_windowTitle.c_str(), m_windowTitle.c_str());
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-29 22:12:04 +00:00
|
|
|
// Enable translating key codes of key press events to unicode chars
|
2012-06-26 20:23:05 +00:00
|
|
|
SDL_EnableUNICODE(1);
|
2013-04-18 19:02:25 +00:00
|
|
|
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-30 10:26:40 +00:00
|
|
|
// Don't generate joystick events
|
|
|
|
SDL_JoystickEventState(SDL_IGNORE);
|
2013-03-10 14:44:21 +00:00
|
|
|
|
2012-07-01 20:59:22 +00:00
|
|
|
// The video is ready, we can create and initalize the graphics device
|
2012-07-29 13:09:53 +00:00
|
|
|
m_device = new Gfx::CGLDevice(m_deviceConfig);
|
2012-07-01 20:59:22 +00:00
|
|
|
if (! m_device->Create() )
|
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
m_errorMessage = std::string("Error in CDevice::Create()\n") + standardInfoMessage;
|
|
|
|
m_exitCode = 5;
|
2012-07-01 20:59:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-08-03 21:23:13 +00:00
|
|
|
// Create the 3D engine
|
2013-02-16 21:37:43 +00:00
|
|
|
m_engine = new Gfx::CEngine(this);
|
2012-08-03 21:23:13 +00:00
|
|
|
|
2012-07-01 20:59:22 +00:00
|
|
|
m_engine->SetDevice(m_device);
|
|
|
|
|
2012-08-03 21:23:13 +00:00
|
|
|
if (! m_engine->Create() )
|
2012-07-01 20:59:22 +00:00
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
m_errorMessage = std::string("Error in CEngine::Init()\n") + standardInfoMessage;
|
|
|
|
m_exitCode = 6;
|
2012-07-01 20:59:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-12-26 19:58:02 +00:00
|
|
|
// Create model manager
|
|
|
|
m_modelManager = new Gfx::CModelManager(m_engine);
|
|
|
|
|
2012-09-15 20:19:32 +00:00
|
|
|
// Create the robot application.
|
2013-05-04 09:56:03 +00:00
|
|
|
m_robotMain = new CRobotMain(this, !defaultValues);
|
2012-09-15 20:19:32 +00:00
|
|
|
|
2013-05-03 19:34:10 +00:00
|
|
|
if (defaultValues) m_robotMain->CreateIni();
|
2012-09-16 08:38:08 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
if (! m_runSceneName.empty())
|
|
|
|
m_robotMain->LoadSceneOnStart(m_runSceneName, m_runSceneRank);
|
|
|
|
else
|
|
|
|
m_robotMain->ChangePhase(PHASE_WELCOME1);
|
2012-08-13 21:09:30 +00:00
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CApplication::CreateVideoSurface()
|
|
|
|
{
|
|
|
|
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
|
2012-09-09 15:51:10 +00:00
|
|
|
if (videoInfo == nullptr)
|
2012-07-29 13:09:53 +00:00
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
m_errorMessage = std::string("SDL error while getting video info:\n ") +
|
|
|
|
std::string(SDL_GetError());
|
|
|
|
GetLogger()->Error(m_errorMessage.c_str());
|
|
|
|
m_exitCode = 7;
|
2012-07-29 13:09:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
|
|
|
|
|
|
|
|
// Use hardware surface if available
|
|
|
|
if (videoInfo->hw_available)
|
|
|
|
videoFlags |= SDL_HWSURFACE;
|
|
|
|
|
|
|
|
// Enable hardware blit if available
|
|
|
|
if (videoInfo->blit_hw)
|
|
|
|
videoFlags |= SDL_HWACCEL;
|
|
|
|
|
|
|
|
if (m_deviceConfig.fullScreen)
|
|
|
|
videoFlags |= SDL_FULLSCREEN;
|
|
|
|
|
|
|
|
if (m_deviceConfig.resizeable)
|
|
|
|
videoFlags |= SDL_RESIZABLE;
|
|
|
|
|
|
|
|
// Set OpenGL attributes
|
|
|
|
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, m_deviceConfig.redSize);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, m_deviceConfig.greenSize);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, m_deviceConfig.blueSize);
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, m_deviceConfig.alphaSize);
|
|
|
|
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, m_deviceConfig.depthSize);
|
|
|
|
|
|
|
|
if (m_deviceConfig.doubleBuf)
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
|
|
|
|
|
|
|
/* If hardware acceleration specifically requested, this will force the hw accel
|
|
|
|
and fail with error if not available */
|
|
|
|
if (m_deviceConfig.hardwareAccel)
|
|
|
|
SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-08-11 15:17:04 +00:00
|
|
|
m_private->surface = SDL_SetVideoMode(m_deviceConfig.size.x, m_deviceConfig.size.y,
|
2012-07-29 13:09:53 +00:00
|
|
|
m_deviceConfig.bpp, videoFlags);
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
return true;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::Destroy()
|
|
|
|
{
|
2012-09-19 19:23:42 +00:00
|
|
|
m_joystickEnabled = false;
|
|
|
|
|
2014-08-10 15:51:47 +00:00
|
|
|
delete m_robotMain;
|
|
|
|
m_robotMain = nullptr;
|
2012-07-01 20:59:22 +00:00
|
|
|
|
2014-08-10 15:51:47 +00:00
|
|
|
delete m_sound;
|
|
|
|
m_sound = nullptr;
|
2012-07-01 20:59:22 +00:00
|
|
|
|
2014-08-10 15:51:47 +00:00
|
|
|
delete m_modelManager;
|
|
|
|
m_modelManager = nullptr;
|
2012-12-26 19:58:02 +00:00
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_engine != nullptr)
|
2012-07-01 20:59:22 +00:00
|
|
|
{
|
2012-08-03 21:23:13 +00:00
|
|
|
m_engine->Destroy();
|
2012-07-01 20:59:22 +00:00
|
|
|
|
|
|
|
delete m_engine;
|
2012-09-09 15:51:10 +00:00
|
|
|
m_engine = nullptr;
|
2012-07-01 20:59:22 +00:00
|
|
|
}
|
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_device != nullptr)
|
2012-07-01 20:59:22 +00:00
|
|
|
{
|
2012-08-03 21:23:13 +00:00
|
|
|
m_device->Destroy();
|
2012-07-01 20:59:22 +00:00
|
|
|
|
|
|
|
delete m_device;
|
2012-09-09 15:51:10 +00:00
|
|
|
m_device = nullptr;
|
2012-07-01 20:59:22 +00:00
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_private->joystick != nullptr)
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
|
|
|
SDL_JoystickClose(m_private->joystick);
|
2012-09-09 15:51:10 +00:00
|
|
|
m_private->joystick = nullptr;
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_private->surface != nullptr)
|
2012-07-01 20:59:22 +00:00
|
|
|
{
|
|
|
|
SDL_FreeSurface(m_private->surface);
|
2012-09-09 15:51:10 +00:00
|
|
|
m_private->surface = nullptr;
|
2012-07-01 20:59:22 +00:00
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
IMG_Quit();
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
SDL_Quit();
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
bool CApplication::ChangeVideoConfig(const Gfx::GLDeviceConfig &newConfig)
|
|
|
|
{
|
|
|
|
static bool restore = false;
|
|
|
|
|
|
|
|
m_lastDeviceConfig = m_deviceConfig;
|
|
|
|
m_deviceConfig = newConfig;
|
|
|
|
|
|
|
|
|
|
|
|
SDL_FreeSurface(m_private->surface);
|
|
|
|
|
|
|
|
if (! CreateVideoSurface())
|
|
|
|
{
|
|
|
|
// Fatal error, so post the quit event
|
2013-06-16 19:39:21 +00:00
|
|
|
m_eventQueue->AddEvent(Event(EVENT_SYS_QUIT));
|
2012-07-29 13:09:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_private->surface == nullptr)
|
2012-07-29 13:09:53 +00:00
|
|
|
{
|
|
|
|
if (! restore)
|
|
|
|
{
|
2012-08-13 21:09:30 +00:00
|
|
|
std::string error = std::string("SDL error while setting video mode:\n") +
|
2012-07-29 13:09:53 +00:00
|
|
|
std::string(SDL_GetError()) + std::string("\n") +
|
2012-08-13 21:09:30 +00:00
|
|
|
std::string("Previous mode will be restored");
|
|
|
|
GetLogger()->Error(error.c_str());
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->SystemDialog( SDT_ERROR, "COLOBT - Error", error);
|
2012-07-29 13:09:53 +00:00
|
|
|
|
|
|
|
restore = true;
|
|
|
|
ChangeVideoConfig(m_lastDeviceConfig);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
restore = false;
|
|
|
|
|
2012-08-13 21:09:30 +00:00
|
|
|
std::string error = std::string("SDL error while restoring previous video mode:\n") +
|
|
|
|
std::string(SDL_GetError());
|
|
|
|
GetLogger()->Error(error.c_str());
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->SystemDialog( SDT_ERROR, "COLOBT - Fatal Error", error);
|
2012-07-29 13:09:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Fatal error, so post the quit event
|
2013-06-16 19:39:21 +00:00
|
|
|
m_eventQueue->AddEvent(Event(EVENT_SYS_QUIT));
|
2012-07-29 13:09:53 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
( static_cast<Gfx::CGLDevice*>(m_device) )->ConfigChanged(m_deviceConfig);
|
|
|
|
|
|
|
|
m_engine->ResetAfterDeviceChanged();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-06-29 22:12:04 +00:00
|
|
|
bool CApplication::OpenJoystick()
|
|
|
|
{
|
2012-07-29 13:09:53 +00:00
|
|
|
if ( (m_joystick.index < 0) || (m_joystick.index >= SDL_NumJoysticks()) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
m_private->joystick = SDL_JoystickOpen(m_joystick.index);
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_private->joystick == nullptr)
|
2012-06-29 22:12:04 +00:00
|
|
|
return false;
|
2012-06-30 08:16:52 +00:00
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
m_joystick.axisCount = SDL_JoystickNumAxes(m_private->joystick);
|
|
|
|
m_joystick.buttonCount = SDL_JoystickNumButtons(m_private->joystick);
|
|
|
|
|
2012-06-30 10:26:40 +00:00
|
|
|
// Create the vectors with joystick axis & button states to exactly the required size
|
2012-07-29 13:09:53 +00:00
|
|
|
m_joyAxeState = std::vector<int>(m_joystick.axisCount, 0);
|
|
|
|
m_joyButtonState = std::vector<bool>(m_joystick.buttonCount, false);
|
2012-06-30 10:26:40 +00:00
|
|
|
|
|
|
|
// Create a timer for polling joystick state
|
2012-09-09 15:51:10 +00:00
|
|
|
m_private->joystickTimer = SDL_AddTimer(JOYSTICK_TIMER_INTERVAL, JoystickTimerCallback, nullptr);
|
2012-06-30 10:26:40 +00:00
|
|
|
|
2012-06-30 08:16:52 +00:00
|
|
|
return true;
|
2012-06-29 22:12:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::CloseJoystick()
|
|
|
|
{
|
2012-06-30 10:26:40 +00:00
|
|
|
// Timer will remove itself automatically
|
|
|
|
|
2012-06-29 22:12:04 +00:00
|
|
|
SDL_JoystickClose(m_private->joystick);
|
2012-09-09 15:51:10 +00:00
|
|
|
m_private->joystick = nullptr;
|
2012-06-30 10:26:40 +00:00
|
|
|
}
|
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
bool CApplication::ChangeJoystick(const JoystickDevice &newJoystick)
|
|
|
|
{
|
|
|
|
if ( (newJoystick.index < 0) || (newJoystick.index >= SDL_NumJoysticks()) )
|
|
|
|
return false;
|
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
if (m_private->joystick != nullptr)
|
2012-07-29 13:09:53 +00:00
|
|
|
CloseJoystick();
|
|
|
|
|
|
|
|
return OpenJoystick();
|
|
|
|
}
|
|
|
|
|
2012-06-30 10:26:40 +00:00
|
|
|
Uint32 JoystickTimerCallback(Uint32 interval, void *)
|
|
|
|
{
|
2012-07-22 20:05:12 +00:00
|
|
|
CApplication *app = CApplication::GetInstancePointer();
|
2012-09-09 15:51:10 +00:00
|
|
|
if ((app == nullptr) || (! app->GetJoystickEnabled()))
|
2012-06-30 10:26:40 +00:00
|
|
|
return 0; // don't run the timer again
|
|
|
|
|
|
|
|
app->UpdateJoystick();
|
|
|
|
|
|
|
|
return interval; // run for the same interval again
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Updates the state info in CApplication and on change, creates SDL events and pushes them to SDL event queue.
|
|
|
|
This way, the events get handled properly in the main event loop and besides, SDL_PushEvent() ensures thread-safety. */
|
|
|
|
void CApplication::UpdateJoystick()
|
|
|
|
{
|
|
|
|
if (! m_joystickEnabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SDL_JoystickUpdate();
|
|
|
|
|
2012-07-30 20:59:18 +00:00
|
|
|
for (int axis = 0; axis < static_cast<int>( m_joyAxeState.size() ); ++axis)
|
2012-06-30 10:26:40 +00:00
|
|
|
{
|
|
|
|
int newValue = SDL_JoystickGetAxis(m_private->joystick, axis);
|
|
|
|
|
|
|
|
if (m_joyAxeState[axis] != newValue)
|
|
|
|
{
|
|
|
|
m_joyAxeState[axis] = newValue;
|
|
|
|
|
|
|
|
SDL_Event joyAxisEvent;
|
|
|
|
|
|
|
|
joyAxisEvent.jaxis.type = SDL_JOYAXISMOTION;
|
|
|
|
joyAxisEvent.jaxis.which = 0;
|
|
|
|
joyAxisEvent.jaxis.axis = axis;
|
|
|
|
joyAxisEvent.jaxis.value = newValue;
|
|
|
|
|
|
|
|
SDL_PushEvent(&joyAxisEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-30 20:59:18 +00:00
|
|
|
for (int button = 0; button < static_cast<int>( m_joyButtonState.size() ); ++button)
|
2012-06-30 10:26:40 +00:00
|
|
|
{
|
|
|
|
bool newValue = SDL_JoystickGetButton(m_private->joystick, button) == 1;
|
|
|
|
|
|
|
|
if (m_joyButtonState[button] != newValue)
|
|
|
|
{
|
|
|
|
m_joyButtonState[button] = newValue;
|
|
|
|
|
|
|
|
SDL_Event joyButtonEvent;
|
|
|
|
|
|
|
|
if (newValue)
|
|
|
|
{
|
|
|
|
joyButtonEvent.jbutton.type = SDL_JOYBUTTONDOWN;
|
|
|
|
joyButtonEvent.jbutton.state = SDL_PRESSED;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
joyButtonEvent.jbutton.type = SDL_JOYBUTTONUP;
|
|
|
|
joyButtonEvent.jbutton.state = SDL_RELEASED;
|
|
|
|
}
|
|
|
|
joyButtonEvent.jbutton.which = 0;
|
|
|
|
joyButtonEvent.jbutton.button = button;
|
|
|
|
|
|
|
|
SDL_PushEvent(&joyButtonEvent);
|
|
|
|
}
|
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
}
|
|
|
|
|
2012-08-12 08:45:04 +00:00
|
|
|
void CApplication::UpdateMouse()
|
|
|
|
{
|
|
|
|
Math::IntPoint pos;
|
|
|
|
SDL_GetMouseState(&pos.x, &pos.y);
|
2012-09-20 18:37:37 +00:00
|
|
|
m_mousePos = m_engine->WindowToInterfaceCoords(pos);
|
2012-08-12 08:45:04 +00:00
|
|
|
}
|
|
|
|
|
2012-06-25 17:59:17 +00:00
|
|
|
int CApplication::Run()
|
|
|
|
{
|
2012-06-26 20:23:05 +00:00
|
|
|
m_active = true;
|
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_baseTimeStamp);
|
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_lastTimeStamp);
|
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_curTimeStamp);
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2012-09-20 18:37:37 +00:00
|
|
|
MoveMouse(Math::Point(0.5f, 0.5f)); // center mouse on start
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
while (true)
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-10-25 21:29:49 +00:00
|
|
|
ResetPerformanceCounters();
|
|
|
|
|
|
|
|
if (m_active)
|
|
|
|
{
|
|
|
|
StartPerformanceCounter(PCNT_ALL);
|
|
|
|
StartPerformanceCounter(PCNT_EVENT_PROCESSING);
|
|
|
|
}
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
// To be sure no old event remains
|
|
|
|
m_private->currentEvent.type = SDL_NOEVENT;
|
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
// Call SDL_PumpEvents() only once here
|
|
|
|
// (SDL_PeepEvents() doesn't call it)
|
2012-07-23 19:41:27 +00:00
|
|
|
if (m_active)
|
|
|
|
SDL_PumpEvents();
|
|
|
|
|
2012-09-22 15:36:10 +00:00
|
|
|
m_private->lastMouseMotionEvent.type = SDL_NOEVENT;
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
bool haveEvent = true;
|
|
|
|
while (haveEvent)
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-07-22 20:05:12 +00:00
|
|
|
haveEvent = false;
|
|
|
|
|
2012-07-23 19:41:27 +00:00
|
|
|
int count = 0;
|
|
|
|
// Use SDL_PeepEvents() if the app is active, so we can use idle time to
|
2012-07-29 13:09:53 +00:00
|
|
|
// render the scene. Else, use SDL_WaitEvent() to avoid eating CPU time.
|
2012-07-22 20:05:12 +00:00
|
|
|
if (m_active)
|
|
|
|
count = SDL_PeepEvents(&m_private->currentEvent, 1, SDL_GETEVENT, SDL_ALLEVENTS);
|
|
|
|
else
|
2012-07-29 13:09:53 +00:00
|
|
|
count = SDL_WaitEvent(&m_private->currentEvent);
|
2012-07-22 20:05:12 +00:00
|
|
|
|
|
|
|
// If received an event
|
|
|
|
if (count > 0)
|
|
|
|
{
|
|
|
|
haveEvent = true;
|
|
|
|
|
2012-09-22 15:36:10 +00:00
|
|
|
// Skip mouse motion events, for now
|
|
|
|
if (m_private->currentEvent.type == SDL_MOUSEMOTION)
|
|
|
|
{
|
|
|
|
m_private->lastMouseMotionEvent = m_private->currentEvent;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-09-21 22:38:17 +00:00
|
|
|
Event event = ProcessSystemEvent();
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
if (event.type == EVENT_SYS_QUIT)
|
2012-07-22 20:05:12 +00:00
|
|
|
goto end; // exit the loop
|
|
|
|
|
|
|
|
if (event.type != EVENT_NULL)
|
2013-06-16 19:39:21 +00:00
|
|
|
m_eventQueue->AddEvent(event);
|
2012-09-19 16:32:18 +00:00
|
|
|
|
|
|
|
Event virtualEvent = CreateVirtualEvent(event);
|
|
|
|
if (virtualEvent.type != EVENT_NULL)
|
2013-06-16 19:39:21 +00:00
|
|
|
m_eventQueue->AddEvent(virtualEvent);
|
2012-07-22 20:05:12 +00:00
|
|
|
}
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
|
|
|
|
2012-09-22 15:36:10 +00:00
|
|
|
// Now, process the last received mouse motion
|
|
|
|
if (m_private->lastMouseMotionEvent.type != SDL_NOEVENT)
|
|
|
|
{
|
|
|
|
m_private->currentEvent = m_private->lastMouseMotionEvent;
|
|
|
|
|
|
|
|
Event event = ProcessSystemEvent();
|
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
if (event.type == EVENT_SYS_QUIT)
|
2012-09-22 15:36:10 +00:00
|
|
|
goto end; // exit the loop
|
|
|
|
|
|
|
|
if (event.type != EVENT_NULL)
|
2013-06-16 19:39:21 +00:00
|
|
|
m_eventQueue->AddEvent(event);
|
2012-09-22 15:36:10 +00:00
|
|
|
}
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
// Enter game update & frame rendering only if active
|
2012-07-29 13:09:53 +00:00
|
|
|
if (m_active)
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
|
|
|
Event event;
|
2012-06-29 22:12:04 +00:00
|
|
|
while (m_eventQueue->GetEvent(event))
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
if (event.type == EVENT_SYS_QUIT || event.type == EVENT_QUIT)
|
2012-06-26 20:23:05 +00:00
|
|
|
goto end; // exit both loops
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
LogEvent(event);
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
bool passOn = true;
|
|
|
|
if (m_engine != nullptr)
|
|
|
|
passOn = m_engine->ProcessEvent(event);
|
2012-06-26 20:23:05 +00:00
|
|
|
|
2012-09-15 20:19:32 +00:00
|
|
|
if (passOn && m_robotMain != nullptr)
|
2013-06-16 19:39:21 +00:00
|
|
|
m_robotMain->ProcessEvent(event);
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
|
|
|
|
2012-10-25 21:29:49 +00:00
|
|
|
StopPerformanceCounter(PCNT_EVENT_PROCESSING);
|
|
|
|
|
|
|
|
StartPerformanceCounter(PCNT_UPDATE_ALL);
|
|
|
|
|
2012-10-25 18:27:40 +00:00
|
|
|
// Prepare and process step simulation event
|
|
|
|
event = CreateUpdateEvent();
|
|
|
|
if (event.type != EVENT_NULL && m_robotMain != nullptr)
|
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
LogEvent(event);
|
|
|
|
|
2012-10-25 18:27:40 +00:00
|
|
|
m_sound->FrameMove(m_relTime);
|
|
|
|
|
2012-10-25 21:29:49 +00:00
|
|
|
StartPerformanceCounter(PCNT_UPDATE_GAME);
|
2013-06-16 19:39:21 +00:00
|
|
|
m_robotMain->ProcessEvent(event);
|
2012-10-25 21:29:49 +00:00
|
|
|
StopPerformanceCounter(PCNT_UPDATE_GAME);
|
2014-01-18 20:35:32 +00:00
|
|
|
|
|
|
|
StartPerformanceCounter(PCNT_UPDATE_ENGINE);
|
|
|
|
m_engine->FrameUpdate();
|
|
|
|
StopPerformanceCounter(PCNT_UPDATE_ENGINE);
|
2012-10-25 18:27:40 +00:00
|
|
|
}
|
|
|
|
|
2012-10-25 21:29:49 +00:00
|
|
|
StopPerformanceCounter(PCNT_UPDATE_ALL);
|
|
|
|
|
2012-08-12 08:45:04 +00:00
|
|
|
/* Update mouse position explicitly right before rendering
|
|
|
|
* because mouse events are usually way behind */
|
|
|
|
UpdateMouse();
|
|
|
|
|
2012-10-25 21:29:49 +00:00
|
|
|
StartPerformanceCounter(PCNT_RENDER_ALL);
|
2012-08-10 21:31:42 +00:00
|
|
|
Render();
|
2012-10-25 21:29:49 +00:00
|
|
|
StopPerformanceCounter(PCNT_RENDER_ALL);
|
|
|
|
|
|
|
|
StopPerformanceCounter(PCNT_ALL);
|
|
|
|
|
|
|
|
UpdatePerformanceCountersData();
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2012-09-20 18:37:37 +00:00
|
|
|
if (m_lowCPU)
|
|
|
|
{
|
|
|
|
usleep(20000); // should still give plenty of fps
|
|
|
|
}
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
|
|
|
|
end:
|
2012-06-26 20:23:05 +00:00
|
|
|
Destroy();
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-26 20:23:05 +00:00
|
|
|
return m_exitCode;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
int CApplication::GetExitCode() const
|
2012-07-04 17:56:22 +00:00
|
|
|
{
|
|
|
|
return m_exitCode;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
const std::string& CApplication::GetErrorMessage() const
|
2012-08-13 21:09:30 +00:00
|
|
|
{
|
|
|
|
return m_errorMessage;
|
|
|
|
}
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
/** The SDL event parsed is stored internally.
|
|
|
|
If event is not available or is not understood, returned event is of type EVENT_NULL. */
|
2012-09-21 22:38:17 +00:00
|
|
|
Event CApplication::ProcessSystemEvent()
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
Event event;
|
2012-07-22 20:05:12 +00:00
|
|
|
|
|
|
|
if (m_private->currentEvent.type == SDL_QUIT)
|
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
event.type = EVENT_SYS_QUIT;
|
2012-07-22 20:05:12 +00:00
|
|
|
}
|
2013-01-03 23:29:19 +00:00
|
|
|
else if (m_private->currentEvent.type == SDL_VIDEORESIZE)
|
2012-09-30 08:56:35 +00:00
|
|
|
{
|
|
|
|
Gfx::GLDeviceConfig newConfig = m_deviceConfig;
|
|
|
|
newConfig.size.x = m_private->currentEvent.resize.w;
|
|
|
|
newConfig.size.y = m_private->currentEvent.resize.h;
|
|
|
|
if (newConfig.size != m_deviceConfig.size)
|
|
|
|
ChangeVideoConfig(newConfig);
|
2013-01-03 23:29:19 +00:00
|
|
|
}
|
2012-07-22 20:05:12 +00:00
|
|
|
else if ( (m_private->currentEvent.type == SDL_KEYDOWN) ||
|
2012-06-29 22:12:04 +00:00
|
|
|
(m_private->currentEvent.type == SDL_KEYUP) )
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
if (m_private->currentEvent.type == SDL_KEYDOWN)
|
|
|
|
event.type = EVENT_KEY_DOWN;
|
|
|
|
else
|
|
|
|
event.type = EVENT_KEY_UP;
|
|
|
|
|
2012-09-19 16:32:18 +00:00
|
|
|
event.key.virt = false;
|
2012-06-30 08:16:52 +00:00
|
|
|
event.key.key = m_private->currentEvent.key.keysym.sym;
|
|
|
|
event.key.unicode = m_private->currentEvent.key.keysym.unicode;
|
2012-09-21 22:38:17 +00:00
|
|
|
|
|
|
|
// Use the occasion to update kmods
|
|
|
|
m_kmodState = m_private->currentEvent.key.keysym.mod;
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
else if ( (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN) ||
|
|
|
|
(m_private->currentEvent.type == SDL_MOUSEBUTTONUP) )
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-09-19 19:23:42 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
else
|
2012-09-19 19:23:42 +00:00
|
|
|
{
|
|
|
|
if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
|
|
|
|
event.type = EVENT_MOUSE_BUTTON_DOWN;
|
|
|
|
else
|
|
|
|
event.type = EVENT_MOUSE_BUTTON_UP;
|
2012-06-29 22:12:04 +00:00
|
|
|
|
2012-09-21 22:38:17 +00:00
|
|
|
event.mouseButton.button = static_cast<MouseButton>(1 << m_private->currentEvent.button.button);
|
|
|
|
|
|
|
|
// Use the occasion to update mouse button state
|
|
|
|
if (m_private->currentEvent.type == SDL_MOUSEBUTTONDOWN)
|
|
|
|
m_mouseButtonsState |= event.mouseButton.button;
|
|
|
|
else
|
|
|
|
m_mouseButtonsState &= ~event.mouseButton.button;
|
2012-09-19 19:23:42 +00:00
|
|
|
}
|
2012-09-21 22:38:17 +00:00
|
|
|
|
|
|
|
// Use the occasion to update mouse pos
|
|
|
|
m_mousePos = m_engine->WindowToInterfaceCoords(
|
|
|
|
Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
|
|
|
else if (m_private->currentEvent.type == SDL_MOUSEMOTION)
|
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
event.type = EVENT_MOUSE_MOVE;
|
|
|
|
|
2012-09-21 22:38:17 +00:00
|
|
|
m_mousePos = m_engine->WindowToInterfaceCoords(
|
2012-08-03 21:23:13 +00:00
|
|
|
Math::IntPoint(m_private->currentEvent.button.x, m_private->currentEvent.button.y));
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
else if (m_private->currentEvent.type == SDL_JOYAXISMOTION)
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
event.type = EVENT_JOY_AXIS;
|
|
|
|
|
2012-06-30 08:16:52 +00:00
|
|
|
event.joyAxis.axis = m_private->currentEvent.jaxis.axis;
|
|
|
|
event.joyAxis.value = m_private->currentEvent.jaxis.value;
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
else if ( (m_private->currentEvent.type == SDL_JOYBUTTONDOWN) ||
|
|
|
|
(m_private->currentEvent.type == SDL_JOYBUTTONUP) )
|
2012-06-26 20:23:05 +00:00
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
if (m_private->currentEvent.type == SDL_JOYBUTTONDOWN)
|
|
|
|
event.type = EVENT_JOY_BUTTON_DOWN;
|
|
|
|
else
|
|
|
|
event.type = EVENT_JOY_BUTTON_UP;
|
2012-06-26 20:23:05 +00:00
|
|
|
|
2012-06-30 08:16:52 +00:00
|
|
|
event.joyButton.button = m_private->currentEvent.jbutton.button;
|
2012-06-26 20:23:05 +00:00
|
|
|
}
|
2012-07-29 13:09:53 +00:00
|
|
|
else if (m_private->currentEvent.type == SDL_ACTIVEEVENT)
|
|
|
|
{
|
|
|
|
event.type = EVENT_ACTIVE;
|
|
|
|
|
|
|
|
if (m_private->currentEvent.active.type & SDL_APPINPUTFOCUS)
|
|
|
|
event.active.flags |= ACTIVE_INPUT;
|
|
|
|
if (m_private->currentEvent.active.type & SDL_APPMOUSEFOCUS)
|
|
|
|
event.active.flags |= ACTIVE_MOUSE;
|
|
|
|
if (m_private->currentEvent.active.type & SDL_APPACTIVE)
|
|
|
|
event.active.flags |= ACTIVE_APP;
|
|
|
|
|
|
|
|
event.active.gain = m_private->currentEvent.active.gain == 1;
|
|
|
|
}
|
2012-06-29 22:12:04 +00:00
|
|
|
|
2012-09-19 16:32:18 +00:00
|
|
|
|
2012-09-21 22:38:17 +00:00
|
|
|
if (event.type == EVENT_KEY_DOWN)
|
2012-07-29 13:09:53 +00:00
|
|
|
{
|
2012-09-21 22:38:17 +00:00
|
|
|
if (event.key.key == KEY(KP8))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_NUM_UP;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP2))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_NUM_DOWN;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP4))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_NUM_LEFT;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP6))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_NUM_RIGHT;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP_PLUS))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_NUM_PLUS;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP_MINUS))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_NUM_MINUS;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(PAGEUP))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_PAGE_UP;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(PAGEDOWN))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys |= TRKEY_PAGE_DOWN;
|
2012-09-12 21:43:04 +00:00
|
|
|
}
|
|
|
|
else if (event.type == EVENT_KEY_UP)
|
|
|
|
{
|
2012-09-21 22:38:17 +00:00
|
|
|
if (event.key.key == KEY(KP8))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_NUM_UP;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP2))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_NUM_DOWN;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP4))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_NUM_LEFT;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP6))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_NUM_RIGHT;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP_PLUS))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_NUM_PLUS;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(KP_MINUS))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_NUM_MINUS;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(PAGEUP))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_PAGE_UP;
|
2012-09-12 21:43:04 +00:00
|
|
|
else if (event.key.key == KEY(PAGEDOWN))
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys &= ~TRKEY_PAGE_DOWN;
|
2012-09-12 21:43:04 +00:00
|
|
|
}
|
2012-09-21 22:38:17 +00:00
|
|
|
|
|
|
|
event.trackedKeysState = m_trackedKeys;
|
|
|
|
event.kmodState = m_kmodState;
|
|
|
|
event.mousePos = m_mousePos;
|
|
|
|
event.mouseButtonsState = m_mouseButtonsState;
|
|
|
|
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
void CApplication::LogEvent(const Event &event)
|
2012-09-21 22:38:17 +00:00
|
|
|
{
|
|
|
|
CLogger *l = GetLogger();
|
2012-07-29 13:09:53 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
auto PrintEventDetails = [&]()
|
2012-06-29 22:12:04 +00:00
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
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);
|
2013-06-16 19:39:21 +00:00
|
|
|
l->Trace(" customParam = %d\n", event.customParam);
|
|
|
|
};
|
2012-07-22 20:05:12 +00:00
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
// Print the events in debug mode to test the code
|
|
|
|
if (IsDebugModeActive(DEBUG_SYS_EVENTS) || IsDebugModeActive(DEBUG_APP_EVENTS))
|
|
|
|
{
|
|
|
|
std::string eventType = ParseEventType(event.type);
|
|
|
|
|
|
|
|
if (IsDebugModeActive(DEBUG_SYS_EVENTS) && event.type <= EVENT_SYS_MAX)
|
|
|
|
{
|
|
|
|
l->Trace("System event %s:\n", eventType.c_str());
|
|
|
|
switch (event.type)
|
|
|
|
{
|
|
|
|
case EVENT_KEY_DOWN:
|
|
|
|
case EVENT_KEY_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_BUTTON_DOWN:
|
|
|
|
case EVENT_MOUSE_BUTTON_UP:
|
|
|
|
l->Trace(" button = %d\n", event.mouseButton.button);
|
|
|
|
break;
|
|
|
|
case EVENT_MOUSE_WHEEL:
|
|
|
|
l->Trace(" dir = %s\n", (event.mouseWheel.dir == WHEEL_DOWN) ? "WHEEL_DOWN" : "WHEEL_UP");
|
|
|
|
break;
|
|
|
|
case EVENT_JOY_AXIS:
|
|
|
|
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->Trace(" button = %d\n", event.joyButton.button);
|
|
|
|
break;
|
|
|
|
case EVENT_ACTIVE:
|
|
|
|
l->Trace(" flags = 0x%x\n", event.active.flags);
|
|
|
|
l->Trace(" gain = %s\n", event.active.gain ? "true" : "false");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
PrintEventDetails();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsDebugModeActive(DEBUG_APP_EVENTS) && event.type > EVENT_SYS_MAX)
|
|
|
|
{
|
|
|
|
l->Trace("App event %s:\n", eventType.c_str());
|
|
|
|
PrintEventDetails();
|
|
|
|
}
|
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2012-09-19 16:32:18 +00:00
|
|
|
|
|
|
|
Event CApplication::CreateVirtualEvent(const Event& sourceEvent)
|
|
|
|
{
|
|
|
|
Event virtualEvent;
|
|
|
|
|
|
|
|
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;
|
2012-09-21 22:38:17 +00:00
|
|
|
|
2012-09-19 16:32:18 +00:00
|
|
|
virtualEvent.key.virt = true;
|
|
|
|
virtualEvent.key.key = VIRTUAL_JOY(sourceEvent.joyButton.button);
|
|
|
|
virtualEvent.key.unicode = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
virtualEvent.type = EVENT_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return virtualEvent;
|
|
|
|
}
|
|
|
|
|
2012-08-10 21:31:42 +00:00
|
|
|
/** Renders the frame and swaps buffers as necessary */
|
|
|
|
void CApplication::Render()
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-08-10 21:31:42 +00:00
|
|
|
m_engine->Render();
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
if (m_deviceConfig.doubleBuf)
|
2012-06-26 20:23:05 +00:00
|
|
|
SDL_GL_SwapBuffers();
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2012-09-12 21:43:04 +00:00
|
|
|
void CApplication::SuspendSimulation()
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-09-12 21:43:04 +00:00
|
|
|
m_simulationSuspended = true;
|
|
|
|
GetLogger()->Info("Suspend simulation\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::ResumeSimulation()
|
|
|
|
{
|
|
|
|
m_simulationSuspended = false;
|
2013-06-13 15:25:58 +00:00
|
|
|
InternalResumeSimulation();
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2013-06-13 15:25:58 +00:00
|
|
|
GetLogger()->Info("Resume simulation\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::ResetTimeAfterLoading()
|
|
|
|
{
|
|
|
|
InternalResumeSimulation();
|
|
|
|
|
|
|
|
GetLogger()->Trace("Resume simulation on loading\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::InternalResumeSimulation()
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_baseTimeStamp);
|
|
|
|
GetSystemUtils()->CopyTimeStamp(m_curTimeStamp, m_baseTimeStamp);
|
2012-09-12 21:43:04 +00:00
|
|
|
m_realAbsTimeBase = m_realAbsTime;
|
|
|
|
m_absTimeBase = m_exactAbsTime;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetSimulationSuspended() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_simulationSuspended;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::SetSimulationSpeed(float speed)
|
|
|
|
{
|
|
|
|
m_simulationSpeed = speed;
|
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_baseTimeStamp);
|
2012-09-12 21:43:04 +00:00
|
|
|
m_realAbsTimeBase = m_realAbsTime;
|
|
|
|
m_absTimeBase = m_exactAbsTime;
|
|
|
|
|
|
|
|
GetLogger()->Info("Simulation speed = %.2f\n", speed);
|
|
|
|
}
|
|
|
|
|
2012-10-25 18:27:40 +00:00
|
|
|
Event CApplication::CreateUpdateEvent()
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
if (m_simulationSuspended)
|
2012-10-25 18:27:40 +00:00
|
|
|
return Event(EVENT_NULL);
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->CopyTimeStamp(m_lastTimeStamp, m_curTimeStamp);
|
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_curTimeStamp);
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
long long absDiff = GetSystemUtils()->TimeStampExactDiff(m_baseTimeStamp, m_curTimeStamp);
|
|
|
|
long long newRealAbsTime = m_realAbsTimeBase + absDiff;
|
|
|
|
long long newRealRelTime = GetSystemUtils()->TimeStampExactDiff(m_lastTimeStamp, m_curTimeStamp);
|
2012-09-12 21:43:04 +00:00
|
|
|
|
2013-03-23 23:03:37 +00:00
|
|
|
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");
|
2013-06-16 19:39:21 +00:00
|
|
|
m_eventQueue->AddEvent(Event(EVENT_SYS_QUIT));
|
2013-03-23 23:03:37 +00:00
|
|
|
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;
|
|
|
|
}
|
2012-09-12 21:43:04 +00:00
|
|
|
|
|
|
|
Event frameEvent(EVENT_FRAME);
|
2012-09-21 22:38:17 +00:00
|
|
|
frameEvent.trackedKeysState = m_trackedKeys;
|
|
|
|
frameEvent.kmodState = m_kmodState;
|
|
|
|
frameEvent.mousePos = m_mousePos;
|
|
|
|
frameEvent.mouseButtonsState = m_mouseButtonsState;
|
2012-09-12 21:43:04 +00:00
|
|
|
frameEvent.rTime = m_relTime;
|
2012-10-25 18:27:40 +00:00
|
|
|
|
|
|
|
return frameEvent;
|
2012-09-12 21:43:04 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
float CApplication::GetSimulationSpeed() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_simulationSpeed;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
float CApplication::GetAbsTime() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_absTime;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
long long CApplication::GetExactAbsTime() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_exactAbsTime;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
long long CApplication::GetRealAbsTime() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_realAbsTime;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
float CApplication::GetRelTime() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_relTime;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
long long CApplication::GetExactRelTime() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_exactRelTime;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
long long CApplication::GetRealRelTime() const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return m_realRelTime;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
Gfx::GLDeviceConfig CApplication::GetVideoConfig() const
|
2012-08-03 21:23:13 +00:00
|
|
|
{
|
|
|
|
return m_deviceConfig;
|
|
|
|
}
|
|
|
|
|
2012-08-11 15:17:04 +00:00
|
|
|
VideoQueryResult CApplication::GetVideoResolutionList(std::vector<Math::IntPoint> &resolutions,
|
2013-05-26 12:50:23 +00:00
|
|
|
bool fullScreen, bool resizeable) const
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-07-29 13:09:53 +00:00
|
|
|
resolutions.clear();
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-07-29 13:09:53 +00:00
|
|
|
const SDL_VideoInfo *videoInfo = SDL_GetVideoInfo();
|
2012-09-09 15:51:10 +00:00
|
|
|
if (videoInfo == nullptr)
|
2012-07-29 13:09:53 +00:00
|
|
|
return VIDEO_QUERY_ERROR;
|
|
|
|
|
|
|
|
Uint32 videoFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE;
|
|
|
|
|
|
|
|
// Use hardware surface if available
|
|
|
|
if (videoInfo->hw_available)
|
|
|
|
videoFlags |= SDL_HWSURFACE;
|
|
|
|
else
|
|
|
|
videoFlags |= SDL_SWSURFACE;
|
|
|
|
|
|
|
|
// Enable hardware blit if available
|
|
|
|
if (videoInfo->blit_hw)
|
|
|
|
videoFlags |= SDL_HWACCEL;
|
|
|
|
|
|
|
|
if (resizeable)
|
|
|
|
videoFlags |= SDL_RESIZABLE;
|
|
|
|
|
|
|
|
if (fullScreen)
|
|
|
|
videoFlags |= SDL_FULLSCREEN;
|
|
|
|
|
|
|
|
|
|
|
|
SDL_Rect **modes = SDL_ListModes(NULL, videoFlags);
|
|
|
|
|
2012-07-30 20:59:18 +00:00
|
|
|
if (modes == reinterpret_cast<SDL_Rect **>(0) )
|
2012-07-29 13:09:53 +00:00
|
|
|
return VIDEO_QUERY_NONE; // no modes available
|
|
|
|
|
2012-07-30 20:59:18 +00:00
|
|
|
if (modes == reinterpret_cast<SDL_Rect **>(-1) )
|
2012-07-29 13:09:53 +00:00
|
|
|
return VIDEO_QUERY_ALL; // all resolutions are possible
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; modes[i] != NULL; ++i)
|
2012-08-11 15:17:04 +00:00
|
|
|
resolutions.push_back(Math::IntPoint(modes[i]->w, modes[i]->h));
|
2012-07-29 13:09:53 +00:00
|
|
|
|
|
|
|
return VIDEO_QUERY_OK;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
void CApplication::SetDebugModeActive(DebugMode mode, bool active)
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
if (active)
|
|
|
|
m_debugModes |= mode;
|
|
|
|
else
|
|
|
|
m_debugModes &= (~mode);
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-06-16 19:39:21 +00:00
|
|
|
bool CApplication::IsDebugModeActive(DebugMode mode) const
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2013-06-16 19:39:21 +00:00
|
|
|
return (m_debugModes & mode) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CApplication::ParseDebugModes(const std::string& str, int& debugModes)
|
|
|
|
{
|
|
|
|
debugModes = 0;
|
|
|
|
|
|
|
|
boost::char_separator<char> sep(",");
|
|
|
|
boost::tokenizer<boost::char_separator<char>> tokens(str, sep);
|
|
|
|
for (const auto& modeToken : tokens)
|
|
|
|
{
|
|
|
|
if (modeToken == "sys_events")
|
|
|
|
{
|
|
|
|
debugModes |= DEBUG_SYS_EVENTS;
|
|
|
|
}
|
|
|
|
else if (modeToken == "app_events")
|
|
|
|
{
|
|
|
|
debugModes |= DEBUG_APP_EVENTS;
|
|
|
|
}
|
|
|
|
else if (modeToken == "events")
|
|
|
|
{
|
|
|
|
debugModes |= DEBUG_EVENTS;
|
|
|
|
}
|
|
|
|
else if (modeToken == "models")
|
|
|
|
{
|
|
|
|
debugModes |= DEBUG_MODELS;
|
|
|
|
}
|
|
|
|
else if (modeToken == "all")
|
|
|
|
{
|
|
|
|
debugModes = DEBUG_ALL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GetLogger()->Error("Invalid debug mode: '%s'\n", modeToken.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
int CApplication::GetKmods() const
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-09-12 21:43:04 +00:00
|
|
|
return m_kmodState;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetKmodState(int kmod) const
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-09-12 21:43:04 +00:00
|
|
|
return (m_kmodState & kmod) != 0;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetTrackedKeyState(TrackedKey key) const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
2012-09-19 16:32:18 +00:00
|
|
|
return (m_trackedKeys & key) != 0;
|
2012-09-12 21:43:04 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetMouseButtonState(int index) const
|
2012-09-12 21:43:04 +00:00
|
|
|
{
|
|
|
|
return (m_mouseButtonsState & (1<<index)) != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::ResetKeyStates()
|
|
|
|
{
|
2013-04-01 10:57:31 +00:00
|
|
|
GetLogger()->Trace("Reset key states\n");
|
2012-09-19 16:32:18 +00:00
|
|
|
m_trackedKeys = 0;
|
2012-09-12 21:43:04 +00:00
|
|
|
m_kmodState = 0;
|
2012-09-19 19:23:42 +00:00
|
|
|
m_robotMain->ResetKeyStates();
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2012-07-22 20:05:12 +00:00
|
|
|
void CApplication::SetGrabInput(bool grab)
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-07-22 20:05:12 +00:00
|
|
|
SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF);
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetGrabInput() const
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-07-22 20:05:12 +00:00
|
|
|
int result = SDL_WM_GrabInput(SDL_GRAB_QUERY);
|
|
|
|
return result == SDL_GRAB_ON;
|
|
|
|
}
|
|
|
|
|
2012-09-20 18:37:37 +00:00
|
|
|
void CApplication::SetMouseMode(MouseMode mode)
|
2012-07-22 20:05:12 +00:00
|
|
|
{
|
2012-09-20 18:37:37 +00:00
|
|
|
m_mouseMode = mode;
|
|
|
|
if ((m_mouseMode == MOUSE_SYSTEM) || (m_mouseMode == MOUSE_BOTH))
|
|
|
|
SDL_ShowCursor(SDL_ENABLE);
|
|
|
|
else
|
|
|
|
SDL_ShowCursor(SDL_DISABLE);
|
2012-07-22 20:05:12 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
MouseMode CApplication::GetMouseMode() const
|
2012-07-22 20:05:12 +00:00
|
|
|
{
|
2012-09-20 18:37:37 +00:00
|
|
|
return m_mouseMode;
|
2012-07-22 20:05:12 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
Math::Point CApplication::GetMousePos() const
|
2012-07-22 20:05:12 +00:00
|
|
|
{
|
2012-09-20 18:37:37 +00:00
|
|
|
return m_mousePos;
|
2012-07-22 20:05:12 +00:00
|
|
|
}
|
|
|
|
|
2012-09-20 18:37:37 +00:00
|
|
|
void CApplication::MoveMouse(Math::Point pos)
|
2012-07-22 20:05:12 +00:00
|
|
|
{
|
2012-09-20 18:37:37 +00:00
|
|
|
m_mousePos = pos;
|
|
|
|
|
|
|
|
Math::IntPoint windowPos = m_engine->InterfaceToWindowCoords(pos);
|
|
|
|
SDL_WarpMouse(windowPos.x, windowPos.y);
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
std::vector<JoystickDevice> CApplication::GetJoystickList() const
|
2012-07-29 13:09:53 +00:00
|
|
|
{
|
|
|
|
std::vector<JoystickDevice> result;
|
|
|
|
|
|
|
|
int count = SDL_NumJoysticks();
|
|
|
|
|
|
|
|
for (int index = 0; index < count; ++index)
|
|
|
|
{
|
|
|
|
JoystickDevice device;
|
|
|
|
device.index = index;
|
|
|
|
device.name = SDL_JoystickName(index);
|
|
|
|
result.push_back(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
JoystickDevice CApplication::GetJoystick() const
|
2012-07-29 13:09:53 +00:00
|
|
|
{
|
|
|
|
return m_joystick;
|
|
|
|
}
|
|
|
|
|
2012-06-29 22:12:04 +00:00
|
|
|
void CApplication::SetJoystickEnabled(bool enable)
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
m_joystickEnabled = enable;
|
2012-06-25 17:59:17 +00:00
|
|
|
|
2012-06-29 22:12:04 +00:00
|
|
|
if (m_joystickEnabled)
|
|
|
|
{
|
|
|
|
if (! OpenJoystick())
|
|
|
|
{
|
|
|
|
m_joystickEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CloseJoystick();
|
|
|
|
}
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetJoystickEnabled() const
|
2012-06-25 17:59:17 +00:00
|
|
|
{
|
2012-06-29 22:12:04 +00:00
|
|
|
return m_joystickEnabled;
|
2012-06-25 17:59:17 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
Language CApplication::GetLanguage() const
|
2012-09-09 15:51:10 +00:00
|
|
|
{
|
|
|
|
return m_language;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
char CApplication::GetLanguageChar() const
|
2012-12-28 22:06:12 +00:00
|
|
|
{
|
|
|
|
char langChar = 'E';
|
|
|
|
switch (m_language)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case LANGUAGE_ENV:
|
|
|
|
case LANGUAGE_ENGLISH:
|
|
|
|
langChar = 'E';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_GERMAN:
|
|
|
|
langChar = 'D';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_FRENCH:
|
|
|
|
langChar = 'F';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_POLISH:
|
|
|
|
langChar = 'P';
|
|
|
|
break;
|
2013-11-07 13:44:12 +00:00
|
|
|
|
|
|
|
case LANGUAGE_RUSSIAN:
|
|
|
|
langChar = 'R';
|
|
|
|
break;
|
2012-12-28 22:06:12 +00:00
|
|
|
}
|
|
|
|
return langChar;
|
|
|
|
}
|
|
|
|
|
2013-03-10 14:44:21 +00:00
|
|
|
bool CApplication::ParseLanguage(const std::string& str, Language& language)
|
|
|
|
{
|
|
|
|
if (str == "en")
|
|
|
|
{
|
|
|
|
language = LANGUAGE_ENGLISH;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (str == "de")
|
|
|
|
{
|
|
|
|
language = LANGUAGE_GERMAN;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (str == "fr")
|
|
|
|
{
|
|
|
|
language = LANGUAGE_FRENCH;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (str == "pl")
|
|
|
|
{
|
|
|
|
language = LANGUAGE_POLISH;
|
|
|
|
return true;
|
|
|
|
}
|
2013-11-07 13:44:12 +00:00
|
|
|
else if (str == "ru")
|
|
|
|
{
|
|
|
|
language = LANGUAGE_RUSSIAN;
|
|
|
|
return true;
|
|
|
|
}
|
2013-03-10 14:44:21 +00:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-09 15:51:10 +00:00
|
|
|
void CApplication::SetLanguage(Language language)
|
|
|
|
{
|
|
|
|
m_language = language;
|
2012-12-28 21:31:47 +00:00
|
|
|
|
|
|
|
/* Gettext initialization */
|
|
|
|
|
|
|
|
std::string locale = "";
|
|
|
|
switch (m_language)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
case LANGUAGE_ENV:
|
|
|
|
locale = "";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_ENGLISH:
|
|
|
|
locale = "en_US.utf8";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_GERMAN:
|
|
|
|
locale = "de_DE.utf8";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_FRENCH:
|
|
|
|
locale = "fr_FR.utf8";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LANGUAGE_POLISH:
|
|
|
|
locale = "pl_PL.utf8";
|
|
|
|
break;
|
2013-11-07 13:44:12 +00:00
|
|
|
|
|
|
|
case LANGUAGE_RUSSIAN:
|
|
|
|
locale = "ru_RU.utf8";
|
|
|
|
break;
|
2012-12-28 21:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (locale.empty())
|
|
|
|
{
|
2013-06-24 11:07:33 +00:00
|
|
|
const char* envLang = gl_locale_name(LC_MESSAGES, "LC_MESSAGES");
|
2013-01-05 22:03:26 +00:00
|
|
|
if (envLang == NULL)
|
|
|
|
{
|
2013-05-03 20:23:36 +00:00
|
|
|
GetLogger()->Error("Failed to get language from environment, setting default language\n");
|
2013-01-05 22:03:26 +00:00
|
|
|
m_language = LANGUAGE_ENGLISH;
|
|
|
|
}
|
2013-06-24 11:07:33 +00:00
|
|
|
else
|
2012-12-28 22:06:12 +00:00
|
|
|
{
|
2013-06-24 11:07:33 +00:00
|
|
|
GetLogger()->Trace("gl_locale_name: '%s'\n", envLang);
|
|
|
|
|
|
|
|
if (strncmp(envLang,"en",2) == 0)
|
|
|
|
{
|
|
|
|
m_language = LANGUAGE_ENGLISH;
|
|
|
|
}
|
|
|
|
else if (strncmp(envLang,"de",2) == 0)
|
|
|
|
{
|
|
|
|
m_language = LANGUAGE_GERMAN;
|
|
|
|
}
|
|
|
|
else if (strncmp(envLang,"fr",2) == 0)
|
|
|
|
{
|
|
|
|
m_language = LANGUAGE_FRENCH;
|
|
|
|
}
|
|
|
|
else if (strncmp(envLang,"pl",2) == 0)
|
|
|
|
{
|
|
|
|
m_language = LANGUAGE_POLISH;
|
|
|
|
}
|
2013-11-07 13:44:12 +00:00
|
|
|
else if (strncmp(envLang,"ru",2) == 0)
|
|
|
|
{
|
|
|
|
m_language = LANGUAGE_RUSSIAN;
|
|
|
|
}
|
2013-06-24 11:07:33 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
GetLogger()->Warn("Enviromnent locale ('%s') is not supported, setting default language\n", envLang);
|
|
|
|
m_language = LANGUAGE_ENGLISH;
|
|
|
|
}
|
2012-12-28 22:06:12 +00:00
|
|
|
}
|
2012-12-28 21:31:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::string langStr = "LANGUAGE=";
|
|
|
|
langStr += locale;
|
|
|
|
strcpy(S_LANGUAGE, langStr.c_str());
|
|
|
|
putenv(S_LANGUAGE);
|
|
|
|
GetLogger()->Trace("SetLanguage: Set LANGUAGE=%s in environment\n", locale.c_str());
|
|
|
|
}
|
2013-06-24 11:07:33 +00:00
|
|
|
|
2012-12-28 21:31:47 +00:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
|
2013-03-28 14:59:13 +00:00
|
|
|
bindtextdomain("colobot", m_langPath.c_str());
|
2012-12-28 21:31:47 +00:00
|
|
|
bind_textdomain_codeset("colobot", "UTF-8");
|
|
|
|
textdomain("colobot");
|
|
|
|
|
|
|
|
GetLogger()->Debug("SetLanguage: Test gettext translation: '%s'\n", gettext("Colobot rules!"));
|
2012-09-09 15:51:10 +00:00
|
|
|
}
|
2012-09-20 18:37:37 +00:00
|
|
|
|
|
|
|
void CApplication::SetLowCPU(bool low)
|
|
|
|
{
|
|
|
|
m_lowCPU = low;
|
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
bool CApplication::GetLowCPU() const
|
2012-09-20 18:37:37 +00:00
|
|
|
{
|
|
|
|
return m_lowCPU;
|
|
|
|
}
|
2012-10-25 21:29:49 +00:00
|
|
|
|
|
|
|
void CApplication::StartPerformanceCounter(PerformanceCounter counter)
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_performanceCounters[counter][0]);
|
2012-10-25 21:29:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::StopPerformanceCounter(PerformanceCounter counter)
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
GetSystemUtils()->GetCurrentTimeStamp(m_performanceCounters[counter][1]);
|
2012-10-25 21:29:49 +00:00
|
|
|
}
|
|
|
|
|
2013-05-26 12:50:23 +00:00
|
|
|
float CApplication::GetPerformanceCounterData(PerformanceCounter counter) const
|
2012-10-25 21:29:49 +00:00
|
|
|
{
|
|
|
|
return m_performanceCountersData[counter];
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::ResetPerformanceCounters()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < PCNT_MAX; ++i)
|
|
|
|
{
|
|
|
|
StartPerformanceCounter(static_cast<PerformanceCounter>(i));
|
|
|
|
StopPerformanceCounter(static_cast<PerformanceCounter>(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CApplication::UpdatePerformanceCountersData()
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
long long sum = GetSystemUtils()->TimeStampExactDiff(m_performanceCounters[PCNT_ALL][0],
|
|
|
|
m_performanceCounters[PCNT_ALL][1]);
|
2012-10-25 21:29:49 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < PCNT_MAX; ++i)
|
|
|
|
{
|
2013-03-23 23:03:37 +00:00
|
|
|
long long diff = GetSystemUtils()->TimeStampExactDiff(m_performanceCounters[i][0],
|
|
|
|
m_performanceCounters[i][1]);
|
2012-10-25 21:29:49 +00:00
|
|
|
|
|
|
|
m_performanceCountersData[static_cast<PerformanceCounter>(i)] =
|
|
|
|
static_cast<float>(diff) / static_cast<float>(sum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-26 21:13:04 +00:00
|
|
|
bool CApplication::GetSceneTestMode()
|
|
|
|
{
|
|
|
|
return m_sceneTest;
|
|
|
|
}
|