X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=world.h;h=49d1aaea690849f6fb32bfb3e645901940d9d33d;hb=8d336ea2cde7c596296dbaf0d3ce27a82c6c6cf0;hp=5318f8e326408c6d75624b2ed4ab8f7b38453328;hpb=89113e9bc9544336b5ac4f53696c3de2d30698a2;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/world.h b/world.h index 5318f8e..49d1aae 100644 --- a/world.h +++ b/world.h @@ -1,71 +1,78 @@ /* - * 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 "font.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 + */ + +enum world_geo_type{ + k_world_geo_type_solid = 0, + k_world_geo_type_nonsolid = 1, + k_world_geo_type_water = 2 +}; -#include "shaders/model_sky.h" +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; + +#define WORLD_SURFACE_HAS_TRAFFIC 0x1 +#define WORLD_SURFACE_HAS_PROPS 0x2 struct world_instance { /* Fixed items * ------------------------------------------------------- */ + v4f player_co; + void *heap; - char world_name[ 64 ]; enum world_status{ k_world_status_unloaded = 0, k_world_status_loading = 1, - k_world_status_loaded = 2 + k_world_status_loaded = 2, + k_world_status_unloading = 3 /* dont spawn sounds and stuff */ } status; @@ -79,6 +86,9 @@ struct world_instance { } water; + f64 time; + f32 tar_min, tar_max; + /* STD140 */ struct ub_world_lighting{ v4f g_cube_min, @@ -124,7 +134,6 @@ struct world_instance { float probabilities[3]; v3i light_cubes; - struct framebuffer heightmap; /* @@ -132,8 +141,6 @@ struct world_instance { * * the following arrays index somewhere into this linear * allocator - * - * (world_gen.h) * -------------------------------------------------------------------------- */ @@ -149,10 +156,12 @@ struct world_instance { 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, @@ -165,7 +174,26 @@ struct world_instance { ent_audio_clip, ent_audio, ent_volume, - ent_traffic; + 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; @@ -174,805 +202,73 @@ struct world_instance { */ /* 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; - rb_object rb_geo; + /* ui */ + struct route_ui *routes_ui; }; -struct world_global{ +struct world_static { /* * Allocated as system memory * -------------------------------------------------------------------------- */ void *heap; - /* rendering */ - glmesh skydome; - glmesh mesh_gate; - mdl_submesh sm_gate_surface, - sm_gate_marker[4]; - - double sky_time, sky_rate, sky_target_rate; - 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 w, h; - float *buffer; - } - sfd; - - v3f render_gate_pos; - int in_volume; - - int switching_to_new_world; - - world_instance worlds[4]; - u32 world_count; - u32 active_world; - - /* text particles */ - font3d font; - - struct timer_text{ - char text[8]; - m4x3f transform; - ent_gate *gate; - ent_route *route; - } - timer_texts[4]; - u32 timer_text_count; - - struct text_particle{ - rb_object obj; - m4x3f mlocal; - ent_glyph *glyph; - v4f colour; - - m4x3f mdl; - } - text_particles[6*4]; - u32 text_particle_count; -} -static 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 ); + u32 active_trigger_volumes[8]; + u32 active_trigger_volume_count; -VG_STATIC -struct world_surface *ray_hit_surface( world_instance *world, ray_hit *hit ); + addon_reg *instance_addons[ k_world_max ]; + world_instance instances[ k_world_max ]; -VG_STATIC -void ray_world_get_tri( world_instance *world, ray_hit *hit, v3f tri[3] ); + enum world_purpose active_instance; + u32 focused_entity; /* like skateshop, challenge.. */ + f32 focus_strength; + vg_camera focus_cam; -VG_STATIC -int ray_world( world_instance *world, v3f pos, v3f dir, ray_hit *hit ); - -VG_STATIC -ent_spawn *world_find_closest_spawn( world_instance *world, v3f position ) -{ - ent_spawn *rp = NULL, *r; - float min_dist = INFINITY; - - for( u32 i=0; ient_spawn); i++ ){ - r = mdl_arritm( &world->ent_spawn, i ); - float d = v3_dist2( r->transform.co, position ); - - if( d < min_dist ){ - min_dist = d; - rp = r; - } - } + /* challenges */ + ent_objective *challenge_target; + f32 challenge_timer; - if( !rp ){ - if( mdl_arrcount(&world->ent_spawn) ){ - vg_warn( "Invalid distances to spawns.. defaulting to first one.\n" ); - return mdl_arritm( &world->ent_spawn, 0 ); - } - else{ - vg_error( "There are no spawns in the level!\n" ); - } + enum world_loader_state{ + k_world_loader_none, + k_world_loader_preload, + k_world_loader_load } + load_state; - return rp; + bool clear_async_op_when_done; } +extern world_static; -VG_STATIC -ent_spawn *world_find_spawn_by_name( world_instance *world, const char *name ) +struct world_load_args { - ent_spawn *rp = NULL, *r; - for( u32 i=0; ient_spawn); i++ ){ - r = mdl_arritm( &world->ent_spawn, i ); - if( !strcmp( mdl_pstr(&world->meta, r->pstr_name), name ) ){ - rp = r; - break; - } - } - - if( !rp ) - vg_warn( "No spawn named '%s'\n", name ); - - return rp; -} - -/* - * Submodules - */ - -VG_STATIC float - k_day_length = 30.0f; /* minutes */ - -VG_STATIC int k_debug_light_indices = 0, - k_debug_light_complexity = 0, - k_light_preview = 0; - -#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) -{ - VG_VAR_F32( k_day_length ); - VG_VAR_I32( k_debug_light_indices ); - VG_VAR_I32( k_debug_light_complexity ); - VG_VAR_I32( k_light_preview ); - - 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.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; + enum world_purpose purpose; + addon_reg *reg; }; -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 ){ - float *co = alloca( sizeof(float)*3 ); - 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 - entity_call( world, call ); - } -} - -VG_STATIC void ent_audio_call( world_instance *world, ent_call *call ) -{ - ent_audio *audio = mdl_arritm( &world->ent_audio, call->ent.index ); - - v3f sound_co; - - if( call->function == k_ent_function_particle_spawn ){ - v3_copy( call->data, sound_co ); - } - else if( call->function == k_ent_function_trigger ){ - v3_copy( audio->transform.co, sound_co ); - } - else - vg_fatal_exit_loop( "ent_audio_call (invalid function id)" ); - - 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 ){ - - audio_lock(); - - if( audio->behaviour == k_channel_behaviour_unlimited ){ - audio_oneshot_3d( &clip->clip, sound_co, - 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, sound_co, 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_channel *ch = - audio_get_group_idle_channel( audio->group, - audio->max_channels ); - - /* group is full */ - if( !ch ){ - audio_channel *existing = - audio_get_group_first_active_channel( audio->group ); - - if( existing ){ - if( existing->source == &clip->clip ){ - audio_unlock(); - return; - } - - existing->group = 0; - existing = audio_channel_fadeout(existing, audio->crossfade); - } - - ch = audio_get_first_idle_channel(); - } - - if( ch ){ - audio_channel_init( ch, &clip->clip, audio->flags ); - audio_channel_group( ch, audio->group ); - audio_channel_fadein( ch, audio->crossfade ); - ch = audio_relinquish_channel( ch ); - } - } - - audio_unlock(); - return; - } - } -} - -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 ); - } -} - -VG_STATIC void world_update( world_instance *world, v3f pos ) -{ - 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_timer_texts( world ); - world_routes_update( world ); - //world_routes_debug( world ); - - /* ---- traffic -------- */ - - for( u32 i=0; ient_traffic ); i++ ){ - ent_traffic *traffic = mdl_arritm( &world->ent_traffic, i ); - - u32 i1 = traffic->index, - i0, - i2 = i1+1; - - if( i1 == 0 ) i0 = traffic->node_count-1; - else i0 = i1-1; - - if( i2 >= traffic->node_count ) i2 = 0; - - i0 += traffic->start_node; - i1 += traffic->start_node; - i2 += traffic->start_node; - - v3f h[3]; - - ent_route_node *rn0 = mdl_arritm( &world->ent_route_node, i0 ), - *rn1 = mdl_arritm( &world->ent_route_node, i1 ), - *rn2 = mdl_arritm( &world->ent_route_node, i2 ); - - v3_copy( rn1->co, h[1] ); - v3_lerp( rn0->co, rn1->co, 0.5f, h[0] ); - v3_lerp( rn1->co, rn2->co, 0.5f, h[2] ); - - float const k_sample_dist = 0.0025f; - v3f pc, pd; - eval_bezier3( h[0], h[1], h[2], traffic->t, pc ); - eval_bezier3( h[0], h[1], h[2], traffic->t+k_sample_dist, pd ); - - v3f v0; - v3_sub( pd, pc, v0 ); - float length = vg_maxf( 0.0001f, v3_length( v0 ) ); - v3_muls( v0, 1.0f/length, v0 ); - - float mod = k_sample_dist / length; - - traffic->t += traffic->speed * vg.time_delta * mod; - - if( traffic->t > 1.0f ){ - traffic->t -= 1.0f; - - if( traffic->t > 1.0f ) traffic->t = 0.0f; - - traffic->index ++; - - if( traffic->index >= traffic->node_count ) - traffic->index = 0; - } - - v3_copy( pc, traffic->transform.co ); - - float a = atan2f( -v0[0], v0[2] ); - q_axis_angle( traffic->transform.q, (v3f){0.0f,1.0f,0.0f}, -a ); - - vg_line_pt3( traffic->transform.co, 0.3f, VG__BLUE ); - } - - /* ---- 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 ); - - if( (fabsf(local[0]) <= 1.0f) && - (fabsf(local[1]) <= 1.0f) && - (fabsf(local[2]) <= 1.0f) ) - { - in_volume = 1; - vg_line_boxf_transformed( volume->to_world, cube, 0xff00ff00 ); - - 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 - vg_line_boxf_transformed( volume->to_world, cube, 0xff0000ff ); - } - 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 -} - -/* - * ----------------------------------------------------------------------------- - * 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] ); -} - -/* - * ----------------------------------------------------------------------------- - * Audio sampling - * ----------------------------------------------------------------------------- - */ - -VG_STATIC -enum audio_sprite_type world_audio_sample_sprite_random(v3f origin, v3f output); -VG_STATIC void world_audio_sample_distances( v3f co, int *index, float *value ); - -#include "audio.h" - -/* - * Trace out a random point, near the player to try and determine water areas - */ -VG_STATIC -enum audio_sprite_type world_audio_sample_sprite_random(v3f origin, v3f output) -{ - v3f chance = { (vg_randf()-0.5f) * 30.0f, - 8.0f, - (vg_randf()-0.5f) * 30.0f }; - - v3f pos; - v3_add( chance, origin, pos ); - - ray_hit contact; - contact.dist = vg_minf( 16.0f, pos[1] ); - - world_instance *world = get_active_world(); - - if( ray_world( world, pos, (v3f){0.0f,-1.0f,0.0f}, &contact ) ){ - struct world_surface *mat = ray_hit_surface( world, &contact ); - - if( mat->info.surface_prop == k_surface_prop_grass){ - v3_copy( contact.pos, output ); - return k_audio_sprite_type_grass; - } - else{ - return k_audio_sprite_type_none; - } - } - - output[0] = pos[0]; - output[1] = 0.0f; - output[2] = pos[2]; - - float dist = fabsf(output[1] - origin[1]); - - if( world->water.enabled && dist<=40.0f ) - return k_audio_sprite_type_water; - else - return k_audio_sprite_type_none; -} - -VG_STATIC void world_audio_sample_distances( v3f co, int *index, float *value ) -{ - float inr3 = 0.57735027, - inr2 = 0.70710678118; - - v3f sample_directions[] = { - { -1.0f, 0.0f, 0.0f }, - { 1.0f, 0.0f, 0.0f }, - { 0.0f, 0.0f, 1.0f }, - { 0.0f, 0.0f, -1.0f }, - { 0.0f, 1.0f, 0.0f }, - { 0.0f, -1.0f, 0.0f }, - { -inr3, inr3, inr3 }, - { inr3, inr3, inr3 }, - { -inr3, inr3, -inr3 }, - { inr3, inr3, -inr3 }, - { -inr2, 0.0f, inr2 }, - { inr2, 0.0f, inr2 }, - { -inr2, 0.0f, -inr2 }, - { inr2, 0.0f, -inr2 }, - }; - - static int si = 0; - static float distances[16]; - - ray_hit ray; - ray.dist = 5.0f; - - v3f rc, rd, ro; - v3_copy( sample_directions[ si ], rd ); - v3_add( co, (v3f){0.0f,1.5f,0.0f}, ro ); - v3_copy( ro, rc ); - - float dist = 200.0f; - - for( int i=0; i<10; i++ ){ - if( ray_world( get_active_world(), rc, rd, &ray ) ){ - dist = (float)i*5.0f + ray.dist; - break; - } - else{ - v3_muladds( rc, rd, ray.dist, rc ); - } - } - - distances[si] = dist; - - if( vg_lines.draw ){ - for( int i=0; i<14; i++ ){ - if( distances[i] != 200.0f ){ - u32 colours[] = { VG__RED, VG__BLUE, VG__GREEN, - VG__CYAN, VG__YELOW, VG__PINK, - VG__WHITE }; - - u32 colour = colours[i%7]; - - v3f p1; - v3_muladds( ro, sample_directions[i], distances[i], p1 ); - vg_line( ro, p1, colour ); - vg_line_pt3( p1, 0.1f, colour ); - } - } - } - - *index = si; - *value = dist; - - si ++; - if( si >= 14 ) - si = 0; -} - -#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 );