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

WindowSDL.cpp 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. /*!
  2. * \file src/system/WindowSDL.cpp
  3. * \brief SDL2 Windowing Implementation
  4. *
  5. * \author xythobuz
  6. */
  7. #include <sstream>
  8. #include "SDL_revision.h"
  9. #include "global.h"
  10. #include "Log.h"
  11. #include "RunTime.h"
  12. #include "UI.h"
  13. #include "system/Window.h"
  14. #include "system/WindowSDL.h"
  15. #define SUBSYSTEMS_USED (SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER)
  16. glm::i32vec2 WindowSDL::size(DEFAULT_WIDTH, DEFAULT_HEIGHT);
  17. bool WindowSDL::fullscreen = false;
  18. bool WindowSDL::mousegrab = false;
  19. bool WindowSDL::textinput = false;
  20. SDL_Window* WindowSDL::window = nullptr;
  21. SDL_GLContext WindowSDL::context = nullptr;
  22. SDL_GameController* WindowSDL::controller = nullptr;
  23. int WindowSDL::initialize() {
  24. if (SDL_Init(SUBSYSTEMS_USED) != 0) {
  25. Log::get(LOG_ERROR) << "SDL_Init Error: " << SDL_GetError() << Log::endl;
  26. return -1;
  27. }
  28. int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE;
  29. if (fullscreen)
  30. flags |= SDL_WINDOW_FULLSCREEN;
  31. if ((SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8) != 0)
  32. || (SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8) != 0)
  33. || (SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8) != 0)
  34. || (SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8) != 0)
  35. || (SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24) != 0)
  36. || (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0)
  37. || (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) != 0)
  38. //|| (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2) != 0)
  39. || (SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4) != 0)
  40. || (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3) != 0)
  41. || (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3) != 0)
  42. || (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE))) {
  43. Log::get(LOG_ERROR) << "SDL_GL_SetAttribute Error: " << SDL_GetError() << Log::endl;
  44. return -2;
  45. }
  46. window = SDL_CreateWindow(VERSION, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
  47. size.x, size.y, flags);
  48. if (!window) {
  49. Log::get(LOG_ERROR) << "SDL_CreateWindow Error: " << SDL_GetError() << Log::endl;
  50. return -3;
  51. }
  52. int w = size.x, h = size.y;
  53. SDL_GetWindowSize(window, &w, &h);
  54. size.x = w;
  55. size.y = h;
  56. context = SDL_GL_CreateContext(window);
  57. if (!context) {
  58. Log::get(LOG_ERROR) << "SDL_GL_CreateContext Error: " << SDL_GetError() << Log::endl;
  59. return -4;
  60. }
  61. setMousegrab(mousegrab);
  62. setTextInput(textinput);
  63. if (SDL_NumJoysticks() == 0) {
  64. Log::get(LOG_INFO) << "No Joystick found!" << Log::endl;
  65. return 0;
  66. }
  67. SDL_GameControllerAddMapping("341a0000000000000208000000000000,"
  68. "USB GAMEPAD 8116,"
  69. "a:b0,x:b2,start:b7,back:b6,leftstick:b8,rightstick:b9,"
  70. "leftshoulder:b4,rightshoulder:b5,"
  71. "dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,"
  72. "leftx:a0,lefty:a1,rightx:a3,righty:a2,"
  73. "lefttrigger:,b:b1,y:b3,lefttrigger:a4,righttrigger:a4");
  74. SDL_GameControllerAddMapping("10080000000000000100000000000000,"
  75. "Twin USB Joystick,"
  76. "a:b4,b:b2,y:b0,x:b6,start:b18,back:b16,leftstick:b20,"
  77. "rightstick:b22,leftshoulder:b12,rightshoulder:b14,dpup:h0.1,"
  78. "dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a2,rightx:a6,"
  79. "righty:a4,lefttrigger:b8,righttrigger:b10");
  80. for (int i = 0; i < SDL_NumJoysticks(); i++) {
  81. if (SDL_IsGameController(i)) {
  82. controller = SDL_GameControllerOpen(i);
  83. if (controller) {
  84. Log::get(LOG_INFO) << "Using controller \"" << SDL_GameControllerName(controller)
  85. << "\"..." << Log::endl;
  86. break;
  87. } else {
  88. Log::get(LOG_WARNING) << "Couldn't open controller \"" << SDL_GameControllerNameForIndex(i)
  89. << "\"!" << Log::endl;
  90. }
  91. } else {
  92. Log::get(LOG_WARNING) << "Joystick \"" << SDL_JoystickNameForIndex(i)
  93. << "\" is no compatible controller!" << Log::endl;
  94. }
  95. }
  96. return 0;
  97. }
  98. void WindowSDL::eventHandling() {
  99. SDL_Event event;
  100. KeyboardButton button;
  101. while (SDL_PollEvent(&event)) {
  102. switch (event.type) {
  103. case SDL_CONTROLLERAXISMOTION:
  104. button = unknownKey;
  105. if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX)
  106. button = leftXAxis;
  107. else if (event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY)
  108. button = leftYAxis;
  109. else if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX)
  110. button = rightXAxis;
  111. else if (event.caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY)
  112. button = rightYAxis;
  113. else if (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT)
  114. button = leftTrigger;
  115. else if (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
  116. button = rightTrigger;
  117. if (button != unknownKey)
  118. UI::handleControllerAxis(event.caxis.value / 32768.0f, button);
  119. break;
  120. case SDL_CONTROLLERBUTTONDOWN:
  121. case SDL_CONTROLLERBUTTONUP:
  122. button = unknownKey;
  123. if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A)
  124. button = aButton;
  125. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_B)
  126. button = bButton;
  127. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_X)
  128. button = xButton;
  129. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_Y)
  130. button = yButton;
  131. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK)
  132. button = backButton;
  133. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_GUIDE)
  134. button = guideButton;
  135. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_START)
  136. button = startButton;
  137. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSTICK)
  138. button = leftStick;
  139. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK)
  140. button = rightStick;
  141. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
  142. button = leftShoulder;
  143. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
  144. button = rightShoulder;
  145. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP)
  146. button = padUp;
  147. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
  148. button = padDown;
  149. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT)
  150. button = padLeft;
  151. else if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
  152. button = padRight;
  153. if (button != unknownKey)
  154. UI::handleControllerButton(button, (event.type == SDL_CONTROLLERBUTTONUP));
  155. break;
  156. case SDL_MOUSEMOTION:
  157. UI::handleMouseMotion(event.motion.xrel, event.motion.yrel, event.motion.x, event.motion.y);
  158. break;
  159. case SDL_MOUSEBUTTONDOWN:
  160. case SDL_MOUSEBUTTONUP:
  161. button = unknownKey;
  162. if (event.button.button == SDL_BUTTON_LEFT)
  163. button = leftmouseKey;
  164. else if (event.button.button == SDL_BUTTON_RIGHT)
  165. button = rightmouseKey;
  166. else if (event.button.button == SDL_BUTTON_MIDDLE)
  167. button = middlemouseKey;
  168. else if (event.button.button == SDL_BUTTON_X1)
  169. button = fourthmouseKey;
  170. else if (event.button.button == SDL_BUTTON_X2)
  171. button = fifthmouseKey;
  172. if (button != unknownKey)
  173. UI::handleMouseClick(event.button.x, event.button.y, button,
  174. (event.type == SDL_MOUSEBUTTONUP));
  175. break;
  176. case SDL_MOUSEWHEEL:
  177. if ((event.wheel.x != 0) || (event.wheel.y != 0))
  178. UI::handleMouseScroll(event.wheel.x, event.wheel.y);
  179. break;
  180. case SDL_TEXTINPUT:
  181. case SDL_TEXTEDITING:
  182. if (event.text.text != nullptr)
  183. UI::handleText(event.text.text, (event.type == SDL_TEXTEDITING));
  184. break;
  185. case SDL_KEYDOWN:
  186. case SDL_KEYUP:
  187. KeyboardButton key;
  188. switch (event.key.keysym.sym) {
  189. case SDLK_0:
  190. key = zeroKey;
  191. break;
  192. case SDLK_1:
  193. key = oneKey;
  194. break;
  195. case SDLK_2:
  196. key = twoKey;
  197. break;
  198. case SDLK_3:
  199. key = threeKey;
  200. break;
  201. case SDLK_4:
  202. key = fourKey;
  203. break;
  204. case SDLK_5:
  205. key = fiveKey;
  206. break;
  207. case SDLK_6:
  208. key = sixKey;
  209. break;
  210. case SDLK_7:
  211. key = sevenKey;
  212. break;
  213. case SDLK_8:
  214. key = eightKey;
  215. break;
  216. case SDLK_9:
  217. key = nineKey;
  218. break;
  219. case SDLK_a:
  220. key = aKey;
  221. break;
  222. case SDLK_b:
  223. key = bKey;
  224. break;
  225. case SDLK_c:
  226. key = cKey;
  227. break;
  228. case SDLK_d:
  229. key = dKey;
  230. break;
  231. case SDLK_e:
  232. key = eKey;
  233. break;
  234. case SDLK_f:
  235. key = fKey;
  236. break;
  237. case SDLK_g:
  238. key = gKey;
  239. break;
  240. case SDLK_h:
  241. key = hKey;
  242. break;
  243. case SDLK_i:
  244. key = iKey;
  245. break;
  246. case SDLK_j:
  247. key = jKey;
  248. break;
  249. case SDLK_k:
  250. key = kKey;
  251. break;
  252. case SDLK_l:
  253. key = lKey;
  254. break;
  255. case SDLK_m:
  256. key = mKey;
  257. break;
  258. case SDLK_n:
  259. key = nKey;
  260. break;
  261. case SDLK_o:
  262. key = oKey;
  263. break;
  264. case SDLK_p:
  265. key = pKey;
  266. break;
  267. case SDLK_q:
  268. key = qKey;
  269. break;
  270. case SDLK_r:
  271. key = rKey;
  272. break;
  273. case SDLK_s:
  274. key = sKey;
  275. break;
  276. case SDLK_t:
  277. key = tKey;
  278. break;
  279. case SDLK_u:
  280. key = uKey;
  281. break;
  282. case SDLK_v:
  283. key = vKey;
  284. break;
  285. case SDLK_w:
  286. key = wKey;
  287. break;
  288. case SDLK_x:
  289. key = xKey;
  290. break;
  291. case SDLK_y:
  292. key = yKey;
  293. break;
  294. case SDLK_z:
  295. key = zKey;
  296. break;
  297. case SDLK_QUOTE:
  298. key = quoteKey;
  299. break;
  300. case SDLK_BACKSLASH:
  301. key = backslashKey;
  302. break;
  303. case SDLK_BACKSPACE:
  304. key = backspaceKey;
  305. break;
  306. case SDLK_CAPSLOCK:
  307. key = capslockKey;
  308. break;
  309. case SDLK_COMMA:
  310. key = commaKey;
  311. break;
  312. case SDLK_DELETE:
  313. key = delKey;
  314. break;
  315. case SDLK_UP:
  316. key = upKey;
  317. break;
  318. case SDLK_DOWN:
  319. key = downKey;
  320. break;
  321. case SDLK_LEFT:
  322. key = leftKey;
  323. break;
  324. case SDLK_RIGHT:
  325. key = rightKey;
  326. break;
  327. case SDLK_END:
  328. key = endKey;
  329. break;
  330. case SDLK_EQUALS:
  331. key = equalsKey;
  332. break;
  333. case SDLK_ESCAPE:
  334. key = escapeKey;
  335. break;
  336. case SDLK_F1:
  337. key = f1Key;
  338. break;
  339. case SDLK_F2:
  340. key = f2Key;
  341. break;
  342. case SDLK_F3:
  343. key = f3Key;
  344. break;
  345. case SDLK_F4:
  346. key = f4Key;
  347. break;
  348. case SDLK_F5:
  349. key = f5Key;
  350. break;
  351. case SDLK_F6:
  352. key = f6Key;
  353. break;
  354. case SDLK_F7:
  355. key = f7Key;
  356. break;
  357. case SDLK_F8:
  358. key = f8Key;
  359. break;
  360. case SDLK_F9:
  361. key = f9Key;
  362. break;
  363. case SDLK_F10:
  364. key = f10Key;
  365. break;
  366. case SDLK_F11:
  367. key = f11Key;
  368. break;
  369. case SDLK_F12:
  370. key = f12Key;
  371. break;
  372. case SDLK_BACKQUOTE:
  373. key = backquoteKey;
  374. break;
  375. case SDLK_HOME:
  376. key = homeKey;
  377. break;
  378. case SDLK_INSERT:
  379. key = insertKey;
  380. break;
  381. case SDLK_LALT:
  382. key = leftaltKey;
  383. break;
  384. case SDLK_LCTRL:
  385. key = leftctrlKey;
  386. break;
  387. case SDLK_LEFTBRACKET:
  388. key = leftbracketKey;
  389. break;
  390. case SDLK_LGUI:
  391. key = leftguiKey;
  392. break;
  393. case SDLK_LSHIFT:
  394. key = leftshiftKey;
  395. break;
  396. case SDLK_MINUS:
  397. key = minusKey;
  398. break;
  399. case SDLK_NUMLOCKCLEAR:
  400. key = numlockKey;
  401. break;
  402. case SDLK_PAGEDOWN:
  403. key = pagedownKey;
  404. break;
  405. case SDLK_PAGEUP:
  406. key = pageupKey;
  407. break;
  408. case SDLK_PAUSE:
  409. key = pauseKey;
  410. break;
  411. case SDLK_PERIOD:
  412. key = dotKey;
  413. break;
  414. case SDLK_RALT:
  415. key = rightaltKey;
  416. break;
  417. case SDLK_RCTRL:
  418. key = rightctrlKey;
  419. break;
  420. case SDLK_RETURN:
  421. case SDLK_RETURN2:
  422. key = enterKey;
  423. break;
  424. case SDLK_RGUI:
  425. key = rightguiKey;
  426. break;
  427. case SDLK_RIGHTBRACKET:
  428. key = rightbracketKey;
  429. break;
  430. case SDLK_RSHIFT:
  431. key = rightshiftKey;
  432. break;
  433. case SDLK_SCROLLLOCK:
  434. key = scrolllockKey;
  435. break;
  436. case SDLK_SEMICOLON:
  437. key = semicolonKey;
  438. break;
  439. case SDLK_SLASH:
  440. key = slashKey;
  441. break;
  442. case SDLK_SPACE:
  443. key = spaceKey;
  444. break;
  445. case SDLK_TAB:
  446. key = tabKey;
  447. break;
  448. default:
  449. key = unknownKey;
  450. break;
  451. }
  452. UI::handleKeyboard(key, (event.type == SDL_KEYDOWN));
  453. break;
  454. case SDL_WINDOWEVENT:
  455. if (event.window.event == SDL_WINDOWEVENT_RESIZED) {
  456. size = glm::i32vec2(event.window.data1, event.window.data2);
  457. Window::setSize(size);
  458. }
  459. break;
  460. case SDL_QUIT:
  461. RunTime::setRunning(false);
  462. break;
  463. }
  464. }
  465. UI::eventsFinished();
  466. }
  467. void WindowSDL::swapBuffers() {
  468. SDL_GL_SwapWindow(window);
  469. }
  470. void WindowSDL::shutdown() {
  471. if (context) {
  472. SDL_GL_DeleteContext(context);
  473. context = nullptr;
  474. }
  475. if (controller) {
  476. SDL_GameControllerClose(controller);
  477. controller = nullptr;
  478. }
  479. if (window) {
  480. SDL_DestroyWindow(window);
  481. SDL_QuitSubSystem(SUBSYSTEMS_USED);
  482. SDL_Quit();
  483. window = nullptr;
  484. }
  485. }
  486. void WindowSDL::setSize(glm::i32vec2 s) {
  487. orAssert((s.x > 0) && (s.y > 0));
  488. if (window) {
  489. if ((s.x != size.x) || (s.y != size.y)) {
  490. SDL_SetWindowSize(window, s.x, s.y);
  491. }
  492. }
  493. size = s;
  494. }
  495. void WindowSDL::setFullscreen(bool f) {
  496. fullscreen = f;
  497. if (window) {
  498. if (fullscreen) {
  499. SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
  500. } else {
  501. SDL_SetWindowFullscreen(window, 0);
  502. }
  503. }
  504. }
  505. void WindowSDL::setMousegrab(bool g) {
  506. mousegrab = g;
  507. if (window) {
  508. if (mousegrab) {
  509. SDL_SetRelativeMouseMode(SDL_TRUE);
  510. } else {
  511. SDL_SetRelativeMouseMode(SDL_FALSE);
  512. SDL_ShowCursor(1);
  513. }
  514. }
  515. }
  516. void WindowSDL::setTextInput(bool t) {
  517. textinput = t;
  518. if (textinput)
  519. SDL_StartTextInput();
  520. else
  521. SDL_StopTextInput();
  522. }
  523. void WindowSDL::setClipboard(const char* s) {
  524. if (window) {
  525. if (SDL_SetClipboardText(s) < 0) {
  526. Log::get(LOG_ERROR) << "SDL_SetClipboardText Error: " << SDL_GetError() << Log::endl;
  527. }
  528. }
  529. }
  530. const char* WindowSDL::getClipboard() {
  531. if (window) {
  532. //! \fixme Should be freed with SDL_free(). But how, where, when?
  533. const char* ret = SDL_GetClipboardText();
  534. if (ret == nullptr) {
  535. Log::get(LOG_ERROR) << "SDL_GetClipboardText Error: " << SDL_GetError() << Log::endl;
  536. }
  537. return ret;
  538. }
  539. return nullptr;
  540. }
  541. void WindowSDL::inputPositionCallback(int x, int y) {
  542. SDL_Rect rect;
  543. rect.x = x;
  544. rect.y = y;
  545. rect.w = 50;
  546. rect.h = 25;
  547. SDL_SetTextInputRect(&rect);
  548. }
  549. std::string WindowSDL::getVersion(bool linked) {
  550. SDL_version vers;
  551. if (linked) {
  552. SDL_GetVersion(&vers);
  553. } else {
  554. SDL_VERSION(&vers);
  555. }
  556. std::ostringstream str;
  557. str << "SDL2 v" << int(vers.major) << "." << int(vers.minor) << "." << int(vers.patch);
  558. if (linked) {
  559. return str.str() + " (" + SDL_GetRevision() + ")";
  560. } else {
  561. return str.str() + " (" + SDL_REVISION + ")";
  562. }
  563. }