Engine.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. #include <GL\glew.h>
  2. #include <sstream>
  3. #include <iostream>
  4. #include "AudioSystem.h"
  5. #include "ClockLocator.h"
  6. #include "Engine.h"
  7. #include "GUIHandlerLocator.h"
  8. #include "GUISystem.h"
  9. #include "ObjectDirectory.h"
  10. #include "PhysicsSystem.h"
  11. #include "RendererSystem.h"
  12. #include "ScriptSystem.h"
  13. #include "TaskManagerLocator.h"
  14. #include "WindowLocator.h"
  15. #include "WorldSystem.h"
  16. int Engine::m_instances = 0;
  17. #define ENUMTOSTRING(ENUM) #ENUM
  18. Engine::Engine() //m_mainMenuState(*this), m_playstate(*this), m_editorState(*this)
  19. {
  20. m_instances++;
  21. m_initialized = false;
  22. m_errorHandler = nullptr;
  23. m_GUIHandler = nullptr;
  24. m_window = nullptr;
  25. m_clock = nullptr;
  26. m_taskManager = nullptr;
  27. m_scheduler = nullptr;
  28. m_changeCtrlScene = nullptr;
  29. m_sceneChangeController = nullptr;
  30. m_objectChangeController = nullptr;
  31. m_currentStateType = Config::engineVar().engineState;
  32. for(unsigned int i = 0; i < EngineStateType::EngineStateType_NumOfTypes; i++)
  33. m_engineStates[i] = nullptr;
  34. for(unsigned int i = 0; i < Systems::NumberOfSystems; i++)
  35. m_systems[i] = nullptr;
  36. }
  37. Engine::~Engine()
  38. {
  39. for(unsigned int i = 0; i < EngineStateType::EngineStateType_NumOfTypes; i++)
  40. if(m_engineStates[i] != nullptr)
  41. delete m_engineStates[i];
  42. // Delete systems
  43. delete m_taskManager;
  44. delete m_errorHandler;
  45. delete m_clock;
  46. }
  47. // Some of the initialization sequences are order sensitive. Do not change the order of calls.
  48. ErrorCode Engine::init()
  49. {
  50. // Allow only one instance. If there's more, someone is doing something wrong.
  51. if(m_instances > 1)
  52. {
  53. printf("Error: Attempting to create multiple engine instances.\n");
  54. return ErrorCode::Failure;
  55. }
  56. // Initialize all services and their locators
  57. auto servicesError = initServices();
  58. if(servicesError != ErrorCode::Success)
  59. return servicesError;
  60. // Initialize all engine systems
  61. auto systemsError = initSystems();
  62. if(systemsError != ErrorCode::Success)
  63. return systemsError;
  64. // ___________________________________
  65. // | |
  66. // | ENGINE STATE INITIALIZATION |
  67. // |___________________________________|
  68. // Set and initialize the current engine state
  69. setCurrentStateType(m_currentStateType);
  70. if(m_engineStates[m_currentStateType] == nullptr || !m_engineStates[m_currentStateType]->isInitialized())
  71. return ErrorCode::Failure;
  72. // If this point is reached, all initializations passed, mark the engine as initialized
  73. m_initialized = true;
  74. return ErrorCode::Success;
  75. }
  76. void Engine::run()
  77. {
  78. // Make sure the engine is initialized before entering the main loop
  79. if(!m_initialized)
  80. return;
  81. // Infinite main loop
  82. while(true)
  83. {
  84. // Update the clock
  85. m_clock->update();
  86. // Handle window and input events
  87. m_window->handleEvents();
  88. // If engine is still running
  89. if(Config::engineVar().running == true)
  90. {
  91. processEngineChanges();
  92. // Load a different engine state, if it has been changed
  93. //if(m_currentStateType != Config::engineVar().engineState)
  94. //{
  95. // m_currentStateType = Config::engineVar().engineState;
  96. // setCurrentStateType();
  97. //}
  98. // Call update on the current engine state
  99. m_engineStates[m_currentStateType]->update(*this);
  100. // Swap buffers. If v-sync is enabled, this call should halt for appropriate time
  101. m_window->swapBuffers();
  102. }
  103. else
  104. {
  105. // If engine is not running anymore, break the loop
  106. break;
  107. }
  108. }
  109. // Call shutdown before returning
  110. shutdown();
  111. }
  112. void Engine::processEngineChanges()
  113. {
  114. // Check if there are any engine changes
  115. auto changeControllerScene = m_engineStates[m_currentStateType]->getChangeControllerScene();
  116. if(changeControllerScene->getEngineChangePending())
  117. {
  118. // Go over each engine change
  119. auto &engineChanges = changeControllerScene->getEngineChangeQueue();
  120. for(auto const &change : engineChanges)
  121. {
  122. switch(change.m_changeType)
  123. {
  124. case EngineChangeType_SceneFilename:
  125. {
  126. m_engineStates[change.m_engineStateType]->setSceneFilename(change.m_filename);
  127. }
  128. break;
  129. case EngineChangeType_SceneLoad:
  130. {
  131. if(m_engineStates[change.m_engineStateType] != nullptr)
  132. {
  133. // Load the scene
  134. ErrorCode loadError = m_engineStates[change.m_engineStateType]->load();
  135. // If it failed to load, log an error
  136. if(loadError != ErrorCode::Success)
  137. ErrHandlerLoc::get().log(loadError, getEngineStateTypeString(change.m_engineStateType), ErrorSource::Source_Engine);
  138. }
  139. else
  140. ErrHandlerLoc::get().log(ErrorCode::Initialize_failure, getEngineStateTypeString(change.m_engineStateType), ErrorSource::Source_Engine);
  141. }
  142. break;
  143. case EngineChangeType_SceneReload:
  144. {
  145. // Delete the current scene
  146. if(m_engineStates[m_currentStateType] != nullptr)
  147. {
  148. delete m_engineStates[m_currentStateType];
  149. m_engineStates[m_currentStateType] = nullptr;
  150. }
  151. setCurrentStateType(m_currentStateType);
  152. return;
  153. }
  154. break;
  155. case EngineChangeType_StateChange:
  156. {
  157. setCurrentStateType(change.m_engineStateType);
  158. }
  159. break;
  160. }
  161. }
  162. // Mark engine changes as being processed by clearing the queue
  163. changeControllerScene->clearEngineChangeQueue();
  164. }
  165. }
  166. ErrorCode Engine::initServices()
  167. {
  168. ErrorCode returnError = ErrorCode::Success;
  169. // ___________________________________
  170. // | |
  171. // | SERVICE LOCATORS INITIALIZATION |
  172. // |___________________________________|
  173. // Initialize all locators before providing them with real instances
  174. ErrHandlerLoc::init();
  175. ClockLocator::init();
  176. GUIHandlerLocator::init();
  177. TaskManagerLocator::init();
  178. WindowLocator::init();
  179. // ___________________________________
  180. // | |
  181. // | ERROR HANDLER INITIALIZATION |
  182. // |___________________________________|
  183. // Create and initialize error handler
  184. m_errorHandler = new ErrorHandler();
  185. ErrorCode errHandlerError = m_errorHandler->init();
  186. // If error handler was initialized successfully, pass it to the locator, if not, log an error
  187. if(errHandlerError == ErrorCode::Success)
  188. {
  189. ErrHandlerLoc::provide(m_errorHandler);
  190. }
  191. else
  192. printf("Error: Error handler has failed to initialize. Error code: %s\n", GetString(errHandlerError));
  193. // ___________________________________
  194. // | |n
  195. // | SET CONFIGURATION VARIABLES |
  196. // |___________________________________|
  197. // Initialize configuration variables
  198. Config::init();
  199. Config::loadFromFile(Config::configFileVar().config_file);
  200. // ___________________________________
  201. // | |
  202. // | CLOCK INITIALIZATION |
  203. // |___________________________________|
  204. // Initialize clock. Still continue if there's an error, nothing would move but the engine would still run.
  205. // The error handler will be responsible for outputting error and asking user if they want to continue in this case.
  206. m_clock = new Clock();
  207. ErrorCode clockError = m_clock->init();
  208. // Check if clock was initialized successfully
  209. if(clockError == ErrorCode::Success)
  210. ClockLocator::provide(m_clock);
  211. else
  212. ErrHandlerLoc::get().log(clockError, ErrorSource::Source_Engine);
  213. // ___________________________________
  214. // | |
  215. // | WINDOW INITIALIZATION |
  216. // |___________________________________|
  217. // Initialize window system and then attempt to spawn a window
  218. m_window = new Window();
  219. ErrorCode windowError = m_window->init();
  220. if(windowError == ErrorCode::Success)
  221. {
  222. windowError = m_window->createWindow();
  223. // If the window creation failed, we don't want to continue with the engine, so return an error
  224. if(windowError != ErrorCode::Success)
  225. {
  226. ErrHandlerLoc::get().log(windowError, ErrorSource::Source_Engine);
  227. return windowError;
  228. }
  229. // Assign window class to the service locator
  230. WindowLocator::provide(m_window);
  231. }
  232. else
  233. ErrHandlerLoc::get().log(windowError, ErrorSource::Source_Engine);
  234. // ___________________________________
  235. // | |
  236. // | GLEW INITIALIZATION |
  237. // |___________________________________|
  238. glewExperimental = GL_TRUE;
  239. GLenum glewError = glewInit();
  240. // It falsely gives error 1280, putting a call here clears the error, so it won't trigger anything
  241. glGetError();
  242. // If GLEW failed to initialize, return failure, as the engine would not be able to continue
  243. if(glewError != GLEW_OK)
  244. {
  245. // Get the GLEW error before returning
  246. std::stringstream stringstreamGlewError;
  247. stringstreamGlewError << glewGetErrorString(glewError);
  248. ErrHandlerLoc::get().log(Glew_failed, ErrorSource::Source_Engine, stringstreamGlewError.str());
  249. return ErrorCode::Failure;
  250. }
  251. // ___________________________________
  252. // | |
  253. // | TASK MANAGER INITIALIZATION |
  254. // |___________________________________|
  255. // Create new task manager and initialize it
  256. m_taskManager = new TaskManager();
  257. ErrorCode taskMgrError = m_taskManager->init();
  258. // If task manager initialized successfully, provide it to the locator, otherwise log an error
  259. if(taskMgrError == ErrorCode::Success)
  260. TaskManagerLocator::provide(m_taskManager);
  261. else
  262. ErrHandlerLoc::get().log(taskMgrError, ErrorSource::Source_Engine);
  263. // ___________________________________
  264. // | |
  265. // | LOADERS INITIALIZATION |
  266. // |___________________________________|
  267. // Initialize all global loaders and check for errors
  268. ErrorCode loaderError = ErrorCode::Success;
  269. // Initialize model loaders
  270. loaderError = Loaders::model().init();
  271. if(loaderError != ErrorCode::Success)
  272. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  273. // Initialize shader loader
  274. loaderError = Loaders::shader().init();
  275. if(loaderError != ErrorCode::Success)
  276. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  277. // Initialize texture2D loader
  278. loaderError = Loaders::texture2D().init();
  279. if(loaderError != ErrorCode::Success)
  280. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  281. // Initialize textureCubemap loader
  282. loaderError = Loaders::textureCubemap().init();
  283. if(loaderError != ErrorCode::Success)
  284. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  285. // Initialize the object directory
  286. loaderError = ObjectDirectory::init();
  287. if(loaderError != ErrorCode::Success)
  288. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  289. // ___________________________________
  290. // | |
  291. // | OBJECT DIRECTORY INITIALIZATION |
  292. // |___________________________________|
  293. // Initialize the object directory, return failure if it wasn't successful
  294. ErrorCode objectDirectoryError = ObjectDirectory::init();
  295. if(objectDirectoryError != ErrorCode::Success)
  296. {
  297. ErrHandlerLoc::get().log(objectDirectoryError, ErrorSource::Source_ObjectDirectory);
  298. return objectDirectoryError;
  299. }
  300. // ___________________________________
  301. // | |
  302. // | GUI HANDLER INITIALIZATION |
  303. // |___________________________________|
  304. // Initialize GUI handler. Still continue if there's an error, the GUI would just be missing.
  305. // The error handler will be responsible for outputting error and asking user if they want to continue in this case.
  306. m_GUIHandler = new GUIHandler();
  307. ErrorCode guiError = m_GUIHandler->init();
  308. // Check if the GUI handler was initialized successfully
  309. // If so, register it in GUI Handler locator and Window system
  310. // and enable GUI in Window system
  311. if(guiError == ErrorCode::Success)
  312. {
  313. GUIHandlerLocator::provide(m_GUIHandler);
  314. m_window->registerGUIHandler(m_GUIHandler);
  315. m_window->setEnableGUI(true);
  316. }
  317. else
  318. ErrHandlerLoc::get().log(guiError, ErrorSource::Source_Engine);
  319. return returnError;
  320. }
  321. ErrorCode Engine::initSystems()
  322. {
  323. ErrorCode returnError = ErrorCode::Success;
  324. // __________________________________
  325. // | |
  326. // | AUDIO SYSTEM INITIALIZATION |
  327. // |__________________________________|
  328. // Create audio system and check if it was successful (if not, assign a null system in it's place)
  329. m_systems[Systems::Audio] = new AudioSystem();
  330. if(m_systems[Systems::Audio]->init() != ErrorCode::Success)
  331. {
  332. delete m_systems[Systems::Audio];
  333. m_systems[Systems::Audio] = &g_nullSystemBase;
  334. }
  335. // __________________________________
  336. // | |
  337. // | RENDERER SYSTEM INITIALIZATION |
  338. // |__________________________________|
  339. // Create graphics system and check if it was successful (if not, assign a null system in it's place)
  340. m_systems[Systems::Graphics] = new RendererSystem();
  341. if(m_systems[Systems::Graphics]->init() != ErrorCode::Success)
  342. {
  343. delete m_systems[Systems::Graphics];
  344. m_systems[Systems::Graphics] = &g_nullSystemBase;
  345. }
  346. // ___________________________________
  347. // | |
  348. // | GUI SYSTEM INITIALIZATION |
  349. // |___________________________________|
  350. // Create GUI system and check if it was successful (if not, assign a null system in it's place)
  351. m_systems[Systems::GUI] = new GUISystem();
  352. if(m_systems[Systems::GUI]->init() != ErrorCode::Success)
  353. {
  354. delete m_systems[Systems::GUI];
  355. m_systems[Systems::GUI] = &g_nullSystemBase;
  356. }
  357. // ___________________________________
  358. // | |
  359. // | PHYSICS SYSTEM INITIALIZATION |
  360. // |___________________________________|
  361. // Create scripting system and check if it was successful (if not, assign a null system in it's place)
  362. m_systems[Systems::Physics] = new PhysicsSystem();
  363. if(m_systems[Systems::Physics]->init() != ErrorCode::Success)
  364. {
  365. delete m_systems[Systems::Physics];
  366. m_systems[Systems::Physics] = &g_nullSystemBase;
  367. }
  368. // ___________________________________
  369. // | |
  370. // | SCRIPTING SYSTEM INITIALIZATION |
  371. // |___________________________________|
  372. // Create scripting system and check if it was successful (if not, assign a null system in it's place)
  373. m_systems[Systems::Script] = new ScriptSystem();
  374. if(m_systems[Systems::Script]->init() != ErrorCode::Success)
  375. {
  376. delete m_systems[Systems::Script];
  377. m_systems[Systems::Script] = &g_nullSystemBase;
  378. }
  379. // ___________________________________
  380. // | |
  381. // | WORLD SYSTEM INITIALIZATION |
  382. // |___________________________________|
  383. // Create scripting system and check if it was successful (if not, assign a null system in it's place)
  384. m_systems[Systems::World] = new WorldSystem();
  385. if(m_systems[Systems::World]->init() != ErrorCode::Success)
  386. {
  387. delete m_systems[Systems::World];
  388. m_systems[Systems::World] = &g_nullSystemBase;
  389. }
  390. return returnError;
  391. }
  392. void Engine::shutdown()
  393. {
  394. // Shutdown engine states
  395. for(unsigned int i = 0; i < EngineStateType::EngineStateType_NumOfTypes; i++)
  396. if(m_engineStates[i] != nullptr)
  397. m_engineStates[i]->shutdown();
  398. // Cancel all the tasks in background threads
  399. m_taskManager->cancelBackgroundThreads();
  400. // Make sure they are canceled, by waiting for them
  401. m_taskManager->waitForBackgroundThreads();
  402. // Shutdown the task manager
  403. m_taskManager->shutdown();
  404. // Set the initialized flag to false, so the engine is not run without initializing again
  405. m_initialized = false;
  406. }