simplify gitignore
[vg.git] / src / vg / vg_input.h
index 2506ba412d7686cde0b8fba74c863aea89e6eccf..5b16287fbce20ca63238037d95a1b5712dad067b 100644 (file)
@@ -1,9 +1,18 @@
 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
+#ifndef VG_INPUT_H
+#define VG_INPUT_H
 
-static inline float vg_get_axis( const char *axis );
-static inline int vg_get_button( const char *button );
-static inline int vg_get_button_down( const char *button );
-static inline int vg_get_button_up( const char *button );
+#include "common.h"
+#include "vg/vg_loader.h"
+
+VG_STATIC inline float vg_get_axis( const char *axis );
+VG_STATIC inline int vg_get_button( const char *button );
+
+/*
+ * Cannot be used in fixed update
+ */
+VG_STATIC inline int vg_get_button_down( const char *button );
+VG_STATIC inline int vg_get_button_up( const char *button );
 
 enum vg_button_state
 {
@@ -13,144 +22,532 @@ enum vg_button_state
        k_button_state_none = 0
 };
 
-GLFWgamepadstate vg_gamepad;
-int                    vg_gamepad_ready = 0;
-const char *vg_gamepad_name = NULL;
-int                    vg_gamepad_id;
+VG_STATIC struct input_binding
+{
+       const char *name;
+
+   enum input_type
+   {
+      k_input_type_button,
+      k_input_type_axis,
+      k_input_type_axis_norm,
+
+      k_input_type_unknown,
+      k_input_type_keyboard_key,
+      k_input_type_mouse_button, /* ? TODO */
+      k_input_type_gamepad_axis,
+      k_input_type_gamepad_button
+   }
+   type;
+
+   union
+   {
+      struct input_axis
+      {
+         u32 gamepad_axis,
+             keyboard_positive,
+             keyboard_negative;
+
+         int gamepad_inverted;
+         float value;
+      }
+      axis;
+
+      struct
+      {
+         u32 gamepad_id, keyboard_id;
+         int value, prev;
+      }
+      button;
+   };
 
-/* TODO: Fix this... */
-enum EInputMode
+   int save_this;
+}
+vg_named_inputs[ 32 ];
+VG_STATIC u32 vg_named_input_count = 0;
+
+VG_STATIC void vg_create_unnamed_input( struct input_binding *bind,
+                                        enum input_type type )
 {
-       k_EInputMode_pc,
-       k_EInputMode_gamepad
+   memset( bind, 0, sizeof(struct input_binding) );
+
+   bind->name = "API DEFINED";
+   bind->save_this = 0;
+   bind->type = type;
+
+   bind->axis.gamepad_axis = -1;
+   bind->axis.keyboard_positive = -1;
+   bind->axis.keyboard_negative = -1;
+   bind->button.gamepad_id = -1;
+   bind->button.keyboard_id = -1;
 }
-vg_input_mode;
 
-static struct axis_binding
+VG_STATIC struct input_binding *vg_create_named_input( const char *name,
+                                                       enum input_type type )
 {
-       const char *name;
-       union
-       {
-               int positive;
-               int bind;
-      int axis;
-       };
-       int negative;
-       
-       float value;
+   struct input_binding *bind = &vg_named_inputs[ vg_named_input_count ++ ];
+   memset( bind, 0, sizeof(struct input_binding) );
+
+   bind->name = name;
+   bind->save_this = 0;
+   bind->type = type;
+
+   bind->axis.gamepad_axis = -1;
+   bind->axis.keyboard_positive = -1;
+   bind->axis.keyboard_negative = -1;
+   bind->button.gamepad_id = -1;
+   bind->button.keyboard_id = -1;
+
+   return bind;
 }
-vg_axis_binds[];
 
-static struct button_binding
+VG_STATIC struct input_binding *vg_get_named_input( const char *name )
 {
-       const char *name;
-       int bind;
-   int controller;
-       
-       int value; int prev;
+   if( name[0] == '+' || name[0] == '-' )
+      name ++;
+
+   for( u32 i=0; i<vg_named_input_count; i++ )
+   {
+      struct input_binding *bind = &vg_named_inputs[i];
+      if( !strcmp( bind->name, name ) )
+         return bind;
+   }
+
+   return NULL;
 }
-vg_button_binds[];
 
