--- /dev/null
+// Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
+
+static inline float vg_get_axis( const char *axis ) __attribute__((unused));
+static inline int vg_get_button( const char *button ) __attribute__((unused));
+static inline int vg_get_button_down( const char *button ) __attribute__((unused));
+static inline int vg_get_button_up( const char *button ) __attribute__((unused));
+
+enum vg_button_state
+{
+ k_button_state_down = 1,
+ k_button_state_up = 3,
+ k_button_state_pressed = 2,
+ k_button_state_none = 0
+};
+
+// Input
+// ===========================================================================================================
+GLFWgamepadstate vg_gamepad;
+int vg_gamepad_ready = 0;
+const char *vg_gamepad_name = NULL;
+int vg_gamepad_id;
+
+enum EInputMode
+{
+ k_EInputMode_pc,
+ k_EInputMode_gamepad
+}
+vg_input_mode;
+
+static struct axis_binding
+{
+ const char *name;
+ union
+ {
+ int positive;
+ int bind;
+ };
+ int negative;
+
+ float value;
+}
+vg_axis_binds[];
+
+static struct button_binding
+{
+ const char *name;
+ int bind;
+
+ int value; int prev;
+}
+vg_button_binds[];
+
+#include "vg/config.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wreturn-type"
+
+static inline float vg_get_axis( const char *axis )
+{
+ for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
+ {
+ if( !strcmp( axis, vg_axis_binds[i].name ) )
+ {
+ return vg_axis_binds[i].value;
+ }
+ }
+}
+
+static inline struct button_binding *vg_get_button_ptr( const char *button )
+{
+ for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
+ {
+ if( !strcmp( button, vg_button_binds[i].name ) )
+ {
+ return vg_button_binds + i;
+ }
+ }
+}
+#pragma GCC diagnostic pop
+
+static int vg_console_enabled(void);
+
+static inline int vg_get_button( const char *button )
+{
+ return vg_get_button_ptr( button )->value && !vg_console_enabled();
+}
+
+static inline int vg_get_button_down( const char *button )
+{
+ struct button_binding *bind = vg_get_button_ptr( button );
+ return bind->value & (bind->value ^ bind->prev) && !vg_console_enabled();
+}
+
+static inline int vg_get_button_up( const char *button )
+{
+ struct button_binding *bind = vg_get_button_ptr( button );
+ return bind->prev & (bind->value ^ bind->prev) && !vg_console_enabled();
+}
+
+static inline enum vg_button_state vg_get_button_state( const char *button )
+{
+ if( vg_get_button_down( button ) ) return k_button_state_down;
+ if( vg_get_button_up( button ) ) return k_button_state_up;
+ if( vg_get_button( button ) ) return k_button_state_pressed;
+ return k_button_state_none;
+}
+
+static inline int key_is_keyboard( int const id )
+{
+ vg_static_assert( GLFW_MOUSE_BUTTON_LAST < GLFW_KEY_SPACE, "GLFW: Mouse has too many buttons" );
+ return id > GLFW_MOUSE_BUTTON_LAST;
+}
+
+// Mouse AND Keyboard get button press
+int get_button_cross_device( int const id )
+{
+ if( key_is_keyboard( id ) )
+ {
+ return glfwGetKey( vg_window, id );
+ }
+ else
+ {
+ return glfwGetMouseButton( vg_window, id ) == GLFW_PRESS;
+ }
+}
+
+void vg_update_inputs(void)
+{
+ // Update button inputs
+ for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
+ {
+ struct button_binding *binding = vg_button_binds + i;
+ binding->prev = binding->value;
+
+ if( vg_input_mode == k_EInputMode_pc )
+ {
+ binding->value = get_button_cross_device( binding->bind );
+ }
+ else
+ {
+ binding->value = vg_gamepad.buttons[ binding->bind ];
+ }
+ }
+
+ // Update axis inputs
+ for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
+ {
+ struct axis_binding *binding = vg_axis_binds + i;
+
+ if( vg_input_mode == k_EInputMode_pc )
+ {
+ binding->value = get_button_cross_device( binding->positive );
+ binding->value -= get_button_cross_device( binding->negative );
+ }
+ else
+ {
+ binding->value = vg_gamepad.axes[ binding->bind ];
+ }
+ }
+}