+
+ 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}, phys->rb.up )),
+ mod = 0.5f,
+ dir = mod + aup*(1.0f-mod);
+
+ v3_copy( phys->rb.v, jumpdir );
+ v3_normalize( jumpdir );
+ v3_muls( jumpdir, 1.0f-dir, jumpdir );
+ v3_muladds( jumpdir, phys->rb.up, dir, jumpdir );
+ v3_normalize( jumpdir );
+
+ 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;
+
+ /* TODO: Move to audio file */
+ audio_lock();
+ audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D );
+ 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()%2] );
+ audio_unlock();
+ }
+}
+
+VG_STATIC void player_physics_control_grind(void)
+{
+ struct player_phys *phys = &player.phys;
+ v2f steer = { player.input_js1h->axis.value,
+ player.input_js1v->axis.value };
+
+ float l2 = v2_length2( steer );
+ if( l2 > 1.0f )
+ v2_muls( steer, 1.0f/sqrtf(l2), steer );
+
+ phys->iY -= steer[0] * k_steer_air * VG_TIMESTEP_FIXED;
+
+ float iX = steer[1] * phys->reverse * k_steer_air * VG_TIMESTEP_FIXED;
+
+ static float siX = 0.0f;
+ siX = vg_lerpf( siX, iX, k_steer_air_lerp );
+
+ v4f rotate;
+ q_axis_angle( rotate, phys->rb.right, siX );
+ q_mul( rotate, phys->rb.q, phys->rb.q );
+
+ phys->slip = 0.0f;