input_device.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. * Copyright (c) 2012-2020 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. #include "core/error/error.h"
  6. #include "core/math/constants.h"
  7. #include "core/math/math.h"
  8. #include "core/math/vector3.inl"
  9. #include "core/memory/allocator.h"
  10. #include "core/memory/memory.inl"
  11. #include "core/strings/string.inl"
  12. #include "core/strings/string_id.inl"
  13. #include "device/input_device.h"
  14. #include <string.h> // strcpy, memset
  15. namespace crown
  16. {
  17. const char* InputDevice::name() const
  18. {
  19. return _name;
  20. }
  21. bool InputDevice::connected() const
  22. {
  23. return _connected;
  24. }
  25. u8 InputDevice::num_buttons() const
  26. {
  27. return _num_buttons;
  28. }
  29. u8 InputDevice::num_axes() const
  30. {
  31. return _num_axes;
  32. }
  33. bool InputDevice::pressed(u8 id) const
  34. {
  35. return id < _num_buttons
  36. ? (~_last_state[id] & _state[id]) != 0
  37. : false
  38. ;
  39. }
  40. bool InputDevice::released(u8 id) const
  41. {
  42. return id < _num_buttons
  43. ? (_last_state[id] & ~_state[id]) != 0
  44. : false
  45. ;
  46. }
  47. u8 InputDevice::any_pressed() const
  48. {
  49. return pressed(_first_button[1]) ? _first_button[1] : UINT8_MAX;
  50. }
  51. u8 InputDevice::any_released() const
  52. {
  53. return released(_first_button[0]) ? _first_button[0] : UINT8_MAX;
  54. }
  55. f32 InputDevice::button(u8 id) const
  56. {
  57. return id < _num_buttons
  58. ? f32(_state[id])
  59. : 0.0f
  60. ;
  61. }
  62. Vector3 InputDevice::axis(u8 id) const
  63. {
  64. if (id >= _num_axes)
  65. return VECTOR3_ZERO;
  66. Vector3 axis = _axis[id];
  67. switch (_deadzone_mode[id])
  68. {
  69. case DeadzoneMode::RAW:
  70. // No deadzone
  71. break;
  72. case DeadzoneMode::INDEPENDENT:
  73. axis.x = fabs(axis.x) < _deadzone_size[id] ? 0.0f : axis.x;
  74. axis.y = fabs(axis.y) < _deadzone_size[id] ? 0.0f : axis.y;
  75. axis.z = fabs(axis.z) < _deadzone_size[id] ? 0.0f : axis.z;
  76. break;
  77. case DeadzoneMode::CIRCULAR:
  78. if (length(axis) < _deadzone_size[id])
  79. {
  80. axis = VECTOR3_ZERO;
  81. }
  82. else
  83. {
  84. const f32 size = 1.0f - _deadzone_size[id];
  85. const f32 size_inv = 1.0f / size;
  86. const f32 axis_len = length(axis);
  87. axis = normalize(axis) * (axis_len - _deadzone_size[id]) * size_inv;
  88. }
  89. break;
  90. default:
  91. CE_FATAL("Unknown deadzone mode");
  92. break;
  93. }
  94. return axis;
  95. }
  96. const char* InputDevice::button_name(u8 id)
  97. {
  98. return id < _num_buttons
  99. ? _button_name[id]
  100. : NULL
  101. ;
  102. }
  103. const char* InputDevice::axis_name(u8 id)
  104. {
  105. return id < _num_axes
  106. ? _axis_name[id]
  107. : NULL
  108. ;
  109. }
  110. u8 InputDevice::button_id(StringId32 name)
  111. {
  112. for (u32 i = 0; i < _num_buttons; ++i)
  113. {
  114. if (_button_hash[i] == name)
  115. return i;
  116. }
  117. return UINT8_MAX;
  118. }
  119. u8 InputDevice::axis_id(StringId32 name)
  120. {
  121. for (u32 i = 0; i < _num_axes; ++i)
  122. {
  123. if (_axis_hash[i] == name)
  124. return i;
  125. }
  126. return UINT8_MAX;
  127. }
  128. f32 InputDevice::deadzone(u8 id, DeadzoneMode::Enum* deadzone_mode)
  129. {
  130. if (id < _num_axes)
  131. {
  132. *deadzone_mode = (DeadzoneMode::Enum)_deadzone_mode[id];
  133. return _deadzone_size[id];
  134. }
  135. else
  136. {
  137. *deadzone_mode = DeadzoneMode::COUNT;
  138. return 0.0f;
  139. }
  140. }
  141. void InputDevice::set_deadzone(u8 id, DeadzoneMode::Enum deadzone_mode, f32 deadzone_size)
  142. {
  143. if (id < _num_axes)
  144. {
  145. _deadzone_mode[id] = deadzone_mode;
  146. _deadzone_size[id] = deadzone_size;
  147. }
  148. }
  149. void InputDevice::set_button(u8 id, u8 state)
  150. {
  151. CE_ASSERT(id < _num_buttons, "Index out of bounds");
  152. _state[id] = state;
  153. if (_first_button[state % countof(_first_button)] == UINT8_MAX)
  154. _first_button[state % countof(_first_button)] = id;
  155. }
  156. void InputDevice::set_axis(u8 id, f32 x, f32 y, f32 z)
  157. {
  158. CE_ASSERT(id < _num_axes, "Index out of bounds");
  159. _axis[id].x = x;
  160. _axis[id].y = y;
  161. _axis[id].z = z;
  162. }
  163. void InputDevice::update()
  164. {
  165. memcpy(_last_state, _state, sizeof(u8)*_num_buttons);
  166. _first_button[0] = UINT8_MAX;
  167. _first_button[1] = UINT8_MAX;
  168. }
  169. namespace input_device
  170. {
  171. InputDevice* create(Allocator& a, const char* name, u8 num_buttons, u8 num_axes, const char** button_names, const char** axis_names)
  172. {
  173. const u32 size = 0
  174. + sizeof(InputDevice) + alignof(InputDevice)
  175. + sizeof(u8)*num_buttons*2 + alignof(u8)
  176. + sizeof(Vector3)*num_axes + alignof(Vector3)
  177. + sizeof(u32)*num_axes + alignof(u32)
  178. + sizeof(f32)*num_axes + alignof(f32)
  179. + sizeof(StringId32)*num_buttons + alignof(StringId32)
  180. + sizeof(StringId32)*num_axes + alignof(StringId32)
  181. + strlen32(name) + 1 + alignof(char)
  182. ;
  183. InputDevice* id = (InputDevice*)a.allocate(size);
  184. id->_connected = false;
  185. id->_num_buttons = num_buttons;
  186. id->_num_axes = num_axes;
  187. id->_first_button[0] = UINT8_MAX;
  188. id->_first_button[1] = UINT8_MAX;
  189. id->_button_name = button_names;
  190. id->_axis_name = axis_names;
  191. id->_last_state = (u8* )&id[1];
  192. id->_state = (u8* )memory::align_top(id->_last_state + num_buttons, alignof(u8 ));
  193. id->_axis = (Vector3* )memory::align_top(id->_state + num_buttons, alignof(Vector3 ));
  194. id->_deadzone_mode = (u32* )memory::align_top(id->_axis + num_axes, alignof(u32 ));
  195. id->_deadzone_size = (f32* )memory::align_top(id->_deadzone_mode + num_axes, alignof(f32 ));
  196. id->_button_hash = (StringId32* )memory::align_top(id->_deadzone_size + num_axes, alignof(StringId32 ));
  197. id->_axis_hash = (StringId32* )memory::align_top(id->_button_hash + num_buttons, alignof(StringId32 ));
  198. id->_name = (char* )memory::align_top(id->_axis_hash + num_axes, alignof(char ));
  199. memset(id->_last_state, 0, sizeof(u8)*num_buttons);
  200. memset(id->_state, 0, sizeof(u8)*num_buttons);
  201. memset(id->_axis, 0, sizeof(Vector3)*num_axes);
  202. memset(id->_deadzone_mode, 0, sizeof(*id->_deadzone_mode)*num_axes);
  203. memset(id->_deadzone_size, 0, sizeof(*id->_deadzone_size)*num_axes);
  204. for (u32 i = 0; i < num_buttons; ++i)
  205. id->_button_hash[i] = StringId32(button_names[i]);
  206. for (u32 i = 0; i < num_axes; ++i)
  207. id->_axis_hash[i] = StringId32(axis_names[i]);
  208. strcpy(id->_name, name);
  209. return id;
  210. }
  211. void destroy(Allocator& a, InputDevice& id)
  212. {
  213. a.deallocate(&id);
  214. }
  215. } // namespace input_device
  216. } // namespace crown