third person better camera
[carveJwlIkooP6JGAAIwe30JlM.git] / player.h
1 /*
2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
3 */
4
5 #define PLAYER_H
6 #ifndef PLAYER_H
7 #define PLAYER_H
8
9 #define PLAYER_REWIND_FRAMES 60*4
10
11 #include "conf.h"
12 #include "audio.h"
13 #include "common.h"
14 #include "world.h"
15 #include "skeleton.h"
16 #include "bvh.h"
17
18
19 /*
20 * -----------------------------------------------------------------------------
21 * Memory
22 * -----------------------------------------------------------------------------
23 */
24
25 VG_STATIC struct gplayer
26 {
27 rigidbody rb, rb_frame;
28 v3f co, angles; /* used as transfer between controllers */
29
30 enum player_controller
31 {
32 k_player_controller_walk,
33 k_player_controller_skate,
34 k_player_controller_ragdoll,
35 k_player_controller_mountain_skate,
36 k_player_controller_snowboard,
37 k_player_controller_drive
38 }
39 controller,
40 controller_frame;
41
42 m4x3f visual_transform,
43 inv_visual_transform;
44
45 int is_dead, death_tick_allowance, rewinding;
46 int rewind_sound_wait;
47
48
49 v3f handl_target, handr_target,
50 handl, handr;
51
52 /* Input */
53 struct input_binding *input_js1h,
54 *input_js1v,
55 *input_js2h,
56 *input_js2v,
57 *input_jump,
58 *input_push,
59 *input_walk,
60 *input_walkh,
61 *input_walkv,
62 *input_switch_mode,
63 *input_reset,
64 *input_grab;
65
66 /* Camera */
67 float air_time;
68 v3f camera_pos, smooth_localcam;
69
70 struct rewind_frame
71 {
72 v3f pos;
73 v3f ang;
74 }
75 *rewind_buffer;
76 u32 rewind_incrementer,
77 rewind_length;
78
79 float rewind_time, rewind_total_length, rewind_predicted_time;
80 double diag_rewind_start, diag_rewind_time;
81 float dist_accum;
82
83 /* animation */
84 double jump_time;
85 float fslide,
86 fdirz, fdirx,
87 fstand,
88 ffly,
89 fpush,
90 fairdir,
91 fsetup,
92 walk_timer,
93 fjump,
94 fonboard,
95 frun,
96 fgrind;
97
98 v3f board_offset;
99 v4f board_rotation;
100
101 float walk;
102 int step_phase;
103 enum mdl_surface_prop surface_prop;
104
105 /* player model */
106 struct player_model
107 {
108 glmesh player_meshes[3];
109
110 mdl_context meta;
111 struct skeleton sk;
112 struct skeleton_anim *anim_stand,
113 *anim_highg,
114 *anim_slide,
115 *anim_air,
116 *anim_push, *anim_push_reverse,
117 *anim_ollie, *anim_ollie_reverse,
118 *anim_grabs, *anim_stop,
119 *anim_walk, *anim_run, *anim_idle,
120 *anim_jump;
121
122 u32 id_hip,
123 id_ik_hand_l,
124 id_ik_hand_r,
125 id_ik_elbow_l,
126 id_ik_elbow_r,
127 id_head,
128 id_ik_foot_l,
129 id_ik_foot_r,
130 id_board;
131
132 v3f cam_pos;
133
134 struct ragdoll_part
135 {
136 u32 bone_id;
137 //v3f offset;
138
139 /* Collider transform relative to bone */
140 m4x3f collider_mtx,
141 inv_collider_mtx;
142
143 u32 use_limits;
144 v3f limits[2];
145
146 rigidbody rb;
147 u32 parent;
148 u32 colour;
149 }
150 ragdoll[32];
151 u32 ragdoll_count;
152
153 rb_constr_pos position_constraints[32];
154 u32 position_constraints_count;
155
156 rb_constr_swingtwist cone_constraints[32];
157 u32 cone_constraints_count;
158
159 int shoes[2];
160 }
161 mdl;
162 }
163 player__OLD
164
165 #if 0
166 =
167 {
168 .collide_front = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f },
169 .collide_back = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f }
170 }
171 #endif
172
173 ;
174
175 /*
176 * API
177 */
178 VG_STATIC float *player_get_pos(void);
179 VG_STATIC void player_kill(void);
180 VG_STATIC float *player_cam_pos(void);
181 VG_STATIC void player_save_frame(void);
182 VG_STATIC void player_restore_frame(void);
183 VG_STATIC void player_save_rewind_frame(void);
184
185 /*
186 * Submodules
187 */
188 VG_STATIC void player_mouseview(void);
189
190 #include "player_physics.h"
191 #include "player_physics_skate.h"
192 #include "player_physics_walk.h"
193 #include "player_ragdoll.h"
194 #include "player_model.h"
195 #include "player_animation.h"
196 #include "player_audio.h"
197
198 /*
199 * player_physics_<INTERFACE>_<SUB-INTERFACE>
200 *
201 *
202 *
203 */
204
205 /*
206 * -----------------------------------------------------------------------------
207 * Events
208 * -----------------------------------------------------------------------------
209 */
210 VG_STATIC int kill_player( int argc, char const *argv[] );
211 VG_STATIC int reset_player( int argc, char const *argv[] );
212 VG_STATIC void reset_player_poll( int argc, char const *argv[] );
213
214 VG_STATIC void player_init(void) /* 1 */
215 {
216 #if 0
217 player.input_js1h = vg_create_named_input( "steer-h", k_input_type_axis );
218 player.input_js1v = vg_create_named_input( "steer-v", k_input_type_axis );
219 player.input_grab = vg_create_named_input( "grab", k_input_type_axis_norm );
220 player.input_js2h = vg_create_named_input( "grab-h", k_input_type_axis );
221 player.input_js2v = vg_create_named_input( "grab-v", k_input_type_axis );
222 player.input_jump = vg_create_named_input( "jump", k_input_type_button );
223 player.input_push = vg_create_named_input( "push", k_input_type_button );
224 player.input_walk = vg_create_named_input( "walk", k_input_type_button );
225
226 player.input_walkh = vg_create_named_input( "walk-h",
227 k_input_type_axis );
228 player.input_walkv = vg_create_named_input( "walk-v",
229 k_input_type_axis );
230
231
232 player.input_switch_mode = vg_create_named_input( "switch-mode",
233 k_input_type_button );
234 player.input_reset = vg_create_named_input( "reset", k_input_type_button );
235
236 const char *default_cfg[] =
237 {
238 "bind steer-h gp-ls-h",
239 "bind -steer-h a",
240 "bind +steer-h d",
241
242 "bind steer-v gp-ls-v",
243 "bind -steer-v w",
244 "bind +steer-v s",
245
246 "bind grab gp-rt",
247 "bind +grab shift",
248 "bind grab-h gp-rs-h",
249 "bind grab-v gp-rs-v",
250
251 "bind jump space",
252 "bind jump gp-a",
253
254 "bind push gp-b",
255 "bind push w",
256
257 "bind walk shift",
258 "bind walk gp-ls",
259
260 "bind walk-h gp-ls-h",
261 "bind walk-v -gp-ls-v",
262 "bind +walk-h d",
263 "bind -walk-h a",
264 "bind +walk-v w",
265 "bind -walk-v s",
266
267 "bind reset gp-lb",
268 "bind reset r",
269
270 "bind switch-mode gp-y",
271 "bind switch-mode e",
272 };
273
274 for( int i=0; i<vg_list_size(default_cfg); i++ )
275 vg_execute_console_input(default_cfg[i]);
276 #endif
277
278 rb_init( &player.rb );
279
280 VG_VAR_F32( k_walkspeed );
281 VG_VAR_F32( k_stopspeed );
282 VG_VAR_F32( k_airspeed );
283 VG_VAR_F32( k_walk_friction );
284 VG_VAR_F32( k_walk_air_accel );
285 VG_VAR_F32( k_runspeed );
286 VG_VAR_F32( k_walk_accel );
287
288 VG_VAR_I32( freecam );
289 VG_VAR_I32( cl_thirdperson );
290 VG_VAR_F32_PERSISTENT( fc_speed );
291
292 /* TODO: NOT PERSISTENT */
293 VG_VAR_F32( k_ragdoll_limit_scale );
294 VG_VAR_I32( k_ragdoll_div );
295 VG_VAR_I32( k_ragdoll_debug_collider );
296 VG_VAR_I32( k_ragdoll_debug_constraints );
297
298 VG_VAR_F32( k_friction_lat );
299
300 VG_VAR_F32( k_cog_spring );
301 VG_VAR_F32( k_cog_damp );
302
303 VG_VAR_F32( k_cog_mass_ratio );
304 VG_VAR_F32( k_downforce );
305
306 VG_VAR_F32( k_spring_force );
307 VG_VAR_F32( k_spring_dampener );
308 VG_VAR_F32( k_spring_angular );
309
310 VG_VAR_F32( k_mmthrow_scale );
311 VG_VAR_F32( k_mmcollect_lat );
312 VG_VAR_F32( k_mmcollect_vert );
313 VG_VAR_F32( k_mmdecay );
314
315 vg_function_push( (struct vg_cmd){
316 .name = "reset",
317 .function = reset_player,
318 .poll_suggest = reset_player_poll
319 });
320
321 vg_function_push( (struct vg_cmd){
322 .name = "kill",
323 .function = kill_player
324 });
325
326 /* HACK */
327 rb_register_cvar();
328
329 player.rewind_length = 0;
330 player.rewind_buffer =
331 vg_linear_alloc( vg_mem.rtmemory,
332 sizeof(struct rewind_frame) * PLAYER_REWIND_FRAMES );
333
334 player_model_init();
335 }
336
337 VG_STATIC void player_save_rewind_frame(void)
338 {
339 if( player.rewind_length < PLAYER_REWIND_FRAMES )
340 {
341 struct rewind_frame *fr =
342 &player.rewind_buffer[ player.rewind_length ++ ];
343
344 v2_copy( player.angles, fr->ang );
345 v3_copy( player.camera_pos, fr->pos );
346
347 player.rewind_incrementer = 0;
348
349 if( player.rewind_length > 1 )
350 {
351 player.rewind_total_length +=
352 v3_dist( player.rewind_buffer[player.rewind_length-1].pos,
353 player.rewind_buffer[player.rewind_length-2].pos );
354 }
355 }
356 }
357
358
359 /* disaster */
360 VG_STATIC int menu_enabled(void);
361 #include "menu.h"
362
363 VG_STATIC void player_do_motion(void);
364 /*
365 * Free camera movement
366 */
367 VG_STATIC void player_mouseview(void)
368 {
369 if( menu_enabled() )
370 return;
371
372 v2_muladds( player.angles, vg.mouse_delta, 0.0025f, player.angles );
373
374 if( vg_input.controller_should_use_trackpad_look )
375 {
376 static v2f last_input;
377 static v2f vel;
378 static v2f vel_smooth;
379
380 v2f input = { player.input_js2h->axis.value,
381 player.input_js2v->axis.value };
382
383 if( (v2_length2(last_input) > 0.001f) && (v2_length2(input) > 0.001f) )
384 {
385 v2_sub( input, last_input, vel );
386 v2_muls( vel, 1.0f/vg.time_delta, vel );
387 }
388 else
389 {
390 v2_zero( vel );
391 }
392
393 v2_lerp( vel_smooth, vel, vg.time_delta*8.0f, vel_smooth );
394
395 v2_muladds( player.angles, vel_smooth, vg.time_delta, player.angles );
396 v2_copy( input, last_input );
397 }
398 else
399 {
400 player.angles[0] += player.input_js2h->axis.value * vg.time_delta * 4.0f;
401 player.angles[1] += player.input_js2v->axis.value * vg.time_delta * 4.0f;
402 }
403
404 player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
405 }
406
407 /* Deal with input etc */
408 VG_STATIC void player_update_pre(void)
409 {
410
411 {
412 v3f ra, rb, rx;
413 v3_copy( main_camera.pos, ra );
414 v3_muladds( ra, main_camera.transform[2], -10.0f, rb );
415
416 float t;
417 if( spherecast_world( ra, rb, 0.4f, &t, rx ) != -1 )
418 {
419 m4x3f mtx;
420 m3x3_identity( mtx );
421 v3_lerp( ra, rb, t, mtx[3] );
422
423 debug_sphere( mtx, 0.4f, 0xff00ff00 );
424
425 v3f x1;
426 v3_muladds( mtx[3], rx, 0.4f, x1 );
427 vg_line( mtx[3], x1, 0xffffffff );
428 }
429 }
430
431 #if 0
432
433 vg_line_pt3( phys->cog, 0.10f, 0xffffffff );
434 vg_line_pt3( phys->cog, 0.09f, 0xffffffff );
435 vg_line_pt3( phys->cog, 0.08f, 0xffffffff );
436 vg_line( phys->cog, phys->rb.co, 0xff000000 );
437
438 v3f spring_end;
439 v3f throw_end, p0, p1;
440 v3_muladds( phys->rb.co, phys->rb.up, 1.0f, spring_end );
441 v3_muladds( spring_end, phys->throw_v, 1.0f, throw_end );
442 v3_muladds( spring_end, player.debug_mmcollect_lat, 1.0f, p0 );
443 v3_muladds( spring_end, player.debug_mmcollect_vert, 1.0f, p1 );
444 vg_line( spring_end, throw_end, VG__RED );
445 vg_line( spring_end, p0, VG__GREEN );
446 vg_line( spring_end, p1, VG__BLUE );
447 #endif
448
449 if( player.rewinding )
450 return;
451
452 if( vg_input_button_down( player.input_reset ) && !menu_enabled() )
453 {
454 double delta = world.time - world.last_use;
455
456 if( (delta <= RESET_MAX_TIME) && (world.last_use != 0.0) )
457 {
458 player.rewinding = 1;
459 player.rewind_sound_wait = 1;
460 player.rewind_time = (float)player.rewind_length - 0.0001f;
461 player_save_rewind_frame();
462 audio_lock();
463 audio_play_oneshot( &audio_rewind[0], 1.0f );
464 audio_unlock();
465
466 /* based on analytical testing. DONT CHANGE!
467 *
468 * time taken: y = (x^(4/5)) * 74.5
469 * inverse : x = (2/149)^(4/5) * y^(4/5)
470 */
471
472 float constant = powf( 2.0f/149.0f, 4.0f/5.0f ),
473 curve = powf( player.rewind_total_length, 4.0f/5.0f );
474
475 player.rewind_predicted_time = constant * curve;
476 player.diag_rewind_start = vg.time;
477 player.diag_rewind_time = player.rewind_time;
478
479 player.is_dead = 0;
480 player.death_tick_allowance = 30;
481 player_restore_frame();
482
483 if( player.controller == k_player_controller_walk )
484 {
485 player.angles[0] = atan2f( -player.rb.forward[2],
486 -player.rb.forward[0] );
487 }
488
489 player.mdl.shoes[0] = 1;
490 player.mdl.shoes[1] = 1;
491
492 world_routes_notify_reset();
493
494 /* apply 1 frame of movement */
495 player_do_motion();
496 }
497 else
498 {
499 if( player.is_dead )
500 {
501 reset_player( 0, NULL );
502 }
503 else
504 {
505 /* cant do that */
506 audio_lock();
507 audio_play_oneshot( &audio_rewind[4], 1.0f );
508 audio_unlock();
509 }
510 }
511 }
512
513 if( vg_input_button_down( player.input_switch_mode ) && !menu_enabled() )
514 {
515 audio_lock();
516
517 #if 0
518 if( phys->controller == k_player_controller_walk )
519 {
520 phys->controller = k_player_controller_skate;
521
522 v3_muladds( phys->rb.v, phys->rb.forward, 0.2f, phys->rb.v );
523 audio_play_oneshot( &audio_lands[6], 1.0f );
524 }
525 else if( phys->controller == k_player_controller_skate )
526 {
527 phys->controller = k_player_controller_walk;
528
529 audio_play_oneshot( &audio_lands[5], 1.0f );
530 }
531 #endif
532
533 audio_unlock();
534 }
535
536 if( player.controller == k_player_controller_walk )
537 player_mouseview();
538 }
539
540 VG_STATIC void player_update_fixed(void) /* 2 */
541 {
542 if( player.rewinding )
543 return;
544
545 if( player.death_tick_allowance )
546 player.death_tick_allowance --;
547
548 if( player.is_dead )
549 {
550 player_ragdoll_iter();
551 }
552 else
553 {
554 player.rewind_incrementer ++;
555
556 if( player.rewind_incrementer > (u32)(0.25/VG_TIMESTEP_FIXED) )
557 {
558 player_save_rewind_frame();
559 }
560
561 player_do_motion();
562 }
563 }
564
565 VG_STATIC void player_update_post(void)
566 {
567 #if 0
568 for( int i=0; i<player.prediction_count; i++ )
569 {
570 struct land_prediction *p = &player.predictions[i];
571
572 for( int j=0; j<p->log_length - 1; j ++ )
573 vg_line( p->log[j], p->log[j+1], p->colour );
574
575 vg_line_cross( p->log[p->log_length-1], p->colour, 0.25f );
576
577 v3f p1;
578 v3_add( p->log[p->log_length-1], p->n, p1 );
579 vg_line( p->log[p->log_length-1], p1, 0xffffffff );
580 }
581 #endif
582
583 #if 0
584 if( player.is_dead )
585 {
586 player_debug_ragdoll();
587
588 if( !freecam )
589 player_animate_death_cam();
590 }
591 else
592 {
593 player_animate();
594
595 if( !freecam )
596 {
597 if( cl_thirdperson )
598 player_animate_camera_thirdperson();
599 else
600 player_animate_camera();
601 }
602 }
603
604 if( freecam )
605 #endif
606 player_freecam();
607
608 /* CAMERA POSITIONING: LAYER 0 */
609 v2_copy( player.angles, main_camera.angles );
610 v3_copy( player.camera_pos, main_camera.pos );
611
612 #if 0
613 if( player.rewinding )
614 {
615 if( player.rewind_time <= 0.0f )
616 {
617 double taken = vg.time - player.diag_rewind_start;
618 vg_success( "Rewind took (rt, pl, tl): %f, %f, %f\n",
619 taken, player.diag_rewind_time,
620 player.rewind_total_length );
621
622 player.rewinding = 0;
623 player.rewind_length = 1;
624 player.rewind_total_length = 0.0f;
625 player.rewind_incrementer = 0;
626 world.sky_target_rate = 1.0;
627 }
628 else
629 {
630 world.sky_target_rate = -100.0;
631 assert( player.rewind_length > 0 );
632
633 v2f override_angles;
634 v3f override_pos;
635
636 float budget = vg.time_delta,
637 overall_length = player.rewind_length;
638
639 world_routes_rollback_time( player.rewind_time / overall_length );
640
641 for( int i=0; (i<10)&&(player.rewind_time>0.0f)&&(budget>0.0f); i ++ )
642 {
643 /* Interpolate frames */
644 int i0 = floorf( player.rewind_time ),
645 i1 = VG_MIN( i0+1, player.rewind_length-1 );
646
647 struct rewind_frame *fr = &player.rewind_buffer[i0],
648 *fr1 = &player.rewind_buffer[i1];
649
650 float dist = vg_maxf( v3_dist( fr->pos, fr1->pos ), 0.001f ),
651 subl = vg_fractf( player.rewind_time ) + 0.001f,
652
653 sramp= 3.0f-(1.0f/(0.4f+0.4f*player.rewind_time)),
654 speed = sramp*28.0f + 0.5f*player.rewind_time,
655 mod = speed * (budget / dist),
656
657 advl = vg_minf( mod, subl ),
658 advt = (advl / mod) * budget;
659
660 player.dist_accum += speed * advt;
661 player.rewind_time -= advl;
662 budget -= advt;
663 }
664
665 player.rewind_time = vg_maxf( 0.0f, player.rewind_time );
666
667 float current_time = vg.time - player.diag_rewind_start,
668 remaining = player.rewind_predicted_time - current_time;
669
670 if( player.rewind_sound_wait )
671 {
672 if( player.rewind_predicted_time >= 6.5f )
673 {
674 if( remaining <= 6.5f )
675 {
676 audio_lock();
677 audio_play_oneshot( &audio_rewind[3], 1.0f );
678 audio_unlock();
679 player.rewind_sound_wait = 0;
680 }
681 }
682 else if( player.rewind_predicted_time >= 2.5f )
683 {
684 if( remaining <= 2.5f )
685 {
686 audio_lock();
687 audio_play_oneshot( &audio_rewind[2], 1.0f );
688 audio_unlock();
689 player.rewind_sound_wait = 0;
690 }
691 }
692 else if( player.rewind_predicted_time >= 1.5f )
693 {
694 if( remaining <= 1.5f )
695 {
696 audio_lock();
697 audio_play_oneshot( &audio_rewind[1], 1.0f );
698 audio_unlock();
699 player.rewind_sound_wait = 0;
700 }
701 }
702 }
703
704 int i0 = floorf( player.rewind_time ),
705 i1 = VG_MIN( i0+1, player.rewind_length-1 );
706
707 struct rewind_frame *fr = &player.rewind_buffer[i0],
708 *fr1 = &player.rewind_buffer[i1];
709
710 float sub = vg_fractf(player.rewind_time);
711
712 v3_lerp( fr->pos, fr1->pos, sub, override_pos );
713 override_angles[0] = vg_alerpf( fr->ang[0], fr1->ang[0], sub );
714 override_angles[1] = vg_lerpf ( fr->ang[1], fr1->ang[1], sub );
715
716 /* CAMERA POSITIONING: LAYER 1 */
717 float blend = (4.0f-player.rewind_time) * 0.25f,
718 c = vg_clampf( blend, 0.0f, 1.0f );
719
720 main_camera.angles[0] =
721 vg_alerpf(override_angles[0], player.angles[0], c);
722 main_camera.angles[1] =
723 vg_lerpf (override_angles[1], player.angles[1], c);
724 v3_lerp( override_pos, player.camera_pos, c, main_camera.pos );
725 }
726 }
727 #endif
728
729 camera_update_transform( &main_camera );
730 player_audio();
731 }
732
733 VG_STATIC void draw_player( camera *cam )
734 {
735 if( player.is_dead )
736 player_model_copy_ragdoll();
737
738 shader_viewchar_use();
739 vg_tex2d_bind( &tex_characters, 0 );
740 shader_viewchar_uTexMain( 0 );
741 shader_viewchar_uCamera( cam->transform[3] );
742 shader_viewchar_uPv( cam->mtx.pv );
743 shader_link_standard_ub( _shader_viewchar.id, 2 );
744 glUniformMatrix4x3fv( _uniform_viewchar_uTransforms,
745 player.mdl.sk.bone_count,
746 0,
747 (float *)player.mdl.sk.final_mtx );
748
749 mesh_bind( &player.mdl.player_meshes[cl_playermdl_id] );
750 mesh_draw( &player.mdl.player_meshes[cl_playermdl_id] );
751 }
752
753 VG_STATIC void player_do_motion(void)
754 {
755 if( world.water.enabled )
756 {
757 if( (player.rb.co[1] < 0.0f) && !player.is_dead )
758 {
759 audio_lock();
760 audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D );
761 audio_player_set_position( &audio_player_extra, player.rb.co );
762 audio_player_set_vol( &audio_player_extra, 20.0f );
763 audio_player_playclip( &audio_player_extra, &audio_splash );
764 audio_unlock();
765
766 player_kill();
767 }
768 }
769
770 v3f prevco;
771 v3_copy( player.rb.co, prevco );
772
773 if( player.controller == k_player_controller_skate )
774 {
775 #if 0
776 player_skate_update();
777 #endif
778 }
779 else
780 player_walk_physics( &player_walky );
781
782
783 /* Real angular velocity integration */
784 #if 0
785 v3_lerp( phys->rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f*0.5f, phys->rb.w );
786 if( v3_length2( phys->rb.w ) > 0.0f )
787 {
788 v4f rotation;
789 v3f axis;
790 v3_copy( phys->rb.w, axis );
791
792 float mag = v3_length( axis );
793 v3_divs( axis, mag, axis );
794 q_axis_angle( rotation, axis, mag*k_rb_delta );
795 q_mul( rotation, phys->rb.q, phys->rb.q );
796 }
797
798 /* Faux angular velocity */
799 v4f rotate;
800
801 float lerpq = (player_skate.activity == k_skate_activity_air)? 0.04f: 0.3f;
802 phys->siY = vg_lerpf( phys->siY, phys->iY, lerpq );
803
804 q_axis_angle( rotate, phys->rb.up, phys->siY );
805 q_mul( rotate, phys->rb.q, phys->rb.q );
806 phys->iY = 0.0f;
807 #endif
808
809 /*
810 * Gate intersection, by tracing a line over the gate planes
811 */
812 #if 0
813 for( int i=0; i<world.gate_count; i++ )
814 {
815 struct route_gate *rg = &world.gates[i];
816 teleport_gate *gate = &rg->gate;
817
818 if( gate_intersect( gate, phys->rb.co, prevco ) )
819 {
820 m4x3_mulv( gate->transport, phys->rb.co, phys->rb.co );
821 m4x3_mulv( gate->transport, phys->cog, phys->cog );
822 m3x3_mulv( gate->transport, phys->cog_v, phys->cog_v );
823 m3x3_mulv( gate->transport, phys->rb.v, phys->rb.v );
824 m3x3_mulv( gate->transport, phys->vl, phys->vl );
825 m3x3_mulv( gate->transport, phys->v_last, phys->v_last );
826 m3x3_mulv( gate->transport, phys->m, phys->m );
827 m3x3_mulv( gate->transport, phys->bob, phys->bob );
828
829 /* Pre-emptively edit the camera matrices so that the motion vectors
830 * are correct */
831 m4x3f transport_i;
832 m4x4f transport_4;
833 m4x3_invert_affine( gate->transport, transport_i );
834 m4x3_expand( transport_i, transport_4 );
835 m4x4_mul( main_camera.mtx.pv, transport_4, main_camera.mtx.pv );
836 m4x4_mul( main_camera.mtx.v, transport_4, main_camera.mtx.v );
837
838 v4f transport_rotation;
839 m3x3_q( gate->transport, transport_rotation );
840 q_mul( transport_rotation, phys->rb.q, phys->rb.q );
841
842 world_routes_activate_gate( i );
843
844 if( phys->controller == k_player_controller_walk )
845 {
846 v3f fwd_dir = {cosf(player.angles[0]),
847 0.0f,
848 sinf(player.angles[0])};
849 m3x3_mulv( gate->transport, fwd_dir, fwd_dir );
850
851 player.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] );
852 }
853
854 player.rewind_length = 0;
855 player.rewind_total_length = 0.0f;
856 player.rewind_incrementer = 10000;
857 player_save_frame();
858
859 audio_lock();
860 audio_play_oneshot( &audio_gate_pass, 1.0f );
861 audio_unlock();
862 break;
863 }
864 }
865 #endif
866
867 rb_update_transform( &player.rb );
868 }
869
870 /*
871 * -----------------------------------------------------------------------------
872 * API implementation
873 * -----------------------------------------------------------------------------
874 */
875
876 VG_STATIC float *player_get_pos(void)
877 {
878 return player.rb.co;
879 }
880
881 VG_STATIC void player_kill(void)
882 {
883 if( player.death_tick_allowance == 0 )
884 {
885 player.is_dead = 1;
886 player_ragdoll_copy_model( player.rb.v );
887 }
888 }
889
890 VG_STATIC float *player_cam_pos(void)
891 {
892 return player.camera_pos;
893 }
894
895
896 VG_STATIC void player_save_frame(void)
897 {
898 player.controller_frame = player.controller;
899
900 /* TODO <interface>->save() */
901 }
902
903 VG_STATIC void player_restore_frame(void)
904 {
905 player.controller = player.controller_frame;
906
907 /* TODO <interface>->load() */
908 }
909
910 #endif /* PLAYER_H */