2 * Copyright 2021-2022 (C) Mount0 Software, Harry Godden - All Rights Reserved
11 //#include "character.h"
12 #include "player_model.h"
20 k_walkspeed
= 7.0f
, /* no longer used */
22 k_board_radius
= 0.3f
,
23 k_board_length
= 0.45f
,
24 k_board_allowance
= 0.04f
,
25 k_friction_lat
= 8.8f
,
26 k_friction_resistance
= 0.01f
,
27 k_max_push_speed
= 16.0f
,
29 k_push_cycle_rate
= 8.0f
,
30 k_steer_ground
= 2.5f
,
32 k_steer_air_lerp
= 0.3f
,
35 k_jump_charge_speed
= (1.0f
/1.0f
),
40 k_walk_friction
= 8.0f
;
42 static int freecam
= 0;
43 static int walk_grid_iterations
= 1;
44 static float fc_speed
= 10.0f
;
49 rigidbody rb
, collide_front
, collide_back
, rb_gate_frame
;
52 m3x3f gate_vr_frame
, gate_vr_pstep_frame
;
53 int on_board_frame
, in_air_frame
;
55 v3f a
, v_last
, m
, bob
, vl
;
58 float vswitch
, slip
, slip_last
,
61 float iY
; /* Yaw inertia */
62 int in_air
, is_dead
, on_board
;
67 float pushing
, push_time
;
69 int jump_charge
, jump_dir
;
72 v3f land_target_log
[22];
73 u32 land_target_colours
[22];
79 v3f handl_target
, handr_target
,
85 v3f camera_pos
, smooth_localcam
;
87 m4x3f camera
, camera_inverse
;
108 .collide_front
= { .type
= k_rb_shape_sphere
, .inf
.sphere
.radius
= 0.3f
},
109 .collide_back
= { .type
= k_rb_shape_sphere
, .inf
.sphere
.radius
= 0.3f
}
116 static float *player_get_pos(void)
123 * Free camera movement
126 static void player_mouseview(void)
128 if( gui_want_mouse() )
131 static v2f mouse_last
,
132 view_vel
= { 0.0f
, 0.0f
};
134 if( vg_get_button_down( "primary" ) )
135 v2_copy( vg_mouse
, mouse_last
);
137 else if( vg_get_button( "primary" ) )
140 v2_sub( vg_mouse
, mouse_last
, delta
);
141 v2_copy( vg_mouse
, mouse_last
);
143 v2_muladds( view_vel
, delta
, 0.001f
, view_vel
);
146 v2_muladds( view_vel
,
147 (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
149 v2_muls( view_vel
, 0.93f
, view_vel
);
150 v2_add( view_vel
, player
.angles
, player
.angles
);
151 player
.angles
[1] = vg_clampf( player
.angles
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
154 static void player_freecam(void)
158 float movespeed
= fc_speed
;
159 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
160 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
162 m3x3_mulv( player
.camera
, lookdir
, lookdir
);
163 m3x3_mulv( player
.camera
, sidedir
, sidedir
);
165 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
166 if( vg_get_button( "forward" ) )
167 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
168 if( vg_get_button( "back" ) )
169 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
170 if( vg_get_button( "left" ) )
171 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
172 if( vg_get_button( "right" ) )
173 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
175 v3_muls( move_vel
, 0.7f
, move_vel
);
176 v3_add( move_vel
, player
.camera_pos
, player
.camera_pos
);
180 * Player Physics Implementation
183 static void apply_gravity( v3f vel
, float const timestep
)
185 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
186 v3_muladds( vel
, gravity
, timestep
, vel
);
190 * TODO: The angle bias should become greater when launching from a steeper
191 * angle and skewed towords more 'downwards' angles when launching from
192 * shallower trajectories
194 * it should also be tweaked by the controller left stick being pushed
197 static void player_start_air(void)
204 float pstep
= ktimestep
*10.0f
;
205 float best_velocity_delta
= -9999.9f
;
206 float k_bias
= 0.96f
;
209 v3_cross( player
.rb
.up
, player
.rb
.v
, axis
);
210 v3_normalize( axis
);
211 player
.land_log_count
= 0;
213 m3x3_identity( player
.vr
);
215 for( int m
=-3;m
<=12; m
++ )
217 float vmod
= ((float)m
/ 15.0f
)*0.09f
;
220 v3_copy( player
.rb
.co
, pco
);
221 v3_muls( player
.rb
.v
, k_bias
, pv
);
224 * Try different 'rotations' of the velocity to find the best possible
225 * landing normal. This conserves magnitude at the expense of slightly
226 * unrealistic results
232 q_axis_angle( vr_q
, axis
, vmod
);
235 m3x3_mulv( vr
, pv
, pv
);
236 v3_muladds( pco
, pv
, pstep
, pco
);
238 for( int i
=0; i
<50; i
++ )
240 v3_copy( pco
, pco1
);
241 apply_gravity( pv
, pstep
);
243 m3x3_mulv( vr
, pv
, pv
);
244 v3_muladds( pco
, pv
, pstep
, pco
);
249 v3_sub( pco
, pco1
, vdir
);
250 contact
.dist
= v3_length( vdir
);
251 v3_divs( vdir
, contact
.dist
, vdir
);
253 if( ray_world( pco1
, vdir
, &contact
))
255 float land_delta
= v3_dot( pv
, contact
.normal
);
256 u32 scolour
= (u8
)(vg_minf(-land_delta
* 2.0f
, 255.0f
));
258 /* Bias prediction towords ramps */
259 if( ray_hit_is_ramp( &contact
) )
262 scolour
|= 0x0000a000;
265 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
267 best_velocity_delta
= land_delta
;
269 v3_copy( contact
.pos
, player
.land_target
);
271 m3x3_copy( vr
, player
.vr_pstep
);
272 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
273 q_m3x3( vr_q
, player
.vr
);
276 v3_copy( contact
.pos
,
277 player
.land_target_log
[player
.land_log_count
] );
278 player
.land_target_colours
[player
.land_log_count
] =
279 0xff000000 | scolour
;
281 player
.land_log_count
++;
289 static void draw_cross(v3f pos
,u32 colour
, float scale
)
292 v3_add( (v3f
){ scale
,0.0f
,0.0f
}, pos
, p0
);
293 v3_add( (v3f
){-scale
,0.0f
,0.0f
}, pos
, p1
);
294 vg_line( p0
, p1
, colour
);
295 v3_add( (v3f
){0.0f
, scale
,0.0f
}, pos
, p0
);
296 v3_add( (v3f
){0.0f
,-scale
,0.0f
}, pos
, p1
);
297 vg_line( p0
, p1
, colour
);
298 v3_add( (v3f
){0.0f
,0.0f
, scale
}, pos
, p0
);
299 v3_add( (v3f
){0.0f
,0.0f
,-scale
}, pos
, p1
);
300 vg_line( p0
, p1
, colour
);
303 static void player_physics_control(void)
306 * Computing localized friction forces for controlling the character
307 * Friction across X is significantly more than Z
311 m3x3_mulv( player
.rb
.to_local
, player
.rb
.v
, vel
);
314 if( fabsf(vel
[2]) > 0.01f
)
315 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
317 if( fabsf( slip
) > 1.2f
)
318 slip
= vg_signf( slip
) * 1.2f
;
320 player
.reverse
= -vg_signf(vel
[2]);
322 float substep
= ktimestep
* 0.2f
;
323 float fwd_resistance
= (vg_get_button( "break" )? 5.0f
: 0.02f
) * -substep
;
325 for( int i
=0; i
<5; i
++ )
327 vel
[2] = stable_force( vel
[2], vg_signf( vel
[2] ) * fwd_resistance
);
328 vel
[0] = stable_force( vel
[0],
329 vg_signf( vel
[0] ) * -k_friction_lat
*substep
);
332 static double start_push
= 0.0;
333 if( vg_get_button_down( "push" ) )
334 start_push
= vg_time
;
336 if( vg_get_button( "jump" ) )
338 player
.jump
+= ktimestep
* k_jump_charge_speed
;
340 if( !player
.jump_charge
)
341 player
.jump_dir
= player
.reverse
> 0.0f
? 1: 0;
343 player
.jump_charge
= 1;
346 if( !vg_get_button("break") && vg_get_button( "push" ) )
348 player
.pushing
= 1.0f
;
349 player
.push_time
= vg_time
-start_push
;
351 float cycle_time
= player
.push_time
*k_push_cycle_rate
,
352 amt
= k_push_accel
* (sinf(cycle_time
)*0.5f
+0.5f
)*ktimestep
,
353 current
= v3_length( vel
),
354 new_vel
= vg_minf( current
+ amt
, k_max_push_speed
);
356 new_vel
-= vg_minf(current
, k_max_push_speed
);
357 vel
[2] -= new_vel
* player
.reverse
;
361 static float previous
= 0.0f
;
362 float delta
= previous
- player
.grab
,
363 pump
= delta
* k_pump_force
*ktimestep
;
364 previous
= player
.grab
;
367 v3_muladds( player
.rb
.co
, player
.rb
.up
, pump
, p1
);
368 vg_line( player
.rb
.co
, p1
, 0xff0000ff );
373 m3x3_mulv( player
.rb
.to_world
, vel
, player
.rb
.v
);
375 float steer
= vg_get_axis( "horizontal" );
376 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * k_steer_ground
* ktimestep
;
378 v2_lerp( player
.board_xy
, (v2f
){ slip
*0.25f
, 0.0f
},
379 ktimestep
*5.0f
, player
.board_xy
);
382 static void player_physics_control_air(void)
384 m3x3_mulv( player
.vr
, player
.rb
.v
, player
.rb
.v
);
385 draw_cross( player
.land_target
, 0xff0000ff, 0.25f
);
392 float pstep
= ktimestep
*10.0f
;
395 v3_copy( player
.rb
.co
, pco
);
396 v3_copy( player
.rb
.v
, pv
);
398 float time_to_impact
= 0.0f
;
399 float limiter
= 1.0f
;
401 for( int i
=0; i
<50; i
++ )
403 v3_copy( pco
, pco1
);
404 m3x3_mulv( player
.vr_pstep
, pv
, pv
);
405 apply_gravity( pv
, pstep
);
406 v3_muladds( pco
, pv
, pstep
, pco
);
408 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
413 v3_sub( pco
, pco1
, vdir
);
414 contact
.dist
= v3_length( vdir
);
415 v3_divs( vdir
, contact
.dist
, vdir
);
417 float orig_dist
= contact
.dist
;
418 if( ray_world( pco1
, vdir
, &contact
))
420 float angle
= v3_dot( player
.rb
.up
, contact
.normal
);
422 v3_cross( player
.rb
.up
, contact
.normal
, axis
);
424 time_to_impact
+= (contact
.dist
/orig_dist
)*pstep
;
425 limiter
= vg_minf( 5.0f
, time_to_impact
)/5.0f
;
426 limiter
= 1.0f
-limiter
;
428 limiter
= 1.0f
-limiter
;
433 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
*(1.0f
-limiter
) );
434 q_mul( correction
, player
.rb
.q
, player
.rb
.q
);
437 draw_cross( contact
.pos
, 0xffff0000, 0.25f
);
440 time_to_impact
+= pstep
;
443 player
.iY
-= vg_get_axis( "horizontal" ) * k_steer_air
* ktimestep
;
445 float iX
= vg_get_axis( "vertical" ) *
446 player
.reverse
* k_steer_air
* limiter
* ktimestep
;
448 static float siX
= 0.0f
;
449 siX
= vg_lerpf( siX
, iX
, k_steer_air_lerp
);
452 q_axis_angle( rotate
, player
.rb
.right
, siX
);
453 q_mul( rotate
, player
.rb
.q
, player
.rb
.q
);
456 v2f target
= {0.0f
,0.0f
};
457 v2_muladds( target
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
458 player
.grab
, target
);
459 v2_lerp( player
.board_xy
, target
, ktimestep
*3.0f
, player
.board_xy
);
462 static void player_init(void)
464 rb_init( &player
.collide_front
);
465 rb_init( &player
.collide_back
);
468 static void player_walk_physics(void)
470 rigidbody
*rbf
= &player
.collide_front
,
471 *rbb
= &player
.collide_back
;
473 m3x3_copy( player
.rb
.to_world
, player
.collide_front
.to_world
);
474 m3x3_copy( player
.rb
.to_world
, player
.collide_back
.to_world
);
479 m4x3_mulv( player
.rb
.to_world
, (v3f
){0.0f
,h0
,0.0f
}, rbf
->co
);
480 v3_copy( rbf
->co
, rbf
->to_world
[3] );
481 m4x3_mulv( player
.rb
.to_world
, (v3f
){0.0f
,h1
,0.0f
}, rbb
->co
);
482 v3_copy( rbb
->co
, rbb
->to_world
[3] );
484 m4x3_invert_affine( rbf
->to_world
, rbf
->to_local
);
485 m4x3_invert_affine( rbb
->to_world
, rbb
->to_local
);
487 rb_update_bounds( rbf
);
488 rb_update_bounds( rbb
);
490 rb_debug( rbf
, 0xff0000ff );
491 rb_debug( rbb
, 0xff0000ff );
496 len
+= rb_sphere_scene( rbf
, &world
.rb_geo
, manifold
+len
);
497 len
+= rb_sphere_scene( rbb
, &world
.rb_geo
, manifold
+len
);
499 rb_presolve_contacts( manifold
, len
);
501 for( int j
=0; j
<5; j
++ )
503 for( int i
=0; i
<len
; i
++ )
505 struct contact
*ct
= &manifold
[i
];
508 float vn
= -v3_dot( player
.rb
.v
, ct
->n
);
511 float temp
= ct
->norm_impulse
;
512 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
513 vn
= ct
->norm_impulse
- temp
;
516 v3_muls( ct
->n
, vn
, impulse
);
518 v3_add( impulse
, player
.rb
.v
, player
.rb
.v
);
521 for( int j
=0; j
<2; j
++ )
523 float f
= k_friction
* ct
->norm_impulse
,
524 vt
= v3_dot( player
.rb
.v
, ct
->t
[j
] ),
527 float temp
= ct
->tangent_impulse
[j
];
528 ct
->tangent_impulse
[j
] = vg_clampf( temp
+ lambda
, -f
, f
);
529 lambda
= ct
->tangent_impulse
[j
] - temp
;
531 v3_muladds( player
.rb
.v
, ct
->t
[j
], lambda
, player
.rb
.v
);
536 player
.in_air
= len
==0?1:0;
538 v3_zero( player
.rb
.w
);
539 q_axis_angle( player
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, -player
.angles
[0] );
541 v3f forward_dir
= { sinf(player
.angles
[0]),0.0f
,-cosf(player
.angles
[0]) };
544 v3_muladds( player
.rb
.co
, forward_dir
, 2.0f
, p1
);
545 vg_line( player
.rb
.co
, p1
, 0xff0000ff );
547 float move_dead
= 0.1f
,
548 move
= vg_get_axis("grabr")*0.5f
+ 0.5f
- move_dead
;
552 float move_norm
= move
* (1.0f
/(1.0f
-move_dead
)),
553 speed
= vg_lerpf( 0.1f
*k_runspeed
, k_runspeed
, move_norm
),
554 amt
= k_walk_accel
* ktimestep
,
555 zvel
= v3_dot( player
.rb
.v
, forward_dir
),
556 new_vel
= vg_minf( zvel
+ amt
, speed
),
557 diff
= new_vel
- vg_minf( zvel
, speed
);
559 v3_muladds( player
.rb
.v
, forward_dir
, diff
, player
.rb
.v
);
562 float walk_norm
= 30.0f
/(float)player
.mdl
.anim_walk
->length
,
563 run_norm
= 30.0f
/(float)player
.mdl
.anim_run
->length
;
565 player
.walk_timer
+= ktimestep
* vg_lerpf( walk_norm
,run_norm
,move_norm
);
569 player
.walk_timer
= 0.0f
;
572 player
.rb
.v
[0] *= 1.0f
- (ktimestep
*k_walk_friction
);
573 player
.rb
.v
[2] *= 1.0f
- (ktimestep
*k_walk_friction
);
576 static void player_physics(void)
579 * Update collision fronts
582 rigidbody
*rbf
= &player
.collide_front
,
583 *rbb
= &player
.collide_back
;
585 m3x3_copy( player
.rb
.to_world
, player
.collide_front
.to_world
);
586 m3x3_copy( player
.rb
.to_world
, player
.collide_back
.to_world
);
588 player
.air_blend
= vg_lerpf( player
.air_blend
, player
.in_air
, 0.1f
);
589 float h
= player
.air_blend
*0.2f
;
591 m4x3_mulv( player
.rb
.to_world
, (v3f
){0.0f
,h
,-k_board_length
}, rbf
->co
);
592 v3_copy( rbf
->co
, rbf
->to_world
[3] );
593 m4x3_mulv( player
.rb
.to_world
, (v3f
){0.0f
,h
, k_board_length
}, rbb
->co
);
594 v3_copy( rbb
->co
, rbb
->to_world
[3] );
596 m4x3_invert_affine( rbf
->to_world
, rbf
->to_local
);
597 m4x3_invert_affine( rbb
->to_world
, rbb
->to_local
);
599 rb_update_bounds( rbf
);
600 rb_update_bounds( rbb
);
602 rb_debug( rbf
, 0xff00ffff );
603 rb_debug( rbb
, 0xffffff00 );
608 len
+= rb_sphere_scene( rbf
, &world
.rb_geo
, manifold
+len
);
609 len
+= rb_sphere_scene( rbb
, &world
.rb_geo
, manifold
+len
);
611 rb_presolve_contacts( manifold
, len
);
612 v3f surface_avg
= {0.0f
, 0.0f
, 0.0f
};
620 for( int i
=0; i
<len
; i
++ )
622 v3_add( manifold
[i
].n
, surface_avg
, surface_avg
);
625 if( manifold
[i
].element_id
<= world
.sm_geo_std_oob
.vertex_count
)
628 character_ragdoll_copypose( &player
.mdl
, player
.rb
.v
);
634 v3_normalize( surface_avg
);
636 if( v3_dot( player
.rb
.v
, surface_avg
) > 0.5f
)
644 for( int j
=0; j
<5; j
++ )
646 for( int i
=0; i
<len
; i
++ )
648 struct contact
*ct
= &manifold
[i
];
651 v3_sub( ct
->co
, player
.rb
.co
, delta
);
652 v3_cross( player
.rb
.w
, delta
, dv
);
653 v3_add( player
.rb
.v
, dv
, dv
);
655 float vn
= -v3_dot( dv
, ct
->n
);
658 float temp
= ct
->norm_impulse
;
659 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
660 vn
= ct
->norm_impulse
- temp
;
663 v3_muls( ct
->n
, vn
, impulse
);
665 if( fabsf(v3_dot( impulse
, player
.rb
.forward
)) > 10.0f
||
666 fabsf(v3_dot( impulse
, player
.rb
.up
)) > 50.0f
)
669 character_ragdoll_copypose( &player
.mdl
, player
.rb
.v
);
673 v3_add( impulse
, player
.rb
.v
, player
.rb
.v
);
674 v3_cross( delta
, impulse
, impulse
);
677 * W Impulses are limited to the Y and X axises, we don't really want
678 * roll angular velocities being included.
680 * Can also tweak the resistance of each axis here by scaling the wx,wy
684 float wy
= v3_dot( player
.rb
.up
, impulse
),
685 wx
= v3_dot( player
.rb
.right
, impulse
)*1.5f
;
687 v3_muladds( player
.rb
.w
, player
.rb
.up
, wy
, player
.rb
.w
);
688 v3_muladds( player
.rb
.w
, player
.rb
.right
, wx
, player
.rb
.w
);
692 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
693 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.14f
);
694 player
.pushing
= 0.0f
;
699 float angle
= v3_dot( player
.rb
.up
, surface_avg
);
700 v3_cross( player
.rb
.up
, surface_avg
, axis
);
702 //float cz = v3_dot( player.rb.forward, axis );
703 //v3_muls( player.rb.forward, cz, axis );
708 q_axis_angle( correction
, axis
, acosf(angle
)*0.3f
);
709 q_mul( correction
, player
.rb
.q
, player
.rb
.q
);
712 v3_muladds( player
.rb
.v
, player
.rb
.up
,
713 -k_downforce
*ktimestep
, player
.rb
.v
);
715 player_physics_control();
717 if( !player
.jump_charge
&& player
.jump
> 0.2f
)
721 /* Launch more up if alignment is up else improve velocity */
722 float aup
= fabsf(v3_dot( (v3f
){0.0f
,1.0f
,0.0f
}, player
.rb
.up
)),
724 dir
= mod
+ aup
*(1.0f
-mod
);
726 v3_copy( player
.rb
.v
, jumpdir
);
727 v3_normalize( jumpdir
);
728 v3_muls( jumpdir
, 1.0f
-dir
, jumpdir
);
729 v3_muladds( jumpdir
, player
.rb
.up
, dir
, jumpdir
);
730 v3_normalize( jumpdir
);
732 float force
= k_jump_force
*player
.jump
;
733 v3_muladds( player
.rb
.v
, jumpdir
, force
, player
.rb
.v
);
736 player
.jump_time
= vg_time
;
739 audio_player_set_flags( &audio_player_extra
, AUDIO_FLAG_SPACIAL_3D
);
740 audio_player_set_position( &audio_player_extra
, player
.rb
.co
);
741 audio_player_set_vol( &audio_player_extra
, 20.0f
);
742 audio_player_playclip( &audio_player_extra
, &audio_jumps
[rand()%4] );
748 player_physics_control_air();
751 if( !player
.jump_charge
)
753 player
.jump
-= k_jump_charge_speed
* ktimestep
;
755 player
.jump_charge
= 0;
756 player
.jump
= vg_clampf( player
.jump
, 0.0f
, 1.0f
);
759 static void player_do_motion(void)
761 float horizontal
= vg_get_axis("horizontal"),
762 vertical
= vg_get_axis("vertical");
764 if( player
.on_board
)
767 player_walk_physics();
769 /* Integrate velocity */
771 v3_copy( player
.rb
.co
, prevco
);
773 apply_gravity( player
.rb
.v
, ktimestep
);
774 v3_muladds( player
.rb
.co
, player
.rb
.v
, ktimestep
, player
.rb
.co
);
776 /* Real angular velocity integration */
777 v3_lerp( player
.rb
.w
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.125f
, player
.rb
.w
);
778 if( v3_length2( player
.rb
.w
) > 0.0f
)
782 v3_copy( player
.rb
.w
, axis
);
784 float mag
= v3_length( axis
);
785 v3_divs( axis
, mag
, axis
);
786 q_axis_angle( rotation
, axis
, mag
*k_rb_delta
);
787 q_mul( rotation
, player
.rb
.q
, player
.rb
.q
);
790 /* Faux angular velocity */
793 static float siY
= 0.0f
;
794 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
795 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
797 q_axis_angle( rotate
, player
.rb
.up
, siY
);
798 q_mul( rotate
, player
.rb
.q
, player
.rb
.q
);
802 * Gate intersection, by tracing a line over the gate planes
804 for( int i
=0; i
<world
.routes
.gate_count
; i
++ )
806 struct route_gate
*rg
= &world
.routes
.gates
[i
];
807 teleport_gate
*gate
= &rg
->gate
;
809 if( gate_intersect( gate
, player
.rb
.co
, prevco
) )
811 m4x3_mulv( gate
->transport
, player
.rb
.co
, player
.rb
.co
);
812 m3x3_mulv( gate
->transport
, player
.rb
.v
, player
.rb
.v
);
813 m3x3_mulv( gate
->transport
, player
.vl
, player
.vl
);
814 m3x3_mulv( gate
->transport
, player
.v_last
, player
.v_last
);
815 m3x3_mulv( gate
->transport
, player
.m
, player
.m
);
816 m3x3_mulv( gate
->transport
, player
.bob
, player
.bob
);
818 v4f transport_rotation
;
819 m3x3_q( gate
->transport
, transport_rotation
);
820 q_mul( transport_rotation
, player
.rb
.q
, player
.rb
.q
);
822 world_routes_activate_gate( i
);
823 player
.rb_gate_frame
= player
.rb
;
824 player
.in_air_frame
= player
.in_air
;
825 player
.on_board_frame
= player
.on_board
;
827 if( !player
.on_board
)
829 v3f fwd_dir
= {cosf(player
.angles
[0]),
831 sinf(player
.angles
[0])};
832 m3x3_mulv( gate
->transport
, fwd_dir
, fwd_dir
);
834 player
.angles
[0] = atan2f( fwd_dir
[2], fwd_dir
[0] );
837 m3x3_copy( player
.vr
, player
.gate_vr_frame
);
838 m3x3_copy( player
.vr_pstep
, player
.gate_vr_pstep_frame
);
841 audio_play_oneshot( &audio_gate_lap
, 1.0f
);
847 rb_update_transform( &player
.rb
);
854 static void player_animate_offboard(void)
856 mdl_keyframe apose
[32], bpose
[32];
857 struct skeleton
*sk
= &player
.mdl
.sk
;
859 float walk_norm
= (float)player
.mdl
.anim_walk
->length
/30.0f
,
860 run_norm
= (float)player
.mdl
.anim_run
->length
/30.0f
,
861 t
= player
.walk_timer
,
862 l
= vg_get_axis("grabr") * 0.5f
+ 0.5f
;
864 skeleton_sample_anim( sk
, player
.mdl
.anim_walk
, t
*walk_norm
, apose
);
865 skeleton_sample_anim( sk
, player
.mdl
.anim_run
, t
*run_norm
, bpose
);
867 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
869 float idle_walk
= vg_minf( l
* 10.0f
, 1.0f
);
871 skeleton_sample_anim( sk
, player
.mdl
.anim_idle
, vg_time
*0.1f
, bpose
);
872 skeleton_lerp_pose( sk
, apose
, bpose
, 1.0f
-idle_walk
, apose
);
874 skeleton_apply_pose( &player
.mdl
.sk
, apose
, k_anim_apply_defer_ik
);
875 skeleton_apply_ik_pass( &player
.mdl
.sk
);
876 skeleton_apply_pose( &player
.mdl
.sk
, apose
, k_anim_apply_deffered_only
);
878 v3_copy( player
.mdl
.sk
.final_mtx
[player
.mdl
.id_head
-1][3],
879 player
.mdl
.cam_pos
);
881 skeleton_apply_inverses( &player
.mdl
.sk
);
885 q_axis_angle( rot
, (v3f
){0.0f
,1.0f
,0.0f
}, -player
.angles
[0] - VG_PIf
*0.5f
);
887 v3_copy( player
.rb
.to_world
[3], mtx
[3] );
889 skeleton_apply_transform( &player
.mdl
.sk
, mtx
);
890 skeleton_debug( &player
.mdl
.sk
);
893 static void player_animate(void)
895 if( !player
.on_board
)
897 player_animate_offboard();
901 /* Camera position */
902 v3_sub( player
.rb
.v
, player
.v_last
, player
.a
);
903 v3_copy( player
.rb
.v
, player
.v_last
);
905 v3_add( player
.m
, player
.a
, player
.m
);
906 v3_lerp( player
.m
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, player
.m
);
908 player
.m
[0] = vg_clampf( player
.m
[0], -2.0f
, 2.0f
);
909 player
.m
[1] = vg_clampf( player
.m
[1], -2.0f
, 2.0f
);
910 player
.m
[2] = vg_clampf( player
.m
[2], -2.0f
, 2.0f
);
911 v3_lerp( player
.bob
, player
.m
, 0.2f
, player
.bob
);
914 float lslip
= fabsf(player
.slip
);
916 float kheight
= 2.0f
,
921 m3x3_mulv( player
.rb
.to_local
, player
.bob
, offset
);
923 static float speed_wobble
= 0.0f
, speed_wobble_2
= 0.0f
;
925 float kickspeed
= vg_clampf(v3_length(player
.rb
.v
)*(1.0f
/40.0f
), 0.0f
, 1.0f
);
926 float kicks
= (vg_randf()-0.5f
)*2.0f
*kickspeed
;
927 float sign
= vg_signf( kicks
);
928 speed_wobble
= vg_lerpf( speed_wobble
, kicks
*kicks
*sign
, 0.1f
);
929 speed_wobble_2
= vg_lerpf( speed_wobble_2
, speed_wobble
, 0.04f
);
932 offset
[0] += speed_wobble_2
*3.0f
;
937 offset
[0] = vg_clampf( offset
[0], -0.8f
, 0.8f
);
938 offset
[1] = vg_clampf( offset
[1], -0.5f
, 0.0f
);
942 * ===========================================
945 /* scalar blending information */
946 float speed
= v3_length( player
.rb
.v
);
950 float desired
= vg_clampf( lslip
, 0.0f
, 1.0f
);
951 player
.fslide
= vg_lerpf( player
.fslide
, desired
, 0.04f
);
954 /* movement information */
956 float dirz
= player
.reverse
> 0.0f
? 0.0f
: 1.0f
,
957 dirx
= player
.slip
< 0.0f
? 0.0f
: 1.0f
,
958 fly
= player
.in_air
? 1.0f
: 0.0f
;
960 player
.fdirz
= vg_lerpf( player
.fdirz
, dirz
, 0.04f
);
961 player
.fdirx
= vg_lerpf( player
.fdirx
, dirx
, 0.01f
);
962 player
.ffly
= vg_lerpf( player
.ffly
, fly
, 0.04f
);
965 struct skeleton
*sk
= &player
.mdl
.sk
;
967 mdl_keyframe apose
[32], bpose
[32];
968 mdl_keyframe ground_pose
[32];
970 /* when the player is moving fast he will crouch down a little bit */
971 float stand
= 1.0f
- vg_clampf( speed
* 0.03f
, 0.0f
, 1.0f
);
972 player
.fstand
= vg_lerpf( player
.fstand
, stand
, 0.1f
);
975 float dir_frame
= player
.fdirz
* (15.0f
/30.0f
),
976 stand_blend
= offset
[1]*-2.0f
;
978 skeleton_sample_anim( sk
, player
.mdl
.anim_stand
, dir_frame
, apose
);
979 skeleton_sample_anim( sk
, player
.mdl
.anim_highg
, dir_frame
, bpose
);
980 skeleton_lerp_pose( sk
, apose
, bpose
, stand_blend
, apose
);
983 float slide_frame
= player
.fdirx
* (15.0f
/30.0f
);
984 skeleton_sample_anim( sk
, player
.mdl
.anim_slide
, slide_frame
, bpose
);
985 skeleton_lerp_pose( sk
, apose
, bpose
, player
.fslide
, apose
);
988 player
.fpush
= vg_lerpf( player
.fpush
, player
.pushing
, 0.1f
);
990 float pt
= player
.push_time
;
991 if( player
.reverse
> 0.0f
)
992 skeleton_sample_anim( sk
, player
.mdl
.anim_push
, pt
, bpose
);
994 skeleton_sample_anim( sk
, player
.mdl
.anim_push_reverse
, pt
, bpose
);
996 skeleton_lerp_pose( sk
, apose
, bpose
, player
.fpush
, apose
);
999 float jump_start_frame
= 14.0f
/30.0f
;
1000 float setup_frame
= player
.jump
* jump_start_frame
,
1001 setup_blend
= vg_minf( player
.jump
*5.0f
, 1.0f
);
1003 float jump_frame
= (vg_time
- player
.jump_time
) + jump_start_frame
;
1004 if( jump_frame
>= jump_start_frame
&& jump_frame
<= (40.0f
/30.0f
) )
1005 setup_frame
= jump_frame
;
1007 struct skeleton_anim
*jump_anim
= player
.jump_dir
?
1008 player
.mdl
.anim_ollie
:
1009 player
.mdl
.anim_ollie_reverse
;
1011 skeleton_sample_anim_clamped( sk
, jump_anim
, setup_frame
, bpose
);
1012 skeleton_lerp_pose( sk
, apose
, bpose
, setup_blend
, ground_pose
);
1015 mdl_keyframe air_pose
[32];
1017 float target
= -vg_get_axis("horizontal");
1018 player
.fairdir
= vg_lerpf( player
.fairdir
, target
, 0.04f
);
1020 float air_frame
= (player
.fairdir
*0.5f
+0.5f
) * (15.0f
/30.0f
);
1022 skeleton_sample_anim( sk
, player
.mdl
.anim_air
, air_frame
, apose
);
1024 static v2f grab_choice
;
1025 v2_lerp( grab_choice
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
1026 0.04f
, grab_choice
);
1028 float ang
= atan2f( grab_choice
[0], grab_choice
[1] ),
1029 ang_unit
= (ang
+VG_PIf
) * (1.0f
/VG_TAUf
),
1030 grab_frame
= ang_unit
* (15.0f
/30.0f
);
1032 skeleton_sample_anim( sk
, player
.mdl
.anim_grabs
, grab_frame
, bpose
);
1033 skeleton_lerp_pose( sk
, apose
, bpose
, player
.grab
, air_pose
);
1036 skeleton_lerp_pose( sk
, ground_pose
, air_pose
, player
.ffly
, apose
);
1038 float add_grab_mod
= 1.0f
- player
.ffly
*player
.grab
;
1040 /* additive effects */
1041 apose
[player
.mdl
.id_hip
-1].co
[0] += offset
[0]*add_grab_mod
;
1042 apose
[player
.mdl
.id_hip
-1].co
[2] += offset
[2]*add_grab_mod
;
1043 apose
[player
.mdl
.id_ik_hand_l
-1].co
[0] += offset
[0]*add_grab_mod
;
1044 apose
[player
.mdl
.id_ik_hand_l
-1].co
[2] += offset
[2]*add_grab_mod
;
1045 apose
[player
.mdl
.id_ik_hand_r
-1].co
[0] += offset
[0]*add_grab_mod
;
1046 apose
[player
.mdl
.id_ik_hand_r
-1].co
[2] += offset
[2]*add_grab_mod
;
1047 apose
[player
.mdl
.id_ik_elbow_l
-1].co
[0] += offset
[0]*add_grab_mod
;
1048 apose
[player
.mdl
.id_ik_elbow_l
-1].co
[2] += offset
[2]*add_grab_mod
;
1049 apose
[player
.mdl
.id_ik_elbow_r
-1].co
[0] += offset
[0]*add_grab_mod
;
1050 apose
[player
.mdl
.id_ik_elbow_r
-1].co
[2] += offset
[2]*add_grab_mod
;
1052 skeleton_apply_pose( &player
.mdl
.sk
, apose
, k_anim_apply_defer_ik
);
1053 skeleton_apply_ik_pass( &player
.mdl
.sk
);
1054 skeleton_apply_pose( &player
.mdl
.sk
, apose
, k_anim_apply_deffered_only
);
1056 v3_copy( player
.mdl
.sk
.final_mtx
[player
.mdl
.id_head
-1][3],
1057 player
.mdl
.cam_pos
);
1058 skeleton_apply_inverses( &player
.mdl
.sk
);
1059 skeleton_apply_transform( &player
.mdl
.sk
, player
.rb
.to_world
);
1061 skeleton_debug( &player
.mdl
.sk
);
1064 static void player_camera_update(void)
1066 /* Update camera matrices */
1067 v4f qyaw
, qpitch
, qcam
;
1068 q_axis_angle( qyaw
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, -player
.angles
[0] );
1069 q_axis_angle( qpitch
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, -player
.angles
[1] );
1071 q_mul( qyaw
, qpitch
, qcam
);
1072 q_m3x3( qcam
, player
.camera
);
1074 v3_copy( player
.camera_pos
, player
.camera
[3] );
1075 m4x3_invert_affine( player
.camera
, player
.camera_inverse
);
1078 static void player_animate_death_cam(void)
1082 v3_copy( player
.mdl
.ragdoll
[0].rb
.co
, head_pos
);
1084 v3_sub( head_pos
, player
.camera_pos
, delta
);
1085 v3_normalize( delta
);
1088 v3_muladds( head_pos
, delta
, -2.5f
, follow_pos
);
1089 v3_lerp( player
.camera_pos
, follow_pos
, 0.1f
, player
.camera_pos
);
1092 * Make sure the camera stays above the ground
1094 v3f min_height
= {0.0f
,1.0f
,0.0f
};
1097 v3_add( player
.camera_pos
, min_height
, sample
);
1099 hit
.dist
= min_height
[1]*2.0f
;
1101 if( ray_world( sample
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
1102 v3_add( hit
.pos
, min_height
, player
.camera_pos
);
1104 player
.camera_pos
[1] =
1105 vg_maxf( wrender
.height
+ 2.0f
, player
.camera_pos
[1] );
1107 player
.angles
[0] = atan2f( delta
[0], -delta
[2] );
1108 player
.angles
[1] = -asinf( delta
[1] );
1111 static void player_animate_camera(void)
1113 static v3f lerp_cam
= {0.0f
,0.0f
,0.0f
};
1116 player
.fonboard
= vg_lerpf(player
.fonboard
, player
.on_board
, ktimestep
*1.0f
);
1118 if( player
.on_board
)
1120 v3f offs
= { -0.4f
, 0.15f
, 0.0f
};
1121 v3_lerp( lerp_cam
, player
.mdl
.cam_pos
, 0.8f
, lerp_cam
);
1122 v3_add( lerp_cam
, offs
, cam_pos
);
1125 v3_lerp( player
.vl
, player
.rb
.v
, 0.05f
, player
.vl
);
1127 float yaw
= atan2f( player
.vl
[0], -player
.vl
[2] ),
1128 pitch
= atan2f( -player
.vl
[1],
1130 player
.vl
[0]*player
.vl
[0] + player
.vl
[2]*player
.vl
[2]
1133 player
.angles
[0] = yaw
;
1134 player
.angles
[1] = vg_lerpf( player
.angles
[1], pitch
+ 0.30f
,
1138 static v2f shake_damp
= {0.0f
,0.0f
};
1139 v2f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
};
1140 v2_muls( shake
, v3_length(player
.rb
.v
)*0.3f
1141 * (1.0f
+fabsf(player
.slip
)), shake
);
1143 v2_lerp( shake_damp
, shake
, 0.01f
, shake_damp
);
1144 shake_damp
[0] *= 0.2f
;
1146 v2_muladds( player
.angles
, shake_damp
, 0.1f
, player
.angles
);
1147 m4x3_mulv( player
.rb
.to_world
, cam_pos
, player
.camera_pos
);
1151 float speed
= ktimestep
* k_look_speed
;
1152 player
.angles
[0] += vg_get_axis( "horizontal" ) * speed
;
1153 player
.angles
[1] += vg_get_axis( "vertical" ) * speed
;
1155 player
.angles
[1] = vg_clampf( player
.angles
[1],
1156 -k_pitch_limit
, k_pitch_limit
);
1158 float s
= sinf(player
.angles
[0]) * 0.2f
,
1159 c
= -cosf(player
.angles
[0]) * 0.2f
;
1160 v3f forward_dir
= { s
,0.15f
,c
};
1165 q_axis_angle( rot
, (v3f
){0.0f
,1.0f
,0.0f
},
1166 -player
.angles
[0] -VG_PIf
*0.5f
);
1168 v3_copy( player
.rb
.to_world
[3], mtx
[3] );
1170 m4x3_mulv( mtx
, player
.mdl
.cam_pos
, cam_pos
);
1171 v3_add( cam_pos
, forward_dir
, player
.camera_pos
);
1172 v3_lerp( player
.vl
, player
.rb
.v
, 0.3f
, player
.vl
);
1179 static void player_audio(void)
1181 static int _ding
= 0;
1184 _ding
= glfwGetKey(vg_window
, GLFW_KEY_C
);
1186 int trigger_ding
= 0;
1187 if( _ding
&& !last
)
1190 static int _air
= 0;
1193 _air
= player
.in_air
;
1195 static double last_revert
= -2000.0;
1202 double revert_delta
= vg_time
- last_revert
;
1203 if( player
.on_board
&& (!_air
&& l2
) && (fabsf(player
.slip
) > 0.5f
) &&
1204 (revert_delta
> 0.7) )
1206 audio_player_set_position( &audio_player_extra
, player
.rb
.co
);
1207 audio_player_set_flags( &audio_player_extra
, AUDIO_FLAG_SPACIAL_3D
);
1208 audio_player_set_vol( &audio_player_extra
, 2.0f
);
1209 audio_player_playclip( &audio_player_extra
, &audio_lands
[rand()%5] );
1211 last_revert
= vg_time
;
1214 static float air
= 0.0f
;
1215 air
= vg_lerpf(air
, player
.in_air
? 1.0f
: 0.0f
, 5.0f
*ktimestep
);
1218 v3f ears
= { 1.0f
,0.0f
,0.0f
};
1221 float *cam
= player
.camera
[3],
1222 *pos
= player
.rb
.co
;
1225 audio_player_playclip( &audio_player_extra
, &audio_ding
);
1227 audio_player_set_position( &audio_player0
, player
.rb
.co
);
1228 audio_player_set_position( &audio_player1
, player
.rb
.co
);
1229 audio_player_set_position( &audio_player2
, player
.rb
.co
);
1230 audio_player_set_position( &audio_player_gate
, world
.render_gate_pos
);
1232 v3_sub( player
.rb
.co
, player
.camera
[3], delta
);
1233 v3_normalize( delta
);
1234 m3x3_mulv( player
.camera
, ears
, ears
);
1236 /* TODO, Make function */
1237 v3_copy( ears
, vg_audio
.listener_ears
);
1238 v3_copy( player
.camera
[3], vg_audio
.listener_pos
);
1240 /* Tunnel / occlusion */
1241 audio_sample_occlusion( player
.camera
[3] );
1243 int sprite_avail
= -1;
1244 for( int i
=0; i
<vg_list_size(ambient_sprites
); i
++ )
1246 if( !audio_player_is_playing( &ambient_sprites
[i
] ) )
1253 if( sprite_avail
!= -1 )
1256 enum audio_sprite_type sprite_type
=
1257 audio_sample_sprite_random( player
.rb
.co
, waterpos
);
1259 if( sprite_type
!= k_audio_sprite_type_none
)
1261 audio_player
*avail
= &ambient_sprites
[ sprite_avail
];
1263 audio_player_set_vol( avail
, 20.0f
);
1264 audio_player_set_flags( avail
, AUDIO_FLAG_SPACIAL_3D
);
1265 audio_player_set_position( avail
, waterpos
);
1267 if( sprite_type
== k_audio_sprite_type_grass
)
1269 audio_player_playclip( avail
, &audio_grass
[rand()%4] );
1271 else if( sprite_type
== k_audio_sprite_type_water
)
1273 audio_player_playclip( avail
, &audio_water
[rand()%6] );
1278 if( freecam
|| player
.is_dead
|| !player
.on_board
)
1280 audio_player_set_vol( &audio_player0
, 0.0f
);
1281 audio_player_set_vol( &audio_player1
, 0.0f
);
1282 audio_player_set_vol( &audio_player2
, 0.0f
);
1285 if( vg_fractf(player
.walk_timer
) > 0.5f
)
1290 if( (player
.step_phase
!= walk_phase
) && !player
.in_air
)
1292 v3_copy( player
.rb
.co
, player
.last_step_pos
);
1294 audio_player_set_flags( &audio_player_extra
, AUDIO_FLAG_SPACIAL_3D
);
1295 audio_player_set_position( &audio_player_extra
, player
.rb
.co
);
1296 audio_player_set_vol( &audio_player_extra
, 6.0f
);
1297 audio_player_playclip( &audio_player_extra
,
1298 &audio_footsteps
[rand()%4] );
1301 player
.step_phase
= walk_phase
;
1306 float speed
= vg_minf(v3_length( player
.rb
.v
)*0.1f
,1.0f
),
1308 slide
= vg_clampf( fabsf(player
.slip
), 0.0f
, 1.0f
),
1309 vol0
= (1.0f
-air
)*attn
*(1.0f
-slide
),
1311 vol2
= (1.0f
-air
)*attn
*slide
;
1313 audio_player_set_vol( &audio_player0
, vol0
);
1314 audio_player_set_vol( &audio_player1
, vol1
);
1315 audio_player_set_vol( &audio_player2
, vol2
);
1317 float reverb_amt
= vol0
* audio_occlusion_current
* 0.5f
;
1318 audio_player_set_pan( &audio_player3
, 0.0f
);
1319 audio_player_set_vol( &audio_player3
, reverb_amt
);
1323 world_audio_update( cam
, ears
);
1331 static float *player_cam_pos(void)
1333 return player
.camera_pos
;
1336 static int reset_player( int argc
, char const *argv
[] )
1338 struct respawn_point
*rp
= NULL
, *r
;
1342 for( int i
=0; i
<world
.spawn_count
; i
++ )
1344 r
= &world
.spawns
[i
];
1345 if( !strcmp( r
->name
, argv
[0] ) )
1353 vg_warn( "No spawn named '%s'\n", argv
[0] );
1358 float min_dist
= INFINITY
;
1360 for( int i
=0; i
<world
.spawn_count
; i
++ )
1362 r
= &world
.spawns
[i
];
1363 float d
= v3_dist2( r
->co
, player
.rb
.co
);
1365 vg_info( "Dist %s : %f\n", r
->name
, d
);
1376 vg_error( "No spawn found\n" );
1377 if( !world
.spawn_count
)
1380 rp
= &world
.spawns
[0];
1383 v4_copy( rp
->q
, player
.rb
.q
);
1384 v3_copy( rp
->co
, player
.rb
.co
);
1386 player
.vswitch
= 1.0f
;
1387 player
.slip_last
= 0.0f
;
1390 m3x3_identity( player
.vr
);
1392 player
.mdl
.shoes
[0] = 1;
1393 player
.mdl
.shoes
[1] = 1;
1395 rb_update_transform( &player
.rb
);
1396 m3x3_mulv( player
.rb
.to_world
, (v3f
){ 0.0f
, 0.0f
, -1.2f
}, player
.rb
.v
);
1397 m3x3_identity( player
.gate_vr_frame
);
1398 m3x3_identity( player
.gate_vr_pstep_frame
);
1400 player
.rb_gate_frame
= player
.rb
;
1401 player
.on_board_frame
= player
.on_board
;
1402 player
.in_air_frame
= player
.in_air
;
1406 static void player_update(void)
1408 for( int i
=0; i
<player
.land_log_count
; i
++ )
1409 draw_cross( player
.land_target_log
[i
],
1410 player
.land_target_colours
[i
], 0.25f
);
1412 if( vg_get_axis("grabl")>0.0f
)
1414 player
.rb
= player
.rb_gate_frame
;
1415 player
.on_board
= player
.on_board_frame
;
1416 player
.in_air
= player
.in_air_frame
;
1417 m3x3_copy( player
.gate_vr_frame
, player
.vr
);
1418 m3x3_copy( player
.gate_vr_pstep_frame
, player
.vr_pstep
);
1423 if( !player
.on_board
)
1425 player
.angles
[0] = atan2f( -player
.rb
.forward
[2],
1426 -player
.rb
.forward
[0] );
1429 m3x3_identity( player
.vr
);
1431 player
.mdl
.shoes
[0] = 1;
1432 player
.mdl
.shoes
[1] = 1;
1434 world_routes_notify_reset();
1437 if( vg_get_button_down( "switchmode" ) )
1439 player
.on_board
^= 0x1;
1442 if( (glfwGetKey( vg_window
, GLFW_KEY_O
) || (player
.rb
.co
[1] < 0.0f
)) &&
1445 character_ragdoll_copypose( &player
.mdl
, player
.rb
.v
);
1449 if( player
.is_dead
)
1451 character_ragdoll_iter( &player
.mdl
);
1452 character_debug_ragdoll( &player
.mdl
);
1455 player_animate_death_cam();
1463 player_animate_camera();
1469 player_camera_update();
1473 static void draw_player(void)
1475 if( player
.is_dead
)
1476 character_mimic_ragdoll( &player
.mdl
);
1478 shader_viewchar_use();
1479 vg_tex2d_bind( &tex_characters
, 0 );
1480 shader_viewchar_uTexMain( 0 );
1481 shader_viewchar_uCamera( player
.camera
[3] );
1482 shader_viewchar_uPv( vg_pv
);
1483 shader_link_standard_ub( _shader_viewchar
.id
, 2 );
1484 glUniformMatrix4x3fv( _uniform_viewchar_uTransforms
,
1485 player
.mdl
.sk
.bone_count
,
1487 (float *)player
.mdl
.sk
.final_mtx
);
1489 mesh_bind( &player
.mdl
.mesh
);
1490 mesh_draw( &player
.mdl
.mesh
);
1493 #endif /* PLAYER_H */