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

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