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 window configuration
  488. // Default values
  489. const char *title = NULL;
  490. int __x = 0, __y = 0, __width = 1280, __height = 800;
  491. bool fullscreen = false;
  492. if (game->getConfig())
  493. {
  494. Properties* config = game->getConfig()->getNamespace("window", true);
  495. if (config)
  496. {
  497. // Read window title.
  498. title = config->getString("title");
  499. // Read window rect.
  500. int x = config->getInt("x");
  501. if (x != 0) __x = x;
  502. int y = config->getInt("y");
  503. if (y != 0) __y = y;
  504. int width = config->getInt("width");
  505. if (width != 0) __width = width;
  506. int height = config->getInt("height");
  507. if (height != 0) __height = height;
  508. fullscreen = config->getBool("fullscreen");
  509. }
  510. }
  511. // Get the display and initialize.
  512. __display = XOpenDisplay(NULL);
  513. if (__display == NULL)
  514. {
  515. perror("XOpenDisplay");
  516. return NULL;
  517. }
  518. // GLX version
  519. GLint majorGLX, minorGLX = 0;
  520. glXQueryVersion(__display, &majorGLX, &minorGLX);
  521. if(majorGLX == 1 && minorGLX < 2)
  522. {
  523. perror("GLX 1.2 or greater is required.");
  524. XCloseDisplay(__display);
  525. return NULL;
  526. }
  527. else
  528. {
  529. printf( "GLX version: %d.%d\n", majorGLX , minorGLX);
  530. }
  531. // Get the GLX Functions
  532. glXCreateContextAttribsARB = (GLXContext(*)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list))glXGetProcAddressARB((GLubyte*)"glXCreateContextAttribsARB");
  533. glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig");
  534. glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig");
  535. glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int *value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib");
  536. // Get the configs
  537. int configAttribs[] =
  538. {
  539. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  540. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
  541. GLX_X_RENDERABLE, True,
  542. GLX_DEPTH_SIZE, 24,
  543. GLX_STENCIL_SIZE, 8,
  544. GLX_RED_SIZE, 8,
  545. GLX_GREEN_SIZE, 8,
  546. GLX_BLUE_SIZE, 8,
  547. GLX_DOUBLEBUFFER, True,
  548. 0
  549. };
  550. GLXFBConfig* configs;
  551. int configCount = 0;
  552. configs = glXChooseFBConfig(__display, DefaultScreen(__display), configAttribs, &configCount);
  553. if( configCount == 0 || configs == 0 )
  554. {
  555. perror( "glXChooseFBConfig" );
  556. return NULL;
  557. }
  558. // Create the windows
  559. XVisualInfo* visualInfo;
  560. visualInfo = glXGetVisualFromFBConfig(__display, configs[0]);
  561. XSetWindowAttributes winAttribs;
  562. long eventMask;
  563. eventMask = ExposureMask | VisibilityChangeMask | StructureNotifyMask |
  564. KeyPressMask | KeyReleaseMask | PointerMotionMask |
  565. ButtonPressMask | ButtonReleaseMask |
  566. EnterWindowMask | LeaveWindowMask;
  567. winAttribs.event_mask = eventMask;
  568. winAttribs.border_pixel = 0;
  569. winAttribs.bit_gravity = StaticGravity;
  570. winAttribs.colormap = XCreateColormap(__display, RootWindow(__display, visualInfo->screen), visualInfo->visual, AllocNone);
  571. GLint winMask;
  572. winMask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
  573. __window = XCreateWindow(__display, DefaultRootWindow(__display), __x, __y, __width, __height, 0,
  574. visualInfo->depth, InputOutput, visualInfo->visual, winMask,
  575. &winAttribs);
  576. // Tell the window manager that it should send the delete window notification through ClientMessage
  577. __atomWmDeleteWindow = XInternAtom(__display, "WM_DELETE_WINDOW", False);
  578. XSetWMProtocols(__display, __window, &__atomWmDeleteWindow, 1);
  579. XMapWindow(__display, __window);
  580. // Send fullscreen atom message to the window; most window managers respect WM_STATE messages
  581. // Note: fullscreen mode will use native desktop resolution and won't care about width/height specified
  582. if (fullscreen)
  583. {
  584. XEvent xev;
  585. Atom atomWm_state = XInternAtom(__display, "_NET_WM_STATE", False);
  586. Atom atomFullscreen = XInternAtom(__display, "_NET_WM_STATE_FULLSCREEN", False);
  587. memset(&xev, 0, sizeof(xev));
  588. xev.type = ClientMessage;
  589. xev.xclient.window = __window;
  590. xev.xclient.message_type = atomWm_state;
  591. xev.xclient.format = 32;
  592. xev.xclient.data.l[0] = 1;
  593. xev.xclient.data.l[1] = atomFullscreen;
  594. xev.xclient.data.l[2] = 0;
  595. XSendEvent(__display, DefaultRootWindow(__display), false, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
  596. }
  597. XStoreName(__display, __window, title ? title : "");
  598. __context = glXCreateContext(__display, visualInfo, NULL, True);
  599. if(!__context)
  600. {
  601. perror("glXCreateContext");
  602. return NULL;
  603. }
  604. glXMakeCurrent(__display, __window, __context);
  605. // Use OpenGL 2.x with GLEW
  606. glewExperimental = GL_TRUE;
  607. GLenum glewStatus = glewInit();
  608. if(glewStatus != GLEW_OK)
  609. {
  610. perror("glewInit");
  611. return NULL;
  612. }
  613. // GL Version
  614. int versionGL[2] = {-1, -1};
  615. glGetIntegerv(GL_MAJOR_VERSION, versionGL);
  616. glGetIntegerv(GL_MINOR_VERSION, versionGL + 1);
  617. printf("GL version: %d.%d\n", versionGL[0], versionGL[1]);
  618. // TODO: Get this workings
  619. //if (GLXEW_EXT_swap_control)
  620. // glXSwapIntervalEXT(__display, glXGetCurrentDrawable(), __vsync ? 1 : 0);
  621. return platform;
  622. }
  623. void cleanupX11()
  624. {
  625. if (__display)
  626. {
  627. glXMakeCurrent(__display, None, NULL);
  628. if (__context)
  629. glXDestroyContext(__display, __context);
  630. if (__window)
  631. XDestroyWindow(__display, __window);
  632. XCloseDisplay(__display);
  633. }
  634. }
  635. double timespec2millis(struct timespec *a)
  636. {
  637. GP_ASSERT(a);
  638. return (1000.0 * a->tv_sec) + (0.000001 * a->tv_nsec);
  639. }
  640. void updateWindowSize()
  641. {
  642. GP_ASSERT(__display);
  643. GP_ASSERT(__window);
  644. XWindowAttributes windowAttrs;
  645. XGetWindowAttributes(__display, __window, &windowAttrs);
  646. __windowSize[0] = windowAttrs.width;
  647. __windowSize[1] = windowAttrs.height;
  648. }
  649. int Platform::enterMessagePump()
  650. {
  651. GP_ASSERT(_game);
  652. updateWindowSize();
  653. static const float ACCELEROMETER_X_FACTOR = 90.0f / __windowSize[0];
  654. static const float ACCELEROMETER_Y_FACTOR = 90.0f / __windowSize[1];
  655. static int lx = 0;
  656. static int ly = 0;
  657. static bool shiftDown = false;
  658. static bool capsOn = false;
  659. static XEvent evt;
  660. // Get the initial time.
  661. clock_gettime(CLOCK_REALTIME, &__timespec);
  662. __timeStart = timespec2millis(&__timespec);
  663. __timeAbsolute = 0L;
  664. // Run the game.
  665. _game->run();
  666. // Setup select for message handling (to allow non-blocking)
  667. int x11_fd = ConnectionNumber(__display);
  668. pollfd xpolls[1];
  669. xpolls[0].fd = x11_fd;
  670. xpolls[0].events = POLLIN|POLLPRI;
  671. // Message loop.
  672. while (true)
  673. {
  674. poll( xpolls, 1, 16 );
  675. // handle all pending events in one block
  676. while (XPending(__display))
  677. {
  678. XNextEvent(__display, &evt);
  679. switch (evt.type)
  680. {
  681. case ClientMessage:
  682. {
  683. // Handle destroy window message correctly
  684. if (evt.xclient.data.l[0] == __atomWmDeleteWindow)
  685. {
  686. _game->exit();
  687. }
  688. }
  689. break;
  690. case DestroyNotify :
  691. {
  692. cleanupX11();
  693. exit(0);
  694. }
  695. break;
  696. case Expose:
  697. {
  698. updateWindowSize();
  699. }
  700. break;
  701. case KeyPress:
  702. {
  703. KeySym sym = XLookupKeysym(&evt.xkey, (evt.xkey.state & shiftDown) ? 1 : 0);
  704. //TempSym needed because XConvertCase operates on two keysyms: One lower and the other upper, we are only interested in the upper case
  705. KeySym tempSym;
  706. if(capsOn && !shiftDown)
  707. XConvertCase(sym, &tempSym, &sym);
  708. Keyboard::Key key = getKey(sym);
  709. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_PRESS, key);
  710. if(key == Keyboard::KEY_CAPS_LOCK)
  711. capsOn = !capsOn;
  712. if(key == Keyboard::KEY_SHIFT)
  713. shiftDown = true;
  714. if(int character = getUnicode(key))
  715. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, character);
  716. }
  717. break;
  718. case KeyRelease:
  719. {
  720. //detect and drop repeating keystrokes (no other way to do this using the event interface)
  721. XEvent next;
  722. if( XPending(__display) )
  723. {
  724. XPeekEvent(__display,&next);
  725. if( next.type == KeyPress
  726. && next.xkey.time == evt.xkey.time
  727. && next.xkey.keycode == evt.xkey.keycode )
  728. {
  729. XNextEvent(__display,&next);
  730. continue;
  731. }
  732. }
  733. KeySym sym = XLookupKeysym(&evt.xkey, 0);
  734. Keyboard::Key key = getKey(sym);
  735. gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_RELEASE, key);
  736. if(key == Keyboard::KEY_SHIFT)
  737. shiftDown = false;
  738. }
  739. break;
  740. case ButtonPress:
  741. {
  742. gameplay::Mouse::MouseEvent mouseEvt;
  743. switch(evt.xbutton.button)
  744. {
  745. case 1:
  746. mouseEvt = gameplay::Mouse::MOUSE_PRESS_LEFT_BUTTON;
  747. break;
  748. case 2:
  749. mouseEvt = gameplay::Mouse::MOUSE_PRESS_MIDDLE_BUTTON;
  750. break;
  751. case 3:
  752. mouseEvt = gameplay::Mouse::MOUSE_PRESS_RIGHT_BUTTON;
  753. break;
  754. case 4:
  755. case 5:
  756. gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_WHEEL,
  757. evt.xbutton.x, evt.xbutton.y,
  758. evt.xbutton.button == Button4 ? 1 : -1);
  759. break;
  760. default:
  761. break;
  762. }
  763. if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
  764. {
  765. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_PRESS, evt.xbutton.x, evt.xbutton.y, 0);
  766. }
  767. }
  768. break;
  769. case ButtonRelease:
  770. {
  771. gameplay::Mouse::MouseEvent mouseEvt;
  772. switch(evt.xbutton.button)
  773. {
  774. case 1:
  775. mouseEvt = gameplay::Mouse::MOUSE_RELEASE_LEFT_BUTTON;
  776. break;
  777. case 2:
  778. mouseEvt = gameplay::Mouse::MOUSE_RELEASE_MIDDLE_BUTTON;
  779. break;
  780. case 3:
  781. mouseEvt = gameplay::Mouse::MOUSE_RELEASE_RIGHT_BUTTON;
  782. break;
  783. default:
  784. break;
  785. }
  786. if (!gameplay::Platform::mouseEventInternal(mouseEvt, evt.xbutton.x, evt.xbutton.y, 0))
  787. {
  788. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_RELEASE, evt.xbutton.x, evt.xbutton.y, 0);
  789. }
  790. }
  791. break;
  792. case MotionNotify:
  793. {
  794. if (!gameplay::Platform::mouseEventInternal(gameplay::Mouse::MOUSE_MOVE, evt.xmotion.x, evt.xmotion.y, 0))
  795. {
  796. if (evt.xmotion.state & Button1Mask)
  797. {
  798. gameplay::Platform::touchEventInternal(gameplay::Touch::TOUCH_MOVE, evt.xmotion.x, evt.xmotion.y, 0);
  799. }
  800. else if (evt.xmotion.state & Button3Mask)
  801. {
  802. // Update the pitch and roll by adding the scaled deltas.
  803. __roll += (float)(evt.xbutton.x - lx) * ACCELEROMETER_X_FACTOR;
  804. __pitch += -(float)(evt.xbutton.y - ly) * ACCELEROMETER_Y_FACTOR;
  805. // Clamp the values to the valid range.
  806. __roll = max(min(__roll, 90.0f), -90.0f);
  807. __pitch = max(min(__pitch, 90.0f), -90.0f);
  808. // Update the last X/Y values.
  809. lx = evt.xbutton.x;
  810. ly = evt.xbutton.y;
  811. }
  812. }
  813. }
  814. break;
  815. default:
  816. break;
  817. }
  818. }
  819. if (_game)
  820. {
  821. // Game state will be uninitialized if game was closed through Game::exit()
  822. if (_game->getState() == Game::UNINITIALIZED)
  823. break;
  824. _game->frame();
  825. }
  826. glXSwapBuffers(__display, __window);
  827. }
  828. cleanupX11();
  829. return 0;
  830. }
  831. void Platform::signalShutdown()
  832. {
  833. // nothing to do
  834. }
  835. bool Platform::canExit()
  836. {
  837. return true;
  838. }
  839. unsigned int Platform::getDisplayWidth()
  840. {
  841. return __windowSize[0];
  842. }
  843. unsigned int Platform::getDisplayHeight()
  844. {
  845. return __windowSize[1];
  846. }
  847. double Platform::getAbsoluteTime()
  848. {
  849. clock_gettime(CLOCK_REALTIME, &__timespec);
  850. double now = timespec2millis(&__timespec);
  851. __timeAbsolute = now - __timeStart;
  852. return __timeAbsolute;
  853. }
  854. void Platform::setAbsoluteTime(double time)
  855. {
  856. __timeAbsolute = time;
  857. }
  858. bool Platform::isVsync()
  859. {
  860. return __vsync;
  861. }
  862. void Platform::setVsync(bool enable)
  863. {
  864. // TODO: Get this working
  865. //if (GLXEW_EXT_swap_control)
  866. // glXSwapIntervalEXT(__display, glXGetCurrentDrawable(), __vsync ? 1 : 0);
  867. __vsync = enable;
  868. }
  869. void Platform::swapBuffers()
  870. {
  871. glXSwapBuffers(__display, __window);
  872. }
  873. void Platform::sleep(long ms)
  874. {
  875. usleep(ms * 1000);
  876. }
  877. void Platform::setMultiTouch(bool enabled)
  878. {
  879. // not supported
  880. }
  881. bool Platform::isMultiTouch()
  882. {
  883. false;
  884. }
  885. void Platform::getAccelerometerValues(float* pitch, float* roll)
  886. {
  887. GP_ASSERT(pitch);
  888. GP_ASSERT(roll);
  889. *pitch = __pitch;
  890. *roll = __roll;
  891. }
  892. bool Platform::hasMouse()
  893. {
  894. return true;
  895. }
  896. void Platform::setMouseCaptured(bool captured)
  897. {
  898. // TODO
  899. }
  900. bool Platform::isMouseCaptured()
  901. {
  902. // TODO
  903. return false;
  904. }
  905. void Platform::setCursorVisible(bool visible)
  906. {
  907. if (visible != __cursorVisible)
  908. {
  909. if (visible)
  910. {
  911. XDefineCursor(__display, __window, None);
  912. }
  913. else
  914. {
  915. XUndefineCursor(__display, __window);
  916. }
  917. XFlush(__display);
  918. __cursorVisible = visible;
  919. }
  920. }
  921. bool Platform::isCursorVisible()
  922. {
  923. return __cursorVisible;
  924. }
  925. void Platform::displayKeyboard(bool display)
  926. {
  927. // not supported
  928. }
  929. void Platform::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
  930. {
  931. if (!Form::touchEventInternal(evt, x, y, contactIndex))
  932. {
  933. Game::getInstance()->touchEvent(evt, x, y, contactIndex);
  934. Game::getInstance()->getScriptController()->touchEvent(evt, x, y, contactIndex);
  935. }
  936. }
  937. void Platform::keyEventInternal(Keyboard::KeyEvent evt, int key)
  938. {
  939. if (!Form::keyEventInternal(evt, key))
  940. {
  941. Game::getInstance()->keyEvent(evt, key);
  942. Game::getInstance()->getScriptController()->keyEvent(evt, key);
  943. }
  944. }
  945. bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
  946. {
  947. if (Form::mouseEventInternal(evt, x, y, wheelDelta))
  948. {
  949. return true;
  950. }
  951. else if (Game::getInstance()->mouseEvent(evt, x, y, wheelDelta))
  952. {
  953. return true;
  954. }
  955. else
  956. {
  957. return Game::getInstance()->getScriptController()->mouseEvent(evt, x, y, wheelDelta);
  958. }
  959. }
  960. bool Platform::isGestureSupported(Gesture::GestureEvent evt)
  961. {
  962. return false;
  963. }
  964. void Platform::registerGesture(Gesture::GestureEvent evt)
  965. {
  966. }
  967. void Platform::unregisterGesture(Gesture::GestureEvent evt)
  968. {
  969. }
  970. bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
  971. {
  972. return false;
  973. }
  974. unsigned int Platform::getGamepadsConnected()
  975. {
  976. return 0;
  977. }
  978. bool Platform::isGamepadConnected(unsigned int gamepadHandle)
  979. {
  980. return false;
  981. }
  982. const char* Platform::getGamepadId(unsigned int gamepadHandle)
  983. {
  984. return NULL;
  985. }
  986. unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
  987. {
  988. return 0;
  989. }
  990. bool Platform::getGamepadButtonState(unsigned int gamepadHandle, unsigned int buttonIndex)
  991. {
  992. return false;
  993. }
  994. unsigned int Platform::getGamepadJoystickCount(unsigned int gamepadHandle)
  995. {
  996. return 0;
  997. }
  998. bool Platform::isGamepadJoystickActive(unsigned int gamepadHandle, unsigned int joystickIndex)
  999. {
  1000. return false;
  1001. }
  1002. float Platform::getGamepadJoystickAxisX(unsigned int gamepadHandle, unsigned int joystickIndex)
  1003. {
  1004. return 0.0f;
  1005. }
  1006. float Platform::getGamepadJoystickAxisY(unsigned int gamepadHandle, unsigned int joystickIndex)
  1007. {
  1008. return 0.0f;
  1009. }
  1010. void Platform::getGamepadJoystickAxisValues(unsigned int gamepadHandle, unsigned int joystickIndex, Vector2* outValue)
  1011. {
  1012. }
  1013. unsigned int Platform::getGamepadTriggerCount(unsigned int gamepadHandle)
  1014. {
  1015. return 0;
  1016. }
  1017. float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int triggerIndex)
  1018. {
  1019. return 0.0f;
  1020. }
  1021. bool Platform::launchURL(const char* url)
  1022. {
  1023. if (url == NULL || *url == '\0')
  1024. return false;
  1025. int len = strlen(url);
  1026. char* cmd = new char[11 + len];
  1027. sprintf(cmd, "xdg-open %s", url);
  1028. int r = system(cmd);
  1029. SAFE_DELETE_ARRAY(cmd);
  1030. return (r == 0);
  1031. }
  1032. }
  1033. #endif