2014-10-14 13:11:37 +00:00
/*
* This file is part of the Colobot : Gold Edition source code
2016-02-13 13:11:30 +00:00
* Copyright ( C ) 2001 - 2016 , Daniel Roux , EPSITEC SA & TerranovaTeam
2015-08-22 14:40:02 +00:00
* http : //epsitec.ch; http://colobot.info; http://github.com/colobot
2014-10-14 13:11:37 +00:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
* See the GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see http : //gnu.org/licenses
*/
2012-06-22 14:31:55 +00:00
# include "app/app.h"
2014-12-22 09:35:05 +00:00
# include "app/controller.h"
2014-12-11 18:01:57 +00:00
# include "app/input.h"
2016-04-04 20:28:08 +00:00
# include "app/pathman.h"
2012-06-25 17:59:17 +00:00
# include "app/system.h"
2012-09-20 18:37:37 +00:00
2015-08-15 12:02:07 +00:00
# include "common/config_file.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"
2015-08-02 11:09:48 +00:00
# include "common/logger.h"
2015-07-17 17:22:31 +00:00
# include "common/make_unique.h"
2013-06-16 19:39:21 +00:00
# include "common/stringutils.h"
2015-10-03 20:05:14 +00:00
# include "common/version.h"
2015-08-02 11:09:48 +00:00
2014-06-20 21:41:38 +00:00
# include "common/resources/resourcemanager.h"
2012-09-20 18:37:37 +00:00
2014-10-31 19:05:06 +00:00
# include "graphics/core/nulldevice.h"
2015-08-02 11:09:48 +00:00
2015-06-15 18:20:03 +00:00
# include "graphics/opengl/glutil.h"
2012-09-20 18:37:37 +00:00
2015-08-13 09:47:32 +00:00
# include "level/robotmain.h"
2012-06-22 14:31:55 +00:00
2015-10-03 20:05:14 +00:00
# include "object/object_manager.h"
2016-03-30 20:22:22 +00:00
# include "sound/sound.h"
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>
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
2015-08-06 08:12:20 +00:00
char CApplication : : m_languageLocale [ ] = { 0 } ;
2012-09-19 16:32:18 +00:00
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
{
2015-09-24 19:09:46 +00:00
//! Main game window
SDL_Window * window ;
//! Main game OpenGL context
SDL_GLContext glcontext ;
2012-06-26 20:23:05 +00:00
//! 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 ;
2015-09-26 22:34:03 +00:00
//! Haptic subsystem for the joystick
SDL_Haptic * haptic ;
2012-06-26 20:23:05 +00:00
ApplicationPrivate ( )
{
2015-08-06 07:33:37 +00:00
SDL_memset ( & currentEvent , 0 , sizeof ( SDL_Event ) ) ;
SDL_memset ( & lastMouseMotionEvent , 0 , sizeof ( SDL_Event ) ) ;
2015-09-24 19:09:46 +00:00
window = nullptr ;
2015-09-25 17:49:50 +00:00
glcontext = nullptr ;
2012-09-09 15:51:10 +00:00
joystick = nullptr ;
2015-09-24 19:09:46 +00:00
joystickTimer = 0 ;
2015-09-26 22:34:03 +00:00
haptic = nullptr ;
2012-06-26 20:23:05 +00:00
}
2012-06-25 17:59:17 +00:00
} ;
2012-06-30 10:26:40 +00:00
2015-08-07 06:31:34 +00:00
CApplication : : CApplication ( CSystemUtils * systemUtils )
: m_systemUtils ( systemUtils ) ,
m_private ( MakeUnique < ApplicationPrivate > ( ) ) ,
m_configFile ( MakeUnique < CConfigFile > ( ) ) ,
m_input ( MakeUnique < CInput > ( ) ) ,
m_pathManager ( MakeUnique < CPathManager > ( systemUtils ) ) ,
m_performanceCounters ( ) ,
m_performanceCountersData ( )
2012-06-25 17:59:17 +00:00
{
2014-12-22 09:35:05 +00:00
m_exitCode = 0 ;
m_active = false ;
m_debugModes = 0 ;
2012-06-25 17:59:17 +00:00
2014-11-01 18:46:06 +00:00
m_windowTitle = " Colobot: Gold Edition " ;
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 ;
2015-08-07 06:31:34 +00:00
m_baseTimeStamp = m_systemUtils - > CreateTimeStamp ( ) ;
m_curTimeStamp = m_systemUtils - > CreateTimeStamp ( ) ;
m_lastTimeStamp = m_systemUtils - > CreateTimeStamp ( ) ;
2012-09-12 21:43:04 +00:00
2015-08-13 22:07:45 +00:00
m_manualFrameLast = m_systemUtils - > CreateTimeStamp ( ) ;
m_manualFrameTime = m_systemUtils - > CreateTimeStamp ( ) ;
2012-10-25 21:29:49 +00:00
for ( int i = 0 ; i < PCNT_MAX ; + + i )
{
2015-08-07 06:31:34 +00:00
m_performanceCounters [ i ] [ 0 ] = m_systemUtils - > CreateTimeStamp ( ) ;
m_performanceCounters [ i ] [ 1 ] = m_systemUtils - > 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 ;
2015-07-18 16:52:37 +00:00
m_runSceneCategory = LevelCategory : : Max ;
2013-06-16 19:39:21 +00:00
m_runSceneRank = 0 ;
2014-09-07 17:26:06 +00:00
2013-12-26 21:13:04 +00:00
m_sceneTest = false ;
2014-10-31 19:05:06 +00:00
m_headless = false ;
2014-08-28 11:08:10 +00:00
m_resolutionOverride = false ;
2013-06-16 19:39:21 +00:00
2012-12-14 10:17:42 +00:00
m_language = LANGUAGE_ENV ;
2012-06-25 17:59:17 +00:00
}
CApplication : : ~ CApplication ( )
{
2015-08-07 06:31:34 +00:00
m_systemUtils - > DestroyTimeStamp ( m_baseTimeStamp ) ;
m_systemUtils - > DestroyTimeStamp ( m_curTimeStamp ) ;
m_systemUtils - > DestroyTimeStamp ( m_lastTimeStamp ) ;
2012-10-25 21:29:49 +00:00
2015-08-13 22:07:45 +00:00
m_systemUtils - > DestroyTimeStamp ( m_manualFrameLast ) ;
m_systemUtils - > DestroyTimeStamp ( m_manualFrameTime ) ;
2012-10-25 21:29:49 +00:00
for ( int i = 0 ; i < PCNT_MAX ; + + i )
{
2015-08-07 06:31:34 +00:00
m_systemUtils - > DestroyTimeStamp ( m_performanceCounters [ i ] [ 0 ] ) ;
m_systemUtils - > DestroyTimeStamp ( m_performanceCounters [ i ] [ 1 ] ) ;
2012-10-25 21:29:49 +00:00
}
2015-08-07 06:31:34 +00:00
m_joystickEnabled = false ;
m_controller . reset ( ) ;
m_sound . reset ( ) ;
if ( m_engine ! = nullptr )
{
m_engine - > Destroy ( ) ;
m_engine . reset ( ) ;
}
if ( m_device ! = nullptr )
{
m_device - > Destroy ( ) ;
m_device . reset ( ) ;
}
if ( m_private - > joystick ! = nullptr )
{
SDL_JoystickClose ( m_private - > joystick ) ;
m_private - > joystick = nullptr ;
}
2015-09-24 19:09:46 +00:00
if ( m_private - > glcontext ! = nullptr )
2015-08-07 06:31:34 +00:00
{
2015-09-24 19:09:46 +00:00
SDL_GL_DeleteContext ( m_private - > glcontext ) ;
m_private - > glcontext = nullptr ;
}
if ( m_private - > window ! = nullptr )
{
SDL_DestroyWindow ( m_private - > window ) ;
m_private - > window = nullptr ;
2015-08-07 06:31:34 +00:00
}
IMG_Quit ( ) ;
if ( SDL_WasInit ( 0 ) )
SDL_Quit ( ) ;
2012-06-25 17:59:17 +00:00
}
2013-02-16 21:37:43 +00:00
CEventQueue * CApplication : : GetEventQueue ( )
{
2015-06-25 22:24:05 +00:00
return m_eventQueue . get ( ) ;
2013-02-16 21:37:43 +00:00
}
CSoundInterface * CApplication : : GetSound ( )
{
2015-06-25 22:24:05 +00:00
return m_sound . get ( ) ;
2013-02-16 21:37:43 +00:00
}
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 ,
2013-03-28 14:59:13 +00:00
OPT_LANGDIR ,
2013-06-16 19:39:21 +00:00
OPT_DATADIR ,
2014-08-06 10:27:17 +00:00
OPT_SAVEDIR ,
2014-05-18 10:12:47 +00:00
OPT_MOD ,
2014-10-31 19:05:06 +00:00
OPT_RESOLUTION ,
2015-05-19 12:29:31 +00:00
OPT_HEADLESS ,
2016-02-15 22:08:56 +00:00
OPT_DEVICE ,
OPT_OPENGL_VERSION ,
OPT_OPENGL_PROFILE
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 } ,
2013-03-28 14:59:13 +00:00
{ " langdir " , required_argument , nullptr , OPT_LANGDIR } ,
2013-06-16 19:39:21 +00:00
{ " datadir " , required_argument , nullptr , OPT_DATADIR } ,
2014-08-06 10:27:17 +00:00
{ " savedir " , required_argument , nullptr , OPT_SAVEDIR } ,
2014-05-18 10:12:47 +00:00
{ " mod " , required_argument , nullptr , OPT_MOD } ,
2014-08-28 11:08:10 +00:00
{ " resolution " , required_argument , nullptr , OPT_RESOLUTION } ,
2014-10-31 19:05:06 +00:00
{ " headless " , no_argument , nullptr , OPT_HEADLESS } ,
2015-05-19 12:29:31 +00:00
{ " graphics " , required_argument , nullptr , OPT_DEVICE } ,
2016-02-15 22:08:56 +00:00
{ " glversion " , required_argument , nullptr , OPT_OPENGL_VERSION } ,
{ " glprofile " , required_argument , nullptr , OPT_OPENGL_PROFILE } ,
2013-05-26 08:23:30 +00:00
{ nullptr , 0 , nullptr , 0 }
2013-03-10 14:44:21 +00:00
} ;
opterr = 0 ;
2015-06-26 16:51:39 +00:00
optind = 1 ;
2013-03-10 14:44:21 +00:00
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 " ) ;
2014-12-11 18:59:24 +00:00
GetLogger ( ) - > Message ( " %s \n " , COLOBOT_FULLNAME ) ;
2013-03-10 14:44:21 +00:00
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 " ) ;
GetLogger ( ) - > Message ( " -langdir path set custom language directory path \n " ) ;
2014-08-06 10:27:17 +00:00
GetLogger ( ) - > Message ( " -datadir path set custom data directory path \n " ) ;
GetLogger ( ) - > Message ( " -savedir path set custom save directory path (must be writable) \n " ) ;
2014-07-24 20:46:47 +00:00
GetLogger ( ) - > Message ( " -mod path load datadir mod from given path \n " ) ;
2014-08-28 11:08:10 +00:00
GetLogger ( ) - > Message ( " -resolution WxH set resolution \n " ) ;
2014-10-31 19:05:06 +00:00
GetLogger ( ) - > Message ( " -headless headless mode - disables graphics, sound and user interaction \n " ) ;
2016-02-27 14:25:23 +00:00
GetLogger ( ) - > Message ( " -graphics changes graphics device (one of: default, auto, opengl, gl14, gl21, gl33 \n " ) ;
2016-02-15 22:08:56 +00:00
GetLogger ( ) - > Message ( " -glversion sets OpenGL context version to use (either default or version in format #.#) \n " ) ;
GetLogger ( ) - > Message ( " -glprofile sets OpenGL context profile to use (one of: default, core, compatibility, opengles) \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 ;
2015-07-18 16:52:37 +00:00
std : : string cat = file . substr ( 0 , file . size ( ) - 3 ) ;
m_runSceneCategory = GetLevelCategoryFromDir ( cat ) ;
2013-06-16 19:39:21 +00:00
m_runSceneRank = StrUtils : : FromString < int > ( file . substr ( file . size ( ) - 3 , 3 ) ) ;
2015-08-07 20:37:56 +00:00
if ( m_runSceneCategory ! = LevelCategory : : Max )
2015-07-18 16:52:37 +00:00
{
GetLogger ( ) - > Info ( " Running scene '%s%d' on start \n " , cat . c_str ( ) , m_runSceneRank ) ;
}
else
{
GetLogger ( ) - > Error ( " Requested to run scene from unknown category '%s' \n " , cat . c_str ( ) ) ;
return PARSE_ARGS_FAIL ;
}
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 ;
}
2014-08-06 10:27:17 +00:00
case OPT_DATADIR :
{
2015-03-08 14:22:21 +00:00
m_pathManager - > SetDataPath ( optarg ) ;
2014-08-06 10:27:17 +00:00
GetLogger ( ) - > Info ( " Using data dir: '%s' \n " , optarg ) ;
break ;
}
case OPT_LANGDIR :
{
2015-03-08 14:22:21 +00:00
m_pathManager - > SetLangPath ( optarg ) ;
2014-08-06 10:27:17 +00:00
GetLogger ( ) - > Info ( " Using language dir: '%s' \n " , optarg ) ;
break ;
}
case OPT_SAVEDIR :
{
2015-03-08 14:22:21 +00:00
m_pathManager - > SetSavePath ( optarg ) ;
2014-08-06 10:27:17 +00:00
GetLogger ( ) - > Info ( " Using save dir: '%s' \n " , optarg ) ;
break ;
}
2014-07-24 20:46:47 +00:00
case OPT_MOD :
{
2015-03-08 14:22:21 +00:00
m_pathManager - > AddMod ( optarg ) ;
2014-07-24 20:46:47 +00:00
break ;
}
2014-08-28 11:08:10 +00:00
case OPT_RESOLUTION :
{
std : : istringstream resolution ( optarg ) ;
std : : string w , h ;
std : : getline ( resolution , w , ' x ' ) ;
std : : getline ( resolution , h , ' x ' ) ;
2015-04-27 16:35:41 +00:00
2014-08-28 11:08:10 +00:00
m_deviceConfig . size . x = atoi ( w . c_str ( ) ) ;
m_deviceConfig . size . y = atoi ( h . c_str ( ) ) ;
m_resolutionOverride = true ;
break ;
}
2014-10-31 19:05:06 +00:00
case OPT_HEADLESS :
{
m_headless = true ;
break ;
}
2015-05-19 12:29:31 +00:00
case OPT_DEVICE :
{
m_graphics = optarg ;
2016-02-15 22:08:56 +00:00
m_graphicsOverride = true ;
break ;
}
case OPT_OPENGL_VERSION :
{
if ( strcmp ( optarg , " default " ) = = 0 )
{
m_glMajor = - 1 ;
m_glMinor = - 1 ;
m_glVersionOverride = true ;
}
else
{
int major = 1 , minor = 1 ;
int parsed = sscanf ( optarg , " %d.%d " , & major , & minor ) ;
if ( parsed < 2 )
{
GetLogger ( ) - > Error ( " Invalid OpenGL version: %s \n " , optarg ) ;
return PARSE_ARGS_FAIL ;
}
m_glMajor = major ;
m_glMinor = minor ;
m_glVersionOverride = true ;
}
break ;
}
case OPT_OPENGL_PROFILE :
{
if ( strcmp ( optarg , " default " ) = = 0 )
{
m_glProfile = 0 ;
m_glProfileOverride = true ;
}
else if ( strcmp ( optarg , " core " ) = = 0 )
{
m_glProfile = SDL_GL_CONTEXT_PROFILE_CORE ;
m_glProfileOverride = true ;
}
else if ( strcmp ( optarg , " compatibility " ) = = 0 )
{
m_glProfile = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY ;
m_glProfileOverride = true ;
}
else if ( strcmp ( optarg , " opengles " ) = = 0 )
{
m_glProfile = SDL_GL_CONTEXT_PROFILE_ES ;
m_glProfileOverride = true ;
}
2016-02-17 22:04:34 +00:00
else
{
GetLogger ( ) - > Error ( " Invalid OpenGL profile: %s \n " , optarg ) ;
return PARSE_ARGS_FAIL ;
}
2015-05-19 12:29:31 +00:00
break ;
}
2013-03-10 14:44:21 +00:00
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 ;
2012-08-13 21:09:30 +00:00
GetLogger ( ) - > Info ( " Creating CApplication \n " ) ;
2015-03-08 14:22:21 +00:00
m_errorMessage = m_pathManager - > VerifyPaths ( ) ;
2015-06-25 22:24:05 +00:00
if ( ! m_errorMessage . empty ( ) )
{
2012-09-13 21:28:06 +00:00
m_exitCode = 1 ;
return false ;
}
2015-03-08 14:22:21 +00:00
m_pathManager - > InitPaths ( ) ;
2014-08-06 10:27:17 +00:00
2015-07-19 13:30:30 +00:00
if ( ! GetConfigFile ( ) . Init ( ) )
2014-08-06 10:27:17 +00:00
{
2016-01-24 15:03:24 +00:00
GetLogger ( ) - > Warn ( " Config could not be loaded. Default values will be used! \n " ) ;
2014-08-06 10:27:17 +00:00
}
2012-09-13 21:28:06 +00:00
2016-01-24 15:03:24 +00:00
// Create the sound instance.
2013-05-03 19:34:10 +00:00
# ifdef OPENAL_SOUND
2015-06-25 22:24:05 +00:00
if ( ! m_headless )
{
2015-10-03 20:05:14 +00:00
m_sound = MakeUnique < CALSound > ( ) ;
2015-06-25 22:24:05 +00:00
}
else
{
2015-07-17 17:22:31 +00:00
m_sound = MakeUnique < CSoundInterface > ( ) ;
2014-10-31 19:05:06 +00:00
}
2013-05-03 19:34:10 +00:00
# else
GetLogger ( ) - > Info ( " No sound support. \n " ) ;
2015-07-17 18:57:12 +00:00
m_sound = MakeUnique < CSoundInterface > ( ) ;
2013-05-03 19:34:10 +00:00
# endif
2013-12-19 21:41:16 +00:00
m_sound - > Create ( ) ;
2014-05-18 10:12:47 +00:00
m_sound - > CacheAll ( ) ;
2016-01-24 20:31:45 +00:00
m_sound - > CacheCommonMusic ( ) ;
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 =
" \n Please 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 \n Joystick(s) will not be available \n " ) ;
}
2015-09-26 22:34:03 +00:00
if ( SDL_InitSubSystem ( SDL_INIT_HAPTIC ) < 0 )
{
GetLogger ( ) - > Warn ( " Joystick haptic subsystem init failed \n Force feedback will not be available \n " ) ;
}
2012-09-29 08:40:11 +00:00
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
2015-06-25 22:24:05 +00:00
if ( ! m_headless )
{
2014-10-31 19:05:06 +00:00
// load settings from profile
int iValue ;
2015-03-19 18:42:01 +00:00
std : : string sValue ;
2015-06-28 19:05:12 +00:00
// GetVideoResolutionList() has to be called here because it is responsible
// for list of resolutions in options menu, not calling it results in empty list
std : : vector < Math : : IntPoint > modes ;
2015-09-24 19:09:46 +00:00
GetVideoResolutionList ( modes ) ;
2015-06-28 19:05:12 +00:00
2015-07-19 13:30:30 +00:00
if ( GetConfigFile ( ) . GetStringProperty ( " Setup " , " Resolution " , sValue ) & & ! m_resolutionOverride )
2014-10-31 19:05:06 +00:00
{
2015-03-19 18:42:01 +00:00
std : : istringstream resolution ( sValue ) ;
std : : string ws , hs ;
std : : getline ( resolution , ws , ' x ' ) ;
std : : getline ( resolution , hs , ' x ' ) ;
int w = 800 , h = 600 ;
2015-08-02 09:40:47 +00:00
if ( ! ws . empty ( ) & & ! hs . empty ( ) )
{
2015-03-19 18:42:01 +00:00
w = atoi ( ws . c_str ( ) ) ;
h = atoi ( hs . c_str ( ) ) ;
}
// Why not just set m_deviceConfig.size to w,h? Because this way if the resolution is no longer supported (e.g. changimg monitor) defaults will be used instead
2015-08-02 09:40:47 +00:00
for ( auto it = modes . begin ( ) ; it ! = modes . end ( ) ; + + it )
{
if ( it - > x = = w & & it - > y = = h )
{
2015-03-19 18:42:01 +00:00
m_deviceConfig . size = * it ;
break ;
}
}
2014-10-31 19:05:06 +00:00
}
2013-03-10 14:44:21 +00:00
2015-07-19 13:30:30 +00:00
if ( GetConfigFile ( ) . GetIntProperty ( " Setup " , " Fullscreen " , iValue ) & & ! m_resolutionOverride )
2014-10-31 19:05:06 +00:00
{
m_deviceConfig . fullScreen = ( iValue = = 1 ) ;
}
2013-03-10 14:44:21 +00:00
2014-10-31 19:05:06 +00:00
if ( ! CreateVideoSurface ( ) )
return false ; // dialog is in function
2012-06-25 17:59:17 +00:00
2015-09-24 19:09:46 +00:00
if ( m_private - > window = = nullptr )
2014-10-31 19:05:06 +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 ;
return false ;
}
2012-06-26 20:23:05 +00:00
}
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
2015-07-09 22:02:39 +00:00
// Report joystick list to log, since we still don't have a GUI for them so you have to set the ID manually in the config
auto joysticks = GetJoystickList ( ) ;
bool first = true ;
for ( const auto & joystick : joysticks )
{
if ( first )
{
ChangeJoystick ( joystick ) ;
first = false ;
}
GetLogger ( ) - > Info ( " Detected joystick: %s [ID %d] \n " , joystick . name . c_str ( ) , joystick . index ) ;
}
if ( first )
{
GetLogger ( ) - > Info ( " No joysticks detected \n " ) ;
}
2015-06-25 22:24:05 +00:00
if ( ! m_headless )
2015-05-19 12:29:31 +00:00
{
2016-02-15 22:08:56 +00:00
std : : string graphics = " default " ;
std : : string value ;
if ( m_graphicsOverride )
{
graphics = m_graphics ;
}
else if ( GetConfigFile ( ) . GetStringProperty ( " Experimental " , " GraphicsDevice " , value ) )
{
graphics = value ;
}
m_device = Gfx : : CreateDevice ( m_deviceConfig , graphics . c_str ( ) ) ;
2015-06-15 18:20:03 +00:00
if ( m_device = = nullptr )
2015-05-19 12:29:31 +00:00
{
2016-02-15 22:08:56 +00:00
GetLogger ( ) - > Error ( " Unknown graphics device: %s \n " , graphics . c_str ( ) ) ;
2015-07-18 10:03:33 +00:00
GetLogger ( ) - > Info ( " Changing to default device \n " ) ;
2015-08-07 06:31:34 +00:00
m_systemUtils - > SystemDialog ( SDT_ERROR , " Graphics initialization error " , " You have selected invalid graphics device with -graphics switch. Game will use default OpenGL device instead. " ) ;
2015-07-18 10:03:33 +00:00
m_device = Gfx : : CreateDevice ( m_deviceConfig , " opengl " ) ;
2015-05-19 12:29:31 +00:00
}
}
else
{
2015-07-17 17:22:31 +00:00
m_device = MakeUnique < Gfx : : CNullDevice > ( ) ;
2014-10-31 19:05:06 +00:00
}
2015-05-19 12:29:31 +00:00
2012-07-01 20:59:22 +00:00
if ( ! m_device - > Create ( ) )
{
2015-12-18 20:04:16 +00:00
m_errorMessage = std : : string ( " Error in CDevice::Create() \n " )
+ " \n \n "
+ m_device - > GetError ( )
+ standardInfoMessage ;
2012-08-13 21:09:30 +00:00
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
2015-08-07 06:31:34 +00:00
m_engine = MakeUnique < Gfx : : CEngine > ( this , m_systemUtils ) ;
2012-08-03 21:23:13 +00:00
2015-06-25 22:24:05 +00:00
m_engine - > SetDevice ( m_device . get ( ) ) ;
2012-07-01 20:59:22 +00:00
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
2015-08-04 18:30:31 +00:00
m_eventQueue = MakeUnique < CEventQueue > ( ) ;
2012-09-15 20:19:32 +00:00
// Create the robot application.
2016-01-24 15:03:24 +00:00
m_controller = MakeUnique < CController > ( ) ;
2014-12-22 09:35:05 +00:00
2015-07-18 16:52:37 +00:00
if ( m_runSceneCategory = = LevelCategory : : Max )
2014-12-22 09:35:05 +00:00
m_controller - > StartApp ( ) ;
2015-06-25 22:24:05 +00:00
else
{
2015-08-06 10:59:09 +00:00
m_controller - > GetRobotMain ( ) - > UpdateCustomLevelList ( ) ; // To load the userlevels
2014-12-22 09:35:05 +00:00
m_controller - > GetRobotMain ( ) - > SetExitAfterMission ( true ) ;
2015-07-18 16:52:37 +00:00
m_controller - > StartGame ( m_runSceneCategory , m_runSceneRank / 100 , m_runSceneRank % 100 ) ;
2014-12-22 09:35:05 +00:00
}
2012-08-13 21:09:30 +00:00
2012-07-29 13:09:53 +00:00
return true ;
}
bool CApplication : : CreateVideoSurface ( )
{
2015-09-25 09:11:35 +00:00
Uint32 videoFlags = SDL_WINDOW_OPENGL ;
2012-07-29 13:09:53 +00:00
if ( m_deviceConfig . fullScreen )
2015-09-24 19:09:46 +00:00
videoFlags | = SDL_WINDOW_FULLSCREEN ;
2012-07-29 13:09:53 +00:00
2015-08-24 17:56:50 +00:00
if ( m_deviceConfig . resizeable )
2015-09-24 19:09:46 +00:00
videoFlags | = SDL_WINDOW_RESIZABLE ;
2012-07-29 13:09:53 +00:00
// 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 ) ;
2016-02-15 22:08:56 +00:00
SDL_GL_SetAttribute ( SDL_GL_STENCIL_SIZE , m_deviceConfig . stencilSize ) ;
2012-07-29 13:09:53 +00:00
if ( m_deviceConfig . doubleBuf )
SDL_GL_SetAttribute ( SDL_GL_DOUBLEBUFFER , 1 ) ;
2016-02-15 22:08:56 +00:00
std : : string value ;
// set OpenGL context version
// -glversion switch overrides config settings
if ( m_glVersionOverride )
{
if ( ( m_glMajor > = 0 ) & & ( m_glMinor > = 0 ) )
{
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MAJOR_VERSION , m_glMajor ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MINOR_VERSION , m_glMinor ) ;
GetLogger ( ) - > Info ( " Requesting OpenGL context version %d.%d \n " , m_glMajor , m_glMinor ) ;
}
}
else if ( GetConfigFile ( ) . GetStringProperty ( " Experimental " , " OpenGLVersion " , value ) )
{
int major = 1 , minor = 1 ;
sscanf ( value . c_str ( ) , " %d.%d " , & major , & minor ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MAJOR_VERSION , major ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MINOR_VERSION , minor ) ;
GetLogger ( ) - > Info ( " Requesting OpenGL context version %d.%d \n " , major , minor ) ;
}
// set OpenGL context profile
// -glprofile switch overrides config settings
int profile = 0 ;
if ( m_glProfileOverride )
{
profile = m_glProfile ;
}
else if ( GetConfigFile ( ) . GetStringProperty ( " Experimental " , " OpenGLProfile " , value ) )
{
if ( value = = " core " )
{
profile = SDL_GL_CONTEXT_PROFILE_CORE ;
}
else if ( value = = " compatibility " )
{
profile = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY ;
}
else if ( value = = " opengles " )
{
profile = SDL_GL_CONTEXT_PROFILE_ES ;
}
}
2016-02-27 14:25:23 +00:00
if ( profile ! = 0 )
2016-02-15 22:08:56 +00:00
{
2016-02-27 14:25:23 +00:00
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_PROFILE_MASK , profile ) ;
switch ( profile )
{
case SDL_GL_CONTEXT_PROFILE_CORE :
GetLogger ( ) - > Info ( " Requesting OpenGL core profile \n " ) ;
break ;
case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY :
GetLogger ( ) - > Info ( " Requesting OpenGL compatibility profile \n " ) ;
break ;
case SDL_GL_CONTEXT_PROFILE_ES :
GetLogger ( ) - > Info ( " Requesting OpenGL ES profile \n " ) ;
break ;
}
2016-02-15 22:08:56 +00:00
}
2016-03-14 19:14:16 +00:00
int msaa = 0 ;
if ( GetConfigFile ( ) . GetIntProperty ( " Experimental " , " MSAA " , msaa ) )
{
2016-03-29 11:38:53 +00:00
if ( msaa > 1 )
{
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLEBUFFERS , 1 ) ;
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLESAMPLES , msaa ) ;
2016-03-14 19:14:16 +00:00
2016-03-29 11:38:53 +00:00
GetLogger ( ) - > Info ( " Using MSAA on default framebuffer (%d samples) \n " , msaa ) ;
}
2016-03-14 19:14:16 +00:00
}
2012-07-29 13:09:53 +00:00
/* 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
2015-09-24 19:09:46 +00:00
m_private - > window = SDL_CreateWindow ( m_windowTitle . c_str ( ) ,
SDL_WINDOWPOS_UNDEFINED , SDL_WINDOWPOS_UNDEFINED ,
m_deviceConfig . size . x , m_deviceConfig . size . y ,
videoFlags ) ;
m_private - > glcontext = SDL_GL_CreateContext ( m_private - > window ) ;
2012-06-25 17:59:17 +00:00
2016-03-29 11:38:53 +00:00
int vsync = 0 ;
if ( GetConfigFile ( ) . GetIntProperty ( " Experimental " , " VSync " , vsync ) )
{
SDL_GL_SetSwapInterval ( vsync ) ;
GetLogger ( ) - > Info ( " Using Vsync: %s \n " , ( vsync ? " true " : " false " ) ) ;
}
2012-06-26 20:23:05 +00:00
return true ;
2012-06-25 17:59:17 +00:00
}
2015-06-16 13:31:59 +00:00
bool CApplication : : ChangeVideoConfig ( const Gfx : : DeviceConfig & newConfig )
2012-07-29 13:09:53 +00:00
{
m_deviceConfig = newConfig ;
2015-09-25 09:11:35 +00:00
// TODO: Somehow this doesn't work for maximized windows (at least on Ubuntu)
SDL_SetWindowSize ( m_private - > window , m_deviceConfig . size . x , m_deviceConfig . size . y ) ;
SDL_SetWindowFullscreen ( m_private - > window , m_deviceConfig . fullScreen ? SDL_WINDOW_FULLSCREEN : 0 ) ;
2012-07-29 13:09:53 +00:00
2015-06-16 13:31:59 +00:00
m_device - > ConfigChanged ( m_deviceConfig ) ;
2012-07-29 13:09:53 +00:00
2016-03-26 17:55:39 +00:00
m_eventQueue - > AddEvent ( Event ( EVENT_RESOLUTION_CHANGED ) ) ;
2012-07-29 13:09:53 +00:00
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 ;
2016-01-24 19:48:07 +00:00
assert ( m_private - > joystick = = nullptr ) ;
2015-07-09 22:02:39 +00:00
GetLogger ( ) - > Info ( " Opening joystick %d \n " , m_joystick . index ) ;
2012-07-29 13:09:53 +00:00
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
2015-09-26 22:34:03 +00:00
// Initialize haptic subsystem
m_private - > haptic = SDL_HapticOpenFromJoystick ( m_private - > joystick ) ;
if ( m_private - > haptic = = nullptr )
{
2015-09-27 16:54:02 +00:00
GetLogger ( ) - > Warn ( " Haptic subsystem open failed: %s \n " , SDL_GetError ( ) ) ;
2015-09-26 22:34:03 +00:00
return true ;
}
if ( SDL_HapticRumbleInit ( m_private - > haptic ) ! = 0 )
{
2015-09-27 16:54:02 +00:00
GetLogger ( ) - > Warn ( " Haptic rumble effect init failed: %s \n " , SDL_GetError ( ) ) ;
2015-09-26 22:34:03 +00:00
return true ;
}
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
2015-07-09 22:02:39 +00:00
GetLogger ( ) - > Info ( " Closing joystick \n " ) ;
2015-09-26 22:34:03 +00:00
StopForceFeedbackEffect ( ) ;
SDL_HapticClose ( m_private - > haptic ) ;
m_private - > haptic = nullptr ;
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 ;
2015-07-09 22:02:39 +00:00
m_joystick = newJoystick ;
2012-09-09 15:51:10 +00:00
if ( m_private - > joystick ! = nullptr )
2012-07-29 13:09:53 +00:00
CloseJoystick ( ) ;
2015-07-10 08:28:04 +00:00
if ( m_joystickEnabled )
return OpenJoystick ( ) ;
else
return true ;
2012-07-29 13:09:53 +00:00
}
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 ) ;
2014-12-11 18:01:57 +00:00
m_input - > MouseMove ( 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 ;
2015-08-07 06:31:34 +00:00
m_systemUtils - > GetCurrentTimeStamp ( m_baseTimeStamp ) ;
m_systemUtils - > GetCurrentTimeStamp ( m_lastTimeStamp ) ;
m_systemUtils - > 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
2015-09-24 19:09:46 +00:00
m_private - > currentEvent . type = SDL_LASTEVENT ;
2012-07-22 20:05:12 +00:00
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 ( ) ;
2015-09-24 19:09:46 +00:00
m_private - > lastMouseMotionEvent . type = SDL_LASTEVENT ;
2012-09-22 15:36:10 +00:00
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 )
2015-09-24 19:09:46 +00:00
count = SDL_PeepEvents ( & m_private - > currentEvent , 1 , SDL_GETEVENT , SDL_FIRSTEVENT , SDL_LASTEVENT ) ;
2012-07-22 20:05:12 +00:00
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
2015-08-06 15:51:28 +00:00
Event virtualEvent = CreateVirtualEvent ( event ) ;
2012-07-22 20:05:12 +00:00
if ( event . type ! = EVENT_NULL )
2015-08-06 15:51:28 +00:00
m_eventQueue - > AddEvent ( std : : move ( event ) ) ;
2012-09-19 16:32:18 +00:00
if ( virtualEvent . type ! = EVENT_NULL )
2015-08-06 15:51:28 +00:00
m_eventQueue - > AddEvent ( std : : move ( 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
2015-09-24 19:09:46 +00:00
if ( m_private - > lastMouseMotionEvent . type ! = SDL_LASTEVENT )
2012-09-22 15:36:10 +00:00
{
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 )
2015-08-06 15:51:28 +00:00
m_eventQueue - > AddEvent ( std : : move ( 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
{
2015-08-06 15:51:28 +00:00
while ( ! m_eventQueue - > IsEmpty ( ) )
2012-06-26 20:23:05 +00:00
{
2015-08-06 15:51:28 +00:00
Event event = m_eventQueue - > GetEvent ( ) ;
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
2015-08-09 21:04:24 +00:00
m_input - > EventProcess ( event ) ;
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
2014-12-22 09:35:05 +00:00
if ( passOn & & m_controller ! = nullptr )
m_controller - > 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
2015-08-06 15:51:28 +00:00
Event event = CreateUpdateEvent ( ) ;
2014-12-22 09:35:05 +00:00
if ( event . type ! = EVENT_NULL & & m_controller ! = nullptr )
2012-10-25 18:27:40 +00:00
{
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 ) ;
2014-12-22 09:35:05 +00:00
m_controller - > 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-08-10 21:31:42 +00:00
Render ( ) ;
2012-10-25 21:29:49 +00:00
StopPerformanceCounter ( PCNT_ALL ) ;
UpdatePerformanceCountersData ( ) ;
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
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
}
2015-09-24 19:09:46 +00:00
else if ( m_private - > currentEvent . type = = SDL_WINDOWEVENT )
2012-09-30 08:56:35 +00:00
{
2015-09-25 19:26:49 +00:00
if ( m_private - > currentEvent . window . event = = SDL_WINDOWEVENT_SIZE_CHANGED )
{
2015-09-24 19:09:46 +00:00
Gfx : : DeviceConfig newConfig = m_deviceConfig ;
newConfig . size . x = m_private - > currentEvent . window . data1 ;
newConfig . size . y = m_private - > currentEvent . window . data2 ;
if ( newConfig . size ! = m_deviceConfig . size )
ChangeVideoConfig ( newConfig ) ;
}
2015-09-25 19:26:49 +00:00
if ( m_private - > currentEvent . window . event = = SDL_WINDOWEVENT_ENTER )
{
event . type = EVENT_MOUSE_ENTER ;
}
2015-09-24 19:09:46 +00:00
2015-09-25 19:26:49 +00:00
if ( m_private - > currentEvent . window . event = = SDL_WINDOWEVENT_LEAVE )
{
event . type = EVENT_MOUSE_LEAVE ;
}
2015-09-24 19:09:46 +00:00
2015-09-25 19:26:49 +00:00
if ( m_private - > currentEvent . window . event = = SDL_WINDOWEVENT_FOCUS_GAINED )
{
event . type = EVENT_FOCUS_GAINED ;
}
2015-09-24 19:09:46 +00:00
2015-09-25 19:26:49 +00:00
if ( m_private - > currentEvent . window . event = = SDL_WINDOWEVENT_FOCUS_LOST )
{
event . type = EVENT_FOCUS_LOST ;
}
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 ;
2015-08-06 15:51:28 +00:00
auto data = MakeUnique < KeyEventData > ( ) ;
data - > virt = false ;
data - > key = m_private - > currentEvent . key . keysym . sym ;
2014-12-11 18:01:57 +00:00
event . kmodState = m_private - > currentEvent . key . keysym . mod ;
2015-03-18 20:10:47 +00:00
2015-03-18 20:12:49 +00:00
// Some keyboards return numerical enter keycode instead of normal enter
// See issue #427 for details
2015-08-06 15:51:28 +00:00
if ( data - > key = = KEY ( KP_ENTER ) )
data - > key = KEY ( RETURN ) ;
2015-03-22 15:10:32 +00:00
2015-08-06 15:51:28 +00:00
if ( data - > key = = KEY ( TAB ) & & ( ( event . kmodState & KEY_MOD ( ALT ) ) ! = 0 ) )
2015-03-22 15:10:32 +00:00
{
GetLogger ( ) - > Debug ( " Minimize to taskbar \n " ) ;
2015-09-24 19:09:46 +00:00
SDL_MinimizeWindow ( m_private - > window ) ;
2015-03-22 15:10:32 +00:00
event . type = EVENT_NULL ;
}
2015-08-06 15:51:28 +00:00
event . data = std : : move ( data ) ;
2012-06-26 20:23:05 +00:00
}
2015-09-25 17:49:50 +00:00
else if ( m_private - > currentEvent . type = = SDL_TEXTINPUT )
{
event . type = EVENT_TEXT_INPUT ;
auto data = MakeUnique < TextInputData > ( ) ;
data - > text = m_private - > currentEvent . text . text ;
event . data = std : : move ( data ) ;
}
2015-09-24 19:09:46 +00:00
else if ( m_private - > currentEvent . type = = SDL_MOUSEWHEEL )
2012-06-26 20:23:05 +00:00
{
2015-09-24 19:09:46 +00:00
event . type = EVENT_MOUSE_WHEEL ;
2015-08-06 15:51:28 +00:00
2015-09-24 19:09:46 +00:00
auto data = MakeUnique < MouseWheelEventData > ( ) ;
2015-09-25 20:54:48 +00:00
data - > y = m_private - > currentEvent . wheel . y ;
data - > x = m_private - > currentEvent . wheel . x ;
2015-08-06 15:51:28 +00:00
2015-09-24 19:09:46 +00:00
event . data = std : : move ( data ) ;
}
else if ( ( m_private - > currentEvent . type = = SDL_MOUSEBUTTONDOWN ) | |
( m_private - > currentEvent . type = = SDL_MOUSEBUTTONUP ) )
{
auto data = MakeUnique < MouseButtonEventData > ( ) ;
2015-08-06 15:51:28 +00:00
2015-09-24 19:09:46 +00:00
if ( m_private - > currentEvent . type = = SDL_MOUSEBUTTONDOWN )
event . type = EVENT_MOUSE_BUTTON_DOWN ;
2012-06-29 22:12:04 +00:00
else
2015-09-24 19:09:46 +00:00
event . type = EVENT_MOUSE_BUTTON_UP ;
2015-08-06 15:51:28 +00:00
2015-09-24 19:09:46 +00:00
data - > button = static_cast < MouseButton > ( 1 < < m_private - > currentEvent . button . button ) ;
2015-08-06 15:51:28 +00:00
2015-09-24 19:09:46 +00:00
event . data = std : : move ( data ) ;
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 ;
2014-12-11 18:01:57 +00:00
m_input - > MouseMove ( 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 ;
2015-08-06 15:51:28 +00:00
auto data = MakeUnique < JoyAxisEventData > ( ) ;
data - > axis = m_private - > currentEvent . jaxis . axis ;
data - > value = m_private - > currentEvent . jaxis . value ;
event . data = std : : move ( data ) ;
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
2015-08-06 15:51:28 +00:00
auto data = MakeUnique < JoyButtonEventData > ( ) ;
data - > button = m_private - > currentEvent . jbutton . button ;
event . data = std : : move ( data ) ;
2012-06-26 20:23:05 +00:00
}
2015-04-27 16:35:41 +00:00
2012-09-21 22:38:17 +00:00
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 ( " 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
2015-09-25 17:49:50 +00:00
if ( IsDebugModeActive ( DEBUG_SYS_EVENTS ) | | IsDebugModeActive ( DEBUG_UPDATE_EVENTS ) | | IsDebugModeActive ( DEBUG_APP_EVENTS ) )
2013-06-16 19:39:21 +00:00
{
std : : string eventType = ParseEventType ( event . type ) ;
2015-09-25 17:49:50 +00:00
if ( IsDebugModeActive ( DEBUG_UPDATE_EVENTS ) & & event . type = = EVENT_FRAME )
{
l - > Trace ( " Update event: %s \n " , eventType . c_str ( ) ) ;
PrintEventDetails ( ) ;
}
if ( IsDebugModeActive ( DEBUG_SYS_EVENTS ) & & ( event . type < = EVENT_SYS_MAX & & event . type ! = EVENT_FRAME ) )
2013-06-16 19:39:21 +00:00
{
l - > Trace ( " System event %s: \n " , eventType . c_str ( ) ) ;
switch ( event . type )
{
case EVENT_KEY_DOWN :
case EVENT_KEY_UP :
2015-08-06 15:51:28 +00:00
{
auto data = event . GetData < KeyEventData > ( ) ;
l - > Trace ( " virt = %s \n " , data - > virt ? " true " : " false " ) ;
l - > Trace ( " key = %d \n " , data - > key ) ;
2015-09-25 17:49:50 +00:00
break ;
}
case EVENT_TEXT_INPUT :
{
auto data = event . GetData < TextInputData > ( ) ;
l - > Trace ( " text = %s \n " , data - > text . c_str ( ) ) ;
2013-06-16 19:39:21 +00:00
break ;
2015-08-06 15:51:28 +00:00
}
2013-06-16 19:39:21 +00:00
case EVENT_MOUSE_BUTTON_DOWN :
case EVENT_MOUSE_BUTTON_UP :
2015-08-06 15:51:28 +00:00
{
auto data = event . GetData < MouseButtonEventData > ( ) ;
l - > Trace ( " button = %d \n " , data - > button ) ;
2013-06-16 19:39:21 +00:00
break ;
2015-08-06 15:51:28 +00:00
}
2013-06-16 19:39:21 +00:00
case EVENT_MOUSE_WHEEL :
2015-08-06 15:51:28 +00:00
{
auto data = event . GetData < MouseWheelEventData > ( ) ;
2015-09-25 20:54:48 +00:00
l - > Trace ( " y = %d \n " , data - > y ) ;
l - > Trace ( " x = %d \n " , data - > x ) ;
2015-08-06 15:51:28 +00:00
break ;
}
2013-06-16 19:39:21 +00:00
case EVENT_JOY_AXIS :
2015-08-06 15:51:28 +00:00
{
auto data = event . GetData < JoyAxisEventData > ( ) ;
l - > Trace ( " axis = %d \n " , data - > axis ) ;
l - > Trace ( " value = %d \n " , data - > value ) ;
2013-06-16 19:39:21 +00:00
break ;
2015-08-06 15:51:28 +00:00
}
2013-06-16 19:39:21 +00:00
case EVENT_JOY_BUTTON_DOWN :
case EVENT_JOY_BUTTON_UP :
2015-08-06 15:51:28 +00:00
{
auto data = event . GetData < JoyButtonEventData > ( ) ;
l - > Trace ( " button = %d \n " , data - > button ) ;
2013-06-16 19:39:21 +00:00
break ;
2015-08-06 15:51:28 +00:00
}
2013-06-16 19:39:21 +00:00
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 ) )
{
2015-08-06 15:51:28 +00:00
auto sourceData = sourceEvent . GetData < KeyEventData > ( ) ;
auto virtualKey = GetVirtualKey ( sourceData - > key ) ;
2012-09-19 16:32:18 +00:00
2015-08-06 15:51:28 +00:00
if ( virtualKey = = sourceData - > key )
{
2012-09-19 16:32:18 +00:00
virtualEvent . type = EVENT_NULL ;
2015-08-06 15:51:28 +00:00
}
else
{
virtualEvent . type = sourceEvent . type ;
auto data = sourceData - > Clone ( ) ;
auto keyData = static_cast < KeyEventData * > ( data . get ( ) ) ;
keyData - > key = virtualKey ;
keyData - > virt = true ;
virtualEvent . data = std : : move ( data ) ;
}
2012-09-19 16:32:18 +00:00
}
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
2015-08-06 15:51:28 +00:00
auto sourceData = sourceEvent . GetData < JoyButtonEventData > ( ) ;
auto data = MakeUnique < KeyEventData > ( ) ;
data - > virt = true ;
data - > key = VIRTUAL_JOY ( sourceData - > button ) ;
virtualEvent . data = std : : move ( data ) ;
2012-09-19 16:32:18 +00:00
}
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
{
2015-08-09 13:20:35 +00:00
StartPerformanceCounter ( PCNT_RENDER_ALL ) ;
2012-08-10 21:31:42 +00:00
m_engine - > Render ( ) ;
2015-08-09 13:20:35 +00:00
StopPerformanceCounter ( PCNT_RENDER_ALL ) ;
2012-06-25 17:59:17 +00:00
2015-08-09 13:20:35 +00:00
StartPerformanceCounter ( PCNT_SWAP_BUFFERS ) ;
2012-07-29 13:09:53 +00:00
if ( m_deviceConfig . doubleBuf )
2015-09-24 19:09:46 +00:00
SDL_GL_SwapWindow ( m_private - > window ) ;
2015-08-09 13:20:35 +00:00
StopPerformanceCounter ( PCNT_SWAP_BUFFERS ) ;
2012-06-25 17:59:17 +00:00
}
2015-08-13 22:07:45 +00:00
void CApplication : : RenderIfNeeded ( int updateRate )
{
m_systemUtils - > GetCurrentTimeStamp ( m_manualFrameTime ) ;
long long diff = m_systemUtils - > TimeStampExactDiff ( m_manualFrameLast , m_manualFrameTime ) ;
if ( diff < 1e9 f / updateRate )
{
return ;
}
m_systemUtils - > CopyTimeStamp ( m_manualFrameLast , m_manualFrameTime ) ;
Render ( ) ;
}
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 ( )
{
2015-08-07 06:31:34 +00:00
m_systemUtils - > GetCurrentTimeStamp ( m_baseTimeStamp ) ;
m_systemUtils - > 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 ;
2015-08-07 06:31:34 +00:00
m_systemUtils - > 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
2015-08-07 06:31:34 +00:00
m_systemUtils - > CopyTimeStamp ( m_lastTimeStamp , m_curTimeStamp ) ;
m_systemUtils - > GetCurrentTimeStamp ( m_curTimeStamp ) ;
2012-09-12 21:43:04 +00:00
2015-08-07 06:31:34 +00:00
long long absDiff = m_systemUtils - > TimeStampExactDiff ( m_baseTimeStamp , m_curTimeStamp ) ;
2013-03-23 23:03:37 +00:00
long long newRealAbsTime = m_realAbsTimeBase + absDiff ;
2015-08-07 06:31:34 +00:00
long long newRealRelTime = m_systemUtils - > 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 ) / 1e9 f ;
m_realRelTime = newRealRelTime ;
m_exactRelTime = m_simulationSpeed * m_realRelTime ;
m_relTime = ( m_simulationSpeed * m_realRelTime ) / 1e9 f ;
}
2012-09-12 21:43:04 +00:00
Event frameEvent ( EVENT_FRAME ) ;
frameEvent . rTime = m_relTime ;
2015-08-09 21:04:24 +00:00
m_input - > EventProcess ( frameEvent ) ;
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
}
2015-06-16 13:31:59 +00:00
Gfx : : DeviceConfig CApplication : : GetVideoConfig ( ) const
2012-08-03 21:23:13 +00:00
{
return m_deviceConfig ;
}
2015-09-24 19:09:46 +00:00
void CApplication : : GetVideoResolutionList ( std : : vector < Math : : IntPoint > & resolutions , int display ) 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
2015-09-24 19:09:46 +00:00
for ( int i = 0 ; i < SDL_GetNumDisplayModes ( display ) ; i + + )
{
SDL_DisplayMode mode ;
SDL_GetDisplayMode ( display , i , & mode ) ;
2015-09-25 09:16:09 +00:00
Math : : IntPoint resolution = Math : : IntPoint ( mode . w , mode . h ) ;
2012-07-29 13:09:53 +00:00
2015-09-25 09:16:09 +00:00
if ( std : : find ( resolutions . begin ( ) , resolutions . end ( ) , resolution ) = = resolutions . end ( ) )
resolutions . push_back ( resolution ) ;
2015-09-24 19:09:46 +00:00
}
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 ;
}
2015-09-25 17:49:50 +00:00
else if ( modeToken = = " update_events " )
{
debugModes | = DEBUG_UPDATE_EVENTS ;
}
2013-06-16 19:39:21 +00:00
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
}
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
}
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
Math : : IntPoint windowPos = m_engine - > InterfaceToWindowCoords ( pos ) ;
2014-12-11 18:01:57 +00:00
m_input - > MouseMove ( windowPos ) ;
2015-09-24 19:09:46 +00:00
SDL_WarpMouseInWindow ( m_private - > window , 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 ;
2015-09-24 19:09:46 +00:00
device . name = SDL_JoystickNameForIndex ( index ) ;
2012-07-29 13:09:53 +00:00
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 ;
}
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 */
2016-01-24 15:03:24 +00:00
static char envLang [ 50 ] = { 0 } ;
if ( envLang [ 0 ] = = 0 )
2012-12-28 21:31:47 +00:00
{
2016-01-24 15:03:24 +00:00
// Get this only at the first call, since this code modifies it
const char * currentEnvLang = gl_locale_name ( LC_MESSAGES , " LC_MESSAGES " ) ;
if ( currentEnvLang ! = nullptr )
{
strcpy ( envLang , currentEnvLang ) ;
}
2012-12-28 21:31:47 +00:00
}
2016-01-24 15:03:24 +00:00
if ( language = = LANGUAGE_ENV )
2012-12-28 21:31:47 +00:00
{
2016-01-24 15:03:24 +00:00
if ( envLang [ 0 ] = = 0 )
2013-01-05 22:03:26 +00:00
{
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
}
2016-01-24 15:03:24 +00:00
std : : string locale = " " ;
switch ( m_language )
2012-12-28 21:31:47 +00:00
{
2016-01-24 15:03:24 +00:00
default :
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 ;
case LANGUAGE_RUSSIAN :
locale = " ru_RU.utf8 " ;
break ;
2012-12-28 21:31:47 +00:00
}
2015-03-21 12:09:05 +00:00
2016-01-24 15:03:24 +00:00
std : : string langStr = " LANGUAGE= " ;
langStr + = locale ;
strcpy ( m_languageLocale , langStr . c_str ( ) ) ;
putenv ( m_languageLocale ) ;
GetLogger ( ) - > Trace ( " SetLanguage: Set LANGUAGE=%s in environment \n " , locale . c_str ( ) ) ;
2015-03-21 19:13:58 +00:00
char * defaultLocale = setlocale ( LC_ALL , " " ) ; // Load system locale
2015-07-17 17:55:02 +00:00
GetLogger ( ) - > Debug ( " Default system locale: %s \n " , defaultLocale ) ;
2015-03-21 16:34:18 +00:00
setlocale ( LC_NUMERIC , " C " ) ; // Force numeric locale to "C" (fixes decimal point problems)
char * systemLocale = setlocale ( LC_ALL , nullptr ) ; // Get current locale configuration
2015-03-21 19:13:58 +00:00
GetLogger ( ) - > Debug ( " Setting locale: %s \n " , systemLocale ) ;
2015-03-21 12:09:05 +00:00
// Update C++ locale
try
{
std : : locale : : global ( std : : locale ( systemLocale ) ) ;
}
2015-06-25 22:24:05 +00:00
catch ( . . . )
2015-03-21 12:09:05 +00:00
{
GetLogger ( ) - > Warn ( " Failed to update locale, possibly incorect system configuration. Will fallback to classic locale. \n " ) ;
try
{
std : : locale : : global ( std : : locale : : classic ( ) ) ;
}
2015-06-25 22:24:05 +00:00
catch ( . . . )
2015-03-21 12:09:05 +00:00
{
2015-03-21 19:13:58 +00:00
GetLogger ( ) - > Warn ( " Failed to set classic locale. Something is really messed up in your system configuration. Translations might not work. \n " ) ;
2015-03-21 12:09:05 +00:00
}
2015-03-21 19:13:58 +00:00
// C locale might still work correctly
setlocale ( LC_ALL , " " ) ;
setlocale ( LC_NUMERIC , " C " ) ;
2015-03-21 12:09:05 +00:00
}
2012-12-28 21:31:47 +00:00
2015-03-08 14:22:21 +00:00
bindtextdomain ( " colobot " , m_pathManager - > GetLangPath ( ) . 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-20 18:37:37 +00:00
}
2012-10-25 21:29:49 +00:00
void CApplication : : StartPerformanceCounter ( PerformanceCounter counter )
{
2015-08-07 06:31:34 +00:00
m_systemUtils - > GetCurrentTimeStamp ( m_performanceCounters [ counter ] [ 0 ] ) ;
2012-10-25 21:29:49 +00:00
}
void CApplication : : StopPerformanceCounter ( PerformanceCounter counter )
{
2015-08-07 06:31:34 +00:00
m_systemUtils - > 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 ( )
{
2015-08-07 06:31:34 +00:00
long long sum = m_systemUtils - > 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 )
{
2015-08-07 06:31:34 +00:00
long long diff = m_systemUtils - > 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 ;
}
2015-09-25 17:49:50 +00:00
void CApplication : : SetTextInput ( bool textInputEnabled )
{
if ( textInputEnabled )
{
SDL_StartTextInput ( ) ;
}
else
{
SDL_StopTextInput ( ) ;
}
}
2015-09-26 22:34:03 +00:00
void CApplication : : PlayForceFeedbackEffect ( float strength , int length )
{
if ( m_private - > haptic = = nullptr ) return ;
GetLogger ( ) - > Trace ( " Force feedback! length = %d ms, strength = %.2f \n " , length , strength ) ;
if ( SDL_HapticRumblePlay ( m_private - > haptic , strength , length ) ! = 0 )
{
2015-09-27 16:54:02 +00:00
GetLogger ( ) - > Debug ( " Failed to play haptic effect: %s \n " , SDL_GetError ( ) ) ;
2015-09-26 22:34:03 +00:00
}
}
void CApplication : : StopForceFeedbackEffect ( )
{
if ( m_private - > haptic = = nullptr ) return ;
SDL_HapticRumbleStop ( m_private - > haptic ) ;
}