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 13KB

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