PlatformLinux.cpp 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  1. #ifdef __linux__
  2. #include "Base.h"
  3. #include "Platform.h"
  4. #include "FileSystem.h"
  5. #include "Game.h"
  6. #include "Form.h"
  7. #include "ScriptController.h"
  8. #include <X11/X.h>
  9. #include <X11/Xlib.h>
  10. #include <X11/keysym.h>
  11. #include <sys/time.h>
  12. #include <GL/glxew.h>
  13. #include <poll.h>
  14. #define TOUCH_COUNT_MAX 4
  15. using namespace std;
  16. struct timespec __timespec;
  17. static double __timeStart;
  18. static double __timeAbsolute;
  19. static bool __vsync = WINDOW_VSYNC;
  20. static float __pitch;
  21. static float __roll;
  22. static bool __cursorVisible = true;
  23. static Display* __display;
  24. static Window __window;
  25. static int __windowSize[2];
  26. static GLXContext __context;
  27. static Window __attachToWindow;
  28. static Atom __atomWmDeleteWindow;
  29. namespace gameplay
  30. {
  31. // Gets the Keyboard::Key enumeration constant that corresponds to the given X11 key symbol.
  32. static Keyboard::Key getKey(KeySym sym)
  33. {
  34. switch (sym)
  35. {
  36. case XK_Sys_Req:
  37. return Keyboard::KEY_SYSREQ;
  38. case XK_Break:
  39. return Keyboard::KEY_BREAK;
  40. case XK_Menu :
  41. return Keyboard::KEY_MENU;
  42. case XK_KP_Enter:
  43. return Keyboard::KEY_KP_ENTER;
  44. case XK_Pause:
  45. return Keyboard::KEY_PAUSE;
  46. case XK_Scroll_Lock:
  47. return Keyboard::KEY_SCROLL_LOCK;
  48. case XK_Print:
  49. return Keyboard::KEY_PRINT;
  50. case XK_Escape:
  51. return Keyboard::KEY_ESCAPE;
  52. case XK_BackSpace:
  53. return Keyboard::KEY_BACKSPACE;
  54. case XK_Tab:
  55. return Keyboard::KEY_TAB;
  56. case XK_Return:
  57. return Keyboard::KEY_RETURN;
  58. case XK_Caps_Lock:
  59. return Keyboard::KEY_CAPS_LOCK;
  60. case XK_Shift_L:
  61. case XK_Shift_R:
  62. return Keyboard::KEY_SHIFT;
  63. case XK_Control_L:
  64. case XK_Control_R:
  65. return Keyboard::KEY_CTRL;
  66. case XK_Alt_L:
  67. case XK_Alt_R:
  68. return Keyboard::KEY_ALT;
  69. case XK_Hyper_L:
  70. case XK_Hyper_R:
  71. return Keyboard::KEY_HYPER;
  72. case XK_Insert:
  73. return Keyboard::KEY_INSERT;
  74. case XK_Home:
  75. return Keyboard::KEY_HOME;
  76. case XK_Page_Up:
  77. return Keyboard::KEY_PG_UP;
  78. case XK_Delete:
  79. return Keyboard::KEY_DELETE;
  80. case XK_End:
  81. return Keyboard::KEY_END;
  82. case XK_Page_Down:
  83. return Keyboard::KEY_PG_DOWN;
  84. case XK_Left:
  85. return Keyboard::KEY_LEFT_ARROW;
  86. case XK_Right:
  87. return Keyboard::KEY_RIGHT_ARROW;
  88. case XK_Up:
  89. return Keyboard::KEY_UP_ARROW;
  90. case XK_Down:
  91. return Keyboard::KEY_DOWN_ARROW;
  92. case XK_Num_Lock:
  93. return Keyboard::KEY_NUM_LOCK;
  94. case XK_KP_Add:
  95. return Keyboard::KEY_KP_PLUS;
  96. case XK_KP_Subtract:
  97. return Keyboard::KEY_KP_MINUS;
  98. case XK_KP_Multiply:
  99. return Keyboard::KEY_KP_MULTIPLY;
  100. case XK_KP_Divide:
  101. return Keyboard::KEY_KP_DIVIDE;
  102. case XK_KP_Home:
  103. return Keyboard::KEY_KP_HOME;
  104. case XK_KP_Up:
  105. return Keyboard::KEY_KP_UP;
  106. case XK_KP_Page_Up:
  107. return Keyboard::KEY_KP_PG_UP;
  108. case XK_KP_Left:
  109. return Keyboard::KEY_KP_LEFT;
  110. case XK_KP_5:
  111. return Keyboard::KEY_KP_FIVE;
  112. case XK_KP_Right:
  113. return Keyboard::KEY_KP_RIGHT;
  114. case XK_KP_End:
  115. return Keyboard::KEY_KP_END;
  116. case XK_KP_Down:
  117. return Keyboard::KEY_KP_DOWN;
  118. case XK_KP_Page_Down:
  119. return Keyboard::KEY_KP_PG_DOWN;
  120. case XK_KP_Insert:
  121. return Keyboard::KEY_KP_INSERT;
  122. case XK_KP_Delete:
  123. return Keyboard::KEY_KP_DELETE;
  124. case XK_F1:
  125. return Keyboard::KEY_F1;
  126. case XK_F2:
  127. return Keyboard::KEY_F2;
  128. case XK_F3:
  129. return Keyboard::KEY_F3;
  130. case XK_F4:
  131. return Keyboard::KEY_F4;
  132. case XK_F5:
  133. return Keyboard::KEY_F5;
  134. case XK_F6:
  135. return Keyboard::KEY_F6;
  136. case XK_F7:
  137. return Keyboard::KEY_F7;
  138. case XK_F8:
  139. return Keyboard::KEY_F8;
  140. case XK_F9:
  141. return Keyboard::KEY_F9;
  142. case XK_F10:
  143. return Keyboard::KEY_F10;
  144. case XK_F11:
  145. return Keyboard::KEY_F11;
  146. case XK_F12:
  147. return Keyboard::KEY_F12;
  148. case XK_KP_Space:
  149. case XK_space:
  150. return Keyboard::KEY_SPACE;
  151. case XK_parenright:
  152. return Keyboard::KEY_RIGHT_PARENTHESIS;
  153. case XK_0:
  154. return Keyboard::KEY_ZERO;
  155. case XK_exclam:
  156. return Keyboard::KEY_EXCLAM;
  157. case XK_1:
  158. return Keyboard::KEY_ONE;
  159. case XK_at:
  160. return Keyboard::KEY_AT;
  161. case XK_2:
  162. return Keyboard::KEY_TWO;
  163. case XK_numbersign:
  164. return Keyboard::KEY_NUMBER;
  165. case XK_3:
  166. return Keyboard::KEY_THREE;
  167. case XK_dollar:
  168. return Keyboard::KEY_DOLLAR;
  169. case XK_4:
  170. return Keyboard::KEY_FOUR;
  171. case XK_percent:
  172. case XK_asciicircum :
  173. return Keyboard::KEY_CIRCUMFLEX;
  174. return Keyboard::KEY_PERCENT;
  175. case XK_5:
  176. return Keyboard::KEY_FIVE;
  177. case XK_6:
  178. return Keyboard::KEY_SIX;
  179. case XK_ampersand:
  180. return Keyboard::KEY_AMPERSAND;
  181. case XK_7:
  182. return Keyboard::KEY_SEVEN;
  183. case XK_asterisk:
  184. return Keyboard::KEY_ASTERISK;
  185. case XK_8:
  186. return Keyboard::KEY_EIGHT;
  187. case XK_parenleft:
  188. return Keyboard::KEY_LEFT_PARENTHESIS;
  189. case XK_9:
  190. return Keyboard::KEY_NINE;
  191. case XK_equal:
  192. return Keyboard::KEY_EQUAL;
  193. case XK_plus:
  194. return Keyboard::KEY_PLUS;
  195. case XK_less:
  196. return Keyboard::KEY_LESS_THAN;
  197. case XK_comma:
  198. return Keyboard::KEY_COMMA;
  199. case XK_underscore:
  200. return Keyboard::KEY_UNDERSCORE;
  201. case XK_minus:
  202. return Keyboard::KEY_MINUS;
  203. case XK_greater:
  204. return Keyboard::KEY_GREATER_THAN;
  205. case XK_period:
  206. return Keyboard::KEY_PERIOD;
  207. case XK_colon:
  208. return Keyboard::KEY_COLON;
  209. case XK_semicolon:
  210. return Keyboard::KEY_SEMICOLON;
  211. case XK_question:
  212. return Keyboard::KEY_QUESTION;
  213. case XK_slash:
  214. return Keyboard::KEY_SLASH;
  215. case XK_grave:
  216. return Keyboard::KEY_GRAVE;
  217. case XK_asciitilde:
  218. return Keyboard::KEY_TILDE;
  219. case XK_braceleft:
  220. return Keyboard::KEY_LEFT_BRACE;
  221. case XK_bracketleft:
  222. return Keyboard::KEY_LEFT_BRACKET;
  223. case XK_bar:
  224. return Keyboard::KEY_BAR;
  225. case XK_backslash:
  226. return Keyboard::KEY_BACK_SLASH;
  227. case XK_braceright:
  228. return Keyboard::KEY_RIGHT_BRACE;
  229. case XK_bracketright:
  230. return Keyboard::KEY_RIGHT_BRACKET;
  231. case XK_quotedbl:
  232. return Keyboard::KEY_QUOTE;
  233. case XK_apostrophe:
  234. return Keyboard::KEY_APOSTROPHE;
  235. case XK_EuroSign:
  236. return Keyboard::KEY_EURO;
  237. case XK_sterling:
  238. return Keyboard::KEY_POUND;
  239. case XK_yen:
  240. return Keyboard::KEY_YEN;
  241. case XK_periodcentered:
  242. return Keyboard::KEY_MIDDLE_DOT;
  243. case XK_A:
  244. return Keyboard::KEY_CAPITAL_A;
  245. case XK_a:
  246. return Keyboard::KEY_A;
  247. case XK_B:
  248. return Keyboard::KEY_CAPITAL_B;
  249. case XK_b:
  250. return Keyboard::KEY_B;
  251. case XK_C:
  252. return Keyboard::KEY_CAPITAL_C;
  253. case XK_c:
  254. return Keyboard::KEY_C;
  255. case XK_D:
  256. return Keyboard::KEY_CAPITAL_D;
  257. case XK_d:
  258. return Keyboard::KEY_D;
  259. case XK_E:
  260. return Keyboard::KEY_CAPITAL_E;
  261. case XK_e:
  262. return Keyboard::KEY_E;
  263. case XK_F:
  264. return Keyboard::KEY_CAPITAL_F;
  265. case XK_f:
  266. return Keyboard::KEY_F;
  267. case XK_G:
  268. return Keyboard::KEY_CAPITAL_G;
  269. case XK_g:
  270. return Keyboard::KEY_G;
  271. case XK_H:
  272. return Keyboard::KEY_CAPITAL_H;
  273. case XK_h:
  274. return Keyboard::KEY_H;
  275. case XK_I:
  276. return Keyboard::KEY_CAPITAL_I;
  277. case XK_i:
  278. return Keyboard::KEY_I;
  279. case XK_J:
  280. return Keyboard::KEY_CAPITAL_J;
  281. case XK_j:
  282. return Keyboard::KEY_J;
  283. case XK_K:
  284. return Keyboard::KEY_CAPITAL_K;
  285. case XK_k:
  286. return Keyboard::KEY_K;
  287. case XK_L:
  288. return Keyboard::KEY_CAPITAL_L;
  289. case XK_l:
  290. return Keyboard::KEY_L;
  291. case XK_M:
  292. return Keyboard::KEY_CAPITAL_M;
  293. case XK_m:
  294. return Keyboard::KEY_M;
  295. case XK_N:
  296. return Keyboard::KEY_CAPITAL_N;
  297. case XK_n:
  298. return Keyboard::KEY_N;
  299. case XK_O:
  300. return Keyboard::KEY_CAPITAL_O;
  301. case XK_o:
  302. return Keyboard::KEY_O;
  303. case XK_P:
  304. return Keyboard::KEY_CAPITAL_P;
  305. case XK_p:
  306. return Keyboard::KEY_P;
  307. case XK_Q:
  308. return Keyboard::KEY_CAPITAL_Q;
  309. case XK_q:
  310. return Keyboard::KEY_Q;
  311. case XK_R:
  312. return Keyboard::KEY_CAPITAL_R;
  313. case XK_r:
  314. return Keyboard::KEY_R;
  315. case XK_S:
  316. return Keyboard::KEY_CAPITAL_S;
  317. case XK_s:
  318. return Keyboard::KEY_S;
  319. case XK_T:
  320. return Keyboard::KEY_CAPITAL_T;
  321. case XK_t:
  322. return Keyboard::KEY_T;
  323. case XK_U:
  324. return Keyboard::KEY_CAPITAL_U;
  325. case XK_u:
  326. return Keyboard::KEY_U;
  327. case XK_V:
  328. return Keyboard::KEY_CAPITAL_V;
  329. case XK_v:
  330. return Keyboard::KEY_V;
  331. case XK_W:
  332. return Keyboard::KEY_CAPITAL_W;
  333. case XK_w:
  334. return Keyboard::KEY_W;
  335. case XK_X:
  336. return Keyboard::KEY_CAPITAL_X;
  337. case XK_x:
  338. return Keyboard::KEY_X;
  339. case XK_Y:
  340. return Keyboard::KEY_CAPITAL_Y;
  341. case XK_y:
  342. return Keyboard::KEY_Y;
  343. case XK_Z:
  344. return Keyboard::KEY_CAPITAL_Z;
  345. case XK_z:
  346. return Keyboard::KEY_Z;
  347. default:
  348. return Keyboard::KEY_NONE;
  349. }
  350. }
  351. /**
  352. * Returns the unicode value for the given keycode or zero if the key is not a valid printable character.
  353. */
  354. static int getUnicode(Keyboard::Key key)
  355. {
  356. switch (key)
  357. {
  358. case Keyboard::KEY_BACKSPACE:
  359. return 0x0008;
  360. case Keyboard::KEY_TAB:
  361. return 0x0009;
  362. case Keyboard::KEY_RETURN:
  363. case Keyboard::KEY_KP_ENTER:
  364. return 0x000A;
  365. case Keyboard::KEY_ESCAPE:
  366. return 0x001B;
  367. case Keyboard::KEY_SPACE:
  368. case Keyboard::KEY_EXCLAM:
  369. case Keyboard::KEY_QUOTE:
  370. case Keyboard::KEY_NUMBER:
  371. case Keyboard::KEY_DOLLAR:
  372. case Keyboard::KEY_PERCENT:
  373. case Keyboard::KEY_CIRCUMFLEX:
  374. case Keyboard::KEY_AMPERSAND:
  375. case Keyboard::KEY_APOSTROPHE:
  376. case Keyboard::KEY_LEFT_PARENTHESIS:
  377. case Keyboard::KEY_RIGHT_PARENTHESIS:
  378. case Keyboard::KEY_ASTERISK:
  379. case Keyboard::KEY_PLUS:
  380. case Keyboard::KEY_COMMA:
  381. case Keyboard::KEY_MINUS:
  382. case Keyboard::KEY_PERIOD:
  383. case Keyboard::KEY_SLASH:
  384. case Keyboard::KEY_ZERO:
  385. case Keyboard::KEY_ONE:
  386. case Keyboard::KEY_TWO:
  387. case Keyboard::KEY_THREE:
  388. case Keyboard::KEY_FOUR:
  389. case Keyboard::KEY_FIVE:
  390. case Keyboard::KEY_SIX:
  391. case Keyboard::KEY_SEVEN:
  392. case Keyboard::KEY_EIGHT:
  393. case Keyboard::KEY_NINE:
  394. case Keyboard::KEY_COLON:
  395. case Keyboard::KEY_SEMICOLON:
  396. case Keyboard::KEY_LESS_THAN:
  397. case Keyboard::KEY_EQUAL:
  398. case Keyboard::KEY_GREATER_THAN:
  399. case Keyboard::KEY_QUESTION:
  400. case Keyboard::KEY_AT:
  401. case Keyboard::KEY_CAPITAL_A:
  402. case Keyboard::KEY_CAPITAL_B:
  403. case Keyboard::KEY_CAPITAL_C:
  404. case Keyboard::KEY_CAPITAL_D:
  405. case Keyboard::KEY_CAPITAL_E:
  406. case Keyboard::KEY_CAPITAL_F:
  407. case Keyboard::KEY_CAPITAL_G:
  408. case Keyboard::KEY_CAPITAL_H:
  409. case Keyboard::KEY_CAPITAL_I:
  410. case Keyboard::KEY_CAPITAL_J:
  411. case Keyboard::KEY_CAPITAL_K:
  412. case Keyboard::KEY_CAPITAL_L:
  413. case Keyboard::KEY_CAPITAL_M:
  414. case Keyboard::KEY_CAPITAL_N:
  415. case Keyboard::KEY_CAPITAL_O:
  416. case Keyboard::KEY_CAPITAL_P:
  417. case Keyboard::KEY_CAPITAL_Q:
  418. case Keyboard::KEY_CAPITAL_R:
  419. case Keyboard::KEY_CAPITAL_S:
  420. case Keyboard::KEY_CAPITAL_T:
  421. case Keyboard::KEY_CAPITAL_U:
  422. case Keyboard::KEY_CAPITAL_V:
  423. case Keyboard::KEY_CAPITAL_W:
  424. case Keyboard::KEY_CAPITAL_X:
  425. case Keyboard::KEY_CAPITAL_Y:
  426. case Keyboard::KEY_CAPITAL_Z:
  427. case Keyboard::KEY_LEFT_BRACKET:
  428. case Keyboard::KEY_BACK_SLASH:
  429. case Keyboard::KEY_RIGHT_BRACKET:
  430. case Keyboard::KEY_UNDERSCORE:
  431. case Keyboard::KEY_GRAVE:
  432. case Keyboard::KEY_A:
  433. case Keyboard::KEY_B:
  434. case Keyboard::KEY_C:
  435. case Keyboard::KEY_D:
  436. case Keyboard::KEY_E:
  437. case Keyboard::KEY_F:
  438. case Keyboard::KEY_G:
  439. case Keyboard::KEY_H:
  440. case Keyboard::KEY_I:
  441. case Keyboard::KEY_J:
  442. case Keyboard::KEY_K:
  443. case Keyboard::KEY_L:
  444. case Keyboard::KEY_M:
  445. case Keyboard::KEY_N:
  446. case Keyboard::KEY_O:
  447. case Keyboard::KEY_P:
  448. case Keyboard::KEY_Q:
  449. case Keyboard::KEY_R:
  450. case Keyboard::KEY_S:
  451. case Keyboard::KEY_T:
  452. case Keyboard::KEY_U:
  453. case Keyboard::KEY_V:
  454. case Keyboard::KEY_W:
  455. case Keyboard::KEY_X:
  456. case Keyboard::KEY_Y:
  457. case Keyboard::KEY_Z:
  458. case Keyboard::KEY_LEFT_BRACE:
  459. case Keyboard::KEY_BAR:
  460. case Keyboard::KEY_RIGHT_BRACE:
  461. case Keyboard::KEY_TILDE:
  462. return key;
  463. default:
  464. return 0;
  465. }
  466. }
  467. extern void print(const char* format, ...)
  468. {
  469. GP_ASSERT(format);
  470. va_list argptr;
  471. va_start(argptr, format);
  472. vfprintf(stderr, format, argptr);
  473. va_end(argptr);
  474. }
  475. Platform::Platform(Game* game) : _game(game)
  476. {
  477. }
  478. Platform::~Platform()
  479. {
  480. }
  481. Platform* Platform::create(Game* game, void* attachToWindow)
  482. {
  483. GP_ASSERT(game);
  484. __attachToWindow = (Window)attachToWindow;
  485. FileSystem::setResourcePath("./");
  486. Platform* platform = new Platform(game);
  487. // Get the display and initialize
  488. __display = XOpenDisplay(NULL);
  489. if (__display == NULL)
  490. {
  491. perror("XOpenDisplay");
  492. return NULL;
  493. }
  494. // Get the window configuration values
  495. const char *title = NULL;
  496. int __x = 0, __y = 0, __width = 1280, __height = 800;
  497. bool fullscreen = false;
  498. if (game->getConfig())
  499. {
  500. Properties* config = game->getConfig()->getNamespace("window", true);
  501. if (config)
  502. {
  503. // Read window title.
  504. title = config->getString("title");
  505. // Read window rect.
  506. int x = config->getInt("x");
  507. int y = config->getInt("y");
  508. int width = config->getInt("width");
  509. int height = config->getInt("height");
  510. fullscreen = config->getBool("fullscreen");
  511. if (fullscreen && width == 0 && height == 0)
  512. {
  513. // Use the screen resolution if fullscreen is true but width and height were not set in the config
  514. int screen_num = DefaultScreen(__display);
  515. width = DisplayWidth(__display, screen_num);
  516. height = DisplayHeight(__display, screen_num);
  517. }
  518. if (x != 0) __x = x;
  519. if (y != 0) __y = y;
  520. if (width != 0) __width = width;
  521. if (height != 0) __height = height;
  522. }
  523. }
  524. // GLX version
  525. GLint majorGLX, minorGLX = 0;
  526. glXQueryVersion(__display, &majorGLX, &minorGLX);
  527. if (majorGLX == 1 && minorGLX < 2)
  528. {
  529. perror("GLX 1.2 or greater is required.");
  530. XCloseDisplay(__display);
  531. return NULL;
  532. }
  533. else
  534. {
  535. printf( "GLX version: %d.%d\n", majorGLX , minorGLX);
  536. }
  537. // Get the GLX Functions
  538. glXCreateContextAttribsARB = (GLXContext(*)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list))glXGetProcAddressARB((GLubyte*)"glXCreateContextAttribsARB");
  539. glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig");
  540. glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig");
  541. glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int *value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib");
  542. // Get the configs
  543. int configAttribs[] =
  544. {
  545. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  546. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
  547. GLX_X_RENDERABLE, True,
  548. GLX_DEPTH_SIZE, 24,
  549. GLX_STENCIL_SIZE, 8,
  550. GLX_RED_SIZE, 8,
  551. GLX_GREEN_SIZE, 8,
  552. GLX_BLUE_SIZE, 8,
  553. GLX_DOUBLEBUFFER, True,
  554. 0
  555. };
  556. GLXFBConfig* configs;
  557. int configCount = 0;
  558. configs = glXChooseFBConfig(__display, DefaultScreen(__display), configAttribs, &configCount);
  559. if ( configCount == 0 || configs == 0 )
  560. {
  561. perror( "glXChooseFBConfig" );
  562. return NULL;
  563. }
  564. // Create the windows
  565. XVisualInfo* visualInfo;
  566. visualInfo = glXGetVisualFromFBConfig(__display, configs[0]);
  567. XSetWindowAttributes winAttribs;
  568. long eventMask;
  569. eventMask = ExposureMask | VisibilityChangeMask | StructureNotifyMask |
  570. KeyPressMask | KeyReleaseMask | PointerMotionMask |
  571. ButtonPressMask | ButtonReleaseMask |
  572. EnterWindowMask | LeaveWindowMask;
  573. winAttribs.event_mask = eventMask;
  574. winAttribs.border_pixel = 0;
  575. winAttribs.bit_gravity = StaticGravity;
  576. winAttribs.colormap = XCreateColormap(__display, RootWindow(__display, visualInfo->screen), visualInfo->visual, AllocNone);
  577. GLint winMask;
  578. winMask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
  579. __window = XCreateWindow(__display, DefaultRootWindow(__display), __x, __y, __width, __height, 0,
  580. visualInfo->depth, InputOutput, visualInfo->visual, winMask,
  581. &winAttribs);
  582. // Tell the window manager that it should send the delete window notification through ClientMessage
  583. __atomWmDeleteWindow = XInternAtom(__display, "WM_DELETE_WINDOW", False);
  584. XSetWMProtocols(__display, __window, &__atomWmDeleteWindow, 1);
  585. XMapWindow(__display, __window);
  586. // Send fullscreen atom message to the window; most window managers respect WM_STATE messages
  587. // Note: fullscreen mode will use native desktop resolution and won't care about width/height specified
  588. if (fullscreen)
  589. {
  590. XEvent xev;
  591. Atom atomWm_state = XInternAtom(__display, "_NET_WM_STATE", False);
  592. Atom atomFullscreen = XInternAtom(__display, "_NET_WM_STATE_FULLSCREEN", False);
  593. memset(&xev, 0, sizeof(xev));
  594. xev.type = ClientMessage;
  595. xev.xclient.window = __window;
  596. xev.xclient.message_type = atomWm_state;
  597. xev.xclient.format = 32;
  598. xev.xclient.data.l[0] = 1;
  599. xev.xclient.data.l[1] = atomFullscreen;
  600. xev.xclient.data.l[2] = 0;
  601. XSendEvent(__display, DefaultRootWindow(__display), false, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
  602. }
  603. XStoreName(__display, __window, title ? title : "");
  604. __context = glXCreateContext(__display, visualInfo, NULL, True);
  605. if (!__context)
  606. {
  607. perror("glXCreateContext");
  608. return NULL;
  609. }
  610. glXMakeCurrent(__display, __window, __context);
  611. // Use OpenGL 2.x with GLEW
  612. glewExperimental = GL_TRUE;
  613. GLenum glewStatus = glewInit();
  614. if (glewStatus != GLEW_OK)
  615. {
  616. perror("glewInit");
  617. return NULL;
  618. }
  619. // GL Version
  620. int versionGL[2] = {-1, -1};
  621. glGetIntegerv(GL_MAJOR_VERSION, versionGL);
  622. glGetIntegerv(GL_MINOR_VERSION, versionGL + 1);
  623. printf("GL version: %d.%d\n", versionGL[0], versionGL[1]);
  624. // TODO: Get this workings
  625. //if (GLXEW_EXT_swap_control)
  626. // glXSwapIntervalEXT(__display, glXGetCurrentDrawable(), __vsync ? 1 : 0);
  627. return platform;
  628. }
  629. void cleanupX11()
  630. {
  631. if (__display)
  632. {
  633. glXMakeCurrent(__display, None, NULL);
  634. if (__context)
  635. glXDestroyContext(__display, __context);
  636. if (__window)
  637. XDestroyWindow(__display, __window);
  638. XCloseDisplay(__display);
  639. }
  640. }
  641. double timespec2millis(struct timespec *a)
  642. {
  643. GP_ASSERT(a);
  644. return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
  645. }
  646. void updateWindowSize()
  647. {
  648. GP_ASSERT(__display);
  649. GP_ASSERT(__window);
  650. XWindowAttributes windowAttrs;
  651. XGetWindowAttributes(__display, __window, &windowAttrs);
  652. __windowSize[0] = windowAttrs.width;
  653. __windowSize[1] = windowAttrs.height;
  654. }
  655. int Platform::enterMessagePump()
  656. {
  657. GP_ASSERT(_game);
  658. updateWindowSize();
  659. static const float ACCELEROMETER_X_FACTOR = 90.0f / __windowSize[0];
  660. static const float ACCELEROMETER_Y_FACTOR = 90.0f / __windowSize[1];
  661. static int lx = 0;
  662. static int ly = 0;
  663. static bool shiftDown = false;
  664. static bool capsOn = false;
  665. static XEvent evt;
  666. // Get the initial time.
  667. clock_gettime(CLOCK_REALTIME, &__timespec);
  668. __timeStart = timespec2millis(&__timespec);
  669. __timeAbsolute = 0L;
  670. // Run the game.
  671. _game->run();
  672. // Setup select for message handling (to allow non-blocking)
  673. int x11_fd = ConnectionNumber(__display);
  674. pollfd xpolls[1];
  675. xpolls[0].fd = x11_fd;
  676. xpolls[0].events = POLLIN|POLLPRI;
  677. // Message loop.
  678. while (true)
  679. {
  680. poll( xpolls, 1, 16 );
  681. // handle all pending events in one block
  682. while (XPending(__display))
  683. {
  684. XNextEvent(__display, &evt);
  685. switch (evt.type)
  686. {
  687. case ClientMessage:
  688. {
  689. // Handle destroy window message correctly
  690. if (evt.xclient.data.l[0] == __atomWmDeleteWindow)
  691. {
  692. _game->exit();
  693. }
  694. }
  695. break;
  696. case DestroyNotify :
  697. {
  698. cleanupX11();
  699. exit(0);
  700. }
  701. break;
  702. case Expose:
  703. {
  704. updateWindowSize();
  705. }
  706. break;
  707. case KeyPress:
  708. {
  709. KeySym sym = XLookupKeysym(&evt.xkey, (evt.xkey.state & shiftDown) ? 1 : 0);
  710. //TempSym needed because XConvertCase operates on two keysyms: One lower and the other upper, we are only interested in the upper case
  711. KeySym tempSym;
  712. if (capsOn && !shiftDown)
  713. XConvertCase(sym, &tempSym, &sym);
  714. Keyboard::Key key = getKey(sym);
  715. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, key);
  716. if (key == Keyboard::KEY_CAPS_LOCK)
  717. capsOn = !capsOn;
  718. if (key == Keyboard::KEY_SHIFT)
  719. shiftDown = true;
  720. if (int character = getUnicode(key))
  721. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, character);
  722. }
  723. break;
  724. case KeyRelease:
  725. {
  726. //detect and drop repeating keystrokes (no other way to do this using the event interface)
  727. XEvent next;
  728. if ( XPending(__display) )
  729. {
  730. XPeekEvent(__display,&next);
  731. if ( next.type == KeyPress
  732. && next.xkey.time == evt.xkey.time
  733. && next.xkey.keycode == evt.xkey.keycode )
  734. {
  735. XNextEvent(__display,&next);
  736. continue;
  737. }
  738. }
  739. KeySym sym = XLookupKeysym(&evt.xkey, 0);
  740. Keyboard::Key key = getKey(sym);
  741. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, key);
  742. if (key == Keyboard::KEY_SHIFT)
  743. shiftDown = false;
  744. }
  745. break;
  746. case ButtonPress:
  747. {
  748. gameplay::Mouse::MouseEvent mouseEvt;
  749. switch (evt.xbutton.button)
  750. {
  751. case 1:
  752. mouseEvt = gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON;
  753. break;
  754. case 2:
  755. mouseEvt = gameplay::Mouse::MOUSE_PRESS_MIDDLE_BUTTON;
  756. break;
  757. case 3:
  758. mouseEvt = gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON;
  759. break;
  760. case 4:
  761. case 5:
  762. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL,
  763. evt.xbutton.x, evt.xbutton.y,
  764. evt.xbutton.button == Button4 ? 1 : -1);
  765. break;
  766. default:
  767. break;
  768. }
  769. if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
  770. {
  771. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, evt.xbutton.x, evt.xbutton.y, 0);
  772. }
  773. }
  774. break;
  775. case ButtonRelease:
  776. {
  777. gameplay::Mouse::MouseEvent mouseEvt;
  778. switch (evt.xbutton.button)
  779. {
  780. case 1:
  781. mouseEvt = gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON;
  782. break;
  783. case 2:
  784. mouseEvt = gameplay::Mouse::MOUSE_RELEASE_MIDDLE_BUTTON;
  785. break;
  786. case 3:
  787. mouseEvt = gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON;
  788. break;
  789. default:
  790. break;
  791. }
  792. if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
  793. {
  794. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, evt.xbutton.x, evt.xbutton.y, 0);
  795. }
  796. }
  797. break;
  798. case MotionNotify:
  799. {
  800. if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, evt.xmotion.x, evt.xmotion.y, 0))
  801. {
  802. if (evt.xmotion.state & Button1Mask)
  803. {
  804. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, evt.xmotion.x, evt.xmotion.y, 0);
  805. }
  806. else if (evt.xmotion.state & Button3Mask)
  807. {
  808. // Update the pitch and roll by adding the scaled deltas.
  809. __roll += (float)(evt.xbutton.x - lx) * ACCELEROMETER_X_FACTOR;
  810. __pitch += -(float)(evt.xbutton.y - ly) * ACCELEROMETER_Y_FACTOR;
  811. // Clamp the values to the valid range.
  812. __roll = max(min(__roll, 90.0f), -90.0f);
  813. __pitch = max(min(__pitch, 90.0f), -90.0f);
  814. // Update the last X/Y values.
  815. lx = evt.xbutton.x;
  816. ly = evt.xbutton.y;
  817. }
  818. }
  819. }
  820. break;
  821. default:
  822. break;
  823. }
  824. }
  825. if (_game)
  826. {
  827. // Game state will be uninitialized if game was closed through Game::exit()
  828. if (_game->getState() == Game::UNINITIALIZED)
  829. break;
  830. _game->frame();
  831. }
  832. glXSwapBuffers(__display, __window);
  833. }
  834. cleanupX11();
  835. return 0;
  836. }
  837. void Platform::signalShutdown()
  838. {
  839. // nothing to do
  840. }
  841. bool Platform::canExit()
  842. {
  843. return true;
  844. }
  845. unsigned int Platform::getDisplayWidth()
  846. {
  847. return __windowSize[0];
  848. }
  849. unsigned int Platform::getDisplayHeight()
  850. {
  851. return __windowSize[1];
  852. }
  853. double Platform::getAbsoluteTime()
  854. {
  855. clock_gettime(CLOCK_REALTIME, &__timespec);
  856. double now = timespec2millis(&__timespec);
  857. __timeAbsolute = now - __timeStart;
  858. return __timeAbsolute;
  859. }
  860. void Platform::setAbsoluteTime(double time)
  861. {
  862. __timeAbsolute = time;
  863. }
  864. bool Platform::isVsync()
  865. {
  866. return __vsync;
  867. }
  868. void Platform::setVsync(bool enable)
  869. {
  870. // TODO: Get this working
  871. //if (GLXEW_EXT_swap_control)
  872. // glXSwapIntervalEXT(__display, glXGetCurrentDrawable(), __vsync ? 1 : 0);
  873. __vsync = enable;
  874. }
  875. void Platform::swapBuffers()
  876. {
  877. glXSwapBuffers(__display, __window);
  878. }
  879. void Platform::sleep(long ms)
  880. {
  881. usleep(ms * 1000);
  882. }
  883. void Platform::setMultiTouch(bool enabled)
  884. {
  885. // not supported
  886. }
  887. bool Platform::isMultiTouch()
  888. {
  889. false;
  890. }
  891. void Platform::getAccelerometerValues(float* pitch, float* roll)
  892. {
  893. GP_ASSERT(pitch);
  894. GP_ASSERT(roll);
  895. *pitch = __pitch;
  896. *roll = __roll;
  897. }
  898. bool Platform::hasMouse()
  899. {
  900. return true;
  901. }
  902. void Platform::setMouseCaptured(bool captured)
  903. {
  904. // TODO
  905. }
  906. bool Platform::isMouseCaptured()
  907. {
  908. // TODO
  909. return false;
  910. }
  911. void Platform::setCursorVisible(bool visible)
  912. {
  913. if (visible != __cursorVisible)
  914. {
  915. if (visible)
  916. {
  917. XDefineCursor(__display, __window, None);
  918. }
  919. else
  920. {
  921. XUndefineCursor(__display, __window);
  922. }
  923. XFlush(__display);
  924. __cursorVisible = visible;
  925. }
  926. }
  927. bool Platform::isCursorVisible()
  928. {
  929. return __cursorVisible;
  930. }
  931. void Platform::displayKeyboard(bool display)
  932. {
  933. // not supported
  934. }
  935. void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  936. {
  937. if (!Form::touchEventInternal(evt, x, y, contactIndex))
  938. {
  939. Game::getInstance()->touchEvent(evt, x, y, contactIndex);
  940. Game::getInstance()->getScriptController()->touchEvent(evt, x, y, contactIndex);
  941. }
  942. }
  943. void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
  944. {
  945. if (!Form::keyEventInternal(evt, key))
  946. {
  947. Game::getInstance()->keyEvent(evt, key);
  948. Game::getInstance()->getScriptController()->keyEvent(evt, key);
  949. }
  950. }
  951. bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  952. {
  953. if (Form::mouseEventInternal(evt, x, y, wheelDelta))
  954. {
  955. return true;
  956. }
  957. else if (Game::getInstance()->mouseEvent(evt, x, y, wheelDelta))
  958. {
  959. return true;
  960. }
  961. else
  962. {
  963. return Game::getInstance()->getScriptController()->mouseEvent(evt, x, y, wheelDelta);
  964. }
  965. }
  966. bool Platform::isGestureSupported(Gesture::GestureEvent evt)
  967. {
  968. return false;
  969. }
  970. void Platform::registerGesture(Gesture::GestureEvent evt)
  971. {
  972. }
  973. void Platform::unregisterGesture(Gesture::GestureEvent evt)
  974. {
  975. }
  976. bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
  977. {
  978. return false;
  979. }
  980. unsigned int Platform::getGamepadsConnected()
  981. {
  982. return 0;
  983. }
  984. bool Platform::isGamepadConnected(unsigned int gamepadHandle)
  985. {
  986. return false;
  987. }
  988. const char* Platform::getGamepadId(unsigned int gamepadHandle)
  989. {
  990. return NULL;
  991. }
  992. unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
  993. {
  994. return 0;
  995. }
  996. bool Platform::getGamepadButtonState(unsigned int gamepadHandle, unsigned int buttonIndex)
  997. {
  998. return false;
  999. }
  1000. unsigned int Platform::getGamepadJoystickCount(unsigned int gamepadHandle)
  1001. {
  1002. return 0;
  1003. }
  1004. bool Platform::isGamepadJoystickActive(unsigned int gamepadHandle, unsigned int joystickIndex)
  1005. {
  1006. return false;
  1007. }
  1008. float Platform::getGamepadJoystickAxisX(unsigned int gamepadHandle, unsigned int joystickIndex)
  1009. {
  1010. return 0.0f;
  1011. }
  1012. float Platform::getGamepadJoystickAxisY(unsigned int gamepadHandle, unsigned int joystickIndex)
  1013. {
  1014. return 0.0f;
  1015. }
  1016. void Platform::getGamepadJoystickAxisValues(unsigned int gamepadHandle, unsigned int joystickIndex, Vector2* outValue)
  1017. {
  1018. }
  1019. unsigned int Platform::getGamepadTriggerCount(unsigned int gamepadHandle)
  1020. {
  1021. return 0;
  1022. }
  1023. float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int triggerIndex)
  1024. {
  1025. return 0.0f;
  1026. }
  1027. bool Platform::launchURL(const char* url)
  1028. {
  1029. if (url == NULL || *url == '\0')
  1030. return false;
  1031. int len = strlen(url);
  1032. char* cmd = new char[11 + len];
  1033. sprintf(cmd, "xdg-open %s", url);
  1034. int r = system(cmd);
  1035. SAFE_DELETE_ARRAY(cmd);
  1036. return (r == 0);
  1037. }
  1038. }
  1039. #endif