Engine.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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()
  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_currentState = nullptr;
  32. m_currentStateType = Config::engineVar().engineState;
  33. }
  34. Engine::~Engine()
  35. {
  36. // Delete systems
  37. delete m_taskManager;
  38. delete m_errorHandler;
  39. delete m_clock;
  40. }
  41. // Some of the initialization sequences are order sensitive. Do not change the order of calls.
  42. ErrorCode Engine::init()
  43. {
  44. // Allow only one instance. If there's more, someone is doing something wrong.
  45. if(m_instances > 1)
  46. {
  47. printf("Error: Attempting to create multiple engine instances.\n");
  48. return ErrorCode::Failure;
  49. }
  50. // Initialize all services and their locators
  51. auto servicesError = initServices();
  52. if(servicesError != ErrorCode::Success)
  53. return servicesError;
  54. // ___________________________________
  55. // | |
  56. // | ENGINE STATE INITIALIZATION |
  57. // |___________________________________|
  58. // Set and initialize the current engine state
  59. setCurrentStateType();
  60. if(!m_currentState->isInitialized())
  61. return ErrorCode::Failure;
  62. // If this point is reached, all initializations passed, mark the engine as initialized
  63. m_initialized = true;
  64. return ErrorCode::Success;
  65. }
  66. void Engine::run()
  67. {
  68. // Make sure the engine is initialized before entering the main loop
  69. if(!m_initialized)
  70. return;
  71. // Infinite main loop
  72. while(true)
  73. {
  74. // Update the clock
  75. m_clock->update();
  76. // Handle window and input events
  77. m_window->handleEvents();
  78. // If engine is still running
  79. if(Config::engineVar().running == true)
  80. {
  81. // Load a different engine state, if it has been changed
  82. if(m_currentStateType != Config::engineVar().engineState)
  83. {
  84. m_currentStateType = Config::engineVar().engineState;
  85. setCurrentStateType();
  86. }
  87. // Call update on the current engine state
  88. m_currentState->update(*this);
  89. // Swap buffers. If v-sync is enabled, this call should halt for appropriate time
  90. m_window->swapBuffers();
  91. }
  92. else
  93. {
  94. // If engine is not running anymore, break the loop
  95. break;
  96. }
  97. }
  98. // Call shutdown before returning
  99. shutdown();
  100. }
  101. ErrorCode Engine::initServices()
  102. {
  103. ErrorCode returnError = ErrorCode::Success;
  104. // ___________________________________
  105. // | |
  106. // | SERVICE LOCATORS INITIALIZATION |
  107. // |___________________________________|
  108. // Initialize all locators before providing them with real instances
  109. ErrHandlerLoc::init();
  110. ClockLocator::init();
  111. GUIHandlerLocator::init();
  112. TaskManagerLocator::init();
  113. WindowLocator::init();
  114. // ___________________________________
  115. // | |
  116. // | ERROR HANDLER INITIALIZATION |
  117. // |___________________________________|
  118. // Create and initialize error handler
  119. m_errorHandler = new ErrorHandler();
  120. ErrorCode errHandlerError = m_errorHandler->init();
  121. // If error handler was initialized successfully, pass it to the locator, if not, log an error
  122. if(errHandlerError == ErrorCode::Success)
  123. {
  124. ErrHandlerLoc::provide(m_errorHandler);
  125. }
  126. else
  127. printf("Error: Error handler has failed to initialize. Error code: %i\n", errHandlerError);
  128. // ___________________________________
  129. // | |
  130. // | SET CONFIGURATION VARIABLES |
  131. // |___________________________________|
  132. // Initialize configuration variables
  133. Config::init();
  134. Config::loadFromFile(Config::configFileVar().config_file);
  135. // ___________________________________
  136. // | |
  137. // | CLOCK INITIALIZATION |
  138. // |___________________________________|
  139. // Initialize clock. Still continue if there's an error, nothing would move but the engine would still run.
  140. // The error handler will be responsible for outputting error and asking user if they want to continue in this case.
  141. m_clock = new Clock();
  142. ErrorCode clockError = m_clock->init();
  143. // Check if clock was initialized successfully
  144. if(clockError == ErrorCode::Success)
  145. ClockLocator::provide(m_clock);
  146. else
  147. ErrHandlerLoc::get().log(clockError, ErrorSource::Source_Engine);
  148. // ___________________________________
  149. // | |
  150. // | WINDOW INITIALIZATION |
  151. // |___________________________________|
  152. // Initialize window system and then attempt to spawn a window
  153. m_window = new Window();
  154. ErrorCode windowError = m_window->init();
  155. if(windowError == ErrorCode::Success)
  156. {
  157. windowError = m_window->createWindow();
  158. // If the window creation failed, we don't want to continue with the engine, so return an error
  159. if(windowError != ErrorCode::Success)
  160. {
  161. ErrHandlerLoc::get().log(windowError, ErrorSource::Source_Engine);
  162. return windowError;
  163. }
  164. // Assign window class to the service locator
  165. WindowLocator::provide(m_window);
  166. }
  167. else
  168. ErrHandlerLoc::get().log(windowError, ErrorSource::Source_Engine);
  169. // ___________________________________
  170. // | |
  171. // | GLEW INITIALIZATION |
  172. // |___________________________________|
  173. glewExperimental = GL_TRUE;
  174. GLenum glewError = glewInit();
  175. // It falsely gives error 1280, putting a call here clears the error, so it won't trigger anything
  176. glGetError();
  177. // If GLEW failed to initialize, return failure, as the engine would not be able to continue
  178. if(glewError != GLEW_OK)
  179. {
  180. // Get the GLEW error before returning
  181. std::stringstream stringstreamGlewError;
  182. stringstreamGlewError << glewGetErrorString(glewError);
  183. ErrHandlerLoc::get().log(Glew_failed, ErrorSource::Source_Engine, stringstreamGlewError.str());
  184. return ErrorCode::Failure;
  185. }
  186. // ___________________________________
  187. // | |
  188. // | TASK MANAGER INITIALIZATION |
  189. // |___________________________________|
  190. // Create new task manager and initialize it
  191. m_taskManager = new TaskManager();
  192. ErrorCode taskMgrError = m_taskManager->init();
  193. // If task manager initialized successfully, provide it to the locator, otherwise log an error
  194. if(taskMgrError == ErrorCode::Success)
  195. TaskManagerLocator::provide(m_taskManager);
  196. else
  197. ErrHandlerLoc::get().log(taskMgrError, ErrorSource::Source_Engine);
  198. // ___________________________________
  199. // | |
  200. // | LOADERS INITIALIZATION |
  201. // |___________________________________|
  202. // Initialize all global loaders and check for errors
  203. ErrorCode loaderError = ErrorCode::Success;
  204. // Initialize model loaders
  205. loaderError = Loaders::model().init();
  206. if(loaderError != ErrorCode::Success)
  207. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  208. // Initialize shader loader
  209. loaderError = Loaders::shader().init();
  210. if(loaderError != ErrorCode::Success)
  211. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  212. // Initialize texture2D loader
  213. loaderError = Loaders::texture2D().init();
  214. if(loaderError != ErrorCode::Success)
  215. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  216. // Initialize textureCubemap loader
  217. loaderError = Loaders::textureCubemap().init();
  218. if(loaderError != ErrorCode::Success)
  219. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  220. // Initialize the object directory
  221. loaderError = ObjectDirectory::init();
  222. if(loaderError != ErrorCode::Success)
  223. ErrHandlerLoc::get().log(loaderError, ErrorSource::Source_Engine);
  224. // ___________________________________
  225. // | |
  226. // | OBJECT DIRECTORY INITIALIZATION |
  227. // |___________________________________|
  228. // Initialize the object directory, return failure if it wasn't successful
  229. ErrorCode objectDirectoryError = ObjectDirectory::init();
  230. if(objectDirectoryError != ErrorCode::Success)
  231. {
  232. ErrHandlerLoc::get().log(objectDirectoryError, ErrorSource::Source_ObjectDirectory);
  233. return objectDirectoryError;
  234. }
  235. // ___________________________________
  236. // | |
  237. // | GUI HANDLER INITIALIZATION |
  238. // |___________________________________|
  239. // Initialize GUI handler. Still continue if there's an error, the GUI would just be missing.
  240. // The error handler will be responsible for outputting error and asking user if they want to continue in this case.
  241. m_GUIHandler = new GUIHandler();
  242. ErrorCode guiError = m_GUIHandler->init();
  243. // Check if gui handler was initialized successfully
  244. // If so, register it in GUI Handler locator and Window system
  245. // and enable GUI in Window system
  246. if(guiError == ErrorCode::Success)
  247. {
  248. GUIHandlerLocator::provide(m_GUIHandler);
  249. m_window->registerGUIHandler(m_GUIHandler);
  250. m_window->setEnableGUI(true);
  251. }
  252. else
  253. ErrHandlerLoc::get().log(guiError, ErrorSource::Source_Engine);
  254. return returnError;
  255. }
  256. void Engine::shutdown()
  257. {
  258. // Shutdown engine states
  259. m_playstate.shutdown();
  260. // Cancel all the tasks in background threads
  261. m_taskManager->cancelBackgroundThreads();
  262. // Make sure they are canceled, by waiting for them
  263. m_taskManager->waitForBackgroundThreads();
  264. // Shutdown the task manager
  265. m_taskManager->shutdown();
  266. // Set the initialized flag to false, so the engine is not run without initializing again
  267. m_initialized = false;
  268. }