You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

503 regels
12 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://www.wtfpl.net/ for more details.
  9. //
  10. #if defined HAVE_CONFIG_H
  11. # include "config.h"
  12. #endif
  13. #include <cstdlib>
  14. #if defined USE_SDL
  15. # if defined HAVE_SDL_SDL_H
  16. # include <SDL/SDL.h>
  17. # else
  18. # include <SDL.h>
  19. # endif
  20. #endif
  21. #include "core.h"
  22. namespace lol
  23. {
  24. /*
  25. * Input implementation class
  26. */
  27. InputTracker* Input::m_input_tracker = nullptr;
  28. static class InputData
  29. {
  30. friend class Input;
  31. public:
  32. InputData()
  33. : mouse(-1),
  34. buttons(0),
  35. nentities(0),
  36. lastfocus(0)
  37. { }
  38. private:
  39. ivec2 mouse;
  40. uint32_t buttons;
  41. static int const MAX_ENTITIES = 100;
  42. WorldEntity *entities[MAX_ENTITIES];
  43. int nentities;
  44. WorldEntity *lastfocus;
  45. Array<Stick *> m_sticks;
  46. }
  47. inputdata;
  48. static InputData * const data = &inputdata;
  49. /*
  50. * ButtonSetting class
  51. */
  52. int ButtonSetting::GetActionSettingIdx(Action a)
  53. {
  54. for (int i = 0; i < m_associated_action_list.Count(); i++)
  55. if (ACTION_CMP(m_associated_action_list[i].m_action, a))
  56. return i;
  57. return -1;
  58. }
  59. /*
  60. * InputTracker class
  61. */
  62. InputTracker::InputTracker()
  63. {
  64. m_gamegroup = GAMEGROUP_BEFORE;
  65. for (int i = 0; i < Key::Last * 2; ++i)
  66. m_input_status << 0;
  67. Ticker::Ref(this);
  68. }
  69. //Internal
  70. int InputTracker::GetButtonSettingIdx(Key k)
  71. {
  72. for (int i = 0; i < m_input_assocation_list.Count(); i++)
  73. if (m_input_assocation_list[i].m_raw_button == k)
  74. return i;
  75. return -1;
  76. }
  77. //-----
  78. int InputTracker::GetCurrentButtonStatus(Key k)
  79. {
  80. if (k < m_input_status.Count())
  81. return m_input_status[k];
  82. return 0;
  83. }
  84. //-----
  85. int InputTracker::GetPreviousButtonStatus(Key k)
  86. {
  87. if (k < m_input_status.Count())
  88. return m_input_status[(int)k + (int)Key::Last];
  89. return 0;
  90. }
  91. //Internal : Updates the action status & timers
  92. void InputTracker::UpdateActionStatus(float seconds)
  93. {
  94. #if defined USE_SDL
  95. # if SDL_VERSION_ATLEAST(1,3,0)
  96. Uint8 *keystate = SDL_GetKeyboardState(nullptr);
  97. # else
  98. Uint8 *keystate = SDL_GetKeyState(nullptr);
  99. # endif
  100. //SOOOoooo ugly.
  101. for (int i = 0; i < Key::Last; ++i)
  102. {
  103. m_input_status[i + Key::Last] = m_input_status[i];
  104. m_input_status[i] = keystate[i];
  105. }
  106. #endif
  107. for (int i = 0; i < m_input_assocation_list.Count(); i++)
  108. {
  109. ButtonSetting &CurIT = m_input_assocation_list[i];
  110. for (int j = 0; j < CurIT.m_associated_action_list.Count(); j++)
  111. {
  112. ActionSetting &CurAS = CurIT.m_associated_action_list[j];
  113. if (CurAS.m_buffered_since <= CurAS.m_buffering_time)
  114. CurAS.m_buffered_since += seconds;
  115. if (GetCurrentButtonStatus(CurIT.m_raw_button) &&
  116. CurAS.m_buffering_time >= .0f)
  117. CurAS.m_buffered_since = .0f;
  118. }
  119. }
  120. }
  121. //Helps link a software input Action-Id to an hardware input Button-Id.
  122. void InputTracker::LinkActionToKey(Action a, Key k)
  123. {
  124. int ITIdx = GetButtonSettingIdx(k);
  125. if (ITIdx == -1)
  126. {
  127. ITIdx = m_input_assocation_list.Count();
  128. m_input_assocation_list << ButtonSetting(k);
  129. }
  130. ButtonSetting &CurIT = m_input_assocation_list[ITIdx];
  131. int ASIdx = CurIT.GetActionSettingIdx(a);
  132. if (ASIdx == -1)
  133. {
  134. ASIdx = CurIT.m_associated_action_list.Count();
  135. CurIT.m_associated_action_list << ActionSetting(a);
  136. }
  137. }
  138. //Helps unlink a software input Action-Id to an hardware input k-Id.
  139. void InputTracker::UnlinkAction(Action a)
  140. {
  141. for (int i = 0; i < m_input_assocation_list.Count(); i++)
  142. {
  143. ButtonSetting &CurIT = m_input_assocation_list[i];
  144. int ASIdx = CurIT.GetActionSettingIdx(a);
  145. if (ASIdx != -1)
  146. CurIT.m_associated_action_list.Remove(ASIdx);
  147. }
  148. }
  149. //Returns the current status of a given action
  150. int InputTracker::GetStatus(Action a)
  151. {
  152. for (int i = 0; i < m_input_assocation_list.Count(); i++)
  153. {
  154. ButtonSetting &CurIT = m_input_assocation_list[i];
  155. int ASIdx = CurIT.GetActionSettingIdx(a);
  156. if (ASIdx != -1)
  157. {
  158. ActionSetting &CurAS = CurIT.m_associated_action_list[ASIdx];
  159. if (CurAS.m_buffering_time >= .0f && CurAS.m_buffered_since <= CurAS.m_buffering_time)
  160. return 1;
  161. return 0;
  162. }
  163. }
  164. return 0;
  165. }
  166. //Returns TRUE if action status went from Active to Inactive this frame
  167. bool InputTracker::WasReleased(Action a)
  168. {
  169. for (int i = 0; i < m_input_assocation_list.Count(); i++)
  170. {
  171. ButtonSetting &CurIT = m_input_assocation_list[i];
  172. int ASIdx = CurIT.GetActionSettingIdx(a);
  173. if (ASIdx != -1)
  174. {
  175. if (GetPreviousButtonStatus(CurIT.m_raw_button) &&
  176. !GetCurrentButtonStatus(CurIT.m_raw_button))
  177. return true;
  178. return false;
  179. }
  180. }
  181. return false;
  182. }
  183. //Returns TRUE if action status went from Inactive to Active this frame
  184. bool InputTracker::WasPressed(Action a)
  185. {
  186. for (int i = 0; i < m_input_assocation_list.Count(); i++)
  187. {
  188. ButtonSetting &CurIT = m_input_assocation_list[i];
  189. int ASIdx = CurIT.GetActionSettingIdx(a);
  190. if (ASIdx != -1)
  191. {
  192. if (!GetPreviousButtonStatus(CurIT.m_raw_button) &&
  193. GetCurrentButtonStatus(CurIT.m_raw_button))
  194. return true;
  195. return false;
  196. }
  197. }
  198. return false;
  199. }
  200. //Returns the current status of a given action
  201. int InputTracker::GetStatus(Key k)
  202. {
  203. return GetCurrentButtonStatus(k);
  204. }
  205. //Returns TRUE if action status went from Active to Inactive this frame
  206. bool InputTracker::WasReleased(Key k)
  207. {
  208. if (GetPreviousButtonStatus(k) &&
  209. !GetCurrentButtonStatus(k))
  210. return true;
  211. return false;
  212. }
  213. //Returns TRUE if action status went from Inactive to Active this frame
  214. bool InputTracker::WasPressed(Key k)
  215. {
  216. if (!GetPreviousButtonStatus(k) &&
  217. GetCurrentButtonStatus(k))
  218. return true;
  219. return false;
  220. }
  221. /*
  222. * Public Input class
  223. */
  224. #if 0
  225. vec2 Input::GetAxis(int axis)
  226. {
  227. vec2 ret;
  228. #if defined USE_SDL
  229. /* Simulate a joystick using the keyboard. This SDL call is free. */
  230. # if SDL_VERSION_ATLEAST(1,3,0)
  231. Uint8 *keystate = SDL_GetKeyboardState(nullptr);
  232. # else
  233. Uint8 *keystate = SDL_GetKeyState(nullptr);
  234. # endif
  235. int left = keystate[SDLK_d] - (keystate[SDLK_a] | keystate[SDLK_q]);
  236. int up = (keystate[SDLK_w] | keystate[SDLK_z]) - keystate[SDLK_s] ;
  237. ret.x += left;
  238. ret.y += up;
  239. if (left && up)
  240. ret = ret * sqrtf(0.5f);
  241. #else
  242. ret = vec2(0, 0);
  243. #endif
  244. return ret;
  245. }
  246. #endif
  247. ivec2 Input::GetMousePos()
  248. {
  249. return data->mouse;
  250. }
  251. uint32_t Input::GetMouseButtons()
  252. {
  253. return data->buttons;
  254. }
  255. //BH : Added this, is a v0.1 Alpha version.
  256. int Input::GetButtonState(int button)
  257. {
  258. #if defined USE_SDL
  259. # if SDL_VERSION_ATLEAST(1,3,0)
  260. Uint8 *keystate = SDL_GetKeyboardState(nullptr);
  261. # else
  262. Uint8 *keystate = SDL_GetKeyState(nullptr);
  263. # endif
  264. return keystate[button];
  265. #else
  266. return 0;
  267. #endif
  268. }
  269. //Helps link a software input Action-Id to an hardware input Button-Id.
  270. void Input::LinkActionToKey(Action a, Key k)
  271. {
  272. if (CheckInputTrackerInit())
  273. Input::m_input_tracker->LinkActionToKey(a, k);
  274. }
  275. //Helps unlink a software input Action-Id to an hardware input Button-Id.
  276. void Input::UnlinkAction(Action a)
  277. {
  278. if (CheckInputTrackerInit())
  279. Input::m_input_tracker->UnlinkAction(a);
  280. }
  281. //Returns the current status of a given action
  282. int Input::GetStatus(Action a)
  283. {
  284. if (CheckInputTrackerInit())
  285. return Input::m_input_tracker->GetStatus(a);
  286. return 0;
  287. }
  288. //Returns TRUE if action status when from Active to Inactive this frame
  289. bool Input::WasPressed(Action a)
  290. {
  291. if (CheckInputTrackerInit())
  292. return Input::m_input_tracker->WasPressed(a);
  293. return false;
  294. }
  295. //Returns TRUE if action status when from Active to Inactive this frame
  296. bool Input::WasReleased(Action a)
  297. {
  298. if (CheckInputTrackerInit())
  299. return Input::m_input_tracker->WasReleased(a);
  300. return false;
  301. }
  302. //Returns the current status of a given action
  303. int Input::GetStatus(Key k)
  304. {
  305. if (CheckInputTrackerInit())
  306. return Input::m_input_tracker->GetStatus(k);
  307. return 0;
  308. }
  309. //Returns TRUE if action status when from Active to Inactive this frame
  310. bool Input::WasPressed(Key k)
  311. {
  312. if (CheckInputTrackerInit())
  313. return Input::m_input_tracker->WasPressed(k);
  314. return false;
  315. }
  316. //Returns TRUE if action status when from Active to Inactive this frame
  317. bool Input::WasReleased(Key k)
  318. {
  319. if (CheckInputTrackerInit())
  320. return Input::m_input_tracker->WasReleased(k);
  321. return false;
  322. }
  323. //--
  324. void Input::TrackMouse(WorldEntity *e)
  325. {
  326. if (data->nentities >= InputData::MAX_ENTITIES)
  327. return;
  328. data->entities[data->nentities] = e;
  329. data->nentities++;
  330. }
  331. void Input::UntrackMouse(WorldEntity *e)
  332. {
  333. for (int n = 0; n < data->nentities; n++)
  334. {
  335. if (data->entities[n] != e)
  336. continue;
  337. data->entities[n] = data->entities[data->nentities - 1];
  338. data->nentities--;
  339. n--;
  340. }
  341. }
  342. void Input::SetMousePos(ivec2 coord)
  343. {
  344. data->mouse = coord;
  345. WorldEntity *top = nullptr;
  346. /* Find the top “widget” amongst all entities that match the
  347. * mouse coordinates */
  348. for (int n = 0; n < data->nentities; n++)
  349. {
  350. if (coord.x < data->entities[n]->m_bbox[0].x
  351. || coord.x >= data->entities[n]->m_bbox[1].x
  352. || coord.y < data->entities[n]->m_bbox[0].y
  353. || coord.y >= data->entities[n]->m_bbox[1].y)
  354. continue;
  355. if (!top || top->m_bbox[1].z < data->entities[n]->m_bbox[1].z)
  356. top = data->entities[n];
  357. }
  358. for (int n = 0; n < data->nentities; n++)
  359. {
  360. if (data->entities[n] == top)
  361. {
  362. data->entities[n]->m_mousepos = coord - (ivec2)top->m_bbox[0].xy;
  363. if (top != data->lastfocus)
  364. data->entities[n]->m_pressed = data->buttons;
  365. else
  366. data->entities[n]->m_clicked = 0;
  367. }
  368. else
  369. {
  370. data->entities[n]->m_mousepos = ivec2(-1);
  371. /* FIXME */
  372. data->entities[n]->m_released = 0;
  373. data->entities[n]->m_pressed = 0;
  374. data->entities[n]->m_clicked = 0;
  375. }
  376. }
  377. data->lastfocus = top;
  378. }
  379. void Input::SetMouseButton(int index)
  380. {
  381. uint32_t flag = 1 << index;
  382. data->buttons |= flag;
  383. if (data->lastfocus)
  384. {
  385. if (!(data->lastfocus->m_pressed & flag))
  386. data->lastfocus->m_clicked |= flag;
  387. data->lastfocus->m_pressed |= flag;
  388. data->lastfocus->m_released &= ~flag;
  389. }
  390. }
  391. void Input::UnsetMouseButton(int index)
  392. {
  393. uint32_t flag = 1 << index;
  394. data->buttons &= ~flag;
  395. if (data->lastfocus)
  396. {
  397. if (!(data->lastfocus->m_pressed & flag))
  398. data->lastfocus->m_released |= flag;
  399. data->lastfocus->m_pressed &= ~flag;
  400. data->lastfocus->m_clicked &= ~flag;
  401. }
  402. }
  403. Stick *Input::CreateStick()
  404. {
  405. Stick *stick = new Stick();
  406. Ticker::Ref(stick);
  407. data->m_sticks.Push(stick);
  408. return stick;
  409. }
  410. void Input::DestroyStick(Stick *stick)
  411. {
  412. for (int i = 0; i < data->m_sticks.Count(); i++)
  413. if (data->m_sticks[i] == stick)
  414. data->m_sticks.Remove(i);
  415. Ticker::Unref(stick);
  416. }
  417. Stick *Input::TrackStick(int desired)
  418. {
  419. /* FIXME: add the possibility to choose amongst sticks */
  420. if (desired >= data->m_sticks.Count())
  421. return nullptr;
  422. Ticker::Ref(data->m_sticks[desired]);
  423. return data->m_sticks[desired];
  424. }
  425. void Input::UntrackStick(Stick *stick)
  426. {
  427. Ticker::Unref(stick);
  428. }
  429. } /* namespace lol */