-#include "vg_config.h"
+struct input_en
+{
+   enum input_type type;
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wreturn-type"
+   const char *alias;
+   int id;
+}
+vg_all_bindable_inputs[] =
+{
+ {k_input_type_keyboard_key, "space", GLFW_KEY_SPACE},
+ {k_input_type_keyboard_key, ";", GLFW_KEY_SEMICOLON},
+ {k_input_type_keyboard_key, "-", GLFW_KEY_MINUS},
+ {k_input_type_keyboard_key, ".", GLFW_KEY_PERIOD},
+ {k_input_type_keyboard_key, ",", GLFW_KEY_COMMA},
+ {k_input_type_keyboard_key, "=", GLFW_KEY_EQUAL},
+ {k_input_type_keyboard_key, "[", GLFW_KEY_LEFT_BRACKET},
+ {k_input_type_keyboard_key, "]", GLFW_KEY_RIGHT_BRACKET},
+ {k_input_type_keyboard_key, "left", GLFW_KEY_LEFT},
+ {k_input_type_keyboard_key, "right", GLFW_KEY_RIGHT},
+ {k_input_type_keyboard_key, "up", GLFW_KEY_UP},
+ {k_input_type_keyboard_key, "down", GLFW_KEY_DOWN},
+ {k_input_type_keyboard_key, "shift", GLFW_KEY_LEFT_SHIFT},
+ {k_input_type_keyboard_key, "control", GLFW_KEY_LEFT_CONTROL},
+ {k_input_type_keyboard_key, "\2enter", GLFW_KEY_ENTER},
+ {k_input_type_keyboard_key, "\2escape", GLFW_KEY_ESCAPE },
+ {k_input_type_gamepad_axis, "gp-lt", GLFW_GAMEPAD_AXIS_LEFT_TRIGGER},
+ {k_input_type_gamepad_axis, "gp-rt", GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER},
+ {k_input_type_gamepad_axis, "gp-ls-h", GLFW_GAMEPAD_AXIS_LEFT_X},
+ {k_input_type_gamepad_axis, "gp-ls-v", GLFW_GAMEPAD_AXIS_LEFT_Y},
+ {k_input_type_gamepad_axis, "gp-rs-h", GLFW_GAMEPAD_AXIS_RIGHT_X},
+ {k_input_type_gamepad_axis, "gp-rs-v", GLFW_GAMEPAD_AXIS_RIGHT_Y},
+ {k_input_type_gamepad_button, "gp-a", GLFW_GAMEPAD_BUTTON_A},
+ {k_input_type_gamepad_button, "gp-b", GLFW_GAMEPAD_BUTTON_B},
+ {k_input_type_gamepad_button, "gp-x", GLFW_GAMEPAD_BUTTON_X},
+ {k_input_type_gamepad_button, "gp-y", GLFW_GAMEPAD_BUTTON_Y},
+ {k_input_type_gamepad_button, "gp-rb", GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER},
+ {k_input_type_gamepad_button, "gp-lb", GLFW_GAMEPAD_BUTTON_LEFT_BUMPER},
+ {k_input_type_gamepad_button, "gp-rs", GLFW_GAMEPAD_BUTTON_RIGHT_THUMB},
+ {k_input_type_gamepad_button, "gp-ls", GLFW_GAMEPAD_BUTTON_LEFT_THUMB},
+ {k_input_type_gamepad_button, "gp-dpad-down", GLFW_GAMEPAD_BUTTON_DPAD_DOWN},
+ {k_input_type_gamepad_button, "gp-dpad-left", GLFW_GAMEPAD_BUTTON_DPAD_LEFT},
+ {k_input_type_gamepad_button, "gp-dpad-right", GLFW_GAMEPAD_BUTTON_DPAD_RIGHT},
+ {k_input_type_gamepad_button, "gp-dpad-up", GLFW_GAMEPAD_BUTTON_DPAD_UP},
+ {k_input_type_gamepad_button, "\2gp-menu", GLFW_GAMEPAD_BUTTON_BACK}
+};
 
