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