7 static int freecam
= 0;
8 static float k_walkspeed
= 2.0f
;
13 v3f co
, v
, a
, v_last
, m
, bob
;
15 float vswitch
, slip
, slip_last
,
18 float iY
; /* Yaw inertia */
19 int in_air
, is_dead
, on_board
;
29 v3f land_target_log
[22];
30 u32 land_target_colours
[22];
34 m4x3f to_world
, to_local
;
38 v3f handl_target
, handr_target
,
44 v3f camera_pos
, smooth_localcam
;
46 m4x3f camera
, camera_inverse
;
50 static void player_transform_update(void)
52 q_normalize( player
.rot
);
53 q_m3x3( player
.rot
, player
.to_world
);
54 v3_copy( player
.co
, player
.to_world
[3] );
56 m4x3_invert_affine( player
.to_world
, player
.to_local
);
59 static int reset_player( int argc
, char const *argv
[] )
65 if( !strcmp( argv
[0], "tutorial" ))
66 v3_copy( world
.tutorial
, player
.co
);
69 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player
.v
);
70 q_identity( player
.rot
);
71 player
.vswitch
= 1.0f
;
72 player
.slip_last
= 0.0f
;
75 m3x3_identity( player
.vr
);
77 player
.mdl
.shoes
[0] = 1;
78 player
.mdl
.shoes
[1] = 1;
80 player_transform_update();
84 static void player_mouseview(void)
86 static v2f mouse_last
,
87 view_vel
= { 0.0f
, 0.0f
};
89 if( vg_get_button_down( "primary" ) )
90 v2_copy( vg_mouse
, mouse_last
);
91 else if( vg_get_button( "primary" ) )
94 v2_sub( vg_mouse
, mouse_last
, delta
);
95 v2_copy( vg_mouse
, mouse_last
);
97 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
100 v2_muls( view_vel
, 0.7f
, view_vel
);
101 v2_add( view_vel
, player
.angles
, player
.angles
);
102 player
.angles
[1] = vg_clampf( player
.angles
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
106 static void player_freecam(void)
110 float movespeed
= 25.0f
;
111 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
112 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
114 m3x3_mulv( player
.camera
, lookdir
, lookdir
);
115 m3x3_mulv( player
.camera
, sidedir
, sidedir
);
117 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
118 if( vg_get_button( "forward" ) )
119 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
120 if( vg_get_button( "back" ) )
121 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
122 if( vg_get_button( "left" ) )
123 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
124 if( vg_get_button( "right" ) )
125 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
127 v3_muls( move_vel
, 0.7f
, move_vel
);
128 v3_add( move_vel
, player
.camera_pos
, player
.camera_pos
);
131 static void apply_gravity( v3f vel
, float const timestep
)
133 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
134 v3_muladds( vel
, gravity
, timestep
, vel
);
137 static void player_start_air(void)
141 float pstep
= ktimestep
*10.0f
;
143 float best_velocity_mod
= 0.0f
,
144 best_velocity_delta
= -9999.9f
;
147 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, vup
);
148 v3_cross( vup
, player
.v
, axis
);
149 v3_normalize( axis
);
150 player
.land_log_count
= 0;
152 m3x3_identity( player
.vr
);
154 for( int m
=-3;m
<=12; m
++ )
156 float vmod
= ((float)m
/ 15.0f
)*0.09f
;
159 v3_copy( player
.co
, pco
);
160 v3_copy( player
.v
, pv
);
163 * Try different 'rotations' of the velocity to find the best possible
164 * landing normal. This conserves magnitude at the expense of slightly
165 * unrealistic results
171 q_axis_angle( vr_q
, axis
, vmod
);
174 m3x3_mulv( vr
, pv
, pv
);
175 v3_muladds( pco
, pv
, ktimestep
, pco
);
177 for( int i
=0; i
<50; i
++ )
179 v3_copy( pco
, pco1
);
180 apply_gravity( pv
, pstep
);
182 m3x3_mulv( vr
, pv
, pv
);
183 v3_muladds( pco
, pv
, pstep
, pco
);
188 v3_sub( pco
, pco1
, vdir
);
189 contact
.dist
= v3_length( vdir
);
190 v3_divs( vdir
, contact
.dist
, vdir
);
192 if( ray_world( pco1
, vdir
, &contact
))
194 float land_delta
= v3_dot( pv
, contact
.normal
);
195 u32 scolour
= (u8
)(vg_minf(-land_delta
* 2.0f
, 255.0f
));
197 /* Bias prediction towords ramps */
198 if( ray_hit_is_ramp( &contact
) )
201 scolour
|= 0x0000a000;
204 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
206 best_velocity_delta
= land_delta
;
207 best_velocity_mod
= vmod
;
209 v3_copy( contact
.pos
, player
.land_target
);
211 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
212 q_m3x3( vr_q
, player
.vr
);
215 v3_copy( contact
.pos
,
216 player
.land_target_log
[player
.land_log_count
] );
217 player
.land_target_colours
[player
.land_log_count
] =
218 0xff000000 | scolour
;
220 player
.land_log_count
++;
227 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
230 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
233 static int sample_if_resistant( v3f pos
)
236 v3_copy( pos
, ground
);
242 if( ray_world( ground
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
245 v3_copy( player
.v
, angle
);
246 v3_normalize( angle
);
247 float resistance
= v3_dot( hit
.normal
, angle
);
249 if( resistance
< 0.25f
)
251 v3_copy( hit
.pos
, pos
);
259 static float stable_force( float current
, float diff
)
261 float new = current
+ diff
;
263 if( new * current
< 0.0f
)
269 static void player_physics_ground(void)
272 * Getting surface collision points,
273 * the contact manifold is a triangle for simplicity.
275 v3f contact_front
, contact_back
, contact_norm
, vup
, vside
,
278 float klength
= 0.65f
;
279 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
280 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
281 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
282 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
283 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
288 sample_if_resistant( contact_front
) +
289 sample_if_resistant( contact_back
) +
290 sample_if_resistant( contact_norm
);
292 if( contact_count
< 3 )
300 v3_sub( contact_norm
, contact_front
, v0
);
301 v3_sub( contact_back
, contact_front
, v1
);
302 v3_cross( v1
, v0
, norm
);
303 v3_normalize( norm
);
305 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
306 vg_line( contact_back
, contact_front
, 0xff0000ff );
308 /* Surface alignment */
309 float angle
= v3_dot( vup
, norm
);
310 v3_cross( vup
, norm
, axis
);
315 q_axis_angle( correction
, axis
, acosf(angle
) );
316 q_mul( correction
, player
.rot
, player
.rot
);
319 float resistance
= v3_dot( norm
, player
.v
);
320 if( resistance
>= 0.0f
)
327 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
330 /* This is where velocity integration used to be */
334 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
337 m3x3_mulv( player
.to_local
, player
.v
, vel
);
339 /* Calculate local forces */
341 if( fabsf(vel
[2]) > 0.01f
)
342 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
344 if( fabsf( slip
) > 1.2f
)
345 slip
= vg_signf( slip
) * 1.2f
;
347 player
.reverse
= -vg_signf(vel
[2]);
349 float substep
= ktimestep
* 0.2f
;
350 float fwd_resistance
= (vg_get_button( "break" )? 5.0f
: 0.02f
) * -substep
;
352 for( int i
=0; i
<5; i
++ )
354 vel
[2] = stable_force( vel
[2], vg_signf( vel
[2] ) * fwd_resistance
);
355 vel
[0] = stable_force( vel
[0], vg_signf( vel
[0] ) * -7.0f
*substep
);
358 static double start_push
= 0.0;
359 if( vg_get_button_down( "push" ) )
360 start_push
= vg_time
;
362 if( !vg_get_button("break") && vg_get_button( "push" ) )
364 float const k_maxpush
= 16.0f
,
367 float cycle_time
= vg_time
-start_push
,
368 amt
= k_pushaccel
* (sinf( cycle_time
* 8.0f
)*0.5f
+0.5f
)*ktimestep
,
369 current
= v3_length( vel
),
370 new_vel
= vg_minf( current
+ amt
, k_maxpush
);
371 new_vel
-= vg_minf(current
, k_maxpush
);
372 vel
[2] -= new_vel
* player
.reverse
;
375 m3x3_mulv( player
.to_world
, vel
, player
.v
);
377 if( vg_get_button( "yawl" ) )
378 player
.iY
+= 3.6f
* ktimestep
;
379 if( vg_get_button( "yawr" ) )
380 player
.iY
-= 3.6f
* ktimestep
;
382 float steer
= vg_get_axis( "horizontal" );
383 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
385 /* Too much lean and it starts to look like a snowboard here */
386 v2_lerp( player
.board_xy
, (v2f
){ slip
*0.25f
, 0.0f
},
387 ktimestep
*5.0f
, player
.board_xy
);
390 static void draw_cross(v3f pos
,u32 colour
, float scale
)
393 v3_add( (v3f
){ scale
,0.0f
,0.0f
}, pos
, p0
);
394 v3_add( (v3f
){-scale
,0.0f
,0.0f
}, pos
, p1
);
395 vg_line( p0
, p1
, colour
);
396 v3_add( (v3f
){0.0f
, scale
,0.0f
}, pos
, p0
);
397 v3_add( (v3f
){0.0f
,-scale
,0.0f
}, pos
, p1
);
398 vg_line( p0
, p1
, colour
);
399 v3_add( (v3f
){0.0f
,0.0f
, scale
}, pos
, p0
);
400 v3_add( (v3f
){0.0f
,0.0f
,-scale
}, pos
, p1
);
401 vg_line( p0
, p1
, colour
);
404 static void player_physics_air(void)
406 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
407 for( int i
=0; i
<player
.land_log_count
; i
++ )
408 draw_cross( player
.land_target_log
[i
], player
.land_target_colours
[i
], 1);
410 draw_cross( player
.land_target
, 0xff0000ff, 1 );
413 v3_copy( player
.co
, ground_pos
);
414 ground_pos
[1] += 4.0f
;
418 if( ray_world( ground_pos
, (v3f
){0.0f
,-1.0f
,0.0f
}, &hit
))
420 if( hit
.pos
[1] > player
.co
[1] )
424 if( !ray_hit_is_ramp( &hit
) )
427 character_ragdoll_copypose( &player
.mdl
, player
.v
);
436 * TODO: Find best landing surface and guide player towords it
438 float pstep
= ktimestep
*10.0f
;
441 v3_copy( player
.co
, pco
);
442 v3_copy( player
.v
, pv
);
444 float time_to_impact
= 0.0f
;
445 float limiter
= 1.0f
;
447 for( int i
=0; i
<50; i
++ )
449 v3_copy( pco
, pco1
);
450 apply_gravity( pv
, pstep
);
451 v3_muladds( pco
, pv
, pstep
, pco
);
453 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
458 v3_sub( pco
, pco1
, vdir
);
459 contact
.dist
= v3_length( vdir
);
460 v3_divs( vdir
, contact
.dist
, vdir
);
462 float orig_dist
= contact
.dist
;
463 if( ray_world( pco1
, vdir
, &contact
))
466 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
468 float angle
= v3_dot( localup
, contact
.normal
);
470 v3_cross( localup
, contact
.normal
, axis
);
472 time_to_impact
+= (contact
.dist
/orig_dist
)*pstep
;
473 limiter
= vg_minf( 5.0f
, time_to_impact
)/5.0f
;
474 limiter
= 1.0f
-limiter
;
476 limiter
= 1.0f
-limiter
;
481 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
*(1.0f
-limiter
) );
482 q_mul( correction
, player
.rot
, player
.rot
);
485 draw_cross( contact
.pos
, 0xffff0000, 1 );
488 time_to_impact
+= pstep
;
491 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
494 float iX
= vg_get_axis( "vertical" ) * 3.6f
* limiter
* ktimestep
;
495 static float siX
= 0.0f
;
496 siX
= vg_lerpf( siX
, iX
, 0.3f
);
501 m3x3_mulv( player
.to_world
, (v3f
){1.0f
,0.0f
,0.0f
}, vside
);
503 q_axis_angle( rotate
, vside
, siX
);
504 q_mul( rotate
, player
.rot
, player
.rot
);
507 v2f target
= {0.0f
,0.0f
};
508 v2_muladds( target
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
509 player
.grab
, target
);
510 v2_lerp( player
.board_xy
, target
, ktimestep
*3.0f
, player
.board_xy
);
513 static void player_do_motion(void)
515 float horizontal
= vg_get_axis("horizontal"),
516 vertical
= vg_get_axis("vertical");
518 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
519 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
522 player_physics_air();
525 player_physics_ground();
527 /* Integrate velocity */
529 v3_copy( player
.co
, prevco
);
531 apply_gravity( player
.v
, ktimestep
);
532 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
534 /* Integrate inertia */
535 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
536 m3x3_mulv( player
.to_world
, vup
, vup
);
538 static float siY
= 0.0f
;
540 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
541 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
543 q_axis_angle( rotate
, vup
, siY
);
544 q_mul( rotate
, player
.rot
, player
.rot
);
546 player
.iY
= 0.0f
; /* temp */
550 if( gate_intersect( &gate_a
, player
.co
, prevco
) )
552 teleport_gate
*gate
= &gate_a
;
555 m4x3_mul( gate
->other
->to_world
, gate
->to_local
, transport
);
556 m4x3_mulv( transport
, player
.co
, player
.co
);
557 m3x3_mulv( transport
, player
.v
, player
.v
);
558 m3x3_mulv( transport
, player
.v_last
, player
.v_last
);
559 m3x3_mulv( transport
, player
.m
, player
.m
);
560 m3x3_mulv( transport
, player
.bob
, player
.bob
);
562 v4f transport_rotation
;
563 m3x3_q( transport
, transport_rotation
);
564 q_mul( transport_rotation
, player
.rot
, player
.rot
);
568 /* Camera and character */
569 player_transform_update();
571 player
.angles
[0] = atan2f( player
.v
[0], -player
.v
[2] );
572 player
.angles
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
573 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
575 player
.air_blend
= vg_lerpf( player
.air_blend
, player
.in_air
, 0.04f
);
576 v3_muladds( player
.camera_pos
, player
.v
, -0.05f
*player
.air_blend
,
581 * Get a sample at this pole location, will return 1 if the sample is valid,
582 * and pos will be updated to be the intersection location.
584 static int player_walkgrid_samplepole( u32
*geo
, int len
, v3f pos
)
590 vg_line( pos
, p1
, 0x20ffffff );
593 v3_copy(pos
, sample_pos
);
595 v3f vdir
= {0.0f
,-1.0f
,0.0f
};
600 for( int i
=0; i
<len
; i
++ )
602 u32
*tri
= &world
.geo
.indices
[ geo
[i
] ];
603 count
+= bvh_ray_tri( &world
.geo
, tri
, sample_pos
, vdir
, &hit
);
609 float *pa
= world
.geo
.verts
[hit
.tri
[0]].co
,
610 *pb
= world
.geo
.verts
[hit
.tri
[1]].co
,
611 *pc
= world
.geo
.verts
[hit
.tri
[2]].co
;
613 v3_sub( pa
, pb
, v0
);
614 v3_sub( pc
, pb
, v1
);
615 v3_cross( v1
, v0
, hit
.normal
);
616 v3_normalize( hit
.normal
);
617 v3_muladds( sample_pos
, vdir
, hit
.dist
, pos
);
619 draw_cross( pos
, 0xff00ff00, 0.05f
);
626 static void player_walkgrid_clip(u32
*geo
, int len
, v3f pos
, v3f dir
, v3f clip
)
628 float max_dist
= 0.0f
;
631 v3_cross( dir
,(v3f
){0.0f
,1.0f
,0.0f
},perp
);
632 v3_copy( pos
, clip
);
634 for( int i
=0; i
<len
; i
++ )
636 u32
*ptri
= &world
.geo
.indices
[ geo
[i
] ];
637 for( int j
=0; j
<3; j
++ )
638 v3_copy( world
.geo
.verts
[ptri
[j
]].co
, tri
[j
] );
640 for( int k
=0; k
<3; k
++ )
646 v3_sub( tri
[ia
], pos
, v0
);
647 v3_sub( tri
[ib
], pos
, v1
);
649 if( (dir
[2]*v0
[0] - dir
[0]*v0
[2]) *
650 (dir
[2]*v1
[0] - dir
[0]*v1
[2]) < 0.0f
)
652 float da
= v3_dot(v0
,perp
),
653 db
= v3_dot(v1
,perp
),
658 v3_muls( v1
, qa
, p0
);
659 v3_muladds( p0
, v0
, 1.0f
-qa
, p0
);
661 float h
= v3_dot(p0
,dir
)/v3_dot(dir
,dir
);
663 if( h
>= max_dist
&& h
<= 1.0f
)
666 float l
= 1.0f
/v3_length(dir
);
667 v3_muls( p0
, l
, clip
);
674 #define WALKGRID_SIZE 8
683 samples
[WALKGRID_SIZE
][WALKGRID_SIZE
];
688 float move
; /* Current amount of movement we have left to apply */
689 v2f dir
; /* The movement delta */
690 v2i cell_id
;/* Current cell */
691 v2f pos
; /* Local position (in cell) */
695 static const struct conf
702 * o: the 'other' point to do a A/B test with
703 * if its -1, all AB is done.
705 * TODO: Check the major edge against point (for the double cases)
715 k_walkgrid_configs
[16] = {
717 {{{ 3,3, 3,0, 1,0, -1,-1 }}, 1},
718 {{{ 2,2, 1,3, 0,1, -1,-1 }}, 1},
719 {{{ 2,3, 1,0, 0,0, 3,-1 }}, 1},
721 {{{ 1,1, 0,1, 1,0, -1,-1 }}, 1},
722 {{{ 3,3, 3,0, 1,0, -1,-1 },
723 { 1,1, 0,1, 1,0, -1,-1 }}, 2},
724 {{{ 1,2, 0,3, 1,1, 2,-1 }}, 1},
725 {{{ 1,3, 0,0, 1,0, 2, 2 }}, 1},
727 {{{ 0,0, 0,0, 0,1, -1,-1 }}, 1},
728 {{{ 3,0, 3,0, 1,1, 0,-1 }}, 1},
729 {{{ 2,2, 1,3, 0,1, -1,-1 },
730 { 0,0, 0,0, 0,1, -1,-1 }}, 2},
731 {{{ 2,0, 1,0, 0,1, 3, 3 }}, 1},
733 {{{ 0,1, 0,1, 0,0, 1,-1 }}, 1},
734 {{{ 3,1, 3,1, 1,0, 0, 0 }}, 1},
735 {{{ 0,2, 0,3, 0,1, 1, 1 }}, 1},
740 * Get a buffer of edges from cell location
742 static const struct conf
*player_walkgrid_conf( struct walkgrid
*wg
,
744 struct grid_sample
*corners
[4] )
746 corners
[0] = &wg
->samples
[cell
[1] ][cell
[0] ];
747 corners
[1] = &wg
->samples
[cell
[1]+1][cell
[0] ];
748 corners
[2] = &wg
->samples
[cell
[1]+1][cell
[0]+1];
749 corners
[3] = &wg
->samples
[cell
[1] ][cell
[0]+1];
751 u32 config
= (corners
[0]->valid
<<3) | (corners
[1]->valid
<<2) |
752 (corners
[2]->valid
<<1) | corners
[3]->valid
;
754 return &k_walkgrid_configs
[ config
];
757 float const k_gridscale
= 0.5f
;
759 static void player_walkgrid_floor(v3f pos
)
761 v3_muls( pos
, 1.0f
/k_gridscale
, pos
);
762 v3_floor( pos
, pos
);
763 v3_muls( pos
, k_gridscale
, pos
);
767 * Computes the barycentric coordinate of location on a triangle (vertical),
768 * then sets the Y position to the interpolation of the three points
770 static void player_walkgrid_stand_tri( v3f a
, v3f b
, v3f c
, v3f pos
)
775 v3_sub( pos
, a
, v2
);
777 float d
= v0
[0]*v1
[2] - v1
[0]*v0
[2],
778 v
= (v2
[0]*v1
[2] - v1
[0]*v2
[2]) / d
,
779 w
= (v0
[0]*v2
[2] - v2
[0]*v0
[2]) / d
,
782 vg_line( pos
, a
, 0xffff0000 );
783 vg_line( pos
, b
, 0xff00ff00 );
784 vg_line( pos
, c
, 0xff0000ff );
785 pos
[1] = u
*a
[1] + v
*b
[1] + w
*c
[1];
789 * Get the minimum time value of pos+dir until a cell edge
791 * t[0] -> t[3] are the individual time values
792 * t[5] & t[6] are the maximum axis values
793 * t[6] is the minimum value
796 static void player_walkgrid_min_cell( float t
[7], v2f pos
, v2f dir
)
798 v2f frac
= { 1.0f
/dir
[0], 1.0f
/dir
[1] };
805 if( fabsf(dir
[0]) > 0.0001f
)
807 t
[0] = (0.0f
-pos
[0]) * frac
[0];
808 t
[1] = (1.0f
-pos
[0]) * frac
[0];
810 if( fabsf(dir
[1]) > 0.0001f
)
812 t
[2] = (0.0f
-pos
[1]) * frac
[1];
813 t
[3] = (1.0f
-pos
[1]) * frac
[1];
816 t
[4] = vg_maxf(t
[0],t
[1]);
817 t
[5] = vg_maxf(t
[2],t
[3]);
818 t
[6] = vg_minf(t
[4],t
[5]);
821 static void player_walkgrid_iter(struct walkgrid
*wg
, int iter
)
825 * For each walkgrid iteration we are stepping through cells and determining
826 * the intersections with the grid, and any edges that are present
830 if( wg
->cell_id
[0] < 0 || wg
->cell_id
[0] >= WALKGRID_SIZE
-1 ||
831 wg
->cell_id
[1] < 0 || wg
->cell_id
[1] >= WALKGRID_SIZE
-1 )
834 * This condition should never be reached if the grid size is big
842 u32 icolours
[] = { 0xffff00ff, 0xff00ffff, 0xffffff00 };
844 v3f pa
, pb
, pc
, pd
, pl0
, pl1
;
845 pa
[0] = wg
->region
[0][0] + (float)wg
->cell_id
[0] *k_gridscale
;
846 pa
[1] = (wg
->region
[0][1] + wg
->region
[1][1]) * 0.5f
+ k_gridscale
;
847 pa
[2] = wg
->region
[0][2] + (float)wg
->cell_id
[1] *k_gridscale
;
850 pb
[2] = pa
[2] + k_gridscale
;
851 pc
[0] = pa
[0] + k_gridscale
;
853 pc
[2] = pa
[2] + k_gridscale
;
854 pd
[0] = pa
[0] + k_gridscale
;
858 vg_line( pa
, pb
, 0xff00ffff );
859 vg_line( pb
, pc
, 0xff00ffff );
860 vg_line( pc
, pd
, 0xff00ffff );
861 vg_line( pd
, pa
, 0xff00ffff );
863 pl0
[0] = pa
[0] + wg
->pos
[0]*k_gridscale
;
865 pl0
[2] = pa
[2] + wg
->pos
[1]*k_gridscale
;
868 * If there are edges present, we need to create a 'substep' event, where
869 * we find the intersection point, find the fully resolved position,
870 * then the new pos dir is the intersection->resolution
872 * the resolution is applied in non-discretized space in order to create a
873 * suitable vector for finding outflow, we want it to leave the cell so it
874 * can be used by the quad
878 v2_copy( wg
->pos
, pos
);
879 v2_muls( wg
->dir
, wg
->move
, dir
);
881 struct grid_sample
*corners
[4];
882 v2f corners2d
[4] = {{0.0f
,0.0f
},{0.0f
,1.0f
},{1.0f
,1.0f
},{1.0f
,0.0f
}};
883 const struct conf
*conf
= player_walkgrid_conf( wg
, wg
->cell_id
, corners
);
886 player_walkgrid_min_cell( t
, pos
, dir
);
888 for( int i
=0; i
<conf
->edge_count
; i
++ )
890 const struct confedge
*edge
= &conf
->edges
[i
];
892 v2f e0
, e1
, n
, r
, target
, res
, tangent
;
893 e0
[0] = corners2d
[edge
->i0
][0] + corners
[edge
->d0
]->clip
[edge
->a0
][0];
894 e0
[1] = corners2d
[edge
->i0
][1] + corners
[edge
->d0
]->clip
[edge
->a0
][2];
895 e1
[0] = corners2d
[edge
->i1
][0] + corners
[edge
->d1
]->clip
[edge
->a1
][0];
896 e1
[1] = corners2d
[edge
->i1
][1] + corners
[edge
->d1
]->clip
[edge
->a1
][2];
898 v3f pe0
= { pa
[0] + e0
[0]*k_gridscale
,
900 pa
[2] + e0
[1]*k_gridscale
};
901 v3f pe1
= { pa
[0] + e1
[0]*k_gridscale
,
903 pa
[2] + e1
[1]*k_gridscale
};
905 v2_sub( e1
, e0
, tangent
);
911 * If we find ourselfs already penetrating the edge, move back out a
914 v2_sub( e0
, pos
, r
);
915 float p1
= v2_dot(r
,n
);
919 v2_muladds( pos
, n
, p1
+0.0001f
, pos
);
920 v2_copy( pos
, wg
->pos
);
921 v3f p_new
= { pa
[0] + pos
[0]*k_gridscale
,
923 pa
[2] + pos
[1]*k_gridscale
};
924 v3_copy( p_new
, pl0
);
927 v2_add( pos
, dir
, target
);
930 v2_sub( e0
, pos
, v1
);
931 v2_sub( target
, pos
, v2
);
935 v2_sub( e0
, target
, r
);
936 float p
= v2_dot(r
,n
),
937 t1
= v2_dot(v1
,v3
)/v2_dot(v2
,v3
);
939 if( t1
< t
[6] && t1
> 0.0f
&& -p
< 0.001f
)
941 v2_muladds( target
, n
, p
+0.0001f
, res
);
944 v2_muladds( pos
, dir
, t1
, intersect
);
945 v2_copy( intersect
, pos
);
946 v2_sub( res
, intersect
, dir
);
948 v3f p_res
= { pa
[0] + res
[0]*k_gridscale
,
950 pa
[2] + res
[1]*k_gridscale
};
951 v3f p_int
= { pa
[0] + intersect
[0]*k_gridscale
,
953 pa
[2] + intersect
[1]*k_gridscale
};
955 vg_line( pl0
, p_int
, icolours
[iter
%3] );
956 v3_copy( p_int
, pl0
);
957 v2_copy( pos
, wg
->pos
);
959 player_walkgrid_min_cell( t
, pos
, dir
);
964 * Compute intersection with grid cell moving outwards
966 t
[6] = vg_minf( t
[6], 1.0f
);
968 pl1
[0] = pl0
[0] + dir
[0]*k_gridscale
*t
[6];
970 pl1
[2] = pl0
[2] + dir
[1]*k_gridscale
*t
[6];
971 vg_line( pl0
, pl1
, icolours
[iter
%3] );
976 * To figure out what t value created the clip so we know which edge
982 wg
->pos
[1] = pos
[1] + dir
[1]*t
[6];
984 if( t
[0] > t
[1] ) /* left edge */
986 wg
->pos
[0] = 0.9999f
;
989 if( wg
->cell_id
[0] == 0 )
992 else /* Right edge */
994 wg
->pos
[0] = 0.0001f
;
997 if( wg
->cell_id
[0] == WALKGRID_SIZE
-2 )
1003 wg
->pos
[0] = pos
[0] + dir
[0]*t
[6];
1005 if( t
[2] > t
[3] ) /* bottom edge */
1007 wg
->pos
[1] = 0.9999f
;
1010 if( wg
->cell_id
[1] == 0 )
1015 wg
->pos
[1] = 0.0001f
;
1018 if( wg
->cell_id
[1] == WALKGRID_SIZE
-2 )
1027 v2_muladds( wg
->pos
, dir
, wg
->move
, wg
->pos
);
1032 static void player_walkgrid_stand_cell(struct walkgrid
*wg
)
1035 * NOTE: as opposed to the other function which is done in discretized space
1036 * this use a combination of both.
1040 world
[0] = wg
->region
[0][0]+((float)wg
->cell_id
[0]+wg
->pos
[0])*k_gridscale
;
1041 world
[2] = wg
->region
[0][2]+((float)wg
->cell_id
[1]+wg
->pos
[1])*k_gridscale
;
1043 struct grid_sample
*corners
[4];
1044 const struct conf
*conf
= player_walkgrid_conf( wg
, wg
->cell_id
, corners
);
1046 if( conf
!= k_walkgrid_configs
)
1048 if( conf
->edge_count
== 0 )
1052 /* Split the basic quad along the shortest diagonal */
1053 if( fabsf(corners
[2]->pos
[1] - corners
[0]->pos
[1]) <
1054 fabsf(corners
[3]->pos
[1] - corners
[1]->pos
[1]) )
1056 vg_line( corners
[2]->pos
, corners
[0]->pos
, 0xffaaaaaa );
1058 if( wg
->pos
[0] > wg
->pos
[1] )
1059 player_walkgrid_stand_tri( corners
[0]->pos
,
1061 corners
[2]->pos
, world
);
1063 player_walkgrid_stand_tri( corners
[0]->pos
,
1065 corners
[1]->pos
, world
);
1069 vg_line( corners
[3]->pos
, corners
[1]->pos
, 0xffaaaaaa );
1071 if( wg
->pos
[0] < 1.0f
-wg
->pos
[1] )
1072 player_walkgrid_stand_tri( corners
[0]->pos
,
1074 corners
[1]->pos
, world
);
1076 player_walkgrid_stand_tri( corners
[3]->pos
,
1078 corners
[1]->pos
, world
);
1083 for( int i
=0; i
<conf
->edge_count
; i
++ )
1085 const struct confedge
*edge
= &conf
->edges
[i
];
1088 v3_muladds( corners
[edge
->i0
]->pos
,
1089 corners
[edge
->d0
]->clip
[edge
->a0
], k_gridscale
, p0
);
1090 v3_muladds( corners
[edge
->i1
]->pos
,
1091 corners
[edge
->d1
]->clip
[edge
->a1
], k_gridscale
, p1
);
1094 * Find penetration distance between player position and the edge
1097 v2f normal
= { -(p1
[2]-p0
[2]), p1
[0]-p0
[0] },
1098 rel
= { world
[0]-p0
[0], world
[2]-p0
[2] };
1100 if( edge
->o0
== -1 )
1102 /* No subregions (default case), just use triangle created by
1104 player_walkgrid_stand_tri( corners
[edge
->i0
]->pos
,
1111 * Test if we are in the first region, which is
1112 * edge.i0, edge.e0, edge.o0,
1115 v3_sub( p0
, corners
[edge
->o0
]->pos
, ref
);
1116 v3_sub( world
, corners
[edge
->o0
]->pos
, v0
);
1118 vg_line( corners
[edge
->o0
]->pos
, p0
, 0xffffff00 );
1119 vg_line( corners
[edge
->o0
]->pos
, world
, 0xff000000 );
1121 if( ref
[0]*v0
[2] - ref
[2]*v0
[0] < 0.0f
)
1123 player_walkgrid_stand_tri( corners
[edge
->i0
]->pos
,
1125 corners
[edge
->o0
]->pos
, world
);
1129 if( edge
->o1
== -1 )
1132 * No other edges mean we just need to use the opposite
1134 * e0, e1, o0 (in our case, also i1)
1136 player_walkgrid_stand_tri( p0
,
1138 corners
[edge
->o0
]->pos
, world
);
1143 * Note: this v0 calculation can be ommited with the
1146 * the last two triangles we have are:
1151 v3_sub( p1
, corners
[edge
->o1
]->pos
, ref
);
1152 v3_sub( world
, corners
[edge
->o1
]->pos
, v0
);
1153 vg_line( corners
[edge
->o1
]->pos
, p1
, 0xff00ffff );
1155 if( ref
[0]*v0
[2] - ref
[2]*v0
[0] < 0.0f
)
1157 player_walkgrid_stand_tri( p0
,
1159 corners
[edge
->o1
]->pos
,
1164 player_walkgrid_stand_tri( p1
,
1165 corners
[edge
->i1
]->pos
,
1166 corners
[edge
->o1
]->pos
,
1176 v3_copy( world
, player
.co
);
1179 static void player_walkgrid_getsurface(void)
1181 float const k_stepheight
= 0.5f
;
1182 float const k_miny
= 0.6f
;
1183 float const k_height
= 1.78f
;
1184 float const k_region_size
= (float)WALKGRID_SIZE
/2.0f
* k_gridscale
;
1189 v3_copy( player
.co
, cell
);
1190 player_walkgrid_floor( cell
);
1192 v3_muladds( cell
, (v3f
){-1.0f
,-1.0f
,-1.0f
}, k_region_size
, wg
.region
[0] );
1193 v3_muladds( cell
, (v3f
){ 1.0f
, 1.0f
, 1.0f
}, k_region_size
, wg
.region
[1] );
1195 int tri_count
= bvh_select_triangles( &world
.geo
, wg
.region
, wg
.geo
, 256 );
1198 for( int i
=0; i
<tri_count
; i
++ )
1200 for( int j
=0; j
<3; j
++ )
1201 v3_copy( world
.geo
.verts
[ world
.geo
.indices
[wg
.geo
[i
]+j
]].co
, tri
[j
] );
1203 vg_line( tri
[0], tri
[1], 0xffa2ff30 );
1204 vg_line( tri
[1], tri
[2], 0xffa2ff30 );
1205 vg_line( tri
[2], tri
[0], 0xffa2ff30 );
1208 /* Get surface samples
1210 * TODO: Replace this with a spiral starting from the player position
1212 for( int y
=0; y
<WALKGRID_SIZE
; y
++ )
1214 for( int x
=0; x
<WALKGRID_SIZE
; x
++ )
1216 struct grid_sample
*s
= &wg
.samples
[y
][x
];
1217 v3_muladds( wg
.region
[0], (v3f
){ x
, 0, y
}, k_gridscale
, s
->pos
);
1218 s
->pos
[1] = player
.co
[1] + k_height
;
1220 s
->valid
= player_walkgrid_samplepole( wg
.geo
,tri_count
,s
->pos
)? 1: 0;
1225 * Calculate h+v clipping distances.
1226 * Distances are stored in A always, so you know that if the sample is
1227 * invalid, this signifies the start of the manifold as opposed to the
1228 * extent or bounds of it.
1230 for( int i
=0; i
<2; i
++ )
1232 for( int x
=0; x
<WALKGRID_SIZE
; x
++ )
1234 for( int z
=0; z
<WALKGRID_SIZE
-1; z
++ )
1236 v3f clipdir
= { 0.0f
, 0.0f
, 0.0f
};
1238 struct grid_sample
*sa
, *sb
;
1241 sa
= &wg
.samples
[z
][x
];
1242 sb
= &wg
.samples
[z
+1][x
];
1246 sa
= &wg
.samples
[x
][z
];
1247 sb
= &wg
.samples
[x
][z
+1];
1250 if( sa
->valid
!= sb
->valid
)
1252 clipdir
[i
*2] = (float)(sa
->valid
- sb
->valid
) * k_gridscale
;
1253 player_walkgrid_clip( wg
.geo
, tri_count
,
1254 sa
->valid
? sa
->pos
: sb
->pos
,
1255 clipdir
, sa
->clip
[i
] );
1261 vg_line( sa
->pos
, sb
->pos
, 0xffffffff );
1268 /* Draw connections */
1269 struct grid_sample
*corners
[4];
1270 for( int x
=0; x
<WALKGRID_SIZE
-1; x
++ )
1272 for( int z
=0; z
<WALKGRID_SIZE
-1; z
++ )
1274 const struct conf
*conf
=
1275 player_walkgrid_conf( &wg
, (v2i
){x
,z
}, corners
);
1277 for( int i
=0; i
<conf
->edge_count
; i
++ )
1279 const struct confedge
*edge
= &conf
->edges
[i
];
1282 v3_muladds( corners
[edge
->i0
]->pos
,
1283 corners
[edge
->d0
]->clip
[edge
->a0
], k_gridscale
, p0
);
1284 v3_muladds( corners
[edge
->i1
]->pos
,
1285 corners
[edge
->d1
]->clip
[edge
->a1
], k_gridscale
, p1
);
1286 vg_line( p0
, p1
, 0xff0000ff );
1288 vg_line( corners
[edge
->i0
]->pos
, p0
, 0xffffffff );
1289 vg_line( corners
[edge
->i1
]->pos
, p1
, 0xffffffff );
1295 * Commit player movement into the grid
1298 v3f delta
= {0.0f
,0.0f
,0.0f
};
1299 v3f fwd
= { -sinf(-player
.angles
[0]), 0.0f
, -cosf(-player
.angles
[0]) },
1300 side
= { -fwd
[2], 0.0f
, fwd
[0] };
1303 if( !vg_console_enabled() )
1305 if( glfwGetKey( vg_window
, GLFW_KEY_W
) )
1306 v3_muladds( delta
, fwd
, ktimestep
*k_walkspeed
, delta
);
1307 if( glfwGetKey( vg_window
, GLFW_KEY_S
) )
1308 v3_muladds( delta
, fwd
, -ktimestep
*k_walkspeed
, delta
);
1310 if( glfwGetKey( vg_window
, GLFW_KEY_A
) )
1311 v3_muladds( delta
, side
, -ktimestep
*k_walkspeed
, delta
);
1312 if( glfwGetKey( vg_window
, GLFW_KEY_D
) )
1313 v3_muladds( delta
, side
, ktimestep
*k_walkspeed
, delta
);
1316 if( v3_length2(delta
) <= 0.00001f
)
1320 * Create our move in grid space
1322 wg
.dir
[0] = delta
[0] * (1.0f
/k_gridscale
);
1323 wg
.dir
[1] = delta
[2] * (1.0f
/k_gridscale
);
1328 (player
.co
[0] - wg
.region
[0][0]) * (1.0f
/k_gridscale
),
1329 (player
.co
[2] - wg
.region
[0][2]) * (1.0f
/k_gridscale
)
1331 v2f region_cell_pos
;
1332 v2_floor( region_pos
, region_cell_pos
);
1333 v2_sub( region_pos
, region_cell_pos
, wg
.pos
);
1335 wg
.cell_id
[0] = region_cell_pos
[0];
1336 wg
.cell_id
[1] = region_cell_pos
[1];
1339 for(; i
<8 && wg
.move
> 0.001f
; i
++ )
1340 player_walkgrid_iter( &wg
, i
);
1342 player_walkgrid_stand_cell( &wg
);
1345 static void player_walkgrid(void)
1347 player_walkgrid_getsurface();
1349 m4x3_mulv( player
.to_world
, (v3f
){0.0f
,1.8f
,0.0f
}, player
.camera_pos
);
1351 player_transform_update();
1354 static void player_animate(void)
1356 /* Camera position */
1357 v3_sub( player
.v
, player
.v_last
, player
.a
);
1358 v3_copy( player
.v
, player
.v_last
);
1360 v3_add( player
.m
, player
.a
, player
.m
);
1361 v3_lerp( player
.m
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, player
.m
);
1364 player
.m
[0] = vg_clampf( player
.m
[0], -2.0f
, 2.0f
);
1365 player
.m
[1] = vg_clampf( player
.m
[1], -0.2f
, 5.0f
);
1366 player
.m
[2] = vg_clampf( player
.m
[2], -2.0f
, 2.0f
);
1367 v3_copy( player
.m
, target
);
1368 v3_lerp( player
.bob
, target
, 0.2f
, player
.bob
);
1371 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
1373 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
1374 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
1376 float kheight
= 2.0f
,
1381 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
1385 m3x3_mulv( player
.to_local
, player
.bob
, offset
);
1387 offset
[0] *= 0.3333f
;
1388 offset
[1] *= -0.25f
;
1390 v3_muladds( head
, offset
, 0.7f
, head
);
1391 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
1396 v3_copy( head
, player
.view
);
1397 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
1398 v3_add( player
.view
, camoffs
, player
.view
);
1403 * Animation blending
1404 * ===========================================
1407 static float fslide
= 0.0f
;
1408 static float fdirz
= 0.0f
;
1409 static float fdirx
= 0.0f
;
1410 static float fstand
= 0.0f
;
1411 static float ffly
= 0.0f
;
1413 float speed
= v3_length( player
.v
);
1415 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
1416 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
1418 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
1419 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
1420 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
1422 character_pose_reset( &player
.mdl
);
1424 float amt_air
= ffly
*ffly
,
1425 amt_ground
= 1.0f
-amt_air
,
1426 amt_std
= (1.0f
-fslide
) * amt_ground
,
1427 amt_stand
= amt_std
* fstand
,
1428 amt_aero
= amt_std
* (1.0f
-fstand
),
1429 amt_slide
= amt_ground
* fslide
;
1431 character_final_pose( &player
.mdl
, offset
, &pose_stand
, amt_stand
);
1432 character_final_pose( &player
.mdl
, offset
, &pose_aero
, amt_aero
*fdirz
);
1433 character_final_pose( &player
.mdl
, offset
,
1434 &pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
1435 character_final_pose( &player
.mdl
, offset
, &pose_slide
, amt_slide
*fdirx
);
1436 character_final_pose( &player
.mdl
, offset
,
1437 &pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
1439 character_final_pose( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
1440 &pose_fly
, amt_air
);
1442 /* Camera position */
1443 v3_lerp( player
.smooth_localcam
, player
.mdl
.cam_pos
, 0.08f
,
1444 player
.smooth_localcam
);
1445 v3_muladds( player
.smooth_localcam
, offset
, 0.7f
, player
.camera_pos
);
1446 player
.camera_pos
[1] = vg_clampf( player
.camera_pos
[1], 0.3f
, kheight
);
1447 m4x3_mulv( player
.to_world
, player
.camera_pos
, player
.camera_pos
);
1451 * ==========================
1453 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
1454 *arm_r
= &player
.mdl
.ik_arm_r
;
1457 m3x3_mulv( player
.to_local
, player
.v
, localv
);
1458 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
1459 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
1461 /* New board transformation */
1462 v4f board_rotation
; v3f board_location
;
1465 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
1466 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
1467 q_mul( rx
, rz
, board_rotation
);
1469 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
1470 q_m3x3( board_rotation
, mboard
);
1471 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
1472 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
1473 v3_copy( board_location
, mboard
[3] );
1476 float wheel_r
= offset
[0]*-0.4f
;
1478 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
1480 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
1482 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
1483 player
.mdl
.matrices
[k_chpart_wf
] );
1484 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
1485 player
.mdl
.matrices
[k_chpart_wb
][3] );
1486 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
1487 player
.mdl
.matrices
[k_chpart_wf
][3] );
1489 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
1490 player
.mdl
.matrices
[k_chpart_wb
] );
1491 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
1492 player
.mdl
.matrices
[k_chpart_wf
] );
1494 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
1495 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
1498 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
1499 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
1501 if( 1||player
.in_air
)
1503 float tuck
= player
.board_xy
[1],
1504 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
1506 float crouch
= player
.grab
*0.3f
;
1507 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
1508 crouch
, player
.mdl
.ik_body
.base
);
1509 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
1510 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
1514 //foot_l *= 1.0f-tuck_amt*1.5f;
1516 if( player
.grab
> 0.1f
)
1518 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
1519 player
.handl_target
);
1524 //foot_r *= 1.0f-tuck_amt*1.4f;
1526 if( player
.grab
> 0.1f
)
1528 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
1529 player
.handr_target
);
1534 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
1535 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
1537 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
1538 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
1542 static float rhead
= 0.0f
;
1543 rhead
= vg_lerpf( rhead
,
1544 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
1545 player
.mdl
.rhead
= rhead
;
1548 static void player_update(void)
1550 if( vg_get_axis("grabl")>0.0f
)
1551 reset_player(0,NULL
);
1559 if( player
.is_dead
)
1561 character_ragdoll_iter( &player
.mdl
);
1562 character_debug_ragdoll( &player
.mdl
);
1566 if( player
.on_board
)
1578 /* Update camera matrices */
1579 m4x3_identity( player
.camera
);
1580 m4x3_rotate_y( player
.camera
, -player
.angles
[0] );
1581 m4x3_rotate_x( player
.camera
, -0.33f
-player
.angles
[1] );
1582 v3_copy( player
.camera_pos
, player
.camera
[3] );
1583 m4x3_invert_affine( player
.camera
, player
.camera_inverse
);
1586 static void draw_player(void)
1589 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
1591 if( player
.is_dead
)
1592 character_mimic_ragdoll( &player
.mdl
);
1594 character_eval( &player
.mdl
);
1596 character_draw( &player
.mdl
, (player
.is_dead
|player
.in_air
)? 0.0f
: 1.0f
);
1599 #endif /* PLAYER_H */