cam rework
[carveJwlIkooP6JGAAIwe30JlM.git] / player_walk.c
1 #ifndef PLAYER_WALK_C
2 #define PLAYER_WALK_C
3
4 #include "player.h"
5
6 VG_STATIC void player_walk_transfer_to_skate( player_instance *player,
7 enum skate_activity init )
8 {
9 struct player_walk *w = &player->_walk;
10
11 v3f xy_speed, v;
12
13 v3_copy( player->rb.v, xy_speed );
14 xy_speed[1] = 0.0f;
15
16 if( v3_length2( xy_speed ) < 0.1f * 0.1f )
17 {
18 v[0] = -sinf( -w->state.angles[0] );
19 v[1] = 0.0f;
20 v[2] = -cosf( -w->state.angles[0] );
21 v3_muls( v, 1.6f, v );
22 }
23 else
24 v3_copy( player->rb.v, v );
25
26 player->subsystem = k_player_subsystem_skate;
27 player__skate_transition( player, v, init );
28 return;
29 }
30
31 VG_STATIC void player__walk_pre_update( player_instance *player )
32 {
33 struct player_walk *w = &player->_walk;
34 player_look( player, w->state.angles );
35
36 if( w->state.outro_anim )
37 {
38 float outro_length = (float)w->state.outro_anim->length /
39 w->state.outro_anim->rate,
40 outro_time = vg.time - w->state.outro_start_time;
41
42 if( outro_time >= outro_length )
43 {
44 w->state.outro_anim = NULL;
45 player_walk_transfer_to_skate( player, k_skate_activity_air );
46 return;
47 }
48 }
49 else if( vg_input_button_down( player->input_use ) )
50 {
51 if( w->state.activity == k_walk_activity_ground )
52 {
53 player_walk_transfer_to_skate( player, k_skate_activity_ground );
54 }
55 else
56 {
57 w->state.outro_anim = w->anim_jump_to_air;
58 w->state.outro_start_time = vg.time;
59 v3_copy( player->cam.pos, player->follow_pos );
60 v3_copy( player->cam.angles, player->follow_angles );
61 return;
62 }
63 }
64 }
65
66 VG_STATIC int player_walk_normal_standable( v3f n )
67 {
68 return n[1] > 0.70710678118f;
69 }
70
71 VG_STATIC void player_accelerate( v3f v, v3f movedir, float speed, float accel )
72 {
73 float currentspeed = v3_dot( v, movedir ),
74 addspeed = speed - currentspeed;
75
76 if( addspeed <= 0 )
77 return;
78
79 float accelspeed = accel * k_rb_delta * speed;
80
81 if( accelspeed > addspeed )
82 accelspeed = addspeed;
83
84 v3_muladds( v, movedir, accelspeed, v );
85 }
86
87 VG_STATIC void player_friction( v3f v )
88 {
89 float speed = v3_length( v ),
90 drop = 0.0f,
91 control = vg_maxf( speed, k_stopspeed );
92
93 if( speed < 0.04f )
94 return;
95
96 drop += control * k_walk_friction * k_rb_delta;
97
98 float newspeed = vg_maxf( 0.0f, speed - drop );
99 newspeed /= speed;
100
101 v3_muls( v, newspeed, v );
102 }
103
104 VG_STATIC void player__walk_update( player_instance *player )
105 {
106 struct player_walk *w = &player->_walk;
107 v3_copy( player->rb.co, w->state.prev_pos );
108
109 w->collider.height = 2.0f;
110 w->collider.radius = 0.3f;
111
112 m4x3f mtx;
113 m3x3_identity( mtx );
114 v3_add( player->rb.co, (v3f){0.0f, 1.0f, 0.0f}, mtx[3] );
115
116 debug_capsule( mtx, w->collider.radius, w->collider.height, VG__WHITE );
117
118 rb_ct manifold[64];
119 int len;
120
121 float yaw = w->state.angles[0];
122
123 v3f forward_dir = { sinf(yaw), 0.0f, -cosf(yaw) };
124 v3f right_dir = { -forward_dir[2], 0.0f, forward_dir[0] };
125
126 v2f walk = { player->input_walkh->axis.value,
127 player->input_walkv->axis.value };
128
129 if( v2_length2(walk) > 0.001f )
130 v2_normalize_clamp( walk );
131
132 w->move_speed = v2_length( walk );
133
134 /*
135 * Collision detection
136 */
137 len = rb_capsule__scene( mtx, &w->collider, NULL,
138 &world.rb_geo.inf.scene, manifold );
139 rb_manifold_filter_coplanar( manifold, len, 0.01f );
140 len = rb_manifold_apply_filtered( manifold, len );
141
142 v3f surface_avg = { 0.0f, 0.0f, 0.0f };
143 w->state.activity = k_walk_activity_air;
144
145 for( int i=0; i<len; i++ )
146 {
147 struct contact *ct = &manifold[i];
148 rb_debug_contact( ct );
149
150 if( player_walk_normal_standable( ct->n ) )
151 {
152 w->state.activity = k_walk_activity_ground;
153 v3_add( surface_avg, ct->n, surface_avg );
154 }
155
156 rb_prepare_contact( ct );
157 }
158
159 /*
160 * Move & Friction
161 */
162 float accel_speed = 0.0f, nominal_speed = 0.0f;
163 v3f movedir;
164 v3_muls( right_dir, walk[0], movedir );
165 v3_muladds( movedir, forward_dir, walk[1], movedir );
166
167 if( w->state.activity == k_walk_activity_ground )
168 {
169 v3_normalize( surface_avg );
170
171 v3f tx, ty;
172 rb_tangent_basis( surface_avg, tx, ty );
173
174 if( v2_length2(walk) > 0.001f )
175 {
176 /* clip movement to the surface */
177 float d = v3_dot(surface_avg,movedir);
178 v3_muladds( movedir, surface_avg, -d, movedir );
179 }
180
181 accel_speed = k_walk_accel;
182 nominal_speed = k_walkspeed;
183
184 /* jump */
185 if( player->input_jump->button.value )
186 {
187 player->rb.v[1] = 5.0f;
188 w->state.activity = k_walk_activity_air;
189 accel_speed = k_walk_air_accel;
190 nominal_speed = k_airspeed;
191 }
192 else
193 {
194 player_friction( player->rb.v );
195
196 struct world_material *surface_mat = world_contact_material(manifold);
197 w->surface = surface_mat->info.surface_prop;
198 }
199 }
200 else
201 {
202 accel_speed = k_walk_air_accel;
203 nominal_speed = k_airspeed;
204 }
205
206 if( v2_length2(walk) > 0.001f )
207 {
208 player_accelerate( player->rb.v, movedir, nominal_speed, accel_speed );
209 v3_normalize( movedir );
210 }
211
212 /*
213 * Resolve velocity constraints
214 */
215 for( int j=0; j<5; j++ )
216 {
217 for( int i=0; i<len; i++ )
218 {
219 struct contact *ct = &manifold[i];
220
221 /*normal */
222 float vn = -v3_dot( player->rb.v, ct->n );
223
224 float temp = ct->norm_impulse;
225 ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
226 vn = ct->norm_impulse - temp;
227
228 v3_muladds( player->rb.v, ct->n, vn, player->rb.v );
229 }
230 }
231
232 /*
233 * Depenetrate
234 */
235 v3f dt;
236 v3_zero( dt );
237 for( int j=0; j<8; j++ )
238 {
239 for( int i=0; i<len; i++ )
240 {
241 struct contact *ct = &manifold[i];
242
243 float resolved_amt = v3_dot( ct->n, dt ),
244 remaining = (ct->p-k_penetration_slop) - resolved_amt,
245 apply = vg_maxf( remaining, 0.0f ) * 0.3f;
246
247 v3_muladds( dt, ct->n, apply, dt );
248 }
249 }
250 v3_add( dt, player->rb.co, player->rb.co );
251
252 /* TODO: Stepping......
253 *
254 * ideas; walkgrid style steps
255 */
256 #if 0
257 if( w->state.activity == k_walk_activity_ground )
258 {
259 /* step */
260 float max_dist = 0.4f;
261
262 v3f pa, pb;
263 v3_copy( player->rb.co, pa );
264 pa[1] += w->collider.radius + max_dist;
265
266 v3_muladds( pa, (v3f){0.0f,1.0f,0.0f}, -max_dist * 2.0f, pb );
267 vg_line( pa, pb, 0xff000000 );
268
269 v3f n;
270 float t;
271 if( spherecast_world( pa, pb, w->collider.radius, &t, n ) != -1 )
272 {
273 if( player_walk_normal_standable( n ) )
274 {
275 v3_lerp( pa, pb, t, player->rb.co );
276 player->rb.co[1] -= w->collider.radius;
277 }
278 }
279 }
280 #endif
281
282
283 /* integrate */
284 if( w->state.activity == k_walk_activity_air )
285 player->rb.v[1] += -k_gravity * k_rb_delta;
286
287 v3_muladds( player->rb.co, player->rb.v, k_rb_delta, player->rb.co );
288
289
290 v3_add( player->rb.co, (v3f){0.0f, 1.0f, 0.0f}, mtx[3] );
291 debug_capsule( mtx, w->collider.radius, w->collider.height, VG__GREEN );
292
293 /*
294 * CCD routine
295 * ---------------------------------------------------
296 *
297 */
298 v3f lwr_prev,
299 lwr_now,
300 lwr_offs = { 0.0f, w->collider.radius, 0.0f };
301
302 v3_add( lwr_offs, w->state.prev_pos, lwr_prev );
303 v3_add( lwr_offs, player->rb.co, lwr_now );
304
305 v3f movedelta;
306 v3_sub( player->rb.co, w->state.prev_pos, movedelta );
307
308 float movedist = v3_length( movedelta );
309
310 if( movedist > 0.3f )
311 {
312 float t, sr = w->collider.radius-0.04f;
313 v3f n;
314
315 if( spherecast_world( lwr_prev, lwr_now, sr, &t, n ) != -1 )
316 {
317 v3_lerp( lwr_prev, lwr_now, vg_maxf(0.01f,t), player->rb.co );
318 player->rb.co[1] -= w->collider.radius;
319 rb_update_transform( &player->rb );
320
321 v3_add( player->rb.co, (v3f){0.0f, 1.0f, 0.0f}, mtx[3] );
322 debug_capsule( mtx, w->collider.radius, w->collider.height, VG__RED );
323 }
324 }
325
326 teleport_gate *gate;
327 if( (gate = world_intersect_gates( player->rb.co, w->state.prev_pos )) )
328 {
329 m4x3_mulv( gate->transport, player->rb.co, player->rb.co );
330 m3x3_mulv( gate->transport, player->rb.v, player->rb.v );
331 rb_update_transform( &player->rb );
332
333 /* analytical rotation of yaw */
334 v3f fwd_dir = { cosf(w->state.angles[0]),
335 0.0f,
336 sinf(w->state.angles[0])};
337 m3x3_mulv( gate->transport, fwd_dir, fwd_dir );
338 w->state.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] );
339
340 w->state_gate_storage = w->state;
341 player__pass_gate( player, gate );
342 }
343 }
344
345 VG_STATIC void player__walk_post_update( player_instance *player )
346 {
347 struct player_walk *w = &player->_walk;
348
349 m4x3f mtx;
350 m3x3_identity( mtx );
351 v3_add( player->rb.co, (v3f){0.0f, 1.0f, 0.0f}, mtx[3] );
352
353 float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f );
354 v3_muladds( mtx[3], player->rb.v, k_rb_delta*substep, mtx[3] );
355 debug_capsule( mtx, w->collider.radius, w->collider.height, VG__YELOW );
356
357
358 /* Calculate header */
359 v3f xy_speed, v;
360
361 v3_copy( player->rb.v, xy_speed );
362 xy_speed[1] = 0.0f;
363
364 if( v3_length2( xy_speed ) > 0.1f * 0.1f )
365 w->state.heading_angle = atan2f( player->rb.v[0], player->rb.v[2] );
366 }
367
368 VG_STATIC void player__walk_animate( player_instance *player,
369 player_animation *dest )
370 {
371 struct player_walk *w = &player->_walk;
372 struct skeleton *sk = &player->playeravatar->sk;
373
374 {
375 float fly = (w->state.activity == k_walk_activity_air)? 1.0f: 0.0f,
376 rate;
377
378 if( w->state.activity == k_walk_activity_air )
379 rate = 2.4f;
380 else
381 rate = 9.0f;
382
383 w->blend_fly = vg_lerpf( w->blend_fly, fly, rate*vg.time_delta );
384 w->blend_run = vg_lerpf( w->blend_run,
385 w->move_speed *
386 (1.0f + player->input_walk->button.value*0.5f),
387 2.0f*vg.time_delta );
388 }
389
390 player_pose apose, bpose;
391
392 if( w->move_speed > 0.025f )
393 {
394 /* TODO move */
395 float walk_norm = 30.0f/(float)w->anim_walk->length,
396 run_norm = 30.0f/(float)w->anim_run->length,
397 walk_adv = vg_lerpf( walk_norm, run_norm, w->move_speed );
398
399 w->walk_timer += walk_adv * vg.time_delta;
400 }
401 else
402 {
403 w->walk_timer = 0.0f;
404 }
405
406 float walk_norm = (float)w->anim_walk->length/30.0f,
407 run_norm = (float)w->anim_run->length/30.0f,
408 t = w->walk_timer,
409 l = vg_clampf( w->blend_run*15.0f, 0.0f, 1.0f ),
410 idle_walk = vg_clampf( (w->blend_run-0.1f)/(1.0f-0.1f), 0.0f, 1.0f );
411
412 /* walk/run */
413 skeleton_sample_anim( sk, w->anim_walk, t*walk_norm, apose );
414 skeleton_sample_anim( sk, w->anim_run, t*run_norm, bpose );
415
416 skeleton_lerp_pose( sk, apose, bpose, l, apose );
417
418 /* idle */
419 skeleton_sample_anim( sk, w->anim_idle, vg.time*0.1f, bpose );
420 skeleton_lerp_pose( sk, apose, bpose, 1.0f-idle_walk, apose );
421
422 /* air */
423 skeleton_sample_anim( sk, w->anim_jump, vg.time*0.6f, bpose );
424 skeleton_lerp_pose( sk, apose, bpose, w->blend_fly, apose );
425
426 /* Create transform */
427 rb_extrapolate( &player->rb, dest->root_co, dest->root_q );
428
429 float walk_yaw = w->state.heading_angle + VG_PIf*0.5f;
430
431 if( w->state.outro_anim )
432 {
433 float outro_length = (float)w->state.outro_anim->length /
434 w->state.outro_anim->rate,
435 outro_time = vg.time - w->state.outro_start_time,
436 outro_t = outro_time / outro_length;
437
438 walk_yaw += -VG_PIf*0.5f*outro_t;
439
440 /* TODO: Compression */
441 v3_muladds( dest->root_co, player->rb.to_world[1],
442 -0.28f * outro_t, dest->root_co );
443
444 skeleton_sample_anim_clamped( sk, w->state.outro_anim,
445 outro_time, bpose );
446 skeleton_lerp_pose( sk, apose, bpose, outro_t * 10.0f, dest->pose );
447 }
448 else
449 {
450 skeleton_copy_pose( sk, apose, dest->pose );
451 }
452
453 q_axis_angle( dest->root_q, (v3f){0.0f,1.0f,0.0f}, walk_yaw );
454 }
455
456 VG_STATIC void player__walk_post_animate( player_instance *player )
457 {
458 /*
459 * Camera
460 */
461 struct player_walk *w = &player->_walk;
462 struct player_avatar *av = player->playeravatar;
463
464 /* 3RD */
465 m3x3f angles;
466 euler_m3x3( w->state.angles, angles );
467
468 v3f cast_dir, origin;
469
470 v3_add( player->rb.co, (v3f){0.0f,2.0f,0.0f}, origin );
471
472 v3_muladds( origin, angles[2], 2.0f, player->override_pos );
473 v3_muladds( player->override_pos, angles[0], 0.5f, player->override_pos );
474
475 float t;
476 v3f n;
477 if( spherecast_world( origin, player->override_pos, 0.1f, &t, n ) != -1 )
478 v3_lerp( origin, player->override_pos, t, player->override_pos );
479 v3_copy( w->state.angles, player->override_angles );
480
481 /* 1ST */
482 /* FIXME: viewpoint entity */
483 v3f vp = {-0.1f,1.8f,0.0f};
484 m4x3_mulv( av->sk.final_mtx[ av->id_head-1 ], vp, player->fpv_pos );
485 v3_copy( w->state.angles, player->fpv_angles );
486
487 /* FIXME: Organize this. Its int wrong fucking place */
488 v3f vp0 = {0.0f,0.1f, 0.6f},
489 vp1 = {0.0f,0.1f,-0.6f};
490
491 if( w->state.outro_anim )
492 {
493 float outro_length = (float)w->state.outro_anim->length /
494 w->state.outro_anim->rate,
495 outro_time = vg.time - w->state.outro_start_time,
496 outro_t = outro_time / outro_length;
497
498 /* FIXME: Compression */
499 v3_add( player->rb.co, (v3f){0.0f,1.35f,0.0f}, origin );
500 player_set_follower_subject( player, origin );
501
502 player->cam_angles_override_strength = 1.0f-outro_t;
503 player->cam_position_override_strength = 1.0f-outro_t;
504
505
506 v3f fpv_angles;
507 player_vector_angles( fpv_angles, player->rb.v, 1.0f, 0.25f );
508 v3_lerp( player->fpv_angles,fpv_angles, outro_t, player->fpv_angles );
509 }
510 else
511 {
512 player->cam_angles_override_strength = 1.0f;
513 player->cam_position_override_strength = 1.0f;
514 }
515
516 m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp0, TEMP_BOARD_0 );
517 m4x3_mulv( av->sk.final_mtx[ av->id_board ], vp1, TEMP_BOARD_1 );
518 }
519
520
521 VG_STATIC void player__walk_im_gui( player_instance *player )
522 {
523 struct player_walk *w = &player->_walk;
524 player__debugtext( 1, "V: %5.2f %5.2f %5.2f",player->rb.v[0],
525 player->rb.v[1],
526 player->rb.v[2] );
527 player__debugtext( 1, "CO: %5.2f %5.2f %5.2f",player->rb.co[0],
528 player->rb.co[1],
529 player->rb.co[2] );
530 player__debugtext( 1, "activity: %s\n",
531 (const char *[]){ "k_walk_activity_air",
532 "k_walk_activity_ground",
533 "k_walk_activity_sleep" }
534 [w->state.activity] );
535
536 if( w->state.outro_anim )
537 {
538 float outro_length = (float)w->state.outro_anim->length /
539 w->state.outro_anim->rate,
540 outro_time = vg.time - w->state.outro_start_time;
541 player__debugtext( 1, "outro time: %f / %f", outro_time, outro_length );
542 }
543 }
544
545 VG_STATIC void player__walk_bind( player_instance *player )
546 {
547 struct player_walk *w = &player->_walk;
548 struct player_avatar *av = player->playeravatar;
549 struct skeleton *sk = &av->sk;
550
551 w->anim_idle = skeleton_get_anim( sk, "idle_cycle" );
552 w->anim_walk = skeleton_get_anim( sk, "walk" );
553 w->anim_run = skeleton_get_anim( sk, "run" );
554 w->anim_jump = skeleton_get_anim( sk, "jump" );
555 w->anim_jump_to_air = skeleton_get_anim( sk, "jump_to_air" );
556 }
557
558 VG_STATIC void player__walk_transition( player_instance *player, v3f angles )
559 {
560 struct player_walk *w = &player->_walk;
561 v3_copy( angles, w->state.angles );
562 }
563
564 #endif /* PLAYER_DEVICE_WALK_H */