steam ugc
authorhgn <hgodden00@gmail.com>
Thu, 4 May 2023 04:35:36 +0000 (05:35 +0100)
committerhgn <hgodden00@gmail.com>
Thu, 4 May 2023 04:35:36 +0000 (05:35 +0100)
12 files changed:
src/fonts/vg_font_thin.png
vg.h
vg_console.h
vg_imgui.h
vg_io.h
vg_loader.h
vg_platform.h
vg_pxfont_thin.h
vg_steam.h
vg_steam_remote_storage.h [new file with mode: 0644]
vg_steam_ugc.h [new file with mode: 0644]
vg_tex.h

index 0c661970f11289eb45919946de610fb1b72827ea..8d7f50f80bcf485b1c260801a2264621e4cbd854 100644 (file)
Binary files a/src/fonts/vg_font_thin.png and b/src/fonts/vg_font_thin.png differ
diff --git a/vg.h b/vg.h
index 64f9187a3befde770f71dc15889c5f12145d3f08..6cbcb960324c061076b777a875a9160878dfd672 100644 (file)
--- a/vg.h
+++ b/vg.h
@@ -124,22 +124,21 @@ VG_STATIC void vg_update_post(void);
 VG_STATIC void vg_render(void);
 VG_STATIC void vg_gui(void);
 
-struct vg
-{
+struct vg{
    /* Engine sync */
    SDL_Window     *window;
    SDL_GLContext  gl_context;
+   const char     *base_path;
 
    SDL_sem *sem_loader;        /* allows only one loader at a time */
-
    jmp_buf env_loader_exit;
 
    SDL_threadID  thread_id_main,
                  thread_id_loader;
+   void         *thread_data;
 
    SDL_SpinLock sl_status;
-   enum engine_status
-   {
+   enum engine_status{
       k_engine_status_none,
       k_engine_status_load_internal,
       k_engine_status_running,
@@ -156,8 +155,7 @@ struct vg
    int display_refresh_rate,
        fps_limit;             /* 0: use vsync, >0: cap fps to this, no vsync */
 
-   enum vsync_feature
-   {
+   enum vsync_feature{
       k_vsync_feature_disabled=0,
       k_vsync_feature_enabled=1,
       k_vsync_feature_enabled_adaptive=2,
@@ -182,8 +180,7 @@ struct vg
 
    int fixed_iterations;
 
-   enum engine_stage
-   {
+   enum engine_stage{
       k_engine_stage_none,
       k_engine_stage_update,
       k_engine_stage_update_fixed,
@@ -194,8 +191,7 @@ struct vg
 
    /* graphics */
    m4x4f pv;
-   enum quality_profile
-   {
+   enum quality_profile{
       k_quality_profile_high = 0,
       k_quality_profile_low = 1,
    }
@@ -304,7 +300,7 @@ void async_internal_complete( void *payload, u32 size )
    SDL_AtomicUnlock( &vg.sl_status );
 }
 
-VG_STATIC void _vg_load_full(void)
+VG_STATIC void _vg_load_full( void *data )
 {
    vg_preload();
 
@@ -332,8 +328,32 @@ VG_STATIC void _vg_process_events(void)
    SDL_Event event;
    while( SDL_PollEvent( &event ) ){
       if( event.type == SDL_KEYDOWN ){
-         //console_proc_key( event.key.keysym );
-         _ui_proc_key( event.key.keysym );
+         if( vg_console.enabled ){
+            if( event.key.keysym.sym == SDLK_ESCAPE ||
+                event.key.keysym.sym == SDLK_BACKQUOTE ){
+               vg_console.enabled = 0;
+               ui_defocus_all();
+            }
+            else if( (event.key.keysym.mod & KMOD_CTRL) && 
+                      event.key.keysym.sym == SDLK_n ){
+               _console_suggest_next();
+            }
+            else if( (event.key.keysym.mod & KMOD_CTRL ) &&
+                      event.key.keysym.sym == SDLK_p ){
+               _console_suggest_prev();
+            }
+            else{
+               _ui_proc_key( event.key.keysym );
+            }
+         }
+         else{
+            if( event.key.keysym.sym == SDLK_BACKQUOTE ){
+               vg_console.enabled = 1;
+            }
+            else {
+               _ui_proc_key( event.key.keysym );
+            }
+         }
       }
       else if( event.type == SDL_MOUSEWHEEL ){
          vg.mouse_wheel[0] += event.wheel.preciseX;
@@ -375,7 +395,6 @@ VG_STATIC void _vg_process_events(void)
          }
       }
       else if( event.type == SDL_TEXTINPUT ){
-         //console_proc_utf8( event.text.text );
          ui_proc_utf8( event.text.text );
       }
    }
@@ -430,7 +449,15 @@ VG_STATIC void _vg_gameloop_render(void)
    vg.engine_stage = k_engine_stage_ui;
    {
       ui_prerender();
-      vg_gui();
+      if( vg_console.enabled ){ 
+         vg_ui.ignore_input_frames = 10;
+         vg_gui();
+         vg_ui.ignore_input_frames = 0;
+         vg_ui.wants_mouse = 1;
+         _vg_console_draw();
+      }
+      else vg_gui();
+
       ui_postrender();
 #if 0
       ui_begin( vg.window_x, vg.window_y );
@@ -480,7 +507,6 @@ VG_STATIC void _vg_gameloop_render(void)
       /* FIXME */
       audio_debug_ui( vg.pv );
       vg_gui();
-      _vg_console_draw();
       
       ui_resolve();
       ui_draw( NULL );
@@ -678,6 +704,15 @@ VG_STATIC void _vg_init_window( const char *window_name )
    SDL_InitSubSystem( SDL_INIT_AUDIO );
    SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER );
 
+   char *exe_basepath = SDL_GetBasePath();
+   u32 len = vg_align8( strlen(exe_basepath)+1 );
+   char *dest  = vg_linear_alloc( vg_mem.rtmemory, len );
+   strcpy( dest, exe_basepath );
+   SDL_free( exe_basepath );
+   vg.base_path = dest;
+
+   vg_info( "Basepath: %s\n", vg.base_path );
+
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
    SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 3 );
@@ -732,7 +767,7 @@ VG_STATIC void _vg_init_window( const char *window_name )
 
 #ifdef VG_DEVWINDOW
          0, 0, vg.window_x, vg.window_y, 
-         SDL_WINDOW_BORDERLESS|SDL_WINDOW_OPENGL
+         SDL_WINDOW_BORDERLESS|SDL_WINDOW_OPENGL|SDL_WINDOW_INPUT_GRABBED
       ))){}
 #else
                                      0, 0,
@@ -800,11 +835,9 @@ VG_STATIC void _vg_init_window( const char *window_name )
 
    vg_info( "Display refresh rate: %d\n", dispmode.refresh_rate );
 
-#ifdef _WIN32
+#if defined(_WIN32) || defined(VG_DEVWINDOW)
    vg.fps_limit = vg.display_refresh_rate;
 #else
-   /* request vsync by default on linux to avoid screen tearing.
-    * this does have its own issues with compositing on X11. */
    vg.fps_limit = 0;
 #endif
 }
@@ -839,10 +872,7 @@ VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name )
    _vg_init_window( window_name );
 
    vg_async_init();
-   
-#ifndef VG_DEVWINDOW
    SDL_SetRelativeMouseMode(1);
-#endif
 
    vg.thread_id_main = SDL_GetThreadID(NULL);
    
@@ -853,7 +883,7 @@ VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name )
    vg.engine_status = k_engine_status_load_internal;
 
    _vg_opengl_sync_init();
-    vg_loader_start( _vg_load_full );
+    vg_loader_start( _vg_load_full, NULL );
    _vg_gameloop();
    _vg_terminate();
 }
index dd9cc77cea02e4d21318feaa51641ecf95f11628..66e7f5f26c65a440d08cbfa907088bcf6720333f 100644 (file)
@@ -7,7 +7,7 @@
   #define VG_GAME
 #endif
 
-#include "vg/vg_ui.h"
+#include "vg/vg_imgui.h"
 #include "vg/vg_log.h"
 
 #define VG_VAR_F32( NAME, ... ) \
@@ -63,7 +63,6 @@ struct vg_console{
        
        char input[96],
         input_copy[96];
-       int cursor_user, cursor_pos, string_length;
        
        char history[32][96];
        int history_last, history_pos, history_count;
@@ -84,14 +83,6 @@ VG_STATIC void  vg_execute_console_input( const char *cmd );
 /*
  * Console interface
  */
-VG_STATIC void console_make_selection( int* start, int* end );
-VG_STATIC void console_move_cursor( int* cursor0, int* cursor1, 
-                                    int dir, int snap_together );
-VG_STATIC int console_makeroom( int datastart, int length );
-VG_STATIC int console_delete_char( int direction );
-VG_STATIC void console_to_clipboard(void);
-VG_STATIC void console_clipboard_paste(void);
-VG_STATIC void console_put_char( char c );
 VG_STATIC void console_history_get( char* buf, int entry_num );
 VG_STATIC int _vg_console_enabled(void);
 VG_STATIC void console_proc_key( SDL_Keysym ev );
@@ -137,96 +128,6 @@ void vg_console_reg_cmd( const char *alias,
    vg_info( "Console function '%s' registered\n", alias );
 }
 
-VG_STATIC void _vg_console_draw(void)
-{
-#if 0
-       if( !vg_console.enabled )
-               return;
-
-   SDL_AtomicLock( &log_print_sl );
-
-       int ptr = vg_log.buffer_line_current;
-   int const fh = 14,
-             log_lines = 32;
-   int console_lines = VG_MIN( log_lines, vg_log.buffer_line_count );
-       
-       vg_uictx.cursor[0] = 0;
-       vg_uictx.cursor[1] = 0;
-       vg_uictx.cursor[3] = log_lines*fh;
-       ui_fill_x();
-       
-   /* 
-    * log
-    */
-       ui_new_node();
-       {
-               ui_fill_rect( vg_uictx.cursor, 0x77181818 );
-       
-               vg_uictx.cursor[3] = fh;
-               ui_align_bottom();
-
-               for( int i=0; i<console_lines; i ++ ){
-                       ptr --;
-
-                       if( ptr < 0 )
-                               ptr = vg_list_size( vg_log.buffer )-1;
-         
-                       ui_text( vg_uictx.cursor, vg_log.buffer[ptr], 1, 0 );
-                       vg_uictx.cursor[1] -= fh;
-               }
-
-       }
-       ui_end_down();
-       
-       
-   /* Input area */
-       vg_uictx.cursor[1] += 2;
-       vg_uictx.cursor[3] = fh;
-
-       ui_new_node();
-       {
-               ui_fill_rect( vg_uictx.cursor, 0x77111111 );
-               ui_text( vg_uictx.cursor, vg_console.input, 1, 0 );
-               
-               int start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user ),
-                        end   = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user );
-               
-               vg_uictx.cursor[0] = start * UI_GLYPH_SPACING_X;
-               vg_uictx.cursor[2] = (start == end? 0.5f: (float)(end-start)) 
-                                             * (float)UI_GLYPH_SPACING_X;
-               
-               ui_fill_rect( vg_uictx.cursor, 0x66ffffff );
-       }
-       ui_end_down();
-
-
-   /* suggestions */
-   if( vg_console.suggestion_count ){
-      vg_uictx.cursor[0] += UI_GLYPH_SPACING_X * vg_console.suggestion_pastepos;
-      vg_uictx.cursor[1] += 2;
-      vg_uictx.cursor[3] = vg_console.suggestion_count * fh;
-      vg_uictx.cursor[2] = UI_GLYPH_SPACING_X * vg_console.suggestion_maxlen;
-
-      ui_new_node();
-      {
-         ui_fill_rect( vg_uictx.cursor, 0x77040404 );
-
-         vg_uictx.cursor[3] = fh;
-         for( int i=0; i<vg_console.suggestion_count; i ++ ){
-            if( i == vg_console.suggestion_select )
-               ui_fill_rect( vg_uictx.cursor, 0x66a0e508 );
-
-            ui_text( vg_uictx.cursor, vg_console.suggestions[i].str, 1, 0 );
-            vg_uictx.cursor[1] += fh;
-         }
-      }
-      ui_end_down();
-   }
-
-   SDL_AtomicUnlock( &log_print_sl );
-#endif
-}
-
 VG_STATIC int _vg_console_list( int argc, char const *argv[] )
 {
        for( int i=0; i<vg_console.function_count; i ++ ){
@@ -531,6 +432,10 @@ VG_STATIC void console_suggest_score_text( const char *str, const char *input,
 
 VG_STATIC void console_update_suggestions(void)
 {
+   if( vg_ui.focused_control_type != k_ui_control_textbox ||
+       vg_ui.textbuf != vg_console.input )
+      return;
+
    vg_console.suggestion_count = 0;
    vg_console.suggestion_select = -1;
    vg_console.suggestion_maxlen = 0;
@@ -542,17 +447,12 @@ VG_STATIC void console_update_suggestions(void)
     * - cursors should match
     */
 
-   if( vg_console.cursor_pos == 0 )
-      return;
-
-   if( vg_console.cursor_pos != vg_console.cursor_user )
-      return;
-
-   if( vg_console.input[ vg_console.cursor_pos ] != '\0' )
-      return;
+   if( vg_ui.textbox.cursor_pos == 0 ) return;
+   if( vg_ui.textbox.cursor_pos != vg_ui.textbox.cursor_user ) return;
+   if( vg_console.input[ vg_ui.textbox.cursor_pos ] != '\0' ) return;
 
-   if(  (vg_console.input[ vg_console.cursor_pos -1 ] == ' ') ||
-        (vg_console.input[ vg_console.cursor_pos -1 ] == '\t') )
+   if(  (vg_console.input[ vg_ui.textbox.cursor_pos -1 ] == ' ') ||
+        (vg_console.input[ vg_ui.textbox.cursor_pos -1 ] == '\t') )
       return;
 
    char temp[128];
@@ -600,114 +500,69 @@ VG_STATIC void console_update_suggestions(void)
 }
 
 /*
- * Console Interface
+ * Suggestion controls
  */
-VG_STATIC void console_make_selection( int* start, int* end )
-{
-       *start = VG_MIN( vg_console.cursor_pos, vg_console.cursor_user );
-       *end   = VG_MAX( vg_console.cursor_pos, vg_console.cursor_user );
-}
-
-VG_STATIC void console_move_cursor( int* cursor0, int* cursor1, 
-                                    int dir, int snap_together )
+VG_STATIC void _console_fetch_suggestion(void)
 {
-       *cursor0 = VG_MAX( 0, vg_console.cursor_user + dir );
-       *cursor0 = 
-      VG_MIN( 
-         VG_MIN( vg_list_size(vg_console.input)-1, strlen( vg_console.input )), 
-      *cursor0 );
-
-       if( snap_together ) 
-               *cursor1 = *cursor0;
-}
+   char *target = &vg_console.input[ vg_console.suggestion_pastepos ];
 
-VG_STATIC int console_makeroom( int datastart, int length )
-{
-       int move_to = VG_MIN( datastart+length, vg_list_size( vg_console.input )-1 );
-       int move_amount = strlen( vg_console.input )-datastart;
-       int move_end = 
-      VG_MIN( move_to+move_amount, vg_list_size( vg_console.input )-1 );
-       move_amount = move_end-move_to;
-       
-       if( move_amount )
-               memmove( &vg_console.input[ move_to ], 
-               &vg_console.input[ datastart ], 
-               move_end-move_to );
-       
-       vg_console.input[ move_end ] = '\0';
-       
-       return VG_MIN( length, vg_list_size( vg_console.input )-datastart-1 );
-}
+   if( vg_console.suggestion_select == -1 ){
+      strcpy( target, vg_console.input_copy );
+      _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user,
+                               &vg_ui.textbox.cursor_pos, 10000, 1 );
+   }
+   else{
+      strncpy( target,
+            vg_console.suggestions[ vg_console.suggestion_select ].str,
+            vg_list_size( vg_console.input )-1 );
 
-VG_STATIC int console_delete_char( int direction )
-{
-       int start, end;
-       console_make_selection( &start, &end );
-       
-       /* There is no selection */
-       if( !(end-start) ){
-               if( direction == 1 ) end = VG_MIN( end+1, strlen( vg_console.input ) );
-               else if( direction == -1 ) start = VG_MAX( start-1, 0 );
-       }
-       
-       /* Still no selction, no need to do anything */
-       if( !(end-start) ) 
-               return start;
-       
-       /* Copy the end->terminator to start */
-       int remaining_length = strlen( vg_console.input )+1-end;
-       memmove( &vg_console.input[ start ], 
-            &vg_console.input[ end ], 
-            remaining_length );
-       return start;
+      _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user,
+                               &vg_ui.textbox.cursor_pos, 10000, 1 );
+      _ui_textbox_put_char( ' ' );
+   }
 }
 
-VG_STATIC void console_to_clipboard(void)
+VG_STATIC void _console_suggest_store_normal(void)
 {
-       int start, end;
-       console_make_selection( &start, &end );
-       char buffer[512];
-       
-       if( end-start ){
-               memcpy( buffer, &vg_console.input[ start ], end-start );
-               buffer[ end-start ] = 0x00;
-      SDL_SetClipboardText( buffer );
-       }
+   if( vg_console.suggestion_select == -1 ){
+      char *target = &vg_console.input[ vg_console.suggestion_pastepos ];
+      strcpy( vg_console.input_copy, target );
+   }
 }
 
-VG_STATIC void console_clipboard_paste(void)
+VG_STATIC void _console_suggest_next(void)
 {
-   if( !SDL_HasClipboardText() )
-      return;
+   if( vg_console.suggestion_count ){
+      _console_suggest_store_normal();
 
-   char *text = SDL_GetClipboardText();
+      vg_console.suggestion_select ++;
 
-   if( !text ) 
-      return;
+      if( vg_console.suggestion_select >= vg_console.suggestion_count )
+         vg_console.suggestion_select = -1;
+      
+      _console_fetch_suggestion();
+   }
+}
 
-   int datastart = console_delete_char( 0 );
-       int length = strlen( text );
-       int cpylength = console_makeroom( datastart, length );
+VG_STATIC void _console_suggest_prev(void)
+{
+   if( vg_console.suggestion_count ){
+      _console_suggest_store_normal();
+   
+      vg_console.suggestion_select --;
 
-       memcpy( vg_console.input + datastart, text, cpylength);
-       console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, cpylength, 1 );
-   SDL_free( text );
+      if( vg_console.suggestion_select < -1 )
+         vg_console.suggestion_select = vg_console.suggestion_count-1;
 
-   console_update_suggestions();
+      _console_fetch_suggestion();
+   }
 }
 
