2D Run-and-gun shooter inspired by One Man's Doomsday, Counter-Strike, and Metal Slug.
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.
 
 
 
 
 
 

248 lines
7.4 KiB

  1. #include "IZ_joystick.h"
  2. static IZ_ConfigItem joystick_config_items[IZ_PLAYERS * (IZ_CONTROLS - 4 + 2) + 1];
  3. bool IZ_JoystickIsValidAxisThreshold(u16 value) {
  4. return (4000 <= value && value <= 12000);
  5. }
  6. void IZ_JoystickHandleDeviceEvents(IZ_JoystickState* state, SDL_Event e) {
  7. if (e.type == SDL_JOYDEVICEADDED) {
  8. if (SDL_NumJoysticks() <= IZ_PLAYERS && !state->device) {
  9. state->device = SDL_JoystickOpen(e.jdevice.which);
  10. }
  11. return;
  12. }
  13. if (e.type == SDL_JOYDEVICEREMOVED) {
  14. if (
  15. state->device
  16. && SDL_JoystickInstanceID(state->device) == e.jdevice.which
  17. ) {
  18. state->device = NULL;
  19. }
  20. }
  21. }
  22. void IZ_JoystickHandleAxisEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) {
  23. if (e.type == SDL_JOYAXISMOTION) {
  24. // XInput handling
  25. u8 control_index;
  26. for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
  27. if (e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_LEFT_SHOULDER && state->config.control_mapping[control_index] == 10) {
  28. const u16 bitflag = (0x1 << control_index);
  29. if (e.jaxis.value > state->config.axis_threshold) {
  30. *action |= bitflag;
  31. return;
  32. }
  33. if (e.jaxis.value <= state->config.axis_threshold) {
  34. *action &= ~bitflag;
  35. return;
  36. }
  37. }
  38. if (e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_RIGHT_SHOULDER && state->config.control_mapping[control_index] == 11) {
  39. const u16 bitflag = (0x1 << control_index);
  40. if (e.jaxis.value > state->config.axis_threshold) {
  41. *action |= bitflag;
  42. return;
  43. }
  44. if (e.jaxis.value <= state->config.axis_threshold) {
  45. *action &= ~bitflag;
  46. return;
  47. }
  48. }
  49. }
  50. if (
  51. e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_HORIZONTAL1
  52. || e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_HORIZONTAL2
  53. ) {
  54. *action &= ~(0x1 << IZ_ACTION_INDEX_RIGHT);
  55. *action &= ~(0x1 << IZ_ACTION_INDEX_LEFT);
  56. if (e.jaxis.value > state->config.axis_threshold) {
  57. *action |= (0x1 << IZ_ACTION_INDEX_RIGHT);
  58. return;
  59. }
  60. if (e.jaxis.value <= -state->config.axis_threshold) {
  61. *action |= (0x1 << IZ_ACTION_INDEX_LEFT);
  62. }
  63. return;
  64. }
  65. if (
  66. e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_VERTICAL1
  67. || e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_VERTICAL2
  68. ) {
  69. *action &= ~(0x1 << IZ_ACTION_INDEX_UP);
  70. *action &= ~(0x1 << IZ_ACTION_INDEX_DOWN);
  71. if (e.jaxis.value > state->config.axis_threshold) {
  72. *action |= (0x1 << IZ_ACTION_INDEX_DOWN);
  73. return;
  74. }
  75. if (e.jaxis.value <= -state->config.axis_threshold) {
  76. *action |= (0x1 << IZ_ACTION_INDEX_UP);
  77. }
  78. }
  79. }
  80. }
  81. void IZ_JoystickHandleHatEvents(IZ_Action* action, SDL_Event e) {
  82. if (e.type == SDL_JOYHATMOTION) {
  83. *action &= ~(0x1 << IZ_ACTION_INDEX_UP);
  84. *action &= ~(0x1 << IZ_ACTION_INDEX_RIGHT);
  85. *action &= ~(0x1 << IZ_ACTION_INDEX_DOWN);
  86. *action &= ~(0x1 << IZ_ACTION_INDEX_LEFT);
  87. if (e.jhat.value != 0) {
  88. *action |= e.jhat.value;
  89. }
  90. }
  91. }
  92. void IZ_JoystickHandleButtonEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) {
  93. u8 control_index;
  94. for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
  95. if (e.jbutton.button == state->config.control_mapping[control_index]) {
  96. const u16 bitflag = (0x1 << control_index);
  97. if (e.type == SDL_JOYBUTTONDOWN) {
  98. *action |= bitflag;
  99. return;
  100. }
  101. if (e.type == SDL_JOYBUTTONUP) {
  102. *action &= ~bitflag;
  103. return;
  104. }
  105. }
  106. }
  107. }
  108. void IZ_JoystickHandleEvents(IZ_JoystickState(* state)[IZ_PLAYERS], IZ_Action(* action)[IZ_PLAYERS], SDL_Event e) {
  109. u8 player_index;
  110. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  111. IZ_JoystickHandleDeviceEvents(&(*state)[player_index], e);
  112. IZ_JoystickHandleAxisEvents(&(*state)[player_index], &(*action)[player_index], e);
  113. IZ_JoystickHandleHatEvents(&(*action)[player_index], e);
  114. IZ_JoystickHandleButtonEvents(&(*state)[player_index], &(*action)[player_index], e);
  115. }
  116. }
  117. void IZ_JoystickBindStateToConfig(IZ_JoystickState(* state)[IZ_PLAYERS], IZ_ConfigItem config_items[]) {
  118. u8 player_index;
  119. u8 control_index;
  120. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  121. u8 base_index = (player_index * (IZ_CONTROLS - 4 + 2));
  122. config_items[base_index].dest = &((*state)[player_index].config.device_id);
  123. config_items[base_index + 1].dest = &((*state)[player_index].config.axis_threshold);
  124. for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
  125. config_items[base_index + 2 + (control_index - 4)].dest = &((*state)[player_index].config.control_mapping[control_index]);
  126. }
  127. }
  128. }
  129. IZ_ProcedureResult IZ_JoystickSaveConfig(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path) {
  130. IZ_JoystickBindStateToConfig(state, joystick_config_items);
  131. return IZ_ConfigSave(joystick_config_items, config_path);
  132. }
  133. void IZ_JoystickInitializeConfigItems(IZ_ConfigItem config_items[]) {
  134. u8 player_index;
  135. u8 control_index;
  136. char* main_section_name;
  137. char* control_mapping_section_name;
  138. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  139. main_section_name = SDL_malloc(sizeof(char) * 64);
  140. sprintf_s(main_section_name, 64, "Joystick.%d", player_index);
  141. u8 base_index = (player_index * (IZ_CONTROLS - 4 + 2));
  142. config_items[base_index] = (IZ_ConfigItem) {
  143. IZ_CONFIG_TYPE_I32,
  144. sizeof(i32),
  145. main_section_name,
  146. "DeviceID",
  147. NULL,
  148. &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.device_id,
  149. NULL,
  150. NULL,
  151. };
  152. config_items[base_index + 1] = (IZ_ConfigItem) {
  153. IZ_CONFIG_TYPE_U16,
  154. sizeof(u16),
  155. main_section_name,
  156. "AxisThreshold",
  157. NULL,
  158. &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.axis_threshold,
  159. IZ_JoystickIsValidAxisThreshold,
  160. NULL,
  161. };
  162. control_mapping_section_name = SDL_malloc(sizeof(char) * 64);
  163. sprintf_s(control_mapping_section_name, 64, "Joystick.%d.ControlMapping", player_index);
  164. for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
  165. config_items[base_index + 2 + (control_index - 4)] = (IZ_ConfigItem) {
  166. IZ_CONFIG_TYPE_U8,
  167. sizeof(u8),
  168. control_mapping_section_name,
  169. IZ_ACTION_NAMES[control_index],
  170. NULL,
  171. &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.control_mapping[control_index],
  172. NULL,
  173. NULL,
  174. };
  175. }
  176. }
  177. config_items[IZ_PLAYERS * (IZ_CONTROLS - 4 + 2)] = (IZ_ConfigItem) {
  178. IZ_CONFIG_TYPE_VOID,
  179. 0,
  180. NULL,
  181. NULL,
  182. NULL,
  183. NULL,
  184. NULL,
  185. NULL,
  186. };
  187. }
  188. IZ_ProcedureResult IZ_JoystickInitializeConfig(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) {
  189. IZ_JoystickInitializeConfigItems(joystick_config_items);
  190. IZ_JoystickBindStateToConfig(state, joystick_config_items);
  191. if (IZ_ConfigInitialize(joystick_config_items, config_path, argc, argv) < 0) {
  192. return -1;
  193. }
  194. return 0;
  195. }
  196. IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) {
  197. SDL_memcpy(state, &IZ_JOYSTICK_DEFAULT_STATE, sizeof(IZ_JoystickState) * IZ_PLAYERS);
  198. if (IZ_JoystickInitializeConfig(state, config_path, argc, argv) < 0) {
  199. return -2;
  200. }
  201. u8 player_index;
  202. u8 joysticks_count = SDL_NumJoysticks();
  203. for (player_index = 0; player_index < joysticks_count; player_index += 1) {
  204. if (player_index >= IZ_PLAYERS) {
  205. break;
  206. }
  207. (*state)[player_index].device = SDL_JoystickOpen(state[player_index]->config.device_id);
  208. }
  209. return 0;
  210. }
  211. void IZ_JoystickTeardown(IZ_JoystickState(* state)[IZ_PLAYERS]) {
  212. u8 player_index;
  213. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  214. if (!(*state)[player_index].device) {
  215. continue;
  216. }
  217. SDL_JoystickClose((*state)[player_index].device);
  218. }
  219. }