bdd819739554e2c35c8ed8b97b30f3e96c832750
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;
57 static int replay_record
= 0;
59 static m4x3f
*replay_buffer
= NULL
;
60 static int replay_buffer_frame
= 0;
62 #define REPLAY_LENGTH 120*60
68 #include "character.h"
71 #include "rigidbody.h"
73 int main( int argc
, char *argv
[] )
75 vg_init( argc
, argv
, "Voyager Game Engine" );
85 float vswitch
, slip
, slip_last
,
88 float iY
; /* Yaw inertia */
96 v2f look_dir
; /* TEMP */
102 v3f land_target_log
[22];
103 u32 land_target_colours
[22];
107 m4x3f to_world
, to_local
;
109 struct character mdl
;
111 v3f handl_target
, handr_target
,
119 submodel sm_road
, sm_terrain
;
125 static struct grender
127 GLuint fb_background
,
135 .bbx
= {{ -1.0f
, -0.25f
, -0.25f
}, { 1.0f
, 0.25f
, 0.25f
}}
138 rigidbody mrs_box
= {
139 .bbx
= {{ -0.5f
, -0.25f
, -0.25f
}, { 0.5f
, 0.25f
, 0.25f
}}
142 static void player_transform_update(void)
144 q_normalize( player
.rot
);
145 q_m3x3( player
.rot
, player
.to_world
);
146 v3_copy( player
.co
, player
.to_world
[3] );
148 m4x3_invert_affine( player
.to_world
, player
.to_local
);
151 static int reset_player( int argc
, char const *argv
[] )
153 v3_zero( player
.co
);
157 if( !strcmp( argv
[0], "tutorial" ))
158 v3_copy( world
.tutorial
, player
.co
);
161 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player
.v
);
162 q_identity( player
.rot
);
163 player
.vswitch
= 1.0f
;
164 player
.slip_last
= 0.0f
;
167 m3x3_identity( player
.vr
);
169 player
.mdl
.shoes
[0] = 1;
170 player
.mdl
.shoes
[1] = 1;
172 player_transform_update();
176 static int playermodel( int argc
, char const *argv
[] )
178 if( argc
< 1 ) return 0;
180 glmesh old_mesh
= player
.mdl
.mesh
;
182 if( character_load( &player
.mdl
, argv
[0] ) )
183 mesh_free( &old_mesh
);
188 void vg_register(void)
191 character_shader_register();
192 SHADER_INIT( shader_blit
);
197 replay_buffer
= malloc( sizeof(m4x3f
) * REPLAY_LENGTH
* (PART_COUNT
) );
199 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
203 mrs_box
.co
[2] += 2.0f
;
205 vg_convar_push( (struct vg_convar
){
207 .data
= &replay_buffer_frame
,
208 .data_type
= k_convar_dtype_i32
,
209 .opt_i32
= { .min
=0, .max
=REPLAY_LENGTH
-1, .clamp
=1 },
213 vg_convar_push( (struct vg_convar
){
215 .data
= &replay_record
,
216 .data_type
= k_convar_dtype_i32
,
217 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
221 vg_convar_push( (struct vg_convar
){
224 .data_type
= k_convar_dtype_i32
,
225 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
229 vg_convar_push( (struct vg_convar
){
231 .data
= &sv_debugcam
,
232 .data_type
= k_convar_dtype_i32
,
233 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
237 vg_convar_push( (struct vg_convar
){
240 .data_type
= k_convar_dtype_i32
,
241 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
245 vg_convar_push( (struct vg_convar
){
248 .data_type
= k_convar_dtype_i32
,
249 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
253 vg_convar_push( (struct vg_convar
){
256 .data_type
= k_convar_dtype_i32
,
257 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
261 vg_convar_push( (struct vg_convar
){
262 .name
= "thirdperson",
263 .data
= &thirdperson
,
264 .data_type
= k_convar_dtype_i32
,
265 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
269 vg_convar_push( (struct vg_convar
){
271 .data
= &clock_divider
,
272 .data_type
= k_convar_dtype_i32
,
273 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
277 vg_function_push( (struct vg_cmd
){
279 .function
= reset_player
282 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
283 v3_normalize( lightDir
);
285 character_load( &player
.mdl
, "ch_default" );
286 character_init_ragdoll( &player
.mdl
);
289 scene_init( &world
.geo
);
290 model
*mworld
= vg_asset_read( "models/mp_dev.mdl" );
292 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "mp_dev" ),
293 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
294 scene_copy_slice( &world
.geo
, &world
.sm_road
);
296 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "terrain" ),
297 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
298 scene_copy_slice( &world
.geo
, &world
.sm_terrain
);
300 v3_copy( submodel_get( mworld
, "tutorial" )->pivot
, world
.tutorial
);
303 scene_upload( &world
.geo
);
304 bvh_create( &world
.geo
);
306 reset_player( 0, NULL
);
307 player_transform_update();
309 /* Create framebuffers */
310 glGenFramebuffers( 1, &render
.fb_background
);
311 glBindFramebuffer( GL_FRAMEBUFFER
, render
.fb_background
);
313 glGenTextures( 1, &render
.rgb_background
);
314 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
315 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
,
316 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
318 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
319 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
320 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
322 render
.rgb_background
, 0);
325 float quad
[] = { 0.0f
, 0.0f
, 1.0f
, 1.0f
, 0.0f
, 1.0f
,
326 0.0f
, 0.0f
, 1.0f
, 0.0f
, 1.0f
, 1.0f
};
328 glGenVertexArrays( 1, &render
.fsquad
.vao
);
329 glGenBuffers( 1, &render
.fsquad
.vbo
);
330 glGenBuffers( 1, &render
.fsquad
.ebo
);
331 glBindVertexArray( render
.fsquad
.vao
);
332 glBindBuffer( GL_ARRAY_BUFFER
, render
.fsquad
.vbo
);
333 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
334 glBindVertexArray( render
.fsquad
.vao
);
335 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
336 sizeof(float)*2, (void*)0 );
337 glEnableVertexAttribArray( 0 );
342 static float ktimestep
= 1.0f
/60.0f
;
344 static void player_freecam(void)
347 m4x3_identity( cam_rot
);
348 m4x3_rotate_y( cam_rot
, -player
.look_dir
[0] );
349 m4x3_rotate_x( cam_rot
, -player
.look_dir
[1] );
351 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
352 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
354 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
355 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
357 float movespeed
= 5.0f
;
358 static v2f mouse_last
,
359 view_vel
= { 0.0f
, 0.0f
};
361 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
363 if( vg_get_button_down( "primary" ) )
364 v2_copy( vg_mouse
, mouse_last
);
365 else if( vg_get_button( "primary" ) )
368 v2_sub( vg_mouse
, mouse_last
, delta
);
369 v2_copy( vg_mouse
, mouse_last
);
371 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
374 v2_muls( view_vel
, 0.75f
, view_vel
);
375 v2_add( view_vel
, player
.look_dir
, player
.look_dir
);
377 vg_clampf( player
.look_dir
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
379 if( vg_get_button( "forward" ) )
380 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
381 if( vg_get_button( "back" ) )
382 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
383 if( vg_get_button( "left" ) )
384 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
385 if( vg_get_button( "right" ) )
386 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
388 v3_muls( move_vel
, 0.75f
, move_vel
);
389 v3_add( move_vel
, player
.view
, player
.view
);
392 static void apply_gravity( v3f vel
, float const timestep
)
394 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
395 v3_muladds( vel
, gravity
, timestep
, vel
);
398 static int ray_hit_is_ramp( ray_hit
*hit
)
400 return hit
->tri
[0] < world
.sm_road
.vertex_count
;
403 static void player_start_air(void)
407 float pstep
= ktimestep
*10.0f
;
409 float best_velocity_mod
= 0.0f
,
410 best_velocity_delta
= -9999.9f
;
413 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, vup
);
414 v3_cross( vup
, player
.v
, axis
);
415 v3_normalize( axis
);
416 player
.land_log_count
= 0;
418 m3x3_identity( player
.vr
);
420 for( int m
=-3;m
<=12; m
++ )
422 float vmod
= ((float)m
/ 15.0f
)*0.09f
;
425 v3_copy( player
.co
, pco
);
426 v3_copy( player
.v
, pv
);
429 * Try different 'rotations' of the velocity to find the best possible
430 * landing normal. This conserves magnitude at the expense of slightly
431 * unrealistic results
437 q_axis_angle( vr_q
, axis
, vmod
);
440 for( int i
=0; i
<50; i
++ )
442 v3_copy( pco
, pco1
);
443 apply_gravity( pv
, pstep
);
445 m3x3_mulv( vr
, pv
, pv
);
446 v3_muladds( pco
, pv
, pstep
, pco
);
451 v3_sub( pco
, pco1
, vdir
);
452 contact
.dist
= v3_length( vdir
);
453 v3_divs( vdir
, contact
.dist
, vdir
);
455 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
457 float land_delta
= v3_dot( pv
, contact
.normal
);
458 u32 scolour
= (u8
)(vg_minf(-land_delta
* 2.0f
, 255.0f
));
460 /* Bias prediction towords ramps */
461 if( ray_hit_is_ramp( &contact
) )
464 scolour
|= 0x0000a000;
467 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
469 best_velocity_delta
= land_delta
;
470 best_velocity_mod
= vmod
;
472 v3_copy( contact
.pos
, player
.land_target
);
474 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
475 q_m3x3( vr_q
, player
.vr
);
478 v3_copy( contact
.pos
,
479 player
.land_target_log
[player
.land_log_count
] );
480 player
.land_target_colours
[player
.land_log_count
] =
481 0xff000000 | scolour
;
483 player
.land_log_count
++;
490 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
493 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
496 static int sample_if_resistant( v3f pos
)
499 v3_copy( pos
, ground
);
502 if( bvh_scene_sample( &world
.geo
, ground
, &hit
) )
505 v3_copy( player
.v
, angle
);
506 v3_normalize( angle
);
507 float resistance
= v3_dot( hit
.normal
, angle
);
509 if( resistance
< 0.25f
)
511 v3_copy( ground
, pos
);
519 static float stable_force( float current
, float diff
)
521 float new = current
+ diff
;
523 if( new * current
< 0.0f
)
529 static void player_physics_ground(void)
532 * Getting surface collision points,
533 * the contact manifold is a triangle for simplicity.
535 v3f contact_front
, contact_back
, contact_norm
, vup
, vside
,
538 float klength
= 0.65f
;
539 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
540 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
541 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
542 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
543 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
548 sample_if_resistant( contact_front
) +
549 sample_if_resistant( contact_back
) +
550 sample_if_resistant( contact_norm
);
552 if( contact_count
< 3 )
560 v3_sub( contact_norm
, contact_front
, v0
);
561 v3_sub( contact_back
, contact_front
, v1
);
562 v3_cross( v1
, v0
, norm
);
563 v3_normalize( norm
);
565 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
566 vg_line( contact_back
, contact_front
, 0xff0000ff );
568 /* Surface alignment */
569 float angle
= v3_dot( vup
, norm
);
570 v3_cross( vup
, norm
, axis
);
575 q_axis_angle( correction
, axis
, acosf(angle
) );
576 q_mul( correction
, player
.rot
, player
.rot
);
579 float resistance
= v3_dot( norm
, player
.v
);
580 if( resistance
>= 0.0f
)
587 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
590 /* This is where velocity integration used to be */
594 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
597 m3x3_mulv( player
.to_local
, player
.v
, vel
);
599 /* Calculate local forces */
601 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
602 if( fabsf( slip
) > 1.2f
)
603 slip
= vg_signf( slip
) * 1.2f
;
605 player
.reverse
= -vg_signf(vel
[2]);
607 float substep
= ktimestep
* 0.2f
;
608 float fwd_resistance
= (vg_get_button( "break" )? 5.0f
: 0.02f
) * -substep
;
610 for( int i
=0; i
<5; i
++ )
612 vel
[2] = stable_force( vel
[2], vg_signf( vel
[2] ) * fwd_resistance
);
613 vel
[0] = stable_force( vel
[0], vg_signf( vel
[0] ) * -7.0f
*substep
);
616 static double start_push
= 0.0;
617 if( vg_get_button_down( "push" ) )
618 start_push
= vg_time
;
620 if( !vg_get_button("break") && vg_get_button( "push" ) )
622 float const k_maxpush
= 16.0f
,
625 float cycle_time
= vg_time
-start_push
,
626 amt
= k_pushaccel
* (sinf( cycle_time
* 8.0f
)*0.5f
+0.5f
)*ktimestep
,
627 current
= v3_length( vel
),
628 new_vel
= vg_minf( current
+ amt
, k_maxpush
);
629 new_vel
-= vg_minf(current
, k_maxpush
);
630 vel
[2] -= new_vel
* player
.reverse
;
633 m3x3_mulv( player
.to_world
, vel
, player
.v
);
635 if( vg_get_button( "yawl" ) )
636 player
.iY
+= 3.6f
* ktimestep
;
637 if( vg_get_button( "yawr" ) )
638 player
.iY
-= 3.6f
* ktimestep
;
640 float steer
= vg_get_axis( "horizontal" );
641 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
643 /* Too much lean and it starts to look like a snowboard here */
644 v2_lerp( player
.board_xy
, (v2f
){ slip
*0.25f
, 0.0f
},
645 ktimestep
*5.0f
, player
.board_xy
);
648 static void draw_cross(v3f pos
,u32 colour
)
651 v3_add( (v3f
){ 1.0f
,0.0f
,0.0f
}, pos
, p0
);
652 v3_add( (v3f
){-1.0f
,0.0f
,0.0f
}, pos
, p1
);
653 vg_line( p0
, p1
, colour
);
654 v3_add( (v3f
){0.0f
, 1.0f
,0.0f
}, pos
, p0
);
655 v3_add( (v3f
){0.0f
,-1.0f
,0.0f
}, pos
, p1
);
656 vg_line( p0
, p1
, colour
);
657 v3_add( (v3f
){0.0f
,0.0f
, 1.0f
}, pos
, p0
);
658 v3_add( (v3f
){0.0f
,0.0f
,-1.0f
}, pos
, p1
);
659 vg_line( p0
, p1
, colour
);
662 static void player_physics_air(void)
664 /* Debug prediciton */
666 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
667 for( int i
=0; i
<player
.land_log_count
; i
++ )
668 draw_cross( player
.land_target_log
[i
],
669 player
.land_target_colours
[i
] );
671 draw_cross( player
.land_target
, 0xff0000ff );
674 v3_copy( player
.co
, ground_pos
);
677 if( bvh_scene_sample( &world
.geo
, ground_pos
, &hit
) )
679 if( ground_pos
[1] > player
.co
[1] )
683 if( !ray_hit_is_ramp( &hit
) )
686 m4x3_mulv( player
.to_world
, player
.view
, player
.follow
);
687 character_ragdoll_copypose( &player
.mdl
, player
.v
);
696 * TODO: Find best landing surface and guide player towords it
698 float pstep
= ktimestep
*10.0f
;
701 v3_copy( player
.co
, pco
);
702 v3_copy( player
.v
, pv
);
704 float time_to_impact
= 0.0f
;
705 float limiter
= 1.0f
;
707 for( int i
=0; i
<50; i
++ )
709 v3_copy( pco
, pco1
);
710 apply_gravity( pv
, pstep
);
711 v3_muladds( pco
, pv
, pstep
, pco
);
713 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
718 v3_sub( pco
, pco1
, vdir
);
719 contact
.dist
= v3_length( vdir
);
720 v3_divs( vdir
, contact
.dist
, vdir
);
722 float orig_dist
= contact
.dist
;
723 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
726 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
728 float angle
= v3_dot( localup
, contact
.normal
);
730 v3_cross( localup
, contact
.normal
, axis
);
732 time_to_impact
+= (contact
.dist
/orig_dist
)*pstep
;
733 limiter
= vg_minf( 5.0f
, time_to_impact
)/5.0f
;
734 limiter
= 1.0f
-limiter
;
736 limiter
= 1.0f
-limiter
;
741 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
*(1.0f
-limiter
) );
742 q_mul( correction
, player
.rot
, player
.rot
);
745 draw_cross( contact
.pos
, 0xffff0000 );
748 time_to_impact
+= pstep
;
752 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
755 float iX
= vg_get_axis( "vertical" ) * 3.6f
* limiter
* ktimestep
;
756 static float siX
= 0.0f
;
757 siX
= vg_lerpf( siX
, iX
, 0.3f
);
762 m3x3_mulv( player
.to_world
, (v3f
){1.0f
,0.0f
,0.0f
}, vside
);
764 q_axis_angle( rotate
, vside
, siX
);
765 q_mul( rotate
, player
.rot
, player
.rot
);
768 v2f target
= {0.0f
,0.0f
};
769 v2_muladds( target
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
770 player
.grab
, target
);
771 v2_lerp( player
.board_xy
, target
, ktimestep
*3.0f
, player
.board_xy
);
774 static void player_animate(void);
775 static void player_update(void)
778 if( vg_get_axis("grabl")>0.0f
)
779 reset_player(0,NULL
);
783 static int clock
= 0;
793 if( clock
>= clock_divider
)
797 float horizontal
= vg_get_axis("horizontal"),
798 vertical
= vg_get_axis("vertical");
800 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
801 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
803 /* Integrate velocity */
806 apply_gravity( player
.v
, ktimestep
);
807 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
810 /* Integrate inertia */
811 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
812 m3x3_mulv( player
.to_world
, vup
, vup
);
814 static float siY
= 0.0f
;
816 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
817 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
819 q_axis_angle( rotate
, vup
, siY
);
820 q_mul( rotate
, player
.rot
, player
.rot
);
822 player
.look_dir
[0] = atan2f( player
.v
[0], -player
.v
[2] );
823 player
.look_dir
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
824 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
826 player
.iY
= 0.0f
; /* temp */
829 player_physics_air();
832 player_physics_ground();
834 /* Camera and character */
836 player_transform_update();
837 q_normalize(player
.rot
);
845 //rb_torque( &mr_box, (v3f){0.0f,0.0f,1.0f}, 0.01f );
847 if( glfwGetKey( vg_window
, GLFW_KEY_F
) )
848 character_ragdoll_go( &player
.mdl
, player
.view
);
850 if( glfwGetKey( vg_window
, GLFW_KEY_G
) )
853 m4x3_mulv( player
.to_world
, player
.view
, player
.follow
);
854 character_ragdoll_copypose( &player
.mdl
, player
.v
);
857 static int clock
= 0;
860 if( clock
>= clock_divider
)
862 character_debug_ragdoll( &player
.mdl
);
865 character_ragdoll_iter( &player
.mdl
, &world
.geo
);
867 rb_build_manifold( &mr_box
, &world
.geo
);
868 rb_build_manifold( &mrs_box
, &world
.geo
);
869 rb_constraint_manifold( &mr_box
);
870 rb_constraint_manifold( &mrs_box
);
875 rb_debug( &mr_box
, 0xffffffff );
876 rb_debug( &mrs_box
, 0xff00ff00 );
878 rb_update_transform( &mr_box
);
879 rb_update_transform( &mrs_box
);
886 static void player_animate(void)
888 /* Camera position */
889 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
890 static v3f momentum
, bob
;
892 v3_sub( player
.v
, last_vel
, player
.a
);
893 v3_copy( player
.v
, last_vel
);
895 v3_add( momentum
, player
.a
, momentum
);
896 v3_lerp( momentum
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, momentum
);
899 momentum
[0] = vg_clampf( momentum
[0], -2.0f
, 2.0f
);
900 momentum
[1] = vg_clampf( momentum
[1], -0.2f
, 5.0f
);
901 momentum
[2] = vg_clampf( momentum
[2], -2.0f
, 2.0f
);
902 v3_copy( momentum
, target
);
903 v3_lerp( bob
, target
, 0.2f
, bob
);
906 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
908 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
909 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
911 float kheight
= 2.0f
,
916 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
920 m3x3_mulv( player
.to_local
, bob
, offset
);
922 offset
[0] *= 0.3333f
;
925 v3_muladds( head
, offset
, 0.7f
, head
);
926 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
931 v3_copy( head
, player
.view
);
932 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
933 v3_add( player
.view
, camoffs
, player
.view
);
940 * ===========================================
943 static float fslide
= 0.0f
;
944 static float fdirz
= 0.0f
;
945 static float fdirx
= 0.0f
;
946 static float fstand
= 0.0f
;
947 static float ffly
= 0.0f
;
949 float speed
= v3_length( player
.v
);
951 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
952 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
954 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
955 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
956 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
958 character_pose_reset( &player
.mdl
);
960 float amt_air
= ffly
*ffly
,
961 amt_ground
= 1.0f
-amt_air
,
962 amt_std
= (1.0f
-fslide
) * amt_ground
,
963 amt_stand
= amt_std
* fstand
,
964 amt_aero
= amt_std
* (1.0f
-fstand
),
965 amt_slide
= amt_ground
* fslide
;
967 character_final_pose( &player
.mdl
, offset
, &pose_stand
, amt_stand
);
968 character_final_pose( &player
.mdl
, offset
, &pose_aero
, amt_aero
*fdirz
);
969 character_final_pose( &player
.mdl
, offset
,
970 &pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
971 character_final_pose( &player
.mdl
, offset
, &pose_slide
, amt_slide
*fdirx
);
972 character_final_pose( &player
.mdl
, offset
,
973 &pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
975 character_final_pose( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
976 &pose_fly
, amt_air
);
980 v3_copy( player
.mdl
.cam_pos
, player
.view
);
981 v3_muladds( player
.view
, offset
, 0.7f
, player
.view
);
982 player
.view
[1] = vg_clampf( player
.view
[1], 0.3f
, kheight
);
987 * ==========================
989 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
990 *arm_r
= &player
.mdl
.ik_arm_r
;
993 m3x3_mulv( player
.to_local
, player
.v
, localv
);
994 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
995 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
997 /* New board transformation */
998 v4f board_rotation
; v3f board_location
;
1001 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
1002 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
1003 q_mul( rx
, rz
, board_rotation
);
1005 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
1006 q_m3x3( board_rotation
, mboard
);
1007 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
1008 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
1009 v3_copy( board_location
, mboard
[3] );
1012 float wheel_r
= offset
[0]*-0.4f
;
1014 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
1016 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
1018 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
1019 player
.mdl
.matrices
[k_chpart_wf
] );
1020 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
1021 player
.mdl
.matrices
[k_chpart_wb
][3] );
1022 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
1023 player
.mdl
.matrices
[k_chpart_wf
][3] );
1025 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
1026 player
.mdl
.matrices
[k_chpart_wb
] );
1027 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
1028 player
.mdl
.matrices
[k_chpart_wf
] );
1030 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
1031 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
1034 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
1035 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
1037 if( 1||player
.in_air
)
1039 float tuck
= player
.board_xy
[1],
1040 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
1042 float crouch
= player
.grab
*0.3f
;
1043 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
1044 crouch
, player
.mdl
.ik_body
.base
);
1045 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
1046 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
1050 //foot_l *= 1.0f-tuck_amt*1.5f;
1052 if( player
.grab
> 0.1f
)
1054 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
1055 player
.handl_target
);
1060 //foot_r *= 1.0f-tuck_amt*1.4f;
1062 if( player
.grab
> 0.1f
)
1064 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
1065 player
.handr_target
);
1070 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
1071 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
1073 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
1074 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
1078 static float rhead
= 0.0f
;
1079 rhead
= vg_lerpf( rhead
,
1080 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
1081 player
.mdl
.rhead
= rhead
;
1084 static void draw_player(void)
1087 vg_tex2d_bind( &tex_pallet
, 0 );
1089 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
1091 if( player
.is_dead
)
1092 character_mimic_ragdoll( &player
.mdl
);
1094 character_eval( &player
.mdl
);
1096 character_draw( &player
.mdl
, (player
.is_dead
|player
.in_air
)? 0.0f
: 1.0f
);
1099 static void vg_framebuffer_resize( int w
, int h
)
1101 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1102 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
1103 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
1106 void vg_render(void)
1108 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1109 glViewport( 0,0, vg_window_x
, vg_window_y
);
1111 glDisable( GL_DEPTH_TEST
);
1112 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1113 glClearColor(111.0f
/255.0f
, 46.0f
/255.0f
, 45.0f
/255.0f
,1.0f
);
1115 glClearColor( powf(0.066f
,1.0f
/2.2f
),
1116 powf(0.050f
,1.0f
/2.2f
),
1117 powf(0.046f
,1.0f
/2.2f
), 1.0f
);
1118 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
1121 static v3f cam_lerped
= {0.0f
,0.0f
,0.0f
};
1122 v3_lerp( cam_lerped
, player
.view
, 0.08f
, cam_lerped
);
1126 m4x3_mulv( player
.to_world
, cam_lerped
, pos_inv
);
1128 static float air_blend
= 0.0f
;
1130 air_blend
= vg_lerpf( air_blend
, player
.in_air
, 0.04f
);
1131 v3_muladds( pos_inv
, player
.v
, -0.05f
*air_blend
, pos_inv
);
1134 v3_add( player
.co
, player
.view
, pos_inv
);
1135 v3_negate( pos_inv
, pos_inv
);
1137 static float vertical_lerp
= 0.0f
;
1138 vertical_lerp
= vg_lerpf( vertical_lerp
, pos_inv
[1], 1.0f
);
1139 v3f final
= { pos_inv
[0], vertical_lerp
, pos_inv
[2] };
1141 float speed
= freecam
? 0.0f
: v3_length( player
.v
);
1142 v3f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
, vg_randf()-0.5f
};
1143 v3_muls( shake
, speed
*0.01f
, shake
);
1145 static v2f cam_lerped_dir
;
1147 m4x3_identity( world_matrix
);
1148 if( player
.is_dead
)
1151 v3_sub( player
.mdl
.ragdoll
[k_chpart_head
].co
, player
.follow
, delta
);
1152 v3_normalize(delta
);
1155 v3_muladds( player
.mdl
.ragdoll
[k_chpart_head
].co
, delta
,
1156 -1.5f
, follow_pos
);
1157 v3_lerp( player
.follow
, follow_pos
, 0.1f
, player
.follow
);
1158 v3_negate( player
.follow
, final
);
1161 float yaw
= atan2f( delta
[0], -delta
[2] );
1162 float pitch
= asinf( delta
[1] );
1163 m4x3_rotate_x( world_matrix
, -pitch
);
1164 m4x3_rotate_y( world_matrix
, yaw
);
1168 v2_lerp( cam_lerped_dir
, player
.look_dir
, 0.04f
, cam_lerped_dir
);
1170 m4x3_rotate_x( world_matrix
,
1173 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
1175 m4x3_rotate_y( world_matrix
,
1178 player
.look_dir
[0]+shake
[0]*0.02f
);
1182 m4x3_translate( world_matrix
, final
);
1185 m4x3_expand( world_matrix
, world_4x4
);
1186 m4x4_projection( vg_pv
,
1187 freecam
? 60.0f
: 120.0f
,
1188 (float)vg_window_x
/ (float)vg_window_y
,
1190 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1192 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, 0xffff0000 );
1193 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, 0xff00ff00 );
1194 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, 0xff0000ff );
1196 glEnable( GL_DEPTH_TEST
);
1201 SHADER_USE(shader_standard_lit
);
1203 m4x3f identity_matrix
;
1204 m4x3_identity( identity_matrix
);
1206 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit
, "uPv" ),
1207 1, GL_FALSE
, (float *)vg_pv
);
1208 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_standard_lit
, "uMdl" ),
1209 1, GL_FALSE
, (float *)identity_matrix
);
1211 vg_tex2d_bind( &tex_grid
, 0 );
1212 glUniform1i( SHADER_UNIFORM( shader_standard_lit
, "uTexMain" ), 0 );
1214 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1215 0.4f
,0.4f
,0.4f
,1.0f
);
1217 scene_bind( &world
.geo
);
1218 scene_draw( &world
.geo
);
1221 if( !replay_record
)
1223 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1225 for( int i
=0; i
<PART_COUNT
; i
++ )
1226 m4x3_copy( base
[i
], player
.mdl
.matrices
[i
] );
1228 replay_buffer_frame
++;
1230 if( replay_buffer_frame
== REPLAY_LENGTH
)
1231 replay_buffer_frame
= 0;
1233 vg_tex2d_bind( &tex_pallet
, 0 );
1234 character_draw( &player
.mdl
, 0.0f
);
1241 /* Copy the RGB of what we have into the background buffer */
1242 glBindFramebuffer( GL_READ_FRAMEBUFFER
, 0 );
1243 glBindFramebuffer( GL_DRAW_FRAMEBUFFER
, render
.fb_background
);
1244 glBlitFramebuffer( 0,0, vg_window_x
, vg_window_y
,
1245 0,0, vg_window_x
, vg_window_y
,
1246 GL_COLOR_BUFFER_BIT
,
1249 /* Clear out the colour buffer, but keep depth */
1250 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1251 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1253 if( !player
.is_dead
)
1254 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
1256 glClear( GL_COLOR_BUFFER_BIT
);
1260 /* Draw back in the background */
1262 glDisable(GL_DEPTH_TEST
);
1263 glBlendFunc(GL_ONE_MINUS_DST_ALPHA
, GL_DST_ALPHA
);
1264 glBlendEquation(GL_FUNC_ADD
);
1266 SHADER_USE( shader_blit
);
1268 glUniform1i( SHADER_UNIFORM(shader_blit
,"uTexMain"), 0 );
1269 glActiveTexture(GL_TEXTURE0
);
1270 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1272 glBindVertexArray( render
.fsquad
.vao
);
1273 glDrawArrays( GL_TRIANGLES
, 0, 6 );
1275 glDisable(GL_BLEND
);
1278 glDisable( GL_DEPTH_TEST
);
1279 vg_lines_drawall( (float *)vg_pv
);
1281 /* Debugger camera */
1282 glViewport( 0,0, 800, 800 );
1283 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1284 glClear( GL_DEPTH_BUFFER_BIT
);
1286 m4x3_identity( world_matrix
);
1289 v3_negate( player
.co
, debugcam
);
1290 debugcam
[2] -= 2.0f
;
1291 debugcam
[1] -= 0.7f
;
1293 m4x3_translate( world_matrix
, debugcam
);
1294 m4x3_expand( world_matrix
, world_4x4
);
1296 m4x4_projection( vg_pv
,
1298 (float)128.0f
/ (float)128.0f
,
1300 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1304 glEnable( GL_DEPTH_TEST
);
1308 glDisable( GL_DEPTH_TEST
);
1309 vg_lines_drawall( (float *)vg_pv
);
1311 glViewport( 0,0, vg_window_x
, vg_window_y
);
1316 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1318 for( int i
=0; i
<PART_COUNT
; i
++ )
1319 m4x3_copy( player
.mdl
.matrices
[i
], base
[i
] );
1321 replay_buffer_frame
++;
1323 if( replay_buffer_frame
== REPLAY_LENGTH
)
1324 replay_buffer_frame
= 0;
1333 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1334 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1336 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1337 player
.a
[0], player
.a
[1], player
.a
[2] );
1338 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1340 snprintf( buf
, 20, "pos %.2f %.2f %.2f",
1341 player
.co
[0], player
.co
[1], player
.co
[2] );
1342 gui_text( (ui_px
[2]){ 0, 40 }, buf
, 1, k_text_align_left
);
1344 if( vg_gamepad_ready
)
1346 for( int i
=0; i
<6; i
++ )
1348 snprintf( buf
, 20, "%.2f", vg_gamepad
.axes
[i
] );
1349 gui_text( (ui_px
[2]){ 0, (i
+3)*20 }, buf
, 1, k_text_align_left
);
1354 gui_text( (ui_px
[2]){ 0, 60 },
1355 "Gamepad not ready", 1, k_text_align_left
);
1359 void vg_free(void){}