From fac9f6fff674421f27fa4f4c1d2844998f0003d6 Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 29 Dec 2023 10:38:31 +0000 Subject: [PATCH] settings menu & texsheet --- build_texsheet.sh | 1 + src/texsheet.c | 433 ++++++++++++++++++++++------------------ vg.h | 75 +++++-- vg_audio.h | 15 +- vg_audio_dsp.h | 24 ++- vg_build_utils_shader.h | 1 + vg_imgui.h | 31 +-- vg_io.h | 28 ++- vg_profiler.h | 33 +-- vg_settings_menu.h | 301 ++++++++++++++++++++++++++++ vg_tex.h | 3 + 11 files changed, 694 insertions(+), 251 deletions(-) create mode 100755 build_texsheet.sh create mode 100644 vg_settings_menu.h diff --git a/build_texsheet.sh b/build_texsheet.sh new file mode 100755 index 0000000..abc0195 --- /dev/null +++ b/build_texsheet.sh @@ -0,0 +1 @@ +clang -fsanitize=address -O0 -I. -DVG_BUILD src/texsheet.c -o /tmp/tmpsr && /tmp/tmpsr $@ diff --git a/src/texsheet.c b/src/texsheet.c index 367136b..4042964 100644 --- a/src/texsheet.c +++ b/src/texsheet.c @@ -1,216 +1,271 @@ // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved +#ifdef VG_BUILD + +#include "vg.h" +#include "vg_platform.h" +#include "vg_log.h" +#include "vg_opt.h" +#include "vg_build.h" + +u32 optimize_test_compile = 0; + +/* + * Scripts + * -------------------------------------------------------------------------- */ + +void s_build(void){ + vg_info( "running script: s_build(void)\n" ); + + vg_build.optimization = optimize_test_compile; + vg_build.fresh = 0; + vg_build.platform = k_platform_linux; + vg_build.arch = k_architecture_x86_64; + vg_build.compiler = k_compiler_clang; + vg_build.libc = k_libc_version_native; + + vg_build_new( "texsheet" ); + vg_add_source( "src/texsheet.c" ); + vg_compile( "texsheet" ); + + vg_success( "Completed 1/1\n" ); +} + +int main( int argc, char *argv[] ){ + char *arg; + while( vg_argp( argc, argv ) ){ + if( vg_long_opt( "native" ) ) + s_build(); + + if( vg_opt('r') ) + optimize_test_compile = 3; + } + + if( vg_build.warnings ) + vg_warn( "Finished with %u warnings\n", vg_build.warnings ); + else + vg_success( "All scripts ran successfully\n" ); +} + +#else + #define VG_TOOLS -#include "vg/vg.h" +#include "vg.h" #define STB_IMAGE_IMPLEMENTATION -#include "stb/stb_image.h" +#include "submodules/stb/stb_image.h" + +#define QOI_IMPLEMENTATION +#include "submodules/qoi/qoi.h" struct image_src { - int x,y,ch; + int x,y,ch; - u8 *data; + u8 *data; }; int image_sort( const void* a, const void* b) { - struct image_src *p_a = (struct image_src *)a; - struct image_src *p_b = (struct image_src *)b; - - if( p_a->x == p_b->x ) - return 0; - else if ( p_a->x < p_b->x ) - return 1; - else - return -1; + struct image_src *p_a = (struct image_src *)a; + struct image_src *p_b = (struct image_src *)b; + + if( p_a->x == p_b->x ) + return 0; + else if ( p_a->x < p_b->x ) + return 1; + else + return -1; } int main( int argc, const char *argv[] ) { - struct image_src *source_images = malloc( sizeof( struct image_src ) * argc ); - - u32 num_images = 0; - - if( argc < 4 ) - { - vg_error( "Missing output file paths\n" ); - return 0; - } - - // Open header handle - // ------------------ - FILE *fp = fopen( argv[2], "w" ); - if( !fp ) - { - vg_error( "Could not open file for writing\n" ); - return 0; - } - - fprintf( fp, "enum %s_index\n{\n", argv[3] ); - - // Load images - // ----------- - stbi_set_flip_vertically_on_load(1); - - for( int i = 4; i < argc; i ++ ) - { - struct image_src *src = &source_images[ num_images ]; - src->data = (u8 *)stbi_load( argv[i], &src->x, &src->y, &src->ch, 4 ); - - char name[ 256 ]; - int j = 0; int ext = 0; - for( ; j < vg_list_size( name )-1; j ++ ) - { - if( argv[i][j] ) - { - name[j] = argv[i][j]; - - if( name[j] == '.' ) - ext = j; - - if( name[j] == '.' || name[j] == '-' ) - name[j] = '_'; - } - else - break; - } - - if( ext ) - name[ext] = 0x00; - else - name[j] = 0x00; - - fprintf( fp, "\tk_sprite_%s,\n", name ); - - if( src->data ) - { - if( src->x != src->y ) - { - vg_error( "Non-square images are currently not supported ('%s')\n", argv[i] ); - free( src->data ); - } - else - num_images ++; - } - else - vg_error( "Could not decode '%s'\n", argv[i] ); - } - - fprintf( fp, "};\n\n" ); - - // Sort by size - // ------------ - qsort( source_images, num_images, sizeof(struct image_src), image_sort ); - - // Process images - // -------------- - fprintf( fp, "static struct vg_sprite %s[] = \n{\n", argv[3] ); - - u8 *dest = (u8 *)malloc( 1024*1024*4 ); - - for( int i = 0; i < 1024*1024; i ++ ) - { - dest[ i*4 + 0 ] = 0; - dest[ i*4 + 1 ] = 0; - dest[ i*4 + 2 ] = 0; - dest[ i*4 + 3 ] = 0; - } - - struct region - { - v2i p0; - v2i p1; - } - region_stack[ 32 ] = - { - { - .p0 = { 0, 0 }, - .p1 = { 1024, 1024 } - } - }; - int stack_h = 0; - - for( int i = 0; i < num_images; i ++ ) - { - struct image_src *psrc = &source_images[ i ]; - - // Region checks - while( 1 ) - { - struct region *pregion = ®ion_stack[ stack_h ]; - - if( (pregion->p0[ 0 ] + psrc->x <= pregion->p1[0]) && (pregion->p0[ 1 ] + psrc->y <= pregion->p1[1]) ) - { - // Passed, add image and create subdivisions - fprintf( fp, "\t{{ %f, %f, %f, %f }}", - (float)pregion->p0[0] / 1024.0f, - (float)pregion->p0[1] / 1024.0f, - (float)psrc->x / 1024.0f, - (float)psrc->y / 1024.0f - ); + struct image_src *source_images = malloc( sizeof( struct image_src ) * argc ); + + u32 num_images = 0; + + if( argc < 4 ) + { + vg_info( "Usage: %s \\\n[output_image output_header name images...]\n", + argv[0] ); + return 0; + } + + // Open header handle + // ------------------ + FILE *fp = fopen( argv[2], "w" ); + if( !fp ) + { + vg_error( "Could not open file for writing\n" ); + return 0; + } + + fprintf( fp, "enum %s_index\n{\n", argv[3] ); + + // Load images + // ----------- + stbi_set_flip_vertically_on_load(1); + + for( int i = 4; i < argc; i ++ ) + { + struct image_src *src = &source_images[ num_images ]; + src->data = (u8 *)stbi_load( argv[i], &src->x, &src->y, &src->ch, 4 ); + + char name[ 256 ]; + int j = 0; int ext = 0; + for( ; j < vg_list_size( name )-1; j ++ ) + { + if( argv[i][j] ) + { + name[j] = argv[i][j]; + + if( name[j] == '.' ) + ext = j; + + if( name[j] == '.' || name[j] == '-' ) + name[j] = '_'; + } + else + break; + } + + if( ext ) + name[ext] = 0x00; + else + name[j] = 0x00; + + fprintf( fp, "\tk_sprite_%s,\n", name ); + + if( src->data ) + { + if( src->x != src->y ) + { + vg_error( "Non-square images are currently not supported ('%s')\n", argv[i] ); + free( src->data ); + } + else + num_images ++; + } + else + vg_error( "Could not decode '%s'\n", argv[i] ); + } + + fprintf( fp, "};\n\n" ); + + // Sort by size + // ------------ + qsort( source_images, num_images, sizeof(struct image_src), image_sort ); + + // Process images + // -------------- + fprintf( fp, "static struct vg_sprite %s[] = \n{\n", argv[3] ); + + u8 *dest = (u8 *)malloc( 1024*1024*4 ); + + for( int i = 0; i < 1024*1024; i ++ ) + { + dest[ i*4 + 0 ] = 0; + dest[ i*4 + 1 ] = 0; + dest[ i*4 + 2 ] = 0; + dest[ i*4 + 3 ] = 0; + } + + struct region + { + v2i p0; + v2i p1; + } + region_stack[ 32 ] = + { + { + .p0 = { 0, 0 }, + .p1 = { 1024, 1024 } + } + }; + int stack_h = 0; + + for( int i = 0; i < num_images; i ++ ) + { + struct image_src *psrc = &source_images[ i ]; + + // Region checks + while( 1 ) + { + struct region *pregion = ®ion_stack[ stack_h ]; + + if( (pregion->p0[ 0 ] + psrc->x <= pregion->p1[0]) && (pregion->p0[ 1 ] + psrc->y <= pregion->p1[1]) ) + { + // Passed, add image and create subdivisions + fprintf( fp, "\t{{ %f, %f, %f, %f }}", + (float)pregion->p0[0] / 1024.0f, + (float)pregion->p0[1] / 1024.0f, + (float)psrc->x / 1024.0f, + (float)psrc->y / 1024.0f + ); if( i != num_images-1 ) fputs( ",\n", fp ); else fputc( '\n', fp ); - // Write image - for( int y = 0; y < psrc->y; y ++ ) - { - int px = pregion->p0[0]; - int py = pregion->p0[1] + y; - - memcpy( &dest[ (py*1024+px) * 4 ], &psrc->data[ y*psrc->x*4 ], psrc->x*4 ); - } - - // Subdivisions - stack_h ++; - struct region *new_region = ®ion_stack[ stack_h ]; - - new_region->p0[0] = pregion->p0[0] + psrc->x; - new_region->p0[1] = pregion->p0[1]; - new_region->p1[0] = pregion->p1[0]; - new_region->p1[1] = pregion->p0[1] + psrc->y; - - pregion->p0[ 1 ] += psrc->y; - break; - } - else - { - // Failed, loop up to next region if can - if( stack_h == 0 ) - { - vg_error( "Could not fit image %d. Pack failed\n", i ); - - goto IL_END_ERR; - } - else - stack_h --; - } - } - } + // Write image + for( int y = 0; y < psrc->y; y ++ ) + { + int px = pregion->p0[0]; + int py = pregion->p0[1] + y; + + memcpy( &dest[ (py*1024+px) * 4 ], &psrc->data[ y*psrc->x*4 ], psrc->x*4 ); + } + + // Subdivisions + stack_h ++; + struct region *new_region = ®ion_stack[ stack_h ]; + + new_region->p0[0] = pregion->p0[0] + psrc->x; + new_region->p0[1] = pregion->p0[1]; + new_region->p1[0] = pregion->p1[0]; + new_region->p1[1] = pregion->p0[1] + psrc->y; + + pregion->p0[ 1 ] += psrc->y; + break; + } + else + { + // Failed, loop up to next region if can + if( stack_h == 0 ) + { + vg_error( "Could not fit image %d. Pack failed\n", i ); + + goto IL_END_ERR; + } + else + stack_h --; + } + } + } IL_END_ERR: - fprintf( fp, "};" ); - fclose( fp ); - - // Write output - // ------------ - qoi_write( argv[1], dest, &(qoi_desc){ - .width = 1024, - .height = 1024, - .channels = 4, - .colorspace = QOI_SRGB - }); - - // Free - // ---- - for( int i = 0; i < num_images; i ++ ) - free( source_images[ i ].data ); - free( dest ); - free( source_images ); - - vg_success( "Processed %u images\n", num_images ); + fprintf( fp, "};" ); + fclose( fp ); + + // Write output + // ------------ + qoi_write( argv[1], dest, &(qoi_desc){ + .width = 1024, + .height = 1024, + .channels = 4, + .colorspace = QOI_SRGB + }); + + // Free + // ---- + for( int i = 0; i < num_images; i ++ ) + free( source_images[ i ].data ); + free( dest ); + free( source_images ); + + vg_success( "Processed %u images\n", num_images ); } + +#endif diff --git a/vg.h b/vg.h index aa86ab5..919f6f3 100644 --- a/vg.h +++ b/vg.h @@ -98,6 +98,12 @@ static void vg_post_update(void); static void vg_render(void); static void vg_gui(void); +enum quality_profile{ + k_quality_profile_high = 0, + k_quality_profile_low = 1, + k_quality_profile_min = 2 +}; + struct vg{ /* Engine sync */ SDL_Window *window; @@ -128,7 +134,11 @@ struct vg{ int display_refresh_rate, fps_limit, - vsync; + vsync, + screen_mode, + display_index; + + int settings_open; enum vsync_feature{ k_vsync_feature_disabled=0, @@ -138,7 +148,7 @@ struct vg{ } vsync_feature; - double mouse_pos[2]; + i32 mouse_pos[2]; v2f mouse_delta, mouse_wheel; @@ -166,12 +176,13 @@ struct vg{ engine_stage; /* graphics */ +#ifdef VG_3D m4x4f pv; - enum quality_profile{ - k_quality_profile_high = 0, - k_quality_profile_low = 1, - } - quality_profile; +#else + m3x3f pv; +#endif + + i32 quality_profile; float loader_ring; GLuint tex_missing; @@ -244,6 +255,7 @@ static void vg_checkgl( const char *src_info ); #include "vg_lines.h" #include "vg_loader.h" #include "vg_opt.h" +#include "vg_settings_menu.h" /* Diagnostic */ static struct vg_profile vg_prof_update = {.name="update()"}, @@ -396,8 +408,7 @@ static void _vg_process_events(void) } } - vg.mouse_pos[0] += vg.mouse_delta[0]; - vg.mouse_pos[1] += vg.mouse_delta[1]; + SDL_GetMouseState( &vg.mouse_pos[0], &vg.mouse_pos[1] ); } static void _vg_gameloop_update(void) @@ -453,21 +464,24 @@ static void _vg_gameloop_render(void) } else vg_gui(); + if( vg.settings_open ) + vg_settings_gui(); + /* vg tools */ #ifndef VG_NO_AUDIO audio_debug_ui( vg.pv ); #endif /* profiling */ - int frame_target = vg.display_refresh_rate; - if( vg.fps_limit > 0 ) frame_target = vg.fps_limit; - vg_profile_drawn( - (struct vg_profile *[]){ - &vg_prof_update,&vg_prof_render,&vg_prof_swap}, 3, - (1.0f/(float)frame_target)*1000.0f, - (ui_rect){ 4, 4, 250, 0 }, 0 - ); if( vg_profiler ){ + int frame_target = vg.display_refresh_rate; + if( vg.fps_limit > 0 ) frame_target = vg.fps_limit; + vg_profile_drawn( + (struct vg_profile *[]){ + &vg_prof_update,&vg_prof_render,&vg_prof_swap}, 3, + (1.0f/(float)frame_target)*1000.0f, + (ui_rect){ 4, 4, 250, 0 }, 0, 0 + ); char perf[256]; snprintf( perf, 255, @@ -494,6 +508,20 @@ static void _vg_gameloop_render(void) vg_profile_end( &vg_prof_render ); } +static void aaaaaaaaaaaaaaaaa( ui_rect r ){ + int frame_target = vg.display_refresh_rate; + if( !vg.vsync ) frame_target = vg.fps_limit; + + vg_profile_drawn( + (struct vg_profile *[]){ + &vg_prof_update,&vg_prof_render,&vg_prof_swap}, 3, + (1.0f/(f32)frame_target)*1500.0f, + r, 0, 1 + ); + + ui_fill( (ui_rect){ r[0], r[1] + (r[3]*2)/3, r[2], 1 }, ui_colour(k_ui_fg) ); +} + static void vg_changevsync(void){ if( vg.vsync && (vg.vsync_feature != k_vsync_feature_error) ){ /* turn on vsync if not enabled */ @@ -537,7 +565,7 @@ static void vg_changevsync(void){ } static int vg_framefilter( double dt ){ - if( vg.fps_limit < 25 ) vg.fps_limit = 25; + if( vg.fps_limit < 24 ) vg.fps_limit = 24; if( vg.fps_limit > 300 ) vg.fps_limit = 300; double min_frametime = 1.0/(double)vg.fps_limit; @@ -731,8 +759,8 @@ static void _vg_init_window( const char *window_name ) vg.window_y = video_mode.h; #ifdef VG_DEVWINDOW - vg.window_x = 1200; - vg.window_y = 880; + vg.window_x = 1280; + vg.window_y = 720; #endif #ifndef _WIN32 @@ -752,6 +780,7 @@ static void _vg_init_window( const char *window_name ) SDL_WINDOW_BORDERLESS|SDL_WINDOW_OPENGL|SDL_WINDOW_INPUT_GRABBED ))){ SDL_SetWindowPosition( vg.window, video_mode.w-vg.window_x, 0 ); + vg.screen_mode = 2; } #else 0, 0, @@ -759,7 +788,8 @@ static void _vg_init_window( const char *window_name ) SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_OPENGL | - SDL_WINDOW_INPUT_GRABBED + SDL_WINDOW_INPUT_GRABBED | + SDL_WINDOW_RESIZABLE ))) { if( SDL_SetWindowDisplayMode( vg.window, &video_mode ) ){ @@ -775,6 +805,8 @@ static void _vg_init_window( const char *window_name ) } SDL_RaiseWindow( vg.window ); + SDL_SetWindowMinimumSize( vg.window, 1280, 720 ); + SDL_SetWindowMaximumSize( vg.window, 4096, 4096 ); vg_info( "CreateContext\n" ); @@ -854,6 +886,7 @@ static void vg_enter( int argc, char *argv[], const char *window_name ){ vg_console_reg_var( "fps_limit", &vg.fps_limit, k_var_dtype_i32, 0 ); vg_console_reg_var( "vsync", &vg.vsync, k_var_dtype_i32, VG_VAR_PERSISTENT ); + vg_console_reg_cmd( "vg_settings", cmd_vg_settings_toggle, NULL ); _vg_init_window( window_name ); vg_async_init(); diff --git a/vg_audio.h b/vg_audio.h index 38290ff..11fb8f4 100644 --- a/vg_audio.h +++ b/vg_audio.h @@ -1312,8 +1312,15 @@ static void audio_require_clip_loaded( audio_clip *clip ) * Debugging */ -static void audio_debug_ui( m4x4f mtx_pv ) -{ +static void audio_debug_ui( + +#ifdef VG_3D + m4x4f +#else + m3x3f +#endif + mtx_pv ){ + if( !vg_audio.debug_ui ) return; @@ -1334,7 +1341,7 @@ static void audio_debug_ui( m4x4f mtx_pv ) &vg_prof_audio_mix, &vg_prof_audio_dsp}, 3, budget, (ui_rect){ 4, VG_PROFILE_SAMPLE_COUNT*2 + 8, - 512, 0 }, 3 ); + 512, 0 }, 3, 0 ); char perf[128]; @@ -1412,6 +1419,7 @@ static void audio_debug_ui( m4x4f mtx_pv ) ui_fill( row, 0xa0000000 | ch->colour ); ui_text( row, perf, 1, k_ui_align_middle_left, 0 ); +#ifdef VG_3D if( AUDIO_FLAG_SPACIAL_3D ){ v4f wpos; v3_copy( ch->editable_state.spacial_falloff, wpos ); @@ -1451,6 +1459,7 @@ static void audio_debug_ui( m4x4f mtx_pv ) rect_copy( wr, overlap_buffer[ overlap_length ++ ] ); } } +#endif } audio_unlock(); diff --git a/vg_audio_dsp.h b/vg_audio_dsp.h index 48926e2..c2bed10 100644 --- a/vg_audio_dsp.h +++ b/vg_audio_dsp.h @@ -4,6 +4,8 @@ #define VG_GAME #include "vg/vg.h" +//#define VG_ECHO_LPF_BUTTERWORTH + static struct vg_dsp{ float *buffer; u32 allocations; @@ -160,7 +162,12 @@ static inline void dsp_process_schroeder( struct dsp_schroeder *sch, /* temporary global design */ static struct dsp_lpf __lpf_mud_free; static struct dsp_delay __echos[8]; + +#ifdef VG_ECHO_LPF_BUTTERWORTH +static struct dsp_biquad __echos_lpf[8]; +#else static struct dsp_lpf __echos_lpf[8]; +#endif static struct dsp_schroeder __diffusion_chain[8]; static void async_vg_dsp_alloc_texture( void *payload, u32 size ) @@ -197,7 +204,12 @@ static void vg_dsp_init( void ){ dsp_init_delay( &__echos[i], total / 1000.0f ); float freq = vg_lerpf( 800.0f, 350.0f, sizes[i] / 256.0f ); + +#ifdef VG_ECHO_LPF_BUTTERWORTH + dsp_init_biquad_butterworth_lpf( &__echos_lpf[i], freq ); +#else dsp_init_lpf( &__echos_lpf[i], freq ); +#endif } float diffusions[] = { 187.0f, 159.0f, 143.0f, 121.0f, @@ -214,10 +226,15 @@ static void vg_dsp_process( float *stereo_in, float *stereo_out ) float recieved = 0.0f; for( int i=0; i<8; i++ ){ - float echo; + f32 echo; dsp_read_delay( __echos+i, &echo, 1 ); + +#ifdef VG_ECHO_LPF_BUTTERWORTH + echo = dsp_biquad_process( __echos_lpf+i, echo ); +#else dsp_write_lpf( __echos_lpf+i, &echo ); dsp_read_lpf( __echos_lpf+i, &echo ); +#endif recieved += echo * vg_dsp.echo_tunings[i]*0.98; } @@ -296,7 +313,12 @@ static void dsp_update_tunings(void) for( int i=0; i<8; i++ ){ float freq = vg_lerpf( 200.0f, 500.0f, vg_dsp.echo_tunings[i] ); + +#ifdef VG_ECHO_LPF_BUTTERWORTH + dsp_init_biquad_butterworth_lpf( &__echos_lpf[i], freq ); +#else dsp_update_lpf( &__echos_lpf[i], freq ); +#endif } for( int i=0;i<8; i++ ){ diff --git a/vg_build_utils_shader.h b/vg_build_utils_shader.h index 39943b3..d1d2d05 100644 --- a/vg_build_utils_shader.h +++ b/vg_build_utils_shader.h @@ -205,6 +205,7 @@ int vg_build_shader( char *src_vert, /* path/to/vert.vs */ { "sampler2D", "int i", "glUniform1i(%s,i);" }, { "samplerCube", "int i", "glUniform1i(%s,i);" }, + { "mat2", "m2x2f m", "glUniformMatrix2fv(%s,1,GL_FALSE,(float*)m);" }, { "mat4x3", "m4x3f m", "glUniformMatrix4x3fv(%s,1,GL_FALSE,(float*)m);" }, { "mat3", "m3x3f m", "glUniformMatrix3fv(%s,1,GL_FALSE,(float*)m);" }, { "mat4", "m4x4f m", "glUniformMatrix4fv(%s,1,GL_FALSE,(float*)m);" }, diff --git a/vg_imgui.h b/vg_imgui.h index c6553e6..62ec169 100644 --- a/vg_imgui.h +++ b/vg_imgui.h @@ -1420,6 +1420,17 @@ static void _ui_textbox_to_clipboard(void){ } } +static void _ui_textbox_change_callback(void){ + if( vg_ui.textbox.callbacks.change ){ + vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); + + /* we gave permission to modify the buffer in this callback so.. */ + int len = strlen( vg_ui.textbuf ); + vg_ui.textbox.cursor_user = VG_MIN( vg_ui.textbox.cursor_user, len ); + vg_ui.textbox.cursor_pos = VG_MIN( vg_ui.textbox.cursor_pos, len ); + } +} + static void ui_start_modal( const char *message, u32 options ); static void _ui_textbox_clipboard_paste(void){ if( !SDL_HasClipboardText() ) @@ -1444,6 +1455,7 @@ static void _ui_textbox_clipboard_paste(void){ _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user, &vg_ui.textbox.cursor_pos, cpylength, 1 ); SDL_free( text ); + _ui_textbox_change_callback(); } static void _ui_textbox_put_char( char c ){ @@ -1582,10 +1594,7 @@ static void _ui_textbox_backspace(void){ if( vg_ui.focused_control_type == k_ui_control_textbox ){ vg_ui.textbox.cursor_user = _ui_textbox_delete_char( -1 ); vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user; - - if( vg_ui.textbox.callbacks.change ){ - vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); - } + _ui_textbox_change_callback(); } } @@ -1593,10 +1602,7 @@ static void _ui_textbox_delete(void){ if( vg_ui.focused_control_type == k_ui_control_textbox ){ vg_ui.textbox.cursor_user = _ui_textbox_delete_char( 1 ); vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user; - - if( vg_ui.textbox.callbacks.change ){ - vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); - } + _ui_textbox_change_callback(); } } @@ -1653,6 +1659,7 @@ static void _ui_textbox_cut(void){ _ui_textbox_to_clipboard(); vg_ui.textbox.cursor_user = _ui_textbox_delete_char(0); vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user; + _ui_textbox_change_callback(); } static void _ui_textbox_enter(void){ @@ -1664,8 +1671,10 @@ static void _ui_textbox_enter(void){ if( vg_ui.focused_control_type != k_ui_control_textbox ) return; - if( vg_ui.textbox.flags & UI_TEXTBOX_MULTILINE ) + if( vg_ui.textbox.flags & UI_TEXTBOX_MULTILINE ){ _ui_textbox_put_char( '\n' ); + _ui_textbox_change_callback(); + } else{ if( !(vg_ui.textbox.flags & UI_TEXTBOX_AUTOFOCUS ) ) ui_defocus_all(); @@ -2102,9 +2111,7 @@ static void ui_proc_utf8( const char *text ){ ptr ++; } - if( vg_ui.textbox.callbacks.change ){ - vg_ui.textbox.callbacks.change( vg_ui.textbuf, vg_ui.textbox.len ); - } + _ui_textbox_change_callback(); } } diff --git a/vg_io.h b/vg_io.h index 87562ac..e39c15f 100644 --- a/vg_io.h +++ b/vg_io.h @@ -159,16 +159,19 @@ static void vg_file_print_invalid( FILE *fp ) } /* read entire binary file */ -static void *vg_file_read( void *lin_alloc, const char *path, u32 *size ) -{ +static void *vg_file_read( void *lin_alloc, const char *path, u32 *size ){ FILE *f = fopen( path, "rb" ); if( f ){ - void *buffer = vg_linear_alloc( lin_alloc, 0 ); + void *buffer = lin_alloc? vg_linear_alloc( lin_alloc, 0 ): + NULL; u64 current = 0; /* read in chunks */ for( u32 i=0; 1; i++ ){ - buffer = vg_linear_extend( lin_alloc, buffer, VG_FILE_IO_CHUNK_SIZE ); + if( lin_alloc ) + buffer = vg_linear_extend( lin_alloc,buffer,VG_FILE_IO_CHUNK_SIZE ); + else + buffer = realloc( buffer, current + VG_FILE_IO_CHUNK_SIZE ); u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f ); current += l; @@ -190,21 +193,24 @@ static void *vg_file_read( void *lin_alloc, const char *path, u32 *size ) } } - buffer = vg_linear_resize( lin_alloc, buffer, vg_align8(current) ); + if( lin_alloc ) + buffer = vg_linear_resize( lin_alloc, buffer, vg_align8(current) ); + else + buffer = realloc( buffer, vg_align8(current) ); + fclose( f ); *size = (u32)current; return buffer; } else{ - vg_error( "vg_disk_open_read: %s\n", strerror(errno) ); + vg_error( "vg_disk_open_read: %s (file: %s)\n", strerror(errno), path ); return NULL; } } /* read entire file and append a null on the end */ -static char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz ) -{ +static char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz ){ u32 size; char *str = vg_file_read( lin_alloc, path, &size ); @@ -212,7 +218,11 @@ static char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz ) return NULL; /* include null terminator */ - str = vg_linear_extend( lin_alloc, str, 1 ); + if( lin_alloc ) + str = vg_linear_extend( lin_alloc, str, 1 ); + else + str = realloc( str, size+1 ); + str[ size ] = '\0'; *sz = size+1; diff --git a/vg_profiler.h b/vg_profiler.h index 67808a7..dfc47ef 100644 --- a/vg_profiler.h +++ b/vg_profiler.h @@ -59,25 +59,23 @@ static void vg_profile_end( struct vg_profile *profile ) } static void vg_profile_drawn( struct vg_profile **profiles, u32 count, - float budget, ui_rect panel, u32 colour_offset ) + float budget, ui_rect panel, u32 colour_offset, + int dir ) { - if( !vg_profiler ) - return; - if( panel[2] == 0 ) panel[2] = 256; if( panel[3] == 0 ) panel[3] = VG_PROFILE_SAMPLE_COUNT * 2; - float sh = panel[3] / VG_PROFILE_SAMPLE_COUNT, - sw = panel[2]; + f32 sh = (f32)panel[3^dir] / (f32)VG_PROFILE_SAMPLE_COUNT, + sw = (f32)panel[2^dir]; ui_fill( panel, 0xa0000000 ); assert( count <= 8 ); - double avgs[8]; - int ptrs[8]; + f64 avgs[8]; + int ptrs[8]; for( int i=0; ibuffer_current; @@ -87,10 +85,10 @@ static void vg_profile_drawn( struct vg_profile **profiles, u32 count, u32 colours[] = { 0xff0000ff, 0xff00ff00, 0xff00ffff, 0xffff0000, 0xffff00ff, 0xffffff00 }; - double rate_mul = 1000.0 / (double)SDL_GetPerformanceFrequency(); + f64 rate_mul = 1000.0 / (f64)SDL_GetPerformanceFrequency(); for( int i=0; isamples[ptrs[j]] * rate_mul, - px = (total / (budget)) * sw, - wx = (sample / (budget)) * sw; + f64 sample = (f64)profiles[j]->samples[ptrs[j]] * rate_mul, + px = (total / (budget)) * sw, + wx = (sample / (budget)) * sw; - ui_rect block = { panel[0] + px, panel[1] + (float)i*sh, - wx, sh }; + ui_rect block; + block[0^dir] = panel[0^dir] + px; + block[1^dir] = panel[1^dir] + (f32)i*sh; + block[2^dir] = wx; + block[3^dir] = ceilf(sh)-1; u32 colour = colours[ (j+colour_offset) % vg_list_size(colours) ]; ui_fill( block, colour ); @@ -117,7 +118,7 @@ static void vg_profile_drawn( struct vg_profile **profiles, u32 count, snprintf( infbuf, 64, "accuracy: %.7fms", rate_mul ); ui_text( (ui_rect){ panel[0] + 4, - panel[1] + 0 * 14, 500, 30 }, + panel[1] + panel[3] - 14, 500, 30 }, infbuf, 1, k_ui_align_left, 0 ); diff --git a/vg_settings_menu.h b/vg_settings_menu.h new file mode 100644 index 0000000..96fc6ea --- /dev/null +++ b/vg_settings_menu.h @@ -0,0 +1,301 @@ +#ifndef VG_SETTINGS_MENU_H +#define VG_SETTINGS_MENU_H + +#include "vg.h" +#include "vg_imgui.h" + +struct ui_enum_opt vg_settings_vsync_enum[] = { + { 0, "None" }, + { 1, "On" }, + {-1, "Adaptive" }, +}; + +struct ui_enum_opt vg_settings_quality_enum[] = { + { 0, "High Quality" }, + { 1, "Faster" }, + { 2, "Absolute Minimum" }, +}; + +struct ui_enum_opt vg_settings_screen_mode_enum[] = { + { 0, "Fullscreen (desktop)" }, + { 1, "Fullscreen (native)" }, + { 2, "Floating Window" } +}; + +struct { + struct vg_setting_ranged_i32{ + i32 new_value, *actual_value, min, max; + char buf[10]; + const char *label; + } + fps_limit; + + struct vg_setting_enum{ + i32 new_value, *actual_value; + + struct ui_enum_opt *options; + u32 option_count; + const char *label; + } + vsync, quality, screenmode; + + int windowed_before[4]; +} +static vg_settings = { + .fps_limit = { .label = "Fps Limit", + .min=24, .max=300, .actual_value = &vg.fps_limit }, + .vsync = { .label = "Vsync", + .actual_value = &vg.vsync, + .options = vg_settings_vsync_enum, .option_count = 3 }, + .quality = { .label = "Graphic Quality", + .actual_value = &vg.quality_profile, + .options = vg_settings_quality_enum, .option_count = 3 }, + .screenmode = { .label = "Type", + .actual_value = &vg.screen_mode, + .options = vg_settings_screen_mode_enum, .option_count=3 } + +}; + +static void vg_settings_ui_draw_diff( ui_rect orig ){ + ui_rect l,r; + ui_split( orig, k_ui_axis_v, -32, 0, l, r ); + ui_text( r, "*", 1, k_ui_align_middle_center, ui_colour(k_ui_blue) ); +} + +/* i32 settings + * ------------------------------------------------------------------------- */ + +static void vg_settings_ui_int( char *buf, u32 len ){ + for( u32 i=0, j=0; i= '0') && (buf[i] <= '9')) || (buf[i] == '\0') ) + buf[j ++] = buf[i]; + } +} + +struct ui_textbox_callbacks static vg_settings_ui_int_callbacks = { + .change = vg_settings_ui_int +}; + +static bool vg_settings_ranged_i32_valid( struct vg_setting_ranged_i32 *prop ){ + if( prop->new_value < prop->min ) return 0; + if( prop->new_value > prop->max ) return 0; + return 1; +} + +static bool vg_settings_ranged_i32_diff( struct vg_setting_ranged_i32 *prop ){ + if( prop->new_value != *prop->actual_value ) return 1; + else return 0; +} + +static bool vg_settings_ui_ranged_i32( struct vg_setting_ranged_i32 *prop, + ui_rect rect ){ + ui_rect orig; + rect_copy( rect, orig ); + + ui_textbox( rect, prop->label, prop->buf, sizeof(prop->buf), + 1, 0, &vg_settings_ui_int_callbacks ); + prop->new_value = atoi( prop->buf ); + + if( vg_settings_ranged_i32_diff( prop ) ) + vg_settings_ui_draw_diff( orig ); + + bool valid = vg_settings_ranged_i32_valid( prop ); + if( !valid ){ + ui_rect _null, line; + ui_split( orig, k_ui_axis_h, -1, 0, _null, line ); + line[1] += 3; + + ui_fill( line, ui_colour( k_ui_red ) ); + } + + return valid; +} + +static void ui_settings_ranged_i32_init( struct vg_setting_ranged_i32 *prop ){ + vg_str tmp; + vg_strnull( &tmp, prop->buf, sizeof(prop->buf) ); + vg_strcati32( &tmp, *prop->actual_value ); + prop->new_value = *prop->actual_value; +} + +/* enum settings + * ------------------------------------------------------------------------- */ + +static bool vg_settings_enum_diff( struct vg_setting_enum *prop ){ + if( prop->new_value != *prop->actual_value ) return 1; + else return 0; +} + +static bool vg_settings_enum( struct vg_setting_enum *prop, ui_rect rect ){ + ui_rect orig; + rect_copy( rect, orig ); + + ui_enum( rect, prop->label, + prop->options, prop->option_count, &prop->new_value ); + + if( vg_settings_enum_diff( prop ) ) + vg_settings_ui_draw_diff( orig ); + + return 1; +} + +static void ui_settings_enum_init( struct vg_setting_enum *prop ){ + prop->new_value = *prop->actual_value; +} + +/* .. */ + +static void vg_settings_ui_header( ui_rect inout_panel, const char *name ){ + ui_rect rect; + ui_standard_widget( inout_panel, rect, 2 ); + ui_text( rect, name, 1, k_ui_align_middle_center, ui_colour(k_ui_fg+3) ); +} + +static void vg_settings_video_apply(void){ + if( vg_settings_enum_diff( &vg_settings.screenmode ) ){ + vg.screen_mode = vg_settings.screenmode.new_value; + + if( (vg.screen_mode == 0) || (vg.screen_mode == 1) ){ + SDL_GetWindowPosition( vg.window, + &vg_settings.windowed_before[0], + &vg_settings.windowed_before[1] ); + vg_settings.windowed_before[2] = vg.window_x; + vg_settings.windowed_before[3] = vg.window_y; + + SDL_DisplayMode video_mode; + if( SDL_GetDesktopDisplayMode( 0, &video_mode ) ){ + vg_error("SDL_GetDesktopDisplayMode failed: %s\n", SDL_GetError()); + } + else { + //vg.display_refresh_rate = video_mode.refresh_rate; + vg.window_x = video_mode.w; + vg.window_y = video_mode.h; + } + SDL_SetWindowResizable( vg.window, SDL_FALSE ); + SDL_SetWindowSize( vg.window, vg.window_x, vg.window_y ); + } + + if( vg.screen_mode == 0 ) + SDL_SetWindowFullscreen( vg.window, SDL_WINDOW_FULLSCREEN_DESKTOP ); + if( vg.screen_mode == 1 ) + SDL_SetWindowFullscreen( vg.window, SDL_WINDOW_FULLSCREEN ); + if( vg.screen_mode == 2 ){ + SDL_SetWindowFullscreen( vg.window, 0 ); + SDL_SetWindowSize( vg.window, + vg_settings.windowed_before[2], + vg_settings.windowed_before[3] ); + SDL_SetWindowPosition( vg.window, + vg_settings.windowed_before[0], + vg_settings.windowed_before[1] ); + SDL_SetWindowResizable( vg.window, SDL_TRUE ); + } + } + + vg.fps_limit = vg_settings.fps_limit.new_value; + vg.quality_profile = vg_settings.quality.new_value; + vg.vsync = vg_settings.vsync.new_value; +} + +static void aaaaaaaaaaaaaaaaa( ui_rect r ); +static void vg_settings_video_gui( ui_rect panel ){ + bool validated = 1; + ui_rect rq; + ui_standard_widget( panel, rq, 1 ); + vg_settings_enum( &vg_settings.quality, rq ); + + /* FIXME */ +#if 0 + if( vg.vsync_feature == k_vsync_feature_error ){ + ui_info( panel, "There was an error activating vsync feature." ); + } +#endif + + /* frame timing */ + vg_settings_ui_header( panel, "Frame Timing" ); + ui_rect duo, d0,d1; + ui_standard_widget( panel, duo, 1 ); + ui_split_ratio( duo, k_ui_axis_v, 0.5f, 16, d0, d1 ); + + vg_settings_enum( &vg_settings.vsync, d0 ); + validated &= vg_settings_ui_ranged_i32( &vg_settings.fps_limit, d1 ); + + ui_standard_widget( panel, duo, 10 ); + aaaaaaaaaaaaaaaaa( duo ); + + /* window spec */ + vg_settings_ui_header( panel, "Window Specification" ); + + ui_standard_widget( panel, duo, 1 ); + vg_settings_enum( &vg_settings.screenmode, duo ); + + /* apply */ + ui_rect last_row; + ui_px height = (vg_ui.font->glyph_height + 18) * k_ui_scale; + ui_split( panel, k_ui_axis_h, -height, k_ui_padding, + panel, last_row ); + + const char *string = "Apply"; + if( validated ){ + if( ui_button( last_row, string ) == 1 ) + vg_settings_video_apply(); + } + else{ + ui_rect rect; + ui_standard_widget( last_row, rect, 1 ); + ui_fill( rect, ui_colour( k_ui_bg+1 ) ); + ui_outline( rect, -1, ui_colour( k_ui_red ), 0 ); + + ui_rect t = { 0,0, ui_text_line_width( string ), 14 }; + ui_rect_center( rect, t ); + ui_text( t, string, 1, k_ui_align_left, ui_colour(k_ui_fg+3) ); + } +} + +static void vg_settings_gui(void){ + ui_rect null; + ui_rect screen = { 0, 0, vg.window_x, vg.window_y }; + ui_rect window = { 0, 0, 1000, 700 }; + ui_rect_center( screen, window ); + vg_ui.wants_mouse = 1; + + ui_fill( window, ui_colour( k_ui_bg+1 ) ); + ui_outline( window, 1, ui_colour( k_ui_bg+7 ), 0 ); + + ui_rect title, panel; + ui_split( window, k_ui_axis_h, 28, 0, title, panel ); + ui_fill( title, ui_colour( k_ui_bg+7 ) ); + ui_text( title, "Settings", 1, k_ui_align_middle_center, + ui_colourcont(k_ui_bg+7) ); + + ui_rect quit_button; + ui_split( title, k_ui_axis_v, title[2]-title[3], 2, title, quit_button ); + + if( ui_button_text( quit_button, "X", 1 ) == 1 ){ + vg.settings_open = 0; + return; + } + + ui_rect_pad( panel, (ui_px[2]){ 8, 8 } ); + + static i32 page = 0; + ui_tabs( panel, panel, (const char *[]){ "video", "audio", "game" }, + 3, &page ); + + if( page == 0 ){ + vg_settings_video_gui( panel ); + } +} + +static int cmd_vg_settings_toggle( int argc, const char *argv[] ){ + vg.settings_open = !vg.settings_open; + + if( vg.settings_open ){ + ui_settings_ranged_i32_init( &vg_settings.fps_limit ); + ui_settings_enum_init( &vg_settings.vsync ); + ui_settings_enum_init( &vg_settings.quality ); + ui_settings_enum_init( &vg_settings.screenmode ); + } + return 0; +} + +#endif /* VG_SETTINGS_MENU_H */ diff --git a/vg_tex.h b/vg_tex.h index 68d9d45..3f9cd98 100644 --- a/vg_tex.h +++ b/vg_tex.h @@ -326,6 +326,9 @@ void vg_tex2d_load_qoi_async( const u8 *bytes, u32 size, static void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest ) { + if( vg_thread_purpose() != k_thread_purpose_loader ) + vg_fatal_error( "wrong thread\n" ); + vg_linear_clear( vg_mem.scratch ); u32 size; -- 2.25.1