X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=world.h;h=49d1aaea690849f6fb32bfb3e645901940d9d33d;hb=8d336ea2cde7c596296dbaf0d3ce27a82c6c6cf0;hp=69def4c85875df63fa9bd9a9c0d207738b94daeb;hpb=0136a935c00e3ea1f231fd88b38b44982fd409ac;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/world.h b/world.h index 69def4c..49d1aae 100644 --- a/world.h +++ b/world.h @@ -1,74 +1,82 @@ /* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved + * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved */ -#include "common.h" - -#ifndef WORLD_H -#define WORLD_H - -typedef struct world_instance world_instance; - -#include "vg/vg_loader.h" - -#include "network.h" +#pragma once +#include "render.h" #include "network_msg.h" +#include "addon.h" #include "scene.h" -#include "render.h" -#include "rigidbody.h" -#include "bvh.h" -#include "model.h" -#include "shaders/scene_standard.h" -#include "shaders/scene_standard_alphatest.h" -#include "shaders/scene_vertex_blend.h" -#include "shaders/scene_terrain.h" -#include "shaders/scene_depth.h" -#include "shaders/scene_position.h" +/* types + */ -#include "shaders/model_sky.h" +enum world_geo_type{ + k_world_geo_type_solid = 0, + k_world_geo_type_nonsolid = 1, + k_world_geo_type_water = 2 +}; -typedef struct teleport_gate teleport_gate; +enum world_purpose{ + k_world_purpose_invalid = -1, + k_world_purpose_hub = 0, + k_world_purpose_client = 1, + k_world_max +}; -enum { k_max_ui_segments = 8 }; +struct leaderboard_cache { + enum request_status status; + f64 cache_time; + u8 *data; + u32 data_len; +}; -enum { k_max_ui_elements = k_max_ui_segments }; -enum { k_max_element_verts = 10 }; -enum { k_max_element_indices = 20 }; +typedef struct world_instance world_instance; -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 }; +void skaterift_world_get_save_path( enum world_purpose which, char buf[128] ); -enum logic_type -{ - k_logic_type_relay = 1, - k_logic_type_chance = 2, - k_logic_type_achievement = 3 -}; +/* submodule headers */ +#include "world_entity.h" +#include "world_gate.h" +#include "world_gen.h" +#include "world_info.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" +#include "world_routes_ui.h" -enum geo_type -{ - k_geo_type_solid = 0, - k_geo_type_nonsolid = 1, - k_geo_type_water = 2 -}; +/* console variables */ -static const float k_light_cube_size = 8.0f; +static f32 k_day_length = 30.0f; /* minutes */ +static i32 k_debug_light_indices = 0, + k_debug_light_complexity= 0, + k_light_preview = 0, + k_light_editor = 0; -struct world_instance -{ - /* This is a small flag we use to changelevel. - * It will not be cleared until all sounds stop playing - */ +#define WORLD_SURFACE_HAS_TRAFFIC 0x1 +#define WORLD_SURFACE_HAS_PROPS 0x2 +struct world_instance { /* Fixed items * ------------------------------------------------------- */ - char world_name[ 64 ]; + v4f player_co; + + 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 - { + struct{ boxf depthbounds; int depth_computed; @@ -78,9 +86,11 @@ struct world_instance } water; + f64 time; + f32 tar_min, tar_max; + /* STD140 */ - struct ub_world_lighting - { + struct ub_world_lighting{ v4f g_cube_min, g_cube_inv_range; @@ -94,9 +104,12 @@ struct world_instance 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; @@ -118,8 +131,9 @@ struct world_instance tex_light_entities, tex_light_cubes; - v3i light_cubes; + float probabilities[3]; + v3i light_cubes; struct framebuffer heightmap; /* @@ -127,790 +141,134 @@ struct world_instance * * the following arrays index somewhere into this linear * allocator - * - * (world_gen.h) * -------------------------------------------------------------------------- */ - /* - * Main world .mdl - */ - mdl_context *meta; /* - * Materials / textures + * Main world .mdl */ + 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; - - /* - * Lights - */ - struct world_light - { - mdl_node *node; - struct classtype_world_light *inf; - m4x3f inverse_world; - v2f angle_sin_cos; - - /* enabled.. etc? - * TODO: we should order entities in the binary by their type */ - } - * lights; - u32 light_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, transport; - } - gate; - - u32 node_id; - - struct route_timing - { - u32 version; /* Incremented on every teleport */ - double time; - } - timing; } - *gates; - u32 gate_count; - - struct nonlocal_gate - { - struct teleport_gate gate; - mdl_node *node; - - u32 target_map_index, working; - } - *nonlocal_gates; - u32 nonlocalgate_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_miniworld, + ent_prop, + ent_region, + ent_glider, + ent_npc; + + enum skybox { + k_skybox_default, + k_skybox_space + } skybox; + + ent_gate *rendering_gate; /* logic * ---------------------------------------------------- */ /* world geometry */ - scene *scene_geo, - *scene_no_collide, - *scene_lines; + scene_context scene_geo, + scene_no_collide, + scene_lines; /* spacial mappings */ - bh_tree *audio_bh, - *trigger_bh, - *geo_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; - rigidbody rb_geo; /* todo.. ... */ + /* leaderboards */ + struct leaderboard_cache *leaderboard_cache; + + /* ui */ + struct route_ui *routes_ui; }; -VG_STATIC struct world_global -{ +struct world_static { /* * Allocated as system memory * -------------------------------------------------------------------------- */ - void *generic_heap; - - /* rendering */ - glmesh skydome; - mdl_submesh dome_upper, dome_lower; - - glmesh mesh_gate_surface; + void *heap; - double sky_time, sky_rate, sky_target_rate; - - /* gates, TODO: active_gate should also know which instance */ - u32 active_gate, - current_run_version; + u32 current_run_version; double time, rewind_from, rewind_to, last_use; - /* water rendering */ - struct - { - struct framebuffer fbreflect, fbdepth; - } - water; + u32 active_trigger_volumes[8]; + u32 active_trigger_volume_count; - /* split flap display */ - struct - { - mdl_submesh *sm_module, *sm_card; - glmesh mesh_base, mesh_display; + addon_reg *instance_addons[ k_world_max ]; + world_instance instances[ k_world_max ]; - 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; - } - ui_bars[16]; - - v3f render_gate_pos; - int active_route_board; - int in_trigger; - - int switching_to_new_world; - - world_instance worlds[4]; - u32 world_count; - u32 active_world; -} -world_global; + enum world_purpose active_instance; + u32 focused_entity; /* like skateshop, challenge.. */ + f32 focus_strength; + vg_camera focus_cam; -VG_STATIC world_instance *get_active_world( void ) -{ - return &world_global.worlds[ world_global.active_world ]; -} - -/* - * API - */ - -VG_STATIC -int ray_hit_is_ramp( world_instance *world, ray_hit *hit ); - -VG_STATIC -struct world_material *ray_hit_material( world_instance *world, ray_hit *hit ); - -VG_STATIC -void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] ); - -VG_STATIC -int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit ); - -/* - * Submodules - */ + /* challenges */ + ent_objective *challenge_target; + f32 challenge_timer; -#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 - * ----------------------------------------------------------------------------- - */ - -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; iaudio_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 ); + enum world_loader_state{ + k_world_loader_none, + k_world_loader_preload, + k_world_loader_load } -#endif + load_state; - 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) -{ -#if 0 - 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 ); -#endif + bool clear_async_op_when_done; } +extern world_static; -VG_STATIC void world_trigger_achievement( world_instance *world, u32 uid ) +struct world_load_args { - 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( world_instance *world, - struct relay_target *rt ); - -VG_STATIC void world_trigger_relay( world_instance *world, u32 uid ) -{ - struct logic_relay *relay = &world->logic_relays[ uid ]; - - for( int i=0; itarget_count; i++ ) - { - world_run_relay( world, &relay->targets[i] ); - } -} - -VG_STATIC void world_trigger_audio( world_instance *world, 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( world_instance *world, - struct relay_target *rt ) -{ - struct entity_instruction - { - enum classtype classtype; - void (*p_trigger)( world_instance *world, 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; iclasstype == rt->classtype ) - { - instr->p_trigger( world, rt->sub_id ); - return; - } - } - - vg_error( "Don't know how to trigger classtype %d\n", rt->classtype ); -} - -VG_STATIC void world_update( world_instance *world, v3f pos ) -{ - /* TEMP!!!!!! */ - static double g_time = 0.0; - g_time += vg.time_delta * (1.0/(k_day_length*60.0)); - - - struct ub_world_lighting *state = &world->ub_lighting; - - state->g_time = g_time; - state->g_debug_indices = k_debug_light_indices; - state->g_light_preview = k_light_preview; - state->g_debug_complexity = k_debug_light_complexity; - - state->g_time_of_day = vg_fractf( g_time ); - state->g_day_phase = cosf( state->g_time_of_day * VG_PIf * 2.0f ); - state->g_sunset_phase= cosf( state->g_time_of_day * VG_PIf * 4.0f + VG_PIf ); - - state->g_day_phase = state->g_day_phase * 0.5f + 0.5f; - state->g_sunset_phase = powf( state->g_sunset_phase * 0.5f + 0.5f, 6.0f ); - - float a = state->g_time_of_day * VG_PIf * 2.0f; - state->g_sun_dir[0] = sinf( a ); - state->g_sun_dir[1] = cosf( a ); - state->g_sun_dir[2] = 0.2f; - v3_normalize( state->g_sun_dir ); - - - - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, - sizeof(struct ub_world_lighting), &world->ub_lighting ); - /* TEMP!!!!!! */ - - -#if 0 - if( world.switching_to_new_world ) - { - int all_stopped = 1; - - audio_lock(); - for( int i=0; iplayer ) ) - { - all_stopped = 0; - break; - } - } - audio_unlock(); - - if( all_stopped ) - { - world.switching_to_new_world = 0; - world_unload(); - vg_loader_start( world_load ); - return; - } - } - -#endif - world_global.sky_time += world_global.sky_rate * vg.time_delta; - world_global.sky_rate = vg_lerp( world_global.sky_rate, - world_global.sky_target_rate, - vg.time_delta * 5.0 ); - - world_routes_update( world ); -#if 0 - world_routes_debug(); -#endif - - if( world->route_count > 0 ) - { - int closest = 0; - float min_dist = INFINITY; - - for( int i=0; iroute_count; i++ ) - { - float d = v3_dist2( world->routes[i].scoreboard_transform[3], pos ); - - if( d < min_dist ) - { - min_dist = d; - closest = i; - } - } - - if( (world_global.active_route_board != closest) - || network_scores_updated ) - { - network_scores_updated = 0; - world_global.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; itrigger_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_global.in_trigger ) - { - world_run_relay( world, &zone->target ); - } - } - - vg_line_boxf_transformed( zone->transform, (boxf){{-1.0f,-1.0f,-1.0f}, - { 1.0f, 1.0f, 1.0f}}, - 0xff00ff00 ); - } - - if( k_debug_light_indices ) - { - for( int i=0; ilight_count; i++ ) - { - struct world_light *light = &world->lights[i]; - struct classtype_world_light *inf = light->inf; - - u32 colour = 0xff000000; - u8 r = inf->colour[0] * 255.0f, - g = inf->colour[1] * 255.0f, - b = inf->colour[2] * 255.0f; - - colour |= r; - colour |= g << 8; - colour |= b << 16; - - vg_line_pt3( light->node->co, 0.25f, colour ); - } - } - - world_global.in_trigger = in_trigger; - sfd_update(); -} - -/* - * ----------------------------------------------------------------------------- - * API implementation - * ----------------------------------------------------------------------------- - */ - -VG_STATIC void ray_world_get_tri( world_instance *world, - 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] ); -} - -VG_STATIC int ray_world( world_instance *world, - v3f pos, v3f dir, ray_hit *hit ) -{ - return scene_raycast( world->scene_geo, world->geo_bh, pos, dir, hit ); -} - -/* - * Cast a sphere from a to b and see what time it hits - */ -VG_STATIC int spherecast_world( world_instance *world, - v3f pa, v3f pb, float r, float *t, v3f n ) -{ - bh_iter it; - bh_iter_init( 0, &it ); - - boxf region; - box_init_inf( region ); - box_addpt( region, pa ); - box_addpt( region, pb ); - - v3_add( (v3f){ r, r, r}, region[1], region[1] ); - v3_add( (v3f){-r,-r,-r}, region[0], region[0] ); - - v3f dir; - v3_sub( pb, pa, dir ); - - v3f dir_inv; - dir_inv[0] = 1.0f/dir[0]; - dir_inv[1] = 1.0f/dir[1]; - dir_inv[2] = 1.0f/dir[2]; - - int hit = -1; - float min_t = 1.0f; - - int idx; - while( bh_next( world->geo_bh, &it, region, &idx ) ) - { - u32 *ptri = &world->scene_geo->arrindices[ idx*3 ]; - v3f tri[3]; - - boxf box; - box_init_inf( box ); - - for( int j=0; j<3; j++ ) - { - v3_copy( world->scene_geo->arrvertices[ptri[j]].co, tri[j] ); - box_addpt( box, tri[j] ); - } - - v3_add( (v3f){ r, r, r}, box[1], box[1] ); - v3_add( (v3f){-r,-r,-r}, box[0], box[0] ); - - if( !ray_aabb1( box, pa, dir_inv, 1.0f ) ) - continue; - - float t; - v3f n1; - if( spherecast_triangle( tri, pa, dir, r, &t, n1 ) ) - { - if( t < min_t ) - { - min_t = t; - hit = idx; - v3_copy( n1, n ); - } - } - } - - *t = min_t; - return hit; -} - -VG_STATIC -struct world_material *world_tri_index_material( world_instance *world, - u32 index ) -{ - for( int i=1; imaterial_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; - } - } - - /* error material */ - return &world->materials[0]; -} - -VG_STATIC struct world_material *world_contact_material( world_instance *world, - rb_ct *ct ) -{ - return world_tri_index_material( world, ct->element_id ); -} - -VG_STATIC struct world_material *ray_hit_material( world_instance *world, - ray_hit *hit ) -{ - return world_tri_index_material( world, hit->tri[0] ); -} + enum world_purpose purpose; + addon_reg *reg; +}; -#endif /* WORLD_H */ +void world_init(void); +world_instance *world_current_instance(void); +void world_switch_instance( u32 index ); +void skaterift_world_load_thread( void *_args ); +void world_update( world_instance *world, v3f pos );