From: hgn Date: Thu, 4 May 2023 04:35:36 +0000 (+0100) Subject: steam ugc X-Git-Url: https://harrygodden.com/git/?p=vg.git;a=commitdiff_plain;h=ffd724233b7a3cb89d0d5d253ba4c475d87c76e2 steam ugc --- diff --git a/src/fonts/vg_font_thin.png b/src/fonts/vg_font_thin.png index 0c66197..8d7f50f 100644 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 64f9187..6cbcb96 100644 --- 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(); } diff --git a/vg_console.h b/vg_console.h index dd9cc77..66e7f5f 100644 --- a/vg_console.h +++ b/vg_console.h @@ -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; iterminator 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= 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; ikey == ev.sym ){ - if( mapping->mod == 0 ){ - if( mod == 0 ){ - mapping->handler(); - return; - } + for( int i=0; imod) == 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 */ diff --git a/vg_imgui.h b/vg_imgui.h index 2f84885..bb98812 100644 --- a/vg_imgui.h +++ b/vg_imgui.h @@ -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; ikey == 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; ikey == 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 9352544..640ceae 100644 --- a/vg_io.h +++ b/vg_io.h @@ -10,11 +10,24 @@ #include #include + #define _TINYDIR_MALLOC(_size) vg_linear_alloc( vg_mem.scratch, _size ) #define _TINYDIR_FREE(_size) #include "submodules/tinydir/tinydir.h" +#include +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 */ diff --git a/vg_loader.h b/vg_loader.h index 3c519b5..ebd1d56 100644 --- a/vg_loader.h +++ b/vg_loader.h @@ -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 ); } diff --git a/vg_platform.h b/vg_platform.h index 52c26c0..9861204 100644 --- a/vg_platform.h +++ b/vg_platform.h @@ -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; ip_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; im_hAsyncCall ) - { - steam_async_trackers[j ++] = steam_async_trackers[i]; + for( int i=0; im_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; icallback_id == callback.m_iCallback ) - { + for( int i=0; icallback_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 index 0000000..7d92cce --- /dev/null +++ b/vg_steam_remote_storage.h @@ -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 index 0000000..5204192 --- /dev/null +++ b/vg_steam_ugc.h @@ -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 */ diff --git a/vg_tex.h b/vg_tex.h index ef7f0e9..1fd2d5a 100644 --- 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;