build system revision
[vg.git] / vg_input.c
1 /* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved */
2
3 #include "vg_input.h"
4 #include "vg_loader.h"
5 #include "vg_engine.h"
6 #include "vg_async.h"
7 #include "vg_string.h"
8
9 f32 controller_deadzone = 0.05f;
10
11 struct vg_input vg_input = {
12 .active_controller_index = -2
13 };
14
15 u8 vg_getkey( SDL_Keycode kc )
16 {
17 SDL_Scancode sc = SDL_GetScancodeFromKey( kc );
18 return vg_input.sdl_keys[sc];
19 }
20
21 /*
22 * takes SDL device index, and tries to open that on any free channel
23 */
24 static int vg_open_gamecontroller( Sint32 index )
25 {
26 struct vg_controller *controller = NULL;
27 int vg_id = 0;
28 const char *name = SDL_GameControllerNameForIndex( index );
29 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
30
31 if( instance_id == -1 ){
32 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
33 return -1;
34 }
35
36 for( int j=0; j<VG_MAX_CONTROLLERS; j++ ){
37 struct vg_controller *esta = &vg_input.controllers[j];
38
39 if( esta->handle ){
40 if( esta->instance_id == instance_id ){
41 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
42 esta->instance_id, j );
43 return -1;
44 }
45 }
46 else{
47 if( !controller ){
48 controller = &vg_input.controllers[j];
49 vg_id = j;
50 }
51 }
52 }
53
54 if( controller ){
55 controller->handle = SDL_GameControllerOpen( index );
56 controller->instance_id = instance_id;
57
58 if( controller->handle ){
59 vg_success(
60 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
61 instance_id, name, vg_id );
62
63 for( u32 i=0; i< SDL_CONTROLLER_BUTTON_MAX; i++ )
64 controller->buttons[i] = 0;
65
66 for( u32 i=0; i< SDL_CONTROLLER_AXIS_MAX; i++ )
67 controller->axises[i] = 0.0f;
68
69 if( vg_input.active_controller_index == -2 ){
70 vg_input.active_controller_index = vg_id;
71 vg_input.display_input_method = k_input_method_controller;
72 vg_input.display_input_type =
73 SDL_GameControllerGetType( controller->handle );
74 }
75
76 return vg_id;
77 }
78 else{
79 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
80 name, SDL_GetError() );
81 return -1;
82 }
83 }
84 else{
85 vg_error( ". Too many controllers open! ignoring '%s'\n", name );
86 return -1;
87 }
88 }
89
90 void vg_input_device_event( SDL_Event *ev )
91 {
92 if( ev->type == SDL_CONTROLLERDEVICEADDED ){
93 int is_controller = SDL_IsGameController( ev->cdevice.which );
94 const char *name = SDL_JoystickNameForIndex( ev->cdevice.which );
95
96 Sint32 index = ev->cdevice.which;
97 SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index );
98 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
99 index, name );
100
101 if( is_controller ){
102 vg_open_gamecontroller( index );
103 }
104 }
105 else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){
106 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
107 ev->cdevice.which );
108
109 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
110 struct vg_controller *controller = &vg_input.controllers[i];
111
112 if( controller->handle ){
113 if( controller->instance_id == ev->cdevice.which ){
114 vg_info( " . closing controller at index #%d\n", i );
115 SDL_GameControllerClose( controller->handle );
116 controller->handle = NULL;
117 controller->instance_id = -1;
118
119 if( vg_input.active_controller_index == i ){
120 vg_input.active_controller_index = -1;
121 vg_input.display_input_method = k_input_method_kbm;
122 vg_info( "display_input: k_input_method_kbm\n" );
123 }
124 break;
125 }
126 }
127 }
128 }
129 }
130
131 void vg_input_controller_event( SDL_Event *ev )
132 {
133 if( ev->type == SDL_CONTROLLERAXISMOTION ){
134 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
135 struct vg_controller *esta = &vg_input.controllers[i];
136
137 if( ev->caxis.which == esta->instance_id ){
138 float value = (float)ev->caxis.value / 32767.0f;
139
140 if( ev->caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ||
141 ev->caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ||
142 ev->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX ||
143 ev->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTY )
144 {
145 float deadz = vg_clampf( controller_deadzone, 0.0f, 0.999f ),
146 high = vg_maxf( 0.0f, fabsf(value) - deadz );
147
148 value = vg_signf(value) * (high / (1.0f-deadz));
149 }
150
151 esta->axises[ ev->caxis.axis ] = value;
152 break;
153 }
154 }
155 }
156 else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){
157 struct vg_controller *active = NULL;
158
159 if( vg_input.active_controller_index >= 0 )
160 active = &vg_input.controllers[vg_input.active_controller_index];
161
162 if( !active || (ev->cbutton.which != active->instance_id) ){
163 active = NULL;
164 vg_input.active_controller_index = -1;
165 vg_input.display_input_method = k_input_method_kbm;
166
167 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
168 if( vg_input.controllers[i].instance_id == ev->cbutton.which ){
169 active = &vg_input.controllers[i];
170 vg_input.active_controller_index = i;
171 vg_input.display_input_type =
172 SDL_GameControllerGetType(active->handle);
173 break;
174 }
175 }
176
177 if( active ){
178 vg_info( "Switching active controller index to #%d\n",
179 vg_input.active_controller_index );
180 }
181 else{
182 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
183 ev->cbutton.which );
184 }
185 }
186
187 if( active ){
188 if( vg_input.display_input_method != k_input_method_controller ){
189 vg_input.display_input_method = k_input_method_controller;
190 vg_info( "display_input: k_input_method_controller\n" );
191 }
192 active->buttons[ ev->cbutton.button ] = 1;
193 }
194 }
195 else if( ev->type == SDL_CONTROLLERBUTTONUP ){
196 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
197 struct vg_controller *esta = &vg_input.controllers[i];
198
199 if( ev->cbutton.which == esta->instance_id ){
200 esta->buttons[ ev->cbutton.button ] = 0;
201 break;
202 }
203 }
204 }
205 }
206
207 void vg_process_inputs(void)
208 {
209 int count;
210 vg_input.sdl_keys = SDL_GetKeyboardState( &count );
211 vg_input.sdl_mouse = SDL_GetMouseState(NULL,NULL);
212
213 if( vg_input.display_input_method != k_input_method_kbm ){
214 /* check for giving keyboard priority */
215 for( int i=0; i<count; i++ ){
216 if( vg_input.sdl_keys[i] ){
217 vg_input.display_input_method = k_input_method_kbm;
218 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i );
219 break;
220 }
221 }
222
223 /* check for giving mouse priority */
224 if( vg_input.sdl_mouse &
225 (SDL_BUTTON(SDL_BUTTON_LEFT)|SDL_BUTTON(SDL_BUTTON_RIGHT)|
226 SDL_BUTTON(SDL_BUTTON_MIDDLE)) )
227 {
228 vg_input.display_input_method = k_input_method_kbm;
229 vg_info( "display_input: k_input_method_kbm (mouse)\n" );
230 }
231 }
232 }
233
234 void async_vg_input_init( void *payload, u32 size )
235 {
236 vg_info( "Checking for controllers\n" );
237 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
238
239 int joy_count = SDL_NumJoysticks();
240 for( int i=0; i<joy_count; i++ ) {
241 const char *name = SDL_JoystickNameForIndex( i );
242 int is_controller = SDL_IsGameController(i);
243
244 vg_info( "%d: %s [controller: %d]\n", i, name, is_controller );
245
246 if( is_controller ){
247 vg_open_gamecontroller( i );
248 }
249 }
250 }
251
252 void vg_input_init(void)
253 {
254 VG_VAR_F32( controller_deadzone, flags=VG_VAR_PERSISTENT );
255 vg_async_call( async_vg_input_init, NULL, 0 );
256 }
257
258 void vg_input_free(void)
259 {
260 for( int i=0; i<VG_MAX_CONTROLLERS; i++ ){
261 struct vg_controller *controller = &vg_input.controllers[i];
262
263 if( controller->handle ){
264 SDL_GameControllerClose( controller->handle );
265 controller->handle = NULL;
266 }
267 }
268 }
269
270 struct vg_controller *vg_active_controller(void)
271 {
272 if( vg_input.active_controller_index >= 0 )
273 return &vg_input.controllers[vg_input.active_controller_index];
274 else
275 return NULL;
276 }
277
278 u8 vg_controller_button( SDL_GameControllerButton button )
279 {
280 struct vg_controller *c = vg_active_controller();
281 if( c ) return c->buttons[ button ];
282 else return 0;
283 }
284
285 f32 vg_controller_axis( SDL_GameControllerAxis axis )
286 {
287 struct vg_controller *c = vg_active_controller();
288 if( c ) return c->axises[ axis ];
289 else return 0;
290 }
291
292 static void vg_input_apply_to_u8( vg_input_op mode, u8 data, u8 *inout_result ){
293 if ( mode == vg_mode_absmax ) *inout_result |= data;
294 else if( mode == vg_mode_mul ) *inout_result &= data;
295 else vg_fatal_error( "mode not supported for destination type (%d)", mode );
296 }
297
298 static void vg_input_apply_to_f32( vg_input_op mode, f32 data,
299 f32 *inout_result ){
300 if ( mode == vg_mode_absmax ){
301 if( fabsf(data) > fabsf(*inout_result) )
302 *inout_result = data;
303 }
304 else if( mode == vg_mode_max ) *inout_result = vg_maxf(*inout_result,data);
305 else if( mode == vg_mode_mul ) *inout_result *= (f32)data;
306 else if( mode == vg_mode_sub ) *inout_result -= (f32)data;
307 else if( mode == vg_mode_add ) *inout_result += (f32)data;
308 else vg_fatal_error( "mode not supported for destination type (%d)", mode );
309 }
310
311 /*
312 * Run an input program. out_result must point to memory with sufficient
313 * storage respective to the size set by type.
314 */
315 void vg_exec_input_program( enum vg_input_type type, vg_input_op *ops,
316 void *out_result ){
317 u8 *out_button = NULL;
318 f32 *out_joy = NULL;
319
320 if( type == k_vg_input_type_button_u8 ){
321 out_button = out_result;
322 *out_button = 0;
323 }
324 else if( type == k_vg_input_type_axis_f32 ){
325 out_joy = out_result;
326 out_joy[0] = 0.0f;
327 }
328 else if( type == k_vg_input_type_joy_v2f ){
329 out_joy = out_result;
330 out_joy[0] = 0.0f;
331 out_joy[1] = 0.0f;
332 }
333
334 /* computer state */
335 vg_input_op mode = vg_mode_absmax;
336 u32 pc = 0, index = 0;
337
338 next_code:;
339 vg_input_op op = ops[ pc ++ ];
340
341 if( (op >= vg_mode_mul) && (op <= vg_mode_max) )
342 mode = op;
343 else if( (op == vg_keyboard) || (op == vg_mouse) || (op == vg_joy_button) ){
344 u8 state = 0;
345
346 if( op == vg_keyboard )
347 state = vg_getkey(ops[pc ++]);
348 else if( op == vg_mouse )
349 state = (vg_input.sdl_mouse & SDL_BUTTON(ops[pc ++]))?1:0;
350 else
351 state = vg_controller_button(ops[pc ++]);
352
353 if( type == k_vg_input_type_button_u8 )
354 vg_input_apply_to_u8( mode, state, out_button );
355 else
356 vg_input_apply_to_f32( mode, (f32)state, &out_joy[index] );
357 }
358 else if( op == vg_joy_axis ){
359 f32 state = vg_controller_axis( ops[pc ++] );
360 if( type == k_vg_input_type_button_u8 )
361 vg_input_apply_to_u8( mode, state>0.5f?1:0, out_button );
362 else
363 vg_input_apply_to_f32( mode, state, &out_joy[index] );
364 }
365 else if( (op == vg_joy_ls) || (op == vg_joy_rs) ){
366 if( type == k_vg_input_type_joy_v2f ){
367 vg_input_apply_to_f32( mode,
368 vg_controller_axis( op==vg_joy_ls? SDL_CONTROLLER_AXIS_LEFTX:
369 SDL_CONTROLLER_AXIS_RIGHTX),
370 &out_joy[0] );
371 vg_input_apply_to_f32( mode,
372 vg_controller_axis( op==vg_joy_ls? SDL_CONTROLLER_AXIS_LEFTY:
373 SDL_CONTROLLER_AXIS_RIGHTY),
374 &out_joy[1] );
375 }
376 }
377 else if( op == vg_index )
378 index = ops[pc ++];
379 else if( op == vg_end )
380 return;
381 else if( op == vg_normalize )
382 v2_normalize( out_joy );
383 else if( op == vg_gui_visible )
384 pc ++;
385 else
386 vg_fatal_error( "unknown op\n" );
387
388 goto next_code;
389 }
390
391 /*
392 * Get vendor specific button glyphs based on SDL button ID
393 */
394 const char *controller_button_str( SDL_GameControllerButton button )
395 {
396 static const char *controller_glyphs[ SDL_CONTROLLER_BUTTON_MAX ][2] = {
397 /* xbox/generic playstation */
398 [ SDL_CONTROLLER_BUTTON_A ] = { "\x1e\x85","\x1e\x82" },
399 [ SDL_CONTROLLER_BUTTON_B ] = { "\x1e\x86","\x1e\x81" },
400 [ SDL_CONTROLLER_BUTTON_X ] = { "\x1e\x83","\x1e\x7f" },
401 [ SDL_CONTROLLER_BUTTON_Y ] = { "\x1e\x84","\x1e\x80" },
402 [ SDL_CONTROLLER_BUTTON_LEFTSTICK ] = { "\x87", "\x87" },
403 [ SDL_CONTROLLER_BUTTON_RIGHTSTICK ] = { "\x8b", "\x8b" },
404 [ SDL_CONTROLLER_BUTTON_LEFTSHOULDER ] = { "\x91", "\x91" },
405 [ SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ]= { "\x92", "\x92" },
406 [ SDL_CONTROLLER_BUTTON_DPAD_LEFT ] = { "\x1e\x93","\x1e\x93" },
407 [ SDL_CONTROLLER_BUTTON_DPAD_UP ] = { "\x1e\x94","\x1e\x94" },
408 [ SDL_CONTROLLER_BUTTON_DPAD_RIGHT ] = { "\x1e\x95","\x1e\x95" },
409 [ SDL_CONTROLLER_BUTTON_DPAD_DOWN ] = { "\x1e\x96","\x1e\x96" },
410 [ SDL_CONTROLLER_BUTTON_GUIDE ] = { "\x91", "\x91" },
411 };
412
413 if( vg_input.display_input_type == SDL_CONTROLLER_TYPE_PS3 ||
414 vg_input.display_input_type == SDL_CONTROLLER_TYPE_PS4 ||
415 vg_input.display_input_type == SDL_CONTROLLER_TYPE_PS5 )
416 {
417 return controller_glyphs[ button ][ 1 ];
418 }
419 else if( vg_input.display_input_type ==
420 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO ||
421 vg_input.display_input_type ==
422 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT ||
423 vg_input.display_input_type ==
424 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR ||
425 vg_input.display_input_type ==
426 SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT )
427 {
428 return NULL;
429 }
430 else
431 return controller_glyphs[ button ][ 0 ];
432 }
433
434 /*
435 * Cat keyboard key string. special_glyphs include SR glyphs
436 */
437 void vg_keyboard_key_string( vg_str *str, u32 key, int special_glyphs )
438 {
439 if( (key >= SDLK_a) && (key <= SDLK_z) ){
440 key = (key-SDLK_a)+(u32)'A';
441
442 if( special_glyphs ){
443 vg_strcatch( str, '\x1f' );
444 vg_strcatch( str, key );
445 vg_strcatch( str, ' ' );
446 }
447 else
448 vg_strcatch( str, key );
449 }
450 else if( (key == SDLK_LSHIFT) || (key == SDLK_RSHIFT) )
451 vg_strcat( str, special_glyphs? "\x9e": "shift" );
452 else if( (key == SDLK_LCTRL) || (key == SDLK_RCTRL) )
453 vg_strcat( str, special_glyphs? "\x9f": "ctrl" );
454 else if( (key == SDLK_LALT) || (key == SDLK_RALT) )
455 vg_strcat( str, special_glyphs? "\xa0": "alt" );
456 else if( key == SDLK_SPACE )
457 vg_strcat( str, special_glyphs? "\xa1": "space" );
458 else if( (key == SDLK_RETURN) || (key == SDLK_RETURN2) )
459 vg_strcat( str, special_glyphs? "\xa2": "return" );
460 else if( key == SDLK_ESCAPE )
461 vg_strcat( str, special_glyphs? "\xa3": "escape" );
462 else if( key == SDLK_RIGHT )
463 vg_strcat( str, special_glyphs? "\x1f\x95 ": "right" );
464 else if( key == SDLK_LEFT )
465 vg_strcat( str, special_glyphs? "\x1f\x93 ": "left" );
466 else if( key == SDLK_UP )
467 vg_strcat( str, special_glyphs? "\x1f\x94 ": "up" );
468 else if( key == SDLK_DOWN )
469 vg_strcat( str, special_glyphs? "\x1f\x96 ": "down" );
470 else {
471 vg_strcat( str, "keyboard key #" );
472 vg_strcati32( str, key );
473 }
474 }
475
476 /*
477 * Cat mouse button string. special_glyphs include SR glyphs
478 */
479 void vg_mouse_button_string( vg_str *str, u32 button, int special_glyphs )
480 {
481 if ( button == SDL_BUTTON_LEFT )
482 vg_strcat( str, special_glyphs? "\x99": "left mouse" );
483 else if( button == SDL_BUTTON_RIGHT )
484 vg_strcat( str, special_glyphs? "\x9a": "right mouse" );
485 else if( button == SDL_BUTTON_MIDDLE )
486 vg_strcat( str, special_glyphs? "\x9c": "middle mouse" );
487 else{
488 vg_strcat( str, "mouse button #" );
489 vg_strcati32( str, button );
490 }
491 }
492
493 /*
494 * Cat string represeinting single axis
495 */
496 void vg_joy_axis_string( vg_str *str, SDL_GameControllerAxis axis,
497 int special_glyphs )
498 {
499 if( axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT )
500 vg_strcat( str, special_glyphs?"\x8f":"left trigger" );
501 else if( axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT )
502 vg_strcat( str, special_glyphs?"\x90":"right trigger" );
503 else if( axis == SDL_CONTROLLER_AXIS_LEFTX )
504 vg_strcat( str, special_glyphs?"\x88":"left stick horizontal" );
505 else if( axis == SDL_CONTROLLER_AXIS_LEFTY )
506 vg_strcat( str, special_glyphs?"\x89":"left stick vertical" );
507 else if( axis == SDL_CONTROLLER_AXIS_RIGHTX )
508 vg_strcat( str, special_glyphs?"\x8c":"right stick horizontal" );
509 else if( axis == SDL_CONTROLLER_AXIS_RIGHTY )
510 vg_strcat( str, special_glyphs?"\x8d":"right stick vertical" );
511 else{
512 vg_strcat( str, "axis " );
513 vg_strcati32( str, axis );
514 }
515 }
516
517 /*
518 * Cat string represeinting whole joystick
519 */
520 void vg_joy_string( vg_str *str, vg_input_op op, int special_glyphs )
521 {
522 if( op == vg_joy_ls )
523 vg_strcat( str, special_glyphs? "\x87": "left stick" );
524 else
525 vg_strcat( str, special_glyphs? "\x8b": "right stick" );
526 }
527
528 /*
529 * Convert an input program into a readable string
530 */
531 void vg_input_string( vg_str *str, vg_input_op *ops, int glyphs )
532 {
533 u32 pc = 0;
534 int applicable = 0, visible = 1;
535
536 next_code:;
537 vg_input_op op = ops[ pc ++ ];
538
539 if( (op == vg_keyboard) || (op == vg_mouse) ){
540 if( (vg_input.display_input_method == k_input_method_kbm) && visible ){
541 applicable = 1;
542
543 if( op == vg_keyboard )
544 vg_keyboard_key_string( str, ops[pc], glyphs );
545 else
546 vg_mouse_button_string( str, ops[pc], glyphs );
547 }
548 else applicable = 0;
549 pc ++;
550 }
551 else if( (op == vg_joy_button) || (op == vg_joy_axis) ){
552 if( (vg_input.display_input_method == k_input_method_controller)
553 && visible ){
554 applicable = 1;
555
556 if( op == vg_joy_button )
557 vg_strcat( str, controller_button_str(ops[pc]) );
558 else
559 vg_joy_axis_string( str, ops[pc], glyphs );
560 }
561 else applicable = 0;
562 pc ++;
563 }
564 else if( (op == vg_joy_ls) || (op == vg_joy_rs) ){
565 if( (vg_input.display_input_method == k_input_method_controller)
566 && visible ){
567 applicable = 1;
568 vg_joy_string( str, op, glyphs );
569 }
570 else applicable = 0;
571 }
572 else if( op == vg_mode_mul ){
573 if( applicable && visible )
574 vg_strcat( str, " + " );
575 }
576 else if( op == vg_index )
577 pc ++;
578 else if( op == vg_gui_visible )
579 visible = ops[pc++];
580 else if( op == vg_end )
581 return;
582
583 goto next_code;
584 }