change to quat
[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
35 #if 0
36 v3f player.co;
37 v3f player.view; /* Relative to pos */
38 v3f player.v = { 0.0f, 0.0f, -0.2f };
39 float player_yaw;
40 v2f player.look_dir;
41 v3f player.a;
42 #endif
43
44 static struct gplayer
45 {
46 v3f co, v, a;
47 v4f rot;
48
49 v3f view;
50 v2f look_dir; /* TEMP */
51
52 m4x3f to_world, to_local;
53 }
54 player;
55
56 road_patch road_main;
57 scene test_scene;
58 scene world_scene;
59 scene player_scene;
60 u32 world_terrain_count,
61 world_road_count;
62
63 static void player_transform_update(void)
64 {
65 q_m3x3( player.rot, player.to_world );
66 v3_copy( player.co, player.to_world[3] );
67
68 v4f inv;
69 q_inv( player.rot, inv );
70 q_m3x3( inv, player.to_local );
71 v3_negate( player.co, player.to_local[3] );
72 }
73
74 static int reset_player( int argc, char const *argv[] )
75 {
76 v3_zero( player.co );
77 v3_copy( (v3f){ 0.0f, 0.0f, -0.2f }, player.v );
78 q_identity( player.rot );
79
80 player_transform_update();
81 return 0;
82 }
83
84 void vg_register(void)
85 {
86 scene_register();
87 }
88
89 void vg_start(void)
90 {
91 vg_tex2d_init( texture_list, vg_list_size( texture_list ) );
92
93 road_patch_init( &road_main );
94 road_generate( &road_main );
95
96 vg_convar_push( (struct vg_convar){
97 .name = "freecam",
98 .data = &freecam,
99 .data_type = k_convar_dtype_i32,
100 .opt_i32 = { .min=0, .max=1, .clamp=1 },
101 .persistent = 1
102 });
103
104 vg_convar_push( (struct vg_convar){
105 .name = "debugview",
106 .data = &debugview,
107 .data_type = k_convar_dtype_i32,
108 .opt_i32 = { .min=0, .max=1, .clamp=0 },
109 .persistent = 1
110 });
111
112 vg_convar_push( (struct vg_convar){
113 .name = "debugsdf",
114 .data = &debugsdf,
115 .data_type = k_convar_dtype_i32,
116 .opt_i32 = { .min=0, .max=1, .clamp=1 },
117 .persistent = 1
118 });
119
120 vg_convar_push( (struct vg_convar){
121 .name = "debugroad",
122 .data = &debugroad,
123 .data_type = k_convar_dtype_i32,
124 .opt_i32 = { .min=0, .max=1, .clamp=1 },
125 .persistent = 1
126 });
127
128 vg_function_push( (struct vg_cmd){
129 .name = "reset",
130 .function = reset_player
131 });
132
133 v3f lightDir = { 0.1f, 0.8f, 0.2f };
134 v3_normalize( lightDir );
135
136 scene_init( &world_scene );
137 scene_init( &test_scene );
138 scene_init( &player_scene );
139 model *world = vg_asset_read( "models/free_dev.mdl" );
140 model *test = vg_asset_read( "models/test.mdl" );
141 model *char_dev = vg_asset_read( "models/char_dev.mdl" );
142 scene_add_model( &player_scene, char_dev,
143 submodel_get( char_dev, "joint" ),
144 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
145 free(char_dev);
146
147 scene_add_model( &world_scene, world,
148 submodel_get( world, "terrain" ),
149 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
150
151 int id_tree = submodel_get( test, "tree" ),
152 id_groundcover[] =
153 {
154 submodel_get( test, "bush" ),
155 submodel_get( test, "grass" ),
156 submodel_get( test, "blubber" ),
157 submodel_get( test, "blubber" ),
158 submodel_get( test, "blubber" ),
159 submodel_get( test, "grassthin" )
160 };
161
162 /* Sprinkle some trees in the terrain areas */
163 v3f range;
164 v3_sub( world_scene.bbx[1], world_scene.bbx[0], range );
165
166 for( int i=0; i<8000; i++ )
167 {
168 v3f pos;
169
170 pos[0] = vg_randf();
171 pos[1] = 0.0f;
172 pos[2] = vg_randf();
173 v3_muladd( world_scene.bbx[0], pos, range, pos );
174
175 if( sample_scene_height( &world_scene, pos ) )
176 {
177 scene_add_model( &test_scene, test,
178 id_tree,
179 pos, vg_randf() * VG_TAUf, vg_randf() * 0.5f + 0.5f );
180 }
181 }
182
183 world_terrain_count = world_scene.indice_count;
184
185 scene_add_model( &world_scene, world,
186 submodel_get( world, "road" ),
187 (v3f){0.0f,0.0f,0.0f}, 0.0f, 1.0f );
188 world_road_count = world_scene.indice_count-world_terrain_count;
189
190 free( test );
191 free( world );
192
193 #if 0
194 scene_compute_occlusion( &test_scene );
195 scene_shadow_gradient( &test_scene, 1, 0.0f, 1.0f );
196 scene_shadow_sphere( &test_scene, (v3f){ 0.0f,4.0f,0.0f},
197 (v4f){1.0f, 2.0f, 0.0f, 0.0f}, lightDir );
198 #endif
199
200 scene_upload( &player_scene );
201 scene_upload( &world_scene );
202 scene_upload( &test_scene );
203
204 reset_player( 0, NULL );
205 player_transform_update();
206 }
207
208 v3f head;
209
210 void vg_update(void)
211 {
212 float timestep = 1.0f/60.0f;
213
214 if( freecam )
215 {
216 m4x3f cam_rot;
217 m4x3_identity( cam_rot );
218 m4x3_rotate_y( cam_rot, -player.look_dir[0] );
219 m4x3_rotate_x( cam_rot, -player.look_dir[1] );
220
221 v3f lookdir = { 0.0f, 0.0f, -1.0f },
222 sidedir = { 1.0f, 0.0f, 0.0f };
223
224 m4x3_mulv( cam_rot, lookdir, lookdir );
225 m4x3_mulv( cam_rot, sidedir, sidedir );
226
227 float movespeed = 5.0f;
228 static v2f mouse_last,
229 view_vel = { 0.0f, 0.0f };
230 static v3f move_vel = { 0.0f, 0.0f, 0.0f };
231
232 if( vg_get_button_down( "primary" ) )
233 {
234 v2_copy( vg_mouse, mouse_last );
235 }
236 else if( vg_get_button( "primary" ) )
237 {
238 v2f delta;
239 v2_sub( vg_mouse, mouse_last, delta );
240 v2_copy( vg_mouse, mouse_last );
241
242 v2_muladds( view_vel, delta, 0.005f, view_vel );
243 }
244
245 v2_muls( view_vel, 0.75f, view_vel );
246 v2_add( view_vel, player.look_dir, player.look_dir );
247 player.look_dir[1] =
248 vg_clampf( player.look_dir[1], -VG_PIf*0.5f, VG_PIf*0.5f );
249
250 if( vg_get_button( "forward" ) )
251 v3_muladds( move_vel, lookdir, timestep * movespeed, move_vel );
252 if( vg_get_button( "back" ) )
253 v3_muladds( move_vel, lookdir, timestep *-movespeed, move_vel );
254 if( vg_get_button( "left" ) )
255 v3_muladds( move_vel, sidedir, timestep *-movespeed, move_vel );
256 if( vg_get_button( "right" ) )
257 v3_muladds( move_vel, sidedir, timestep * movespeed, move_vel );
258
259 v3_muls( move_vel, 0.75f, move_vel );
260 v3_add( move_vel, player.view, player.view );
261
262 return;
263 }
264
265 if( vg_get_button( "forward" ) )
266 {
267 v3f dir = { 0.0f, 0.0f, -1.0f };
268
269 m3x3_mulv( player.to_world, dir, dir );
270 v3_muladds( player.v, dir, 5.0f * timestep, player.v );
271 }
272
273 /* Get front and back contact points */
274 v3f contact_front, contact_back, fwd, fwd1, contact_norm, vup;
275
276 m3x3_mulv( player.to_world, (v3f){0.0f,0.0f,-1.0f}, fwd );
277 m3x3_mulv( player.to_world, (v3f){0.03f,0.0f,-1.0f}, fwd1 );
278 m3x3_mulv( player.to_world, (v3f){0.0f,1.0f,0.0f}, vup );
279
280 v3_muladds( player.co, fwd, 1.0f, contact_front );
281 v3_muladds( player.co, fwd,-1.0f, contact_back );
282 v3_muladds( player.co, fwd1, 1.0f, contact_norm );
283
284 sample_scene_height( &world_scene, contact_front );
285 sample_scene_height( &world_scene, contact_back );
286 sample_scene_height( &world_scene, contact_norm );
287
288 v3f norm;
289 v3f v0, v1;
290 v3_sub( contact_back, contact_norm, v0 );
291 v3_sub( contact_front, contact_norm, v1 );
292 v3_cross( v1, v0, norm );
293 v3_normalize( norm );
294
295 v3f gravity = { 0.0f, -9.6f, 0.0f };
296 v3_muladds( player.v, gravity, timestep, player.v );
297
298 v3f ground_pos;
299 v3_copy( player.co, ground_pos );
300 sample_scene_height( &world_scene, ground_pos );
301
302 static int in_air = 1;
303
304 if( in_air )
305 {
306 if( ground_pos[1] > player.co[1] )
307 in_air = 0;
308 }
309
310 if( !in_air )
311 {
312 float resistance = v3_dot( norm, player.v );
313
314 if( resistance >= 0.0f )
315 in_air = 1;
316 else
317 {
318 v3_muladds( player.v, norm, -resistance, player.v );
319 }
320 }
321
322 /* vg_info( "%.3f | %.3f\n", player.v[1], resistance ); */
323 v3_muladds( player.co, player.v, timestep, player.co );
324
325 float slip = 0.0f;
326 float yawamt = 0.0f;
327
328 if( !in_air )
329 {
330 player.co[1] = (contact_front[1]+contact_back[1])*0.5f;
331
332 vg_line( player.co, contact_front, 0xff00ffff );
333 vg_line( player.co, contact_back, 0xff00ffa0 );
334
335 /* Create the 'travel' vector */
336 v3f travel;
337 v3_sub( contact_front, contact_back, travel );
338 v3_normalize( travel );
339
340 /* Apply gravity */
341 #if 0
342 float gravity_conversion = -v3_dot( travel, gravity );
343 vel[2] += gravity_conversion * substep;
344 #endif
345
346 /* Get localized (rotated) rigidbody forces
347 * -z
348 * ^
349 * -|-
350 * |
351 * +z
352 */
353
354 v3f vel;
355 m3x3_mulv( player.to_local, player.v, vel );
356
357 /* Calculate local forces */
358 slip = -vel[0] / vel[2];
359 float substep = timestep * 0.2f;
360
361 if( fabsf( slip ) > 1.2f )
362 {
363 slip = vg_signf( slip ) * 1.2f;
364 }
365
366 for( int i=0; i<5; i++ )
367 {
368 if( fabsf(vel[2]) >= 0.02f*substep )
369 vel[2] += vg_signf( vel[2] ) * -0.02f * substep;
370 if( fabsf(vel[0]) >= 6.0f*substep )
371 vel[0] += vg_signf( vel[0] ) * -6.0f * substep;
372 }
373
374 m3x3_mulv( player.to_world, vel, player.v );
375
376 if( vg_get_button( "yawl" ) )
377 yawamt = 1.6f * timestep;
378 if( vg_get_button( "yawr" ) )
379 yawamt = -1.6f * timestep;
380
381 yawamt -= vg_get_axis( "horizontal" ) * 1.6f * timestep;
382
383 }
384 else
385 {
386 yawamt -= vg_get_axis( "horizontal" ) * 3.6f * timestep;
387 }
388
389 v4f rotate;
390 q_axis_angle( rotate, vup, yawamt );
391 q_mul( rotate, player.rot, player.rot );
392
393 player.look_dir[0] = atan2f( player.v[0], -player.v[2] );
394
395 /* Creating a skeleton of the player dynamically */
396 float kheight = 1.8f,
397 kleg = 0.6f;
398
399 v2f ac;
400
401 static v3f last_vel = { 0.0f, 0.0f, 0.0f };
402 static v3f bob, bob1;
403
404 v3_sub( player.v, last_vel, player.a );
405 v3_copy( player.v, last_vel );
406 v3_add( bob, player.a, bob );
407
408 bob[0] = vg_clampf( bob[0], -0.4f, 1.0f );
409 bob[1] = vg_clampf( bob[1], -0.4f, 1.3f );
410 bob[2] = vg_clampf( bob[2], -0.4f, 1.0f );
411
412 v3_lerp( bob, (v3f){ 0.0f, 0.0f, 0.0f }, 0.1f, bob );
413 v3_lerp( bob1, bob, 0.1f, bob1 );
414
415 /* Head */
416 head[0] = (-sinf(slip)*0.9f * kheight + bob1[0]*0.6f) * 0.54f;
417 head[1] = cosf(slip)*0.9f * kheight +-bob1[1]*1.4f;
418 head[2] = 0.0f;
419
420 m4x3_mulv( player.to_world, head, head );
421 v3_copy( head, player.view );
422
423 player_transform_update();
424 }
425
426 static void debug_grid( v3f at )
427 {
428 v3f base;
429 v3_floor( at, base );
430
431 for( int y=0; y<16; y++ )
432 {
433 vg_line( (v3f){ base[0] - 8, base[1], base[2]+y-8 },
434 (v3f){ base[0] + 8, base[1], base[2]+y-8 },
435 0x40ffffff );
436 }
437 for( int x=0; x<16; x++ )
438 {
439 vg_line( (v3f){ base[0]+x-8, base[1], base[2]-8 },
440 (v3f){ base[0]+x-8, base[1], base[2]+8 },
441 0x40ffffff );
442 }
443 }
444
445 void vg_render(void)
446 {
447 glViewport( 0,0, vg_window_x, vg_window_y );
448
449 glDisable( GL_DEPTH_TEST );
450 glClearColor( 0.1f, 0.0f, 0.2f, 1.0f );
451 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
452
453 v3f pos_inv;
454 v3_negate( player.view, pos_inv );
455
456 float speed = v3_length( player.v );
457 v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f };
458 v3_muls( shake, speed*0.01f, shake );
459
460 m4x3_identity( world_matrix );
461 m4x3_rotate_x( world_matrix,
462 freecam? player.look_dir[1]: 0.3f+shake[1]*0.04f );
463 m4x3_rotate_y( world_matrix, player.look_dir[0]+shake[0]*0.02f );
464 m4x3_translate( world_matrix, pos_inv );
465
466 m4x4f world_4x4;
467 m4x3_expand( world_matrix, world_4x4 );
468
469 m4x4_projection( vg_pv,
470 freecam? 90.0f: 130.0f,
471 (float)vg_window_x / (float)vg_window_y,
472 0.01f, 1000.0f );
473 m4x4_mul( vg_pv, world_4x4, vg_pv );
474
475 if( debugroad )
476 draw_road_patch_dev( &road_main );
477
478 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 );
479 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 );
480 vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
481
482 v3f board_fwd = { 0.0f, 0.0f, -1.0f };
483 v3f board_side = { 1.0f, 0.0f, 0.0f };
484
485 m3x3_mulv( player.to_world, board_fwd, board_fwd );
486 m3x3_mulv( player.to_world, board_side, board_side );
487
488 v3f bnw, bne, bse, bsw;
489
490 v3_muladds( player.co, board_fwd, 0.75f, bnw );
491 v3_muladds( player.co, board_fwd, -0.75f, bsw );
492 v3_muladds( bnw, board_side, 0.1f, bne );
493 v3_muladds( bnw, board_side, -0.1f, bnw );
494 v3_muladds( bsw, board_side, 0.1f, bse );
495 v3_muladds( bsw, board_side, -0.1f, bsw );
496
497 vg_line( bnw, bne, 0xff00ff00 );
498 vg_line( bne, bse, 0xff00ff00 );
499 vg_line( bse, bsw, 0xff00ff00 );
500 vg_line( bsw, bnw, 0xff00ff00 );
501
502 glEnable( GL_DEPTH_TEST );
503
504 SHADER_USE( shader_debug_vcol );
505 m4x3f temp;
506 m4x4f temp1;
507
508 vg_tex2d_bind( &tex_grid, 0 );
509 scene_tree_sway = 0.0f;
510
511 m4x3_identity( temp );
512 m4x3_expand( temp, temp1 );
513 glUniformMatrix4fv( SHADER_UNIFORM( shader_debug_vcol, "uMdl" ),
514 1, GL_FALSE, (float *)temp1 );
515 scene_draw( &player_scene, -1, 0 );
516
517 m4x3_identity( temp );
518 m4x3_expand( temp, temp1 );
519 glUniformMatrix4fv( SHADER_UNIFORM( shader_debug_vcol, "uMdl" ),
520 1, GL_FALSE, (float *)temp1 );
521
522 vg_tex2d_bind( &tex_norwey, 0 );
523 scene_tree_sway = 0.1f;
524 scene_draw( &test_scene, -1, 0 );
525
526 vg_tex2d_bind( &tex_grid, 0 );
527 scene_tree_sway = 0.0f;
528 scene_draw( &world_scene, world_terrain_count, 0 );
529
530 vg_tex2d_bind( &tex_road, 0 );
531 scene_draw( &world_scene, world_road_count, world_terrain_count );
532
533 glDisable( GL_DEPTH_TEST );
534 }
535
536 void vg_ui(void)
537 {
538 char buf[20];
539
540 snprintf( buf, 20, "%.2fm/s", v3_length( player.v ) );
541 gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left );
542
543 snprintf( buf, 20, "%.2f %.2f %.2f m/s",
544 player.a[0], player.a[1], player.a[2] );
545
546 gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left );
547
548 if( vg_gamepad_ready )
549 {
550 for( int i=0; i<6; i++ )
551 {
552 snprintf( buf, 20, "%.2f", vg_gamepad.axes[i] );
553 gui_text( (ui_px [2]){ 0, (i+2)*20 }, buf, 1, k_text_align_left );
554 }
555 }
556 else
557 {
558 gui_text( (ui_px [2]){ 0, 40 },
559 "Gamepad not ready", 1, k_text_align_left );
560 }
561 }
562
563 void vg_free(void){}