1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
6 #include "vg/vg_loader.h"
8 #define VG_MAX_CONTROLLERS 4
10 static float controller_deadzone
= 0.05f
;
11 typedef u32 vg_input_op
;
12 typedef vg_input_op
*vg_input_program
;
15 k_vg_input_type_button_u8
,
16 k_vg_input_type_axis_f32
,
17 k_vg_input_type_joy_v2f
53 SDL_GameController
*handle
; /* handle for controller. NULL if unused */
54 SDL_JoystickID instance_id
; /* uid used in events */
56 float axises
[ SDL_CONTROLLER_AXIS_MAX
];
57 u32 buttons
[ SDL_CONTROLLER_BUTTON_MAX
];
61 int active_controller_index
; /* most recent controller (by button press)
62 will be -1 if no controllers active */
64 /* what the user is currently using. the keyboard and controller are still
65 * active simultaneously, but this reflects what the UI should show */
68 k_input_method_controller
71 SDL_GameControllerType display_input_type
;
73 static vg_input
= { .active_controller_index
= -2 };
75 static u8
vg_getkey( SDL_Keycode kc
)
77 SDL_Scancode sc
= SDL_GetScancodeFromKey( kc
);
78 return vg_input
.sdl_keys
[sc
];
82 * takes SDL device index, and tries to open that on any free channel
84 static int vg_open_gamecontroller( Sint32 index
)
86 struct vg_controller
*controller
= NULL
;
88 const char *name
= SDL_GameControllerNameForIndex( index
);
89 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
91 if( instance_id
== -1 ){
92 vg_error( ". Invalid device index (vg_open_gamecontroller)\n" );
96 for( int j
=0; j
<VG_MAX_CONTROLLERS
; j
++ ){
97 struct vg_controller
*esta
= &vg_input
.controllers
[j
];
100 if( esta
->instance_id
== instance_id
){
101 vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n",
102 esta
->instance_id
, j
);
108 controller
= &vg_input
.controllers
[j
];
115 controller
->handle
= SDL_GameControllerOpen( index
);
116 controller
->instance_id
= instance_id
;
118 if( controller
->handle
){
120 " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n",
121 instance_id
, name
, vg_id
);
123 for( u32 i
=0; i
< SDL_CONTROLLER_BUTTON_MAX
; i
++ )
124 controller
->buttons
[i
] = 0;
126 for( u32 i
=0; i
< SDL_CONTROLLER_AXIS_MAX
; i
++ )
127 controller
->axises
[i
] = 0.0f
;
129 if( vg_input
.active_controller_index
== -2 ){
130 vg_input
.active_controller_index
= vg_id
;
131 vg_input
.display_input_method
= k_input_method_controller
;
132 vg_input
.display_input_type
=
133 SDL_GameControllerGetType( controller
->handle
);
139 vg_error( ". Failed to attach game controller '%s'. Reason: %s\n",
140 name
, SDL_GetError() );
145 vg_error( ". Too many controllers open! ignoring '%s'\n", name
);
150 static void vg_input_device_event( SDL_Event
*ev
)
152 if( ev
->type
== SDL_CONTROLLERDEVICEADDED
){
153 int is_controller
= SDL_IsGameController( ev
->cdevice
.which
);
154 const char *name
= SDL_JoystickNameForIndex( ev
->cdevice
.which
);
156 Sint32 index
= ev
->cdevice
.which
;
157 SDL_JoystickID instance_id
= SDL_JoystickGetDeviceInstanceID( index
);
158 vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n",
162 vg_open_gamecontroller( index
);
165 else if( ev
->type
== SDL_CONTROLLERDEVICEREMOVED
){
166 vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n",
169 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
170 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
172 if( controller
->handle
){
173 if( controller
->instance_id
== ev
->cdevice
.which
){
174 vg_info( " . closing controller at index #%d\n", i
);
175 SDL_GameControllerClose( controller
->handle
);
176 controller
->handle
= NULL
;
177 controller
->instance_id
= -1;
179 if( vg_input
.active_controller_index
== i
){
180 vg_input
.active_controller_index
= -1;
181 vg_input
.display_input_method
= k_input_method_kbm
;
182 vg_info( "display_input: k_input_method_kbm\n" );
191 static void vg_input_controller_event( SDL_Event
*ev
)
193 if( ev
->type
== SDL_CONTROLLERAXISMOTION
){
194 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
195 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
197 if( ev
->caxis
.which
== esta
->instance_id
){
198 float value
= (float)ev
->caxis
.value
/ 32767.0f
;
200 if( ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTX
||
201 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_LEFTY
||
202 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTX
||
203 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_RIGHTY
)
205 float deadz
= vg_clampf( controller_deadzone
, 0.0f
, 0.999f
),
206 high
= vg_maxf( 0.0f
, fabsf(value
) - deadz
);
208 value
= vg_signf(value
) * (high
/ (1.0f
-deadz
));
210 else if( ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_TRIGGERLEFT
||
211 ev
->caxis
.axis
== SDL_CONTROLLER_AXIS_TRIGGERRIGHT
){
212 value
= 0.5f
+ value
*0.5f
;
215 esta
->axises
[ ev
->caxis
.axis
] = value
;
220 else if( ev
->type
== SDL_CONTROLLERBUTTONDOWN
){
221 struct vg_controller
*active
= NULL
;
223 if( vg_input
.active_controller_index
>= 0 )
224 active
= &vg_input
.controllers
[vg_input
.active_controller_index
];
226 if( !active
|| (ev
->cbutton
.which
!= active
->instance_id
) ){
228 vg_input
.active_controller_index
= -1;
229 vg_input
.display_input_method
= k_input_method_kbm
;
231 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
232 if( vg_input
.controllers
[i
].instance_id
== ev
->cbutton
.which
){
233 active
= &vg_input
.controllers
[i
];
234 vg_input
.active_controller_index
= i
;
235 vg_input
.display_input_type
=
236 SDL_GameControllerGetType(active
->handle
);
242 vg_info( "Switching active controller index to #%d\n",
243 vg_input
.active_controller_index
);
246 vg_error( "Input out of range (SDL_JoystickID#%d)\n",
252 if( vg_input
.display_input_method
!= k_input_method_controller
){
253 vg_input
.display_input_method
= k_input_method_controller
;
254 vg_info( "display_input: k_input_method_controller\n" );
256 active
->buttons
[ ev
->cbutton
.button
] = 1;
259 else if( ev
->type
== SDL_CONTROLLERBUTTONUP
){
260 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
261 struct vg_controller
*esta
= &vg_input
.controllers
[i
];
263 if( ev
->cbutton
.which
== esta
->instance_id
){
264 esta
->buttons
[ ev
->cbutton
.button
] = 0;
271 static void vg_process_inputs(void)
274 vg_input
.sdl_keys
= SDL_GetKeyboardState( &count
);
275 vg_input
.sdl_mouse
= SDL_GetMouseState(NULL
,NULL
);
277 if( vg_input
.display_input_method
!= k_input_method_kbm
){
278 /* check for giving keyboard priority */
279 for( int i
=0; i
<count
; i
++ ){
280 if( vg_input
.sdl_keys
[i
] ){
281 vg_input
.display_input_method
= k_input_method_kbm
;
282 vg_info( "display_input: k_input_method_kbm (keyboard %d)\n", i
);
287 /* check for giving mouse priority */
288 if( vg_input
.sdl_mouse
&
289 (SDL_BUTTON(SDL_BUTTON_LEFT
)|SDL_BUTTON(SDL_BUTTON_RIGHT
)|
290 SDL_BUTTON(SDL_BUTTON_MIDDLE
)) )
292 vg_input
.display_input_method
= k_input_method_kbm
;
293 vg_info( "display_input: k_input_method_kbm (mouse)\n" );
298 static void async_vg_input_init( void *payload
, u32 size
)
300 VG_VAR_F32( controller_deadzone
, flags
=VG_VAR_PERSISTENT
);
302 vg_info( "Checking for controllers\n" );
303 SDL_GameControllerAddMappingsFromFile( "gamecontrollerdb.txt" );
305 int joy_count
= SDL_NumJoysticks();
306 for( int i
=0; i
<joy_count
; i
++ ) {
307 const char *name
= SDL_JoystickNameForIndex( i
);
308 int is_controller
= SDL_IsGameController(i
);
310 vg_info( "%d: %s [controller: %d]\n", i
, name
, is_controller
);
313 vg_open_gamecontroller( i
);
318 static void vg_input_init(void)
320 vg_async_call( async_vg_input_init
, NULL
, 0 );
323 static void vg_input_free(void)
325 for( int i
=0; i
<VG_MAX_CONTROLLERS
; i
++ ){
326 struct vg_controller
*controller
= &vg_input
.controllers
[i
];
328 if( controller
->handle
){
329 SDL_GameControllerClose( controller
->handle
);
330 controller
->handle
= NULL
;
335 struct vg_controller
*vg_active_controller(void){
336 if( vg_input
.active_controller_index
>= 0 )
337 return &vg_input
.controllers
[vg_input
.active_controller_index
];
342 static u8
vg_controller_button( SDL_GameControllerButton button
){
343 struct vg_controller
*c
= vg_active_controller();
344 if( c
) return c
->buttons
[ button
];
348 static f32
vg_controller_axis( SDL_GameControllerAxis axis
){
349 struct vg_controller
*c
= vg_active_controller();
350 if( c
) return c
->axises
[ axis
];
354 static void vg_input_apply_to_u8( vg_input_op mode
, u8 data
, u8
*inout_result
){
355 if ( mode
== vg_mode_absmax
) *inout_result
|= data
;
356 else if( mode
== vg_mode_mul
) *inout_result
&= data
;
357 else vg_fatal_error( "mode not supported for destination type (%d)", mode
);
360 static void vg_input_apply_to_f32( vg_input_op mode
, f32 data
,
362 if ( mode
== vg_mode_absmax
){
363 if( fabsf(data
) > fabsf(*inout_result
) )
364 *inout_result
= data
;
366 else if( mode
== vg_mode_max
) *inout_result
= vg_maxf(*inout_result
,data
);
367 else if( mode
== vg_mode_mul
) *inout_result
*= (f32
)data
;
368 else if( mode
== vg_mode_sub
) *inout_result
-= (f32
)data
;
369 else if( mode
== vg_mode_add
) *inout_result
+= (f32
)data
;
370 else vg_fatal_error( "mode not supported for destination type (%d)", mode
);
373 static void vg_exec_input_program( enum vg_input_type type
, vg_input_op
*ops
,
375 u8
*out_button
= NULL
;
378 if( type
== k_vg_input_type_button_u8
){
379 out_button
= out_result
;
382 else if( type
== k_vg_input_type_axis_f32
){
383 out_joy
= out_result
;
386 else if( type
== k_vg_input_type_joy_v2f
){
387 out_joy
= out_result
;
393 vg_input_op mode
= vg_mode_absmax
;
394 u32 pc
= 0, index
= 0;
397 vg_input_op op
= ops
[ pc
++ ];
399 if( (op
>= vg_mode_mul
) && (op
<= vg_mode_max
) ){
402 else if( (op
== vg_keyboard
) || (op
== vg_mouse
) || (op
== vg_joy_button
) ){
405 if( op
== vg_keyboard
)
406 state
= vg_getkey(ops
[pc
++]);
407 else if( op
== vg_mouse
)
408 state
= (vg_input
.sdl_mouse
& SDL_BUTTON(ops
[pc
++]))?1:0;
410 state
= vg_controller_button(ops
[pc
++]);
412 if( type
== k_vg_input_type_button_u8
)
413 vg_input_apply_to_u8( mode
, state
, out_button
);
415 vg_input_apply_to_f32( mode
, (f32
)state
, &out_joy
[index
] );
417 else if( op
== vg_joy_axis
){
418 f32 state
= vg_controller_axis( ops
[pc
++] );
419 if( type
== k_vg_input_type_button_u8
)
420 vg_input_apply_to_u8( mode
, state
>0.5f
?1:0, out_button
);
422 vg_input_apply_to_f32( mode
, state
, &out_joy
[index
] );
424 else if( (op
>= vg_0_0f
) && (op
<= vg_2_0f
) ){
425 f32 value
= (f32
)(op
- vg_0_5f
) * 0.5f
;
426 vg_input_apply_to_f32( mode
, value
, &out_joy
[index
] );
428 else if( op
== vg_index
){
431 else if( op
== vg_end
){
434 else if( op
== vg_normalize
){
435 v2_normalize( out_joy
);
438 vg_fatal_error( "unknown op\n" );