From: hgn Date: Thu, 27 Apr 2023 19:31:18 +0000 (+0100) Subject: way better controller handling X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=commitdiff_plain;h=6d772a1e69860f4ae3e838e8c5c164754e6533ae way better controller handling --- diff --git a/vg.h b/vg.h index d98828e..2eb8e7a 100644 --- a/vg.h +++ b/vg.h @@ -200,6 +200,8 @@ struct vg k_quality_profile_low = 1, } quality_profile; + + float loader_ring; } VG_STATIC vg = { .time_rate = 1.0 }; @@ -332,12 +334,14 @@ VG_STATIC void _vg_process_events(void) vg.mouse_wheel[0] += event.wheel.preciseX; vg.mouse_wheel[1] += event.wheel.preciseY; } + else if( event.type == SDL_CONTROLLERDEVICEADDED || + event.type == SDL_CONTROLLERDEVICEREMOVED ) + { + vg_input_device_event( &event ); + } else if( event.type == SDL_CONTROLLERAXISMOTION || event.type == SDL_CONTROLLERBUTTONDOWN || - event.type == SDL_CONTROLLERBUTTONUP || - event.type == SDL_CONTROLLERDEVICEADDED || - event.type == SDL_CONTROLLERDEVICEREMOVED - ) + event.type == SDL_CONTROLLERBUTTONUP ) { vg_input_controller_event( &event ); } @@ -374,7 +378,7 @@ VG_STATIC void _vg_process_events(void) vg.mouse_pos[1] += vg.mouse_delta[1]; /* Update input */ - vg_update_inputs(); + vg_process_inputs(); } VG_STATIC void _vg_gameloop_update(void) @@ -546,11 +550,10 @@ VG_STATIC int vg_framefilter( double dt ) VG_STATIC int _vg_crashscreen(void) { - if( vg.window_should_close ) - return 1; - +#if 0 if( vg_getkey( SDLK_ESCAPE ) ) return 1; +#endif glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glEnable(GL_BLEND); @@ -594,20 +597,20 @@ VG_STATIC void _vg_gameloop(void) enum engine_status status = _vg_engine_status(); + vg.time_delta = vg.time_frame_delta * vg.time_rate; + vg.time += vg.time_delta; + + vg_run_async_checked(); + _vg_process_events(); + + if( vg.window_should_close ) + break; + if( status == k_engine_status_crashed ){ if( _vg_crashscreen() ) break; } else{ - vg.time_delta = vg.time_frame_delta * vg.time_rate; - vg.time += vg.time_delta; - - vg_run_async_checked(); - _vg_process_events(); - - if( vg.window_should_close ) - break; - if( status == k_engine_status_running ){ _vg_gameloop_update(); _vg_gameloop_render(); @@ -617,6 +620,11 @@ VG_STATIC void _vg_gameloop(void) } } + if( vg.loader_ring > 0.01f ){ + vg.loader_ring -= vg.time_frame_delta * 0.5f; + _vg_loader_render_ring( vg.loader_ring ); + } + vg.time_frame_delta = 0.0; vg.time_spinning = 0; } diff --git a/vg_audio.h b/vg_audio.h index 34bc9ee..0e76efd 100644 --- a/vg_audio.h +++ b/vg_audio.h @@ -303,8 +303,6 @@ VG_STATIC void vg_audio_init(void) " Channels: 2\n" " Format: s16 or f32\n" ); } - - vg_success( "Ready\n" ); } VG_STATIC void vg_audio_free(void) @@ -336,7 +334,7 @@ static void audio_channel_init( audio_channel *ch, audio_clip *clip, u32 flags ) if( (ch->source->flags & AUDIO_FLAG_FORMAT) == k_audio_format_bird ) strcpy( ch->name, "[array]" ); else - strncpy( ch->name, clip->path, 31 ); + vg_strncpy( clip->path, ch->name, 32, k_strncpy_always_add_null ); ch->allocated = 1; diff --git a/vg_build_utils_shader.h b/vg_build_utils_shader.h index 1c81c41..72afd4e 100644 --- a/vg_build_utils_shader.h +++ b/vg_build_utils_shader.h @@ -45,13 +45,15 @@ static void parse_uniform_name( char *start, struct uniform *uf ) if( start[i] == ';' ) { start[i] = '\0'; - strncpy( uf->name, start, sizeof(uf->name) ); + vg_strncpy( start, uf->name, sizeof(uf->name), + k_strncpy_always_add_null ); } if( start[i] == '[' ) { start[i] = '\0'; - strncpy( uf->name, start, sizeof(uf->name) ); + vg_strncpy( start, uf->name, sizeof(uf->name), + k_strncpy_always_add_null ); uf->array = 1; } @@ -61,7 +63,8 @@ static void parse_uniform_name( char *start, struct uniform *uf ) if( !type_set ) { - strncpy( uf->type, start, sizeof(uf->type) ); + vg_strncpy( start, uf->type, sizeof(uf->type), + k_strncpy_always_add_null ); type_set = 1; } start = start+i+1; diff --git a/vg_input.h b/vg_input.h index 02c271a..17f3f16 100644 --- a/vg_input.h +++ b/vg_input.h @@ -5,6 +5,8 @@ #include "common.h" #include "vg/vg_loader.h" +#define VG_MAX_CONTROLLERS 4 + VG_STATIC inline float vg_get_axis( const char *axis ); VG_STATIC inline int vg_get_button( const char *button ); @@ -67,15 +69,35 @@ struct struct input_binding named_inputs[ 32 ]; u32 named_input_count; - const char *controller_name; - SDL_GameController *controller_handle; /* null if unplugged */ - SDL_JoystickID controller_joystick_id; - int controller_should_use_trackpad_look; + struct vg_controller{ + SDL_GameController *handle; /* handle for controller. NULL if unused */ + SDL_JoystickID instance_id; /* uid used in events */ + + enum evg_controller_type{ + k_vg_controller_type_standard, + k_vg_controller_type_trackpads + } + type; - float controller_axises[ SDL_CONTROLLER_AXIS_MAX ]; - int controller_buttons[ SDL_CONTROLLER_BUTTON_MAX ]; + float axises[ SDL_CONTROLLER_AXIS_MAX ]; + int buttons[ SDL_CONTROLLER_BUTTON_MAX ]; + } + controllers[4]; + + int active_controller_index; /* most recent controller (by button press) + will be -1 if no controllers active */ + + /* what the user is currently using. the keyboard and controller are still + * active simultaneously, but this reflects what the UI should show */ + enum userinput_method{ + k_userinput_method_xbox, + k_userinput_method_playstation, + k_userinput_method_steamgeneric, + k_userinput_method_kbm + } + input_method; } -VG_STATIC vg_input; +static vg_input; VG_STATIC void vg_create_unnamed_input( struct input_binding *bind, enum input_type type ) @@ -438,6 +460,11 @@ VG_STATIC void vg_input_update( u32 num, struct input_binding *binds ) return; } + struct vg_controller *acontroller = NULL; + + if( vg_input.active_controller_index != -1 ) + acontroller = &vg_input.controllers[vg_input.active_controller_index]; + for( i32 i=0; ibutton.prev = bind->button.value; bind->button.value = 0; - if( bind->button.gamepad_id != -1 ) - bind->button.value |= - vg_input.controller_buttons[ bind->button.gamepad_id ]; + if( acontroller && (bind->button.gamepad_id != -1) ) + bind->button.value |= acontroller->buttons[bind->button.gamepad_id]; - if( bind->button.keyboard_id != -1 ){ + if( bind->button.keyboard_id != -1 ) bind->button.value |= vg_getkey( bind->button.keyboard_id ); - } if( bind->button.mouse_id != -1 ){ - if( SDL_GetMouseState(NULL, NULL) & - SDL_BUTTON( bind->button.mouse_id ) ) + if(SDL_GetMouseState(NULL,NULL) & SDL_BUTTON(bind->button.mouse_id)) bind->button.value |= 1; } } @@ -471,9 +495,8 @@ VG_STATIC void vg_input_update( u32 num, struct input_binding *binds ) if( vg_getkey( bind->axis.keyboard_negative ) ) keyboard_value -= 1.0f; - if( bind->axis.gamepad_axis != -1 ){ - gamepad_value = - vg_input.controller_axises[ bind->axis.gamepad_axis ]; + if( acontroller && (bind->axis.gamepad_axis != -1) ){ + gamepad_value = acontroller->axises[ bind->axis.gamepad_axis ]; if( bind->axis.gamepad_inverted ) gamepad_value *= -1.0f; @@ -496,61 +519,188 @@ VG_STATIC void vg_input_update( u32 num, struct input_binding *binds ) if( vg_getkey( bind->axis.keyboard_positive )) value = 1.0f; - if( bind->axis.gamepad_axis != -1 ) - value = vg_maxf( value, - vg_input.controller_axises[bind->axis.gamepad_axis] ); + if( acontroller && (bind->axis.gamepad_axis != -1) ){ + float value1 = acontroller->axises[bind->axis.gamepad_axis]; + value = vg_maxf( value, value1 ); + } bind->axis.value = value; } } } -VG_STATIC void vg_input_controller_event( SDL_Event *ev ) +/* + * takes SDL device index, and tries to open that on any free channel + */ +VG_STATIC void vg_open_gamecontroller( Sint32 index ) { - if( ev->type == SDL_CONTROLLERAXISMOTION ){ - if( ev->caxis.which == vg_input.controller_joystick_id ){ - vg_input.controller_axises[ ev->caxis.axis ] = - (float)ev->caxis.value / 32767.0f; + struct vg_controller *controller = NULL; + int vg_id = 0; + const char *name = SDL_GameControllerNameForIndex( index ); + SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index ); + + if( instance_id == -1 ){ + vg_error( ". Invalid device index (vg_open_gamecontroller)\n" ); + return; + } + + for( int j=0; jhandle ){ + if( esta->instance_id == instance_id ){ + vg_warn( " . SDL_JoystickID[%d] is already in open at index #%d\n", + esta->instance_id, j ); + return; + } + } + else{ + if( !controller ){ + controller = &vg_input.controllers[j]; + vg_id = j; + } } } - else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){ - if( ev->cbutton.which == vg_input.controller_joystick_id ) - vg_input.controller_buttons[ ev->cbutton.button ] = 1; + + if( controller ){ + controller->handle = SDL_GameControllerOpen( index ); + controller->instance_id = instance_id; + + if( controller->handle ){ + vg_success( + " . opened SDL_JoystickID[%d] as controller '%s' at index #%d\n", + instance_id, name, vg_id ); + + controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERLEFT ] = -1.0f; + controller->axises[ SDL_CONTROLLER_AXIS_TRIGGERRIGHT ] = -1.0f; + } + else{ + vg_error( ". Failed to attach game controller '%s'. Reason: %s\n", + name, SDL_GetError() ); + } } - else if( ev->type == SDL_CONTROLLERBUTTONUP ){ - if( ev->cbutton.which == vg_input.controller_joystick_id ) - vg_input.controller_buttons[ ev->cbutton.button ] = 0; + else{ + vg_error( ". Too many controllers open! ignoring '%s'\n", name ); + } } -VG_STATIC void vg_try_attach_controller(void) +VG_STATIC void vg_input_device_event( SDL_Event *ev ) { - int joy_count = SDL_NumJoysticks(); - for( int i=0; itype == SDL_CONTROLLERDEVICEADDED ){ + int is_controller = SDL_IsGameController( ev->cdevice.which ); + const char *name = SDL_JoystickNameForIndex( ev->cdevice.which ); + + Sint32 index = ev->cdevice.which; + SDL_JoystickID instance_id = SDL_JoystickGetDeviceInstanceID( index ); + vg_info( "SDL_CONTROLLERDEVICEADDED | device index: %d, name: '%s'\n", + index, name ); + + if( is_controller ){ + vg_open_gamecontroller( index ); + } + } + else if( ev->type == SDL_CONTROLLERDEVICEREMOVED ){ + vg_info( "SDL_CONTROLLERDEVICEREMOVED | instance_id: %d\n", + ev->cdevice.which ); + + for( int i=0; ihandle ){ + if( controller->instance_id == ev->cdevice.which ){ + vg_info( " . closing controller at index #%d\n", i ); + SDL_GameControllerClose( controller->handle ); + controller->handle = NULL; + controller->instance_id = -1; + + if( vg_input.active_controller_index == i ){ + vg_input.active_controller_index = -1; + vg_info( " . active controller is now keyboard and mouse\n" ); + } + break; + } + } } } } -VG_STATIC void vg_update_inputs(void) +VG_STATIC void vg_input_controller_event( SDL_Event *ev ) { - vg_input.sdl_keys = SDL_GetKeyboardState(NULL); + if( ev->type == SDL_CONTROLLERAXISMOTION ){ + for( int i=0; icaxis.which == esta->instance_id ){ + float value = (float)ev->caxis.value / 32767.0f; + esta->axises[ ev->caxis.axis ] = value; + break; + } + } + } + else if( ev->type == SDL_CONTROLLERBUTTONDOWN ){ + struct vg_controller *active = NULL; + + if( vg_input.active_controller_index != -1 ) + active = &vg_input.controllers[vg_input.active_controller_index]; + + if( !active || (ev->cbutton.which != active->instance_id) ){ + active = NULL; + vg_input.active_controller_index = -1; + + for( int i=0; icbutton.which ){ + active = &vg_input.controllers[i]; + vg_input.active_controller_index = i; + break; + } + } + + if( active ){ + vg_info( "Switching active controller index to #%d\n", + vg_input.active_controller_index ); + } + else{ + vg_error( "Input out of range (SDL_JoystickID#%d)\n", + ev->cbutton.which ); + } + } - if( vg_input.controller_handle ){ - if( !SDL_GameControllerGetAttached( vg_input.controller_handle ) ){ - SDL_GameControllerClose( vg_input.controller_handle ); - vg_input.controller_handle = NULL; + if( active ) + active->buttons[ ev->cbutton.button ] = 1; + } + else if( ev->type == SDL_CONTROLLERBUTTONUP ){ + for( int i=0; icbutton.which == esta->instance_id ){ + esta->buttons[ ev->cbutton.button ] = 0; + break; + } } } +} + +VG_STATIC void vg_process_inputs(void) +{ + int count; + vg_input.sdl_keys = SDL_GetKeyboardState( &count ); + + if( vg_input.input_method != k_userinput_method_kbm ){ + /* check for giving keyboard priority */ + for( int i=0; ihandle ){ + SDL_GameControllerClose( controller->handle ); + controller->handle = NULL; + } } } diff --git a/vg_io.h b/vg_io.h index 779b872..9352544 100644 --- a/vg_io.h +++ b/vg_io.h @@ -10,6 +10,11 @@ #include #include +#define _TINYDIR_MALLOC(_size) vg_linear_alloc( vg_mem.scratch, _size ) +#define _TINYDIR_FREE(_size) + +#include "submodules/tinydir/tinydir.h" + /* * File I/O */ @@ -18,12 +23,10 @@ VG_STATIC void vg_file_print_invalid( FILE *fp ) { - if( feof( fp )) - { + if( feof( fp )) { vg_error( "mdl_open: header too short\n" ); } - else - { + else{ if( ferror( fp )) vg_error( "mdl_open: %s\n", strerror(errno) ); else @@ -71,8 +74,7 @@ VG_STATIC void *vg_file_read( void *lin_alloc, const char *path, u32 *size ) return buffer; } - else - { + else{ vg_error( "vg_disk_open_read: %s\n", strerror(errno) ); return NULL; } @@ -96,17 +98,14 @@ VG_STATIC char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz ) } -VG_STATIC int vg_asset_write( const char *path, void *data, i64 size ) -{ +VG_STATIC int vg_asset_write( const char *path, void *data, i64 size ){ FILE *f = fopen( path, "wb" ); - if( f ) - { + if( f ){ fwrite( data, size, 1, f ); fclose( f ); return 1; } - else - { + else{ return 0; } } diff --git a/vg_lines.h b/vg_lines.h index 58818f2..4a77502 100644 --- a/vg_lines.h +++ b/vg_lines.h @@ -106,8 +106,6 @@ VG_STATIC void async_vg_lines_init( void *payload, u32 payload_size ) glEnableVertexAttribArray( 1 ); VG_CHECK_GL_ERR(); - vg_success( "done\n" ); - vg_lines.allow_input = 1; } diff --git a/vg_loader.h b/vg_loader.h index f62763d..f6f3a26 100644 --- a/vg_loader.h +++ b/vg_loader.h @@ -20,44 +20,7 @@ static struct vg_shader _shader_loader = .name = "[vg] loader", .link = NULL, - /* This is the old background shader */ -#if 0 - .vs = - { - .orig_file = NULL, - .static_src = "" - "layout (location=0) in vec2 a_co;" - "out vec2 aUv;" - "void main()" - "{" - "gl_Position = vec4(a_co*2.0-1.0,0.0,1.0);" - "aUv = a_co;" - "}" - }, - .fs = - { - .orig_file = NULL, - .static_src = - - "out vec4 FragColor;" - "uniform float uTime;" - "in vec2 aUv;" - - "void main()" - "{" - "float dither=fract(dot(vec2(171.0,231.0),gl_FragCoord.xy)/71.0)-0.5;" - "float grad = 1.0-(aUv.y*0.5+0.5)*0.5;" - "float fmt1 = step( 0.5, grad+dither );" - - "vec3 col = 0.5+0.5*sin( uTime + aUv.xyx + vec3(0.0,2.0,4.0) );" - - "FragColor = vec4(vec3(0.5,0.5,0.5)*grad*fmt1,1.0);" - "}" - } -#else - /* This is the new foreground shader */ - .vs = { .orig_file = NULL, @@ -78,6 +41,7 @@ static struct vg_shader _shader_loader = "out vec4 FragColor;" "uniform float uTime;" "uniform float uRatio;" + "uniform float uOpacity;" "in vec2 aUv;" "float eval_zero( vec2 uv )" @@ -107,11 +71,9 @@ static struct vg_shader _shader_loader = "float dither=fract(dot(vec2(171.0,231.0),gl_FragCoord.xy)/71.0)-0.5;" "float fmt1 = step( 0.5, zero*zero + dither )*0.8+0.2;" - "FragColor = vec4(vec3(fmt1),0.8);" + "FragColor = vec4(vec3(fmt1),uOpacity);" "}" } - -#endif }; static struct vg_loader @@ -162,8 +124,6 @@ VG_STATIC void _vg_loader_free(void) vg_info( " -> %p\n", step->fn_free ); step->fn_free(); } - - vg_info( "done\n" ); } VG_STATIC void _vg_render_log(void) @@ -199,23 +159,8 @@ VG_STATIC void _vg_render_log(void) ui_draw( NULL ); } -VG_STATIC void _vg_loader_render(void) +VG_STATIC void _vg_loader_render_ring( float opacity ) { - glViewport( 0,0, vg.window_x, vg.window_y ); - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - -#if 0 - glUseProgram( _shader_loader.id ); - glUniform1f( glGetUniformLocation( _shader_loader.id, "uTime" ), vg.time ); - glBindVertexArray( vg_loader.vao ); - glDrawArrays( GL_TRIANGLES, 0, 6 ); -#endif - - _vg_render_log(); - -#if 1 glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_ADD); @@ -224,9 +169,20 @@ VG_STATIC void _vg_loader_render(void) glUniform1f( glGetUniformLocation( _shader_loader.id, "uTime" ), vg.time ); float ratio = (float)vg.window_x / (float)vg.window_y; glUniform1f( glGetUniformLocation( _shader_loader.id, "uRatio"), ratio ); + glUniform1f( glGetUniformLocation( _shader_loader.id, "uOpacity"), opacity ); glBindVertexArray( vg_loader.vao ); glDrawArrays( GL_TRIANGLES, 0, 6 ); -#endif +} + +VG_STATIC void _vg_loader_render(void) +{ + glViewport( 0,0, vg.window_x, vg.window_y ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + + _vg_render_log(); + vg.loader_ring = 0.8f; } diff --git a/vg_platform.h b/vg_platform.h index 210192d..52c26c0 100644 --- a/vg_platform.h +++ b/vg_platform.h @@ -39,17 +39,35 @@ struct vg_achievement #define vg_list_size( A ) (sizeof(A)/sizeof(A[0])) #define VG_MUST_USE_RESULT __attribute__((warn_unused_result)) -VG_STATIC void vg_strncpy( const char *src, char *dst, u32 len ) +enum strncpy_behaviour{ + k_strncpy_always_add_null = 0, + k_strncpy_allow_cutoff = 1 +}; + +VG_STATIC void vg_strncpy( const char *src, char *dst, u32 len, + enum strncpy_behaviour behaviour ) { - for( u32 i=0; i #include #include diff --git a/vg_tex.h b/vg_tex.h index e857aa8..ef7f0e9 100644 --- a/vg_tex.h +++ b/vg_tex.h @@ -19,9 +19,9 @@ struct vg_sprite static u8 const_vg_tex2d_err[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, - 0xff, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff };