PlatformLinux.cpp 34 KB

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