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
[] =
19 static int freecam
= 0;
20 static int debugview
= 0;
21 static int debugsdf
= 0;
22 static int debugroad
= 0;
28 int main( int argc
, char *argv
[] )
30 vg_init( argc
, argv
, "Voyager Game Engine" );
35 v3f player_head
; /* Relative to pos */
36 v3f player_vel
= { 0.0f
, 0.0f
, -0.2f
};
41 float waves
[128][128];
47 u32 world_terrain_count
,
50 static int reset_player( int argc
, char const *argv
[] )
52 v3_zero( player_pos
);
53 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player_vel
);
59 void vg_register(void)
66 for( int y
=0; y
<128; y
++ )
68 for( int x
=0; x
<128; x
++ )
72 waves
[x
][y
] = sinf( pos
[0] * 0.1f
) *
73 cosf( pos
[1] * 0.3f
) * 5.0f
+ x
*-0.2f
;
77 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
79 road_patch_init( &road_main
);
80 road_generate( &road_main
);
82 vg_convar_push( (struct vg_convar
){
85 .data_type
= k_convar_dtype_i32
,
86 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
90 vg_convar_push( (struct vg_convar
){
93 .data_type
= k_convar_dtype_i32
,
94 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
98 vg_convar_push( (struct vg_convar
){
101 .data_type
= k_convar_dtype_i32
,
102 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
106 vg_convar_push( (struct vg_convar
){
109 .data_type
= k_convar_dtype_i32
,
110 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
114 vg_function_push( (struct vg_cmd
){
116 .function
= reset_player
119 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
120 v3_normalize( lightDir
);
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
);
133 scene_add_model( &world_scene
, world
,
134 submodel_get( world
, "terrain" ),
135 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
137 int id_tree
= submodel_get( test
, "tree" ),
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" )
148 /* Sprinkle some trees in the terrain areas */
150 v3_sub( world_scene
.bbx
[1], world_scene
.bbx
[0], range
);
152 for( int i
=0; i
<8000; i
++ )
159 v3_muladd( world_scene
.bbx
[0], pos
, range
, pos
);
161 if( sample_scene_height( &world_scene
, pos
) )
163 scene_add_model( &test_scene
, test
,
165 pos
, vg_randf() * VG_TAUf
, vg_randf() * 0.5f
+ 0.5f
);
169 world_terrain_count
= world_scene
.indice_count
;
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
;
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
);
186 scene_upload( &player_scene
);
187 scene_upload( &world_scene
);
188 scene_upload( &test_scene
);
191 static float sample_terrain( v3f pos
)
194 v3_muls( pos
, 0.1f
, local
);
196 v2i ico
= { local
[0], local
[2] };
197 for( int i
=0; i
<2; i
++ )
199 if( ico
[i
] < 0 ) ico
[i
] = 0;
200 if( ico
[i
] > 126 ) ico
[i
] = 126;
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];
209 v3_floor( local
, subcoord
);
210 v3_sub( local
, subcoord
, subcoord
);
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] );
216 return sampleh
*10.0f
;
219 static void draw_terrain(void)
225 for( int y
=0; y
<63; y
++ )
227 for( int x
=0; x
<63; x
++ )
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
},
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
},
242 v3f head
, butt
, knee_r
, knee_l
, foot_r
, foot_l
, hand_r
, hand_l
,
243 shoulder_r
, shoulder_l
;
248 float timestep
= 1.0f
/60.0f
;
253 m4x3_identity( cam_rot
);
254 m4x3_rotate_y( cam_rot
, -look_dir
[0] );
255 m4x3_rotate_x( cam_rot
, -look_dir
[1] );
257 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
258 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
260 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
261 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
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
};
268 if( vg_get_button_down( "primary" ) )
270 v2_copy( vg_mouse
, mouse_last
);
272 else if( vg_get_button( "primary" ) )
275 v2_sub( vg_mouse
, mouse_last
, delta
);
276 v2_copy( vg_mouse
, mouse_last
);
278 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
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
);
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
);
294 v3_muls( move_vel
, 0.75f
, move_vel
);
295 v3_add( move_vel
, player_head
, player_head
);
300 if( vg_get_button( "forward" ) )
302 v3f accel
= { sinf( player_yaw
), 0.0f
, -cosf( player_yaw
) };
303 v3_muladds( player_vel
, accel
, 5.0f
* timestep
, player_vel
);
306 m4x3f player_transform
,
307 world_to_local
, local_to_world
;
309 m4x3_identity( player_transform
);
310 m4x3_translate( player_transform
, player_pos
);
311 m4x3_rotate_y( player_transform
, -player_yaw
);
313 m4x3_identity( world_to_local
);
314 m4x3_rotate_y( world_to_local
, player_yaw
);
316 m4x3_identity( local_to_world
);
317 m4x3_rotate_y( local_to_world
, -player_yaw
);
319 /* Get front and back contact points */
320 v3f contact_front
, contact_back
, fwd
, fwd1
, contact_norm
;
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
);
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
);
330 road_patch_setplayer( &road_main
, player_pos
);
331 sample_road_height( &road_main
, contact_front
);
332 sample_road_height( &road_main
, contact_back
);
334 sample_scene_height( &world_scene
, contact_front
);
335 sample_scene_height( &world_scene
, contact_back
);
336 sample_scene_height( &world_scene
, contact_norm
);
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
);
346 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
347 v3_muladds( player_vel
, gravity
, timestep
, player_vel
);
350 v3_copy( player_pos
, ground_pos
);
351 sample_scene_height( &world_scene
, ground_pos
);
353 static int in_air
= 1;
357 if( ground_pos
[1] > player_pos
[1] )
363 float resistance
= v3_dot( norm
, player_vel
);
365 if( resistance
>= 0.0f
)
369 v3_muladds( player_vel
, norm
, -resistance
, player_vel
);
373 /* vg_info( "%.3f | %.3f\n", player_vel[1], resistance ); */
374 v3_muladds( player_pos
, player_vel
, timestep
, player_pos
);
380 player_pos
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
382 vg_line( player_pos
, contact_front
, 0xff00ffff );
383 vg_line( player_pos
, contact_back
, 0xff00ffa0 );
385 /* Create the 'travel' vector */
387 v3_sub( contact_front
, contact_back
, travel
);
388 v3_normalize( travel
);
392 float gravity_conversion
= -v3_dot( travel
, gravity
);
393 vel
[2] += gravity_conversion
* substep
;
396 /* Get localized (rotated) rigidbody forces
405 m4x3_mulv( world_to_local
, player_vel
, vel
);
407 /* Calculate local forces */
408 slip
= -vel
[0] / vel
[2];
409 float substep
= timestep
* 0.2f
;
411 if( fabsf( slip
) > 1.2f
)
413 slip
= vg_signf( slip
) * 1.2f
;
416 for( int i
=0; i
<5; i
++ )
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
;
424 m4x3_mulv( local_to_world
, vel
, player_vel
);
426 if( vg_get_button( "yawl" ) )
427 player_yaw
-= 1.6f
* timestep
;
428 if( vg_get_button( "yawr" ) )
429 player_yaw
+= 1.6f
* timestep
;
431 player_yaw
+= vg_get_axis( "horizontal" ) * 1.6f
* timestep
;
435 player_yaw
+= vg_get_axis( "horizontal" ) * 3.6f
* timestep
;
436 look_dir
[0] = player_yaw
;
439 look_dir
[0] = atan2f( player_vel
[0], -player_vel
[2] );
441 /* Creating a skeleton of the player dynamically */
442 float kheight
= 1.8f
,
447 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
448 static v3f bob
, bob1
;
450 v3_sub( player_vel
, last_vel
, player_accel
);
451 v3_copy( player_vel
, last_vel
);
452 v3_add( bob
, player_accel
, bob
);
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
);
458 v3_lerp( bob
, (v3f
){ 0.0f
, 0.0f
, 0.0f
}, 0.1f
, bob
);
459 v3_lerp( bob1
, bob
, 0.1f
, bob1
);
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
;
476 butt
[0] = -sinf(slip
)*0.2f
;
477 butt
[1] = cosf(slip
);
480 v2_muls( butt
, -0.7f
, butt
);
481 v2_add( head
, butt
, butt
);
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
;
490 v2_muladds( (v2f
){0.0f
,0.0f
},
491 (v2f
){ sinf( ad
+x
), cosf( ad
+ x
) },
495 v2_copy( knee_l
, knee_r
);
499 v3_add( (v3f
){0.0f
,-0.1f
,-0.2f
}, head
, shoulder_r
);
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
);
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
);
516 v3_copy( head
, player_head
);
520 static void debug_grid( v3f at
)
523 v3_floor( at
, base
);
525 for( int y
=0; y
<16; y
++ )
527 vg_line( (v3f
){ base
[0] - 8, base
[1], base
[2]+y
-8 },
528 (v3f
){ base
[0] + 8, base
[1], base
[2]+y
-8 },
531 for( int x
=0; x
<16; x
++ )
533 vg_line( (v3f
){ base
[0]+x
-8, base
[1], base
[2]-8 },
534 (v3f
){ base
[0]+x
-8, base
[1], base
[2]+8 },
541 glViewport( 0,0, vg_window_x
, vg_window_y
);
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
);
548 v3_negate( player_head
, pos_inv
);
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
);
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
);
560 m4x3_expand( world_matrix
, world_4x4
);
562 m4x4_projection( vg_pv
,
563 freecam
? 90.0f
: 130.0f
,
564 (float)vg_window_x
/ (float)vg_window_y
,
566 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
569 draw_road_patch_dev( &road_main
);
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 );
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
;
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
);
586 vg_line( bnw
, bne
, 0xff00ff00 );
587 vg_line( bne
, bse
, 0xff00ff00 );
588 vg_line( bse
, bsw
, 0xff00ff00 );
589 vg_line( bsw
, bnw
, 0xff00ff00 );
591 glEnable( GL_DEPTH_TEST
);
593 v3f leg_dr
, leg_dl
, leg_ar
, leg_al
;
595 v3_sub( foot_l
, butt
, leg_dl
);
596 v3_sub( foot_r
, butt
, leg_dr
);
599 v3_normalize( leg_dl
);
600 v3_normalize( leg_dr
);
603 v3_sub( butt
, knee_l
, v0
);
604 float leg_pl
= atan2f( v0
[1], v3_dot( v0
, leg_dl
) );
606 v3_sub( knee_l
, foot_l
, v0
);
607 float knee_pl
= atan2f( v0
[1], v3_dot( v0
, leg_dl
) );
609 float leg_yl
= -atan2f( leg_dl
[2], leg_dl
[0] ),
610 leg_yr
= atan2f( leg_dr
[2], leg_dr
[0] );
612 SHADER_USE( shader_debug_vcol
);
616 vg_tex2d_bind( &tex_grid
, 0 );
617 scene_tree_sway
= 0.0f
;
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
);
628 m4x3_translate( temp
, knee_l
);
629 m4x3_rotate_x( temp
, knee_pl
);
630 m4x3_rotate_y( temp
, leg_yl
);
632 m4x3_expand( temp
, temp1
);
633 glUniformMatrix4fv( SHADER_UNIFORM( shader_debug_vcol
, "uMdl" ),
634 1, GL_FALSE
, (float *)temp1
);
636 scene_draw( &player_scene
, -1, 0 );
638 m4x3_identity( temp
);
639 m4x3_expand( temp
, temp1
);
640 glUniformMatrix4fv( SHADER_UNIFORM( shader_debug_vcol
, "uMdl" ),
641 1, GL_FALSE
, (float *)temp1
);
643 vg_tex2d_bind( &tex_norwey
, 0 );
644 scene_tree_sway
= 0.1f
;
645 scene_draw( &test_scene
, -1, 0 );
647 vg_tex2d_bind( &tex_grid
, 0 );
648 scene_tree_sway
= 0.0f
;
649 scene_draw( &world_scene
, world_terrain_count
, 0 );
651 vg_tex2d_bind( &tex_road
, 0 );
652 scene_draw( &world_scene
, world_road_count
, world_terrain_count
);
654 glDisable( GL_DEPTH_TEST
);
661 snprintf( buf
, 20, "%.2fm/s", v3_length( player_vel
) );
662 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
664 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
665 player_accel
[0], player_accel
[1], player_accel
[2] );
667 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
669 if( vg_gamepad_ready
)
671 for( int i
=0; i
<6; i
++ )
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
);
679 gui_text( (ui_px
[2]){ 0, 40 },
680 "Gamepad not ready", 1, k_text_align_left
);