settings menu & texsheet
authorhgn <hgodden00@gmail.com>
Fri, 29 Dec 2023 10:38:31 +0000 (10:38 +0000)
committerhgn <hgodden00@gmail.com>
Fri, 29 Dec 2023 10:38:31 +0000 (10:38 +0000)
build_texsheet.sh [new file with mode: 0755]
src/texsheet.c
vg.h
vg_audio.h
vg_audio_dsp.h
vg_build_utils_shader.h
vg_imgui.h
vg_io.h
vg_profiler.h
vg_settings_menu.h [new file with mode: 0644]
vg_tex.h

diff --git a/build_texsheet.sh b/build_texsheet.sh
new file mode 100755 (executable)
index 0000000..abc0195
--- /dev/null
@@ -0,0 +1 @@
+clang -fsanitize=address -O0 -I. -DVG_BUILD src/texsheet.c -o /tmp/tmpsr && /tmp/tmpsr $@
index 367136bbc3e8d1d009cad32c479575e8725c5fc7..404296443010671b948134761743f9a59e0eb1cc 100644 (file)
 // 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 = &region_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 = &region_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 = &region_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 = &region_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 aa86ab547a27e3cb84d106b0154c6f36246bdc54..919f6f3b878049b68f55afb749eddf904d7c37c1 100644 (file)
--- 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();
index 38290ff129f95c4ce00658303ef1f75bb9f7a45d..11fb8f46596465e6a0afae0e59728318fff60ea3 100644 (file)
@@ -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();
index 48926e282628eb476e5bd2b78eda908eb0b2450a..c2bed10ebde2a7935fc2c53ddf8167743bb14350 100644 (file)
@@ -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++ ){
index 39943b3c0de63494d6b97dc976b25d96ef30deaa..d1d2d05c9fd3cf242004ef4d7ab15a12cc6e3dee 100644 (file)
@@ -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);" },
index c6553e61c0b24352636de4c3ba6619ee3f61a724..62ec1697b0cd34db8b7e633dcf2bfe823508a625 100644 (file)
@@ -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 87562ace408a919ba0d02afdc4c0262ac3e64893..e39c15fa5975b6103e791cb56b41991016c252b6 100644 (file)
--- 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;
 
index 67808a7a6d42d898f42e747d0be49f0a4528b8aa..dfc47ef1266d680b5fe1db657f4ad9b583870493 100644 (file)
@@ -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; i<count; i++ ){
       ptrs[i] = profiles[i]->buffer_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; i<VG_PROFILE_SAMPLE_COUNT-1; i++ ){
-      double total = 0.0;
+      f64 total = 0.0;
 
       for( int j=0; j<count; j++ ){
          ptrs[j] --;
@@ -98,12 +96,15 @@ static void vg_profile_drawn( struct vg_profile **profiles, u32 count,
          if( ptrs[j] < 0 )
             ptrs[j] = VG_PROFILE_SAMPLE_COUNT-1;
 
-         double sample  = (double)profiles[j]->samples[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 (file)
index 0000000..96fc6ea
--- /dev/null
@@ -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<len; i ++ ){
+      if( ((buf[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 */
index 68d9d458654721dc17a06f6acd6eea2b54a7e20c..3f9cd9850eb8ae45191d0dd5ddb24250e58d2bb9 100644 (file)
--- 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;