-static inline float vg_get_axis( const char *axis )
+VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
 {
-       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;
-               }
-       }
+   if( input == -1 )
+      return NULL;
+
+   if( input_type == k_input_type_keyboard_key )
+   {
+      if( (input >= GLFW_KEY_A) && (input <= GLFW_KEY_Z) )
+      {
+         return &"a\0b\0c\0d\0e\0f\0g\0h\0i\0j\0k\0l\0m\0n\0o\0p\0"
+                 "q\0r\0s\0t\0u\0v\0w\0x\0y\0z\0"[(input-GLFW_KEY_A)*2];
+      }
+
+      if( (input >= GLFW_KEY_0) && (input <= GLFW_KEY_9) )
+      {
+         return &"0\0" "1\0" "2\0" "3\0" "4\0" 
+                 "5\0" "6\0" "7\0" "8\0" "9\0"[(input-GLFW_KEY_0)*2];
+      }
+   }
+
+   for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
+   {
+      struct input_en *desc = &vg_all_bindable_inputs[i];
+
+      if( (desc->type == input_type) && (desc->id == input) )
+         return desc->alias;
+   }
+
+   return NULL;
 }
 
-static inline struct button_binding *vg_get_button_ptr( const char *button )
+VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
 {
-       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;
-               }
-       }
+   if( !str )
+   {
+      *input = -1;
+      return k_input_type_unknown;
+   }
+
+   u32 len = strlen(str);
+
+   if( len == 0 )
+   {
+      *input = -1;
+      return k_input_type_unknown;
+   }
+
+   if( len == 1 )
+   {
+      u8 uch = str[0];
+
+      if( (uch >= (u8)'a') && (uch <= (u8)'z') )
+      {
+         *input = GLFW_KEY_A + (uch-(u8)'a');
+         return k_input_type_keyboard_key;
+      }
+
+      if( (uch >= (u8)'0') && (uch <= (u8)'9') )
+      {
+         *input = GLFW_KEY_0 + (uch-(u8)'0');
+         return k_input_type_keyboard_key;
+      }
+   }
+
+   for( int i=0; i<vg_list_size(vg_all_bindable_inputs); i++ )
+   {
+      struct input_en *desc = &vg_all_bindable_inputs[i];
+
+      if( !strcmp( desc->alias, str ) )
+      {
+         *input = desc->id;
+         return desc->type;
+      }
+   }
+   
+   *input = -1;
+   return k_input_type_unknown;
 }
-#pragma GCC diagnostic pop
 
