Engine.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. /***************************************************************************
  2. Engine.cpp - description
  3. -------------------
  4. begin : Wed Jan 26 2000
  5. copyright : (C) 2000 by Henrik Enqvist, GPL
  6. email : henqvist@excite.com
  7. ***************************************************************************/
  8. #include <cstdlib>
  9. #include <cmath>
  10. #include <cstring>
  11. #include <ctime>
  12. #if EM_THREADS
  13. #include <sched.h>
  14. #endif
  15. #include "Private.h"
  16. #include "Engine.h"
  17. #include "Camera.h"
  18. #include "Keyboard.h"
  19. #include "AlignVisitor.h"
  20. #include "AllegroVisitor.h"
  21. #include "AmbientLightVisitor.h"
  22. #include "BehaviorVisitor.h"
  23. #include "CollisionVisitor.h"
  24. #include "OpenGLVisitor.h"
  25. //#include "PointLightVisitor.h"
  26. //#include "PNormalVisitor.h"
  27. #include "SoundVisitor.h"
  28. #include "SignalSender.h"
  29. #include "TransformVisitor.h"
  30. #include "Config.h"
  31. #include "SoundUtil.h"
  32. #include "TextureUtil.h"
  33. #include "Profiler.h"
  34. // TODO Remove glu
  35. #if EM_USE_SDL
  36. #if EM_DEBUG
  37. #include <GL/glu.h>
  38. #endif
  39. #endif
  40. volatile int g_iStartTime = -1;
  41. //volatile int g_iDesiredTime = -1;
  42. volatile int g_iLastRender = 0;
  43. volatile unsigned int g_iLoops = 0;
  44. volatile unsigned int g_iMSeconds = 0;
  45. //volatile float g_fFps = 0.0f;
  46. #if EM_DEBUG
  47. #define StartProfile(a) Profiler::getInstance()->startProfile(a)
  48. #define StopProfile() Profiler::getInstance()->stopProfile()
  49. #else
  50. #define StartProfile(a)
  51. #define StopProfile()
  52. #endif
  53. #if EM_USE_ALLEGRO
  54. extern "C" {
  55. void fctCallBack() {
  56. g_iMSeconds += 10;
  57. }
  58. END_OF_FUNCTION(fctCallBack)
  59. }
  60. #endif
  61. #if EM_USE_SDL
  62. #define GET_TIME (signed)SDL_GetTicks()
  63. #endif
  64. #if EM_USE_ALLEGRO
  65. #define GET_TIME g_iMSeconds
  66. #endif
  67. float Engine::m_fFps = 0.0f;
  68. Engine * Engine::p_Engine = NULL;
  69. Engine::Engine(int & argc, char *argv[]) {
  70. Config * config = Config::getInstance();
  71. config->loadArgs(argc, argv);
  72. if (!config->useExternGL()) {
  73. #if EM_USE_SDL
  74. SDL_Init(SDL_INIT_TIMER);
  75. #endif
  76. TextureUtil::getInstance()->initGrx();
  77. #if EM_USE_ALLEGRO
  78. LOCK_VARIABLE(g_iStartTime);
  79. //LOCK_VARIABLE(g_iDesiredTime);
  80. LOCK_VARIABLE(g_iLastRender);
  81. LOCK_VARIABLE(g_iLoops);
  82. LOCK_VARIABLE(g_iMSeconds);
  83. LOCK_VARIABLE(g_fFps);
  84. LOCK_FUNCTION(fctCallBack);
  85. install_int(fctCallBack, 10); // 100 tick per sec
  86. #endif
  87. }
  88. SoundUtil::getInstance()->applyConfigVolume();
  89. // if (config->getSound() != 0 || config->getMusic() != 0) {
  90. // SoundUtil::getInstance()->initSound();
  91. // } else {
  92. // cerr << "**************************************************" << endl;
  93. // cerr << "Sound turned off in init function. Sound must be" << endl;
  94. // cerr << "turned on and the game must be restarted to enable" << endl;
  95. // cerr << "playback." << endl;
  96. // cerr << "**************************************************" << endl;
  97. // }
  98. srand((unsigned int)time((time_t *)NULL));
  99. p_Engine = this;
  100. }
  101. Engine::~Engine() {
  102. p_Engine = NULL;
  103. this->stopEngine();
  104. }
  105. void Engine::stopEngine() {
  106. #if EM_USE_SDL
  107. SoundUtil::getInstance()->stopSound();
  108. TextureUtil::getInstance()->stopGrx();
  109. #endif
  110. #if EM_DEBUG
  111. extern float em_groups_m, em_shapes_m, em_bounds_m, em_polygons_m;
  112. cerr << "Collision profile ********************" << endl;
  113. cerr << "Group-group detections " << em_groups_m << endl;
  114. cerr << "Shape-shape detections " << em_shapes_m << endl;
  115. cerr << "Bound-bound detections " << em_bounds_m << endl;
  116. cerr << "Poly-poly detections " << em_polygons_m << endl;
  117. Profiler::getInstance()->printProfile();
  118. // cerr << "Seconds " << ((float)g_iSeconds/FPS) <<" " << ((float)g_iLoops*FPS/g_iSeconds)
  119. // << " fps" << endl;
  120. // cerr << "Fps " << (float)(g_iLoops)*1000 / (SDL_GetTicks()-g_iStartTime) << endl;
  121. #endif
  122. }
  123. void Engine::clear() {
  124. SignalSender::getInstance()->clear();
  125. AmbientLightVisitor::getInstance()->clear();
  126. //PointLightVisitor::getInstance()->clear();
  127. this->freeObjects();
  128. }
  129. void Engine::addLight(Light* l) {
  130. //PointLightVisitor::getInstance()->add(l);
  131. AmbientLightVisitor::getInstance()->add(l);
  132. }
  133. void Engine::setClearColor(float r, float g, float b, float a) {
  134. TextureUtil::getInstance()->setClearColor(r, g, b, a);
  135. }
  136. void Engine::clearScreen() {
  137. StartProfile(SWAP);
  138. #if EM_USE_SDL
  139. glDepthMask(GL_TRUE);
  140. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  141. glColor3f(1, 1, 1);
  142. glLoadIdentity();
  143. //gluLookAt(0,0,0, 0,0,-1, 0,1,0);
  144. #endif
  145. #if EM_USE_ALLEGRO
  146. clear_zbuffer(zbuffer, 0);
  147. clear_bitmap(backbuffer);
  148. #endif
  149. StopProfile();
  150. }
  151. void Engine::setLightning(float diffuse, float ambient) {
  152. AmbientLightVisitor::getInstance()->setLightning(diffuse, ambient);
  153. // light model
  154. }
  155. void Engine::drawSplash(EmTexture * tex) {
  156. if (tex == NULL) return;
  157. #if EM_USE_SDL
  158. int filter = Config::getInstance()->getGLFilter();
  159. if (filter == -1) return;
  160. glDisable(GL_DEPTH_TEST);
  161. glDepthMask(GL_FALSE);
  162. glDisable(GL_ALPHA_TEST);
  163. glDisable(GL_BLEND);
  164. glDepthMask(GL_FALSE);
  165. glEnable(GL_TEXTURE_2D);
  166. glBindTexture(GL_TEXTURE_2D, *(tex));
  167. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
  168. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
  169. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  170. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  171. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  172. glBegin(GL_QUADS);
  173. glTexCoord2f(0, 0);
  174. glVertex3f(-EM_RIGHT, EM_UP, -1);
  175. glTexCoord2f(1, 0);
  176. glVertex3f(EM_RIGHT, EM_UP, -1);
  177. glTexCoord2f(1, 1);
  178. glVertex3f(EM_RIGHT, -EM_UP, -1);
  179. glTexCoord2f(0, 1);
  180. glVertex3f(-EM_RIGHT, -EM_UP, -1);
  181. glEnd();
  182. #endif
  183. // allegro todo
  184. #if EM_USE_ALLEGRO
  185. // TODO fix static 256x256 image size
  186. stretch_blit(tex, backbuffer, 0, 0, 256, 256, 0, 0,
  187. Config::getInstance()->getWidth(), Config::getInstance()->getHeight());
  188. #endif
  189. }
  190. void Engine::setEngineCamera(Group* g) {
  191. AlignVisitor::getInstance()->setCamera(g);
  192. TransformVisitor::getInstance()->setCamera(g);
  193. }
  194. void Engine::render() {
  195. EM_COUT("Engine::render()", 0);
  196. if (GET_TIME - g_iLastRender != 0.0f) {
  197. m_fFps = m_fFps*0.9f + 0.1f*1000.0f/(GET_TIME - g_iLastRender);
  198. }
  199. g_iLastRender = GET_TIME;
  200. // Put some overall light.
  201. StartProfile(GLIGHT);
  202. AmbientLightVisitor::getInstance()->empty();
  203. this->accept(AmbientLightVisitor::getInstance());
  204. StopProfile();
  205. // Put some light from light sources.
  206. EM_COUT("Engine::render() lights", 0);
  207. StartProfile(PLIGHT);
  208. //PointLightVisitor::getInstance()->empty();
  209. //this->accept(PointLightVisitor::getInstance());
  210. StopProfile();
  211. // Align vertices to view space.
  212. EM_COUT("Engine::render() align", 0);
  213. StartProfile(ALIGN);
  214. AlignVisitor::getInstance()->empty();
  215. this->accept(AlignVisitor::getInstance());
  216. StopProfile();
  217. // Adjust sounds.
  218. StartProfile(SOUND);
  219. // p_SoundVisitor->empty();
  220. // this->accept(p_SoundVisitor);
  221. StopProfile();
  222. this->clearScreen();
  223. // Draw screenr
  224. EM_COUT("Engine::render() render", 0);
  225. StartProfile(RENDER);
  226. #if EM_USE_SDL
  227. OpenGLVisitor::getInstance()->setMode(EM_GL_GCOL_TEX);
  228. OpenGLVisitor::getInstance()->empty();
  229. this->accept(OpenGLVisitor::getInstance());
  230. OpenGLVisitor::getInstance()->setMode(EM_GL_GCOL_TEX_TRANS);
  231. OpenGLVisitor::getInstance()->empty();
  232. this->accept(OpenGLVisitor::getInstance());
  233. OpenGLVisitor::getInstance()->setMode(EM_GL_CLEAN);
  234. OpenGLVisitor::getInstance()->empty();
  235. #endif
  236. #if EM_USE_ALLEGRO
  237. AllegroVisitor::getInstance()->setMode(EM_ALLEGRO_GCOL_TEX);
  238. AllegroVisitor::getInstance()->empty();
  239. this->accept(AllegroVisitor::getInstance());
  240. AllegroVisitor::getInstance()->setMode(EM_ALLEGRO_GCOL_TEX_TRANS);
  241. AllegroVisitor::getInstance()->empty();
  242. this->accept(AllegroVisitor::getInstance());
  243. AllegroVisitor::getInstance()->setMode(EM_GL_CLEAN);
  244. AllegroVisitor::getInstance()->empty();
  245. #endif
  246. StopProfile();
  247. }
  248. void Engine::swap() {
  249. StartProfile(SWAP);
  250. EM_COUT("Engine::swap()", 0);
  251. g_iLoops++;
  252. // Draw to screen.
  253. #if EM_USE_SDL
  254. SDL_GL_SwapBuffers();
  255. EM_GLERROR(" In Engine::swap ");
  256. #endif
  257. #if EM_USE_ALLEGRO
  258. blit(backbuffer, screen, 0, 0, 0, 0, Config::getInstance()->getWidth(), Config::getInstance()->getHeight());
  259. #endif
  260. StopProfile();
  261. }
  262. void Engine::tick() {
  263. EM_COUT("Engine::tick() key", 0);
  264. if (!Config::getInstance()->useExternGL()) {
  265. StartProfile(KEY);
  266. // Check keyboard.
  267. Keyboard::poll();
  268. StopProfile();
  269. }
  270. // Perform behaviors. Behaviors must be done before transformation and collision.
  271. EM_COUT("Engine::tick() beh", 0);
  272. StartProfile(BEH);
  273. BehaviorVisitor::getInstance()->empty();
  274. this->accept(BehaviorVisitor::getInstance());
  275. StopProfile();
  276. // Calculate positions
  277. EM_COUT("Engine::tick() trans", 0);
  278. StartProfile(TRANS);
  279. TransformVisitor::getInstance()->empty();
  280. this->accept(TransformVisitor::getInstance());
  281. StopProfile();
  282. // Detect collision.
  283. EM_COUT("Engine::tick() coll", 0);
  284. StartProfile(COLLISION);
  285. CollisionVisitor::getInstance()->empty();
  286. this->accept(CollisionVisitor::getInstance());
  287. StopProfile();
  288. // Perform signals. Signals must be done last.
  289. StartProfile(SIG);
  290. SignalSender::getInstance()->tick();
  291. StopProfile();
  292. }
  293. void Engine::delay(int ms) {
  294. #if EM_USE_SDL
  295. SDL_Delay(ms);
  296. #endif
  297. #if EM_USE_ALLEGRO
  298. rest(ms);
  299. #endif
  300. }
  301. bool Engine::nextTickFPS(int fps) {
  302. // default 100 FPS
  303. int delay = 10;
  304. if (fps > 0) {
  305. delay = 1000/fps;
  306. }
  307. if ((g_iStartTime + delay) <= GET_TIME) {
  308. g_iStartTime += delay;
  309. return true;
  310. }
  311. return false;
  312. }
  313. void Engine::resetTick() {
  314. g_iStartTime = GET_TIME;
  315. }
  316. #undef GET_TIME
  317. #if EM_THREADS
  318. volatile bool g_bThread = true;;
  319. SDL_mutex* g_Mutex = NULL;
  320. SDL_Thread* g_Thread = NULL;
  321. void Engine::renderThreadSafe() {
  322. this->pauseTickThread();
  323. EM_COUT("Engine::render()", 0);
  324. // Put some overall light.
  325. EM_COUT("Engine::render() glight", 0);
  326. AmbientLightVisitor::getInstance()->empty();
  327. this->accept(AmbientLightVisitor::getInstance());
  328. // Put some light from light sources.
  329. // EM_COUT("Engine::render() plight", 0);
  330. // PointLightVisitor::getInstance()->empty();
  331. // this->accept(PointLightVisitor::getInstance());
  332. // Align vertices to view space.
  333. EM_COUT("Engine::render() align", 0);
  334. AlignVisitor::getInstance()->empty();
  335. this->accept(AlignVisitor::getInstance());
  336. // Adjust sounds.
  337. EM_COUT("Engine::render() sound", 0);
  338. // p_SoundVisitor->empty();
  339. // this->accept(p_SoundVisitor);
  340. this->resumeTickThread();
  341. this->pauseTickThread();
  342. // Draw screen
  343. EM_COUT("Engine::render() opengl", 0);
  344. this->clearScreen();
  345. OpenGLVisitor::getInstance()->setMode(EM_GL_GCOL);
  346. OpenGLVisitor::getInstance()->empty();
  347. this->accept(OpenGLVisitor::getInstance());
  348. OpenGLVisitor::getInstance()->setMode(EM_GL_TEX);
  349. OpenGLVisitor::getInstance()->empty();
  350. this->accept(OpenGLVisitor::getInstance());
  351. this->resumeTickThread();
  352. this->pauseTickThread();
  353. OpenGLVisitor::getInstance()->setMode(EM_GL_GCOL_TRANS);
  354. OpenGLVisitor::getInstance()->empty();
  355. this->accept(OpenGLVisitor::getInstance());
  356. OpenGLVisitor::getInstance()->setMode(EM_GL_TEX_TRANS);
  357. OpenGLVisitor::getInstance()->empty();
  358. this->accept(OpenGLVisitor::getInstance());
  359. OpenGLVisitor::getInstance()->setMode(EM_GL_CLEAN);
  360. OpenGLVisitor::getInstance()->empty();
  361. EM_COUT("Engine::render() opengltrans", 0);
  362. //OpenGLTransVisitor::getInstance()->empty();
  363. //this->accept(OpenGLTransVisitor::getInstance());
  364. // The keyboard is polled here cause it is not allowed get polled from fctThread
  365. Keyboard::poll();
  366. this->resumeTickThread();
  367. }
  368. /* This function is not allowed to call render or event functions.
  369. * that's why the poll is moved to 'renderThreadSafe()' */
  370. int fctThread(void * data) {
  371. Engine* engine = (Engine*) data;
  372. while (g_bThread) {
  373. //cerr << "tick" << endl;
  374. if (SDL_mutexP(g_Mutex) == -1) cerr << "Error locking mutex" << endl;
  375. EM_COUT("Engine::tick()", 0);
  376. // Perform signals.
  377. EM_COUT("Engine::tick() signal", 0);
  378. SignalSender::getInstance()->tick();
  379. // Perform behaviors.
  380. EM_COUT("Engine::tick() behavior", 0);
  381. BehaviorVisitor::getInstance()->empty();
  382. engine->accept(BehaviorVisitor::getInstance());
  383. // Calculate positions
  384. EM_COUT("Engine::tick() trans", 0);
  385. TransformVisitor::getInstance()->empty();
  386. engine->accept(TransformVisitor::getInstance());
  387. // Detect collision.
  388. EM_COUT("Engine::tick() collision", 0);
  389. CollisionVisitor::getInstance()->empty();
  390. engine->accept(CollisionVisitor::getInstance());
  391. if (SDL_mutexV(g_Mutex) == -1) cerr << "Error unlocking mutex" << endl;
  392. engine->limitFPS(100);
  393. }
  394. return 0;
  395. }
  396. void Engine::startTickThread() {
  397. g_bThread = true;
  398. if (g_Mutex == NULL) {
  399. g_Mutex = SDL_CreateMutex();
  400. } else {
  401. cerr << "Mutex already created" << endl;
  402. }
  403. if (g_Thread == NULL) {
  404. g_Thread = SDL_CreateThread(fctThread, this);
  405. } else {
  406. cerr << "Thread already created" << endl;
  407. }
  408. }
  409. void Engine::endTickThread() {
  410. int status;
  411. g_bThread = false;
  412. SDL_WaitThread(g_Thread, &status);
  413. SDL_DestroyMutex(g_Mutex);
  414. g_Thread = NULL;
  415. g_Mutex = NULL;
  416. }
  417. void Engine::pauseTickThread() {
  418. if (g_Mutex != NULL) {
  419. if (SDL_mutexP(g_Mutex) == -1) cerr << "Error unlocking mutex" << endl;
  420. }
  421. }
  422. void Engine::resumeTickThread() {
  423. if (g_Mutex != NULL) {
  424. if (SDL_mutexV(g_Mutex) == -1) cerr << "Error unlocking mutex" << endl;
  425. }
  426. sched_yield();
  427. }
  428. #endif