- }
-}
-
-static void draw_cross(v3f pos,u32 colour, float scale)
-{
- v3f p0, p1;
- v3_add( (v3f){ scale,0.0f,0.0f}, pos, p0 );
- v3_add( (v3f){-scale,0.0f,0.0f}, pos, p1 );
- vg_line( p0, p1, colour );
- v3_add( (v3f){0.0f, scale,0.0f}, pos, p0 );
- v3_add( (v3f){0.0f,-scale,0.0f}, pos, p1 );
- vg_line( p0, p1, colour );
- v3_add( (v3f){0.0f,0.0f, scale}, pos, p0 );
- v3_add( (v3f){0.0f,0.0f,-scale}, pos, p1 );
- vg_line( p0, p1, colour );
-}
-
-static void player_physics_control(void)
-{
- /*
- * 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 );
- float slip = 0.0f;
-
- if( fabsf(vel[2]) > 0.01f )
- slip = fabsf(-vel[0] / vel[2]) * vg_signf(vel[0]);
-
- if( fabsf( slip ) > 1.2f )
- slip = vg_signf( slip ) * 1.2f;
- player.slip = slip;
- player.reverse = -vg_signf(vel[2]);
-
- float substep = ktimestep * 0.2f;
- float fwd_resistance = (vg_get_button( "break" )? 5.0f: 0.02f) * -substep;
-
- for( int i=0; i<5; i++ )
- {
- vel[2] = stable_force( vel[2], vg_signf( vel[2] ) * fwd_resistance );
- vel[0] = stable_force( vel[0],
- vg_signf( vel[0] ) * -k_friction_lat*substep );
- }
-
- static double start_push = 0.0;
- if( vg_get_button_down( "push" ) )
- start_push = vg_time;
-
- if( vg_get_button( "jump" ) )
- {
- player.jump += ktimestep * k_jump_charge_speed;
-
- if( !player.jump_charge )
- player.jump_dir = player.reverse > 0.0f? 1: 0;
-
- player.jump_charge = 1;
- }
-
- if( !vg_get_button("break") && vg_get_button( "push" ) )
- {
- player.pushing = 1.0f;
- player.push_time = vg_time-start_push;
-
- float cycle_time = player.push_time*k_push_cycle_rate,
- amt = k_push_accel * (sinf(cycle_time)*0.5f+0.5f)*ktimestep,
- current = v3_length( vel ),
- 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;
- }
-
- /* Pumping */
- static float previous = 0.0f;
- float delta = previous - player.grab,
- pump = delta * k_pump_force*ktimestep;
- previous = player.grab;
-
- v3f p1;
- v3_muladds( player.rb.co, player.rb.up, pump, p1 );
- vg_line( player.rb.co, p1, 0xff0000ff );
-
- vel[1] += pump;
-
-
- m3x3_mulv( player.rb.to_world, vel, player.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);
-}
-
-static void player_physics_control_air(void)
-{
- m3x3_mulv( player.vr, player.rb.v, player.rb.v );
- draw_cross( player.land_target, 0xff0000ff, 0.25f );
-
- ray_hit hit;
-
- /*
- * Prediction
- */
- float pstep = ktimestep*10.0f;
-
- v3f pco, pco1, pv;
- v3_copy( player.rb.co, pco );
- v3_copy( player.rb.v, pv );
-
- float time_to_impact = 0.0f;
- float limiter = 1.0f;
-
- for( int i=0; i<50; i++ )
- {
- v3_copy( pco, pco1 );
- m3x3_mulv( player.vr_pstep, pv, pv );
- apply_gravity( pv, pstep );
- v3_muladds( pco, pv, pstep, pco );
-
- //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
-
- ray_hit contact;
- v3f vdir;
-
- v3_sub( pco, pco1, vdir );
- contact.dist = v3_length( vdir );
- v3_divs( vdir, contact.dist, vdir);
-
- float orig_dist = contact.dist;
- if( ray_world( pco1, vdir, &contact ))
- {
- float angle = v3_dot( player.rb.up, contact.normal );
- v3f axis;
- v3_cross( player.rb.up, contact.normal, axis );
-
- time_to_impact += (contact.dist/orig_dist)*pstep;
- limiter = vg_minf( 5.0f, time_to_impact )/5.0f;
- limiter = 1.0f-limiter;
- limiter *= limiter;
- limiter = 1.0f-limiter;
-
- if( angle < 0.99f )
- {
- v4f correction;
- q_axis_angle( correction, axis, acosf(angle)*0.05f*(1.0f-limiter) );
- q_mul( correction, player.rb.q, player.rb.q );
- }
-
- draw_cross( contact.pos, 0xffff0000, 0.25f );
- break;
- }
- time_to_impact += pstep;
- }
-
- player.iY -= vg_get_axis( "horizontal" ) * k_steer_air * ktimestep;
- {
- float iX = vg_get_axis( "vertical" ) *
- player.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 );
- }
-
- 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 );
-}
-
-static void player_init(void)
-{
- rb_init( &player.collide_front );
- rb_init( &player.collide_back );
-}
-
-static void player_walk_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 );
-
- float h0 = 0.3f,
- h1 = 0.9f;
-
- m4x3_mulv( player.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 );
- v3_copy( rbb->co, rbb->to_world[3] );
-
- m4x3_invert_affine( rbf->to_world, rbf->to_local );
- m4x3_invert_affine( rbb->to_world, rbb->to_local );
-
- rb_update_bounds( rbf );
- rb_update_bounds( rbb );
-
- rb_debug( rbf, 0xff0000ff );
- rb_debug( rbb, 0xff0000ff );
-
- rb_ct manifold[64];
- int len = 0;
-
- len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
- len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
-
- rb_presolve_contacts( manifold, len );
-
- for( int j=0; j<5; j++ )
- {
- for( int i=0; i<len; i++ )
- {
- struct contact *ct = &manifold[i];
-
- /*normal */
- float vn = -v3_dot( player.rb.v, ct->n );
- vn += ct->bias;
-
- float temp = ct->norm_impulse;
- ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
- vn = ct->norm_impulse - temp;
-
- v3f impulse;
- v3_muls( ct->n, vn, impulse );
-
- v3_add( impulse, player.rb.v, player.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] ),
- 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 );
- }
- }
- }
-
- player.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] );
-
- 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 );
-
- float move_dead = 0.1f,
- move = vg_get_axis("grabr")*0.5f + 0.5f - move_dead;
-
- if( move > 0.0f )
- {
- 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 ),
- 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 );
-
- /* TODO move */
- float walk_norm = 30.0f/(float)player.mdl.anim_walk->length,
- run_norm = 30.0f/(float)player.mdl.anim_run->length ;
-
- player.walk_timer += ktimestep * vg_lerpf( walk_norm,run_norm,move_norm );
- }
- else
- {
- 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);
-}
-
-static void player_physics(void)
-{
- /*
- * Update collision fronts
- */
-
- 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 );
-
- player.air_blend = vg_lerpf( player.air_blend, player.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 );
- v3_copy( rbf->co, rbf->to_world[3] );
- m4x3_mulv( player.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 );
- m4x3_invert_affine( rbb->to_world, rbb->to_local );
-
- rb_update_bounds( rbf );
- rb_update_bounds( rbb );
-
- rb_debug( rbf, 0xff00ffff );
- rb_debug( rbb, 0xffffff00 );
-
- rb_ct manifold[64];
- int len = 0;
-
- len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
- len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
-
- rb_presolve_contacts( manifold, len );
- v3f surface_avg = {0.0f, 0.0f, 0.0f};
-
- if( !len )
- {
- player_start_air();
- }
- else
- {
- for( int i=0; i<len; i++ )
- {
- v3_add( manifold[i].n, surface_avg, surface_avg );
-
-#if 0
- if( manifold[i].element_id <= world.sm_geo_std_oob.vertex_count )
- {
- player.is_dead = 1;
- character_ragdoll_copypose( &player.mdl, player.rb.v );
- return;
- }
-#endif
- }
-
- v3_normalize( surface_avg );
-
- if( v3_dot( player.rb.v, surface_avg ) > 0.5f )
- {
- player_start_air();
- }
- else
- player.in_air = 0;
- }
-
- for( int j=0; j<5; j++ )
- {
- for( int i=0; i<len; i++ )
- {
- 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 );
-
- float vn = -v3_dot( dv, ct->n );
- vn += ct->bias;
-
- float temp = ct->norm_impulse;
- ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
- vn = ct->norm_impulse - temp;
-
- 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 )
- {
- player.is_dead = 1;
- character_ragdoll_copypose( &player.mdl, player.rb.v );
- return;
- }
-
- v3_add( impulse, player.rb.v, player.rb.v );
- v3_cross( delta, impulse, impulse );
-
- /*
- * W Impulses are limited to the Y and X axises, we don't really want
- * roll angular velocities being included.
- *
- * Can also tweak the resistance of each axis here by scaling the wx,wy
- * components.
- */
-
- float wy = v3_dot( player.rb.up, impulse ),
- wx = v3_dot( player.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 );
- }
- }
-
- float grabt = vg_get_axis( "grabr" )*0.5f+0.5f;
- player.grab = vg_lerpf( player.grab, grabt, 0.14f );
- player.pushing = 0.0f;
-
- if( !player.in_air )
- {
- v3f axis;
- float angle = v3_dot( player.rb.up, surface_avg );
- v3_cross( player.rb.up, surface_avg, axis );
-
- //float cz = v3_dot( player.rb.forward, axis );
- //v3_muls( player.rb.forward, cz, axis );
-
- if( angle < 0.999f )
- {
- v4f correction;
- q_axis_angle( correction, axis, acosf(angle)*0.3f );
- q_mul( correction, player.rb.q, player.rb.q );
- }
-
- v3_muladds( player.rb.v, player.rb.up,
- -k_downforce*ktimestep, player.rb.v );
-
- player_physics_control();
-
- if( !player.jump_charge && player.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 )),
- mod = 0.5f,
- dir = mod + aup*(1.0f-mod);
-
- v3_copy( player.rb.v, jumpdir );
- v3_normalize( jumpdir );
- v3_muls( jumpdir, 1.0f-dir, jumpdir );
- v3_muladds( jumpdir, player.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;
-
- 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_vol( &audio_player_extra, 20.0f );
- audio_player_playclip( &audio_player_extra, &audio_jumps[rand()%4] );
- audio_unlock();
- }
- }
- else
- {
- player_physics_control_air();
- }