-VG_STATIC void console_put_char( char c )
+VG_STATIC void _vg_console_on_update( char *buf, u32 len )
 {
-       if( !vg_console.enabled ) 
-               return;
-       
-       vg_console.cursor_user = console_delete_char(0);
-       
-       if( console_makeroom( vg_console.cursor_user, 1 ) )
-               vg_console.input[ vg_console.cursor_user ] = c;
-       
-       console_move_cursor( &vg_console.cursor_user, &vg_console.cursor_pos, 1, 1 );
+   if( buf == vg_console.input ){
+      console_update_suggestions();
+   }
 }
 
 VG_STATIC void console_history_get( char* buf, int entry_num )
@@ -721,298 +576,147 @@ VG_STATIC void console_history_get( char* buf, int entry_num )
        strcpy( buf, vg_console.history[ pick ] );
 }
 
-/* Receed secondary cursor */
-VG_STATIC void _console_left_select(void)
-{
-   console_move_cursor( &vg_console.cursor_user, NULL, -1, 0 );
-}
-
-/* Match and receed both cursors */
-VG_STATIC void _console_left(void)
+VG_STATIC void _vg_console_on_up( char *buf, u32 len )
 {
-   int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
-
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, -cursor_diff, 1 );
-}
-
-VG_STATIC void _console_right_select(void)
-{
-   console_move_cursor( &vg_console.cursor_user, NULL, 1, 0 );
-}
-
-VG_STATIC void _console_right(void)
-{
-   int cursor_diff = vg_console.cursor_pos - vg_console.cursor_user? 0: 1;
-
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, +cursor_diff, 1 );
-}
-
-VG_STATIC void _console_down(void)
-{
-   vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 );
-   console_history_get( vg_console.input, vg_console.history_pos );
-
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, 
-                        vg_list_size(vg_console.input)-1, 1 );
-}
-
-VG_STATIC void _console_up(void)
-{
-   vg_console.history_pos = VG_MAX
-   ( 
-      0, 
-      VG_MIN
-      (
-         vg_console.history_pos+1, 
-         VG_MIN
-         ( 
+   if( buf == vg_console.input ){
+      vg_console.history_pos = 
+      VG_MAX
+      ( 
+        0, 
+        VG_MIN
+        (
+          vg_console.history_pos+1, 
+          VG_MIN
+          ( 
             vg_list_size( vg_console.history ), 
             vg_console.history_count - 1 
-         )
-      )
-   );
-   
-   console_history_get( vg_console.input, vg_console.history_pos );
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, 
-                        vg_list_size(vg_console.input)-1, 1);
-}
-
-VG_STATIC void _console_backspace(void)
-{
-   vg_console.cursor_user = console_delete_char( -1 );
-   vg_console.cursor_pos = vg_console.cursor_user;
-
-   console_update_suggestions();
-}
-
-VG_STATIC void _console_delete(void)
-{
-   vg_console.cursor_user = console_delete_char( 1 );
-   vg_console.cursor_pos = vg_console.cursor_user;
-
-   console_update_suggestions();
+          )
+        )
+      );
+      
+      console_history_get( vg_console.input, vg_console.history_pos );
+      _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user,
+                               &vg_ui.textbox.cursor_pos,
+                               vg_list_size(vg_console.input)-1, 1);
+   }
 }
 
-VG_STATIC void _console_home_select(void)
+VG_STATIC void _vg_console_on_down( char *buf, u32 len )
 {
-   console_move_cursor( &vg_console.cursor_user, NULL, -10000, 0 );
-}
+   if( buf == vg_console.input ){
+      vg_console.history_pos = VG_MAX( 0, vg_console.history_pos-1 );
+      console_history_get( vg_console.input, vg_console.history_pos );
 
-VG_STATIC void _console_home(void)
-{
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, -10000, 1 );
+      _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user,
+                               &vg_ui.textbox.cursor_pos,
+                               vg_list_size(vg_console.input)-1, 1 );
+   }
 }
 
-VG_STATIC void _console_end_select(void)
+VG_STATIC void _vg_console_on_enter( char *buf, u32 len )
 {
-   console_move_cursor( &vg_console.cursor_user, NULL, 10000, 0 );
-}
+   if( buf == vg_console.input ){
+      if( !strlen( vg_console.input ) ) 
+         return;
 
-VG_STATIC void _console_end(void)
-{
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, 
-                        vg_list_size(vg_console.input)-1, 1 );
-}
+      vg_info( "%s\n", vg_console.input );
 
-VG_STATIC void _console_select_all(void)
-{
-   console_move_cursor( &vg_console.cursor_user, NULL,  10000, 0);
-   console_move_cursor( &vg_console.cursor_pos,  NULL, -10000, 0);
-}
-
-VG_STATIC void _console_cut(void)
-{
-   console_to_clipboard();
-   vg_console.cursor_user = console_delete_char(0);
-   vg_console.cursor_pos = vg_console.cursor_user;
-}
+      if( strcmp( vg_console.input, 
+                  vg_console.history[ vg_console.history_last ]) )
+      {
+         vg_console.history_last = ( vg_console.history_last + 1) % 
+                                    vg_list_size(vg_console.history );
+         vg_console.history_count = 
+            VG_MIN( vg_list_size( vg_console.history ), 
+                  vg_console.history_count + 1 );
+         strcpy( vg_console.history[ vg_console.history_last ], 
+                 vg_console.input );
+      }
 
-VG_STATIC void _console_enter(void)
-{
-   if( !strlen( vg_console.input ) ) 
-      return;
+      vg_console.history_pos = -1;
+      vg_execute_console_input( vg_console.input );
+      _ui_textbox_move_cursor( &vg_ui.textbox.cursor_user,
+                               &vg_ui.textbox.cursor_pos, -10000, 1 );
 
-   vg_info( "%s\n", vg_console.input );
-
-   if( strcmp( vg_console.input, 
-            vg_console.history[ vg_console.history_last ]) )
-   {
-      vg_console.history_last = ( vg_console.history_last + 1) % 
-                                 vg_list_size(vg_console.history );
-      vg_console.history_count = 
-         VG_MIN( vg_list_size( vg_console.history ), 
-               vg_console.history_count + 1 );
-      strcpy( vg_console.history[ vg_console.history_last ], 
-              vg_console.input );
+      vg_console.input[0] = '\0';
+      console_update_suggestions();
    }
-
-   vg_console.history_pos = -1;
-   vg_execute_console_input( vg_console.input );
-   console_move_cursor( &vg_console.cursor_user, 
-                        &vg_console.cursor_pos, -10000, 1 );
-   vg_console.input[0] = '\0';
-
-   console_update_suggestions();
 }
 
-/*
- * Suggestion controls
- */
-VG_STATIC void _console_fetch_suggestion(void)
+VG_STATIC void _vg_console_draw(void)
 {
-   char *target = &vg_console.input[ vg_console.suggestion_pastepos ];
+       if( !vg_console.enabled ) return;
 
-   if( vg_console.suggestion_select == -1 ){
-      strcpy( target, vg_console.input_copy );
-      console_move_cursor( &vg_console.cursor_user, 
-                           &vg_console.cursor_pos, 10000, 1 );
-   }
-   else{
-      strncpy( target,
-            vg_console.suggestions[ vg_console.suggestion_select ].str,
-            vg_list_size( vg_console.input )-1 );
+   SDL_AtomicLock( &log_print_sl );
 
-      console_move_cursor( &vg_console.cursor_user, 
-                           &vg_console.cursor_pos, 10000, 1 );
-      console_put_char( ' ' ); 
-   }
-}
+       int ptr = vg_log.buffer_line_current;
+   int const fh = 14, log_lines = 32;
+   int console_lines = VG_MIN( log_lines, vg_log.buffer_line_count );
 
-VG_STATIC void _console_suggest_store_normal(void)
-{
-   if( vg_console.suggestion_select == -1 ){
-      char *target = &vg_console.input[ vg_console.suggestion_pastepos ];
-      strcpy( vg_console.input_copy, target );
-   }
-}
+   ui_rect rect_log   = { 0, 0,                vg.window_x, log_lines*fh },
+           rect_input = { 0, log_lines*fh + 1, vg.window_x, fh*2 },
+           rect_line  = { 0, 0,                vg.window_x, fh };
+       
+   /* 
+    * log
+    */
+   u32 bg_colour = (ui_colour( k_ui_bg )&0x00ffffff)|0x9f000000;
 