-static int vg_console_enabled(void);
+VG_STATIC void vg_print_binding_info( struct input_binding *bind )
+{
+   vg_info( "    name: %s\n", bind->name );
+   vg_info( "    type: %s\n", (const char *[]){"button","axis","axis[0-1]"}
+                                                [ bind->type ] );
+   vg_info( "    save this? %d\n", bind->save_this );
+
+   if( (bind->type == k_input_type_axis) ||
+       (bind->type == k_input_type_axis_norm) )
+   {
+      vg_info( "      gamepad_axis: %s\n", 
+         vg_input_to_str(bind->axis.gamepad_axis, k_input_type_gamepad_axis));
 
-static inline int vg_get_button( const char *button )
+      vg_info( "      keyboard_positive: %s\n",
+         vg_input_to_str(bind->axis.keyboard_positive, 
+                         k_input_type_keyboard_key ));
+
+      vg_info( "      keyboard_negative: %s\n",
+         vg_input_to_str(bind->axis.keyboard_negative, 
+                         k_input_type_keyboard_key ));
+   }
+   else
+   {
+      vg_info( "      gamepad_id: %s\n", 
+         vg_input_to_str(bind->button.gamepad_id, k_input_type_gamepad_button));
+      vg_info( "      keyboard_id: %s\n",
+         vg_input_to_str(bind->button.keyboard_id,
+                         k_input_type_keyboard_key));
+   }
+}
+
+VG_STATIC void vg_apply_bind_str( struct input_binding *bind,
+                                  const char *mod,
+                                  const char *str )
 {
-       return vg_get_button_ptr( button )->value && !vg_console_enabled();
+   int axis_mod = 0;
+   char modch = ' ';
+   if( (mod[0] == '-') || (mod[0] == '+') )
+   {
+      axis_mod = 1;
+      modch = mod[0];
+      mod ++;
+   }
+   
+   int invert = 0;
+   if( (str[0] == '-' ) )
+   {
+      invert = 1;
+      str ++;
+   }
+
+   u32 id;
+   enum input_type type = vg_str_to_input( str, &id );
+
+   if( bind->type == k_input_type_button )
+   {
+      if( axis_mod )
+      {
+         vg_error( "Cannot use axis modifiers on button input!\n" );
+         return;
+      }
+
+      if( invert )
+      {
+         vg_error( "Cannot invert button input!\n" );
+         return;
+      }
+
+      if( type == k_input_type_keyboard_key )
+         bind->button.keyboard_id = id;
+      else if( type == k_input_type_gamepad_button )
+         bind->button.gamepad_id = id;
+      else
+      {
+         vg_error( "Unknown button or key '%s'\n", str );
+         return;
+      }
+   }
+   else if( (bind->type == k_input_type_axis ) ||
+            (bind->type == k_input_type_axis_norm))
+   {
+      if( axis_mod )
+      {
+         if( type == k_input_type_keyboard_key )
+         {
+            if( invert )
+            {
+               vg_error( "Cannot invert a keyboard key!\n" );
+               return;
+            }
+
+            if( modch == '+' )
+               bind->axis.keyboard_positive = id;
+            else
+               bind->axis.keyboard_negative = id;
+         }
+         else
+         {
+            vg_error( "You can only bind keyboard keys to +- axises\n" );
+            return;
+         }
+      }
+      else
+      {
+         if( type == k_input_type_gamepad_axis )
+         {
+            bind->axis.gamepad_inverted = invert;
+            bind->axis.gamepad_axis = id;
+         }
+         else
+         {
+            vg_error( "You can only bind gamepad axises to this\n" );
+            return;
+         }
+      }
+   }
+}
+
+/* 
+ * bind x jump 
+ * bind a -horizontal
+ * bind d +horizontal
+ * bind -gp-ls-h horizontal
+ */
+
+VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] )
+{
+   if( argc == 0 )
+   {
+      vg_info( "Usage: bind jump x\n" );
+      vg_info( "       bind -steerh j\n" );
+      vg_info( "       bind steerh gp-ls-h\n" );
+      return 0;
+   }
+
+   const char *str_bind_name = argv[0];
+   struct input_binding *bind = vg_get_named_input( str_bind_name );
+
+   if( !bind )
+   {
+      vg_error( "There is no bind with that name '%s'\n", str_bind_name );
+      return 0;
+   }
+
+   if( argc == 1 )
+   {
+      vg_print_binding_info( bind );
+      return 0;
+   }
+
+   if( argc == 2 )
+   {
+      const char *str_input_id  = argv[1];
+
+      vg_apply_bind_str( bind, str_bind_name, str_input_id );
+      return 0;
+   }
+
+   return 0;
+}
+
+VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
+{
+   if( vg_console.enabled )
+   {
+      for( i32 i=0; i<num; i++ )
+      {
+         struct input_binding *bind = &binds[i];
+
+         if( bind->type == k_input_type_button )
+         {
+            bind->button.prev = bind->button.value;
+            bind->button.value = 0;
+         }
+      }
+
+      return;
+   }
+
+   for( i32 i=0; i<num; i++ )
+   {
+      struct input_binding *bind = &binds[i];
+
+      if( bind->type == k_input_type_button )
+      {
+         bind->button.prev = bind->button.value;
+         bind->button.value = 0;
+
+         if( bind->button.gamepad_id != -1 )
+            bind->button.value |= vg.gamepad.buttons[ bind->button.gamepad_id ];
+
+         if( bind->button.keyboard_id != -1 )
+            bind->button.value |= glfwGetKey( vg.window, 
+                                              bind->button.keyboard_id );
+      }
+      else if( bind->type == k_input_type_axis )
+      {
+         float keyboard_value = 0.0f,
+               gamepad_value = 0.0f;
+
+         if( bind->axis.keyboard_positive != -1 )
+            if( glfwGetKey( vg.window, bind->axis.keyboard_positive ) )
+               keyboard_value += 1.0f;
+
+         if( bind->axis.keyboard_negative != -1 )
+            if( glfwGetKey( vg.window, bind->axis.keyboard_negative ) )
+               keyboard_value -= 1.0f;
+
+         if( bind->axis.gamepad_axis != -1 )
+         {
+            gamepad_value = vg.gamepad.axes[ bind->axis.gamepad_axis ];
+            if( bind->axis.gamepad_inverted )
+               gamepad_value *= -1.0f;
+         }
+
+         if( fabsf(gamepad_value) <= 0.01f )
+            gamepad_value = 0.0f;
+
+         if( fabsf(keyboard_value) > fabsf(gamepad_value) )
+            bind->axis.value = keyboard_value;
+         else
+            bind->axis.value = gamepad_value;
+      }
+      else if( bind->type == k_input_type_axis_norm )
+      {
+         float value = -1.0f;
+         if( bind->axis.keyboard_positive != -1 )
+            if( glfwGetKey( vg.window, bind->axis.keyboard_positive ))
+               value = 1.0f;
+         
+         if( bind->axis.gamepad_axis != -1 )
+            value = vg_maxf( value, vg.gamepad.axes[bind->axis.gamepad_axis] );
+
+         bind->axis.value = value * 0.5f + 0.5f;
+      }
+   }
+}
+
+VG_STATIC int vg_console_enabled(void);
+VG_STATIC int vg_input_button_down( struct input_binding *bind )
+{
+   if( bind->button.value && !bind->button.prev )
+      return 1;
+   return 0;
 }
