init
[carveJwlIkooP6JGAAIwe30JlM.git] / main.c
1 #define VG_3D
2 #include "vg/vg.h"
3
4 /* Resources */
5 vg_tex2d tex_norwey = { .path = "textures/norway_foliage.qoi" };
6 vg_tex2d tex_grid = { .path = "textures/grid.qoi" };
7 vg_tex2d tex_road = { .path = "textures/road.qoi" };
8 vg_tex2d tex_gradients = { .path = "textures/gradients.qoi",
9 .flags = VG_TEXTURE_CLAMP };
10 vg_tex2d *texture_list[] =
11 {
12 &tex_norwey,
13 &tex_gradients,
14 &tex_grid,
15 &tex_road
16 };
17
18 /* Convars */
19 static int freecam = 0;
20 static int debugview = 0;
21 static int debugsdf = 0;
22 static int debugroad = 0;
23
24 /* Components */
25 #include "road.h"
26 #include "scene.h"
27
28 int main( int argc, char *argv[] )
29 {
30 vg_init( argc, argv, "Voyager Game Engine" );
31 }
32
33 m4x3f world_matrix;
34 v3f player_pos;
35 v3f player_head; /* Relative to pos */
36 v3f player_vel = { 0.0f, 0.0f, -0.2f };
37 float player_yaw;
38 v2f look_dir;
39 v3f player_accel;
40
41 float waves[128][128];
42
43 road_patch road_main;
44 scene test_scene;
45 scene world_scene;
46 scene player_scene;
47 u32 world_terrain_count,
48 world_road_count;
49
50 static int reset_player( int argc, char const *argv[] )
51 {
52 v3_zero( player_pos );
53 v3_copy( (v3f){ 0.0f, 0.0f, -0.2f }, player_vel );
54 player_yaw = 0.0f;
55
56 return 0;
57 }
58
59 void vg_register(void)
60 {
61 scene_register();
62 }
63
64 void vg_start(void)
65 {
66 for( int y=0; y<128; y++ )
67 {
68 for( int x=0; x<128; x++ )
69 {
70 v2f pos = {x,y};
71
72 waves[x][y] = sinf( pos[0] * 0.1f ) *
73 cosf( pos[1] * 0.3f ) * 5.0f + x*-0.2f;
74 }
75 }
76
77 vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
78
79 road_patch_init( &road_main );
80 road_generate( &road_main );
81
82 vg_convar_push( (struct vg_convar){
83 .name = "freecam",
84 .data = &freecam,
85 .data_type = k_convar_dtype_i32,
86 .opt_i32 = { .min=0, .max=1, .clamp=1 },
87 .persistent = 1
88 });
89
90 vg_convar_push( (struct vg_convar){
91 .name = "debugview",
92 .data = &debugview,
93 .data_type = k_convar_dtype_i32,
94 .opt_i32 = { .min=0, .max=1, .clamp=0 },
95 .persistent = 1
96 });
97
98 vg_convar_push( (struct vg_convar){
99 .name = "debugsdf",
100 .data = &debugsdf,
101 .data_type = k_convar_dtype_i32,
102 .opt_i32 = { .min=0, .max=1, .clamp=1 },
103 .persistent = 1
104 });
105
106 vg_convar_push( (struct vg_convar){
107 .name = "debugroad",
108 .data = &debugroad,
109 .data_type = k_convar_dtype_i32,
110 .opt_i32 = { .min=0, .max=1, .clamp=1 },
111 .persistent = 1
112 });
113
114 vg_function_push( (struct vg_cmd){
115 .name = "reset",
116 .function = reset_player
117 });
118
119 v3f lightDir = { 0.1f, 0.8f, 0.2f };
120 v3_normalize( lightDir );
121
122 scene_init( &world_scene );
123 scene_init( &test_scene );
124 scene_init( &player_scene );
125 model *world = vg_asset_read( "models/free_dev.mdl" );
126 model *test = vg_asset_read( "models/test.mdl" );
127 model *char_dev = vg_asset_read( "models/char_dev.mdl" );
128 scene_add_model( &player_scene, char_dev,
129 submodel_get( char_dev, "joint" ),
130 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
131 free(char_dev);
132
133 scene_add_model( &world_scene, world,
134 submodel_get( world, "terrain" ),
135 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
136
137 int id_tree = submodel_get( test, "tree" ),
138 id_groundcover[] =
139 {
140 submodel_get( test, "bush" ),
141 submodel_get( test, "grass" ),
142 submodel_get( test, "blubber" ),
143 submodel_get( test, "blubber" ),
144 submodel_get( test, "blubber" ),
145 submodel_get( test, "grassthin" )
146 };
147
148 /* Sprinkle some trees in the terrain areas */
149 v3f range;
150 v3_sub( world_scene.bbx[1], world_scene.bbx[0], range );
151
152 for( int i=0; i<8000; i++ )
153 {
154 v3f pos;
155
156 pos[0] = vg_randf();
157 pos[1] = 0.0f;
158 pos[2] = vg_randf();
159 v3_muladd( world_scene.bbx[0], pos, range, pos );
160
161 if( sample_scene_height( &world_scene, pos ) )
162 {
163 scene_add_model( &test_scene, test,
164 id_tree,
165 pos, vg_randf() * VG_TAUf, vg_randf() * 0.5f + 0.5f );
166 }
167 }
168
169 world_terrain_count = world_scene.indice_count;
170
171 scene_add_model( &world_scene, world,
172 submodel_get( world, "road" ),
173 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
174 world_road_count = world_scene.indice_count-world_terrain_count;
175
176 free( test );
177 free( world );
178
179 #if 0
180 scene_compute_occlusion( &test_scene );
181 scene_shadow_gradient( &test_scene, 1, 0.0f, 1.0f );
182 scene_shadow_sphere( &test_scene, (v3f){ 0.0f,4.0f,0.0f},
183 (v4f){1.0f, 2.0f, 0.0f, 0.0f}, lightDir );
184 #endif
185
186 scene_upload( &player_scene );
187 scene_upload( &world_scene );
188 scene_upload( &test_scene );
189 }
190
191 static float sample_terrain( v3f pos )
192 {
193 v3f local;
194 v3_muls( pos, 0.1f, local );
195
196 v2i ico = { local[0], local[2] };
197 for( int i=0; i<2; i++ )
198 {
199 if( ico[i] < 0 ) ico[i] = 0;
200 if( ico[i] > 126 ) ico[i] = 126;
201 }
202
203 float hse = waves[ico[0]+1][ico[1]],
204 hsw = waves[ico[0]][ico[1]],
205 hne = waves[ico[0]+1][ico[1]+1],
206 hnw = waves[ico[0]][ico[1]+1];
207
208 v3f subcoord;
209 v3_floor( local, subcoord );
210 v3_sub( local, subcoord, subcoord );
211
212 float hs = vg_lerpf( hse, hsw, 1.0f-subcoord[0] ),
213 hn = vg_lerpf( hne, hnw, 1.0f-subcoord[0] ),
214 sampleh = vg_lerpf( hs, hn, subcoord[2] );
215
216 return sampleh*10.0f;
217 }
218
219 static void draw_terrain(void)
220 {
221 float sf = 10.0f;
222
223 /* Draw waves
224 */
225 for( int y=0; y<63; y++ )
226 {
227 for( int x=0; x<63; x++ )
228 {
229 v2i pos = {x*2,y*2};
230 vg_line( (v3f){ pos[0]*sf, waves[pos[0]][pos[1]]*sf, pos[1]*sf },
231 (v3f){ (pos[0]+2)*sf, waves[pos[0]+2][pos[1]]*sf, pos[1]*sf },
232 0xa0ffffff );
233
234 vg_line( (v3f){ pos[1]*sf, waves[pos[1]][pos[0]]*sf, pos[0]*sf },
235 (v3f){ pos[1]*sf, waves[pos[1]][pos[0]+2]*sf, (pos[0]+2)*sf },
236 0xa0ffffff );
237 }
238 }
239
240 }
241
242 v3f head, butt, knee_r, knee_l, foot_r, foot_l, hand_r, hand_l,
243 shoulder_r, shoulder_l;
244
245
246 void vg_update(void)
247 {
248 float timestep = 1.0f/60.0f;
249
250 if( freecam )
251 {
252 m4x3f cam_rot;
253 m4x3_identity( cam_rot );
254 m4x3_rotate_y( cam_rot, -look_dir[0] );
255 m4x3_rotate_x( cam_rot, -look_dir[1] );
256
257 v3f lookdir = { 0.0f, 0.0f, -1.0f },
258 sidedir = { 1.0f, 0.0f, 0.0f };
259
260 m4x3_mulv( cam_rot, lookdir, lookdir );
261 m4x3_mulv( cam_rot, sidedir, sidedir );
262
263 float movespeed = 5.0f;
264 static v2f mouse_last,
265 view_vel = { 0.0f, 0.0f };
266 static v3f move_vel = { 0.0f, 0.0f, 0.0f };
267
268 if( vg_get_button_down( "primary" ) )
269 {
270 v2_copy( vg_mouse, mouse_last );
271 }
272 else if( vg_get_button( "primary" ) )
273 {
274 v2f delta;
275 v2_sub( vg_mouse, mouse_last, delta );
276 v2_copy( vg_mouse, mouse_last );
277
278 v2_muladds( view_vel, delta, 0.005f, view_vel );
279 }
280
281 v2_muls( view_vel, 0.75f, view_vel );
282 v2_add( view_vel, look_dir, look_dir );
283 look_dir[1] = vg_clampf( look_dir[1], -VG_PIf*0.5f, VG_PIf*0.5f );
284
285 if( vg_get_button( "forward" ) )
286 v3_muladds( move_vel, lookdir, timestep * movespeed, move_vel );
287 if( vg_get_button( "back" ) )
288 v3_muladds( move_vel, lookdir, timestep *-movespeed, move_vel );
289 if( vg_get_button( "left" ) )
290 v3_muladds( move_vel, sidedir, timestep *-movespeed, move_vel );
291 if( vg_get_button( "right" ) )
292 v3_muladds( move_vel, sidedir, timestep * movespeed, move_vel );
293
294 v3_muls( move_vel, 0.75f, move_vel );
295 v3_add( move_vel, player_head, player_head );
296
297 return;
298 }
299
300 if( vg_get_button( "forward" ) )
301 {
302 v3f accel = { sinf( player_yaw ), 0.0f, -cosf( player_yaw ) };
303 v3_muladds( player_vel, accel, 5.0f * timestep, player_vel );
304 }
305
306 m4x3f player_transform,
307 world_to_local, local_to_world;
308
309 m4x3_identity( player_transform );
310 m4x3_translate( player_transform, player_pos );
311 m4x3_rotate_y( player_transform, -player_yaw );
312
313 m4x3_identity( world_to_local );
314 m4x3_rotate_y( world_to_local, player_yaw );
315
316 m4x3_identity( local_to_world );
317 m4x3_rotate_y( local_to_world, -player_yaw );
318
319 /* Get front and back contact points */
320 v3f contact_front, contact_back, fwd, fwd1, contact_norm;
321
322 m4x3_mulv( local_to_world, (v3f){0.0f,0.0f,-1.0f}, fwd );
323 m4x3_mulv( local_to_world, (v3f){0.03f,0.0f,-1.0f}, fwd1 );
324
325 v3_muladds( player_pos, fwd, 1.0f, contact_front );
326 v3_muladds( player_pos, fwd,-1.0f, contact_back );
327 v3_muladds( player_pos, fwd1, 1.0f, contact_norm );
328
329 #if 0
330 road_patch_setplayer( &road_main, player_pos );
331 sample_road_height( &road_main, contact_front );
332 sample_road_height( &road_main, contact_back );
333 #else
334 sample_scene_height( &world_scene, contact_front );
335 sample_scene_height( &world_scene, contact_back );
336 sample_scene_height( &world_scene, contact_norm );
337 #endif
338
339 v3f norm;
340 v3f v0, v1;
341 v3_sub( contact_back, contact_norm, v0 );
342 v3_sub( contact_front, contact_norm, v1 );
343 v3_cross( v1, v0, norm );
344 v3_normalize( norm );
345
346 v3f gravity = { 0.0f, -9.6f, 0.0f };
347 v3_muladds( player_vel, gravity, timestep, player_vel );
348
349 v3f ground_pos;
350 v3_copy( player_pos, ground_pos );
351 sample_scene_height( &world_scene, ground_pos );
352
353 static int in_air = 1;
354
355 if( in_air )
356 {
357 if( ground_pos[1] > player_pos[1] )
358 in_air = 0;
359 }
360
361 if( !in_air )
362 {
363 float resistance = v3_dot( norm, player_vel );
364
365 if( resistance >= 0.0f )
366 in_air = 1;
367 else
368 {
369 v3_muladds( player_vel, norm, -resistance, player_vel );
370 }
371 }
372
373 /* vg_info( "%.3f | %.3f\n", player_vel[1], resistance ); */
374 v3_muladds( player_pos, player_vel, timestep, player_pos );
375
376 float slip = 0.0f;
377
378 if( !in_air )
379 {
380 player_pos[1] = (contact_front[1]+contact_back[1])*0.5f;
381
382 vg_line( player_pos, contact_front, 0xff00ffff );
383 vg_line( player_pos, contact_back, 0xff00ffa0 );
384
385 /* Create the 'travel' vector */
386 v3f travel;
387 v3_sub( contact_front, contact_back, travel );
388 v3_normalize( travel );
389
390 /* Apply gravity */
391 #if 0
392 float gravity_conversion = -v3_dot( travel, gravity );
393 vel[2] += gravity_conversion * substep;
394 #endif
395
396 /* Get localized (rotated) rigidbody forces
397 * -z
398 * ^
399 * -|-
400 * |
401 * +z
402 */
403
404 v3f vel;
405 m4x3_mulv( world_to_local, player_vel, vel );
406
407 /* Calculate local forces */
408 slip = -vel[0] / vel[2];
409 float substep = timestep * 0.2f;
410
411 if( fabsf( slip ) > 1.2f )
412 {
413 slip = vg_signf( slip ) * 1.2f;
414 }
415
416 for( int i=0; i<5; i++ )
417 {
418 if( fabsf(vel[2]) >= 0.02f*substep )
419 vel[2] += vg_signf( vel[2] ) * -0.02f * substep;
420 if( fabsf(vel[0]) >= 6.0f*substep )
421 vel[0] += vg_signf( vel[0] ) * -6.0f * substep;
422 }
423
424 m4x3_mulv( local_to_world, vel, player_vel );
425
426 if( vg_get_button( "yawl" ) )
427 player_yaw -= 1.6f * timestep;
428 if( vg_get_button( "yawr" ) )
429 player_yaw += 1.6f * timestep;
430
431 player_yaw += vg_get_axis( "horizontal" ) * 1.6f * timestep;
432 }
433 else
434 {
435 player_yaw += vg_get_axis( "horizontal" ) * 3.6f * timestep;
436 look_dir[0] = player_yaw;
437 }
438
439 look_dir[0] = atan2f( player_vel[0], -player_vel[2] );
440
441 /* Creating a skeleton of the player dynamically */
442 float kheight = 1.8f,
443 kleg = 0.6f;
444
445 v2f ac;
446
447 static v3f last_vel = { 0.0f, 0.0f, 0.0f };
448 static v3f bob, bob1;
449
450 v3_sub( player_vel, last_vel, player_accel );
451 v3_copy( player_vel, last_vel );
452 v3_add( bob, player_accel, bob );
453
454 bob[0] = vg_clampf( bob[0], -0.4f, 1.0f );
455 bob[1] = vg_clampf( bob[1], -0.4f, 1.3f );
456 bob[2] = vg_clampf( bob[2], -0.4f, 1.0f );
457
458 v3_lerp( bob, (v3f){ 0.0f, 0.0f, 0.0f }, 0.1f, bob );
459 v3_lerp( bob1, bob, 0.1f, bob1 );
460
461 /* Feet */
462 foot_r[0] = 0.0f;
463 foot_r[1] = 0.0f;
464 foot_r[2] = 0.3f;
465
466 foot_l[0] = 0.0f;
467 foot_l[1] = 0.0f;
468 foot_l[2] = -0.3f;
469
470 /* Head */
471 head[0] = (-sinf(slip)*0.9f * kheight + bob1[0]*0.6f) * 0.54f;
472 head[1] = cosf(slip)*0.9f * kheight +-bob1[1]*1.4f;
473 head[2] = 0.0f;
474
475 /* Hips */
476 butt[0] = -sinf(slip)*0.2f;
477 butt[1] = cosf(slip);
478 butt[2] = 0.0f;
479 v2_normalize(butt);
480 v2_muls( butt, -0.7f, butt );
481 v2_add( head, butt, butt );
482
483 /* Knees */
484 v2_sub( butt, (v2f){0.0f,0.0f}, ac );
485 float cl = v2_length( ac ),
486 d = acosf( (2.0f * kleg*kleg - cl*cl) / 2.0f * kleg*kleg ),
487 x = atan2f( ac[0], ac[1] ),
488 ad = (-VG_PIf-d)/2.0f;
489
490 v2_muladds( (v2f){0.0f,0.0f},
491 (v2f){ sinf( ad+x ), cosf( ad + x ) },
492 kleg, knee_l );
493 knee_l[2] = -0.3f;
494
495 v2_copy( knee_l, knee_r );
496 knee_r[2] = 0.3f;
497
498 /* shoulders */
499 v3_add( (v3f){0.0f,-0.1f,-0.2f}, head, shoulder_r );
500
501 /* Hands */
502 hand_r[0] = sinf( slip ) * 0.1f;
503 hand_r[1] = -cosf( slip*5.0f ) * 0.5f - 0.5f;
504 hand_r[2] = -sinf( fabsf(slip) * 2.4f );
505 v3_add( shoulder_r, hand_r, hand_r );
506
507 m4x3_mulv( player_transform, head, head );
508 m4x3_mulv( player_transform, butt, butt );
509 m4x3_mulv( player_transform, knee_l, knee_l );
510 m4x3_mulv( player_transform, knee_r, knee_r );
511 m4x3_mulv( player_transform, foot_l, foot_l );
512 m4x3_mulv( player_transform, foot_r, foot_r );
513 m4x3_mulv( player_transform, hand_r, hand_r );
514 m4x3_mulv( player_transform, shoulder_r, shoulder_r );
515
516 v3_copy( head, player_head );
517
518 }
519
520 static void debug_grid( v3f at )
521 {
522 v3f base;
523 v3_floor( at, base );
524
525 for( int y=0; y<16; y++ )
526 {
527 vg_line( (v3f){ base[0] - 8, base[1], base[2]+y-8 },
528 (v3f){ base[0] + 8, base[1], base[2]+y-8 },
529 0x40ffffff );
530 }
531 for( int x=0; x<16; x++ )
532 {
533 vg_line( (v3f){ base[0]+x-8, base[1], base[2]-8 },
534 (v3f){ base[0]+x-8, base[1], base[2]+8 },
535 0x40ffffff );
536 }
537 }
538
539 void vg_render(void)
540 {
541 glViewport( 0,0, vg_window_x, vg_window_y );
542
543 glDisable( GL_DEPTH_TEST );
544 glClearColor( 0.1f, 0.0f, 0.2f, 1.0f );
545 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
546
547 v3f pos_inv;
548 v3_negate( player_head, pos_inv );
549
550 float speed = v3_length( player_vel );
551 v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f };
552 v3_muls( shake, speed*0.01f, shake );
553
554 m4x3_identity( world_matrix );
555 m4x3_rotate_x( world_matrix, freecam? look_dir[1]: 0.3f+shake[1]*0.04f );
556 m4x3_rotate_y( world_matrix, look_dir[0]+shake[0]*0.02f );
557 m4x3_translate( world_matrix, pos_inv );
558
559 m4x4f world_4x4;
560 m4x3_expand( world_matrix, world_4x4 );
561
562 m4x4_projection( vg_pv,
563 freecam? 90.0f: 130.0f,
564 (float)vg_window_x / (float)vg_window_y,
565 0.01f, 1000.0f );
566 m4x4_mul( vg_pv, world_4x4, vg_pv );
567
568 if( debugroad )
569 draw_road_patch_dev( &road_main );
570
571 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
572 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
573 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
574
575 v3f board_fwd = { -sinf( player_yaw ), 0.0f, cosf( player_yaw ) };
576 v3f board_side = { -board_fwd[2], 0.0f, board_fwd[0] };
577 v3f bnw, bne, bse, bsw;
578
579 v3_muladds( player_pos, board_fwd, 0.75f, bnw );
580 v3_muladds( player_pos, board_fwd, -0.75f, bsw );
581 v3_muladds( bnw, board_side, 0.1f, bne );
582 v3_muladds( bnw, board_side, -0.1f, bnw );
583 v3_muladds( bsw, board_side, 0.1f, bse );
584 v3_muladds( bsw, board_side, -0.1f, bsw );
585
586 vg_line( bnw, bne, 0xff00ff00 );
587 vg_line( bne, bse, 0xff00ff00 );
588 vg_line( bse, bsw, 0xff00ff00 );
589 vg_line( bsw, bnw, 0xff00ff00 );
590
591 glEnable( GL_DEPTH_TEST );
592
593 v3f leg_dr, leg_dl, leg_ar, leg_al;
594
595 v3_sub( foot_l, butt, leg_dl );
596 v3_sub( foot_r, butt, leg_dr );
597 leg_dl[1] = 0.0f;
598 leg_dr[1] = 0.0f;
599 v3_normalize( leg_dl );
600 v3_normalize( leg_dr );
601
602 v3f v0;
603 v3_sub( butt, knee_l, v0 );
604 float leg_pl = atan2f( v0[1], v3_dot( v0, leg_dl ) );
605
606 v3_sub( knee_l, foot_l, v0 );
607 float knee_pl = atan2f( v0[1], v3_dot( v0, leg_dl ) );
608
609 float leg_yl = -atan2f( leg_dl[2], leg_dl[0] ),
610 leg_yr = atan2f( leg_dr[2], leg_dr[0] );
611
612 SHADER_USE( shader_debug_vcol );
613 m4x3f temp;
614 m4x4f temp1;
615
616 vg_tex2d_bind( &tex_grid, 0 );
617 scene_tree_sway = 0.0f;
618
619 vg_line( head, butt, 0xff0000ff );
620 vg_line( butt, knee_l, 0xff0000ff );
621 vg_line( butt, knee_r, 0xff0000ff );
622 vg_line( foot_l, knee_l, 0xff00a0ff );
623 vg_line( foot_r, knee_r, 0xff00a0ff );
624 vg_line( head, shoulder_r, 0xa0ff00ff );
625 vg_line( shoulder_r, hand_r, 0xffff00ff );
626 m4x3_identity( temp );
627
628 m4x3_translate( temp, knee_l );
629 m4x3_rotate_x( temp, knee_pl );
630 m4x3_rotate_y( temp, leg_yl );
631
632 m4x3_expand( temp, temp1 );
633 glUniformMatrix4fv( SHADER_UNIFORM( shader_debug_vcol, "uMdl" ),
634 1, GL_FALSE, (float *)temp1 );
635
636 scene_draw( &player_scene, -1, 0 );
637
638 m4x3_identity( temp );
639 m4x3_expand( temp, temp1 );
640 glUniformMatrix4fv( SHADER_UNIFORM( shader_debug_vcol, "uMdl" ),
641 1, GL_FALSE, (float *)temp1 );
642
643 vg_tex2d_bind( &tex_norwey, 0 );
644 scene_tree_sway = 0.1f;
645 scene_draw( &test_scene, -1, 0 );
646
647 vg_tex2d_bind( &tex_grid, 0 );
648 scene_tree_sway = 0.0f;
649 scene_draw( &world_scene, world_terrain_count, 0 );
650
651 vg_tex2d_bind( &tex_road, 0 );
652 scene_draw( &world_scene, world_road_count, world_terrain_count );
653
654 glDisable( GL_DEPTH_TEST );
655 }
656
657 void vg_ui(void)
658 {
659 char buf[20];
660
661 snprintf( buf, 20, "%.2fm/s", v3_length( player_vel ) );
662 gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
663
664 snprintf( buf, 20, "%.2f %.2f %.2f m/s",
665 player_accel[0], player_accel[1], player_accel[2] );
666
667 gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
668
669 if( vg_gamepad_ready )
670 {
671 for( int i=0; i<6; i++ )
672 {
673 snprintf( buf, 20, "%.2f", vg_gamepad.axes[i] );
674 gui_text( (ui_px [2]){ 0, (i+2)*20 }, buf, 1, k_text_align_left );
675 }
676 }
677 else
678 {
679 gui_text( (ui_px [2]){ 0, 40 },
680 "Gamepad not ready", 1, k_text_align_left );
681 }
682 }
683
684 void vg_free(void){}