+/*
+ * -----------------------------------------------------------------------------
+ * Events
+ * -----------------------------------------------------------------------------
+ */
+
+VG_STATIC int world_stop_sound( int argc, const char *argv[] )
+{
+ world_instance *world = get_active_world();
+
+ /*
+ * None of our world audio runs as one shots, they always have a player.
+ * Therefore it is safe to delete clip data after the players are
+ * disconnected
+ */
+ audio_lock();
+ for( int i=0; i<world->audio_things_count; i++ )
+ {
+ struct world_audio_thing *at = &world->audio_things[i];
+
+ if( audio_player_is_playing( &at->player ) )
+ {
+ u32 cflags = audio_player_get_flags( &at->player );
+ audio_player_set_flags( &at->player, cflags | AUDIO_FLAG_KILL );
+ }
+ }
+ audio_unlock();
+
+ return 0;
+}
+
+VG_STATIC int world_change_world( int argc, const char *argv[] )
+{
+#if 0
+ world_instance *world = get_active_world();
+
+ if( argc == 0 )
+ {
+ vg_info( "%s\n", world.world_name );
+ return 0;
+ }
+ else
+ {
+ vg_info( "Switching world...\n" );
+ strcpy( world.world_name, argv[0] );
+ world.switching_to_new_world = 1;
+ world_stop_sound( 0, NULL );
+ }
+#endif
+
+ return 0;
+}
+
+VG_STATIC void world_init(void)
+{
+#if 0
+ vg_var_push( (struct vg_var){
+ .name = "water_enable",
+ .data = &world.water.enabled,
+ .data_type = k_var_dtype_i32,
+ .opt_i32 = { .min=0, .max=1, .clamp=1 },
+ .persistent = 0
+ });
+#endif
+
+ vg_function_push( (struct vg_cmd)
+ {
+ .name = "world_stop_sound",
+ .function = world_stop_sound
+ });
+
+ vg_function_push( (struct vg_cmd)
+ {
+ .name = "world",
+ .function = world_change_world
+ });
+
+ world_global.sky_rate = 1.0;
+ world_global.sky_target_rate = 1.0;
+
+ shader_scene_standard_register();
+ shader_scene_standard_alphatest_register();
+ shader_scene_vertex_blend_register();
+ shader_scene_terrain_register();
+ shader_scene_depth_register();
+ shader_scene_position_register();
+
+ shader_model_sky_register();
+
+ vg_info( "Loading world resources\n" );
+
+ vg_linear_clear( vg_mem.scratch );
+ mdl_context *msky = mdl_load_full( vg_mem.scratch, "models/rs_skydome.mdl" );
+
+ mdl_node *nupper = mdl_node_from_name( msky, "dome_complete" );
+ world_global.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
+
+ vg_acquire_thread_sync();
+ {
+ mdl_unpack_glmesh( msky, &world_global.skydome );
+ }
+ vg_release_thread_sync();
+
+ /* Other systems */
+ vg_info( "Loading other world systems\n" );
+
+ vg_loader_step( world_render_init, NULL );
+ vg_loader_step( world_sfd_init, NULL );
+ vg_loader_step( world_water_init, NULL );
+ vg_loader_step( world_gates_init, NULL );
+ vg_loader_step( world_routes_init, NULL );
+
+ /* Allocate dynamic world memory arena */
+ u32 max_size = 76*1024*1024;
+ world_global.generic_heap = vg_create_linear_allocator( vg_mem.rtmemory,
+ max_size,
+ VG_MEMORY_SYSTEM );
+}
+
+VG_STATIC void world_audio_init(void)
+{
+ u32 size = vg_linear_remaining( vg_audio.audio_pool )
+ - sizeof(vg_linear_allocator);
+
+ world_global.audio_heap = vg_create_linear_allocator( vg_audio.audio_pool,
+ size,
+ VG_MEMORY_SYSTEM );