X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player_device_skate.h;fp=player_device_skate.h;h=0000000000000000000000000000000000000000;hb=e3bf80ff27b675f5e7f87dcebd16fab6fe08df7a;hp=d657b4a20440784e70d811d9ff0f9f96cf3261dc;hpb=5430d708f058626a6c8fed7dd2aa8ba5f0a06c84;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player_device_skate.h b/player_device_skate.h deleted file mode 100644 index d657b4a..0000000 --- a/player_device_skate.h +++ /dev/null @@ -1,1769 +0,0 @@ -#ifndef PLAYER_DEVICE_SKATE_H -#define PLAYER_DEVICE_SKATE_H - -#include "player_interface.h" -#include "skeleton.h" -#include "player_model.h" -#include "player_device_common.h" - -VG_STATIC -struct player_device_skate -{ - struct - { - enum skate_activity - { - k_skate_activity_air, - k_skate_activity_ground, - k_skate_activity_grind - } - activity, - activity_prev; - - float steery, - steerx, - steery_s, - steerx_s, - reverse, - slip; - - v3f flip_axis; - float flip_time, - flip_rate; - - m3x3f velocity_bias, - velocity_bias_pstep; - v3f apex; - - int lift_frames; - - v3f throw_v; - v3f cog_v, cog; - - float grabbing; - v2f grab_mouse_delta; - - int charging_jump, jump_dir; - float jump_charge; - double jump_time; - - double start_push, - cur_push; - - v3f prev_pos; - - /* FIXME: Sensible names */ - v3f vl, /* 1st */ - posl, dirl; /* 3rd */ - } - state, - state_gate_storage; - - struct land_prediction - { - v3f log[50]; - v3f n; - v3f apex; - u32 log_length; - float score, - land_dist; - - enum prediction_type - { - k_prediction_none, - k_prediction_land, - k_prediction_grind - } - type; - - u32 colour; - } - predictions[22]; - u32 prediction_count; - float land_dist; - v3f land_normal; - - /* animation */ - struct skeleton_anim *anim_stand, *anim_highg, *anim_slide, - *anim_air, - *anim_push, *anim_push_reverse, - *anim_ollie, *anim_ollie_reverse, - *anim_grabs, *anim_stop; - rb_sphere sphere_front, sphere_back; - v3f board_offset; - v4f board_rotation; - - float blend_slide, - blend_z, - blend_x, - blend_fly, - blend_stand, - blend_push, - blend_jump, - blend_airdir; - - v2f wobble; - - float debug_normal_pressure; - u32 device_id_walk; -} -localplayer_device_skate; - -VG_STATIC void player_skate_bind( player_device *dev, - player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - struct player_avatar *av = player->playeravatar; - struct skeleton *sk = &av->sk; - - rb_update_transform( &player->rb ); - s->anim_stand = skeleton_get_anim( sk, "pose_stand" ); - s->anim_highg = skeleton_get_anim( sk, "pose_highg" ); - s->anim_air = skeleton_get_anim( sk, "pose_air" ); - s->anim_slide = skeleton_get_anim( sk, "pose_slide" ); - s->anim_push = skeleton_get_anim( sk, "push" ); - s->anim_push_reverse = skeleton_get_anim( sk, "push_reverse" ); - s->anim_ollie = skeleton_get_anim( sk, "ollie" ); - s->anim_ollie_reverse = skeleton_get_anim( sk, "ollie_reverse" ); - s->anim_grabs = skeleton_get_anim( sk, "grabs" ); - - s->device_id_walk = player_get_device( player, "walk" ); -} - -/* - * Collision detection routines - * - * - */ - -/* - * Does collision detection on a sphere vs world, and applies some smoothing - * filters to the manifold afterwards - */ -VG_STATIC int skate_collide_smooth( player_interface *player, - m4x3f mtx, rb_sphere *sphere, - rb_ct *man ) -{ - debug_sphere( mtx, sphere->radius, VG__BLACK ); - - int len = 0; - len = rb_sphere__scene( mtx, sphere, NULL, &world.rb_geo.inf.scene, man ); - - for( int i=0; irb; - man[i].rbb = NULL; - } - - rb_manifold_filter_coplanar( man, len, 0.05f ); - - 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 ); - } - int new_len = rb_manifold_apply_filtered( man, len ); - if( len && !new_len ) - len = 1; - else - len = new_len; - - return len; -} -/* - * Gets the closest grindable edge to the player within max_dist - */ -VG_STATIC struct grind_edge *skate_collect_grind_edge( v3f p0, v3f p1, - v3f c0, v3f c1, - float max_dist ) -{ - bh_iter it; - bh_iter_init( 0, &it ); - - boxf region; - - box_init_inf( region ); - box_addpt( region, p0 ); - box_addpt( region, p1 ); - - float k_r = max_dist; - v3_add( (v3f){ k_r, k_r, k_r}, region[1], region[1] ); - v3_add( (v3f){-k_r,-k_r,-k_r}, region[0], region[0] ); - - float closest = k_r*k_r; - struct grind_edge *closest_edge = NULL; - - int idx; - while( bh_next( world.grind_bh, &it, region, &idx ) ) - { - struct grind_edge *edge = &world.grind_edges[ idx ]; - - float s,t; - v3f pa, pb; - - float d2 = - closest_segment_segment( p0, p1, edge->p0, edge->p1, &s,&t, pa, pb ); - - if( d2 < closest ) - { - closest = d2; - closest_edge = edge; - v3_copy( pa, c0 ); - v3_copy( pb, c1 ); - } - } - - return closest_edge; -} - -VG_STATIC int skate_grind_collide( player_device *dev, - player_interface *player, - rb_ct *contact ) -{ - v3f p0, p1, c0, c1; - v3_muladds( player->rb.co, player->rb.to_world[2], 0.5f, p0 ); - v3_muladds( player->rb.co, player->rb.to_world[2], -0.5f, p1 ); - v3_muladds( p0, player->rb.to_world[1], 0.125f-0.15f, p0 ); - v3_muladds( p1, player->rb.to_world[1], 0.125f-0.15f, p1 ); - - float const k_r = 0.25f; - struct grind_edge *closest_edge = skate_collect_grind_edge( p0, p1, - c0, c1, k_r ); - - if( closest_edge ) - { - v3f delta; - v3_sub( c1, c0, delta ); - - if( v3_dot( delta, player->rb.to_world[1] ) > 0.0001f ) - { - contact->p = v3_length( delta ); - contact->type = k_contact_type_edge; - contact->element_id = 0; - v3_copy( c1, contact->co ); - contact->rba = NULL; - contact->rbb = NULL; - - v3f edge_dir, axis_dir; - v3_sub( closest_edge->p1, closest_edge->p0, edge_dir ); - v3_normalize( edge_dir ); - v3_cross( (v3f){0.0f,1.0f,0.0f}, edge_dir, axis_dir ); - v3_cross( edge_dir, axis_dir, contact->n ); - - return 1; - } - else - return 0; - } - - return 0; -} - -/* - * - * Prediction system - * - * - */ - -/* - * Trace a path given a velocity rotation. - * - * TODO: this MIGHT be worth doing RK4 on the gravity field. - */ -VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, - struct land_prediction *prediction ) -{ - float pstep = VG_TIMESTEP_FIXED * 10.0f; - float k_bias = 0.96f; - - v3f pco, pco1, pv; - v3_copy( co, pco ); - v3_muls( v, k_bias, pv ); - - m3x3_mulv( vr, pv, pv ); - v3_muladds( pco, pv, pstep, pco ); - - struct grind_edge *best_grind = NULL; - float closest_grind = INFINITY; - - float grind_score = INFINITY, - air_score = INFINITY, - time_to_impact = 0.0f; - - prediction->log_length = 0; - v3_copy( pco, prediction->apex ); - - for( int i=0; ilog); i++ ) - { - v3_copy( pco, pco1 ); - - pv[1] += -k_gravity * pstep; - - m3x3_mulv( vr, pv, pv ); - v3_muladds( pco, pv, pstep, pco ); - - if( pco[1] > prediction->apex[1] ) - v3_copy( pco, prediction->apex ); - - v3f vdir; - - v3_sub( pco, pco1, vdir ); - - float l = v3_length( vdir ); - v3_muls( vdir, 1.0f/l, vdir ); - - v3f c0, c1; - struct grind_edge *ge = skate_collect_grind_edge( pco, pco1, - c0, c1, 0.4f ); - - if( ge && (v3_dot((v3f){0.0f,1.0f,0.0f},vdir) < -0.2f ) ) - { - float d2 = v3_dist2( c0, c1 ); - if( d2 < closest_grind ) - { - closest_grind = d2; - best_grind = ge; - grind_score = closest_grind * 0.05f; - } - } - - v3f n1; - - float t1; - int idx = spherecast_world( pco1, pco, 0.4f, &t1, n1 ); - if( idx != -1 ) - { - v3_copy( n1, prediction->n ); - air_score = -v3_dot( pv, n1 ); - - u32 vert_index = world.scene_geo->arrindices[ idx*3 ]; - struct world_material *mat = world_tri_index_material( vert_index ); - - /* Bias prediction towords ramps */ - if( mat->info.flags & k_material_flag_skate_surface ) - air_score *= 0.1f; - - v3_lerp( pco1, pco, t1, prediction->log[ prediction->log_length ++ ] ); - time_to_impact += t1 * pstep; - break; - } - - time_to_impact += pstep; - v3_copy( pco, prediction->log[ prediction->log_length ++ ] ); - } - - if( grind_score < air_score ) - { - prediction->score = grind_score; - prediction->type = k_prediction_grind; - } - else if( air_score < INFINITY ) - { - prediction->score = air_score; - prediction->type = k_prediction_land; - } - else - { - prediction->score = INFINITY; - prediction->type = k_prediction_none; - } - - prediction->land_dist = time_to_impact; -} - -VG_STATIC -void player_approximate_best_trajectory( player_interface *player, - struct player_device_skate *s ) -{ - float pstep = VG_TIMESTEP_FIXED * 10.0f; - float best_velocity_delta = -9999.9f; - - v3f axis; - v3_cross( player->rb.to_world[1], player->rb.v, axis ); - v3_normalize( axis ); - - s->prediction_count = 0; - m3x3_identity( s->state.velocity_bias ); - - float best_vmod = 0.0f, - min_score = INFINITY, - max_score = -INFINITY; - - v3_zero( s->state.apex ); - s->land_dist = 0.0f; - - /* - * Search a broad selection of futures - */ - for( int m=-3;m<=12; m++ ) - { - struct land_prediction *p = &s->predictions[ s->prediction_count ++ ]; - - float vmod = ((float)m / 15.0f)*0.09f; - - m3x3f bias; - v4f bias_q; - - q_axis_angle( bias_q, axis, vmod ); - q_m3x3( bias_q, bias ); - - skate_score_biased_path( player->rb.co, player->rb.v, bias, p ); - - if( p->type != k_prediction_none ) - { - if( p->score < min_score ) - { - min_score = p->score; - best_vmod = vmod; - s->land_dist = p->land_dist; - v3_copy( p->apex, s->state.apex ); - } - - if( p->score > max_score ) - max_score = p->score; - } - } - - v4f vr_q; - q_axis_angle( vr_q, axis, best_vmod*0.1f ); - q_m3x3( vr_q, s->state.velocity_bias ); - - q_axis_angle( vr_q, axis, best_vmod ); - q_m3x3( vr_q, s->state.velocity_bias_pstep ); - - /* - * Logging - */ - for( int i=0; iprediction_count; i ++ ) - { - struct land_prediction *p = &s->predictions[i]; - - float l = p->score; - - if( l < 0.0f ) - { - vg_error( "negative score! (%f)\n", l ); - } - - l -= min_score; - l /= (max_score-min_score); - l = 1.0f - l; - l *= 255.0f; - - p->colour = l; - p->colour <<= 8; - p->colour |= 0xff000000; - } - - - v2f steer = { player->input_js1h->axis.value, - player->input_js1v->axis.value }; - v2_normalize_clamp( steer ); - - if( (fabsf(steer[1]) > 0.5f) && (s->land_dist >= 1.0f) ) - { - s->state.flip_rate = (1.0f/s->land_dist) * vg_signf(steer[1]) * - s->state.reverse ; - s->state.flip_time = 0.0f; - v3_copy( player->rb.to_world[0], s->state.flip_axis ); - } - else - { - s->state.flip_rate = 0.0f; - v3_zero( s->state.flip_axis ); - } -} - -/* - * - * Varius physics models - * ------------------------------------------------ - */ - -VG_STATIC void skate_apply_grind_model( player_interface *player, - struct player_device_skate *s, - rb_ct *manifold, int len ) -{ - /* 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 ); - - 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; - -#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 - } -} - -/* - * Air control, no real physics - */ -VG_STATIC void skate_apply_air_model( player_interface *player, - struct player_device_skate *s ) -{ - if( s->state.activity != k_skate_activity_air ) - return; - - if( s->state.activity_prev != k_skate_activity_air ) - player_approximate_best_trajectory( player, s ); - - m3x3_mulv( s->state.velocity_bias, player->rb.v, player->rb.v ); - ray_hit hit; - - /* - * Prediction - */ - float pstep = VG_TIMESTEP_FIXED * 1.0f; - float k_bias = 0.98f; - - v3f pco, pco1, pv; - v3_copy( player->rb.co, pco ); - v3_muls( player->rb.v, 1.0f, pv ); - - float time_to_impact = 0.0f; - float limiter = 1.0f; - - struct grind_edge *best_grind = NULL; - float closest_grind = INFINITY; - - v3f target_normal = { 0.0f, 1.0f, 0.0f }; - int has_target = 0; - - for( int i=0; i<250; i++ ) - { - v3_copy( pco, pco1 ); - m3x3_mulv( s->state.velocity_bias, pv, pv ); - - pv[1] += -k_gravity * pstep; - v3_muladds( pco, pv, pstep, pco ); - - ray_hit contact; - v3f vdir; - - v3_sub( pco, pco1, vdir ); - contact.dist = v3_length( vdir ); - v3_divs( vdir, contact.dist, vdir); - - v3f c0, c1; - struct grind_edge *ge = skate_collect_grind_edge( pco, pco1, - c0, c1, 0.4f ); - - if( ge && (v3_dot((v3f){0.0f,1.0f,0.0f},vdir) < -0.2f ) ) - { - vg_line( ge->p0, ge->p1, 0xff0000ff ); - vg_line_cross( pco, 0xff0000ff, 0.25f ); - has_target = 1; - break; - } - - float orig_dist = contact.dist; - if( ray_world( pco1, vdir, &contact ) ) - { - v3_copy( contact.normal, target_normal ); - has_target = 1; - time_to_impact += (contact.dist/orig_dist)*pstep; - vg_line_cross( contact.pos, 0xffff0000, 0.25f ); - break; - } - time_to_impact += pstep; - } - - 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; - - if( fabsf(angle) < 0.99f ) - { - 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 ); - } - } - - v2f steer = { player->input_js1h->axis.value, - player->input_js1v->axis.value }; - v2_normalize_clamp( steer ); - - s->state.steery -= steer[0] * k_steer_air * VG_TIMESTEP_FIXED; - s->state.steerx += steer[1] * s->state.reverse * k_steer_air - * limiter * k_rb_delta; - s->land_dist = time_to_impact; - v3_copy( target_normal, s->land_normal ); -} - -VG_STATIC void skate_get_board_points( player_interface *player, - struct player_device_skate *s, - 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 ); -} - -/* - * Casts and pushes a sphere-spring model into the world - */ -VG_STATIC int skate_simulate_spring( player_interface *player, - struct player_device_skate *s, - v3f pos ) -{ - 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; - } -} - - -/* - * Handles connection between the player and the ground - */ -VG_STATIC void skate_apply_interface_model( player_interface *player, - struct player_device_skate *s, - rb_ct *manifold, int len ) -{ - if( !((s->state.activity == k_skate_activity_ground) || - (s->state.activity == k_skate_activity_air )) ) - return; - - if( s->state.activity == k_skate_activity_air ) - s->debug_normal_pressure = 0.0f; - else - s->debug_normal_pressure = v3_dot( player->rb.to_world[1], player->rb.v ); - - /* springs */ - v3f spring0, spring1; - - skate_get_board_points( player, s, 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; - - 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( 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 ); - } - } - } -} - -VG_STATIC void skate_apply_grab_model( player_interface *player, - struct player_device_skate *s ) -{ - float grabt = player->input_grab->axis.value; - - if( grabt > 0.5f ) - { - v2_muladds( s->state.grab_mouse_delta, vg.mouse_delta, 0.02f, - s->state.grab_mouse_delta ); - - v2_normalize_clamp( s->state.grab_mouse_delta ); - } - else - v2_zero( s->state.grab_mouse_delta ); - - s->state.grabbing = vg_lerpf( s->state.grabbing, grabt, 8.4f*k_rb_delta ); -} - -/* - * Computes friction and surface interface model - */ -VG_STATIC void skate_apply_friction_model( player_interface *player, - struct player_device_skate *s ) -{ - if( s->state.activity != k_skate_activity_ground ) - return; - - /* - * 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; - - s->state.slip = slip; - s->state.reverse = -vg_signf(vel[2]); - - vel[0] += vg_cfrictf( vel[0], k_friction_lat * k_rb_delta ); - vel[2] += vg_cfrictf( vel[2], k_friction_resistance * k_rb_delta ); - - /* Pushing additive force */ - - if( !player->input_jump->button.value ) - { - if( player->input_push->button.value ) - { - if( (vg.time - s->state.cur_push) > 0.25 ) - s->state.start_push = vg.time; - - s->state.cur_push = vg.time; - - double push_time = vg.time - s->state.start_push; - - float cycle_time = push_time*k_push_cycle_rate, - accel = k_push_accel * (sinf(cycle_time)*0.5f+0.5f), - amt = accel * VG_TIMESTEP_FIXED, - current = v3_length( vel ), - new_vel = vg_minf( current + amt, k_max_push_speed ), - delta = new_vel - vg_minf( current, k_max_push_speed ); - - vel[2] += delta * -s->state.reverse; - } - } - - /* Send back to velocity */ - m3x3_mulv( player->rb.to_world, vel, player->rb.v ); - - /* Steering */ - float input = player->input_js1h->axis.value, - grab = player->input_grab->axis.value, - steer = input * (1.0f-(s->state.jump_charge+grab)*0.4f), - steer_scaled = vg_signf(steer) * powf(steer,2.0f) * k_steer_ground; - - s->state.steery -= steer_scaled * k_rb_delta; -} - -VG_STATIC void skate_apply_jump_model( player_interface *player, - struct player_device_skate *s ) -{ - int charging_jump_prev = s->state.charging_jump; - s->state.charging_jump = player->input_jump->button.value; - - /* Cannot charge this in air */ - if( s->state.activity != k_skate_activity_ground ) - s->state.charging_jump = 0; - - if( s->state.charging_jump ) - { - s->state.jump_charge += k_rb_delta * k_jump_charge_speed; - - if( !charging_jump_prev ) - s->state.jump_dir = s->state.reverse>0.0f? 1: 0; - } - else - { - s->state.jump_charge -= k_jump_charge_speed * VG_TIMESTEP_FIXED; - } - - s->state.jump_charge = vg_clampf( s->state.jump_charge, 0.0f, 1.0f ); - - if( s->state.activity == k_skate_activity_air ) - return; - - /* player let go after charging past 0.2: trigger jump */ - if( (!s->state.charging_jump) && (s->state.jump_charge > 0.2f) ) - { - v3f jumpdir; - - /* Launch more up if alignment is up else improve velocity */ - float aup = v3_dot( (v3f){0.0f,1.0f,0.0f}, player->rb.to_world[1] ), - mod = 0.5f, - dir = mod + fabsf(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.to_world[1], dir, jumpdir ); - v3_normalize( jumpdir ); - - float force = k_jump_force*s->state.jump_charge; - v3_muladds( player->rb.v, jumpdir, force, player->rb.v ); - s->state.jump_charge = 0.0f; - - s->state.jump_time = vg.time; - - v2f steer = { player->input_js1h->axis.value, - player->input_js1v->axis.value }; - v2_normalize_clamp( steer ); - - float maxspin = k_steer_air * k_rb_delta * k_spin_boost; - s->state.steery_s = -steer[0] * maxspin; - s->state.steerx = s->state.steerx_s; - - /* FIXME audio events */ -#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_jumps[rand()%2] ); - audio_unlock(); -#endif - } -} - -VG_STATIC void skate_apply_pump_model( player_interface *player, - struct player_device_skate *s ) -{ - /* Throw / collect routine - * - * TODO: Max speed boost - */ - if( player->input_grab->axis.value > 0.5f ) - { - if( s->state.activity == k_skate_activity_ground ) - { - /* Throw */ - v3_muls( player->rb.to_world[1], k_mmthrow_scale, s->state.throw_v ); - } - } - else - { - /* Collect */ - float doty = v3_dot( player->rb.to_world[1], s->state.throw_v ); - - v3f Fl, Fv; - v3_muladds( s->state.throw_v, player->rb.to_world[1], -doty, Fl); - - if( s->state.activity == k_skate_activity_ground ) - { - v3_muladds( player->rb.v, Fl, k_mmcollect_lat, player->rb.v ); - v3_muladds( s->state.throw_v, Fl, -k_mmcollect_lat, s->state.throw_v ); - } - - v3_muls( player->rb.to_world[1], -doty, Fv ); - v3_muladds( player->rb.v, Fv, k_mmcollect_vert, player->rb.v ); - v3_muladds( s->state.throw_v, Fv, k_mmcollect_vert, s->state.throw_v ); - } - - /* Decay */ - if( v3_length2( s->state.throw_v ) > 0.0001f ) - { - v3f dir; - v3_copy( s->state.throw_v, dir ); - v3_normalize( dir ); - - float max = v3_dot( dir, s->state.throw_v ), - amt = vg_minf( k_mmdecay * k_rb_delta, max ); - v3_muladds( s->state.throw_v, dir, -amt, s->state.throw_v ); - } -} - -VG_STATIC void skate_apply_cog_model( player_interface *player, - struct player_device_skate *s ) -{ - v3f ideal_cog, ideal_diff; - v3_muladds( player->rb.co, player->rb.to_world[1], - 1.0f-player->input_grab->axis.value, ideal_cog ); - v3_sub( ideal_cog, s->state.cog, ideal_diff ); - - /* Apply velocities */ - v3f rv; - v3_sub( player->rb.v, s->state.cog_v, rv ); - - v3f F; - v3_muls( ideal_diff, -k_cog_spring * k_rb_rate, F ); - v3_muladds( F, rv, -k_cog_damp * k_rb_rate, F ); - - float ra = k_cog_mass_ratio, - rb = 1.0f-k_cog_mass_ratio; - - /* Apply forces & intergrate */ - v3_muladds( s->state.cog_v, F, -rb, s->state.cog_v ); - s->state.cog_v[1] += -9.8f * k_rb_delta; - v3_muladds( s->state.cog, s->state.cog_v, k_rb_delta, s->state.cog ); -} - -VG_STATIC void skate_collision_response( player_interface *player, - struct player_device_skate *s, - rb_ct *manifold, int len ) -{ - for( int j=0; j<10; j++ ) - { - for( int i=0; ico, 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.to_world[2] )) > 10.0f || - fabsf(v3_dot( impulse, player->rb.to_world[1] )) > 50.0f ) - { - /* FIXME */ -#if 0 - player_kill(); - return; -#endif - } - - 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.to_world[1], impulse ) * 0.8f, - wx = v3_dot( player->rb.to_world[0], impulse ) * 1.0f; - - v3_muladds( player->rb.w, player->rb.to_world[1], wy, player->rb.w ); - v3_muladds( player->rb.w, player->rb.to_world[0], wx, player->rb.w ); - } - } -} - -VG_STATIC void skate_integrate( player_interface *player, - struct player_device_skate *s ) -{ - /* integrate rigidbody velocities */ - v3f gravity = { 0.0f, -9.6f, 0.0f }; - v3_muladds( player->rb.v, gravity, k_rb_delta, player->rb.v ); - v3_muladds( player->rb.co, player->rb.v, k_rb_delta, player->rb.co ); - - float decay_rate = 0.5f*0.125f; - - if( s->state.activity == k_skate_activity_air ) - { - float dist = 1.0f-(s->land_dist/4.0f); - decay_rate = 0.5f * vg_maxf( dist*dist, 0.0f ); - } - - v3_lerp( player->rb.w, (v3f){0.0f,0.0f,0.0f}, decay_rate, player->rb.w ); - - if( v3_length2( player->rb.w ) > 0.0f ) - { - v4f rotation; - v3f axis; - v3_copy( player->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 ); - } - - /* integrate steering velocities */ - v4f rotate; - float l = (s->state.activity == k_skate_activity_air)? 0.04f: 0.24f; - - s->state.steery_s = vg_lerpf( s->state.steery_s, s->state.steery, l ); - s->state.steerx_s = vg_lerpf( s->state.steerx_s, s->state.steerx, l ); - - q_axis_angle( rotate, player->rb.to_world[1], s->state.steery_s ); - q_mul( rotate, player->rb.q, player->rb.q ); - - q_axis_angle( rotate, player->rb.to_world[0], s->state.steerx_s ); - q_mul( rotate, player->rb.q, player->rb.q ); - - s->state.steerx = 0.0f; - s->state.steery = 0.0f; - -#if 0 - v3_sub( player.rb.v, s->phys.v_prev, s->phys.a ); - v3_muls( s->phys.a, 1.0f/VG_TIMESTEP_FIXED, s->phys.a ); - v3_copy( player.rb.v, s->phys.v_prev ); -#endif - - s->state.flip_time += s->state.flip_rate * k_rb_delta; - rb_update_transform( &player->rb ); -} - -VG_STATIC void player_skate_update( player_device *dev, - player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - v3_copy( player->rb.co, s->state.prev_pos ); - s->state.activity_prev = s->state.activity; - - /* Setup colliders */ - m4x3f mtx_front, mtx_back; - m3x3_identity( mtx_front ); - m3x3_identity( mtx_back ); - - skate_get_board_points( player, s, mtx_front[3], mtx_back[3] ); - - s->sphere_back.radius = 0.3f; - s->sphere_front.radius = 0.3f; - - /* create manifold(s) */ - rb_ct manifold[72], - *interface_manifold = NULL, - *grind_manifold = NULL; - - int - len_front = skate_collide_smooth( player, mtx_front, - &s->sphere_front, manifold ), - len_back = skate_collide_smooth( player, mtx_back, - &s->sphere_back, &manifold[len_front] ), - interface_len = len_front + len_back; - - /* try to slap both wheels onto the ground when landing to prevent mega - * angular velocities being added */ - if( (s->state.activity == k_skate_activity_air) && (len_front != len_back) ) - { - v3f trace_from, trace_dir; - v3_muls( player->rb.to_world[1], -1.0f, trace_dir ); - - if( len_front ) - v3_copy( mtx_back[3], trace_from ); - else - v3_copy( mtx_front[3], trace_from ); - - ray_hit ray; - ray.dist = 0.6f; - - if( ray_world( trace_from, trace_dir, &ray ) ) - { - rb_ct *ct = &manifold[ interface_len ]; - - v3_copy( ray.pos, ct->co ); - v3_copy( ray.normal, ct->n ); - ct->p = 0.0f; - - interface_len ++; - } - } - - interface_manifold = manifold; - grind_manifold = manifold + interface_len; - - int grind_len = skate_grind_collide( dev, player, grind_manifold ); - - for( int i=0; istate.cog, 0.1f, VG__WHITE ); - vg_line_pt3( s->state.cog, 0.11f, VG__WHITE ); - vg_line_pt3( s->state.cog, 0.12f, VG__WHITE ); - vg_line_pt3( s->state.cog, 0.13f, VG__WHITE ); - vg_line_pt3( s->state.cog, 0.14f, VG__WHITE ); - - vg_line( player->rb.co, s->state.cog, VG__RED ); - - - teleport_gate *gate; - if( (gate = world_intersect_gates( player->rb.co, s->state.prev_pos )) ) - { - m4x3_mulv( gate->transport, player->rb.co, player->rb.co ); - m3x3_mulv( gate->transport, player->rb.v, player->rb.v ); - m4x3_mulv( gate->transport, s->state.cog, s->state.cog ); - m3x3_mulv( gate->transport, s->state.cog_v, s->state.cog_v ); - m3x3_mulv( gate->transport, s->state.throw_v, s->state.throw_v ); - - /*camera */ - m4x3_mulv( gate->transport, s->state.posl, s->state.posl ); - m3x3_mulv( gate->transport, s->state.vl, s->state.vl ); - m3x3_mulv( gate->transport, s->state.dirl, s->state.dirl ); - -#if 0 - mixedcam_transport( &s->state.cam, gate ); -#endif - - v4f transport_rotation; - m3x3_q( gate->transport, transport_rotation ); - q_mul( transport_rotation, player->rb.q, player->rb.q ); - rb_update_transform( &player->rb ); - - s->state_gate_storage = s->state; - player_pass_gate( player, gate ); - } -} - -VG_STATIC void player_skate_ui( player_device *dev, player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - - /* FIXME: Compression */ - player_debugtext( 1, "V: %5.2f %5.2f %5.2f",player->rb.v[0], - player->rb.v[1], - player->rb.v[2] ); - player_debugtext( 1, "CO: %5.2f %5.2f %5.2f",player->rb.co[0], - player->rb.co[1], - player->rb.co[2] ); - player_debugtext( 1, "W: %5.2f %5.2f %5.2f",player->rb.w[0], - player->rb.w[1], - player->rb.w[2] ); - - player_debugtext( 1, "activity: %s\n", - (const char *[]){ "k_skate_activity_air", - "k_skate_activity_ground", - "k_skate_activity_grind }" } - [s->state.activity] ); - player_debugtext( 1, "steer_s: %5.2f %5.2f [%.2f %.2f]\n", - s->state.steerx_s, s->state.steery_s, - k_steer_ground, k_steer_air ); - player_debugtext( 1, "flip: %.4f %.4f\n", s->state.flip_rate, - s->state.flip_time ); -} - -VG_STATIC void player_skate_animate( player_device *dev, - player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - struct player_avatar *av = player->playeravatar; - struct skeleton *sk = &av->sk; - - /* Camera position */ - /* TODO split up */ - /* FIXME */ - -#if 0 - v3_muladds( phys->m, phys->a, VG_TIMESTEP_FIXED, phys->m ); - v3_lerp( phys->m, (v3f){0.0f,0.0f,0.0f}, 0.1f, phys->m ); - - 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 ); -#endif - - /* Head */ - float kheight = 2.0f, - kleg = 0.6f; - - v3f offset; - v3_zero( offset ); - - m4x3_mulv( player->rb.to_local, s->state.cog, offset ); - v3_muls( offset, -4.0f, offset ); - -#if 0 - m3x3_mulv( player.inv_visual_transform, phys->bob, offset ); -#endif - - static float speed_wobble = 0.0f, speed_wobble_2 = 0.0f; - - float curspeed = v3_length( player->rb.v ), - kickspeed = vg_clampf( curspeed*(1.0f/40.0f), 0.0f, 1.0f ), - kicks = (vg_randf()-0.5f)*2.0f*kickspeed, - sign = vg_signf( kicks ); - - s->wobble[0] = vg_lerpf( s->wobble[0], kicks*kicks*sign, 6.0f*vg.time_delta); - s->wobble[1] = vg_lerpf( s->wobble[1], speed_wobble, 2.4f*vg.time_delta); - - offset[0] *= 0.26f; - offset[0] += speed_wobble_2*3.0f; - - offset[1] *= -0.3f; - offset[2] *= 0.01f; - - offset[0]=vg_clampf(offset[0],-0.8f,0.8f)*(1.0f-fabsf(s->blend_slide)*0.9f); - offset[1]=vg_clampf(offset[1],-0.5f,0.0f); - - /* - * Animation blending - * =========================================== - */ - - /* sliding */ - { - float desired = vg_clampf( fabsf( s->state.slip ), 0.0f, 1.0f ); - s->blend_slide = vg_lerpf( s->blend_slide, desired, 2.4f*vg.time_delta); - } - - /* movement information */ - { - int iair = (s->state.activity == k_skate_activity_air) || - (s->state.activity == k_skate_activity_grind ); - - float dirz = s->state.reverse > 0.0f? 0.0f: 1.0f, - dirx = s->state.slip < 0.0f? 0.0f: 1.0f, - fly = iair? 1.0f: 0.0f; - - s->blend_z = vg_lerpf( s->blend_z, dirz, 2.4f*vg.time_delta ); - s->blend_x = vg_lerpf( s->blend_x, dirx, 0.6f*vg.time_delta ); - s->blend_fly = vg_lerpf( s->blend_fly, fly, 2.4f*vg.time_delta ); - } - - mdl_keyframe apose[32], bpose[32]; - mdl_keyframe ground_pose[32]; - { - /* when the player is moving fast he will crouch down a little bit */ - float stand = 1.0f - vg_clampf( curspeed * 0.03f, 0.0f, 1.0f ); - s->blend_stand = vg_lerpf( s->blend_stand, stand, 6.0f*vg.time_delta ); - - /* stand/crouch */ - float dir_frame = s->blend_z * (15.0f/30.0f), - stand_blend = offset[1]*-2.0f; - - v3f local_cog; - m4x3_mulv( player->rb.to_local, s->state.cog, local_cog ); - - stand_blend = vg_clampf( 1.0f-local_cog[1], 0, 1 ); - - skeleton_sample_anim( sk, s->anim_stand, dir_frame, apose ); - skeleton_sample_anim( sk, s->anim_highg, dir_frame, bpose ); - skeleton_lerp_pose( sk, apose, bpose, stand_blend, apose ); - - /* sliding */ - float slide_frame = s->blend_x * (15.0f/30.0f); - skeleton_sample_anim( sk, s->anim_slide, slide_frame, bpose ); - skeleton_lerp_pose( sk, apose, bpose, s->blend_slide, apose ); - - /* pushing */ - double push_time = vg.time - s->state.start_push; - s->blend_push = vg_lerpf( s->blend_push, - (vg.time - s->state.cur_push) < 0.125, - 6.0f*vg.time_delta ); - - float pt = push_time + vg.accumulator; - if( s->state.reverse > 0.0f ) - skeleton_sample_anim( sk, s->anim_push, pt, bpose ); - else - skeleton_sample_anim( sk, s->anim_push_reverse, pt, bpose ); - - skeleton_lerp_pose( sk, apose, bpose, s->blend_push, apose ); - - /* trick setup */ - float jump_start_frame = 14.0f/30.0f; - - float charge = s->state.jump_charge; - s->blend_jump = vg_lerpf( s->blend_jump, charge, 8.4f*vg.time_delta ); - - float setup_frame = charge * jump_start_frame, - setup_blend = vg_minf( s->blend_jump, 1.0f ); - - float jump_frame = (vg.time - s->state.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 = s->state.jump_dir? - s->anim_ollie: - s->anim_ollie_reverse; - - skeleton_sample_anim_clamped( sk, jump_anim, setup_frame, bpose ); - skeleton_lerp_pose( sk, apose, bpose, setup_blend, ground_pose ); - } - - mdl_keyframe air_pose[32]; - { - float target = -player->input_js1h->axis.value; - s->blend_airdir = vg_lerpf( s->blend_airdir, target, 2.4f*vg.time_delta ); - - float air_frame = (s->blend_airdir*0.5f+0.5f) * (15.0f/30.0f); - skeleton_sample_anim( sk, s->anim_air, air_frame, apose ); - - static v2f grab_choice; - - v2f grab_input = { player->input_js2h->axis.value, - player->input_js2v->axis.value }; - v2_add( s->state.grab_mouse_delta, grab_input, grab_input ); - if( v2_length2( grab_input ) <= 0.001f ) - grab_input[0] = -1.0f; - else - v2_normalize_clamp( grab_input ); - v2_lerp( grab_choice, grab_input, 2.4f*vg.time_delta, grab_choice ); - - float ang = atan2f( grab_choice[0], grab_choice[1] ), - ang_unit = (ang+VG_PIf) * (1.0f/VG_TAUf), - grab_frame = ang_unit * (15.0f/30.0f); - - skeleton_sample_anim( sk, s->anim_grabs, grab_frame, bpose ); - skeleton_lerp_pose( sk, apose, bpose, s->state.grabbing, air_pose ); - } - - skeleton_lerp_pose( sk, ground_pose, air_pose, s->blend_fly, dev->pose ); - - float add_grab_mod = 1.0f - s->blend_fly; - - /* additive effects */ - { - u32 apply_to[] = { av->id_hip, - av->id_ik_hand_l, - av->id_ik_hand_r, - av->id_ik_elbow_l, - av->id_ik_elbow_r }; - - for( int i=0; ipose[apply_to[i]-1].co[0] += offset[0]*add_grab_mod; - dev->pose[apply_to[i]-1].co[2] += offset[2]*add_grab_mod; - } - - mdl_keyframe *kf_board = &dev->pose[av->id_board-1], - *kf_foot_l = &dev->pose[av->id_ik_foot_l-1], - *kf_foot_r = &dev->pose[av->id_ik_foot_r-1]; - - v3f bo; - v3_muls( s->board_offset, add_grab_mod, bo ); - - v3_add( bo, kf_board->co, kf_board->co ); - v3_add( bo, kf_foot_l->co, kf_foot_l->co ); - v3_add( bo, kf_foot_r->co, kf_foot_r->co ); - - m3x3f c; - q_m3x3( s->board_rotation, c ); - - v3f d; - v3_sub( kf_foot_l->co, bo, d ); - m3x3_mulv( c, d, d ); - v3_add( bo, d, kf_foot_l->co ); - - v3_sub( kf_foot_r->co, bo, d ); - m3x3_mulv( c, d, d ); - v3_add( bo, d, kf_foot_r->co ); - - q_mul( s->board_rotation, kf_board->q, kf_board->q ); - q_normalize( kf_board->q ); - } - - /* transform */ - rb_extrapolate( &player->rb, dev->pose_root_co, dev->pose_root_q ); - - v3_muladds( dev->pose_root_co, player->rb.to_world[1], -0.28f, - dev->pose_root_co ); - - v4f qresy, qresx, qresidual; - m3x3f mtx_residual; - float substep = vg_clampf( vg.accumulator / VG_TIMESTEP_FIXED, 0.0f, 1.0f ); - q_axis_angle( qresy, player->rb.to_world[1], s->state.steery_s*substep ); - q_axis_angle( qresx, player->rb.to_world[0], s->state.steerx_s*substep ); - - q_mul( qresy, qresx, qresidual ); - q_normalize( qresidual ); - q_mul( dev->pose_root_q, qresidual, dev->pose_root_q ); - q_normalize( dev->pose_root_q ); - - v4f qflip; - if( (s->state.activity == k_skate_activity_air) && - (fabsf(s->state.flip_rate) > 0.01f) ) - { - float angle = vg_clampf( s->state.flip_time, -1.0f, 1.0f ) * VG_TAUf, - distm = s->land_dist * fabsf(s->state.flip_rate) * 3.0f, - blend = vg_clampf( 1.0f-distm, 0.0f, 1.0f ); - - angle = vg_lerpf( angle, vg_signf(s->state.flip_rate) * VG_TAUf, blend ); - - q_axis_angle( qflip, s->state.flip_axis, angle ); - q_mul( qflip, dev->pose_root_q, dev->pose_root_q ); - q_normalize( dev->pose_root_q ); - - v3f rotation_point, rco; - v3_muladds( player->rb.co, player->rb.to_world[1], 0.5f, rotation_point ); - v3_sub( dev->pose_root_co, rotation_point, rco ); - - /* FIXME: q_mul v3 */ - m3x3f TEMP; - q_m3x3( qflip, TEMP ); - m3x3_mulv( TEMP, rco, rco ); - v3_add( rco, rotation_point, dev->pose_root_co ); - } - -#if 0 - if( cl_thirdperson ) - { - if( !followcam_will_hit_gate( player, &s->state.cam ) ) - { - m4x3f inverse; - m4x3_invert_affine( s->state.cam.gate->transport, inverse ); - m4x3_mul( inverse, transform, transform ); - } - } -#endif -} - -VG_STATIC void skate_camera_vector_look( camera *cam, v3f v, float C, float k ) -{ - float yaw = atan2f( v[0], -v[2] ), - pitch = atan2f - ( - -v[1], - sqrtf - ( - v[0]*v[0] + v[2]*v[2] - ) - ) * C + k; - - cam->angles[0] = yaw; - cam->angles[1] = pitch; -} - -VG_STATIC void skate_camera_firstperson( player_device *dev, - player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - struct player_avatar *av = player->playeravatar; - - /* FIXME: viewpoint entity */ - v3f vp = {-0.1f,1.8f,0.0f}; - m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, dev->cam_1st.pos ); - - v3_zero( dev->cam_1st.angles ); - dev->cam_1st.fov = 119.0f; - - v3f flat_dir, - vel_dir, - look_dir; - - v3_copy( player->rb.v, vel_dir ); - //v3_normalize( vel_dir ); - - float tti = s->land_dist; - v3f norm; - v3_copy( s->land_normal, norm ); - - if( s->state.activity == k_skate_activity_ground ) - { - tti = 0.0f; - v3_copy( player->rb.to_world[1], norm ); - } - - v3_muladds( vel_dir, norm, -v3_dot(vel_dir,norm), flat_dir ); - //v3_normalize( flat_dir ); - - v3_lerp( flat_dir, vel_dir, vg_clampf( tti / 2.0f, 0.4f, 1.0f ), look_dir ); - v3_lerp( s->state.vl, look_dir, 4.0f*vg.time_delta, s->state.vl ); - - skate_camera_vector_look( &dev->cam_1st, s->state.vl, 1.0f, 0.25f ); -} - -VG_STATIC void skate_camera_thirdperson( player_device *dev, - player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - struct player_avatar *av = player->playeravatar; - - v3f origin, dir, target; - v3_copy( player->rb.co, origin ); - v3_add( origin, (v3f){0.0f,1.35f,0.0f}, origin ); - v3_sub( origin, s->state.posl, dir ); - - if( v3_length2( dir ) < 0.1f*0.1f ) - v3_copy( (v3f){ 0.0f, 0.0f, 1.0f }, dir ); /* FIXME */ - else - v3_normalize( dir ); - - if( s->state.activity == k_skate_activity_air ) - dir[1] *= vg_maxf( 0.0f, 1.0f - (s->land_dist/2.0f) ); - dir[1] *= 0.0f; - - v3_muladds( origin, dir, -2.0f, target ); - - v3_lerp( s->state.posl, target, vg.frame_delta * 15.0f, s->state.posl ); - v3_lerp( s->state.dirl, dir, 18.0f*vg.time_delta, s->state.dirl ); - - v3_copy( s->state.posl, dev->cam_3rd.pos ); - skate_camera_vector_look( &dev->cam_3rd, s->state.dirl, 1.0f, 0.2f ); -} - -VG_STATIC void player_skate_post_animate( player_device *dev, - player_interface *player ) -{ - struct player_device_skate *s = dev->storage; - struct player_avatar *av = player->playeravatar; - - v3_zero( dev->cam_1st.pos ); - v3_zero( dev->cam_1st.angles ); - dev->cam_1st.fov = 90.0f; - - skate_camera_thirdperson( dev, player ); - skate_camera_firstperson( dev, player ); - - /* FIXME: Organize this. Its int wrong fucking place */ - v3f vp0 = {0.0f,0.1f, 0.6f}, - vp1 = {0.0f,0.1f,-0.6f}; - - m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, TEMP_BOARD_0 ); - m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp1, TEMP_BOARD_1 ); -} - -VG_STATIC void player_skate_reset( player_device *dev, - player_interface *player, - struct respawn_point *rp ) -{ - struct player_device_skate *s = dev->storage; - v3_muladds( player->rb.co, player->rb.to_world[1], 1.0f, s->state.cog ); - -#if 0 - mixedcam_reset( player, &s->state.cam ); -#endif -} - -VG_STATIC int player_skate_event( player_device *dev, player_interface *player, - enum player_device_event_type ev, - void *data ) -{ - struct player_device_skate *s = dev->storage; - - if( ev == k_player_device_event_bind ) - player_skate_bind( dev, player ); - else if( ev == k_player_device_event_respawn ) - player_skate_reset( dev, player, data ); - else if( ev == k_player_device_event_pre_update ) - { - if( vg_input_button_down( player->input_use ) ) - { - struct device_transition_walk inf; - v3_copy( player->cam.angles, inf.angles ); - inf.angles[2] = 0.0f; - - player_transition_to_device( player, s->device_id_walk, &inf ); - return 1; - } - } - else if( ev == k_player_device_event_custom_transition ) - { - /* transition coming in from walking */ - struct device_transition_skateboard *inf = data; - - q_axis_angle( player->rb.q, (v3f){0.0f,1.0f,0.0f}, - atan2f( inf->dir[0], inf->dir[2] ) ); - v3_copy( player->cam.pos, s->state.posl ); - - m3x3f temp; - euler_m3x3( player->cam.angles, temp ); - v3_muls( temp[2], -1.0f, s->state.dirl ); - - rb_update_transform( &player->rb ); - v3_muladds( player->rb.co, player->rb.to_world[1], 1.0f, s->state.cog ); - v3_copy( player->rb.v, s->state.cog_v ); - } - else if( ev == k_player_device_event_update ) - { - player_skate_update( dev, player ); - } - else if( ev == k_player_device_event_post_update ) - { - 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 ); - - vg_line_cross( p->log[p->log_length-1], p->colour, 0.25f ); - - v3f p1; - v3_add( p->log[p->log_length-1], p->n, p1 ); - vg_line( p->log[p->log_length-1], p1, 0xffffffff ); - - 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 ); - } - else if( ev == k_player_device_event_animate ) - { - player_skate_animate( dev, player ); - } - else if( ev == k_player_device_event_post_animate ) - { - player_skate_post_animate( dev, player ); - } - else if( ev == k_player_device_event_debug_ui ) - { - player_skate_ui( dev, player ); - } - else - return 0; - - return 1; -} - -VG_STATIC player_device player_device_skate = -{ - .name = "skateboard", - .event = player_skate_event, - .storage = &localplayer_device_skate -}; - -#endif /* PLAYER_DEVICE_SKATE_H */