Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

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 = tan(float(m_fovY / 360.0f * 3.14159f)) * m_clipNear;
  447. GLfloat fW = fH * ((GLdouble)w)/((GLdouble)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. }