-VG_STATIC void _console_suggest_next(void)
-{
-   if( vg_console.suggestion_count ){
-      _console_suggest_store_normal();
+   ui_fill( rect_log, bg_colour );
+   rect_line[1] = rect_log[1]+rect_log[3]-fh;
 
-      vg_console.suggestion_select ++;
+   for( int i=0; i<console_lines; i ++ ){
+      ptr --;
 
-      if( vg_console.suggestion_select >= vg_console.suggestion_count )
-         vg_console.suggestion_select = -1;
+      if( ptr < 0 ) ptr = vg_list_size( vg_log.buffer )-1;
       
-      _console_fetch_suggestion();
+      ui_text( rect_line, vg_log.buffer[ptr], 1, k_ui_align_left, 0 );
+      rect_line[1] -= fh;
    }
-}
+       
+   /* 
+    * Input area 
+    */
+   vg_ui.textbuf_on_up = _vg_console_on_up;
+   vg_ui.textbuf_on_down = _vg_console_on_down;
+   vg_ui.textbuf_on_change = _vg_console_on_update;
+   vg_ui.textbuf_on_enter = _vg_console_on_enter;
+   ui_textbox( rect_input, vg_console.input, vg_list_size(vg_console.input),
+               UI_TEXTBOX_AUTOFOCUS );
 
-VG_STATIC void _console_suggest_prev(void)
-{
+   /* 
+    * suggestions 
+    */
    if( vg_console.suggestion_count ){
-      _console_suggest_store_normal();
+      ui_rect rect_suggest;
+      rect_copy( rect_input, rect_suggest );
 
-      vg_console.suggestion_select --;
-
-      if( vg_console.suggestion_select < -1 )
-         vg_console.suggestion_select = vg_console.suggestion_count-1;
-
-      _console_fetch_suggestion();
-   }
-}
+      rect_suggest[0] += 6 + UI_GLYPH_SPACING_X*vg_console.suggestion_pastepos;
+      rect_suggest[1] += rect_input[3];
+      rect_suggest[2]  = UI_GLYPH_SPACING_X * vg_console.suggestion_maxlen;
+      rect_suggest[3]  = vg_console.suggestion_count * fh;
 
-/*
- * Handles binds
- */
-VG_STATIC void console_proc_key( SDL_Keysym ev )
-{
-   /* Open / close console */
-   if( ev.sym == SDLK_BACKQUOTE ){
-      vg_console.enabled = !vg_console.enabled;
+      ui_fill( rect_suggest, bg_colour );
 
-      if( vg_console.enabled ){
-         vg_info( "SDL_StartTextInput()\n" );
-         SDL_StartTextInput();
-      }
-      else{
-         SDL_StopTextInput();
-      }
-   }
-   
-   if( !vg_console.enabled ) return;
+      rect_suggest[3] = fh;
 
-   struct console_mapping
-   {
-      u16 mod;
-      SDL_Keycode key;
-      
-      void (*handler)(void);
-   }
-   mappings[] =
-   {
-      { 0,              SDLK_LEFT,       _console_left              },
-      { KMOD_SHIFT,     SDLK_LEFT,       _console_left_select       },
-      { 0,              SDLK_RIGHT,      _console_right             },
-      { KMOD_SHIFT,     SDLK_RIGHT,      _console_right_select      },
-      { 0,              SDLK_DOWN,       _console_down              },
-      { 0,              SDLK_UP,         _console_up                },
-      { 0,              SDLK_BACKSPACE,  _console_backspace         },
-      { 0,              SDLK_DELETE,     _console_delete            },
-      { 0,              SDLK_HOME,       _console_home              },
-      { KMOD_SHIFT,     SDLK_HOME,       _console_home_select       },
-      { 0,              SDLK_END,        _console_end               },
-      { KMOD_SHIFT,     SDLK_END,        _console_end_select        },
-      { KMOD_CTRL,      SDLK_a,          _console_select_all        },
-      { KMOD_CTRL,      SDLK_c,          console_to_clipboard       },
-      { KMOD_CTRL,      SDLK_x,          _console_cut               },
-      { KMOD_CTRL,      SDLK_v,          console_clipboard_paste    },
-      { 0,              SDLK_RETURN,     _console_enter             },
-      { KMOD_CTRL,      SDLK_n,          _console_suggest_next      },
-      { KMOD_CTRL,      SDLK_p,          _console_suggest_prev      }
-   };
-
-   SDL_Keymod mod = 0;
-
-   if( ev.mod & KMOD_SHIFT )
-      mod |= KMOD_SHIFT;
-
-   if( ev.mod & KMOD_CTRL )
-      mod |= KMOD_CTRL;
-
-   if( ev.mod & KMOD_ALT )
-      mod |= KMOD_ALT;
-
-   for( int i=0; i<vg_list_size( mappings ); i++ ){
-      struct console_mapping *mapping = &mappings[i];
-
-      if( mapping->key == ev.sym ){
-         if( mapping->mod == 0 ){
-            if( mod == 0 ){
-               mapping->handler();
-               return;
-            }
+      for( int i=0; i<vg_console.suggestion_count; i ++ ){
+         u32 text_colour;
+         if( i == vg_console.suggestion_select ){
+            ui_fill( rect_suggest, ui_colour( k_ui_orange ) );
+            text_colour = ui_colourcont( k_ui_orange );
          }
-         else if( (mod & mapping->mod) == mapping->mod ){
-            mapping->handler();
-            return;
-         }
-      }
-   }
-}
+         else text_colour = ui_colourcont( k_ui_bg );
 
-/*
- * Callback for text entry mode
- */
-VG_STATIC void console_proc_utf8( const char *text )
-{
-   const char *ptr = text;
+         ui_text( rect_suggest, vg_console.suggestions[i].str, 1,
+                  k_ui_align_left, text_colour );
 
-   while( *ptr ){
-      if( *ptr != '`' ) 
-         console_put_char( *ptr );
-      ptr ++;
+         rect_suggest[1] += fh;
+      }
    }
 
-   console_update_suggestions();
+   SDL_AtomicUnlock( &log_print_sl );
 }
 
+
 #endif /* VG_CONSOLE_H */
index 2f84885e64b1a89f2ab7ee5103ad95c4cc78b202..bb98812f3d90a76148ea0bcedac79f1e6b91188b 100644 (file)
@@ -76,6 +76,10 @@ typedef u32 ui_scheme[8*4];
 
 #define UI_TEXTBOX_MULTILINE 0x1
 #define UI_TEXTBOX_WRAP      0x2
+#define UI_TEXTBOX_AUTOFOCUS 0x4
+#define UI_MOUSE_LEFT   (SDL_BUTTON(SDL_BUTTON_LEFT))
+#define UI_MOUSE_RIGHT  (SDL_BUTTON(SDL_BUTTON_RIGHT))
+#define UI_MOUSE_MIDDLE (SDL_BUTTON(SDL_BUTTON_MIDDLE))
 
 struct{
    struct ui_vert *vertex_buffer;
@@ -103,12 +107,18 @@ struct{
       u32 flags;
    }
    textbox;
+
+   void (*textbuf_on_enter) ( char *buf, u32 len );
+   void (*textbuf_on_up)    ( char *buf, u32 len );
+   void (*textbuf_on_down)  ( char *buf, u32 len );
+   void (*textbuf_on_change)( char *buf, u32 len );
        
        GLuint tex_glyphs, vao, vbo, ebo;
 
        ui_px mouse[2], mouse_click[2];
    u32 mouse_state[2];
    u32 ignore_input_frames;
+   int wants_mouse;
 
    ui_rect click_fader, click_fader_end;
    float click_fade_opacity;
@@ -420,6 +430,7 @@ VG_STATIC void ui_flush( enum ui_shader shader )
        glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, indice_offset, indice_size,
                     vg_ui.indice_buffer+vg_ui.indice_start );
        
+   glDisable( GL_DEPTH_TEST );
        glEnable( GL_BLEND );
        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
        glBlendEquation( GL_FUNC_ADD );
@@ -609,13 +620,11 @@ static ui_px ui_text_line_width( const char *str )
 {
    int length = 0;
    const char *_c = str;
-   char c;
+   u8 c;
 
    while( (c = *(_c ++)) ){
-      if( c >= 32 && c <= 126 )
-         length ++;
-      else if( c == '\n' )
-         break;
+      if( c >= 32 ) length ++;
+      else if( c == '\n' ) break;
    }
 
    return length * 8;
@@ -625,7 +634,7 @@ static ui_px ui_text_string_height( const char *str )
 {
    int height = 1;
    const char *_c = str;
-   char c;
+   u8 c;
 
    while( (c = *(_c ++)) ){
       if( c == '\n' ) height ++;
@@ -693,28 +702,27 @@ static int ui_inside_rect( ui_rect rect, ui_px co[2] )
       return 0;
 }
 
-static int ui_click_down(void)
+static int ui_click_down( u32 mask )
 {
    if( vg_ui.ignore_input_frames ) return 0;
-
-   if( (vg_ui.mouse_state[0] & SDL_BUTTON(SDL_BUTTON_LEFT)) &&
-      !(vg_ui.mouse_state[1] & SDL_BUTTON(SDL_BUTTON_LEFT)) )
+   if( (vg_ui.mouse_state[0] & mask) &&
+      !(vg_ui.mouse_state[1] & mask) )
       return 1;
    else
       return 0;
 }
 
-static int ui_clicking(void)
+static int ui_clicking( u32 mask )
 {
    if( vg_ui.ignore_input_frames ) return 0;
-   return vg_ui.mouse_state[0] & SDL_BUTTON(SDL_BUTTON_LEFT);
+   return vg_ui.mouse_state[0] & mask;
 }
 
-static int ui_click_up(void)
+static int ui_click_up( u32 mask )
 {
    if( vg_ui.ignore_input_frames ) return 0;
-   if( (vg_ui.mouse_state[1] & SDL_BUTTON(SDL_BUTTON_LEFT)) &&
-      !(vg_ui.mouse_state[0] & SDL_BUTTON(SDL_BUTTON_LEFT)) )
+   if( (vg_ui.mouse_state[1] & mask) &&
+      !(vg_ui.mouse_state[0] & mask) )
       return 1;
    else
       return 0;
@@ -734,13 +742,14 @@ static void ui_prerender(void)
    vg_ui.indice_start = 0;
    vg_ui.focused_control_hit = 0;
    vg_ui.cursor = k_ui_cursor_default;
+   vg_ui.wants_mouse = 0;
 
    if( vg_ui.ignore_input_frames ){
       vg_ui.ignore_input_frames --;
       return;
    }
 
-   if( ui_click_down() ){
+   if( ui_click_down(UI_MOUSE_LEFT)||ui_click_down(UI_MOUSE_MIDDLE) ){
       vg_ui.mouse_click[0] = vg_ui.mouse[0];
       vg_ui.mouse_click[1] = vg_ui.mouse[1];
    }
@@ -819,8 +828,7 @@ static u32 ui_ntext( ui_rect rect, const char *str, u32 len, ui_px scale,
          printed_chars = 0;
                        continue;
                }
-               else 
-         if( c >= 33 ){
+               else if( c >= 33 ){
                        u8 glyph_base[2];
                        u8 glyph_index = c;
                        glyph_base[0] = glyph_index & 0xf;
@@ -858,7 +866,7 @@ static u32 ui_ntext( ui_rect rect, const char *str, u32 len, ui_px scale,
                    case '3'|'4'<<8: colour = ui_colour( k_ui_blue ); break;
                    case '3'|'5'<<8: colour = ui_colour( k_ui_purple ); break;
                    case '3'|'6'<<8: colour = ui_colour( k_ui_aqua ); break;
-                   case '3'|'7'<<8: colour = ui_colour( 0xffffffff ); break;
+                   case '3'|'7'<<8: colour = 0xffffffff; break;
                                                }
 
                   colour &= 0x00ffffff;
@@ -900,7 +908,7 @@ static void ui_image( ui_rect rect, GLuint image )
 
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, image );
-   ui_fill_rect( rect, 0xffffffff, (ui_px[4]){ 0,0, 255,255 } );
+   ui_fill_rect( rect, 0xffffffff, (ui_px[4]){ 0,128, 128, 0 } );
    ui_flush( k_ui_shader_image );
 }
 
@@ -917,7 +925,6 @@ static u32 v4f_u32_colour( v4f colour )
 static void ui_defocus_all(void)
 {
    if( vg_ui.focused_control_type == k_ui_control_textbox ){
-      vg_info( "SDL_StopTextInput()\n" );
       SDL_StopTextInput();
    }
 
@@ -926,10 +933,10 @@ static void ui_defocus_all(void)
    vg_ui.focused_control_type = k_ui_control_none;
 }
 
-static int ui_button( ui_rect rect, enum ui_scheme_colour colour )
+static int ui_colourbutton( ui_rect rect, enum ui_scheme_colour colour )
 {
-   int clickup= ui_click_up(),
-       click  = ui_clicking() | clickup,
+   int clickup= ui_click_up(UI_MOUSE_LEFT),
+       click  = ui_clicking(UI_MOUSE_LEFT) | clickup,
        target = ui_inside_rect( rect, vg_ui.mouse_click ) && click,
        hover  = ui_inside_rect( rect, vg_ui.mouse );
 
@@ -985,16 +992,21 @@ static int ui_button( ui_rect rect, enum ui_scheme_colour colour )
    }
 }
 
-static int ui_button_text( ui_rect rect, const char *string, ui_px scale,
-                           enum ui_scheme_colour colour )
+static int ui_colourbutton_text( ui_rect rect, const char *string, ui_px scale,
+                                 enum ui_scheme_colour colour )
 {
-   int result = ui_button( rect, colour );
+   int result = ui_colourbutton( rect, colour );
    ui_rect t = { 0,0, ui_text_line_width( string )*scale, 14*scale };
    ui_rect_center( rect, t );
    ui_text( t, string, scale, k_ui_align_left, ui_colourcont(colour) );
    return result;
 }
 
+static int ui_button_text( ui_rect rect, const char *string, ui_px scale )
+{
+   return ui_colourbutton_text( rect, string, scale, k_ui_bg+4 );
+}
+
 static void ui_postrender(void)
 {
    if( vg_ui.click_fade_opacity > 0.0f ){
@@ -1026,12 +1038,19 @@ static void ui_postrender(void)
       ui_defocus_all();
    }
 
+   if( vg_ui.wants_mouse ){
+      SDL_SetWindowGrab( vg.window, SDL_FALSE );
+      SDL_SetRelativeMouseMode( SDL_FALSE );
+   }
+   else{
+      SDL_SetWindowGrab( vg.window, SDL_TRUE );
+      SDL_SetRelativeMouseMode( SDL_TRUE );
+   }
+
    SDL_SetCursor( vg_ui.cursor_map[ vg_ui.cursor ] );
    SDL_ShowCursor(1);
 }
 
-
-
 static void ui_dev_colourview(void)
 {
    ui_rect window = {vg.window_x-256,0,256,vg.window_y}, swatch;
@@ -1062,13 +1081,34 @@ static void ui_dev_colourview(void)
    }
 }
 
+/*
+ * checkbox
+ * -----------------------------------------------------------------------------
+ */
 
+static int ui_checkbox( ui_rect rect, const char *str_label, int *data )
+{
+   ui_rect label, box;
+   ui_split_px( rect, k_ui_axis_v, rect[2]-rect[3], 0, label, box );
+   ui_text( label, str_label, 1, k_ui_align_middle_left, 0 );
 
+   int changed = ui_colourbutton( box, k_ui_bg );
+   if( changed )
+      *data = (*data) ^ 0x1;
 
+   if( *data ){
+      ui_rect_pad( box, 4 );
+      ui_fill( box, ui_colour( k_ui_orange ) );
+   }
+
+   return changed;
+}
 
 /*
- * text box interface
+ * Textbox chaos
+ * -----------------------------------------------------------------------------
  */
+
 static void _ui_textbox_make_selection( int *start, int *end )
 {
        *start = VG_MIN( vg_ui.textbox.cursor_pos, vg_ui.textbox.cursor_user );
@@ -1225,7 +1265,9 @@ static void _ui_textbox_up(void)
       }
    }
    else{
-      
+      if( vg_ui.textbuf_on_up ){
+         vg_ui.textbuf_on_up( vg_ui.textbuf, vg_ui.textbox.len );
+      }
    }
 }
 
@@ -1278,7 +1320,9 @@ static void _ui_textbox_down(void)
       vg_ui.textbox.cursor_pos = line_below_begin+offset;
    }
    else{
-      
+      if( vg_ui.textbuf_on_down ){
+         vg_ui.textbuf_on_down( vg_ui.textbuf, vg_ui.textbox.len );
+      }
    }
 }
 
@@ -1297,14 +1341,24 @@ static void _ui_textbox_right(void)
 
 static void _ui_textbox_backspace(void)
 {
-   vg_ui.textbox.cursor_user = _ui_textbox_delete_char( -1 );
-   vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user;
+   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.textbuf_on_change )
+         vg_ui.textbuf_on_change( vg_ui.textbuf, vg_ui.textbox.len );
+   }
 }
 
 static void _ui_textbox_delete(void)
 {
-   vg_ui.textbox.cursor_user = _ui_textbox_delete_char( 1 );
-   vg_ui.textbox.cursor_pos = vg_ui.textbox.cursor_user;
+   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.textbuf_on_change )
+         vg_ui.textbuf_on_change( vg_ui.textbuf, vg_ui.textbox.len );
+   }
 }
 
 static void _ui_textbox_home_select(void)
@@ -1350,130 +1404,23 @@ static void _ui_textbox_enter(void)
          _ui_textbox_put_char( '\n' );
       }
       else{
-         ui_defocus_all();
+         if( !(vg_ui.textbox.flags & UI_TEXTBOX_AUTOFOCUS ) )
+            ui_defocus_all();
       }
