2325f72e5c3fc71f38093f5d0851d62d45b8eb51
[carveJwlIkooP6JGAAIwe30JlM.git] / player.h
1 /*
2 * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 /*
6 * TODO: Tilt camera down to face borde when its behind you or out of vision
7 */
8
9 #ifndef PLAYER_H
10 #define PLAYER_H
11
12 #define PLAYER_REWIND_FRAMES 60*4
13
14 #include "conf.h"
15 #include "audio.h"
16 #include "common.h"
17 #include "world.h"
18 #include "skeleton.h"
19 #include "bvh.h"
20
21 VG_STATIC float
22 k_walkspeed = 12.0f,
23 k_air_accelerate = 20.0f,
24
25 k_runspeed = 20.0f,
26 k_board_radius = 0.3f,
27 k_board_length = 0.45f,
28 k_board_allowance = 0.04f,
29 //k_friction_lat = 8.8f,
30 k_friction_lat = 12.0f,
31 k_friction_resistance = 0.01f,
32 k_max_push_speed = 16.0f,
33 k_push_accel = 10.0f,
34 k_push_cycle_rate = 8.0f,
35 k_steer_ground = 2.5f,
36 k_steer_air = 3.6f,
37 k_steer_air_lerp = 0.3f,
38 k_pump_force = 0.0f,
39 k_downforce = 8.0f,
40 k_walk_downforce = 8.0f,
41 k_jump_charge_speed = (1.0f/1.0f),
42 k_jump_force = 5.0f,
43 k_pitch_limit = 1.5f,
44 k_look_speed = 2.0f,
45 k_walk_accel = 150.0f,
46 k_walk_friction = 8.0f;
47
48 VG_STATIC int freecam = 0;
49 VG_STATIC int walk_grid_iterations = 1;
50 VG_STATIC float fc_speed = 10.0f;
51 VG_STATIC int cl_thirdperson = 0;
52
53 /*
54 * -----------------------------------------------------------------------------
55 * Memory
56 * -----------------------------------------------------------------------------
57 */
58
59 VG_STATIC struct gplayer
60 {
61 /* Physics */
62 rigidbody collide_front, collide_back;
63
64 struct player_phys
65 {
66 rigidbody rb, rb_gate_frame;
67 float iY, siY; /* Yaw inertia */
68
69 v3f a, v_last, m, bob, vl;
70
71 /* Utility */
72 float vswitch, slip, slip_last, reverse;
73 float grab, jump, pushing, push_time, rise;
74 v2f grab_mouse_delta;
75
76 int lift_frames;
77
78 double start_push;
79 int in_air, on_board, jump_charge, jump_dir, grind;
80
81 m3x3f vr,vr_pstep;
82 }
83 phys,
84 phys_gate_frame;
85
86 m4x3f visual_transform,
87 inv_visual_transform;
88
89 int is_dead, death_tick_allowance, rewinding;
90 int rewind_sound_wait;
91
92 struct land_prediction
93 {
94 v3f log[50];
95 v3f n;
96 u32 log_length;
97 float score;
98
99 enum prediction_type
100 {
101 k_prediction_none,
102 k_prediction_land,
103 k_prediction_grind
104 }
105 type;
106
107 u32 colour;
108 }
109 predictions[22];
110 u32 prediction_count;
111
112 v3f handl_target, handr_target,
113 handl, handr;
114
115 /* Input */
116 struct input_binding *input_js1h,
117 *input_js1v,
118 *input_js2h,
119 *input_js2v,
120 *input_jump,
121 *input_push,
122 *input_walk,
123 *input_walkh,
124 *input_walkv,
125 *input_switch_mode,
126 *input_reset,
127 *input_grab;
128
129 /* Camera */
130 float air_blend;
131 float air_time;
132
133 v3f camera_pos, smooth_localcam;
134 v2f angles;
135
136 struct rewind_frame
137 {
138 v3f pos;
139 v2f ang;
140 }
141 *rewind_buffer;
142 u32 rewind_incrementer,
143 rewind_length;
144
145 float rewind_time, rewind_total_length, rewind_predicted_time;
146 double diag_rewind_start, diag_rewind_time;
147 float dist_accum;
148
149 /* animation */
150 double jump_time;
151 float fslide,
152 fdirz, fdirx,
153 fstand,
154 ffly,
155 fpush,
156 fairdir,
157 fsetup,
158 walk_timer,
159 fjump,
160 fonboard,
161 frun,
162 fgrind;
163
164 float walk;
165 int step_phase;
166 enum mdl_surface_prop surface_prop;
167
168 /* player model */
169 struct player_model
170 {
171 glmesh player_meshes[3];
172
173 mdl_context meta;
174 struct skeleton sk;
175 struct skeleton_anim *anim_stand,
176 *anim_highg,
177 *anim_slide,
178 *anim_air,
179 *anim_push, *anim_push_reverse,
180 *anim_ollie, *anim_ollie_reverse,
181 *anim_grabs, *anim_stop,
182 *anim_walk, *anim_run, *anim_idle,
183 *anim_jump;
184
185 u32 id_hip,
186 id_ik_hand_l,
187 id_ik_hand_r,
188 id_ik_elbow_l,
189 id_ik_elbow_r,
190 id_head;
191
192 v3f cam_pos;
193
194 struct ragdoll_part
195 {
196 u32 bone_id;
197 v3f offset;
198
199 u32 use_limits;
200 v3f limits[2];
201
202 rigidbody rb;
203 u32 parent;
204 }
205 ragdoll[32];
206 u32 ragdoll_count;
207
208 int shoes[2];
209 }
210 mdl;
211 }
212 player =
213 {
214 .collide_front = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f },
215 .collide_back = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f }
216 };
217
218 /*
219 * API
220 */
221 VG_STATIC float *player_get_pos(void);
222 VG_STATIC void player_kill(void);
223 VG_STATIC float *player_cam_pos(void);
224 VG_STATIC void player_save_frame(void);
225 VG_STATIC void player_restore_frame(void);
226 VG_STATIC void player_save_rewind_frame(void);
227
228 /*
229 * Submodules
230 */
231 VG_STATIC void player_mouseview(void);
232
233 #include "player_physics.h"
234 #include "player_ragdoll.h"
235 #include "player_model.h"
236 #include "player_animation.h"
237 #include "player_audio.h"
238
239 /*
240 * -----------------------------------------------------------------------------
241 * Events
242 * -----------------------------------------------------------------------------
243 */
244
245 VG_STATIC void player_init(void) /* 1 */
246 {
247 player.input_js1h = vg_create_named_input( "steer-h", k_input_type_axis );
248 player.input_js1v = vg_create_named_input( "steer-v", k_input_type_axis );
249 player.input_grab = vg_create_named_input( "grab", k_input_type_axis_norm );
250 player.input_js2h = vg_create_named_input( "grab-h", k_input_type_axis );
251 player.input_js2v = vg_create_named_input( "grab-v", k_input_type_axis );
252 player.input_jump = vg_create_named_input( "jump", k_input_type_button );
253 player.input_push = vg_create_named_input( "push", k_input_type_button );
254 player.input_walk = vg_create_named_input( "walk", k_input_type_button );
255
256 player.input_walkh = vg_create_named_input( "walk-h",
257 k_input_type_axis );
258 player.input_walkv = vg_create_named_input( "walk-v",
259 k_input_type_axis );
260
261
262 player.input_switch_mode = vg_create_named_input( "switch-mode",
263 k_input_type_button );
264 player.input_reset = vg_create_named_input( "reset", k_input_type_button );
265
266 const char *default_cfg[] =
267 {
268 "bind steer-h gp-ls-h",
269 "bind -steer-h a",
270 "bind +steer-h d",
271
272 "bind steer-v gp-ls-v",
273 "bind -steer-v w",
274 "bind +steer-v s",
275
276 "bind grab gp-rt",
277 "bind +grab shift",
278 "bind grab-h gp-rs-h",
279 "bind grab-v gp-rs-v",
280
281 "bind jump space",
282 "bind jump gp-a",
283
284 "bind push gp-b",
285 "bind push w",
286
287 "bind walk shift",
288 "bind walk gp-ls",
289
290 "bind walk-h gp-ls-h",
291 "bind walk-v -gp-ls-v",
292 "bind +walk-h d",
293 "bind -walk-h a",
294 "bind +walk-v w",
295 "bind -walk-v s",
296
297 "bind reset gp-lb",
298 "bind reset r",
299
300 "bind switch-mode gp-y",
301 "bind switch-mode e",
302 };
303
304 for( int i=0; i<vg_list_size(default_cfg); i++ )
305 vg_execute_console_input(default_cfg[i]);
306
307 rb_init( &player.phys.rb );
308 rb_init( &player.collide_front );
309 rb_init( &player.collide_back );
310
311 vg_convar_push( (struct vg_convar){
312 .name = "gwalk_speed",
313 .data = &k_walkspeed,
314 .data_type = k_convar_dtype_f32,
315 .opt_f32 = { .clamp = 0 },
316 .persistent = 0
317 });
318
319 vg_convar_push( (struct vg_convar){
320 .name = "air_accelerate",
321 .data = &k_air_accelerate,
322 .data_type = k_convar_dtype_f32,
323 .opt_f32 = { .clamp = 0 },
324 .persistent = 0
325 });
326
327 vg_convar_push( (struct vg_convar){
328 .name = "run_speed",
329 .data = &k_runspeed,
330 .data_type = k_convar_dtype_f32,
331 .opt_f32 = { .clamp = 0 },
332 .persistent = 1
333 });
334
335 vg_convar_push( (struct vg_convar){
336 .name = "walk_accel",
337 .data = &k_walk_accel,
338 .data_type = k_convar_dtype_f32,
339 .opt_f32 = { .clamp = 0 },
340 .persistent = 1
341 });
342
343 vg_convar_push( (struct vg_convar){
344 .name = "fc",
345 .data = &freecam,
346 .data_type = k_convar_dtype_i32,
347 .opt_i32 = { .min=0, .max=1, .clamp=1 },
348 .persistent = 1
349 });
350
351 vg_convar_push( (struct vg_convar){
352 .name = "cl_thirdperson",
353 .data = &cl_thirdperson,
354 .data_type = k_convar_dtype_i32,
355 .opt_i32 = { .min=0, .max=1, .clamp=1 },
356 .persistent = 1
357 });
358
359 vg_convar_push( (struct vg_convar){
360 .name = "fcs",
361 .data = &fc_speed,
362 .data_type = k_convar_dtype_f32,
363 .opt_f32 = { .clamp = 0 },
364 .persistent = 1
365 });
366
367 vg_function_push( (struct vg_cmd){
368 .name = "reset",
369 .function = reset_player
370 });
371
372 player.rewind_length = 0;
373 player.rewind_buffer =
374 vg_linear_alloc( vg_mem.rtmemory,
375 sizeof(struct rewind_frame) * PLAYER_REWIND_FRAMES );
376
377 player_model_init();
378
379 /* controls */
380
381 }
382
383 VG_STATIC void player_save_rewind_frame(void)
384 {
385 if( player.rewind_length < PLAYER_REWIND_FRAMES )
386 {
387 struct rewind_frame *fr =
388 &player.rewind_buffer[ player.rewind_length ++ ];
389
390 v2_copy( player.angles, fr->ang );
391 v3_copy( player.camera_pos, fr->pos );
392
393 player.rewind_incrementer = 0;
394
395 if( player.rewind_length > 1 )
396 {
397 player.rewind_total_length +=
398 v3_dist( player.rewind_buffer[player.rewind_length-1].pos,
399 player.rewind_buffer[player.rewind_length-2].pos );
400 }
401 }
402 }
403
404
405 /* disaster */
406 VG_STATIC int menu_enabled(void);
407 #include "menu.h"
408
409 /*
410 * Free camera movement
411 */
412 VG_STATIC void player_mouseview(void)
413 {
414 if( menu_enabled() )
415 return;
416
417 v2_muladds( player.angles, vg.mouse_delta, 0.0025f, player.angles );
418
419 if( vg_input.controller_should_use_trackpad_look )
420 {
421 static v2f last_input;
422 static v2f vel;
423 static v2f vel_smooth;
424
425 v2f input = { player.input_js2h->axis.value,
426 player.input_js2v->axis.value };
427
428 if( (v2_length2(last_input) > 0.001f) && (v2_length2(input) > 0.001f) )
429 {
430 v2_sub( input, last_input, vel );
431 v2_muls( vel, 1.0f/vg.time_delta, vel );
432 }
433 else
434 {
435 v2_zero( vel );
436 }
437
438 v2_lerp( vel_smooth, vel, vg.time_delta*8.0f, vel_smooth );
439
440 v2_muladds( player.angles, vel_smooth, vg.time_delta, player.angles );
441 v2_copy( input, last_input );
442 }
443 else
444 {
445 player.angles[0] += player.input_js2h->axis.value * vg.time_delta * 4.0f;
446 player.angles[1] += player.input_js2v->axis.value * vg.time_delta * 4.0f;
447 }
448
449 player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
450 }
451
452 /* Deal with input etc */
453 VG_STATIC void player_update_pre(void)
454 {
455 struct player_phys *phys = &player.phys;
456
457
458 {
459 v3f ra, rb, rx;
460 v3_copy( main_camera.pos, ra );
461 v3_muladds( ra, main_camera.transform[2], -10.0f, rb );
462
463 float t;
464 if( spherecast_world( ra, rb, 0.4f, &t, rx ) != -1 )
465 {
466 m4x3f mtx;
467 m3x3_identity( mtx );
468 v3_lerp( ra, rb, t, mtx[3] );
469
470 debug_sphere( mtx, 0.4f, 0xff00ff00 );
471
472 v3f x1;
473 v3_muladds( mtx[3], rx, 0.4f, x1 );
474 vg_line( mtx[3], x1, 0xffffffff );
475 }
476 }
477
478
479
480
481
482
483
484
485 if( player.rewinding )
486 return;
487
488 if( vg_input_button_down( player.input_reset ) && !menu_enabled() )
489 {
490 double delta = world.time - world.last_use;
491
492 if( (delta <= RESET_MAX_TIME) && (world.last_use != 0.0) )
493 {
494 player.rewinding = 1;
495 player.rewind_sound_wait = 1;
496 player.rewind_time = (float)player.rewind_length - 0.0001f;
497 player_save_rewind_frame();
498 audio_lock();
499 audio_play_oneshot( &audio_rewind[0], 1.0f );
500 audio_unlock();
501
502 /* based on analytical testing. DONT CHANGE!
503 *
504 * time taken: y = (x^(4/5)) * 74.5
505 * inverse : x = (2/149)^(4/5) * y^(4/5)
506 */
507
508 float constant = powf( 2.0f/149.0f, 4.0f/5.0f ),
509 curve = powf( player.rewind_total_length, 4.0f/5.0f );
510
511 player.rewind_predicted_time = constant * curve;
512 player.diag_rewind_start = vg.time;
513 player.diag_rewind_time = player.rewind_time;
514
515 player.is_dead = 0;
516 player.death_tick_allowance = 30;
517 player_restore_frame();
518
519 if( !phys->on_board )
520 {
521 player.angles[0] = atan2f( -phys->rb.forward[2],
522 -phys->rb.forward[0] );
523 }
524
525 player.mdl.shoes[0] = 1;
526 player.mdl.shoes[1] = 1;
527
528 world_routes_notify_reset();
529
530 /* apply 1 frame of movement */
531 player_do_motion();
532 }
533 else
534 {
535 if( player.is_dead )
536 {
537 reset_player( 0, NULL );
538 }
539 else
540 {
541 /* cant do that */
542 audio_lock();
543 audio_play_oneshot( &audio_rewind[4], 1.0f );
544 audio_unlock();
545 }
546 }
547 }
548
549 if( vg_input_button_down( player.input_switch_mode ) && !menu_enabled() )
550 {
551 phys->on_board ^= 0x1;
552
553 audio_lock();
554 if( phys->on_board )
555 {
556 v3_muladds( phys->rb.v, phys->rb.forward, 0.2f, phys->rb.v );
557 audio_play_oneshot( &audio_lands[6], 1.0f );
558 }
559 else
560 {
561 audio_play_oneshot( &audio_lands[5], 1.0f );
562 }
563
564 audio_unlock();
565 }
566
567 if( !phys->on_board )
568 player_mouseview();
569 }
570
571 VG_STATIC void player_update_fixed(void) /* 2 */
572 {
573 if( player.rewinding )
574 return;
575
576 if( player.death_tick_allowance )
577 player.death_tick_allowance --;
578
579 struct player_phys *phys = &player.phys;
580
581 if( player.is_dead )
582 {
583 player_ragdoll_iter();
584 }
585 else
586 {
587 player.rewind_incrementer ++;
588
589 if( player.rewind_incrementer > (u32)(0.25/VG_TIMESTEP_FIXED) )
590 {
591 player_save_rewind_frame();
592 }
593
594 player_do_motion();
595 }
596 }
597
598 VG_STATIC void player_update_post(void)
599 {
600 for( int i=0; i<player.prediction_count; i++ )
601 {
602 struct land_prediction *p = &player.predictions[i];
603
604 for( int j=0; j<p->log_length - 1; j ++ )
605 vg_line( p->log[j], p->log[j+1], p->colour );
606
607 vg_line_cross( p->log[p->log_length-1], p->colour, 0.25f );
608
609 v3f p1;
610 v3_add( p->log[p->log_length-1], p->n, p1 );
611 vg_line( p->log[p->log_length-1], p1, 0xffffffff );
612 }
613
614 if( player.is_dead )
615 {
616 player_debug_ragdoll();
617
618 if( !freecam )
619 player_animate_death_cam();
620 }
621 else
622 {
623 player_animate();
624
625 if( !freecam )
626 {
627 if( cl_thirdperson )
628 player_animate_camera_thirdperson();
629 else
630 player_animate_camera();
631 }
632 }
633
634 if( freecam )
635 player_freecam();
636
637 /* CAMERA POSITIONING: LAYER 0 */
638 v2_copy( player.angles, main_camera.angles );
639 v3_copy( player.camera_pos, main_camera.pos );
640
641 if( player.rewinding )
642 {
643 if( player.rewind_time <= 0.0f )
644 {
645 double taken = vg.time - player.diag_rewind_start;
646 vg_success( "Rewind took (rt, pl, tl): %f, %f, %f\n",
647 taken, player.diag_rewind_time,
648 player.rewind_total_length );
649
650 player.rewinding = 0;
651 player.rewind_length = 1;
652 player.rewind_total_length = 0.0f;
653 player.rewind_incrementer = 0;
654 world.sky_target_rate = 1.0;
655 }
656 else
657 {
658 world.sky_target_rate = -100.0;
659 assert( player.rewind_length > 0 );
660
661 v2f override_angles;
662 v3f override_pos;
663
664 float budget = vg.time_delta,
665 overall_length = player.rewind_length;
666
667 world_routes_rollback_time( player.rewind_time / overall_length );
668
669 for( int i=0; (i<10)&&(player.rewind_time>0.0f)&&(budget>0.0f); i ++ )
670 {
671 /* Interpolate frames */
672 int i0 = floorf( player.rewind_time ),
673 i1 = VG_MIN( i0+1, player.rewind_length-1 );
674
675 struct rewind_frame *fr = &player.rewind_buffer[i0],
676 *fr1 = &player.rewind_buffer[i1];
677
678 float dist = vg_maxf( v3_dist( fr->pos, fr1->pos ), 0.001f ),
679 subl = vg_fractf( player.rewind_time ) + 0.001f,
680
681 sramp= 3.0f-(1.0f/(0.4f+0.4f*player.rewind_time)),
682 speed = sramp*28.0f + 0.5f*player.rewind_time,
683 mod = speed * (budget / dist),
684
685 advl = vg_minf( mod, subl ),
686 advt = (advl / mod) * budget;
687
688 player.dist_accum += speed * advt;
689 player.rewind_time -= advl;
690 budget -= advt;
691 }
692
693 player.rewind_time = vg_maxf( 0.0f, player.rewind_time );
694
695 float current_time = vg.time - player.diag_rewind_start,
696 remaining = player.rewind_predicted_time - current_time;
697
698 if( player.rewind_sound_wait )
699 {
700 if( player.rewind_predicted_time >= 6.5f )
701 {
702 if( remaining <= 6.5f )
703 {
704 audio_lock();
705 audio_play_oneshot( &audio_rewind[3], 1.0f );
706 audio_unlock();
707 player.rewind_sound_wait = 0;
708 }
709 }
710 else if( player.rewind_predicted_time >= 2.5f )
711 {
712 if( remaining <= 2.5f )
713 {
714 audio_lock();
715 audio_play_oneshot( &audio_rewind[2], 1.0f );
716 audio_unlock();
717 player.rewind_sound_wait = 0;
718 }
719 }
720 else if( player.rewind_predicted_time >= 1.5f )
721 {
722 if( remaining <= 1.5f )
723 {
724 audio_lock();
725 audio_play_oneshot( &audio_rewind[1], 1.0f );
726 audio_unlock();
727 player.rewind_sound_wait = 0;
728 }
729 }
730 }
731
732 int i0 = floorf( player.rewind_time ),
733 i1 = VG_MIN( i0+1, player.rewind_length-1 );
734
735 struct rewind_frame *fr = &player.rewind_buffer[i0],
736 *fr1 = &player.rewind_buffer[i1];
737
738 float sub = vg_fractf(player.rewind_time);
739
740 v3_lerp( fr->pos, fr1->pos, sub, override_pos );
741 override_angles[0] = vg_alerpf( fr->ang[0], fr1->ang[0], sub );
742 override_angles[1] = vg_lerpf ( fr->ang[1], fr1->ang[1], sub );
743
744 /* CAMERA POSITIONING: LAYER 1 */
745 float blend = (4.0f-player.rewind_time) * 0.25f,
746 c = vg_clampf( blend, 0.0f, 1.0f );
747
748 main_camera.angles[0] =
749 vg_alerpf(override_angles[0], player.angles[0], c);
750 main_camera.angles[1] =
751 vg_lerpf (override_angles[1], player.angles[1], c);
752 v3_lerp( override_pos, player.camera_pos, c, main_camera.pos );
753 }
754 }
755
756 camera_update_transform( &main_camera );
757 player_audio();
758 }
759
760 VG_STATIC void draw_player( camera *cam )
761 {
762 if( player.is_dead )
763 player_model_copy_ragdoll();
764
765 shader_viewchar_use();
766 vg_tex2d_bind( &tex_characters, 0 );
767 shader_viewchar_uTexMain( 0 );
768 shader_viewchar_uCamera( cam->transform[3] );
769 shader_viewchar_uPv( cam->mtx.pv );
770 shader_link_standard_ub( _shader_viewchar.id, 2 );
771 glUniformMatrix4x3fv( _uniform_viewchar_uTransforms,
772 player.mdl.sk.bone_count,
773 0,
774 (float *)player.mdl.sk.final_mtx );
775
776 mesh_bind( &player.mdl.player_meshes[cl_playermdl_id] );
777 mesh_draw( &player.mdl.player_meshes[cl_playermdl_id] );
778 }
779
780 /*
781 * -----------------------------------------------------------------------------
782 * API implementation
783 * -----------------------------------------------------------------------------
784 */
785
786 VG_STATIC float *player_get_pos(void)
787 {
788 return player.phys.rb.co;
789 }
790
791 VG_STATIC void player_kill(void)
792 {
793 if( player.death_tick_allowance == 0 )
794 {
795 player.is_dead = 1;
796 player_ragdoll_copy_model( player.phys.rb.v );
797 }
798 }
799
800 VG_STATIC float *player_cam_pos(void)
801 {
802 return player.camera_pos;
803 }
804
805
806 #endif /* PLAYER_H */