simplify gitignore
[vg.git] / src / vg / 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 VG_STATIC inline float vg_get_axis( const char *axis );
9 VG_STATIC inline int vg_get_button( const char *button );
10
11 /*
12 * Cannot be used in fixed update
13 */
14 VG_STATIC inline int vg_get_button_down( const char *button );
15 VG_STATIC inline int vg_get_button_up( const char *button );
16
17 enum vg_button_state
18 {
19 k_button_state_down = 1,
20 k_button_state_up = 3,
21 k_button_state_pressed = 2,
22 k_button_state_none = 0
23 };
24
25 VG_STATIC struct input_binding
26 {
27 const char *name;
28
29 enum input_type
30 {
31 k_input_type_button,
32 k_input_type_axis,
33 k_input_type_axis_norm,
34
35 k_input_type_unknown,
36 k_input_type_keyboard_key,
37 k_input_type_mouse_button, /* ? TODO */
38 k_input_type_gamepad_axis,
39 k_input_type_gamepad_button
40 }
41 type;
42
43 union
44 {
45 struct input_axis
46 {
47 u32 gamepad_axis,
48 keyboard_positive,
49 keyboard_negative;
50
51 int gamepad_inverted;
52 float value;
53 }
54 axis;
55
56 struct
57 {
58 u32 gamepad_id, keyboard_id;
59 int value, prev;
60 }
61 button;
62 };
63
64 int save_this;
65 }
66 vg_named_inputs[ 32 ];
67 VG_STATIC u32 vg_named_input_count = 0;
68
69 VG_STATIC void vg_create_unnamed_input( struct input_binding *bind,
70 enum input_type type )
71 {
72 memset( bind, 0, sizeof(struct input_binding) );
73
74 bind->name = "API DEFINED";
75 bind->save_this = 0;
76 bind->type = type;
77
78 bind->axis.gamepad_axis = -1;
79 bind->axis.keyboard_positive = -1;
80 bind->axis.keyboard_negative = -1;
81 bind->button.gamepad_id = -1;
82 bind->button.keyboard_id = -1;
83 }
84
85 VG_STATIC struct input_binding *vg_create_named_input( const char *name,
86 enum input_type type )
87 {
88 struct input_binding *bind = &vg_named_inputs[ vg_named_input_count ++ ];
89 memset( bind, 0, sizeof(struct input_binding) );
90
91 bind->name = name;
92 bind->save_this = 0;
93 bind->type = type;
94
95 bind->axis.gamepad_axis = -1;
96 bind->axis.keyboard_positive = -1;
97 bind->axis.keyboard_negative = -1;
98 bind->button.gamepad_id = -1;
99 bind->button.keyboard_id = -1;
100
101 return bind;
102 }
103
104 VG_STATIC struct input_binding *vg_get_named_input( const char *name )
105 {
106 if( name[0] == '+' || name[0] == '-' )
107 name ++;
108
109 for( u32 i=0; i<vg_named_input_count; i++ )
110 {
111 struct input_binding *bind = &vg_named_inputs[i];
112 if( !strcmp( bind->name, name ) )
113 return bind;
114 }
115
116 return NULL;
117 }
118
119 struct input_en
120 {
121 enum input_type type;
122
123 const char *alias;
124 int id;
125 }
126 vg_all_bindable_inputs[] =
127 {
128 {k_input_type_keyboard_key, "space", GLFW_KEY_SPACE},
129 {k_input_type_keyboard_key, ";", GLFW_KEY_SEMICOLON},
130 {k_input_type_keyboard_key, "-", GLFW_KEY_MINUS},
131 {k_input_type_keyboard_key, ".", GLFW_KEY_PERIOD},
132 {k_input_type_keyboard_key, ",", GLFW_KEY_COMMA},
133 {k_input_type_keyboard_key, "=", GLFW_KEY_EQUAL},
134 {k_input_type_keyboard_key, "[", GLFW_KEY_LEFT_BRACKET},
135 {k_input_type_keyboard_key, "]", GLFW_KEY_RIGHT_BRACKET},
136 {k_input_type_keyboard_key, "left", GLFW_KEY_LEFT},
137 {k_input_type_keyboard_key, "right", GLFW_KEY_RIGHT},
138 {k_input_type_keyboard_key, "up", GLFW_KEY_UP},
139 {k_input_type_keyboard_key, "down", GLFW_KEY_DOWN},
140 {k_input_type_keyboard_key, "shift", GLFW_KEY_LEFT_SHIFT},
141 {k_input_type_keyboard_key, "control", GLFW_KEY_LEFT_CONTROL},
142 {k_input_type_keyboard_key, "\2enter", GLFW_KEY_ENTER},
143 {k_input_type_keyboard_key, "\2escape", GLFW_KEY_ESCAPE },
144
145 {k_input_type_gamepad_axis, "gp-lt", GLFW_GAMEPAD_AXIS_LEFT_TRIGGER},
146 {k_input_type_gamepad_axis, "gp-rt", GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER},
147 {k_input_type_gamepad_axis, "gp-ls-h", GLFW_GAMEPAD_AXIS_LEFT_X},
148 {k_input_type_gamepad_axis, "gp-ls-v", GLFW_GAMEPAD_AXIS_LEFT_Y},
149 {k_input_type_gamepad_axis, "gp-rs-h", GLFW_GAMEPAD_AXIS_RIGHT_X},
150 {k_input_type_gamepad_axis, "gp-rs-v", GLFW_GAMEPAD_AXIS_RIGHT_Y},
151
152 {k_input_type_gamepad_button, "gp-a", GLFW_GAMEPAD_BUTTON_A},
153 {k_input_type_gamepad_button, "gp-b", GLFW_GAMEPAD_BUTTON_B},
154 {k_input_type_gamepad_button, "gp-x", GLFW_GAMEPAD_BUTTON_X},
155 {k_input_type_gamepad_button, "gp-y", GLFW_GAMEPAD_BUTTON_Y},
156 {k_input_type_gamepad_button, "gp-rb", GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER},
157 {k_input_type_gamepad_button, "gp-lb", GLFW_GAMEPAD_BUTTON_LEFT_BUMPER},
158 {k_input_type_gamepad_button, "gp-rs", GLFW_GAMEPAD_BUTTON_RIGHT_THUMB},
159 {k_input_type_gamepad_button, "gp-ls", GLFW_GAMEPAD_BUTTON_LEFT_THUMB},
160 {k_input_type_gamepad_button, "gp-dpad-down", GLFW_GAMEPAD_BUTTON_DPAD_DOWN},
161 {k_input_type_gamepad_button, "gp-dpad-left", GLFW_GAMEPAD_BUTTON_DPAD_LEFT},
162 {k_input_type_gamepad_button, "gp-dpad-right", GLFW_GAMEPAD_BUTTON_DPAD_RIGHT},
163 {k_input_type_gamepad_button, "gp-dpad-up", GLFW_GAMEPAD_BUTTON_DPAD_UP},
164 {k_input_type_gamepad_button, "\2gp-menu", GLFW_GAMEPAD_BUTTON_BACK}
165 };
166
167 VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
168 {
169 if( input == -1 )
170 return NULL;
171
172 if( input_type == k_input_type_keyboard_key )
173 {
174 if( (input >= GLFW_KEY_A) && (input <= GLFW_KEY_Z) )
175 {
176 return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
177 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input-GLFW_KEY_A)*2];
178 }
179
180 if( (input >= GLFW_KEY_0) && (input <= GLFW_KEY_9) )
181 {
182 return &"0\0" "1\0" "2\0" "3\0" "4\0"
183 "5\0" "6\0" "7\0" "8\0" "9\0"[(input-GLFW_KEY_0)*2];
184 }
185 }
186
187 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
188 {
189 struct input_en *desc = &vg_all_bindable_inputs[i];
190
191 if( (desc->type == input_type) && (desc->id == input) )
192 return desc->alias;
193 }
194
195 return NULL;
196 }
197
198 VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
199 {
200 if( !str )
201 {
202 *input = -1;
203 return k_input_type_unknown;
204 }
205
206 u32 len = strlen(str);
207
208 if( len == 0 )
209 {
210 *input = -1;
211 return k_input_type_unknown;
212 }
213
214 if( len == 1 )
215 {
216 u8 uch = str[0];
217
218 if( (uch >= (u8)'a') && (uch <= (u8)'z') )
219 {
220 *input = GLFW_KEY_A + (uch-(u8)'a');
221 return k_input_type_keyboard_key;
222 }
223
224 if( (uch >= (u8)'0') && (uch <= (u8)'9') )
225 {
226 *input = GLFW_KEY_0 + (uch-(u8)'0');
227 return k_input_type_keyboard_key;
228 }
229 }
230
231 for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
232 {
233 struct input_en *desc = &vg_all_bindable_inputs[i];
234
235 if( !strcmp( desc->alias, str ) )
236 {
237 *input = desc->id;
238 return desc->type;
239 }
240 }
241
242 *input = -1;
243 return k_input_type_unknown;
244 }
245
246 VG_STATIC void vg_print_binding_info( struct input_binding *bind )
247 {
248 vg_info( " name: %s\n", bind->name );
249 vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
250 [ bind->type ] );
251 vg_info( " save this? %d\n", bind->save_this );
252
253 if( (bind->type == k_input_type_axis) ||
254 (bind->type == k_input_type_axis_norm) )
255 {
256 vg_info( " gamepad_axis: %s\n",
257 vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis));
258
259 vg_info( " keyboard_positive: %s\n",
260 vg_input_to_str(bind->axis.keyboard_positive,
261 k_input_type_keyboard_key ));
262
263 vg_info( " keyboard_negative: %s\n",
264 vg_input_to_str(bind->axis.keyboard_negative,
265 k_input_type_keyboard_key ));
266 }
267 else
268 {
269 vg_info( " gamepad_id: %s\n",
270 vg_input_to_str(bind->button.gamepad_id, k_input_type_gamepad_button));
271 vg_info( " keyboard_id: %s\n",
272 vg_input_to_str(bind->button.keyboard_id,
273 k_input_type_keyboard_key));
274 }
275 }
276
277 VG_STATIC void vg_apply_bind_str( struct input_binding *bind,
278 const char *mod,
279 const char *str )
280 {
281 int axis_mod = 0;
282 char modch = ' ';
283 if( (mod[0] == '-') || (mod[0] == '+') )
284 {
285 axis_mod = 1;
286 modch = mod[0];
287 mod ++;
288 }
289
290 int invert = 0;
291 if( (str[0] == '-' ) )
292 {
293 invert = 1;
294 str ++;
295 }
296
297 u32 id;
298 enum input_type type = vg_str_to_input( str, &id );
299
300 if( bind->type == k_input_type_button )
301 {
302 if( axis_mod )
303 {
304 vg_error( "Cannot use axis modifiers on button input!\n" );
305 return;
306 }
307
308 if( invert )
309 {
310 vg_error( "Cannot invert button input!\n" );
311 return;
312 }
313
314 if( type == k_input_type_keyboard_key )
315 bind->button.keyboard_id = id;
316 else if( type == k_input_type_gamepad_button )
317 bind->button.gamepad_id = id;
318 else
319 {
320 vg_error( "Unknown button or key '%s'\n", str );
321 return;
322 }
323 }
324 else if( (bind->type == k_input_type_axis ) ||
325 (bind->type == k_input_type_axis_norm))
326 {
327 if( axis_mod )
328 {
329 if( type == k_input_type_keyboard_key )
330 {
331 if( invert )
332 {
333 vg_error( "Cannot invert a keyboard key!\n" );
334 return;
335 }
336
337 if( modch == '+' )
338 bind->axis.keyboard_positive = id;
339 else
340 bind->axis.keyboard_negative = id;
341 }
342 else
343 {
344 vg_error( "You can only bind keyboard keys to +- axises\n" );
345 return;
346 }
347 }
348 else
349 {
350 if( type == k_input_type_gamepad_axis )
351 {
352 bind->axis.gamepad_inverted = invert;
353 bind->axis.gamepad_axis = id;
354 }
355 else
356 {
357 vg_error( "You can only bind gamepad axises to this\n" );
358 return;
359 }
360 }
361 }
362 }
363
364 /*
365 * bind x jump
366 * bind a -horizontal
367 * bind d +horizontal
368 * bind -gp-ls-h horizontal
369 */
370
371 VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] )
372 {
373 if( argc == 0 )
374 {
375 vg_info( "Usage: bind jump x\n" );
376 vg_info( " bind -steerh j\n" );
377 vg_info( " bind steerh gp-ls-h\n" );
378 return 0;
379 }
380
381 const char *str_bind_name = argv[0];
382 struct input_binding *bind = vg_get_named_input( str_bind_name );
383
384 if( !bind )
385 {
386 vg_error( "There is no bind with that name '%s'\n", str_bind_name );
387 return 0;
388 }
389
390 if( argc == 1 )
391 {
392 vg_print_binding_info( bind );
393 return 0;
394 }
395
396 if( argc == 2 )
397 {
398 const char *str_input_id = argv[1];
399
400 vg_apply_bind_str( bind, str_bind_name, str_input_id );
401 return 0;
402 }
403
404 return 0;
405 }
406
407 VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
408 {
409 if( vg_console.enabled )
410 {
411 for( i32 i=0; i<num; i++ )
412 {
413 struct input_binding *bind = &binds[i];
414
415 if( bind->type == k_input_type_button )
416 {
417 bind->button.prev = bind->button.value;
418 bind->button.value = 0;
419 }
420 }
421
422 return;
423 }
424
425 for( i32 i=0; i<num; i++ )
426 {
427 struct input_binding *bind = &binds[i];
428
429 if( bind->type == k_input_type_button )
430 {
431 bind->button.prev = bind->button.value;
432 bind->button.value = 0;
433
434 if( bind->button.gamepad_id != -1 )
435 bind->button.value |= vg.gamepad.buttons[ bind->button.gamepad_id ];
436
437 if( bind->button.keyboard_id != -1 )
438 bind->button.value |= glfwGetKey( vg.window,
439 bind->button.keyboard_id );
440 }
441 else if( bind->type == k_input_type_axis )
442 {
443 float keyboard_value = 0.0f,
444 gamepad_value = 0.0f;
445
446 if( bind->axis.keyboard_positive != -1 )
447 if( glfwGetKey( vg.window, bind->axis.keyboard_positive ) )
448 keyboard_value += 1.0f;
449
450 if( bind->axis.keyboard_negative != -1 )
451 if( glfwGetKey( vg.window, bind->axis.keyboard_negative ) )
452 keyboard_value -= 1.0f;
453
454 if( bind->axis.gamepad_axis != -1 )
455 {
456 gamepad_value = vg.gamepad.axes[ bind->axis.gamepad_axis ];
457 if( bind->axis.gamepad_inverted )
458 gamepad_value *= -1.0f;
459 }
460
461 if( fabsf(gamepad_value) <= 0.01f )
462 gamepad_value = 0.0f;
463
464 if( fabsf(keyboard_value) > fabsf(gamepad_value) )
465 bind->axis.value = keyboard_value;
466 else
467 bind->axis.value = gamepad_value;
468 }
469 else if( bind->type == k_input_type_axis_norm )
470 {
471 float value = -1.0f;
472 if( bind->axis.keyboard_positive != -1 )
473 if( glfwGetKey( vg.window, bind->axis.keyboard_positive ))
474 value = 1.0f;
475
476 if( bind->axis.gamepad_axis != -1 )
477 value = vg_maxf( value, vg.gamepad.axes[bind->axis.gamepad_axis] );
478
479 bind->axis.value = value * 0.5f + 0.5f;
480 }
481 }
482 }
483
484 VG_STATIC int vg_console_enabled(void);
485 VG_STATIC int vg_input_button_down( struct input_binding *bind )
486 {
487 if( bind->button.value && !bind->button.prev )
488 return 1;
489 return 0;
490 }
491 #if 0
492
493 VG_STATIC float vg_get_axis( const char *axis )
494 {
495 return 0.0f;
496 }
497
498
499 VG_STATIC void vg_get_button_states( const char *name, int *cur, int *prev )
500 {
501 }
502
503 VG_STATIC int vg_get_button( const char *button )
504 {
505 return 0;
506 }
507
508 VG_STATIC int vg_get_button_down( const char *button )
509 {
510 return 0;
511 }
512
513 VG_STATIC int vg_get_button_up( const char *button )
514 {
515 return 0;
516 }
517
518 VG_STATIC enum vg_button_state vg_get_button_state( const char *button )
519 {
520 if(vg_get_button_down( button )) return k_button_state_down;
521 if(vg_get_button_up( button )) return k_button_state_up;
522 if(vg_get_button( button )) return k_button_state_pressed;
523 return k_button_state_none;
524 }
525 #endif
526
527 void vg_update_inputs(void)
528 {
529 if( !glfwGetGamepadState( GLFW_JOYSTICK_1, &vg.gamepad) )
530 {
531 vg.gamepad_ready = 0;
532 vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER ] = -1.0f;
533 vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_LEFT_TRIGGER ] = -1.0f;
534 }
535
536 /* update all inputs */
537 vg_input_update( vg_named_input_count, vg_named_inputs );
538 }
539
540 VG_STATIC void vg_gamepad_init(void)
541 {
542 vg_acquire_thread_sync();
543
544 vg_function_push( (struct vg_cmd)
545 {
546 .name = "bind",
547 .function = vg_rebind_input_cmd
548 });
549
550 for( int id=0; id<=GLFW_JOYSTICK_LAST; id ++ )
551 {
552 if( glfwJoystickPresent( id ) )
553 {
554 vg_info( "Joystick found: '%s'\n", glfwGetJoystickName(id) );
555 }
556
557 if( glfwJoystickIsGamepad( id ) )
558 {
559 vg.gamepad_name = glfwGetGamepadName( id );
560 vg_success( "Gamepad mapping registered: %s\n", vg.gamepad_name );
561
562 /* This path usually only gets chosen when starting outside of steam */
563 if( !strcmp(vg.gamepad_name, "Steam Controller") )
564 vg.gamepad_use_trackpad_look = 1;
565
566 vg.gamepad_ready = 1;
567 vg.gamepad_id = id;
568 break;
569 }
570 }
571
572 vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER ] = -1.0f;
573 vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_LEFT_TRIGGER ] = -1.0f;
574
575 vg_release_thread_sync();
576 }
577
578 #endif