/*
- * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
+ * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
*/
-#include "common.h"
-
-VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
-
#ifndef WORLD_H
#define WORLD_H
-#include "vg/vg_loader.h"
-
-#include "network.h"
-#include "network_msg.h"
-#include "scene.h"
#include "render.h"
-#include "rigidbody.h"
-#include "bvh.h"
-#include "model.h"
-
-#include "shaders/terrain.h"
-#include "shaders/sky.h"
-#include "shaders/standard.h"
-#include "shaders/vblend.h"
-#include "shaders/gpos.h"
-#include "shaders/blitcolour.h"
-#include "shaders/alphatest.h"
-
-typedef struct teleport_gate teleport_gate;
-
-enum { k_max_ui_segments = 8 };
-
-enum { k_max_ui_elements = k_max_ui_segments };
-enum { k_max_element_verts = 10 };
-enum { k_max_element_indices = 20 };
-
-enum { k_route_ui_max_verts = k_max_ui_elements*k_max_element_verts };
-enum { k_route_ui_max_indices = k_max_ui_elements*k_max_element_indices };
-
-enum logic_type
-{
- k_logic_type_relay = 1,
- k_logic_type_chance = 2,
- k_logic_type_achievement = 3
+#include "network_msg.h"
+
+/* types
+ */
+
+enum world_geo_type{
+ k_world_geo_type_solid = 0,
+ k_world_geo_type_nonsolid = 1,
+ k_world_geo_type_water = 2
};
-enum geo_type
-{
- k_geo_type_solid = 0,
- k_geo_type_nonsolid = 1,
- k_geo_type_water = 2
+enum world_purpose{
+ k_world_purpose_hub = 0,
+ k_world_purpose_client = 1,
+ k_world_max
};
-VG_STATIC struct gworld
-{
- /*
- * Allocated as system memory
- * --------------------------------------------------------------------------
- */
+struct leaderboard_cache {
+ enum request_status status;
+ f64 cache_time;
+ u8 *data;
+ u32 data_len;
+};
+
+typedef struct world_instance world_instance;
+
+static void skaterift_world_get_save_path( enum world_purpose which,
+ char buf[128] );
+
+/* submodule headers */
+#include "world_entity.h"
+#include "world_gate.h"
+#include "world_gen.h"
+#include "world_info.h"
+#include "world_load.h"
+#include "world_physics.h"
+#include "world_render.h"
+#include "world_sfd.h"
+#include "world_volumes.h"
+#include "world_water.h"
+#include "world_audio.h"
+#include "world_routes.h"
- /* rendering */
- glmesh skydome;
- mdl_submesh dome_upper, dome_lower;
+/* console variables */
- glmesh mesh_gate_surface;
+static f32 k_day_length = 30.0f; /* minutes */
+static i32 k_debug_light_indices = 0,
+ k_debug_light_complexity= 0,
+ k_light_preview = 0;
- double sky_time, sky_rate, sky_target_rate;
- /* water rendering */
- struct
- {
- struct framebuffer fbreflect, fbdepth;
+struct world_instance {
+ /* Fixed items
+ * -------------------------------------------------------
+ */
+
+ void *heap;
+ enum world_status{
+ k_world_status_unloaded = 0,
+ k_world_status_loading = 1,
+ k_world_status_loaded = 2,
+ k_world_status_unloading = 3 /* dont spawn sounds and stuff */
+ }
+ status;
+ struct{
boxf depthbounds;
int depth_computed;
}
water;
- /* split flap display */
- struct
- {
- mdl_submesh *sm_module, *sm_card;
- glmesh mesh_base, mesh_display;
+ f64 time;
- u32 w, h;
- float *buffer;
- }
- sfd;
-
- /* timing bars, fixed maximum amount */
- struct route_ui_bar
- {
- GLuint vao, vbo, ebo;
-
- u32 indices_head;
- u32 vertex_head;
-
- struct route_ui_segment
- {
- float length;
- u32 vertex_start, vertex_count,
- index_start, index_count, notches;
- }
- segments[k_max_ui_segments];
-
- u32 segment_start, segment_count, fade_start, fade_count;
- double fade_timer_start;
- float xpos;
+ /* STD140 */
+ struct ub_world_lighting{
+ v4f g_cube_min,
+ g_cube_inv_range;
+
+ v4f g_water_plane,
+ g_depth_bounds;
+
+ v4f g_daysky_colour;
+ v4f g_nightsky_colour;
+ v4f g_sunset_colour;
+ v4f g_ambient_colour;
+ v4f g_sunset_ambient;
+ v4f g_sun_colour;
+ v4f g_sun_dir;
+ v4f g_board_0;
+ v4f g_board_1;
+
+ float g_water_fog;
+ float g_time;
+ float g_realtime;
+ float g_shadow_length;
+ float g_shadow_spread;
+
+ float g_time_of_day;
+ float g_day_phase;
+ float g_sunset_phase;
+
+ int g_light_preview;
+ int g_shadow_samples;
+
+ int g_debug_indices;
+ int g_debug_complexity;
}
- ui_bars[16];
+ ub_lighting;
+ GLuint ubo_lighting;
+ int ubo_bind_point;
- v3f render_gate_pos;
- int active_route_board;
- int in_trigger;
+ GLuint tbo_light_entities,
+ tex_light_entities,
+ tex_light_cubes;
- /* This is a small flag we use to changelevel.
- * It will not be cleared until all sounds stop playing
- */
- int switching_to_new_world;
- char world_name[ 64 ];
+ float probabilities[3];
+
+ v3i light_cubes;
+ struct framebuffer heightmap;
/*
* Dynamically allocated when world_load is called.
*
* the following arrays index somewhere into this linear
* allocator
- *
- * (world_gen.h)
* --------------------------------------------------------------------------
*/
- void *dynamic_vgl,
- *audio_vgl; /* sub buffer of the audio buffer */
/*
* Main world .mdl
*/
- mdl_context *meta;
-
- /*
- * Materials / textures
- */
+ mdl_context meta;
GLuint *textures;
u32 texture_count;
- struct world_material
- {
+ struct world_surface{
mdl_material info;
mdl_submesh sm_geo,
sm_no_collide;
}
- * materials;
- u32 material_count;
-
- /*
- * Named safe places to respawn
- */
- struct respawn_point
- {
- v3f co;
- v4f q;
- const char *name;
- }
- * spawns;
- u32 spawn_count;
-
- /*
- * Audio player entities
- */
- struct world_audio_thing
- {
- v3f pos;
- float volume;
- u32 flags;
-
- audio_player player;
- audio_clip temp_embedded_clip;
- }
- * audio_things;
- u32 audio_things_count;
-
- /*
- * Relays
- */
- struct logic_relay
- {
- v3f pos;
-
- struct relay_target
- {
- u32 sub_id;
- enum classtype classtype;
- }
- targets[4];
- u32 target_count;
- }
- * logic_relays;
- u32 relay_count;
-
- /*
- * Box trigger entities
- */
- struct trigger_zone
- {
- m4x3f transform, inv_transform;
-
- struct relay_target target;
- }
- * triggers;
- u32 trigger_count;
-
- /*
- * Achievements
- */
- struct logic_achievement
- {
- v3f pos;
- const char *achievement_id;
- u32 achieved;
- }
- * logic_achievements;
- u32 achievement_count;
-
-
- /*
- * Routes (world_routes.h)
- * --------------------------------------------------------------------------
- */
- struct route_node
- {
- v3f co, right, up, h;
- u32 next[2];
-
- u32 special_type, special_id, current_refs, ref_count;
- u32 route_ids[4]; /* Gates can be linked into up to four routes */
- }
- *nodes;
- u32 node_count;
-
- struct route
- {
- u32 track_id;
- v4f colour;
-
- u32 start;
- mdl_submesh sm;
-
- int active;
- float factive;
-
- double best_lap, latest_pass; /* Session */
-
- m4x3f scoreboard_transform;
- }
- *routes;
- u32 route_count;
-
- struct route_gate
- {
- struct teleport_gate
- {
- v3f co[2];
- v4f q[2];
- v2f dims;
-
- m4x3f to_world, recv_to_world, transport;
- }
- gate;
-
- u32 node_id;
-
- struct route_timing
- {
- u32 version; /* Incremented on every teleport */
- double time;
- }
- timing;
- }
- *gates;
- u32 gate_count;
-
- struct route_collector
- {
- struct route_timing timing;
- }
- *collectors;
- u32 collector_count;
-
+ * surfaces;
+ u32 surface_count;
+
+ ent_worldinfo info;
+ mdl_array_ptr ent_spawn,
+ ent_gate,
+ ent_light,
+ ent_route_node,
+ ent_path_index,
+ ent_checkpoint,
+ ent_route,
+ ent_water,
+
+ ent_audio_clip,
+ ent_audio,
+ ent_volume,
+ ent_traffic,
+ ent_skateshop,
+ ent_marker,
+ ent_camera,
+ ent_swspreview,
+ ent_ccmd,
+ ent_objective,
+ ent_challenge,
+ ent_relay,
+ ent_cubemap;
+
+ ent_gate *rendering_gate;
/* logic
* ----------------------------------------------------
*/
- u32 active_gate,
- current_run_version;
- double time, rewind_from, rewind_to, last_use;
-
/* world geometry */
- scene *scene_geo,
- *scene_no_collide,
- *scene_lines;
-
- struct grind_edge
- {
- v3f p0, p1;
- }
- *grind_edges;
- u32 grind_edge_count;
+ scene_context scene_geo,
+ scene_no_collide,
+ scene_lines;
/* spacial mappings */
- bh_tree *audio_bh,
- *trigger_bh,
- *geo_bh,
- *grind_bh;
+ bh_tree *geo_bh,
+ *entity_bh;
+ u32 *entity_list;
/* graphics */
glmesh mesh_route_lines;
-
glmesh mesh_geo,
mesh_no_collide,
mesh_water;
+ u32 cubemap_cooldown, cubemap_side;
- mdl_submesh sm_foliage_main;
- rigidbody rb_geo;
-}
-world;
-
-
-/*
- * API
- */
+ rb_object rb_geo;
-VG_STATIC int ray_hit_is_ramp( ray_hit *hit );
-VG_STATIC struct world_material *ray_hit_material( ray_hit *hit );
-VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] );
-VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit );
-
-/*
- * Submodules
- */
-
-#include "world_routes.h"
-#include "world_sfd.h"
-#include "world_render.h"
-#include "world_water.h"
-#include "world_gen.h"
-#include "world_gate.h"
-
-/*
- * -----------------------------------------------------------------------------
- * Events
- * -----------------------------------------------------------------------------
- */
+ /* leaderboards */
+ struct leaderboard_cache *leaderboard_cache;
+};
-VG_STATIC int world_stop_sound( int argc, const char *argv[] )
-{
- /*
- * 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
+struct world_static {
+ /*
+ * Allocated as system memory
+ * --------------------------------------------------------------------------
*/
- 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( 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 );
- }
-
- return 0;
-}
-
-VG_STATIC void world_init(void)
-{
- 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
- });
-
- 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.sky_rate = 1.0;
- world.sky_target_rate = 1.0;
-
- shader_terrain_register();
- shader_sky_register();
- shader_gpos_register();
- shader_blitcolour_register();
- shader_alphatest_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.dome_upper = *mdl_node_submesh( msky, nupper, 0 );
-
- vg_acquire_thread_sync();
- {
- mdl_unpack_glmesh( msky, &world.skydome );
- }
- vg_release_thread_sync();
-
- /* Other systems */
- vg_info( "Loading other world systems\n" );
+ void *heap;
- 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.dynamic_vgl = 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.audio_vgl = vg_create_linear_allocator( vg_audio.audio_pool,
- size, VG_MEMORY_SYSTEM );
-}
-
-VG_STATIC void world_trigger_achievement( u32 uid )
-{
- struct logic_achievement *ach = &world.logic_achievements[ uid ];
-
- if( ach->achieved )
- return;
-
- steam_set_achievement( ach->achievement_id );
- steam_store_achievements();
-
- ach->achieved = 1;
-}
-
-VG_STATIC void world_run_relay( struct relay_target *rt );
-VG_STATIC void world_trigger_relay( u32 uid )
-{
- struct logic_relay *relay = &world.logic_relays[ uid ];
-
- for( int i=0; i<relay->target_count; i++ )
- {
- world_run_relay( &relay->targets[i] );
- }
-}
-
-VG_STATIC void world_trigger_audio( u32 uid )
-{
- struct world_audio_thing *wat = &world.audio_things[ uid ];
-
- audio_lock();
- audio_player_playclip( &wat->player,
- &wat->temp_embedded_clip );
- audio_unlock();
-}
-
-VG_STATIC void world_run_relay( struct relay_target *rt )
-{
- struct entity_instruction
- {
- enum classtype classtype;
- void (*p_trigger)( u32 uid );
- }
- entity_instructions[] =
- {
- { k_classtype_logic_achievement, world_trigger_achievement },
- { k_classtype_logic_relay, world_trigger_relay },
- { k_classtype_audio, world_trigger_audio }
- };
-
- for( int i=0; i<vg_list_size(entity_instructions); i++ )
- {
- struct entity_instruction *instr = &entity_instructions[i];
-
- if( instr->classtype == rt->classtype )
- {
- instr->p_trigger( rt->sub_id );
- return;
- }
- }
-
- vg_error( "Don't know how to trigger classtype %d\n", rt->classtype );
-}
-
-VG_STATIC void world_update( v3f pos )
-{
- if( world.switching_to_new_world )
- {
- int all_stopped = 1;
-
- 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 ) )
- {
- all_stopped = 0;
- break;
- }
- }
- audio_unlock();
-
- if( all_stopped )
- {
- world.switching_to_new_world = 0;
- world_unload();
- vg_loader_start( world_load );
- return;
- }
- }
-
- world.sky_time += world.sky_rate * vg.time_delta;
- world.sky_rate = vg_lerp( world.sky_rate, world.sky_target_rate,
- vg.time_delta * 5.0 );
-
- world_routes_update();
-#if 0
- world_routes_debug();
-#endif
-
- if( world.route_count > 0 )
- {
- int closest = 0;
- float min_dist = INFINITY;
-
- for( int i=0; i<world.route_count; i++ )
- {
- float d = v3_dist2( world.routes[i].scoreboard_transform[3], pos );
-
- if( d < min_dist )
- {
- min_dist = d;
- closest = i;
- }
- }
-
- if( (world.active_route_board != closest) || network_scores_updated )
- {
- network_scores_updated = 0;
- world.active_route_board = closest;
-
- struct route *route = &world.routes[closest];
-
- u32 id = route->track_id;
-
- if( id != 0xffffffff )
- {
- struct netmsg_board *local_board =
- &scoreboard_client_data.boards[id];
-
- for( int i=0; i<13; i++ )
- {
- sfd_encode( i, &local_board->data[27*i] );
- }
- }
- }
- }
-
- int in_trigger = 0;
- for( int i=0; i<world.trigger_count; i++ )
- {
- struct trigger_zone *zone = &world.triggers[i];
-
- v3f local;
- m4x3_mulv( zone->inv_transform, pos, local );
-
- if( (fabsf(local[0]) <= 1.0f) &&
- (fabsf(local[1]) <= 1.0f) &&
- (fabsf(local[2]) <= 1.0f) )
- {
- in_trigger = 1;
-
- if( !world.in_trigger )
- {
- world_run_relay( &zone->target );
- }
- }
-
- vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f},
- { 1.0f, 1.0f, 1.0f}},
- 0xff00ff00 );
- }
+ u32 current_run_version;
+ double time, rewind_from, rewind_to, last_use;
- world.in_trigger = in_trigger;
- sfd_update();
-}
+ u32 active_trigger_volumes[8];
+ u32 active_trigger_volume_count;
-/*
- * -----------------------------------------------------------------------------
- * API implementation
- * -----------------------------------------------------------------------------
- */
+ addon_reg *instance_addons[ k_world_max ];
+ world_instance instances[ k_world_max ];
-VG_STATIC void ray_world_get_tri( ray_hit *hit, v3f tri[3] )
-{
- for( int i=0; i<3; i++ )
- v3_copy( world.scene_geo->arrvertices[ hit->tri[i] ].co, tri[i] );
-}
+ enum world_purpose active_instance;
+ u32 focused_entity; /* like skateshop, challenge.. */
+ f32 focus_strength;
+ camera focus_cam;
-VG_STATIC int ray_world( v3f pos, v3f dir, ray_hit *hit )
-{
- return scene_raycast( world.scene_geo, world.geo_bh, pos, dir, hit );
-}
+ /* challenges */
+ ent_objective *challenge_target;
+ f32 challenge_timer;
-VG_STATIC struct world_material *world_tri_index_material( u32 index )
-{
- for( int i=1; i<world.material_count; i++ )
- {
- struct world_material *mat = &world.materials[i];
-
- if( (index >= mat->sm_geo.vertex_start) &&
- (index < mat->sm_geo.vertex_start+mat->sm_geo.vertex_count ) )
- {
- return mat;
- }
+ enum world_loader_state{
+ k_world_loader_none,
+ k_world_loader_preload,
+ k_world_loader_load
}
-
- /* error material */
- return &world.materials[0];
-}
-
-VG_STATIC struct world_material *world_contact_material( rb_ct *ct )
-{
- return world_tri_index_material( ct->element_id );
+ load_state;
}
+static world_static;
-VG_STATIC struct world_material *ray_hit_material( ray_hit *hit )
-{
- return world_tri_index_material( hit->tri[0] );
-}
+static void world_init(void);
+static world_instance *world_current_instance(void);
+static void world_set_active_instance( u32 index );
#endif /* WORLD_H */