#include "workshop.h"
#include <string.h>
-struct addon_system addon_system;
+struct _addon _addon;
+
+/*
+ * internal
+ * --------------------------------------------------------------------------------------------------------------------
+ */
+
+addon_reg *addon_details( addon_id id )
+{
+ if( id ) return &_addon.registry[id-1];
+ else return NULL;
+}
static bool addon_filter( addon_reg *reg, u32 whitelist, u32 blacklist )
{
return 1;
}
-u32 addon_count( enum addon_type type, u32 whitelist, u32 blacklist )
+u32 _addon_filtered_count( enum addon_type type, u32 whitelist, u32 blacklist )
{
- if( whitelist || blacklist )
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ u32 registry_count = _addon.registry_count;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
+
+ u32 count = 0;
+ for( u32 i=0; i < registry_count; i++ )
{
- u32 typecount = 0, count = 0;
- for( u32 i=0; typecount<addon_count( type, 0,0 ); i++ )
+ addon_reg *reg = &_addon.registry[i];
+ if( reg->alias.type == type )
{
- addon_reg *reg = &addon_system.registry[i];
- if( reg->alias.type == type )
- {
- typecount ++;
-
- if( addon_filter( reg, whitelist, blacklist ) )
- count ++;
- }
+ if( addon_filter( reg, whitelist, blacklist ) )
+ count ++;
}
-
- return count;
}
- else
- return addon_system.registry_type_counts[ type ];
+ return count;
}
-
-/* these kind of suck, oh well. */
-addon_reg *get_addon_from_index( enum addon_type type, u32 index, u32 whitelist, u32 blacklist )
+addon_id _addon_get_filtered( enum addon_type type, u32 index, u32 whitelist, u32 blacklist )
{
- u32 typecount = 0, count = 0;
- for( u32 i=0; typecount<addon_count(type,0,0); i++ )
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ u32 registry_count = _addon.registry_count;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
+
+ u32 count = 0;
+ for( u32 i=0; i<registry_count; i++ )
{
- addon_reg *reg = &addon_system.registry[i];
+ addon_reg *reg = &_addon.registry[i];
if( reg->alias.type == type )
{
- typecount ++;
-
if( addon_filter( reg, whitelist, blacklist ) )
{
if( index == count )
- return reg;
+ return i+1;
count ++;
}
}
}
-
- return NULL;
+ return 0;
}
-u32 get_index_from_addon( enum addon_type type, addon_reg *a, u32 whitelist, u32 blacklist )
+bool _addon_get_filtered_index( enum addon_type type, addon_id id, u32 whitelist, u32 blacklist, u32 *out_index )
{
- u32 typecount = 0, count = 0;
- for( u32 i=0; typecount<addon_system.registry_type_counts[type]; i++ )
+ if( !id )
+ return 0;
+
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ u32 registry_count = _addon.registry_count;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
+
+ u32 count = 0;
+ for( u32 i=0; i < registry_count; i++ )
{
- addon_reg *reg = &addon_system.registry[i];
+ addon_reg *reg = &_addon.registry[i];
if( reg->alias.type == type )
{
- typecount ++;
-
if( addon_filter( reg, whitelist, blacklist ) )
{
- if( reg == a )
- return count;
+ if( i == (id-1) )
+ {
+ *out_index = count;
+ return 1;
+ }
count ++;
}
}
}
-
- return 0xffffffff;
+ return 0;
}
-u32 addon_match( addon_alias *alias )
+addon_id _get_addon_by_alias( addon_alias *alias )
{
- if( alias->type == k_addon_type_none ) return 0xffffffff;
+ if( alias->type == k_addon_type_none )
+ return 0;
u32 foldername_djb2 = 0;
if( !alias->workshop_id )
foldername_djb2 = vg_strdjb2( alias->foldername );
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ u32 registry_count = _addon.registry_count;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
+
u32 count = 0;
- for( u32 i=0; count<addon_system.registry_type_counts[alias->type]; i++ )
+ for( u32 i=0; i < registry_count; i++ )
{
- addon_reg *reg = &addon_system.registry[i];
+ addon_reg *reg = &_addon.registry[i];
if( reg->alias.type == alias->type )
{
if( alias->workshop_id )
{
if( alias->workshop_id == reg->alias.workshop_id )
- return count;
+ return i+1;
}
else
{
if( reg->foldername_hash == foldername_djb2 )
{
if( !strcmp( reg->alias.foldername, alias->foldername ) )
- return count;
+ return i+1;
}
}
count ++;
}
}
-
- return 0xffffffff;
-}
-
-/*
- * Create a string version of addon alias in buf
- */
-void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] )
-{
- if( alias->workshop_id )
- {
- snprintf( buf, 128, "sr%03d-steam-"PRINTF_U64,
- alias->type, alias->workshop_id );
- }
- else
- {
- snprintf( buf, 128, "sr%03d-local-%s",
- alias->type, alias->foldername );
- }
+
+ return 0;
}
/*
* equality check
*/
-int addon_alias_eq( addon_alias *a, addon_alias *b )
+bool addon_alias_eq( addon_alias *a, addon_alias *b )
{
- if( a->type == b->type ){
- if( a->workshop_id == b->workshop_id ){
+ if( a->type == b->type )
+ {
+ if( a->workshop_id == b->workshop_id )
+ {
if( a->workshop_id )
return 1;
else
else return 0;
}
+
/*
- * make alias represent NULL.
+ * Create a string version of addon alias in buf
*/
-void invalidate_addon_alias( addon_alias *alias )
+void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] )
{
- alias->type = k_addon_type_none;
- alias->workshop_id = 0;
- alias->foldername[0] = '\0';
+ if( alias->workshop_id ) snprintf( buf, 128, "sr%03d-steam-"PRINTF_U64, alias->type, alias->workshop_id );
+ else snprintf( buf, 128, "sr%03d-local-%s", alias->type, alias->foldername );
+}
+
+void addon_uid( addon_id id, char buf[ ADDON_UID_MAX ] )
+{
+ if( id ) addon_alias_uid( &addon_details(id)->alias, buf );
+ else buf[0] = '\0';
}
/*
* parse uid to alias. returns 1 if successful
*/
-int addon_uid_to_alias( const char *uid, addon_alias *alias )
+bool addon_uid_to_alias( const char *uid, addon_alias *alias )
{
/* 1
* 01234567890123
* |
* location
*/
- if( strlen(uid) < 13 ){
- invalidate_addon_alias( alias );
+ alias->type = k_addon_type_none;
+ alias->workshop_id = 0;
+ alias->foldername[0] = '\0';
+
+ if( strlen(uid) < 13 )
return 0;
- }
- if( !((uid[0] == 's') && (uid[1] == 'r')) ){
- invalidate_addon_alias( alias );
+ if( !((uid[0] == 's') && (uid[1] == 'r')) )
return 0;
- }
char type[4];
memcpy( type, uid+2, 3 );
if( !strcmp(location,"steam") )
alias->workshop_id = atoll( uid+12 );
- else if( !strcmp(location,"local") ){
+ else if( !strcmp(location,"local") )
+ {
alias->workshop_id = 0;
vg_strncpy( uid+12, alias->foldername, 64, k_strncpy_always_add_null );
}
- else{
- invalidate_addon_alias( alias );
+ else
return 0;
- }
return 1;
}
void addon_system_init( void )
{
- u32 reg_size = sizeof(addon_reg)*ADDON_MOUNTED_MAX;
- addon_system.registry = vg_linear_alloc( vg_mem.rtmemory, reg_size );
- addon_system.cache_lock = SDL_CreateMutex();
- VG_ASSERT( addon_system.cache_lock );
+ THREAD_1;
+
+ u32 reg_size = sizeof(addon_reg)*ADDON_MOUNTED_MAX;
+ _addon.registry = vg_linear_alloc( vg_mem.rtmemory, reg_size );
for( u32 type=0; type<k_addon_type_max; type++ )
{
struct addon_type_info *inf = &addon_type_infos[type];
- struct addon_cache *cache = &addon_system.cache[type];
+ struct addon_cache *cache = &_addon.cache[type];
if( inf->cache_count )
{
for( i32 j=0; j<inf->cache_count; j++ )
{
struct addon_cache_entry *alloc = &cache->allocs[j];
- alloc->reg_ptr = NULL;
- alloc->reg_index = 0xffffffff;
+ alloc->addon_id = 0;
if( inf->item_arena_size )
{
- cache->arenas[j] = _vg_create_linear_allocator(
- vg_mem.rtmemory, inf->item_arena_size, VG_MEMORY_SYSTEM,
- "Item cache's arena" );
+ cache->arenas[j] = _vg_create_linear_allocator( vg_mem.rtmemory, inf->item_arena_size, VG_MEMORY_SYSTEM,
+ "Item cache's arena" );
}
}
}
}
}
-/*
- * Scanning routines
- * -----------------------------------------------------------------------------
- */
+static void addon_set_foldername( addon_reg *reg, const char name[64] )
+{
+ vg_strncpy( name, reg->alias.foldername, 64, k_strncpy_always_add_null );
+ reg->foldername_hash = vg_strdjb2( reg->alias.foldername );
+}
-/*
- * Reciever for scan completion. copies the registry counts back into main fred
- */
-void async_addon_reg_update( void *data, u32 size )
+static bool addon_try_load_metadata( addon_reg *reg, const char *folder_path )
{
- vg_info( "Registry update notify\n" );
-
- for( u32 i=0; i<k_addon_type_max; i++ ){
- addon_system.registry_type_counts[i] = 0;
+ THREAD_1;
+ VG_ASSERT( reg );
+
+ char path_buf[ 4096 ];
+ vg_str meta_path;
+ vg_strnull( &meta_path, path_buf, sizeof(path_buf) );
+ vg_strcat( &meta_path, folder_path );
+ vg_strcat( &meta_path, "/addon.inf" );
+
+ if( !vg_strgood( &meta_path ) )
+ {
+ vg_error( "The metadata path is too long\n" );
+ return 0;
}
- for( u32 i=0; i<addon_system.registry_count; i++ ){
- enum addon_type type = addon_system.registry[i].alias.type;
- addon_system.registry_type_counts[ type ] ++;
+ FILE *fp = fopen( meta_path.buffer, "rb" );
+ if( !fp )
+ {
+ vg_error( "Could not open the '%s'\n", meta_path.buffer );
+ return 0;
}
-}
-static void addon_set_foldername( addon_reg *reg, const char name[64] ){
- vg_strncpy( name, reg->alias.foldername, 64, k_strncpy_always_add_null );
- reg->foldername_hash = vg_strdjb2( reg->alias.foldername );
+ reg->metadata_len = fread( reg->metadata, 1, 512, fp );
+ if( !feof(fp) )
+ {
+ fclose(fp);
+ vg_error( "Metadata too big\n" );
+ return 0;
+ }
+ fclose(fp);
+
+ return 1;
}
-/*
- * Create a new registry
- */
-static addon_reg *addon_alloc_reg( PublishedFileId_t workshop_id, enum addon_type type )
+static addon_id addon_alloc_reg( PublishedFileId_t workshop_id, enum addon_type type )
{
- if( addon_system.registry_count == ADDON_MOUNTED_MAX )
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ if( _addon.registry_count == ADDON_MOUNTED_MAX )
{
vg_error( "You have too many addons installed!\n" );
- return NULL;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
+ return 0;
}
+ addon_id id = _addon.registry_count+1;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
- addon_reg *reg = &addon_system.registry[ addon_system.registry_count ];
+ addon_reg *reg = &_addon.registry[ id-1 ];
reg->flags = 0;
reg->metadata_len = 0;
reg->cache_id = 0;
addon_set_foldername( reg, foldername );
reg->flags |= ADDON_REG_WORKSHOP;
}
- return reg;
+ return id;
}
-/*
- * If the addon.inf exists int the folder, load into the reg
- */
-static int addon_try_load_metadata( addon_reg *reg, vg_str folder_path )
+static void addon_complete_allocation(void)
{
- vg_str meta_path = folder_path;
- vg_strcat( &meta_path, "/addon.inf" );
- if( !vg_strgood( &meta_path ) )
- {
- vg_error( "The metadata path is too long\n" );
- return 0;
- }
-
- FILE *fp = fopen( meta_path.buffer, "rb" );
- if( !fp )
- {
- vg_error( "Could not open the '%s'\n", meta_path.buffer );
- return 0;
- }
-
- reg->metadata_len = fread( reg->metadata, 1, 512, fp );
- if( reg->metadata_len != 512 )
- {
- if( !feof(fp) )
- {
- fclose(fp);
- vg_error( "unknown error codition" );
- reg->metadata_len = 0;
- return 0;
- }
- }
- fclose(fp);
- return 1;
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ _addon.registry_count ++;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
}
-static void addon_print_info( addon_reg *reg )
+static void addon_fail_allocation(void)
{
- vg_info( "addon_reg #%u{\n", addon_system.registry_count );
- vg_info( " type: %d\n", reg->alias.type );
- vg_info( " workshop_id: " PRINTF_U64 "\n", reg->alias.workshop_id );
- vg_info( " folder: [%u]%s\n", reg->foldername_hash, reg->alias.foldername );
- vg_info( " metadata_len: %u\n", reg->metadata_len );
- vg_info( " cache_id: %hu\n", reg->cache_id );
- vg_info( " flags: %hu\n", reg->flags );
- vg_info( "}\n" );
-}
-
-static void addon_mount_finish( addon_reg *reg ){
-#if 0
- addon_print_info( reg );
-#endif
- addon_system.registry_count ++;
}
/*
- * Mount a fully packaged addon, one that certainly has a addon.inf
+ * local addons / mods
+ * ---------------------------------------------------------------------------------------------------------------------
*/
-static addon_reg *addon_mount_workshop_folder( PublishedFileId_t workshop_id, vg_str folder_path )
+addon_id _addon_mount_from_folder( const char *folder, enum addon_type type, const char *content_ext )
{
- addon_reg *reg = addon_alloc_reg( workshop_id, k_addon_type_none );
- if( !reg ) return NULL;
+ THREAD_1;
- if( !addon_try_load_metadata( reg, folder_path ) )
- return NULL;
-
- enum addon_type type = k_addon_type_none;
- vg_msg msg;
- vg_msg_init( &msg, reg->metadata, reg->metadata_len );
-
- if( vg_msg_seekframe( &msg, "workshop" ))
+ const char *folder_name = folder;
+ for( u32 i=0; i<4096; i ++ )
{
- vg_msg_getkvintg( &msg, "type", k_vg_msg_u32, &type, NULL );
- }
-
- if( type == k_addon_type_none )
- {
- vg_error( "Cannot determine addon type\n" );
- return NULL;
+ if( folder[i] == '/' )
+ {
+ folder_name = folder + i + 1;
+ break;
+ }
+ else if( folder[i] == '\0' )
+ break;
}
- reg->alias.type = type;
- addon_mount_finish( reg );
- return reg;
-}
-
-/*
- * Mount a local folder. may or may not have addon.inf
- */
-addon_reg *addon_mount_local_addon( const char *folder, enum addon_type type, const char *content_ext )
-{
- char folder_path_buf[4096];
- vg_str folder_path;
- vg_strnull( &folder_path, folder_path_buf, 4096 );
- vg_strcat( &folder_path, folder );
-
- const char *folder_name = vg_strch( &folder_path, '/' )+1;
+ VG_MUTEX_LOCK( _addon.registry_lock );
+ u32 registry_count = _addon.registry_count;
+ VG_MUTEX_UNLOCK( _addon.registry_lock );
+
u32 folder_hash = vg_strdjb2(folder_name);
- for( u32 i=0; i<addon_system.registry_count; i++ )
+ for( u32 i=0; i<registry_count; i++ )
{
- addon_reg *reg = &addon_system.registry[i];
-
+ addon_reg *reg = &_addon.registry[i];
if( (reg->alias.type == type) && (reg->foldername_hash == folder_hash) )
{
if( !strcmp( reg->alias.foldername, folder_name ) )
- {
- return reg;
- }
+ return i+1;
}
}
- addon_reg *reg = addon_alloc_reg( 0, type );
- if( !reg ) return NULL;
+ addon_id id = addon_alloc_reg( 0, type );
+ if( !id )
+ return 0;
+
+ addon_reg *reg = &_addon.registry[ id-1 ];
addon_set_foldername( reg, folder_name );
- addon_try_load_metadata( reg, folder_path );
+ bool loaded_metadata = addon_try_load_metadata( reg, folder );
- if( reg->metadata_len )
+ if( loaded_metadata )
{
vg_msg msg;
vg_msg_init( &msg, reg->metadata, reg->metadata_len );
u32 flags = 0x00;
vg_msg_getkvintg( &msg, "flags", k_vg_msg_u32, &flags, NULL );
- reg->flags |= flags;
+ reg->flags = ADDON_REG_MOUNTED | flags;
+ addon_complete_allocation();
+ return id;
}
else
{
- vg_strcat( &folder_path, "" ); /* NOTE: this looks fucky because try_load_metadata edits the buffer, this sets it
- back. to remove the addon.inf which it appened to that buffer (but not
- edit the vg_str)....... */
+ char path_buf[ 4096 ];
+ vg_str folder_path;
+ vg_strnull( &folder_path, path_buf, sizeof(path_buf) );
+ vg_strcat( &folder_path, folder );
+
vg_dir subdir;
- enum dir_open_result result = vg_dir_open(&subdir, folder_path.buffer);
+ enum dir_open_result result = vg_dir_open( &subdir, folder_path.buffer );
if( result != k_dir_open_ok )
{
vg_error( "Failed to open '%s' (%s)\n", folder_path.buffer, dir_open_result_str[result] );
- return NULL;
+ addon_fail_allocation();
+ return 0;
}
/* create our own content commands */
vg_msg_end_frame( &msg );
u32 content_count = 0;
-
while( vg_dir_next_entry(&subdir) )
{
if( vg_dir_entry_type(&subdir) == k_vg_entry_type_file )
{
const char *fname = vg_dir_entry_name(&subdir);
- vg_str file = folder_path;
- vg_strcat( &file, "/" );
- vg_strcat( &file, fname );
- if( !vg_strgood( &file ) ) continue;
-
- char *ext = vg_strch( &file, '.' );
- if( !ext ) continue;
- if( strcmp(ext,content_ext) ) continue;
-
+ vg_str file_path = folder_path;
+ vg_strcat( &file_path, "/" );
+ vg_strcat( &file_path, fname );
+ if( !vg_strgood( &file_path ) )
+ continue;
+
+ char *ext = vg_strch( &file_path, '.' );
+ if( !ext )
+ continue;
+ if( strcmp( ext, content_ext ) )
+ continue;
vg_msg_wkvstr( &msg, "content", fname );
content_count ++;
}
vg_dir_close(&subdir);
if( !content_count )
- return NULL;
+ {
+ addon_fail_allocation();
+ return 0;
+ }
if( msg.error == k_vg_msg_error_OK )
+ {
reg->metadata_len = msg.cur.co;
+ reg->flags = ADDON_REG_MOUNTED;
+ addon_complete_allocation();
+ return id;
+ }
else
{
vg_error( "Error creating metadata: %d\n", msg.error );
- return NULL;
+ addon_fail_allocation();
+ return 0;
}
}
-
- addon_mount_finish( reg );
- return reg;
}
-/*
- * Check all subscribed items
- */
-void addon_mount_workshop_items(void)
+void _addon_mount_content_folder( enum addon_type type, const char *base_folder, const char *content_ext )
{
- if( skaterift.demo_mode )
- {
- vg_info( "Won't load workshop items in demo mode\n" );
- return;
- }
-
- if( !steam_ready )
- return;
-
- /*
- * Steam workshop scan
- */
- vg_info( "Mounting steam workshop subscriptions\n" );
- PublishedFileId_t workshop_ids[ ADDON_MOUNTED_MAX ];
- u32 workshop_count = ADDON_MOUNTED_MAX;
-
- vg_async_item *call = vg_async_alloc( sizeof(struct async_workshop_installed_files_info));
- struct async_workshop_installed_files_info *info = call->payload;
- info->buffer = workshop_ids;
- info->len = &workshop_count;
- vg_async_dispatch( call, async_workshop_get_installed_files );
- vg_async_stall();
-
- for( u32 j=0; j<workshop_count; j++ )
- {
- /* check for existance in both our caches
- * ----------------------------------------------------------*/
- PublishedFileId_t id = workshop_ids[j];
- for( u32 i=0; i<addon_system.registry_count; i++ )
- {
- addon_reg *reg = &addon_system.registry[i];
-
- if( reg->alias.workshop_id == id )
- goto next_file_workshop;
- }
-
- vg_async_item *call1 =
- vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
-
- char path[ 4096 ];
-
- struct async_workshop_filepath_info *info = call1->payload;
- info->buf = path;
- info->id = id;
- info->len = VG_ARRAY_LEN(path);
- vg_async_dispatch( call1, async_workshop_get_filepath );
- vg_async_stall(); /* too bad! */
+ THREAD_1;
- vg_str folder = {.buffer = path, .i=strlen(path), .len=4096};
- addon_mount_workshop_folder( id, folder );
-next_file_workshop:;
- }
-}
-
-/*
- * Scan a local content folder for addons. It must find at least one file with
- * the specified content_ext to be considered.
- */
-void addon_mount_content_folder( enum addon_type type,
- const char *base_folder,
- const char *content_ext )
-{
- vg_info( "Mounting addons(type:%d) matching skaterift/%s/*/*%s\n",
- type, base_folder, content_ext );
+ vg_info( "Mounting addons(type:%d) matching skaterift/%s/*/*%s\n", type, base_folder, content_ext );
char path_buf[4096];
vg_str path;
vg_strcat(&path,"/");
- while( vg_dir_next_entry(&dir) ){
- if( vg_dir_entry_type(&dir) == k_vg_entry_type_dir ){
+ while( vg_dir_next_entry(&dir) )
+ {
+ if( vg_dir_entry_type(&dir) == k_vg_entry_type_dir )
+ {
const char *d_name = vg_dir_entry_name(&dir);
vg_str folder = path;
- if( strlen( d_name ) > ADDON_FOLDERNAME_MAX ){
+ if( strlen( d_name ) > ADDON_FOLDERNAME_MAX )
+ {
vg_warn( "folder too long: %s\n", d_name );
continue;
}
vg_strcat( &folder, d_name );
- if( !vg_strgood( &folder ) ) continue;
-
- addon_mount_local_addon( folder.buffer, type, content_ext );
+ if( !vg_strgood( &folder ) )
+ continue;
+
+ _addon_mount_from_folder( path_buf, type, content_ext );
}
}
vg_dir_close(&dir);
}
-/*
- * write the full path of the addon's folder into the vg_str
+/* workshop mounting
+ * ------------------------------------------------------------------------------------------------------------------
*/
-int addon_get_content_folder( addon_reg *reg, vg_str *folder, int async)
+struct workshop_mount_info
{
- if( reg->alias.workshop_id )
+ u64 workshop_id;
+ char path[];
+};
+static void workshop_mount_task( vg_async_task *task )
+{
+ THREAD_1;
+ struct workshop_mount_info *info = (void *)task->data;
+
+ addon_id id = addon_alloc_reg( info->workshop_id, k_addon_type_none );
+ if( !id )
+ return;
+
+ addon_reg *reg = &_addon.registry[ id-1 ];
+ bool loaded_metadata = addon_try_load_metadata( reg, info->path );
+
+ if( !loaded_metadata )
+ {
+ addon_fail_allocation();
+ return;
+ }
+
+ enum addon_type type = k_addon_type_none;
+ vg_msg msg;
+ vg_msg_init( &msg, reg->metadata, reg->metadata_len );
+
+ if( vg_msg_seekframe( &msg, "workshop" ))
+ vg_msg_getkvintg( &msg, "type", k_vg_msg_u32, &type, NULL );
+
+ if( type == k_addon_type_none )
+ {
+ vg_error( "Cannot determine addon type\n" );
+ addon_fail_allocation();
+ return;
+ }
+
+ reg->alias.type = type;
+ reg->flags = ADDON_REG_MOUNTED;
+ addon_complete_allocation();
+}
+
+struct workshop_scan_info
+{
+ enum workshop_scan_state
+ {
+ k_workshop_scan_state_filter_mounted,
+ k_workshop_scan_state_mount
+ }
+ state;
+
+ u32 count;
+ PublishedFileId_t workshop_ids[ ADDON_MOUNTED_MAX ];
+};
+static void workshop_scan_t1( vg_async_task *co_task )
+{
+ THREAD_1;
+ struct workshop_scan_info *co_info = (void *)co_task->data;
+
+ if( co_info->state == k_workshop_scan_state_filter_mounted )
{
- struct async_workshop_filepath_info *info = NULL;
- vg_async_item *call = NULL;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct workshop_scan_info), 1 );
+ struct workshop_scan_info *info = (void *)task->data;
+ info->state = k_workshop_scan_state_mount;
- if( async )
+ u32 send_count = 0;
+ for( u32 i=0; i<co_info->count; i ++ )
{
- call = vg_async_alloc( sizeof(struct async_workshop_filepath_info) );
- info = call->payload;
+ for( u32 j=0; j<_addon.registry_count; j ++ )
+ {
+ if( _addon.registry[j].alias.workshop_id == co_info->workshop_ids[i] )
+ goto s1;
+ }
+
+ info->workshop_ids[ send_count ++ ] = co_info->workshop_ids[i];
+s1:;
}
- else
- info = alloca( sizeof(struct async_workshop_filepath_info) );
- info->buf = folder->buffer;
- info->id = reg->alias.workshop_id;
- info->len = folder->len;
+ info->count = send_count;
+ vg_async_task_dispatch( task, _mount_workshop_addons );
+ }
+}
+
+void _mount_workshop_addons( vg_async_task *co_task )
+{
+ THREAD_0;
+
+ if( skaterift.demo_mode )
+ {
+ vg_info( "Won't load workshop items in demo mode\n" );
+ return;
+ }
+
+ if( !steam_ready )
+ return;
+
+ ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
- if( async )
+ if( !co_task )
+ {
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct workshop_scan_info), 1 );
+ struct workshop_scan_info *info = (void *)task->data;
+ info->state = k_workshop_scan_state_filter_mounted;
+
+ u32 count = SteamAPI_ISteamUGC_GetSubscribedItems( hSteamUGC, info->workshop_ids, ADDON_MOUNTED_MAX );
+ vg_info( "Found %u subscribed items\n", count );
+
+ u32 send_count = 0;
+
+ for( u32 i=0; i<count; i++ )
{
- vg_async_dispatch( call, async_workshop_get_filepath );
- vg_async_stall(); /* too bad! */
+ u32 state = SteamAPI_ISteamUGC_GetItemState( hSteamUGC, info->workshop_ids[i] );
+ if( !(state & k_EItemStateInstalled) )
+ continue;
+
+ info->workshop_ids[ send_count ++ ] = info->workshop_ids[i];
}
- else
+
+ info->count = send_count;
+ vg_async_task_dispatch( task, workshop_scan_t1 );
+ }
+ else
+ {
+ struct workshop_scan_info *co_info = (void *)co_task->data;
+ for( u32 i=0; i<co_info->count; i ++ )
{
- async_workshop_get_filepath( info, 0 );
+ char path[ 4096 ];
+
+ u64 _size;
+ u32 _ts;
+ if( !SteamAPI_ISteamUGC_GetItemInstallInfo( hSteamUGC, co_info->workshop_ids[i],
+ &_size, path, sizeof(path), &_ts ))
+ {
+ vg_error( "GetItemInstallInfo failed for addon %lu\n", co_info->workshop_ids[i] );
+ continue;
+ }
+
+ u32 len = strlen( path );
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct workshop_mount_info)+len+1, 1 );
+ struct workshop_mount_info *info = (void *)task->data;
+ strcpy( info->path, path );
+ info->workshop_id = co_info->workshop_ids[i];
+ vg_async_task_dispatch( task, workshop_mount_task );
}
+ }
+}
- if( folder->buffer[0] == '\0' )
+bool addon_get_content_folder( addon_id addon_id, vg_str *folder )
+{
+ THREAD_0;
+ VG_ASSERT( addon_id );
+
+ addon_reg *reg = addon_details( addon_id );
+ if( reg->alias.workshop_id )
+ {
+ ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
+ u64 _size;
+ u32 _ts;
+ if( !SteamAPI_ISteamUGC_GetItemInstallInfo( hSteamUGC, reg->alias.workshop_id, &_size,
+ folder->buffer, folder->len, &_ts ))
{
- vg_error( "Failed SteamAPI_GetItemInstallInfo(" PRINTF_U64 ")\n", reg->alias.workshop_id );
+ vg_error( "GetItemInstallInfo failed for addon %lu\n", reg->alias.workshop_id );
return 0;
}
+
folder->i = strlen( folder->buffer );
return 1;
}
else
{
- folder->i = 0;
-
- const char *local_folder =
- addon_type_infos[reg->alias.type].local_content_folder;
+ const char *local_folder = addon_type_infos[reg->alias.type].local_content_folder;
+ if( !local_folder )
+ return 0;
- if( !local_folder ) return 0;
vg_strcat( folder, local_folder );
vg_strcat( folder, reg->alias.foldername );
return 1;
}
}
+#if 0
/*
- * Return existing cache id if reg_index points to a registry with its cache
- * already set.
+ * write the full path of the addon's folder into the vg_str
*/
-u16 addon_cache_fetch( enum addon_type type, u32 reg_index )
-{
- addon_reg *reg = NULL;
-
- if( reg_index < addon_count( type, 0,0 ) )
- {
- reg = get_addon_from_index( type, reg_index, 0,0 );
- if( reg->cache_id )
- return reg->cache_id;
- }
-
- return 0;
-}
+#endif
+#if 0
/*
- * Allocate a new cache item from the pool
+ * cache section
+ * --------------------------------------------------------------------------------------------------------------------
*/
-u16 addon_cache_alloc( enum addon_type type, u32 reg_index )
-{
- struct addon_cache *cache = &addon_system.cache[ type ];
-
- u16 new_id = vg_pool_lru( &cache->pool );
- struct addon_cache_entry *new_entry = vg_pool_item( &cache->pool, new_id );
-
- addon_reg *reg = NULL;
- if( reg_index < addon_count( type, 0,0 ) )
- reg = get_addon_from_index( type, reg_index, 0,0 );
-
- if( new_entry ){
- if( new_entry->reg_ptr )
- new_entry->reg_ptr->cache_id = 0;
-
- if( reg )
- reg->cache_id = new_id;
- new_entry->reg_ptr = reg;
- new_entry->reg_index = reg_index;
- return new_id;
- }
- else{
- vg_error( "cache full (type: %u)!\n", type );
- return 0;
- }
-}
+/*
+ * Return existing cache id if reg_index points to a registry with its cache
+ * already set.
+ */
/*
* Get the real item data for cache id
*/
-void *addon_cache_item( enum addon_type type, u16 id )
-{
- if( !id ) return NULL;
-
- struct addon_cache *cache = &addon_system.cache[type];
- return cache->items + ((size_t)(id-1) * cache->stride);
-}
-
-void *addon_cache_item_arena( enum addon_type type, u16 id )
-{
- VG_ASSERT( id );
- struct addon_cache *cache = &addon_system.cache[type];
- return cache->arenas[ id-1 ];
-}
/*
* Get the real item data for cache id ONLY if the item is completely loaded.
*/
-void *addon_cache_item_if_loaded( enum addon_type type, u16 id )
-{
- if( !id )
- return NULL;
-
- struct addon_cache *cache = &addon_system.cache[type];
- struct addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
-
- if( entry->state == k_addon_cache_state_loaded )
- return addon_cache_item( type, id );
- else
- return NULL;
-}
/*
* Updates the item state from the main thread
void async_addon_setstate( void *_entry, u32 _state )
{
addon_cache_entry *entry = _entry;
- SDL_LockMutex( addon_system.cache_lock );
+ SDL_LockMutex( _addon.cache_lock );
entry->state = _state;
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
vg_success( " loaded (%s)\n", entry->reg_ptr->alias.foldername );
}
return 0;
}
-static void addon_cache_free_item( enum addon_type type, u16 id ){
- if( type == k_addon_type_board ){
- struct player_board *board = addon_cache_item( type, id );
- player_board_unload( board );
- }
- else if( type == k_addon_type_player ){
- struct player_model *model = addon_cache_item( type, id );
- player_model_unload( model );
- }
-}
-
/*
* Goes over cache item load requests and calls the above ^
*/
for( u32 type=0; type<k_addon_type_max; type++ )
{
- struct addon_cache *cache = &addon_system.cache[type];
+ struct addon_cache *cache = &_addon.cache[type];
for( u32 id=1; id<=cache->pool.count; id++ )
{
addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
- SDL_LockMutex( addon_system.cache_lock );
+ SDL_LockMutex( _addon.cache_lock );
if( entry->state == k_addon_cache_state_load_request )
{
vg_info( "process cache load request (%u#%u, reg:%u)\n", type, id, entry->reg_index );
{
/* should maybe have a different value for this case */
entry->state = k_addon_cache_state_none;
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
continue;
}
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
/* continue with the request */
addon_reg *reg = get_addon_from_index( type, entry->reg_index, 0,0 );
}
vg_warn( "cache item did not load (%u#%u)\n", type, id );
- SDL_LockMutex( addon_system.cache_lock );
+ SDL_LockMutex( _addon.cache_lock );
entry->state = k_addon_cache_state_none;
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
}
else
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
}
}
}
{
if( !vg_loader_availible() ) return;
- SDL_LockMutex( addon_system.cache_lock );
+ SDL_LockMutex( _addon.cache_lock );
for( u32 type=0; type<k_addon_type_max; type++ )
{
- struct addon_cache *cache = &addon_system.cache[type];
+ struct addon_cache *cache = &_addon.cache[type];
for( u32 id=1; id<=cache->pool.count; id++ )
{
addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
if( entry->state == k_addon_cache_state_load_request )
{
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
vg_loader_start( T1_addon_cache_load_loop, NULL );
return;
}
}
}
- SDL_UnlockMutex( addon_system.cache_lock );
+ SDL_UnlockMutex( _addon.cache_lock );
+}
+
+#endif
+
+void *addon_cache_item_arena( enum addon_type type, addon_cache_id id )
+{
+ VG_ASSERT( id );
+ struct addon_cache *cache = &_addon.cache[type];
+ return cache->arenas[ id-1 ];
+}
+
+struct cache_complete_info
+{
+ enum addon_type type;
+ addon_cache_id cache_id;
+ enum addon_cache_state result_state;
+};
+static void cache_load_complete( vg_async_task *task )
+{
+ THREAD_0;
+ struct cache_complete_info *info = (void *)task->data;
+
+ struct addon_cache *cache = &_addon.cache[info->type];
+ addon_cache_entry *cache_entry = vg_pool_item( &cache->pool, info->cache_id );
+ cache_entry->state = info->result_state;
+}
+
+struct cache_load_info
+{
+ enum addon_type type;
+ addon_cache_id cache_id;
+
+ char path[];
+};
+static void cache_load_task( vg_async_task *task )
+{
+ THREAD_1;
+ struct cache_load_info *info = (void *)task->data;
+ struct addon_cache *cache = &_addon.cache[info->type];
+ addon_cache_entry *cache_entry = vg_pool_item( &cache->pool, info->cache_id );
+ vg_info( "process cache load request (%u#%u): %s\n", info->type, info->cache_id, info->path );
+
+ /* load content files
+ * --------------------------------- */
+ char path_buf[4096];
+ vg_str content_path;
+ vg_strnull( &content_path, path_buf, sizeof(path_buf) );
+ vg_strcat( &content_path, info->path );
+
+ addon_reg *reg = addon_details( cache_entry->addon_id );
+ vg_msg msg;
+ vg_msg_init( &msg, reg->metadata, reg->metadata_len );
+ enum addon_cache_state result_state = k_addon_cache_state_errored;
+
+ const char *kv_content = vg_msg_getkvstr( &msg, "content" );
+ if( kv_content )
+ {
+ vg_strcat( &content_path, "/" );
+ vg_strcat( &content_path, kv_content );
+ }
+ else
+ {
+ vg_error( " No content paths in metadata\n" );
+ goto e0;
+ }
+
+ if( !vg_strgood( &content_path ) )
+ {
+ vg_error( " Metadata path too long\n" );
+ goto e0;
+ }
+
+ if( info->type == k_addon_type_board )
+ {
+ struct player_board *board = addon_cache_item_data( info->type, info->cache_id, 0 );
+ void *arena = addon_cache_item_arena( info->type, info->cache_id );
+ vg_linear_clear( arena );
+
+ player_board_load( board, content_path.buffer, arena );
+ result_state = k_addon_cache_state_loaded;
+ }
+ else if( info->type == k_addon_type_player )
+ {
+ struct player_model *model = addon_cache_item_data( info->type, info->cache_id, 0 );
+ void *arena = addon_cache_item_arena( info->type, info->cache_id );
+ vg_linear_clear( arena );
+
+ player_model_load( model, content_path.buffer, arena );
+ result_state = k_addon_cache_state_loaded;
+ }
+
+e0:;
+ vg_async_task *res_task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct cache_complete_info), 1 );
+ struct cache_complete_info *complete_info = (void *)res_task->data;
+ complete_info->type = info->type;
+ complete_info->cache_id = info->cache_id;
+ complete_info->result_state = result_state;
+ vg_async_task_dispatch( res_task, cache_load_complete );
}
/*
- * Perform the cache interactions required to create a viewslot which will
- * eventually be loaded by other parts of the system.
+ * cache section
+ * --------------------------------------------------------------------------------------------------------------------
*/
-u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id )
+void _addon_system_pre_update(void)
{
- struct addon_cache *cache = &addon_system.cache[type];
- vg_pool *pool = &cache->pool;
+ for( u32 type=0; type<k_addon_type_max; type++ )
+ {
+ struct addon_cache *cache = &_addon.cache[type];
- u16 cache_id = addon_cache_fetch( type, reg_id );
+ for( u32 id=1; id<=cache->pool.count; id++ )
+ {
+ addon_cache_entry *entry = vg_pool_item( &cache->pool, id );
+ if( entry->state == k_addon_cache_state_load_request )
+ {
+ char path_buf[4096];
+ vg_str folder;
+ vg_strnull( &folder, path_buf, 4096 );
+ if( !addon_get_content_folder( entry->addon_id, &folder ) )
+ {
+ entry->state = k_addon_cache_state_errored;
+ continue;
+ }
+
+ u32 len = strlen( path_buf ) + 1;
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct cache_load_info) + len, 1 );
+ struct cache_load_info *info = (void *)task->data;
+
+ info->type = type;
+ info->cache_id = id;
+ strcpy( info->path, path_buf );
+
+ entry->state = k_addon_cache_state_loading;
+ vg_async_task_dispatch( task, cache_load_task );
+ }
+ }
+ }
+}
+
+void *addon_cache_item_data( enum addon_type type, addon_cache_id cache_id, bool only_if_loaded )
+{
+ if( !cache_id )
+ return NULL;
+
+ struct addon_cache *cache = &_addon.cache[type];
+
+ if( only_if_loaded )
+ {
+ struct addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
+ if( entry->state != k_addon_cache_state_loaded )
+ return NULL;
+ }
+
+ return cache->items + ((size_t)(cache_id-1) * cache->stride);
+}
+
+addon_cache_id addon_cache_create_viewer( enum addon_type type, addon_id addon_id )
+{
+ THREAD_0;
+
+ if( !addon_id )
+ return 0;
+
+ struct addon_cache *cache = &_addon.cache[type];
+ addon_reg *reg = addon_details( addon_id );
+ VG_ASSERT( reg->alias.type == type );
+
+ addon_cache_id cache_id = reg->cache_id;
if( !cache_id )
{
- cache_id = addon_cache_alloc( type, reg_id );
+ struct addon_cache *cache = &_addon.cache[ type ];
+ cache_id = vg_pool_lru( &cache->pool );
- if( cache_id )
+ if( !cache_id )
{
- SDL_LockMutex( addon_system.cache_lock );
- addon_cache_entry *entry = vg_pool_item( pool, cache_id );
+ vg_error( "cache full (type: %u)!\n", type );
+ return 0;
+ }
- if( entry->state == k_addon_cache_state_loaded )
- addon_cache_free_item( type, cache_id );
+ struct addon_cache_entry *new_entry = vg_pool_item( &cache->pool, cache_id );
+ if( new_entry->state == k_addon_cache_state_loaded )
+ {
+ if( type == k_addon_type_board )
+ {
+ player_board_unload( addon_cache_item_data( type, cache_id, 0 ) );
+ }
+ else if( type == k_addon_type_player )
+ {
+ player_model_unload( addon_cache_item_data( type, cache_id, 0 ) );
+ }
+ new_entry->state = k_addon_cache_state_none;
+ }
- entry->state = k_addon_cache_state_load_request;
- SDL_UnlockMutex( addon_system.cache_lock );
+ if( new_entry->addon_id )
+ {
+ addon_reg *previous_owner = addon_details( new_entry->addon_id );
+ previous_owner->cache_id = 0;
}
+
+ new_entry->state = k_addon_cache_state_load_request;
+ new_entry->addon_id = addon_id;
+ reg->cache_id = cache_id;
}
if( cache_id )
- vg_pool_watch( pool, cache_id );
+ vg_pool_watch( &cache->pool, cache_id );
return cache_id;
}
-u16 addon_cache_create_viewer_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] )
+addon_cache_id addon_cache_create_viewer_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] )
{
+ THREAD_0;
+
addon_alias q;
if( !addon_uid_to_alias( uid, &q ) )
return 0;
if( q.type != type )
return 0;
- u32 reg_id = addon_match( &q );
-
- if( reg_id == 0xffffffff )
+ addon_id addon_id = _get_addon_by_alias( &q );
+ if( addon_id )
+ {
+ return addon_cache_create_viewer( type, addon_id );
+ }
+ else
{
vg_warn( "We dont have the addon '%s' installed.\n", uid );
return 0;
}
- else
- return addon_cache_create_viewer( type, reg_id );
}
-void addon_cache_watch( enum addon_type type, u16 cache_id )
+void addon_cache_watch( enum addon_type type, addon_cache_id cache_id )
{
- if( !cache_id ) return;
+ THREAD_0;
+
+ if( !cache_id )
+ return;
- struct addon_cache *cache = &addon_system.cache[type];
- vg_pool *pool = &cache->pool;
- vg_pool_watch( pool, cache_id );
+ struct addon_cache *cache = &_addon.cache[type];
+ vg_pool_watch( &cache->pool, cache_id );
}
-void addon_cache_unwatch( enum addon_type type, u16 cache_id )
+void addon_cache_unwatch( enum addon_type type, addon_cache_id cache_id )
{
+ THREAD_0;
+
if( !cache_id )
return;
- struct addon_cache *cache = &addon_system.cache[type];
- vg_pool *pool = &cache->pool;
- vg_pool_unwatch( pool, cache_id );
+ struct addon_cache *cache = &_addon.cache[type];
+ vg_pool_unwatch( &cache->pool, cache_id );
}
+
#include "vg/vg_mem_pool.h"
#include "vg/vg_string.h"
#include "addon_types.h"
+#include "vg/vg_mutex.h"
typedef struct addon_reg addon_reg;
typedef struct addon_cache_entry addon_cache_entry;
typedef struct addon_alias addon_alias;
+typedef u16 addon_id;
+typedef u16 addon_cache_id;
struct addon_alias
{
char foldername[ ADDON_FOLDERNAME_MAX ];
};
-struct addon_system
+struct _addon
{
struct addon_reg
{
u8 metadata[512]; /* vg_msg buffer */
u32 metadata_len;
u32 flags;
- u16 cache_id;
+ addon_cache_id cache_id;
}
*registry;
u32 registry_count;
-
- /* deffered: updates in main thread */
- u32 registry_type_counts[k_addon_type_max];
+ vg_mutex registry_lock;
struct addon_cache
{
struct addon_cache_entry
{
- u32 reg_index;
- addon_reg *reg_ptr; /* TODO: only use reg_index? */
-
+ addon_id addon_id;
vg_pool_node poolnode;
- enum addon_cache_state{
+ enum addon_cache_state
+ {
k_addon_cache_state_none,
k_addon_cache_state_loaded,
- k_addon_cache_state_load_request
+ k_addon_cache_state_load_request,
+ k_addon_cache_state_loading,
+ k_addon_cache_state_errored
}
state;
}
size_t stride;
}
cache[k_addon_type_max];
- SDL_mutex *cache_lock;
}
-extern addon_system;
+extern _addon;
void addon_system_init( void );
-u32 addon_count( enum addon_type type, u32 whitelist, u32 blacklist );
-addon_reg *get_addon_from_index( enum addon_type type, u32 index, u32 whitelist, u32 blacklist );
-u32 get_index_from_addon( enum addon_type type, addon_reg *a, u32 whitelist, u32 blacklist );
-int addon_get_content_folder( addon_reg *reg, vg_str *folder, int async);
-/* scanning routines */
-u32 addon_match( addon_alias *alias );
-int addon_alias_eq( addon_alias *a, addon_alias *b );
+addon_reg *addon_details( addon_id id );
+u32 _addon_filtered_count( enum addon_type type, u32 whitelist, u32 blacklist );
+addon_id _addon_get_filtered( enum addon_type type, u32 index, u32 whitelist, u32 blacklist );
+bool _addon_get_filtered_index( enum addon_type type, addon_id id, u32 whitelist, u32 blacklist, u32 *out_index );
+addon_id _get_addon_by_alias( addon_alias *alias );
+bool addon_alias_eq( addon_alias *a, addon_alias *b );
void addon_alias_uid( addon_alias *alias, char buf[ADDON_UID_MAX] );
-int addon_uid_to_alias( const char *uid, addon_alias *alias );
-void invalidate_addon_alias( addon_alias *alias );
-void addon_mount_content_folder( enum addon_type type,
- const char *base_folder,
- const char *content_ext );
-void addon_mount_workshop_items(void);
-void async_addon_reg_update( void *data, u32 size );
-addon_reg *addon_mount_local_addon( const char *folder,
- enum addon_type type,
- const char *content_ext );
-u16 addon_cache_fetch( enum addon_type type, u32 reg_index );
-u16 addon_cache_alloc( enum addon_type type, u32 reg_index );
-void *addon_cache_item( enum addon_type type, u16 id );
-void *addon_cache_item_if_loaded( enum addon_type type, u16 id );
-void async_addon_setstate( void *data, u32 size );
+bool addon_uid_to_alias( const char *uid, addon_alias *alias );
+bool addon_get_content_folder( addon_id addon_id, vg_str *folder );
+
+/* Loader thread only
+ * Mount a specific addon from folder path
+ */
+addon_id _addon_mount_from_folder( const char *folder, enum addon_type type, const char *content_ext );
+
+void _addon_mount_content_folder( enum addon_type type, const char *base_folder, const char *content_ext );
+void _mount_workshop_addons( vg_async_task *co_task );
+
+
-void addon_system_pre_update(void);
-u16 addon_cache_create_viewer( enum addon_type type, u16 reg_id);
-void addon_cache_watch( enum addon_type type, u16 cache_id );
-void addon_cache_unwatch( enum addon_type type, u16 cache_id );
-u16 addon_cache_create_viewer_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] );
+void _addon_system_pre_update(void);
+addon_cache_id addon_cache_create_viewer( enum addon_type type, addon_id addon_id );
+addon_cache_id addon_cache_create_viewer_from_uid( enum addon_type type, const char uid[ADDON_UID_MAX] );
+void addon_cache_watch( enum addon_type type, addon_cache_id cache_id );
+void addon_cache_unwatch( enum addon_type type, addon_cache_id cache_id );
+void *addon_cache_item_data( enum addon_type type, addon_cache_id cache_id, bool only_if_loaded );
#define ADDON_REG_VALLEY 0x100
+#define ADDON_REG_MOUNTED 0x10000
+#define ADDON_REG_BROKEN 0x20000
+
#ifdef VG_ENGINE
struct addon_type_info
/* image loader thread
* ---------------------------------------- */
-struct async_board_maker_image_load_thread_data
+struct board_maker_image_info
{
void *data;
i32 w, h;
};
-static void _async_board_maker_image_finish( void *payload, u32 size )
+static void _async_board_maker_image_finish( vg_async_task *task )
{
- struct async_board_maker_image_load_thread_data *inf = payload;
-
+ struct board_maker_image_info *inf = (void *)task->data;
struct board_maker_decal *decal = &_board_maker.decals[ _board_maker.ui_target_part ];
if( decal->loaded )
_board_maker.compositor_state = k_board_maker_compositor_dirty;
}
-static void _board_maker_image_thread( void *_ )
+static void _board_maker_image_t1( void *userdata )
{
- vg_async_item *call = vg_async_alloc( sizeof(struct async_board_maker_image_load_thread_data) );
- struct async_board_maker_image_load_thread_data *inf = call->payload;
-
+ THREAD_1;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct board_maker_image_info), 1 );
+ struct board_maker_image_info *info = (void *)task->data;
i32 nc;
stbi_set_flip_vertically_on_load(1);
- inf->data = stbi_load( _board_maker.browser->current_path, &inf->w, &inf->h, &nc, 4 );
- vg_async_dispatch( call, _async_board_maker_image_finish );
+ info->data = stbi_load( _board_maker.browser->current_path, &info->w, &info->h, &nc, 4 );
+ vg_async_task_dispatch( task, _async_board_maker_image_finish );
}
/* model loader thread
* ----------------------------------------- */
-static void _async_board_maker_load_finish( void *payload, u32 size )
+static void _async_board_maker_load_finish( void *userdata )
{
_board_maker.state = k_board_maker_state_none;
_board_maker.template_loaded = _board_maker.template_selection;
static void _board_maker_load_template( void *_ )
{
+ THREAD_1;
vg_linear_clear( _board_maker.template_heap );
mdl_context *mdl = &_board_maker.template_mdl;
mdl_async_full_load_std( mdl, NULL );
mdl_close( mdl );
-
- vg_async_call( _async_board_maker_load_finish, NULL, 0 );
+ vg_async_call( &vg.main_tasks, _async_board_maker_load_finish, NULL );
}
/* system init thread
* ----------------------------------------------------- */
-static void _async_board_maker_init_finish( void *payload, u32 size )
+static void _async_board_maker_init_finish( void *userdata )
{
+ THREAD_0;
_board_maker.state = k_board_maker_state_none;
}
-static void _board_maker_init_thread( void *_ )
+static void _board_maker_init_t1( void *userdata )
{
+ THREAD_1;
vg_framebuffer_create( &_board_maker.compositor_fb );
- vg_async_call( _async_board_maker_init_finish, NULL, 0 );
+ vg_async_call( &vg.main_tasks, _async_board_maker_init_finish, NULL );
}
static void _board_maker_export(void)
_board_maker.template_loaded = -1;
}
- if( vg_loader_availible() )
- {
- _board_maker.state = k_board_maker_state_loading_template;
- vg_loader_start( _board_maker_load_template, NULL );
- }
+ _board_maker.state = k_board_maker_state_loading_template;
+ vg_async_call( &vg.loader_tasks, _board_maker_load_template, NULL );
}
}
else
{
if( _board_maker.state == k_board_maker_state_not_ready )
{
- if( vg_loader_availible() )
- {
- _board_maker.state = k_board_maker_state_initializing;
- vg_loader_start( _board_maker_init_thread, NULL );
- }
+ _board_maker.state = k_board_maker_state_initializing;
+ vg_async_call( &vg.loader_tasks, _board_maker_init_t1, NULL );
}
else if( _board_maker.state == k_board_maker_state_load_image )
{
- if( vg_loader_availible() )
- {
- vg_loader_start( _board_maker_image_thread, NULL );
- _board_maker.state = k_board_maker_state_loading_image;
- }
+ _board_maker.state = k_board_maker_state_loading_image;
+ vg_async_call( &vg.loader_tasks, _board_maker_image_t1, NULL );
}
else if( _board_maker.state == k_board_maker_state_export )
{
#include "vg/vg_loader.h"
#include "vg/vg_io.h"
#include "vg/vg_audio.h"
-#include "vg/vg_async.h"
#include "client.h"
#include "render.h"
.unreadyness = 2 /* once for client, once for world switcher */
};
-static void async_client_ready( void *payload, u32 size )
+void async_client_ready( void *userdata )
{
+ THREAD_0;
+
g_client.unreadyness --;
if( network_client.auto_connect )
void vg_load(void)
{
+ THREAD_1;
+
//vg_audio.always_keep_compressed = 1;
vg_loader_step( render_init, NULL );
-
game_load();
-
- vg_async_call( async_client_ready, NULL, 0 );
}
void vg_preload(void)
mdl_draw_submesh( &control_overlay.mdl.submeshes[ index ] );
}
-void control_overlay_init(void)
+static void control_overlay_init_finish( void *userdata )
{
- void *alloc = vg_mem.rtmemory;
mdl_context *mdl = &control_overlay.mdl;
-
- mdl_open( mdl, "models/rs_overlay.mdl", alloc );
- mdl_load_metadata_block( mdl, alloc );
- mdl_async_full_load_std( mdl, NULL );
- mdl_close( mdl );
-
- vg_async_stall();
-
if( mdl->texture_count )
{
mdl_texture *tex = &mdl->textures[ 0 ];
control_overlay.tex = vg.tex_missing;
vg_error( "No texture in control overlay\n" );
}
+}
+
+void control_overlay_init(void)
+{
+ void *alloc = vg_mem.rtmemory;
+ mdl_context *mdl = &control_overlay.mdl;
+
+ mdl_open( mdl, "models/rs_overlay.mdl", alloc );
+ mdl_load_metadata_block( mdl, alloc );
+ mdl_async_full_load_std( mdl, NULL );
+ mdl_close( mdl );
+ vg_async_call( &vg.main_tasks, control_overlay_init_finish, NULL );
- vg_console_reg_var( "control_overlay", &control_overlay.enabled,
- k_var_dtype_i32, VG_VAR_PERSISTENT );
+ vg_console_reg_var( "control_overlay", &control_overlay.enabled, k_var_dtype_i32, VG_VAR_PERSISTENT );
}
static void draw_key( bool press, bool wide )
}
}
- if( _world.main.addon->flags & ADDON_REG_MTZERO )
+ addon_reg *world_reg = addon_details( _world.main.addon_id );
+
+ if( world_reg->flags & ADDON_REG_MTZERO )
{
if( world_total & k_ent_route_flag_achieve_gold )
{
steam_store_achievements();
}
}
- else if( _world.main.addon->flags & ADDON_REG_CITY )
+ else if( world_reg->flags & ADDON_REG_CITY )
{
if( world_total & k_ent_route_flag_achieve_silver )
{
#include "save.h"
#include "network.h"
-struct global_skateshop _skateshop =
-{
- .render={.reg_id=0xffffffff,.world_reg=0xffffffff},
-};
+struct global_skateshop _skateshop;
static void skateshop_update_viewpage(void)
{
- u32 page = _skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
+ u32 page = _skateshop.selected_board_index/SKATESHOP_VIEW_SLOT_MAX;
for( u32 i=0; i<SKATESHOP_VIEW_SLOT_MAX; i++ )
{
for( u32 i=0; i<SKATESHOP_VIEW_SLOT_MAX; i++ )
{
struct shop_view_slot *slot = &_skateshop.shop_view_slots[i];
- u32 request_id = page*SKATESHOP_VIEW_SLOT_MAX + i;
- slot->cache_id = addon_cache_create_viewer( k_addon_type_board, request_id );
- }
-}
-
-struct async_preview_load_thread_data
-{
- void *data;
- addon_reg *reg;
-};
-
-static void skateshop_async_preview_imageload( void *data, u32 len )
-{
- struct async_preview_load_thread_data *inf = data;
-
- if( inf->data ){
- glBindTexture( GL_TEXTURE_2D, _skateshop.tex_preview );
- glTexSubImage2D( GL_TEXTURE_2D, 0,0,0,
- WORKSHOP_PREVIEW_WIDTH, WORKSHOP_PREVIEW_HEIGHT,
- GL_RGB, GL_UNSIGNED_BYTE, inf->data );
- glGenerateMipmap( GL_TEXTURE_2D );
- stbi_image_free( inf->data );
-
- skaterift.rt_textures[k_skaterift_rt_workshop_preview] = _skateshop.tex_preview;
- }
- else {
- skaterift.rt_textures[k_skaterift_rt_workshop_preview] = vg.tex_missing;
+ u32 index = page*SKATESHOP_VIEW_SLOT_MAX + i;
+ addon_id addon_id = _addon_get_filtered( k_addon_type_board, index, 0, ADDON_REG_HIDDEN );
+ slot->cache_id = addon_cache_create_viewer( k_addon_type_board, addon_id );
}
-
- SDL_LockMutex( addon_system.cache_lock );
- _skateshop.reg_loaded_preview = inf->reg;
- SDL_UnlockMutex( addon_system.cache_lock );
}
-static void skateshop_update_preview_image_thread(void *_args)
+static void skateshop_init_async( void *userdata )
{
- char path_buf[4096];
- vg_str folder;
- vg_strnull( &folder, path_buf, sizeof(path_buf) );
-
- SDL_LockMutex( addon_system.cache_lock );
- addon_reg *reg_preview = _skateshop.reg_preview;
- SDL_UnlockMutex( addon_system.cache_lock );
-
- if( !addon_get_content_folder( reg_preview, &folder, 1 ) )
- {
- SDL_LockMutex( addon_system.cache_lock );
- _skateshop.reg_loaded_preview = reg_preview;
- SDL_UnlockMutex( addon_system.cache_lock );
- return;
- }
-
- vg_strcat( &folder, "/preview.jpg" );
- vg_async_item *call = vg_async_alloc( sizeof(struct async_preview_load_thread_data) );
- struct async_preview_load_thread_data *inf = call->payload;
-
- inf->reg = reg_preview;
-
- if( vg_strgood( &folder ) )
- {
- stbi_set_flip_vertically_on_load(1);
- int x, y, nc;
- inf->data = stbi_load( folder.buffer, &x, &y, &nc, 3 );
-
- if( inf->data )
- {
- if( (x != WORKSHOP_PREVIEW_WIDTH) || (y != WORKSHOP_PREVIEW_HEIGHT) )
- {
- vg_error( "Resolution does not match framebuffer, so we can't show it\n" );
- stbi_image_free( inf->data );
- inf->data = NULL;
- }
- }
-
- vg_async_dispatch( call, skateshop_async_preview_imageload );
- }
- else
- {
- vg_error( "Path too long to workshop preview image.\n" );
-
- SDL_LockMutex( addon_system.cache_lock );
- _skateshop.reg_loaded_preview = reg_preview;
- SDL_UnlockMutex( addon_system.cache_lock );
- }
-}
-
-void skateshop_world_preview_preupdate(void)
-{
- /* try to load preview image if we availible to do. */
- if( vg_loader_availible() )
- {
- SDL_LockMutex( addon_system.cache_lock );
- if( _skateshop.reg_preview != _skateshop.reg_loaded_preview )
- {
- SDL_UnlockMutex( addon_system.cache_lock );
- vg_loader_start( skateshop_update_preview_image_thread, NULL );
- }
- else SDL_UnlockMutex( addon_system.cache_lock );
- }
-}
-
-static void skateshop_init_async(void *_data,u32 size)
-{
- glGenTextures( 1, &_skateshop.tex_preview );
- glBindTexture( GL_TEXTURE_2D, _skateshop.tex_preview );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, WORKSHOP_PREVIEW_WIDTH, WORKSHOP_PREVIEW_HEIGHT,
- 0, GL_RGB, GL_UNSIGNED_BYTE, NULL );
-
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ THREAD_0;
skaterift.rt_textures[ k_skaterift_rt_workshop_preview ] = vg.tex_missing;
skaterift.rt_textures[ k_skaterift_rt_server_status ] = vg.tex_missing;
*/
void skateshop_init(void)
{
- vg_async_call( skateshop_init_async, NULL, 0 );
+ THREAD_1;
+ vg_async_call( &vg.main_tasks, skateshop_init_async, NULL );
}
-static u16 skateshop_selected_cache_id(void)
+static addon_cache_id skateshop_selected_board_cache_id(void)
{
- if( addon_count(k_addon_type_board, 0,ADDON_REG_HIDDEN) )
+ addon_id id = _addon_get_filtered( k_addon_type_board, _skateshop.selected_board_index, 0, ADDON_REG_HIDDEN );
+ if( id )
{
- addon_reg *reg = get_addon_from_index( k_addon_type_board, _skateshop.selected_board_id, 0, ADDON_REG_HIDDEN );
+ addon_reg *reg = addon_details( id );
return reg->cache_id;
}
else return 0;
}
}
-static void board_scan_thread( void *_args )
+struct skateshop_scan_info
+{
+ enum addon_type type;
+};
+static void skateshop_addon_scan_task( vg_async_task *task )
{
- addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
- addon_mount_workshop_items();
- vg_async_call( async_addon_reg_update, NULL, 0 );
- vg_async_stall();
+ THREAD_1;
+ struct skateshop_scan_info *info = (void *)task->data;
+ if( info->type == k_addon_type_board )
+ _addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
+ else if( info->type == k_addon_type_player )
+ _addon_mount_content_folder( k_addon_type_world, "playermodels", ".mdl" );
+ else if( info->type == k_addon_type_world )
+ _addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" );
}
-static void world_scan_thread( void *_args )
+static void skateshop_scan( enum addon_type specific_type )
{
- addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" );
- addon_mount_workshop_items();
- vg_async_call( async_addon_reg_update, NULL, 0 );
+ THREAD_0;
+ _mount_workshop_addons( NULL );
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct skateshop_scan_info), 1 );
+ struct skateshop_scan_info *info = (void *)task->data;
+ info->type = specific_type;
+ vg_async_task_dispatch( task, skateshop_addon_scan_task );
}
-
static void ent_skateshop_helpers_pickable( const char *acceptance )
{
vg_str text;
srinput.state = k_input_state_resume;
}
-static void skateshop_accept_board( u16 cache_id )
+static void skateshop_accept_board( addon_cache_id cache_id )
{
- vg_info( "chose board from skateshop (%u)\n", _skateshop.selected_board_id );
+ vg_info( "chose board from skateshop (%u)\n", _skateshop.selected_board_index );
addon_cache_unwatch( k_addon_type_board, localplayer.board_view_slot );
addon_cache_watch( k_addon_type_board, cache_id );
localplayer.board_view_slot = cache_id;
static void skateshop_accept_playermodel(void)
{
- addon_reg *addon = get_addon_from_index( k_addon_type_player, _skateshop.selected_player_id, 0, ADDON_REG_HIDDEN );
- u32 real_id = get_index_from_addon( k_addon_type_player, addon,0,0 );
- player__use_model( real_id );
- network_send_item( k_netmsg_playeritem_player );
+ addon_id id = _addon_get_filtered( k_addon_type_player, _skateshop.selected_player_index, 0, ADDON_REG_HIDDEN );
+ if( id )
+ {
+ player__use_model( id );
+ network_send_item( k_netmsg_playeritem_player );
+ }
}
void ent_skateshop_update(void)
/* input */
if( shop->type == k_skateshop_type_boardshop )
{
- if( !vg_loader_availible() )
- return;
-
- u16 cache_id = skateshop_selected_cache_id();
+ addon_cache_id cache_id = skateshop_selected_board_cache_id();
_skateshop.helper_pick->greyed = !cache_id;
/*
* Controls
* ----------------------
*/
- u32 opage = _skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
+ u32 opage = _skateshop.selected_board_index/SKATESHOP_VIEW_SLOT_MAX;
if( button_down( k_srbind_mleft ) )
{
- if( _skateshop.selected_board_id > 0 )
- _skateshop.selected_board_id --;
+ if( _skateshop.selected_board_index > 0 )
+ _skateshop.selected_board_index --;
}
if( button_down( k_srbind_mright ) )
{
- u32 valid_count = addon_count( k_addon_type_board, 0,0 );
- if( _skateshop.selected_board_id+1 < valid_count )
- _skateshop.selected_board_id ++;
+ u32 valid_count = _addon_filtered_count( k_addon_type_board, 0,0 );
+ if( _skateshop.selected_board_index+1 < valid_count )
+ _skateshop.selected_board_index ++;
}
- u32 npage = _skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
+ u32 npage = _skateshop.selected_board_index/SKATESHOP_VIEW_SLOT_MAX;
if( opage != npage )
skateshop_update_viewpage();
}
else if( shop->type == k_skateshop_type_charshop )
{
- if( !vg_loader_availible() )
- return;
-
int changed = 0;
- u32 valid_count = addon_count( k_addon_type_player, 0, ADDON_REG_HIDDEN );
+ u32 valid_count = _addon_filtered_count( k_addon_type_player, 0, ADDON_REG_HIDDEN );
if( button_down( k_srbind_mleft ) )
{
- if( _skateshop.selected_player_id > 0 )
- _skateshop.selected_player_id --;
+ if( _skateshop.selected_player_index > 0 )
+ _skateshop.selected_player_index --;
else
- _skateshop.selected_player_id = valid_count-1;
+ _skateshop.selected_player_index = valid_count-1;
changed = 1;
}
if( button_down( k_srbind_mright ) )
{
- if( _skateshop.selected_player_id+1 < valid_count )
- _skateshop.selected_player_id ++;
+ if( _skateshop.selected_player_index+1 < valid_count )
+ _skateshop.selected_player_index ++;
else
- _skateshop.selected_player_id = 0;
+ _skateshop.selected_player_index = 0;
changed = 1;
}
_skateshop.open = 0;
}
}
- else if( shop->type == k_skateshop_type_worldshop )
- {
-#if 0
- int browseable = 0,
- loadable = 0;
-
- u32 valid_count = addon_count( k_addon_type_world, ADDON_REG_HIDDEN );
-
- if( valid_count && vg_loader_availible() )
- browseable = 1;
-
- if( valid_count && vg_loader_availible() )
- loadable = 1;
-
- _skateshop.helper_browse->greyed = !browseable;
- _skateshop.helper_pick->greyed = !loadable;
-
- addon_reg *selected_world = NULL;
-
- int change = 0;
- if( browseable ){
- if( button_down( k_srbind_mleft ) ){
- if( _skateshop.selected_world_id > 0 ){
- _skateshop.selected_world_id --;
- change = 1;
- }
- }
-
- if( button_down( k_srbind_mright ) ){
- if( _skateshop.selected_world_id+1 < valid_count ){
- _skateshop.selected_world_id ++;
- change = 1;
- }
- }
-
- selected_world = get_addon_from_index( k_addon_type_world,
- _skateshop.selected_world_id, ADDON_REG_HIDDEN );
-
- if( change || (_skateshop.reg_preview == NULL) ){
- SDL_LockMutex( addon_system.cache_lock );
- _skateshop.reg_preview = selected_world;
- SDL_UnlockMutex( addon_system.cache_lock );
- }
- }
-
- if( loadable )
- {
- if( button_down( k_srbind_maccept ) )
- {
- skaterift_switch_world_start( selected_world );
- }
- }
-#endif
- }
else if( shop->type == k_skateshop_type_server )
{
f64 delta = vg.time_real - network_client.last_intent_change;
}
else
{
- if( vg_loader_availible() )
+ if( button_down( k_srbind_use ) )
{
- if( button_down( k_srbind_use ) )
+ ent_skateshop *shop = _skateshop.current_shop;
+ if( shop->type == k_skateshop_type_boardshop )
{
- ent_skateshop *shop = _skateshop.current_shop;
- if( shop->type == k_skateshop_type_boardshop )
- {
- skateshop_update_viewpage();
- vg_loader_start( board_scan_thread, NULL );
- }
-
- gui_helper_reset( k_gui_helper_mode_clear );
- ent_skateshop_helpers_pickable( "Pick" );
- _skateshop.open = 1;
-
- skateshop_playermod( 1 );
+ skateshop_update_viewpage();
+ skateshop_scan( k_addon_type_board );
}
- }
- }
-}
-
-#if 0
-void skateshop_world_preupdate(void)
-{
- world_instance *world = &_world.main;
- for( u32 i=0; i<af_arrcount(&world->ent_skateshop); i++ )
- {
- ent_skateshop *shop = af_arritm( &world->ent_skateshop, i );
-
- if( shop->type == k_skateshop_type_server )
- {
- f32 a = network_client.user_intent;
-
- vg_slewf( &network_client.fintent, a, vg.time_frame_delta );
- a = (vg_smoothstepf( network_client.fintent ) - 0.5f) * (VG_PIf/2.0f);
-
- ent_prop *lever = af_arritm( &world->ent_prop,
- mdl_entity_id_id(shop->server.id_lever) );
- /* we need parent transforms now? */
- q_axis_angle( lever->transform.q, (v3f){0,0,1}, a );
+ gui_helper_reset( k_gui_helper_mode_clear );
+ ent_skateshop_helpers_pickable( "Pick" );
+ _skateshop.open = 1;
+ skateshop_playermod( 1 );
}
}
}
-#endif
static void skateshop_render_boardshop( ent_skateshop *shop, vg_camera *cam )
{
world_instance *world = &_world.main;
u32 slot_count = VG_ARRAY_LEN(_skateshop.shop_view_slots);
- ent_marker *mark_rack = af_arritm( &world->ent_marker,
- mdl_entity_id_id(shop->boards.id_rack)),
- *mark_display = af_arritm( &world->ent_marker,
- mdl_entity_id_id(shop->boards.id_display));
+ ent_marker *mark_rack = af_arritm( &world->ent_marker, mdl_entity_id_id(shop->boards.id_rack)),
+ *mark_display = af_arritm( &world->ent_marker, mdl_entity_id_id(shop->boards.id_display));
- SDL_LockMutex( addon_system.cache_lock );
- struct addon_cache *cache = &addon_system.cache[k_addon_type_board];
+ struct addon_cache *cache = &_addon.cache[k_addon_type_board];
+ u32 page = _skateshop.selected_board_index/SKATESHOP_VIEW_SLOT_MAX;
/* Render loaded boards in the view slots */
for( u32 i=0; i<slot_count; i++ )
goto fade_out;
addon_cache_entry *entry = vg_pool_item( &cache->pool, slot->cache_id );
-
- if( entry->state != k_addon_cache_state_loaded )
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, slot->cache_id, 1 );
+ if( !board )
goto fade_out;
- struct player_board *board =
- addon_cache_item( k_addon_type_board, slot->cache_id );
-
mdl_transform xform;
transform_identity( &xform );
mdl_transform_mul( &mark_rack->transform, &xform, &xform );
- if( entry->reg_index == _skateshop.selected_board_id ){
+ if( page*SKATESHOP_VIEW_SLOT_MAX + i == _skateshop.selected_board_index )
selected = 1.0f;
- }
float t = slot->view_blend;
v3_lerp( xform.co, mark_display->transform.co, t, xform.co );
mlocal[3][2] = -0.7f;
m4x3_mul( mrack, mlocal, mmdl );
- u32 valid_count = addon_count(k_addon_type_board,0,0);
+ u32 valid_count = _addon_filtered_count(k_addon_type_board,0,0);
if( valid_count )
{
char buf[16];
vg_str str;
vg_strnull( &str, buf, sizeof(buf) );
- vg_strcati32( &str, _skateshop.selected_board_id+1 );
+ vg_strcati32( &str, _skateshop.selected_board_index+1 );
vg_strcatch( &str, '/' );
vg_strcati32( &str, valid_count );
font3d_simple_draw( 0, buf, cam, mmdl );
}
- else{
+ else
font3d_simple_draw( 0, "Nothing installed", cam, mmdl );
- }
- u16 cache_id = skateshop_selected_cache_id();
+ u16 cache_id = skateshop_selected_board_cache_id();
struct addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
addon_reg *reg = NULL;
-
- if( entry ) reg = entry->reg_ptr;
+ if( entry )
+ reg = addon_details( entry->addon_id );
if( !reg )
{
- SDL_UnlockMutex( addon_system.cache_lock );
_skateshop.render.item_title = "";
_skateshop.render.item_desc = "";
return;
}
- if( _skateshop.render.reg_id != _skateshop.selected_board_id )
+ if( _skateshop.render.addon_id != entry->addon_id )
{
_skateshop.render.item_title = "";
_skateshop.render.item_desc = "";
vg_msg_skip_frame( &msg );
}
- _skateshop.render.reg_id = _skateshop.selected_board_id;
+ _skateshop.render.addon_id = entry->addon_id;
}
/* Skin title
mlocal[3][2] = 0.0f;
m4x3_mul( mtext, mlocal, mmdl );
font3d_simple_draw( 0, _skateshop.render.item_desc, cam, mmdl );
-
- SDL_UnlockMutex( addon_system.cache_lock );
}
static void skateshop_render_charshop( ent_skateshop *shop, vg_camera *cam )
{
}
-static void skateshop_render_worldshop( ent_skateshop *shop, vg_camera *cam )
-{
- world_instance *world = &_world.main;
-
- ent_marker *mark_display = af_arritm( &world->ent_marker, mdl_entity_id_id(shop->worlds.id_display)),
- *mark_info = af_arritm( &world->ent_marker, mdl_entity_id_id(shop->boards.id_info));
-
- if( _skateshop.render.world_reg != _skateshop.selected_world_id)
- {
- _skateshop.render.world_title = "missing: workshop.title";
- addon_reg *reg = get_addon_from_index( k_addon_type_world, _skateshop.selected_world_id, 0, ADDON_REG_HIDDEN );
-
- if( !reg )
- goto none;
-
- if( reg->alias.workshop_id )
- {
- vg_msg msg;
- vg_msg_init( &msg, reg->metadata, reg->metadata_len );
-
- _skateshop.render.world_loc = vg_msg_getkvstr(&msg,"location");
- _skateshop.render.world_reg = _skateshop.selected_world_id;
-
- if( vg_msg_seekframe( &msg, "workshop" ) )
- {
- _skateshop.render.world_title = vg_msg_getkvstr(&msg,"title");
- vg_msg_skip_frame( &msg );
- }
- else
- vg_warn( "No workshop body\n" );
- }
- else
- _skateshop.render.world_title = reg->alias.foldername;
- }
-
-none:;
-
- /* Text */
- char buftext[128], bufsubtext[128];
- vg_str info, subtext;
- vg_strnull( &info, buftext, 128 );
- vg_strnull( &subtext, bufsubtext, 128 );
-
- u32 valid_count = addon_count(k_addon_type_world,0,ADDON_REG_HIDDEN);
- if( valid_count )
- {
- vg_strcati32( &info, _skateshop.selected_world_id+1 );
- vg_strcatch( &info, '/' );
- vg_strcati32( &info, valid_count );
- vg_strcatch( &info, ' ' );
- vg_strcat( &info, _skateshop.render.world_title );
-
- if( !vg_loader_availible() )
- {
- vg_strcat( &subtext, "Loading..." );
- }
- else
- {
- addon_reg *reg = get_addon_from_index( k_addon_type_world, _skateshop.selected_world_id, 0, ADDON_REG_HIDDEN );
-
- if( reg->alias.workshop_id )
- vg_strcat( &subtext, "(Workshop) " );
-
- vg_strcat( &subtext, _skateshop.render.world_loc );
- }
- }
- else
- {
- vg_strcat( &info, "No workshop worlds installed" );
- }
-
- m4x3f mtext,mlocal,mtextmdl;
- mdl_transform_m4x3( &mark_info->transform, mtext );
-
- font3d_bind( &gui.font, k_font_shader_default, 0, NULL, cam );
- shader_model_font_uColour( (v4f){1.0f,1.0f,1.0f,1.0f} );
-
- float scale = 0.2f, thickness = 0.015f, scale1 = 0.08f;
- m3x3_zero( mlocal );
- m3x3_setdiagonalv3( mlocal, (v3f){ scale, scale, thickness } );
- mlocal[3][0] = -font3d_string_width( 0, buftext );
- mlocal[3][0] *= scale*0.5f;
- mlocal[3][1] = 0.1f;
- mlocal[3][2] = 0.0f;
- m4x3_mul( mtext, mlocal, mtextmdl );
- font3d_simple_draw( 0, buftext, cam, mtextmdl );
-
- m3x3_setdiagonalv3( mlocal, (v3f){ scale1, scale1, thickness } );
- mlocal[3][0] = -font3d_string_width( 0, bufsubtext );
- mlocal[3][0] *= scale1*0.5f;
- mlocal[3][1] = -scale1*0.3f;
- m4x3_mul( mtext, mlocal, mtextmdl );
- font3d_simple_draw( 0, bufsubtext, cam, mtextmdl );
-}
-
void ent_skateshop_render( vg_camera *cam )
{
bool dont_render_ghost = 0;
skateshop_render_boardshop( shop, cam );
else if( shop->type == k_skateshop_type_charshop )
skateshop_render_charshop( shop, cam );
- else if( shop->type == k_skateshop_type_worldshop )
- skateshop_render_worldshop( shop, cam );
else if( shop->type == k_skateshop_type_server ){
}
else
bool changed_playermodel = 0;
if( shop->type == k_skateshop_type_boardshop )
- original_page = _skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
+ original_page = _skateshop.selected_board_index/SKATESHOP_VIEW_SLOT_MAX;
if( menu_button_rect( ctx, left_box, 0, 1, "<" ) )
{
if( shop->type == k_skateshop_type_boardshop )
{
- if( _skateshop.selected_board_id > 0 )
- _skateshop.selected_board_id --;
+ if( _skateshop.selected_board_index > 0 )
+ _skateshop.selected_board_index --;
}
else if( shop->type == k_skateshop_type_charshop )
{
- u32 valid_count = addon_count( k_addon_type_player, 0, ADDON_REG_HIDDEN );
+ u32 valid_count = _addon_filtered_count( k_addon_type_player, 0, ADDON_REG_HIDDEN );
- if( _skateshop.selected_player_id > 0 )
- _skateshop.selected_player_id --;
+ if( _skateshop.selected_player_index > 0 )
+ _skateshop.selected_player_index --;
else
- _skateshop.selected_player_id = valid_count-1;
+ _skateshop.selected_player_index = valid_count-1;
changed_playermodel = 1;
}
{
if( shop->type == k_skateshop_type_boardshop )
{
- u32 valid_count = addon_count( k_addon_type_board, 0,0 );
- if( _skateshop.selected_board_id+1 < valid_count )
- _skateshop.selected_board_id ++;
+ u32 valid_count = _addon_filtered_count( k_addon_type_board, 0,0 );
+ if( _skateshop.selected_board_index+1 < valid_count )
+ _skateshop.selected_board_index ++;
}
else if( shop->type == k_skateshop_type_charshop )
{
- u32 valid_count = addon_count( k_addon_type_player, 0, ADDON_REG_HIDDEN );
- if( _skateshop.selected_player_id+1 < valid_count )
- _skateshop.selected_player_id ++;
+ u32 valid_count = _addon_filtered_count( k_addon_type_player, 0, ADDON_REG_HIDDEN );
+ if( _skateshop.selected_player_index+1 < valid_count )
+ _skateshop.selected_player_index ++;
else
- _skateshop.selected_player_id = 0;
+ _skateshop.selected_player_index = 0;
changed_playermodel = 1;
}
if( shop->type == k_skateshop_type_boardshop )
{
- u32 new_page = _skateshop.selected_board_id/SKATESHOP_VIEW_SLOT_MAX;
+ u32 new_page = _skateshop.selected_board_index/SKATESHOP_VIEW_SLOT_MAX;
if( original_page != new_page )
skateshop_update_viewpage();
}
{
if( shop->type == k_skateshop_type_boardshop )
{
- u16 cache_id = skateshop_selected_cache_id();
+ addon_cache_id cache_id = skateshop_selected_board_cache_id();
if( cache_id )
skateshop_accept_board( cache_id );
}
{
v3f look_target;
- struct shop_view_slot{
- u16 cache_id;
+ struct shop_view_slot
+ {
+ addon_cache_id cache_id;
float view_blend;
}
shop_view_slots[ SKATESHOP_VIEW_SLOT_MAX ];
- u32 selected_world_id,
- selected_board_id,
- selected_player_id,
- pointcloud_world_id;
+ u32 selected_board_index,
+ selected_player_index;
- struct {
+ struct
+ {
const char *item_title, *item_desc;
- u32 reg_id;
-
- const char *world_title, *world_loc;
- u32 world_reg;
+ addon_id addon_id;
}
render;
struct gui_helper *helper_browse;
- addon_reg *reg_preview, *reg_loaded_preview;
- GLuint tex_preview;
-
ent_skateshop *current_shop;
bool open;
}
union
{
u32 timing_version;
- u32 addon_reg;
+ addon_id remote_addon_id;
struct{
u8 ref_count;
struct task_set_username *info = (void *)task->data;
info->steamid = steamid;
vg_strncpy( username, info->name, sizeof(info->name), k_strncpy_always_add_null );
- vg_async_task_dispatch( &_gs_db.tasks, task, task_set_username );
+ vg_async_task_dispatch( task, task_set_username );
}
enum request_status gameserver_cat_table( vg_msg *msg, const char *mod, const char *route, u32 week, const char *alias )
}
replay_inf->buffer_size = output_size;
- vg_async_task_dispatch( &_gs_db.tasks, task, task_write_replay );
+ vg_async_task_dispatch( task, task_write_replay );
flags |= (u8)k_replay_minute_saved;
}
info->steam_id = steamid;
info->last_second = last_second;
info->centiseconds = centiseconds;
- vg_async_task_dispatch( &_gameserver.tasks, task, _gs_replay_async_request_save );
+ vg_async_task_dispatch( task, _gs_replay_async_request_save );
return;
}
descriptor_info->message_length = msg.cur.co;
descriptor_info->last_second = last_second;
descriptor_info->steamid = steamid;
- vg_async_task_dispatch( &_gs_db.tasks, replay_descriptor_task, _gs_replay_write_descriptor );
+ vg_async_task_dispatch( replay_descriptor_task, _gs_replay_write_descriptor );
}
void _gs_replay_server_tick(void)
vg_async_task *run_task = vg_allocate_async_task( &_gs_db.tasks, sizeof(struct task_request_run_info), 1 );
struct task_request_run_info *info = (void *)run_task->data;
info->pool_id = rc->current_request;
- vg_async_task_dispatch( &_gs_db.tasks, run_task, task_request_run );
+ vg_async_task_dispatch( run_task, task_request_run );
req->state = k_request_state_server_processing;
log_request_status( req );
E0:;
vg_async_task *return_task = vg_allocate_async_task( &_gameserver.tasks, sizeof(struct task_request_run_info), 1 );
memcpy( return_task->data, info, sizeof(struct task_request_run_info) );
- vg_async_task_dispatch( &_gameserver.tasks, return_task, task_request_processing_complete );
+ vg_async_task_dispatch( return_task, task_request_processing_complete );
}
void _gs_handle_request_message( u32 client_id, SteamNetworkingMessage_t *msg )
void menu_init(void)
{
vg_console_reg_var( "skip_starter_menu", &menu.skip_starter, k_var_dtype_i32, VG_VAR_PERSISTENT );
- vg_tex2d_load_qoi_async_file( "textures/prem.qoi",
- VG_TEX2D_CLAMP|VG_TEX2D_NOMIP|VG_TEX2D_NEAREST, &menu.prem_tex );
+ vg_tex2d_load_qoi_async_file( "textures/prem.qoi", VG_TEX2D_CLAMP|VG_TEX2D_NOMIP|VG_TEX2D_NEAREST, &menu.prem_tex );
}
static void menu_update_world_filter(void)
menu.world_list_whitelist = ADDON_REG_VENUS;
}
-void menu_on_world_change( addon_reg *addon_reg )
+void menu_on_world_change( addon_id addon )
{
- if( addon_reg == NULL )
+ if( !addon )
return;
+
+ addon_reg *reg = addon_details( addon );
i32 super_id = 0;
- if( addon_reg->flags & ADDON_REG_CAMPAIGN ) super_id = k_superworld_campaign;
- if( addon_reg->flags & ADDON_REG_INFINITE ) super_id = k_superworld_infinite;
- if( addon_reg->flags & ADDON_REG_WORKSHOP ) super_id = k_superworld_steam_workshop;
- if( addon_reg->flags & ADDON_REG_VENUS ) super_id = k_superworld_venus_moon;
+ if( reg->flags & ADDON_REG_CAMPAIGN ) super_id = k_superworld_campaign;
+ if( reg->flags & ADDON_REG_INFINITE ) super_id = k_superworld_infinite;
+ if( reg->flags & ADDON_REG_WORKSHOP ) super_id = k_superworld_steam_workshop;
+ if( reg->flags & ADDON_REG_VENUS ) super_id = k_superworld_venus_moon;
world_map.superworld_actual_world = super_id;
world_map.superworld_list_selected = super_id;
menu_update_world_filter();
- u32 index = get_index_from_addon( k_addon_type_world, addon_reg,
- menu.world_list_whitelist, menu.world_list_blacklist );
- menu.world_list_selected_index[ super_id ] = (index == 0xffffffff)? 0: index;
- menu.clicked_world_reg = addon_reg;
+
+ u32 index = 0;
+ _addon_get_filtered_index( k_addon_type_world, addon, menu.world_list_whitelist, menu.world_list_blacklist, &index );
+ menu.world_list_selected_index[ super_id ] = index;
+ menu.clicked_world_id = addon;
vg_msg msg;
- vg_msg_init( &msg, addon_reg->metadata, addon_reg->metadata_len );
+ vg_msg_init( &msg, reg->metadata, reg->metadata_len );
const char *name = NULL;
if( vg_msg_seekframe( &msg, "workshop" ) )
name = vg_msg_getkvstr( &msg, "title" );
if( !name )
- name = addon_reg->alias.foldername;
+ name = reg->alias.foldername;
menu.clicked_world_name = name;
world_map_initialize_view();
}
menu.world_list_display_count = 0;
}
- menu.world_list_total_count = addon_count( k_addon_type_world, menu.world_list_whitelist, menu.world_list_blacklist );
+ u32 total = _addon_filtered_count( k_addon_type_world, menu.world_list_whitelist, menu.world_list_blacklist );
+ menu.world_list_total_count = total;
menu.world_list_display_count = 0;
i32 *selected_world_index = &menu.world_list_selected_index[ world_map.superworld_list_selected ];
u32 world_index = page_base + i;
if( world_index >= menu.world_list_total_count )
- menu.world_list_entries[i] = NULL;
+ menu.world_list_entries[i] = 0;
else
{
- addon_reg *reg = get_addon_from_index( k_addon_type_world, world_index,
- menu.world_list_whitelist, menu.world_list_blacklist );
+ addon_id addon_id = _addon_get_filtered( k_addon_type_world, world_index,
+ menu.world_list_whitelist, menu.world_list_blacklist );
+ VG_ASSERT( addon_id );
+ addon_reg *reg = addon_details( addon_id );
bool unlocked = 1;
-
if( reg->flags & ADDON_REG_MTZERO )
unlocked = _skaterift_script_nugget_status( "unlock_mtzero" )?1:0;
if( reg->flags & ADDON_REG_CITY )
if( reg->flags & ADDON_REG_VALLEY )
unlocked = _skaterift_script_nugget_status( "unlock_valley" )?1:0;
- menu.world_list_entries[ menu.world_list_display_count ] = unlocked? reg: NULL;
+ menu.world_list_entries[ menu.world_list_display_count ] = unlocked? addon_id: 0;
if( unlocked )
{
vg_msg_init( &msg, reg->metadata, reg->metadata_len );
if( vg_msg_seekframe( &msg, "workshop" ) )
- {
name = vg_msg_getkvstr( &msg, "title" );
- }
if( !name )
name = reg->alias.foldername;
menu.world_list_names[ menu.world_list_display_count ] = name;
}
else
- {
menu.world_list_names[ menu.world_list_display_count ] = "...";
- }
menu.world_list_display_count ++;
}
}
GLuint prem_tex;
- addon_reg *world_list_entries[ MENU_WORLD_MAX_COUNT ];
+ addon_id world_list_entries[ MENU_WORLD_MAX_COUNT ];
const char *world_list_names[ MENU_WORLD_MAX_COUNT ];
i32 world_list_display_count,
u32 world_list_whitelist,
world_list_blacklist;
- addon_reg *clicked_world_reg;
+ addon_id clicked_world_id;
const char *clicked_world_name;
}
extern menu;
bool menu_viewing_map(void);
bool menu_viewing_preview(void);
void menu_update_world_list(void);
-void menu_on_world_change( addon_reg *addon_reg );
+void menu_on_world_change( addon_id addon );
bool menu_button_rect( ui_context *ctx, ui_rect rect, bool select, bool clickable, const char *text );
}
}
-static void sync_cutscene_loaded( void *payload, u32 size )
+static void sync_cutscene_loaded( void *userdata )
{
+ THREAD_0;
+
vg_info( "Cutscene loaded\n" );
_cutscene.state = k_cutscene_state_ready;
}
-static void cutscene_load_thread( void *data )
+struct cutscene_load_info
+{
+ u32 nothing;
+ char path[];
+};
+static void cutscene_load_thread( vg_async_task *task )
{
- const char *path = data;
- vg_info( "Loading cutscene: %s\n", path );
+ struct cutscene_load_info *info = (void *)task->data;
+ vg_info( "Loading cutscene: %s\n", info->path );
u32 size = 20*1024*1024;
- _cutscene.arena =
- _vg_create_linear_allocator( NULL, size, VG_MEMORY_SYSTEM, "Cutscene" );
-
- metascene_load( &_cutscene.meta, path, _cutscene.arena );
+ _cutscene.arena = _vg_create_linear_allocator( NULL, size, VG_MEMORY_SYSTEM, "Cutscene" );
+ metascene_load( &_cutscene.meta, info->path, _cutscene.arena );
_cutscene.instance_count = af_arrcount( &_cutscene.meta.instances );
- _cutscene.instances = vg_linear_alloc( _cutscene.arena,
- sizeof(struct cs_instance) * _cutscene.instance_count );
+ _cutscene.instances = vg_linear_alloc( _cutscene.arena, sizeof(struct cs_instance) * _cutscene.instance_count );
_cutscene.refs = NULL;
_cutscene.unique_refs = 0;
}
}
- vg_async_call( sync_cutscene_loaded, NULL, 0 );
+ vg_async_call( &vg.main_tasks, sync_cutscene_loaded, NULL );
}
static int cmd_cutscene_load( int argc, const char *argv[] )
return 0;
}
- if( vg_loader_availible() )
- {
- _cutscene.state = k_cutscene_state_loading;
- _cutscene.time = 0.0f;
- _cutscene.strip = 0;
- _cutscene.active_samplers = 0;
-
- vg_linear_clear( vg_async.buffer );
- u32 len = strlen( argv[0] ) +1;
- char *path_buf = vg_linear_alloc( vg_async.buffer, len );
- strcpy( path_buf, argv[0] );
- vg_loader_start( cutscene_load_thread, path_buf );
- return 1;
- }
- else
- {
- vg_error( "The loading thread is currently occupied.\n" );
- return 0;
- }
+ _cutscene.state = k_cutscene_state_loading;
+ _cutscene.time = 0.0f;
+ _cutscene.strip = 0;
+ _cutscene.active_samplers = 0;
+
+ u32 len = strlen( argv[0] ) +1;
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct cutscene_load_info) + len, 1 );
+ struct cutscene_load_info *info = (void *)task->data;
+ strcpy( info->path, argv[0] );
+ vg_async_task_dispatch( task, cutscene_load_thread );
+ return 1;
}
else
{
#include "vg/vg_io.h"
#ifdef VG_3D
-#include "vg/vg_async.h"
#include "vg/vg_tex.h"
#endif
glmesh *mesh;
};
-static void _sync_mdl_load_glmesh( void *payload, u32 size )
+static void _sync_mdl_load_glmesh( vg_async_task *task )
{
- struct payload_glmesh_load *job = payload;
+ THREAD_0;
+
+ struct payload_glmesh_load *job = (void *)task->data;
mesh_upload( job->mesh, job->verts, job->vertex_count, job->indices, job->indice_count );
}
void mdl_async_load_glmesh( mdl_context *mdl, glmesh *mesh, u32 *fixup_table )
{
+ THREAD_1;
+
array_file_meta *arr_vertices = af_find_array( &mdl->af, "mdl_vert" );
array_file_meta *arr_indices = af_find_array( &mdl->af, "mdl_indice" );
size_hdr = vg_align8(sizeof(struct payload_glmesh_load)),
total = size_hdr + size_verts + size_indices;
- vg_async_item *call = vg_async_alloc( total );
- struct payload_glmesh_load *job = call->payload;
-
- u8 *payload = call->payload;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, total, 1 );
+ struct payload_glmesh_load *job = (void *)task->data;
job->mesh = mesh;
- job->verts = (void*)(payload + size_hdr);
- job->indices = (void*)(payload + size_hdr + size_verts);
+ job->verts = (void*)(task->data + size_hdr);
+ job->indices = (void*)(task->data + size_hdr + size_verts);
job->vertex_count = arr_vertices->item_count;
job->indice_count = arr_indices->item_count;
-
af_load_array_file_buffer( &mdl->af, arr_vertices, job->verts, sizeof(mdl_vert) );
af_load_array_file_buffer( &mdl->af, arr_indices, job->indices, sizeof(mdl_indice) );
* -------------------------
*/
- vg_async_dispatch( call, _sync_mdl_load_glmesh );
+ vg_async_task_dispatch( task, _sync_mdl_load_glmesh );
}
else
{
if( (type == k_netmsg_playeritem_world0) || (type == k_netmsg_playeritem_world1) )
{
- addon_reg *reg = _world.main.addon;
-
- if( reg )
- addon_alias_uid( ®->alias, item->uid );
- else
- item->uid[0] = '\0';
+ addon_uid( _world.main.addon_id, item->uid );
}
else
{
addon_type = k_addon_type_player;
}
- struct addon_cache *cache = &addon_system.cache[addon_type];
- vg_pool *pool = &cache->pool;
-
- SDL_LockMutex( addon_system.cache_lock );
- addon_cache_entry *entry = vg_pool_item( pool, view_id );
- addon_alias_uid( &entry->reg_ptr->alias, item->uid );
- SDL_UnlockMutex( addon_system.cache_lock );
+ struct addon_cache *cache = &_addon.cache[addon_type];
+ addon_cache_entry *entry = vg_pool_item( &cache->pool, view_id );
+ addon_uid( entry->addon_id, item->uid );
}
- vg_info( "send equip: [%u] %s\n",
- item->type_index, item->uid );
+ vg_info( "send equip: [%u] %s\n", item->type_index, item->uid );
u32 chs = strlen(item->uid);
-
- SteamAPI_ISteamNetworkingSockets_SendMessageToConnection(
- hSteamNetworkingSockets, network_client.remote,
- item, sizeof(netmsg_playeritem)+chs+1,
- k_nSteamNetworkingSend_Reliable, NULL );
+ SteamAPI_ISteamNetworkingSockets_SendMessageToConnection( hSteamNetworkingSockets, network_client.remote,
+ item, sizeof(netmsg_playeritem)+chs+1,
+ k_nSteamNetworkingSend_Reliable, NULL );
}
static void network_disconnect(void)
void network_set_host( const char *host_str, const char *port_str )
{
- vg_strncpy( host_str, network_client.host_adress,
- sizeof(network_client.host_adress), k_strncpy_overflow_fatal );
+ vg_strncpy( host_str, network_client.host_adress, sizeof(network_client.host_adress), k_strncpy_overflow_fatal );
memset( &network_client.ip, 0, sizeof(network_client.ip) );
- network_client.ip_resolved = 0;
+ network_client.resolve_state = k_resolve_state_no;
if( port_str )
{
- vg_strncpy( port_str, network_client.host_port,
- sizeof(network_client.host_port), k_strncpy_overflow_fatal );
+ vg_strncpy( port_str, network_client.host_port, sizeof(network_client.host_port), k_strncpy_overflow_fatal );
}
else
{
vg_str str;
- vg_strnull( &str, network_client.host_port,
- sizeof(network_client.host_port) );
+ vg_strnull( &str, network_client.host_port, sizeof(network_client.host_port) );
vg_strcati32( &str, NETWORK_PORT );
}
static void network_connect(void)
{
- VG_ASSERT( network_client.ip_resolved );
+ VG_ASSERT( network_client.resolve_state == k_resolve_state_resolved );
vg_info( "connecting...\n" );
- network_client.remote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(
- hSteamNetworkingSockets, &network_client.ip, 0, NULL );
+ network_client.remote = SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(
+ hSteamNetworkingSockets, &network_client.ip, 0, NULL );
}
static void network_sign_on_complete(void)
}
}
-static void network_resolve_host_async( void *payload, u32 size )
+struct resolve_info
{
- u32 *status = payload;
- network_client.ip_resolved = *status;
-
- char buf[256];
- SteamAPI_SteamNetworkingIPAddr_ToString( &network_client.ip, buf, 256, 1 );
- vg_info( "Resolved host address to: %s\n", buf );
-}
-
-static void network_resolve_host_thread( void *_ )
-{
- vg_async_item *call = vg_async_alloc(8);
- u32 *status = call->payload;
- *status = 0;
+ enum resolve_opt
+ {
+ k_resolve_opt_resolve,
+ k_resolve_opt_parse_numeric,
+ k_resolve_opt_ipv6,
+ k_resolve_opt_fail
+ }
+ opt;
- if( (network_client.host_adress[0] >= '0') &&
- (network_client.host_adress[0] <= '9') )
+ union
{
- SteamAPI_SteamNetworkingIPAddr_ParseString(
- &network_client.ip,
- network_client.host_adress );
- network_client.ip.m_port = atoi( network_client.host_port );
- *status = 1;
- goto end;
+ struct
+ {
+ char port[8], adress[256];
+ }
+ host;
+ struct addrinfo *ipv6;
}
+ alias;
+};
+static void _network_resolve_host( vg_async_task *co_task )
+{
+ VG_ASSERT( co_task );
- vg_info( "Resolving host.. %s (:%s)\n",
- network_client.host_adress, network_client.host_port );
+ if( co_task )
+ {
+ struct resolve_info *co_info = (void *)co_task->data;
+ if( co_info->opt == k_resolve_opt_resolve )
+ {
+ THREAD_1;
- struct addrinfo hints;
- struct addrinfo *result;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct resolve_info), 1 );
+ struct resolve_info *info = (void *)task->data;
+ vg_info( "Resolving host.. %s (:%s)\n", co_info->alias.host.adress, co_info->alias.host.port );
- /* Obtain address(es) matching host/port. */
+ /* Obtain address(es) matching host/port. */
- memset( &hints, 0, sizeof(hints) );
- hints.ai_family = AF_INET6;
- hints.ai_socktype = SOCK_DGRAM;
- hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
- hints.ai_protocol = 0;
+ struct addrinfo hints;
+ memset( &hints, 0, sizeof(hints) );
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG;
+ hints.ai_protocol = 0;
- int s = getaddrinfo( network_client.host_adress, network_client.host_port,
- &hints, &result);
- if( s != 0 )
- {
+ int s = getaddrinfo( co_info->alias.host.adress, co_info->alias.host.port, &hints, &info->alias.ipv6 );
+ if( s != 0 )
+ {
#ifndef _WIN32
- vg_error( "getaddrinfo: %s\n", gai_strerror(s) );
+ vg_error( "getaddrinfo: %s\n", gai_strerror(s) );
#endif
+ if( !strcmp( co_info->alias.host.adress, "skaterift.com" ) )
+ {
+ vg_warn( "getaddrinfo failed for skaterift.com;\n "
+ "falling back to a hardcoded IPv4. This might be wrong.\n" );
+
+ strcpy( info->alias.host.adress, "46.101.34.155" );
+ strcpy( info->alias.host.port, "27403" );
+ info->opt = k_resolve_opt_parse_numeric;
+ vg_async_task_dispatch( task, _network_resolve_host );
+ return;
+ }
+ else
+ {
+ info->opt = k_resolve_opt_fail;
+ vg_async_task_dispatch( task, _network_resolve_host );
+ return;
+ }
+ }
+ else
+ {
+ info->opt = k_resolve_opt_ipv6;
+ vg_async_task_dispatch( task, _network_resolve_host );
+ return;
+ }
+ }
+ else
+ {
+ THREAD_0;
+
+ strcpy( network_client.host_adress, co_info->alias.host.adress );
+ strcpy( network_client.host_port, co_info->alias.host.port );
- if( !strcmp( network_client.host_adress, "skaterift.com" ) )
+ if( co_info->opt == k_resolve_opt_fail )
+ {
+ network_client.resolve_state = k_resolve_state_no;
+ return;
+ }
+ else if( co_info->opt == k_resolve_opt_ipv6 )
+ {
+ struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)co_info->alias.ipv6->ai_addr;
+ memcpy( network_client.ip.m_ipv6, &inaddr->sin6_addr, 16 );
+ freeaddrinfo( co_info->alias.ipv6 );
+ network_client.resolve_state = k_resolve_state_resolved;
+ return;
+ }
+ else if( co_info->opt == k_resolve_opt_parse_numeric )
+ goto parse_numeric;
+ }
+ }
+ else
+ {
+ THREAD_0;
+ if( (network_client.host_adress[0] >= '0') && (network_client.host_adress[0] <= '9') )
+ goto parse_numeric;
+ else
{
- vg_warn( "getaddrinfo failed for skaterift.com;\n "
- "falling back to a hardcoded IPv4\n" );
- strcpy( network_client.host_adress, "46.101.34.155" );
- SteamAPI_SteamNetworkingIPAddr_ParseString(
- &network_client.ip,
- network_client.host_adress );
- network_client.ip.m_port = NETWORK_PORT;
- *status = 1;
+ network_client.resolve_state = k_resolve_state_resolving;
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct resolve_info), 1 );
+ struct resolve_info *info = (void *)task->data;
+ info->opt = k_resolve_opt_resolve;
+ strcpy( info->alias.host.port, network_client.host_port );
+ strcpy( info->alias.host.adress, network_client.host_adress );
+ vg_async_task_dispatch( task, _network_resolve_host );
+ return;
}
-
- goto end;
}
- struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)result->ai_addr;
- memcpy( network_client.ip.m_ipv6, &inaddr->sin6_addr, 16 );
- freeaddrinfo( result );
-
- *status = 1;
+ VG_ASSERT(0);
+parse_numeric:
-end: vg_async_dispatch( call, network_resolve_host_async );
+ THREAD_0;
+ SteamAPI_SteamNetworkingIPAddr_ParseString( &network_client.ip, network_client.host_adress );
+ network_client.ip.m_port = atoi( network_client.host_port );
+ network_client.resolve_state = k_resolve_state_resolved;
}
void network_update(void)
if( waited < min_wait )
return;
- if( !network_client.ip_resolved )
- {
- if( vg_loader_availible() )
- {
- vg_loader_start( network_resolve_host_thread, NULL );
- }
- else return;
- }
- else
+ if( network_client.resolve_state == k_resolve_state_no )
+ _network_resolve_host(NULL);
+ else if( network_client.resolve_state == k_resolve_state_resolved )
network_connect();
network_client.retries ++;
SteamNetworkingIPAddr ip;
char host_port[8], host_adress[256];
- bool ip_resolved;
+
+ enum resolve_state
+ {
+ k_resolve_state_no,
+ k_resolve_state_resolving,
+ k_resolve_state_resolved
+ }
+ resolve_state;
enum server_intent {
k_server_intent_offline,
#include "vg/vg_lines.h"
-#include "vg/vg_async.h"
#include "particle.h"
#include "shaders/particle.h"
}
}
-struct particle_init_args {
+struct particle_init_args
+{
particle_system *sys;
u16 indices[];
};
-
-static void async_particle_init( void *payload, u32 size ){
- struct particle_init_args *args = payload;
+static void particle_init_task( vg_async_task *task )
+{
+ struct particle_init_args *args = (void *)task->data;
particle_system *sys = args->sys;
glGenVertexArrays( 1, &sys->vao );
glBindBuffer( GL_ARRAY_BUFFER, sys->vbo );
glBufferData( GL_ARRAY_BUFFER, sys->max*stride*4, NULL, GL_DYNAMIC_DRAW );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, sys->ebo );
- glBufferData( GL_ELEMENT_ARRAY_BUFFER,
- sys->max*sizeof(u16)*6, args->indices, GL_STATIC_DRAW );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER, sys->max*sizeof(u16)*6, args->indices, GL_STATIC_DRAW );
/* 0: coordinates */
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
glEnableVertexAttribArray( 0 );
/* 3: colour */
- glVertexAttribPointer( 1, 4, GL_UNSIGNED_BYTE, GL_TRUE,
- stride, (void *)offsetof(particle_vert, colour) );
+ glVertexAttribPointer( 1, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void *)offsetof(particle_vert, colour) );
glEnableVertexAttribArray( 1 );
}
sys->array = vg_linear_alloc( vg_mem.rtmemory, max*sizeof(particle) );
sys->vertices = vg_linear_alloc( vg_mem.rtmemory, max*stride*4 );
- vg_async_item *call =
- vg_async_alloc( sizeof(particle_system *) + max*sizeof(u16)*6 );
- struct particle_init_args *init = call->payload;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(particle_system *) + max*sizeof(u16)*6, 1 );
+ struct particle_init_args *init = (void *)task->data;
init->sys = sys;
- for( u32 i=0; i<max; i ++ ){
+ for( u32 i=0; i<max; i ++ )
+ {
init->indices[i*6+0] = i*4;
init->indices[i*6+1] = i*4+1;
init->indices[i*6+2] = i*4+2;
init->indices[i*6+4] = i*4+2;
init->indices[i*6+5] = i*4+3;
}
-
- vg_async_dispatch( call, async_particle_init );
+ vg_async_task_dispatch( task, particle_init_task );
}
void particle_system_prerender( particle_system *sys )
* Appearence
*/
-void player__use_model( u16 reg_id )
+void player__use_model( addon_id addon_id )
{
addon_cache_unwatch( k_addon_type_player, localplayer.playermodel_view_slot );
- localplayer.playermodel_view_slot = addon_cache_create_viewer( k_addon_type_player, reg_id );
+ localplayer.playermodel_view_slot = addon_cache_create_viewer( k_addon_type_player, addon_id );
}
void player__bind(void)
_world.copy_of_nonlocal_sender.key = 0;
_world.copy_of_nonlocal_sender.submesh_start = 0;
_world.copy_of_nonlocal_sender.submesh_count = 0;
-
- vg_strncpy( af_str( &world->meta.af, gate->key ),
- _world.nonlocal_destination_key, 32,
- k_strncpy_overflow_fatal );
-
+ vg_strncpy( af_str( &world->meta.af, gate->key ), _world.nonlocal_destination_key, 32, k_strncpy_overflow_fatal );
player__clean_refs();
-
- addon_reg *reg = get_addon_from_index( k_addon_type_world, gate->addon_reg, 0,0 );
- skaterift_load_world_start( reg, 0 );
+ skaterift_load_world_start( gate->remote_addon_id, 0 );
return;
}
else
g_player_debugger[3] = 32;
char buf[96];
- if( _world.main.addon )
- addon_alias_uid( &_world.main.addon->alias, buf );
+ if( _world.main.addon_id )
+ addon_uid( _world.main.addon_id, buf );
else
strcpy( buf, "none" );
player__debugtext( ctx, 1, "world #%u: %s", 0, buf );
addon_alias q;
addon_uid_to_alias( player->items[k_netmsg_playeritem_world0], &q );
- if( addon_alias_eq( &q, &_world.main.addon->alias ) )
+ addon_reg *current_world_reg = addon_details( _world.main.addon_id );
+ if( addon_alias_eq( &q, ¤t_world_reg->alias ) )
player->same_world = 1;
}
}
}
- // FIXME: Need to redo addon caching. board can be in race condition here!
struct network_player *player = &netplayers.list[ index ];
struct skeleton *sk = &localplayer.skeleton;
m4x3f *final_mtx = &netplayers.final_mtx[ sk->bone_count*index ];
v3f *glider_mtx = netplayers.glider_mtx[ index ];
struct player_board_pose *board_pose = &netplayers.board_poses[index];
- struct player_board *board = addon_cache_item_if_loaded( k_addon_type_board, player->board_view_slot );
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, player->board_view_slot, 1 );
struct player_effects_data *effects = &player->effect_data;
bool *glider_flag = &player->render_glider;
struct skeleton *sk = &localplayer.skeleton;
- // TODO: Make this a reference count instead of mutex?
- SDL_LockMutex( addon_system.cache_lock );
for( u32 j=0; j<draw_list_count; j ++ )
{
u32 index = draw_list[j];
struct network_player *player = &netplayers.list[index];
m4x3f *final_mtx = &netplayers.final_mtx[ sk->bone_count*index ];
- struct player_model *model = addon_cache_item_if_loaded( k_addon_type_player, player->playermodel_view_slot );
-
- if( !model )
- model = &localplayer.fallback_model;
+ struct player_model *model = addon_cache_item_data( k_addon_type_player, player->playermodel_view_slot, 1 );
render_playermodel( cam, world, 0, model, sk, final_mtx );
- struct player_board *board = addon_cache_item_if_loaded( k_addon_type_board, player->board_view_slot );
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, player->board_view_slot, 1 );
render_board( cam, world, board, final_mtx[localplayer.id_board],
&netplayers.board_poses[ index ], k_board_shader_player );
}
- SDL_UnlockMutex( addon_system.cache_lock );
if( !gliders )
return;
/* TODO: allow error handling */
void player_board_load( player_board *board, const char *path, void *arena )
{
+ THREAD_1;
+
mdl_open( &board->mdl, path, arena );
mdl_load_metadata_block( &board->mdl, arena );
mdl_async_full_load_std( &board->mdl, NULL );
u32 index = mdl_entity_id_id( mesh->entity_id );
ent_marker *marker = af_arritm( &markers, index );
-
mdl_submesh *sm0 = &board->mdl.submeshes[ mesh->submesh_start ];
const char *alias = af_str( &board->mdl.af, marker->pstr_alias );
void player__animate(void)
{
- struct player_subsystem_interface *sys =
- player_subsystems[localplayer.subsystem];
+ struct player_subsystem_interface *sys = player_subsystems[localplayer.subsystem];
- struct player_board *board =
- addon_cache_item_if_loaded( k_addon_type_board,
- localplayer.board_view_slot );
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, localplayer.board_view_slot, 1 );
+ if( !board )
+ board = &localplayer.fallback_board;
sys->animate();
&localplayer.pose, vg.time_delta );
apply_full_skeleton_pose( sk, &localplayer.pose, localplayer.final_mtx );
- if( sys->effects ){
- sys->effects( sys->animator_data, localplayer.final_mtx, board,
- &localplayer.effect_data );
- }
+ if( sys->effects )
+ sys->effects( sys->animator_data, localplayer.final_mtx, board, &localplayer.effect_data );
skeleton_debug( sk, localplayer.final_mtx );
player__cam_iterate();
}
-static void player_copy_frame_animator( replay_frame *frame ){
- struct player_subsystem_interface *sys =
- player_subsystems[localplayer.subsystem];
+static void player_copy_frame_animator( replay_frame *frame )
+{
+ struct player_subsystem_interface *sys = player_subsystems[localplayer.subsystem];
- if( sys->animator_size ){
+ if( sys->animator_size )
+ {
void *src = replay_frame_data( frame, k_replay_framedata_animator );
memcpy( sys->animator_data, src, sys->animator_size );
}
}
-void lerp_player_pose( player_pose *pose0, player_pose *pose1, f32 t,
- player_pose *posed ){
+void lerp_player_pose( player_pose *pose0, player_pose *pose1, f32 t, player_pose *posed )
+{
struct skeleton *sk = &localplayer.skeleton;
v3_lerp( pose0->root_co, pose1->root_co, t, posed->root_co );
posed->type = pose0->type;
posed->board.lean = vg_lerpf( pose0->board.lean, pose1->board.lean, t );
- if( pose0->type != pose1->type ){
+ if( pose0->type != pose1->type )
+ {
/* it would be nice to apply IK pass in-keyframes. TOO BAD! */
skeleton_copy_pose( sk, pose0->keyframes, posed->keyframes );
}
- else {
- skeleton_lerp_pose( sk, pose0->keyframes, pose1->keyframes, t,
- posed->keyframes );
- }
+ else
+ skeleton_lerp_pose( sk, pose0->keyframes, pose1->keyframes, t, posed->keyframes );
}
void player__observe_system( enum player_subsystem id )
{
- if( id != localplayer.observing_system ){
- struct player_subsystem_interface *sysm1 =
- player_subsystems[ localplayer.observing_system ];
+ if( id != localplayer.observing_system )
+ {
+ struct player_subsystem_interface *sysm1 = player_subsystems[ localplayer.observing_system ];
- if( sysm1->sfx_kill ) sysm1->sfx_kill();
+ if( sysm1->sfx_kill )
+ sysm1->sfx_kill();
localplayer.observing_system = id;
}
}
{
replay_frame *frame = replay->cursor_frame,
*next = NULL;
- if( frame ){
+ if( frame )
+ {
next = frame->r;
- struct player_subsystem_interface
- *sys0 = player_subsystems[frame->system];
+ struct player_subsystem_interface *sys0 = player_subsystems[frame->system];
void *a0 = replay_frame_data( frame, k_replay_framedata_animator );
struct replay_glider_data
f32 t = 0.0f;
- if( next ){
+ if( next )
+ {
t = replay_subframe_time( replay );
player_pose pose0, pose1;
-
- struct player_subsystem_interface
- *sys1 = player_subsystems[next->system];
+ struct player_subsystem_interface *sys1 = player_subsystems[next->system];
void *a1 = replay_frame_data( next, k_replay_framedata_animator );
sys0->pose( a0, &pose0 );
lerp_player_pose( &pose0, &pose1, t, &localplayer.pose );
g1 = replay_frame_data( next, k_replay_framedata_glider );
}
- else{
+ else
+ {
sys0->pose( a0, &localplayer.pose );
g1 = NULL;
}
if( sys0->sfx_comp )
sys0->sfx_comp( a0 );
- if( g0 ){
- if( g0->glider_orphan ){
- if( g1 ){
+ if( g0 )
+ {
+ if( g0->glider_orphan )
+ {
+ if( g1 )
+ {
v3_lerp( g0->co, g1->co, t, player_glide.rb.co );
q_nlerp( g0->q, g1->q, t, player_glide.rb.q );
}
- else {
+ else
+ {
v3_copy( g0->co, player_glide.rb.co );
v4_copy( g0->q, player_glide.rb.q );
}
localplayer.have_glider = g0->have_glider;
localplayer.glider_orphan = g0->glider_orphan;
}
- else /* no glider data in g1, or edge case we dont care about */ {
+ else /* no glider data in g1, or edge case we dont care about */
+ {
localplayer.have_glider = 0;
localplayer.glider_orphan = 0;
player_glide.t = 0.0f;
}
else return;
- apply_full_skeleton_pose( &localplayer.skeleton, &localplayer.pose,
- localplayer.final_mtx );
+ apply_full_skeleton_pose( &localplayer.skeleton, &localplayer.pose, localplayer.final_mtx );
}
void player__pre_render(void)
{
/* shadowing/ao info */
- struct player_board *board =
- addon_cache_item_if_loaded( k_addon_type_board,
- localplayer.board_view_slot );
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, localplayer.board_view_slot, 1 );
v3f vp0, vp1;
- if( board ){
+ if( board )
+ {
v3_copy((v3f){0.0f,0.1f, board->truck_positions[0][2]}, vp0 );
v3_copy((v3f){0.0f,0.1f, board->truck_positions[1][2]}, vp1 );
}
m4x4f m4mdl;
- if( board->board.indice_count ){
+ if( board->board.indice_count )
+ {
m4x3f mlocal;
m3x3_identity( mlocal );
struct skeleton *skeleton,
m4x3f *final_mtx )
{
- if( !model ) return;
+ if( !model )
+ model = &localplayer.fallback_model;
shader_model_character_view_use();
void player__render( vg_camera *cam )
{
world_instance *world = &_world.main;
- SDL_LockMutex( addon_system.cache_lock );
-
- struct player_model *model =
- addon_cache_item_if_loaded( k_addon_type_player,
- localplayer.playermodel_view_slot );
-
- if( !model ) model = &localplayer.fallback_model;
- render_playermodel( cam, world, 1, model, &localplayer.skeleton,
- localplayer.final_mtx );
-
- struct player_board *board =
- addon_cache_item_if_loaded( k_addon_type_board,
- localplayer.board_view_slot );
+ struct player_model *model = addon_cache_item_data( k_addon_type_player, localplayer.playermodel_view_slot, 1 );
+ render_playermodel( cam, world, 1, model, &localplayer.skeleton, localplayer.final_mtx );
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, localplayer.board_view_slot, 1 );
render_board( cam, world, board, localplayer.final_mtx[localplayer.id_board],
- &localplayer.pose.board, k_board_shader_player );
-
- SDL_UnlockMutex( addon_system.cache_lock );
+ &localplayer.pose.board, k_board_shader_player );
glEnable( GL_CULL_FACE );
player_glide_render( cam, world, &localplayer.pose );
vg_lerpf(animator->board_lean, lean, vg.time_delta*18.0f);
/* feet placement */
- struct player_board *board =
- addon_cache_item_if_loaded( k_addon_type_board,
- localplayer.board_view_slot );
- if( board ){
- if( animator->weight > 0.0f ){
- animator->foot_offset[0] =
- board->truck_positions[k_board_truck_back][2]+0.3f;
- }
- else{
- animator->foot_offset[1] =
- board->truck_positions[k_board_truck_front][2]-0.3f;
- }
+ struct player_board *board = addon_cache_item_data( k_addon_type_board, localplayer.board_view_slot, 1 );
+ if( board )
+ {
+ if( animator->weight > 0.0f )
+ animator->foot_offset[0] = board->truck_positions[k_board_truck_back][2]+0.3f;
+ else
+ animator->foot_offset[1] = board->truck_positions[k_board_truck_front][2]-0.3f;
}
f32 slapm = vg_maxf( 1.0f-v3_length2( state->trick_vel ), 0.0f );
animator->slap = state->slap;
- animator->subslap = vg_lerpf( animator->subslap, slapm,
- vg.time_delta*10.0f );
+ animator->subslap = vg_lerpf( animator->subslap, slapm, vg.time_delta*10.0f );
#if 0
f32 l = ((state->activity < k_skate_activity_ground) &&
#include "vg/vg_platform.h"
#include "vg/vg_framebuffer.h"
-static void async_render_init( void *payload, u32 size )
+static void async_render_init( void *userdata )
{
+ THREAD_0;
f32 rh = 0x1p-4f, ih = 0.3f;
float quad[] = {
void render_init(void)
{
+ THREAD_1;
+
vg_console_reg_var( "fov", &k_fov, k_var_dtype_f32, VG_VAR_PERSISTENT );
vg_console_reg_var( "cam_height", &k_cam_height, k_var_dtype_f32, VG_VAR_PERSISTENT );
};
vg_framebuffer_create( g_render.fb_compass );
- vg_async_call( async_render_init, NULL, 0 );
+ vg_async_call( &vg.main_tasks, async_render_init, NULL );
}
/*
}
}
- _remote_replay.state = k_remote_replay_state_downloading;
+ _remote_replay.state = k_remote_replay_state_waitnext;
return;
}
_replay2_seek( frame_end->time, 0 );
}
}
+ else
+ _remote_replay.state = k_remote_replay_state_waitnext;
return;
}
u32 data_length;
u8 data[];
};
-
-static void async_cache_check_result( void *payload, u32 size )
+static void async_cache_check_result( vg_async_task *task )
{
- struct async_cache_check_result *result = payload;
+ THREAD_0;
+ struct async_cache_check_result *result = (void *)task->data;
if( result->found_in_cache )
{
static const u32 k_download_option_preparing = 0x00;
static const u32 k_download_option_data = 0x00;
-static void _remote_replay_cache_check( void *_ )
+static void _remote_replay_cache_check( void *userdata )
{
char path[1024];
if( _remote_replay.state == k_remote_replay_state_getinfo )
snprintf( path, sizeof(path), "replaydata/%lx@%x", _remote_replay.steamid, chunk->minute );
}
- vg_async_item *item = vg_async_alloc( sizeof(struct async_cache_check_result) + 20*1024*1024 );
- struct async_cache_check_result *result = item->payload;
+ vg_async_task *result_task =
+ vg_allocate_async_task( &vg.main_tasks, sizeof(struct async_cache_check_result) + 8*1024*1024, 1 );
+ struct async_cache_check_result *result = (void *)result_task->data;
result->broken = 0;
FILE *fp = fopen( path, "rb" );
result->data_length = 0;
}
- vg_async_dispatch( item, async_cache_check_result );
- vg_async_stall();
+ vg_async_task_dispatch( result_task, async_cache_check_result );
}
static void _remote_replay_pre_update(void)
{
if( _remote_replay.state == k_remote_replay_state_init )
{
- if( vg_loader_availible() )
- {
- _remote_replay.state = k_remote_replay_state_getinfo;
- vg_loader_start( _remote_replay_cache_check, NULL );
- }
+ _remote_replay.state = k_remote_replay_state_getinfo;
+ vg_async_call( &vg.loader_tasks, _remote_replay_cache_check, NULL );
}
- else if( _remote_replay.state == k_remote_replay_state_downloading )
+ else if( _remote_replay.state == k_remote_replay_state_waitnext )
{
+ _remote_replay.state = k_remote_replay_state_downloading;
+
struct remote_replay_chunk *chunk = &_remote_replay.chunks[ _remote_replay.chunks_downloaded ];
if( chunk->state == k_chunk_state_none )
{
- if( vg_loader_availible() )
- {
- chunk->state = k_chunk_state_cache_check;
- vg_loader_start( _remote_replay_cache_check, NULL );
- }
+ chunk->state = k_chunk_state_cache_check;
+ vg_async_call( &vg.loader_tasks, _remote_replay_cache_check, NULL );
}
}
}
u32 s0 = current_frame->net_frame_size - sizeof(netmsg_playerframe);
decode_playerframe( ¤t_frame->net_frame, s0, &interp_frame0 );
-
m4x3f *final_mtx = _replay_player.final_mtx;
v3f *glider_mtx = _replay_player.glider_mtx;
struct player_board_pose *board_pose = &_replay_player.board_pose;
if( skaterift.activity != k_skaterift_replay )
return;
- SDL_LockMutex( addon_system.cache_lock );
-
//struct player_model *model = addon_cache_item_if_loaded( k_addon_type_player, player->playermodel_view_slot );
//if( !model )
// model = &localplayer.fallback_model;
render_board( cam, world, board, _replay_player.final_mtx[localplayer.id_board],
&_replay_player.board_pose, k_board_shader_player );
- SDL_UnlockMutex( addon_system.cache_lock );
-
#if 0
if( !gliders )
return;
enum remote_replay_state
{
k_remote_replay_state_none,
+
k_remote_replay_state_init,
k_remote_replay_state_getinfo,
+
+ k_remote_replay_state_waitnext,
k_remote_replay_state_downloading,
+
k_remote_replay_state_ready,
k_remote_replay_state_failed
}
void savedata_group_write( savedata_group *group )
{
- for( u32 i=0; i<group->file_count; i++ )
- savedata_file_write( &group->files[i] );
}
void savedata_file_read( savedata_file *file )
static void skaterift_write_viewslot( vg_msg *msg, const char *key, enum addon_type type, u16 cache_id )
{
- if( !cache_id ) return;
+ THREAD_0;
- struct addon_cache *cache = &addon_system.cache[type];
- addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
- addon_reg *reg = entry->reg_ptr;
+ if( !cache_id )
+ return;
+ struct addon_cache *cache = &_addon.cache[type];
+ addon_cache_entry *entry = vg_pool_item( &cache->pool, cache_id );
+
+ addon_reg *reg = addon_details( entry->addon_id );
if( reg )
skaterift_write_addon_alias( msg, key, ®->alias );
}
vg_msg_frame( &sav, "player" );
{
- skaterift_write_viewslot( &sav, "board", k_addon_type_board,
- localplayer.board_view_slot );
- skaterift_write_viewslot( &sav, "playermodel", k_addon_type_player,
- localplayer.playermodel_view_slot );
+ skaterift_write_viewslot( &sav, "board", k_addon_type_board, localplayer.board_view_slot );
+ skaterift_write_viewslot( &sav, "playermodel", k_addon_type_player, localplayer.playermodel_view_slot );
- addon_reg *reg = _world.main.addon;
+ addon_reg *reg = addon_details( _world.main.addon_id );
if( reg )
skaterift_write_addon_alias( &sav, "location", ®->alias );
else
{
file->path[0] = '\0';
file->len = 0;
- addon_reg *reg = _world.main.addon;
- if( !reg )
+ if( !_world.main.addon_id )
{
- vg_error( "Tried to save unspecified world (reg was null)\n" );
+ vg_error( "Tried to save unspecified world (id was null)\n" );
return;
}
- skaterift_world_get_save_path( reg, file->path );
+ skaterift_world_get_save_path( _world.main.addon_id, file->path );
vg_msg sav;
vg_msg_init( &sav, file->buf, sizeof(file->buf) );
file->len = sav.cur.co;
}
-int skaterift_write_all_savedata( bool async )
+static void savedata_group_write_task( vg_async_task *task )
{
- if( async )
- {
- if( !vg_loader_availible() )
- return 0;
- }
+ savedata_group *group = (void *)task->data;
+ for( u32 i=0; i<group->file_count; i++ )
+ savedata_file_write( &group->files[i] );
+}
+void skaterift_write_all_savedata( bool async )
+{
u32 save_data_size = sizeof(savedata_group) + sizeof(savedata_file)*2;
+ vg_async_task *task = NULL;
savedata_group *group;
if( async )
{
- vg_linear_clear( vg_async.buffer );
- group = vg_linear_alloc( vg_async.buffer, vg_align8(save_data_size) );
+ task = vg_allocate_async_task( &vg.loader_tasks, sizeof(save_data_size), 1 );
+ group = (void *)task->data;
}
else
group = alloca( save_data_size );
skaterift_populate_world_savedata( &group->files[1] );
if( async )
- vg_loader_start( (void *)savedata_group_write, group );
+ vg_async_task_dispatch( task, savedata_group_write_task );
else
- savedata_group_write( group );
-
- return 1;
+ {
+ for( u32 i=0; i<group->file_count; i++ )
+ savedata_file_write( &group->files[i] );
+ }
}
void skaterift_autosave_synchronous(void)
{
if( (vg.time - _last_autosave) > 60.0 )
{
- if( skaterift_write_all_savedata(1) )
- {
- _last_autosave = vg.time;
- }
+ skaterift_write_all_savedata(1);
+ _last_autosave = vg.time;
}
}
+struct equip_saved_items_info
+{
+ addon_id board_id, player_id;
+};
+static void equip_async( vg_async_task *task )
+{
+ struct equip_saved_items_info *info = (void *)task->data;
+ localplayer.board_view_slot = addon_cache_create_viewer( k_addon_type_board, info->board_id );
+ localplayer.playermodel_view_slot = addon_cache_create_viewer( k_addon_type_player, info->player_id );
+}
+
void skaterift_load_mainsave(void)
{
+ THREAD_1;
+
savedata_file sav;
strcpy( sav.path, str_skaterift_main_save );
savedata_file_read( &sav );
vg_msg_getkvintg( &kvsav, "ach", k_vg_msg_u32, &ach, NULL );
skaterift.achievements |= ach;
- u32 board_reg_id = time(NULL) % addon_count( k_addon_type_board, 0,0 ),
- player_reg_id = (time(NULL)+44) % addon_count( k_addon_type_player, 0,0 );
+ u32 board_index = time(NULL) % _addon_filtered_count( k_addon_type_board, 0,0 ),
+ player_index = (time(NULL)+44) % _addon_filtered_count( k_addon_type_player, 0,0 );
+ addon_id board_id = _addon_get_filtered( k_addon_type_board, board_index, 0,0 ),
+ player_id =_addon_get_filtered( k_addon_type_player,player_index, 0,0 );
vg_msg_cursor orig = kvsav.cur;
if( vg_msg_seekframe( &kvsav, "player" ) )
{
addon_alias q;
- u32 reg_id;
-
- /* board */
if( skaterift_read_addon_alias( &kvsav, "board", k_addon_type_board, &q ) )
- {
- reg_id = addon_match( &q );
- if( reg_id != 0xffffffff )
- board_reg_id = reg_id;
- }
+ board_id = _get_addon_by_alias( &q );
- /* playermodel */
if( skaterift_read_addon_alias( &kvsav, "playermodel", k_addon_type_player, &q ) )
- {
- reg_id = addon_match( &q );
- if( reg_id != 0xffffffff )
- player_reg_id = reg_id;
- }
+ player_id = _get_addon_by_alias( &q );
if( skaterift_read_addon_alias( &kvsav, "location", k_addon_type_world, &q ) )
{
vg_info( "Loading client world from save.\n" );
+ addon_id world_id = _get_addon_by_alias( &q );
- reg_id = addon_match( &q );
- if( reg_id != 0xffffffff )
- {
- _world.loader_reg = get_addon_from_index( k_addon_type_world, reg_id, 0,0 );
- }
+ if( world_id )
+ _world.load_addon = world_id;
else
{
char buf[ADDON_UID_MAX];
addon_alias_uid( &q, buf );
-
vg_error( "While loading player location from save file, couldn't find addon '%s'\n", buf );
}
}
}
- localplayer.board_view_slot = addon_cache_create_viewer( k_addon_type_board, board_reg_id );
- localplayer.playermodel_view_slot = addon_cache_create_viewer( k_addon_type_player, player_reg_id );
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct equip_saved_items_info), 1 );
+ struct equip_saved_items_info *info = (void *)task->data;
+ info->board_id = board_id;
+ info->player_id = player_id;
+ vg_async_task_dispatch( task, equip_async );
kvsav.cur = orig;
else
{
vg_info( "Starting new story!\n" );
- _world.loader_reg = addon_mount_local_addon( "maps/dev_heaven", k_addon_type_world, ".mdl" );
+ _world.load_addon = _addon_mount_from_folder( "maps/dev_heaven", k_addon_type_world, ".mdl" );
}
}
void skaterift_autosave_synchronous(void);
void skaterift_autosave_update(void);
-int skaterift_write_all_savedata( bool async );
+void skaterift_write_all_savedata( bool async );
void skaterift_load_mainsave(void);
glmesh *mesh;
};
-void async_scene_upload( void *payload, u32 size )
+void async_scene_upload( vg_async_task *task )
{
- struct scene_upload_info *info = payload;
+ THREAD_0;
- //assert( mesh->loaded == 0 );
+ struct scene_upload_info *info = (void *)task->data;
glmesh *mesh = info->mesh;
scene_context *ctx = info->ctx;
size_t stride = sizeof(scene_vert);
glBindBuffer( GL_ARRAY_BUFFER, mesh->vbo );
- glBufferData( GL_ARRAY_BUFFER, ctx->vertex_count*stride,
- ctx->arrvertices, GL_STATIC_DRAW );
+ glBufferData( GL_ARRAY_BUFFER, ctx->vertex_count*stride, ctx->arrvertices, GL_STATIC_DRAW );
glBindVertexArray( mesh->vao );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, mesh->ebo );
- glBufferData( GL_ELEMENT_ARRAY_BUFFER, ctx->indice_count*sizeof(u32),
- ctx->arrindices, GL_STATIC_DRAW );
+ glBufferData( GL_ELEMENT_ARRAY_BUFFER, ctx->indice_count*sizeof(u32), ctx->arrindices, GL_STATIC_DRAW );
/* 0: coordinates */
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
glEnableVertexAttribArray( 0 );
/* 1: normal */
- glVertexAttribPointer( 1, 4, GL_BYTE, GL_TRUE,
- stride, (void *)offsetof(scene_vert, norm) );
+ glVertexAttribPointer( 1, 4, GL_BYTE, GL_TRUE, stride, (void *)offsetof(scene_vert, norm) );
glEnableVertexAttribArray( 1 );
/* 2: uv */
- glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE,
- stride, (void *)offsetof(scene_vert, uv) );
+ glVertexAttribPointer( 2, 2, GL_FLOAT, GL_FALSE, stride, (void *)offsetof(scene_vert, uv) );
glEnableVertexAttribArray( 2 );
mesh->indice_count = ctx->indice_count;
vg_info( " verts:%u\n", ctx->vertex_count );
}
-void scene_upload_async( scene_context *ctx, glmesh *mesh )
+vg_async_task *scene_alloc_async( scene_context *scene, glmesh *mesh, u32 max_vertices, u32 max_indices )
{
- vg_async_item *call = vg_async_alloc( sizeof(struct scene_upload_info) );
+ THREAD_1;
- struct scene_upload_info *info = call->payload;
- info->mesh = mesh;
- info->ctx = ctx;
-
- vg_async_dispatch( call, async_scene_upload );
-}
-
-vg_async_item *scene_alloc_async( scene_context *scene, glmesh *mesh,
- u32 max_vertices, u32 max_indices )
-{
scene_init( scene, max_vertices, max_indices );
u32 buf_size = scene_mem_required( scene );
u32 hdr_size = vg_align8(sizeof(struct scene_upload_info));
- vg_async_item *call = vg_async_alloc( hdr_size + buf_size );
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, hdr_size + buf_size, 1 );
- struct scene_upload_info *info = call->payload;
+ struct scene_upload_info *info = (void *)task->data;
info->mesh = mesh;
info->ctx = scene;
-
- void *buffer = ((u8*)call->payload)+hdr_size;
- scene_supply_buffer( scene, buffer );
-
- return call;
+ scene_supply_buffer( scene, task->data + hdr_size );
+ return task;
}
-
/*
* BVH implementation
*/
#pragma once
#include "vg/vg_bvh.h"
-#include "vg/vg_async.h"
#include "common.h"
#include "model.h"
extern bh_system bh_system_scene;
bh_tree *scene_bh_create( void *lin_alloc, scene_context *s );
-int scene_raycast( scene_context *s, bh_tree *bh,
- v3f co, v3f dir, ray_hit *hit, u16 ignore );
-vg_async_item *scene_alloc_async( scene_context *scene, glmesh *mesh,
- u32 max_vertices, u32 max_indices );
+int scene_raycast( scene_context *s, bh_tree *bh, v3f co, v3f dir, ray_hit *hit, u16 ignore );
+vg_async_task *scene_alloc_async( scene_context *scene, glmesh *mesh, u32 max_vertices, u32 max_indices );
void scene_copy_slice( scene_context *ctx, mdl_submesh *sm );
void scene_push_vert( scene_context *ctx, scene_vert *v );
void scene_vert_pack_norm( scene_vert *vert, v3f norm, f32 blend );
void scene_push_tri( scene_context *ctx, u32 tri[3] );
-void scene_add_mdl_submesh( scene_context *ctx, mdl_context *mdl,
- mdl_submesh *sm, m4x3f transform );
-void scene_set_vertex_flags( scene_context *ctx,
- u32 start, u32 count, u16 flags );
+void scene_add_mdl_submesh( scene_context *ctx, mdl_context *mdl, mdl_submesh *sm, m4x3f transform );
+void scene_set_vertex_flags( scene_context *ctx, u32 start, u32 count, u16 flags );
void scene_supply_buffer( scene_context *ctx, void *buffer );
void scene_init( scene_context *ctx, u32 max_vertices, u32 max_indices );
u32 scene_mem_required( scene_context *ctx );
-void async_scene_upload( void *payload, u32 size );
-void scene_upload_async( scene_context *ctx, glmesh *mesh );
+void async_scene_upload( vg_async_task *task );
player_board_load( &localplayer.fallback_board, "models/board_none.mdl", vg_mem.rtmemory );
}
-void game_load(void)
+static void game_load_0(void *_);
+static void game_load_1(void *_);
+static void game_load_2(void *_);
+static void game_load_3(void *_);
+static void game_load_4( vg_async_task *task );
+void game_load(void) { THREAD_1; game_load_0(NULL); }
+
+static void game_load_0(void *_)
{
+ THREAD_1;
+
_skaterift_script_init();
vg_loader_set_user_information( "Initializing subsystems" );
-
vg_console_reg_cmd( "load_world", skaterift_load_world_command, NULL );
vg_console_reg_var( "immobile", &localplayer.immobile, k_var_dtype_i32, 0 );
vg_console_reg_var( "allow_resume", &skaterift.allow_replay_resume, k_var_dtype_i32, VG_VAR_CHEAT );
vg_loader_set_user_information( "Loading content files" );
vg_loader_step( audio_init, NULL );
- _world.default_hub_addon = addon_mount_local_addon( "maps/dev_hub", k_addon_type_world, ".mdl" );
- if( !_world.default_hub_addon )
- vg_fatal_error( "Hub world not found\n" );
+ _world.default_hub_addon = _addon_mount_from_folder( "maps/dev_hub", k_addon_type_world, ".mdl" );
+ VG_ASSERT( _world.default_hub_addon );
vg_console_load_autos();
-
vg_loader_set_user_information( "Mounting addons" );
- addon_mount_content_folder( k_addon_type_player, "playermodels", ".mdl" );
- addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
- addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" );
- addon_mount_workshop_items();
- vg_async_call( async_addon_reg_update, NULL, 0 );
- vg_async_stall();
+ _addon_mount_content_folder( k_addon_type_player, "playermodels", ".mdl" );
+ _addon_mount_content_folder( k_addon_type_board, "boards", ".mdl" );
+ _addon_mount_content_folder( k_addon_type_world, "maps", ".mdl" );
+ vg_async_call( &vg.main_tasks, game_load_1, NULL );
+}
+
+static void game_load_1(void *_)
+{
+ THREAD_0;
+ _mount_workshop_addons( NULL );
+ vg_async_call( &vg.loader_tasks, game_load_2, NULL );
+}
+
+static void game_load_2(void *_)
+{
+ THREAD_1;
/* initializing / loading world. */
vg_loader_set_user_information( "Loading savedata" );
skaterift_load_mainsave();
if( skaterift.override_load_world )
- _world.loader_reg = addon_mount_local_addon( skaterift.override_load_world, k_addon_type_world, ".mdl" );
+ _world.load_addon = _addon_mount_from_folder( skaterift.override_load_world, k_addon_type_world, ".mdl" );
_world.loader_instance = &_world.main;
_world.loader_preview_mode = 0;
_world.loader_heap = _world.heap;
- if( !_world.loader_reg )
+ if( !_world.load_addon )
{
vg_warn( "Falling back to default hub world...\n" );
- _world.loader_reg = _world.default_hub_addon;
+ _world.load_addon = _world.default_hub_addon;
}
- _world_loader_set_target_reg( _world.loader_reg );
- world_switcher_thread( NULL );
-
- vg_async_stall();
- menu_on_world_change( _world.main.addon );
+ _world_loader_set_addon( _world.load_addon );
+ vg_async_call( &vg.main_tasks, game_load_3, NULL );
+}
+
+static void game_load_3(void *_)
+{
+ THREAD_0;
+ vg_async_task *task = world_load_go();
+ vg_async_task_dispatch( task, game_load_4 );
+}
+
+static void game_load_4( vg_async_task *task )
+{
+ THREAD_1;
+ skaterift_world_load_t1( task );
/* add autosave function to exit list */
vg_loader_step( NULL, skaterift_autosave_synchronous );
+ vg_async_call( &vg.main_tasks, async_client_ready, NULL );
+ _vg_load_temp_end();
}
+/*
+ * UPDATE LOOP
+ * ---------------------------------------------------------------------------*/
+
static void draw_origin_axis(void)
{
vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
}
void skaterift_change_client_world_preupdate(void);
-/*
- * UPDATE LOOP
- * ---------------------------------------------------------------------------*/
-
void vg_pre_update(void)
{
skaterift_preupdate_inputs();
//draw_origin_axis();
//_skaterift_script_update();
- addon_system_pre_update();
- skateshop_world_preview_preupdate();
+ _addon_system_pre_update();
network_update();
/* time rate */
else
{
_world.entity_camera_modulate = vg_maxf( 0.0f, _world.entity_camera_modulate-vg.time_frame_delta );
- }
+}
vg_camera_lerp( &localplayer.cam, &_world.entity_driven_camera,
vg_smoothstepf(_world.entity_camera_modulate), &g_render.cam );
#include "vg/vg_platform.h"
#include "vg/vg_m.h"
#include "vg/vg_lines.h"
-#include "vg/vg_async.h"
#include "vg/vg_camera.h"
#include "trail.h"
#include "shaders/particle.h"
sys->count ++;
}
-void trail_system_update( trail_system *sys, f32 dt,
- v3f co, v3f normal, f32 alpha )
+void trail_system_update( trail_system *sys, f32 dt, v3f co, v3f normal, f32 alpha )
{
/* update existing points and clip dead ones */
bool clip_allowed = 1;
- for( i32 i=0; i<sys->count; i ++ ){
+ for( i32 i=0; i<sys->count; i ++ )
+ {
i32 i0 = sys->head - sys->count + i;
if( i0 < 0 ) i0 += sys->max;
trail_point *p0 = &sys->array[i0];
p0->alpha -= dt/sys->lifetime;
- if( clip_allowed ){
+ if( clip_allowed )
+ {
if( p0->alpha <= 0.0f )
sys->count --;
else
f32 k_min = 0.001f;
- if( sys->count == 0 ){
+ if( sys->count == 0 )
+ {
trail_increment( sys );
v3_copy( (v3f){0,0,-1}, dir );
pdest = phead;
}
- else if( sys->count == 1 ){
+ else if( sys->count == 1 )
+ {
if( v3_dist2( pcur->co, co ) < k_min*k_min )
return;
pdest = phead;
v3_sub( co, pcur->co, dir );
}
- else {
+ else
+ {
if( v3_dist2( pprev->co, co ) < k_min*k_min )
return;
- if( v3_dist2( pprev->co, co ) > sys->min_dist*sys->min_dist ){
+ if( v3_dist2( pprev->co, co ) > sys->min_dist*sys->min_dist )
+ {
trail_increment( sys );
pdest = phead;
}
void trail_system_debug( trail_system *sys )
{
- for( i32 i=0; i<sys->count; i ++ ){
+ for( i32 i=0; i<sys->count; i ++ )
+ {
i32 i0 = sys->head - sys->count + i;
if( i0 < 0 ) i0 += sys->max;
trail_system *sys;
};
-void async_trail_init( void *payload, u32 size )
+void async_trail_init( vg_async_task *task )
{
- struct trail_init_args *args = payload;
+ THREAD_0;
+
+ struct trail_init_args *args = (void *)task->data;
trail_system *sys = args->sys;
glGenVertexArrays( 1, &sys->vao );
void trail_alloc( trail_system *sys, u32 max )
{
+ THREAD_1;
+
size_t stride = sizeof(trail_vert);
sys->max = max;
sys->array = vg_linear_alloc( vg_mem.rtmemory, max*sizeof(trail_point) );
sys->vertices = vg_linear_alloc( vg_mem.rtmemory, max*stride*2 );
- vg_async_item *call = vg_async_alloc( sizeof(struct trail_init_args) );
-
- struct trail_init_args *init = call->payload;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct trail_init_args), 1 );
+ struct trail_init_args *init = (void *)task->data;
init->sys = sys;
- vg_async_dispatch( call, async_trail_init );
+ vg_async_task_dispatch( task, async_trail_init );
}
void trail_system_prerender( trail_system *sys )
#include "vg/vg_loader.h"
#include "vg/vg_io.h"
#include "vg/vg_audio.h"
-#include "vg/vg_async.h"
#include "vg/vg_magi.h"
#include "vg/vg_ui/imgui.h"
#include "vg/vg_ui/filebrowser.h"
/*
* Close the form and discard UGC query result
*/
-static void workshop_quit_form(void){
+static void workshop_quit_form(void)
+{
player_board_unload( &workshop_form.board_model );
workshop_form.file_intent = k_workshop_form_file_intent_none;
* reciever on completion of packaging the files, it will then start the item
* update with Steam API
*/
-static void workshop_form_upload_submission( PublishedFileId_t file_id,
- char *metadata )
+static void workshop_form_upload_submission( PublishedFileId_t file_id, char *metadata )
{
+ THREAD_0;
ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
- UGCUpdateHandle_t handle
- = SteamAPI_ISteamUGC_StartItemUpdate( hSteamUGC, SKATERIFT_APPID,
- file_id );
+ UGCUpdateHandle_t handle = SteamAPI_ISteamUGC_StartItemUpdate( hSteamUGC, SKATERIFT_APPID, file_id );
/* TODO: Handle failure cases for these */
SteamAPI_ISteamUGC_SetItemMetadata( hSteamUGC, handle, metadata );
- if( workshop_form.submission.submit_title ){
+ if( workshop_form.submission.submit_title )
+ {
vg_info( "Setting title\n" );
- SteamAPI_ISteamUGC_SetItemTitle( hSteamUGC, handle,
- workshop_form.submission.title );
+ SteamAPI_ISteamUGC_SetItemTitle( hSteamUGC, handle, workshop_form.submission.title );
}
- if( workshop_form.submission.submit_description ){
+ if( workshop_form.submission.submit_description )
+ {
vg_info( "Setting description\n" );
- SteamAPI_ISteamUGC_SetItemDescription( hSteamUGC, handle,
- workshop_form.submission.description);
+ SteamAPI_ISteamUGC_SetItemDescription( hSteamUGC, handle, workshop_form.submission.description);
}
- if( workshop_form.submission.submit_file_and_image ){
+ if( workshop_form.submission.submit_file_and_image )
+ {
char path_buf[4096];
vg_str folder;
vg_strnull( &folder, path_buf, 4096 );
}
vg_info( "Setting visibility\n" );
- SteamAPI_ISteamUGC_SetItemVisibility( hSteamUGC, handle,
- workshop_form.submission.visibility );
+ SteamAPI_ISteamUGC_SetItemVisibility( hSteamUGC, handle, workshop_form.submission.visibility );
vg_info( "Submitting updates\n" );
vg_steam_async_call *call = vg_alloc_async_steam_api_call();
{
CreateItemResult_t *result = data;
- if( result->m_eResult == k_EResultOK ){
- vg_info( "Created workshop file with id: %lu\n",
- result->m_nPublishedFileId );
+ if( result->m_eResult == k_EResultOK )
+ {
+ vg_info( "Created workshop file with id: %lu\n", result->m_nPublishedFileId );
- if( result->m_bUserNeedsToAcceptWorkshopLegalAgreement ){
+ if( result->m_bUserNeedsToAcceptWorkshopLegalAgreement )
vg_warn( "Workshop agreement currently not accepted\n" );
- }
-
workshop_form_upload_submission( result->m_nPublishedFileId, user );
}
- else{
+ else
+ {
const char *errstr = workshop_EResult_user_string( result->m_eResult );
- if( errstr ){
- vg_error( "ISteamUGC_CreateItem() failed(%d): '%s' \n",
- result->m_eResult, errstr );
- }
+ if( errstr )
+ vg_error( "ISteamUGC_CreateItem() failed(%d): '%s' \n", result->m_eResult, errstr );
workshop_form.page = k_workshop_form_closing_bad;
workshop_form.failure_or_success_string = errstr;
/*
* Starts the workshop upload process through Steam API
*/
-static void workshop_form_async_submit_begin( void *payload, u32 size )
+static void workshop_form_async_submit_begin( void *userdata )
{
-
/* use existing file */
- if( workshop_form.submission.file_id ){
- workshop_form_upload_submission( workshop_form.submission.file_id,
- payload );
+ if( workshop_form.submission.file_id )
+ {
+ workshop_form_upload_submission( workshop_form.submission.file_id, userdata );
}
- else{
+ else
+ {
vg_steam_async_call *call = vg_alloc_async_steam_api_call();
- call->userdata = payload;
+ call->userdata = userdata;
call->p_handler = on_workshop_createitem;
ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
- call->id = SteamAPI_ISteamUGC_CreateItem( hSteamUGC, SKATERIFT_APPID,
- k_EWorkshopFileTypeCommunity );
+ call->id = SteamAPI_ISteamUGC_CreateItem( hSteamUGC, SKATERIFT_APPID, k_EWorkshopFileTypeCommunity );
}
}
-/*
- * Downloads the framebuffer into scratch memory
- */
-static void workshop_form_async_download_image( void *payload, u32 size )
+static void _workshop_form_end_op( void *userdata )
{
- int w, h;
- vg_framebuffer_get_res( g_render.fb_workshop_preview, &w, &h );
- vg_linear_clear( vg_mem.scratch );
- workshop_form.img_buffer = vg_linear_alloc( vg_mem.scratch, w*h*3 );
-
- vg_info( "read framebuffer: glReadPixels( %dx%d )\n", w,h );
-
- glBindFramebuffer( GL_READ_FRAMEBUFFER, g_render.fb_workshop_preview->id );
- glReadBuffer( GL_COLOR_ATTACHMENT0 );
- glReadPixels( 0,0, w,h, GL_RGB, GL_UNSIGNED_BYTE, workshop_form.img_buffer );
-
- workshop_form.img_w = w;
- workshop_form.img_h = h;
+ workshop_form.op = k_workshop_op_none;
}
/*
* Thread which kicks off the upload process
*/
-static void _workshop_form_submit_thread( void *data )
+static void _workshop_form_submit_t1( void *userdata )
{
- vg_async_call( workshop_form_async_download_image, NULL, 0 );
- vg_async_stall();
-
char path_buf[4096];
vg_str folder;
vg_strnull( &folder, path_buf, 4096 );
vg_strcat( &folder, workshop_filetype_folder() );
vg_strcat( &folder, workshop_form.addon_folder );
- if( !vg_strgood(&folder) ){
+ if( !vg_strgood(&folder) )
+ {
vg_error( "addon folder path too long\n" );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
/* short description */
vg_msg_frame( &descriptor, "workshop" );
+ {
vg_msg_wkvstr( &descriptor, "title", workshop_form.submission.title );
//vg_msg_wkvstr( &descriptor, "author", "unknown" );
- vg_msg_wkvnum( &descriptor, "type", k_vg_msg_u32, 1,
- &workshop_form.submission.type );
+ vg_msg_wkvnum( &descriptor, "type", k_vg_msg_u32, 1, &workshop_form.submission.type );
vg_msg_wkvstr( &descriptor, "folder", workshop_form.addon_folder );
+ }
vg_msg_end_frame( &descriptor );
//vg_msg_wkvstr( &descriptor, "location", "USA" );
- char *short_descriptor_str =
- vg_linear_alloc( vg_mem.scratch, vg_align8(descriptor.cur.co*2+1));
+ char *short_descriptor_str = vg_linear_alloc( vg_mem.scratch, vg_align8(descriptor.cur.co*2+1));
vg_bin_str( descriptor_buf, short_descriptor_str, descriptor.cur.co );
short_descriptor_str[descriptor.cur.co*2] = '\0';
vg_info( "binstr: %s\n", short_descriptor_str );
if( vg_dir_open( &dir, folder.buffer ) != k_dir_open_ok )
{
vg_error( "could not open addon folder '%s'\n", folder.buffer );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
vg_strcat( &descriptor_file, "/addon.inf" );
if( !vg_strgood(&descriptor_file) ){
vg_error( "Addon info path too long\n" );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
FILE *fp = fopen( descriptor_file.buffer, "wb" );
- if( !fp ){
- vg_error( "Could not open addon info file '%s'\n",
- descriptor_file.buffer );
- workshop_form.op = k_workshop_op_none;
+ if( !fp )
+ {
+ vg_error( "Could not open addon info file '%s'\n", descriptor_file.buffer );
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
fwrite( descriptor_buf, descriptor.cur.co, 1, fp );
vg_str preview = folder;
vg_strcat( &preview, "/preview.jpg" );
- if( !vg_strgood(&preview) ){
+ if( !vg_strgood(&preview) )
+ {
vg_error( "preview image path too long\n" );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
stbi_flip_vertically_on_write(1);
stbi_write_jpg( preview.buffer, w,h, 3, workshop_form.img_buffer, 90 );
- vg_async_call( workshop_form_async_submit_begin, short_descriptor_str, 0 );
+ vg_async_call( &vg.main_tasks, workshop_form_async_submit_begin, short_descriptor_str );
}
/*
workshop_form.file_intent = k_workshop_form_file_intent_none;
workshop_form.op = k_workshop_op_publishing_update;
- vg_loader_start( _workshop_form_submit_thread, NULL );
+ int w, h;
+ vg_framebuffer_get_res( g_render.fb_workshop_preview, &w, &h );
+ vg_linear_clear( vg_mem.scratch );
+ workshop_form.img_buffer = vg_linear_alloc( vg_mem.scratch, w*h*3 );
+
+ vg_info( "read framebuffer: glReadPixels( %dx%d )\n", w,h );
+
+ glBindFramebuffer( GL_READ_FRAMEBUFFER, g_render.fb_workshop_preview->id );
+ glReadBuffer( GL_COLOR_ATTACHMENT0 );
+ glReadPixels( 0,0, w,h, GL_RGB, GL_UNSIGNED_BYTE, workshop_form.img_buffer );
+
+ workshop_form.img_w = w;
+ workshop_form.img_h = h;
+
+ vg_async_call( &vg.loader_tasks, _workshop_form_submit_t1, NULL );
}
/*
/*
* Reciever for completion of the model file load
*/
-static void workshop_form_loadmodel_async_complete( void *payload, u32 size )
+static void workshop_form_loadmodel_async_complete( void *userdata )
{
+ THREAD_0;
+
v2_zero( workshop_form.view_angles );
v3_zero( workshop_form.view_offset );
workshop_form.view_dist = 1.0f;
workshop_form.op = k_workshop_op_none;
}
-/*
- * Reciever for failure to load
- */
-static void workshop_form_loadmodel_async_error( void *payload, u32 size ){
-}
-
/*
* Thread which loads the model from the disk
*/
-static void _workshop_form_load_thread( void *data )
+static void _workshop_form_load_t1( void *userdata )
{
+ THREAD_1;
+
char path_buf[4096];
vg_str folder;
vg_strnull( &folder, path_buf, 4096 );
vg_strcat( &folder, workshop_filetype_folder() );
vg_strcat( &folder, workshop_form.addon_folder );
- if( !vg_strgood(&folder) ){
+ if( !vg_strgood(&folder) )
+ {
vg_error( "workshop async load failed: path too long\n" );
- vg_async_call( workshop_form_loadmodel_async_error, NULL, 0 );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
if( vg_dir_open( &dir, folder.buffer ) != k_dir_open_ok )
{
vg_error( "workshop async load failed: could not open folder\n" );
- vg_async_call( workshop_form_loadmodel_async_error, NULL, 0 );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
vg_info( "Searching %s for model files\n", folder.buffer );
int found_mdl = 0;
- while( vg_dir_next_entry(&dir) ){
- if( vg_dir_entry_type(&dir) == k_vg_entry_type_file ){
+ while( vg_dir_next_entry(&dir) )
+ {
+ if( vg_dir_entry_type(&dir) == k_vg_entry_type_file )
+ {
const char *d_name = vg_dir_entry_name(&dir);
if( d_name[0] == '.' ) continue;
}
vg_dir_close(&dir);
- if( !found_mdl ){
+ if( !found_mdl )
+ {
vg_error( "workshop async load failed: no model files found\n" );
- vg_async_call( workshop_form_loadmodel_async_error, NULL, 0 );
- workshop_form.op = k_workshop_op_none;
+ vg_async_call( &vg.main_tasks, _workshop_form_end_op, NULL );
return;
}
if( workshop_form.model_arena == NULL )
{
- workshop_form.model_arena = _vg_create_linear_allocator(
- NULL, 1024*2, VG_MEMORY_SYSTEM, "Workshop model data arena" );
+ workshop_form.model_arena =
+ _vg_create_linear_allocator( NULL, 1024*2, VG_MEMORY_SYSTEM, "Workshop model data arena" );
}
void *arena = workshop_form.model_arena;
vg_linear_clear( arena );
if( workshop_form.submission.type == k_addon_type_board )
- {
player_board_load( &workshop_form.board_model, path_buf, arena );
- }
else if( workshop_form.submission.type == k_addon_type_player )
- {
player_model_load( &workshop_form.player_model, path_buf, arena );
- }
- vg_async_call( workshop_form_loadmodel_async_complete, NULL, 0 );
+ vg_async_call( &vg.main_tasks, workshop_form_loadmodel_async_complete, NULL );
}
/*
*/
static void workshop_op_load_model( ui_context *ctx )
{
+ THREAD_0;
world_instance *world = &_world.main;
workshop_form.view_world = world;
}
workshop_form.op = k_workshop_op_loading_model;
- vg_loader_start( _workshop_form_load_thread, NULL );
+ vg_async_call( &vg.loader_tasks, _workshop_form_load_t1, NULL );
}
/*
/*
* The image has been decoded and is ready to slap into the framebuffer
*/
-static void workshop_form_async_imageload( void *data, u32 len )
+static void workshop_form_async_imageload( void *data )
{
+ THREAD_0;
+
if( data )
{
- vg_framebuffer_attachment *a =
- &g_render.fb_workshop_preview->attachments[0];
-
+ vg_framebuffer_attachment *a = &g_render.fb_workshop_preview->attachments[0];
glBindTexture( GL_TEXTURE_2D, a->id );
- glTexSubImage2D( GL_TEXTURE_2D, 0,0,0,
- WORKSHOP_PREVIEW_WIDTH, WORKSHOP_PREVIEW_HEIGHT,
- a->format, a->type, data );
+ glTexSubImage2D( GL_TEXTURE_2D, 0,0,0, WORKSHOP_PREVIEW_WIDTH, WORKSHOP_PREVIEW_HEIGHT, a->format, a->type, data );
stbi_image_free( data );
vg_success( "Loaded workshop preview image\n" );
}
/*
* Load the image located at ./workshop_preview.jpg into our framebuffer
*/
-static void _workshop_load_preview_thread( void *data ){
+static void _workshop_load_preview_t1( void *userdata )
+{
+ THREAD_1;
+
char path_buf[ 4096 ];
vg_str path;
vg_strnull( &path, path_buf, 4096 );
{
if( (x == WORKSHOP_PREVIEW_WIDTH) && (y == WORKSHOP_PREVIEW_HEIGHT) )
{
- vg_async_call( workshop_form_async_imageload, rgb, x*y*3 );
+ vg_async_call( &vg.main_tasks, workshop_form_async_imageload, rgb );
}
else
{
- vg_error( "Resolution does not match framebuffer, so we can't"
- " show it\n" );
+ vg_error( "Resolution does not match framebuffer, so we can't show it\n" );
stbi_image_free( rgb );
- vg_async_call( workshop_form_async_imageload, NULL, 0 );
+ vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL );
}
}
else
{
- vg_async_call( workshop_form_async_imageload, NULL, 0 );
+ vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL );
}
}
else
{
- vg_async_call( workshop_form_async_imageload, NULL, 0 );
+ vg_async_call( &vg.main_tasks, workshop_form_async_imageload, NULL );
}
}
*/
static void workshop_op_download_and_view_submission( int result_index )
{
+ THREAD_0;
+
workshop_form.op = k_workshop_op_downloading_submission;
ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
ISteamRemoteStorage *hSteamRemoteStorage = SteamAPI_SteamRemoteStorage();
SteamUGCDetails_t details;
- if( SteamAPI_ISteamUGC_GetQueryUGCResult( hSteamUGC,
- workshop_form.ugc_query.handle,
- result_index,
- &details ) )
+ if( SteamAPI_ISteamUGC_GetQueryUGCResult( hSteamUGC, workshop_form.ugc_query.handle, result_index, &details ) )
{
workshop_reset_submission_data();
workshop_form.submission.submit_description = 0;
u8 metadata_buf[512];
char metadata_str[1024+1];
- int have_meta = SteamAPI_ISteamUGC_GetQueryUGCMetadata( hSteamUGC,
- workshop_form.ugc_query.handle,
+ int have_meta = SteamAPI_ISteamUGC_GetQueryUGCMetadata( hSteamUGC, workshop_form.ugc_query.handle,
result_index, metadata_str,
1024+1 );
- vg_strncpy( details.m_rgchDescription,
- workshop_form.submission.description,
- VG_ARRAY_LEN( workshop_form.submission.description ),
- k_strncpy_always_add_null );
+ vg_strncpy( details.m_rgchDescription, workshop_form.submission.description,
+ VG_ARRAY_LEN( workshop_form.submission.description ), k_strncpy_always_add_null );
- vg_strncpy( details.m_rgchTitle,
- workshop_form.submission.title,
- VG_ARRAY_LEN( workshop_form.submission.title ),
- k_strncpy_always_add_null );
+ vg_strncpy( details.m_rgchTitle, workshop_form.submission.title,
+ VG_ARRAY_LEN( workshop_form.submission.title ), k_strncpy_always_add_null );
- snprintf( workshop_form.addon_folder,
- VG_ARRAY_LEN( workshop_form.addon_folder ),
+ snprintf( workshop_form.addon_folder, VG_ARRAY_LEN( workshop_form.addon_folder ),
"Steam Cloud ("PRINTF_U64")", details.m_nPublishedFileId );
workshop_form.submission.file_id = details.m_nPublishedFileId;
const char *kv_folder = vg_msg_getkvstr( &msg, "folder" );
if( kv_folder )
{
- vg_strncpy( kv_folder, workshop_form.addon_folder,
- sizeof(workshop_form.addon_folder),
+ vg_strncpy( kv_folder, workshop_form.addon_folder, sizeof(workshop_form.addon_folder),
k_strncpy_always_add_null );
}
}
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glViewport( 0,0, vg.window_x, vg.window_y );
- vg_loader_start( _workshop_load_preview_thread, NULL );
+ vg_async_call( &vg.loader_tasks, _workshop_load_preview_t1, NULL );
}
else
{
int page = VG_MAX(VG_MIN(req, workshop_form.view_published_page_count-1),0),
start = page * WORKSHOP_VIEW_PER_PAGE,
- end = VG_MIN( (page+1) * WORKSHOP_VIEW_PER_PAGE,
- workshop_form.ugc_query.returned_item_count ),
+ end = VG_MIN( (page+1) * WORKSHOP_VIEW_PER_PAGE, workshop_form.ugc_query.returned_item_count ),
count = end-start;
vg_info( "View page %d\n", page );
struct published_file *pfile = &workshop_form.published_files_list[i];
SteamUGCDetails_t details;
- if( SteamAPI_ISteamUGC_GetQueryUGCResult( hSteamUGC,
- workshop_form.ugc_query.handle,
- start+i,
- &details ) )
+ if( SteamAPI_ISteamUGC_GetQueryUGCResult( hSteamUGC, workshop_form.ugc_query.handle, start+i, &details ) )
{
if( details.m_eResult != k_EResultOK )
- {
snprintf( pfile->title, 80, "Error (%d)", details.m_eResult );
- }
else
- {
- vg_strncpy( details.m_rgchTitle, pfile->title, 80,
- k_strncpy_always_add_null );
- }
+ vg_strncpy( details.m_rgchTitle, pfile->title, 80, k_strncpy_always_add_null );
pfile->result = details.m_eResult;
pfile->result_index = start+i;
{
if( query->m_unTotalMatchingResults > 50 )
{
- vg_warn( "You have %d items submitted, "
- "we can only view the last 50\n" );
+ vg_warn( "You have %d items submitted, we can only view the last 50\n" );
}
workshop_form.ugc_query.all_item_count = query->m_unTotalMatchingResults;
- workshop_form.ugc_query.returned_item_count =
- query->m_unNumResultsReturned;
+ workshop_form.ugc_query.returned_item_count = query->m_unNumResultsReturned;
workshop_form.ugc_query.handle = query->m_handle;
- workshop_form.view_published_page_count =
- (query->m_unNumResultsReturned+WORKSHOP_VIEW_PER_PAGE-1)/
- WORKSHOP_VIEW_PER_PAGE;
+ workshop_form.view_published_page_count = (query->m_unNumResultsReturned+WORKSHOP_VIEW_PER_PAGE-1)/
+ WORKSHOP_VIEW_PER_PAGE;
workshop_form.view_published_page_id = 0;
workshop_form.published_files_list_length = 0;
-
workshop_view_page( 0 );
}
else
vg_camera_update_projection( &cam, WORKSHOP_PREVIEW_WIDTH, WORKSHOP_PREVIEW_HEIGHT );
vg_camera_finalize( &cam );
- render_playermodel( &cam, &_world.main, 0,
- &workshop_form.player_model, sk, localplayer.final_mtx );
+ render_playermodel( &cam, &_world.main, 0, &workshop_form.player_model, sk, localplayer.final_mtx );
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glViewport( 0,0, vg.window_x, vg.window_y );
ui_rect file_button, file_label;
char buf[128];
- snprintf( buf, 128,
- "Addon folder: skaterift/%s", workshop_filetype_folder() );
+ snprintf( buf, 128, "Addon folder: skaterift/%s", workshop_filetype_folder() );
if( type == k_addon_type_world )
{
if( workshop_form.file_intent != k_workshop_form_file_intent_none )
{
- ui_text( ctx, file_entry, workshop_form.addon_folder, 1,
- k_ui_align_middle_left, ui_colour( ctx, k_ui_fg+4 ) );
+ ui_text( ctx, file_entry, workshop_form.addon_folder, 1, k_ui_align_middle_left, ui_colour( ctx, k_ui_fg+4 ) );
if( ui_button_text( ctx, file_button, "Remove", 1 ) == 1 )
{
.change = workshop_changed_model_path
};
- ui_textbox( ctx, file_entry, buf, workshop_form.addon_folder,
- VG_ARRAY_LEN(workshop_form.addon_folder), 1,
+ ui_textbox( ctx, file_entry, buf, workshop_form.addon_folder, VG_ARRAY_LEN(workshop_form.addon_folder), 1,
0, &callbacks );
if( ui_button_text( ctx, file_button, "Load", 1 ) == 1 )
- {
workshop_op_load_model( ctx );
- }
}
}
/* visibility option */
{
- ui_enum( ctx, content, "Visibility:", workshop_form_visibility_opts,
- 4, &workshop_form.submission.visibility );
+ ui_enum( ctx, content, "Visibility:", workshop_form_visibility_opts, 4, &workshop_form.submission.visibility );
}
/* description box */
ui_rect_center( final_row, submission_center );
ui_rect btn_left, btn_right;
- ui_split_ratio( submission_center, k_ui_axis_v, 0.5f, 8,
- btn_left, btn_right );
+ ui_split_ratio( submission_center, k_ui_axis_v, 0.5f, 8, btn_left, btn_right );
if( ui_button_text( ctx, btn_left, "Publish", 1 ) == 1 )
{
}
/* disclaimer */
- const char *disclaimer_text =
- "By submitting this item, you agree to the workshop terms of service";
+ const char *disclaimer_text = "By submitting this item, you agree to the workshop terms of service";
ui_rect disclaimer_row, inner, link;
ui_split( content, k_ui_axis_h, content[3]-32, 0, content, disclaimer_row );
k_EActivateGameOverlayToWebPageMode_Default );
}
- ui_text( ctx, label, disclaimer_text, 1, k_ui_align_middle_left,
- ui_colour( ctx, k_ui_fg+4 ) );
+ ui_text( ctx, label, disclaimer_text, 1, k_ui_align_middle_left, ui_colour( ctx, k_ui_fg+4 ) );
}
static void workshop_form_gui_sidebar( ui_context *ctx, ui_rect sidebar )
void workshop_form_gui( ui_context *ctx )
{
enum workshop_form_page stable_page = workshop_form.page;
- if( stable_page == k_workshop_form_hidden ) return;
+ if( stable_page == k_workshop_form_hidden )
+ return;
ui_rect null;
ui_rect screen = { 0, 0, vg.window_x, vg.window_y };
ui_rect title, panel;
ui_split( window, k_ui_axis_h, 28, 0, title, panel );
ui_fill( ctx, title, ui_colour( ctx, k_ui_bg+7 ) );
- ui_text( ctx, title, "Workshop tool", 1, k_ui_align_middle_center,
- ui_colourcont( ctx, k_ui_bg+7 ) );
-
- ui_rect quit_button;
- ui_split( title, k_ui_axis_v, title[2]-title[3], 2, title, quit_button );
-
- if( vg_loader_availible() )
- {
- if( ui_button_text( ctx, quit_button, "X", 1 ) == 1 )
- {
- workshop_quit_form();
- return;
- }
- }
+ ui_text( ctx, title, "Workshop tool", 1, k_ui_align_middle_center, ui_colourcont( ctx, k_ui_bg+7 ) );
/*
* temporary operation blinders, we don't yet have a nice way to show the
ui_text( ctx, panel, op_string, 1, k_ui_align_middle_center, 0 );
return;
}
+ else
+ {
+ ui_rect quit_button;
+ ui_split( title, k_ui_axis_v, title[2]-title[3], 2, title, quit_button );
+ if( ui_button_text( ctx, quit_button, "X", 1 ) == 1 )
+ {
+ workshop_quit_form();
+ return;
+ }
+ }
/* re draw board preview if need to */
if( (stable_page == k_workshop_form_edit) &&
* -----------------------------------------------------------------------------
*/
+#if 0
void async_workshop_get_filepath( void *data, u32 len )
{
struct async_workshop_filepath_info *info = data;
u32 _ts;
ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
- if( !SteamAPI_ISteamUGC_GetItemInstallInfo( hSteamUGC, info->id, &_size,
- info->buf, info->len, &_ts ))
+ if( !SteamAPI_ISteamUGC_GetItemInstallInfo( hSteamUGC, info->id, &_size, info->buf, info->len, &_ts ))
{
vg_error( "GetItemInstallInfo failed\n" );
info->buf[0] = '\0';
}
}
-
-void async_workshop_get_installed_files( void *data, u32 len )
-{
- struct async_workshop_installed_files_info *info = data;
-
- ISteamUGC *hSteamUGC = SteamAPI_SteamUGC();
- u32 count = SteamAPI_ISteamUGC_GetSubscribedItems( hSteamUGC, info->buffer,
- *info->len );
-
- vg_info( "Found %u subscribed items\n", count );
-
- u32 j=0;
- for( u32 i=0; i<count; i++ ){
- u32 state = SteamAPI_ISteamUGC_GetItemState( hSteamUGC, info->buffer[i] );
- if( state & k_EItemStateInstalled ){
- info->buffer[j ++] = info->buffer[i];
- }
- }
-
- *info->len = j;
-}
+#endif
#define WORKSHOP_VIEW_PER_PAGE 15
-struct workshop_form{
- enum workshop_op {
+struct workshop_form
+{
+ enum workshop_op
+ {
k_workshop_op_none,
k_workshop_op_downloading_submission,
k_workshop_op_publishing_update,
}
op;
- struct {
+ struct
+ {
char title[80];
char description[512];
char author[32];
}
submission;
- enum workshop_form_page{
+ enum workshop_form_page
+ {
k_workshop_form_hidden,
k_workshop_form_open, /* open but not looking at anything */
k_workshop_form_edit, /* editing a submission */
_world.preview_heap = vg_create_linear_allocator( vg_mem.rtmemory, max_size, VG_MEMORY_SYSTEM );
}
-void skaterift_world_get_save_path( addon_reg *world_reg, char buf[128] )
+void skaterift_world_get_save_path( addon_id addon_id, char buf[128] )
{
- char id[76];
- addon_alias_uid( &world_reg->alias, id );
- snprintf( buf, 128, "savedata/%s.bkv", id );
+ char uid[76];
+ addon_uid( addon_id, uid );
+ snprintf( buf, 128, "savedata/%s.bkv", uid );
}
void world_update( world_instance *world, v3f pos )
typedef struct world_instance world_instance;
-void skaterift_world_get_save_path( addon_reg *world_reg, char buf[128] );
+void skaterift_world_get_save_path( addon_id world_id, char buf[128] );
/* submodule headers */
#include "world_entity.h"
{
bool complete;
- addon_reg *addon;
+ addon_id addon_id;
void *heap;
struct
/* world geometry */
scene_context scene_geo,
+ scene_geo_gpu,
scene_no_collide,
scene_lines;
u32 active_trigger_volume_count;
world_instance main, preview_instance;
- addon_reg *default_hub_addon;
-
- addon_reg *previous_world_addon;
+ addon_id default_hub_addon,
+ previous_world_addon;
char nonlocal_destination_key[32];
bool travelled_through_nonlocal_gate;
ent_gate copy_of_nonlocal_sender;
k_world_loader_unloading_current,
k_world_loader_ready,
k_world_loader_loading,
+ k_world_loader_init,
+ k_world_loader_load_savedata,
k_world_loader_done
}
loader_state;
- addon_reg *loader_reg;
+ addon_id load_addon;
world_instance *loader_instance;
void *loader_heap;
bool loader_preview_mode;
light->angle_sin_cos[1] = cosf( light->angle * 0.5f );
}
- vg_async_call( world_link_gates_async, world, 0 );
- vg_async_stall();
-
+ world_link_gates( world );
world->nonlocal_gate_count = 0;
for( u32 j=0; j<af_arrcount(&world->ent_gate); j ++ )
{
ent_gate *gate = af_arritm( &world->ent_gate, j );
if( (gate->flags & k_ent_gate_nonlocal) && (gate->flags & k_ent_gate_linked) )
{
- if( gate->addon_reg != 0xffffffff )
+ if( gate->remote_addon_id )
{
- addon_reg *reg = get_addon_from_index( k_addon_type_world, gate->addon_reg, 0,0 );
-
char cubemap_path[256];
- nonlocal_gate_cubemap_path( reg, af_str( &world->meta.af, gate->key ), cubemap_path );
+ nonlocal_gate_cubemap_path( gate->remote_addon_id, af_str( &world->meta.af, gate->key ), cubemap_path );
vg_tex2d_load_qoi_async_file( cubemap_path, VG_TEX2D_CUBEMAP,
&world->nonlocal_gates_cubemaps[ gate->cubemap_id ] );
}
}
}
-void nonlocal_gate_cubemap_path( addon_reg *world_addon, const char *gate_key, char path[256] )
+void nonlocal_gate_cubemap_path( addon_id world_addon_id, const char *gate_key, char path[256] )
{
- char id[76];
- addon_alias_uid( &world_addon->alias, id );
+ char uid[76];
+ addon_uid( world_addon_id, uid );
vg_str path_str;
vg_strnull( &path_str, path, 256 );
vg_strcat( &path_str, "maps/" );
- vg_strcat( &path_str, id );
+ vg_strcat( &path_str, uid );
vg_strcat( &path_str, "-cm-" );
vg_strcat( &path_str, gate_key );
vg_strcat( &path_str, ".qoi" );
}
-/*
- * This has to be synchronous because main thread looks at gate data for
- * rendering, and we modify gates that the main thread has ownership of.
+/* NOTE: This used to be async'd to main thread. But isn't anymore. I think the reason was because some gates would
+ * refresh / relink sometimes. But now it should be OK to do in the loader.
*/
-void world_link_gates_async( void *payload, u32 size )
+void world_link_gates( world_instance *world )
{
- VG_ASSERT( vg_thread_purpose() == k_thread_purpose_main );
+ THREAD_1;
- world_instance *world = payload;
bool found_nonlocal_reciever = 0;
for( u32 j=0; j<af_arrcount(&world->ent_gate); j ++ )
addon_alias q;
addon_uid_to_alias( dest_world, &q );
- gate->addon_reg = addon_match( &q );
- if( gate->addon_reg != 0xffffffff )
+ gate->remote_addon_id = _get_addon_by_alias( &q );
+ if( gate->remote_addon_id )
{
gate->flags |= k_ent_gate_linked;
- vg_info( "Linked non-local gate to addon #%u\n", gate->addon_reg );
+ vg_info( "Linked non-local gate to addon #%u\n", (u32)gate->remote_addon_id );
}
else
- {
vg_error( "Reference in non-local gate to other world '%s' was not found.\n", dest_world );
- }
}
if( _world.travelled_through_nonlocal_gate )
if( !(_world.copy_of_nonlocal_sender.flags & k_ent_gate_no_linkback) )
{
- gate->addon_reg = get_index_from_addon( k_addon_type_world, _world.previous_world_addon,0,0 );
-
- if( gate->addon_reg != 0xffffffff )
+ gate->remote_addon_id = _world.previous_world_addon;
+ if( gate->remote_addon_id )
{
gate->flags |= k_ent_gate_linked;
- vg_info( "Linked non-local gate to addon #%u\n", gate->addon_reg );
+ vg_info( "Linked non-local gate to addon #%u\n", gate->remote_addon_id );
}
else
- {
vg_error( "Error while linking to previous world.\n" );
- }
}
}
}
if( _world.travelled_through_nonlocal_gate && !found_nonlocal_reciever )
{
- vg_error( "Player travelled through non-local gate, but no reciever gate was found. Player will default to start spawn or world save file.\n" );
+ vg_error( "Player travelled through non-local gate, but no reciever gate was found.\n"
+ "Player will default to start spawn or world save file.\n" );
_world.travelled_through_nonlocal_gate = 0;
}
}
void world_gates_init(void);
void gate_transform_update( ent_gate *gate );
int render_gate( world_instance *world, world_instance *world_inside,
- ent_gate *gate, vg_camera *cam, vg_framebuffer *target_fb );
+ ent_gate *gate, vg_camera *cam, vg_framebuffer *target_fb );
int gate_intersect( ent_gate *gate, v3f pos, v3f last );
u32 world_intersect_gates( world_instance *world, v3f pos, v3f last );
entity_call_result ent_gate_call( world_instance *world, ent_call *call );
void ent_gate_get_mdl_mtx( ent_gate *gate, m4x3f mmdl );
-void world_link_gates_async( void *payload, u32 size );
+void world_link_gates( world_instance *world );
void world_unlink_nonlocal( world_instance *world );
-void render_gate_unlinked( world_instance *world,
- ent_gate *gate, vg_camera *cam );
-void nonlocal_gate_cubemap_path( addon_reg *world_addon, const char *gate_key, char path[256] );
+void render_gate_unlinked( world_instance *world, ent_gate *gate, vg_camera *cam );
+void nonlocal_gate_cubemap_path( addon_id world_addon_id, const char *gate_key, char path[256] );
/*
* Compile meshes into the world scenes
*/
- scene_init( &world->scene_geo, 320000, 1200000 );
+ u32 geo_max_verts = 320000,
+ geo_max_indices = 1200000;
+ scene_init( &world->scene_geo, geo_max_verts, geo_max_indices );
u32 buf_size = scene_mem_required( &world->scene_geo );
u8 *buffer = vg_linear_alloc( world->heap, buf_size );
scene_supply_buffer( &world->scene_geo, buffer );
struct world_surface *surf = &world->surfaces[ i ];
if( surf->info.flags & k_material_flag_collision )
- world_add_all_if_material( midentity, &world->scene_geo,
- &world->meta, i );
+ world_add_all_if_material( midentity, &world->scene_geo, &world->meta, i );
scene_copy_slice( &world->scene_geo, &surf->sm_geo );
scene_set_vertex_flags( &world->scene_geo,
(u16)(surf->info.flags & 0xffff) );
}
- /* compress that bad boy */
+ /* reduce down to minimum size */
u32 new_vert_max = world->scene_geo.vertex_count,
new_vert_size = vg_align8(new_vert_max*sizeof(scene_vert)),
new_indice_len = world->scene_geo.indice_count*sizeof(u32);
-
u32 *src_indices = world->scene_geo.arrindices,
*dst_indices = (u32 *)(buffer + new_vert_size);
-
memmove( dst_indices, src_indices, new_indice_len );
world->scene_geo.max_indices = world->scene_geo.indice_count;
world->scene_geo.max_vertices = world->scene_geo.vertex_count;
buf_size = scene_mem_required( &world->scene_geo );
-
buffer = vg_linear_resize( world->heap, buffer, buf_size );
world->scene_geo.arrvertices = (scene_vert *)(buffer);
world->scene_geo.arrindices = (u32 *)(buffer + new_vert_size);
- scene_upload_async( &world->scene_geo, &world->mesh_geo );
-
- /* need send off the memory to the gpu before we can create the bvh. */
- vg_async_stall();
+ /* create a copy for the GPU (bvh scrambles the data) */
+ scene_context *gpu_scene = &world->scene_geo_gpu;
+ vg_async_task *task = scene_alloc_async( gpu_scene, &world->mesh_geo, geo_max_verts, geo_max_indices );
+ memcpy( gpu_scene->arrvertices, world->scene_geo.arrvertices, world->scene_geo.vertex_count*sizeof(scene_vert) );
+ memcpy( gpu_scene->arrindices, world->scene_geo.arrindices, world->scene_geo.indice_count*sizeof(u32) );
+ gpu_scene->vertex_count = world->scene_geo.vertex_count;
+ gpu_scene->indice_count = world->scene_geo.indice_count;
+ box_copy( world->scene_geo.bbx, gpu_scene->bbx );
+ vg_async_task_dispatch( task, async_scene_upload );
if( !_world.loader_preview_mode )
{
* ----------------------------------------------------------------
*/
vg_info( "Generating non-collidable geometry\n" );
-
- vg_async_item *call = scene_alloc_async( &world->scene_no_collide,
- &world->mesh_no_collide,
- 250000, 500000 );
+ vg_async_task *task2 = scene_alloc_async( &world->scene_no_collide, &world->mesh_no_collide, 250000, 500000 );
for( u32 i=0; i<world->surface_count; i++ )
{
}
IL_UPLOAD:
- vg_async_dispatch( call, async_scene_upload );
+ vg_async_task_dispatch( task2, async_scene_upload );
}
/* signed distance function for cone */
return d * ((q[0]*c[1]-q[1]*c[0]<0.0f)?-1.0f:1.0f);
}
-struct light_indices_upload_info{
+struct light_indices_upload_info
+{
world_instance *world;
v3i count;
-
- void *data;
+ u8 data[];
};
-
-/*
- * Async reciever to buffer light index data
- */
-static void async_upload_light_indices( void *payload, u32 size ){
- struct light_indices_upload_info *info = payload;
+static void async_upload_light_indices_task( vg_async_task *task )
+{
+ THREAD_0;
+ struct light_indices_upload_info *info = (void *)task->data;
glGenTextures( 1, &info->world->tex_light_cubes );
glBindTexture( GL_TEXTURE_3D, info->world->tex_light_cubes );
- glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI,
- info->count[0], info->count[1], info->count[2],
+ glTexImage3D( GL_TEXTURE_3D, 0, GL_RG32UI, info->count[0], info->count[1], info->count[2],
0, GL_RG_INTEGER, GL_UNSIGNED_INT, info->data );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
int total_cubes = icubes_count[0]*icubes_count[1]*icubes_count[2];
- u32 data_size = vg_align8(total_cubes*sizeof(u32)*2),
- hdr_size = vg_align8(sizeof(struct light_indices_upload_info));
+ u32 data_size = total_cubes*sizeof(u32)*2;
- vg_async_item *call = vg_async_alloc( data_size + hdr_size );
- struct light_indices_upload_info *info = call->payload;
- info->data = ((u8*)call->payload) + hdr_size;
+ vg_async_task *task =
+ vg_allocate_async_task( &vg.main_tasks, sizeof(struct light_indices_upload_info) + data_size, 1 );
+ struct light_indices_upload_info *info = (void *)task->data;
info->world = world;
- u32 *cubes_index = info->data;
+ u32 *cubes_index = (void *)info->data;
for( int i=0; i<3; i++ )
info->count[i] = icubes_count[i];
float bound_radius = v3_length( cube_size );
- for( int iz = 0; iz<icubes_count[2]; iz ++ ){
- for( int iy = 0; iy<icubes_count[1]; iy++ ){
- for( int ix = 0; ix<icubes_count[0]; ix++ ){
+ for( int iz = 0; iz<icubes_count[2]; iz ++ )
+ {
+ for( int iy = 0; iy<icubes_count[1]; iy++ )
+ {
+ for( int ix = 0; ix<icubes_count[0]; ix++ )
+ {
boxf bbx;
v3_div( (v3f){ ix, iy, iz }, world->ub_lighting.g_cube_inv_range,
bbx[0] );
float influences[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
const int N = VG_ARRAY_LEN( influences );
- for( u32 j=0; j<af_arrcount(&world->ent_light); j ++ ){
+ for( u32 j=0; j<af_arrcount(&world->ent_light); j ++ )
+ {
ent_light *light = af_arritm( &world->ent_light, j );
v3f closest;
closest_point_aabb( light->transform.co, bbx, closest );
f32 dist = sqrtf(dist2),
influence = 1.0f/(dist+1.0f);
- if( light->type == k_light_type_spot){
+ if( light->type == k_light_type_spot)
+ {
v3f local;
m4x3_mulv( light->inverse_world, center, local );
if( influence > influences[k] )
best_pos = k;
- if( best_pos < N ){
- for( int k=N-1; k>best_pos; k -- ){
+ if( best_pos < N )
+ {
+ for( int k=N-1; k>best_pos; k -- )
+ {
influences[k] = influences[k-1];
indices[k] = indices[k-1];
}
}
}
- vg_async_dispatch( call, async_upload_light_indices );
+ vg_async_task_dispatch( task, async_upload_light_indices_task );
}
/*
* Rendering pass needed to complete the world
*/
-void async_world_postprocess( void *payload, u32 _size )
+void async_world_postprocess( void *userdata )
{
/* create scene lighting buffer */
- world_instance *world = payload;
+ world_instance *world = userdata;
u32 size = VG_MAX(af_arrcount(&world->ent_light),1) * sizeof(float)*12;
vg_info( "Upload %ubytes (lighting)\n", size );
*/
v4f *light_dst = glMapBuffer( GL_TEXTURE_BUFFER, GL_WRITE_ONLY );
- for( u32 i=0; i<af_arrcount(&world->ent_light); i++ ){
+ for( u32 i=0; i<af_arrcount(&world->ent_light); i++ )
+ {
ent_light *light = af_arritm( &world->ent_light, i );
/* colour + night */
v3_muls( light->colour, light->colour[3] * 2.0f, light_dst[i*3+0] );
light_dst[i*3+0][3] = 2.0f;
- if( !light->daytime ){
+ if( !light->daytime )
+ {
u32 hash = (i * 29986577u) & 0xffu;
float switch_on = hash;
switch_on *= (1.0f/255.0f);
/* upload full buffer */
glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
- glBufferSubData( GL_UNIFORM_BUFFER, 0,
- sizeof(struct ub_world_lighting), &world->ub_lighting );
+ glBufferSubData( GL_UNIFORM_BUFFER, 0, sizeof(struct ub_world_lighting), &world->ub_lighting );
/*
* Allocate cubemaps
*/
- for( u32 i=0; i<af_arrcount(&world->ent_cubemap); i++ ){
+ for( u32 i=0; i<af_arrcount(&world->ent_cubemap); i++ )
+ {
ent_cubemap *cm = af_arritm(&world->ent_cubemap,i);
glGenTextures( 1, &cm->texture_id );
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
- for( u32 j=0; j<6; j ++ ) {
- glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, 0, GL_RGB,
- WORLD_CUBEMAP_RES, WORLD_CUBEMAP_RES,
+ for( u32 j=0; j<6; j ++ )
+ {
+ glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, 0, GL_RGB, WORLD_CUBEMAP_RES, WORLD_CUBEMAP_RES,
0, GL_RGB, GL_UNSIGNED_BYTE, NULL );
}
glBindFramebuffer( GL_FRAMEBUFFER, cm->framebuffer_id );
glGenRenderbuffers(1, &cm->renderbuffer_id );
glBindRenderbuffer( GL_RENDERBUFFER, cm->renderbuffer_id );
- glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24,
- WORLD_CUBEMAP_RES, WORLD_CUBEMAP_RES );
- glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
- GL_RENDERBUFFER, cm->renderbuffer_id );
+ glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, WORLD_CUBEMAP_RES, WORLD_CUBEMAP_RES );
+ glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cm->renderbuffer_id );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_CUBE_MAP_POSITIVE_X, cm->texture_id, 0 );
- if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE ){
+ if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )
vg_error( "Cubemap framebuffer incomplete.\n" );
- }
}
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
void world_gen_load_surfaces( world_instance *world );
void world_gen_generate_meshes( world_instance *world );
void world_gen_compute_light_indices( world_instance *world );
-void async_world_postprocess( void *payload, u32 _size );
+void async_world_postprocess( void *userdata );
ent_script_alloc( world, heap );
vg_loader_set_user_information( "Postprocessing world" );
- vg_async_call( async_world_postprocess, world, 0 );
- vg_async_stall();
+ vg_async_call( &vg.main_tasks, async_world_postprocess, world );
}
-
- vg_loader_set_user_information( NULL );
}
-static void async_world_loader_done( void *payload, u32 size )
+static void async_world_loader_done( void *userdata )
{
- _world.loader_state = k_world_loader_done;
+ THREAD_0;
+ _world.loader_state = k_world_loader_init;
_world.loader_instance->complete = 1;
+
+ if( !_world.loader_preview_mode )
+ menu_on_world_change( _world.main.addon_id );
}
-void skaterift_world_load_thread( void *_ )
+struct world_load_info
+{
+ bool OK;
+ char path[4096];
+};
+void skaterift_world_load_t1( vg_async_task *task )
{
+ THREAD_1;
+ struct world_load_info *info = (void *)task->data;
+
+ if( !info->OK )
+ return;
+
vg_loader_set_user_information( "Scanning world directory" );
- addon_reg *reg = _world.loader_reg;
- _world.loader_instance->addon = reg;
+ addon_reg *reg = addon_details( _world.load_addon );
+ _world.loader_instance->addon_id = _world.load_addon;
char uid[ADDON_UID_MAX];
- addon_alias_uid( &_world.loader_reg->alias, uid );
- vg_info( "LOAD WORLD %s @%d\n", uid );
+ addon_alias_uid( ®->alias, uid );
+ vg_info( "LOAD WORLD %s\n", uid );
- char path_buf[4096];
+ char path_buf[ 4096 ];
vg_str path;
- vg_strnull( &path, path_buf, 4096 );
-
- addon_get_content_folder( reg, &path, 1 );
-
+ vg_strnull( &path, path_buf, sizeof( path_buf ) );
+ vg_strcat( &path, info->path );
+
vg_str folder = path;
if( !vg_strgood( &folder ) )
{
}
world_instance_load_mdl( _world.loader_instance, mdl_path, _world.loader_heap );
-
- vg_async_call( async_world_loader_done, NULL, 0 );
- vg_async_stall();
+ vg_async_call( &vg.main_tasks, async_world_loader_done, NULL );
}
-struct world_savedata_thread_data
+struct world_savedata_info
{
savedata_file save;
world_instance *instance;
};
-void async_start_player_from_worldsave( void *payload, u32 size )
+void async_worldsave_go( vg_async_task *task )
{
- struct world_savedata_thread_data *data = payload;
+ THREAD_0;
+ struct world_savedata_info *info = (void *)task->data;
vg_msg sav;
- vg_msg_init( &sav, data->save.buf, data->save.len );
+ vg_msg_init( &sav, info->save.buf, info->save.len );
/* start entities in the world */
- world_entity_start( data->instance, &sav );
+ world_entity_start( info->instance, &sav );
/* start player in the world */
if( _world.travelled_through_nonlocal_gate )
{
bool restored_player_position = 0;
- vg_msg_init( &sav, data->save.buf, data->save.len );
+ vg_msg_init( &sav, info->save.buf, info->save.len );
vg_msg player_frame = sav;
if( vg_msg_seekframe( &player_frame, "player" ) )
{
}
if( !restored_player_position )
- world_default_spawn_pos( data->instance, localplayer.rb.co );
+ world_default_spawn_pos( info->instance, localplayer.rb.co );
player__reset();
}
network_send_item( k_netmsg_playeritem_world0 );
+ _world.loader_state = k_world_loader_done;
+ _world.load_addon = 0;
+ g_client.unreadyness --;
}
-void load_player_from_world_savedata_thread( void *_ )
+void load_world_savedata_t1( void *userdata )
{
- vg_async_item *call = vg_async_alloc( sizeof(struct world_savedata_thread_data) );
- struct world_savedata_thread_data *data = call->payload;
-
- data->instance = _world.loader_instance;
- skaterift_world_get_save_path( _world.loader_reg, data->save.path );
- savedata_file_read( &data->save );
-
- vg_async_dispatch( call, async_start_player_from_worldsave );
- vg_async_stall();
+ THREAD_1;
+ vg_async_task *task = vg_allocate_async_task( &vg.main_tasks, sizeof(struct world_savedata_info), 1 );
+ struct world_savedata_info *info = (void *)task->data;
+
+ info->instance = _world.loader_instance;
+ skaterift_world_get_save_path( _world.load_addon, info->save.path );
+ savedata_file_read( &info->save );
+ vg_async_task_dispatch( task, async_worldsave_go );
}
-void async_world_switcher_done( void *payload, u32 size )
+vg_async_task *world_load_go(void)
{
- _world.loader_reg = NULL;
-
- if( !_world.loader_preview_mode )
- g_client.unreadyness --;
-}
-
-void world_switcher_thread( void *_ )
-{
- skaterift_world_load_thread( NULL );
- vg_async_stall();
-
- if( !_world.loader_preview_mode )
- {
- load_player_from_world_savedata_thread( NULL );
- vg_async_stall();
- }
-
- vg_async_call( async_world_switcher_done, NULL, 0 );
+ THREAD_0;
+ _world.loader_state = k_world_loader_loading;
+ vg_linear_clear( _world.loader_heap );
+ vg_async_task *task = vg_allocate_async_task( &vg.loader_tasks, sizeof(struct world_load_info), 1 );
+ struct world_load_info *info = (void *)task->data;
+ vg_str folder_str;
+ vg_strnull( &folder_str, info->path, sizeof(info->path) );
+ info->OK = addon_get_content_folder( _world.load_addon, &folder_str );
+ return task;
}
void world_switcher_update(void)
{
- if( !_world.loader_reg )
+ if( !_world.load_addon )
return;
if( _world.loader_state == k_world_loader_saving_current )
{
- if( skaterift_write_all_savedata(1) )
- {
- _world.loader_state = k_world_loader_unloading_current;
- vg_loader_set_user_information( "Unloading current world" );
- }
+ skaterift_write_all_savedata(1);
+ _world.loader_state = k_world_loader_unloading_current;
+ vg_loader_set_user_information( "Unloading current world" );
}
/* pre-load step aka waiting for audio to end. */
if( _world.loader_state == k_world_loader_ready )
{
- if( vg_loader_availible() )
- {
- _world.loader_state = k_world_loader_loading;
+ vg_async_task *task = world_load_go();
+ vg_async_task_dispatch( task, skaterift_world_load_t1 );
+ }
- vg_linear_clear( vg_async.buffer );
- vg_linear_clear( _world.loader_heap );
- vg_loader_start( world_switcher_thread, NULL );
+ if( _world.loader_state == k_world_loader_init )
+ {
+ if( _world.loader_preview_mode )
+ {
+ _world.load_addon = 0;
+ _world.loader_state = k_world_loader_done;
+ }
+ else
+ {
+ _world.loader_state = k_world_loader_load_savedata;
+ vg_async_call( &vg.loader_tasks, load_world_savedata_t1, NULL );
}
}
}
-void skaterift_load_world_start( addon_reg *reg, bool preview )
+void skaterift_load_world_start( addon_id addon_id, bool preview )
{
if( g_client.unreadyness )
{
world_instance *world = preview? &_world.preview_instance: &_world.main;
- if( !reg )
+ if( !addon_id )
{
- if( world->addon )
- {
- reg = world->addon;
- }
+ if( world->addon_id )
+ addon_id = world->addon_id;
else
{
vg_error( "Loaded world has no associated addon registration, can't reload this!\n" );
if( !preview )
{
- if( reg != world->addon )
- _world.previous_world_addon = _world.main.addon;
+ if( addon_id != world->addon_id )
+ _world.previous_world_addon = _world.main.addon_id;
g_client.unreadyness ++;
_world.loader_state = k_world_loader_saving_current;
_world.loader_state = k_world_loader_ready;
char buf[76];
- addon_alias_uid( ®->alias, buf );
+ addon_uid( addon_id, buf );
vg_info( "loading world: %s %s\n", buf, preview? "(preview mode)": "" );
vg_linear_clear( vg_mem.scratch ); /* ?? */
_world.loader_instance = world;
_world.loader_heap = preview? _world.preview_heap: _world.heap;
_world.loader_preview_mode = preview;
- _world_loader_set_target_reg( reg );
+ _world_loader_set_addon( addon_id );
}
-void _world_loader_set_target_reg( addon_reg *reg )
+void _world_loader_set_addon( addon_id addon_id )
{
strcpy( _world.loader_filename, "main.mdl" );
- _world.loader_reg = reg;
+ _world.load_addon = addon_id;
+
+ addon_reg *reg = addon_details(addon_id);
if( reg->flags & ADDON_REG_MTZERO )
{
u64 status = _skaterift_script_nugget_status( "ch2s5_view" );
{
if( !strcmp( argv[0], "reload" ) )
{
- skaterift_load_world_start( NULL, 0 );
+ skaterift_load_world_start( 0, 0 );
return 0;
}
addon_alias q;
addon_uid_to_alias( argv[0], &q );
- u32 reg_id = addon_match( &q );
- if( reg_id != 0xffffffff )
+ addon_id addon_id = _get_addon_by_alias( &q );
+ if( addon_id )
{
- addon_reg *reg = get_addon_from_index( k_addon_type_world, reg_id, 0,0 );
- menu_on_world_change( reg );
- skaterift_load_world_start( reg, 0 );
+ skaterift_load_world_start( addon_id, 0 );
}
else
- {
vg_error( "Addon '%s' is not installed or not found.\n", argv[0] );
- }
}
else
{
vg_info( "worlds availible to load:\n" );
-
- for( int i=0; i<addon_count(k_addon_type_world,0,0); i ++ )
+
+ u32 count = _addon_filtered_count( k_addon_type_world,0,0 );
+ for( int i=0; i<count; i ++ )
{
- addon_reg *w = get_addon_from_index( k_addon_type_world, i, 0,0);
+ addon_id ai = _addon_get_filtered( k_addon_type_world, i, 0,0 );
+ addon_reg *reg = addon_details(ai);
char buf[ADDON_UID_MAX];
- addon_alias_uid( &w->alias, buf );
+ addon_alias_uid( ®->alias, buf );
- if( w->flags & ADDON_REG_HIDDEN )
+ if( reg->flags & ADDON_REG_HIDDEN )
vg_info( " %s [hidden]\n", buf );
else
vg_info( " %s\n", buf );
#include "addon.h"
int skaterift_load_world_command( int argc, const char *argv[] );
-void skaterift_load_world_start( addon_reg *reg, bool preview_mode );
-void _world_loader_set_target_reg( addon_reg *reg );
+void skaterift_load_world_start( addon_id addon, bool preview_mode );
+void _world_loader_set_addon( addon_id addon );
void world_switcher_update(void);
-void world_switcher_thread( void *_ );
void world_instance_free_graphics_data( world_instance *world );
+vg_async_task *world_load_go(void);
+void skaterift_world_load_t1( vg_async_task *task );
title_text = menu.clicked_world_name? menu.clicked_world_name: "...";
- subtitle_text = (menu.clicked_world_reg == _world.main.addon)? "Current Location": NULL;
+ subtitle_text = (menu.clicked_world_id == _world.main.addon_id)? "Current Location": NULL;
ctx->font = &vgf_default_title;
upper_title[2] = ui_text_line_width(ctx,title_text) + 24;
for( u32 i=0; i<menu.world_list_display_count; i ++ )
{
- addon_reg *reg = menu.world_list_entries[i];
-
+ addon_id addon_id = menu.world_list_entries[i];
bool clickable = 1;
- if( reg )
+ if( addon_id )
{
- bool selected = reg == menu.clicked_world_reg;
+ addon_reg *reg = addon_details( addon_id );
+ bool selected = addon_id == menu.clicked_world_id;
if( selected )
{
ui_rect sel_box, _null;
clickable = !selected;
}
else
- {
clickable = 0;
- }
if( menu_button( ctx, panel, R == (page_base + i), clickable, menu.world_list_names[i] ) )
{
- menu.clicked_world_reg = reg;
+ menu.clicked_world_id = addon_id;
menu.clicked_world_name = menu.world_list_names[i];
}
}
menu_update_world_list();
}
- if( (_world.loader_state == k_world_loader_done) && (menu.clicked_world_reg) )
+ if( (_world.loader_state == k_world_loader_done) && (menu.clicked_world_id) )
{
bool do_load = 0;
if( _world.preview_instance.complete )
{
- if( _world.preview_instance.addon != menu.clicked_world_reg )
+ if( _world.preview_instance.addon_id != menu.clicked_world_id )
do_load = 1;
}
else
do_load = 1;
if( do_load )
- skaterift_load_world_start( menu.clicked_world_reg, 1 );
+ skaterift_load_world_start( menu.clicked_world_id, 1 );
}
ctx->font = &vgf_default_title;
vg_input_string( &enter_helper, input_button_list[k_srbind_mhub], 1 );
bool enter_location = 0;
- if( menu_button( ctx, enter_world_box, 0, menu.clicked_world_reg?1:0, buf ) )
+ if( menu_button( ctx, enter_world_box, 0, menu.clicked_world_id?1:0, buf ) )
enter_location = 1;
if( button_down( k_srbind_mhub ) )
enter_location = 1;
- if( enter_location && menu.clicked_world_reg )
+ if( enter_location && menu.clicked_world_id )
{
- if( menu.clicked_world_reg != _world.main.addon )
- skaterift_load_world_start( menu.clicked_world_reg, 0 );
+ if( menu.clicked_world_id != _world.main.addon_id )
+ skaterift_load_world_start( menu.clicked_world_id, 0 );
world_map.activity = k_map_activity_local_world;
world_map.superworld_actual_world = world_map.superworld_list_selected;
return 0;
}
-static void async_world_render_init( void *payload, u32 size )
+static void async_world_render_init( void *userdata )
{
vg_info( "Allocate uniform buffers\n" );
world_instance *world = &_world.main;
world->ubo_bind_point = 0;
-
glGenBuffers( 1, &world->ubo_lighting );
glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting );
- glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting),
- NULL, GL_DYNAMIC_DRAW );
-
+ glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), NULL, GL_DYNAMIC_DRAW );
glBindBufferBase( GL_UNIFORM_BUFFER, 0, world->ubo_lighting );
}
.attachment = GL_COLOR_ATTACHMENT0
};
vg_framebuffer_create( world->heightmap );
-
- vg_async_call( async_world_render_init, NULL, 0 );
+ vg_async_call( &vg.main_tasks, async_world_render_init, NULL );
}
/*
}
}
+// dev
void render_world_portal_cubemaps(void)
{
- if( vg_loader_availible() ) // HACK?
+ qoi_desc desc =
{
- qoi_desc desc =
- {
- .width = 512,
- .height = 512*6,
- .channels = 3,
- .colorspace = 0
- };
-
- vg_linear_clear( vg_async.buffer );
- u8 *src_image = vg_linear_alloc( vg_async.buffer, 512*512*3*6 );
- u8 *compressed_image = vg_linear_alloc( vg_async.buffer, vg_query_qoi_storage_size( &desc ) );
-
- GLuint temp_tex, temp_fb, temp_rb;
+ .width = 512,
+ .height = 512*6,
+ .channels = 3,
+ .colorspace = 0
+ };
- glGenFramebuffers( 1, &temp_fb );
- glBindFramebuffer( GL_FRAMEBUFFER, temp_fb );
+ u8 *src_image = malloc( 512*512*3*6 );
+ u8 *compressed_image = malloc( vg_query_qoi_storage_size( &desc ) );
- glGenRenderbuffers( 1, &temp_rb );
- glBindRenderbuffer( GL_RENDERBUFFER, temp_rb );
- glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512 );
- glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, temp_rb );
+ GLuint temp_tex, temp_fb, temp_rb;
+ glGenFramebuffers( 1, &temp_fb );
+ glBindFramebuffer( GL_FRAMEBUFFER, temp_fb );
- glGenTextures( 1, &temp_tex );
- glBindTexture( GL_TEXTURE_2D, temp_tex );
- glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL );
- glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_tex, 0 );
+ glGenRenderbuffers( 1, &temp_rb );
+ glBindRenderbuffer( GL_RENDERBUFFER, temp_rb );
+ glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512 );
+ glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, temp_rb );
- if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )
- {
- vg_error( "Cubemap framebuffer incomplete.\n" );
- return;
- }
+ glGenTextures( 1, &temp_tex );
+ glBindTexture( GL_TEXTURE_2D, temp_tex );
+ glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, 512, 512, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL );
+ glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_tex, 0 );
- glViewport( 0, 0, 512, 512 );
- vg_framebuffer temp_vg_framebuffer =
- {
- .display_name = NULL,
- .resolution_div = 0,
- .fixed_w = 512,
- .fixed_h = 512,
- .id = temp_fb,
- .attachment_count = 0,
- .attachments = NULL
- };
+ if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )
+ {
+ vg_error( "Cubemap framebuffer incomplete.\n" );
+ goto e0;
+ }
- world_instance *world = &_world.main;
+ glViewport( 0, 0, 512, 512 );
+ vg_framebuffer temp_vg_framebuffer =
+ {
+ .display_name = NULL,
+ .resolution_div = 0,
+ .fixed_w = 512,
+ .fixed_h = 512,
+ .id = temp_fb,
+ .attachment_count = 0,
+ .attachments = NULL
+ };
- for( u32 j=0; j<af_arrcount(&world->ent_gate); j ++ )
+ world_instance *world = &_world.main;
+ for( u32 j=0; j<af_arrcount(&world->ent_gate); j ++ )
+ {
+ ent_gate *gate = af_arritm( &world->ent_gate, j );
+ if( gate->flags & k_ent_gate_nonlocal )
{
- ent_gate *gate = af_arritm( &world->ent_gate, j );
- if( gate->flags & k_ent_gate_nonlocal )
- {
- v3f co;
- v3_add( gate->co[0], (v3f){0,2,0}, co );
+ v3f co;
+ v3_add( gate->co[0], (v3f){0,2,0}, co );
- m3x3f rotation;
- m3x3f correction = {{0,0,1},{0,1,0},{-1,0,0}};
- m3x3_mul( correction, gate->to_world, rotation );
+ m3x3f rotation;
+ m3x3f correction = {{0,0,1},{0,1,0},{-1,0,0}};
+ m3x3_mul( correction, gate->to_world, rotation );
- for( u32 i=0; i<6; i ++ )
- {
- glClear( GL_DEPTH_BUFFER_BIT );
- render_cubemap_side( &_world.main, co, gate->to_world, i, &temp_vg_framebuffer );
+ for( u32 i=0; i<6; i ++ )
+ {
+ glClear( GL_DEPTH_BUFFER_BIT );
+ render_cubemap_side( &_world.main, co, gate->to_world, i, &temp_vg_framebuffer );
- u8 *dest_side = src_image + i*512*512*3;
- glReadBuffer( GL_COLOR_ATTACHMENT0 );
- glReadPixels( 0,0, 512,512, GL_RGB, GL_UNSIGNED_BYTE, dest_side );
- }
+ u8 *dest_side = src_image + i*512*512*3;
+ glReadBuffer( GL_COLOR_ATTACHMENT0 );
+ glReadPixels( 0,0, 512,512, GL_RGB, GL_UNSIGNED_BYTE, dest_side );
+ }
- char path[256];
- nonlocal_gate_cubemap_path( world->addon, af_str( &world->meta.af, gate->key ), path );
+ char path[256];
+ nonlocal_gate_cubemap_path( world->addon_id, af_str( &world->meta.af, gate->key ), path );
- int file_size;
- if( vg_encode_qoi2( src_image, &desc, compressed_image, &file_size ) )
- {
- vg_asset_write( path, compressed_image, file_size );
- }
- }
+ int file_size;
+ if( vg_encode_qoi2( src_image, &desc, compressed_image, &file_size ) )
+ vg_asset_write( path, compressed_image, file_size );
}
-
- glDeleteTextures( 1, &temp_tex );
- glDeleteFramebuffers( 1, &temp_fb );
- glDeleteRenderbuffers( 1, &temp_rb );
}
+
+e0:glDeleteTextures( 1, &temp_tex );
+ glDeleteFramebuffers( 1, &temp_fb );
+ glDeleteRenderbuffers( 1, &temp_rb );
+ free( src_image );
+ free( compressed_image );
}
static int ccmd_render_portals( int argc, const char *argv[] )
}
}
- addon_alias *alias = &_world.main.addon->alias;
-
char mod_uid[ ADDON_UID_MAX ];
- addon_alias_uid( alias, mod_uid );
+ addon_uid( _world.main.addon_id, mod_uid );
network_publish_laptime( mod_uid, af_str( &world->meta.af, route->pstr_name ), lap_time );
}
route->valid_checkpoints = valid_sections+1;
-
vg_info( "valid sections: %u\n", valid_sections );
vg_info( "----------------------------\n" );
*/
void world_gen_routes_generate( world_instance *world )
{
+ THREAD_1;
vg_info( "Generating route meshes\n" );
- vg_async_stall();
-
- vg_async_item *call_scene = scene_alloc_async( &world->scene_lines,
- &world->mesh_route_lines,
- 200000, 300000 );
+ vg_async_task *task = scene_alloc_async( &world->scene_lines, &world->mesh_route_lines, 200000, 300000 );
for( u32 i=0; i<af_arrcount(&world->ent_gate); i++ )
{
}
}
- for( u32 i=0; i<af_arrcount(&world->ent_route); i++ ){
+ for( u32 i=0; i<af_arrcount(&world->ent_route); i++ )
world_routes_gen_meshes( world, i, &world->scene_lines );
- }
- vg_async_dispatch( call_scene, async_scene_upload );
+ vg_async_task_dispatch( task, async_scene_upload );
world_routes_clear( world );
}
{
board->cache_time = vg.time_real;
ent_route *route = af_arritm( &world->ent_route, closest );
- addon_reg *world_reg = _world.main.addon;
char mod_uid[ ADDON_UID_MAX ];
- addon_alias_uid( &world_reg->alias, mod_uid );
+ addon_uid( _world.main.addon_id, mod_uid );
- network_request_scoreboard(
- mod_uid,
- af_str( &world->meta.af, route->pstr_name ),
- NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK, closest );
+ network_request_scoreboard( mod_uid, af_str( &world->meta.af, route->pstr_name ),
+ NETWORK_LEADERBOARD_ALLTIME_AND_CURRENT_WEEK, closest );
}
}
mdl_load_mesh_block( &mscoreboard, vg_mem.scratch );
scene_context *scene = &world_sfd.scene;
- vg_async_item *call = scene_alloc_async( scene, &world_sfd.mesh_display, 3000, 8000 );
+ vg_async_task *task = scene_alloc_async( scene, &world_sfd.mesh_display, 3000, 8000 );
mdl_submesh *sm_card = &mscoreboard.submeshes[ mdl_get_submesh_index( &mscoreboard, "score_card" ) ];
world_sfd.sm_base = mscoreboard.submeshes[ mdl_get_submesh_index( &mscoreboard, "backer" ) ];
}
}
- vg_async_dispatch( call, async_scene_upload );
- vg_tex2d_load_qoi_async_file( "textures/scoretext.qoi",
- VG_TEX2D_CLAMP|VG_TEX2D_NEAREST,
- &world_sfd.tex_scoretex );
-
+ vg_async_task_dispatch( task, async_scene_upload );
+ vg_tex2d_load_qoi_async_file( "textures/scoretext.qoi", VG_TEX2D_CLAMP|VG_TEX2D_NEAREST, &world_sfd.tex_scoretex );
mdl_close( &mscoreboard );
int w = 27,