-   }
-}
-
-/*
- * Handles binds
- */
-static void _ui_proc_key( SDL_Keysym ev )
-{
-   struct textbox_mapping
-   {
-      u16 mod;
-      SDL_Keycode key;
-      
-      void (*handler)(void);
-   }
-   mappings[] =
-   {
-      { 0,              SDLK_LEFT,       _ui_textbox_left              },
-      { KMOD_SHIFT,     SDLK_LEFT,       _ui_textbox_left_select       },
-      { 0,              SDLK_RIGHT,      _ui_textbox_right             },
-      { KMOD_SHIFT,     SDLK_RIGHT,      _ui_textbox_right_select      },
-      { 0,              SDLK_DOWN,       _ui_textbox_down              },
-      { 0,              SDLK_UP,         _ui_textbox_up                },
-      { 0,              SDLK_BACKSPACE,  _ui_textbox_backspace         },
-      { KMOD_SHIFT,     SDLK_BACKSPACE,  _ui_textbox_backspace         },
-      { KMOD_CTRL,      SDLK_BACKSPACE,  _ui_textbox_backspace         },
-      { 0,              SDLK_DELETE,     _ui_textbox_delete            },
-      { 0,              SDLK_HOME,       _ui_textbox_home              },
-      { KMOD_SHIFT,     SDLK_HOME,       _ui_textbox_home_select       },
-      { 0,              SDLK_END,        _ui_textbox_end               },
-      { KMOD_SHIFT,     SDLK_END,        _ui_textbox_end_select        },
-      { KMOD_CTRL,      SDLK_a,          _ui_textbox_select_all        },
-      { KMOD_CTRL,      SDLK_c,          _ui_textbox_to_clipboard      },
-      { KMOD_CTRL,      SDLK_x,          _ui_textbox_cut               },
-      { KMOD_CTRL,      SDLK_v,          _ui_textbox_clipboard_paste   },
-      { 0,              SDLK_RETURN,     _ui_textbox_enter             },
-#if 0
-      { KMOD_CTRL,      SDLK_n,          _ui_textbox_suggest_next      },
-      { KMOD_CTRL,      SDLK_p,          _ui_textbox_suggest_prev      }
-#endif
-      { 0,              SDLK_ESCAPE,     ui_defocus_all                },
-   };
-
-   if( vg_ui.focused_control_type == k_ui_control_none ){
-      return;
-   }
-
-   SDL_Keymod mod = 0;
-
-   if( ev.mod & KMOD_SHIFT )
-      mod |= KMOD_SHIFT;
-
-   if( ev.mod & KMOD_CTRL )
-      mod |= KMOD_CTRL;
-
-   if( ev.mod & KMOD_ALT )
-      mod |= KMOD_ALT;
-
-   for( int i=0; i<vg_list_size( mappings ); i++ ){
-      struct textbox_mapping *mapping = &mappings[i];
 
-      if( mapping->key == ev.sym ){
-         if( mapping->mod == 0 ){
-            if( mod == 0 ){
-               mapping->handler();
-               return;
-            }
-         }
-         else if( (mod & mapping->mod) == mapping->mod ){
-            mapping->handler();
-            return;
-         }
+      if( vg_ui.textbuf_on_enter ){
+         vg_ui.textbuf_on_enter( vg_ui.textbuf, vg_ui.textbox.len );
       }
    }
 }
 
-/*
- * Callback for text entry mode
+/* 
+ * based on a visual character coordinate relative to the anchor of the textbox, 
+ * this works out the linear place in the buffer that coordinate maps to
+ *
+ * input coordinates go in co[0], co[1], and the result index is in co[2]
  */
-VG_STATIC void ui_proc_utf8( const char *text )
-{
-   const char *ptr = text;
-
-   while( *ptr ){
-      if( *ptr != '`' ) _ui_textbox_put_char( *ptr );
-      ptr ++;
-   }
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-static void _ui_textbox_cursor_rect( ui_rect text_rect, ui_rect cursor )
-{
-   int start = VG_MIN( vg_ui.textbox.cursor_pos, vg_ui.textbox.cursor_user ),
-       end   = VG_MAX( vg_ui.textbox.cursor_pos, vg_ui.textbox.cursor_user );
-
-   cursor[0] = text_rect[0] + start*UI_GLYPH_SPACING_X-1;
-   cursor[1] = text_rect[1];
-   cursor[2] = start == end? 2: (float)(end-start)*(float)UI_GLYPH_SPACING_X;
-   cursor[3] = 14;
-}
-
-static void _ui_textbox_calc_index_from_grid( int co[3], int char_width )
+static void _ui_textbox_calc_index_from_grid( int co[3], int wrap_length )
 {
    int i[3] = {0,0,0};
 
@@ -1481,7 +1428,7 @@ static void _ui_textbox_calc_index_from_grid( int co[3], int char_width )
    while( (c = vg_ui.textbuf[i[2]]) ){
       if( i[1]==co[1] && i[0]>=co[0] ) break;
 
-      if( i[0] >= char_width ){
+      if( i[0] >= wrap_length ){
          i[1] ++;
          i[0] = 0;
       }
@@ -1506,8 +1453,11 @@ static void _ui_textbox_calc_index_from_grid( int co[3], int char_width )
    co[2] = i[2];
 }
 
-static 
-void _ui_textbox_index_calc_coords( int co[3], int char_width )
+/* 
+ * based on the index specied in co[2], work out the visual character
+ * coordinates and store them in co[0], co[1]
+ */
+static void _ui_textbox_index_calc_coords( int co[3], int wrap_length )
 {
    co[0] = 0;
    co[1] = 0;
@@ -1517,7 +1467,7 @@ void _ui_textbox_index_calc_coords( int co[3], int char_width )
 
    while( (c = vg_ui.textbuf[i ++]) ){
       if( i > co[2] ) break;
-      if( co[0] >= char_width ){
+      if( co[0] >= wrap_length ){
          co[1] ++;
          co[0] = 0;
       }
@@ -1529,12 +1479,19 @@ void _ui_textbox_index_calc_coords( int co[3], int char_width )
    }
 }
 
-static int _ui_textbox_run_remaining( int index[3], int char_width )
+/*
+ * calculate the number of characters remaining until either:
+ *    - the wrap_length limit is hit
+ *    - end of the line/string
+ *
+ * index must be fully populated with visual X/Y, and linear index
+ */
+static int _ui_textbox_run_remaining( int index[3], int wrap_length )
 {
    int i=0, printed_chars=0;
    char c;
    while( (c = vg_ui.textbuf[index[2] + (i ++)]) ){
-      if( index[0]+i >= char_width ) break;
+      if( index[0]+i >= wrap_length ) break;
       if( c >= 32 && c <= 126 ) printed_chars ++;
       else if( c == '\n' ) break;
    }
@@ -1544,8 +1501,8 @@ static int _ui_textbox_run_remaining( int index[3], int char_width )
 
 static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
 {
-   int clickup= ui_click_up(),
-       click  = ui_clicking() | clickup,
+   int clickup= ui_click_up(UI_MOUSE_LEFT),
+       click  = ui_clicking(UI_MOUSE_LEFT) | clickup,
        target = ui_inside_rect( rect, vg_ui.mouse_click ) && click,
        hover  = ui_inside_rect( rect, vg_ui.mouse );
 
@@ -1564,10 +1521,10 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
    text_rect[2] -= 16;
    ui_rect_center( rect, text_rect );
 
-   ui_px char_width = 1024;
+   ui_px wrap_length = 1024;
 
    if( flags & UI_TEXTBOX_WRAP ) 
-      char_width = text_rect[2] / UI_GLYPH_SPACING_X;
+      wrap_length = text_rect[2] / UI_GLYPH_SPACING_X;
 
    if( hover ){
       vg_ui.cursor = k_ui_cursor_ibeam;
@@ -1575,9 +1532,10 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
 
    if( vg_ui.focused_control_id == buf ){
       ui_fill( rect, col_base );
-      ui_ntext( text_rect, buf, char_width, 1, k_ui_align_left, 0 );
+      ui_ntext( text_rect, buf, wrap_length, 1, k_ui_align_left, 0 );
 
-      if( (clickup||ui_click_down()) && !target ){
+      if( !(flags & UI_TEXTBOX_AUTOFOCUS) && 
+           ((clickup||ui_click_down(UI_MOUSE_LEFT)) && !target) ){
          ui_defocus_all();
       }
       else{
@@ -1595,8 +1553,8 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
             };
 
             if( flags & UI_TEXTBOX_MULTILINE ){
-               _ui_textbox_calc_index_from_grid( p0, char_width );
-               _ui_textbox_calc_index_from_grid( p1, char_width );
+               _ui_textbox_calc_index_from_grid( p0, wrap_length );
+               _ui_textbox_calc_index_from_grid( p1, wrap_length );
 
                vg_ui.textbox.cursor_pos = p0[2];
                vg_ui.textbox.cursor_user = p1[2];
@@ -1623,7 +1581,7 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
             int pos[3], remaining = chars;
 
             pos[2] = start;
-            _ui_textbox_index_calc_coords( pos, char_width );
+            _ui_textbox_index_calc_coords( pos, wrap_length );
 
             if( start==end ){
                cursor[0] = text_rect[0] + pos[0]*UI_GLYPH_SPACING_X-1;
@@ -1636,9 +1594,9 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
             else{
                while( remaining ){
                   /* TODO: scan for newlines and stuff
-                   *       eol or char_width can have line breaks! */
+                   *       eol or wrap_length can have line breaks! */
 
-                  int run = _ui_textbox_run_remaining( pos, char_width );
+                  int run = _ui_textbox_run_remaining( pos, wrap_length );
                       run = VG_MIN( run, remaining );
 
                   cursor[0] = text_rect[0] + pos[0]*UI_GLYPH_SPACING_X-1;
@@ -1680,8 +1638,8 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
       return 0;
    }
 
-   if( click ){
-      if( target && hover ){
+   if( click || (flags & UI_TEXTBOX_AUTOFOCUS) ){
+      if( (target && hover) || (flags & UI_TEXTBOX_AUTOFOCUS) ){
          ui_defocus_all();
 
          ui_fill( rect, col_highlight );
@@ -1698,7 +1656,6 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
          vg_ui.textbox.cursor_pos = 0;
          vg_ui.textbox.cursor_user = 0;
 
-         vg_info( "SDL_StartTextInput()\n" );
          SDL_StartTextInput();
       }
    }
@@ -1709,8 +1666,101 @@ static int ui_textbox( ui_rect rect, char *buf, u32 len, u32 flags )
       ui_outline( rect, -1, col_highlight );
    }
 
-   ui_ntext( text_rect, buf, char_width, 1, k_ui_align_left, 0 );
+   ui_ntext( text_rect, buf, wrap_length, 1, k_ui_align_left, 0 );
    return 0;
 }
 
+/*
+ * Input handling
+ * -----------------------------------------------------------------------------
+ */
+
+/*
+ * Handles binds
+ */
+static void _ui_proc_key( SDL_Keysym ev )
+{
+   if( vg_ui.focused_control_type != k_ui_control_textbox ){
+      return;
+   }
+
+   struct textbox_mapping
+   {
+      u16 mod;
+      SDL_Keycode key;
+      
+      void (*handler)(void);
+   }
+   mappings[] =
+   {
+      { 0,              SDLK_LEFT,       _ui_textbox_left              },
+      { KMOD_SHIFT,     SDLK_LEFT,       _ui_textbox_left_select       },
+      { 0,              SDLK_RIGHT,      _ui_textbox_right             },
+      { KMOD_SHIFT,     SDLK_RIGHT,      _ui_textbox_right_select      },
+      { 0,              SDLK_DOWN,       _ui_textbox_down              },
+      { 0,              SDLK_UP,         _ui_textbox_up                },
+      { 0,              SDLK_BACKSPACE,  _ui_textbox_backspace         },
+      { KMOD_SHIFT,     SDLK_BACKSPACE,  _ui_textbox_backspace         },
+      { KMOD_CTRL,      SDLK_BACKSPACE,  _ui_textbox_backspace         },
+      { 0,              SDLK_DELETE,     _ui_textbox_delete            },
+      { 0,              SDLK_HOME,       _ui_textbox_home              },
+      { KMOD_SHIFT,     SDLK_HOME,       _ui_textbox_home_select       },
+      { 0,              SDLK_END,        _ui_textbox_end               },
+      { KMOD_SHIFT,     SDLK_END,        _ui_textbox_end_select        },
+      { KMOD_CTRL,      SDLK_a,          _ui_textbox_select_all        },
+      { KMOD_CTRL,      SDLK_c,          _ui_textbox_to_clipboard      },
+      { KMOD_CTRL,      SDLK_x,          _ui_textbox_cut               },
+      { KMOD_CTRL,      SDLK_v,          _ui_textbox_clipboard_paste   },
+      { 0,              SDLK_RETURN,     _ui_textbox_enter             },
+      { 0,              SDLK_ESCAPE,     ui_defocus_all                },
+   };
+
+   SDL_Keymod mod = 0;
+
+   if( ev.mod & KMOD_SHIFT )
+      mod |= KMOD_SHIFT;
+
+   if( ev.mod & KMOD_CTRL )
+      mod |= KMOD_CTRL;
+
+   if( ev.mod & KMOD_ALT )
+      mod |= KMOD_ALT;
+
+   for( int i=0; i<vg_list_size( mappings ); i++ ){
+      struct textbox_mapping *mapping = &mappings[i];
+
+      if( mapping->key == ev.sym ){
+         if( mapping->mod == 0 ){
+            if( mod == 0 ){
+               mapping->handler();
+               return;
+            }
+         }
+         else if( (mod & mapping->mod) == mapping->mod ){
+            mapping->handler();
+            return;
+         }
+      }
+   }
+}
+
+/*
+ * Callback for text entry mode
+ */
+VG_STATIC void ui_proc_utf8( const char *text )
+{
+   if( vg_ui.focused_control_type == k_ui_control_textbox ){
+      const char *ptr = text;
+
+      while( *ptr ){
+         if( *ptr != '`' ) _ui_textbox_put_char( *ptr );
+         ptr ++;
+      }
+
+      if( vg_ui.textbuf_on_change ){
+         vg_ui.textbuf_on_change( vg_ui.textbuf, vg_ui.textbox.len );
+      }
+   }
+}
+
 #endif /* VG_IMGUI_H */
diff --git a/vg_io.h b/vg_io.h
index 93525446094aa6a9ee3dac9ff9e0fad914b4673f..640ceaea12dd0397320c9cb143f1527b02641460 100644 (file)
--- a/vg_io.h
+++ b/vg_io.h
 #include <stdio.h>
 #include <errno.h>
 
+
 #define _TINYDIR_MALLOC(_size) vg_linear_alloc( vg_mem.scratch, _size )
 #define _TINYDIR_FREE(_size) 
 
 #include "submodules/tinydir/tinydir.h"
 
+#include <sys/stat.h>
+VG_STATIC int vg_mkdir( const char *path )
+{
+   if( mkdir( path, S_IRWXU|S_IRWXG|S_IWOTH|S_IXOTH ) ){
+      vg_error( "Failed to create directory: %s\n", path );
+      return 0;
+   }
+   else{
+      return 1;
+   }
+}
+
 /*
  * File I/O
  */
@@ -71,7 +84,6 @@ VG_STATIC void *vg_file_read( void *lin_alloc, const char *path, u32 *size )
                fclose( f );
 
       *size = (u32)current;
-      
       return buffer;
        }
        else{
@@ -110,4 +122,27 @@ VG_STATIC int vg_asset_write( const char *path, void *data, i64 size ){
        }
 }
 
+/* TODO: error handling if read fails */
+VG_STATIC int vg_file_copy( const char *src, const char *dst, void *lin_alloc )
+{
+   vg_info( "vg_file_copy( %s -> %s )\n", src, dst );
+   u32 size;
+   void *data = vg_file_read( lin_alloc, src, &size );
+   return vg_asset_write( dst, data, size );
+}
+
+VG_STATIC const char *vg_path_filename( const char *path )
+{
+   const char *base = path;
+   
+   for( int i=0; i<1024; i++ ){
+      if( path[i] == '\0' ) break;
+      if( path[i] == '/' ){
+         base = path+i+1;
+      }
+   }
+
+   return base;
+}
+
 #endif /* VG_IO_H */
index 3c519b57137bc99d19707c80b07c421e1c178079..ebd1d561cfa44e9cb9ed71a240827565a1ed4171 100644 (file)
@@ -12,7 +12,7 @@
 
 #include "common.h"
 
-VG_STATIC void vg_loader_start( void(*pfn)(void) );
+VG_STATIC void vg_loader_start( void(*pfn)(void *data), void *data );
 VG_STATIC void vg_loader_step( void( *fn_load )(void), void( *fn_free )(void) );
 
 static struct vg_shader _shader_loader = 
@@ -79,8 +79,7 @@ static struct vg_shader _shader_loader =
 static struct vg_loader
 {
    /* Shutdown steps */
-   struct loader_free_step
-   {
+   struct loader_free_step{
       void (*fn_free)(void);
    }
    step_buffer[16];
@@ -190,15 +189,15 @@ VG_STATIC void _vg_loader_render(void)
 
 VG_STATIC void vg_load_full(void);
 
-VG_STATIC int _vg_loader_thread(void *pfn)
+VG_STATIC int _vg_loader_thread( void *pfn )
 {
    if( setjmp( vg.env_loader_exit ) )
       return 0;
 
    /* Run client loader */
    vg_info( "Starting client loader thread @%p\n", pfn );
-   void (*call_func)(void) = pfn;
-   call_func();
+   void (*call_func)(void *data) = pfn;
+   call_func( vg.thread_data );
 
    SDL_SemPost( vg.sem_loader );
    vg.thread_id_loader = 0;
@@ -206,9 +205,11 @@ VG_STATIC int _vg_loader_thread(void *pfn)
    return 0;
 }
 
-VG_STATIC void vg_loader_start( void(*pfn)(void) )
+VG_STATIC void vg_loader_start( void(*pfn)(void *data), void *data )
 {
    SDL_SemWait( vg.sem_loader );
+
+   vg.thread_data = data;
    SDL_CreateThread( _vg_loader_thread, "Loader thread", pfn );
 }
 
index 52c26c0933fc67ecabb60b6bb2e5a772b6d50257..98612048aa6533c562fedf8cd0fef4da5e675695 100644 (file)
@@ -44,18 +44,21 @@ enum strncpy_behaviour{
    k_strncpy_allow_cutoff = 1
 };
 
-VG_STATIC void vg_strncpy( const char *src, char *dst, u32 len,
-                           enum strncpy_behaviour behaviour )
+VG_STATIC u32 vg_strncpy( const char *src, char *dst, u32 len,
+                          enum strncpy_behaviour behaviour )
 {
    for( u32 i=0; i<len; i++ ){
       dst[i] = src[i];
 
-      if( !src[i] )
-         break;
+      if( !src[i] ) return i;
 
-      if( (behaviour == k_strncpy_always_add_null) && (i == len-1) )
+      if( (behaviour == k_strncpy_always_add_null) && (i == len-1) ){
          dst[i] = '\0';
+         return i;
+      }
    }
+
+   return 0;
 }
 
 VG_STATIC u32 vg_strdjb2( const char *str )
index 9f5d7c6dea1a078aa05d798b0ec93ceb31d6807c..0ff18e11ea4052dca294ff1f3fce07f30ec142d8 100644 (file)
 0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,
-0x400000,0,0,0,0,0,0,0,
-0x800000,0,0,0,0,0,0,0,
-0x1000000,0,0,0,0,0,0,0,
-0x1000000,0,0,0,0,0,0,0,
-0x1000000,0,0,0,0,0,0,0,
-0xe00000,0,0,0,0,0,0,0,
-0,0,0,0,0,0,0,0,
+0x400070,0,0,0,0,0,0,0,
+0x800730,0,0,0,0,0,0,0,
+0x1000450,0,0,0,0,0,0,0,
+0x1000480,0,0,0,0,0,0,0,
+0x1000420,0,0,0,0,0,0,0,
+0xe00420,0,0,0,0,0,0,0,
+0x7e0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,
 0,0,0,0,0,0,0,0,
index b39da94fb1c0122aa06a843bf0c531ba11f7033f..01c448acf076f6ae33826c91b85d479768b9fd3a 100644 (file)
@@ -40,6 +40,7 @@ typedef u32 DepotId_t;
 const DepotId_t k_uDepotIdInvalid = 0x0;
 
 typedef u32 RTime32;
+typedef u32 AccountID_t;
 
 enum { k_iSteamUserCallbacks = 100 };
 enum { k_iSteamGameServerCallbacks = 200 };
@@ -56,7 +57,7 @@ enum { k_iSteamNetworkingCallbacks = 1200 };
 enum { k_iSteamNetworkingSocketsCallbacks = 1220 };
 enum { k_iSteamNetworkingMessagesCallbacks = 1250 };
 enum { k_iSteamNetworkingUtilsCallbacks = 1280 };
-enum { k_iClientRemoteStorageCallbacks = 1300 };
+enum { k_iSteamRemoteStorageCallbacks = 1300 };
 enum { k_iClientDepotBuilderCallbacks = 1400 };
 enum { k_iSteamGameServerItemsCallbacks = 1500 };
 enum { k_iClientUtilsCallbacks = 1600 };
@@ -78,6 +79,7 @@ enum { k_iClientNetworkDeviceManagerCallbacks = 3100 };
 enum { k_iClientMusicCallbacks = 3200 };
 enum { k_iClientRemoteClientManagerCallbacks = 3300 };
 enum { k_iClientUGCCallbacks = 3400 };
+enum { k_iSteamUGCCallbacks = 3400 };
 enum { k_iSteamStreamClientCallbacks = 3500 };
 enum { k_IClientProductBuilderCallbacks = 3600 };
 enum { k_iClientShortcutsCallbacks = 3700 };
@@ -453,27 +455,37 @@ u64  SteamGameServer_GetSteamID(void);
  * Async callbacks
  * =============================================================================
  */
-typedef struct steam_async steam_async;
-struct steam_async
-{
-   SteamAPICall_t id;
-   void *data;
 
-   void (*p_handler)( void *result, void *userdata );
+typedef struct vg_steam_async_call vg_steam_async_call;
+typedef struct vg_steam_callback_handler vg_steam_callback_handler;
+
+struct vg_steam{
+   struct vg_steam_async_call{
+      SteamAPICall_t id;
+      void *userdata;
+
+      void (*p_handler)( void *result, void *userdata );
+   }
+   calls[4];
+   u32 call_count;
+
+   struct vg_steam_callback_handler{
+      u32 callback_id;
+      void (*p_handler)( CallbackMsg_t *msg );
+   }
+   callback_handlers[32];
+   u32 callback_handler_count;
 }
-static steam_async_trackers[32];
-static u32 steam_async_track_count;
+static vg_steam;
 
-steam_async *steam_new_async(void)
+vg_steam_async_call *vg_alloc_async_steam_api_call(void)
 {
-   if( steam_async_track_count == vg_list_size(steam_async_trackers) )
-   {
-      vg_error( "Maximum concurrent API calls exceeded (%u)\n",
-                steam_async_track_count );
-      return NULL;
+   if( vg_steam.call_count == vg_list_size(vg_steam.calls) ){
+      vg_fatal_error( "Maximum concurrent API calls exceeded (%u)\n",
+                      vg_steam.call_count );
    }
 
-   return &steam_async_trackers[ steam_async_track_count ++ ];
+   return &vg_steam.calls[ vg_steam.call_count ++ ];
 }
 
 /*
@@ -481,33 +493,21 @@ steam_async *steam_new_async(void)
  * =============================================================================
  */
 
-typedef struct steam_callback_handler steam_callback_handler;
-struct steam_callback_handler
-{
-   u32 callback_id;
-   void (*p_handler)( CallbackMsg_t *msg );
-}
-static steam_callback_handlers[64];
-static u32 steam_callback_handler_count;
-
-static int steam_register_callback( u32 id, 
-                                    void (*p_handler)( CallbackMsg_t *msg ) )
+static void steam_register_callback( u32 id, 
+                                     void (*p_handler)( CallbackMsg_t *msg ) )
 {
-   if( steam_callback_handler_count == vg_list_size(steam_callback_handlers) )
+   if( vg_steam.callback_handler_count == 
+       vg_list_size(vg_steam.callback_handlers) )
    {
-      vg_error( "Too many steam callback handlers registered (%u)\n", 
-                  steam_callback_handler_count );
-
-      return 0;
+      vg_fatal_error( "Too many steam callback handlers registered (%u)\n", 
+                      vg_steam.callback_handler_count );
    }
    
-   steam_callback_handler *handler = &steam_callback_handlers[
-      steam_callback_handler_count ++ ];
+   vg_steam_callback_handler *handler = 
+      &vg_steam.callback_handlers[ vg_steam.callback_handler_count ++ ];
 
    handler->p_handler = p_handler;
    handler->callback_id = id;
-   
-   return 1;
 }
 
 /*
@@ -535,13 +535,12 @@ static void steamworks_process_api_call( HSteamPipe pipe,
       (SteamAPICallCompleted_t *)callback->m_pubParam;
 
    int bFailed;
-
-   void *temp = alloca( pCallCompleted->m_cubParam );
+   void *call_data = alloca( pCallCompleted->m_cubParam );
    
    if( SteamAPI_ManualDispatch_GetAPICallResult( 
       pipe,
       pCallCompleted->m_hAsyncCall, 
-      temp,
+      call_data,
       pCallCompleted->m_cubParam, 
       pCallCompleted->m_iCallback, 
       &bFailed ) 
@@ -553,28 +552,24 @@ static void steamworks_process_api_call( HSteamPipe pipe,
        */
       
       vg_info( "steamworks_event::api_call_completed( %lu )\n", 
-            pCallCompleted->m_hAsyncCall );
+                  pCallCompleted->m_hAsyncCall );
       
       int j=0;
-      for( int i=0; i<steam_async_track_count; i++ )
-      {
-         if( steam_async_trackers[j].id != pCallCompleted->m_hAsyncCall )
-         {
-            steam_async_trackers[j ++] = steam_async_trackers[i];
+      for( int i=0; i<vg_steam.call_count; i++ ){
+         if( vg_steam.calls[i].id != pCallCompleted->m_hAsyncCall ){
+            vg_steam.calls[j ++] = vg_steam.calls[i];
          }
-         else
-         {
-            steam_async *pasync = &steam_async_trackers[j];
-            pasync->p_handler( temp, pasync->data );
+         else{
+            vg_steam_async_call *call = &vg_steam.calls[i];
+            call->p_handler( call_data, call->userdata );
          }
       }
 
-      if( steam_async_track_count == j )
-      {
+      if( vg_steam.call_count == j ){
          vg_error( "No tracker was register for API call\n" );
       }
 
-      steam_async_track_count = j;
+      vg_steam.call_count = j;
    } 
    else 
    { 
@@ -605,28 +600,23 @@ static void steamworks_event_loop( HSteamPipe pipe )
        SteamAPI_ManualDispatch_RunFrame( pipe );
        CallbackMsg_t callback;
        
-       while( SteamAPI_ManualDispatch_GetNextCallback( pipe, &callback ) )
-       {
+       while( SteamAPI_ManualDispatch_GetNextCallback( pipe, &callback ) ){
                vg_low( "steamworks_event::callback( %i )\n", callback.m_iCallback );
        
                /* Check for dispatching API call results */
-               if( callback.m_iCallback == k_iSteamAPICallCompleted )
-      {
+               if( callback.m_iCallback == k_iSteamAPICallCompleted ){
          steamworks_process_api_call( pipe, &callback );
                } 
-               else 
-               {
+               else {
                        /* 
           * Look at callback.m_iCallback to see what kind of callback it is,
                         * and dispatch to appropriate handler(s)
                         * void *data = callback.m_pubParam;
           */
 
-         for( int i=0; i<steam_callback_handler_count; i++ )
-         {
-            steam_callback_handler *handler = &steam_callback_handlers[i];
-            if( handler->callback_id == callback.m_iCallback )
-            {
+         for( int i=0; i<vg_steam.callback_handler_count; i++ ){
+            vg_steam_callback_handler *handler = &vg_steam.callback_handlers[i];
+            if( handler->callback_id == callback.m_iCallback ){
                handler->p_handler( &callback );
                break;
             }
diff --git a/vg_steam_remote_storage.h b/vg_steam_remote_storage.h
new file mode 100644 (file)
index 0000000..7d92cce
--- /dev/null
@@ -0,0 +1,424 @@
+#ifndef VG_STEAM_REMOTE_STORAGE_H
+#define VG_STEAM_REMOTE_STORAGE_H
+
+#include "vg/vg_steam.h"
+
+const u32 k_unMaxCloudFileChunkSize = 100 * 1024 * 1024;
+
+#if defined( VALVE_CALLBACK_PACK_SMALL )
+#pragma pack( push, 4 )
+#elif defined( VALVE_CALLBACK_PACK_LARGE )
+#pragma pack( push, 8 )
+#else
+#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx
+#endif 
+typedef struct SteamParamStringArray_t SteamParamStringArray_t;
+struct SteamParamStringArray_t{
+   const char **m_ppStrings;
+   i32 m_nNumStrings;
+};
+#pragma pack( pop )
+
+/* A handle to a piece of user generated content */
+typedef u64 UGCHandle_t;
+typedef u64 PublishedFileUpdateHandle_t;
+typedef u64 PublishedFileId_t;
+const PublishedFileId_t k_PublishedFileIdInvalid = 0;
+const UGCHandle_t k_UGCHandleInvalid = 0xffffffffffffffffull;
+const PublishedFileUpdateHandle_t 
+k_PublishedFileUpdateHandleInvalid = 0xffffffffffffffffull;
+
+/* Handle for writing to Steam Cloud */
+typedef u64 UGCFileWriteStreamHandle_t;
+const UGCFileWriteStreamHandle_t 
+k_UGCFileStreamHandleInvalid = 0xffffffffffffffffull;
+
+enum{ k_cchPublishedDocumentTitleMax = 128 + 1 };
+enum{ k_cchPublishedDocumentDescriptionMax = 8000 };
+enum{ k_cchPublishedDocumentChangeDescriptionMax = 8000 };
+enum{ k_unEnumeratePublishedFilesMaxResults = 50 };
+enum{ k_cchTagListMax = 1024 + 1 };
+enum{ k_cchFilenameMax = 260 };
+enum{ k_cchPublishedFileURLMax = 256 };
+
+typedef enum ERemoteStoragePlatform ERemoteStoragePlatform;
+enum ERemoteStoragePlatform{
+   k_ERemoteStoragePlatformNone        = 0,
+   k_ERemoteStoragePlatformWindows     = (1 << 0),
+   k_ERemoteStoragePlatformOSX         = (1 << 1),
+   k_ERemoteStoragePlatformPS3         = (1 << 2),
+   k_ERemoteStoragePlatformLinux       = (1 << 3),
+   k_ERemoteStoragePlatformSwitch      = (1 << 4),
+   k_ERemoteStoragePlatformAndroid     = (1 << 5),
+   k_ERemoteStoragePlatformIOS         = (1 << 6),
+   
+   /* NB we get one more before we need to widen some things */
+   k_ERemoteStoragePlatformAll = 0xffffffff
+};
+
+typedef enum ERemoteStoragePublishedFileVisibility
+             ERemoteStoragePublishedFileVisibility;
+enum ERemoteStoragePublishedFileVisibility{
+   k_ERemoteStoragePublishedFileVisibilityPublic = 0,
+   k_ERemoteStoragePublishedFileVisibilityFriendsOnly = 1,
+   k_ERemoteStoragePublishedFileVisibilityPrivate = 2,
+   k_ERemoteStoragePublishedFileVisibilityUnlisted = 3,
+};
+
+
+typedef enum EWorkshopFileType EWorkshopFileType;
+enum EWorkshopFileType{
+   k_EWorkshopFileTypeFirst = 0,
+   k_EWorkshopFileTypeCommunity = 0,
+   k_EWorkshopFileTypeMicrotransaction = 1,
+   k_EWorkshopFileTypeCollection = 2,
+   k_EWorkshopFileTypeArt = 3,
+   k_EWorkshopFileTypeVideo = 4,
+   k_EWorkshopFileTypeScreenshot = 5,
+   k_EWorkshopFileTypeGame = 6,
+   k_EWorkshopFileTypeSoftware = 7,
+   k_EWorkshopFileTypeConcept = 8,
+   k_EWorkshopFileTypeWebGuide = 9,
+   k_EWorkshopFileTypeIntegratedGuide = 10,
+   k_EWorkshopFileTypeMerch = 11,
+   k_EWorkshopFileTypeControllerBinding = 12,
+   k_EWorkshopFileTypeSteamworksAccessInvite = 13,
+   k_EWorkshopFileTypeSteamVideo = 14,
+   k_EWorkshopFileTypeGameManagedItem = 15,
+   k_EWorkshopFileTypeMax = 16
+};
+
+typedef enum EWorkshopVote EWorkshopVote;
+enum EWorkshopVote{
+   k_EWorkshopVoteUnvoted = 0,
+   k_EWorkshopVoteFor = 1,
+   k_EWorkshopVoteAgainst = 2,
+   k_EWorkshopVoteLater = 3,
+};
+
+typedef enum EWorkshopFileAction EWorkshopFileAction;
+enum EWorkshopFileAction{
+   k_EWorkshopFileActionPlayed = 0,
+   k_EWorkshopFileActionCompleted = 1,
+};
+
+typedef enum EWorkshopEnumerationType EWorkshopEnumerationType;
+enum EWorkshopEnumerationType{
+   k_EWorkshopEnumerationTypeRankedByVote = 0,
+   k_EWorkshopEnumerationTypeRecent = 1,
+   k_EWorkshopEnumerationTypeTrending = 2,
+   k_EWorkshopEnumerationTypeFavoritesOfFriends = 3,
+   k_EWorkshopEnumerationTypeVotedByFriends = 4,
+   k_EWorkshopEnumerationTypeContentByFriends = 5,
+   k_EWorkshopEnumerationTypeRecentFromFollowedUsers = 6,
+};
+
+typedef enum EWorkshopVideoProvider EWorkshopVideoProvider;
+enum EWorkshopVideoProvider{
+   k_EWorkshopVideoProviderNone = 0,
+   k_EWorkshopVideoProviderYoutube = 1
+};
+
+typedef enum EUGCReadAction EUGCReadAction;
+enum EUGCReadAction{
+   k_EUGCRead_ContinueReadingUntilFinished = 0,
+   k_EUGCRead_ContinueReading = 1,
+   k_EUGCRead_Close = 2,   
+};
+
+typedef enum ERemoteStorageLocalFileChange ERemoteStorageLocalFileChange;
+enum ERemoteStorageLocalFileChange{
+   k_ERemoteStorageLocalFileChange_Invalid = 0,
+   k_ERemoteStorageLocalFileChange_FileUpdated = 1,
+   k_ERemoteStorageLocalFileChange_FileDeleted = 2,
+};
+
+typedef enum ERemoteStorageFilePathType ERemoteStorageFilePathType;
+enum ERemoteStorageFilePathType{
+   k_ERemoteStorageFilePathType_Invalid = 0,
+   k_ERemoteStorageFilePathType_Absolute = 1,
+   k_ERemoteStorageFilePathType_APIFilename = 2,
+};
+
+#define STEAMREMOTESTORAGE_INTERFACE_VERSION \
+            "STEAMREMOTESTORAGE_INTERFACE_VERSION016"
+
+#if defined( VALVE_CALLBACK_PACK_SMALL )
+#pragma pack( push, 4 )
+#elif defined( VALVE_CALLBACK_PACK_LARGE )
+#pragma pack( push, 8 )
+#else
+#error steam_api_common.h should define VALVE_CALLBACK_PACK_xxx
+#endif 
+
+typedef struct RemoteStorageFileShareResult_t RemoteStorageFileShareResult_t;
+struct RemoteStorageFileShareResult_t{
+   EResult m_eResult;
+   UGCHandle_t m_hFile;
+   char m_rgchFilename[k_cchFilenameMax];
+};
+enum { k_iRemoteStorageFileShareResult = k_iSteamRemoteStorageCallbacks + 7 };
+
+typedef struct RemoteStoragePublishFileResult_t 
+               RemoteStoragePublishFileResult_t;
+struct RemoteStoragePublishFileResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   int m_bUserNeedsToAcceptWorkshopLegalAgreement;
+};
+enum { k_iRemoteStoragePublushFileResult = k_iSteamRemoteStorageCallbacks + 9 };
+
+typedef struct RemoteStorageDeletePublishedFileResult_t 
+               RemoteStorageDeletePublishedFileResult_t;
+struct RemoteStorageDeletePublishedFileResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iRemoteStorageDeletePublishedFileResult = 
+         k_iSteamRemoteStorageCallbacks + 11 };
+
+typedef struct RemoteStorageEnumerateUserPublishedFilesResult_t
+               RemoteStorageEnumerateUserPublishedFilesResult_t;
+struct RemoteStorageEnumerateUserPublishedFilesResult_t{
+   EResult m_eResult;
+   i32 m_nResultsReturned;
+   i32 m_nTotalResultCount;
+   PublishedFileId_t m_rgPublishedFileId[k_unEnumeratePublishedFilesMaxResults];
+};
+enum { k_iRemoteStorageEnumerateUserPublishedFilesResult = 
+         k_iSteamRemoteStorageCallbacks + 12 };
+
+typedef struct RemoteStorageSubscribePublishedFileResult_t 
+               RemoteStorageSubscribePublishedFileResult_t;
+struct RemoteStorageSubscribePublishedFileResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iRemoteStorageSubscribePublishedFileResult = 
+         k_iSteamRemoteStorageCallbacks + 13 };
+
+
+typedef struct RemoteStorageEnumerateUserSubscribedFilesResult_t
+               RemoteStorageEnumerateUserSubscribedFilesResult_t;
+struct RemoteStorageEnumerateUserSubscribedFilesResult_t{
+   EResult m_eResult;
+   i32 m_nResultsReturned;
+   i32 m_nTotalResultCount;
+   PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ];
+   u32 m_rgRTimeSubscribed[ k_unEnumeratePublishedFilesMaxResults ];
+};
+enum { k_iRemoteStorageEnumerateUserSubscribedFilesResult = 
+         k_iSteamRemoteStorageCallbacks + 14 };
+
+typedef struct RemoteStorageUnsubscribePublishedFileResult_t
+               RemoteStorageUnsubscribePublishedFileResult_t;
+struct RemoteStorageUnsubscribePublishedFileResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iRemoteStorageUnsubscribePublishedFileResult = 
+   k_iSteamRemoteStorageCallbacks + 15 };
+
+typedef struct RemoteStorageUpdatePublishedFileResult_t
+               RemoteStorageUpdatePublishedFileResult_t;
+struct RemoteStorageUpdatePublishedFileResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   int m_bUserNeedsToAcceptWorkshopLegalAgreement;
+};
+enum { k_iRemoteStorageUpdatePublishedFileResult = 
+   k_iSteamRemoteStorageCallbacks + 16 };
+
+
+typedef struct RemoteStorageDownloadUGCResult_t 
+               RemoteStorageDownloadUGCResult_t;
+struct RemoteStorageDownloadUGCResult_t{
+   EResult m_eResult;
+   UGCHandle_t m_hFile;
+   AppId_t m_nAppID;
+   i32 m_nSizeInBytes;
+   char m_pchFileName[k_cchFilenameMax];
+   u64 m_ulSteamIDOwner;
+};
+enum { k_iRemoteStorageDownloadUGCResult = 
+   k_iSteamRemoteStorageCallbacks + 17 };
+
+
+typedef struct RemoteStorageGetPublishedFileDetailsResult_t
+               RemoteStorageGetPublishedFileDetailsResult_t;
+struct RemoteStorageGetPublishedFileDetailsResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nCreatorAppID;
+   AppId_t m_nConsumerAppID;
+   char m_rgchTitle[k_cchPublishedDocumentTitleMax];
+   char m_rgchDescription[k_cchPublishedDocumentDescriptionMax];
+   UGCHandle_t m_hFile;
+   UGCHandle_t m_hPreviewFile;
+   u64 m_ulSteamIDOwner;
+   u32 m_rtimeCreated;
+   u32 m_rtimeUpdated;
+   ERemoteStoragePublishedFileVisibility m_eVisibility;
+   int m_bBanned;
+   char m_rgchTags[k_cchTagListMax];
+   int m_bTagsTruncated;
+   char m_pchFileName[k_cchFilenameMax];
+   i32 m_nFileSize;
+   i32 m_nPreviewFileSize;
+   char m_rgchURL[k_cchPublishedFileURLMax];
+   EWorkshopFileType m_eFileType;
+   int m_bAcceptedForUse;
+};
+enum { k_iRemoteStorageGetPublishedFileDetailsResult = 
+   k_iSteamRemoteStorageCallbacks + 18 };
+
+typedef struct RemoteStorageEnumerateWorkshopFilesResult_t
+               RemoteStorageEnumerateWorkshopFilesResult_t;
+struct RemoteStorageEnumerateWorkshopFilesResult_t{
+   EResult m_eResult;
+   i32 m_nResultsReturned;
+   i32 m_nTotalResultCount;
+   PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ];
+   float m_rgScore[ k_unEnumeratePublishedFilesMaxResults ];
+   AppId_t m_nAppId;
+   u32 m_unStartIndex;
+};
+enum { k_iRemoteStorageEnumerateWorkshopFilesResult_t = 
+   k_iSteamRemoteStorageCallbacks + 19 };
+
+
+typedef struct RemoteStorageGetPublishedItemVoteDetailsResult_t
+               RemoteStorageGetPublishedItemVoteDetailsResult_t;
+struct RemoteStorageGetPublishedItemVoteDetailsResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_unPublishedFileId;
+   i32 m_nVotesFor;
+   i32 m_nVotesAgainst;
+   i32 m_nReports;
+   float m_fScore;
+};
+enum { k_iRemoteStorageGetPublishedItemVoteDetailsResult_t = 
+   k_iSteamRemoteStorageCallbacks + 20 };
+
+
+typedef struct RemoteStoragePublishedFileSubscribed_t
+               RemoteStoragePublishedFileSubscribed_t;
+struct RemoteStoragePublishedFileSubscribed_t{
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nAppID;
+};
+enum { k_iRemoteStoragePublishedFileSubscribed_t = 
+   k_iSteamRemoteStorageCallbacks + 21 };
+
+typedef struct RemoteStoragePublishedFileUnsubscribed_t
+               RemoteStoragePublishedFileUnsubscribed_t;
+struct RemoteStoragePublishedFileUnsubscribed_t{
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nAppID;
+};
+enum { k_iRemoteStoragePublishedFileUnsubscribed_t = 
+   k_iSteamRemoteStorageCallbacks + 22 };
+
+
+typedef struct RemoteStoragePublishedFileDeleted_t
+               RemoteStoragePublishedFileDeleted_t;
+struct RemoteStoragePublishedFileDeleted_t{
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nAppID;
+};
+enum { k_iRemoteStoragePublishedFileDeleted_t = 
+   k_iSteamRemoteStorageCallbacks + 23 };
+
+typedef struct RemoteStorageUpdateUserPublishedItemVoteResult_t
+               RemoteStorageUpdateUserPublishedItemVoteResult_t;
+struct RemoteStorageUpdateUserPublishedItemVoteResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iRemoteStorageUpdateUserPublishedItemVoteResult_t = 
+   k_iSteamRemoteStorageCallbacks + 24 };
+
+typedef struct RemoteStorageUserVoteDetails_t RemoteStorageUserVoteDetails_t;
+struct RemoteStorageUserVoteDetails_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   EWorkshopVote m_eVote;
+};
+enum { k_iRemoteStorageUserVoteDetails_t = 
+   k_iSteamRemoteStorageCallbacks + 25 };
+
+typedef struct RemoteStorageEnumerateUserSharedWorkshopFilesResult_t
+               RemoteStorageEnumerateUserSharedWorkshopFilesResult_t;
+struct RemoteStorageEnumerateUserSharedWorkshopFilesResult_t{
+   EResult m_eResult;
+   i32 m_nResultsReturned;
+   i32 m_nTotalResultCount;
+   PublishedFileId_t m_rgPublishedFileId[k_unEnumeratePublishedFilesMaxResults];
+};
+enum { k_iRemoteStorageEnumerateUserSharedWorkshopFilesResult_t = 
+   k_iSteamRemoteStorageCallbacks + 26 };
+
+typedef struct RemoteStorageSetUserPublishedFileActionResult_t
+               RemoteStorageSetUserPublishedFileActionResult_t;
+struct RemoteStorageSetUserPublishedFileActionResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   EWorkshopFileAction m_eAction;
+};
+enum { k_iRemoteStorageSetUserPublishedFileActionResult_t = 
+   k_iSteamRemoteStorageCallbacks + 27 };
+
+typedef struct RemoteStorageEnumeratePublishedFilesByUserActionResult_t
+               RemoteStorageEnumeratePublishedFilesByUserActionResult_t;
+struct RemoteStorageEnumeratePublishedFilesByUserActionResult_t{
+   EResult m_eResult;
+   EWorkshopFileAction m_eAction;
+   i32 m_nResultsReturned;
+   i32 m_nTotalResultCount;
+   PublishedFileId_t m_rgPublishedFileId[ k_unEnumeratePublishedFilesMaxResults ];
+   u32 m_rgRTimeUpdated[ k_unEnumeratePublishedFilesMaxResults ];
+};
+enum { k_iRemoteStorageEnumeratePublishedFilesByUserActionResult_t = 
+   k_iSteamRemoteStorageCallbacks + 28 };
+
+typedef struct RemoteStoragePublishFileProgress_t
+               RemoteStoragePublishFileProgress_t;
+struct RemoteStoragePublishFileProgress_t{
+   double m_dPercentFile;
+   int m_bPreview;
+};
+enum { k_iRemoteStoragePublishFileProgress_t = 
+   k_iSteamRemoteStorageCallbacks + 29 };
+
+typedef struct RemoteStoragePublishedFileUpdated_t
+               RemoteStoragePublishedFileUpdated_t;
+struct RemoteStoragePublishedFileUpdated_t{
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nAppID;
+   u64 m_ulUnused;
+};
+enum { k_iRemoteStoragePublishedFileUpdated_t = 
+   k_iSteamRemoteStorageCallbacks + 30 };
+
+typedef struct RemoteStorageFileWriteAsyncComplete_t
+               RemoteStorageFileWriteAsyncComplete_t;
+struct RemoteStorageFileWriteAsyncComplete_t{
+   EResult m_eResult;
+};
+enum { k_iRemoteStorageFileWriteAsyncComplete_t = 
+   k_iSteamRemoteStorageCallbacks + 31 };
+
+typedef struct RemoteStorageFileReadAsyncComplete_t
+               RemoteStorageFileReadAsyncComplete_t;
+struct RemoteStorageFileReadAsyncComplete_t{
+   SteamAPICall_t m_hFileReadAsync;
+   EResult m_eResult;
+   u32 m_nOffset;
+   u32 m_cubRead;
+};
+enum { k_iRemoteStorageFileReadAsyncComplete_t =
+   k_iSteamRemoteStorageCallbacks + 32 };
+
+#pragma pack( pop )
+
+#endif /* VG_STEAM_REMOTE_STORAGE_H */
diff --git a/vg_steam_ugc.h b/vg_steam_ugc.h
new file mode 100644 (file)
index 0000000..5204192
--- /dev/null
@@ -0,0 +1,778 @@
+#ifndef VG_STEAM_UGC_H
+#define VG_STEAM_UGC_H
+
+#include "vg_steam.h"
+#include "vg_steam_remote_storage.h"
+
+#if defined( VALVE_CALLBACK_PACK_SMALL )
+ ;
+ #pragma pack( push, 4 )
+#elif defined( VALVE_CALLBACK_PACK_LARGE )
+ #pragma pack( push, 8 )
+#endif 
+
+typedef void ISteamUGC;
+typedef u64 UGCQueryHandle_t;
+typedef u64 UGCUpdateHandle_t;
+
+const UGCQueryHandle_t k_UGCQueryHandleInvalid = 0xffffffffffffffffull;
+const UGCUpdateHandle_t k_UGCUpdateHandleInvalid = 0xffffffffffffffffull;
+
+/* Matching UGC types for queries */
+typedef enum EUGCMatchingUGCType EUGCMatchingUGCType;
+enum EUGCMatchingUGCType{
+   /* both mtx items and ready-to-use items */
+   k_EUGCMatchingUGCType_Items            = 0,      
+   k_EUGCMatchingUGCType_Items_Mtx        = 1,
+   k_EUGCMatchingUGCType_Items_ReadyToUse = 2,
+   k_EUGCMatchingUGCType_Collections      = 3,
+   k_EUGCMatchingUGCType_Artwork          = 4,
+   k_EUGCMatchingUGCType_Videos           = 5,
+   k_EUGCMatchingUGCType_Screenshots      = 6,
+   
+   /* both web guides and integrated guides */
+   k_EUGCMatchingUGCType_AllGuides        = 7,
+   k_EUGCMatchingUGCType_WebGuides        = 8,
+   k_EUGCMatchingUGCType_IntegratedGuides = 9,
+   
+   /* ready-to-use items and integrated guides */
+   k_EUGCMatchingUGCType_UsableInGame     = 10,  
+   k_EUGCMatchingUGCType_ControllerBindings= 11,
+
+   /* game managed items (not managed by users) */
+   k_EUGCMatchingUGCType_GameManagedItems  = 12, 
+   
+   /* @note: will only be valid for CreateQueryUserUGCRequest requests */
+   k_EUGCMatchingUGCType_All               = ~0, 
+};
+
+/* 
+ * Different lists of published UGC for a user.
+ * If the current logged in user is different than the specified user, then some
+ * options may not be allowed.
+ */
+typedef enum EUserUGCList EUserUGCList;
+enum EUserUGCList{
+   k_EUserUGCList_Published,
+   k_EUserUGCList_VotedOn,
+   k_EUserUGCList_VotedUp,
+   k_EUserUGCList_VotedDown,
+   k_EUserUGCList_WillVoteLater,
+   k_EUserUGCList_Favorited,
+   k_EUserUGCList_Subscribed,
+   k_EUserUGCList_UsedOrPlayed,
+   k_EUserUGCList_Followed,
+};
+
+/* 
+ * Sort order for user published UGC lists (defaults to creation order 
+ * descending)
+ */
+typedef enum EUserUGCListSortOrder EUserUGCListSortOrder;
+enum EUserUGCListSortOrder{
+   k_EUserUGCListSortOrder_CreationOrderDesc,
+   k_EUserUGCListSortOrder_CreationOrderAsc,
+   k_EUserUGCListSortOrder_TitleAsc,
+   k_EUserUGCListSortOrder_LastUpdatedDesc,
+   k_EUserUGCListSortOrder_SubscriptionDateDesc,
+   k_EUserUGCListSortOrder_VoteScoreDesc,
+   k_EUserUGCListSortOrder_ForModeration,
+};
+
+/*
+ * Combination of sorting and filtering for queries across all UGC
+ */
+typedef enum EUGCQuery EUGCQuery;
+enum EUGCQuery{
+   k_EUGCQuery_RankedByVote                                 = 0,
+   k_EUGCQuery_RankedByPublicationDate                      = 1,
+   k_EUGCQuery_AcceptedForGameRankedByAcceptanceDate        = 2,
+   k_EUGCQuery_RankedByTrend                                = 3,
+   k_EUGCQuery_FavoritedByFriendsRankedByPublicationDate    = 4,
+   k_EUGCQuery_CreatedByFriendsRankedByPublicationDate      = 5,
+   k_EUGCQuery_RankedByNumTimesReported                     = 6,
+   k_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate= 7,
+   k_EUGCQuery_NotYetRated                                  = 8,
+   k_EUGCQuery_RankedByTotalVotesAsc                        = 9,
+   k_EUGCQuery_RankedByVotesUp                              = 10,
+   k_EUGCQuery_RankedByTextSearch                           = 11,
+   k_EUGCQuery_RankedByTotalUniqueSubscriptions             = 12,
+   k_EUGCQuery_RankedByPlaytimeTrend                        = 13,
+   k_EUGCQuery_RankedByTotalPlaytime                        = 14,
+   k_EUGCQuery_RankedByAveragePlaytimeTrend                 = 15,
+   k_EUGCQuery_RankedByLifetimeAveragePlaytime              = 16,
+   k_EUGCQuery_RankedByPlaytimeSessionsTrend                = 17,
+   k_EUGCQuery_RankedByLifetimePlaytimeSessions             = 18,
+   k_EUGCQuery_RankedByLastUpdatedDate                      = 19,
+};
+
+typedef enum EItemUpdateStatus EItemUpdateStatus;
+enum EItemUpdateStatus{
+   /* The item update handle was invalid, job might be finished, listen too 
+    * SubmitItemUpdateResult_t */
+   k_EItemUpdateStatusInvalid         = 0, 
+
+   /* The item update is processing configuration data */
+   k_EItemUpdateStatusPreparingConfig = 1, 
+
+   /* The item update is reading and processing content files */
+   k_EItemUpdateStatusPreparingContent= 2, 
+
+   /* The item update is uploading content changes to Steam */
+   k_EItemUpdateStatusUploadingContent= 3, 
+
+   /* The item update is uploading new preview file image */
+   k_EItemUpdateStatusUploadingPreviewFile= 4, 
+   
+   /* The item update is committing all changes */
+   k_EItemUpdateStatusCommittingChanges   = 5  
+};
+
+typedef enum EItemState EItemState;
+enum EItemState{
+   /* item not tracked on client */
+   k_EItemStateNone           = 0,
+
+   /* current user is subscribed to this item. Not just cached. */
+   k_EItemStateSubscribed     = 1,
+
+   /* item was created with ISteamRemoteStorage */
+   k_EItemStateLegacyItem     = 2,
+   
+   /* item is installed and usable (but maybe out of date) */
+   k_EItemStateInstalled      = 4,
+   
+   /* items needs an update. Either because it's not installed yet or creator 
+    * updated content */
+   k_EItemStateNeedsUpdate    = 8,
+
+   /* item update is currently downloading */
+   k_EItemStateDownloading    = 16,
+   
+   /* DownloadItem() was called for this item, content isn't available until 
+    * DownloadItemResult_t is fired */
+   k_EItemStateDownloadPending= 32,   
+};
+
+typedef enum EItemStatistic EItemStatistic;
+enum EItemStatistic{
+   k_EItemStatistic_NumSubscriptions                  = 0,
+   k_EItemStatistic_NumFavorites                      = 1,
+   k_EItemStatistic_NumFollowers                      = 2,
+   k_EItemStatistic_NumUniqueSubscriptions            = 3,
+   k_EItemStatistic_NumUniqueFavorites                = 4,
+   k_EItemStatistic_NumUniqueFollowers                = 5,
+   k_EItemStatistic_NumUniqueWebsiteViews             = 6,
+   k_EItemStatistic_ReportScore                       = 7,
+   k_EItemStatistic_NumSecondsPlayed                  = 8,
+   k_EItemStatistic_NumPlaytimeSessions               = 9,
+   k_EItemStatistic_NumComments                       = 10,
+   k_EItemStatistic_NumSecondsPlayedDuringTimePeriod    = 11,
+   k_EItemStatistic_NumPlaytimeSessionsDuringTimePeriod = 12,
+};
+
+typedef enum EItemPreviewType EItemPreviewType;
+enum EItemPreviewType{
+   /* standard image file expected (e.g. jpg, png, gif, etc.) */
+   k_EItemPreviewType_Image = 0, 
+
+   k_EItemPreviewType_YouTubeVideo = 1, /* video id is stored */
+   k_EItemPreviewType_Sketchfab = 2, /* model id is stored */
+
+   /* 
+    * standard image file expected - cube map in the layout
+    * +---+---+-------+
+    * |   |Up |       |
+    * +---+---+---+---+
+    * | L | F | R | B |
+    * +---+---+---+---+
+    * |   |Dn |       |
+    * +---+---+---+---+
+    */
+   k_EItemPreviewType_EnvironmentMap_HorizontalCross = 3,
+   
+   /* standard image file expected */
+   k_EItemPreviewType_EnvironmentMap_LatLong = 4,
+
+   /* you can specify your own types above this value */
+   k_EItemPreviewType_ReservedMax = 255,
+};
+
+const u32 kNumUGCResultsPerPage = 50;
+const u32 k_cchDeveloperMetadataMax = 5000;
+
+/* Details for a single published file/UGC */
+typedef struct SteamUGCDetails_t SteamUGCDetails_t;
+struct SteamUGCDetails_t{
+   PublishedFileId_t m_nPublishedFileId;
+   EResult m_eResult; /* The result of the operation. */
+   EWorkshopFileType m_eFileType; /* Type of the file */
+   AppId_t m_nCreatorAppID; /*ID of the app that created this file. */
+   AppId_t m_nConsumerAppID; /* ID of the app that will consume this file. */
+   char m_rgchTitle[k_cchPublishedDocumentTitleMax]; /* title of document */
+   
+   /* description of document */
+   char m_rgchDescription[k_cchPublishedDocumentDescriptionMax]; 
+   u64 m_ulSteamIDOwner; /* Steam ID of the user who created this content. */
+   u32 m_rtimeCreated; /* time when the published file was created */
+   u32 m_rtimeUpdated; /* time when the published file was last updated */
+   
+   /* time when the user added the published file to their list (not always 
+    * applicable) */
+   u32 m_rtimeAddedToUserList; 
+   ERemoteStoragePublishedFileVisibility m_eVisibility; /* visibility */
+   int m_bBanned; /* whether the file was banned */
+
+   /* developer has specifically flagged this item as accepted in the Workshop*/
+   int m_bAcceptedForUse; 
+
+   /* whether the list of tags was too long to be returned in the provided 
+    * buffer */
+   int m_bTagsTruncated;
+   
+   /* comma separated list of all tags associated with this file */
+   char m_rgchTags[k_cchTagListMax]; 
+   
+   /* file/url information */
+   UGCHandle_t m_hFile; /* The handle of the primary file */
+   UGCHandle_t m_hPreviewFile; /* The handle of the preview file */
+   
+   /* The cloud filename of the primary file */
+   char m_pchFileName[k_cchFilenameMax];
+   
+   /* Size of the primary file */
+   i32 m_nFileSize;
+   i32 m_nPreviewFileSize; /* Size of the preview file */
+   char m_rgchURL[k_cchPublishedFileURLMax]; /* URL (for a video or a website)*/
+
+   /* voting information */
+   u32 m_unVotesUp; /* number of votes up */
+   u32 m_unVotesDown; /* number of votes down */
+   float m_flScore; /* calculated score */
+
+   /* collection details */
+   u32 m_unNumChildren;                     
+};
+
+/* 
+ * Callback for querying UGC 
+ */
+typedef struct SteamUGCQueryCompleted_t SteamUGCQueryCompleted_t;
+struct SteamUGCQueryCompleted_t{
+   UGCQueryHandle_t m_handle;
+   EResult m_eResult;
+   u32 m_unNumResultsReturned;
+   u32 m_unTotalMatchingResults;
+   
+   /* indicates whether this data was retrieved from the local on-disk cache */
+   int m_bCachedData; 
+   
+   /* If a paging cursor was used, then this will be the next cursor to get the 
+    * next result set. */
+   char m_rgchNextCursor[k_cchPublishedFileURLMax]; 
+};
+enum { k_iSteamUGCQueryCompleted = k_iSteamUGCCallbacks + 31 };
+
+/* 
+ * Callback for requesting details on one piece of UGC 
+ */
+typedef struct SteamUGCRequestUGCDetailsResult_t 
+               SteamUGCRequestUGCDetailsResult_t;
+struct SteamUGCRequestUGCDetailsResult_t{
+   SteamUGCDetails_t m_details;
+   
+   /* indicates whether this data was retrieved from the local on-disk cache */
+   int m_bCachedData; 
+};
+enum { k_iSteamUGCRequestUGCDetailsResult = k_iSteamUGCCallbacks + 2 };
+
+
+/*
+ * Purpose: result for ISteamUGC::CreateItem() 
+ */
+typedef struct CreateItemResult_t CreateItemResult_t;
+struct CreateItemResult_t{
+   EResult m_eResult;
+   
+   /* new item got this UGC PublishFileID */
+   PublishedFileId_t m_nPublishedFileId; 
+   int m_bUserNeedsToAcceptWorkshopLegalAgreement;
+};
+enum { k_iCreateItemResult = k_iSteamUGCCallbacks + 3 };
+
+
+/*
+ * Purpose: result for ISteamUGC::SubmitItemUpdate() 
+ */
+typedef struct SubmitItemUpdateResult_t SubmitItemUpdateResult_t;
+struct SubmitItemUpdateResult_t{
+   EResult m_eResult;
+   int m_bUserNeedsToAcceptWorkshopLegalAgreement;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iSubmitItemUpdateResult = k_iSteamUGCCallbacks + 4 };
+
+
+/*
+ * Purpose: a Workshop item has been installed or updated
+ */
+typedef struct ItemInstalled_t ItemInstalled_t;
+struct ItemInstalled_t{
+   AppId_t m_unAppID;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iItemInstalled = k_iSteamUGCCallbacks + 5 };
+
+
+/*
+ * Purpose: result of DownloadItem(), existing item files can be accessed again
+ */
+typedef struct DownloadItemResult_t DownloadItemResult_t;
+struct DownloadItemResult_t{
+   AppId_t m_unAppID;
+   PublishedFileId_t m_nPublishedFileId;
+   EResult m_eResult;
+};
+enum { k_iDownloadItemResult = k_iSteamUGCCallbacks + 6 };
+
+/*
+ * Purpose: result of AddItemToFavorites() or RemoveItemFromFavorites()
+ */
+typedef struct UserFavoriteItemsListChanged_t UserFavoriteItemsListChanged_t;
+struct UserFavoriteItemsListChanged_t{
+   PublishedFileId_t m_nPublishedFileId;
+   EResult m_eResult;
+   int m_bWasAddRequest;
+};
+enum { k_iUserFavoriteItemsListChanged = k_iSteamUGCCallbacks + 7 };
+
+/*
+ * Purpose: The result of a call to SetUserItemVote()
+ */
+typedef struct SetUserItemVoteResult_t SetUserItemVoteResult_t;
+struct SetUserItemVoteResult_t{
+   PublishedFileId_t m_nPublishedFileId;
+   EResult m_eResult;
+   int m_bVoteUp;
+};
+enum { k_iSetUserItemVoteResult = k_iSteamUGCCallbacks + 8 };
+
+/*
+ * Purpose: The result of a call to GetUserItemVote()
+ */
+typedef struct GetUserItemVoteResult_t GetUserItemVoteResult_t;
+struct GetUserItemVoteResult_t{
+   PublishedFileId_t m_nPublishedFileId;
+   EResult m_eResult;
+   int m_bVotedUp;
+   int m_bVotedDown;
+   int m_bVoteSkipped;
+};
+enum { k_iGetUserItemVoteResult = k_iSteamUGCCallbacks + 9 };
+
+/*
+ * Purpose: The result of a call to StartPlaytimeTracking()
+ */
+typedef struct StartPlaytimeTrackingResult_t StartPlaytimeTrackingResult_t;
+struct StartPlaytimeTrackingResult_t{
+   EResult m_eResult;
+};
+enum { k_iStartPlaytimeTrackingResult = k_iSteamUGCCallbacks + 10 };
+
+/*
+ * Purpose: The result of a call to StopPlaytimeTracking()
+ */
+typedef struct StopPlaytimeTrackingResult_t StopPlaytimeTrackingResult_t;
+struct StopPlaytimeTrackingResult_t{
+   EResult m_eResult;
+};
+enum { k_iStopPlaytimeTrackingResult = k_iSteamUGCCallbacks + 11 };
+
+/*
+ * Purpose: The result of a call to AddDependency
+ */
+typedef struct AddUGCDependencyResult_t AddUGCDependencyResult_t;
+struct AddUGCDependencyResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   PublishedFileId_t m_nChildPublishedFileId;
+};
+enum { k_iAddUGCDependecyResult = k_iSteamUGCCallbacks + 12 };
+
+/*
+ * Purpose: The result of a call to RemoveDependency
+ */
+typedef struct RemoveUGCDependencyResult_t RemoveUGCDependencyResult_t;
+struct RemoveUGCDependencyResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   PublishedFileId_t m_nChildPublishedFileId;
+};
+enum { k_iRemoveUGCDependecyResult = k_iSteamUGCCallbacks + 13 };
+
+
+/*
+ * Purpose: The result of a call to AddAppDependency
+ */
+typedef struct AddAppDependencyResult_t AddAppDependencyResult_t;
+struct AddAppDependencyResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nAppID;
+};
+enum { k_iAddAppDependencyResult = k_iSteamUGCCallbacks + 14 };
+
+/*
+ * Purpose: The result of a call to RemoveAppDependency
+ */
+typedef struct RemoveAppDependencyResult_t RemoveAppDependencyResult_t;
+struct RemoveAppDependencyResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_nAppID;
+};
+enum { k_iRemoveAppDependencyResult = k_iSteamUGCCallbacks + 15 };
+
+/*
+ * Purpose: The result of a call to GetAppDependencies.  Callback may be called
+ *         multiple times until all app dependencies have been returned.
+ */
+typedef struct GetAppDependenciesResult_t GetAppDependenciesResult_t;
+struct GetAppDependenciesResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+   AppId_t m_rgAppIDs[32];
+   u32 m_nNumAppDependencies;      // number returned in this struct
+   u32 m_nTotalNumAppDependencies;   // total found
+};
+enum { k_iGetAppDependeniesResult = k_iSteamUGCCallbacks + 16 };
+
+/*
+ * Purpose: The result of a call to DeleteItem
+ */
+typedef struct DeleteItemResult_t DeleteItemResult_t;
+struct DeleteItemResult_t{
+   EResult m_eResult;
+   PublishedFileId_t m_nPublishedFileId;
+};
+enum { k_iDeleteItemResult = k_iSteamUGCCallbacks + 17 };
+
+
+/*
+ * Purpose: signal that the list of subscribed items changed
+ */
+typedef struct UserSubscribedItemsListChanged_t 
+               UserSubscribedItemsListChanged_t;
+struct UserSubscribedItemsListChanged_t{
+   AppId_t m_nAppID;
+};
+enum { k_iUserSubscribedItemsListChanged = k_iSteamUGCCallbacks + 18 };
+
+
+/*
+ * Purpose: Status of the user's acceptable/rejection of the app's specific 
+ * Workshop EULA
+ */
+typedef struct WorkshopEULAStatus_t WorkshopEULAStatus_t;
+struct WorkshopEULAStatus_t{
+   EResult m_eResult;
+   AppId_t m_nAppID;
+   u32 m_unVersion;
+   RTime32 m_rtAction;
+   int m_bAccepted;
+   int m_bNeedsAction;
+};
+enum { k_iWorkshopEULAStatus = k_iSteamUGCCallbacks + 20 };
+
+#pragma pack( pop )
+
+#define STEAMUGC_INTERFACE_VERSION "STEAMUGC_INTERFACE_VERSION016"
+
+ISteamUGC *SteamAPI_SteamUGC_v016();
+ISteamUGC *SteamAPI_SteamUGC() 
+{ 
+   return SteamAPI_SteamUGC_v016(); 
+}
+ISteamUGC *SteamAPI_SteamGameServerUGC_v016();
+ISteamUGC *SteamAPI_SteamGameServerUGC() 
+{ 
+   return SteamAPI_SteamGameServerUGC_v016(); 
+}
+UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryUserUGCRequest( 
+      ISteamUGC *self, AccountID_t unAccountID, EUserUGCList eListType, 
+      EUGCMatchingUGCType eMatchingUGCType, EUserUGCListSortOrder eSortOrder, 
+      AppId_t nCreatorAppID, AppId_t nConsumerAppID, u32 unPage );
+
+UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryAllUGCRequestPage( 
+      ISteamUGC *self, EUGCQuery eQueryType, 
+      EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, 
+      AppId_t nCreatorAppID, AppId_t nConsumerAppID, u32 unPage );
+
+UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryAllUGCRequestCursor( 
+      ISteamUGC *self, EUGCQuery eQueryType, 
+      EUGCMatchingUGCType eMatchingeMatchingUGCTypeFileType, 
+      AppId_t nCreatorAppID, AppId_t nConsumerAppID, const char * pchCursor );
+
+UGCQueryHandle_t SteamAPI_ISteamUGC_CreateQueryUGCDetailsRequest( 
+      ISteamUGC *self, PublishedFileId_t *pvecPublishedFileID, 
+      u32 unNumPublishedFileIDs );
+
+SteamAPICall_t SteamAPI_ISteamUGC_SendQueryUGCRequest( ISteamUGC* self, 
+      UGCQueryHandle_t handle );
+
+int SteamAPI_ISteamUGC_GetQueryUGCResult( 
+      ISteamUGC *self, UGCQueryHandle_t handle, u32 index, 
+      SteamUGCDetails_t *pDetails );
+
+u32 SteamAPI_ISteamUGC_GetQueryUGCNumTags( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index );
+
+int SteamAPI_ISteamUGC_GetQueryUGCTag( 
+      ISteamUGC* self, UGCQueryHandle_t handle, u32 index, u32 indexTag, 
+      char * pchValue, u32 cchValueSize );
+
+int SteamAPI_ISteamUGC_GetQueryUGCTagDisplayName( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, u32 indexTag, char * pchValue, 
+      u32 cchValueSize );
+
+int SteamAPI_ISteamUGC_GetQueryUGCPreviewURL( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, char * pchURL, u32 cchURLSize );
+
+int SteamAPI_ISteamUGC_GetQueryUGCMetadata( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, char * pchMetadata, 
+      u32 cchMetadatasize );
+
+int SteamAPI_ISteamUGC_GetQueryUGCChildren( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, 
+      PublishedFileId_t *pvecPublishedFileID, u32 cMaxEntries );
+
+int SteamAPI_ISteamUGC_GetQueryUGCStatistic( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, EItemStatistic eStatType, 
+      u64 *pStatValue );
+
+u32 SteamAPI_ISteamUGC_GetQueryUGCNumAdditionalPreviews( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index );
+
+int SteamAPI_ISteamUGC_GetQueryUGCAdditionalPreview( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, u32 previewIndex, 
+      char *pchURLOrVideoID, u32 cchURLSize, char *pchOriginalFileName, 
+      u32 cchOriginalFileNameSize, EItemPreviewType *pPreviewType );
+
+u32 SteamAPI_ISteamUGC_GetQueryUGCNumKeyValueTags( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index );
+
+int SteamAPI_ISteamUGC_GetQueryUGCKeyValueTag( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, u32 keyValueTagIndex, char *pchKey, 
+      u32 cchKeySize, char * pchValue, u32 cchValueSize );
+
+int SteamAPI_ISteamUGC_GetQueryFirstUGCKeyValueTag( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 index, const char *pchKey, char *pchValue, 
+      u32 cchValueSize );
+
+int SteamAPI_ISteamUGC_ReleaseQueryUGCRequest( ISteamUGC* self, 
+      UGCQueryHandle_t handle );
+
+int SteamAPI_ISteamUGC_AddRequiredTag( ISteamUGC* self, UGCQueryHandle_t handle,
+      const char * pTagName );
+
+int SteamAPI_ISteamUGC_AddRequiredTagGroup( ISteamUGC* self, 
+      UGCQueryHandle_t handle, const SteamParamStringArray_t * pTagGroups );
+
+int SteamAPI_ISteamUGC_AddExcludedTag( ISteamUGC* self, UGCQueryHandle_t handle,
+      const char * pTagName );
+
+int SteamAPI_ISteamUGC_SetReturnOnlyIDs( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnOnlyIDs );
+
+int SteamAPI_ISteamUGC_SetReturnKeyValueTags( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnKeyValueTags );
+
+int SteamAPI_ISteamUGC_SetReturnLongDescription( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnLongDescription );
+
+int SteamAPI_ISteamUGC_SetReturnMetadata( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnMetadata );
+
+int SteamAPI_ISteamUGC_SetReturnChildren( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnChildren );
+
+int SteamAPI_ISteamUGC_SetReturnAdditionalPreviews( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnAdditionalPreviews );
+
+int SteamAPI_ISteamUGC_SetReturnTotalOnly( ISteamUGC* self, 
+      UGCQueryHandle_t handle, int bReturnTotalOnly );
+
+int SteamAPI_ISteamUGC_SetReturnPlaytimeStats( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 unDays );
+
+int SteamAPI_ISteamUGC_SetLanguage( ISteamUGC* self, UGCQueryHandle_t handle, 
+      const char * pchLanguage );
+
+int SteamAPI_ISteamUGC_SetAllowCachedResponse( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 unMaxAgeSeconds );
+
+int SteamAPI_ISteamUGC_SetCloudFileNameFilter( ISteamUGC* self, 
+      UGCQueryHandle_t handle, const char * pMatchCloudFileName );
+
+int SteamAPI_ISteamUGC_SetMatchAnyTag( ISteamUGC* self, UGCQueryHandle_t handle,
+      int bMatchAnyTag );
+
+int SteamAPI_ISteamUGC_SetSearchText( ISteamUGC* self, UGCQueryHandle_t handle,
+      const char * pSearchText );
+
+int SteamAPI_ISteamUGC_SetRankedByTrendDays( ISteamUGC* self, 
+      UGCQueryHandle_t handle, u32 unDays );
+
+int SteamAPI_ISteamUGC_SetTimeCreatedDateRange( ISteamUGC* self, 
+      UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd );
+
+int SteamAPI_ISteamUGC_SetTimeUpdatedDateRange( ISteamUGC* self, 
+      UGCQueryHandle_t handle, RTime32 rtStart, RTime32 rtEnd );
+
+int SteamAPI_ISteamUGC_AddRequiredKeyValueTag( ISteamUGC* self, 
+      UGCQueryHandle_t handle, const char * pKey, const char * pValue );
+
+SteamAPICall_t SteamAPI_ISteamUGC_RequestUGCDetails( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, u32 unMaxAgeSeconds );
+
+SteamAPICall_t SteamAPI_ISteamUGC_CreateItem( ISteamUGC* self, 
+      AppId_t nConsumerAppId, EWorkshopFileType eFileType );
+
+UGCUpdateHandle_t SteamAPI_ISteamUGC_StartItemUpdate( ISteamUGC* self, 
+      AppId_t nConsumerAppId, PublishedFileId_t nPublishedFileID );
+
+int SteamAPI_ISteamUGC_SetItemTitle( ISteamUGC* self, UGCUpdateHandle_t handle, 
+      const char * pchTitle );
+
+int SteamAPI_ISteamUGC_SetItemDescription( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pchDescription );
+
+int SteamAPI_ISteamUGC_SetItemUpdateLanguage( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pchLanguage );
+
+int SteamAPI_ISteamUGC_SetItemMetadata( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pchMetaData );
+
+int SteamAPI_ISteamUGC_SetItemVisibility( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, 
+      ERemoteStoragePublishedFileVisibility eVisibility );
+
+int SteamAPI_ISteamUGC_SetItemTags( ISteamUGC* self, 
+      UGCUpdateHandle_t updateHandle, const SteamParamStringArray_t * pTags );
+
+int SteamAPI_ISteamUGC_SetItemContent( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pszContentFolder );
+
+int SteamAPI_ISteamUGC_SetItemPreview( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pszPreviewFile );
+
+int SteamAPI_ISteamUGC_SetAllowLegacyUpload( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, int bAllowLegacyUpload );
+
+int SteamAPI_ISteamUGC_RemoveAllItemKeyValueTags( ISteamUGC* self, 
+      UGCUpdateHandle_t handle );
+
+int SteamAPI_ISteamUGC_RemoveItemKeyValueTags( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pchKey );
+
+int SteamAPI_ISteamUGC_AddItemKeyValueTag( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pchKey, const char * pchValue );
+
+int SteamAPI_ISteamUGC_AddItemPreviewFile( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pszPreviewFile, 
+      EItemPreviewType type );
+
+int SteamAPI_ISteamUGC_AddItemPreviewVideo( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pszVideoID );
+
+int SteamAPI_ISteamUGC_UpdateItemPreviewFile( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, u32 index, const char * pszPreviewFile );
+
+int SteamAPI_ISteamUGC_UpdateItemPreviewVideo( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, u32 index, const char * pszVideoID );
+
+int SteamAPI_ISteamUGC_RemoveItemPreview( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, u32 index );
+
+SteamAPICall_t SteamAPI_ISteamUGC_SubmitItemUpdate( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, const char * pchChangeNote );
+
+EItemUpdateStatus SteamAPI_ISteamUGC_GetItemUpdateProgress( ISteamUGC* self, 
+      UGCUpdateHandle_t handle, u64 * punBytesProcessed, u64 * punBytesTotal );
+
+SteamAPICall_t SteamAPI_ISteamUGC_SetUserItemVote( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, int bVoteUp );
+
+SteamAPICall_t SteamAPI_ISteamUGC_GetUserItemVote( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_AddItemToFavorites( ISteamUGC* self, 
+      AppId_t nAppId, PublishedFileId_t nPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_RemoveItemFromFavorites( ISteamUGC* self,
+      AppId_t nAppId, PublishedFileId_t nPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_SubscribeItem( ISteamUGC* self,
+      PublishedFileId_t nPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_UnsubscribeItem( ISteamUGC* self,
+      PublishedFileId_t nPublishedFileID );
+
+u32 SteamAPI_ISteamUGC_GetNumSubscribedItems( ISteamUGC* self );
+
+u32 SteamAPI_ISteamUGC_GetSubscribedItems( ISteamUGC* self, 
+      PublishedFileId_t * pvecPublishedFileID, u32 cMaxEntries );
+
+u32 SteamAPI_ISteamUGC_GetItemState( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID );
+
+int SteamAPI_ISteamUGC_GetItemInstallInfo( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, u64 * punSizeOnDisk, char * pchFolder, 
+      u32 cchFolderSize, u32 * punTimeStamp );
+
+int SteamAPI_ISteamUGC_GetItemDownloadInfo( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, u64 * punBytesDownloaded, 
+      u64 * punBytesTotal );
+
+int SteamAPI_ISteamUGC_DownloadItem( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, int bHighPriority );
+
+int SteamAPI_ISteamUGC_BInitWorkshopForGameServer( ISteamUGC* self, 
+      DepotId_t unWorkshopDepotID, const char * pszFolder );
+
+void SteamAPI_ISteamUGC_SuspendDownloads( ISteamUGC* self, int bSuspend );
+
+SteamAPICall_t SteamAPI_ISteamUGC_StartPlaytimeTracking( ISteamUGC* self, 
+      PublishedFileId_t * pvecPublishedFileID, u32 unNumPublishedFileIDs );
+
+SteamAPICall_t SteamAPI_ISteamUGC_StopPlaytimeTracking( ISteamUGC* self,
+      PublishedFileId_t * pvecPublishedFileID, u32 unNumPublishedFileIDs );
+
+SteamAPICall_t SteamAPI_ISteamUGC_StopPlaytimeTrackingForAllItems( 
+      ISteamUGC* self );
+
+SteamAPICall_t SteamAPI_ISteamUGC_AddDependency( ISteamUGC* self, 
+      PublishedFileId_t nParentPublishedFileID, 
+      PublishedFileId_t nChildPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_RemoveDependency( ISteamUGC* self, 
+      PublishedFileId_t nParentPublishedFileID, 
+      PublishedFileId_t nChildPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_AddAppDependency( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, AppId_t nAppID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_RemoveAppDependency( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID, AppId_t nAppID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_GetAppDependencies( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID );
+
+SteamAPICall_t SteamAPI_ISteamUGC_DeleteItem( ISteamUGC* self, 
+      PublishedFileId_t nPublishedFileID );
+
+int SteamAPI_ISteamUGC_ShowWorkshopEULA( ISteamUGC* self );
+
+SteamAPICall_t SteamAPI_ISteamUGC_GetWorkshopEULAStatus( ISteamUGC* self );
+
+#endif /* VG_STEAM_UGC_H */
index ef7f0e99bfb55db0350a3dbf0589d1bb3150bb32..1fd2d5a29cf293306ffa4c0bb19e19c17bf947e9 100644 (file)
--- a/vg_tex.h
+++ b/vg_tex.h
@@ -1,4 +1,35 @@
-/* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
+/* Copyright (C) 2021-2023 Harry Godden (hgn) - All Rights Reserved 
+ *
+ * A portion of this file is copied and altered from the QOI projects' source,
+ * Originally written by Dominic Szablewski. It is slightly modified.
+ * For the original unaltered QOI header, you can find it here:
+ *    https://github.com/phoboslab/qoi/blob/master/qoi.h
+ *
+ * Copyright (C) 2021, Dominic Szablewski 
+ * SPDX-License-Identifier: MIT
+ *
+ * MIT License
+  Copyright (c) 2022 Dominic Szablewski - https://phoboslab.org
+  
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+  
+  The above copyright notice and this permission notice shall be included in all
+  copies or substantial portions of the Software.
+  
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
 #ifndef VG_TEX_H
 #define VG_TEX_H
 
@@ -6,6 +37,9 @@
 #include "vg/vg.h"
 #include "vg/vg_log.h"
 
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include "vg/submodules/stb/stb_image_write.h"
+
 struct vg_sprite
 {
        v4f uv_xywh;