X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player_skate.c;h=9609b7fa0fb9b7601740f9c474fcb78c381eef92;hb=fc1d543772607ab0643e54ebd2db9ec9dce614d1;hp=01e3d7a005c71b6948cbd8c345a9721a959aa440;hpb=0a5ec40708e7d128511cac04f84d85055e6fc164;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player_skate.c b/player_skate.c index 01e3d7a..9609b7f 100644 --- a/player_skate.c +++ b/player_skate.c @@ -44,13 +44,13 @@ VG_STATIC int skate_collide_smooth( player_instance *player, man[i].rbb = NULL; } - rb_manifold_filter_coplanar( man, len, 0.05f ); + rb_manifold_filter_coplanar( man, len, 0.03f ); if( len > 1 ) { rb_manifold_filter_backface( man, len ); - rb_manifold_filter_joint_edges( man, len, 0.05f ); - rb_manifold_filter_pairs( man, len, 0.05f ); + rb_manifold_filter_joint_edges( man, len, 0.03f ); + rb_manifold_filter_pairs( man, len, 0.03f ); } int new_len = rb_manifold_apply_filtered( man, len ); if( len && !new_len ) @@ -152,8 +152,7 @@ struct grind_info v3f co, dir, n; }; -VG_STATIC int skate_grind_scansq( player_instance *player, - v3f pos, v3f dir, float r, +VG_STATIC int skate_grind_scansq( v3f pos, v3f dir, float r, struct grind_info *inf ) { v4f plane; @@ -164,12 +163,6 @@ VG_STATIC int skate_grind_scansq( player_instance *player, boxf box; v3_add( pos, (v3f){ r, r, r }, box[1] ); v3_sub( pos, (v3f){ r, r, r }, box[0] ); - - vg_line_boxf( box, VG__BLACK ); - - m4x3f mtx; - m3x3_copy( player->rb.to_world, mtx ); - v3_copy( pos, mtx[3] ); bh_iter it; bh_iter_init( 0, &it ); @@ -236,13 +229,13 @@ VG_STATIC int skate_grind_scansq( player_instance *player, sample_count ++; if( sample_count == vg_list_size( samples ) ) - { - break; - } + goto too_many_samples; } } } +too_many_samples: + if( sample_count < 2 ) return 0; @@ -635,6 +628,12 @@ VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, air_score = INFINITY, time_to_impact = 0.0f; + v3f ground_normal, + grind_normal; + + v3_copy( (v3f){0.0f,1.0f,0.0f}, ground_normal ); + v3_copy( (v3f){0.0f,1.0f,0.0f}, grind_normal ); + prediction->log_length = 0; v3_copy( pco, prediction->apex ); @@ -657,6 +656,7 @@ VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, float l = v3_length( vdir ); v3_muls( vdir, 1.0f/l, vdir ); +#if 0 v3f c0, c1; struct grind_edge *ge = skate_collect_grind_edge( pco, pco1, c0, c1, 0.4f ); @@ -671,6 +671,26 @@ VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, grind_score = closest_grind * 0.05f; } } +#endif + + /* TODO: binary search grind once we find it, do not need to + * recompute scansq, or collision. only distance + */ + + v3f closest; + if( bh_closest_point( world.geo_bh, pco, closest, k_board_length ) != -1 ) + { + struct grind_info inf; + if( skate_grind_scansq( closest, vdir, 0.5f, &inf ) ) + { + float score = -v3_dot( pv, inf.n ) * 0.06f; + + if( (score > 0.0f) && (score < grind_score) ) + { + grind_score = score; + } + } + } v3f n1; @@ -678,7 +698,7 @@ VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, int idx = spherecast_world( pco1, pco, 0.4f, &t1, n1 ); if( idx != -1 ) { - v3_copy( n1, prediction->n ); + v3_copy( n1, ground_normal ); air_score = -v3_dot( pv, n1 ); u32 vert_index = world.scene_geo->arrindices[ idx*3 ]; @@ -701,11 +721,13 @@ VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, { prediction->score = grind_score; prediction->type = k_prediction_grind; + v3_copy( grind_normal, prediction->n ); } else if( air_score < INFINITY ) { prediction->score = air_score; prediction->type = k_prediction_land; + v3_copy( ground_normal, prediction->n ); } else { @@ -736,6 +758,9 @@ void player__approximate_best_trajectory( player_instance *player ) max_score = -INFINITY; v3_zero( s->state.apex ); + v3_copy( (v3f){0.0f,1.0f,0.0f}, s->land_normal ); + /* TODO: Make part of state */ + s->land_dist = 0.0f; /* @@ -763,6 +788,9 @@ void player__approximate_best_trajectory( player_instance *player ) best_vmod = vmod; s->land_dist = p->land_dist; v3_copy( p->apex, s->state.apex ); + v3_copy( p->n, s->land_normal ); + + /* TODO: Store this as pointer? */ } if( p->score > max_score ) @@ -794,10 +822,13 @@ void player__approximate_best_trajectory( player_instance *player ) l -= min_score; l /= (max_score-min_score); l = 1.0f - l; - l *= 255.0f; - p->colour = l; - p->colour <<= 8; + p->score = l; + p->colour = l * 255.0f; + + if( p->type == k_prediction_land ) + p->colour <<= 8; + p->colour |= 0xff000000; } @@ -826,85 +857,6 @@ void player__approximate_best_trajectory( player_instance *player ) * ------------------------------------------------ */ -#if 0 -VG_STATIC void skate_apply_grind_model( player_instance *player, - rb_ct *manifold, int len ) -{ - struct player_skate *s = &player->_skate; - - /* FIXME: Queue audio events instead */ - if( len == 0 ) - { - if( s->state.activity == k_skate_activity_grind ) - { -#if 0 - 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_board[6] ); - audio_unlock(); -#endif - - s->state.activity = k_skate_activity_air; - } - return; - } - - v2f steer = { player->input_js1h->axis.value, - player->input_js1v->axis.value }; - v2_normalize_clamp( steer ); - -#if 0 - s->state.steery -= steer[0] * k_steer_air * k_rb_delta; - s->state.steerx += steer[1] * s->state.reverse * k_steer_air * k_rb_delta; -#endif - -#if 0 - v4f rotate; - q_axis_angle( rotate, player->rb.to_world[0], siX ); - q_mul( rotate, player.rb.q, player.rb.q ); -#endif - - s->state.slip = 0.0f; - s->state.activity = k_skate_activity_grind; - - /* TODO: Compression */ - v3f up = { 0.0f, 1.0f, 0.0f }; - float angle = v3_dot( player->rb.to_world[1], up ); - - if( fabsf(angle) < 0.99f ) - { - v3f axis; - v3_cross( player->rb.to_world[1], up, axis ); - - v4f correction; - q_axis_angle( correction, axis, k_rb_delta * 10.0f * acosf(angle) ); - q_mul( correction, player->rb.q, player->rb.q ); - } - - float const DOWNFORCE = -k_downforce*1.2f*VG_TIMESTEP_FIXED; - v3_muladds( player->rb.v, manifold->n, DOWNFORCE, player->rb.v ); - m3x3_identity( s->state.velocity_bias ); - m3x3_identity( s->state.velocity_bias_pstep ); - - if( s->state.activity_prev != k_skate_activity_grind ) - { - /* FIXME: Queue audio events instead */ -#if 0 - 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_board[5] ); - audio_unlock(); -#endif - } -} -#endif - /* * Air control, no real physics */ @@ -916,8 +868,9 @@ VG_STATIC void skate_apply_air_model( player_instance *player ) player__approximate_best_trajectory( player ); m3x3_mulv( s->state.velocity_bias, player->rb.v, player->rb.v ); - ray_hit hit; +#if 0 + ray_hit hit; /* * Prediction */ @@ -975,197 +928,24 @@ VG_STATIC void skate_apply_air_model( player_instance *player ) } time_to_impact += pstep; } +#endif - if( has_target ) - { - float angle = v3_dot( player->rb.to_world[1], target_normal ); - v3f axis; - v3_cross( player->rb.to_world[1], target_normal, axis ); - - limiter = vg_minf( 5.0f, time_to_impact )/5.0f; - limiter = 1.0f-limiter; - limiter *= limiter; - limiter = 1.0f-limiter; + float angle = v3_dot( player->rb.to_world[1], s->land_normal ); + angle = vg_clampf( angle, -1.0f, 1.0f ); + v3f axis; + v3_cross( player->rb.to_world[1], s->land_normal, axis ); -#if 0 - if( fabsf(angle) < 0.9999f ) - { - v4f correction; - q_axis_angle( correction, axis, - acosf(angle)*(1.0f-limiter)*2.0f*VG_TIMESTEP_FIXED ); - q_mul( correction, player->rb.q, player->rb.q ); - } -#endif - } + v4f correction; + q_axis_angle( correction, axis, + acosf(angle)*2.0f*VG_TIMESTEP_FIXED ); + q_mul( correction, player->rb.q, player->rb.q ); v2f steer = { player->input_js1h->axis.value, player->input_js1v->axis.value }; v2_normalize_clamp( steer ); - s->land_dist = time_to_impact; - v3_copy( target_normal, s->land_normal ); -} - -#if 0 -VG_STATIC void skate_get_board_points( player_instance *player, - v3f front, v3f back ) -{ - v3f pos_front = {0.0f,0.0f,-k_board_length}, - pos_back = {0.0f,0.0f, k_board_length}; - - m4x3_mulv( player->rb.to_world, pos_front, front ); - m4x3_mulv( player->rb.to_world, pos_back, back ); -} -#endif - -#if 0 -/* - * Casts and pushes a sphere-spring model into the world - */ -VG_STATIC int skate_simulate_spring( player_instance *player, - v3f pos ) -{ - struct player_skate *s = &player->_skate; - - float mod = 0.7f * player->input_grab->axis.value + 0.3f, - spring_k = mod * k_spring_force, - damp_k = mod * k_spring_dampener, - disp_k = 0.4f; - - v3f start, end; - v3_copy( pos, start ); - v3_muladds( pos, player->rb.to_world[1], -disp_k, end ); - - float t; - v3f n; - int hit_info = spherecast_world( start, end, 0.2f, &t, n ); - - if( hit_info != -1 ) - { - v3f F, delta; - v3_sub( start, player->rb.co, delta ); - - float displacement = vg_clampf( 1.0f-t, 0.0f, 1.0f ), - damp = - vg_maxf( 0.0f, v3_dot( player->rb.to_world[1], player->rb.v ) ); - - v3_muls( player->rb.to_world[1], displacement*spring_k*k_rb_delta - - damp*damp_k*k_rb_delta, F ); - - v3_muladds( player->rb.v, F, 1.0f, player->rb.v ); - - /* Angular velocity */ - v3f wa; - v3_cross( delta, F, wa ); - v3_muladds( player->rb.w, wa, k_spring_angular, player->rb.w ); - - v3_lerp( start, end, t, pos ); - return 1; - } - else - { - v3_copy( end, pos ); - return 0; - } -} -#endif - - -/* - * Handles connection between the player and the ground - * - * TODO: Must save original velocity to use here - */ -VG_STATIC void skate_apply_interface_model( player_instance *player, - rb_ct *manifold, int len ) -{ - struct player_skate *s = &player->_skate; - - /* springs */ - -#if 0 - v3f spring0, spring1; - - skate_get_board_points( player, spring1, spring0 ); - int spring_hit0 = 0, //skate_simulate_spring( player, s, spring0 ), - spring_hit1 = 0; //skate_simulate_spring( player, s, spring1 ); - - v3f animavg, animdelta; - v3_add( spring0, spring1, animavg ); - v3_muls( animavg, 0.5f, animavg ); - - v3_sub( spring1, spring0, animdelta ); - v3_normalize( animdelta ); - - m4x3_mulv( player->rb.to_local, animavg, s->board_offset ); - - float dx = -v3_dot( animdelta, player->rb.to_world[2] ), - dy = v3_dot( animdelta, player->rb.to_world[1] ); - - float angle = -atan2f( dy, dx ); - q_axis_angle( s->board_rotation, (v3f){1.0f,0.0f,0.0f}, angle ); - - int lift_frames_limit = 6; - - /* Surface connection */ - if( len == 0 && !(spring_hit0 && spring_hit1) ) - { - s->state.lift_frames ++; - - if( s->state.lift_frames >= lift_frames_limit ) - s->state.activity = k_skate_activity_air; - } - else - { - v3f surface_avg; - v3_zero( surface_avg ); - - for( int i=0; irb.v, surface_avg ) > 0.7f ) - { - s->state.lift_frames ++; - - if( s->state.lift_frames >= lift_frames_limit ) - s->state.activity = k_skate_activity_air; - } - else - { - s->state.activity = k_skate_activity_ground; - s->state.lift_frames = 0; - v3f projected, axis; - - if( s->state.activity_prev == k_skate_activity_air ) - { - player->cam_land_punch_v += v3_dot( player->rb.v, surface_avg ) * - k_cam_punch; - } - - float const DOWNFORCE = -k_downforce*VG_TIMESTEP_FIXED; - v3_muladds( player->rb.v, player->rb.to_world[1], - DOWNFORCE, player->rb.v ); - - float d = v3_dot( player->rb.to_world[2], surface_avg ); - v3_muladds( surface_avg, player->rb.to_world[2], -d, projected ); - v3_normalize( projected ); - - float angle = v3_dot( player->rb.to_world[1], projected ); - v3_cross( player->rb.to_world[1], projected, axis ); - -#if 0 - if( fabsf(angle) < 0.9999f ) - { - v4f correction; - q_axis_angle( correction, axis, - acosf(angle)*4.0f*VG_TIMESTEP_FIXED ); - q_mul( correction, player->rb.q, player->rb.q ); - } -#endif - } - } -#endif + //s->land_dist = time_to_impact; + s->land_dist = 1.0f; } VG_STATIC int player_skate_trick_input( player_instance *player ); @@ -1274,20 +1054,38 @@ VG_STATIC void skate_apply_steering_model( player_instance *player ) v3f steer_axis; v3_muls( player->rb.to_world[1], -vg_signf( steer_scaled ), steer_axis ); - float rate = 26.0f; + float rate = 26.0f, + top = 1.0f; if( s->state.activity == k_skate_activity_air ) { rate = 6.0f * fabsf(steer_scaled); + top = 1.5f; } else if( s->state.activity >= k_skate_activity_grind_any ) { rate *= fabsf(steer_scaled); + + float a = 0.8f * -steer_scaled * k_rb_delta; + + v4f q; + q_axis_angle( q, player->rb.to_world[1], a ); + q_mulv( q, s->grind_vec, s->grind_vec ); + +#if 0 + float tilt = player->input_js1v->axis.value; + tilt *= tilt * 0.8f * k_rb_delta; + + q_axis_angle( q, player->rb.to_world[0], tilt ); + q_mulv( q, s->grind_vec, s->grind_vec ); +#endif + + v3_normalize( s->grind_vec ); } float current = v3_dot( player->rb.to_world[1], player->rb.w ), - addspeed = (steer_scaled * -1.0f) - current, + addspeed = (steer_scaled * -top) - current, maxaccel = rate * k_rb_delta, accel = vg_clampf( addspeed, -maxaccel, maxaccel ); @@ -1595,13 +1393,17 @@ VG_STATIC void player__skate_post_update( player_instance *player ) { struct player_skate *s = &player->_skate; -#if 0 for( int i=0; iprediction_count; i++ ) { struct land_prediction *p = &s->predictions[i]; for( int j=0; jlog_length - 1; j ++ ) - vg_line( p->log[j], p->log[j+1], p->colour ); + { + float brightness = p->score*p->score*p->score; + v3f p1; + v3_lerp( p->log[j], p->log[j+1], brightness, p1 ); + vg_line( p->log[j], p1, p->colour ); + } vg_line_cross( p->log[p->log_length-1], p->colour, 0.25f ); @@ -1612,9 +1414,7 @@ VG_STATIC void player__skate_post_update( player_instance *player ) vg_line_pt3( p->apex, 0.02f, 0xffffffff ); } - vg_line_pt3( s->state.apex, 0.200f, 0xff0000ff ); - vg_line_pt3( s->state.apex, 0.201f, 0xff00ffff ); -#endif + vg_line_pt3( s->state.apex, 0.030f, 0xff0000ff ); } /* @@ -1863,63 +1663,95 @@ VG_STATIC void skate_grind_orient( struct grind_info *inf, m3x3f mtx ) v3_cross( mtx[0], mtx[1], mtx[2] ); } -VG_STATIC void skate_grind_truck_apply( player_instance *player, - v3f grind_co, struct grind_info *inf, - float strength ) +VG_STATIC void skate_grind_friction( player_instance *player, + struct grind_info *inf, float strength ) { - struct player_skate *s = &player->_skate; + v3f v2; + v3_muladds( player->rb.to_world[2], inf->n, + -v3_dot( player->rb.to_world[2], inf->n ), v2 ); - v3f delta; - v3_sub( inf->co, grind_co, delta ); + float a = 1.0f-fabsf( v3_dot( v2, inf->dir ) ), + dir = vg_signf( v3_dot( player->rb.v, inf->dir ) ), + F = a * -dir * k_grind_max_friction; + v3_muladds( player->rb.v, inf->dir, F*k_rb_delta*strength, player->rb.v ); +} + +VG_STATIC void skate_grind_decay( player_instance *player, + struct grind_info *inf, float strength ) +{ m3x3f mtx, mtx_inv; skate_grind_orient( inf, mtx ); m3x3_transpose( mtx, mtx_inv ); - /* decay 'force' */ v3f v_grind; m3x3_mulv( mtx_inv, player->rb.v, v_grind ); float decay = 1.0f - ( k_rb_delta * k_grind_decayxy * strength ); v3_mul( v_grind, (v3f){ 1.0f, decay, decay }, v_grind ); m3x3_mulv( mtx, v_grind, player->rb.v ); +} + +VG_STATIC void skate_grind_truck_apply( player_instance *player, + v3f grind_co, struct grind_info *inf, + float strength ) +{ + struct player_skate *s = &player->_skate; + + v3f delta; + v3_sub( inf->co, grind_co, delta ); /* spring force */ v3_muladds( player->rb.v, delta, k_spring_force*strength*k_rb_delta, player->rb.v ); - /* friction force */ - float a = 1.0f-fabsf( v3_dot( player->rb.to_world[2], inf->dir ) ), - dir = vg_signf( v3_dot( player->rb.v, inf->dir ) ), - F = a * -dir * k_grind_max_friction; + skate_grind_decay( player, inf, strength ); + skate_grind_friction( player, inf, strength ); - v3_muladds( player->rb.v, inf->dir, F*k_rb_delta*strength, player->rb.v ); + /* yeah yeah yeah yeah */ + v3f raw, axis; + v3_sub( grind_co, player->rb.co, raw ); + v3_muladds( raw, inf->n, -v3_dot( inf->n, raw ), raw ); + v3_cross( raw, inf->n, axis ); + v3_normalize( axis ); /* orientation */ - rb_effect_spring_target_vector( &player->rb, player->rb.to_world[1], - inf->n, + m3x3f mtx; + skate_grind_orient( inf, mtx ); + v3f target_fwd, fwd, up, target_up; + m3x3_mulv( mtx, s->grind_vec, target_fwd ); + v3_copy( raw, fwd ); + v3_copy( player->rb.to_world[1], up ); + v3_copy( inf->n, target_up ); + + v3_muladds( target_fwd, inf->n, -v3_dot(inf->n,target_fwd), target_fwd ); + v3_muladds( fwd, inf->n, -v3_dot(inf->n,fwd), fwd ); + + v3_normalize( target_fwd ); + v3_normalize( fwd ); + + float way = player->input_js1v->axis.value * + vg_signf( v3_dot( raw, player->rb.v ) ); + + v4f q; + q_axis_angle( q, axis, VG_PIf*0.125f * way ); + q_mulv( q, target_up, target_up ); + q_mulv( q, target_fwd, target_fwd ); + + rb_effect_spring_target_vector( &player->rb, up, target_up, k_grind_spring, k_grind_dampener, k_rb_delta ); - vg_line_arrow( player->rb.co, inf->n, 1.0f, VG__GREEN ); - - /* TODO: This was a nice idea, but we should just apply steering to the - * target vector instead of this strange feedback loop thing! */ - v3f target_fwd; - m3x3_mulv( mtx, s->grind_vec, target_fwd ); - rb_effect_spring_target_vector( &player->rb, player->rb.to_world[2], - target_fwd, + rb_effect_spring_target_vector( &player->rb, fwd, target_fwd, k_grind_spring*strength, k_grind_dampener*strength, k_rb_delta ); + vg_line_arrow( player->rb.co, target_up, 1.0f, VG__GREEN ); + vg_line_arrow( player->rb.co, fwd, 0.8f, VG__RED ); vg_line_arrow( player->rb.co, target_fwd, 1.0f, VG__YELOW ); - v3f new_target; - m3x3_mulv( mtx_inv, player->rb.to_world[2], new_target ); - v3_lerp( s->grind_vec, new_target, k_rb_delta * 0.1f, s->grind_vec ); - s->grind_strength = strength; /* Fake contact */ @@ -1931,6 +1763,7 @@ VG_STATIC void skate_grind_truck_apply( player_instance *player, VG_STATIC int skate_grind_truck_singular( player_instance *player, float sign ) { + struct player_skate *s = &player->_skate; struct grind_info inf; v3f wheel_co = { 0.0f, 0.0f, sign * k_board_length }, @@ -1940,7 +1773,7 @@ VG_STATIC int skate_grind_truck_singular( player_instance *player, float sign ) m4x3_mulv( player->rb.to_world, grind_co, grind_co ); /* Exit condition: lost grind tracking */ - if( !skate_grind_scansq( player, grind_co, player->rb.v, 0.3f, &inf ) ) + if( !skate_grind_scansq( grind_co, player->rb.v, 0.3f, &inf ) ) return 0; /* Exit condition: cant see grind target directly */ @@ -1954,6 +1787,11 @@ VG_STATIC int skate_grind_truck_singular( player_instance *player, float sign ) if( dv < minv ) return 0; + if( fabsf(v3_dot( inf.dir, s->grind_dir )) < k_grind_max_edge_angle ) + return 0; + + v3_copy( inf.dir, s->grind_dir ); + float t = vg_clampf( (dv-minv)/(k_grind_axel_min_vel-minv), 0.0f, 1.0f ); skate_grind_truck_apply( player, grind_co, &inf, t ); return 1; @@ -1971,9 +1809,7 @@ VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign ) m3x3_mulv( player->rb.to_world, ra, raw ); v3_add( player->rb.co, raw, wsp ); - if( skate_grind_scansq( player, - wsp, player->rb.v, 0.3, - &inf ) ) + if( skate_grind_scansq( wsp, player->rb.v, 0.3, &inf ) ) { if( fabsf(v3_dot( player->rb.v, inf.dir )) < k_grind_axel_min_vel ) return 0; @@ -1990,6 +1826,11 @@ VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign ) if( fabsf(v3_dot( pv, inf.dir )) < k_grind_axel_max_angle ) return 0; + /* check for vertical alignment */ + if( v3_dot( player->rb.to_world[1], inf.n ) < k_grind_axel_max_vangle ) + return 0; + + /* TODO: new condition, opposite wheel MUST be in-air or close to it */ v3f local_co, local_dir, local_n; m4x3_mulv( player->rb.to_local, inf.co, local_co ); @@ -2011,7 +1852,9 @@ VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign ) m3x3f mtx; skate_grind_orient( &inf, mtx ); m3x3_transpose( mtx, mtx ); - m3x3_mulv( mtx, player->rb.to_world[2], s->grind_vec ); + m3x3_mulv( mtx, raw, s->grind_vec ); + v3_normalize( s->grind_vec ); + v3_copy( inf.dir, s->grind_dir ); skate_grind_truck_apply( player, wsp, &inf, 1.0f ); return 1; @@ -2021,81 +1864,131 @@ VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign ) return 0; } -VG_STATIC enum skate_activity skate_availible_grind( player_instance *player ) +VG_STATIC void skate_boardslide_apply( player_instance *player, + struct grind_info *inf ) { struct player_skate *s = &player->_skate; - /* - * BOARDSLIDE - * ------------------------------------ - */ + v3f local_co, local_dir, local_n; + m4x3_mulv( player->rb.to_local, inf->co, local_co ); + m3x3_mulv( player->rb.to_local, inf->dir, local_dir ); + m3x3_mulv( player->rb.to_local, inf->n, local_n ); + + v3f intersection; + v3_muladds( local_co, local_dir, local_co[0]/-local_dir[0], + intersection ); + v3_copy( intersection, s->weight_distribution ); - struct grind_info grind_center; - if( skate_grind_scansq( player, - player->rb.co, + skate_grind_decay( player, inf, 0.1f ); + skate_grind_friction( player, inf, 0.25f ); + + /* direction alignment */ + v3f dir, perp; + v3_cross( local_dir, local_n, perp ); + v3_muls( local_dir, vg_signf(local_dir[0]), dir ); + v3_muls( perp, vg_signf(perp[2]), perp ); + + m3x3_mulv( player->rb.to_world, dir, dir ); + m3x3_mulv( player->rb.to_world, perp, perp ); + + rb_effect_spring_target_vector( &player->rb, player->rb.to_world[0], + dir, + k_grind_spring, k_grind_dampener, + k_rb_delta ); + + rb_effect_spring_target_vector( &player->rb, player->rb.to_world[2], + perp, + k_grind_spring, k_grind_dampener, + k_rb_delta ); + + vg_line_arrow( player->rb.co, dir, 0.5f, VG__GREEN ); + vg_line_arrow( player->rb.co, perp, 0.5f, VG__BLUE ); +} + +VG_STATIC int skate_boardslide_entry_condition( player_instance *player ) +{ + struct player_skate *s = &player->_skate; + + struct grind_info inf; + if( skate_grind_scansq( player->rb.co, player->rb.to_world[0], k_board_length, - &grind_center ) ) + &inf ) ) { - v3f local_co, local_dir, local_n; - m4x3_mulv( player->rb.to_local, grind_center.co, local_co ); - m3x3_mulv( player->rb.to_local, grind_center.dir, local_dir ); - m3x3_mulv( player->rb.to_local, grind_center.n, local_n ); + v3f local_co, local_dir; + m4x3_mulv( player->rb.to_local, inf.co, local_co ); + m3x3_mulv( player->rb.to_local, inf.dir, local_dir ); if( (fabsf(local_co[2]) <= k_board_length) && /* within wood area */ (local_co[1] >= 0.0f) && /* at deck level */ (fabsf(local_dir[0]) >= 0.5f) ) /* perpendicular to us */ { - /* compute position on center line */ + if( fabsf(v3_dot( player->rb.v, inf.dir )) < k_grind_axel_min_vel ) + return 0; - v3f intersection; - v3_muladds( local_co, local_dir, local_co[0]/-local_dir[0], - intersection ); - v3_copy( intersection, s->weight_distribution ); + v3_copy( inf.dir, s->grind_dir ); + skate_boardslide_apply( player, &inf ); + return 1; + } + } - /* TODO: alignment & strengths should be proportional to speed */ - /* dont apply correction in connecting velocities */ - /* friciton */ + return 0; +} - v3f ideal_v, diff; - v3_muls( grind_center.dir, - v3_dot( player->rb.v, grind_center.dir ), ideal_v ); +VG_STATIC int skate_boardslide_singular( player_instance *player ) +{ + struct player_skate *s = &player->_skate; - v3_sub( ideal_v, player->rb.v, diff ); - v3_muladds( player->rb.v, diff, k_grind_aligment * k_rb_delta, - player->rb.v ); + struct grind_info inf; + if( !skate_grind_scansq( player->rb.co, + player->rb.to_world[0], k_board_length, + &inf ) ) + return 0; + /* Exit condition: cant see grind target directly */ + v3f vis; + v3_muladds( player->rb.co, player->rb.to_world[1], 0.2f, vis ); + if( !skate_point_visible( vis, inf.co ) ) + return 0; - /* direction alignment */ - v3f dir, perp; - v3_cross( local_dir, local_n, perp ); - v3_muls( local_dir, vg_signf(local_dir[0]), dir ); - v3_muls( perp, vg_signf(perp[2]), perp ); + /* Exit condition: minimum velocity not reached, but allow a bit of error + * TODO: trash compactor */ + float dv = fabsf(v3_dot( player->rb.v, inf.dir )), + minv = k_grind_axel_min_vel*0.8f; - m3x3_mulv( player->rb.to_world, dir, dir ); - m3x3_mulv( player->rb.to_world, perp, perp ); + if( dv < minv ) + return 0; - rb_effect_spring_target_vector( &player->rb, player->rb.to_world[0], - dir, - k_grind_spring, k_grind_dampener, - k_rb_delta ); + if( fabsf(v3_dot( inf.dir, s->grind_dir )) < k_grind_max_edge_angle ) + return 0; + v3_copy( inf.dir, s->grind_dir ); - rb_effect_spring_target_vector( &player->rb, player->rb.to_world[2], - perp, - k_grind_spring, k_grind_dampener, - k_rb_delta ); + float t = vg_clampf( (dv-minv)/(k_grind_axel_min_vel-minv), 0.0f, 1.0f ); - vg_line_arrow( player->rb.co, dir, 0.5f, VG__GREEN ); - vg_line_arrow( player->rb.co, perp, 0.5f, VG__BLUE ); + skate_boardslide_apply( player, &inf ); + return 1; +} - return k_skate_activity_grind_boardslide; - } - } +VG_STATIC enum skate_activity skate_availible_grind( player_instance *player ) +{ + struct player_skate *s = &player->_skate; + + if( s->state.activity == k_skate_activity_grind_boardslide ) + { + int result = skate_boardslide_singular( player ); + const enum skate_activity table[] = + { + k_skate_activity_undefined, + k_skate_activity_grind_boardslide + }; + + return table[ result ]; + } if( s->state.activity == k_skate_activity_grind_back50 ) { int result = skate_grind_truck_singular( player, 1.0f ), - front = skate_truck_entry_condition( player, -1.0f ); + front = 0;//skate_truck_entry_condition( player, -1.0f ); const enum skate_activity table[] = { /* result | front */ @@ -2110,7 +2003,7 @@ VG_STATIC enum skate_activity skate_availible_grind( player_instance *player ) else if( s->state.activity == k_skate_activity_grind_front50 ) { int result = skate_grind_truck_singular( player, -1.0f ), - back = skate_truck_entry_condition( player, 1.0f ); + back = 0;//skate_truck_entry_condition( player, 1.0f ); const enum skate_activity table[] = { /* result | back */ @@ -2129,6 +2022,11 @@ VG_STATIC enum skate_activity skate_availible_grind( player_instance *player ) } else { + int slide = skate_boardslide_entry_condition( player ); + + if( slide ) + return k_skate_activity_grind_boardslide; + int front = skate_truck_entry_condition( player, -1.0f ), back = skate_truck_entry_condition( player, 1.0f ); @@ -2146,11 +2044,6 @@ VG_STATIC enum skate_activity skate_availible_grind( player_instance *player ) return 0; } -VG_STATIC void skate_grind_boardslide( player_instance *player ) -{ - -} - VG_STATIC void player__skate_update( player_instance *player ) { struct player_skate *s = &player->_skate; @@ -2436,6 +2329,13 @@ begin_collision:; int l = rb_capsule__scene( mtx, &capsule, NULL, &world.rb_geo.inf.scene, cman ); + + /* weld joints */ + for( int i=0; i