_S( "scene_standard_alphatest", "scene.vs", "scene_standard_alphatest.fs" );
_S( "scene_foliage", "scene_foliage.vs", "scene_foliage.fs" );
_S( "scene_override", "scene_override.vs", "scene_override.fs" );
+ _S( "scene_preview", "scene_override.vs", "scene_preview.fs" );
_S( "scene_fxglow", "scene_fxglow.vs", "scene_fxglow.fs" );
_S( "scene_vertex_blend", "scene.vs", "scene_vertex_blend.fs" );
_S( "scene_terrain", "scene.vs", "scene_terrain.fs" );
--- /dev/null
+in vec2 aUv;
+in vec4 aNorm;
+in vec3 aCo;
+in vec3 aWorldCo;
+
+uniform bool uAlphatest;
+uniform vec4 uMapInfo; /* x: min, y: max, z: iso line amount */
+
+layout (location = 0) out vec4 oColour;
+
+#include "motion_vectors_fs.glsl"
+
+void main()
+{
+ vec2 ssuv = gl_FragCoord.xy;
+ vec3 vDither = vec3( dot( vec2( 171.0, 231.0 ), ssuv) );
+ float dither = fract( vDither.g / 71.0 ) - 0.5;
+
+ float dy0 = aCo.y - uMapInfo.x;
+ float dy1 = uMapInfo.y - aCo.y;
+
+ if( min(dy0,dy1)*0.5 + dither < 0.51 )
+ discard;
+
+ compute_motion_vectors();
+
+ vec3 vfrag = vec3(aUv.xy,0.0);
+ vec3 qnorm = aNorm.xyz;
+
+ qnorm = normalize(floor(aNorm.xyz*4.0)*0.25);
+ qnorm += vec3(0.001,0.0,0.0);
+
+ if( uAlphatest ){
+ //vec4 vSample = texture( uTexMain, aUv );
+ //if( vSample.a < 0.5 )
+ // discard;
+ }
+ else{
+ }
+
+ oColour = vec4( vfrag, 1.0 );
+}
{
network_set_host( "skaterift.com", NULL );
vg_mem.use_libc_malloc = 0;
- vg_set_mem_quota( 160*1024*1024 );
+ vg_set_mem_quota( 200*1024*1024 );
vg_enter( argc, argv, "Voyager Game Engine" );
return 0;
}
}
static bool menu_button( ui_context *ctx,
- ui_rect inout_panel, bool select, const char *text )
+ ui_rect inout_panel, bool select, bool clickable, const char *text )
{
ui_rect rect;
menu_standard_widget( ctx, inout_panel, rect, 1 );
{
menu_decor_select( ctx, rect );
- if( button_down( k_srbind_maccept ) )
+ if( clickable && button_down( k_srbind_maccept ) )
state = k_ui_button_click;
}
}
else
{
- state = ui_button_base( ctx, rect );
+ if( clickable )
+ state = ui_button_base( ctx, rect );
select = 0;
}
- if( state == k_ui_button_click )
- {
- ui_fill( ctx, rect, GUI_COL_DARK );
- }
- else if( state == k_ui_button_holding_inside )
+ if( clickable )
{
- ui_fill( ctx, rect, GUI_COL_DARK );
+ if( state == k_ui_button_click )
+ {
+ ui_fill( ctx, rect, GUI_COL_DARK );
+ }
+ else if( state == k_ui_button_holding_inside )
+ {
+ ui_fill( ctx, rect, GUI_COL_DARK );
+ }
+ else if( state == k_ui_button_holding_outside )
+ {
+ ui_fill( ctx, rect, GUI_COL_DARK );
+ ui_outline( ctx, rect, 1, GUI_COL_CLICK, 0 );
+ }
+ else if( state == k_ui_button_hover )
+ {
+ ui_fill( ctx, rect, GUI_COL_ACTIVE );
+ ui_outline( ctx, rect, 1, GUI_COL_CLICK, 0 );
+ }
+ else
+ {
+ ui_fill( ctx, rect, select? GUI_COL_ACTIVE: GUI_COL_NORM );
+ if( select )
+ ui_outline( ctx, rect, 1, GUI_COL_HI, 0 );
+ }
}
- else if( state == k_ui_button_holding_outside )
+ else
{
ui_fill( ctx, rect, GUI_COL_DARK );
- ui_outline( ctx, rect, 1, GUI_COL_CLICK, 0 );
- }
- else if( state == k_ui_button_hover )
- {
- ui_fill( ctx, rect, GUI_COL_ACTIVE );
- ui_outline( ctx, rect, 1, GUI_COL_CLICK, 0 );
- }
- else
- {
- ui_fill( ctx, rect, select? GUI_COL_ACTIVE: GUI_COL_NORM );
- if( select )
- ui_outline( ctx, rect, 1, GUI_COL_HI, 0 );
}
- ui_text( ctx, rect, text, 1, k_ui_align_middle_center, 0 );
+ ui_text( ctx, rect, text, 1, k_ui_align_middle_center, clickable? 0: ui_colour(ctx,k_ui_bg) );
if( state == k_ui_button_click )
{
menu.web_choice = 0;
}
+static void menu_update_world_list(void)
+{
+ menu.world_list_total_count = addon_count( k_addon_type_world, ADDON_REG_HIDDEN );
+
+ if( menu.world_list_selected_index >= menu.world_list_total_count )
+ vg_fatal_error( "World list index out of range! (%d >= %d)\n",
+ menu.world_list_selected_index, menu.world_list_total_count );
+
+ u32 selected_world_index = menu.world_list_selected_index,
+ page_base = (selected_world_index / MENU_WORLD_COUNT) * MENU_WORLD_COUNT;
+
+ menu.world_list_display_count = 0;
+
+ for( u32 i=0; i<MENU_WORLD_COUNT; i ++ )
+ {
+ u32 world_index = page_base + i;
+
+ if( world_index >= menu.world_list_total_count )
+ menu.world_list_entries[i] = NULL;
+ else
+ {
+ addon_reg *reg = get_addon_from_index( k_addon_type_world, world_index, ADDON_REG_HIDDEN );
+ menu.world_list_entries[ menu.world_list_display_count ] = reg;
+
+ vg_msg msg;
+ vg_msg_init( &msg, reg->metadata, reg->metadata_len );
+
+ const char *name = vg_msg_getkvstr( &msg, "location" );
+
+ if( !name )
+ name = reg->alias.foldername;
+
+ menu.world_list_names[ menu.world_list_display_count ] = name;
+ menu.world_list_display_count ++;
+ }
+ }
+}
+
void menu_gui( ui_context *ctx )
{
if( button_down( k_srbind_mopen ) )
i32 R = menu_nav( &menu.web_choice, mh, 2 );
- if( menu_button( ctx, a, R==0, "Steam Overlay" ) )
+ if( menu_button( ctx, a, R==0, steam_ready, "Steam Overlay" ) )
{
- if( steam_ready )
- {
- ISteamFriends *hSteamFriends = SteamAPI_SteamFriends();
- SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage( hSteamFriends,
- menu.web_link,
- k_EActivateGameOverlayToWebPageMode_Default );
- menu.web_link = NULL;
- }
+ ISteamFriends *hSteamFriends = SteamAPI_SteamFriends();
+ SteamAPI_ISteamFriends_ActivateGameOverlayToWebPage( hSteamFriends,
+ menu.web_link,
+ k_EActivateGameOverlayToWebPageMode_Default );
+ menu.web_link = NULL;
}
- if( menu_button( ctx, b, R==1, "Web Browser" ) )
+ if( menu_button( ctx, b, R==1, 1, "Web Browser" ) )
{
char buf[512];
vg_str str;
menu.web_link = NULL;
}
- if( menu_button( ctx, c, R==2, "No" ) || button_down( k_srbind_mback ) )
+ if( menu_button( ctx, c, R==2, 1, "No" ) || button_down( k_srbind_mback ) )
{
audio_lock();
audio_oneshot( &audio_ui[3], 1.0f, 0.0f );
ui_rect end = { panel[0], panel[1] + panel[3] - 64, panel[2], 64 };
- if( menu_button( ctx, end, 1, "Back" ) || button_down( k_srbind_mback ) )
+ if( menu_button( ctx, end, 1, 1, "Back" ) || button_down( k_srbind_mback ) )
{
menu.page = k_menu_page_main;
}
ui_rect end = { panel[0], panel[1] + panel[3] - 100, panel[2], 100 };
menu_checkbox( ctx, end, R == 2,
"Don't show this again", &menu.skip_starter );
- if( menu_button( ctx, end, R == 3, "OK" ) )
+ if( menu_button( ctx, end, R == 3, 1, "OK" ) )
{
menu.page = k_menu_page_main;
skaterift.activity = k_skaterift_default;
ui_rect end = { panel[0], panel[1] + panel[3] - 48, panel[2], 48 }, a,b;
ui_split_ratio( end, k_ui_axis_v, 0.5f, 2, a, b );
- if( menu_button( ctx, a, R == 0, "Store Page" ) )
+ if( menu_button( ctx, a, R == 0, steam_ready, "Store Page" ) )
{
- if( steam_ready )
- SteamAPI_ISteamFriends_ActivateGameOverlayToStore(
- SteamAPI_SteamFriends(), 2103940, k_EOverlayToStoreFlag_None);
+ SteamAPI_ISteamFriends_ActivateGameOverlayToStore(
+ SteamAPI_SteamFriends(), 2103940, k_EOverlayToStoreFlag_None);
}
- if( menu_button( ctx, b, R == 1, "Nah" ) || button_down( k_srbind_mback ) )
+ if( menu_button( ctx, b, R == 1, 1, "Nah" ) || button_down( k_srbind_mback ) )
{
audio_lock();
audio_oneshot( &audio_ui[3], 1.0f, 0.0f );
goto menu_draw;
}
+ else if( menu.page == k_menu_page_world_select )
+ {
+ ctx->font = &vgf_default_large;
+
+ ui_rect left_world_list = { 0, 0, 300, vg.window_y };
+ ui_fill( ctx, left_world_list, ui_opacity( GUI_COL_DARK, 0.35f ) );
+
+ ui_rect title;
+ ui_split( left_world_list, k_ui_axis_h, 28, 0, title, left_world_list );
+ ui_text( ctx, title, "Locations", 1, k_ui_align_middle_center, 0 );
+
+ i32 selected_world_index = menu.world_list_selected_index,
+ page = selected_world_index / MENU_WORLD_COUNT,
+ page_base = page * MENU_WORLD_COUNT,
+ max_page = (menu.world_list_total_count-1) / MENU_WORLD_COUNT;
+
+ i32 R = menu_nav( &menu.world_list_selected_index, mv, menu.world_list_total_count-1 );
+
+
+
+ if( menu_button( ctx, left_world_list, R == -999, page>0, "\x94" ) )
+ menu.world_list_selected_index = (page-1)*MENU_WORLD_COUNT;
+
+ for( u32 i=0; i<menu.world_list_display_count; i ++ )
+ {
+ addon_reg *reg = menu.world_list_entries[i];
+ if( menu_button( ctx, left_world_list, R == (page_base + i), 1, menu.world_list_names[i] ) )
+ {
+ }
+ }
+
+ if( menu_button( ctx, left_world_list, R == -999, page<max_page, "\x96" ) )
+ menu.world_list_selected_index = (page+1)*MENU_WORLD_COUNT;
+
+ if( menu.world_list_selected_index < page_base ||
+ menu.world_list_selected_index >= (page_base+MENU_WORLD_COUNT) )
+ {
+ menu_update_world_list();
+ }
+
+
+
+
+ if( /*menu_button( ctx, end, 1, 1, "Back" ) ||*/ button_down( k_srbind_mback ) )
+ {
+ menu.page = k_menu_page_main;
+ }
+
+ goto menu_draw;
+ }
/* TOP BAR
* -------------------------------------------------------------------*/
{
i32 R = menu_nav( &menu.main_row, mv, 2 );
- if( menu_button( ctx, list, R == 0, "Resume" ) )
+ if( menu_button( ctx, list, R == 0, 1, "Resume" ) )
{
skaterift.activity = k_skaterift_default;
return;
}
- if( menu_button( ctx, list, R == 1, "Credits" ) )
+ if( menu_button( ctx, list, R == 1, 1, "Change World" ) )
+ {
+ menu.page = k_menu_page_world_select;
+ menu_update_world_list();
+ }
+
+ if( menu_button( ctx, list, R == 2, 1, "Credits" ) )
{
menu.page = k_menu_page_credits;
}
ui_rect end = { list[0], list[1]+list[3]-64, list[2], 72 };
- if( menu_button( ctx, end, R == 2, "Quit Game" ) )
+ if( menu_button( ctx, end, R == 3, 1, "Quit Game" ) )
{
vg.window_should_close = 1;
}
ui_rect end = { list[0], list[1]+list[3]-64, list[2], 72 };
ctx->font = &vgf_default_small;
menu_heading( ctx, end, "Advanced", 0 );
- if( menu_button( ctx, end, R == 8, "Open Engine Settings" ) )
+ if( menu_button( ctx, end, R == 8, 1, "Open Engine Settings" ) )
{
vg_settings_open();
}
vs[2].co[1] = vs[0].co[1] + 84 + vgf_default_large.sy*11 + 16;
vs[3].co[1] = vs[2].co[1];
}
- if( menu_button( ctx, list, R == 0, "Where to go" ) )
+ if( menu_button( ctx, list, R == 0, 1, "Where to go" ) )
menu.guide_sel = 1;
if( menu.guide_sel == 3 )
vs[2].co[1] = vs[0].co[1] + 84 + vgf_default_large.sy*7 + 16;
vs[3].co[1] = vs[2].co[1];
}
- if( menu_button( ctx, list, R == 1, "Playing Online" ) )
+ if( menu_button( ctx, list, R == 1, 1, "Playing Online" ) )
menu.guide_sel = 3;
menu_heading( ctx, list, "Controls", 0 );
- if( menu_button( ctx, list, R == 2, "Skating \xb2" ) )
+ if( menu_button( ctx, list, R == 2, 1, "Skating \xb2" ) )
{
menu.guide_sel = 0;
menu_link_modal(
}
//if( menu.guide_sel == 0 || menu.guide_sel > 3 ) menu_try_find_cam( 3 );
- if( menu_button( ctx, list, R == 3, "Tricks \xb2" ) )
+ if( menu_button( ctx, list, R == 3, 1, "Tricks \xb2" ) )
{
menu.guide_sel = 0;
menu_link_modal(
}
menu_heading( ctx, list, "Workshop", 0 );
- if( menu_button( ctx, list, R == 4, "Create a Board \xb2" ) )
+ if( menu_button( ctx, list, R == 4, 1, "Create a Board \xb2" ) )
{
menu.guide_sel = 0;
menu_link_modal(
"https://skaterift.com/index.php?page=workshop_board" );
}
- if( menu_button( ctx, list, R == 5, "Create a World \xb2" ) )
+ if( menu_button( ctx, list, R == 5, 1, "Create a World \xb2" ) )
{
menu.guide_sel = 0;
menu_link_modal(
"https://skaterift.com/index.php?page=workshop_world" );
}
- if( menu_button( ctx, list, R == 6, "Create a Playermodel \xb2" ) )
+ if( menu_button( ctx, list, R == 6, 1, "Create a Playermodel \xb2" ) )
{
menu.guide_sel = 0;
menu_link_modal(
#pragma once
#define MENU_STACK_SIZE 8
+#define MENU_WORLD_COUNT 4
#include "vg/vg_engine.h"
#include "entity.h"
k_menu_page_main,
k_menu_page_credits,
k_menu_page_help,
+ k_menu_page_world_select
};
enum menu_main_subpage
i32 web_choice;
GLuint prem_tex;
+
+ addon_reg *world_list_entries[ MENU_WORLD_COUNT ];
+ const char *world_list_names[ MENU_WORLD_COUNT ];
+
+ i32 world_list_display_count,
+ world_list_total_count,
+ world_list_selected_index;
}
extern menu;
k_strncpy_overflow_fatal );
addon_reg *reg = get_addon_from_index( k_addon_type_world, gate->addon_reg, 0 );
- skaterift_switch_world_start( reg );
+ skaterift_load_world_start( reg, 0 );
return;
}
else
reg_id = addon_match( &q );
if( reg_id != 0xffffffff )
{
- _world.switch_to_addon =
- get_addon_from_index( k_addon_type_world, reg_id, 0 );
+ _world.loader_reg = get_addon_from_index( k_addon_type_world, reg_id, 0 );
}
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 );
+ vg_error( "While loading player location from save file, couldn't find addon '%s'\n", buf );
}
}
}
else
{
vg_info( "Starting new story!\n" );
- _world.switch_to_addon =
- addon_mount_local_addon( "maps/dev_heaven", k_addon_type_world, ".mdl" );
+ _world.loader_reg = addon_mount_local_addon( "maps/dev_heaven", k_addon_type_world, ".mdl" );
_skaterift_script_hook( 2, (const char *[]){ "unlock", "intro" } );
}
}
{
addon_reg *reg = addon_mount_local_addon( path, k_addon_type_world, ".mdl" );
if( !reg ) vg_fatal_error( "world not found\n" );
- reg->flags |= (ADDON_REG_HIDDEN | ext);
+ reg->flags |= (ext);
return reg;
}
static void skaterift_load_world_content(void)
{
/* hub world */
- _world.default_hub_addon =
- skaterift_mount_world_unloadable( "maps/dev_hub", 0 );
- skaterift_mount_world_unloadable( "maps/dev_heaven", 0 );
+ _world.default_hub_addon = skaterift_mount_world_unloadable( "maps/dev_hub", 0 );
+ skaterift_mount_world_unloadable( "maps/dev_heaven", ADDON_REG_HIDDEN );
skaterift_mount_world_unloadable( "maps/mp_spawn", ADDON_REG_CITY|ADDON_REG_PREMIUM );
skaterift_mount_world_unloadable( "maps/mp_mtzero", ADDON_REG_MTZERO|ADDON_REG_PREMIUM );
skaterift_mount_world_unloadable( "maps/dev_tutorial", 0 );
- skaterift_mount_world_unloadable( "maps/dev_flatworld", 0 );
+ skaterift_mount_world_unloadable( "maps/dev_flatworld", ADDON_REG_HIDDEN );
skaterift_mount_world_unloadable( "maps/mp_line1", ADDON_REG_PREMIUM );
}
player_load_animation_reference( "models/ch_none.mdl" );
player_load_animations( "metascenes/skater.ms" );
- player_model_load( &localplayer.fallback_model, "models/ch_none.mdl",
- vg_mem.rtmemory );
+ player_model_load( &localplayer.fallback_model, "models/ch_none.mdl", vg_mem.rtmemory );
player__bind();
- player_board_load( &localplayer.fallback_board, "models/board_none.mdl",
- vg_mem.rtmemory );
+ player_board_load( &localplayer.fallback_board, "models/board_none.mdl", vg_mem.rtmemory );
}
void game_load(void)
vg_loader_set_user_information( "Initializing subsystems" );
- vg_console_reg_cmd( "switch_world", skaterift_switch_world_command, NULL );
+ vg_console_reg_cmd( "load_world", skaterift_load_world_command, NULL );
vg_console_reg_var( "immobile", &localplayer.immobile, k_var_dtype_i32, 0 );
vg_loader_step( menu_init, NULL );
vg_loader_step( control_overlay_init, NULL );
vg_loader_set_user_information( "Loading savedata" );
skaterift_load_mainsave();
- if( !_world.switch_to_addon )
+ _world.loader_instance = &_world.main;
+ _world.loader_preview_mode = 0;
+ _world.loader_heap = _world.heap;
+
+ if( !_world.loader_reg )
{
vg_warn( "Falling back to default hub world...\n" );
- _world.switch_to_addon = _world.default_hub_addon;
+ _world.loader_reg = _world.default_hub_addon;
}
world_switcher_thread( NULL );
player__render( &small_cam );
}
+
+
+
static void render_scene(void)
{
/* Draw world */
render_world_routes( world, world, identity, &g_render.cam, 0, 1 );
return;
}
-
- render_world( &_world.main, &g_render.cam, 0, 0, 1, 1 );
+
+ if( _world.preview_instance.complete )
+ {
+ render_world_preview();
+ }
+ else
+ render_world( &_world.main, &g_render.cam, 0, 0, 1, 1 );
particle_system_update( &particles_grind, vg.time_delta );
//particle_system_debug( &particles_grind );
/* Allocate dynamic world memory arena */
u32 max_size = 76*1024*1024;
- _world.heap = vg_create_linear_allocator( vg_mem.rtmemory, max_size,
- VG_MEMORY_SYSTEM );
+ _world.heap = vg_create_linear_allocator( vg_mem.rtmemory, max_size, VG_MEMORY_SYSTEM );
+
+ max_size = 32*1024*1024;
+ _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] )
struct world_instance
{
+ bool complete;
+
addon_reg *addon;
void *heap;
* Allocated as system memory
* --------------------------------------------------------------------------
*/
- void *heap;
+ void *heap, *preview_heap;
u32 current_run_version;
double time, rewind_from, rewind_to;
u32 active_trigger_volumes[8];
u32 active_trigger_volume_count;
- world_instance main;
- addon_reg *default_hub_addon, *switch_to_addon;
+ world_instance main, preview_instance;
+ addon_reg *default_hub_addon;
addon_reg *previous_world_addon;
char nonlocal_destination_key[32];
}
loader_state;
+ addon_reg *loader_reg;
+ world_instance *loader_instance;
+ void *loader_heap;
+ bool loader_preview_mode;
+
enum world_event
{
k_world_event_none = 0,
}
extern _world;
-struct world_load_args
-{
- addon_reg *reg;
- world_instance *instance;
- void *heap;
-};
-
void world_init(void);
-void skaterift_world_load_thread( void *_args );
+void skaterift_world_load_thread( void *_ );
void world_update( world_instance *world, v3f pos );
bool world_set_event( enum world_event activity );
world->entity_list[index ++] = mdl_entity_id( type, j );
}
- world->entity_bh = bh_create( world->heap, &bh_system_entity_list, world,
- indexed_count, 2 );
+ world->entity_bh = bh_create( world->heap, &bh_system_entity_list, world, indexed_count, 2 );
+ /* FIXME: This should be scene geometry instead?????????? */
world->tar_min = world->entity_bh->nodes[0].bbx[0][1];
world->tar_max = world->entity_bh->nodes[0].bbx[1][1] + 20.0f;
vg_str path_str;
vg_strnull( &path_str, path, 256 );
+ vg_strcat( &path_str, "maps/" );
vg_strcat( &path_str, id );
vg_strcat( &path_str, "-cm-" );
vg_strcat( &path_str, gate_key );
vg_info( "Generating collidable geometry\n" );
- for( u32 i=0; i<world->surface_count; i++ ){
+ for( u32 i=0; i<world->surface_count; i++ )
+ {
struct world_surface *surf = &world->surfaces[ i ];
if( surf->info.flags & k_material_flag_collision )
/* need send off the memory to the gpu before we can create the bvh. */
vg_async_stall();
- vg_info( "creating bvh\n" );
- world->geo_bh = scene_bh_create( world->heap, &world->scene_geo );
+
+ if( !_world.loader_preview_mode )
+ {
+ vg_info( "creating bvh\n" );
+ world->geo_bh = scene_bh_create( world->heap, &world->scene_geo );
+ }
/*
* Generate scene: non-collidable geometry
&world->mesh_no_collide,
250000, 500000 );
- for( u32 i=0; i<world->surface_count; i++ ){
+ for( u32 i=0; i<world->surface_count; i++ )
+ {
struct world_surface *surf = &world->surfaces[ i ];
- if( !(surf->info.flags & k_material_flag_collision) ){
- world_add_all_if_material( midentity,
- &world->scene_no_collide, &world->meta, i );
- }
+ if( !(surf->info.flags & k_material_flag_collision) )
+ world_add_all_if_material( midentity, &world->scene_no_collide, &world->meta, i );
- if( surf->info.flags & k_material_flag_grow_grass ){
- world_apply_procedural_foliage( world, &world->scene_no_collide,
- surf );
+ if( !_world.loader_preview_mode )
+ {
+ if( surf->info.flags & k_material_flag_grow_grass )
+ world_apply_procedural_foliage( world, &world->scene_no_collide, surf );
}
scene_copy_slice( &world->scene_no_collide, &surf->sm_no_collide );
}
+ if( _world.loader_preview_mode )
+ goto IL_UPLOAD;
+
/* unpack traffic models.. TODO: should we just put all these submeshes in a
* dynamic models list? and then the actual entitities point to the
* models. we only have 2 types at the moment which need dynamic models but
* would make sense to do this when/if we have more.
+ *
+ * update to self: there were more than 2 and we never gave a shit anyway.
*/
+
for( u32 i=0; i<af_arrcount( &world->ent_traffic ); i++ )
{
ent_traffic *vehc = af_arritm( &world->ent_traffic, i );
}
}
+IL_UPLOAD:
vg_async_dispatch( call, async_scene_upload );
}
/* signed distance function for cone */
-static f32 fsd_cone_infinite( v3f p, v2f c ){
+static f32 fsd_cone_infinite( v3f p, v2f c )
+{
v2f q = { v2_length( (v2f){ p[0], p[2] } ), -p[1] };
float s = vg_maxf( 0.0f, v2_dot( q, c ) );
/* Loads textures from the pack file */
void world_gen_load_surfaces( world_instance *world )
{
- vg_info( "Loading textures\n" );
- world->texture_count = 0;
-
- world->texture_count = world->meta.texture_count+1;
- world->textures = vg_linear_alloc( world->heap,
- vg_align8(sizeof(GLuint)*world->texture_count) );
- world->textures[0] = vg.tex_missing;
-
- for( u32 i=0; i<world->meta.texture_count; i++ )
+ if( _world.loader_preview_mode )
+ {
+ world->texture_count = 0;
+ }
+ else
{
- mdl_texture *tex = &world->meta.textures[ i ];
+ vg_info( "Loading textures\n" );
+ world->texture_count = world->meta.texture_count+1;
+ world->textures = vg_linear_alloc( world->heap, vg_align8(sizeof(GLuint)*world->texture_count) );
+ world->textures[0] = vg.tex_missing;
- if( !tex->file.pack_size )
+ for( u32 i=0; i<world->meta.texture_count; i++ )
{
- vg_fatal_error( "World models must have packed textures!" );
- }
+ mdl_texture *tex = &world->meta.textures[ i ];
- vg_linear_clear( vg_mem.scratch );
- void *src_data = vg_linear_alloc( vg_mem.scratch,
- tex->file.pack_size );
- mdl_fread_pack_file( &world->meta, &tex->file, src_data );
+ if( !tex->file.pack_size )
+ {
+ vg_fatal_error( "World models must have packed textures!" );
+ }
- vg_tex2d_load_qoi_async( src_data, tex->file.pack_size,
- VG_TEX2D_NEAREST|VG_TEX2D_REPEAT,
- &world->textures[i+1] );
+ vg_linear_clear( vg_mem.scratch );
+ void *src_data = vg_linear_alloc( vg_mem.scratch, tex->file.pack_size );
+ mdl_fread_pack_file( &world->meta, &tex->file, src_data );
+
+ vg_tex2d_load_qoi_async( src_data, tex->file.pack_size,
+ VG_TEX2D_NEAREST|VG_TEX2D_REPEAT,
+ &world->textures[i+1] );
+ }
}
vg_info( "Loading materials\n" );
world->surface_count = world->meta.material_count+1;
- world->surfaces = vg_linear_alloc( world->heap,
- vg_align8(sizeof(struct world_surface)*world->surface_count) );
+ world->surfaces = vg_linear_alloc( world->heap, vg_align8(sizeof(struct world_surface)*world->surface_count) );
/* error material */
struct world_surface *errmat = &world->surfaces[0];
world->ub_lighting.g_water_fog = props->fog_scale;
}
- if( surf->info.shader == k_shader_standard_cutout ||
- surf->info.shader == k_shader_foliage )
+ if( surf->info.shader == k_shader_standard_cutout || surf->info.shader == k_shader_foliage )
{
struct shader_props_standard *props = surf->info.props.compiled;
surf->alpha_tex = props->tex_diffuse;
/*
* load the .mdl file located in path as a world instance
*/
-static void world_instance_load_mdl( world_instance *world, const char *path,
- void *heap )
+static void world_instance_load_mdl( world_instance *world, const char *path, void *heap )
{
vg_loader_set_user_information( "Loading world data" );
mdl_load_metadata_block( meta, world->heap );
mdl_load_mesh_block( meta, world->heap );
- vg_info( "%u\n", sizeof(ent_cubemap) );
+ bool load_all = !_world.loader_preview_mode;
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_gate, ent_gate, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_camera, ent_camera, heap );
-
-#if (MDL_VERSION_MIN <= 107)
- if( meta->version <= 107 )
+ if( load_all )
{
- array_file_ptr legacy_cameras;
- af_load_array( af, &legacy_cameras, "ent_camera",
- vg_mem.scratch, sizeof(struct ent_camera_v107) );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_gate, ent_gate, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_camera, ent_camera, heap );
- for( u32 i=0; i<af_arrcount(&legacy_cameras); i ++ )
+#if (MDL_VERSION_MIN <= 107)
+ if( meta->version <= 107 )
{
- fix_ent_camera_v107( af_arritm( &legacy_cameras, i ),
- af_arritm( &world->ent_camera, i ) );
+ array_file_ptr legacy_cameras;
+ af_load_array( af, &legacy_cameras, "ent_camera",
+ vg_mem.scratch, sizeof(struct ent_camera_v107) );
+
+ for( u32 i=0; i<af_arrcount(&legacy_cameras); i ++ )
+ {
+ fix_ent_camera_v107( af_arritm( &legacy_cameras, i ),
+ af_arritm( &world->ent_camera, i ) );
+ }
}
- }
#endif
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_spawn, ent_spawn, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_light, ent_light, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_route_node,ent_route_node, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_path_index,ent_path_index, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_checkpoint,ent_checkpoint, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_route, ent_route, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_water, ent_water, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_audio_clip,ent_audio_clip, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_audio, ent_audio, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_volume, ent_volume, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_traffic, ent_traffic, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_marker, ent_marker, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_skateshop, ent_skateshop, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_swspreview,ent_swspreview, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_ccmd, ent_ccmd, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_objective, ent_objective, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_challenge, ent_challenge, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_relay, ent_relay, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_cubemap, ent_cubemap, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_miniworld, ent_miniworld, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_prop, ent_prop, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_region, ent_region, heap );
- AF_LOAD_ARRAY_STRUCT( af, &world->ent_glider, ent_glider, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_spawn, ent_spawn, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_light, ent_light, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_route_node,ent_route_node, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_path_index,ent_path_index, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_checkpoint,ent_checkpoint, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_route, ent_route, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_water, ent_water, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_audio_clip,ent_audio_clip, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_audio, ent_audio, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_volume, ent_volume, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_traffic, ent_traffic, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_marker, ent_marker, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_skateshop, ent_skateshop, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_swspreview,ent_swspreview, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_ccmd, ent_ccmd, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_objective, ent_objective, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_challenge, ent_challenge, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_relay, ent_relay, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_cubemap, ent_cubemap, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_miniworld, ent_miniworld, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_prop, ent_prop, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_region, ent_region, heap );
+ AF_LOAD_ARRAY_STRUCT( af, &world->ent_glider, ent_glider, heap );
+ }
array_file_ptr infos;
AF_LOAD_ARRAY_STRUCT( af, &infos, ent_worldinfo, vg_mem.scratch );
world->info.flags = 0;
}
- world->events = vg_linear_alloc( heap,
- af_arrcount(&world->ent_challenge)*sizeof(struct event_info) );
+ if( load_all )
+ {
+ world->events = vg_linear_alloc( heap, af_arrcount(&world->ent_challenge)*sizeof(struct event_info) );
+ }
vg_loader_set_user_information( "Compiling world details" );
u64 t4 = SDL_GetPerformanceCounter();
world_gen_load_surfaces( world );
u64 t5 = SDL_GetPerformanceCounter();
- world_gen_routes_ent_init( world );
- world_gen_entities_init( world );
+
+ if( load_all )
+ {
+ world_gen_routes_ent_init( world );
+ world_gen_entities_init( world );
+ }
+
u64 t6 = SDL_GetPerformanceCounter();
/* main bulk */
u64 t0 = SDL_GetPerformanceCounter();
world_gen_generate_meshes( world );
u64 t1 = SDL_GetPerformanceCounter();
- world_gen_routes_generate( world );
+
+ if( load_all )
+ world_gen_routes_generate( world );
+
u64 t2 = SDL_GetPerformanceCounter();
- world_gen_compute_light_indices( world );
+
+ if( load_all )
+ world_gen_compute_light_indices( world );
+
u64 t3 = SDL_GetPerformanceCounter();
mdl_close( meta );
ftime_mesh, ftime_route, ftime_ind, ftime_tex, ftime_ent );
/* allocate leaderboard buffers */
- u32 bs = af_arrcount(&world->ent_route)*sizeof(struct leaderboard_cache);
- world->leaderboard_cache = vg_linear_alloc( heap, bs );
-
- for( u32 i=0; i<af_arrcount( &world->ent_route ); i ++ )
+ if( load_all )
{
- struct leaderboard_cache *board = &world->leaderboard_cache[i];
- board->data = vg_linear_alloc( heap, NETWORK_REQUEST_MAX );
- board->status = k_request_status_client_error;
- board->cache_time = 0.0;
- board->data_len = 0;
- }
+ u32 bs = af_arrcount(&world->ent_route)*sizeof(struct leaderboard_cache);
+ world->leaderboard_cache = vg_linear_alloc( heap, bs );
- world->routes_ui = vg_linear_alloc( heap,
- sizeof(struct route_ui)*af_arrcount(&world->ent_route) );
+ for( u32 i=0; i<af_arrcount( &world->ent_route ); i ++ )
+ {
+ struct leaderboard_cache *board = &world->leaderboard_cache[i];
+ board->data = vg_linear_alloc( heap, NETWORK_REQUEST_MAX );
+ board->status = k_request_status_client_error;
+ board->cache_time = 0.0;
+ board->data_len = 0;
+ }
- vg_loader_set_user_information( "Postprocessing world" );
- vg_async_call( async_world_postprocess, world, 0 );
- vg_async_stall();
+ world->routes_ui = vg_linear_alloc( heap,
+ sizeof(struct route_ui)*af_arrcount(&world->ent_route) );
+
+ vg_loader_set_user_information( "Postprocessing world" );
+ vg_async_call( async_world_postprocess, world, 0 );
+ vg_async_stall();
+ }
vg_loader_set_user_information( NULL );
}
static void async_world_loader_done( void *payload, u32 size )
{
_world.loader_state = k_world_loader_done;
+ _world.loader_instance->complete = 1;
}
-void skaterift_world_load_thread( void *_args )
+void skaterift_world_load_thread( void *_ )
{
vg_loader_set_user_information( "Scanning world directory" );
- struct world_load_args args = *((struct world_load_args *)_args);
- args.instance->addon = args.reg;
+ addon_reg *reg = _world.loader_reg;
+ _world.loader_instance->addon = reg;
char uid[ADDON_UID_MAX];
- addon_alias_uid( &args.reg->alias, uid );
+ addon_alias_uid( &_world.loader_reg->alias, uid );
vg_info( "LOAD WORLD %s @%d\n", uid );
char path_buf[4096];
vg_str path;
vg_strnull( &path, path_buf, 4096 );
- addon_get_content_folder( args.reg, &path, 1 );
+ addon_get_content_folder( reg, &path, 1 );
vg_str folder = path;
if( !vg_strgood( &folder ) )
vg_fatal_error( "No .mdl files found in the map folder.\n" );
}
- world_instance_load_mdl( args.instance, mdl_path, args.heap );
+ world_instance_load_mdl( _world.loader_instance, mdl_path, _world.loader_heap );
vg_async_call( async_world_loader_done, NULL, 0 );
vg_async_stall();
}
}
-void load_player_from_world_savedata_thread( void *_args )
+void load_player_from_world_savedata_thread( void *_ )
{
- struct world_load_args *args = _args;
-
vg_async_item *call = vg_async_alloc( sizeof(struct world_savedata_thread_data) );
struct world_savedata_thread_data *data = call->payload;
- data->instance = args->instance;
- skaterift_world_get_save_path( args->reg, data->save.path );
+ 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 );
void async_world_switcher_done( void *payload, u32 size )
{
- _world.switch_to_addon = NULL;
- g_client.unreadyness --;
+ _world.loader_reg = NULL;
+
+ if( !_world.loader_preview_mode )
+ g_client.unreadyness --;
}
void world_switcher_thread( void *_ )
{
- struct world_load_args args =
- {
- .reg = _world.switch_to_addon,
- .instance = &_world.main,
- .heap = _world.heap
- };
-
- skaterift_world_load_thread( &args );
+ skaterift_world_load_thread( NULL );
vg_async_stall();
- load_player_from_world_savedata_thread( &args );
- 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 );
}
void world_switcher_update(void)
{
- if( !_world.switch_to_addon )
+ if( !_world.loader_reg )
return;
if( _world.loader_state == k_world_loader_saving_current )
_skaterift_script_unlink_all_challenges();
world_instance_free_graphics_data( &_world.main );
+ _world.main.complete = 0;
_world.loader_state = k_world_loader_ready;
vg_loader_set_user_information( "Waiting for loading thread" );
}
_world.loader_state = k_world_loader_loading;
vg_linear_clear( vg_async.buffer );
- vg_linear_clear( _world.heap );
+ vg_linear_clear( _world.loader_heap );
vg_loader_start( world_switcher_thread, NULL );
}
}
}
-void skaterift_switch_world_start( addon_reg *reg )
+void skaterift_load_world_start( addon_reg *reg, bool preview )
{
if( g_client.unreadyness )
{
return;
}
- if( _world.main.addon == reg )
- {
- vg_warn( "World is already loaded\n" );
- return;
- }
+ world_instance *world = preview? &_world.preview_instance: &_world.main;
if( !reg )
{
- if( _world.main.addon )
+ if( world->addon )
{
- reg = _world.main.addon;
+ reg = world->addon;
}
else
{
- vg_error( "Loaded world has no associated addon registration."
- " Can't reload this!\n" );
+ vg_error( "Loaded world has no associated addon registration, can't reload this!\n" );
return;
}
}
- if( reg != _world.main.addon )
- _world.previous_world_addon = _world.main.addon;
+ if( !preview )
+ {
+ if( reg != world->addon )
+ _world.previous_world_addon = _world.main.addon;
- g_client.unreadyness ++;
- _world.loader_state = k_world_loader_saving_current;
- vg_loader_set_user_information( "Saving current world" );
+ g_client.unreadyness ++;
+ _world.loader_state = k_world_loader_saving_current;
+ vg_loader_set_user_information( "Saving current world" );
+ }
+ else
+ _world.loader_state = k_world_loader_ready;
char buf[76];
addon_alias_uid( ®->alias, buf );
- vg_info( "switching to: %s\n", buf );
+ vg_info( "loading world: %s %s\n", buf, preview? "(preview mode)": "" );
vg_linear_clear( vg_mem.scratch ); /* ?? */
- world_fadeout_audio( &_world.main );
- _world.switch_to_addon = reg;
+ if( preview )
+ {
+ if( world->complete )
+ {
+ world_instance_free_graphics_data( world );
+ world->complete = 0;
+ }
+ }
+ else
+ world_fadeout_audio( &_world.main );
+
+ _world.loader_reg = reg;
+ _world.loader_instance = world;
+ _world.loader_heap = preview? _world.preview_heap: _world.heap;
+ _world.loader_preview_mode = preview;
}
/* console command for the above function */
-int skaterift_switch_world_command( int argc, const char *argv[] )
+int skaterift_load_world_command( int argc, const char *argv[] )
{
if( !vg_loader_availible() )
{
return 0;
}
- if( argc == 1 )
+ if( argc >= 1 )
{
if( !strcmp( argv[0], "reload" ) )
{
- skaterift_switch_world_start( NULL );
+ skaterift_load_world_start( NULL, 0 );
return 0;
}
+ bool preview = 0;
+
+ if( argc >= 2 )
+ {
+ if( !strcmp( argv[1], "preview" ) )
+ {
+ preview = 1;
+ }
+ }
+
addon_alias q;
addon_uid_to_alias( argv[0], &q );
if( reg_id != 0xffffffff )
{
addon_reg *reg = get_addon_from_index( k_addon_type_world, reg_id, 0 );
- skaterift_switch_world_start( reg );
+ skaterift_load_world_start( reg, preview );
}
else
{
glDeleteTextures( 1, &world->tex_light_cubes );
/* delete textures and meshes */
- glDeleteTextures( world->texture_count-1, world->textures+1 );
+ if( world->texture_count )
+ glDeleteTextures( world->texture_count-1, world->textures+1 );
for( u32 i=0; i<af_arrcount(&world->ent_cubemap); i++ )
{
glDeleteRenderbuffers( 1, &cm->renderbuffer_id );
}
- glDeleteTextures( world->nonlocal_gate_count, world->nonlocal_gates_cubemaps );
+ if( world->nonlocal_gate_count )
+ glDeleteTextures( world->nonlocal_gate_count, world->nonlocal_gates_cubemaps );
}
/*
v3_copy( (v3f){0.25f, 0.17f, 0.51f}, state->g_sunset_ambient );
v3_copy( (v3f){1.000f, 0.809f, 0.318f}, state->g_sun_colour );
#endif
+
+ world->tbo_light_entities = 0;
+ world->tex_light_entities = 0;
+ world->tex_light_cubes = 0;
+ world->nonlocal_gates_cubemaps = NULL;
}
#include "world.h"
#include "addon.h"
-int skaterift_switch_world_command( int argc, const char *argv[] );
-void skaterift_switch_world_start( addon_reg *reg );
+int skaterift_load_world_command( int argc, const char *argv[] );
+void skaterift_load_world_start( addon_reg *reg, bool preview_mode );
void world_switcher_update(void);
void world_switcher_thread( void *_ );
void world_instance_free_graphics_data( world_instance *world );
#include "ent_skateshop.h"
#include "shaders/model_entity.h"
#include "shaders/model_sky_cubemap.h"
+#include "shaders/scene_preview.h"
+#include "shaders/scene_override.h"
struct world_render world_render;
shader_scene_terrain_uSandColour( props->sand_colour );
}
-static void bindpoint_override( world_instance *world,
- struct world_surface *mat )
+static void bindpoint_override( world_instance *world, struct world_surface *mat )
{
if( mat->info.flags & k_material_flag_collision )
{
}
}
+static void bindpoint_world_preview( world_instance *world, struct world_surface *mat )
+{
+ if( mat->info.flags & k_material_flag_collision )
+ {
+ }
+ else
+ {
+ }
+}
+
+
static void render_terrain( world_instance *world, vg_camera *cam )
{
shader_scene_terrain_use();
render_world_fxglow( world, world, cam, mmdl, 0, 0, 1 );
}
+void render_world_preview(void)
+{
+ world_instance *world = &_world.preview_instance;
+ struct world_pass pass =
+ {
+ .cam = &g_render.cam,
+ .fn_bind = bindpoint_world_preview,
+ .fn_set_mdl = shader_scene_preview_uMdl,
+ .fn_set_uPvmPrev = shader_scene_preview_uPvmPrev,
+ .fn_set_uNormalMtx = shader_scene_preview_uNormalMtx,
+ .shader = k_shader_override
+ };
+
+ shader_scene_preview_use();
+ shader_scene_preview_uPv( pass.cam->mtx.pv );
+ shader_scene_preview_uMapInfo((v4f){-1000.0f, 1000.0f, 0.0f, 0.0f});
+ //shader_scene_preview_uMapInfo((v4f){world->tar_min, world->tar_max, 1.0f, 0.0f});
+
+ m4x3f mmdl;
+ m4x3_identity( mmdl );
+
+ m4x4f mpvm_prev;
+ m4x3_expand( mmdl, mpvm_prev );
+ m4x4_mul( pass.cam->mtx_prev.pv, mpvm_prev, mpvm_prev );
+
+ m3x3f mnormal;
+ m3x3_inv( mmdl, mnormal );
+ m3x3_transpose( mnormal, mnormal );
+ v3_normalize( mnormal[0] );
+ v3_normalize( mnormal[1] );
+ v3_normalize( mnormal[2] );
+
+ glDisable( GL_CULL_FACE );
+ mesh_bind( &world->mesh_geo );
+ pass.geo_type = k_world_geo_type_solid;
+ render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev );
+ mesh_bind( &world->mesh_no_collide );
+ pass.geo_type = k_world_geo_type_nonsolid;
+ render_world_override_pass( world, &pass, mmdl, mnormal, mpvm_prev );
+ glEnable( GL_CULL_FACE );
+}
+
static void render_cubemap_side( world_instance *world, v3f co, m3x3f rotation, u32 side )
{
vg_camera cam;
m4x3f mmdl,
vg_camera *cam,
ent_spawn *dest_spawn, v4f map_info );
+void render_world_preview(void);
void render_world_gates( world_instance *world, vg_camera *cam );
void imgui_world_light_edit( ui_context *ctx, world_instance *world );