From 86dbcd5796ed674ca9433cce1ace8bef322cd121 Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 4 Oct 2022 16:59:29 +0100 Subject: [PATCH] gate frame fix --- common.h | 3 +- gate.h | 2 +- main.c | 16 +- network.h | 1 - player.h | 69 ++-- player_animation.h | 104 +++--- player_audio.h | 32 +- player_physics.h | 282 +++++++------- world.h | 786 ++++++++------------------------------- world_gen.h | 365 ++++++++++++++++++ world_render.h | 254 +++++++++++++ world_routes.h | 304 ++++++--------- world_sfd.h | 30 +- water.h => world_water.h | 85 +---- 14 files changed, 1156 insertions(+), 1177 deletions(-) create mode 100644 world_gen.h create mode 100644 world_render.h rename water.h => world_water.h (67%) diff --git a/common.h b/common.h index f423963..e4015a8 100644 --- a/common.h +++ b/common.h @@ -47,7 +47,6 @@ static void eval_bezier_time( v3f p0, v3f p1, v3f h0, v3f h1, float t, v3f p ) v3_muladds( p, p0, 3.0f*tt -ttt -3.0f*t +1.0f, p ); } -/* TODO: he needs a home somewhere */ -static float *player_get_pos(void); +static int network_scores_updated = 0; #endif /* COMMON_H */ diff --git a/gate.h b/gate.h index 175a8c6..fec2826 100644 --- a/gate.h +++ b/gate.h @@ -6,7 +6,7 @@ #include "render.h" #include "shaders/gate.h" #include "shaders/gatelq.h" -#include "water.h" +#include "world_water.h" typedef struct teleport_gate teleport_gate; diff --git a/main.c b/main.c index 0732057..e967bcf 100644 --- a/main.c +++ b/main.c @@ -54,7 +54,6 @@ static int cl_ui = 1; #include "anim_test.h" #include "gate.h" -#include "water.h" void vg_register(void) { @@ -65,7 +64,6 @@ void vg_register(void) player_register(); world_register(); - water_register(); gate_register(); } @@ -237,7 +235,7 @@ void vg_start(void) world_load(); reset_player( 1, (const char *[]){ "start" } ); - rb_init( &player.rb ); + rb_init( &player.phys.rb ); network_init(); } @@ -270,7 +268,7 @@ void vg_update(void) { network_update(); player_update(); - world_update(); + world_update( player.phys.rb.co ); //traffic_visualize( world.traffic, world.traffic_count ); // /* TEMP */ @@ -305,7 +303,7 @@ static void draw_origin_axis(void) static void render_main_game(void) { - float speed = freecam? 0.0f: v3_length( player.rb.v ); + float speed = freecam? 0.0f: v3_length( player.phys.rb.v ); v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f }; v3_muls( shake, speed*0.01f, shake ); @@ -336,7 +334,7 @@ static void render_main_game(void) render_water_surface( vg_pv, player.camera ); vg_tex2d_bind( &tex_water, 1 ); /*TODO: ?*/ - render_world_gates( vg_pv, player.rb.co, player.camera ); + render_world_gates( vg_pv, player.phys.rb.co, player.camera ); /* Copy the RGB of what we have into the background buffer */ glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 ); @@ -437,15 +435,15 @@ static void run_debug_info(void) { char buf[40]; - snprintf( buf, 40, "%.2fm/s", v3_length( player.rb.v ) ); + snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) ); gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left ); snprintf( buf, 40, "%.2f %.2f %.2f m/s", - player.a[0], player.a[1], player.a[2] ); + player.phys.a[0], player.phys.a[1], player.phys.a[2] ); gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left ); snprintf( buf, 40, "pos %.2f %.2f %.2f", - player.rb.co[0], player.rb.co[1], player.rb.co[2] ); + player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] ); gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left ); if( vg_gamepad_ready ) diff --git a/network.h b/network.h index ef3455d..a9b5c8f 100644 --- a/network.h +++ b/network.h @@ -38,7 +38,6 @@ static void network_submit_highscore( u32 trackid, u16 points, u16 time ); static u8 steam_app_ticket[ 1024 ]; static u32 steam_app_ticket_length; static int network_name_update = 1; -static int network_scores_updated = 0; static HSteamNetConnection cremote; static ESteamNetworkingConnectionState cremote_state = diff --git a/player.h b/player.h index 92db1fb..e4c0fce 100644 --- a/player.h +++ b/player.h @@ -52,33 +52,34 @@ static float fc_speed = 10.0f; static struct gplayer { /* Physics */ - rigidbody rb, collide_front, collide_back, rb_gate_frame; + rigidbody collide_front, collide_back; - /* TODO: eugh */ - m3x3f gate_vr_frame, gate_vr_pstep_frame; - int on_board_frame, in_air_frame; + struct player_phys + { + rigidbody rb, rb_gate_frame; + float iY, siY; /* Yaw inertia */ + + v3f a, v_last, m, bob, vl; - v3f a, v_last, m, bob, vl; + /* Utility */ + float vswitch, slip, slip_last, + reverse; - /* Utility */ - float vswitch, slip, slip_last, - reverse; + float grab, jump; + int in_air, on_board, jump_charge, jump_dir; - float iY; /* Yaw inertia */ - int in_air, is_dead, on_board; + m3x3f vr,vr_pstep; + } + phys, + phys_gate_frame; - v2f board_xy; - float grab; - float pitch; float pushing, push_time; - float jump; - int jump_charge, jump_dir; - + int is_dead; + v3f land_target; v3f land_target_log[22]; u32 land_target_colours[22]; int land_log_count; - m3x3f vr,vr_pstep; v3f handl_target, handr_target, handl, handr; @@ -100,7 +101,9 @@ static struct gplayer fairdir, fsetup, walk_timer, + fjump, fonboard; + int step_phase; /* player model */ @@ -146,8 +149,6 @@ static struct gplayer } player = { - .on_board = 0, - .collide_front = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f }, .collide_back = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f } }; @@ -158,6 +159,8 @@ player = static float *player_get_pos(void); static void player_kill(void); static float *player_cam_pos(void); +static void player_save_frame(void); +static void player_restore_frame(void); /* * Submodules @@ -189,29 +192,23 @@ static void player_init(void) /* 1 */ static void player_update(void) /* 2 */ { + struct player_phys *phys = &player.phys; + for( int i=0; i0.0f) { - player.rb = player.rb_gate_frame; - player.on_board = player.on_board_frame; - player.in_air = player.in_air_frame; - m3x3_copy( player.gate_vr_frame, player.vr ); - m3x3_copy( player.gate_vr_pstep_frame, player.vr_pstep ); player.is_dead = 0; - player.in_air = 1; + player_restore_frame(); - - if( !player.on_board ) + if( !phys->on_board ) { - player.angles[0] = atan2f( -player.rb.forward[2], - -player.rb.forward[0] ); + player.angles[0] = atan2f( -phys->rb.forward[2], + -phys->rb.forward[0] ); } - m3x3_identity( player.vr ); - player.mdl.shoes[0] = 1; player.mdl.shoes[1] = 1; @@ -220,13 +217,13 @@ static void player_update(void) /* 2 */ if( vg_get_button_down( "switchmode" ) ) { - player.on_board ^= 0x1; + phys->on_board ^= 0x1; } - if( (glfwGetKey( vg_window, GLFW_KEY_O ) || (player.rb.co[1] < 0.0f)) && + if( (glfwGetKey( vg_window, GLFW_KEY_O ) || (phys->rb.co[1] < 0.0f)) && !player.is_dead) { - player_ragdoll_copy_model( player.rb.v ); + player_ragdoll_copy_model( phys->rb.v ); player.is_dead = 1; } @@ -282,13 +279,13 @@ static void draw_player(void) /* 3 */ static float *player_get_pos(void) { - return player.rb.co; + return player.phys.rb.co; } static void player_kill(void) { player.is_dead = 1; - player_ragdoll_copy_model( player.rb.v ); + player_ragdoll_copy_model( player.phys.rb.v ); } static float *player_cam_pos(void) diff --git a/player_animation.h b/player_animation.h index 101bd22..33dc3bf 100644 --- a/player_animation.h +++ b/player_animation.h @@ -5,6 +5,8 @@ static void player_animate_offboard(void) { + struct player_phys *phys = &player.phys; + mdl_keyframe apose[32], bpose[32]; struct skeleton *sk = &player.mdl.sk; @@ -36,7 +38,7 @@ static void player_animate_offboard(void) v4f rot; q_axis_angle( rot, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] - VG_PIf*0.5f ); q_m3x3( rot, mtx ); - v3_copy( player.rb.to_world[3], mtx[3] ); + v3_copy( phys->rb.to_world[3], mtx[3] ); skeleton_apply_transform( &player.mdl.sk, mtx ); skeleton_debug( &player.mdl.sk ); @@ -44,37 +46,39 @@ static void player_animate_offboard(void) static void player_animate(void) { - if( !player.on_board ) + struct player_phys *phys = &player.phys; + + if( !phys->on_board ) { player_animate_offboard(); return; } /* Camera position */ - v3_sub( player.rb.v, player.v_last, player.a ); - v3_copy( player.rb.v, player.v_last ); + v3_sub( phys->rb.v, phys->v_last, phys->a ); + v3_copy( phys->rb.v, phys->v_last ); - v3_add( player.m, player.a, player.m ); - v3_lerp( player.m, (v3f){0.0f,0.0f,0.0f}, 0.1f, player.m ); + v3_add( phys->m, phys->a, phys->m ); + v3_lerp( phys->m, (v3f){0.0f,0.0f,0.0f}, 0.1f, phys->m ); - player.m[0] = vg_clampf( player.m[0], -2.0f, 2.0f ); - player.m[1] = vg_clampf( player.m[1], -2.0f, 2.0f ); - player.m[2] = vg_clampf( player.m[2], -2.0f, 2.0f ); - v3_lerp( player.bob, player.m, 0.2f, player.bob ); + phys->m[0] = vg_clampf( phys->m[0], -2.0f, 2.0f ); + phys->m[1] = vg_clampf( phys->m[1], -2.0f, 2.0f ); + phys->m[2] = vg_clampf( phys->m[2], -2.0f, 2.0f ); + v3_lerp( phys->bob, phys->m, 0.2f, phys->bob ); /* Head */ - float lslip = fabsf(player.slip); + float lslip = fabsf(phys->slip); float kheight = 2.0f, kleg = 0.6f; v3f offset; v3_zero( offset ); - m3x3_mulv( player.rb.to_local, player.bob, offset ); + m3x3_mulv( phys->rb.to_local, phys->bob, offset ); static float speed_wobble = 0.0f, speed_wobble_2 = 0.0f; - float kickspeed = vg_clampf(v3_length(player.rb.v)*(1.0f/40.0f), 0.0f, 1.0f); + float kickspeed = vg_clampf(v3_length(phys->rb.v)*(1.0f/40.0f), 0.0f, 1.0f); float kicks = (vg_randf()-0.5f)*2.0f*kickspeed; float sign = vg_signf( kicks ); speed_wobble = vg_lerpf( speed_wobble, kicks*kicks*sign, 0.1f ); @@ -95,7 +99,7 @@ static void player_animate(void) */ /* scalar blending information */ - float speed = v3_length( player.rb.v ); + float speed = v3_length( phys->rb.v ); /* sliding */ { @@ -105,9 +109,9 @@ static void player_animate(void) /* movement information */ { - float dirz = player.reverse > 0.0f? 0.0f: 1.0f, - dirx = player.slip < 0.0f? 0.0f: 1.0f, - fly = player.in_air? 1.0f: 0.0f; + float dirz = phys->reverse > 0.0f? 0.0f: 1.0f, + dirx = phys->slip < 0.0f? 0.0f: 1.0f, + fly = phys->in_air? 1.0f: 0.0f; player.fdirz = vg_lerpf( player.fdirz, dirz, 0.04f ); player.fdirx = vg_lerpf( player.fdirx, dirx, 0.01f ); @@ -140,7 +144,7 @@ static void player_animate(void) player.fpush = vg_lerpf( player.fpush, player.pushing, 0.1f ); float pt = player.push_time; - if( player.reverse > 0.0f ) + if( phys->reverse > 0.0f ) skeleton_sample_anim( sk, player.mdl.anim_push, pt, bpose ); else skeleton_sample_anim( sk, player.mdl.anim_push_reverse, pt, bpose ); @@ -149,14 +153,17 @@ static void player_animate(void) /* trick setup */ float jump_start_frame = 14.0f/30.0f; - float setup_frame = player.jump * jump_start_frame, - setup_blend = vg_minf( player.jump*5.0f, 1.0f ); + + player.fjump = vg_lerpf( player.fjump, phys->jump, 0.08f ); + + float setup_frame = phys->jump * jump_start_frame, + setup_blend = vg_minf( player.fjump, 1.0f ); float jump_frame = (vg_time - player.jump_time) + jump_start_frame; if( jump_frame >= jump_start_frame && jump_frame <= (40.0f/30.0f) ) setup_frame = jump_frame; - struct skeleton_anim *jump_anim = player.jump_dir? + struct skeleton_anim *jump_anim = phys->jump_dir? player.mdl.anim_ollie: player.mdl.anim_ollie_reverse; @@ -182,25 +189,28 @@ static void player_animate(void) grab_frame = ang_unit * (15.0f/30.0f); skeleton_sample_anim( sk, player.mdl.anim_grabs, grab_frame, bpose ); - skeleton_lerp_pose( sk, apose, bpose, player.grab, air_pose ); + skeleton_lerp_pose( sk, apose, bpose, phys->grab, air_pose ); } skeleton_lerp_pose( sk, ground_pose, air_pose, player.ffly, apose ); - float add_grab_mod = 1.0f - player.ffly*player.grab; + float add_grab_mod = 1.0f - player.ffly*phys->grab; /* additive effects */ - apose[player.mdl.id_hip-1].co[0] += offset[0]*add_grab_mod; - apose[player.mdl.id_hip-1].co[2] += offset[2]*add_grab_mod; - apose[player.mdl.id_ik_hand_l-1].co[0] += offset[0]*add_grab_mod; - apose[player.mdl.id_ik_hand_l-1].co[2] += offset[2]*add_grab_mod; - apose[player.mdl.id_ik_hand_r-1].co[0] += offset[0]*add_grab_mod; - apose[player.mdl.id_ik_hand_r-1].co[2] += offset[2]*add_grab_mod; - apose[player.mdl.id_ik_elbow_l-1].co[0] += offset[0]*add_grab_mod; - apose[player.mdl.id_ik_elbow_l-1].co[2] += offset[2]*add_grab_mod; - apose[player.mdl.id_ik_elbow_r-1].co[0] += offset[0]*add_grab_mod; - apose[player.mdl.id_ik_elbow_r-1].co[2] += offset[2]*add_grab_mod; - + { + u32 apply_to[] = { player.mdl.id_hip, + player.mdl.id_ik_hand_l, + player.mdl.id_ik_hand_r, + player.mdl.id_ik_elbow_l, + player.mdl.id_ik_elbow_r }; + + for( int i=0; irb.to_world ); skeleton_debug( &player.mdl.sk ); } @@ -248,24 +258,26 @@ static void player_animate_death_cam(void) static void player_animate_camera(void) { + struct player_phys *phys = &player.phys; + static v3f lerp_cam = {0.0f,0.0f,0.0f}; v3f cam_pos; - player.fonboard = vg_lerpf(player.fonboard, player.on_board, ktimestep*1.0f); + player.fonboard = vg_lerpf(player.fonboard, phys->on_board, ktimestep*1.0f); - if( player.on_board ) + if( phys->on_board ) { v3f offs = { -0.4f, 0.15f, 0.0f }; v3_lerp( lerp_cam, player.mdl.cam_pos, 0.8f, lerp_cam ); v3_add( lerp_cam, offs, cam_pos ); /* Look angles */ - v3_lerp( player.vl, player.rb.v, 0.05f, player.vl ); + v3_lerp( phys->vl, phys->rb.v, 0.05f, phys->vl ); - float yaw = atan2f( player.vl[0], -player.vl[2] ), - pitch = atan2f( -player.vl[1], + float yaw = atan2f( phys->vl[0], -phys->vl[2] ), + pitch = atan2f( -phys->vl[1], sqrtf( - player.vl[0]*player.vl[0] + player.vl[2]*player.vl[2] + phys->vl[0]*phys->vl[0] + phys->vl[2]*phys->vl[2] )) * 0.7f; player.angles[0] = yaw; @@ -275,14 +287,14 @@ static void player_animate_camera(void) /* Camera shake */ static v2f shake_damp = {0.0f,0.0f}; v2f shake = { vg_randf()-0.5f, vg_randf()-0.5f }; - v2_muls( shake, v3_length(player.rb.v)*0.3f - * (1.0f+fabsf(player.slip)), shake); + v2_muls( shake, v3_length(phys->rb.v)*0.3f + * (1.0f+fabsf(phys->slip)), shake); v2_lerp( shake_damp, shake, 0.01f, shake_damp ); shake_damp[0] *= 0.2f; v2_muladds( player.angles, shake_damp, 0.1f, player.angles ); - m4x3_mulv( player.rb.to_world, cam_pos, player.camera_pos ); + m4x3_mulv( phys->rb.to_world, cam_pos, player.camera_pos ); } else { @@ -303,11 +315,11 @@ static void player_animate_camera(void) q_axis_angle( rot, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] -VG_PIf*0.5f ); q_m3x3( rot, mtx ); - v3_copy( player.rb.to_world[3], mtx[3] ); + v3_copy( phys->rb.to_world[3], mtx[3] ); m4x3_mulv( mtx, player.mdl.cam_pos, cam_pos ); v3_add( cam_pos, forward_dir, player.camera_pos ); - v3_lerp( player.vl, player.rb.v, 0.3f, player.vl ); + v3_lerp( phys->vl, phys->rb.v, 0.3f, phys->vl ); } } diff --git a/player_audio.h b/player_audio.h index 01c13fc..b5ba735 100644 --- a/player_audio.h +++ b/player_audio.h @@ -8,6 +8,8 @@ */ static void player_audio(void) { + struct player_phys *phys = &player.phys; + static int _ding = 0; int last = _ding; @@ -20,7 +22,7 @@ static void player_audio(void) static int _air = 0; int l2 = _air; - _air = player.in_air; + _air = phys->in_air; static double last_revert = -2000.0; @@ -30,10 +32,10 @@ static void player_audio(void) audio_lock(); double revert_delta = vg_time - last_revert; - if( player.on_board && (!_air && l2) && (fabsf(player.slip) > 0.5f) && + if( phys->on_board && (!_air && l2) && (fabsf(phys->slip) > 0.5f) && (revert_delta > 0.7) ) { - audio_player_set_position( &audio_player_extra, player.rb.co ); + audio_player_set_position( &audio_player_extra, phys->rb.co ); audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D ); audio_player_set_vol( &audio_player_extra, 2.0f ); audio_player_playclip( &audio_player_extra, &audio_lands[rand()%5] ); @@ -42,24 +44,24 @@ static void player_audio(void) } static float air = 0.0f; - air = vg_lerpf(air, player.in_air? 1.0f: 0.0f, 5.0f*ktimestep); + air = vg_lerpf(air, phys->in_air? 1.0f: 0.0f, 5.0f*ktimestep); /* Spacial info */ v3f ears = { 1.0f,0.0f,0.0f }; v3f delta; float *cam = player.camera[3], - *pos = player.rb.co; + *pos = phys->rb.co; if( trigger_ding ) audio_player_playclip( &audio_player_extra, &audio_ding ); - audio_player_set_position( &audio_player0, player.rb.co ); - audio_player_set_position( &audio_player1, player.rb.co ); - audio_player_set_position( &audio_player2, player.rb.co ); + audio_player_set_position( &audio_player0, phys->rb.co ); + audio_player_set_position( &audio_player1, phys->rb.co ); + audio_player_set_position( &audio_player2, phys->rb.co ); audio_player_set_position( &audio_player_gate, world.render_gate_pos ); - v3_sub( player.rb.co, player.camera[3], delta ); + v3_sub( phys->rb.co, player.camera[3], delta ); v3_normalize( delta ); m3x3_mulv( player.camera, ears, ears ); @@ -84,7 +86,7 @@ static void player_audio(void) { v3f waterpos; enum audio_sprite_type sprite_type = - audio_sample_sprite_random( player.rb.co, waterpos ); + audio_sample_sprite_random( phys->rb.co, waterpos ); if( sprite_type != k_audio_sprite_type_none ) { @@ -105,7 +107,7 @@ static void player_audio(void) } } - if( freecam || player.is_dead || !player.on_board ) + if( freecam || player.is_dead || !phys->on_board ) { audio_player_set_vol( &audio_player0, 0.0f ); audio_player_set_vol( &audio_player1, 0.0f ); @@ -117,10 +119,10 @@ static void player_audio(void) else walk_phase = 0; - if( (player.step_phase != walk_phase) && !player.in_air ) + if( (player.step_phase != walk_phase) && !phys->in_air ) { audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D ); - audio_player_set_position( &audio_player_extra, player.rb.co ); + audio_player_set_position( &audio_player_extra, phys->rb.co ); audio_player_set_vol( &audio_player_extra, 6.0f ); audio_player_playclip( &audio_player_extra, &audio_footsteps[rand()%4] ); @@ -131,9 +133,9 @@ static void player_audio(void) else { /* Composite */ - float speed = vg_minf(v3_length( player.rb.v )*0.1f,1.0f), + float speed = vg_minf(v3_length( phys->rb.v )*0.1f,1.0f), attn = speed, - slide = vg_clampf( fabsf(player.slip), 0.0f, 1.0f ), + slide = vg_clampf( fabsf(phys->slip), 0.0f, 1.0f ), vol0 = (1.0f-air)*attn*(1.0f-slide), vol1 = air *attn, vol2 = (1.0f-air)*attn*slide; diff --git a/player_physics.h b/player_physics.h index baaa70e..f9584a2 100644 --- a/player_physics.h +++ b/player_physics.h @@ -24,29 +24,31 @@ static void apply_gravity( v3f vel, float const timestep ) */ static void player_start_air(void) { - if( player.in_air ) + struct player_phys *phys = &player.phys; + + if( phys->in_air ) return; - player.in_air = 1; + phys->in_air = 1; float pstep = ktimestep*10.0f; float best_velocity_delta = -9999.9f; float k_bias = 0.96f; v3f axis; - v3_cross( player.rb.up, player.rb.v, axis ); + v3_cross( phys->rb.up, phys->rb.v, axis ); v3_normalize( axis ); player.land_log_count = 0; - m3x3_identity( player.vr ); + m3x3_identity( phys->vr ); for( int m=-3;m<=12; m++ ) { float vmod = ((float)m / 15.0f)*0.09f; v3f pco, pco1, pv; - v3_copy( player.rb.co, pco ); - v3_muls( player.rb.v, k_bias, pv ); + v3_copy( phys->rb.co, pco ); + v3_muls( phys->rb.v, k_bias, pv ); /* * Try different 'rotations' of the velocity to find the best possible @@ -96,9 +98,9 @@ static void player_start_air(void) v3_copy( contact.pos, player.land_target ); - m3x3_copy( vr, player.vr_pstep ); + m3x3_copy( vr, phys->vr_pstep ); q_axis_angle( vr_q, axis, vmod*0.1f ); - q_m3x3( vr_q, player.vr ); + q_m3x3( vr_q, phys->vr ); } v3_copy( contact.pos, @@ -119,13 +121,15 @@ static void player_start_air(void) */ static void player_physics_control(void) { + struct player_phys *phys = &player.phys; + /* * Computing localized friction forces for controlling the character * Friction across X is significantly more than Z */ v3f vel; - m3x3_mulv( player.rb.to_local, player.rb.v, vel ); + m3x3_mulv( phys->rb.to_local, phys->rb.v, vel ); float slip = 0.0f; if( fabsf(vel[2]) > 0.01f ) @@ -133,8 +137,8 @@ static void player_physics_control(void) if( fabsf( slip ) > 1.2f ) slip = vg_signf( slip ) * 1.2f; - player.slip = slip; - player.reverse = -vg_signf(vel[2]); + phys->slip = slip; + phys->reverse = -vg_signf(vel[2]); float substep = ktimestep * 0.2f; float fwd_resistance = (vg_get_button( "break" )? 5.0f: 0.02f) * -substep; @@ -152,12 +156,12 @@ static void player_physics_control(void) if( vg_get_button( "jump" ) ) { - player.jump += ktimestep * k_jump_charge_speed; + phys->jump += ktimestep * k_jump_charge_speed; - if( !player.jump_charge ) - player.jump_dir = player.reverse > 0.0f? 1: 0; + if( !phys->jump_charge ) + phys->jump_dir = phys->reverse > 0.0f? 1: 0; - player.jump_charge = 1; + phys->jump_charge = 1; } if( !vg_get_button("break") && vg_get_button( "push" ) ) @@ -171,29 +175,26 @@ static void player_physics_control(void) new_vel = vg_minf( current + amt, k_max_push_speed ); new_vel -= vg_minf(current, k_max_push_speed); - vel[2] -= new_vel * player.reverse; + vel[2] -= new_vel * phys->reverse; } /* Pumping */ static float previous = 0.0f; - float delta = previous - player.grab, + float delta = previous - phys->grab, pump = delta * k_pump_force*ktimestep; - previous = player.grab; + previous = phys->grab; v3f p1; - v3_muladds( player.rb.co, player.rb.up, pump, p1 ); - vg_line( player.rb.co, p1, 0xff0000ff ); + v3_muladds( phys->rb.co, phys->rb.up, pump, p1 ); + vg_line( phys->rb.co, p1, 0xff0000ff ); vel[1] += pump; - m3x3_mulv( player.rb.to_world, vel, player.rb.v ); + m3x3_mulv( phys->rb.to_world, vel, phys->rb.v ); float steer = vg_get_axis( "horizontal" ); - player.iY -= vg_signf(steer)*powf(steer,2.0f) * k_steer_ground * ktimestep; - - v2_lerp( player.board_xy, (v2f){ slip*0.25f, 0.0f }, - ktimestep*5.0f, player.board_xy); + phys->iY -= vg_signf(steer)*powf(steer,2.0f) * k_steer_ground * ktimestep; } /* @@ -201,7 +202,9 @@ static void player_physics_control(void) */ static void player_physics_control_air(void) { - m3x3_mulv( player.vr, player.rb.v, player.rb.v ); + struct player_phys *phys = &player.phys; + + m3x3_mulv( phys->vr, phys->rb.v, phys->rb.v ); vg_line_cross( player.land_target, 0xff0000ff, 0.25f ); ray_hit hit; @@ -212,8 +215,8 @@ static void player_physics_control_air(void) float pstep = ktimestep*10.0f; v3f pco, pco1, pv; - v3_copy( player.rb.co, pco ); - v3_copy( player.rb.v, pv ); + v3_copy( phys->rb.co, pco ); + v3_copy( phys->rb.v, pv ); float time_to_impact = 0.0f; float limiter = 1.0f; @@ -221,7 +224,7 @@ static void player_physics_control_air(void) for( int i=0; i<50; i++ ) { v3_copy( pco, pco1 ); - m3x3_mulv( player.vr_pstep, pv, pv ); + m3x3_mulv( phys->vr_pstep, pv, pv ); apply_gravity( pv, pstep ); v3_muladds( pco, pv, pstep, pco ); @@ -235,9 +238,9 @@ static void player_physics_control_air(void) float orig_dist = contact.dist; if( ray_world( pco1, vdir, &contact )) { - float angle = v3_dot( player.rb.up, contact.normal ); + float angle = v3_dot( phys->rb.up, contact.normal ); v3f axis; - v3_cross( player.rb.up, contact.normal, axis ); + v3_cross( phys->rb.up, contact.normal, axis ); time_to_impact += (contact.dist/orig_dist)*pstep; limiter = vg_minf( 5.0f, time_to_impact )/5.0f; @@ -249,7 +252,7 @@ static void player_physics_control_air(void) { v4f correction; q_axis_angle( correction, axis, acosf(angle)*0.05f*(1.0f-limiter) ); - q_mul( correction, player.rb.q, player.rb.q ); + q_mul( correction, phys->rb.q, phys->rb.q ); } vg_line_cross( contact.pos, 0xffff0000, 0.25f ); @@ -258,23 +261,22 @@ static void player_physics_control_air(void) time_to_impact += pstep; } - player.iY -= vg_get_axis( "horizontal" ) * k_steer_air * ktimestep; + phys->iY -= vg_get_axis( "horizontal" ) * k_steer_air * ktimestep; { float iX = vg_get_axis( "vertical" ) * - player.reverse * k_steer_air * limiter * ktimestep; + phys->reverse * k_steer_air * limiter * ktimestep; static float siX = 0.0f; siX = vg_lerpf( siX, iX, k_steer_air_lerp ); v4f rotate; - q_axis_angle( rotate, player.rb.right, siX ); - q_mul( rotate, player.rb.q, player.rb.q ); + q_axis_angle( rotate, phys->rb.right, siX ); + q_mul( rotate, phys->rb.q, phys->rb.q ); } v2f target = {0.0f,0.0f}; v2_muladds( target, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") }, - player.grab, target ); - v2_lerp( player.board_xy, target, ktimestep*3.0f, player.board_xy ); + phys->grab, target ); } /* @@ -283,18 +285,19 @@ static void player_physics_control_air(void) */ static void player_walk_physics(void) { + struct player_phys *phys = &player.phys; rigidbody *rbf = &player.collide_front, *rbb = &player.collide_back; - m3x3_copy( player.rb.to_world, player.collide_front.to_world ); - m3x3_copy( player.rb.to_world, player.collide_back.to_world ); + m3x3_copy( phys->rb.to_world, player.collide_front.to_world ); + m3x3_copy( phys->rb.to_world, player.collide_back.to_world ); float h0 = 0.3f, h1 = 0.9f; - m4x3_mulv( player.rb.to_world, (v3f){0.0f,h0,0.0f}, rbf->co ); + m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h0,0.0f}, rbf->co ); v3_copy( rbf->co, rbf->to_world[3] ); - m4x3_mulv( player.rb.to_world, (v3f){0.0f,h1,0.0f}, rbb->co ); + m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h1,0.0f}, rbb->co ); v3_copy( rbb->co, rbb->to_world[3] ); m4x3_invert_affine( rbf->to_world, rbf->to_local ); @@ -321,7 +324,7 @@ static void player_walk_physics(void) struct contact *ct = &manifold[i]; /*normal */ - float vn = -v3_dot( player.rb.v, ct->n ); + float vn = -v3_dot( phys->rb.v, ct->n ); vn += ct->bias; float temp = ct->norm_impulse; @@ -331,34 +334,34 @@ static void player_walk_physics(void) v3f impulse; v3_muls( ct->n, vn, impulse ); - v3_add( impulse, player.rb.v, player.rb.v ); + v3_add( impulse, phys->rb.v, phys->rb.v ); /* friction */ for( int j=0; j<2; j++ ) { float f = k_friction * ct->norm_impulse, - vt = v3_dot( player.rb.v, ct->t[j] ), + vt = v3_dot( phys->rb.v, ct->t[j] ), lambda = -vt; float temp = ct->tangent_impulse[j]; ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f ); lambda = ct->tangent_impulse[j] - temp; - v3_muladds( player.rb.v, ct->t[j], lambda, player.rb.v ); + v3_muladds( phys->rb.v, ct->t[j], lambda, phys->rb.v ); } } } - player.in_air = len==0?1:0; + phys->in_air = len==0?1:0; - v3_zero( player.rb.w ); - q_axis_angle( player.rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] ); + v3_zero( phys->rb.w ); + q_axis_angle( phys->rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] ); v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) }; v3f p1; - v3_muladds( player.rb.co, forward_dir, 2.0f, p1 ); - vg_line( player.rb.co, p1, 0xff0000ff ); + v3_muladds( phys->rb.co, forward_dir, 2.0f, p1 ); + vg_line( phys->rb.co, p1, 0xff0000ff ); float move_dead = 0.1f, move = vg_get_axis("grabr")*0.5f + 0.5f - move_dead; @@ -368,11 +371,11 @@ static void player_walk_physics(void) float move_norm = move * (1.0f/(1.0f-move_dead)), speed = vg_lerpf( 0.1f*k_runspeed, k_runspeed, move_norm ), amt = k_walk_accel * ktimestep, - zvel = v3_dot( player.rb.v, forward_dir ), + zvel = v3_dot( phys->rb.v, forward_dir ), new_vel = vg_minf( zvel + amt, speed ), diff = new_vel - vg_minf( zvel, speed ); - v3_muladds( player.rb.v, forward_dir, diff, player.rb.v ); + v3_muladds( phys->rb.v, forward_dir, diff, phys->rb.v ); /* TODO move */ float walk_norm = 30.0f/(float)player.mdl.anim_walk->length, @@ -385,8 +388,8 @@ static void player_walk_physics(void) player.walk_timer = 0.0f; } - player.rb.v[0] *= 1.0f - (ktimestep*k_walk_friction); - player.rb.v[2] *= 1.0f - (ktimestep*k_walk_friction); + phys->rb.v[0] *= 1.0f - (ktimestep*k_walk_friction); + phys->rb.v[2] *= 1.0f - (ktimestep*k_walk_friction); } /* @@ -394,6 +397,7 @@ static void player_walk_physics(void) */ static void player_physics(void) { + struct player_phys *phys = &player.phys; /* * Update collision fronts */ @@ -401,15 +405,15 @@ static void player_physics(void) rigidbody *rbf = &player.collide_front, *rbb = &player.collide_back; - m3x3_copy( player.rb.to_world, player.collide_front.to_world ); - m3x3_copy( player.rb.to_world, player.collide_back.to_world ); + m3x3_copy( phys->rb.to_world, player.collide_front.to_world ); + m3x3_copy( phys->rb.to_world, player.collide_back.to_world ); - player.air_blend = vg_lerpf( player.air_blend, player.in_air, 0.1f ); + player.air_blend = vg_lerpf( player.air_blend, phys->in_air, 0.1f ); float h = player.air_blend*0.2f; - m4x3_mulv( player.rb.to_world, (v3f){0.0f,h,-k_board_length}, rbf->co ); + m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h,-k_board_length}, rbf->co ); v3_copy( rbf->co, rbf->to_world[3] ); - m4x3_mulv( player.rb.to_world, (v3f){0.0f,h, k_board_length}, rbb->co ); + m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h, k_board_length}, rbb->co ); v3_copy( rbb->co, rbb->to_world[3] ); m4x3_invert_affine( rbf->to_world, rbf->to_local ); @@ -443,12 +447,12 @@ static void player_physics(void) v3_normalize( surface_avg ); - if( v3_dot( player.rb.v, surface_avg ) > 0.5f ) + if( v3_dot( phys->rb.v, surface_avg ) > 0.5f ) { player_start_air(); } else - player.in_air = 0; + phys->in_air = 0; } for( int j=0; j<5; j++ ) @@ -458,9 +462,9 @@ static void player_physics(void) struct contact *ct = &manifold[i]; v3f dv, delta; - v3_sub( ct->co, player.rb.co, delta ); - v3_cross( player.rb.w, delta, dv ); - v3_add( player.rb.v, dv, dv ); + v3_sub( ct->co, phys->rb.co, delta ); + v3_cross( phys->rb.w, delta, dv ); + v3_add( phys->rb.v, dv, dv ); float vn = -v3_dot( dv, ct->n ); vn += ct->bias; @@ -472,14 +476,14 @@ static void player_physics(void) v3f impulse; v3_muls( ct->n, vn, impulse ); - if( fabsf(v3_dot( impulse, player.rb.forward )) > 10.0f || - fabsf(v3_dot( impulse, player.rb.up )) > 50.0f ) + if( fabsf(v3_dot( impulse, phys->rb.forward )) > 10.0f || + fabsf(v3_dot( impulse, phys->rb.up )) > 50.0f ) { player_kill(); return; } - v3_add( impulse, player.rb.v, player.rb.v ); + v3_add( impulse, phys->rb.v, phys->rb.v ); v3_cross( delta, impulse, impulse ); /* @@ -490,23 +494,23 @@ static void player_physics(void) * components. */ - float wy = v3_dot( player.rb.up, impulse ), - wx = v3_dot( player.rb.right, impulse )*1.5f; + float wy = v3_dot( phys->rb.up, impulse ), + wx = v3_dot( phys->rb.right, impulse )*1.5f; - v3_muladds( player.rb.w, player.rb.up, wy, player.rb.w ); - v3_muladds( player.rb.w, player.rb.right, wx, player.rb.w ); + v3_muladds( phys->rb.w, phys->rb.up, wy, phys->rb.w ); + v3_muladds( phys->rb.w, phys->rb.right, wx, phys->rb.w ); } } float grabt = vg_get_axis( "grabr" )*0.5f+0.5f; - player.grab = vg_lerpf( player.grab, grabt, 0.14f ); + phys->grab = vg_lerpf( phys->grab, grabt, 0.14f ); player.pushing = 0.0f; - if( !player.in_air ) + if( !phys->in_air ) { v3f axis; - float angle = v3_dot( player.rb.up, surface_avg ); - v3_cross( player.rb.up, surface_avg, axis ); + float angle = v3_dot( phys->rb.up, surface_avg ); + v3_cross( phys->rb.up, surface_avg, axis ); //float cz = v3_dot( player.rb.forward, axis ); //v3_muls( player.rb.forward, cz, axis ); @@ -515,38 +519,38 @@ static void player_physics(void) { v4f correction; q_axis_angle( correction, axis, acosf(angle)*0.3f ); - q_mul( correction, player.rb.q, player.rb.q ); + q_mul( correction, phys->rb.q, phys->rb.q ); } - v3_muladds( player.rb.v, player.rb.up, - -k_downforce*ktimestep, player.rb.v ); + v3_muladds( phys->rb.v, phys->rb.up, + -k_downforce*ktimestep, phys->rb.v ); player_physics_control(); - if( !player.jump_charge && player.jump > 0.2f ) + if( !phys->jump_charge && phys->jump > 0.2f ) { v3f jumpdir; /* Launch more up if alignment is up else improve velocity */ - float aup = fabsf(v3_dot( (v3f){0.0f,1.0f,0.0f}, player.rb.up )), + float aup = fabsf(v3_dot( (v3f){0.0f,1.0f,0.0f}, phys->rb.up )), mod = 0.5f, dir = mod + aup*(1.0f-mod); - v3_copy( player.rb.v, jumpdir ); + v3_copy( phys->rb.v, jumpdir ); v3_normalize( jumpdir ); v3_muls( jumpdir, 1.0f-dir, jumpdir ); - v3_muladds( jumpdir, player.rb.up, dir, jumpdir ); + v3_muladds( jumpdir, phys->rb.up, dir, jumpdir ); v3_normalize( jumpdir ); - float force = k_jump_force*player.jump; - v3_muladds( player.rb.v, jumpdir, force, player.rb.v ); - player.jump = 0.0f; + float force = k_jump_force*phys->jump; + v3_muladds( phys->rb.v, jumpdir, force, phys->rb.v ); + phys->jump = 0.0f; player.jump_time = vg_time; audio_lock(); audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D ); - audio_player_set_position( &audio_player_extra, player.rb.co ); + audio_player_set_position( &audio_player_extra, phys->rb.co ); audio_player_set_vol( &audio_player_extra, 20.0f ); audio_player_playclip( &audio_player_extra, &audio_jumps[rand()%4] ); audio_unlock(); @@ -557,55 +561,67 @@ static void player_physics(void) player_physics_control_air(); } - if( !player.jump_charge ) + if( !phys->jump_charge ) { - player.jump -= k_jump_charge_speed * ktimestep; + phys->jump -= k_jump_charge_speed * ktimestep; } - player.jump_charge = 0; - player.jump = vg_clampf( player.jump, 0.0f, 1.0f ); + phys->jump_charge = 0; + phys->jump = vg_clampf( phys->jump, 0.0f, 1.0f ); +} + +static void player_save_frame(void) +{ + player.phys_gate_frame = player.phys; +} + +static void player_restore_frame(void) +{ + player.phys = player.phys_gate_frame; + rb_update_transform( &player.phys.rb ); } static void player_do_motion(void) { + struct player_phys *phys = &player.phys; + float horizontal = vg_get_axis("horizontal"), vertical = vg_get_axis("vertical"); - if( player.on_board ) + if( phys->on_board ) player_physics(); else player_walk_physics(); /* Integrate velocity */ v3f prevco; - v3_copy( player.rb.co, prevco ); + v3_copy( phys->rb.co, prevco ); - apply_gravity( player.rb.v, ktimestep ); - v3_muladds( player.rb.co, player.rb.v, ktimestep, player.rb.co ); + apply_gravity( phys->rb.v, ktimestep ); + v3_muladds( phys->rb.co, phys->rb.v, ktimestep, phys->rb.co ); /* Real angular velocity integration */ - v3_lerp( player.rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f, player.rb.w ); - if( v3_length2( player.rb.w ) > 0.0f ) + v3_lerp( phys->rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f, phys->rb.w ); + if( v3_length2( phys->rb.w ) > 0.0f ) { v4f rotation; v3f axis; - v3_copy( player.rb.w, axis ); + v3_copy( phys->rb.w, axis ); float mag = v3_length( axis ); v3_divs( axis, mag, axis ); q_axis_angle( rotation, axis, mag*k_rb_delta ); - q_mul( rotation, player.rb.q, player.rb.q ); + q_mul( rotation, phys->rb.q, phys->rb.q ); } /* Faux angular velocity */ v4f rotate; - static float siY = 0.0f; - float lerpq = player.in_air? 0.04f: 0.3f; - siY = vg_lerpf( siY, player.iY, lerpq ); + float lerpq = phys->in_air? 0.04f: 0.3f; + phys->siY = vg_lerpf( phys->siY, phys->iY, lerpq ); - q_axis_angle( rotate, player.rb.up, siY ); - q_mul( rotate, player.rb.q, player.rb.q ); - player.iY = 0.0f; + q_axis_angle( rotate, phys->rb.up, phys->siY ); + q_mul( rotate, phys->rb.q, phys->rb.q ); + phys->iY = 0.0f; /* * Gate intersection, by tracing a line over the gate planes @@ -615,25 +631,22 @@ static void player_do_motion(void) struct route_gate *rg = &world.routes.gates[i]; teleport_gate *gate = &rg->gate; - if( gate_intersect( gate, player.rb.co, prevco ) ) + if( gate_intersect( gate, phys->rb.co, prevco ) ) { - m4x3_mulv( gate->transport, player.rb.co, player.rb.co ); - m3x3_mulv( gate->transport, player.rb.v, player.rb.v ); - m3x3_mulv( gate->transport, player.vl, player.vl ); - m3x3_mulv( gate->transport, player.v_last, player.v_last ); - m3x3_mulv( gate->transport, player.m, player.m ); - m3x3_mulv( gate->transport, player.bob, player.bob ); + m4x3_mulv( gate->transport, phys->rb.co, phys->rb.co ); + m3x3_mulv( gate->transport, phys->rb.v, phys->rb.v ); + m3x3_mulv( gate->transport, phys->vl, phys->vl ); + m3x3_mulv( gate->transport, phys->v_last, phys->v_last ); + m3x3_mulv( gate->transport, phys->m, phys->m ); + m3x3_mulv( gate->transport, phys->bob, phys->bob ); v4f transport_rotation; m3x3_q( gate->transport, transport_rotation ); - q_mul( transport_rotation, player.rb.q, player.rb.q ); + q_mul( transport_rotation, phys->rb.q, phys->rb.q ); world_routes_activate_gate( i ); - player.rb_gate_frame = player.rb; - player.in_air_frame = player.in_air; - player.on_board_frame = player.on_board; - if( !player.on_board ) + if( !phys->on_board ) { v3f fwd_dir = {cosf(player.angles[0]), 0.0f, @@ -643,8 +656,7 @@ static void player_do_motion(void) player.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] ); } - m3x3_copy( player.vr, player.gate_vr_frame ); - m3x3_copy( player.vr_pstep, player.gate_vr_pstep_frame ); + player_save_frame(); audio_lock(); audio_play_oneshot( &audio_gate_lap, 1.0f ); @@ -653,7 +665,7 @@ static void player_do_motion(void) } } - rb_update_transform( &player.rb ); + rb_update_transform( &phys->rb ); } /* @@ -728,6 +740,7 @@ static void player_camera_update(void) static int reset_player( int argc, char const *argv[] ) { + struct player_phys *phys = &player.phys; struct respawn_point *rp = NULL, *r; if( argc == 1 ) @@ -753,7 +766,7 @@ static int reset_player( int argc, char const *argv[] ) for( int i=0; ico, player.rb.co ); + float d = v3_dist2( r->co, phys->rb.co ); vg_info( "Dist %s : %f\n", r->name, d ); if( d < min_dist ) @@ -773,26 +786,23 @@ static int reset_player( int argc, char const *argv[] ) rp = &world.spawns[0]; } - v4_copy( rp->q, player.rb.q ); - v3_copy( rp->co, player.rb.co ); - - player.vswitch = 1.0f; - player.slip_last = 0.0f; player.is_dead = 0; - player.in_air = 1; - m3x3_identity( player.vr ); + + v4_copy( rp->q, phys->rb.q ); + v3_copy( rp->co, phys->rb.co ); + v3_zero( phys->rb.v ); + + phys->vswitch = 1.0f; + phys->slip_last = 0.0f; + phys->in_air = 1; + phys->on_board = 0; + m3x3_identity( phys->vr ); player.mdl.shoes[0] = 1; player.mdl.shoes[1] = 1; - rb_update_transform( &player.rb ); - m3x3_mulv( player.rb.to_world, (v3f){ 0.0f, 0.0f, -1.2f }, player.rb.v ); - m3x3_identity( player.gate_vr_frame ); - m3x3_identity( player.gate_vr_pstep_frame ); - - player.rb_gate_frame = player.rb; - player.on_board_frame = player.on_board; - player.in_air_frame = player.in_air; + rb_update_transform( &phys->rb ); + player_save_frame(); return 1; } diff --git a/world.h b/world.h index cf721e8..007d672 100644 --- a/world.h +++ b/world.h @@ -5,10 +5,11 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); #ifndef WORLD_H #define WORLD_H +#include "network.h" +#include "network_msg.h" #include "scene.h" #include "terrain.h" #include "render.h" -#include "water.h" #include "rigidbody.h" #include "gate.h" #include "bvh.h" @@ -16,11 +17,6 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); #include "model.h" #include "traffic.h" /*TODO: -> world_traffic.h */ -#include "world_routes.h" -#include "world_sfd.h" -#include "world_audio.h" -#include "network.h" -#include "network_msg.h" #include "shaders/terrain.h" #include "shaders/sky.h" @@ -31,6 +27,10 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); #include "shaders/fscolour.h" #include "shaders/alphatest.h" +enum { k_max_ui_segments = 32 }; +enum { k_route_ui_max_verts = 2000 }; +enum { k_route_ui_max_indices = 3000 }; + static struct gworld { /* gameplay */ @@ -43,8 +43,112 @@ static struct gworld spawns[32]; u32 spawn_count; - struct subworld_routes routes; - struct subworld_sfd sfd; + struct subworld_routes + { + 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, + node_cap; + + struct route + { + u32 track_id; + v4f colour; + + u32 start; + mdl_submesh sm; + + int active; + float factive; + + double best_lap, latest_pass; /* Session */ + + struct + { + GLuint vao, vbo, ebo; + + u32 indices_head; + u32 vertex_head; + + float last_notch; + + struct route_ui_segment + { + float length; + u32 vertex_start, vertex_count, + index_start, index_count; + } + segments[k_max_ui_segments]; + + u32 segment_start, segment_count, fade_start, fade_count; + double fade_timer_start; + float xpos; + } + ui; + + m4x3f scoreboard_transform; + } + *routes; + + u32 route_count, + route_cap; + + struct route_gate + { + teleport_gate gate; + + u32 node_id; + + struct route_timing + { + u32 version; /* Incremented on every teleport */ + double time; + } + timing; + } + *gates; + + struct route_collector + { + struct route_timing timing; + } + *collectors; + + u32 gate_count, + gate_cap, + collector_count, + collector_cap; + + u32 active_gate, + current_run_version; + + scene scene_lines; + } + routes; + + struct subworld_sfd + { + scene mesh; + mdl_submesh *sm_module, *sm_card; + glmesh temp; + + struct sfd_instance + { + float *buffer; + + u32 w,h; + } + tester; + } + sfd; /* Paths */ traffic_node traffic[128]; @@ -89,51 +193,30 @@ static struct gworld } world; -static struct subworld_routes *subworld_routes(void) { return &world.routes; } -static struct subworld_sfd *subworld_sfd(void) { return &world.sfd; } - - -vg_tex2d tex_terrain_colours = { .path = "textures/gradients.qoi", - .flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST }; - -vg_tex2d tex_terrain_noise = { .path = "textures/garbage.qoi", - .flags = VG_TEXTURE_NEAREST }; - -vg_tex2d tex_alphatest = { .path = "textures/alphatest.qoi", - .flags = VG_TEXTURE_NEAREST }; - -vg_tex2d tex_graffiti = { .path = "textures/graffitibox.qoi", - .flags = VG_TEXTURE_NEAREST }; - -static void ray_world_get_tri( ray_hit *hit, v3f tri[3] ) -{ - for( int i=0; i<3; i++ ) - v3_copy( world.geo.verts[ hit->tri[i] ].co, tri[i] ); -} - -static int ray_world( v3f pos, v3f dir, ray_hit *hit ) -{ - return scene_raycast( &world.geo, pos, dir, hit ); -} - -static int ray_hit_is_terrain( ray_hit *hit ) -{ - u32 valid_start = 0, - valid_end = world.sm_terrain.vertex_count; - - return (hit->tri[0] >= valid_start) && - (hit->tri[0] < valid_end); -} - -static int ray_hit_is_ramp( ray_hit *hit ) -{ - u32 valid_start = world.sm_geo_std.vertex_start, - valid_end = world.sm_geo_vb.vertex_start; +/* + * API + */ - return (hit->tri[0] >= valid_start) && - (hit->tri[0] < valid_end); -} +static int ray_hit_is_ramp( ray_hit *hit ); +static int ray_hit_is_terrain( ray_hit *hit ); +static void ray_world_get_tri( ray_hit *hit, v3f tri[3] ); +static int ray_world( v3f pos, v3f dir, ray_hit *hit ); +/* + * Submodules + */ +#include "world_routes.h" +#include "world_sfd.h" +#include "world_audio.h" +#include "world_render.h" +#include "world_water.h" +#include "world_gen.h" + +/* + * ----------------------------------------------------------------------------- + * Events + * ----------------------------------------------------------------------------- + */ static void world_register(void) { shader_terrain_register(); @@ -145,6 +228,7 @@ static void world_register(void) world_routes_register(); world_sfd_register(); + world_water_register(); } static void world_free(void) @@ -154,373 +238,9 @@ static void world_free(void) world_sfd_free(); } -static void render_world_depth( m4x4f projection, m4x3f camera ); - -static void add_all_if_material( m4x3f transform, scene *pscene, - mdl_header *mdl, u32 id ) -{ - for( int i=0; inode_count; i++ ) - { - mdl_node *pnode = mdl_node_from_id( mdl, i ); - - for( int j=0; jsubmesh_count; j++ ) - { - mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j ); - - if( sm->material_id == id ) - { - m4x3f transform2; - mdl_node_transform( pnode, transform2 ); - m4x3_mul( transform, transform2, transform2 ); - - scene_add_submesh( pscene, mdl, sm, transform2 ); - } - } - - if( pnode->classtype == k_classtype_instance ) - { - if( pnode->sub_uid ) - { - u32 instance_id = pnode->sub_uid -1; - struct instance_cache *cache = &world.instance_cache[instance_id]; - mdl_header *mdl2 = cache->mdl; - - m4x3f transform2; - mdl_node_transform( pnode, transform2 ); - m4x3_mul( transform, transform2, transform2 ); - - add_all_if_material( transform2, pscene, mdl2, id ); - } - } - } -} - -static void world_apply_procedural_foliage(void) -{ - mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl"); - - v3f volume; - v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume ); - volume[1] = 1.0f; - - m4x3f transform; - mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" ); - mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 ); - - for( int i=0;i<100000;i++ ) - { - v3f pos; - v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos ); - pos[1] = 1000.0f; - v3_add( pos, world.geo.bbx[0], pos ); - - ray_hit hit; - hit.dist = INFINITY; - - if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit )) - { - if( (hit.normal[1] > 0.8f) && ray_hit_is_terrain(&hit) && - (hit.pos[1] > water_height()+10.0f) ) - { - v4f qsurface, qrandom; - v3f axis; - - v3_cross( (v3f){0.0f,1.0f,0.0f}, hit.normal, axis ); - - float angle = v3_dot(hit.normal,(v3f){0.0f,1.0f,0.0f}); - q_axis_angle( qsurface, axis, angle ); - q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf ); - q_mul( qsurface, qrandom, qsurface ); - q_m3x3( qsurface, transform ); - - v3_copy( hit.pos, transform[3] ); - scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform); - } - } - } - free( mfoliage ); -} - -static void world_load(void) -{ - mdl_header *mworld = mdl_load( "models/mp_dev.mdl" ); - - world.spawn_count = 0; - world.traffic_count = 0; - world.instance_cache = NULL; - - /* - * Process entities - */ - for( int i=0; inode_count; i++ ) - { - mdl_node *pnode = mdl_node_from_id( mworld, i ); - - if( pnode->classtype == k_classtype_none ) - {} - else if( pnode->classtype == k_classtype_spawn ) - { - struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ]; - - v3_copy( pnode->co, rp->co ); - v4_copy( pnode->q, rp->q ); - strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) ); - } - else if( pnode->classtype == k_classtype_water ) - { - if( wrender.enabled ) - { - vg_warn( "Multiple water surfaces in level! ('%s')\n", - mdl_pstr( mworld, pnode->pstr_name )); - continue; - } - - mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 ); - - if( sm ) - { - glmesh surf; - mdl_unpack_submesh( mworld, &surf, sm ); - water_init(); - water_set_surface( &surf, pnode->co[1] ); - } - } - else if( pnode->classtype == k_classtype_car_path ) - { - struct classtype_car_path *p = mdl_get_entdata( mworld, pnode ); - traffic_node *tn = &world.traffic[ world.traffic_count ]; - tn->mn_next = NULL; - tn->mn_next1 = NULL; - - if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target ); - if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 ); - - m4x3f transform; - mdl_node_transform( pnode, transform ); - m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h ); - v3_copy( transform[3], tn->co ); - - pnode->sub_uid = world.traffic_count ++; - } - else if( pnode->classtype == k_classtype_instance ) - { - struct classtype_instance *inst = mdl_get_entdata( mworld, pnode ); - pnode->sub_uid = 0; - - int cached = 0; - for( int i=0; ipstr_file == cache->pstr_file ) - { - cached = 1; - pnode->sub_uid = i+1; - break; - } - } - - if( !cached ) - { - world.instance_cache = buffer_reserve( - world.instance_cache, world.instance_cache_count, - &world.instance_cache_cap, 1, - sizeof(struct instance_cache) ); - - struct instance_cache *cache = - &world.instance_cache[world.instance_cache_count]; - - const char *filename = mdl_pstr(mworld, inst->pstr_file); - - cache->pstr_file = inst->pstr_file; - cache->mdl = mdl_load( filename ); - - if( cache->mdl ) - { - world.instance_cache_count ++; - pnode->sub_uid = world.instance_cache_count; - mdl_link_materials( mworld, cache->mdl ); - vg_success( "Cached %s\n", filename ); - } - else - { - vg_warn( "Failed to cache %s\n", filename ); - } - } - } - } - - world.instance_cache = buffer_fix( world.instance_cache, - world.instance_cache_count, - &world.instance_cache_cap, - sizeof( struct instance_cache ) ); - -#if 0 - traffic_finalize( world.traffic, world.traffic_count ); - for( int i=0; imaterial_count; i++ ) - { - mdl_material *mat = mdl_material_from_id( mworld, i ); - const char *mat_name = mdl_pstr( mworld, mat->pstr_name ); - - if( !strcmp( "surf", mat_name )) - mat_surf = i; - else if( !strcmp( "surf_oob", mat_name )) - mat_surf_oob = i; - else if( !strcmp( "vertex_blend", mat_name )) - mat_vertex_blend = i; - else if( !strcmp( "alphatest", mat_name )) - mat_alphatest = i; - else if( !strcmp( "graffitibox", mat_name )) - mat_graffiti = i; - else if( !strcmp( "terrain", mat_name ) ) - mat_terrain = i; - } - - m4x3f midentity; - m4x3_identity( midentity ); - - if( mat_terrain ) - add_all_if_material( midentity, &world.geo, mworld, mat_terrain ); - scene_copy_slice( &world.geo, &world.sm_terrain ); - - if( mat_surf_oob ) - add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob ); - else - vg_warn( "No OOB surface\n" ); - scene_copy_slice( &world.geo, &world.sm_geo_std_oob ); - - if( mat_surf ) - add_all_if_material( midentity, &world.geo, mworld, mat_surf ); - scene_copy_slice( &world.geo, &world.sm_geo_std ); - - if( mat_vertex_blend ) - add_all_if_material( midentity, &world.geo, mworld, mat_vertex_blend ); - scene_copy_slice( &world.geo, &world.sm_geo_vb ); - - scene_upload( &world.geo ); - scene_bh_create( &world.geo ); - - - /* Foliage /nocollide layer. - * TODO: Probably should have material traits for this - */ - scene_init( &world.foliage ); - - world_apply_procedural_foliage(); - scene_copy_slice( &world.foliage, &world.sm_foliage_main ); - - add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest ); - scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest ); - - add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti ); - scene_copy_slice( &world.foliage, &world.sm_graffiti ); - - scene_upload( &world.foliage ); - world_routes_loadfrom( mworld ); - - for( int i=0; ig_water_plane ); - - v4f bounds; - bounds[0] = world.geo.bbx[0][0]; - bounds[1] = world.geo.bbx[0][2]; - bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]); - bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]); - v4_copy( bounds, winfo->g_depth_bounds ); - - winfo->g_water_fog = 0.04f; - render_update_lighting_ub(); - - - world.mr_ball.type = k_rb_shape_sphere; - world.mr_ball.inf.sphere.radius = 2.0f; - v3_copy( (v3f){ 0.0f, 110.0f, 0.0f }, world.mr_ball.co ); - - q_identity(world.mr_ball.q); - rb_init( &world.mr_ball ); - - /* - * Setup scene collider - */ - v3_zero( world.rb_geo.co ); - q_identity( world.rb_geo.q ); - - world.rb_geo.type = k_rb_shape_scene; - world.rb_geo.inf.scene.pscene = &world.geo; - world.rb_geo.is_world = 1; - rb_init( &world.rb_geo ); -} static void world_init(void) { - vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours, - &tex_terrain_noise, - &tex_alphatest, - &tex_graffiti }, 4 ); - mdl_header *mcars = mdl_load( "models/rs_cars.mdl" ); mdl_unpack_glmesh( mcars, &world.cars ); mdl_node *nholden = mdl_node_from_name( mcars, "holden" ); @@ -540,11 +260,12 @@ static void world_init(void) /* Other systems */ + world_render_init(); world_sfd_init(); world_audio_init(); } -static void world_update(void) +static void world_update( v3f pos ) { world_routes_update(); world_routes_debug(); @@ -554,12 +275,11 @@ static void world_update(void) for( int i=0; itri[i] ].co, tri[i] ); } -static void render_world_gates( m4x4f projection, v3f playerco, m4x3f camera ) +static int ray_world( v3f pos, v3f dir, ray_hit *hit ) { - float closest = INFINITY; - int id = 0; - - for( int i=0; igate.co[0], camera[3] ); - - if( dist < closest ) - { - closest = dist; - id = i; - } - } - - render_gate( &world.routes.gates[id].gate, playerco, camera ); - v3_lerp( world.render_gate_pos, - world.routes.gates[id].gate.co[0], - 1.0f, - world.render_gate_pos ); + return scene_raycast( &world.geo, pos, dir, hit ); } -static void render_world( m4x4f projection, m4x3f camera ) +static int ray_hit_is_terrain( ray_hit *hit ) { - render_sky( camera ); - render_world_routes( projection, camera[3] ); - render_world_vb( projection, camera[3] ); - render_world_alphatest( projection, camera[3] ); - render_terrain( projection, camera[3] ); - - int closest = 0; - float min_dist = INFINITY; - - for( int i=0; itri[0] >= valid_start) && + (hit->tri[0] < valid_end); } -static void render_world_depth( m4x4f projection, m4x3f camera ) +static int ray_hit_is_ramp( ray_hit *hit ) { - m4x3f identity_matrix; - m4x3_identity( identity_matrix ); - - shader_gpos_use(); - shader_gpos_uCamera( camera[3] ); - shader_gpos_uPv( projection ); - shader_gpos_uMdl( identity_matrix ); - - scene_bind( &world.geo ); - scene_draw( &world.geo ); + u32 valid_start = world.sm_geo_std.vertex_start, + valid_end = world.sm_geo_vb.vertex_start; -#if 0 - glDisable(GL_CULL_FACE); - scene_bind( &world.foliage ); - scene_draw( &world.foliage ); - glEnable(GL_CULL_FACE); -#endif + return (hit->tri[0] >= valid_start) && + (hit->tri[0] < valid_end); } #endif /* WORLD_H */ diff --git a/world_gen.h b/world_gen.h new file mode 100644 index 0000000..74907c6 --- /dev/null +++ b/world_gen.h @@ -0,0 +1,365 @@ +#ifndef WORLD_GEN_H +#define WORLD_GEN_H + +#include "world.h" + + +static void world_add_all_if_material( m4x3f transform, scene *pscene, + mdl_header *mdl, u32 id ) +{ + for( int i=0; inode_count; i++ ) + { + mdl_node *pnode = mdl_node_from_id( mdl, i ); + + for( int j=0; jsubmesh_count; j++ ) + { + mdl_submesh *sm = mdl_node_submesh( mdl, pnode, j ); + + if( sm->material_id == id ) + { + m4x3f transform2; + mdl_node_transform( pnode, transform2 ); + m4x3_mul( transform, transform2, transform2 ); + + scene_add_submesh( pscene, mdl, sm, transform2 ); + } + } + + if( pnode->classtype == k_classtype_instance ) + { + if( pnode->sub_uid ) + { + u32 instance_id = pnode->sub_uid -1; + struct instance_cache *cache = &world.instance_cache[instance_id]; + mdl_header *mdl2 = cache->mdl; + + m4x3f transform2; + mdl_node_transform( pnode, transform2 ); + m4x3_mul( transform, transform2, transform2 ); + + world_add_all_if_material( transform2, pscene, mdl2, id ); + } + } + } +} + +static void world_apply_procedural_foliage(void) +{ + mdl_header *mfoliage = mdl_load("models/rs_foliage.mdl"); + + v3f volume; + v3_sub( world.geo.bbx[1], world.geo.bbx[0], volume ); + volume[1] = 1.0f; + + m4x3f transform; + mdl_node *mblob = mdl_node_from_name( mfoliage, "blob" ); + mdl_submesh *sm_blob = mdl_node_submesh( mfoliage, mblob, 0 ); + + for( int i=0;i<100000;i++ ) + { + v3f pos; + v3_mul( volume, (v3f){ vg_randf(), 1000.0f, vg_randf() }, pos ); + pos[1] = 1000.0f; + v3_add( pos, world.geo.bbx[0], pos ); + + ray_hit hit; + hit.dist = INFINITY; + + if( ray_world( pos, (v3f){0.0f,-1.0f,0.0f}, &hit )) + { + if( (hit.normal[1] > 0.8f) && ray_hit_is_terrain(&hit) && + (hit.pos[1] > 0.0f+10.0f) ) + { + v4f qsurface, qrandom; + v3f axis; + + v3_cross( (v3f){0.0f,1.0f,0.0f}, hit.normal, axis ); + + float angle = v3_dot(hit.normal,(v3f){0.0f,1.0f,0.0f}); + q_axis_angle( qsurface, axis, angle ); + q_axis_angle( qrandom, (v3f){0.0f,1.0f,0.0f}, vg_randf()*VG_TAUf ); + q_mul( qsurface, qrandom, qsurface ); + q_m3x3( qsurface, transform ); + + v3_copy( hit.pos, transform[3] ); + scene_add_submesh( &world.foliage, mfoliage, sm_blob, transform); + } + } + } + free( mfoliage ); +} + +static void world_load(void) +{ + mdl_header *mworld = mdl_load( "models/mp_dev.mdl" ); + + world.spawn_count = 0; + world.traffic_count = 0; + world.instance_cache = NULL; + + /* + * Process entities + */ + for( int i=0; inode_count; i++ ) + { + mdl_node *pnode = mdl_node_from_id( mworld, i ); + + if( pnode->classtype == k_classtype_none ) + {} + else if( pnode->classtype == k_classtype_spawn ) + { + struct respawn_point *rp = &world.spawns[ world.spawn_count ++ ]; + + v3_copy( pnode->co, rp->co ); + v4_copy( pnode->q, rp->q ); + strcpy( rp->name, mdl_pstr( mworld, pnode->pstr_name ) ); + } + else if( pnode->classtype == k_classtype_water ) + { + if( wrender.enabled ) + { + vg_warn( "Multiple water surfaces in level! ('%s')\n", + mdl_pstr( mworld, pnode->pstr_name )); + continue; + } + + mdl_submesh *sm = mdl_node_submesh( mworld, pnode, 0 ); + + if( sm ) + { + glmesh surf; + mdl_unpack_submesh( mworld, &surf, sm ); + world_water_init(); + water_set_surface( &surf, pnode->co[1] ); + } + } + else if( pnode->classtype == k_classtype_car_path ) + { + struct classtype_car_path *p = mdl_get_entdata( mworld, pnode ); + traffic_node *tn = &world.traffic[ world.traffic_count ]; + tn->mn_next = NULL; + tn->mn_next1 = NULL; + + if( p->target ) tn->mn_next = mdl_node_from_id( mworld, p->target ); + if( p->target1 ) tn->mn_next1 = mdl_node_from_id( mworld, p->target1 ); + + m4x3f transform; + mdl_node_transform( pnode, transform ); + m3x3_mulv( transform, (v3f){1.0f,0.0f,0.0f}, tn->h ); + v3_copy( transform[3], tn->co ); + + pnode->sub_uid = world.traffic_count ++; + } + else if( pnode->classtype == k_classtype_instance ) + { + struct classtype_instance *inst = mdl_get_entdata( mworld, pnode ); + pnode->sub_uid = 0; + + int cached = 0; + for( int i=0; ipstr_file == cache->pstr_file ) + { + cached = 1; + pnode->sub_uid = i+1; + break; + } + } + + if( !cached ) + { + world.instance_cache = buffer_reserve( + world.instance_cache, world.instance_cache_count, + &world.instance_cache_cap, 1, + sizeof(struct instance_cache) ); + + struct instance_cache *cache = + &world.instance_cache[world.instance_cache_count]; + + const char *filename = mdl_pstr(mworld, inst->pstr_file); + + cache->pstr_file = inst->pstr_file; + cache->mdl = mdl_load( filename ); + + if( cache->mdl ) + { + world.instance_cache_count ++; + pnode->sub_uid = world.instance_cache_count; + mdl_link_materials( mworld, cache->mdl ); + vg_success( "Cached %s\n", filename ); + } + else + { + vg_warn( "Failed to cache %s\n", filename ); + } + } + } + } + + world.instance_cache = buffer_fix( world.instance_cache, + world.instance_cache_count, + &world.instance_cache_cap, + sizeof( struct instance_cache ) ); + +#if 0 + traffic_finalize( world.traffic, world.traffic_count ); + for( int i=0; imaterial_count; i++ ) + { + mdl_material *mat = mdl_material_from_id( mworld, i ); + const char *mat_name = mdl_pstr( mworld, mat->pstr_name ); + + if( !strcmp( "surf", mat_name )) + mat_surf = i; + else if( !strcmp( "surf_oob", mat_name )) + mat_surf_oob = i; + else if( !strcmp( "vertex_blend", mat_name )) + mat_vertex_blend = i; + else if( !strcmp( "alphatest", mat_name )) + mat_alphatest = i; + else if( !strcmp( "graffitibox", mat_name )) + mat_graffiti = i; + else if( !strcmp( "terrain", mat_name ) ) + mat_terrain = i; + } + + m4x3f midentity; + m4x3_identity( midentity ); + + if( mat_terrain ) + world_add_all_if_material( midentity, &world.geo, mworld, mat_terrain ); + scene_copy_slice( &world.geo, &world.sm_terrain ); + + if( mat_surf_oob ) + world_add_all_if_material( midentity, &world.geo, mworld, mat_surf_oob ); + else + vg_warn( "No OOB surface\n" ); + scene_copy_slice( &world.geo, &world.sm_geo_std_oob ); + + if( mat_surf ) + world_add_all_if_material( midentity, &world.geo, mworld, mat_surf ); + scene_copy_slice( &world.geo, &world.sm_geo_std ); + + if( mat_vertex_blend ) + world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend); + scene_copy_slice( &world.geo, &world.sm_geo_vb ); + + scene_upload( &world.geo ); + scene_bh_create( &world.geo ); + + + /* Foliage /nocollide layer. + * TODO: Probably should have material traits for this + */ + scene_init( &world.foliage ); + + world_apply_procedural_foliage(); + scene_copy_slice( &world.foliage, &world.sm_foliage_main ); + + world_add_all_if_material( midentity, &world.foliage, mworld, mat_alphatest); + scene_copy_slice( &world.foliage, &world.sm_foliage_alphatest ); + + world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti ); + scene_copy_slice( &world.foliage, &world.sm_graffiti ); + + scene_upload( &world.foliage ); + world_routes_loadfrom( mworld ); + + for( int i=0; ig_water_plane ); + + v4f bounds; + bounds[0] = world.geo.bbx[0][0]; + bounds[1] = world.geo.bbx[0][2]; + bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]); + bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]); + v4_copy( bounds, winfo->g_depth_bounds ); + + winfo->g_water_fog = 0.04f; + render_update_lighting_ub(); + + + world.mr_ball.type = k_rb_shape_sphere; + world.mr_ball.inf.sphere.radius = 2.0f; + v3_copy( (v3f){ 0.0f, 110.0f, 0.0f }, world.mr_ball.co ); + + q_identity(world.mr_ball.q); + rb_init( &world.mr_ball ); + + /* + * Setup scene collider + */ + v3_zero( world.rb_geo.co ); + q_identity( world.rb_geo.q ); + + world.rb_geo.type = k_rb_shape_scene; + world.rb_geo.inf.scene.pscene = &world.geo; + world.rb_geo.is_world = 1; + rb_init( &world.rb_geo ); +} + +#endif /* WORLD_GEN_H */ diff --git a/world_render.h b/world_render.h new file mode 100644 index 0000000..3662bb1 --- /dev/null +++ b/world_render.h @@ -0,0 +1,254 @@ +#ifndef WORLD_RENDER_H +#define WORLD_RENDER_H + +#include "world.h" + +vg_tex2d tex_terrain_colours = { .path = "textures/gradients.qoi", + .flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST }; + +vg_tex2d tex_terrain_noise = { .path = "textures/garbage.qoi", + .flags = VG_TEXTURE_NEAREST }; + +vg_tex2d tex_alphatest = { .path = "textures/alphatest.qoi", + .flags = VG_TEXTURE_NEAREST }; + +vg_tex2d tex_graffiti = { .path = "textures/graffitibox.qoi", + .flags = VG_TEXTURE_NEAREST }; + +static void world_render_init(void) +{ + vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours, + &tex_terrain_noise, + &tex_alphatest, + &tex_graffiti }, 4 ); +} + + + +static void render_world_depth( m4x4f projection, m4x3f camera ); + + + + +/* + * Rendering + */ + +static void bind_terrain_textures(void) +{ + vg_tex2d_bind( &tex_terrain_noise, 0 ); + vg_tex2d_bind( &tex_terrain_colours, 1 ); +} + +static void render_world_vb( m4x4f projection, v3f camera ) +{ + m4x3f identity_matrix; + m4x3_identity( identity_matrix ); + + shader_vblend_use(); + shader_vblend_uTexGarbage(0); + shader_vblend_uTexGradients(1); + shader_link_standard_ub( _shader_vblend.id, 2 ); + bind_terrain_textures(); + + shader_vblend_uPv( projection ); + shader_vblend_uMdl( identity_matrix ); + shader_vblend_uCamera( camera ); + + scene_bind( &world.geo ); + mdl_draw_submesh( &world.sm_geo_vb ); + + mesh_bind( &world.cars ); + +#if 0 + for( int i=0; igate.co[0], camera[3] ); + + if( dist < closest ) + { + closest = dist; + id = i; + } + } + + render_gate( &world.routes.gates[id].gate, playerco, camera ); + v3_lerp( world.render_gate_pos, + world.routes.gates[id].gate.co[0], + 1.0f, + world.render_gate_pos ); +} + +static void render_world( m4x4f projection, m4x3f camera ) +{ + render_sky( camera ); + render_world_routes( projection, camera[3] ); + render_world_vb( projection, camera[3] ); + render_world_alphatest( projection, camera[3] ); + render_terrain( projection, camera[3] ); + + int closest = 0; + float min_dist = INFINITY; + + for( int i=0; iroutes[route]; if( pr->ui.segment_count ) @@ -223,7 +124,7 @@ static void world_routes_ui_popfirst( u32 route ) */ static void world_routes_ui_clear( u32 route ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; pr->ui.segment_start = (pr->ui.segment_start + pr->ui.segment_count) % k_max_ui_segments; @@ -316,7 +217,7 @@ static struct route_ui_segment *world_routes_ui_curseg( struct route *pr ) */ static void world_routes_ui_newseg( u32 route ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; pr->ui.last_notch = 0.0; @@ -373,7 +274,7 @@ static void world_routes_ui_newseg( u32 route ) */ static void world_routes_ui_updatetime( u32 route, float time ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; v2f verts[2]; @@ -396,7 +297,7 @@ static void world_routes_ui_updatetime( u32 route, float time ) */ static void world_routes_ui_notch( u32 route, float time ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; if( (time - pr->ui.last_notch) > 1.0 ) @@ -485,7 +386,7 @@ static void world_routes_ui_draw( u32 route, v4f colour, float offset ) float const k_bar_height = 0.05f, k_bar_scale_x = 0.005f; - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; float cx = pr->ui.xpos; @@ -558,7 +459,7 @@ static void world_routes_local_set_record( u32 route, double lap_time ) { vg_success( " NEW LAP TIME: %f\n", lap_time ); - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; if( pr->track_id != 0xffffffff ) @@ -591,7 +492,7 @@ static void world_routes_local_set_record( u32 route, double lap_time ) */ static void world_routes_verify_run( u32 route ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route *pr = &r->routes[route]; u32 stack[64]; @@ -691,7 +592,7 @@ static void world_routes_verify_run( u32 route ) */ static void world_routes_activate_gate( u32 id ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; struct route_gate *rg = &r->gates[id]; struct route_node *pnode = &r->nodes[rg->node_id], *pdest = &r->nodes[pnode->next[0]]; @@ -742,7 +643,7 @@ static void world_routes_activate_gate( u32 id ) */ static void world_routes_notify_reset(void) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; for( int i=0; iroute_count; i++ ) { @@ -755,7 +656,7 @@ static void world_routes_notify_reset(void) static void world_routes_debug(void) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; for( int i=0; inode_count; i++ ) { @@ -799,15 +700,6 @@ static void world_routes_debug(void) } } -static void world_routes_free(void) -{ - struct subworld_routes *r = subworld_routes(); - - free( r->nodes ); - free( r->routes ); - free( r->gates ); -} - static void world_id_fixup( u32 *uid, mdl_header *mdl ) { if( *uid ) @@ -821,7 +713,7 @@ static void world_id_fixup( u32 *uid, mdl_header *mdl ) */ static void world_routes_gen_meshes(void) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; scene_init( &r->scene_lines ); for( int i=0; iroute_count; i++ ) @@ -948,85 +840,10 @@ static void world_routes_gen_meshes(void) scene_free_offline_buffers( &r->scene_lines ); } -static void world_routes_update(void) -{ - struct subworld_routes *r = subworld_routes(); - - for( int i=0; iroute_count; i++ ) - { - struct route *route = &r->routes[i]; - route->factive = vg_lerpf( route->factive, route->active, 0.01f ); - - if( route->active ) - { - world_routes_ui_updatetime( i, vg_time - route->latest_pass ); - } - } -} - -static void bind_terrain_textures(void); -static void render_world_routes( m4x4f projection, v3f camera ) -{ - struct subworld_routes *r = subworld_routes(); - - m4x3f identity_matrix; - m4x3_identity( identity_matrix ); - - shader_route_use(); - shader_route_uTexGarbage(0); - shader_link_standard_ub( _shader_route.id, 2 ); - bind_terrain_textures(); - - shader_route_uPv( projection ); - shader_route_uMdl( identity_matrix ); - shader_route_uCamera( camera ); - - scene_bind( &r->scene_lines ); - - for( int i=0; iroute_count; i++ ) - { - struct route *route = &r->routes[i]; - - v4f colour; - v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour ); - colour[3] = 1.0f; - - shader_route_uColour( colour ); - mdl_draw_submesh( &route->sm ); - } -} - -static void render_world_routes_ui(void) -{ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - struct subworld_routes *r = subworld_routes(); - - float active_offset = 0.0f; - for( int i=0; iroute_count; i++ ) - { - struct route *route = &r->routes[i]; - world_routes_ui_draw( i, route->colour, active_offset ); - active_offset += route->factive; - } - - glDisable(GL_BLEND); -} - -static void world_routes_register(void) -{ - struct subworld_routes *r = subworld_routes(); - r->current_run_version = 2; - - shader_route_register(); - shader_routeui_register(); -} static void world_routes_loadfrom( mdl_header *mdl ) { - struct subworld_routes *r = subworld_routes(); + struct subworld_routes *r = &world.routes; r->nodes = NULL; r->node_count = 0; r->node_cap = 0; @@ -1229,4 +1046,95 @@ static void world_routes_loadfrom( mdl_header *mdl ) world_routes_gen_meshes(); } +/* + * ----------------------------------------------------------------------------- + * Events + * ----------------------------------------------------------------------------- + */ + +static void world_routes_register(void) +{ + struct subworld_routes *r = &world.routes; + r->current_run_version = 2; + + shader_route_register(); + shader_routeui_register(); +} + +static void world_routes_free(void) +{ + struct subworld_routes *r = &world.routes; + + free( r->nodes ); + free( r->routes ); + free( r->gates ); +} + +static void world_routes_update(void) +{ + struct subworld_routes *r = &world.routes; + + for( int i=0; iroute_count; i++ ) + { + struct route *route = &r->routes[i]; + route->factive = vg_lerpf( route->factive, route->active, 0.01f ); + + if( route->active ) + { + world_routes_ui_updatetime( i, vg_time - route->latest_pass ); + } + } +} + +static void bind_terrain_textures(void); +static void render_world_routes( m4x4f projection, v3f camera ) +{ + struct subworld_routes *r = &world.routes; + + m4x3f identity_matrix; + m4x3_identity( identity_matrix ); + + shader_route_use(); + shader_route_uTexGarbage(0); + shader_link_standard_ub( _shader_route.id, 2 ); + bind_terrain_textures(); + + shader_route_uPv( projection ); + shader_route_uMdl( identity_matrix ); + shader_route_uCamera( camera ); + + scene_bind( &r->scene_lines ); + + for( int i=0; iroute_count; i++ ) + { + struct route *route = &r->routes[i]; + + v4f colour; + v3_lerp( (v3f){0.7f,0.7f,0.7f}, route->colour, route->factive, colour ); + colour[3] = 1.0f; + + shader_route_uColour( colour ); + mdl_draw_submesh( &route->sm ); + } +} + +static void render_world_routes_ui(void) +{ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + struct subworld_routes *r = &world.routes; + + float active_offset = 0.0f; + for( int i=0; iroute_count; i++ ) + { + struct route *route = &r->routes[i]; + world_routes_ui_draw( i, route->colour, active_offset ); + active_offset += route->factive; + } + + glDisable(GL_BLEND); +} + #endif /* ROUTES_H */ diff --git a/world_sfd.h b/world_sfd.h index 515232c..c6fa66b 100644 --- a/world_sfd.h +++ b/world_sfd.h @@ -1,8 +1,6 @@ #ifndef SFD_H #define SFD_H -#include "common.h" -#include "model.h" #include "world.h" #include "shaders/scoretext.h" @@ -11,25 +9,9 @@ vg_tex2d tex_scoretext = { .path = "textures/scoretext.qoi", .flags = VG_TEXTURE_CLAMP|VG_TEXTURE_NEAREST }; -struct sfd_instance -{ - float *buffer; - - u32 w,h; -}; - - -struct subworld_sfd -{ - scene mesh; - mdl_submesh *sm_module, *sm_card; - glmesh temp; - - struct sfd_instance tester; -}; - -static struct subworld_sfd *subworld_sfd(void); - +/* + * TODO: utf-8 -> ascii + */ float sfd_encode_glyph( char c ) { @@ -120,7 +102,7 @@ static void sfd_update( struct sfd_instance *display ) static void sfd_render( struct sfd_instance *display, m4x4f projection, v3f camera, m4x3f transform ) { - struct subworld_sfd *sfd = subworld_sfd(); + struct subworld_sfd *sfd = &world.sfd; scene_bind( &sfd->mesh ); shader_scoretext_use(); @@ -160,7 +142,7 @@ static void sfd_render( struct sfd_instance *display, static int world_sfd_test( int argc, const char *argv[] ) { - struct subworld_sfd *sfd = subworld_sfd(); + struct subworld_sfd *sfd = &world.sfd; if( argc == 2 ) { @@ -173,7 +155,7 @@ static int world_sfd_test( int argc, const char *argv[] ) static void world_sfd_init(void) { - struct subworld_sfd *sfd = subworld_sfd(); + struct subworld_sfd *sfd = &world.sfd; vg_function_push( (struct vg_cmd){ .name = "sfd", diff --git a/water.h b/world_water.h similarity index 67% rename from water.h rename to world_water.h index 1de2554..85f4b5d 100644 --- a/water.h +++ b/world_water.h @@ -1,12 +1,3 @@ -#include "common.h" -#include "model.h" - -static void water_register(void); -static void water_init(void); -static void water_fb_resize(void); -static void water_set_surface( glmesh *surf, float height ); -static float water_height(void); - #ifndef WATER_H #define WATER_H @@ -35,17 +26,12 @@ wrender = .fbdepth = { .format = GL_RGBA, .div = 4 } }; -static float water_height(void) -{ - return wrender.height; -} - -static void water_register(void) +static void world_water_register(void) { shader_water_register(); } -static void water_init(void) +static void world_water_init(void) { /* TODO: probably dont do this every time */ wrender.enabled = 1; @@ -63,73 +49,6 @@ static void water_fb_resize(void) fb_resize( &wrender.fbdepth ); } -#if 0 -static void water_compute_depth( boxf bounds ) -{ - if( !wrender.enabled ) - return; - -#ifdef VG_RELEASE - int const kres = 512; -#else - int const kres = 1024; -#endif - - vg_info( "Computing depth map\n" ); - float *img = malloc( kres*kres*sizeof(float) ); - - boxf interior; - v3_add(bounds[0],(v3f){1.0f,1.0f,1.0f},interior[0]); - v3_sub(bounds[1],(v3f){1.0f,1.0f,1.0f},interior[1]); - - v3f volume; - v3_sub( interior[1], interior[0], volume ); - box_copy( interior, wrender.depthbounds ); - - for( int y=0; y