2 #define VG_FRAMEBUFFER_RESIZE 1
6 vg_tex2d tex_norwey
= { .path
= "textures/norway_foliage.qoi" };
7 vg_tex2d tex_grid
= { .path
= "textures/grid.qoi" };
8 vg_tex2d tex_sky
= { .path
= "textures/sky.qoi" };
9 vg_tex2d tex_gradients
= { .path
= "textures/gradients.qoi",
10 .flags
= VG_TEXTURE_CLAMP
};
11 vg_tex2d tex_cement
= { .path
= "textures/cement512.qoi" };
12 vg_tex2d tex_pallet
= { .path
= "textures/ch_gradient.qoi" };
14 vg_tex2d
*texture_list
[] =
24 SHADER_DEFINE( shader_blit
,
25 "layout (location=0) in vec2 a_co;"
30 "gl_Position = vec4(a_co*2.0-1.0,0.0,1.0);"
37 "uniform sampler2D uTexMain;"
43 "FragColor = texture( uTexMain, aUv );"
46 UNIFORMS({ "uTexMain" })
50 static int freecam
= 0;
51 static int debugview
= 0;
52 static int debugsdf
= 0;
53 static int sv_debugcam
= 0;
54 static int sv_phys
= 0;
55 static int thirdperson
= 0;
56 static int clock_divider
= 1;
62 #include "character.h"
64 int main( int argc
, char *argv
[] )
66 vg_init( argc
, argv
, "Voyager Game Engine" );
76 float vswitch
, slip
, slip_last
,
79 float iY
; /* Yaw inertia */
86 v2f look_dir
; /* TEMP */
92 v3f land_target_log
[12];
96 m4x3f to_world
, to_local
;
111 leg_r0
, leg_r1
, foot_r
,
112 leg_l0
, leg_l1
, foot_l
,
113 arm_r0
, arm_r1
, hand_r
,
114 arm_l0
, arm_l1
, hand_l
,
118 m4x3f mleg_l
, mknee_l
, mleg_r
, mknee_r
, mboard
;
119 m4x3f marm_l
, melbow_l
, marm_r
, melbow_r
, mbutt
,
123 v3f handl_target
, handr_target
,
133 scene foliage
, /* Tree shader */
134 geo
, /* Std shader, collisions */
135 detail
; /* Std shader, no collisions */
143 static struct grender
145 GLuint fb_background
,
152 static void player_transform_update(void)
154 q_m3x3( player
.rot
, player
.to_world
);
155 v3_copy( player
.co
, player
.to_world
[3] );
157 m4x3_invert_affine( player
.to_world
, player
.to_local
);
160 static int reset_player( int argc
, char const *argv
[] )
162 v3_zero( player
.co
);
163 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player
.v
);
164 q_identity( player
.rot
);
165 player
.vswitch
= 1.0f
;
166 player
.slip_last
= 0.0f
;
168 player_transform_update();
172 void vg_register(void)
175 character_shader_register();
176 SHADER_INIT( shader_blit
);
181 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
183 vg_convar_push( (struct vg_convar
){
186 .data_type
= k_convar_dtype_i32
,
187 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
191 vg_convar_push( (struct vg_convar
){
193 .data
= &sv_debugcam
,
194 .data_type
= k_convar_dtype_i32
,
195 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
199 vg_convar_push( (struct vg_convar
){
202 .data_type
= k_convar_dtype_i32
,
203 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
207 vg_convar_push( (struct vg_convar
){
210 .data_type
= k_convar_dtype_i32
,
211 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
215 vg_convar_push( (struct vg_convar
){
218 .data_type
= k_convar_dtype_i32
,
219 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
223 vg_convar_push( (struct vg_convar
){
224 .name
= "thirdperson",
225 .data
= &thirdperson
,
226 .data_type
= k_convar_dtype_i32
,
227 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
231 vg_convar_push( (struct vg_convar
){
233 .data
= &clock_divider
,
234 .data_type
= k_convar_dtype_i32
,
235 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
239 vg_function_push( (struct vg_cmd
){
241 .function
= reset_player
244 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
245 v3_normalize( lightDir
);
247 character_load( &player
.mdl
, "ch_default" );
250 model
*cement_model
= vg_asset_read("models/cement_r1.mdl" );
251 model_unpack( cement_model
, &world
.cement
);
252 free( cement_model
);
255 scene_init( &world
.geo
);
256 scene_init( &world
.detail
);
257 scene_init( &world
.foliage
);
259 model
*mworld
= vg_asset_read( "models/free_dev.mdl" );
260 model
*mtest
= vg_asset_read( "models/test.mdl" );
262 model
*msky
= vg_asset_read( "models/skydome.mdl" );
263 model_unpack( msky
, &world
.skydome
);
266 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "terrain" ),
267 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
268 scene_copy_slice( &world
.geo
, &world
.terrain
);
270 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "terrain_rocks" ),
271 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
272 scene_copy_slice( &world
.geo
, &world
.terrain_rocks
);
274 submodel
*ptree
= submodel_get( mtest
, "tree" ),
277 submodel_get( mtest
, "bush" ),
278 submodel_get( mtest
, "bush" ),
279 submodel_get( mtest
, "blubber" ),
282 /* Sprinkle some trees in the terrain areas */
284 v3_sub( world
.geo
.bbx
[1], world
.geo
.bbx
[0], range
);
287 int const ktree_count
= 8000,
288 kfoliage_count
= 200000;
290 int const ktree_count
= 200,
294 for( int i
=0; i
<ktree_count
; i
++ )
296 v3f pos
= { vg_randf(), 0.0f
, vg_randf() },
299 v3_muladd( world
.geo
.bbx
[0], pos
, range
, pos
);
301 if( sample_scene_height( &world
.geo
, pos
, norm
) )
303 if( v3_dot( norm
, (v3f
){ 0.0f
, 1.0f
, 0.0f
} ) > 0.9f
)
305 scene_add_model( &world
.foliage
, mtest
, ptree
,
306 pos
, vg_randf() * VG_TAUf
, vg_randf() * 0.5f
+ 0.5f
);
311 for( int i
=0; i
<kfoliage_count
; i
++ )
313 v3f pos
= { vg_randf(), 0.0f
, vg_randf() },
316 v3_muladd( world
.geo
.bbx
[0], pos
, range
, pos
);
318 if( sample_scene_height( &world
.geo
, pos
, norm
) )
320 if( v3_dot( norm
, (v3f
){ 0.0f
, 1.0f
, 0.0f
} ) > 0.7f
)
322 scene_add_model( &world
.foliage
, mtest
,
323 pt_groundcover
[rand()%vg_list_size(pt_groundcover
)],
324 pos
, vg_randf() * VG_TAUf
, vg_randf() * 0.5f
+ 0.5f
);
329 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "road" ),
330 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
331 scene_copy_slice( &world
.geo
, &world
.terrain_road
);
333 scene_add_model( &world
.detail
, mworld
, submodel_get( mworld
, "art" ),
334 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
339 scene_compute_occlusion( &world
.foliage
);
341 scene_upload( &world
.foliage
);
342 scene_upload( &world
.geo
);
343 scene_upload( &world
.detail
);
345 reset_player( 0, NULL
);
346 player_transform_update();
348 /* Create framebuffers */
349 glGenFramebuffers( 1, &render
.fb_background
);
350 glBindFramebuffer( GL_FRAMEBUFFER
, render
.fb_background
);
352 glGenTextures( 1, &render
.rgb_background
);
353 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
354 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
,
355 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
357 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
358 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
359 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
361 render
.rgb_background
, 0);
364 float quad
[] = { 0.0f
, 0.0f
, 1.0f
, 1.0f
, 0.0f
, 1.0f
,
365 0.0f
, 0.0f
, 1.0f
, 0.0f
, 1.0f
, 1.0f
};
367 glGenVertexArrays( 1, &render
.fsquad
.vao
);
368 glGenBuffers( 1, &render
.fsquad
.vbo
);
369 glGenBuffers( 1, &render
.fsquad
.ebo
);
370 glBindVertexArray( render
.fsquad
.vao
);
371 glBindBuffer( GL_ARRAY_BUFFER
, render
.fsquad
.vbo
);
372 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
373 glBindVertexArray( render
.fsquad
.vao
);
374 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
375 sizeof(float)*2, (void*)0 );
376 glEnableVertexAttribArray( 0 );
381 static float ktimestep
= 1.0f
/60.0f
;
383 static void player_freecam(void)
386 m4x3_identity( cam_rot
);
387 m4x3_rotate_y( cam_rot
, -player
.look_dir
[0] );
388 m4x3_rotate_x( cam_rot
, -player
.look_dir
[1] );
390 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
391 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
393 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
394 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
396 float movespeed
= 5.0f
;
397 static v2f mouse_last
,
398 view_vel
= { 0.0f
, 0.0f
};
400 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
402 if( vg_get_button_down( "primary" ) )
403 v2_copy( vg_mouse
, mouse_last
);
404 else if( vg_get_button( "primary" ) )
407 v2_sub( vg_mouse
, mouse_last
, delta
);
408 v2_copy( vg_mouse
, mouse_last
);
410 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
413 v2_muls( view_vel
, 0.75f
, view_vel
);
414 v2_add( view_vel
, player
.look_dir
, player
.look_dir
);
416 vg_clampf( player
.look_dir
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
418 if( vg_get_button( "forward" ) )
419 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
420 if( vg_get_button( "back" ) )
421 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
422 if( vg_get_button( "left" ) )
423 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
424 if( vg_get_button( "right" ) )
425 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
427 v3_muls( move_vel
, 0.75f
, move_vel
);
428 v3_add( move_vel
, player
.view
, player
.view
);
432 static void apply_gravity( v3f vel
, float const timestep
)
434 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
435 v3_muladds( vel
, gravity
, timestep
, vel
);
438 static void player_start_air(void)
442 float pstep
= ktimestep
*10.0f
;
444 float best_velocity_mod
= 0.0f
,
445 best_velocity_delta
= -9999.9f
;
450 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, vup
);
451 v3_cross( vup
, player
.v
, axis
);
452 v3_normalize( axis
);
453 player
.land_log_count
= 0;
455 m3x3_identity( player
.vr
);
457 for( int m
=0;m
<=5; m
++ )
459 float vmod
= ((float)m
/ 5.0f
)*0.09f
;
462 v3_copy( player
.co
, pco
);
463 v3_copy( player
.v
, pv
);
466 * Try different 'rotations' of the velocity to find the best possible
467 * landing normal. This conserves magnitude at the expense of slightly
468 * unrealistic results
474 q_axis_angle( vr_q
, axis
, vmod
);
477 for( int i
=0; i
<50; i
++ )
479 v3_copy( pco
, pco1
);
480 apply_gravity( pv
, pstep
);
482 m3x3_mulv( vr
, pv
, pv
);
483 v3_muladds( pco
, pv
, pstep
, pco
);
485 vg_line( pco
, pco1
, i
&0x1?0xff000000:0xffffffff );
489 int hit
= sample_scene_height( &world
.geo
, sh
, targetn
);
491 if( sh
[1] >= pco
[1] && hit
)
493 float land_delta
= v3_dot( pv
, targetn
);
495 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
497 best_velocity_delta
= land_delta
;
498 best_velocity_mod
= vmod
;
500 v3_copy( sh
, player
.land_target
);
502 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
503 q_m3x3( vr_q
, player
.vr
);
505 v3_copy( sh
, player
.land_target_log
[player
.land_log_count
++] );
511 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
514 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
517 static int sample_if_resistant( v3f pos
)
520 v3_copy( pos
, ground
);
522 if( sample_scene_height( &world
.geo
, ground
, norm
) )
525 v3_copy( player
.v
, angle
);
526 v3_normalize( angle
);
527 float resistance
= v3_dot( norm
, angle
);
529 if( resistance
< 0.25f
)
531 v3_copy( ground
, pos
);
539 static void player_physics_ground(void)
542 * Getting surface collision points,
543 * the contact manifold is a triangle for simplicity.
545 v3f contact_front
, contact_back
, fwd
, fwd1
, contact_norm
, vup
, vside
,
548 float klength
= 0.65f
;
549 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 0.0f
,-1.0f
}, fwd
);
550 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
551 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
552 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
553 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
554 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
559 sample_if_resistant( contact_front
) +
560 sample_if_resistant( contact_back
) +
561 sample_if_resistant( contact_norm
);
563 if( contact_count
< 3 )
571 v3_sub( contact_norm
, contact_front
, v0
);
572 v3_sub( contact_back
, contact_front
, v1
);
573 v3_cross( v1
, v0
, norm
);
574 v3_normalize( norm
);
576 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
577 vg_line( contact_back
, contact_front
, 0xff0000ff );
579 /* Surface alignment */
580 float angle
= v3_dot( vup
, norm
);
581 v3_cross( vup
, norm
, axis
);
586 q_axis_angle( correction
, axis
, acosf(angle
) );
587 q_mul( correction
, player
.rot
, player
.rot
);
590 float resistance
= v3_dot( norm
, player
.v
);
592 if( resistance
>= 0.0f
)
599 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
602 /* This is where velocity integration used to be */
606 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
609 m3x3_mulv( player
.to_local
, player
.v
, vel
);
611 /* Calculate local forces */
613 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
614 if( fabsf( slip
) > 1.2f
)
615 slip
= vg_signf( slip
) * 1.2f
;
617 player
.reverse
= -vg_signf(vel
[2]);
619 float substep
= ktimestep
* 0.2f
;
620 for( int i
=0; i
<5; i
++ )
622 if( fabsf(vel
[2]) >= 0.02f
*substep
)
623 vel
[2] += vg_signf( vel
[2] ) * -0.02f
* substep
;
624 if( fabsf(vel
[0]) >= 7.0f
*substep
)
625 vel
[0] += vg_signf( vel
[0] ) * -7.0f
* substep
;
628 m3x3_mulv( player
.to_world
, vel
, player
.v
);
630 if( vg_get_button( "yawl" ) )
631 player
.iY
+= 3.6f
* ktimestep
;
632 if( vg_get_button( "yawr" ) )
633 player
.iY
-= 3.6f
* ktimestep
;
635 float steer
= vg_get_axis( "horizontal" );
636 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
639 static void draw_cross(v3f pos
,u32 colour
)
642 v3_add( (v3f
){ 1.0f
,0.0f
,0.0f
}, pos
, p0
);
643 v3_add( (v3f
){-1.0f
,0.0f
,0.0f
}, pos
, p1
);
644 vg_line( p0
, p1
, colour
);
645 v3_add( (v3f
){0.0f
, 1.0f
,0.0f
}, pos
, p0
);
646 v3_add( (v3f
){0.0f
,-1.0f
,0.0f
}, pos
, p1
);
647 vg_line( p0
, p1
, colour
);
648 v3_add( (v3f
){0.0f
,0.0f
, 1.0f
}, pos
, p0
);
649 v3_add( (v3f
){0.0f
,0.0f
,-1.0f
}, pos
, p1
);
650 vg_line( p0
, p1
, colour
);
653 static void player_physics_air(void)
655 /* Debug prediciton */
657 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
658 for( int i
=0; i
<player
.land_log_count
; i
++ )
659 draw_cross( player
.land_target_log
[i
], 0xff00ffff );
661 draw_cross( player
.land_target
, 0xff0000ff );
663 v3f ground_pos
, ground_norm
;
664 v3_copy( player
.co
, ground_pos
);
666 if( sample_scene_height( &world
.geo
, ground_pos
, ground_norm
) )
668 if( ground_pos
[1] > player
.co
[1] )
677 * TODO: Find best landing surface and guide player towords it
679 float pstep
= ktimestep
*10.0f
;
682 v3_copy( player
.co
, pco
);
683 v3_copy( player
.v
, pv
);
686 for( int i
=0; i
<50; i
++ )
688 v3_copy( pco
, pco1
);
689 apply_gravity( pv
, pstep
);
690 v3_muladds( pco
, pv
, pstep
, pco
);
692 vg_line( pco
, pco1
, i
&0x1?0xff000000:0xffffffff );
696 int hit
= sample_scene_height( &world
.geo
, sh
, targetn
);
698 if( sh
[1] >= pco
[1] && hit
)
701 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
703 float angle
= v3_dot( localup
, targetn
);
705 v3_cross( localup
, targetn
, axis
);
710 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
);
711 q_mul( correction
, player
.rot
, player
.rot
);
714 draw_cross( sh
, 0xffff0000 );
720 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
723 static void player_animate(void);
724 static void player_update(void)
726 static int clock
= 0;
729 if( clock
>= clock_divider
)
741 if( vg_get_axis("grabl")>0.0f
)
742 reset_player(0,NULL
);
743 if( vg_get_button( "push" ) )
745 v3f dir
= { 0.0f
, 0.0f
, -1.0f
};
747 m3x3_mulv( player
.to_world
, dir
, dir
);
748 v3_muladds( player
.v
, dir
, 5.0f
* ktimestep
, player
.v
);
751 float horizontal
= vg_get_axis("horizontal"),
752 vertical
= vg_get_axis("vertical");
754 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
755 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
757 /* Integrate velocity */
760 apply_gravity( player
.v
, ktimestep
);
761 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
764 /* Integrate inertia */
765 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
766 m3x3_mulv( player
.to_world
, vup
, vup
);
768 static float siY
= 0.0f
;
770 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
771 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
773 q_axis_angle( rotate
, vup
, siY
);
774 q_mul( rotate
, player
.rot
, player
.rot
);
776 player
.look_dir
[0] = atan2f( player
.v
[0], -player
.v
[2] );
777 player
.look_dir
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
778 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
780 player
.iY
= 0.0f
; /* temp */
783 player_physics_air();
786 player_physics_ground();
788 /* Camera and character */
790 player_transform_update();
791 q_normalize(player
.rot
);
799 /* Creating a skeleton of the player dynamically */
803 player
.handl_target
[0] = head
[0] + 0.2f
;
804 player
.handl_target
[1] = head
[1] - 0.8f
*(1.0f
-fabsf(slip
));
805 player
.handl_target
[2] = head
[2] + 0.2f
+ 0.7f
*fabsf(slip
);
807 player
.handr_target
[0] = head
[0] + 0.2f
;
808 player
.handr_target
[1] = head
[1] - 0.8f
*(1.0f
-fabsf(slip
));
809 player
.handr_target
[2] = head
[2] - (0.2f
+ 0.7f
*fabsf(slip
));
811 if( vg_maxf(lslip
,grab
) > 0.5f
)
813 if( player
.slip
< 0.0f
&& player
.in_air
)
815 player
.handl_target
[0] = 0.15f
;
816 player
.handl_target
[1] = 0.1f
;
817 player
.handl_target
[2] = 0.4f
;
821 player
.handr_target
[0] = 0.15f
;
822 player
.handr_target
[1] = 0.1f
;
823 player
.handr_target
[2] = -0.4f
;
828 player
.handr_target
[0] = -0.15f
;
829 player
.handr_target
[1] = 0.1f
;
830 player
.handr_target
[2] = 0.4f
;
837 static void player_animate(void)
839 /* Camera position */
840 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
841 static v3f momentum
, bob
;
843 v3_sub( player
.v
, last_vel
, player
.a
);
844 v3_copy( player
.v
, last_vel
);
846 v3_add( momentum
, player
.a
, momentum
);
847 v3_lerp( momentum
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, momentum
);
850 momentum
[0] = vg_clampf( momentum
[0], -2.0f
, 2.0f
);
851 momentum
[1] = vg_clampf( momentum
[1], -0.2f
, 5.0f
);
852 momentum
[2] = vg_clampf( momentum
[2], -2.0f
, 2.0f
);
853 v3_copy( momentum
, target
);
854 v3_lerp( bob
, target
, 0.2f
, bob
);
857 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
859 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
860 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
862 float kheight
= 2.0f
,
867 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
871 m3x3_mulv( player
.to_local
, bob
, offset
);
873 offset
[0] *= 0.3333f
;
876 v3_muladds( head
, offset
, 0.7f
, head
);
877 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
879 v3_copy( head
, player
.view
);
880 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
881 v3_add( player
.view
, camoffs
, player
.view
);
886 * ===========================================
889 static float fslide
= 0.0f
;
890 static float fdirz
= 0.0f
;
891 static float fdirx
= 0.0f
;
892 static float fstand
= 0.0f
;
893 static float ffly
= 0.0f
;
895 float speed
= v3_length( player
.v
);
897 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
898 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
900 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
901 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
902 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
904 character_pose_reset( &player
.mdl
);
906 float amt_air
= ffly
*ffly
,
907 amt_ground
= 1.0f
-amt_air
,
908 amt_std
= (1.0f
-fslide
) * amt_ground
,
909 amt_stand
= amt_std
* fstand
,
910 amt_aero
= amt_std
* (1.0f
-fstand
),
911 amt_slide
= amt_ground
* fslide
;
913 character_pose_with_tilt( &player
.mdl
, offset
,
914 &character_pose_stand
, amt_stand
);
916 character_pose_with_tilt( &player
.mdl
, offset
,
917 &character_pose_aero
, amt_aero
* fdirz
);
918 character_pose_with_tilt( &player
.mdl
, offset
,
919 &character_pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
921 character_pose_with_tilt( &player
.mdl
, offset
,
922 &character_pose_slide
, amt_slide
*fdirx
);
923 character_pose_with_tilt( &player
.mdl
, offset
,
924 &character_pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
926 character_pose_with_tilt( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
927 &character_pose_fly
, amt_air
);
931 v3_copy( player
.mdl
.cam_pos
, player
.view
);
932 v3_muladds( player
.view
, offset
, 0.7f
, player
.view
);
933 player
.view
[1] = vg_clampf( player
.view
[1], 0.3f
, kheight
);
938 * ==========================
940 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
941 *arm_r
= &player
.mdl
.ik_arm_r
;
944 m3x3_mulv( player
.to_local
, player
.v
, localv
);
945 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
946 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
948 /* New board transformation */
949 v4f board_rotation
; v3f board_location
;
951 /* TODO: Move this out of animate into update */
952 v2_lerp( player
.board_xy
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
953 ktimestep
*3.0f
, player
.board_xy
);
956 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
957 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
958 q_mul( rx
, rz
, board_rotation
);
960 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
961 q_m3x3( board_rotation
, mboard
);
962 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
963 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
964 v3_copy( board_location
, mboard
[3] );
967 float wheel_r
= offset
[0]*-0.4f
;
969 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
971 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
973 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
974 player
.mdl
.matrices
[k_chpart_wf
] );
975 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
976 player
.mdl
.matrices
[k_chpart_wb
][3] );
977 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
978 player
.mdl
.matrices
[k_chpart_wf
][3] );
980 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
981 player
.mdl
.matrices
[k_chpart_wb
] );
982 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
983 player
.mdl
.matrices
[k_chpart_wf
] );
985 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
986 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
989 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
990 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
992 if( 1||player
.in_air
)
994 float tuck
= player
.board_xy
[1],
995 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
997 float crouch
= player
.grab
*0.3f
;
998 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
999 crouch
, player
.mdl
.ik_body
.base
);
1000 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
1001 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
1005 //foot_l *= 1.0f-tuck_amt*1.5f;
1007 if( player
.grab
> 0.1f
)
1009 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
1010 player
.handl_target
);
1015 //foot_r *= 1.0f-tuck_amt*1.4f;
1017 if( player
.grab
> 0.1f
)
1019 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
1020 player
.handr_target
);
1025 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
1026 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
1028 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
1029 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
1033 static float rhead
= 0.0f
;
1034 rhead
= vg_lerpf( rhead
,
1035 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
1036 player
.mdl
.rhead
= rhead
;
1042 /* In the air, the dude should grab with the side thats highest,
1043 * while also sliding the same foot downwards a bit */
1045 float foot_l
= 0.3f
,
1048 player
.handl_target
[0] = 0.0f
;
1049 player
.handl_target
[1] = 0.0f
;
1050 player
.handl_target
[2] = 0.6f
;
1052 player
.handr_target
[0] = 0.0f
;
1053 player
.handr_target
[1] = 0.0f
;
1054 player
.handr_target
[2] = -0.6f
;
1056 if( 1||player
.in_air
)
1058 float tuck
= player
.board_xy
[1],
1059 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
1063 foot_l
*= 1.0f
-tuck_amt
*1.5f
;
1065 if( player
.grab
> 0.1f
)
1067 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
1068 player
.handl_target
);
1073 foot_r
*= 1.0f
-tuck_amt
*1.4f
;
1075 if( player
.grab
> 0.1f
)
1077 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
1078 player
.handr_target
);
1089 float *hips
= player
.mdl
.ik_body
.base
,
1090 *collar
= player
.mdl
.ik_body
.end
,
1091 *pole
= player
.mdl
.ik_body
.pole
;
1093 v3_add( hips
, collar
, pole
);
1094 v3_muls( pole
, 0.5f
, pole
);
1095 v3_add( pole
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, pole
);
1097 v3_copy( player
.view
, collar
);
1098 v3_add( (v3f
){ 0.2f
,-0.55f
,0.0f
}, collar
, hips
);
1100 player
.mdl
.rhip
= 0.0f
;//-1.0f;//sinf(vg_time);
1101 player
.mdl
.rcollar
= 0.0f
;//-0.5f;//sinf(vg_time)*0.5f;
1103 struct ik_basic
*ik_leg_l
= &player
.mdl
.ik_leg_l
,
1104 *ik_leg_r
= &player
.mdl
.ik_leg_r
,
1105 *ik_arm_l
= &player
.mdl
.ik_arm_l
,
1106 *ik_arm_r
= &player
.mdl
.ik_arm_r
;
1108 m4x3_mulv( mboard
, (v3f
){ 0.0f
,0.16f
, foot_r
}, ik_leg_r
->end
);
1109 m4x3_mulv( mboard
, (v3f
){ 0.0f
,0.16f
, foot_l
}, ik_leg_l
->end
);
1112 m4x3_identity(tomp
);
1113 m4x3_mulv( tomp
, (v3f
){ -0.4f
,0.50f
,-0.50f
}, ik_leg_r
->pole
);
1114 m4x3_mulv( tomp
, (v3f
){ -0.4f
,0.50f
,-0.3f
}, ik_leg_l
->pole
);
1117 v3f hl
, hr
, neckl
= {0.0f
, 0.5f
, 0.2f
},
1118 neckr
= {0.0f
, 0.5f
,-0.2f
};
1120 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
1121 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
1123 v3_copy( player
.handl
, ik_arm_l
->end
);
1124 v3_copy( player
.handr
, ik_arm_r
->end
);
1125 v3_copy( (v3f
){ 0.6f
,0.7f
, 0.4f
}, ik_arm_l
->pole
);
1126 v3_copy( (v3f
){ 0.6f
,0.7f
,-0.35f
}, ik_arm_r
->pole
);
1131 v3_copy( player
.v
, nv
);
1133 v3_muladds( player
.view
, nv
, -3.0f
, player
.view
);
1136 m4x3_copy( mboard
, player
.mdl
.matrices
[k_chpart_wheels
] );
1140 static void draw_player(void)
1143 vg_tex2d_bind( &tex_pallet
, 0 );
1145 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
1146 character_eval( &player
.mdl
);
1147 character_draw( &player
.mdl
);
1150 static void vg_framebuffer_resize( int w
, int h
)
1152 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1153 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
1154 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
1157 void vg_render(void)
1159 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1160 glViewport( 0,0, vg_window_x
, vg_window_y
);
1162 glDisable( GL_DEPTH_TEST
);
1163 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1164 glClearColor(141.0f
/255.0f
, 176.0f
/255.0f
, 215.0f
/255.0f
,1.0f
);
1165 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
1168 static v3f cam_lerped
= {0.0f
,0.0f
,0.0f
};
1169 v3_lerp( cam_lerped
, player
.view
, 0.08f
, cam_lerped
);
1171 m4x3_mulv( player
.to_world
, cam_lerped
, pos_inv
);
1172 v3_negate( pos_inv
, pos_inv
);
1174 static float vertical_lerp
= 0.0f
;
1175 vertical_lerp
= vg_lerpf( vertical_lerp
, pos_inv
[1], 1.0f
);
1176 v3f final
= { pos_inv
[0], vertical_lerp
, pos_inv
[2] };
1178 float speed
= v3_length( player
.v
);
1179 v3f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
, vg_randf()-0.5f
};
1180 v3_muls( shake
, speed
*0.01f
, shake
);
1182 m4x3_identity( world_matrix
);
1183 m4x3_rotate_x( world_matrix
,
1186 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
1188 m4x3_rotate_y( world_matrix
, player
.look_dir
[0]+shake
[0]*0.02f
);
1189 m4x3_translate( world_matrix
, final
);
1192 m4x3_expand( world_matrix
, world_4x4
);
1193 m4x4_projection( vg_pv
,
1194 freecam
? 90.0f
: 120.0f
,
1195 (float)vg_window_x
/ (float)vg_window_y
,
1197 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1199 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, 0xffff0000 );
1200 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, 0xff00ff00 );
1201 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, 0xff0000ff );
1203 glEnable( GL_DEPTH_TEST
);
1205 scene_foliage_shader_use();
1207 m4x3_identity( temp1
);
1208 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_debug_vcol
, "uMdl" ),
1209 1, GL_FALSE
, (float *)temp1
);
1211 vg_tex2d_bind( &tex_norwey
, 0 );
1212 scene_tree_sway
= 0.1f
;
1214 scene_bind( &world
.foliage
);
1215 scene_draw( &world
.foliage
);
1217 scene_debugsdf( &world
.foliage
);
1219 SHADER_USE(shader_unlit
);
1221 m4x3_identity(temp2
);
1222 m4x3_translate( temp2
, player
.co
);
1223 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_unlit
, "uMdl" ),
1224 1, GL_FALSE
, (float *)temp2
);
1225 glUniformMatrix4fv( SHADER_UNIFORM( shader_unlit
, "uPv" ),
1226 1, GL_FALSE
, (float *)vg_pv
);
1228 glUniform1i( SHADER_UNIFORM( shader_unlit
, "uTexMain" ), 0 );
1229 vg_tex2d_bind( &tex_sky
, 0 );
1231 mesh_bind( &world
.skydome
);
1232 mesh_draw( &world
.skydome
);
1235 vg_tex2d_bind( &tex_cement
, 0 );
1236 mesh_bind( &world
.cement
);
1237 mesh_draw( &world
.cement
);
1240 SHADER_USE(shader_standard_lit
);
1242 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit
, "uPv" ),
1243 1, GL_FALSE
, (float *)vg_pv
);
1244 glUniform1i( SHADER_UNIFORM( shader_standard_lit
, "uTexMain" ), 0 );
1245 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_standard_lit
, "uMdl" ),
1246 1, GL_FALSE
, (float *)temp1
);
1248 vg_tex2d_bind( &tex_grid
, 0 );
1250 scene_bind( &world
.geo
);
1252 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1253 0.2f
,0.36f
,0.25f
,1.0f
);
1254 submodel_draw( &world
.terrain
);
1256 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1257 0.2f
,0.2f
,0.21f
,1.0f
);
1258 submodel_draw( &world
.terrain_rocks
);
1259 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1260 0.4f
,0.4f
,0.4f
,1.0f
);
1261 submodel_draw( &world
.terrain_road
);
1264 scene_bind( &world
.detail
);
1265 scene_draw( &world
.detail
);
1269 /* Copy the RGB of what we have into the background buffer */
1270 glBindFramebuffer( GL_READ_FRAMEBUFFER
, 0 );
1271 glBindFramebuffer( GL_DRAW_FRAMEBUFFER
, render
.fb_background
);
1272 glBlitFramebuffer( 0,0, vg_window_x
, vg_window_y
,
1273 0,0, vg_window_x
, vg_window_y
,
1274 GL_COLOR_BUFFER_BIT
,
1277 /* Clear out the colour buffer, but keep depth */
1278 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1279 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1282 glClear( GL_COLOR_BUFFER_BIT
);
1284 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
1289 /* Draw back in the background */
1291 glDisable(GL_DEPTH_TEST
);
1292 glBlendFunc(GL_ONE_MINUS_DST_ALPHA
, GL_DST_ALPHA
);
1293 glBlendEquation(GL_FUNC_ADD
);
1295 SHADER_USE( shader_blit
);
1297 glUniform1i( SHADER_UNIFORM(shader_blit
,"uTexMain"), 0 );
1298 glActiveTexture(GL_TEXTURE0
);
1299 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1301 glBindVertexArray( render
.fsquad
.vao
);
1302 glDrawArrays( GL_TRIANGLES
, 0, 6 );
1304 glDisable(GL_BLEND
);
1308 glDisable( GL_DEPTH_TEST
);
1309 vg_lines_drawall( (float *)vg_pv
);
1311 /* Debugger camera */
1312 glViewport( 0,0, 800, 800 );
1313 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1314 glClear( GL_DEPTH_BUFFER_BIT
);
1316 m4x3_identity( world_matrix
);
1319 v3_negate( player
.co
, debugcam
);
1320 debugcam
[2] -= 2.0f
;
1321 debugcam
[1] -= 0.7f
;
1323 m4x3_translate( world_matrix
, debugcam
);
1324 m4x3_expand( world_matrix
, world_4x4
);
1326 m4x4_projection( vg_pv
,
1328 (float)128.0f
/ (float)128.0f
,
1330 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1334 glEnable( GL_DEPTH_TEST
);
1339 glDisable( GL_DEPTH_TEST
);
1340 vg_lines_drawall( (float *)vg_pv
);
1342 glViewport( 0,0, vg_window_x
, vg_window_y
);
1349 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1350 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1352 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1353 player
.a
[0], player
.a
[1], player
.a
[2] );
1355 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1357 if( vg_gamepad_ready
)
1359 for( int i
=0; i
<6; i
++ )
1361 snprintf( buf
, 20, "%.2f", vg_gamepad
.axes
[i
] );
1362 gui_text( (ui_px
[2]){ 0, (i
+2)*20 }, buf
, 1, k_text_align_left
);
1367 gui_text( (ui_px
[2]){ 0, 40 },
1368 "Gamepad not ready", 1, k_text_align_left
);
1372 void vg_free(void){}