cleanup+walgrid init
[carveJwlIkooP6JGAAIwe30JlM.git] / player.h
1 #ifndef PLAYER_H
2 #define PLAYER_H
3
4 #include "common.h"
5 #include "character.h"
6
7 static int freecam = 0;
8
9 static struct gplayer
10 {
11 /* Physics */
12 v3f co, v, a, v_last, m, bob;
13 v4f rot;
14 float vswitch, slip, slip_last,
15 reverse;
16
17 float iY; /* Yaw inertia */
18 int in_air, is_dead, on_board;
19
20 /* Input */
21 v2f joy_l;
22
23 v2f board_xy;
24 float grab;
25 float pitch;
26
27 v3f land_target;
28 v3f land_target_log[22];
29 u32 land_target_colours[22];
30 int land_log_count;
31 m3x3f vr;
32
33 m4x3f to_world, to_local;
34
35 struct character mdl;
36
37 v3f handl_target, handr_target,
38 handl, handr;
39
40 /* Camera */
41 float air_blend;
42
43 v3f camera_pos, smooth_localcam;
44 v2f angles;
45 m4x3f camera, camera_inverse;
46 }
47 player;
48
49 static void player_transform_update(void)
50 {
51 q_normalize( player.rot );
52 q_m3x3( player.rot, player.to_world );
53 v3_copy( player.co, player.to_world[3] );
54
55 m4x3_invert_affine( player.to_world, player.to_local );
56 }
57
58 static int reset_player( int argc, char const *argv[] )
59 {
60 v3_zero( player.co );
61
62 if( argc == 1 )
63 {
64 if( !strcmp( argv[0], "tutorial" ))
65 v3_copy( world.tutorial, player.co );
66 }
67
68 v3_copy( (v3f){ 0.0f, 0.0f, -0.2f }, player.v );
69 q_identity( player.rot );
70 player.vswitch = 1.0f;
71 player.slip_last = 0.0f;
72 player.is_dead = 0;
73 player.in_air = 1;
74 m3x3_identity( player.vr );
75
76 player.mdl.shoes[0] = 1;
77 player.mdl.shoes[1] = 1;
78
79 player_transform_update();
80 return 0;
81 }
82
83 static void player_mouseview(void)
84 {
85 static v2f mouse_last,
86 view_vel = { 0.0f, 0.0f };
87
88 if( vg_get_button_down( "primary" ) )
89 v2_copy( vg_mouse, mouse_last );
90 else if( vg_get_button( "primary" ) )
91 {
92 v2f delta;
93 v2_sub( vg_mouse, mouse_last, delta );
94 v2_copy( vg_mouse, mouse_last );
95
96 v2_muladds( view_vel, delta, 0.005f, view_vel );
97 }
98
99 v2_muls( view_vel, 0.7f, view_vel );
100 v2_add( view_vel, player.angles, player.angles );
101 player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
102
103 }
104
105 static void player_freecam(void)
106 {
107 player_mouseview();
108
109 float movespeed = 25.0f;
110 v3f lookdir = { 0.0f, 0.0f, -1.0f },
111 sidedir = { 1.0f, 0.0f, 0.0f };
112
113 m3x3_mulv( player.camera, lookdir, lookdir );
114 m3x3_mulv( player.camera, sidedir, sidedir );
115
116 static v3f move_vel = { 0.0f, 0.0f, 0.0f };
117 if( vg_get_button( "forward" ) )
118 v3_muladds( move_vel, lookdir, ktimestep * movespeed, move_vel );
119 if( vg_get_button( "back" ) )
120 v3_muladds( move_vel, lookdir, ktimestep *-movespeed, move_vel );
121 if( vg_get_button( "left" ) )
122 v3_muladds( move_vel, sidedir, ktimestep *-movespeed, move_vel );
123 if( vg_get_button( "right" ) )
124 v3_muladds( move_vel, sidedir, ktimestep * movespeed, move_vel );
125
126 v3_muls( move_vel, 0.7f, move_vel );
127 v3_add( move_vel, player.camera_pos, player.camera_pos );
128 }
129
130 static void apply_gravity( v3f vel, float const timestep )
131 {
132 v3f gravity = { 0.0f, -9.6f, 0.0f };
133 v3_muladds( vel, gravity, timestep, vel );
134 }
135
136 static void player_start_air(void)
137 {
138 player.in_air = 1;
139
140 float pstep = ktimestep*10.0f;
141
142 float best_velocity_mod = 0.0f,
143 best_velocity_delta = -9999.9f;
144
145 v3f axis, vup;
146 m3x3_mulv( player.to_world, (v3f){0.0f,1.0f,0.0f}, vup );
147 v3_cross( vup, player.v, axis );
148 v3_normalize( axis );
149 player.land_log_count = 0;
150
151 m3x3_identity( player.vr );
152
153 for( int m=-3;m<=12; m++ )
154 {
155 float vmod = ((float)m / 15.0f)*0.09f;
156
157 v3f pco, pco1, pv;
158 v3_copy( player.co, pco );
159 v3_copy( player.v, pv );
160
161 /*
162 * Try different 'rotations' of the velocity to find the best possible
163 * landing normal. This conserves magnitude at the expense of slightly
164 * unrealistic results
165 */
166
167 m3x3f vr;
168 v4f vr_q;
169
170 q_axis_angle( vr_q, axis, vmod );
171 q_m3x3( vr_q, vr );
172
173 m3x3_mulv( vr, pv, pv );
174 v3_muladds( pco, pv, ktimestep, pco );
175
176 for( int i=0; i<50; i++ )
177 {
178 v3_copy( pco, pco1 );
179 apply_gravity( pv, pstep );
180
181 m3x3_mulv( vr, pv, pv );
182 v3_muladds( pco, pv, pstep, pco );
183
184 ray_hit contact;
185 v3f vdir;
186
187 v3_sub( pco, pco1, vdir );
188 contact.dist = v3_length( vdir );
189 v3_divs( vdir, contact.dist, vdir);
190
191 if( ray_world( pco1, vdir, &contact ))
192 {
193 float land_delta = v3_dot( pv, contact.normal );
194 u32 scolour = (u8)(vg_minf(-land_delta * 2.0f, 255.0f));
195
196 /* Bias prediction towords ramps */
197 if( ray_hit_is_ramp( &contact ) )
198 {
199 land_delta *= 0.1f;
200 scolour |= 0x0000a000;
201 }
202
203 if( (land_delta < 0.0f) && (land_delta > best_velocity_delta) )
204 {
205 best_velocity_delta = land_delta;
206 best_velocity_mod = vmod;
207
208 v3_copy( contact.pos, player.land_target );
209
210 q_axis_angle( vr_q, axis, vmod*0.1f );
211 q_m3x3( vr_q, player.vr );
212 }
213
214 v3_copy( contact.pos,
215 player.land_target_log[player.land_log_count] );
216 player.land_target_colours[player.land_log_count] =
217 0xff000000 | scolour;
218
219 player.land_log_count ++;
220
221 break;
222 }
223 }
224 }
225
226 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
227
228 return;
229 v3_muls( player.v, best_velocity_mod, player.v );
230 }
231
232 static int sample_if_resistant( v3f pos )
233 {
234 v3f ground;
235 v3_copy( pos, ground );
236 ground[1] += 4.0f;
237
238 ray_hit hit;
239 hit.dist = INFINITY;
240
241 if( ray_world( ground, (v3f){0.0f,-1.0f,0.0f}, &hit ))
242 {
243 v3f angle;
244 v3_copy( player.v, angle );
245 v3_normalize( angle );
246 float resistance = v3_dot( hit.normal, angle );
247
248 if( resistance < 0.25f )
249 {
250 v3_copy( hit.pos, pos );
251 return 1;
252 }
253 }
254
255 return 0;
256 }
257
258 static float stable_force( float current, float diff )
259 {
260 float new = current + diff;
261
262 if( new * current < 0.0f )
263 return 0.0f;
264
265 return new;
266 }
267
268 static void player_physics_ground(void)
269 {
270 /*
271 * Getting surface collision points,
272 * the contact manifold is a triangle for simplicity.
273 */
274 v3f contact_front, contact_back, contact_norm, vup, vside,
275 axis;
276
277 float klength = 0.65f;
278 m4x3_mulv( player.to_world, (v3f){ 0.15f,0.0f,-klength}, contact_norm );
279 m4x3_mulv( player.to_world, (v3f){-0.15f,0.0f,-klength}, contact_front );
280 m4x3_mulv( player.to_world, (v3f){ 0.00f,0.0f, klength}, contact_back );
281 m3x3_mulv( player.to_world, (v3f){ 0.0f, 1.0f, 0.0f}, vup );
282 m3x3_mulv( player.to_world, (v3f){ 1.0f, 0.0f, 0.0f}, vside );
283
284 v3f cn0, cn1, cn2;
285
286 int contact_count =
287 sample_if_resistant( contact_front ) +
288 sample_if_resistant( contact_back ) +
289 sample_if_resistant( contact_norm );
290
291 if( contact_count < 3 )
292 {
293 player_start_air();
294 return;
295 }
296
297 v3f norm;
298 v3f v0, v1;
299 v3_sub( contact_norm, contact_front, v0 );
300 v3_sub( contact_back, contact_front, v1 );
301 v3_cross( v1, v0, norm );
302 v3_normalize( norm );
303
304 vg_line( contact_norm, contact_front, 0xff00ff00 );
305 vg_line( contact_back, contact_front, 0xff0000ff );
306
307 /* Surface alignment */
308 float angle = v3_dot( vup, norm );
309 v3_cross( vup, norm, axis );
310
311 if( angle < 0.999f )
312 {
313 v4f correction;
314 q_axis_angle( correction, axis, acosf(angle) );
315 q_mul( correction, player.rot, player.rot );
316 }
317
318 float resistance = v3_dot( norm, player.v );
319 if( resistance >= 0.0f )
320 {
321 player_start_air();
322 return;
323 }
324 else
325 {
326 v3_muladds( player.v, norm, -resistance, player.v );
327 }
328
329 /* This is where velocity integration used to be */
330
331 float slip = 0.0f;
332
333 player.co[1] = (contact_front[1]+contact_back[1])*0.5f;
334
335 v3f vel;
336 m3x3_mulv( player.to_local, player.v, vel );
337
338 /* Calculate local forces */
339
340 if( fabsf(vel[2]) > 0.01f )
341 slip = fabsf(-vel[0] / vel[2]) * vg_signf(vel[0]);
342
343 if( fabsf( slip ) > 1.2f )
344 slip = vg_signf( slip ) * 1.2f;
345 player.slip = slip;
346 player.reverse = -vg_signf(vel[2]);
347
348 float substep = ktimestep * 0.2f;
349 float fwd_resistance = (vg_get_button( "break" )? 5.0f: 0.02f) * -substep;
350
351 for( int i=0; i<5; i++ )
352 {
353 vel[2] = stable_force( vel[2], vg_signf( vel[2] ) * fwd_resistance );
354 vel[0] = stable_force( vel[0], vg_signf( vel[0] ) * -7.0f *substep );
355 }
356
357 static double start_push = 0.0;
358 if( vg_get_button_down( "push" ) )
359 start_push = vg_time;
360
361 if( !vg_get_button("break") && vg_get_button( "push" ) )
362 {
363 float const k_maxpush = 16.0f,
364 k_pushaccel = 5.0f;
365
366 float cycle_time = vg_time-start_push,
367 amt = k_pushaccel * (sinf( cycle_time * 8.0f )*0.5f+0.5f)*ktimestep,
368 current = v3_length( vel ),
369 new_vel = vg_minf( current + amt, k_maxpush );
370 new_vel -= vg_minf(current, k_maxpush);
371 vel[2] -= new_vel * player.reverse;
372 }
373
374 m3x3_mulv( player.to_world, vel, player.v );
375
376 if( vg_get_button( "yawl" ) )
377 player.iY += 3.6f * ktimestep;
378 if( vg_get_button( "yawr" ) )
379 player.iY -= 3.6f * ktimestep;
380
381 float steer = vg_get_axis( "horizontal" );
382 player.iY -= vg_signf(steer)*powf(steer,2.0f) * 1.5f * ktimestep;
383
384 /* Too much lean and it starts to look like a snowboard here */
385 v2_lerp( player.board_xy, (v2f){ slip*0.25f, 0.0f },
386 ktimestep*5.0f, player.board_xy);
387 }
388
389 static void draw_cross(v3f pos,u32 colour, float scale)
390 {
391 v3f p0, p1;
392 v3_add( (v3f){ scale,0.0f,0.0f}, pos, p0 );
393 v3_add( (v3f){-scale,0.0f,0.0f}, pos, p1 );
394 vg_line( p0, p1, colour );
395 v3_add( (v3f){0.0f, scale,0.0f}, pos, p0 );
396 v3_add( (v3f){0.0f,-scale,0.0f}, pos, p1 );
397 vg_line( p0, p1, colour );
398 v3_add( (v3f){0.0f,0.0f, scale}, pos, p0 );
399 v3_add( (v3f){0.0f,0.0f,-scale}, pos, p1 );
400 vg_line( p0, p1, colour );
401 }
402
403 static void player_physics_air(void)
404 {
405 m3x3_mulv( player.vr, player.v, player.v );
406 for( int i=0; i<player.land_log_count; i++ )
407 draw_cross( player.land_target_log[i], player.land_target_colours[i], 1);
408
409 draw_cross( player.land_target, 0xff0000ff, 1 );
410
411 v3f ground_pos;
412 v3_copy( player.co, ground_pos );
413 ground_pos[1] += 4.0f;
414
415 ray_hit hit;
416 hit.dist = INFINITY;
417 if( ray_world( ground_pos, (v3f){0.0f,-1.0f,0.0f}, &hit ))
418 {
419 if( hit.pos[1] > player.co[1] )
420 {
421 player.in_air = 0;
422
423 if( !ray_hit_is_ramp( &hit ) )
424 {
425 player.is_dead = 1;
426 character_ragdoll_copypose( &player.mdl, player.v );
427 }
428
429 return;
430 }
431 }
432
433 /* Prediction
434 *
435 * TODO: Find best landing surface and guide player towords it
436 */
437 float pstep = ktimestep*10.0f;
438
439 v3f pco, pco1, pv;
440 v3_copy( player.co, pco );
441 v3_copy( player.v, pv );
442
443 float time_to_impact = 0.0f;
444 float limiter = 1.0f;
445
446 for( int i=0; i<50; i++ )
447 {
448 v3_copy( pco, pco1 );
449 apply_gravity( pv, pstep );
450 v3_muladds( pco, pv, pstep, pco );
451
452 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
453
454 ray_hit contact;
455 v3f vdir;
456
457 v3_sub( pco, pco1, vdir );
458 contact.dist = v3_length( vdir );
459 v3_divs( vdir, contact.dist, vdir);
460
461 float orig_dist = contact.dist;
462 if( ray_world( pco1, vdir, &contact ))
463 {
464 v3f localup;
465 m3x3_mulv( player.to_world, (v3f){0.0f,1.0f,0.0f}, localup );
466
467 float angle = v3_dot( localup, contact.normal );
468 v3f axis;
469 v3_cross( localup, contact.normal, axis );
470
471 time_to_impact += (contact.dist/orig_dist)*pstep;
472 limiter = vg_minf( 5.0f, time_to_impact )/5.0f;
473 limiter = 1.0f-limiter;
474 limiter *= limiter;
475 limiter = 1.0f-limiter;
476
477 if( angle < 0.99f )
478 {
479 v4f correction;
480 q_axis_angle( correction, axis, acosf(angle)*0.05f*(1.0f-limiter) );
481 q_mul( correction, player.rot, player.rot );
482 }
483
484 draw_cross( contact.pos, 0xffff0000, 1 );
485 break;
486 }
487 time_to_impact += pstep;
488 }
489
490 player.iY -= vg_get_axis( "horizontal" ) * 3.6f * ktimestep;
491 {
492
493 float iX = vg_get_axis( "vertical" ) * 3.6f * limiter * ktimestep;
494 static float siX = 0.0f;
495 siX = vg_lerpf( siX, iX, 0.3f );
496
497 v4f rotate;
498 v3f vside;
499
500 m3x3_mulv( player.to_world, (v3f){1.0f,0.0f,0.0f}, vside );
501
502 q_axis_angle( rotate, vside, siX );
503 q_mul( rotate, player.rot, player.rot );
504 }
505
506 v2f target = {0.0f,0.0f};
507 v2_muladds( target, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") },
508 player.grab, target );
509 v2_lerp( player.board_xy, target, ktimestep*3.0f, player.board_xy );
510 }
511
512 static void player_do_motion(void)
513 {
514 float horizontal = vg_get_axis("horizontal"),
515 vertical = vg_get_axis("vertical");
516
517 player.joy_l[0] = vg_signf(horizontal) * powf( horizontal, 2.0f );
518 player.joy_l[1] = vg_signf(vertical) * powf( vertical, 2.0f );
519
520 if( player.in_air )
521 player_physics_air();
522
523 if( !player.in_air )
524 player_physics_ground();
525
526 /* Integrate velocity */
527 v3f prevco;
528 v3_copy( player.co, prevco );
529
530 apply_gravity( player.v, ktimestep );
531 v3_muladds( player.co, player.v, ktimestep, player.co );
532
533 /* Integrate inertia */
534 v4f rotate; v3f vup = {0.0f,1.0f,0.0f};
535 m3x3_mulv( player.to_world, vup, vup );
536
537 static float siY = 0.0f;
538
539 float lerpq = player.in_air? 0.04f: 0.3f;
540 siY = vg_lerpf( siY, player.iY, lerpq );
541
542 q_axis_angle( rotate, vup, siY );
543 q_mul( rotate, player.rot, player.rot );
544
545 player.iY = 0.0f; /* temp */
546
547 #if 0
548 /* GATE COLLISION */
549 if( gate_intersect( &gate_a, player.co, prevco ) )
550 {
551 teleport_gate *gate = &gate_a;
552
553 m4x3f transport;
554 m4x3_mul( gate->other->to_world, gate->to_local, transport );
555 m4x3_mulv( transport, player.co, player.co );
556 m3x3_mulv( transport, player.v, player.v );
557 m3x3_mulv( transport, player.v_last, player.v_last );
558 m3x3_mulv( transport, player.m, player.m );
559 m3x3_mulv( transport, player.bob, player.bob );
560
561 v4f transport_rotation;
562 m3x3_q( transport, transport_rotation );
563 q_mul( transport_rotation, player.rot, player.rot );
564 }
565 #endif
566
567 /* Camera and character */
568 player_transform_update();
569
570 player.angles[0] = atan2f( player.v[0], -player.v[2] );
571 player.angles[1] = atan2f( -player.v[1], sqrtf(player.v[0]*player.v[0]+
572 player.v[2]*player.v[2]) ) * 0.3f;
573
574 player.air_blend = vg_lerpf( player.air_blend, player.in_air, 0.04f );
575 v3_muladds( player.camera_pos, player.v, -0.05f*player.air_blend,
576 player.camera_pos );
577 }
578
579 static void player_walkgrid(void)
580 {
581 float const k_gridscale = 0.5f;
582 float const k_stepheight = 0.5f;
583 float const k_walkspeed = 6.0f;
584 float const k_miny = 0.6f;
585 float const k_height = 1.78f;
586 int const k_gridamt = 8;
587
588 v3f cell;
589 v3_muls( player.co, 1.0f/k_gridscale, cell );
590 v3_floor( cell, cell );
591 v3_muls( cell, k_gridscale, cell );
592
593 struct grid_sample
594 {
595 ray_hit hit;
596 int valid;
597 }
598 samples[ k_gridamt ][ k_gridamt ];
599
600 v3f grid_origin;
601 v3_muladds( cell, (v3f){ -1.0f,0.0f,-1.0f },
602 (float)(k_gridamt/2) * k_gridscale, grid_origin );
603
604 /*
605 * Get sample 'poles'
606 */
607 for( int y=0; y<k_gridamt; y++ )
608 {
609 for( int x=0; x<k_gridamt; x++ )
610 {
611 v3f sample_coord;
612 v3_muladds( grid_origin, (v3f){ x, 0, y }, k_gridscale, sample_coord );
613 sample_coord[1] += k_height;
614
615 struct grid_sample *sample = &samples[y][x];
616 sample->valid = 0;
617 sample->hit.dist = k_stepheight+k_height;
618
619 if( ray_world( sample_coord, (v3f){0.0f,-1.0f,0.0f}, &sample->hit ))
620 {
621 if( sample->hit.normal[1] >= k_miny &&
622 ray_hit_is_ramp( &sample->hit ))
623 {
624 sample->valid = 1;
625 draw_cross( sample->hit.pos, 0xff00ff00, 0.1f );
626 }
627 else
628 draw_cross( sample->hit.pos, 0xff0000ff, 0.1f );
629 }
630 }
631 }
632
633 /*
634 * Clip grid intersections with triangle edges
635 */
636 for( int x=0; x<k_gridamt; x++ )
637 {
638 for( int y=0; y<k_gridamt-1; y++ )
639 {
640 struct grid_sample *sa = &samples[y][x],
641 *sb = &samples[y+1][x];
642
643 if( (sa->valid != sb->valid) && (sa->valid||sb->valid) )
644 {
645 v3f tri[3];
646 ray_world_get_tri( sa->valid? &sa->hit: &sb->hit, tri );
647
648 v3f sample;
649 v3_muladds( grid_origin, (v3f){ x, 0, y },
650 k_gridscale, sample);
651
652 /* Clip triangles until we find an edge inside the cell */
653 int axis = 0;
654 float offset = sample[axis==0?0:2],
655 basis = sample[axis==0?2:0];
656
657 for( int i=0; i<3; i++ )
658 {
659 int ia = i,
660 ib = (i+1)%3;
661 float pa = tri[ia][axis],
662 pb = tri[ib][axis];
663
664 vg_line( tri[ia],tri[ib],0xffaaaaaa );
665
666 if( (pa-offset)*(pb-offset) > 0.0f )
667 continue;
668
669 float d = pb-pa,
670 qa = (offset-pa)/d,
671 h = qa*tri[ib][2] + (1.0f-qa)*tri[ia][2],
672 q = (h-basis)/k_gridscale;
673
674 if( q >= 0.0f && q <= 1.0f )
675 {
676 float height = qa*tri[ia][1] + (1.0f-qa)*tri[ib][1];
677
678 v3f intersection = { offset, height, h };
679 draw_cross( intersection, 0xffff0000, 0.06f );
680 break;
681 }
682 }
683 }
684 }
685 }
686
687 v3f fwd = { -sinf(-player.angles[0]), 0.0f, -cosf(-player.angles[0]) },
688 side = { -fwd[2], 0.0f, fwd[0] };
689
690 /* Temp */
691 if( glfwGetKey( vg_window, GLFW_KEY_W ) )
692 v3_muladds( player.co, fwd, ktimestep*k_walkspeed, player.co );
693 if( glfwGetKey( vg_window, GLFW_KEY_S ) )
694 v3_muladds( player.co, fwd, -ktimestep*k_walkspeed, player.co );
695
696 if( glfwGetKey( vg_window, GLFW_KEY_A ) )
697 v3_muladds( player.co, side, -ktimestep*k_walkspeed, player.co );
698 if( glfwGetKey( vg_window, GLFW_KEY_D ) )
699 v3_muladds( player.co, side, ktimestep*k_walkspeed, player.co );
700
701 m4x3_mulv( player.to_world, (v3f){0.0f,1.8f,0.0f}, player.camera_pos );
702 player_mouseview();
703 player_transform_update();
704 }
705
706 static void player_animate(void)
707 {
708 /* Camera position */
709 v3_sub( player.v, player.v_last, player.a );
710 v3_copy( player.v, player.v_last );
711
712 v3_add( player.m, player.a, player.m );
713 v3_lerp( player.m, (v3f){0.0f,0.0f,0.0f}, 0.1f, player.m );
714 v3f target;
715
716 player.m[0] = vg_clampf( player.m[0], -2.0f, 2.0f );
717 player.m[1] = vg_clampf( player.m[1], -0.2f, 5.0f );
718 player.m[2] = vg_clampf( player.m[2], -2.0f, 2.0f );
719 v3_copy( player.m, target );
720 v3_lerp( player.bob, target, 0.2f, player.bob );
721
722 /* Head */
723 float lslip = fabsf(player.slip); //vg_minf( 0.4f, slip );
724
725 float grabt = vg_get_axis( "grabr" )*0.5f+0.5f;
726 player.grab = vg_lerpf( player.grab, grabt, 0.04f );
727
728 float kheight = 2.0f,
729 kleg = 0.6f;
730
731 v3f head;
732 head[0] = 0.0f;
733 head[1] = (0.3f+cosf(lslip)*0.5f*(1.0f-player.grab*0.7f)) * kheight;
734 head[2] = 0.0f;
735
736 v3f offset;
737 m3x3_mulv( player.to_local, player.bob, offset );
738
739 offset[0] *= 0.3333f;
740 offset[1] *= -0.25f;
741 offset[2] *= 0.7f;
742 v3_muladds( head, offset, 0.7f, head );
743 head[1] = vg_clampf( head[1], 0.3f, kheight );
744
745 #if 0
746 if( !freecam )
747 {
748 v3_copy( head, player.view );
749 v3f camoffs = {-0.2f,-0.6f,0.00f};
750 v3_add( player.view, camoffs, player.view );
751 }
752 #endif
753
754 /*
755 * Animation blending
756 * ===========================================
757 */
758
759 static float fslide = 0.0f;
760 static float fdirz = 0.0f;
761 static float fdirx = 0.0f;
762 static float fstand = 0.0f;
763 static float ffly = 0.0f;
764
765 float speed = v3_length( player.v );
766
767 fstand = vg_lerpf(fstand, 1.0f-vg_clampf(speed*0.03f,0.0f,1.0f),0.1f);
768 fslide = vg_lerpf(fslide, vg_clampf(lslip+fabsf(offset[0])*0.2f,
769 0.0f,1.0f), 0.04f);
770 fdirz = vg_lerpf(fdirz, player.reverse > 0.0f? 1.0f: 0.0f, 0.04f );
771 fdirx = vg_lerpf(fdirx, player.slip < 0.0f? 1.0f: 0.0f, 0.04f );
772 ffly = vg_lerpf(ffly, player.in_air? 1.0f: 0.0f, 0.04f );
773
774 character_pose_reset( &player.mdl );
775
776 float amt_air = ffly*ffly,
777 amt_ground = 1.0f-amt_air,
778 amt_std = (1.0f-fslide) * amt_ground,
779 amt_stand = amt_std * fstand,
780 amt_aero = amt_std * (1.0f-fstand),
781 amt_slide = amt_ground * fslide;
782
783 character_final_pose( &player.mdl, offset, &pose_stand, amt_stand );
784 character_final_pose( &player.mdl, offset, &pose_aero, amt_aero*fdirz );
785 character_final_pose( &player.mdl, offset,
786 &pose_aero_reverse, amt_aero * (1.0f-fdirz) );
787 character_final_pose( &player.mdl, offset, &pose_slide, amt_slide*fdirx );
788 character_final_pose( &player.mdl, offset,
789 &pose_slide1, amt_slide*(1.0f-fdirx) );
790
791 character_final_pose( &player.mdl, (v3f){0.0f,0.0f,0.0f},
792 &pose_fly, amt_air );
793
794 /* Camera position */
795 v3_lerp( player.smooth_localcam, player.mdl.cam_pos, 0.08f,
796 player.smooth_localcam );
797 v3_muladds( player.smooth_localcam, offset, 0.7f, player.camera_pos );
798 player.camera_pos[1] = vg_clampf( player.camera_pos[1], 0.3f, kheight );
799 m4x3_mulv( player.to_world, player.camera_pos, player.camera_pos );
800
801 /*
802 * Additive effects
803 * ==========================
804 */
805 struct ik_basic *arm_l = &player.mdl.ik_arm_l,
806 *arm_r = &player.mdl.ik_arm_r;
807
808 v3f localv;
809 m3x3_mulv( player.to_local, player.v, localv );
810 v3_muladds( arm_l->end, localv, -0.01f, arm_l->end );
811 v3_muladds( arm_r->end, localv, -0.01f, arm_r->end );
812
813 /* New board transformation */
814 v4f board_rotation; v3f board_location;
815
816 v4f rz, rx;
817 q_axis_angle( rz, (v3f){ 0.0f, 0.0f, 1.0f }, player.board_xy[0] );
818 q_axis_angle( rx, (v3f){ 1.0f, 0.0f, 0.0f }, player.board_xy[1] );
819 q_mul( rx, rz, board_rotation );
820
821 v3f *mboard = player.mdl.matrices[k_chpart_board];// player.mboard;
822 q_m3x3( board_rotation, mboard );
823 m3x3_mulv( mboard, (v3f){ 0.0f, -0.5f, 0.0f }, board_location );
824 v3_add( (v3f){0.0f,0.5f,0.0f}, board_location, board_location );
825 v3_copy( board_location, mboard[3] );
826
827
828 float wheel_r = offset[0]*-0.4f;
829 v4f qwheel;
830 q_axis_angle( qwheel, (v3f){0.0f,1.0f,0.0f}, wheel_r );
831
832 q_m3x3( qwheel, player.mdl.matrices[k_chpart_wb] );
833
834 m3x3_transpose( player.mdl.matrices[k_chpart_wb],
835 player.mdl.matrices[k_chpart_wf] );
836 v3_copy( player.mdl.offsets[k_chpart_wb],
837 player.mdl.matrices[k_chpart_wb][3] );
838 v3_copy( player.mdl.offsets[k_chpart_wf],
839 player.mdl.matrices[k_chpart_wf][3] );
840
841 m4x3_mul( mboard, player.mdl.matrices[k_chpart_wb],
842 player.mdl.matrices[k_chpart_wb] );
843 m4x3_mul( mboard, player.mdl.matrices[k_chpart_wf],
844 player.mdl.matrices[k_chpart_wf] );
845
846 m4x3_mulv( mboard, player.mdl.ik_leg_l.end, player.mdl.ik_leg_l.end );
847 m4x3_mulv( mboard, player.mdl.ik_leg_r.end, player.mdl.ik_leg_r.end );
848
849
850 v3_copy( player.mdl.ik_arm_l.end, player.handl_target );
851 v3_copy( player.mdl.ik_arm_r.end, player.handr_target );
852
853 if( 1||player.in_air )
854 {
855 float tuck = player.board_xy[1],
856 tuck_amt = fabsf( tuck ) * (1.0f-fabsf(player.board_xy[0]));
857
858 float crouch = player.grab*0.3f;
859 v3_muladds( player.mdl.ik_body.base, (v3f){0.0f,-1.0f,0.0f},
860 crouch, player.mdl.ik_body.base );
861 v3_muladds( player.mdl.ik_body.end, (v3f){0.0f,-1.0f,0.0f},
862 crouch*1.2f, player.mdl.ik_body.end );
863
864 if( tuck < 0.0f )
865 {
866 //foot_l *= 1.0f-tuck_amt*1.5f;
867
868 if( player.grab > 0.1f )
869 {
870 m4x3_mulv( mboard, (v3f){0.1f,0.14f,0.6f},
871 player.handl_target );
872 }
873 }
874 else
875 {
876 //foot_r *= 1.0f-tuck_amt*1.4f;
877
878 if( player.grab > 0.1f )
879 {
880 m4x3_mulv( mboard, (v3f){0.1f,0.14f,-0.6f},
881 player.handr_target );
882 }
883 }
884 }
885
886 v3_lerp( player.handl, player.handl_target, 0.1f, player.handl );
887 v3_lerp( player.handr, player.handr_target, 0.1f, player.handr );
888
889 v3_copy( player.handl, player.mdl.ik_arm_l.end );
890 v3_copy( player.handr, player.mdl.ik_arm_r.end );
891
892 /* Head rotation */
893
894 static float rhead = 0.0f;
895 rhead = vg_lerpf( rhead,
896 vg_clampf(atan2f( localv[2], -localv[0] ),-1.0f,1.0f), 0.04f );
897 player.mdl.rhead = rhead;
898 }
899
900 static void player_update(void)
901 {
902 if( vg_get_axis("grabl")>0.0f)
903 reset_player(0,NULL);
904
905 if( freecam )
906 {
907 player_freecam();
908 }
909 else
910 {
911 if( player.is_dead )
912 {
913 character_ragdoll_iter( &player.mdl );
914 character_debug_ragdoll( &player.mdl );
915 }
916 else
917 {
918 if( player.on_board )
919 {
920 player_do_motion();
921 player_animate();
922 }
923 else
924 {
925 player_walkgrid();
926 }
927 }
928 }
929
930 /* Update camera matrices */
931 m4x3_identity( player.camera );
932 m4x3_rotate_y( player.camera, -player.angles[0] );
933 m4x3_rotate_x( player.camera, -0.33f -player.angles[1] );
934 v3_copy( player.camera_pos, player.camera[3] );
935 m4x3_invert_affine( player.camera, player.camera_inverse );
936 }
937
938 static void draw_player(void)
939 {
940 /* Draw */
941 m4x3_copy( player.to_world, player.mdl.mroot );
942
943 if( player.is_dead )
944 character_mimic_ragdoll( &player.mdl );
945 else
946 character_eval( &player.mdl );
947
948 character_draw( &player.mdl, (player.is_dead|player.in_air)? 0.0f: 1.0f );
949 }
950
951 #endif /* PLAYER_H */