foot alignment
[carveJwlIkooP6JGAAIwe30JlM.git] / main.c
1 #define VG_3D
2 #define VG_FRAMEBUFFER_RESIZE 1
3 #include "vg/vg.h"
4
5 /* Resources */
6 vg_tex2d tex_norwey = { .path = "textures/norway_foliage.qoi" };
7 vg_tex2d tex_grid = { .path = "textures/grid.qoi" };
8 vg_tex2d tex_sky = { .path = "textures/sky.qoi" };
9 vg_tex2d tex_gradients = { .path = "textures/gradients.qoi",
10 .flags = VG_TEXTURE_CLAMP };
11 vg_tex2d tex_cement = { .path = "textures/cement512.qoi" };
12 vg_tex2d tex_pallet = { .path = "textures/ch_gradient.qoi" };
13
14 vg_tex2d *texture_list[] =
15 {
16 &tex_norwey,
17 &tex_gradients,
18 &tex_grid,
19 &tex_sky,
20 &tex_cement,
21 &tex_pallet
22 };
23
24 SHADER_DEFINE( shader_blit,
25 "layout (location=0) in vec2 a_co;"
26 "out vec2 aUv;"
27 ""
28 "void main()"
29 "{"
30 "gl_Position = vec4(a_co*2.0-1.0,0.0,1.0);"
31 "aUv = a_co;"
32 "}",
33
34 /* Fragment */
35 "out vec4 FragColor;"
36 ""
37 "uniform sampler2D uTexMain;"
38 ""
39 "in vec2 aUv;"
40 ""
41 "void main()"
42 "{"
43 "FragColor = texture( uTexMain, aUv );"
44 "}"
45 ,
46 UNIFORMS({ "uTexMain" })
47 )
48
49 /* Convars */
50 static int freecam = 0;
51 static int debugview = 0;
52 static int debugsdf = 0;
53 static int sv_debugcam = 0;
54 static int sv_phys = 0;
55 static int thirdperson = 0;
56 static int clock_divider = 1;
57 static int replay_record = 0;
58
59 static m4x3f *replay_buffer = NULL;
60 static int replay_buffer_frame = 0;
61
62 #define REPLAY_LENGTH 120*60
63
64 /* Components */
65 #include "road.h"
66 #include "scene.h"
67 #include "ik.h"
68 #include "character.h"
69 #include "terrain.h"
70
71 int main( int argc, char *argv[] )
72 {
73 vg_init( argc, argv, "Voyager Game Engine" );
74 }
75
76 m4x3f world_matrix;
77
78 static struct gplayer
79 {
80 /* Physics */
81 v3f co, v, a;
82 v4f rot;
83 float vswitch, slip, slip_last,
84 reverse;
85
86 float iY; /* Yaw inertia */
87 int in_air;
88
89 /* Input */
90 v2f joy_l;
91
92 v3f view;
93 v2f look_dir; /* TEMP */
94 v2f board_xy;
95 float grab;
96 float pitch;
97
98 v3f land_target;
99 v3f land_target_log[12];
100 int land_log_count;
101 m3x3f vr;
102
103 m4x3f to_world, to_local;
104
105 struct character mdl;
106
107 v3f handl_target, handr_target,
108 handl, handr;
109 }
110 player;
111
112 static struct gworld
113 {
114 scene geo;
115 submodel terrain,
116 terrain_rocks,
117 terrain_road;
118 }
119 world;
120
121 static struct grender
122 {
123 GLuint fb_background,
124 rgb_background;
125
126 glmesh fsquad;
127 }
128 render;
129
130 static void player_transform_update(void)
131 {
132 q_m3x3( player.rot, player.to_world );
133 v3_copy( player.co, player.to_world[3] );
134
135 m4x3_invert_affine( player.to_world, player.to_local );
136 }
137
138 static int reset_player( int argc, char const *argv[] )
139 {
140 v3_zero( player.co );
141 v3_copy( (v3f){ 0.0f, 0.0f, -0.2f }, player.v );
142 q_identity( player.rot );
143 player.vswitch = 1.0f;
144 player.slip_last = 0.0f;
145
146 player_transform_update();
147 return 0;
148 }
149
150 static int playermodel( int argc, char const *argv[] )
151 {
152 if( argc < 1 ) return 0;
153
154 glmesh old_mesh = player.mdl.mesh;
155
156 if( character_load( &player.mdl, argv[0] ) )
157 mesh_free( &old_mesh );
158
159 return 1;
160 }
161
162 void vg_register(void)
163 {
164 scene_register();
165 character_shader_register();
166 SHADER_INIT( shader_blit );
167 }
168
169 void vg_start(void)
170 {
171 replay_buffer = malloc( sizeof(m4x3f) * REPLAY_LENGTH * (PART_COUNT) );
172
173 vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
174
175 vg_convar_push( (struct vg_convar){
176 .name = "frame",
177 .data = &replay_buffer_frame,
178 .data_type = k_convar_dtype_i32,
179 .opt_i32 = { .min=0, .max=REPLAY_LENGTH-1, .clamp=1 },
180 .persistent = 0
181 });
182
183 vg_convar_push( (struct vg_convar){
184 .name = "rec",
185 .data = &replay_record,
186 .data_type = k_convar_dtype_i32,
187 .opt_i32 = { .min=0, .max=1, .clamp=1 },
188 .persistent = 0
189 });
190
191 vg_convar_push( (struct vg_convar){
192 .name = "freecam",
193 .data = &freecam,
194 .data_type = k_convar_dtype_i32,
195 .opt_i32 = { .min=0, .max=1, .clamp=1 },
196 .persistent = 1
197 });
198
199 vg_convar_push( (struct vg_convar){
200 .name = "debugcam",
201 .data = &sv_debugcam,
202 .data_type = k_convar_dtype_i32,
203 .opt_i32 = { .min=0, .max=1, .clamp=0 },
204 .persistent = 1
205 });
206
207 vg_convar_push( (struct vg_convar){
208 .name = "debugview",
209 .data = &debugview,
210 .data_type = k_convar_dtype_i32,
211 .opt_i32 = { .min=0, .max=1, .clamp=0 },
212 .persistent = 1
213 });
214
215 vg_convar_push( (struct vg_convar){
216 .name = "debugsdf",
217 .data = &debugsdf,
218 .data_type = k_convar_dtype_i32,
219 .opt_i32 = { .min=0, .max=1, .clamp=1 },
220 .persistent = 1
221 });
222
223 vg_convar_push( (struct vg_convar){
224 .name = "phys",
225 .data = &sv_phys,
226 .data_type = k_convar_dtype_i32,
227 .opt_i32 = { .min=0, .max=1, .clamp=1 },
228 .persistent = 1
229 });
230
231 vg_convar_push( (struct vg_convar){
232 .name = "thirdperson",
233 .data = &thirdperson,
234 .data_type = k_convar_dtype_i32,
235 .opt_i32 = { .min=0, .max=1, .clamp=1 },
236 .persistent = 1
237 });
238
239 vg_convar_push( (struct vg_convar){
240 .name = "div",
241 .data = &clock_divider,
242 .data_type = k_convar_dtype_i32,
243 .opt_i32 = { .min=0, .max=1, .clamp=0 },
244 .persistent = 1
245 });
246
247 vg_function_push( (struct vg_cmd){
248 .name = "reset",
249 .function = reset_player
250 });
251
252 v3f lightDir = { 0.1f, 0.8f, 0.2f };
253 v3_normalize( lightDir );
254
255 character_load( &player.mdl, "ch_default" );
256
257 /* Setup scene */
258 scene_init( &world.geo );
259 model *mworld = vg_asset_read( "models/mp_dev.mdl" );
260
261 scene_add_model( &world.geo, mworld, submodel_get( mworld, "mp_dev" ),
262 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
263
264 free( mworld );
265 scene_upload( &world.geo );
266 bvh_create( &world.geo );
267
268
269 reset_player( 0, NULL );
270 player_transform_update();
271
272 /* Create framebuffers */
273 glGenFramebuffers( 1, &render.fb_background );
274 glBindFramebuffer( GL_FRAMEBUFFER, render.fb_background );
275
276 glGenTextures( 1, &render.rgb_background );
277 glBindTexture( GL_TEXTURE_2D, render.rgb_background );
278 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y,
279 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
280
281 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
282 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
283 glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
284 GL_TEXTURE_2D,
285 render.rgb_background, 0);
286
287 {
288 float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
289 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f };
290
291 glGenVertexArrays( 1, &render.fsquad.vao );
292 glGenBuffers( 1, &render.fsquad.vbo );
293 glGenBuffers( 1, &render.fsquad.ebo );
294 glBindVertexArray( render.fsquad.vao );
295 glBindBuffer( GL_ARRAY_BUFFER, render.fsquad.vbo );
296 glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW );
297 glBindVertexArray( render.fsquad.vao );
298 glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE,
299 sizeof(float)*2, (void*)0 );
300 glEnableVertexAttribArray( 0 );
301 VG_CHECK_GL();
302 }
303 }
304
305 static float ktimestep = 1.0f/60.0f;
306
307 static void player_freecam(void)
308 {
309 m4x3f cam_rot;
310 m4x3_identity( cam_rot );
311 m4x3_rotate_y( cam_rot, -player.look_dir[0] );
312 m4x3_rotate_x( cam_rot, -player.look_dir[1] );
313
314 v3f lookdir = { 0.0f, 0.0f, -1.0f },
315 sidedir = { 1.0f, 0.0f, 0.0f };
316
317 m4x3_mulv( cam_rot, lookdir, lookdir );
318 m4x3_mulv( cam_rot, sidedir, sidedir );
319
320 float movespeed = 5.0f;
321 static v2f mouse_last,
322 view_vel = { 0.0f, 0.0f };
323
324 static v3f move_vel = { 0.0f, 0.0f, 0.0f };
325
326 if( vg_get_button_down( "primary" ) )
327 v2_copy( vg_mouse, mouse_last );
328 else if( vg_get_button( "primary" ) )
329 {
330 v2f delta;
331 v2_sub( vg_mouse, mouse_last, delta );
332 v2_copy( vg_mouse, mouse_last );
333
334 v2_muladds( view_vel, delta, 0.005f, view_vel );
335 }
336
337 v2_muls( view_vel, 0.75f, view_vel );
338 v2_add( view_vel, player.look_dir, player.look_dir );
339 player.look_dir[1] =
340 vg_clampf( player.look_dir[1], -VG_PIf*0.5f, VG_PIf*0.5f );
341
342 if( vg_get_button( "forward" ) )
343 v3_muladds( move_vel, lookdir, ktimestep * movespeed, move_vel );
344 if( vg_get_button( "back" ) )
345 v3_muladds( move_vel, lookdir, ktimestep *-movespeed, move_vel );
346 if( vg_get_button( "left" ) )
347 v3_muladds( move_vel, sidedir, ktimestep *-movespeed, move_vel );
348 if( vg_get_button( "right" ) )
349 v3_muladds( move_vel, sidedir, ktimestep * movespeed, move_vel );
350
351 v3_muls( move_vel, 0.75f, move_vel );
352 v3_add( move_vel, player.view, player.view );
353 }
354
355 static void apply_gravity( v3f vel, float const timestep )
356 {
357 v3f gravity = { 0.0f, -9.6f, 0.0f };
358 v3_muladds( vel, gravity, timestep, vel );
359 }
360
361 static void player_start_air(void)
362 {
363 player.in_air = 1;
364
365 float pstep = ktimestep*10.0f;
366
367 float best_velocity_mod = 0.0f,
368 best_velocity_delta = -9999.9f;
369
370 v3f axis, vup;
371 m3x3_mulv( player.to_world, (v3f){0.0f,1.0f,0.0f}, vup );
372 v3_cross( vup, player.v, axis );
373 v3_normalize( axis );
374 player.land_log_count = 0;
375
376 m3x3_identity( player.vr );
377
378 for( int m=0;m<=5; m++ )
379 {
380 float vmod = ((float)m / 5.0f)*0.09f;
381
382 v3f pco, pco1, pv;
383 v3_copy( player.co, pco );
384 v3_copy( player.v, pv );
385
386 /*
387 * Try different 'rotations' of the velocity to find the best possible
388 * landing normal. This conserves magnitude at the expense of slightly
389 * unrealistic results
390 */
391
392 m3x3f vr;
393 v4f vr_q;
394
395 q_axis_angle( vr_q, axis, vmod );
396 q_m3x3( vr_q, vr );
397
398 for( int i=0; i<50; i++ )
399 {
400 v3_copy( pco, pco1 );
401 apply_gravity( pv, pstep );
402
403 m3x3_mulv( vr, pv, pv );
404 v3_muladds( pco, pv, pstep, pco );
405
406 ray_hit contact;
407 v3f vdir;
408
409 v3_sub( pco, pco1, vdir );
410 contact.dist = v3_length( vdir );
411 v3_divs( vdir, contact.dist, vdir);
412
413 if( bvh_raycast( &world.geo, pco1, vdir, &contact ))
414 {
415 float land_delta = v3_dot( pv, contact.normal );
416
417 if( (land_delta < 0.0f) && (land_delta > best_velocity_delta) )
418 {
419 best_velocity_delta = land_delta;
420 best_velocity_mod = vmod;
421
422 v3_copy( contact.pos, player.land_target );
423
424 q_axis_angle( vr_q, axis, vmod*0.1f );
425 q_m3x3( vr_q, player.vr );
426 }
427
428 v3_copy( contact.pos,
429 player.land_target_log[player.land_log_count ++] );
430 break;
431 }
432 }
433 }
434
435 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
436
437 return;
438 v3_muls( player.v, best_velocity_mod, player.v );
439 }
440
441 static int sample_if_resistant( v3f pos )
442 {
443 v3f ground, norm;
444 v3_copy( pos, ground );
445
446 if( bvh_scene_sample( &world.geo, ground, norm ) )
447 {
448 v3f angle;
449 v3_copy( player.v, angle );
450 v3_normalize( angle );
451 float resistance = v3_dot( norm, angle );
452
453 if( resistance < 0.25f )
454 {
455 v3_copy( ground, pos );
456 return 1;
457 }
458 }
459
460 return 0;
461 }
462
463 static float stable_force( float current, float diff )
464 {
465 float new = current + diff;
466
467 if( new * current < 0.0f )
468 return 0.0f;
469
470 return new;
471 }
472
473 static void player_physics_ground(void)
474 {
475 /*
476 * Getting surface collision points,
477 * the contact manifold is a triangle for simplicity.
478 */
479 v3f contact_front, contact_back, fwd, fwd1, contact_norm, vup, vside,
480 axis;
481
482 float klength = 0.65f;
483 m3x3_mulv( player.to_world, (v3f){ 0.0f, 0.0f,-1.0f}, fwd );
484 m4x3_mulv( player.to_world, (v3f){ 0.15f,0.0f,-klength}, contact_norm );
485 m4x3_mulv( player.to_world, (v3f){-0.15f,0.0f,-klength}, contact_front );
486 m4x3_mulv( player.to_world, (v3f){ 0.00f,0.0f, klength}, contact_back );
487 m3x3_mulv( player.to_world, (v3f){ 0.0f, 1.0f, 0.0f}, vup );
488 m3x3_mulv( player.to_world, (v3f){ 1.0f, 0.0f, 0.0f}, vside );
489
490 v3f cn0, cn1, cn2;
491
492 int contact_count =
493 sample_if_resistant( contact_front ) +
494 sample_if_resistant( contact_back ) +
495 sample_if_resistant( contact_norm );
496
497 if( contact_count < 3 )
498 {
499 player_start_air();
500 return;
501 }
502
503 v3f norm;
504 v3f v0, v1;
505 v3_sub( contact_norm, contact_front, v0 );
506 v3_sub( contact_back, contact_front, v1 );
507 v3_cross( v1, v0, norm );
508 v3_normalize( norm );
509
510 vg_line( contact_norm, contact_front, 0xff00ff00 );
511 vg_line( contact_back, contact_front, 0xff0000ff );
512
513 /* Surface alignment */
514 float angle = v3_dot( vup, norm );
515 v3_cross( vup, norm, axis );
516
517 if( angle < 0.999f )
518 {
519 v4f correction;
520 q_axis_angle( correction, axis, acosf(angle) );
521 q_mul( correction, player.rot, player.rot );
522 }
523
524 float resistance = v3_dot( norm, player.v );
525
526 if( resistance >= 0.0f )
527 {
528 player_start_air();
529 return;
530 }
531 else
532 {
533 v3_muladds( player.v, norm, -resistance, player.v );
534 }
535
536 /* This is where velocity integration used to be */
537
538 float slip = 0.0f;
539
540 player.co[1] = (contact_front[1]+contact_back[1])*0.5f;
541
542 v3f vel;
543 m3x3_mulv( player.to_local, player.v, vel );
544
545 /* Calculate local forces */
546
547 slip = fabsf(-vel[0] / vel[2]) * vg_signf(vel[0]);
548 if( fabsf( slip ) > 1.2f )
549 slip = vg_signf( slip ) * 1.2f;
550 player.slip = slip;
551 player.reverse = -vg_signf(vel[2]);
552
553 float substep = ktimestep * 0.2f;
554 for( int i=0; i<5; i++ )
555 {
556 vel[2] = stable_force( vel[2], vg_signf( vel[2] ) * -0.02f*substep );
557 vel[0] = stable_force( vel[0], vg_signf( vel[0] ) * -7.0f *substep );
558 }
559
560 m3x3_mulv( player.to_world, vel, player.v );
561
562 if( vg_get_button( "yawl" ) )
563 player.iY += 3.6f * ktimestep;
564 if( vg_get_button( "yawr" ) )
565 player.iY -= 3.6f * ktimestep;
566
567 float steer = vg_get_axis( "horizontal" );
568 player.iY -= vg_signf(steer)*powf(steer,2.0f) * 1.5f * ktimestep;
569
570 /* Too much lean and it starts to look like a snowboard here */
571 v2_lerp( player.board_xy, (v2f){ slip*0.25f, 0.0f },
572 ktimestep*5.0f, player.board_xy);
573 }
574
575 static void draw_cross(v3f pos,u32 colour)
576 {
577 v3f p0, p1;
578 v3_add( (v3f){ 1.0f,0.0f,0.0f}, pos, p0 );
579 v3_add( (v3f){-1.0f,0.0f,0.0f}, pos, p1 );
580 vg_line( p0, p1, colour );
581 v3_add( (v3f){0.0f, 1.0f,0.0f}, pos, p0 );
582 v3_add( (v3f){0.0f,-1.0f,0.0f}, pos, p1 );
583 vg_line( p0, p1, colour );
584 v3_add( (v3f){0.0f,0.0f, 1.0f}, pos, p0 );
585 v3_add( (v3f){0.0f,0.0f,-1.0f}, pos, p1 );
586 vg_line( p0, p1, colour );
587 }
588
589 static void player_physics_air(void)
590 {
591 /* Debug prediciton */
592
593 m3x3_mulv( player.vr, player.v, player.v );
594 for( int i=0; i<player.land_log_count; i++ )
595 draw_cross( player.land_target_log[i], 0xff00ffff );
596
597 draw_cross( player.land_target, 0xff0000ff );
598
599 v3f ground_pos, ground_norm;
600 v3_copy( player.co, ground_pos );
601
602 if( bvh_scene_sample( &world.geo, ground_pos, ground_norm ) )
603 {
604 if( ground_pos[1] > player.co[1] )
605 {
606 player.in_air = 0;
607 return;
608 }
609 }
610
611 /* Prediction
612 *
613 * TODO: Find best landing surface and guide player towords it
614 */
615 float pstep = ktimestep*10.0f;
616
617 v3f pco, pco1, pv;
618 v3_copy( player.co, pco );
619 v3_copy( player.v, pv );
620
621 for( int i=0; i<50; i++ )
622 {
623 v3_copy( pco, pco1 );
624 apply_gravity( pv, pstep );
625 v3_muladds( pco, pv, pstep, pco );
626
627 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
628
629 ray_hit contact;
630 v3f vdir;
631
632 v3_sub( pco, pco1, vdir );
633 contact.dist = v3_length( vdir );
634 v3_divs( vdir, contact.dist, vdir);
635
636 if( bvh_raycast( &world.geo, pco1, vdir, &contact ))
637 {
638 v3f localup;
639 m3x3_mulv( player.to_world, (v3f){0.0f,1.0f,0.0f}, localup );
640
641 float angle = v3_dot( localup, contact.normal );
642 v3f axis;
643 v3_cross( localup, contact.normal, axis );
644
645 if( angle < 0.99f )
646 {
647 v4f correction;
648 q_axis_angle( correction, axis, acosf(angle)*0.05f );
649 q_mul( correction, player.rot, player.rot );
650 }
651
652 draw_cross( contact.pos, 0xffff0000 );
653
654 break;
655 }
656 }
657
658 player.iY -= vg_get_axis( "horizontal" ) * 3.6f * ktimestep;
659
660 v2f target = {0.0f,0.0f};
661 v2_muladds( target, (v2f){ vg_get_axis("h1"), vg_get_axis("v1") },
662 player.grab, target );
663 v2_lerp( player.board_xy, target, ktimestep*3.0f, player.board_xy );
664 }
665
666 static void player_animate(void);
667 static void player_update(void)
668 {
669 static int clock = 0;
670
671 clock ++;
672 if( clock >= clock_divider )
673 clock = 0;
674 else
675 return;
676
677 /* temp */
678 if( freecam )
679 {
680 player_freecam();
681 return;
682 }
683
684 if( vg_get_axis("grabl")>0.0f)
685 reset_player(0,NULL);
686 if( vg_get_button( "push" ) )
687 {
688 v3f dir = { 0.0f, 0.0f, -1.0f };
689
690 m3x3_mulv( player.to_world, dir, dir );
691 v3_muladds( player.v, dir, 5.0f * ktimestep, player.v );
692 }
693
694 float horizontal = vg_get_axis("horizontal"),
695 vertical = vg_get_axis("vertical");
696
697 player.joy_l[0] = vg_signf(horizontal) * powf( horizontal, 2.0f );
698 player.joy_l[1] = vg_signf(vertical) * powf( vertical, 2.0f );
699
700 /* Integrate velocity */
701 if( sv_phys )
702 {
703 apply_gravity( player.v, ktimestep );
704 v3_muladds( player.co, player.v, ktimestep, player.co );
705 }
706
707 /* Integrate inertia */
708 v4f rotate; v3f vup = {0.0f,1.0f,0.0f};
709 m3x3_mulv( player.to_world, vup, vup );
710
711 static float siY = 0.0f;
712
713 float lerpq = player.in_air? 0.04f: 0.3f;
714 siY = vg_lerpf( siY, player.iY, lerpq );
715
716 q_axis_angle( rotate, vup, siY );
717 q_mul( rotate, player.rot, player.rot );
718
719 player.look_dir[0] = atan2f( player.v[0], -player.v[2] );
720 player.look_dir[1] = atan2f( -player.v[1], sqrtf(player.v[0]*player.v[0]+
721 player.v[2]*player.v[2]) ) * 0.3f;
722
723 player.iY = 0.0f; /* temp */
724
725 if( player.in_air )
726 player_physics_air();
727
728 if( !player.in_air )
729 player_physics_ground();
730
731 /* Camera and character */
732
733 player_transform_update();
734 q_normalize(player.rot);
735 player_animate();
736 }
737
738 void vg_update(void)
739 {
740 player_update();
741 bvh_debug( &world.geo, player.co );
742 }
743
744 static void player_animate(void)
745 {
746 /* Camera position */
747 static v3f last_vel = { 0.0f, 0.0f, 0.0f };
748 static v3f momentum, bob;
749
750 v3_sub( player.v, last_vel, player.a );
751 v3_copy( player.v, last_vel );
752
753 v3_add( momentum, player.a, momentum );
754 v3_lerp( momentum, (v3f){0.0f,0.0f,0.0f}, 0.1f, momentum );
755 v3f target;
756
757 momentum[0] = vg_clampf( momentum[0], -2.0f, 2.0f );
758 momentum[1] = vg_clampf( momentum[1], -0.2f, 5.0f );
759 momentum[2] = vg_clampf( momentum[2], -2.0f, 2.0f );
760 v3_copy( momentum, target );
761 v3_lerp( bob, target, 0.2f, bob );
762
763 /* Head */
764 float lslip = fabsf(player.slip); //vg_minf( 0.4f, slip );
765
766 float grabt = vg_get_axis( "grabr" )*0.5f+0.5f;
767 player.grab = vg_lerpf( player.grab, grabt, 0.04f );
768
769 float kheight = 2.0f,
770 kleg = 0.6f;
771
772 v3f head;
773 head[0] = 0.0f;
774 head[1] = (0.3f+cosf(lslip)*0.5f*(1.0f-player.grab*0.7f)) * kheight;
775 head[2] = 0.0f;
776
777 v3f offset;
778 m3x3_mulv( player.to_local, bob, offset );
779
780 offset[0] *= 0.3333f;
781 offset[1] *= -0.25f;
782 offset[2] *= 0.7f;
783 v3_muladds( head, offset, 0.7f, head );
784 head[1] = vg_clampf( head[1], 0.3f, kheight );
785
786 #if 0
787 if( !freecam )
788 {
789 v3_copy( head, player.view );
790 v3f camoffs = {-0.2f,-0.6f,0.00f};
791 v3_add( player.view, camoffs, player.view );
792 }
793 #endif
794
795
796 /*
797 * Animation blending
798 * ===========================================
799 */
800
801 static float fslide = 0.0f;
802 static float fdirz = 0.0f;
803 static float fdirx = 0.0f;
804 static float fstand = 0.0f;
805 static float ffly = 0.0f;
806
807 float speed = v3_length( player.v );
808
809 fstand = vg_lerpf(fstand, 1.0f-vg_clampf(speed*0.03f,0.0f,1.0f),0.1f);
810 fslide = vg_lerpf(fslide, vg_clampf(lslip+fabsf(offset[0])*0.2f,
811 0.0f,1.0f), 0.04f);
812 fdirz = vg_lerpf(fdirz, player.reverse > 0.0f? 1.0f: 0.0f, 0.04f );
813 fdirx = vg_lerpf(fdirx, player.slip < 0.0f? 1.0f: 0.0f, 0.04f );
814 ffly = vg_lerpf(ffly, player.in_air? 1.0f: 0.0f, 0.04f );
815
816 character_pose_reset( &player.mdl );
817
818 float amt_air = ffly*ffly,
819 amt_ground = 1.0f-amt_air,
820 amt_std = (1.0f-fslide) * amt_ground,
821 amt_stand = amt_std * fstand,
822 amt_aero = amt_std * (1.0f-fstand),
823 amt_slide = amt_ground * fslide;
824
825 character_final_pose( &player.mdl, offset, &pose_stand, amt_stand );
826 character_final_pose( &player.mdl, offset, &pose_aero, amt_aero*fdirz );
827 character_final_pose( &player.mdl, offset,
828 &pose_aero_reverse, amt_aero * (1.0f-fdirz) );
829 character_final_pose( &player.mdl, offset, &pose_slide, amt_slide*fdirx );
830 character_final_pose( &player.mdl, offset,
831 &pose_slide1, amt_slide*(1.0f-fdirx) );
832
833 character_final_pose( &player.mdl, (v3f){0.0f,0.0f,0.0f},
834 &pose_fly, amt_air );
835
836 if( !freecam )
837 {
838 v3_copy( player.mdl.cam_pos, player.view );
839 v3_muladds( player.view, offset, 0.7f, player.view );
840 player.view[1] = vg_clampf( player.view[1], 0.3f, kheight );
841 }
842
843 /*
844 * Additive effects
845 * ==========================
846 */
847 struct ik_basic *arm_l = &player.mdl.ik_arm_l,
848 *arm_r = &player.mdl.ik_arm_r;
849
850 v3f localv;
851 m3x3_mulv( player.to_local, player.v, localv );
852 v3_muladds( arm_l->end, localv, -0.01f, arm_l->end );
853 v3_muladds( arm_r->end, localv, -0.01f, arm_r->end );
854
855 /* New board transformation */
856 v4f board_rotation; v3f board_location;
857
858 v4f rz, rx;
859 q_axis_angle( rz, (v3f){ 0.0f, 0.0f, 1.0f }, player.board_xy[0] );
860 q_axis_angle( rx, (v3f){ 1.0f, 0.0f, 0.0f }, player.board_xy[1] );
861 q_mul( rx, rz, board_rotation );
862
863 v3f *mboard = player.mdl.matrices[k_chpart_board];// player.mboard;
864 q_m3x3( board_rotation, mboard );
865 m3x3_mulv( mboard, (v3f){ 0.0f, -0.5f, 0.0f }, board_location );
866 v3_add( (v3f){0.0f,0.5f,0.0f}, board_location, board_location );
867 v3_copy( board_location, mboard[3] );
868
869
870 float wheel_r = offset[0]*-0.4f;
871 v4f qwheel;
872 q_axis_angle( qwheel, (v3f){0.0f,1.0f,0.0f}, wheel_r );
873
874 q_m3x3( qwheel, player.mdl.matrices[k_chpart_wb] );
875
876 m3x3_transpose( player.mdl.matrices[k_chpart_wb],
877 player.mdl.matrices[k_chpart_wf] );
878 v3_copy( player.mdl.offsets[k_chpart_wb],
879 player.mdl.matrices[k_chpart_wb][3] );
880 v3_copy( player.mdl.offsets[k_chpart_wf],
881 player.mdl.matrices[k_chpart_wf][3] );
882
883 m4x3_mul( mboard, player.mdl.matrices[k_chpart_wb],
884 player.mdl.matrices[k_chpart_wb] );
885 m4x3_mul( mboard, player.mdl.matrices[k_chpart_wf],
886 player.mdl.matrices[k_chpart_wf] );
887
888 m4x3_mulv( mboard, player.mdl.ik_leg_l.end, player.mdl.ik_leg_l.end );
889 m4x3_mulv( mboard, player.mdl.ik_leg_r.end, player.mdl.ik_leg_r.end );
890
891
892 v3_copy( player.mdl.ik_arm_l.end, player.handl_target );
893 v3_copy( player.mdl.ik_arm_r.end, player.handr_target );
894
895 if( 1||player.in_air )
896 {
897 float tuck = player.board_xy[1],
898 tuck_amt = fabsf( tuck ) * (1.0f-fabsf(player.board_xy[0]));
899
900 float crouch = player.grab*0.3f;
901 v3_muladds( player.mdl.ik_body.base, (v3f){0.0f,-1.0f,0.0f},
902 crouch, player.mdl.ik_body.base );
903 v3_muladds( player.mdl.ik_body.end, (v3f){0.0f,-1.0f,0.0f},
904 crouch*1.2f, player.mdl.ik_body.end );
905
906 if( tuck < 0.0f )
907 {
908 //foot_l *= 1.0f-tuck_amt*1.5f;
909
910 if( player.grab > 0.1f )
911 {
912 m4x3_mulv( mboard, (v3f){0.1f,0.14f,0.6f},
913 player.handl_target );
914 }
915 }
916 else
917 {
918 //foot_r *= 1.0f-tuck_amt*1.4f;
919
920 if( player.grab > 0.1f )
921 {
922 m4x3_mulv( mboard, (v3f){0.1f,0.14f,-0.6f},
923 player.handr_target );
924 }
925 }
926 }
927
928 v3_lerp( player.handl, player.handl_target, 0.1f, player.handl );
929 v3_lerp( player.handr, player.handr_target, 0.1f, player.handr );
930
931 v3_copy( player.handl, player.mdl.ik_arm_l.end );
932 v3_copy( player.handr, player.mdl.ik_arm_r.end );
933
934 /* Head rotation */
935
936 static float rhead = 0.0f;
937 rhead = vg_lerpf( rhead,
938 vg_clampf(atan2f( localv[2], -localv[0] ),-1.0f,1.0f), 0.04f );
939 player.mdl.rhead = rhead;
940 }
941
942 static void draw_player(void)
943 {
944 /* Draw */
945 vg_tex2d_bind( &tex_pallet, 0 );
946
947 m4x3_copy( player.to_world, player.mdl.mroot );
948 character_eval( &player.mdl );
949 character_draw( &player.mdl, 1.0f );
950 }
951
952 static void vg_framebuffer_resize( int w, int h )
953 {
954 glBindTexture( GL_TEXTURE_2D, render.rgb_background );
955 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
956 GL_RGB, GL_UNSIGNED_BYTE, NULL );
957 }
958
959 void vg_render(void)
960 {
961 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
962 glViewport( 0,0, vg_window_x, vg_window_y );
963
964 glDisable( GL_DEPTH_TEST );
965 glClearColor( 0.1f, 0.0f, 0.2f, 1.0f );
966 glClearColor(111.0f/255.0f, 46.0f/255.0f, 45.0f/255.0f,1.0f);
967
968 glClearColor( powf(0.066f,1.0f/2.2f),
969 powf(0.050f,1.0f/2.2f),
970 powf(0.046f,1.0f/2.2f), 1.0f );
971 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
972
973 v3f pos_inv;
974 static v3f cam_lerped = {0.0f,0.0f,0.0f};
975 v3_lerp( cam_lerped, player.view, 0.08f, cam_lerped );
976
977 if( !freecam )
978 m4x3_mulv( player.to_world, cam_lerped, pos_inv );
979 else
980 v3_add( player.co, player.view, pos_inv );
981 v3_negate( pos_inv, pos_inv );
982
983 static float vertical_lerp = 0.0f;
984 vertical_lerp = vg_lerpf( vertical_lerp, pos_inv[1], 1.0f );
985 v3f final = { pos_inv[0], vertical_lerp, pos_inv[2] };
986
987 float speed = freecam? 0.0f: v3_length( player.v );
988 v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f };
989 v3_muls( shake, speed*0.01f, shake );
990
991 static v2f cam_lerped_dir;
992
993 v2_lerp( cam_lerped_dir, player.look_dir, 0.04f, cam_lerped_dir );
994
995 m4x3_identity( world_matrix );
996 m4x3_rotate_x( world_matrix,
997 freecam?
998 cam_lerped_dir[1]:
999 0.6f+shake[1]*0.04f+player.look_dir[1] );
1000
1001 m4x3_rotate_y( world_matrix,
1002 freecam?
1003 cam_lerped_dir[0]:
1004 player.look_dir[0]+shake[0]*0.02f );
1005 m4x3_translate( world_matrix, final );
1006
1007 m4x4f world_4x4;
1008 m4x3_expand( world_matrix, world_4x4 );
1009 m4x4_projection( vg_pv,
1010 freecam? 60.0f: 120.0f,
1011 (float)vg_window_x / (float)vg_window_y,
1012 0.01f, 1000.0f );
1013 m4x4_mul( vg_pv, world_4x4, vg_pv );
1014
1015 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
1016 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
1017 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
1018
1019 glEnable( GL_DEPTH_TEST );
1020
1021 /*
1022 * Draw world
1023 */
1024 SHADER_USE(shader_standard_lit);
1025
1026 m4x3f identity_matrix;
1027 m4x3_identity( identity_matrix );
1028
1029 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit, "uPv" ),
1030 1, GL_FALSE, (float *)vg_pv );
1031 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_standard_lit, "uMdl" ),
1032 1, GL_FALSE, (float *)identity_matrix );
1033
1034 vg_tex2d_bind( &tex_grid, 0 );
1035 glUniform1i( SHADER_UNIFORM( shader_standard_lit, "uTexMain" ), 0 );
1036
1037 glUniform4f( SHADER_UNIFORM(shader_standard_lit,"uColour"),
1038 0.4f,0.4f,0.4f,1.0f );
1039
1040 scene_bind( &world.geo );
1041 scene_draw( &world.geo );
1042
1043 if( !replay_record )
1044 {
1045 m4x3f *base = &replay_buffer[(PART_COUNT)*replay_buffer_frame];
1046
1047 for( int i=0; i<PART_COUNT; i++ )
1048 m4x3_copy( base[i], player.mdl.matrices[i] );
1049
1050 replay_buffer_frame ++;
1051
1052 if( replay_buffer_frame == REPLAY_LENGTH )
1053 replay_buffer_frame = 0;
1054
1055 vg_tex2d_bind( &tex_pallet, 0 );
1056 character_draw( &player.mdl, 0.0f );
1057 player_animate();
1058 }
1059
1060
1061
1062 /* Copy the RGB of what we have into the background buffer */
1063 glBindFramebuffer( GL_READ_FRAMEBUFFER, 0 );
1064 glBindFramebuffer( GL_DRAW_FRAMEBUFFER, render.fb_background );
1065 glBlitFramebuffer( 0,0, vg_window_x, vg_window_y,
1066 0,0, vg_window_x, vg_window_y,
1067 GL_COLOR_BUFFER_BIT,
1068 GL_LINEAR );
1069
1070 /* Clear out the colour buffer, but keep depth */
1071 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
1072 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
1073
1074 #if 1
1075 glClear( GL_COLOR_BUFFER_BIT );
1076 #else
1077 glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
1078 #endif
1079
1080 if( !freecam )
1081 draw_player();
1082
1083 /* Draw back in the background */
1084 glEnable(GL_BLEND);
1085 glDisable(GL_DEPTH_TEST);
1086 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
1087 glBlendEquation(GL_FUNC_ADD);
1088
1089 SHADER_USE( shader_blit );
1090
1091 glUniform1i( SHADER_UNIFORM(shader_blit,"uTexMain"), 0 );
1092 glActiveTexture(GL_TEXTURE0);
1093 glBindTexture( GL_TEXTURE_2D, render.rgb_background );
1094
1095 glBindVertexArray( render.fsquad.vao );
1096 glDrawArrays( GL_TRIANGLES, 0, 6 );
1097
1098 glDisable(GL_BLEND);
1099
1100 /* Other shite */
1101 glDisable( GL_DEPTH_TEST );
1102 vg_lines_drawall( (float *)vg_pv );
1103
1104 /* Debugger camera */
1105 glViewport( 0,0, 800, 800 );
1106 glClearColor( 0.1f, 0.0f, 0.2f, 1.0f );
1107 glClear( GL_DEPTH_BUFFER_BIT );
1108
1109 m4x3_identity( world_matrix );
1110
1111 v3f debugcam;
1112 v3_negate( player.co, debugcam );
1113 debugcam[2] -= 2.0f;
1114 debugcam[1] -= 0.7f;
1115
1116 m4x3_translate( world_matrix, debugcam );
1117 m4x3_expand( world_matrix, world_4x4 );
1118
1119 m4x4_projection( vg_pv,
1120 100.0f,
1121 (float)128.0f / (float)128.0f,
1122 0.01f, 1000.0f );
1123 m4x4_mul( vg_pv, world_4x4, vg_pv );
1124
1125 if(sv_debugcam)
1126 {
1127 glEnable( GL_DEPTH_TEST );
1128 draw_player();
1129 }
1130
1131 glDisable( GL_DEPTH_TEST );
1132 vg_lines_drawall( (float *)vg_pv );
1133
1134 glViewport( 0,0, vg_window_x, vg_window_y );
1135
1136
1137 if( replay_record )
1138 {
1139 m4x3f *base = &replay_buffer[(PART_COUNT)*replay_buffer_frame];
1140
1141 for( int i=0; i<PART_COUNT; i++ )
1142 m4x3_copy( player.mdl.matrices[i], base[i] );
1143
1144 replay_buffer_frame ++;
1145
1146 if( replay_buffer_frame == REPLAY_LENGTH )
1147 replay_buffer_frame = 0;
1148 }
1149 }
1150
1151 void vg_ui(void)
1152 {
1153 char buf[20];
1154
1155 snprintf( buf, 20, "%.2fm/s", v3_length( player.v ) );
1156 gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
1157
1158 snprintf( buf, 20, "%.2f %.2f %.2f m/s",
1159 player.a[0], player.a[1], player.a[2] );
1160 gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
1161
1162 snprintf( buf, 20, "pos %.2f %.2f %.2f",
1163 player.co[0], player.co[1], player.co[2] );
1164 gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left );
1165
1166 if( vg_gamepad_ready )
1167 {
1168 for( int i=0; i<6; i++ )
1169 {
1170 snprintf( buf, 20, "%.2f", vg_gamepad.axes[i] );
1171 gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left );
1172 }
1173 }
1174 else
1175 {
1176 gui_text( (ui_px [2]){ 0, 60 },
1177 "Gamepad not ready", 1, k_text_align_left );
1178 }
1179 }
1180
1181 void vg_free(void){}