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" };
13 vg_tex2d
*texture_list
[] =
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;
36 #include "character.h"
38 int main( int argc
, char *argv
[] )
40 vg_init( argc
, argv
, "Voyager Game Engine" );
50 float vswitch
, slip
, slip_last
;
52 float iY
; /* Yaw inertia */
59 v2f look_dir
; /* TEMP */
65 v3f land_target_log
[12];
69 m4x3f to_world
, to_local
;
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
,
91 m4x3f mleg_l
, mknee_l
, mleg_r
, mknee_r
, mboard
;
92 m4x3f marm_l
, melbow_l
, marm_r
, melbow_r
, mbutt
,
96 v3f handl_target
, handr_target
,
106 scene foliage
, /* Tree shader */
107 geo
, /* Std shader, collisions */
108 detail
; /* Std shader, no collisions */
116 static void player_transform_update(void)
118 q_m3x3( player
.rot
, player
.to_world
);
119 v3_copy( player
.co
, player
.to_world
[3] );
121 m4x3_invert_affine( player
.to_world
, player
.to_local
);
124 static int reset_player( int argc
, char const *argv
[] )
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
;
132 player_transform_update();
136 void vg_register(void)
143 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
145 vg_convar_push( (struct vg_convar
){
148 .data_type
= k_convar_dtype_i32
,
149 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
153 vg_convar_push( (struct vg_convar
){
155 .data
= &sv_debugcam
,
156 .data_type
= k_convar_dtype_i32
,
157 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
161 vg_convar_push( (struct vg_convar
){
164 .data_type
= k_convar_dtype_i32
,
165 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
169 vg_convar_push( (struct vg_convar
){
172 .data_type
= k_convar_dtype_i32
,
173 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
177 vg_convar_push( (struct vg_convar
){
180 .data_type
= k_convar_dtype_i32
,
181 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
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 },
193 vg_convar_push( (struct vg_convar
){
195 .data
= &clock_divider
,
196 .data_type
= k_convar_dtype_i32
,
197 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
201 vg_function_push( (struct vg_cmd
){
203 .function
= reset_player
206 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
207 v3_normalize( lightDir
);
209 character_load( &player
.mdl
, "ch_default" );
212 model
*cement_model
= vg_asset_read("models/cement_r1.mdl" );
213 model_unpack( cement_model
, &world
.cement
);
214 free( cement_model
);
217 scene_init( &world
.geo
);
218 scene_init( &world
.detail
);
219 scene_init( &world
.foliage
);
221 model
*mworld
= vg_asset_read( "models/free_dev.mdl" );
222 model
*mtest
= vg_asset_read( "models/test.mdl" );
224 model
*msky
= vg_asset_read( "models/skydome.mdl" );
225 model_unpack( msky
, &world
.skydome
);
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
);
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
);
236 submodel
*ptree
= submodel_get( mtest
, "tree" ),
239 submodel_get( mtest
, "bush" ),
240 submodel_get( mtest
, "bush" ),
241 submodel_get( mtest
, "blubber" ),
244 /* Sprinkle some trees in the terrain areas */
246 v3_sub( world
.geo
.bbx
[1], world
.geo
.bbx
[0], range
);
249 int const ktree_count
= 8000,
250 kfoliage_count
= 200000;
252 int const ktree_count
= 200,
256 for( int i
=0; i
<ktree_count
; i
++ )
258 v3f pos
= { vg_randf(), 0.0f
, vg_randf() },
261 v3_muladd( world
.geo
.bbx
[0], pos
, range
, pos
);
263 if( sample_scene_height( &world
.geo
, pos
, norm
) )
265 if( v3_dot( norm
, (v3f
){ 0.0f
, 1.0f
, 0.0f
} ) > 0.9f
)
267 scene_add_model( &world
.foliage
, mtest
, ptree
,
268 pos
, vg_randf() * VG_TAUf
, vg_randf() * 0.5f
+ 0.5f
);
273 for( int i
=0; i
<kfoliage_count
; i
++ )
275 v3f pos
= { vg_randf(), 0.0f
, vg_randf() },
278 v3_muladd( world
.geo
.bbx
[0], pos
, range
, pos
);
280 if( sample_scene_height( &world
.geo
, pos
, norm
) )
282 if( v3_dot( norm
, (v3f
){ 0.0f
, 1.0f
, 0.0f
} ) > 0.7f
)
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
);
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
);
295 scene_add_model( &world
.detail
, mworld
, submodel_get( mworld
, "art" ),
296 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
301 scene_compute_occlusion( &world
.foliage
);
303 scene_upload( &world
.foliage
);
304 scene_upload( &world
.geo
);
305 scene_upload( &world
.detail
);
307 reset_player( 0, NULL
);
308 player_transform_update();
311 static float ktimestep
= 1.0f
/60.0f
;
313 static void player_freecam(void)
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] );
320 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
321 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
323 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
324 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
326 float movespeed
= 5.0f
;
327 static v2f mouse_last
,
328 view_vel
= { 0.0f
, 0.0f
};
330 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
332 if( vg_get_button_down( "primary" ) )
333 v2_copy( vg_mouse
, mouse_last
);
334 else if( vg_get_button( "primary" ) )
337 v2_sub( vg_mouse
, mouse_last
, delta
);
338 v2_copy( vg_mouse
, mouse_last
);
340 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
343 v2_muls( view_vel
, 0.75f
, view_vel
);
344 v2_add( view_vel
, player
.look_dir
, player
.look_dir
);
346 vg_clampf( player
.look_dir
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
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
);
357 v3_muls( move_vel
, 0.75f
, move_vel
);
358 v3_add( move_vel
, player
.view
, player
.view
);
362 static void apply_gravity( v3f vel
, float const timestep
)
364 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
365 v3_muladds( vel
, gravity
, timestep
, vel
);
368 static void player_start_air(void)
372 float pstep
= ktimestep
*10.0f
;
374 float best_velocity_mod
= 0.0f
,
375 best_velocity_delta
= -9999.9f
;
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;
385 m3x3_identity( player
.vr
);
387 for( int m
=0;m
<=5; m
++ )
389 float vmod
= ((float)m
/ 5.0f
)*0.15f
;
392 v3_copy( player
.co
, pco
);
393 v3_copy( player
.v
, pv
);
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
404 q_axis_angle( vr_q
, axis
, vmod
);
407 for( int i
=0; i
<50; i
++ )
409 v3_copy( pco
, pco1
);
410 apply_gravity( pv
, pstep
);
412 m3x3_mulv( vr
, pv
, pv
);
413 v3_muladds( pco
, pv
, pstep
, pco
);
415 vg_line( pco
, pco1
, i
&0x1?0xff000000:0xffffffff );
419 int hit
= sample_scene_height( &world
.geo
, sh
, targetn
);
421 if( sh
[1] >= pco
[1] && hit
)
423 float land_delta
= v3_dot( pv
, targetn
);
425 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
427 best_velocity_delta
= land_delta
;
428 best_velocity_mod
= vmod
;
430 v3_copy( sh
, player
.land_target
);
432 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
433 q_m3x3( vr_q
, player
.vr
);
435 v3_copy( sh
, player
.land_target_log
[player
.land_log_count
++] );
441 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
444 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
447 static int sample_if_resistant( v3f pos
)
450 v3_copy( pos
, ground
);
452 if( sample_scene_height( &world
.geo
, ground
, norm
) )
455 v3_copy( player
.v
, angle
);
456 v3_normalize( angle
);
457 float resistance
= v3_dot( norm
, angle
);
459 if( resistance
< 0.25f
)
461 v3_copy( ground
, pos
);
469 static void player_physics_ground(void)
472 * Getting surface collision points,
473 * the contact manifold is a triangle for simplicity.
475 v3f contact_front
, contact_back
, fwd
, fwd1
, contact_norm
, vup
, vside
,
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
);
488 sample_if_resistant( contact_front
) +
489 sample_if_resistant( contact_back
) +
490 sample_if_resistant( contact_norm
);
492 if( contact_count
< 3 )
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
);
505 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
506 vg_line( contact_back
, contact_front
, 0xff0000ff );
508 /* Surface alignment */
509 float angle
= v3_dot( vup
, norm
);
510 v3_cross( vup
, norm
, axis
);
515 q_axis_angle( correction
, axis
, acosf(angle
) );
516 q_mul( correction
, player
.rot
, player
.rot
);
519 float resistance
= v3_dot( norm
, player
.v
);
521 if( resistance
>= 0.0f
)
528 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
531 /* This is where velocity integration used to be */
535 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
538 m3x3_mulv( player
.to_local
, player
.v
, vel
);
540 /* Calculate local forces */
542 slip
= (-vel
[0] / vel
[2]) * player
.vswitch
;
543 if( fabsf( slip
) > 1.2f
)
544 slip
= vg_signf( slip
) * 1.2f
;
548 if( player
.slip_last
*slip
< 0.0f
&& fabsf(slip
) > 0.7f
)
550 vg_warn( "SWITCH\n" );
551 player
.vswitch
= -player
.vswitch
;
555 player
.slip_last
= slip
;
558 float substep
= ktimestep
* 0.2f
;
560 for( int i
=0; i
<5; i
++ )
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
;
568 m3x3_mulv( player
.to_world
, vel
, player
.v
);
570 if( vg_get_button( "yawl" ) )
571 player
.iY
+= 3.6f
* ktimestep
;
572 if( vg_get_button( "yawr" ) )
573 player
.iY
-= 3.6f
* ktimestep
;
575 float steer
= vg_get_axis( "horizontal" );
576 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
579 static void draw_cross(v3f pos
,u32 colour
)
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
);
593 static void player_physics_air(void)
595 /* Debug prediciton */
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 );
601 draw_cross( player
.land_target
, 0xff0000ff );
603 v3f ground_pos
, ground_norm
;
604 v3_copy( player
.co
, ground_pos
);
606 if( sample_scene_height( &world
.geo
, ground_pos
, ground_norm
) )
608 if( ground_pos
[1] > player
.co
[1] )
617 * TODO: Find best landing surface and guide player towords it
619 float pstep
= ktimestep
*10.0f
;
622 v3_copy( player
.co
, pco
);
623 v3_copy( player
.v
, pv
);
626 for( int i
=0; i
<50; i
++ )
628 v3_copy( pco
, pco1
);
629 apply_gravity( pv
, pstep
);
630 v3_muladds( pco
, pv
, pstep
, pco
);
632 vg_line( pco
, pco1
, i
&0x1?0xff000000:0xffffffff );
636 int hit
= sample_scene_height( &world
.geo
, sh
, targetn
);
638 if( sh
[1] >= pco
[1] && hit
)
641 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
643 float angle
= v3_dot( localup
, targetn
);
645 v3_cross( localup
, targetn
, axis
);
650 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
);
651 q_mul( correction
, player
.rot
, player
.rot
);
654 draw_cross( sh
, 0xffff0000 );
660 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
663 static void player_animate(void);
664 static void player_update(void)
666 static int clock
= 0;
669 if( clock
>= clock_divider
)
681 if( vg_get_axis("grabl")>0.0f
)
682 reset_player(0,NULL
);
683 if( vg_get_button( "push" ) )
685 v3f dir
= { 0.0f
, 0.0f
, -1.0f
};
687 m3x3_mulv( player
.to_world
, dir
, dir
);
688 v3_muladds( player
.v
, dir
, 5.0f
* ktimestep
, player
.v
);
691 float horizontal
= vg_get_axis("horizontal"),
692 vertical
= vg_get_axis("vertical");
694 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
695 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
697 /* Integrate velocity */
700 apply_gravity( player
.v
, ktimestep
);
701 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
704 /* Integrate inertia */
705 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
706 m3x3_mulv( player
.to_world
, vup
, vup
);
708 q_axis_angle( rotate
, vup
, player
.iY
);
709 q_mul( rotate
, player
.rot
, player
.rot
);
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
;
715 player
.iY
= 0.0f
; /* temp */
718 player_physics_air();
721 player_physics_ground();
723 /* Camera and character */
725 player_transform_update();
726 q_normalize(player
.rot
);
734 /* Creating a skeleton of the player dynamically */
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
);
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
));
746 if( vg_maxf(lslip
,grab
) > 0.5f
)
748 if( player
.slip
< 0.0f
&& player
.in_air
)
750 player
.handl_target
[0] = 0.15f
;
751 player
.handl_target
[1] = 0.1f
;
752 player
.handl_target
[2] = 0.4f
;
756 player
.handr_target
[0] = 0.15f
;
757 player
.handr_target
[1] = 0.1f
;
758 player
.handr_target
[2] = -0.4f
;
763 player
.handr_target
[0] = -0.15f
;
764 player
.handr_target
[1] = 0.1f
;
765 player
.handr_target
[2] = 0.4f
;
772 static void player_animate(void)
774 /* Camera position */
775 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
776 static v3f momentum
, bob
;
778 v3_sub( player
.v
, last_vel
, player
.a
);
779 v3_copy( player
.v
, last_vel
);
781 v3_add( momentum
, player
.a
, momentum
);
782 v3_lerp( momentum
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, momentum
);
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
);
792 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
794 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
795 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
797 float kheight
= 2.0f
,
802 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
806 m3x3_mulv( player
.to_local
, bob
, offset
);
808 offset
[0] *= 0.3333f
;
811 v3_muladds( head
, offset
, 0.7f
, head
);
812 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
814 v3_copy( head
, player
.view
);
816 /* New board transformation */
817 v4f board_rotation
; v3f board_location
;
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
);
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
);
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] );
834 /* In the air, the dude should grab with the side thats highest,
835 * while also sliding the same foot downwards a bit */
840 player
.handl_target
[0] = 0.0f
;
841 player
.handl_target
[1] = 0.0f
;
842 player
.handl_target
[2] = 0.6f
;
844 player
.handr_target
[0] = 0.0f
;
845 player
.handr_target
[1] = 0.0f
;
846 player
.handr_target
[2] = -0.6f
;
848 if( 1||player
.in_air
)
850 float tuck
= player
.board_xy
[1],
851 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
855 foot_l
*= 1.0f
-tuck_amt
*1.5f
;
857 if( player
.grab
> 0.1f
)
859 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
860 player
.handl_target
);
865 foot_r
*= 1.0f
-tuck_amt
*1.4f
;
867 if( player
.grab
> 0.1f
)
869 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
870 player
.handr_target
);
881 float *hips
= player
.mdl
.ik_body
.base
,
882 *collar
= player
.mdl
.ik_body
.end
,
883 *pole
= player
.mdl
.ik_body
.pole
;
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
);
889 v3_copy( player
.view
, collar
);
890 v3_add( (v3f
){ 0.2f
,-0.45f
,0.0f
}, collar
, hips
);
892 player
.mdl
.rhip
= sinf(vg_time
);
893 player
.mdl
.rcollar
= sinf(vg_time
)*0.5f
;
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
;
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
);
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
);
909 v3f hl
, hr
, neckl
= {0.0f
, 0.5f
, 0.2f
},
910 neckr
= {0.0f
, 0.5f
,-0.2f
};
912 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
913 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
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
);
923 v3_copy( player
.v
, nv
);
925 v3_muladds( player
.view
, nv
, -3.0f
, player
.view
);
928 v3f camoffs
= {-0.3f
,0.0f
,0.3f
};
929 v3_add( player
.view
, camoffs
, player
.view
);
931 m4x3_copy( mboard
, player
.mdl
.matrices
[k_chpart_wheels
] );
934 static void draw_player(void)
937 SHADER_USE(shader_standard_lit
);
939 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit
, "uPv" ),
940 1, GL_FALSE
, (float *)vg_pv
);
941 glUniform1i( SHADER_UNIFORM( shader_standard_lit
, "uTexMain" ), 0 );
943 GLint kuMdl
= SHADER_UNIFORM( shader_standard_lit
, "uMdl" );
947 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
948 0.35f
*kscale
,0.35f
*kscale
,0.35f
*kscale
,1.0f
);
950 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.mboard
);
951 submodel_draw( &player
.board
);
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
);
958 glBlendFunc(GL_SRC_ALPHA
, GL_ONE
);
959 glBlendEquation(GL_FUNC_ADD
);
960 glDisable( GL_DEPTH_TEST
);
963 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
964 0.2f
*kscale
,0.8f
*kscale
,0.4f
*kscale
,0.14f
);
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
);
971 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.mleg_l
);
972 submodel_draw( &player
.leg_l0
);
974 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.mknee_l
);
975 submodel_draw( &player
.leg_l1
);
977 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.mleg_r
);
978 submodel_draw( &player
.leg_r0
);
980 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.mknee_r
);
981 submodel_draw( &player
.leg_r1
);
984 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.marm_l
);
985 submodel_draw( &player
.arm_l0
);
987 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.melbow_l
);
988 submodel_draw( &player
.arm_l1
);
990 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.marm_r
);
991 submodel_draw( &player
.arm_r0
);
993 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.melbow_r
);
994 submodel_draw( &player
.arm_r1
);
997 glUniformMatrix4x3fv( kuMdl
, 1, GL_FALSE
, (float *)player
.mbutt
);
998 submodel_draw( &player
.body
);
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
);
1004 glDisable(GL_BLEND
);
1005 glEnable( GL_DEPTH_TEST
);
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
);
1016 void vg_render(void)
1018 glViewport( 0,0, vg_window_x
, vg_window_y
);
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
);
1026 m4x3_mulv( player
.to_world
, player
.view
, pos_inv
);
1027 v3_negate( pos_inv
, pos_inv
);
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
);
1033 m4x3_identity( world_matrix
);
1034 m4x3_rotate_x( world_matrix
,
1037 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
1039 m4x3_rotate_y( world_matrix
, player
.look_dir
[0]+shake
[0]*0.02f
);
1040 m4x3_translate( world_matrix
, pos_inv
);
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
,
1048 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
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 );
1054 glEnable( GL_DEPTH_TEST
);
1056 scene_foliage_shader_use();
1058 m4x3_identity( temp1
);
1059 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_debug_vcol
, "uMdl" ),
1060 1, GL_FALSE
, (float *)temp1
);
1062 vg_tex2d_bind( &tex_norwey
, 0 );
1063 scene_tree_sway
= 0.1f
;
1065 scene_bind( &world
.foliage
);
1066 scene_draw( &world
.foliage
);
1068 scene_debugsdf( &world
.foliage
);
1070 SHADER_USE(shader_unlit
);
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
);
1079 glUniform1i( SHADER_UNIFORM( shader_unlit
, "uTexMain" ), 0 );
1080 vg_tex2d_bind( &tex_sky
, 0 );
1082 mesh_bind( &world
.skydome
);
1083 mesh_draw( &world
.skydome
);
1086 vg_tex2d_bind( &tex_cement
, 0 );
1087 mesh_bind( &world
.cement
);
1088 mesh_draw( &world
.cement
);
1091 SHADER_USE(shader_standard_lit
);
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
);
1099 vg_tex2d_bind( &tex_grid
, 0 );
1101 scene_bind( &world
.geo
);
1103 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1104 0.2f
,0.36f
,0.25f
,1.0f
);
1105 submodel_draw( &world
.terrain
);
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
);
1115 scene_bind( &world
.detail
);
1116 scene_draw( &world
.detail
);
1120 glDisable( GL_DEPTH_TEST
);
1121 vg_lines_drawall( (float *)vg_pv
);
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
);
1128 m4x3_identity( world_matrix
);
1131 v3_negate( player
.co
, debugcam
);
1132 debugcam
[2] -= 2.0f
;
1133 debugcam
[1] -= 0.7f
;
1135 m4x3_translate( world_matrix
, debugcam
);
1136 m4x3_expand( world_matrix
, world_4x4
);
1138 m4x4_projection( vg_pv
,
1140 (float)128.0f
/ (float)128.0f
,
1142 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1146 glEnable( GL_DEPTH_TEST
);
1151 glDisable( GL_DEPTH_TEST
);
1152 vg_lines_drawall( (float *)vg_pv
);
1154 glViewport( 0,0, vg_window_x
, vg_window_y
);
1161 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1162 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1164 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1165 player
.a
[0], player
.a
[1], player
.a
[2] );
1167 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1169 if( vg_gamepad_ready
)
1171 for( int i
=0; i
<6; i
++ )
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
);
1179 gui_text( (ui_px
[2]){ 0, 40 },
1180 "Gamepad not ready", 1, k_text_align_left
);
1184 void vg_free(void){}