c33853136ceb01e15dd8ff94dbd7c383ddd8eff6
[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 static inline float vg_get_axis( const char *axis );
9 static inline int vg_get_button( const char *button );
10 static inline int vg_get_button_down( const char *button );
11 static inline int vg_get_button_up( const char *button );
12
13 enum vg_button_state
14 {
15 k_button_state_down = 1,
16 k_button_state_up = 3,
17 k_button_state_pressed = 2,
18 k_button_state_none = 0
19 };
20
21 /* TODO: Fix this... */
22 enum EInputMode
23 {
24 k_EInputMode_pc,
25 k_EInputMode_gamepad
26 }
27 vg_input_mode;
28
29 static struct axis_binding
30 {
31 const char *name;
32 union
33 {
34 int positive;
35 int bind;
36 int axis;
37 };
38 int negative;
39
40 float value;
41 }
42 vg_axis_binds[];
43
44 static struct button_binding
45 {
46 const char *name;
47 int bind;
48
49 int value; int prev;
50 }
51 vg_button_binds[],
52 vg_controller_binds[];
53
54 #include "vg_config.h"
55
56 #pragma GCC diagnostic push
57 #pragma GCC diagnostic ignored "-Wreturn-type"
58
59 static inline float vg_get_axis( const char *axis )
60 {
61 for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
62 if( !strcmp( axis, vg_axis_binds[i].name ) )
63 return vg_axis_binds[i].value;
64 }
65
66 static inline struct button_binding *vg_get_button_ptr( const char *button )
67 {
68 for( int i=0; i<vg_list_size(vg_button_binds); i ++ )
69 if( !strcmp(button,vg_button_binds[i].name) )
70 return vg_button_binds + i;
71 return NULL;
72 }
73
74 static inline struct button_binding *vg_get_button_ptr_c( const char *button )
75 {
76 for( int i=0; i<vg_list_size(vg_controller_binds); i ++ )
77 if( !strcmp(button,vg_controller_binds[i].name) )
78 return vg_controller_binds + i;
79 return NULL;
80 }
81
82 #pragma GCC diagnostic pop
83
84 static int vg_console_enabled(void);
85
86 static inline void vg_get_button_states( const char *name, int *cur, int *prev )
87 {
88 struct button_binding *bind = vg_get_button_ptr( name ),
89 *bindc = vg_get_button_ptr_c( name );
90
91 *cur = 0; *prev = 0;
92
93 if( bind )
94 {
95 *cur |= bind->value;
96 *prev |= bind->prev;
97 }
98
99 if( bindc )
100 {
101 *cur |= bindc->value;
102 *prev |= bindc->prev;
103 }
104 }
105
106 static inline int vg_get_button( const char *button )
107 {
108 int cur, prev;
109 vg_get_button_states( button, &cur, &prev );
110
111 return cur && !vg_console_enabled();
112 }
113
114 static inline int vg_get_button_down( const char *button )
115 {
116 int cur, prev;
117 vg_get_button_states( button, &cur, &prev );
118
119 return cur & (cur ^ prev) && !vg_console_enabled();
120 }
121
122 static inline int vg_get_button_up( const char *button )
123 {
124 int cur, prev;
125 vg_get_button_states( button, &cur, &prev );
126
127 return prev & (cur ^ prev) && !vg_console_enabled();
128 }
129
130 static inline enum vg_button_state vg_get_button_state( const char *button )
131 {
132 if(vg_get_button_down( button )) return k_button_state_down;
133 if(vg_get_button_up( button )) return k_button_state_up;
134 if(vg_get_button( button )) return k_button_state_pressed;
135 return k_button_state_none;
136 }
137
138 static inline int key_is_keyboard( int const id )
139 {
140 vg_static_assert( GLFW_MOUSE_BUTTON_LAST < GLFW_KEY_SPACE,
141 "GLFW: Mouse has too many buttons" );
142 return id > GLFW_MOUSE_BUTTON_LAST;
143 }
144
145 int get_button_cross_device( int const id )
146 {
147 if( key_is_keyboard( id ) )
148 return glfwGetKey( vg.window, id );
149 else
150 return glfwGetMouseButton( vg.window, id ) == GLFW_PRESS;
151 }
152
153 void vg_update_inputs(void)
154 {
155 if( !glfwGetGamepadState( GLFW_JOYSTICK_1, &vg.gamepad) )
156 vg.gamepad_ready = 0;
157
158 /* Update button inputs */
159 for( int i = 0; i < vg_list_size( vg_button_binds ); i ++ )
160 {
161 struct button_binding *binding = vg_button_binds + i;
162 binding->prev = binding->value;
163 binding->value = get_button_cross_device( binding->bind );
164 }
165
166 for( int i=0; i<vg_list_size( vg_controller_binds ); i++ )
167 {
168 struct button_binding *binding = vg_controller_binds + i;
169 binding->prev = binding->value;
170 binding->value = vg.gamepad.buttons[ binding->bind ];
171 }
172
173 /* Update axis inputs */
174 for( int i = 0; i < vg_list_size( vg_axis_binds ); i ++ )
175 {
176 struct axis_binding *binding = vg_axis_binds + i;
177 binding->value = vg.gamepad.axes[ binding->bind ];
178 }
179 }
180
181 static void vg_gamepad_init(void)
182 {
183 vg_acquire_thread_sync();
184
185 for( int id=0; id<=GLFW_JOYSTICK_LAST; id ++ )
186 {
187 if( glfwJoystickPresent( id ) )
188 {
189 vg_info( "Joystick found: '%s'\n", glfwGetJoystickName(id) );
190 }
191
192 if( glfwJoystickIsGamepad( id ) )
193 {
194 vg.gamepad_name = glfwGetGamepadName( id );
195 vg_success( "Gamepad mapping registered: %s\n", vg.gamepad_name );
196
197 vg.gamepad_ready = 1;
198 vg.gamepad_id = id;
199 break;
200 }
201 }
202
203 vg_release_thread_sync();
204 }
205
206 #endif