From e3bf80ff27b675f5e7f87dcebd16fab6fe08df7a Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 2 Feb 2023 10:38:41 +0000 Subject: [PATCH] the never ending refactor --- .gitignore | 1 + camera.h | 7 + player.c | 318 +++++++ player.h | 166 ++++ player_api.h | 73 ++ player_common.c | 44 + player_common.h | 8 + player_device_common.h | 19 - player_device_dead.h | 64 -- player_interface.h | 2 + player_model.h | 18 - player_physics.h | 171 ---- player_physics_skate.h | 1117 ----------------------- player_physics_walk.h | 327 ------- player_device_skate.h => player_skate.c | 503 ++++------ player_skate.h | 121 +++ player_device_walk.h => player_walk.c | 211 +---- player_walk.h | 47 + player_walkgrid.h | 967 -------------------- skaterift.c | 42 +- 20 files changed, 1025 insertions(+), 3201 deletions(-) create mode 100644 player.c create mode 100644 player_api.h create mode 100644 player_common.c create mode 100644 player_common.h delete mode 100644 player_device_common.h delete mode 100644 player_device_dead.h delete mode 100644 player_physics.h delete mode 100644 player_physics_skate.h delete mode 100644 player_physics_walk.h rename player_device_skate.h => player_skate.c (77%) create mode 100644 player_skate.h rename player_device_walk.h => player_walk.c (65%) create mode 100644 player_walk.h delete mode 100644 player_walkgrid.h diff --git a/.gitignore b/.gitignore index 510138c..d14eaf6 100755 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.so *.dll *.log +*.old # soft links steamworks_sdk diff --git a/camera.h b/camera.h index dbacc26..77fc089 100644 --- a/camera.h +++ b/camera.h @@ -27,6 +27,13 @@ struct camera } VG_STATIC main_camera; +VG_STATIC void camera_lerp_angles( v3f a, v3f b, float t, v3f d ) +{ + d[0] = vg_alerpf( a[0], b[0], t ); + d[1] = vg_lerpf( a[1], b[1], t ); + d[2] = vg_lerpf( a[2], b[2], t ); +} + VG_STATIC void camera_lerp( camera *a, camera *b, float t, camera *d ) { v3_lerp( a->pos, b->pos, t, d->pos ); diff --git a/player.c b/player.c new file mode 100644 index 0000000..08741d3 --- /dev/null +++ b/player.c @@ -0,0 +1,318 @@ +#ifndef PLAYER_C +#define PLAYER_C + +#include "player.h" +#include "camera.h" +#include "player_model.h" + +PLAYER_API +void player__debugtext( int size, const char *fmt, ... ) +{ + char buffer[ 1024 ]; + + va_list args; + va_start( args, fmt ); + vsnprintf( buffer, 1024, fmt, args ); + va_end( args ); + + ui_text( vg_uictx.cursor, buffer, size, k_text_align_right ); + vg_uictx.cursor[1] += 14*size; +} + +/* + * Init + */ +PLAYER_API +void player__create( player_instance *inst ) +{ + static int only_once = 0; + assert( only_once == 0 ); + only_once ++; + + inst->input_js1h = vg_create_named_input( "steer-h", k_input_type_axis ); + inst->input_js1v = vg_create_named_input( "steer-v", k_input_type_axis ); + inst->input_grab = vg_create_named_input( "grab", k_input_type_axis_norm); + inst->input_js2h = vg_create_named_input( "grab-h", k_input_type_axis ); + inst->input_js2v = vg_create_named_input( "grab-v", k_input_type_axis ); + inst->input_jump = vg_create_named_input( "jump", k_input_type_button ); + inst->input_push = vg_create_named_input( "push", k_input_type_button ); + inst->input_walk = vg_create_named_input( "walk", k_input_type_button ); + inst->input_walkh= vg_create_named_input( "walk-h", k_input_type_axis ); + inst->input_walkv= vg_create_named_input( "walk-v", k_input_type_axis ); + inst->input_use = vg_create_named_input( "use", k_input_type_button ); + inst->input_reset= vg_create_named_input( "reset", k_input_type_button ); + inst->input_camera=vg_create_named_input( "camera", k_input_type_button ); + + const char *default_cfg[] = + { + "bind steer-h gp-ls-h", + "bind -steer-h a", + "bind +steer-h d", + + "bind steer-v gp-ls-v", + "bind -steer-v w", + "bind +steer-v s", + + "bind grab gp-rt", + "bind +grab shift", + "bind grab-h gp-rs-h", + "bind grab-v gp-rs-v", + + "bind jump space", + "bind jump gp-a", + + "bind push gp-b", + "bind push w", + + "bind walk shift", + "bind walk gp-ls", + + "bind walk-h gp-ls-h", + "bind walk-v -gp-ls-v", + "bind +walk-h d", + "bind -walk-h a", + "bind +walk-v w", + "bind -walk-v s", + + "bind reset gp-lb", + "bind reset r", + + "bind use gp-y", + "bind use e", + "bind camera c" + }; + + for( int i=0; irb.co ); + v3_zero( inst->rb.w ); + v3_zero( inst->rb.v ); + q_identity( inst->rb.q ); + m4x3_identity( inst->rb.to_world ); + m4x3_identity( inst->rb.to_local ); +} + +/* + * Appearence + */ +PLAYER_API +void player__use_avatar( player_instance *player, struct player_avatar *av ) +{ + player->playeravatar = av; + player_setup_ragdoll_from_avatar( &player->ragdoll, av ); +} + +PLAYER_API +void player__use_mesh( player_instance *player, glmesh *mesh ) +{ + player->playermesh = mesh; +} + +PLAYER_API +void player__use_texture( player_instance *player, vg_tex2d *tex ) +{ + player->playertex = tex; +} + +PLAYER_API +void player__bind( player_instance *player ) +{ + player__skate_bind( player ); + player__walk_bind( player ); +} + +/* + * Gameloop events + * ---------------------------------------------------------------------------- + */ +PLAYER_API +void player__pre_update( player_instance *player ) +{ + if( vg_input_button_down( player->input_camera ) ) + { + if( player->camera_mode == k_cam_firstperson ) + player->camera_mode = k_cam_thirdperson; + else + player->camera_mode = k_cam_firstperson; + } + + if( _player_pre_update[ player->subsystem ] ) + _player_pre_update[ player->subsystem ]( player ); +} + +PLAYER_API +void player__update( player_instance *player ) +{ + if( _player_update[ player->subsystem ] ) + _player_update[ player->subsystem ]( player ); +} + +PLAYER_API +void player__post_update( player_instance *player ) +{ + if( _player_post_update[ player->subsystem ] ) + _player_post_update[ player->subsystem ]( player ); +} + +VG_STATIC void player_apply_transport_to_cam( m4x3f transport ) +{ + /* FIXME: Applies to main_camera directly! */ + + /* Pre-emptively edit the camera matrices so that the motion vectors + * are correct */ + m4x3f transport_i; + m4x4f transport_4; + m4x3_invert_affine( transport, transport_i ); + m4x3_expand( transport_i, transport_4 ); + m4x4_mul( main_camera.mtx.pv, transport_4, main_camera.mtx.pv ); + m4x4_mul( main_camera.mtx.v, transport_4, main_camera.mtx.v ); +} + +/* + * Applies gate transport to a player_interface + */ +PLAYER_API +void player__pass_gate( player_instance *player, teleport_gate *gate ) +{ + player->gate_waiting = gate; + + /* TODO: Add back other logic thats normally here */ +} + +VG_STATIC void player_camera_portal_correction( player_instance *player ) +{ + if( player->gate_waiting ) + { + /* construct plane equation for reciever gate */ + v4f plane; + v3_copy( player->gate_waiting->recv_to_world[2], plane ); + plane[3] = v3_dot( plane, player->gate_waiting->recv_to_world[3] ); + + /* check camera polarity */ + if( v3_dot( player->cam.pos, plane ) < plane[3] ) + { + vg_success( "Plane cleared\n" ); + player_apply_transport_to_cam( player->gate_waiting->transport ); + player->gate_waiting = NULL; + } + else + { + /* de-transform camera and player back */ + m4x3f inverse; + m4x3_invert_affine( player->gate_waiting->transport, inverse ); + m4x3_mulv( inverse, player->cam.pos, player->cam.pos ); + + /* TODO: Find robust method for this */ + v3f fwd_dir = { cosf(player->cam.angles[0]), + 0.0f, + sinf(player->cam.angles[0])}; + m3x3_mulv( inverse, fwd_dir, fwd_dir ); + player->cam.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] ); + + struct skeleton *sk = &player->playeravatar->sk; + skeleton_apply_transform( sk, inverse ); + } + } +} + +VG_STATIC void player__pre_render( player_instance *player ) +{ + if( _player_animate[ player->subsystem ] ) + { + player_animation res; + _player_animate[ player->subsystem ]( player, &res ); + + /* TODO: eventually, blending code goes here */ + + m4x3f transform; + q_m3x3( res.root_q, transform ); + v3_copy( res.root_co, transform[3] ); + + struct skeleton *sk = &player->playeravatar->sk; + + skeleton_apply_pose( sk, res.pose, k_anim_apply_defer_ik ); + skeleton_apply_ik_pass( sk ); + skeleton_apply_pose( sk, res.pose, k_anim_apply_deffered_only ); + skeleton_apply_inverses( sk ); + skeleton_apply_transform( sk, transform ); + skeleton_debug( sk ); + } + + if( _player_post_animate[ player->subsystem ] ) + _player_post_animate[ player->subsystem ]( player ); + + /* TODO: eventually, blending code goes here */ + + float camera_blend_target = 1.0f; + if( player->camera_mode == k_cam_firstperson ) + camera_blend_target = 0.0f; + + player->camera_type_blend = vg_lerpf( player->camera_type_blend, + camera_blend_target, + 5.0f * vg.frame_delta ); + + float t = player->camera_type_blend; + camera_lerp_angles( player->cam1.angles, player->cam3.angles, + t, player->cam.angles ); + v3_lerp( player->cam1.co, player->cam3.co, t, player->cam.pos ); + player->cam.fov = vg_lerpf( 118.0f, 90.0f, t ); + + player_camera_portal_correction( player ); +} + +PLAYER_API void player__render( camera *cam, player_instance *player ) +{ + shader_viewchar_use(); + vg_tex2d_bind( player->playertex, 0 ); + shader_viewchar_uTexMain( 0 ); + shader_viewchar_uCamera( cam->transform[3] ); + shader_viewchar_uPv( cam->mtx.pv ); + shader_link_standard_ub( _shader_viewchar.id, 2 ); + glUniformMatrix4x3fv( _uniform_viewchar_uTransforms, + player->playeravatar->sk.bone_count, + 0, + (float *)player->playeravatar->sk.final_mtx ); + + mesh_bind( player->playermesh ); + mesh_draw( player->playermesh ); +} + +PLAYER_API void player__im_gui( player_instance *player ) +{ + vg_uictx.cursor[0] = vg.window_x - 200; + vg_uictx.cursor[1] = 0; + vg_uictx.cursor[2] = 200; + vg_uictx.cursor[3] = 200; + + struct ui_vert *b = ui_fill_rect( vg_uictx.cursor, 0x70000000 ); + + vg_uictx.cursor[0] = vg.window_x; + + if( _player_im_gui[ player->subsystem ] ) + _player_im_gui[ player->subsystem ]( player ); + + b[2].co[1] = vg_uictx.cursor[1]; + b[3].co[1] = vg_uictx.cursor[1]; +} + +PLAYER_API void player__spawn( player_instance *player, + struct respawn_point *rp ) +{ + v3_copy( rp->co, player->rb.co ); + v3_zero( player->rb.v ); + v3_zero( player->rb.w ); + q_identity( player->rb.q ); + rb_update_transform( &player->rb ); + + if( _player_reset[ player->subsystem ] ) + _player_reset[ player->subsystem ]( player, rp ); +} + + +PLAYER_API void player__kill( player_instance *player ) +{ + +} + +#endif /* PLAYER_C */ diff --git a/player.h b/player.h index 1a97e1a..c9f13f7 100644 --- a/player.h +++ b/player.h @@ -1,3 +1,168 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include "player_api.h" + +#include "player_common.h" +#include "player_walk.h" +#include "player_skate.h" +//#include "player_dead.h" + +struct player_instance +{ + /* transform definition */ + rigidbody rb; + v3f angles; + + /* + * Camera management + * --------------------------- + */ + camera cam; /* output final camera */ + + enum camera_mode + { + k_cam_firstperson = 0, + k_cam_thirdperson = 1 + } + camera_mode; + float camera_type_blend; + + struct + { + v3f co, angles; + } + cam1, cam3; + + teleport_gate *gate_waiting; + + /* + * Input + * -------------------------------- + */ + struct input_binding *input_js1h, + *input_js1v, + *input_js2h, + *input_js2v, + *input_jump, + *input_push, + *input_walk, + *input_walkh, + *input_walkv, + *input_use, + *input_reset, + *input_grab, + *input_camera; + + /* + * Animation + * -------------------------------------------------- + */ + + struct player_avatar *playeravatar; + glmesh *playermesh; + struct player_ragdoll ragdoll; + vg_tex2d *playertex; + + /* + * Subsystems + * ------------------------------------------------- + */ + + enum player_subsystem + { + k_player_subsystem_walk = 0, + k_player_subsystem_skate = 1, + k_player_subsystem_dead = 2 + } + subsystem; + + struct player_skate _skate; + struct player_walk _walk; + //struct player_dead _dead; +}; + +/* + * Gameloop tables + * --------------------------------------------------------- + */ + +VG_STATIC +void (*_player_bind[])( player_instance *player ) = +{ + player__walk_bind, + player__skate_bind, + NULL +}; + +VG_STATIC +void (*_player_reset[])( player_instance *player, struct respawn_point *rp ) = +{ + NULL, + player__skate_reset, + NULL +}; + +VG_STATIC +void (*_player_pre_update[])( player_instance *player ) = +{ + player__walk_pre_update, + player__skate_pre_update, + NULL +}; + +VG_STATIC +void( *_player_update[])( player_instance *player ) = +{ + player__walk_update, + player__skate_update, + NULL +}; + +VG_STATIC +void( *_player_post_update[])( player_instance *player ) = +{ + player__walk_post_update, + player__skate_post_update, + NULL +}; + +VG_STATIC +void( *_player_im_gui[])( player_instance *player ) = +{ + player__walk_im_gui, + player__skate_im_gui, + NULL +}; + +VG_STATIC +void( *_player_animate[])( player_instance *player, player_animation *dest ) = +{ + player__walk_animate, + player__skate_animate, + NULL +}; + +VG_STATIC +void( *_player_post_animate[])( player_instance *player ) = +{ + player__walk_post_animate, + player__skate_post_animate, + NULL +}; + +/* implementation */ + +#include "player.c" +#include "player_common.c" +#include "player_walk.c" +#include "player_skate.c" +//#include "player_dead.c" + +#endif /* PLAYER_H */ + + +#if 0 /* * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved */ @@ -908,3 +1073,4 @@ VG_STATIC void player_restore_frame(void) } #endif /* PLAYER_H */ +#endif diff --git a/player_api.h b/player_api.h new file mode 100644 index 0000000..75c3873 --- /dev/null +++ b/player_api.h @@ -0,0 +1,73 @@ +#ifndef PLAYER_API_H +#define PLAYER_API_H + +#define VG_GAME +#include "vg/vg.h" + +#include "player_ragdoll.h" +#include "player_model.h" + +/* + * Defines a set of routines used to interact with the player + */ + +#define PLAYER_API VG_STATIC +typedef struct player_instance player_instance; +typedef mdl_keyframe player_pose[32]; +typedef struct player_animation player_animation; + +struct player_animation +{ +#if 0 + camera camera_firstperson, + camera_thirdperson; +#endif + + player_pose pose; + v3f root_co; + v4f root_q; +}; + +/* + * Init + */ +PLAYER_API void player_create ( player_instance *player ); + +/* + * Appearence + */ +PLAYER_API void player_use_avatar ( player_instance *player, + struct player_avatar *av ); +PLAYER_API void player_use_mesh ( player_instance *player, glmesh *mesh ); +PLAYER_API void player_use_texture ( player_instance *player, vg_tex2d *tex ); + + +/* + * Gameloop events + * ---------------------------------------------------------------------------- + */ +PLAYER_API void player__bind ( player_instance *player ); +PLAYER_API void player__pre_update ( player_instance *player ); +PLAYER_API void player__update ( player_instance *player ); +PLAYER_API void player__post_update ( player_instance *player ); +PLAYER_API void player__pre_render ( player_instance *player ); +PLAYER_API void player__render ( camera *cam, player_instance *player ); +PLAYER_API void player__im_gui ( player_instance *player ); + +/* + * Mechanic events + * ---------------------------------------------------------------------------- + */ +PLAYER_API void player__spawn ( player_instance *player, + struct respawn_point *rp ); +PLAYER_API void player__kill ( player_instance *player ); +PLAYER_API void player__pass_gate ( player_instance *player, + teleport_gate *gate ); + +/* + * Utiltiy + * ---------------------------------------------------------------------------- + */ +PLAYER_API void player__debugtext( int size, const char *fmt, ... ); + +#endif /* PLAYER_API_H */ diff --git a/player_common.c b/player_common.c new file mode 100644 index 0000000..69d35ab --- /dev/null +++ b/player_common.c @@ -0,0 +1,44 @@ +#ifndef PLAYER_COMMON_C +#define PLAYER_COMMON_C + +#include "player.h" + +void player_look( player_instance *player, v3f angles ) +{ + angles[2] = 0.0f; + v2_muladds( angles, vg.mouse_delta, 0.0025f, angles ); + + if( vg_input.controller_should_use_trackpad_look ) + { + static v2f last_input; + static v2f vel; + static v2f vel_smooth; + + v2f input = { player->input_js2h->axis.value, + player->input_js2v->axis.value }; + + if( (v2_length2(last_input) > 0.001f) && (v2_length2(input) > 0.001f) ) + { + v2_sub( input, last_input, vel ); + v2_muls( vel, 1.0f/vg.time_delta, vel ); + } + else + { + v2_zero( vel ); + } + + v2_lerp( vel_smooth, vel, vg.time_delta*8.0f, vel_smooth ); + + v2_muladds( angles, vel_smooth, vg.time_delta, angles ); + v2_copy( input, last_input ); + } + else + { + angles[0] += player->input_js2h->axis.value * vg.time_delta * 4.0f; + angles[1] += player->input_js2v->axis.value * vg.time_delta * 4.0f; + } + + angles[1] = vg_clampf( angles[1], -VG_PIf*0.5f, VG_PIf*0.5f ); +} + +#endif /* PLAYER_COMMON_C */ diff --git a/player_common.h b/player_common.h new file mode 100644 index 0000000..91298fc --- /dev/null +++ b/player_common.h @@ -0,0 +1,8 @@ +#ifndef PLAYER_COMMON_H +#define PLAYER_COMMON_H + +#include "player_api.h" + +void player_look( player_instance *player, v3f angles ); + +#endif /* PLAYER_COMMON_H */ diff --git a/player_device_common.h b/player_device_common.h deleted file mode 100644 index 07a3d87..0000000 --- a/player_device_common.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef PLAYER_DEVICE_COMMON_H -#define PLAYER_DEVICE_COMMON_H - -#define VG_GAME -#include "vg/vg.h" -#include "common.h" -#include "player_interface.h" - -struct device_transition_skateboard -{ - v3f dir; -}; - -struct device_transition_walk -{ - v3f angles; -}; - -#endif /* PLAYER_DEVICE_COMMON_H */ diff --git a/player_device_dead.h b/player_device_dead.h deleted file mode 100644 index 5605571..0000000 --- a/player_device_dead.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef PLAYER_DEVICE_DEAD_H -#define PLAYER_DEVICE_DEAD_H - -#include "player_interface.h" -#include "skeleton.h" -#include "player_model.h" - -VG_STATIC -struct player_device_dead -{ - int _; -} -localplayer_device_dead; - -VG_STATIC int player_dead_event( player_device *dev, player_interface *player, - enum player_device_event_type ev, void *data ) -{ - if( ev == k_player_device_event_update ) - { - player_ragdoll_iter( &player->ragdoll ); - } - else if( ev == k_player_device_event_custom_transition ) - { - copy_avatar_pose_to_ragdoll( player->playeravatar, &player->ragdoll, - player->rb.v ); - } - else if( ev == k_player_device_event_animate ) - { - v3_zero( dev->pose_root_co ); - q_identity( dev->pose_root_q ); - - for( int i=0; ipose ); i ++ ) - { - v3_zero( dev->pose[i].co ); - v3_fill( dev->pose[i].s, 1.0f ); - q_identity( dev->pose[i].q ); - } - } - else if( ev == k_player_device_event_post_animate ) - { - struct player_avatar *av = player->playeravatar; - - v3_zero( dev->cam_1st.pos ); - v3_zero( dev->cam_1st.angles ); - dev->cam_1st.fov = 90.0f; - - /* FIXME: This overwrites pose blending, however, do we need to blend with - * this device, anyway? */ - copy_ragdoll_pose_to_avatar( &player->ragdoll, player->playeravatar ); - } - else - return 0; - - return 1; -} - -VG_STATIC player_device player_device_dead = -{ - .name = "ragdoll/dead", - .event = player_dead_event, - .storage = &localplayer_device_dead -}; - -#endif /* PLAYER_DEVICE_DEAD_H */ diff --git a/player_interface.h b/player_interface.h index 38b98b7..dc23776 100644 --- a/player_interface.h +++ b/player_interface.h @@ -1,3 +1,4 @@ +#if 0 #ifndef PLAYER_INTERFACE_H #define PLAYER_INTERFACE_H @@ -494,3 +495,4 @@ void player_look( player_interface *player, v3f angles ) } #endif /* PLAYER_INTERFACE_H */ +#endif diff --git a/player_model.h b/player_model.h index 7bf801c..6c46f08 100644 --- a/player_model.h +++ b/player_model.h @@ -8,10 +8,6 @@ #define VG_GAME #include "vg/vg.h" -#if 0 -#include "player.h" -#endif - #include "model.h" #include "skeleton.h" #include "player_ragdoll.h" @@ -24,20 +20,6 @@ struct player_avatar mdl_context meta; struct skeleton sk; - v3f cam_pos; /* FIXME ? */ - -#if 0 - 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, - *anim_walk, *anim_run, *anim_idle, - *anim_jump; -#endif - u32 id_hip, id_ik_hand_l, id_ik_hand_r, diff --git a/player_physics.h b/player_physics.h deleted file mode 100644 index 73bad63..0000000 --- a/player_physics.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#define PLAYER_PHYSICS_H -#ifndef PLAYER_PHYSICS_H -#define PLAYER_PHYSICS_H - -#include "player.h" -#include "camera.h" - -VG_STATIC void player_integrate(void); - -VG_STATIC int player_collide_sphere( rigidbody *rb, rb_ct *manifold ) -{ -#if 0 - int len = 0; - - len = rb_sphere_scene( rb, &world.rb_geo, manifold ); - rb_manifold_filter_coplanar( manifold, len, 0.05f ); - if( len > 1 ) - { - rb_manifold_filter_backface( manifold, len ); - rb_manifold_filter_joint_edges( manifold, len, 0.05f ); - rb_manifold_filter_pairs( manifold, len, 0.05f ); - } - int new_len = rb_manifold_apply_filtered( manifold, len ); - if( len && !new_len ) - len = 1; - else - len = new_len; - - return len; -#endif - - return 0; -} - -#if 0 -VG_STATIC void apply_gravity( v3f vel, float const timestep ) -{ - v3f gravity = { 0.0f, -9.6f, 0.0f }; - v3_muladds( vel, gravity, timestep, vel ); -} - -VG_STATIC void player_integrate(void) -{ - struct player_phys *phys = &player.phys; - v3_sub( phys->rb.v, phys->v_last, phys->a ); - v3_muls( phys->a, 1.0f/VG_TIMESTEP_FIXED, phys->a ); - v3_copy( phys->rb.v, phys->v_last ); - - apply_gravity( phys->rb.v, VG_TIMESTEP_FIXED ); - v3_muladds( phys->rb.co, phys->rb.v, VG_TIMESTEP_FIXED, phys->rb.co ); -} -#endif - -VG_STATIC void player_freecam(void) -{ - player_mouseview(); - - float movespeed = fc_speed * VG_TIMESTEP_FIXED; - v3f lookdir = { 0.0f, 0.0f, -1.0f }, - sidedir = { 1.0f, 0.0f, 0.0f }; - - m3x3_mulv( main_camera.transform, lookdir, lookdir ); - m3x3_mulv( main_camera.transform, sidedir, sidedir ); - - static v3f move_vel = { 0.0f, 0.0f, 0.0f }; - - v2f steer = { player.input_js1h->axis.value, - player.input_js1v->axis.value }; - - v3_muladds( move_vel, sidedir, movespeed*steer[0], move_vel ); - v3_muladds( move_vel, lookdir, -movespeed*steer[1], move_vel ); - - v3_muls( move_vel, 0.7f, move_vel ); - v3_add( move_vel, player.camera_pos, player.camera_pos ); -} - -VG_STATIC int kill_player( int argc, char const *argv[] ) -{ - player_kill(); - return 0; -} - -VG_STATIC int reset_player( int argc, char const *argv[] ) -{ - struct respawn_point *rp = NULL, *r; - - if( argc == 1 ) - { - for( int i=0; iname, argv[0] ) ) - { - rp = r; - break; - } - } - - if( !rp ) - vg_warn( "No spawn named '%s'\n", argv[0] ); - } - - if( !rp ) - { - float min_dist = INFINITY; - - for( int i=0; ico, player.co ); - - vg_info( "Dist %s : %f\n", r->name, d ); - if( d < min_dist ) - { - min_dist = d; - rp = r; - } - } - } - - if( !rp ) - { - vg_error( "No spawn found\n" ); - vg_info( "Player position: %f %f %f\n", player.co[0], - player.co[1], - player.co[2] ); - - if( !world.spawn_count ) - return 0; - - rp = &world.spawns[0]; - } - - player.is_dead = 0; - - m3x3f the_long_way; - q_m3x3( rp->q, the_long_way ); - - v3f delta = {1.0f,0.0f,0.0f}; - m3x3_mulv( the_long_way, delta, delta ); - - if( !freecam ) - { - player.angles[0] = atan2f( delta[0], -delta[2] ); - player.angles[1] = -asinf( delta[1] ); - } - - player.controller = k_player_controller_walk; - /* TODO: trigger controller slurp */ - - player_save_frame(); - return 1; -} - -VG_STATIC void reset_player_poll( int argc, char const *argv[] ) -{ - if( argc == 1 ) - { - for( int i=0; iname, argv[argc-1], 0 ); - } - } -} - -#endif /* PLAYER_PHYSICS_H */ diff --git a/player_physics_skate.h b/player_physics_skate.h deleted file mode 100644 index f4b960f..0000000 --- a/player_physics_skate.h +++ /dev/null @@ -1,1117 +0,0 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef PLAYER_PHYSICS_SKATE_H -#define PLAYER_PHYSICS_SKATE_H - -#include "player.h" -#include "camera.h" - -VG_STATIC struct player_skate -{ - struct skate_phys - { - enum skate_activity - { - k_skate_activity_air, - k_skate_activity_ground, - k_skate_activity_grind - } - activity, - activity_prev; - - v3f v_prev, a, m, bob, vl; /* TODO: please clarify */ - - float iY, siY; /* Yaw inertia */ - - float vswitch, slip, slip_last, reverse; - float grab, jump; - v2f grab_mouse_delta; - - v3f throw_v; - v3f cog, - cog_v; - - int lift_frames; - - double start_push, - cur_push; - - int charging_jump, jump_dir; - - m3x3f vr,vr_pstep; - } - phys, - phys_frame; - - float normal_pressure; - v3f debug_mmcollect_lat, - debug_mmcollect_vert; - - struct land_prediction - { - v3f log[50]; - v3f n; - u32 log_length; - float score; - - enum prediction_type - { - k_prediction_none, - k_prediction_land, - k_prediction_grind - } - type; - - u32 colour; - } - predictions[22]; - u32 prediction_count; - - rigidbody rbf, rbb; -} -player_skater; - -/* - * Gets the closest grindable edge to the player within max_dist - */ -VG_STATIC struct grind_edge *player_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; -} - -/* - * Trace a path given a velocity rotation. - * - * TODO: this MIGHT be worth doing RK4 on the gravity field. - */ -VG_STATIC void player_score_vr_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; - - prediction->log_length = 0; - - 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 ); - - 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 = player_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 ++ ] ); - break; - } - - 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; - } -} - -/* - * Calculate best launch trajectory - */ -VG_STATIC void player_approximate_best_trajectory( struct player_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->phys.vr ); - - float - best_vmod = 0.0f, - min_score = INFINITY, - max_score = -INFINITY; - - /* - * 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 vr; - v4f vr_q; - - q_axis_angle( vr_q, axis, vmod ); - q_m3x3( vr_q, vr ); - - player_score_vr_path( player.rb.co, player.rb.v, vr, p ); - - if( p->type != k_prediction_none ) - { - if( p->score < min_score ) - { - min_score = p->score; - best_vmod = vmod; - } - - 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->phys.vr ); - - q_axis_angle( vr_q, axis, best_vmod ); - q_m3x3( vr_q, s->phys.vr_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; - } -} - -VG_STATIC void player_skate_apply_grab_model( struct player_skate *s ) -{ - float grabt = player.input_grab->axis.value; - - if( grabt > 0.5f ) - { - v2_muladds( s->phys.grab_mouse_delta, vg.mouse_delta, 0.02f, - s->phys.grab_mouse_delta ); - - v2_normalize_clamp( s->phys.grab_mouse_delta ); - } - else - v2_zero( s->phys.grab_mouse_delta ); - - s->phys.grab = vg_lerpf( s->phys.grab, grabt, 8.4f * VG_TIMESTEP_FIXED ); -} - -/* - * Computes friction and surface interface model - */ -VG_STATIC void player_skate_apply_friction_model( struct player_skate *s ) -{ - if( s->phys.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->phys.slip = slip; - s->phys.reverse = -vg_signf(vel[2]); - - float substep = VG_TIMESTEP_FIXED; - float fwd_resistance = k_friction_resistance; - - vel[2] = stable_force( vel[2],vg_signf(vel[2]) * -fwd_resistance*substep); - vel[0] = stable_force( vel[0],vg_signf(vel[0]) * -k_friction_lat*substep); - - /* Pushing additive force */ - - if( !player.input_jump->button.value ) - { - if( player.input_push->button.value ) - { - if( (vg.time - s->phys.cur_push) > 0.25 ) - { - s->phys.start_push = vg.time; - } - - s->phys.cur_push = vg.time; - - double push_time = vg.time - s->phys.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->phys.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->phys.jump+grab)*0.4f), - steer_scaled = vg_signf(steer) * powf(steer,2.0f) * k_steer_ground; - - s->phys.iY -= steer_scaled * VG_TIMESTEP_FIXED; -} - -VG_STATIC void player_skate_apply_jump_model( struct player_skate *s ) -{ - int charging_jump_prev = s->phys.charging_jump; - s->phys.charging_jump = player.input_jump->button.value; - - /* Cannot charge this in air */ - if( s->phys.activity != k_skate_activity_ground ) - s->phys.charging_jump = 0; - - if( s->phys.charging_jump ) - { - s->phys.jump += VG_TIMESTEP_FIXED * k_jump_charge_speed; - - if( !charging_jump_prev ) - s->phys.jump_dir = s->phys.reverse > 0.0f? 1: 0; - } - else - { - s->phys.jump -= k_jump_charge_speed * VG_TIMESTEP_FIXED; - } - - s->phys.jump = vg_clampf( s->phys.jump, 0.0f, 1.0f ); - - if( s->phys.activity == k_skate_activity_air ) - return; - - /* player let go after charging past 0.2: trigger jump */ - if( !s->phys.charging_jump && s->phys.jump > 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->phys.jump; - v3_muladds( player.rb.v, jumpdir, force, player.rb.v ); - s->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, player.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_skate_apply_grind_model( struct player_skate *s, - rb_ct *manifold, int len ) -{ - if( len == 0 ) - { - if( s->phys.activity == k_skate_activity_grind ) - { - 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(); - - s->phys.activity = k_skate_activity_air; - } - return; - } - - 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 ); - - s->phys.iY -= steer[0] * k_steer_air * VG_TIMESTEP_FIXED; - - float iX = steer[1] * s->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, player.rb.to_world[0], siX ); - q_mul( rotate, player.rb.q, player.rb.q ); - - s->phys.slip = 0.0f; - s->phys.activity = k_skate_activity_grind; - - 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, - VG_TIMESTEP_FIXED * 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->phys.vr ); - m3x3_identity( s->phys.vr_pstep ); - - if( s->phys.activity_prev != k_skate_activity_grind ) - { - 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(); - } -} - -/* - * Air control, no real physics - */ -VG_STATIC void player_skate_apply_air_model( struct player_skate *s ) -{ - if( s->phys.activity != k_skate_activity_air ) - return; - - if( s->phys.activity_prev != k_skate_activity_air ) - player_approximate_best_trajectory( s ); - - m3x3_mulv( s->phys.vr, 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->phys.vr, 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 = player_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)*3.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 }; - - float l2 = v2_length2( steer ); - if( l2 > 1.0f ) - v2_muls( steer, 1.0f/sqrtf(l2), steer ); - - s->phys.iY -= steer[0] * k_steer_air * VG_TIMESTEP_FIXED; - - float iX = steer[1] * - s->phys.reverse * k_steer_air - * limiter * VG_TIMESTEP_FIXED; - - static float siX = 0.0f; - siX = vg_lerpf( siX, iX, k_steer_air_lerp ); - - v4f rotate; - q_axis_angle( rotate, player.rb.to_world[0], siX ); - q_mul( rotate, player.rb.q, player.rb.q ); - -#if 0 - v2f target = {0.0f,0.0f}; - v2_muladds( target, (v2f){ vg_get_axis("grabh"), vg_get_axis("grabv") }, - player_skate.phys.grab, target ); -#endif -} - -VG_STATIC void player_regular_collider_configuration( struct player_skate *s ) -{ - /* Standard ground configuration */ - m3x3_copy( player.rb.to_world, s->rbf.to_world ); - m3x3_copy( player.rb.to_world, s->rbb.to_world ); - - v3f front = {0.0f,0.0f,-k_board_length}, - back = {0.0f,0.0f, k_board_length}; - - m4x3_mulv( player.rb.to_world, front, s->rbf.co ); - m4x3_mulv( player.rb.to_world, back, s->rbb.co ); - v3_copy( s->rbf.co, s->rbf.to_world[3] ); - v3_copy( s->rbb.co, s->rbb.to_world[3] ); - - m4x3_invert_affine( s->rbf.to_world, s->rbf.to_local ); - m4x3_invert_affine( s->rbb.to_world, s->rbb.to_local ); - - rb_update_bounds( &s->rbf ); - rb_update_bounds( &s->rbb ); -} - -VG_STATIC void player_grind( struct player_skate *s ) -{ - v3f closest; - int idx = bh_closest_point( world.grind_bh, player.rb.co, - closest, INFINITY ); - if( idx == -1 ) - return; - - struct grind_edge *edge = &world.grind_edges[ idx ]; - - vg_line( player.rb.co, closest, 0xff000000 ); - vg_line_cross( closest, 0xff000000, 0.3f ); - vg_line( edge->p0, edge->p1, 0xff000000 ); - - v3f grind_delta; - v3_sub( closest, player.rb.co, grind_delta ); - - float p = v3_dot( player.rb.to_world[2], grind_delta ); - v3_muladds( grind_delta, player.rb.to_world[2], -p, grind_delta ); - - float a = vg_maxf( 0.0f, 4.0f-v3_dist2( closest, player.rb.co ) ); - v3_muladds( player.rb.v, grind_delta, a*0.2f, player.rb.v ); -} - -VG_STATIC int player_update_grind_collision( struct player_skate *s, - 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 = player_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; -} - -/* - * Handles connection between the player and the ground - */ -VG_STATIC void player_skate_apply_interface_model( struct player_skate *s, - rb_ct *manifold, int len ) -{ - if( !((s->phys.activity == k_skate_activity_ground) || - (s->phys.activity == k_skate_activity_air )) ) - return; - - v3f surface_avg; - v3_zero( surface_avg ); - - /* - * - * EXPERIMENTAL - * ================================================================ - */ - if( s->phys.activity == k_skate_activity_air ) - s->normal_pressure = 0.0f; - else - s->normal_pressure = v3_dot( player.rb.to_world[1], player.rb.v ); - - v3f p0_0, p0_1, - p1_0, p1_1, - n0, n1; - - float t0, t1; - - 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; - - v3_copy( s->rbf.co, p0_0 ); - v3_copy( s->rbb.co, p1_0 ); - - v3_muladds( p0_0, player.rb.to_world[1], -disp_k, p0_1 ); - v3_muladds( p1_0, player.rb.to_world[1], -disp_k, p1_1 ); - - int cast0 = spherecast_world( p0_0, p0_1, 0.2f, &t0, n0 ), - cast1 = spherecast_world( p1_0, p1_1, 0.2f, &t1, n1 ); - - v3f animp0, animp1; - - m4x3f temp; - m3x3_copy( player.rb.to_world, temp ); - if( cast0 != -1 ) - { - v3_lerp( p0_0, p0_1, t0, temp[3] ); - v3_copy( temp[3], animp0 ); - debug_sphere( temp, 0.2f, VG__PINK ); - - v3f F, delta; - v3_sub( p0_0, player.rb.co, delta ); - - float displacement = vg_clampf( 1.0f-t0, 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 ); - } - else - v3_copy( p0_1, animp0 ); - - if( cast1 != -1 ) - { - v3_lerp( p1_0, p1_1, t1, temp[3] ); - v3_copy( temp[3], animp1 ); - debug_sphere( temp, 0.2f, VG__PINK ); - - v3f F, delta; - v3_sub( p1_0, player.rb.co, delta ); - - float displacement = vg_clampf( 1.0f-t1, 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 ); - } - else - v3_copy( p1_1, animp1 ); - - v3f animavg, animdelta; - v3_add( animp0, animp1, animavg ); - v3_muls( animavg, 0.5f, animavg ); - - v3_sub( animp1, animp0, animdelta ); - v3_normalize( animdelta ); - - m4x3_mulv( player.rb.to_local, animavg, player.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( player.board_rotation, (v3f){ 1.0f, 0.0f, 0.0f }, angle ); - - /* - * ================================================================ - * EXPERIMENTAL - */ - - if( len == 0 && !((cast0 !=-1)&&(cast1!=-1)) ) - { - s->phys.lift_frames ++; - - if( s->phys.lift_frames >= 8 ) - s->phys.activity = k_skate_activity_air; - } - else - { - for( int i=0; i 0.7f ) - { - s->phys.lift_frames ++; - - if( s->phys.lift_frames >= 8 ) - s->phys.activity = k_skate_activity_air; - } - else - { - s->phys.activity = k_skate_activity_ground; - s->phys.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 0 - v3f p0, p1; - v3_add( phys->rb.co, projected, p0 ); - v3_add( phys->rb.co, player_skate.phys.up, p1 ); - vg_line( phys->rb.co, p0, 0xff00ff00 ); - vg_line( phys->rb.co, p1, 0xff000fff ); -#endif - - if( fabsf(angle) < 0.999f ) - { - 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 player_collision_response( struct player_skate *s, - rb_ct *manifold, int len ) -{ - /* TODO: RElocate */ - /* Throw / collect routine - * - * TODO: Max speed boost - */ - if( player.input_grab->axis.value > 0.5f ) - { - if( s->phys.activity == k_skate_activity_ground ) - { - /* Throw */ - v3_muls( player.rb.to_world[1], k_mmthrow_scale, s->phys.throw_v ); - } - } - else - { - /* Collect */ - float doty = v3_dot( player.rb.to_world[1], s->phys.throw_v ); - - v3f Fl, Fv; - v3_muladds( s->phys.throw_v, player.rb.to_world[1], -doty, Fl); - - if( s->phys.activity == k_skate_activity_ground ) - { - v3_muladds( player.rb.v, Fl, k_mmcollect_lat, player.rb.v ); - v3_muladds( s->phys.throw_v, Fl, -k_mmcollect_lat, s->phys.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->phys.throw_v, Fv, k_mmcollect_vert, s->phys.throw_v ); - - v3_copy( Fl, s->debug_mmcollect_lat ); - v3_copy( Fv, s->debug_mmcollect_vert ); - } - - /* Decay */ - if( v3_length2( s->phys.throw_v ) > 0.0001f ) - { - v3f dir; - v3_copy( s->phys.throw_v, dir ); - v3_normalize( dir ); - - float max = v3_dot( dir, s->phys.throw_v ), - amt = vg_minf( k_mmdecay * k_rb_delta, max ); - - v3_muladds( s->phys.throw_v, dir, -amt, s->phys.throw_v ); - } - - - /* TODO: RElocate */ - { - - 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->phys.cog, ideal_diff ); - - /* Apply velocities */ - v3f rv; - v3_sub( player.rb.v, s->phys.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; - - v3_muladds( s->phys.cog_v, F, -rb, s->phys.cog_v ); - } - - /* stripped down presolve */ - for( int i=0; ibias = -0.2f * k_rb_rate * vg_minf( 0.0f, -ct->p+k_penetration_slop ); - - rb_debug_contact( ct ); - } - - 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 ) - { - player_kill(); - 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.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 ); - } - } - - /* early integrate this */ - s->phys.cog_v[1] += -9.8f * k_rb_delta; - v3_muladds( s->phys.cog, s->phys.cog_v, k_rb_delta, s->phys.cog ); -} - -VG_STATIC void player_skate_update( struct player_skate *s ) -{ - s->phys.activity_prev = s->phys.activity; - - rb_ct manifold[72], - *interface_manifold = NULL, - *grind_manifold = NULL; - - player_regular_collider_configuration( s ); - - int nfront = player_collide_sphere( &s->rbf, manifold ), - nback = player_collide_sphere( &s->rbb, manifold + nfront ), - interface_len = nfront + nback; - - interface_manifold = manifold; - grind_manifold = manifold + interface_len; - - int grind_len = player_update_grind_collision( s, grind_manifold ); - - player_skate_apply_grind_model( s, grind_manifold, grind_len ); - player_skate_apply_interface_model( s, manifold, interface_len ); - - rb_presolve_contacts( manifold, interface_len + grind_len ); - player_collision_response( s, manifold, interface_len + grind_len ); - - player_skate_apply_grab_model( s ); - player_skate_apply_friction_model( s ); - player_skate_apply_jump_model( s ); - player_skate_apply_air_model( s ); - - v3f gravity = { 0.0f, -9.6f, 0.0f }; - v3_muladds( player.rb.v, gravity, k_rb_delta, player.rb.v ); - - 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 ); - - player.rb.v[1] += -9.6f * VG_TIMESTEP_FIXED; - - v3_muladds( player.rb.co, player.rb.v, VG_TIMESTEP_FIXED, player.rb.co ); -} - -VG_STATIC void player_physics_gui(void) -{ -#if 0 - return; - - vg_uictx.cursor[0] = 0; - vg_uictx.cursor[1] = vg.window_y - 128; - vg_uictx.cursor[3] = 14; - ui_fill_x(); - - char buf[128]; - - snprintf( buf, 127, "v: %6.3f %6.3f %6.3f\n", player.phys.rb.v[0], - player.phys.rb.v[1], - player.phys.rb.v[2] ); - - ui_text( vg_uictx.cursor, buf, 1, 0 ); - vg_uictx.cursor[1] += 14; - - - snprintf( buf, 127, "a: %6.3f %6.3f %6.3f (%6.3f)\n", player.phys.a[0], - player.phys.a[1], - player.phys.a[2], - v3_length(player.phys.a)); - ui_text( vg_uictx.cursor, buf, 1, 0 ); - vg_uictx.cursor[1] += 14; - - float normal_acceleration = v3_dot( player.phys.a, player.phys.rb.up ); - snprintf( buf, 127, "Normal acceleration: %6.3f\n", normal_acceleration ); - - ui_text( vg_uictx.cursor, buf, 1, 0 ); - vg_uictx.cursor[1] += 14; - - snprintf( buf, 127, "Normal Pressure: %6.3f\n", player.normal_pressure ); - ui_text( vg_uictx.cursor, buf, 1, 0 ); - vg_uictx.cursor[1] += 14; -#endif -} - -#endif /* PLAYER_PHYSICS_SKATE_H */ diff --git a/player_physics_walk.h b/player_physics_walk.h deleted file mode 100644 index 35dbf29..0000000 --- a/player_physics_walk.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#define PLAYER_PHYSICS_WALK_H -#ifndef PLAYER_PHYSICS_WALK_H -#define PLAYER_PHYSICS_WALK_H - -#include "player.h" -#include "camera.h" - -VG_STATIC struct player_walk -{ - struct - { - enum walk_activityaaaaaa - { - k_walk_activity_airaaaa, - k_walk_activity_groundaaaaaa - } - activity; - } - state; - - rigidbody capsule; /* TODO: rigidbody::collider_capsule */ -} -player_walky = -{ - .capsule = { .inf.capsule.height = 2.0f, .inf.capsule.radius = 0.3f } -}; - -VG_STATIC void player_walk_collider_configuration(void) -{ - v3_add( player.rb.co, (v3f){0.0f,1.0f,0.0f}, player_walky.capsule.co ); - rb_update_transform( &player_walky.capsule ); - -#if 0 - float h0 = 0.3f, - h1 = 0.9f; - - rigidbody *rbf = &player.collide_front, - *rbb = &player.collide_back; - - v3_add( phys->rb.co, (v3f){0.0f,h0,0.0f}, rbf->co ); - v3_add( phys->rb.co, (v3f){0.0f,h1,0.0f}, rbb->co ); - v3_copy( rbf->co, rbf->to_world[3] ); - 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 ); -#endif -} - -__attribute__ ((deprecated)) -VG_STATIC int player_walk_surface_standable( v3f n ) -{ - return v3_dot( n, (v3f){0.0f,1.0f,0.0f} ) > 0.5f; -} - -__attribute__ ((deprecated)) -VG_STATIC void player_walk_stepdown( struct player_walk *w ) -{ - float max_dist = 0.4f; - - v3f pa, pb; - v3_copy( player.rb.co, pa ); - pa[1] += 0.3f; - - v3_muladds( pa, (v3f){0.01f,1.0f,0.01f}, -max_dist, pb ); - vg_line( pa, pb, 0xff000000 ); - - /* TODO: Make #define */ - float r = 0.3f, - t; - - v3f n; - if( spherecast_world( pa, pb, r, &t, n ) != -1 ) - { - if( player_walk_surface_standable( n ) ) - { - w->state.activity = k_walk_activity_ground; - v3_lerp( pa, pb, t+0.001f, player.rb.co ); - player.rb.co[1] -= 0.3f; - } - } -} - -__attribute__ ((deprecated)) -VG_STATIC void player_walk_physics( struct player_walk *w ) -{ - v3_zero( player.rb.w ); - q_axis_angle( player.rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] ); - - rb_ct manifold[64]; - int len; - - v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) }; - v3f right_dir = { -forward_dir[2], 0.0f, forward_dir[0] }; - - v2f walk = { player.input_walkh->axis.value, - player.input_walkv->axis.value }; - - if( freecam ) - v2_zero( walk ); - - if( v2_length2(walk) > 0.001f ) - v2_normalize_clamp( walk ); - - if( w->state.activity == k_walk_activity_air ) - { - player_walk_collider_configuration(); - - /* allow player to accelerate a bit */ - v3f walk_3d; - v3_muls( forward_dir, walk[1], walk_3d ); - v3_muladds( walk_3d, right_dir, walk[0], walk_3d ); - - float current_vel = fabsf(v3_dot( walk_3d, player.rb.v )), - new_vel = current_vel + VG_TIMESTEP_FIXED*999999.0f, - clamped_new = vg_clampf( new_vel, 0.0f, k_walkspeed ), - vel_diff = vg_maxf( 0.0f, clamped_new - current_vel ); - - v3_muladds( player.rb.v, right_dir, walk[0] * vel_diff, player.rb.v ); - v3_muladds( player.rb.v, forward_dir, walk[1] * vel_diff, player.rb.v ); - - len = rb_capsule_scene( &w->capsule, &world.rb_geo, manifold ); - rb_presolve_contacts( manifold, len ); - - for( int i=0; in, (v3f){0.0f,1.0f,0.0f} ) > 0.5f ) - w->state.activity = k_walk_activity_ground; - } - - /* - * TODO: Compression - */ - for( int j=0; j<5; j++ ) - { - for( int i=0; in ); - 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.rb.v[1] += -k_gravity * k_rb_delta; - v3_muladds( player.rb.co, player.rb.v, k_rb_delta, player.rb.co ); - } - else - { - player.walk = v2_length( walk ); - - if( player.input_walk->button.value ) - v2_muls( walk, 0.5f, walk ); - - v2_muls( walk, k_walkspeed * VG_TIMESTEP_FIXED, walk ); - - /* Do XY translation */ - v3f walk_apply, walk_measured; - v3_zero( walk_apply ); - v3_muladds( walk_apply, right_dir, walk[0], walk_apply ); - v3_muladds( walk_apply, forward_dir, walk[1], walk_apply ); - v3_add( walk_apply, player.rb.co, player.rb.co ); - - /* Directly resolve collisions */ - player_walk_collider_configuration(); - len = rb_capsule_scene( &w->capsule, &world.rb_geo, manifold ); - - v3f dt; - v3_zero( dt ); - for( int j=0; j<8; j++ ) - { - for( int i=0; in, dt ), - remaining = (ct->p-k_penetration_slop) - resolved_amt, - apply = vg_maxf( remaining, 0.0f ) * 0.3f; - - v3_muladds( dt, ct->n, apply, dt ); - } - } - v3_add( dt, player.rb.co, player.rb.co ); - - v3_add( dt, walk_apply, walk_measured ); - v3_divs( walk_measured, VG_TIMESTEP_FIXED, player.rb.v ); - - if( len ) - { - struct world_material *surface_mat = world_contact_material(manifold); - player.surface_prop = surface_mat->info.surface_prop; - } - - w->state.activity = k_walk_activity_air; - - /* jump */ - if( player.input_jump->button.value ) - { - player.rb.v[1] = 5.0f; - return; - } - - /* Check if grounded by current manifold */ - for( int i=0; in ) ) - w->state.activity = k_walk_activity_ground; - } - - /* otherwise... */ - if( w->state.activity == k_walk_activity_air ) - player_walk_stepdown( w ); - } -} - -__attribute__ ((deprecated)) -VG_STATIC void player_walk_animate( void *_w, - struct skeleton *sk, player_pose pose ) -{ - struct player_walk *w = _w; - - { - float fly = (w->state.activity == k_walk_activity_air)? 1.0f: 0.0f, - rate; - - if( w->state.activity == k_walk_activity_air ) - rate = 2.4f; - else - rate = 9.0f; - - player.ffly = vg_lerpf( player.ffly, fly, rate*vg.time_delta ); - player.frun = vg_lerpf( player.frun, - player.walk * - (1.0f + player.input_walk->button.value*0.5f), - 2.0f*vg.time_delta ); - } - - player_pose apose, bpose; - - if( player.walk > 0.025f ) - { - /* TODO move */ - float walk_norm = 30.0f/(float)player.mdl.anim_walk->length, - run_norm = 30.0f/(float)player.mdl.anim_run->length, - walk_adv = vg_lerpf( walk_norm, run_norm, player.walk ); - - player.walk_timer += walk_adv * vg.time_delta; - } - else - { - player.walk_timer = 0.0f; - } - - float walk_norm = (float)player.mdl.anim_walk->length/30.0f, - run_norm = (float)player.mdl.anim_run->length/30.0f, - t = player.walk_timer, - l = vg_clampf( player.frun*15.0f, 0.0f, 1.0f ), - idle_walk = vg_clampf( (player.frun-0.1f)/(1.0f-0.1f), 0.0f, 1.0f ); - - /* walk/run */ - skeleton_sample_anim( sk, player.mdl.anim_walk, t*walk_norm, apose ); - skeleton_sample_anim( sk, player.mdl.anim_run, t*run_norm, bpose ); - - skeleton_lerp_pose( sk, apose, bpose, l, apose ); - - /* idle */ - skeleton_sample_anim( sk, player.mdl.anim_idle, vg.time*0.1f, bpose ); - skeleton_lerp_pose( sk, apose, bpose, 1.0f-idle_walk, apose ); - - /* air */ - skeleton_sample_anim( sk, player.mdl.anim_jump, vg.time*0.6f, bpose ); - skeleton_lerp_pose( sk, apose, bpose, player.ffly, apose ); - - skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_defer_ik ); - skeleton_apply_ik_pass( &player.mdl.sk ); - skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_deffered_only ); - - v3_copy( player.mdl.sk.final_mtx[player.mdl.id_head-1][3], - player.mdl.cam_pos ); - - - - skeleton_apply_inverses( &player.mdl.sk ); - - m4x3f mtx; - v4f rot; - q_axis_angle( rot, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] - VG_PIf*0.5f ); - q_m3x3( rot, mtx ); - v3_copy( player.visual_transform[3], mtx[3] ); - - skeleton_apply_transform( &player.mdl.sk, mtx ); - skeleton_debug( &player.mdl.sk ); -} - -#endif /* PLAYER_PHYSICS_WALK_H */ diff --git a/player_device_skate.h b/player_skate.c similarity index 77% rename from player_device_skate.h rename to player_skate.c index d657b4a..fedeee8 100644 --- a/player_device_skate.h +++ b/player_skate.c @@ -1,118 +1,11 @@ -#ifndef PLAYER_DEVICE_SKATE_H -#define PLAYER_DEVICE_SKATE_H +#ifndef PLAYER_SKATE_C +#define PLAYER_SKATE_C -#include "player_interface.h" -#include "skeleton.h" -#include "player_model.h" -#include "player_device_common.h" +#include "player.h" -VG_STATIC -struct player_device_skate +VG_STATIC void player__skate_bind( player_instance *player ) { - 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_skate *s = &player->_skate; struct player_avatar *av = player->playeravatar; struct skeleton *sk = &av->sk; @@ -126,8 +19,6 @@ VG_STATIC void player_skate_bind( player_device *dev, 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" ); } /* @@ -140,7 +31,7 @@ VG_STATIC void player_skate_bind( player_device *dev, * 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, +VG_STATIC int skate_collide_smooth( player_instance *player, m4x3f mtx, rb_sphere *sphere, rb_ct *man ) { @@ -217,9 +108,7 @@ VG_STATIC struct grind_edge *skate_collect_grind_edge( v3f p0, v3f p1, return closest_edge; } -VG_STATIC int skate_grind_collide( player_device *dev, - player_interface *player, - rb_ct *contact ) +VG_STATIC int skate_grind_collide( player_instance *player, rb_ct *contact ) { v3f p0, p1, c0, c1; v3_muladds( player->rb.co, player->rb.to_world[2], 0.5f, p0 ); @@ -374,9 +263,10 @@ VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr, } VG_STATIC -void player_approximate_best_trajectory( player_interface *player, - struct player_device_skate *s ) +void player_approximate_best_trajectory( player_instance *player ) { + struct player_skate *s = &player->_skate; + float pstep = VG_TIMESTEP_FIXED * 10.0f; float best_velocity_delta = -9999.9f; @@ -482,10 +372,11 @@ void player_approximate_best_trajectory( player_interface *player, * ------------------------------------------------ */ -VG_STATIC void skate_apply_grind_model( player_interface *player, - struct player_device_skate *s, +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 ) { @@ -559,14 +450,15 @@ VG_STATIC void skate_apply_grind_model( player_interface *player, /* * Air control, no real physics */ -VG_STATIC void skate_apply_air_model( player_interface *player, - struct player_device_skate *s ) +VG_STATIC void skate_apply_air_model( player_instance *player ) { + struct player_skate *s = &player->_skate; + if( s->state.activity != k_skate_activity_air ) return; if( s->state.activity_prev != k_skate_activity_air ) - player_approximate_best_trajectory( player, s ); + player_approximate_best_trajectory( player ); m3x3_mulv( s->state.velocity_bias, player->rb.v, player->rb.v ); ray_hit hit; @@ -609,9 +501,9 @@ VG_STATIC void skate_apply_air_model( player_interface *player, 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 ); + 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; @@ -660,8 +552,7 @@ VG_STATIC void skate_apply_air_model( player_interface *player, v3_copy( target_normal, s->land_normal ); } -VG_STATIC void skate_get_board_points( player_interface *player, - struct player_device_skate *s, +VG_STATIC void skate_get_board_points( player_instance *player, v3f front, v3f back ) { v3f pos_front = {0.0f,0.0f,-k_board_length}, @@ -674,10 +565,11 @@ VG_STATIC void skate_get_board_points( player_interface *player, /* * Casts and pushes a sphere-spring model into the world */ -VG_STATIC int skate_simulate_spring( player_interface *player, - struct player_device_skate *s, +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, @@ -724,10 +616,11 @@ VG_STATIC int skate_simulate_spring( player_interface *player, /* * Handles connection between the player and the ground */ -VG_STATIC void skate_apply_interface_model( player_interface *player, - struct player_device_skate *s, +VG_STATIC void skate_apply_interface_model( player_instance *player, rb_ct *manifold, int len ) { + struct player_skate *s = &player->_skate; + if( !((s->state.activity == k_skate_activity_ground) || (s->state.activity == k_skate_activity_air )) ) return; @@ -740,7 +633,7 @@ VG_STATIC void skate_apply_interface_model( player_interface *player, /* springs */ v3f spring0, spring1; - skate_get_board_points( player, s, spring1, spring0 ); + 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 ); @@ -813,9 +706,10 @@ VG_STATIC void skate_apply_interface_model( player_interface *player, } } -VG_STATIC void skate_apply_grab_model( player_interface *player, - struct player_device_skate *s ) +VG_STATIC void skate_apply_grab_model( player_instance *player ) { + struct player_skate *s = &player->_skate; + float grabt = player->input_grab->axis.value; if( grabt > 0.5f ) @@ -834,9 +728,10 @@ VG_STATIC void skate_apply_grab_model( player_interface *player, /* * Computes friction and surface interface model */ -VG_STATIC void skate_apply_friction_model( player_interface *player, - struct player_device_skate *s ) +VG_STATIC void skate_apply_friction_model( player_instance *player ) { + struct player_skate *s = &player->_skate; + if( s->state.activity != k_skate_activity_ground ) return; @@ -897,9 +792,9 @@ VG_STATIC void skate_apply_friction_model( player_interface *player, s->state.steery -= steer_scaled * k_rb_delta; } -VG_STATIC void skate_apply_jump_model( player_interface *player, - struct player_device_skate *s ) +VG_STATIC void skate_apply_jump_model( player_instance *player ) { + struct player_skate *s = &player->_skate; int charging_jump_prev = s->state.charging_jump; s->state.charging_jump = player->input_jump->button.value; @@ -966,9 +861,10 @@ VG_STATIC void skate_apply_jump_model( player_interface *player, } } -VG_STATIC void skate_apply_pump_model( player_interface *player, - struct player_device_skate *s ) +VG_STATIC void skate_apply_pump_model( player_instance *player ) { + struct player_skate *s = &player->_skate; + /* Throw / collect routine * * TODO: Max speed boost @@ -1013,9 +909,10 @@ VG_STATIC void skate_apply_pump_model( player_interface *player, } } -VG_STATIC void skate_apply_cog_model( player_interface *player, - struct player_device_skate *s ) +VG_STATIC void skate_apply_cog_model( player_instance *player ) { + struct player_skate *s = &player->_skate; + v3f ideal_cog, ideal_diff; v3_muladds( player->rb.co, player->rb.to_world[1], 1.0f-player->input_grab->axis.value, ideal_cog ); @@ -1038,10 +935,11 @@ VG_STATIC void skate_apply_cog_model( player_interface *player, 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, +VG_STATIC void skate_collision_response( player_instance *player, rb_ct *manifold, int len ) { + struct player_skate *s = &player->_skate; + for( int j=0; j<10; j++ ) { for( int i=0; i_skate; + /* integrate rigidbody velocities */ v3f gravity = { 0.0f, -9.6f, 0.0f }; v3_muladds( player->rb.v, gravity, k_rb_delta, player->rb.v ); @@ -1139,20 +1038,51 @@ VG_STATIC void skate_integrate( player_interface *player, 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 ) +VG_STATIC void player__skate_pre_update( player_instance *player ) +{ + if( vg_input_button_down( player->input_use ) ) + { + player->subsystem = k_player_subsystem_walk; + + v3f angles; + v3_copy( player->cam.angles, angles ); + angles[2] = 0.0f; + + player__walk_transition( player, angles ); + return; + } +} + +VG_STATIC void player__skate_post_update( player_instance *player ) +{ + struct player_skate *s = &player->_skate; + 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 ); +} + +VG_STATIC void player__skate_update( player_instance *player ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; v3_copy( player->rb.co, s->state.prev_pos ); s->state.activity_prev = s->state.activity; @@ -1161,7 +1091,7 @@ VG_STATIC void player_skate_update( player_device *dev, m3x3_identity( mtx_front ); m3x3_identity( mtx_back ); - skate_get_board_points( player, s, mtx_front[3], mtx_back[3] ); + skate_get_board_points( player, mtx_front[3], mtx_back[3] ); s->sphere_back.radius = 0.3f; s->sphere_front.radius = 0.3f; @@ -1208,7 +1138,7 @@ VG_STATIC void player_skate_update( player_device *dev, interface_manifold = manifold; grind_manifold = manifold + interface_len; - int grind_len = skate_grind_collide( dev, player, grind_manifold ); + int grind_len = skate_grind_collide( player, grind_manifold ); for( int i=0; istate.cog, 0.1f, VG__WHITE ); vg_line_pt3( s->state.cog, 0.11f, VG__WHITE ); @@ -1263,58 +1193,44 @@ VG_STATIC void player_skate_update( player_device *dev, rb_update_transform( &player->rb ); s->state_gate_storage = s->state; - player_pass_gate( player, gate ); + player__pass_gate( player, gate ); } } -VG_STATIC void player_skate_ui( player_device *dev, player_interface *player ) +VG_STATIC void player__skate_im_gui( player_instance *player ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; /* FIXME: Compression */ - player_debugtext( 1, "V: %5.2f %5.2f %5.2f",player->rb.v[0], + 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__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__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", + 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", + 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, + 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 ) +VG_STATIC void player__skate_animate( player_instance *player, + player_animation *dest ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; 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; @@ -1325,10 +1241,6 @@ VG_STATIC void player_skate_animate( player_device *dev, 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 ), @@ -1460,7 +1372,7 @@ VG_STATIC void player_skate_animate( player_device *dev, skeleton_lerp_pose( sk, apose, bpose, s->state.grabbing, air_pose ); } - skeleton_lerp_pose( sk, ground_pose, air_pose, s->blend_fly, dev->pose ); + skeleton_lerp_pose( sk, ground_pose, air_pose, s->blend_fly, dest->pose ); float add_grab_mod = 1.0f - s->blend_fly; @@ -1474,13 +1386,13 @@ VG_STATIC void player_skate_animate( player_device *dev, 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; + dest->pose[apply_to[i]-1].co[0] += offset[0]*add_grab_mod; + dest->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]; + mdl_keyframe *kf_board = &dest->pose[av->id_board-1], + *kf_foot_l = &dest->pose[av->id_ik_foot_l-1], + *kf_foot_r = &dest->pose[av->id_ik_foot_r-1]; v3f bo; v3_muls( s->board_offset, add_grab_mod, bo ); @@ -1506,10 +1418,9 @@ VG_STATIC void player_skate_animate( player_device *dev, } /* transform */ - rb_extrapolate( &player->rb, dev->pose_root_co, dev->pose_root_q ); + rb_extrapolate( &player->rb, dest->root_co, dest->root_q ); - v3_muladds( dev->pose_root_co, player->rb.to_world[1], -0.28f, - dev->pose_root_co ); + v3_muladds( dest->root_co, player->rb.to_world[1], -0.28f, dest->root_co ); v4f qresy, qresx, qresidual; m3x3f mtx_residual; @@ -1519,48 +1430,37 @@ VG_STATIC void player_skate_animate( player_device *dev, 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 ); + q_mul( dest->root_q, qresidual, dest->root_q ); + q_normalize( dest->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, + float t = s->state.flip_time + s->state.flip_rate*substep*k_rb_delta, + angle = vg_clampf( t, -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 ); + q_mul( qflip, dest->root_q, dest->root_q ); + q_normalize( dest->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 ); + v3_sub( dest->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 ); + v3_add( rco, rotation_point, dest->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 ) +VG_STATIC void skate_camera_vector_look( v3f angles, v3f v, float C, float k ) { float yaw = atan2f( v[0], -v[2] ), pitch = atan2f @@ -1572,22 +1472,19 @@ VG_STATIC void skate_camera_vector_look( camera *cam, v3f v, float C, float k ) ) ) * C + k; - cam->angles[0] = yaw; - cam->angles[1] = pitch; + angles[0] = yaw; + angles[1] = pitch; } -VG_STATIC void skate_camera_firstperson( player_device *dev, - player_interface *player ) +VG_STATIC void skate_camera_firstperson( player_instance *player ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; 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; + m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->cam1.co ); + v3_zero( player->cam1.angles ); v3f flat_dir, vel_dir, @@ -1612,13 +1509,12 @@ VG_STATIC void skate_camera_firstperson( player_device *dev, 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 ); + skate_camera_vector_look( player->cam1.angles, s->state.vl, 1.0f, 0.25f ); } -VG_STATIC void skate_camera_thirdperson( player_device *dev, - player_interface *player ) +VG_STATIC void skate_camera_thirdperson( player_instance *player ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; struct player_avatar *av = player->playeravatar; v3f origin, dir, target; @@ -1640,22 +1536,20 @@ VG_STATIC void skate_camera_thirdperson( player_device *dev, 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 ); + v3_copy( s->state.posl, player->cam3.co ); + skate_camera_vector_look( player->cam3.angles, s->state.dirl, 1.0f, 0.2f ); } -VG_STATIC void player_skate_post_animate( player_device *dev, - player_interface *player ) +VG_STATIC void player__skate_post_animate( player_instance *player ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; struct player_avatar *av = player->playeravatar; - v3_zero( dev->cam_1st.pos ); - v3_zero( dev->cam_1st.angles ); - dev->cam_1st.fov = 90.0f; + v3_zero( player->cam1.co ); + v3_zero( player->cam1.angles ); - skate_camera_thirdperson( dev, player ); - skate_camera_firstperson( dev, player ); + skate_camera_thirdperson( player ); + skate_camera_firstperson( player ); /* FIXME: Organize this. Its int wrong fucking place */ v3f vp0 = {0.0f,0.1f, 0.6f}, @@ -1665,11 +1559,10 @@ VG_STATIC void player_skate_post_animate( player_device *dev, 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, +VG_STATIC void player__skate_reset( player_instance *player, struct respawn_point *rp ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; v3_muladds( player->rb.co, player->rb.to_world[1], 1.0f, s->state.cog ); #if 0 @@ -1677,93 +1570,31 @@ VG_STATIC void player_skate_reset( player_device *dev, #endif } -VG_STATIC int player_skate_event( player_device *dev, player_interface *player, - enum player_device_event_type ev, - void *data ) +VG_STATIC void player__skate_transition( player_instance *player, + v3f init_velocity ) { - struct player_device_skate *s = dev->storage; + struct player_skate *s = &player->_skate; + s->state.activity_prev = k_skate_activity_ground; + s->state.activity = k_skate_activity_air; - 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; + v3f dir; + v3_copy( init_velocity, dir ); + v3_normalize( dir ); - 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 ); + q_axis_angle( player->rb.q, (v3f){0.0f,1.0f,0.0f}, + atan2f( dir[0], dir[2] ) ); + v3_copy( player->cam.pos, s->state.posl ); - vg_line_pt3( p->apex, 0.02f, 0xffffffff ); - } + m3x3f temp; + euler_m3x3( player->cam.angles, temp ); + v3_muls( temp[2], -1.0f, s->state.dirl ); - 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; + v3_muladds( player->rb.co, player->rb.to_world[1], 1.0f, s->state.cog ); + v3_copy( init_velocity, s->state.cog_v ); + v3_copy( init_velocity, player->rb.v ); - return 1; + rb_update_transform( &player->rb ); } -VG_STATIC player_device player_device_skate = -{ - .name = "skateboard", - .event = player_skate_event, - .storage = &localplayer_device_skate -}; -#endif /* PLAYER_DEVICE_SKATE_H */ +#endif /* PLAYER_SKATE_C */ diff --git a/player_skate.h b/player_skate.h new file mode 100644 index 0000000..57922a6 --- /dev/null +++ b/player_skate.h @@ -0,0 +1,121 @@ +#ifndef PLAYER_SKATE_H +#define PLAYER_SKATE_H + +#include "player_api.h" + +struct player_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; +}; + +VG_STATIC void player__skate_bind ( player_instance *player ); +VG_STATIC void player__skate_pre_update ( player_instance *player ); +VG_STATIC void player__skate_update ( player_instance *player ); +VG_STATIC void player__skate_post_update ( player_instance *player ); +VG_STATIC void player__skate_im_gui ( player_instance *player ); +VG_STATIC void player__skate_animate ( player_instance *player, + player_animation *anim ); +VG_STATIC void player__skate_post_animate ( player_instance *player ); +VG_STATIC void player__skate_reset ( player_instance *player, + struct respawn_point *rp ); + +VG_STATIC void player__skate_transition ( player_instance *player, + v3f init_velocity ); + +#endif /* PLAYER_SKATE_H */ diff --git a/player_device_walk.h b/player_walk.c similarity index 65% rename from player_device_walk.h rename to player_walk.c index c1fbd4f..77386fa 100644 --- a/player_device_walk.h +++ b/player_walk.c @@ -1,89 +1,32 @@ -#ifndef PLAYER_DEVICE_WALK_H -#define PLAYER_DEVICE_WALK_H +#ifndef PLAYER_WALK_C +#define PLAYER_WALK_C -#include "player_interface.h" -#include "player_device_common.h" -#include "skeleton.h" -#include "player_model.h" +#include "player.h" -VG_STATIC -struct player_device_walk +VG_STATIC void player__walk_pre_update( player_instance *player ) { - rb_capsule collider; - - struct - { - v3f angles; - v3f prev_pos; - - enum walk_activity - { - k_walk_activity_air, - k_walk_activity_ground, - k_walk_activity_sleep - } - activity; - } - state, - state_gate_storage; - - enum mdl_surface_prop surface; - struct skeleton_anim *anim_walk, *anim_run, *anim_idle, *anim_jump; - - float blend_fly, - blend_run, - blend_walk, - - move_speed, - walk_timer; - - u32 device_id_skate; -} -localplayer_device_walk; - -VG_STATIC void player_walk_pre_update( player_device *dev, - player_interface *player ) -{ - struct player_device_walk *w = dev->storage; + struct player_walk *w = &player->_walk; player_look( player, w->state.angles ); if( vg_input_button_down( player->input_use ) ) { - struct device_transition_skateboard inf; - - v3f xy_speed; - v3_copy( player->rb.v, xy_speed ); + v3f xy_speed, v; + v3_copy( player->rb.v, v ); + v3_copy( v, xy_speed ); xy_speed[1] = 0.0f; - if( v3_length2( xy_speed ) > 0.1f * 0.1f ) - { - v3_copy( player->rb.v, inf.dir ); - } - else + if( v3_length2( xy_speed ) < 0.1f * 0.1f ) { - inf.dir[0] = -sinf( -w->state.angles[0] ); - inf.dir[1] = 0.0f; - inf.dir[2] = -cosf( -w->state.angles[0] ); - v3_muls( inf.dir, 1.6f, player->rb.v ); + v[0] = -sinf( -w->state.angles[0] ); + v[1] = 0.0f; + v[2] = -cosf( -w->state.angles[0] ); + v3_muls( v, 1.6f, v ); } - player_transition_to_device( player, w->device_id_skate, &inf ); + player->subsystem = k_player_subsystem_skate; + player__skate_transition( player, v ); return; } - -#if 0 - v3f walk = { player->input_walkh->axis.value, - 0.0f, - -player->input_walkv->axis.value }; - - v3_muls( walk, 10.0f * vg.time_delta, walk ); - - m3x3f m; - euler_m3x3( w->angles, m ); - v3_muladds( player->rb.co, m[0], walk[0], player->rb.co ); - v3_muladds( player->rb.co, m[1], walk[1], player->rb.co ); - v3_muladds( player->rb.co, m[2], walk[2], player->rb.co ); -#endif } VG_STATIC int player_walk_normal_standable( v3f n ) @@ -124,10 +67,9 @@ VG_STATIC void player_friction( v3f v ) v3_muls( v, newspeed, v ); } -VG_STATIC void player_walk_update( player_device *dev, - player_interface *player ) +VG_STATIC void player__walk_update( player_instance *player ) { - struct player_device_walk *w = dev->storage; + struct player_walk *w = &player->_walk; v3_copy( player->rb.co, w->state.prev_pos ); w->collider.height = 2.0f; @@ -351,8 +293,6 @@ VG_STATIC void player_walk_update( player_device *dev, teleport_gate *gate; if( (gate = world_intersect_gates( player->rb.co, w->state.prev_pos )) ) { - struct player_device_walk *w = dev->storage; - m4x3_mulv( gate->transport, player->rb.co, player->rb.co ); m3x3_mulv( gate->transport, player->rb.v, player->rb.v ); rb_update_transform( &player->rb ); @@ -365,14 +305,13 @@ VG_STATIC void player_walk_update( player_device *dev, w->state.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] ); w->state_gate_storage = w->state; - player_pass_gate( player, gate ); + player__pass_gate( player, gate ); } } -VG_STATIC void player_walk_post_update( player_device *dev, - player_interface *player ) +VG_STATIC void player__walk_post_update( player_instance *player ) { - struct player_device_walk *w = dev->storage; + struct player_walk *w = &player->_walk; m4x3f mtx; m3x3_identity( mtx ); @@ -381,17 +320,12 @@ VG_STATIC void player_walk_post_update( player_device *dev, float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f ); v3_muladds( mtx[3], player->rb.v, k_rb_delta*substep, mtx[3] ); debug_capsule( mtx, w->collider.radius, w->collider.height, VG__YELOW ); - -#if 0 - player_apply_transport_to_cam( gate->transport ); -#endif - } -VG_STATIC void player_walk_animate( player_device *dev, - player_interface *player ) +VG_STATIC void player__walk_animate( player_instance *player, + player_animation *dest ) { - struct player_device_walk *w = dev->storage; + struct player_walk *w = &player->_walk; struct skeleton *sk = &player->playeravatar->sk; { @@ -444,21 +378,20 @@ VG_STATIC void player_walk_animate( player_device *dev, /* air */ skeleton_sample_anim( sk, w->anim_jump, vg.time*0.6f, bpose ); - skeleton_lerp_pose( sk, apose, bpose, w->blend_fly, dev->pose ); + skeleton_lerp_pose( sk, apose, bpose, w->blend_fly, dest->pose ); /* Create transform */ - rb_extrapolate( &player->rb, dev->pose_root_co, dev->pose_root_q ); - q_axis_angle( dev->pose_root_q, (v3f){0.0f,1.0f,0.0f}, + rb_extrapolate( &player->rb, dest->root_co, dest->root_q ); + q_axis_angle( dest->root_q, (v3f){0.0f,1.0f,0.0f}, -w->state.angles[0]-VG_PIf*0.5f ); } -VG_STATIC void player_walk_post_animate( player_device *dev, - player_interface *player ) +VG_STATIC void player__walk_post_animate( player_instance *player ) { /* * Camera */ - struct player_device_walk *w = dev->storage; + struct player_walk *w = &player->_walk; struct player_avatar *av = player->playeravatar; /* 3RD */ @@ -469,23 +402,20 @@ VG_STATIC void player_walk_post_animate( player_device *dev, v3_add( player->rb.co, (v3f){0.0f,2.0f,0.0f}, origin ); - v3_muladds( origin, angles[2], 2.0f, dev->cam_3rd.pos ); - v3_muladds( dev->cam_3rd.pos, angles[0], 0.5f, dev->cam_3rd.pos ); + v3_muladds( origin, angles[2], 2.0f, player->cam3.co ); + v3_muladds( player->cam3.co, angles[0], 0.5f, player->cam3.co ); float t; v3f n; - if( spherecast_world( origin, dev->cam_3rd.pos, 0.1f, &t, n ) != -1 ) - v3_lerp( origin, dev->cam_3rd.pos, t, dev->cam_3rd.pos ); - v3_copy( w->state.angles, dev->cam_3rd.angles ); - dev->cam_3rd.fov = 90.0f; - + if( spherecast_world( origin, player->cam3.co, 0.1f, &t, n ) != -1 ) + v3_lerp( origin, player->cam3.co, t, player->cam3.co ); + v3_copy( w->state.angles, player->cam3.angles ); /* 1ST */ /* 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_copy( w->state.angles, dev->cam_1st.angles ); - dev->cam_1st.fov = 90.0f; + m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->cam1.co ); + v3_copy( w->state.angles, player->cam1.angles ); /* FIXME: Organize this. Its int wrong fucking place */ v3f vp0 = {0.0f,0.1f, 0.6f}, @@ -496,19 +426,19 @@ VG_STATIC void player_walk_post_animate( player_device *dev, } -VG_STATIC void player_walk_ui( player_device *dev, player_interface *player ) +VG_STATIC void player__walk_im_gui( player_instance *player ) { - 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, "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] ); } -VG_STATIC void player_walk_bind( player_device *dev, player_interface *player ) +VG_STATIC void player__walk_bind( player_instance *player ) { - struct player_device_walk *w = dev->storage; + struct player_walk *w = &player->_walk; struct player_avatar *av = player->playeravatar; struct skeleton *sk = &av->sk; @@ -516,59 +446,12 @@ VG_STATIC void player_walk_bind( player_device *dev, player_interface *player ) w->anim_walk = skeleton_get_anim( sk, "walk" ); w->anim_run = skeleton_get_anim( sk, "run" ); w->anim_jump = skeleton_get_anim( sk, "jump" ); - - w->device_id_skate = player_get_device( player, "skateboard" ); } -VG_STATIC int player_walk_event( player_device *dev, player_interface *player, - enum player_device_event_type ev, void *data ) +VG_STATIC void player__walk_transition( player_instance *player, v3f angles ) { - struct player_device_walk *w = dev->storage; - - if( ev == k_player_device_event_bind ) - { - player_walk_bind( dev, player ); - } - else if( ev == k_player_device_event_custom_transition ) - { - struct device_transition_walk *inf = data; - v3_copy( inf->angles, w->state.angles ); - } - else if( ev == k_player_device_event_pre_update ) - { - player_walk_pre_update( dev, player ); - } - else if( ev == k_player_device_event_update ) - { - player_walk_update( dev, player ); - } - else if( ev == k_player_device_event_post_update ) - { - player_walk_post_update( dev, player ); - } - else if( ev == k_player_device_event_animate ) - { - player_walk_animate( dev, player ); - } - else if( ev == k_player_device_event_post_animate ) - { - player_walk_post_animate( dev, player ); - } - else if( ev == k_player_device_event_debug_ui ) - { - player_walk_ui( dev, player ); - } - else - return 0; - - return 1; + struct player_walk *w = &player->_walk; + v3_copy( angles, w->state.angles ); } -VG_STATIC player_device player_device_walk = -{ - .name = "walk", - .event = player_walk_event, - .storage = &localplayer_device_walk -}; - #endif /* PLAYER_DEVICE_WALK_H */ diff --git a/player_walk.h b/player_walk.h new file mode 100644 index 0000000..7a597c3 --- /dev/null +++ b/player_walk.h @@ -0,0 +1,47 @@ +#ifndef PLAYER_WALK_H +#define PLAYER_WALK_H + +#include "player_api.h" + +struct player_walk +{ + rb_capsule collider; + + struct + { + v3f angles; + v3f prev_pos; + + enum walk_activity + { + k_walk_activity_air, + k_walk_activity_ground, + k_walk_activity_sleep + } + activity; + } + state, + state_gate_storage; + + enum mdl_surface_prop surface; + struct skeleton_anim *anim_walk, *anim_run, *anim_idle, *anim_jump; + + float blend_fly, + blend_run, + blend_walk, + + move_speed, + walk_timer; +}; + +VG_STATIC void player__walk_pre_update ( player_instance *player ); +VG_STATIC void player__walk_update ( player_instance *player ); +VG_STATIC void player__walk_post_update ( player_instance *player ); +VG_STATIC void player__walk_animate ( player_instance *player, + player_animation *anim ); +VG_STATIC void player__walk_post_animate( player_instance *player ); +VG_STATIC void player__walk_im_gui ( player_instance *player ); +VG_STATIC void player__walk_bind ( player_instance *player ); +VG_STATIC void player__walk_transition ( player_instance *player, v3f angles ); + +#endif /* PLAYER_WALK_H */ diff --git a/player_walkgrid.h b/player_walkgrid.h deleted file mode 100644 index b2fff82..0000000 --- a/player_walkgrid.h +++ /dev/null @@ -1,967 +0,0 @@ -/* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved - */ - -#ifndef PLAYER_WALKGRID_H -#define PLAYER_WALKGRID_H - -#include "common.h" -#include "player.h" - -/* - * Walkgrid implementation, - * loosely based of cmuratoris youtube video 'Killing the Walkmonster' - */ - -#define WALKGRID_SIZE 16 -struct walkgrid -{ - struct grid_sample - { - enum sample_type - { - k_sample_type_air, /* Nothing was hit. */ - k_sample_type_invalid, /* The point is invalid, but there is a sample - underneath that can be used */ - k_sample_type_valid, /* This point is good */ - } - type; - - v3f clip[2]; - v3f pos; - - enum traverse_state - { - k_traverse_none = 0x00, - k_traverse_h = 0x01, - k_traverse_v = 0x02 - } - state; - } - samples[WALKGRID_SIZE][WALKGRID_SIZE]; - - boxf region; - - float move; /* Current amount of movement we have left to apply */ - v2f dir; /* The movement delta */ - v2i cell_id;/* Current cell */ - v2f pos; /* Local position (in cell) */ - float h; -}; - -static int player_walkgrid_tri_walkable( u32 tri[3] ) -{ - return tri[0] > world.sm_geo_std_oob.vertex_count; -} - -/* - * Get a sample at this pole location, will return 1 if the sample is valid, - * and pos will be updated to be the intersection location. - */ -static void player_walkgrid_samplepole( struct grid_sample *s ) -{ - boxf region = {{ s->pos[0] -0.01f, s->pos[1] - 4.0f, s->pos[2] -0.01f}, - { s->pos[0] +0.01f, s->pos[1] + 4.0f, s->pos[2] +0.01f}}; - - u32 geo[256]; - v3f tri[3]; - int len = bh_select( &world.geo.bhtris, region, geo, 256 ); - - const float k_minworld_y = -2000.0f; - - float walk_height = k_minworld_y, - block_height = k_minworld_y; - - s->type = k_sample_type_air; - - for( int i=0; ipos, sample_from ); - sample_from[1] = region[1][1]; - - float dist; - if( ray_tri( tri, sample_from, vdown, &dist )) - { - v3f p0; - v3_muladds( sample_from, vdown, dist, p0 ); - - if( player_walkgrid_tri_walkable(ptri) ) - { - if( p0[1] > walk_height ) - { - walk_height = p0[1]; - } - } - else - { - if( p0[1] > block_height ) - block_height = p0[1]; - } - } - } - - s->pos[1] = walk_height; - - if( walk_height > k_minworld_y ) - if( block_height > walk_height ) - s->type = k_sample_type_invalid; - else - s->type = k_sample_type_valid; - else - s->type = k_sample_type_air; -} - -float const k_gridscale = 0.5f; - -enum eclipdir -{ - k_eclipdir_h = 0, - k_eclipdir_v = 1 -}; - -static void player_walkgrid_clip_blocker( struct grid_sample *sa, - struct grid_sample *sb, - struct grid_sample *st, - enum eclipdir dir ) -{ - v3f clipdir, pos; - int valid_a = sa->type == k_sample_type_valid, - valid_b = sb->type == k_sample_type_valid; - struct grid_sample *target = valid_a? sa: sb, - *other = valid_a? sb: sa; - v3_copy( target->pos, pos ); - v3_sub( other->pos, target->pos, clipdir ); - - boxf cell_region; - v3_muladds( pos, (v3f){1.0f,1.0f,1.0f}, -k_gridscale*2.1f, cell_region[0]); - v3_muladds( pos, (v3f){1.0f,1.0f,1.0f}, k_gridscale*2.1f, cell_region[1]); - - u32 geo[256]; - v3f tri[3]; - int len = bh_select( &world.geo.bhtris, cell_region, geo, 256 ); - - float start_time = v3_length( clipdir ), - min_time = start_time; - v3_normalize( clipdir ); - v3_muls( clipdir, 0.0001f, st->clip[dir] ); - - for( int i=0; i 0.0f && dist < min_time ) - { - min_time = dist; - sb->type = k_sample_type_air; - } - } - } - - if( !(min_time < start_time) ) - min_time = 0.5f * k_gridscale; - - min_time = vg_clampf( min_time/k_gridscale, 0.01f, 0.99f ); - - v3_muls( clipdir, min_time, st->clip[dir] ); - - v3f p0; - v3_muladds( target->pos, st->clip[dir], k_gridscale, p0 ); -} - -static void player_walkgrid_clip_edge( struct grid_sample *sa, - struct grid_sample *sb, - struct grid_sample *st, /* data store */ - enum eclipdir dir ) -{ - v3f clipdir = { 0.0f, 0.0f, 0.0f }, pos; - int valid_a = sa->type == k_sample_type_valid, - valid_b = sb->type == k_sample_type_valid; - - struct grid_sample *target = valid_a? sa: sb, - *other = valid_a? sb: sa; - - v3_sub( other->pos, target->pos, clipdir ); - clipdir[1] = 0.0f; - - v3_copy( target->pos, pos ); - - boxf cell_region; - v3_muladds( pos, (v3f){1.0f,1.0f,1.0f}, -k_gridscale*1.1f, cell_region[0]); - v3_muladds( pos, (v3f){1.0f,1.0f,1.0f}, k_gridscale*1.1f, cell_region[1]); - - u32 geo[256]; - int len = bh_select( &world.geo.bhtris, cell_region, geo, 256 ); - - float max_dist = 0.0f; - v3f tri[3]; - v3f perp; - v3_cross( clipdir,(v3f){0.0f,1.0f,0.0f},perp ); - v3_muls( clipdir, 0.001f, st->clip[dir] ); - - for( int i=0; i= max_dist && h <= 1.0f ) - { - max_dist = h; - float l = 1.0f/v3_length(clipdir); - v3_muls( p0, l, st->clip[dir] ); - } - } - } - } -} - -static const struct conf -{ - struct confedge - { - /* i: sample index - * d: data index - * a: axis index - * o: the 'other' point to do a A/B test with - * if its -1, all AB is done. - */ - int i0, i1, - d0, d1, - a0, a1, - o0, o1; - } - edges[2]; - int edge_count; -} -k_walkgrid_configs[16] = { - {{},0}, - {{{ 3,3, 3,0, 1,0, -1,-1 }}, 1}, - {{{ 2,2, 1,3, 0,1, -1,-1 }}, 1}, - {{{ 2,3, 1,0, 0,0, 3,-1 }}, 1}, - - {{{ 1,1, 0,1, 1,0, -1,-1 }}, 1}, - {{{ 3,3, 3,0, 1,0, -1,-1 }, - { 1,1, 0,1, 1,0, -1,-1 }}, 2}, - {{{ 1,2, 0,3, 1,1, 2,-1 }}, 1}, - {{{ 1,3, 0,0, 1,0, 2, 2 }}, 1}, - - {{{ 0,0, 0,0, 0,1, -1,-1 }}, 1}, - {{{ 3,0, 3,0, 1,1, 0,-1 }}, 1}, - {{{ 2,2, 1,3, 0,1, -1,-1 }, - { 0,0, 0,0, 0,1, -1,-1 }}, 2}, - {{{ 2,0, 1,0, 0,1, 3, 3 }}, 1}, - - {{{ 0,1, 0,1, 0,0, 1,-1 }}, 1}, - {{{ 3,1, 3,1, 1,0, 0, 0 }}, 1}, - {{{ 0,2, 0,3, 0,1, 1, 1 }}, 1}, - {{},0}, -}; - -/* - * Get a buffer of edges from cell location - */ -static const struct conf *player_walkgrid_conf( struct walkgrid *wg, - v2i cell, - struct grid_sample *corners[4] ) -{ - corners[0] = &wg->samples[cell[1] ][cell[0] ]; - corners[1] = &wg->samples[cell[1]+1][cell[0] ]; - corners[2] = &wg->samples[cell[1]+1][cell[0]+1]; - corners[3] = &wg->samples[cell[1] ][cell[0]+1]; - - u32 vd0 = corners[0]->type == k_sample_type_valid, - vd1 = corners[1]->type == k_sample_type_valid, - vd2 = corners[2]->type == k_sample_type_valid, - vd3 = corners[3]->type == k_sample_type_valid, - config = (vd0<<3) | (vd1<<2) | (vd2<<1) | vd3; - - return &k_walkgrid_configs[ config ]; -} - -static void player_walkgrid_floor(v3f pos) -{ - v3_muls( pos, 1.0f/k_gridscale, pos ); - v3_floor( pos, pos ); - v3_muls( pos, k_gridscale, pos ); -} - -/* - * Computes the barycentric coordinate of location on a triangle (vertical), - * then sets the Y position to the interpolation of the three points - */ -static void player_walkgrid_stand_tri( v3f a, v3f b, v3f c, v3f pos ) -{ - v3f v0,v1,v2; - v3_sub( b, a, v0 ); - v3_sub( c, a, v1 ); - v3_sub( pos, a, v2 ); - - float d = v0[0]*v1[2] - v1[0]*v0[2], - v = (v2[0]*v1[2] - v1[0]*v2[2]) / d, - w = (v0[0]*v2[2] - v2[0]*v0[2]) / d, - u = 1.0f - v - w; - - vg_line( pos, a, 0xffff0000 ); - vg_line( pos, b, 0xff00ff00 ); - vg_line( pos, c, 0xff0000ff ); - pos[1] = u*a[1] + v*b[1] + w*c[1]; -} - -/* - * Get the minimum time value of pos+dir until a cell edge - * - * t[0] -> t[3] are the individual time values - * t[5] & t[6] are the maximum axis values - * t[6] is the minimum value - * - */ -static void player_walkgrid_min_cell( float t[7], v2f pos, v2f dir ) -{ - v2f frac = { 1.0f/dir[0], 1.0f/dir[1] }; - - t[0] = 999.9f; - t[1] = 999.9f; - t[2] = 999.9f; - t[3] = 999.9f; - - if( fabsf(dir[0]) > 0.0001f ) - { - t[0] = (0.0f-pos[0]) * frac[0]; - t[1] = (1.0f-pos[0]) * frac[0]; - } - if( fabsf(dir[1]) > 0.0001f ) - { - t[2] = (0.0f-pos[1]) * frac[1]; - t[3] = (1.0f-pos[1]) * frac[1]; - } - - t[4] = vg_maxf(t[0],t[1]); - t[5] = vg_maxf(t[2],t[3]); - t[6] = vg_minf(t[4],t[5]); -} - -static void player_walkgrid_iter(struct walkgrid *wg, int iter) -{ - - /* - * For each walkgrid iteration we are stepping through cells and determining - * the intersections with the grid, and any edges that are present - */ - - u32 icolours[] = { 0xffff00ff, 0xff00ffff, 0xffffff00 }; - - v3f pa, pb, pc, pd, pl0, pl1; - pa[0] = wg->region[0][0] + (float)wg->cell_id[0] *k_gridscale; - pa[1] = (wg->region[0][1] + wg->region[1][1]) * 0.5f + k_gridscale; - pa[2] = wg->region[0][2] + (float)wg->cell_id[1] *k_gridscale; -#if 0 - pb[0] = pa[0]; - pb[1] = pa[1]; - pb[2] = pa[2] + k_gridscale; - pc[0] = pa[0] + k_gridscale; - pc[1] = pa[1]; - pc[2] = pa[2] + k_gridscale; - pd[0] = pa[0] + k_gridscale; - pd[1] = pa[1]; - pd[2] = pa[2]; - /* if you want to draw the current cell */ - vg_line( pa, pb, 0xff00ffff ); - vg_line( pb, pc, 0xff00ffff ); - vg_line( pc, pd, 0xff00ffff ); - vg_line( pd, pa, 0xff00ffff ); -#endif - pl0[0] = pa[0] + wg->pos[0]*k_gridscale; - pl0[1] = pa[1]; - pl0[2] = pa[2] + wg->pos[1]*k_gridscale; - - /* - * If there are edges present, we need to create a 'substep' event, where - * we find the intersection point, find the fully resolved position, - * then the new pos dir is the intersection->resolution - * - * the resolution is applied in non-discretized space in order to create a - * suitable vector for finding outflow, we want it to leave the cell so it - * can be used by the quad - */ - - v2f pos, dir; - v2_copy( wg->pos, pos ); - v2_muls( wg->dir, wg->move, dir ); - - struct grid_sample *corners[4]; - v2f corners2d[4] = {{0.0f,0.0f},{0.0f,1.0f},{1.0f,1.0f},{1.0f,0.0f}}; - const struct conf *conf = player_walkgrid_conf( wg, wg->cell_id, corners ); - - float t[7]; - player_walkgrid_min_cell( t, pos, dir ); - - for( int i=0; iedge_count; i++ ) - { - const struct confedge *edge = &conf->edges[i]; - - v2f e0, e1, n, r, target, res, tangent; - e0[0] = corners2d[edge->i0][0] + corners[edge->d0]->clip[edge->a0][0]; - e0[1] = corners2d[edge->i0][1] + corners[edge->d0]->clip[edge->a0][2]; - e1[0] = corners2d[edge->i1][0] + corners[edge->d1]->clip[edge->a1][0]; - e1[1] = corners2d[edge->i1][1] + corners[edge->d1]->clip[edge->a1][2]; - - v3f pe0 = { pa[0] + e0[0]*k_gridscale, - pa[1], - pa[2] + e0[1]*k_gridscale }; - v3f pe1 = { pa[0] + e1[0]*k_gridscale, - pa[1], - pa[2] + e1[1]*k_gridscale }; - - v2_sub( e1, e0, tangent ); - n[0] = -tangent[1]; - n[1] = tangent[0]; - v2_normalize( n ); - - /* - * If we find ourselfs already penetrating the edge, move back out a - * little - */ - v2_sub( e0, pos, r ); - float p1 = v2_dot(r,n); - - if( -p1 < 0.0001f ) - { - v2_muladds( pos, n, p1+0.0001f, pos ); - v2_copy( pos, wg->pos ); - v3f p_new = { pa[0] + pos[0]*k_gridscale, - pa[1], - pa[2] + pos[1]*k_gridscale }; - v3_copy( p_new, pl0 ); - } - - v2_add( pos, dir, target ); - - v2f v1, v2, v3; - v2_sub( e0, pos, v1 ); - v2_sub( target, pos, v2 ); - - v2_copy( n, v3 ); - - v2_sub( e0, target, r ); - float p = v2_dot(r,n), - t1 = v2_dot(v1,v3)/v2_dot(v2,v3); - - if( t1 < t[6] && t1 > 0.0f && -p < 0.001f ) - { - v2_muladds( target, n, p+0.0001f, res ); - - v2f intersect; - v2_muladds( pos, dir, t1, intersect ); - v2_copy( intersect, pos ); - v2_sub( res, intersect, dir ); - - v3f p_res = { pa[0] + res[0]*k_gridscale, - pa[1], - pa[2] + res[1]*k_gridscale }; - v3f p_int = { pa[0] + intersect[0]*k_gridscale, - pa[1], - pa[2] + intersect[1]*k_gridscale }; - - vg_line( pl0, p_int, icolours[iter%3] ); - v3_copy( p_int, pl0 ); - v2_copy( pos, wg->pos ); - - player_walkgrid_min_cell( t, pos, dir ); - } - } - - /* - * Compute intersection with grid cell moving outwards - */ - t[6] = vg_minf( t[6], 1.0f ); - - pl1[0] = pl0[0] + dir[0]*k_gridscale*t[6]; - pl1[1] = pl0[1]; - pl1[2] = pl0[2] + dir[1]*k_gridscale*t[6]; - vg_line( pl0, pl1, icolours[iter%3] ); - - if( t[6] < 1.0f ) - { - /* - * To figure out what t value created the clip so we know which edge - * to wrap around - */ - - if( t[4] < t[5] ) - { - wg->pos[1] = pos[1] + dir[1]*t[6]; - - if( t[0] > t[1] ) /* left edge */ - { - wg->pos[0] = 0.9999f; - wg->cell_id[0] --; - - if( wg->cell_id[0] == 0 ) - wg->move = -1.0f; - } - else /* Right edge */ - { - wg->pos[0] = 0.0001f; - wg->cell_id[0] ++; - - if( wg->cell_id[0] == WALKGRID_SIZE-2 ) - wg->move = -1.0f; - } - } - else - { - wg->pos[0] = pos[0] + dir[0]*t[6]; - - if( t[2] > t[3] ) /* bottom edge */ - { - wg->pos[1] = 0.9999f; - wg->cell_id[1] --; - - if( wg->cell_id[1] == 0 ) - wg->move = -1.0f; - } - else /* top edge */ - { - wg->pos[1] = 0.0001f; - wg->cell_id[1] ++; - - if( wg->cell_id[1] == WALKGRID_SIZE-2 ) - wg->move = -1.0f; - } - } - - wg->move -= t[6]; - } - else - { - v2_muladds( wg->pos, dir, wg->move, wg->pos ); - wg->move = 0.0f; - } -} - -static void player_walkgrid_stand_cell(struct walkgrid *wg) -{ - /* - * NOTE: as opposed to the other function which is done in discretized space - * this use a combination of both. - */ - - v3f world; - world[0] = wg->region[0][0]+((float)wg->cell_id[0]+wg->pos[0])*k_gridscale; - world[1] = player.phys.rb.co[1]; - world[2] = wg->region[0][2]+((float)wg->cell_id[1]+wg->pos[1])*k_gridscale; - - struct grid_sample *corners[4]; - const struct conf *conf = player_walkgrid_conf( wg, wg->cell_id, corners ); - - if( conf != k_walkgrid_configs ) - { - if( conf->edge_count == 0 ) - { - v3f v0; - - /* Split the basic quad along the shortest diagonal */ - if( fabsf(corners[2]->pos[1] - corners[0]->pos[1]) < - fabsf(corners[3]->pos[1] - corners[1]->pos[1]) ) - { - vg_line( corners[2]->pos, corners[0]->pos, 0xffaaaaaa ); - - if( wg->pos[0] > wg->pos[1] ) - player_walkgrid_stand_tri( corners[0]->pos, - corners[3]->pos, - corners[2]->pos, world ); - else - player_walkgrid_stand_tri( corners[0]->pos, - corners[2]->pos, - corners[1]->pos, world ); - } - else - { - vg_line( corners[3]->pos, corners[1]->pos, 0xffaaaaaa ); - - if( wg->pos[0] < 1.0f-wg->pos[1] ) - player_walkgrid_stand_tri( corners[0]->pos, - corners[3]->pos, - corners[1]->pos, world ); - else - player_walkgrid_stand_tri( corners[3]->pos, - corners[2]->pos, - corners[1]->pos, world ); - } - } - else - { - for( int i=0; iedge_count; i++ ) - { - const struct confedge *edge = &conf->edges[i]; - - v3f p0, p1; - v3_muladds( corners[edge->i0]->pos, - corners[edge->d0]->clip[edge->a0], k_gridscale, p0 ); - v3_muladds( corners[edge->i1]->pos, - corners[edge->d1]->clip[edge->a1], k_gridscale, p1 ); - - /* - * Find penetration distance between player position and the edge - */ - - v2f normal = { -(p1[2]-p0[2]), p1[0]-p0[0] }, - rel = { world[0]-p0[0], world[2]-p0[2] }; - - if( edge->o0 == -1 ) - { - /* No subregions (default case), just use triangle created by - * i0, e0, e1 */ - player_walkgrid_stand_tri( corners[edge->i0]->pos, - p0, - p1, world ); - } - else - { - /* - * Test if we are in the first region, which is - * edge.i0, edge.e0, edge.o0, - */ - v3f v0, ref; - v3_sub( p0, corners[edge->o0]->pos, ref ); - v3_sub( world, corners[edge->o0]->pos, v0 ); - - vg_line( corners[edge->o0]->pos, p0, 0xffffff00 ); - vg_line( corners[edge->o0]->pos, world, 0xff000000 ); - - if( ref[0]*v0[2] - ref[2]*v0[0] < 0.0f ) - { - player_walkgrid_stand_tri( corners[edge->i0]->pos, - p0, - corners[edge->o0]->pos, world ); - } - else - { - if( edge->o1 == -1 ) - { - /* - * No other edges mean we just need to use the opposite - * - * e0, e1, o0 (in our case, also i1) - */ - player_walkgrid_stand_tri( p0, - p1, - corners[edge->o0]->pos, world ); - } - else - { - /* - * Note: this v0 calculation can be ommited with the - * current tileset. - * - * the last two triangles we have are: - * e0, e1, o1 - * and - * e1, i1, o1 - */ - v3_sub( p1, corners[edge->o1]->pos, ref ); - v3_sub( world, corners[edge->o1]->pos, v0 ); - vg_line( corners[edge->o1]->pos, p1, 0xff00ffff ); - - if( ref[0]*v0[2] - ref[2]*v0[0] < 0.0f ) - { - player_walkgrid_stand_tri( p0, - p1, - corners[edge->o1]->pos, - world ); - } - else - { - player_walkgrid_stand_tri( p1, - corners[edge->i1]->pos, - corners[edge->o1]->pos, - world ); - } - } - } - } - } - } - } - - v3_copy( world, player.phys.rb.co ); -} - -static void player_walkgrid_getsurface(void) -{ - float const k_stepheight = 0.5f; - float const k_miny = 0.6f; - float const k_height = 1.78f; - float const k_region_size = (float)WALKGRID_SIZE/2.0f * k_gridscale; - - static struct walkgrid wg; - - v3f cell; - v3_copy( player.phys.rb.co, cell ); - player_walkgrid_floor( cell ); - - v3_muladds( cell, (v3f){-1.0f,-1.0f,-1.0f}, k_region_size, wg.region[0] ); - v3_muladds( cell, (v3f){ 1.0f, 1.0f, 1.0f}, k_region_size, wg.region[1] ); - - - /* - * Create player input vector - */ - v3f delta = {0.0f,0.0f,0.0f}; - v3f fwd = { -sinf(-player.angles[0]), 0.0f, -cosf(-player.angles[0]) }, - side = { -fwd[2], 0.0f, fwd[0] }; - - /* Temp */ - if( !vg_console_enabled() ) - { - if( glfwGetKey( vg.window, GLFW_KEY_W ) ) - v3_muladds( delta, fwd, ktimestep*k_walkspeed, delta ); - if( glfwGetKey( vg.window, GLFW_KEY_S ) ) - v3_muladds( delta, fwd, -ktimestep*k_walkspeed, delta ); - - if( glfwGetKey( vg.window, GLFW_KEY_A ) ) - v3_muladds( delta, side, -ktimestep*k_walkspeed, delta ); - if( glfwGetKey( vg.window, GLFW_KEY_D ) ) - v3_muladds( delta, side, ktimestep*k_walkspeed, delta ); - - v3_muladds( delta, fwd, - vg_get_axis("vertical")*-ktimestep*k_walkspeed, delta ); - v3_muladds( delta, side, - vg_get_axis("horizontal")*ktimestep*k_walkspeed, delta ); - } - - /* - * Create our move in grid space - */ - wg.dir[0] = delta[0] * (1.0f/k_gridscale); - wg.dir[1] = delta[2] * (1.0f/k_gridscale); - wg.move = 1.0f; - - v2f region_pos = - { - (player.phys.rb.co[0] - wg.region[0][0]) * (1.0f/k_gridscale), - (player.phys.rb.co[2] - wg.region[0][2]) * (1.0f/k_gridscale) - }; - v2f region_cell_pos; - v2_floor( region_pos, region_cell_pos ); - v2_sub( region_pos, region_cell_pos, wg.pos ); - - wg.cell_id[0] = region_cell_pos[0]; - wg.cell_id[1] = region_cell_pos[1]; - - for(int y=0; ypos ); - s->state = k_traverse_none; - s->type = k_sample_type_air; - v3_zero( s->clip[0] ); - v3_zero( s->clip[1] ); - } - } - - v2i border[WALKGRID_SIZE*WALKGRID_SIZE]; - v2i *cborder = border; - u32 border_length = 1; - - struct grid_sample *base = NULL; - - v2i starters[] = {{0,0},{1,1},{0,1},{1,0}}; - - for( int i=0;i<4;i++ ) - { - v2i test; - v2i_add( wg.cell_id, starters[i], test ); - v2i_copy( test, border[0] ); - base = &wg.samples[test[1]][test[0]]; - - base->pos[1] = cell[1]; - player_walkgrid_samplepole( base ); - - if( base->type == k_sample_type_valid ) - break; - else - base->type = k_sample_type_air; - } - - vg_line_pt3( base->pos, 0.1f, 0xffffffff ); - - int iter = 0; - - while( border_length ) - { - v2i directions[] = {{1,0},{0,1},{-1,0},{0,-1}}; - - v2i *old_border = cborder; - int len = border_length; - - border_length = 0; - cborder = old_border+len; - - for( int i=0; istate & thismove) == 0x00 || - sb->type == k_sample_type_air ) - { - sb->pos[1] = sa->pos[1]; - - player_walkgrid_samplepole( sb ); - - if( sb->type != k_sample_type_air ) - { - /* - * Need to do a blocker pass - */ - - struct grid_sample *store = (j>>1 == 0)? sa: sb; - player_walkgrid_clip_blocker( sa, sb, store, j%2 ); - - - if( sb->type != k_sample_type_air ) - { - vg_line( sa->pos, sb->pos, 0xffffffff ); - - if( sb->state == k_traverse_none ) - v2i_copy( newp, cborder[ border_length ++ ] ); - } - else - { - v3f p1; - v3_muladds( sa->pos, store->clip[j%2], k_gridscale, p1 ); - vg_line( sa->pos, p1, 0xffffffff ); - } - } - else - { - /* - * A clipping pass is now done on the edge of the walkable - * surface - */ - - struct grid_sample *store = (j>>1 == 0)? sa: sb; - player_walkgrid_clip_edge( sa, sb, store, j%2 ); - - v3f p1; - v3_muladds( sa->pos, store->clip[j%2], k_gridscale, p1 ); - vg_line( sa->pos, p1, 0xffffffff ); - } - - sb->state |= thismove; - } - } - - sa->state = k_traverse_h|k_traverse_v; - } - - iter ++; - if( iter == walk_grid_iterations ) - break; - } - - /* Draw connections */ - struct grid_sample *corners[4]; - for( int x=0; xedge_count; i++ ) - { - const struct confedge *edge = &conf->edges[i]; - - v3f p0, p1; - v3_muladds( corners[edge->i0]->pos, - corners[edge->d0]->clip[edge->a0], k_gridscale, p0 ); - v3_muladds( corners[edge->i1]->pos, - corners[edge->d1]->clip[edge->a1], k_gridscale, p1 ); - - vg_line( p0, p1, 0xff0000ff ); - } - } - } - - /* - * Commit player movement into the grid - */ - - if( v3_length2(delta) <= 0.00001f ) - return; - - int i=0; - for(; i<8 && wg.move > 0.001f; i++ ) - player_walkgrid_iter( &wg, i ); - - player_walkgrid_stand_cell( &wg ); -} - -static void player_walkgrid(void) -{ - player_walkgrid_getsurface(); - - m4x3_mulv(player.phys.rb.to_world, (v3f){0.0f,1.8f,0.0f}, player.camera_pos); - player_mouseview(); - rb_update_transform( &player.phys.rb ); -} - -#endif /* PLAYER_WALKGRID_H */ diff --git a/skaterift.c b/skaterift.c index b3d51c3..574f3a6 100644 --- a/skaterift.c +++ b/skaterift.c @@ -22,16 +22,26 @@ #if 0 #include "player.h" #else + +#include "player.h" +VG_STATIC player_instance localplayer; + +#if 0 + #include "player_interface.h" #include "player_device_walk.h" #include "player_device_skate.h" #include "player_device_dead.h" #include "player_model.h" + /* temp */ VG_STATIC player_interface localplayer; +#endif + VG_STATIC struct player_avatar localplayer_avatar; VG_STATIC glmesh localplayer_meshes[3]; +vg_tex2d localplayer_texture = { .path = "textures/ch_gradient.qoi" }; #endif @@ -121,7 +131,7 @@ VG_STATIC int __respawn( int argc, const char *argv[] ) rp = &world.spawns[0]; } - player_spawn( &localplayer, rp ); + player__spawn( &localplayer, rp ); return 1; } @@ -225,7 +235,7 @@ VG_STATIC void load_playermodels(void) shader_viewchar_register(); vg_acquire_thread_sync(); { - vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 ); + vg_tex2d_init( (vg_tex2d *[]){ &localplayer_texture }, 1 ); } vg_release_thread_sync(); } @@ -244,16 +254,12 @@ VG_STATIC void vg_load(void) vg_loader_step( load_playermodels, NULL ); /* player setup */ - player_interface_create_player( &localplayer ); - + player__create( &localplayer ); player_avatar_load( &localplayer_avatar, "models/ch_new.mdl" ); - player_use_avatar( &localplayer, &localplayer_avatar ); - player_use_mesh( &localplayer, &localplayer_meshes[0] ); - - player_add_device( &localplayer, &player_device_walk ); - player_add_device( &localplayer, &player_device_skate ); - player_add_device( &localplayer, &player_device_dead ); - player_bind( &localplayer ); + player__use_avatar( &localplayer, &localplayer_avatar ); + player__use_mesh( &localplayer, &localplayer_meshes[0] ); + player__use_texture( &localplayer, &localplayer_texture ); + player__bind( &localplayer ); /* --------------------- */ @@ -294,7 +300,7 @@ VG_STATIC void vg_update(void) player_update_pre(); #endif - player_pre_update( &localplayer ); + player__pre_update( &localplayer ); world_update( localplayer.rb.co ); } } @@ -310,7 +316,7 @@ VG_STATIC void vg_update_fixed(void) vehicle_update_fixed(); #endif - player_update( &localplayer ); + player__update( &localplayer ); } } @@ -329,7 +335,7 @@ VG_STATIC void vg_update_post(void) } #endif - player_post_update( &localplayer ); + player__post_update( &localplayer ); #if 0 menu_update(); @@ -400,7 +406,7 @@ VG_STATIC void render_player_transparent(void) /* Draw player to window buffer and blend background ontop */ glBindFramebuffer( GL_FRAMEBUFFER, 0 ); - player_render( &small_cam, &localplayer ); + player__render( &small_cam, &localplayer ); } VG_STATIC void render_scene(void) @@ -419,7 +425,7 @@ VG_STATIC void render_scene(void) player_draw = 1; if( !player_transparent && player_draw ) - player_render( &main_camera, &localplayer ); + player__render( &main_camera, &localplayer ); render_water_texture( &main_camera ); render_fb_bind( gpipeline.fb_main ); @@ -459,7 +465,7 @@ VG_STATIC void render_main_game(void) * TODO: blend with camera from menu */ /* FIXME: TEMP!! */ - player_pre_render( &localplayer ); + player__pre_render( &localplayer ); v3_copy( localplayer.cam.pos, main_camera.pos ); v3_copy( localplayer.cam.angles, main_camera.angles ); @@ -510,7 +516,7 @@ VG_STATIC void vg_render(void) VG_STATIC void run_light_widget( struct light_widget *lw ); VG_STATIC void vg_ui(void) { - player_ui( &localplayer ); + player__im_gui( &localplayer ); #if 0 menu_crap_ui(); -- 2.25.1