Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

System.cpp 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. /*!
  2. * \file src/System.cpp
  3. * \brief Mostly defines the interface of System implementations.
  4. *
  5. * Currently only SDL is used, but there was a GLUT implementation.
  6. *
  7. * \author Mongoose
  8. */
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <sys/stat.h>
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #include <stdarg.h>
  15. #include <cmath>
  16. #ifdef USING_OPENGL
  17. #ifdef __APPLE__
  18. #include <OpenGL/gl.h>
  19. #include <OpenGL/glu.h>
  20. #else
  21. #include <GL/gl.h>
  22. #include <GL/glu.h>
  23. #endif
  24. #endif
  25. #if defined(linux) || defined(__APPLE__)
  26. #include <time.h>
  27. #include <sys/time.h>
  28. #endif
  29. #ifdef MEMORY_TEST
  30. #include <memory_test.h>
  31. #endif
  32. #include <System.h>
  33. ////////////////////////////////////////////////////////////
  34. // Constructors
  35. ////////////////////////////////////////////////////////////
  36. System::System()
  37. {
  38. m_width = 800;
  39. m_height = 600;
  40. m_fastCard = true;
  41. m_driver = 0x0;
  42. m_clipFar = 4000.0f;
  43. m_clipNear = 4.0f;
  44. m_fovY = 45.0f;
  45. mConsoleMode = false;
  46. printf("[System.Core]\n");
  47. // Hack for bad Map class, as well as reserved commands
  48. addCommandMode("[System.Console]");
  49. mConsoleKey = '`';
  50. bindKeyCommand("+console", mConsoleKey, 0);
  51. #ifdef WIN32
  52. setDriverGL("libGL32.dll");
  53. #else
  54. setDriverGL("/usr/lib/libGL.so.1");
  55. #endif
  56. }
  57. System::~System()
  58. {
  59. }
  60. ////////////////////////////////////////////////////////////
  61. // Public Accessors
  62. ////////////////////////////////////////////////////////////
  63. char *System::bufferString(const char *string, ...)
  64. {
  65. int sz = 60;
  66. int n;
  67. char *text;
  68. va_list args;
  69. // Mongoose 2002.01.01, Only allow valid strings
  70. // we must assume it's NULL terminated also if it passes...
  71. if (!string || !string[0])
  72. {
  73. return NULL;
  74. }
  75. text = new char[sz];
  76. va_start(args, string);
  77. // Mongoose 2002.01.01, Get exact size needed if the first try fails
  78. n = vsnprintf(text, sz, string, args);
  79. // Mongoose 2002.01.01, Realloc correct amount if truncated
  80. while (1)
  81. {
  82. if (n > -1 && n < sz)
  83. {
  84. break;
  85. }
  86. // Mongoose 2002.01.01, For glibc 2.1
  87. if (n > -1)
  88. {
  89. sz = n + 1;
  90. delete [] text;
  91. text = new char[sz];
  92. n = vsnprintf(text, sz, string, args);
  93. break;
  94. }
  95. else // glibc 2.0
  96. {
  97. sz *= 2;
  98. delete [] text;
  99. text = new char[sz];
  100. n = vsnprintf(text, sz, string, args);
  101. }
  102. }
  103. va_end(args);
  104. return text;
  105. }
  106. char *System::fullPath(const char *path, char end)
  107. {
  108. unsigned int i, lenPath, lenEnv, len;
  109. char *env, *dir;
  110. if (!path || !path[0])
  111. return 0;
  112. if (path[0] == '~')
  113. {
  114. #if defined(unix) || defined(__APPLE__)
  115. env = getenv("HOME");
  116. if (!env || !env[0])
  117. {
  118. return 0;
  119. }
  120. lenEnv = strlen(env);
  121. lenPath = strlen(path);
  122. len = lenEnv + lenPath;
  123. dir = new char[len+1];
  124. // Mongoose 2002.08.17, Copy ENV, strip '~', append rest of path
  125. for (i = 0; i < len; ++i)
  126. {
  127. if (i < lenEnv)
  128. {
  129. dir[i] = env[i];
  130. }
  131. else
  132. {
  133. dir[i] = path[1+(i-lenEnv)];
  134. }
  135. }
  136. #else
  137. #error Platform not supported!
  138. #endif
  139. }
  140. else
  141. {
  142. lenPath = strlen(path);
  143. dir = new char[lenPath+1];
  144. strncpy(dir, path, lenPath);
  145. i = lenPath;
  146. }
  147. // Make sure ends in "end" char
  148. if (end && dir[i-1] != end)
  149. {
  150. dir[i++] = end;
  151. }
  152. dir[i] = 0;
  153. return dir;
  154. }
  155. char *System::getFileFromFullPath(char *filename)
  156. {
  157. int i, j, len;
  158. char *str;
  159. len = strlen(filename);
  160. for (i = len, j = 0; i > 0; --i, ++j)
  161. {
  162. if (filename[i] == '/' || filename[i] == '\\')
  163. break;
  164. }
  165. j--;
  166. str = new char[len - j + 1];
  167. for (i = 0; i < len - j; ++i)
  168. {
  169. str[i] = filename[i + len - j];
  170. }
  171. str[i] = 0;
  172. return str;
  173. }
  174. unsigned int System::getTicks()
  175. {
  176. return system_timer(1);
  177. }
  178. int System::createDir(char *path)
  179. {
  180. #ifdef WIN32
  181. return _mkdir(path);
  182. #else
  183. return mkdir(path, S_IRWXU | S_IRWXG);
  184. #endif
  185. }
  186. ////////////////////////////////////////////////////////////
  187. // Public Mutators
  188. ////////////////////////////////////////////////////////////
  189. unsigned int System::addCommandMode(const char *command)
  190. {
  191. if (command && command[0] == '[')
  192. {
  193. mCmdModes.pushBack(command);
  194. return (mCmdModes.size() - 1);
  195. }
  196. else
  197. {
  198. return 0;
  199. }
  200. }
  201. //! \fixme Modifer support later
  202. void System::bindKeyCommand(const char *cmd, unsigned int key, int event)
  203. {
  204. printf("Bound command '%s' -> event %i (0x%x key)\n", cmd, event, key);
  205. mKeyEvents.Add(key, event);
  206. }
  207. void System::command(const char *cmd)
  208. {
  209. bool modeFound = false;
  210. char *cmdbuf;
  211. if (!cmd || !cmd[0]) // Null command string
  212. return;
  213. if (cmd[0] == '[') // Set a mode, eg "[Engine.OpenGL.Driver]"
  214. {
  215. for (mCmdModes.start(); mCmdModes.forward(); mCmdModes.next())
  216. {
  217. if (strcmp(cmd, mCmdModes.current()) == 0)
  218. {
  219. mCommandMode = mCmdModes.getCurrentIndex();
  220. modeFound = true;
  221. }
  222. }
  223. if (!modeFound)
  224. {
  225. // mCommandMode = 0;
  226. printf("Command> Unknown mode '%s'\n", cmd);
  227. }
  228. }
  229. else // Execute a command in current mode, eg "stat fps"
  230. {
  231. cmdbuf = new char[strlen(cmd) + 1];
  232. strncpy(cmdbuf, cmd, strlen(cmd) + 1);
  233. handleCommand(cmdbuf, mCommandMode);
  234. }
  235. }
  236. int System::loadResourceFile(const char *filename)
  237. {
  238. char buffer[256];
  239. bool line_comment = false;
  240. FILE *f;
  241. char c;
  242. int i, j;
  243. f = fopen(filename, "r");
  244. if (!f)
  245. {
  246. perror(filename);
  247. return -1;
  248. }
  249. printf("Loading %s...\n", filename);
  250. i = 0;
  251. buffer[0] = 0;
  252. // Strip out whitespace and comments
  253. while (fscanf(f, "%c", &c) != EOF)
  254. {
  255. if (line_comment && c != '\n')
  256. continue;
  257. if (i > 254)
  258. {
  259. printf("loadResourceFile> Overflow handled\n");
  260. i = 254;
  261. }
  262. switch (c)
  263. {
  264. case '\v':
  265. case '\t':
  266. break;
  267. case '#':
  268. buffer[i++] = 0;
  269. line_comment = true;
  270. break;
  271. case '\n':
  272. if (line_comment)
  273. {
  274. line_comment = false;
  275. }
  276. if (buffer[0] == 0)
  277. {
  278. i = 0;
  279. continue;
  280. }
  281. buffer[i] = 0;
  282. //printf("'%s'\n", buffer);
  283. // 'Preprocessor' commands
  284. if (buffer[0] == '@')
  285. {
  286. if (strncmp(buffer, "@include ", 9) == 0)
  287. {
  288. for (j = 9; j < i; ++j)
  289. {
  290. buffer[j-9] = buffer[j];
  291. buffer[j-8] = 0;
  292. }
  293. printf("Importing '%s'\n", buffer);
  294. loadResourceFile(fullPath(buffer, '/'));
  295. }
  296. }
  297. else
  298. {
  299. command(buffer);
  300. }
  301. i = 0;
  302. buffer[0] = 0;
  303. break;
  304. default:
  305. buffer[i++] = c;
  306. }
  307. }
  308. fclose(f);
  309. return 0;
  310. }
  311. void System::setDriverGL(const char *driver)
  312. {
  313. unsigned int len;
  314. if (m_driver)
  315. {
  316. delete [] m_driver;
  317. }
  318. if (driver && driver[0])
  319. {
  320. len = strlen(driver);
  321. m_driver = new char[len+1];
  322. strncpy(m_driver, driver, len);
  323. m_driver[len] = 0;
  324. }
  325. }
  326. void System::setFastCardPerformance(bool is_fast)
  327. {
  328. m_fastCard = is_fast;
  329. }
  330. void System::resetTicks()
  331. {
  332. system_timer(0);
  333. }
  334. void System::initGL()
  335. {
  336. char *s;
  337. // Print driver support information
  338. printf("\n\n\t## GL Driver Info 1 ##\n");
  339. printf("\tVendor : %s\n", glGetString(GL_VENDOR));
  340. printf("\tRenderer : %s\n", glGetString(GL_RENDERER));
  341. printf("\tVersion : %s\n", glGetString(GL_VERSION));
  342. printf("\tExtensions : %s\n\n\n", (char*)glGetString(GL_EXTENSIONS));
  343. // Testing for goodies
  344. // Mongoose 2001.12.31, Fixed string use to check for bad strings
  345. s = (char*)glGetString(GL_EXTENSIONS);
  346. if (s && s[0])
  347. {
  348. printf("\tGL_ARB_multitexture \t\t");
  349. if (strstr(s, "GL_ARB_multitexture"))
  350. {
  351. printf("YES\n");
  352. }
  353. else
  354. {
  355. printf("NO\n");
  356. }
  357. //glActiveTextureARB
  358. //glMultiTexCoord2fARB
  359. //glFogCoordfEXT
  360. printf("\tGL_EXT_texture_env_combine\t\t");
  361. if (strstr(s, "GL_EXT_texture_env_combine"))
  362. {
  363. printf("YES\n");
  364. }
  365. else
  366. {
  367. printf("NO\n");
  368. }
  369. }
  370. // Set up Z buffer
  371. glEnable(GL_DEPTH_TEST);
  372. glDepthFunc(GL_LESS);
  373. // Set up culling
  374. glEnable(GL_CULL_FACE);
  375. //glFrontFace(GL_CW);
  376. glFrontFace(GL_CCW);
  377. //glCullFace(GL_FRONT);
  378. // Set background to black
  379. glClearColor(0.0, 0.0, 0.0, 1.0);
  380. // Disable lighting
  381. glDisable(GL_LIGHTING);
  382. // Set up alpha blending
  383. if (m_fastCard)
  384. {
  385. glEnable(GL_BLEND);
  386. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  387. //glEnable(GL_ALPHA_TEST); // Disable per pixel alpha blending
  388. glAlphaFunc(GL_GREATER, 0);
  389. }
  390. else
  391. {
  392. glDisable(GL_BLEND);
  393. glDisable(GL_ALPHA_TEST);
  394. }
  395. glPointSize(5.0);
  396. // Setup shading
  397. glShadeModel(GL_SMOOTH);
  398. if (m_fastCard)
  399. {
  400. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  401. glHint(GL_FOG_HINT, GL_NICEST);
  402. glDisable(GL_COLOR_MATERIAL);
  403. glEnable(GL_DITHER);
  404. // AA polygon edges
  405. //glEnable(GL_POLYGON_SMOOTH);
  406. //glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
  407. glEnable(GL_POINT_SMOOTH);
  408. }
  409. else
  410. {
  411. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
  412. glHint(GL_FOG_HINT, GL_FASTEST);
  413. glDisable(GL_COLOR_MATERIAL);
  414. glDisable(GL_DITHER);
  415. glDisable(GL_POLYGON_SMOOTH);
  416. glDisable(GL_POINT_SMOOTH);
  417. glDisable(GL_FOG);
  418. }
  419. glDisable(GL_LINE_SMOOTH);
  420. glDisable(GL_AUTO_NORMAL);
  421. glDisable(GL_LOGIC_OP);
  422. glDisable(GL_TEXTURE_1D);
  423. glDisable(GL_STENCIL_TEST);
  424. glDisable(GL_NORMALIZE);
  425. glEnableClientState(GL_VERTEX_ARRAY);
  426. glDisableClientState(GL_EDGE_FLAG_ARRAY);
  427. glDisableClientState(GL_COLOR_ARRAY);
  428. glDisableClientState(GL_NORMAL_ARRAY);
  429. glPolygonMode(GL_FRONT, GL_FILL);
  430. glMatrixMode(GL_MODELVIEW);
  431. }
  432. void System::resizeGL(unsigned int w, unsigned int h)
  433. {
  434. if (!w || !h)
  435. {
  436. printf("resizeGL> ERROR assertions 'w > 0', 'h > 0' failed\n");
  437. return;
  438. }
  439. glViewport(0, 0, w, h);
  440. glMatrixMode(GL_PROJECTION);
  441. glLoadIdentity();
  442. // Adjust clipping
  443. // gluPerspective is deprecated!
  444. // gluPerspective(m_fovY, ((GLdouble)w)/((GLdouble)h), m_clipNear, m_clipFar);
  445. // Fix: http://stackoverflow.com/a/2417756
  446. GLfloat fH = tanf(m_fovY / 360.0f * 3.14159f) * m_clipNear;
  447. GLfloat fW = fH * ((GLfloat)w)/((GLfloat)h);
  448. glFrustum(-fW, fW, -fH, fH, m_clipNear, m_clipFar);
  449. glMatrixMode(GL_MODELVIEW);
  450. }
  451. ////////////////////////////////////////////////////////////
  452. // Private Accessors
  453. ////////////////////////////////////////////////////////////
  454. ////////////////////////////////////////////////////////////
  455. // Private Mutators
  456. ////////////////////////////////////////////////////////////
  457. ////////////////////////////////////////////////////////////
  458. // Gobal helper functions
  459. ////////////////////////////////////////////////////////////
  460. // Mongoose 2002.03.23, Checks command to see if it's same
  461. // as symbol, then returns the arg list in command buffer
  462. bool rc_command(const char *symbol, char *command)
  463. {
  464. int i, j, lens, lenc;
  465. if (!symbol || !symbol[0] || !command || !command[0])
  466. {
  467. return false;
  468. }
  469. lens = strlen(symbol);
  470. if (strncmp(command, symbol, lens) == 0)
  471. {
  472. lenc = strlen(command);
  473. // lens+1 skips '=' or ' '
  474. for (i = 0, j = lens+1; j < lenc; ++i, ++j)
  475. {
  476. command[i] = command[j];
  477. command[i+1] = 0;
  478. }
  479. return true;
  480. }
  481. return false;
  482. }
  483. int rc_get_bool(char *buffer, bool *val)
  484. {
  485. if (!buffer || !buffer[0])
  486. {
  487. return -1;
  488. }
  489. if (strncmp(buffer, "true", 4) == 0)
  490. *val = true;
  491. else if (strncmp(buffer, "false", 5) == 0)
  492. *val = false;
  493. else
  494. return -2;
  495. return 0;
  496. }
  497. unsigned int system_timer(int state)
  498. {
  499. static struct timeval start;
  500. static struct timeval stop;
  501. static struct timeval total;
  502. static struct timezone tz;
  503. switch (state)
  504. {
  505. case 0:
  506. gettimeofday(&start, &tz);
  507. total.tv_sec = 0;
  508. total.tv_usec = 0;
  509. break;
  510. case 1:
  511. gettimeofday(&stop, &tz);
  512. if (start.tv_usec > stop.tv_usec)
  513. {
  514. #ifdef OBSOLETE
  515. stop.tv_usec = (1000000 + stop.tv_usec);
  516. #else
  517. stop.tv_usec = (1000 + stop.tv_usec);
  518. #endif
  519. stop.tv_sec--;
  520. }
  521. stop.tv_usec -= start.tv_usec;
  522. stop.tv_sec -= start.tv_sec;
  523. #ifdef OBSOLETE
  524. total.tv_sec += stop.tv_sec;
  525. total.tv_usec += stop.tv_usec;
  526. while (total.tv_usec > 1000000)
  527. {
  528. total.tv_usec -= 1000000;
  529. total.tv_sec++;
  530. }
  531. return total.tv_sec * 1000000 + total.tv_usec;
  532. #else
  533. return (stop.tv_sec-start.tv_sec)*1000+(stop.tv_usec-start.tv_usec)/1000;
  534. #endif
  535. }
  536. return 0;
  537. }