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