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