選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

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