1 /* 2 * This file is part of the Colobot: Gold Edition source code 3 * Copyright (C) 2001-2020, Daniel Roux, EPSITEC SA & TerranovaTeam 4 * http://epsitec.ch; http://colobot.info; http://github.com/colobot 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 14 * See the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see http://gnu.org/licenses 18 */ 19 20 /** 21 * \file app/app.h 22 * \brief CApplication class 23 */ 24 25 #pragma once 26 27 #include "common/event.h" 28 #include "common/language.h" 29 #include "common/singleton.h" 30 31 #include "graphics/core/device.h" 32 33 #include "level/level_category.h" 34 35 36 #include <string> 37 #include <vector> 38 #include <map> 39 40 41 class CEventQueue; 42 class CController; 43 class CSoundInterface; 44 class CInput; 45 class CModManager; 46 class CPathManager; 47 class CConfigFile; 48 class CSystemUtils; 49 struct SystemTimeStamp; 50 51 namespace Gfx 52 { 53 class CEngine; 54 struct DeviceConfig; 55 } 56 57 /** 58 * \struct JoystickDevice 59 * \brief Information about a joystick device 60 */ 61 struct JoystickDevice 62 { 63 //! Device index (-1 = invalid device) 64 int index; 65 //! Device name 66 std::string name; 67 //! Number of axes (only available after joystick opened) 68 int axisCount; 69 //! Number of buttons (only available after joystick opened) 70 int buttonCount; 71 JoystickDeviceJoystickDevice72 JoystickDevice() 73 : index(-1), axisCount(0), buttonCount(0) {} 74 }; 75 76 /** 77 * \enum ParseArgsStatus 78 * \brief State of parsing commandline arguments 79 */ 80 enum ParseArgsStatus 81 { 82 PARSE_ARGS_OK = 1, //! < all ok 83 PARSE_ARGS_FAIL = 2, //! < invalid syntax 84 PARSE_ARGS_HELP = 3 //! < -help requested 85 }; 86 87 /** 88 * \enum MouseMode 89 * \brief Mode of mouse cursor 90 */ 91 enum MouseMode 92 { 93 MOUSE_SYSTEM, //! < system cursor visible; in-game cursor hidden 94 MOUSE_ENGINE, //! < in-game cursor visible; system cursor hidden 95 MOUSE_BOTH, //! < both cursors visible (only for debug) 96 MOUSE_NONE, //! < no cursor visible 97 }; 98 99 enum DebugMode 100 { 101 DEBUG_SYS_EVENTS = 1 << 0, 102 DEBUG_UPDATE_EVENTS = 1 << 1, 103 DEBUG_APP_EVENTS = 1 << 2, 104 DEBUG_EVENTS = DEBUG_SYS_EVENTS | DEBUG_UPDATE_EVENTS | DEBUG_APP_EVENTS, 105 DEBUG_MODELS = 1 << 3, 106 DEBUG_ALL = DEBUG_SYS_EVENTS | DEBUG_APP_EVENTS | DEBUG_MODELS 107 }; 108 109 struct ApplicationPrivate; 110 111 /** 112 * \class CApplication 113 * \brief Main application 114 * 115 * This class is responsible for main application execution, including creating 116 * and handling main application window, receiving events, etc. 117 * 118 * It is a singleton class with only one instance that can be created. 119 * 120 * \section Creation Creation of other main objects 121 * 122 * The class creates the only instance of CEventQueue, CEngine, 123 * CRobotMain and CSoundInterface classes. 124 * 125 * \section Window Window management 126 * 127 * The class is responsible for creating app window, setting and changing the video mode, 128 * joystick management, grabbing input and changing the system mouse cursor 129 * position and visibility. 130 * ("System mouse cursor" means the cursor displayed by the OS in constrast to the cursor 131 * displayed by CEngine). 132 * 133 * \section Events Events 134 * 135 * Events are taken from SDL event queue, translated to common events from src/common.h 136 * and pushed to global event queue CEventQueue. 137 * 138 * Joystick events are generated somewhat differently, by running a separate timer, 139 * polling the device for changes and synthesising events on change. It avoids flooding 140 * the event queue with too many joystick events and the granularity of the timer can be 141 * adjusted. 142 * 143 * The events are passed to ProcessEvent() of classes in this order: CApplication, CEngine 144 * and CRobotMain. CApplication and CEngine's ProcessEvent() functions return bool, which 145 * means whether to pass the event on, or stop the chain. This is to enable handling some 146 * events which are internal to CApplication or CEngine. 147 * 148 * \section Portability Portability 149 * 150 * Currently, the class only handles OpenGL devices. SDL can be used with DirectX, but 151 * for that to work, video initialization and video setting must be done differently. 152 * 153 */ 154 class CApplication : public CSingleton<CApplication> 155 { 156 public: 157 //! Constructor (can only be called once!) 158 CApplication(CSystemUtils* systemUtils); 159 //! Destructor 160 ~CApplication(); 161 162 //! Returns the application's event queue 163 CEventQueue* GetEventQueue(); 164 //! Returns the sound subsystem 165 CSoundInterface* GetSound(); 166 //! Returns the mod manager 167 CModManager* GetModManager(); 168 169 public: 170 //! Loads some data from environment variables 171 void LoadEnvironmentVariables(); 172 //! Parses commandline arguments (they take priority) 173 ParseArgsStatus ParseArguments(int argc, char *argv[]); 174 //! Initializes the application 175 bool Create(); 176 //! Reloads the application resources, e.g. mods 177 void ReloadResources(); 178 //! Main event loop 179 int Run(); 180 //! Returns the code to be returned at main() exit 181 int GetExitCode() const; 182 183 //! Returns the message of error (set to something if exit code is not 0) 184 const std::string& GetErrorMessage() const; 185 186 //! Returns a list of possible video modes 187 void GetVideoResolutionList(std::vector<Math::IntPoint> &resolutions, int display = 0) const; 188 189 //! Returns the current video mode 190 Gfx::DeviceConfig GetVideoConfig() const; 191 192 //! Change the video mode to given mode 193 bool ChangeVideoConfig(const Gfx::DeviceConfig &newConfig); 194 195 //! Suspends animation (time will not be updated) 196 void SuspendSimulation(); 197 //! Resumes animation 198 void ResumeSimulation(); 199 //! Returns whether simulation is suspended 200 bool GetSimulationSuspended() const; 201 202 //! Resets time counters to account for time spent loading game 203 void ResetTimeAfterLoading(); 204 205 //@{ 206 //! Management of simulation speed 207 void SetSimulationSpeed(float speed); 208 float GetSimulationSpeed() const; 209 //@} 210 211 //! Returns the absolute time counter [seconds] 212 float GetAbsTime() const; 213 //! Returns the exact absolute time counter [nanoseconds] 214 long long GetExactAbsTime() const; 215 216 //! Returns the exact absolute time counter disregarding speed setting [nanoseconds] 217 long long GetRealAbsTime() const; 218 219 //! Returns the relative time since last update [seconds] 220 float GetRelTime() const; 221 //! Returns the exact realative time since last update [nanoseconds] 222 long long GetExactRelTime() const; 223 224 //! Returns the exact relative time since last update disregarding speed setting [nanoseconds] 225 long long GetRealRelTime() const; 226 227 //! Returns a list of available joystick devices 228 std::vector<JoystickDevice> GetJoystickList() const; 229 230 //! Returns info about the current joystick 231 JoystickDevice GetJoystick() const; 232 233 //! Change the current joystick device 234 bool ChangeJoystick(const JoystickDevice &newJoystick); 235 236 //! Management of joystick enable state 237 //@{ 238 void SetJoystickEnabled(bool enable); 239 bool GetJoystickEnabled() const; 240 //@} 241 242 //! Polls the state of joystick axes and buttons 243 void UpdateJoystick(); 244 245 //! Updates the mouse position explicitly 246 void UpdateMouse(); 247 248 //! Management of mouse mode 249 //@{ 250 void SetMouseMode(MouseMode mode); 251 MouseMode GetMouseMode() const; 252 //@} 253 254 //! Enable/disable text input, this toggles the on-screen keyboard on some platforms 255 /** This also allows for writing in CJK languages (not tested!), see https://wiki.libsdl.org/Tutorials/TextInput for detailed explanation */ 256 void SetTextInput(bool textInputEnabled, int id); 257 258 //! Moves (warps) the mouse cursor to the specified position (in interface coords) 259 void MoveMouse(Math::Point pos); 260 261 //! Management of debug modes (printing more info in logger) 262 //@{ 263 void SetDebugModeActive(DebugMode mode, bool active); 264 bool IsDebugModeActive(DebugMode mode) const; 265 static bool ParseDebugModes(const std::string& str, int& debugModes); 266 //@} 267 268 //! Management of language 269 //@{ 270 Language GetLanguage() const; 271 char GetLanguageChar() const; 272 void SetLanguage(Language language); 273 //@} 274 275 bool GetSceneTestMode(); 276 277 //! Renders the image in window 278 void Render(); 279 280 //! Renders the image in window if needed 281 void RenderIfNeeded(int updateRate); 282 283 //! Starts a force feedback effect on the joystick 284 void PlayForceFeedbackEffect(float strength = 1.0f, int length = 999999); 285 //! Stops a force feedback effect on the joystick 286 void StopForceFeedbackEffect(); 287 288 protected: 289 //! Creates the window's SDL_Surface 290 bool CreateVideoSurface(); 291 //! Tries to set the SDL vsync state desired by the 3D engine 292 //! The final state of SDL vsync is set in the 3D engine afterwards 293 void TryToSetVSync(); 294 295 //! Processes the captured SDL event to Event struct 296 Event ProcessSystemEvent(); 297 //! If applicable, creates a virtual event to match the changed state as of new event 298 Event CreateVirtualEvent(const Event& sourceEvent); 299 //! Prepares a simulation update event 300 TEST_VIRTUAL Event CreateUpdateEvent(SystemTimeStamp *newTimeStamp); 301 //! Logs debug data for event 302 void LogEvent(const Event& event); 303 304 //! Opens the joystick device 305 bool OpenJoystick(); 306 //! Closes the joystick device 307 void CloseJoystick(); 308 309 //! Internal procedure to reset time counters 310 void InternalResumeSimulation(); 311 312 //! Loads music in a new thread 313 void StartLoadingMusic(); 314 315 protected: 316 //! System utils instance 317 CSystemUtils* m_systemUtils; 318 //! Private (SDL-dependent data) 319 std::unique_ptr<ApplicationPrivate> m_private; 320 //! Global event queue 321 std::unique_ptr<CEventQueue> m_eventQueue; 322 //! Graphics engine 323 std::unique_ptr<Gfx::CEngine> m_engine; 324 //! Graphics device 325 std::unique_ptr<Gfx::CDevice> m_device; 326 //! Sound subsystem 327 std::unique_ptr<CSoundInterface> m_sound; 328 //! Game controller - game engine and UI 329 std::unique_ptr<CController> m_controller; 330 //! Profile (INI) reader/writer 331 std::unique_ptr<CConfigFile> m_configFile; 332 //! Input manager 333 std::unique_ptr<CInput> m_input; 334 //! Path manager 335 std::unique_ptr<CPathManager> m_pathManager; 336 //! Mod manager 337 std::unique_ptr<CModManager> m_modManager; 338 339 //! Code to return at exit 340 int m_exitCode; 341 //! Whether application window is active 342 bool m_active; 343 //! Bit array of active debug modes 344 long m_debugModes; 345 346 //! Message to be displayed as error to the user 347 std::string m_errorMessage; 348 349 //! Current configuration of OpenGL display device 350 Gfx::DeviceConfig m_deviceConfig; 351 352 //! Text set as window title 353 std::string m_windowTitle; 354 355 //! Animation time stamps, etc. 356 //@{ 357 SystemTimeStamp* m_baseTimeStamp; 358 SystemTimeStamp* m_lastTimeStamp; 359 SystemTimeStamp* m_curTimeStamp; 360 361 long long m_realAbsTimeBase; 362 long long m_realAbsTime; 363 long long m_realRelTime; 364 365 long long m_absTimeBase; 366 long long m_exactAbsTime; 367 long long m_exactRelTime; 368 369 float m_absTime; 370 float m_relTime; 371 372 float m_simulationSpeed; 373 bool m_simulationSuspended; 374 //@} 375 376 SystemTimeStamp* m_manualFrameLast; 377 SystemTimeStamp* m_manualFrameTime; 378 379 //! Graphics device to use 380 bool m_graphicsOverride = false; 381 std::string m_graphics = "default"; 382 //! OpenGL version to use 383 bool m_glVersionOverride = false; 384 int m_glMajor = -1; 385 int m_glMinor = -1; 386 //! OpenGL profile 387 bool m_glProfileOverride = false; 388 int m_glProfile = 0; 389 390 //! Current mode of mouse 391 MouseMode m_mouseMode; 392 393 //! Info about current joystick device 394 JoystickDevice m_joystick; 395 //! Whether joystick is enabled 396 bool m_joystickEnabled; 397 //! Current state of joystick axes; may be updated from another thread 398 std::vector<int> m_joyAxeState; 399 //! Current state of joystick buttons; may be updated from another thread 400 std::vector<bool> m_joyButtonState; 401 402 //@{ 403 //! Scene to run on startup 404 LevelCategory m_runSceneCategory; 405 int m_runSceneRank; 406 //@} 407 408 //! Scene test mode 409 bool m_sceneTest; 410 411 //! Application language 412 Language m_language; 413 414 //! Screen resoultion overriden by commandline 415 bool m_resolutionOverride; 416 417 //! Headles mode 418 bool m_headless; 419 420 //! Static buffer for putenv locale 421 static char m_languageLocale[50]; 422 423 std::map<int, bool> m_textInputEnabled; 424 }; 425