small refactors
[vg.git] / vg_input.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2 #ifndef VG_INPUT_H
3 #define VG_INPUT_H
4
5 #include "common.h"
6 #include "vg/vg_loader.h"
7
8 #define VG_MAX_CONTROLLERS 4
9
10 VG_STATIC float controller_deadzone = 0.05f;
11
12 struct{
13 const u8 *sdl_keys;
14
15 struct vg_controller{
16 SDL_GameController *handle; /* handle for controller. NULL if unused */
17 SDL_JoystickID instance_id; /* uid used in events */
18
19 float axises[ SDL_CONTROLLER_AXIS_MAX ];
20 u32 buttons[ SDL_CONTROLLER_BUTTON_MAX ];
21 }
22 controllers[4];
23
24 int active_controller_index; /* most recent controller (by button press)
25 will be -1 if no controllers active */
26
27 /* what the user is currently using. the keyboard and controller are still
28 * active simultaneously, but this reflects what the UI should show */
29 enum input_method{
30 k_input_method_kbm,
31 k_input_method_controller
32 }
33 display_input_method;
34 SDL_GameControllerType display_input_type;
35 }
36 static vg_input = { .active_controller_index = -2 };
37
38 VG_STATIC u8 vg_getkey( SDL_Keycode kc )
39 {
40 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
41 return vg_input.sdl_keys[sc];
42 }
43
44 /*
45 * takes SDL device index, and tries to open that on any free channel
46 */
47 VG_STATIC int vg_open_gamecontroller( Sint32 index )
48 {
49 struct vg_controller *controller = NULL;
50 int vg_id = 0;
51 const char *name = SDL_GameControllerNameForIndex( index );
52 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
53
54 if( instance_id == -1 ){
55 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
56 return -1;
57 }
58
59 for( int j=0; j<VG_MAX_CONTROLLERS; j++ ){
60 struct vg_controller *esta = &vg_input.controllers[j];
61
62 if( esta->handle ){
63 if( esta->instance_id == instance_id ){
64 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
65 esta->instance_id, j );
66 return -1;
67 }
68 }
69 else{
70 if( !controller ){
71 controller = &vg_input.controllers[j];
72 vg_id = j;
73 }
74 }
75 }
76
77 if( controller ){
78 controller->handle = SDL_GameControllerOpen( index );
79 controller->instance_id = instance_id;
80
81 if( controller->handle ){
82 vg_success(
83 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
84 instance_id, name, vg_id );
85
86 for( u32 i=0; i< SDL_CONTROLLER_BUTTON_MAX; i++ )
87 controller->buttons[i] = 0;
88
89 for( u32 i=0; i< SDL_CONTROLLER_AXIS_MAX; i++ )
90 controller->axises[i] = 0.0f;
91
92 controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f;
93 controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f;
94
95 if( vg_input.active_controller_index == -2 ){
96 vg_input.active_controller_index = vg_id;
97 vg_input.display_input_method = k_input_method_controller;
98 vg_input.display_input_type =
99 SDL_GameControllerGetType( controller->handle );
100 }
101
102 return vg_id;
103 }
104 else{
105 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
106 name, SDL_GetError() );
107 return -1;
108 }
109 }
110 else{
111 vg_error( ". Too many controllers open! ignoring '%s'\n", name );
112 return -1;
113 }
114 }
115
116 VG_STATIC void vg_input_device_event( SDL_Event *ev )
117 {
118 if( ev->type == SDL_CONTROLLERDEVICEADDED ){
119 int is_controller = SDL_IsGameController( ev->cdevice.which );
120 const char *name = SDL_JoystickNameForIndex( ev->cdevice.which );
121
122 Sint32 index = ev->cdevice.which;
123 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
124 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
125 index, name );
126
127 if( is_controller ){
128 vg_open_gamecontroller( index );
129 }
130 }
131 else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){
132 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
133 ev->cdevice.which );
134
135 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
136 struct vg_controller *controller = &vg_input.controllers[i];
137
138 if( controller->handle ){
139 if( controller->instance_id == ev->cdevice.which ){
140 vg_info( " . closing controller at index #%d\n", i );
141 SDL_GameControllerClose( controller->handle );
142 controller->handle = NULL;
143 controller->instance_id = -1;
144
145 if( vg_input.active_controller_index == i ){
146 vg_input.active_controller_index = -1;
147 vg_input.display_input_method = k_input_method_kbm;
148 vg_info( "display_input: k_input_method_kbm\n" );
149 }
150 break;
151 }
152 }
153 }
154 }
155 }
156
157 VG_STATIC void vg_input_controller_event( SDL_Event *ev )
158 {
159 if( ev->type == SDL_CONTROLLERAXISMOTION ){
160 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
161 struct vg_controller *esta = &vg_input.controllers[i];
162
163 if( ev->caxis.which == esta->instance_id ){
164 float value = (float)ev->caxis.value / 32767.0f;
165
166 if( ev->caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ||
167 ev->caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ||
168 ev->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX ||
169 ev->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY )
170 {
171 float deadz = vg_clampf( controller_deadzone, 0.0f, 0.999f ),
172 high = vg_maxf( 0.0f, fabsf(value) - deadz );
173
174 value = vg_signf(value) * (high / (1.0f-deadz));
175 }
176
177 esta->axises[ ev->caxis.axis ] = value;
178 break;
179 }
180 }
181 }
182 else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){
183 struct vg_controller *active = NULL;
184
185 if( vg_input.active_controller_index >= 0 )
186 active = &vg_input.controllers[vg_input.active_controller_index];
187
188 if( !active || (ev->cbutton.which != active->instance_id) ){
189 active = NULL;
190 vg_input.active_controller_index = -1;
191 vg_input.display_input_method = k_input_method_kbm;
192
193 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
194 if( vg_input.controllers[i].instance_id == ev->cbutton.which ){
195 active = &vg_input.controllers[i];
196 vg_input.active_controller_index = i;
197 vg_input.display_input_type =
198 SDL_GameControllerGetType(active->handle);
199 break;
200 }
201 }
202
203 if( active ){
204 vg_info( "Switching active controller index to #%d\n",
205 vg_input.active_controller_index );
206 }
207 else{
208 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
209 ev->cbutton.which );
210 }
211 }
212
213 if( active ){
214 if( vg_input.display_input_method != k_input_method_controller ){
215 vg_input.display_input_method = k_input_method_controller;
216 vg_info( "display_input: k_input_method_controller\n" );
217 }
218 active->buttons[ ev->cbutton.button ] = 1;
219 }
220 }
221 else if( ev->type == SDL_CONTROLLERBUTTONUP ){
222 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
223 struct vg_controller *esta = &vg_input.controllers[i];
224
225 if( ev->cbutton.which == esta->instance_id ){
226 esta->buttons[ ev->cbutton.button ] = 0;
227 break;
228 }
229 }
230 }
231 }
232
233 VG_STATIC void vg_process_inputs(void)
234 {
235 int count;
236 vg_input.sdl_keys = SDL_GetKeyboardState( &count );
237
238 if( vg_input.display_input_method != k_input_method_kbm ){
239 /* check for giving keyboard priority */
240 for( int i=0; i<count; i++ ){
241 if( vg_input.sdl_keys[i] ){
242 vg_input.display_input_method = k_input_method_kbm;
243 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i );
244 break;
245 }
246 }
247
248 /* check for giving mouse priority */
249 if( SDL_GetMouseState(NULL,NULL) &
250 (SDL_BUTTON(SDL_BUTTON_LEFT)|SDL_BUTTON(SDL_BUTTON_RIGHT)|
251 SDL_BUTTON(SDL_BUTTON_MIDDLE)) )
252 {
253 vg_input.display_input_method = k_input_method_kbm;
254 vg_info( "display_input: k_input_method_kbm (mouse)\n" );
255 }
256 }
257 }
258
259 VG_STATIC void async_vg_input_init( void *payload, u32 size )
260 {
261 VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT );
262
263 vg_info( "Checking for controllers\n" );
264 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
265
266 int joy_count = SDL_NumJoysticks();
267 for( int i=0; i<joy_count; i++ ) {
268 const char *name = SDL_JoystickNameForIndex( i );
269 int is_controller = SDL_IsGameController(i);
270
271 vg_info( "%d: %s [controller: %d]\n", i, name, is_controller );
272
273 if( is_controller ){
274 vg_open_gamecontroller( i );
275 }
276 }
277 }
278
279 VG_STATIC void vg_input_init(void)
280 {
281 vg_async_call( async_vg_input_init, NULL, 0 );
282 }
283
284 VG_STATIC void vg_input_free(void)
285 {
286 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
287 struct vg_controller *controller = &vg_input.controllers[i];
288
289 if( controller->handle ){
290 SDL_GameControllerClose( controller->handle );
291 controller->handle = NULL;
292 }
293 }
294 }
295
296 #endif