X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=world.h;h=49d1aaea690849f6fb32bfb3e645901940d9d33d;hb=8d336ea2cde7c596296dbaf0d3ce27a82c6c6cf0;hp=997ff312b03fc0a28377aab2515810671b398c78;hpb=5f01e7ab4aad052faad262b55404819dac3d25ce;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/world.h b/world.h index 997ff31..49d1aae 100644 --- a/world.h +++ b/world.h @@ -1,73 +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 "entity.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 +}; -enum { k_max_ui_segments = 8 }; +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_elements = k_max_ui_segments }; -enum { k_max_element_verts = 10 }; -enum { k_max_element_indices = 20 }; +struct leaderboard_cache { + enum request_status status; + f64 cache_time; + u8 *data; + u32 data_len; +}; -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 }; +typedef struct world_instance world_instance; -enum logic_type -{ - k_logic_type_relay = 1, - k_logic_type_chance = 2, - k_logic_type_achievement = 3 -}; +void skaterift_world_get_save_path( enum world_purpose which, char buf[128] ); -enum geo_type -{ - k_geo_type_solid = 0, - k_geo_type_nonsolid = 1, - k_geo_type_water = 2 -}; +/* 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" -static const float k_light_cube_size = 8.0f; +/* console variables */ -struct world_instance -{ - /* This is a small flag we use to changelevel. - * It will not be cleared until all sounds stop playing - */ +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; +#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; @@ -77,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; @@ -93,6 +104,8 @@ 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; @@ -121,7 +134,6 @@ struct world_instance float probabilities[3]; v3i light_cubes; - struct framebuffer heightmap; /* @@ -129,10 +141,9 @@ struct world_instance * * the following arrays index somewhere into this linear * allocator - * - * (world_gen.h) * -------------------------------------------------------------------------- */ + /* * Main world .mdl */ @@ -141,15 +152,16 @@ struct world_instance GLuint *textures; u32 texture_count; - struct world_surface - { + struct world_surface{ mdl_material info; mdl_submesh sm_geo, sm_no_collide; + u32 flags; } * surfaces; u32 surface_count; + ent_worldinfo info; mdl_array_ptr ent_spawn, ent_gate, ent_light, @@ -161,726 +173,102 @@ struct world_instance ent_audio_clip, ent_audio, - ent_volume; + 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; -#if 0 - /* - * 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, range; - u32 flags; - audio_clip temp_embedded_clip; - } - * audio_things; - u32 audio_things_count; - - struct soundscape - { - /* locking */ - audio_channel *channels[4]; - - /* accessable without locking */ - v3f spawn_position; - - u32 usage_count; - u32 max_instances; - u32 allow_transitions; - float transition_duration; - const char *label; - } - * soundscapes; - u32 soundscape_count; - - /* - * Box volume entities - */ - struct world_volume - { - m4x3f transform, inv_transform; - mdl_node *node; - } - * volumes; - u32 volume_count; - - /* - * Lights - */ - struct world_light - { - mdl_node *node; - struct classtype_world_light *inf; - m4x3f inverse_world; - v2f angle_sin_cos; - } - * 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; -#endif - - /* 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, - *volume_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; + + /* leaderboards */ + struct leaderboard_cache *leaderboard_cache; - rigidbody rb_geo; /* todo.. ... */ + /* ui */ + struct route_ui *routes_ui; }; -VG_STATIC struct world_global -{ +struct world_static { /* * Allocated as system memory * -------------------------------------------------------------------------- */ - void *generic_heap; - - /* rendering */ - glmesh skydome; - glmesh mesh_gate; - mdl_submesh sm_gate_surface, - sm_gate_marker[4]; - - double sky_time, sky_rate, sky_target_rate; + void *heap; u32 current_run_version; double time, rewind_from, rewind_to, last_use; - /* water rendering */ - struct - { - struct framebuffer fbreflect, fbdepth; - } - water; - - /* split flap display */ - struct - { - glmesh mesh_base, mesh_display; - mdl_submesh sm_base; - u32 active_route_board; + u32 active_trigger_volumes[8]; + u32 active_trigger_volume_count; - u32 w, h; - float *buffer; - } - sfd; + addon_reg *instance_addons[ k_world_max ]; + world_instance instances[ k_world_max ]; - v3f render_gate_pos; - int in_volume; + enum world_purpose active_instance; + u32 focused_entity; /* like skateshop, challenge.. */ + f32 focus_strength; + vg_camera focus_cam; - int switching_to_new_world; + /* challenges */ + ent_objective *challenge_target; + f32 challenge_timer; - world_instance worlds[4]; - u32 world_count; - u32 active_world; -} -world_global; - -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_surface *ray_hit_surface( 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 - */ - -#include "world_routes.h" -#include "world_sfd.h" -#include "world_render.h" -#include "world_water.h" -#include "world_volumes.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(); - return 0; -} - -VG_STATIC void world_init(void) -{ - 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_open( &msky, "models/rs_skydome.mdl", vg_mem.scratch ); - mdl_load_metadata_block( &msky, vg_mem.scratch ); - mdl_load_mesh_block( &msky, vg_mem.scratch ); - mdl_close( &msky ); - - 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 ); -} - -typedef struct ent_call ent_call; -struct ent_call{ - ent_index ent; - u32 function; - void *data; -}; - -VG_STATIC void entity_call( world_instance *world, ent_call *call ); - -VG_STATIC void ent_volume_call( world_instance *world, ent_call *call ) -{ - ent_volume *volume = mdl_arritm( &world->ent_volume, call->ent.index ); - if( !volume->target.type ) return; - - if( call->function == k_ent_function_trigger ){ - call->ent = volume->target; - - if( volume->type == k_volume_subtype_particle ){ - v3f co; - co[0] = vg_randf()*2.0f-1.0f; - co[1] = vg_randf()*2.0f-1.0f; - co[2] = vg_randf()*2.0f-1.0f; - m4x3_mulv( volume->to_world, co, co ); - - call->function = k_ent_function_particle_spawn; - call->data = co; - - entity_call( world, call ); - } - else if( volume->type == k_volume_subtype_trigger ){ - /* TODO */ - } - } -} - -VG_STATIC void ent_audio_call( world_instance *world, ent_call *call ) -{ - ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index ); - - if( call->function == k_ent_function_particle_spawn ){ - float chance = vg_randf()*100.0f, - bar = 0.0f; - - for( u32 i=0; iclip_count; i++ ){ - ent_audio_clip *clip = mdl_arritm( &world->ent_audio_clip, - audio->clip_start+i ); - - float mod = world->probabilities[ audio->probability_curve ], - p = clip->probability * mod; - - bar += p; - - if( chance < bar ){ - float *pos = call->data; - - audio_lock(); - - if( audio->behaviour == k_channel_behaviour_unlimited ){ - audio_oneshot_3d( &clip->clip, pos, - audio->transform.s[0], - audio->volume ); - } - else if( audio->behaviour == k_channel_behaviour_discard_if_full ){ - audio_channel *ch = - audio_get_group_idle_channel( audio->group, - audio->max_channels ); - - if( ch ){ - audio_channel_init( ch, &clip->clip, audio->flags ); - audio_channel_group( ch, audio->group ); - audio_channel_set_spacial( ch, pos, audio->transform.s[0] ); - audio_channel_edit_volume( ch, audio->volume, 1 ); - ch = audio_relinquish_channel( ch ); - } - } - else if( audio->behaviour == k_channel_behaviour_crossfade_if_full){ - - } - - - - audio_unlock(); - break; - } - } + enum world_loader_state{ + k_world_loader_none, + k_world_loader_preload, + k_world_loader_load } -} + load_state; -VG_STATIC void entity_call( world_instance *world, ent_call *call ) -{ - if( call->ent.type == k_ent_volume ){ - ent_volume_call( world, call ); - } else if( call->ent.type == k_ent_audio ){ - ent_audio_call( world, call ); - } + bool clear_async_op_when_done; } +extern world_static; -VG_STATIC void world_update( world_instance *world, v3f pos ) +struct world_load_args { - /* 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_realtime = vg.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 ); - - - world->probabilities[ k_probability_curve_constant ] = 1.0f; - - float dp = state->g_day_phase; - - world->probabilities[ k_probability_curve_wildlife_day ] = - (dp*dp*0.8f+state->g_sunset_phase)*0.8f; - world->probabilities[ k_probability_curve_wildlife_night ] = - 1.0f-powf(fabsf((state->g_time_of_day-0.5f)*5.0f),5.0f); - - - glBindBuffer( GL_UNIFORM_BUFFER, world->ubo_lighting ); - glBufferSubData( GL_UNIFORM_BUFFER, 0, - sizeof(struct ub_world_lighting), &world->ub_lighting ); - /* TEMP!!!!!! */ - - 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 ); - world_routes_debug( world ); - - /* ---- SFD ------------ */ - - if( mdl_arrcount( &world->ent_route ) ){ - u32 closest = 0; - float min_dist = INFINITY; - - for( u32 i=0; ient_route ); i++ ){ - ent_route *route = mdl_arritm( &world->ent_route, i ); - float dist = v3_dist2( route->board_transform[3], pos ); - - if( dist < min_dist ){ - min_dist = dist; - closest = i; - } - } - - if( (world_global.sfd.active_route_board != closest) - || network_scores_updated ) - { - network_scores_updated = 0; - world_global.sfd.active_route_board = closest; - - ent_route *route = mdl_arritm( &world->ent_route, closest ); - u32 id = route->official_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] ); - } - }else{ - sfd_encode( 0, mdl_pstr( &world->meta, route->pstr_name ) ); - sfd_encode( 1, "No data" ); - } - } - } - sfd_update(); - - - - static float random_accum = 0.0f; - random_accum += vg.time_delta; - - u32 random_ticks = 0; - - while( random_accum > 0.1f ){ - random_accum -= 0.1f; - random_ticks ++; - } - - float radius = 25.0f; - boxf volume_proximity; - v3_add( pos, (v3f){ radius, radius, radius }, volume_proximity[1] ); - v3_sub( pos, (v3f){ radius, radius, radius }, volume_proximity[0] ); - - bh_iter it; - bh_iter_init( 0, &it ); - int idx; - - int in_volume = 0; - - while( bh_next( world->volume_bh, &it, volume_proximity, &idx ) ){ - ent_volume *volume = mdl_arritm( &world->ent_volume, idx ); - - boxf cube = {{-1.0f,-1.0f,-1.0f},{1.0f,1.0f,1.0f}}; - - if( volume->type == k_volume_subtype_trigger ){ - v3f local; - m4x3_mulv( volume->to_local, pos, local ); - vg_line_boxf_transformed( volume->to_world, cube, 0xff00ff00 ); - - if( (fabsf(local[0]) <= 1.0f) && - (fabsf(local[1]) <= 1.0f) && - (fabsf(local[2]) <= 1.0f) ) - { - in_volume = 1; - - if( !world_global.in_volume ){ - ent_call basecall; - basecall.ent.index = idx; - basecall.ent.type = k_ent_volume; - basecall.function = k_ent_function_trigger; - basecall.data = NULL; - - entity_call( world, &basecall ); - } - } - } - else if( volume->type == k_volume_subtype_particle ){ - vg_line_boxf_transformed( volume->to_world, cube, 0xff00c0ff ); - - for( int j=0; jlight_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 ); - } - } - -#endif - -#if 0 - - /* process soundscape transactions */ - audio_lock(); - for( int i=0; isoundscape_count; i++ ) - { - struct soundscape *s = &world->soundscapes[i]; - s->usage_count = 0; - - for( int j=0; jmax_instances; j++ ) - { - if( s->channels[j] ) - { - if( audio_channel_finished(s->channels[j]) ) - s->channels[j] = audio_relinquish_channel( s->channels[j] ); - else - s->usage_count ++; - } - } - } - audio_unlock(); -#endif -} - -/* - * ----------------------------------------------------------------------------- - * 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_surface *world_tri_index_surface( world_instance *world, - u32 index ) -{ - for( int i=1; isurface_count; i++ ){ - struct world_surface *surf = &world->surfaces[i]; - - if( (index >= surf->sm_geo.vertex_start) && - (index < surf->sm_geo.vertex_start+surf->sm_geo.vertex_count ) ) - { - return surf; - } - } - - return &world->surfaces[0]; -} - -VG_STATIC struct world_surface *world_contact_surface( world_instance *world, - rb_ct *ct ) -{ - return world_tri_index_surface( world, ct->element_id ); -} - -VG_STATIC struct world_surface *ray_hit_surface( world_instance *world, - ray_hit *hit ) -{ - return world_tri_index_surface( 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 );