+#if 0
 
-static inline int vg_get_button_down( const char *button )
+VG_STATIC float vg_get_axis( const char *axis )
 {
-       struct button_binding *bind = vg_get_button_ptr( button );
-       return bind->value & (bind->value ^ bind->prev) && !vg_console_enabled();
+   return 0.0f;
 }
 
-static inline int vg_get_button_up( const char *button )
+
+VG_STATIC void vg_get_button_states( const char *name, int *cur, int *prev )
 {
-       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 )
+VG_STATIC int vg_get_button( 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;
+   return 0;
 }
 
-static inline int key_is_keyboard( int const id )
+VG_STATIC int vg_get_button_down( const char *button )
 {
-       vg_static_assert( GLFW_MOUSE_BUTTON_LAST < GLFW_KEY_SPACE, 
-         "GLFW: Mouse has too many buttons" );
-       return id > GLFW_MOUSE_BUTTON_LAST;
+   return 0;
 }
 
-int get_button_cross_device( int const id )
+VG_STATIC int vg_get_button_up( const char *button )
 {
-       if( key_is_keyboard( id ) )
-               return glfwGetKey( vg_window, id );
-       else
-               return glfwGetMouseButton( vg_window, id ) == GLFW_PRESS;
+   return 0;
 }
 
+VG_STATIC 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;
+}
+#endif
+
 void vg_update_inputs(void)
 {
-   if( !glfwGetGamepadState( GLFW_JOYSTICK_1, &vg_gamepad) )
+   if( !glfwGetGamepadState( GLFW_JOYSTICK_1, &vg.gamepad) )
    {
-      vg_gamepad_ready = 0;
+      vg.gamepad_ready = 0;
+      vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER ] = -1.0f;
+      vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_LEFT_TRIGGER  ] = -1.0f;
    }
 
-       /* 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( binding->controller )
-         binding->value = vg_gamepad.buttons[ binding->controller ];
-      else
-         binding->value = get_button_cross_device( 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;
-      binding->value = vg_gamepad.axes[ binding->bind ];
-       }
+   /* update all inputs */
+   vg_input_update( vg_named_input_count, vg_named_inputs );
 }
 
-static void vg_gamepad_init(void)
+VG_STATIC void vg_gamepad_init(void)
 {
-   for( int id = 0; id <= GLFW_JOYSTICK_LAST; id ++ )
+   vg_acquire_thread_sync();
+
+   vg_function_push( (struct vg_cmd)
+   {
+      .name = "bind",
+      .function = vg_rebind_input_cmd
+   });
+
+   for( int id=0; id<=GLFW_JOYSTICK_LAST; id ++ )
    {
       if( glfwJoystickPresent( id ) )
       {
@@ -159,13 +556,23 @@ static void vg_gamepad_init(void)
 
       if( glfwJoystickIsGamepad( id ) )
       {
-         vg_gamepad_name = glfwGetGamepadName( id );
-         vg_success( "Gamepad with mapping registered: %s\n", vg_gamepad_name );
+         vg.gamepad_name = glfwGetGamepadName( id );
+         vg_success( "Gamepad mapping registered: %s\n", vg.gamepad_name );
          
-         vg_gamepad_ready = 1;
-         vg_gamepad_id = id;
+         /* This path usually only gets chosen when starting outside of steam */
+         if( !strcmp(vg.gamepad_name, "Steam Controller") )
+            vg.gamepad_use_trackpad_look = 1;
          
+         vg.gamepad_ready = 1;
+         vg.gamepad_id = id;
          break;
       }
    }
+
+   vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER ] = -1.0f;
+   vg.gamepad.axes[ GLFW_GAMEPAD_AXIS_LEFT_TRIGGER  ] = -1.0f;
+
+   vg_release_thread_sync();
 }
+
+#endif