latest
[carveJwlIkooP6JGAAIwe30JlM.git] / player.h
1 #ifndef PLAYER_H
2 #define PLAYER_H
3
4 #include "audio.h"
5 #include "common.h"
6 #include "world.h"
7 //#include "character.h"
8 #include "player_model.h"
9 #include "bvh.h"
10
11 /*
12 * Constants
13 */
14
15 static float
16 k_walkspeed = 7.0f, /* no longer used */
17 k_runspeed = 14.0f,
18 k_board_radius = 0.3f,
19 k_board_length = 0.45f,
20 k_board_allowance = 0.04f,
21 k_friction_lat = 8.8f,
22 k_friction_resistance = 0.01f,
23 k_max_push_speed = 16.0f,
24 k_push_accel = 10.0f,
25 k_push_cycle_rate = 8.0f,
26 k_steer_ground = 2.5f,
27 k_steer_air = 3.6f,
28 k_steer_air_lerp = 0.3f,
29 k_pump_force = 0.0f,
30 k_downforce = 5.0f,
31 k_jump_charge_speed = (1.0f/1.0f),
32 k_jump_force = 5.0f,
33 k_pitch_limit = 1.5f,
34 k_look_speed = 2.0f,
35 k_walk_accel = 5.0f,
36 k_walk_friction = 8.0f;
37
38 static int freecam = 0;
39 static int walk_grid_iterations = 1;
40 static float fc_speed = 10.0f;
41
42 static struct gplayer
43 {
44 /* Physics */
45 rigidbody rb, collide_front, collide_back, rb_gate_frame;
46
47 /* TODO: eugh */
48 m3x3f gate_vr_frame, gate_vr_pstep_frame;
49
50 v3f a, v_last, m, bob, vl;
51
52 /* Utility */
53 float vswitch, slip, slip_last,
54 reverse;
55
56 float iY; /* Yaw inertia */
57 int in_air, is_dead, on_board;
58
59 v2f board_xy;
60 float grab;
61 float pitch;
62 float pushing, push_time;
63 float jump;
64 int jump_charge, jump_dir;
65
66 v3f land_target;
67 v3f land_target_log[22];
68 u32 land_target_colours[22];
69 int land_log_count;
70 m3x3f vr,vr_pstep;
71
72 struct character mdl;
73
74 v3f handl_target, handr_target,
75 handl, handr;
76
77 /* Camera */
78 float air_blend;
79
80 v3f camera_pos, smooth_localcam;
81 v2f angles;
82 m4x3f camera, camera_inverse;
83
84 /* animation */
85 double jump_time;
86 float fslide,
87 fdirz, fdirx,
88 fstand,
89 ffly,
90 fpush,
91 fairdir,
92 fsetup,
93 walk_timer,
94 fonboard;
95 }
96 player =
97 {
98 .on_board = 0,
99
100 .collide_front = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f },
101 .collide_back = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f }
102 };
103
104 /*
105 * Player API
106 */
107
108
109 /*
110 * Free camera movement
111 */
112
113 static void player_mouseview(void)
114 {
115 if( gui_want_mouse() )
116 return;
117
118 static v2f mouse_last,
119 view_vel = { 0.0f, 0.0f };
120
121 if( vg_get_button_down( "primary" ) )
122 v2_copy( vg_mouse, mouse_last );
123
124 else if( vg_get_button( "primary" ) )
125 {
126 v2f delta;
127 v2_sub( vg_mouse, mouse_last, delta );
128 v2_copy( vg_mouse, mouse_last );
129
130 v2_muladds( view_vel, delta, 0.001f, view_vel );
131 }
132
133 v2_muladds( view_vel,
134 (v2f){ vg_get_axis("h1"), vg_get_axis("v1") },
135 0.05f, view_vel );
136 v2_muls( view_vel, 0.93f, view_vel );
137 v2_add( view_vel, player.angles, player.angles );
138 player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
139 }
140
141 static void player_freecam(void)
142 {
143 player_mouseview();
144
145 float movespeed = fc_speed;
146 v3f lookdir = { 0.0f, 0.0f, -1.0f },
147 sidedir = { 1.0f, 0.0f, 0.0f };
148
149 m3x3_mulv( player.camera, lookdir, lookdir );
150 m3x3_mulv( player.camera, sidedir, sidedir );
151
152 static v3f move_vel = { 0.0f, 0.0f, 0.0f };
153 if( vg_get_button( "forward" ) )
154 v3_muladds( move_vel, lookdir, ktimestep * movespeed, move_vel );
155 if( vg_get_button( "back" ) )
156 v3_muladds( move_vel, lookdir, ktimestep *-movespeed, move_vel );
157 if( vg_get_button( "left" ) )
158 v3_muladds( move_vel, sidedir, ktimestep *-movespeed, move_vel );
159 if( vg_get_button( "right" ) )
160 v3_muladds( move_vel, sidedir, ktimestep * movespeed, move_vel );
161
162 v3_muls( move_vel, 0.7f, move_vel );
163 v3_add( move_vel, player.camera_pos, player.camera_pos );
164 }
165
166 /*
167 * Player Physics Implementation
168 */
169
170 static void apply_gravity( v3f vel, float const timestep )
171 {
172 v3f gravity = { 0.0f, -9.6f, 0.0f };
173 v3_muladds( vel, gravity, timestep, vel );
174 }
175
176 /*
177 * TODO: The angle bias should become greater when launching from a steeper
178 * angle and skewed towords more 'downwards' angles when launching from
179 * shallower trajectories
180 *
181 * it should also be tweaked by the controller left stick being pushed
182 * up or down
183 */
184 static void player_start_air(void)
185 {
186 if( player.in_air )
187 return;
188
189 player.in_air = 1;
190
191 float pstep = ktimestep*10.0f;
192 float best_velocity_delta = -9999.9f;
193 float k_bias = 0.96f;
194
195 v3f axis;
196 v3_cross( player.rb.up, player.rb.v, axis );
197 v3_normalize( axis );
198 player.land_log_count = 0;
199
200 m3x3_identity( player.vr );
201
202 for( int m=-3;m<=12; m++ )
203 {
204 float vmod = ((float)m / 15.0f)*0.09f;
205
206 v3f pco, pco1, pv;
207 v3_copy( player.rb.co, pco );
208 v3_muls( player.rb.v, k_bias, pv );
209
210 /*
211 * Try different 'rotations' of the velocity to find the best possible
212 * landing normal. This conserves magnitude at the expense of slightly
213 * unrealistic results
214 */
215
216 m3x3f vr;
217 v4f vr_q;
218
219 q_axis_angle( vr_q, axis, vmod );
220 q_m3x3( vr_q, vr );
221
222 m3x3_mulv( vr, pv, pv );
223 v3_muladds( pco, pv, pstep, pco );
224
225 for( int i=0; i<50; i++ )
226 {
227 v3_copy( pco, pco1 );
228 apply_gravity( pv, pstep );
229
230 m3x3_mulv( vr, pv, pv );
231 v3_muladds( pco, pv, pstep, pco );
232
233 ray_hit contact;
234 v3f vdir;
235
236 v3_sub( pco, pco1, vdir );
237 contact.dist = v3_length( vdir );
238 v3_divs( vdir, contact.dist, vdir);
239
240 if( ray_world( pco1, vdir, &contact ))
241 {
242 float land_delta = v3_dot( pv, contact.normal );
243 u32 scolour = (u8)(vg_minf(-land_delta * 2.0f, 255.0f));
244
245 /* Bias prediction towords ramps */
246 if( ray_hit_is_ramp( &contact ) )
247 {
248 land_delta *= 0.1f;
249 scolour |= 0x0000a000;
250 }
251
252 if( (land_delta < 0.0f) && (land_delta > best_velocity_delta) )
253 {
254 best_velocity_delta = land_delta;
255
256 v3_copy( contact.pos, player.land_target );
257
258 m3x3_copy( vr, player.vr_pstep );
259 q_axis_angle( vr_q, axis, vmod*0.1f );
260 q_m3x3( vr_q, player.vr );
261 }
262
263 v3_copy( contact.pos,
264 player.land_target_log[player.land_log_count] );
265 player.land_target_colours[player.land_log_count] =
266 0xff000000 | scolour;
267
268 player.land_log_count ++;
269
270 break;
271 }
272 }
273 }
274 }
275
276 static void draw_cross(v3f pos,u32 colour, float scale)
277 {
278 v3f p0, p1;
279 v3_add( (v3f){ scale,0.0f,0.0f}, pos, p0 );
280 v3_add( (v3f){-scale,0.0f,0.0f}, pos, p1 );
281 vg_line( p0, p1, colour );
282 v3_add( (v3f){0.0f, scale,0.0f}, pos, p0 );
283 v3_add( (v3f){0.0f,-scale,0.0f}, pos, p1 );
284 vg_line( p0, p1, colour );
285 v3_add( (v3f){0.0f,0.0f, scale}, pos, p0 );
286 v3_add( (v3f){0.0f,0.0f,-scale}, pos, p1 );
287 vg_line( p0, p1, colour );
288 }
289
290 static void player_physics_control(void)
291 {
292 /*
293 * Computing localized friction forces for controlling the character
294 * Friction across X is significantly more than Z
295 */
296
297 v3f vel;
298 m3x3_mulv( player.rb.to_local, player.rb.v, vel );
299 float slip = 0.0f;
300
301 if( fabsf(vel[2]) > 0.01f )
302 slip = fabsf(-vel[0] / vel[2]) * vg_signf(vel[0]);
303
304 if( fabsf( slip ) > 1.2f )
305 slip = vg_signf( slip ) * 1.2f;
306 player.slip = slip;
307 player.reverse = -vg_signf(vel[2]);
308
309 float substep = ktimestep * 0.2f;
310 float fwd_resistance = (vg_get_button( "break" )? 5.0f: 0.02f) * -substep;
311
312 for( int i=0; i<5; i++ )
313 {
314 vel[2] = stable_force( vel[2], vg_signf( vel[2] ) * fwd_resistance );
315 vel[0] = stable_force( vel[0],
316 vg_signf( vel[0] ) * -k_friction_lat*substep );
317 }
318
319 static double start_push = 0.0;
320 if( vg_get_button_down( "push" ) )
321 start_push = vg_time;
322
323 if( vg_get_button( "jump" ) )
324 {
325 player.jump += ktimestep * k_jump_charge_speed;
326
327 if( !player.jump_charge )
328 player.jump_dir = player.reverse > 0.0f? 1: 0;
329
330 player.jump_charge = 1;
331 }
332
333 if( !vg_get_button("break") && vg_get_button( "push" ) )
334 {
335 player.pushing = 1.0f;
336 player.push_time = vg_time-start_push;
337
338 float cycle_time = player.push_time*k_push_cycle_rate,
339 amt = k_push_accel * (sinf(cycle_time)*0.5f+0.5f)*ktimestep,
340 current = v3_length( vel ),
341 new_vel = vg_minf( current + amt, k_max_push_speed );
342
343 new_vel -= vg_minf(current, k_max_push_speed);
344 vel[2] -= new_vel * player.reverse;
345 }
346
347 /* Pumping */
348 static float previous = 0.0f;
349 float delta = previous - player.grab,
350 pump = delta * k_pump_force*ktimestep;
351 previous = player.grab;
352
353 v3f p1;
354 v3_muladds( player.rb.co, player.rb.up, pump, p1 );
355 vg_line( player.rb.co, p1, 0xff0000ff );
356
357 vel[1] += pump;
358
359
360 m3x3_mulv( player.rb.to_world, vel, player.rb.v );
361
362 float steer = vg_get_axis( "horizontal" );
363 player.iY -= vg_signf(steer)*powf(steer,2.0f) * k_steer_ground * ktimestep;
364
365 v2_lerp( player.board_xy, (v2f){ slip*0.25f, 0.0f },
366 ktimestep*5.0f, player.board_xy);
367 }
368
369 static void player_physics_control_air(void)
370 {
371 m3x3_mulv( player.vr, player.rb.v, player.rb.v );
372 draw_cross( player.land_target, 0xff0000ff, 0.25f );
373
374 ray_hit hit;
375
376 /*
377 * Prediction
378 */
379 float pstep = ktimestep*10.0f;
380
381 v3f pco, pco1, pv;
382 v3_copy( player.rb.co, pco );
383 v3_copy( player.rb.v, pv );
384
385 float time_to_impact = 0.0f;
386 float limiter = 1.0f;
387
388 for( int i=0; i<50; i++ )
389 {
390 v3_copy( pco, pco1 );
391 m3x3_mulv( player.vr_pstep, pv, pv );
392 apply_gravity( pv, pstep );
393 v3_muladds( pco, pv, pstep, pco );
394
395 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
396
397 ray_hit contact;
398 v3f vdir;
399
400 v3_sub( pco, pco1, vdir );
401 contact.dist = v3_length( vdir );
402 v3_divs( vdir, contact.dist, vdir);
403
404 float orig_dist = contact.dist;
405 if( ray_world( pco1, vdir, &contact ))
406 {
407 float angle = v3_dot( player.rb.up, contact.normal );
408 v3f axis;
409 v3_cross( player.rb.up, contact.normal, axis );
410
411 time_to_impact += (contact.dist/orig_dist)*pstep;
412 limiter = vg_minf( 5.0f, time_to_impact )/5.0f;
413 limiter = 1.0f-limiter;
414 limiter *= limiter;
415 limiter = 1.0f-limiter;
416
417 if( angle < 0.99f )
418 {
419 v4f correction;
420 q_axis_angle( correction, axis, acosf(angle)*0.05f*(1.0f-limiter) );
421 q_mul( correction, player.rb.q, player.rb.q );
422 }
423
424 draw_cross( contact.pos, 0xffff0000, 0.25f );
425 break;
426 }
427 time_to_impact += pstep;
428 }
429
430 player.iY -= vg_get_axis( "horizontal" ) * k_steer_air * ktimestep;
431 {
432 float iX = vg_get_axis( "vertical" ) *
433 player.reverse * k_steer_air * limiter * ktimestep;
434
435 static float siX = 0.0f;
436 siX = vg_lerpf( siX, iX, k_steer_air_lerp );
437
438 v4f rotate;
439 q_axis_angle( rotate, player.rb.right, siX );
440 q_mul( rotate, player.rb.q, player.rb.q );
441 }
442
443 v2f target = {0.0f,0.0f};
444 v2_muladds( target, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") },
445 player.grab, target );
446 v2_lerp( player.board_xy, target, ktimestep*3.0f, player.board_xy );
447 }
448
449 static void player_init(void)
450 {
451 rb_init( &player.collide_front );
452 rb_init( &player.collide_back );
453 }
454
455 static void player_walk_physics(void)
456 {
457 rigidbody *rbf = &player.collide_front,
458 *rbb = &player.collide_back;
459
460 m3x3_copy( player.rb.to_world, player.collide_front.to_world );
461 m3x3_copy( player.rb.to_world, player.collide_back.to_world );
462
463 float h0 = 0.3f,
464 h1 = 0.9f;
465
466 m4x3_mulv( player.rb.to_world, (v3f){0.0f,h0,0.0f}, rbf->co );
467 v3_copy( rbf->co, rbf->to_world[3] );
468 m4x3_mulv( player.rb.to_world, (v3f){0.0f,h1,0.0f}, rbb->co );
469 v3_copy( rbb->co, rbb->to_world[3] );
470
471 m4x3_invert_affine( rbf->to_world, rbf->to_local );
472 m4x3_invert_affine( rbb->to_world, rbb->to_local );
473
474 rb_update_bounds( rbf );
475 rb_update_bounds( rbb );
476
477 rb_debug( rbf, 0xff0000ff );
478 rb_debug( rbb, 0xff0000ff );
479
480 rb_ct manifold[64];
481 int len = 0;
482
483 len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
484 len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
485
486 rb_presolve_contacts( manifold, len );
487
488 for( int j=0; j<5; j++ )
489 {
490 for( int i=0; i<len; i++ )
491 {
492 struct contact *ct = &manifold[i];
493
494 /*normal */
495 float vn = -v3_dot( player.rb.v, ct->n );
496 vn += ct->bias;
497
498 float temp = ct->norm_impulse;
499 ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
500 vn = ct->norm_impulse - temp;
501
502 v3f impulse;
503 v3_muls( ct->n, vn, impulse );
504
505 v3_add( impulse, player.rb.v, player.rb.v );
506
507 /* friction */
508 for( int j=0; j<2; j++ )
509 {
510 float f = k_friction * ct->norm_impulse,
511 vt = v3_dot( player.rb.v, ct->t[j] ),
512 lambda = -vt;
513
514 float temp = ct->tangent_impulse[j];
515 ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
516 lambda = ct->tangent_impulse[j] - temp;
517
518 v3_muladds( player.rb.v, ct->t[j], lambda, player.rb.v );
519 }
520 }
521 }
522
523 v3_zero( player.rb.w );
524 q_axis_angle( player.rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] );
525
526 v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) };
527
528 v3f p1;
529 v3_muladds( player.rb.co, forward_dir, 2.0f, p1 );
530 vg_line( player.rb.co, p1, 0xff0000ff );
531
532 float move_dead = 0.1f,
533 move = vg_get_axis("grabr")*0.5f + 0.5f - move_dead;
534
535 if( move > 0.0f )
536 {
537 float move_norm = move * (1.0f/(1.0f-move_dead)),
538 speed = vg_lerpf( 0.1f*k_runspeed, k_runspeed, move_norm ),
539 amt = k_walk_accel * ktimestep,
540 zvel = v3_dot( player.rb.v, forward_dir ),
541 new_vel = vg_minf( zvel + amt, speed ),
542 diff = new_vel - vg_minf( zvel, speed );
543
544 v3_muladds( player.rb.v, forward_dir, diff, player.rb.v );
545
546 /* TODO move */
547 float walk_norm = (float)player.mdl.anim_walk->length / 30.0f,
548 run_norm = (float)player.mdl.anim_run->length / 30.0f;
549
550 player.walk_timer += ktimestep * vg_lerpf( walk_norm,run_norm,move_norm );
551 }
552 else
553 {
554 player.walk_timer = 0.0f;
555 }
556
557 player.rb.v[0] *= 1.0f - (ktimestep*k_walk_friction);
558 player.rb.v[2] *= 1.0f - (ktimestep*k_walk_friction);
559 }
560
561 static void player_physics(void)
562 {
563 /*
564 * Update collision fronts
565 */
566
567 rigidbody *rbf = &player.collide_front,
568 *rbb = &player.collide_back;
569
570 m3x3_copy( player.rb.to_world, player.collide_front.to_world );
571 m3x3_copy( player.rb.to_world, player.collide_back.to_world );
572
573 player.air_blend = vg_lerpf( player.air_blend, player.in_air, 0.1f );
574 float h = player.air_blend*0.2f;
575
576 m4x3_mulv( player.rb.to_world, (v3f){0.0f,h,-k_board_length}, rbf->co );
577 v3_copy( rbf->co, rbf->to_world[3] );
578 m4x3_mulv( player.rb.to_world, (v3f){0.0f,h, k_board_length}, rbb->co );
579 v3_copy( rbb->co, rbb->to_world[3] );
580
581 m4x3_invert_affine( rbf->to_world, rbf->to_local );
582 m4x3_invert_affine( rbb->to_world, rbb->to_local );
583
584 rb_update_bounds( rbf );
585 rb_update_bounds( rbb );
586
587 rb_debug( rbf, 0xff00ffff );
588 rb_debug( rbb, 0xffffff00 );
589
590 rb_ct manifold[64];
591 int len = 0;
592
593 len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
594 len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
595
596 rb_presolve_contacts( manifold, len );
597 v3f surface_avg = {0.0f, 0.0f, 0.0f};
598
599 if( !len )
600 {
601 player_start_air();
602 }
603 else
604 {
605 for( int i=0; i<len; i++ )
606 {
607 v3_add( manifold[i].n, surface_avg, surface_avg );
608
609 #if 0
610 if( manifold[i].element_id <= world.sm_geo_std_oob.vertex_count )
611 {
612 player.is_dead = 1;
613 character_ragdoll_copypose( &player.mdl, player.rb.v );
614 return;
615 }
616 #endif
617 }
618
619 v3_normalize( surface_avg );
620
621 if( v3_dot( player.rb.v, surface_avg ) > 0.5f )
622 {
623 player_start_air();
624 }
625 else
626 player.in_air = 0;
627 }
628
629 for( int j=0; j<5; j++ )
630 {
631 for( int i=0; i<len; i++ )
632 {
633 struct contact *ct = &manifold[i];
634
635 v3f dv, delta;
636 v3_sub( ct->co, player.rb.co, delta );
637 v3_cross( player.rb.w, delta, dv );
638 v3_add( player.rb.v, dv, dv );
639
640 float vn = -v3_dot( dv, ct->n );
641 vn += ct->bias;
642
643 float temp = ct->norm_impulse;
644 ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
645 vn = ct->norm_impulse - temp;
646
647 v3f impulse;
648 v3_muls( ct->n, vn, impulse );
649
650 if( fabsf(v3_dot( impulse, player.rb.forward )) > 10.0f ||
651 fabsf(v3_dot( impulse, player.rb.up )) > 50.0f )
652 {
653 player.is_dead = 1;
654 character_ragdoll_copypose( &player.mdl, player.rb.v );
655 return;
656 }
657
658 v3_add( impulse, player.rb.v, player.rb.v );
659 v3_cross( delta, impulse, impulse );
660
661 /*
662 * W Impulses are limited to the Y and X axises, we don't really want
663 * roll angular velocities being included.
664 *
665 * Can also tweak the resistance of each axis here by scaling the wx,wy
666 * components.
667 */
668
669 float wy = v3_dot( player.rb.up, impulse ),
670 wx = v3_dot( player.rb.right, impulse )*1.5f;
671
672 v3_muladds( player.rb.w, player.rb.up, wy, player.rb.w );
673 v3_muladds( player.rb.w, player.rb.right, wx, player.rb.w );
674 }
675 }
676
677 float grabt = vg_get_axis( "grabr" )*0.5f+0.5f;
678 player.grab = vg_lerpf( player.grab, grabt, 0.14f );
679 player.pushing = 0.0f;
680
681 if( !player.in_air )
682 {
683 v3f axis;
684 float angle = v3_dot( player.rb.up, surface_avg );
685 v3_cross( player.rb.up, surface_avg, axis );
686
687 //float cz = v3_dot( player.rb.forward, axis );
688 //v3_muls( player.rb.forward, cz, axis );
689
690 if( angle < 0.999f )
691 {
692 v4f correction;
693 q_axis_angle( correction, axis, acosf(angle)*0.3f );
694 q_mul( correction, player.rb.q, player.rb.q );
695 }
696
697 v3_muladds( player.rb.v, player.rb.up,
698 -k_downforce*ktimestep, player.rb.v );
699
700 player_physics_control();
701
702 if( !player.jump_charge && player.jump > 0.2f )
703 {
704 v3f jumpdir;
705
706 /* Launch more up if alignment is up else improve velocity */
707 float aup = fabsf(v3_dot( (v3f){0.0f,1.0f,0.0f}, player.rb.up )),
708 mod = 0.5f,
709 dir = mod + aup*(1.0f-mod);
710
711 v3_copy( player.rb.v, jumpdir );
712 v3_normalize( jumpdir );
713 v3_muls( jumpdir, 1.0f-dir, jumpdir );
714 v3_muladds( jumpdir, player.rb.up, dir, jumpdir );
715 v3_normalize( jumpdir );
716
717 float force = k_jump_force*player.jump;
718 v3_muladds( player.rb.v, jumpdir, force, player.rb.v );
719 player.jump = 0.0f;
720
721 player.jump_time = vg_time;
722
723 audio_lock();
724 audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D );
725 audio_player_set_position( &audio_player_extra, player.rb.co );
726 audio_player_set_vol( &audio_player_extra, 3.0f );
727 audio_player_playclip( &audio_player_extra, &audio_jumps[rand()%4] );
728 audio_unlock();
729 }
730 }
731 else
732 {
733 player_physics_control_air();
734 }
735
736 if( !player.jump_charge )
737 {
738 player.jump -= k_jump_charge_speed * ktimestep;
739 }
740 player.jump_charge = 0;
741 player.jump = vg_clampf( player.jump, 0.0f, 1.0f );
742 }
743
744 static void player_do_motion(void)
745 {
746 float horizontal = vg_get_axis("horizontal"),
747 vertical = vg_get_axis("vertical");
748
749 if( player.on_board )
750 player_physics();
751 else
752 player_walk_physics();
753
754 /* Integrate velocity */
755 v3f prevco;
756 v3_copy( player.rb.co, prevco );
757
758 apply_gravity( player.rb.v, ktimestep );
759 v3_muladds( player.rb.co, player.rb.v, ktimestep, player.rb.co );
760
761 /* Real angular velocity integration */
762 v3_lerp( player.rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f, player.rb.w );
763 if( v3_length2( player.rb.w ) > 0.0f )
764 {
765 v4f rotation;
766 v3f axis;
767 v3_copy( player.rb.w, axis );
768
769 float mag = v3_length( axis );
770 v3_divs( axis, mag, axis );
771 q_axis_angle( rotation, axis, mag*k_rb_delta );
772 q_mul( rotation, player.rb.q, player.rb.q );
773 }
774
775 /* Faux angular velocity */
776 v4f rotate;
777
778 static float siY = 0.0f;
779 float lerpq = player.in_air? 0.04f: 0.3f;
780 siY = vg_lerpf( siY, player.iY, lerpq );
781
782 q_axis_angle( rotate, player.rb.up, siY );
783 q_mul( rotate, player.rb.q, player.rb.q );
784 player.iY = 0.0f;
785
786 /*
787 * Gate intersection, by tracing a line over the gate planes
788 */
789 for( int i=0; i<world.routes.gate_count; i++ )
790 {
791 struct route_gate *rg = &world.routes.gates[i];
792 teleport_gate *gate = &rg->gate;
793
794 if( gate_intersect( gate, player.rb.co, prevco ) )
795 {
796 m4x3_mulv( gate->transport, player.rb.co, player.rb.co );
797 m3x3_mulv( gate->transport, player.rb.v, player.rb.v );
798 m3x3_mulv( gate->transport, player.vl, player.vl );
799 m3x3_mulv( gate->transport, player.v_last, player.v_last );
800 m3x3_mulv( gate->transport, player.m, player.m );
801 m3x3_mulv( gate->transport, player.bob, player.bob );
802
803 v4f transport_rotation;
804 m3x3_q( gate->transport, transport_rotation );
805 q_mul( transport_rotation, player.rb.q, player.rb.q );
806
807 world_routes_activate_gate( i );
808 player.rb_gate_frame = player.rb;
809
810 m3x3_copy( player.vr, player.gate_vr_frame );
811 m3x3_copy( player.vr_pstep, player.gate_vr_pstep_frame );
812
813 audio_lock();
814 audio_play_oneshot( &audio_gate_lap, 1.0f );
815 audio_unlock();
816 break;
817 }
818 }
819
820 rb_update_transform( &player.rb );
821 }
822
823 /*
824 * Animation
825 */
826
827 static void player_animate_offboard(void)
828 {
829 mdl_keyframe apose[32], bpose[32];
830 struct skeleton *sk = &player.mdl.sk;
831
832 float walk_norm = 30.0f/(float)player.mdl.anim_walk->length,
833 run_norm = 30.0f/(float)player.mdl.anim_run->length,
834 t = player.walk_timer,
835 l = vg_get_axis("grabr") * 0.5f + 0.5f;
836
837 skeleton_sample_anim( sk, player.mdl.anim_walk, t*walk_norm, apose );
838 skeleton_sample_anim( sk, player.mdl.anim_run, t*run_norm, bpose );
839
840 skeleton_lerp_pose( sk, apose, bpose, l, apose );
841
842 float idle_walk = vg_minf( l * 10.0f, 1.0f);
843
844 skeleton_sample_anim( sk, player.mdl.anim_idle, vg_time*0.1f, bpose );
845 skeleton_lerp_pose( sk, apose, bpose, 1.0f-idle_walk, apose );
846
847 skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_defer_ik );
848 skeleton_apply_ik_pass( &player.mdl.sk );
849 skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_deffered_only );
850
851 v3_copy( player.mdl.sk.final_mtx[player.mdl.id_head-1][3],
852 player.mdl.cam_pos );
853
854 skeleton_apply_inverses( &player.mdl.sk );
855
856 m4x3f mtx;
857 v4f rot;
858 q_axis_angle( rot, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] - VG_PIf*0.5f );
859 q_m3x3( rot, mtx );
860 v3_copy( player.rb.to_world[3], mtx[3] );
861
862 skeleton_apply_transform( &player.mdl.sk, mtx );
863 skeleton_debug( &player.mdl.sk );
864 }
865
866 static void player_animate(void)
867 {
868 if( !player.on_board )
869 {
870 player_animate_offboard();
871 return;
872 }
873
874 /* Camera position */
875 v3_sub( player.rb.v, player.v_last, player.a );
876 v3_copy( player.rb.v, player.v_last );
877
878 v3_add( player.m, player.a, player.m );
879 v3_lerp( player.m, (v3f){0.0f,0.0f,0.0f}, 0.1f, player.m );
880
881 player.m[0] = vg_clampf( player.m[0], -2.0f, 2.0f );
882 player.m[1] = vg_clampf( player.m[1], -2.0f, 2.0f );
883 player.m[2] = vg_clampf( player.m[2], -2.0f, 2.0f );
884 v3_lerp( player.bob, player.m, 0.2f, player.bob );
885
886 /* Head */
887 float lslip = fabsf(player.slip);
888
889 float kheight = 2.0f,
890 kleg = 0.6f;
891
892 v3f offset;
893 v3_zero( offset );
894 m3x3_mulv( player.rb.to_local, player.bob, offset );
895
896 static float speed_wobble = 0.0f, speed_wobble_2 = 0.0f;
897
898 float kickspeed = vg_clampf(v3_length(player.rb.v)*(1.0f/40.0f), 0.0f, 1.0f);
899 float kicks = (vg_randf()-0.5f)*2.0f*kickspeed;
900 float sign = vg_signf( kicks );
901 speed_wobble = vg_lerpf( speed_wobble, kicks*kicks*sign, 0.1f );
902 speed_wobble_2 = vg_lerpf( speed_wobble_2, speed_wobble, 0.04f );
903
904 offset[0] *= 0.26f;
905 offset[0] += speed_wobble_2*3.0f;
906
907 offset[1] *= -0.3f;
908 offset[2] *= 0.01f;
909
910 offset[0] = vg_clampf( offset[0], -0.8f, 0.8f );
911 offset[1] = vg_clampf( offset[1], -0.5f, 0.0f );
912 offset[1] = 0.0f;
913
914 /*
915 * Animation blending
916 * ===========================================
917 */
918
919 /* scalar blending information */
920 float speed = v3_length( player.rb.v );
921
922 /* sliding */
923 {
924 float desired = vg_clampf( lslip, 0.0f, 1.0f );
925 player.fslide = vg_lerpf( player.fslide, desired, 0.04f );
926 }
927
928 /* movement information */
929 {
930 float dirz = player.reverse > 0.0f? 0.0f: 1.0f,
931 dirx = player.slip < 0.0f? 0.0f: 1.0f,
932 fly = player.in_air? 1.0f: 0.0f;
933
934 player.fdirz = vg_lerpf( player.fdirz, dirz, 0.04f );
935 player.fdirx = vg_lerpf( player.fdirx, dirx, 0.01f );
936 player.ffly = vg_lerpf( player.ffly, fly, 0.04f );
937 }
938
939 struct skeleton *sk = &player.mdl.sk;
940
941 mdl_keyframe apose[32], bpose[32];
942 mdl_keyframe ground_pose[32];
943 {
944 /* when the player is moving fast he will crouch down a little bit */
945 float stand = 1.0f - vg_clampf( speed * 0.03f, 0.0f, 1.0f );
946 player.fstand = vg_lerpf( player.fstand, stand, 0.1f );
947
948 /* stand/crouch */
949 float dir_frame = player.fdirz * (15.0f/30.0f),
950 stand_blend = offset[1]*-2.0f;
951
952 skeleton_sample_anim( sk, player.mdl.anim_stand, dir_frame, apose );
953 skeleton_sample_anim( sk, player.mdl.anim_highg, dir_frame, bpose );
954 skeleton_lerp_pose( sk, apose, bpose, stand_blend, apose );
955
956 /* sliding */
957 float slide_frame = player.fdirx * (15.0f/30.0f);
958 skeleton_sample_anim( sk, player.mdl.anim_slide, slide_frame, bpose );
959 skeleton_lerp_pose( sk, apose, bpose, player.fslide, apose );
960
961 /* pushing */
962 player.fpush = vg_lerpf( player.fpush, player.pushing, 0.1f );
963
964 float pt = player.push_time;
965 if( player.reverse > 0.0f )
966 skeleton_sample_anim( sk, player.mdl.anim_push, pt, bpose );
967 else
968 skeleton_sample_anim( sk, player.mdl.anim_push_reverse, pt, bpose );
969
970 skeleton_lerp_pose( sk, apose, bpose, player.fpush, apose );
971
972 /* trick setup */
973 float jump_start_frame = 14.0f/30.0f;
974 float setup_frame = player.jump * jump_start_frame,
975 setup_blend = vg_minf( player.jump*5.0f, 1.0f );
976
977 float jump_frame = (vg_time - player.jump_time) + jump_start_frame;
978 if( jump_frame >= jump_start_frame && jump_frame <= (40.0f/30.0f) )
979 setup_frame = jump_frame;
980
981 struct skeleton_anim *jump_anim = player.jump_dir?
982 player.mdl.anim_ollie:
983 player.mdl.anim_ollie_reverse;
984
985 skeleton_sample_anim_clamped( sk, jump_anim, setup_frame, bpose );
986 skeleton_lerp_pose( sk, apose, bpose, setup_blend, ground_pose );
987 }
988
989 mdl_keyframe air_pose[32];
990 {
991 float target = -vg_get_axis("horizontal");
992 player.fairdir = vg_lerpf( player.fairdir, target, 0.04f );
993
994 float air_frame = (player.fairdir*0.5f+0.5f) * (15.0f/30.0f);
995
996 skeleton_sample_anim( sk, player.mdl.anim_air, air_frame, apose );
997
998 static v2f grab_choice;
999 v2_lerp( grab_choice, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") },
1000 0.04f, grab_choice );
1001
1002 float ang = atan2f( grab_choice[0], grab_choice[1] ),
1003 ang_unit = (ang+VG_PIf) * (1.0f/VG_TAUf),
1004 grab_frame = ang_unit * (15.0f/30.0f);
1005
1006 skeleton_sample_anim( sk, player.mdl.anim_grabs, grab_frame, bpose );
1007 skeleton_lerp_pose( sk, apose, bpose, player.grab, air_pose );
1008 }
1009
1010 skeleton_lerp_pose( sk, ground_pose, air_pose, player.ffly, apose );
1011
1012 float add_grab_mod = player.ffly * player.grab;
1013
1014 /* additive effects */
1015 apose[player.mdl.id_hip-1].co[0] += offset[0]*add_grab_mod;
1016 apose[player.mdl.id_hip-1].co[2] += offset[2]*add_grab_mod;
1017 apose[player.mdl.id_ik_hand_l-1].co[0] += offset[0]*add_grab_mod;
1018 apose[player.mdl.id_ik_hand_l-1].co[2] += offset[2]*add_grab_mod;
1019 apose[player.mdl.id_ik_hand_r-1].co[0] += offset[0]*add_grab_mod;
1020 apose[player.mdl.id_ik_hand_r-1].co[2] += offset[2]*add_grab_mod;
1021 apose[player.mdl.id_ik_elbow_l-1].co[0] += offset[0]*add_grab_mod;
1022 apose[player.mdl.id_ik_elbow_l-1].co[2] += offset[2]*add_grab_mod;
1023 apose[player.mdl.id_ik_elbow_r-1].co[0] += offset[0]*add_grab_mod;
1024 apose[player.mdl.id_ik_elbow_r-1].co[2] += offset[2]*add_grab_mod;
1025
1026 skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_defer_ik );
1027 skeleton_apply_ik_pass( &player.mdl.sk );
1028 skeleton_apply_pose( &player.mdl.sk, apose, k_anim_apply_deffered_only );
1029
1030 v3_copy( player.mdl.sk.final_mtx[player.mdl.id_head-1][3],
1031 player.mdl.cam_pos );
1032 skeleton_apply_inverses( &player.mdl.sk );
1033 skeleton_apply_transform( &player.mdl.sk, player.rb.to_world );
1034
1035 skeleton_debug( &player.mdl.sk );
1036 }
1037
1038 static void player_camera_update(void)
1039 {
1040 /* Update camera matrices */
1041 m4x3_identity( player.camera );
1042 m4x3_rotate_y( player.camera, -player.angles[0] );
1043 m4x3_rotate_x( player.camera, -player.angles[1] );
1044 v3_copy( player.camera_pos, player.camera[3] );
1045 m4x3_invert_affine( player.camera, player.camera_inverse );
1046 }
1047
1048 static void player_animate_death_cam(void)
1049 {
1050 v3f delta;
1051 v3f head_pos;
1052 v3_copy( player.mdl.ragdoll[0].rb.co, head_pos );
1053
1054 v3_sub( head_pos, player.camera_pos, delta );
1055 v3_normalize( delta );
1056
1057 v3f follow_pos;
1058 v3_muladds( head_pos, delta, -2.5f, follow_pos );
1059 v3_lerp( player.camera_pos, follow_pos, 0.1f, player.camera_pos );
1060
1061 /*
1062 * Make sure the camera stays above the ground
1063 */
1064 v3f min_height = {0.0f,1.0f,0.0f};
1065
1066 v3f sample;
1067 v3_add( player.camera_pos, min_height, sample );
1068 ray_hit hit;
1069 hit.dist = min_height[1]*2.0f;
1070
1071 if( ray_world( sample, (v3f){0.0f,-1.0f,0.0f}, &hit ))
1072 v3_add( hit.pos, min_height, player.camera_pos );
1073
1074 player.camera_pos[1] =
1075 vg_maxf( wrender.height + 2.0f, player.camera_pos[1] );
1076
1077 player.angles[0] = atan2f( delta[0], -delta[2] );
1078 player.angles[1] = -asinf( delta[1] );
1079 }
1080
1081 static void player_animate_camera(void)
1082 {
1083 static v3f lerp_cam = {0.0f,0.0f,0.0f};
1084 v3f cam_pos;
1085
1086 player.fonboard = vg_lerpf(player.fonboard, player.on_board, ktimestep*1.0f);
1087
1088 if( player.on_board )
1089 {
1090 v3f offs = { -0.4f, 0.15f, 0.0f };
1091 v3_lerp( lerp_cam, player.mdl.cam_pos, 0.8f, lerp_cam );
1092 v3_add( lerp_cam, offs, cam_pos );
1093
1094 /* Look angles */
1095 v3_lerp( player.vl, player.rb.v, 0.05f, player.vl );
1096
1097 float yaw = atan2f( player.vl[0], -player.vl[2] ),
1098 pitch = atan2f( -player.vl[1],
1099 sqrtf(
1100 player.vl[0]*player.vl[0] + player.vl[2]*player.vl[2]
1101 )) * 0.7f;
1102
1103 player.angles[0] = yaw;
1104 player.angles[1] = vg_lerpf( player.angles[1], pitch + 0.30f,
1105 player.fonboard );
1106
1107 /* Camera shake */
1108 static v2f shake_damp = {0.0f,0.0f};
1109 v2f shake = { vg_randf()-0.5f, vg_randf()-0.5f };
1110 v2_muls( shake, v3_length(player.rb.v)*0.3f
1111 * (1.0f+fabsf(player.slip)), shake);
1112
1113 v2_lerp( shake_damp, shake, 0.01f, shake_damp );
1114 shake_damp[0] *= 0.2f;
1115
1116 v2_muladds( player.angles, shake_damp, 0.1f, player.angles );
1117 m4x3_mulv( player.rb.to_world, cam_pos, player.camera_pos );
1118 }
1119 else
1120 {
1121 float speed = ktimestep * k_look_speed;
1122 player.angles[0] += vg_get_axis( "horizontal" ) * speed;
1123 player.angles[1] += vg_get_axis( "vertical" ) * speed;
1124
1125 player.angles[1] = vg_clampf( player.angles[1],
1126 -k_pitch_limit, k_pitch_limit );
1127
1128 float s = sinf(player.angles[0]) * 0.2f,
1129 c = -cosf(player.angles[0]) * 0.2f;
1130 v3f forward_dir = { s,0.15f,c };
1131
1132
1133 m4x3f mtx;
1134 v4f rot;
1135 q_axis_angle( rot, (v3f){0.0f,1.0f,0.0f},
1136 -player.angles[0] -VG_PIf*0.5f );
1137 q_m3x3( rot, mtx );
1138 v3_copy( player.rb.to_world[3], mtx[3] );
1139
1140 m4x3_mulv( mtx, player.mdl.cam_pos, cam_pos );
1141 v3_add( cam_pos, forward_dir, player.camera_pos );
1142 v3_lerp( player.vl, player.rb.v, 0.3f, player.vl );
1143 }
1144 }
1145
1146 /*
1147 * Audio
1148 */
1149 static void player_audio(void)
1150 {
1151 static int _ding = 0;
1152
1153 int last = _ding;
1154 _ding = glfwGetKey(vg_window, GLFW_KEY_C);
1155
1156 int trigger_ding = 0;
1157 if( _ding && !last )
1158 trigger_ding = 1;
1159
1160 static int _air = 0;
1161
1162 int l2 = _air;
1163 _air = player.in_air;
1164
1165 static double last_revert = -2000.0;
1166
1167
1168
1169
1170 audio_lock();
1171
1172 double revert_delta = vg_time - last_revert;
1173 if( (!_air && l2) && (fabsf(player.slip) > 0.5f) && (revert_delta > 0.7) )
1174 {
1175 audio_player_set_position( &audio_player_extra, player.rb.co );
1176 audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D );
1177 audio_player_set_vol( &audio_player_extra, 2.0f );
1178 audio_player_playclip( &audio_player_extra, &audio_lands[rand()%5] );
1179
1180 last_revert = vg_time;
1181 }
1182
1183 static float air = 0.0f;
1184 air = vg_lerpf(air, player.in_air? 1.0f: 0.0f, 5.0f*ktimestep);
1185
1186 /* Spacial info */
1187 v3f ears = { 1.0f,0.0f,0.0f };
1188 v3f delta;
1189
1190 float *cam = player.camera[3],
1191 *pos = player.rb.co;
1192
1193 if( trigger_ding )
1194 audio_player_playclip( &audio_player_extra, &audio_ding );
1195
1196 audio_player_set_position( &audio_player0, player.rb.co );
1197 audio_player_set_position( &audio_player1, player.rb.co );
1198 audio_player_set_position( &audio_player2, player.rb.co );
1199 audio_player_set_position( &audio_player_gate, world.render_gate_pos );
1200
1201 v3_sub( player.rb.co, player.camera[3], delta );
1202 v3_normalize( delta );
1203 m3x3_mulv( player.camera, ears, ears );
1204
1205 /* TODO, Make function */
1206 v3_copy( ears, vg_audio.listener_ears );
1207 v3_copy( player.camera[3], vg_audio.listener_pos );
1208
1209 /* Tunnel / occlusion */
1210 audio_sample_occlusion( player.camera[3] );
1211
1212 if( freecam || player.is_dead || !player.on_board )
1213 {
1214 audio_player_set_vol( &audio_player0, 0.0f );
1215 audio_player_set_vol( &audio_player1, 0.0f );
1216 audio_player_set_vol( &audio_player2, 0.0f );
1217 }
1218 else
1219 {
1220 /* Composite */
1221 float speed = vg_minf(v3_length( player.rb.v )*0.1f,1.0f),
1222 attn = speed,
1223 slide = vg_clampf( fabsf(player.slip), 0.0f, 1.0f ),
1224 vol0 = (1.0f-air)*attn*(1.0f-slide),
1225 vol1 = air *attn,
1226 vol2 = (1.0f-air)*attn*slide;
1227
1228 audio_player_set_vol( &audio_player0, vol0 );
1229 audio_player_set_vol( &audio_player1, vol1 );
1230 audio_player_set_vol( &audio_player2, vol2 );
1231
1232 float reverb_amt = vol0 * audio_occlusion_current * 0.5f;
1233 audio_player_set_pan( &audio_player3, 0.0f );
1234 audio_player_set_vol( &audio_player3, reverb_amt );
1235 }
1236
1237 #if 0
1238 world_audio_update( cam, ears );
1239 #endif
1240 audio_unlock();
1241 }
1242
1243 /*
1244 * Public Endpoints
1245 */
1246 static float *player_cam_pos(void)
1247 {
1248 return player.camera_pos;
1249 }
1250
1251 static int reset_player( int argc, char const *argv[] )
1252 {
1253 struct respawn_point *rp = NULL, *r;
1254
1255 if( argc == 1 )
1256 {
1257 for( int i=0; i<world.spawn_count; i++ )
1258 {
1259 r = &world.spawns[i];
1260 if( !strcmp( r->name, argv[0] ) )
1261 {
1262 rp = r;
1263 break;
1264 }
1265 }
1266
1267 if( !rp )
1268 vg_warn( "No spawn named '%s'\n", argv[0] );
1269 }
1270
1271 if( !rp )
1272 {
1273 float min_dist = INFINITY;
1274
1275 for( int i=0; i<world.spawn_count; i++ )
1276 {
1277 r = &world.spawns[i];
1278 float d = v3_dist2( r->co, player.rb.co );
1279
1280 vg_info( "Dist %s : %f\n", r->name, d );
1281 if( d < min_dist )
1282 {
1283 min_dist = d;
1284 rp = r;
1285 }
1286 }
1287 }
1288
1289 if( !rp )
1290 {
1291 vg_error( "No spawn found\n" );
1292 if( !world.spawn_count )
1293 return 0;
1294
1295 rp = &world.spawns[0];
1296 }
1297
1298 v4_copy( rp->q, player.rb.q );
1299 v3_copy( rp->co, player.rb.co );
1300
1301 player.vswitch = 1.0f;
1302 player.slip_last = 0.0f;
1303 player.is_dead = 0;
1304 player.in_air = 1;
1305 m3x3_identity( player.vr );
1306
1307 player.mdl.shoes[0] = 1;
1308 player.mdl.shoes[1] = 1;
1309
1310 rb_update_transform( &player.rb );
1311 m3x3_mulv( player.rb.to_world, (v3f){ 0.0f, 0.0f, -1.2f }, player.rb.v );
1312 m3x3_identity( player.gate_vr_frame );
1313 m3x3_identity( player.gate_vr_pstep_frame );
1314
1315 player.rb_gate_frame = player.rb;
1316 return 1;
1317 }
1318
1319 static void player_update(void)
1320 {
1321 for( int i=0; i<player.land_log_count; i++ )
1322 draw_cross( player.land_target_log[i],
1323 player.land_target_colours[i], 0.25f);
1324
1325 if( vg_get_axis("grabl")>0.0f)
1326 {
1327 player.rb = player.rb_gate_frame;
1328 m3x3_copy( player.gate_vr_frame, player.vr );
1329 m3x3_copy( player.gate_vr_pstep_frame, player.vr_pstep );
1330 player.is_dead = 0;
1331 player.in_air = 1;
1332 m3x3_identity( player.vr );
1333
1334 player.mdl.shoes[0] = 1;
1335 player.mdl.shoes[1] = 1;
1336
1337 world_routes_notify_reset();
1338 }
1339
1340 if( vg_get_button_down( "switchmode" ) )
1341 {
1342 player.on_board ^= 0x1;
1343 }
1344
1345 if( (glfwGetKey( vg_window, GLFW_KEY_O ) || (player.rb.co[1] < 0.0f)) &&
1346 !player.is_dead)
1347 {
1348 character_ragdoll_copypose( &player.mdl, player.rb.v );
1349 player.is_dead = 1;
1350 }
1351
1352 if( player.is_dead )
1353 {
1354 character_ragdoll_iter( &player.mdl );
1355 character_debug_ragdoll( &player.mdl );
1356
1357 if( !freecam )
1358 player_animate_death_cam();
1359 }
1360 else
1361 {
1362 player_do_motion();
1363 player_animate();
1364
1365 if( !freecam )
1366 player_animate_camera();
1367 }
1368
1369 if( freecam )
1370 player_freecam();
1371
1372 player_camera_update();
1373 player_audio();
1374 }
1375
1376 static void draw_player(void)
1377 {
1378 if( player.is_dead )
1379 character_mimic_ragdoll( &player.mdl );
1380
1381 shader_viewchar_use();
1382 vg_tex2d_bind( &tex_characters, 0 );
1383 shader_viewchar_uTexMain( 0 );
1384 shader_viewchar_uCamera( player.camera[3] );
1385 shader_viewchar_uPv( vg_pv );
1386 shader_link_standard_ub( _shader_viewchar.id, 2 );
1387 glUniformMatrix4x3fv( _uniform_viewchar_uTransforms,
1388 player.mdl.sk.bone_count,
1389 0,
1390 (float *)player.mdl.sk.final_mtx );
1391
1392 mesh_bind( &player.mdl.mesh );
1393 mesh_draw( &player.mdl.mesh );
1394 }
1395
1396 #endif /* PLAYER_H */