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