+/*
+ * TODO: more flexible way to call
+ * - this depends on the current state, but we need to pass a struct in
+ * that can hold that information instead so we can save it into
+ * the replay
+ */
+static void player_glide_render( camera *cam, world_instance *world,
+ player_pose *pose ){
+ if( !((localplayer.subsystem == k_player_subsystem_glide) ||
+ (localplayer.observing_system == k_player_subsystem_glide) ||
+ localplayer.have_glider ||
+ localplayer.glider_orphan) )
+ return;
+
+ shader_model_board_view_use();
+ shader_model_board_view_uTexMain( 0 );
+ shader_model_board_view_uCamera( cam->transform[3] );
+ shader_model_board_view_uPv( cam->mtx.pv );
+
+ shader_model_board_view_uDepthCompare(1);
+ depth_compare_bind(
+ shader_model_board_view_uTexSceneDepth,
+ shader_model_board_view_uInverseRatioDepth,
+ shader_model_board_view_uInverseRatioMain,
+ cam );
+
+ WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_board_view );
+
+ mdl_keyframe kf_res;
+ if( localplayer.glider_orphan ){
+ rb_extrapolate( &player_glide.rb, kf_res.co, kf_res.q );
+ v3_fill( kf_res.s, 1.0f );
+
+ v3f temp;
+ q_mulv( kf_res.q, (v3f){0,-0.5f,0}, temp );
+ v3_add( temp, kf_res.co, kf_res.co );
+ }
+ else {
+ f32 target;
+ if( localplayer.subsystem == k_player_subsystem_glide ) target = 1.0f;
+ else target = 0.0f;
+
+ /* TODO: TEMP */
+ if( skaterift.activity != k_skaterift_replay )
+ vg_slewf( &player_glide.t, target, vg.time_frame_delta * 4.0f );
+
+ mdl_keyframe kf_backpack;
+
+ struct skeleton *sk = &localplayer.skeleton;
+ m4x3_mulv( localplayer.final_mtx[localplayer.id_chest ],
+ sk->bones[localplayer.id_chest].co,
+ kf_backpack.co );
+
+ v4f qyaw, qpitch, qchest, q;
+ q_axis_angle( qyaw, (v3f){0,1,0}, VG_TAUf*0.25f );
+ q_axis_angle( qpitch, (v3f){1,0,0}, VG_TAUf*0.25f );
+ m3x3_q( localplayer.final_mtx[ localplayer.id_chest ], qchest );
+
+ q_mul( qyaw, qpitch, q );
+ q_mul( qchest, q, kf_backpack.q );
+ q_normalize( kf_backpack.q );
+
+ f32 scale;
+ if( player_glide.t <= 0.0f ){
+ f32 st = player_glide.t + 1.0f,
+ sst = vg_smoothstepf(st),
+ isst= 1.0f - sst;
+ scale = vg_lerpf( 0.0f, 0.2f, sst );
+
+ v4f qspin;
+ q_axis_angle( qspin, (v3f){0,0,1}, VG_TAUf * isst * 0.5f );
+ q_mul( kf_backpack.q, qspin, kf_backpack.q );
+ kf_backpack.co[1] += isst * 1.0f;
+ v3_muladds( kf_backpack.co,
+ localplayer.final_mtx[ localplayer.id_chest ][0],
+ isst * 0.25f,
+ kf_backpack.co );
+ }
+ else{
+ scale = vg_lerpf( 0.2f, 1.0f, vg_smoothstepf(player_glide.t) );
+ }
+
+
+ v3_fill( kf_backpack.s, scale );
+
+ v3_copy( pose->root_co, kf_res.co );
+ v4_copy( pose->root_q, kf_res.q );
+ v3_fill( kf_res.s, scale );
+
+ f32 blend = vg_smoothstepf( vg_maxf( 0, player_glide.t ) );
+ keyframe_lerp( &kf_backpack, &kf_res, blend, &kf_res );
+ }
+
+ m4x3f mmdl;
+ q_m3x3( kf_res.q, mmdl );
+ m3x3_scale( mmdl, kf_res.s );
+ v3_copy( kf_res.co, mmdl[3] );
+
+ render_glider_model( cam, world, mmdl, k_board_shader_player );
+
+ /* totally FUCKED */
+ v4_copy( kf_res.q, player_glide.remote_animator.root_q );
+ v3_copy( kf_res.co, player_glide.remote_animator.root_co );
+ player_glide.remote_animator.s = kf_res.s[0];
+}
+
+static void player_glide_render_effects( camera *cam ){
+ v3f co, temp;
+ v4f q;
+ rb_extrapolate( &player_glide.rb, co, q );
+ q_mulv( q, (v3f){0,-0.5f,0}, temp );
+ v3_add( temp, co, co );
+
+ f32 alpha = vg_maxf( (fabsf(player_glide.info_lift[2])-1.0f), 0.0f ) /18.0f;
+
+ for( u32 i=0; i<player_glide.trail_count; i ++ ){
+ v3f vvert;
+ q_mulv( q, player_glide.trail_positions[i], vvert );
+ v3_add( co, vvert, vvert );
+
+ trail_system_update( &trails_glider[i], vg.time_delta, vvert,
+ localplayer.rb.to_world[1], alpha );
+
+ trail_system_prerender( &trails_glider[i] );
+ trail_system_render( &trails_glider[i], &skaterift.cam );
+ }
+}
+