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 */
95 v2f look_dir
; /* TEMP */
101 v3f land_target_log
[22];
105 m4x3f to_world
, to_local
;
107 struct character mdl
;
109 v3f handl_target
, handr_target
,
123 static struct grender
125 GLuint fb_background
,
133 .bbx
= {{ -1.0f
, -0.25f
, -0.25f
}, { 1.0f
, 0.25f
, 0.25f
}}
136 rigidbody mrs_box
= {
137 .bbx
= {{ -0.5f
, -0.25f
, -0.25f
}, { 0.5f
, 0.25f
, 0.25f
}}
140 static void player_transform_update(void)
142 q_normalize( player
.rot
);
143 q_m3x3( player
.rot
, player
.to_world
);
144 v3_copy( player
.co
, player
.to_world
[3] );
146 m4x3_invert_affine( player
.to_world
, player
.to_local
);
149 static int reset_player( int argc
, char const *argv
[] )
151 v3_zero( player
.co
);
152 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player
.v
);
153 q_identity( player
.rot
);
154 player
.vswitch
= 1.0f
;
155 player
.slip_last
= 0.0f
;
157 player_transform_update();
161 static int playermodel( int argc
, char const *argv
[] )
163 if( argc
< 1 ) return 0;
165 glmesh old_mesh
= player
.mdl
.mesh
;
167 if( character_load( &player
.mdl
, argv
[0] ) )
168 mesh_free( &old_mesh
);
173 void vg_register(void)
176 character_shader_register();
177 SHADER_INIT( shader_blit
);
182 replay_buffer
= malloc( sizeof(m4x3f
) * REPLAY_LENGTH
* (PART_COUNT
) );
184 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
188 mrs_box
.co
[2] += 2.0f
;
190 vg_convar_push( (struct vg_convar
){
192 .data
= &replay_buffer_frame
,
193 .data_type
= k_convar_dtype_i32
,
194 .opt_i32
= { .min
=0, .max
=REPLAY_LENGTH
-1, .clamp
=1 },
198 vg_convar_push( (struct vg_convar
){
200 .data
= &replay_record
,
201 .data_type
= k_convar_dtype_i32
,
202 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
206 vg_convar_push( (struct vg_convar
){
209 .data_type
= k_convar_dtype_i32
,
210 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
214 vg_convar_push( (struct vg_convar
){
216 .data
= &sv_debugcam
,
217 .data_type
= k_convar_dtype_i32
,
218 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
222 vg_convar_push( (struct vg_convar
){
225 .data_type
= k_convar_dtype_i32
,
226 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
230 vg_convar_push( (struct vg_convar
){
233 .data_type
= k_convar_dtype_i32
,
234 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
238 vg_convar_push( (struct vg_convar
){
241 .data_type
= k_convar_dtype_i32
,
242 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
246 vg_convar_push( (struct vg_convar
){
247 .name
= "thirdperson",
248 .data
= &thirdperson
,
249 .data_type
= k_convar_dtype_i32
,
250 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
254 vg_convar_push( (struct vg_convar
){
256 .data
= &clock_divider
,
257 .data_type
= k_convar_dtype_i32
,
258 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
262 vg_function_push( (struct vg_cmd
){
264 .function
= reset_player
267 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
268 v3_normalize( lightDir
);
270 character_load( &player
.mdl
, "ch_default" );
271 character_init_ragdoll( &player
.mdl
);
274 scene_init( &world
.geo
);
275 model
*mworld
= vg_asset_read( "models/mp_dev.mdl" );
277 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "mp_dev" ),
278 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
280 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "terrain" ),
281 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
284 scene_upload( &world
.geo
);
285 bvh_create( &world
.geo
);
288 reset_player( 0, NULL
);
289 player_transform_update();
291 /* Create framebuffers */
292 glGenFramebuffers( 1, &render
.fb_background
);
293 glBindFramebuffer( GL_FRAMEBUFFER
, render
.fb_background
);
295 glGenTextures( 1, &render
.rgb_background
);
296 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
297 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
,
298 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
300 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
301 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
302 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
304 render
.rgb_background
, 0);
307 float quad
[] = { 0.0f
, 0.0f
, 1.0f
, 1.0f
, 0.0f
, 1.0f
,
308 0.0f
, 0.0f
, 1.0f
, 0.0f
, 1.0f
, 1.0f
};
310 glGenVertexArrays( 1, &render
.fsquad
.vao
);
311 glGenBuffers( 1, &render
.fsquad
.vbo
);
312 glGenBuffers( 1, &render
.fsquad
.ebo
);
313 glBindVertexArray( render
.fsquad
.vao
);
314 glBindBuffer( GL_ARRAY_BUFFER
, render
.fsquad
.vbo
);
315 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
316 glBindVertexArray( render
.fsquad
.vao
);
317 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
318 sizeof(float)*2, (void*)0 );
319 glEnableVertexAttribArray( 0 );
324 static float ktimestep
= 1.0f
/60.0f
;
326 static void player_freecam(void)
329 m4x3_identity( cam_rot
);
330 m4x3_rotate_y( cam_rot
, -player
.look_dir
[0] );
331 m4x3_rotate_x( cam_rot
, -player
.look_dir
[1] );
333 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
334 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
336 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
337 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
339 float movespeed
= 5.0f
;
340 static v2f mouse_last
,
341 view_vel
= { 0.0f
, 0.0f
};
343 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
345 if( vg_get_button_down( "primary" ) )
346 v2_copy( vg_mouse
, mouse_last
);
347 else if( vg_get_button( "primary" ) )
350 v2_sub( vg_mouse
, mouse_last
, delta
);
351 v2_copy( vg_mouse
, mouse_last
);
353 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
356 v2_muls( view_vel
, 0.75f
, view_vel
);
357 v2_add( view_vel
, player
.look_dir
, player
.look_dir
);
359 vg_clampf( player
.look_dir
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
361 if( vg_get_button( "forward" ) )
362 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
363 if( vg_get_button( "back" ) )
364 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
365 if( vg_get_button( "left" ) )
366 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
367 if( vg_get_button( "right" ) )
368 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
370 v3_muls( move_vel
, 0.75f
, move_vel
);
371 v3_add( move_vel
, player
.view
, player
.view
);
374 static void apply_gravity( v3f vel
, float const timestep
)
376 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
377 v3_muladds( vel
, gravity
, timestep
, vel
);
380 static void player_start_air(void)
384 float pstep
= ktimestep
*10.0f
;
386 float best_velocity_mod
= 0.0f
,
387 best_velocity_delta
= -9999.9f
;
390 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, vup
);
391 v3_cross( vup
, player
.v
, axis
);
392 v3_normalize( axis
);
393 player
.land_log_count
= 0;
395 m3x3_identity( player
.vr
);
397 for( int m
=-3;m
<=12; m
++ )
399 float vmod
= ((float)m
/ 15.0f
)*0.09f
;
402 v3_copy( player
.co
, pco
);
403 v3_copy( player
.v
, pv
);
406 * Try different 'rotations' of the velocity to find the best possible
407 * landing normal. This conserves magnitude at the expense of slightly
408 * unrealistic results
414 q_axis_angle( vr_q
, axis
, vmod
);
417 for( int i
=0; i
<50; i
++ )
419 v3_copy( pco
, pco1
);
420 apply_gravity( pv
, pstep
);
422 m3x3_mulv( vr
, pv
, pv
);
423 v3_muladds( pco
, pv
, pstep
, pco
);
428 v3_sub( pco
, pco1
, vdir
);
429 contact
.dist
= v3_length( vdir
);
430 v3_divs( vdir
, contact
.dist
, vdir
);
432 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
434 float land_delta
= v3_dot( pv
, contact
.normal
);
436 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
438 best_velocity_delta
= land_delta
;
439 best_velocity_mod
= vmod
;
441 v3_copy( contact
.pos
, player
.land_target
);
443 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
444 q_m3x3( vr_q
, player
.vr
);
447 v3_copy( contact
.pos
,
448 player
.land_target_log
[player
.land_log_count
++] );
454 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
457 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
460 static int sample_if_resistant( v3f pos
)
463 v3_copy( pos
, ground
);
465 if( bvh_scene_sample( &world
.geo
, ground
, norm
) )
468 v3_copy( player
.v
, angle
);
469 v3_normalize( angle
);
470 float resistance
= v3_dot( norm
, angle
);
472 if( resistance
< 0.25f
)
474 v3_copy( ground
, pos
);
482 static float stable_force( float current
, float diff
)
484 float new = current
+ diff
;
486 if( new * current
< 0.0f
)
492 static void player_physics_ground(void)
495 * Getting surface collision points,
496 * the contact manifold is a triangle for simplicity.
498 v3f contact_front
, contact_back
, contact_norm
, vup
, vside
,
501 float klength
= 0.65f
;
502 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
503 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
504 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
505 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
506 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
511 sample_if_resistant( contact_front
) +
512 sample_if_resistant( contact_back
) +
513 sample_if_resistant( contact_norm
);
515 if( contact_count
< 3 )
523 v3_sub( contact_norm
, contact_front
, v0
);
524 v3_sub( contact_back
, contact_front
, v1
);
525 v3_cross( v1
, v0
, norm
);
526 v3_normalize( norm
);
528 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
529 vg_line( contact_back
, contact_front
, 0xff0000ff );
531 /* Surface alignment */
532 float angle
= v3_dot( vup
, norm
);
533 v3_cross( vup
, norm
, axis
);
538 q_axis_angle( correction
, axis
, acosf(angle
) );
539 q_mul( correction
, player
.rot
, player
.rot
);
542 float resistance
= v3_dot( norm
, player
.v
);
543 if( resistance
>= 0.0f
)
550 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
553 /* This is where velocity integration used to be */
557 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
560 m3x3_mulv( player
.to_local
, player
.v
, vel
);
562 /* Calculate local forces */
564 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
565 if( fabsf( slip
) > 1.2f
)
566 slip
= vg_signf( slip
) * 1.2f
;
568 player
.reverse
= -vg_signf(vel
[2]);
570 float substep
= ktimestep
* 0.2f
;
571 for( int i
=0; i
<5; i
++ )
573 vel
[2] = stable_force( vel
[2], vg_signf( vel
[2] ) * -0.02f
*substep
);
574 vel
[0] = stable_force( vel
[0], vg_signf( vel
[0] ) * -7.0f
*substep
);
577 m3x3_mulv( player
.to_world
, vel
, player
.v
);
579 if( vg_get_button( "yawl" ) )
580 player
.iY
+= 3.6f
* ktimestep
;
581 if( vg_get_button( "yawr" ) )
582 player
.iY
-= 3.6f
* ktimestep
;
584 float steer
= vg_get_axis( "horizontal" );
585 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
587 /* Too much lean and it starts to look like a snowboard here */
588 v2_lerp( player
.board_xy
, (v2f
){ slip
*0.25f
, 0.0f
},
589 ktimestep
*5.0f
, player
.board_xy
);
592 static void draw_cross(v3f pos
,u32 colour
)
595 v3_add( (v3f
){ 1.0f
,0.0f
,0.0f
}, pos
, p0
);
596 v3_add( (v3f
){-1.0f
,0.0f
,0.0f
}, pos
, p1
);
597 vg_line( p0
, p1
, colour
);
598 v3_add( (v3f
){0.0f
, 1.0f
,0.0f
}, pos
, p0
);
599 v3_add( (v3f
){0.0f
,-1.0f
,0.0f
}, pos
, p1
);
600 vg_line( p0
, p1
, colour
);
601 v3_add( (v3f
){0.0f
,0.0f
, 1.0f
}, pos
, p0
);
602 v3_add( (v3f
){0.0f
,0.0f
,-1.0f
}, pos
, p1
);
603 vg_line( p0
, p1
, colour
);
606 static void player_physics_air(void)
608 /* Debug prediciton */
610 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
611 for( int i
=0; i
<player
.land_log_count
; i
++ )
612 draw_cross( player
.land_target_log
[i
], 0xff00ffff );
614 draw_cross( player
.land_target
, 0xff0000ff );
616 v3f ground_pos
, ground_norm
;
617 v3_copy( player
.co
, ground_pos
);
619 if( bvh_scene_sample( &world
.geo
, ground_pos
, ground_norm
) )
621 if( ground_pos
[1] > player
.co
[1] )
630 * TODO: Find best landing surface and guide player towords it
632 float pstep
= ktimestep
*10.0f
;
635 v3_copy( player
.co
, pco
);
636 v3_copy( player
.v
, pv
);
638 for( int i
=0; i
<50; i
++ )
640 v3_copy( pco
, pco1
);
641 apply_gravity( pv
, pstep
);
642 v3_muladds( pco
, pv
, pstep
, pco
);
644 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
649 v3_sub( pco
, pco1
, vdir
);
650 contact
.dist
= v3_length( vdir
);
651 v3_divs( vdir
, contact
.dist
, vdir
);
653 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
656 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
658 float angle
= v3_dot( localup
, contact
.normal
);
660 v3_cross( localup
, contact
.normal
, axis
);
665 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
);
666 q_mul( correction
, player
.rot
, player
.rot
);
669 draw_cross( contact
.pos
, 0xffff0000 );
675 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
677 v2f target
= {0.0f
,0.0f
};
678 v2_muladds( target
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
679 player
.grab
, target
);
680 v2_lerp( player
.board_xy
, target
, ktimestep
*3.0f
, player
.board_xy
);
683 static void player_animate(void);
684 static void player_update(void)
686 static int clock
= 0;
696 if( clock
>= clock_divider
)
701 if( vg_get_axis("grabl")>0.0f
)
702 reset_player(0,NULL
);
703 if( vg_get_button( "push" ) )
705 v3f dir
= { 0.0f
, 0.0f
, -1.0f
};
707 m3x3_mulv( player
.to_world
, dir
, dir
);
708 v3_muladds( player
.v
, dir
, 5.0f
* ktimestep
, player
.v
);
711 float horizontal
= vg_get_axis("horizontal"),
712 vertical
= vg_get_axis("vertical");
714 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
715 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
717 /* Integrate velocity */
720 apply_gravity( player
.v
, ktimestep
);
721 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
724 /* Integrate inertia */
725 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
726 m3x3_mulv( player
.to_world
, vup
, vup
);
728 static float siY
= 0.0f
;
730 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
731 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
733 q_axis_angle( rotate
, vup
, siY
);
734 q_mul( rotate
, player
.rot
, player
.rot
);
736 player
.look_dir
[0] = atan2f( player
.v
[0], -player
.v
[2] );
737 player
.look_dir
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
738 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
740 player
.iY
= 0.0f
; /* temp */
743 player_physics_air();
746 player_physics_ground();
748 /* Camera and character */
750 player_transform_update();
751 q_normalize(player
.rot
);
759 //rb_torque( &mr_box, (v3f){0.0f,0.0f,1.0f}, 0.01f );
761 if( glfwGetKey( vg_window
, GLFW_KEY_F
) )
762 character_ragdoll_go( &player
.mdl
, player
.view
);
764 if( glfwGetKey( vg_window
, GLFW_KEY_G
) )
765 character_ragdoll_copypose( &player
.mdl
, player
.v
);
767 static int clock
= 0;
770 if( clock
>= clock_divider
)
772 character_debug_ragdoll( &player
.mdl
);
773 character_ragdoll_iter( &player
.mdl
, &world
.geo
);
776 rb_build_manifold( &mr_box
, &world
.geo
);
777 rb_build_manifold( &mrs_box
, &world
.geo
);
778 rb_constraint_manifold( &mr_box
);
779 rb_constraint_manifold( &mrs_box
);
784 rb_debug( &mr_box
, 0xffffffff );
785 rb_debug( &mrs_box
, 0xff00ff00 );
787 rb_update_transform( &mr_box
);
788 rb_update_transform( &mrs_box
);
795 static void player_animate(void)
797 /* Camera position */
798 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
799 static v3f momentum
, bob
;
801 v3_sub( player
.v
, last_vel
, player
.a
);
802 v3_copy( player
.v
, last_vel
);
804 v3_add( momentum
, player
.a
, momentum
);
805 v3_lerp( momentum
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, momentum
);
808 momentum
[0] = vg_clampf( momentum
[0], -2.0f
, 2.0f
);
809 momentum
[1] = vg_clampf( momentum
[1], -0.2f
, 5.0f
);
810 momentum
[2] = vg_clampf( momentum
[2], -2.0f
, 2.0f
);
811 v3_copy( momentum
, target
);
812 v3_lerp( bob
, target
, 0.2f
, bob
);
815 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
817 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
818 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
820 float kheight
= 2.0f
,
825 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
829 m3x3_mulv( player
.to_local
, bob
, offset
);
831 offset
[0] *= 0.3333f
;
834 v3_muladds( head
, offset
, 0.7f
, head
);
835 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
840 v3_copy( head
, player
.view
);
841 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
842 v3_add( player
.view
, camoffs
, player
.view
);
849 * ===========================================
852 static float fslide
= 0.0f
;
853 static float fdirz
= 0.0f
;
854 static float fdirx
= 0.0f
;
855 static float fstand
= 0.0f
;
856 static float ffly
= 0.0f
;
858 float speed
= v3_length( player
.v
);
860 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
861 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
863 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
864 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
865 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
867 character_pose_reset( &player
.mdl
);
869 float amt_air
= ffly
*ffly
,
870 amt_ground
= 1.0f
-amt_air
,
871 amt_std
= (1.0f
-fslide
) * amt_ground
,
872 amt_stand
= amt_std
* fstand
,
873 amt_aero
= amt_std
* (1.0f
-fstand
),
874 amt_slide
= amt_ground
* fslide
;
876 character_final_pose( &player
.mdl
, offset
, &pose_stand
, amt_stand
);
877 character_final_pose( &player
.mdl
, offset
, &pose_aero
, amt_aero
*fdirz
);
878 character_final_pose( &player
.mdl
, offset
,
879 &pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
880 character_final_pose( &player
.mdl
, offset
, &pose_slide
, amt_slide
*fdirx
);
881 character_final_pose( &player
.mdl
, offset
,
882 &pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
884 character_final_pose( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
885 &pose_fly
, amt_air
);
889 v3_copy( player
.mdl
.cam_pos
, player
.view
);
890 v3_muladds( player
.view
, offset
, 0.7f
, player
.view
);
891 player
.view
[1] = vg_clampf( player
.view
[1], 0.3f
, kheight
);
896 * ==========================
898 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
899 *arm_r
= &player
.mdl
.ik_arm_r
;
902 m3x3_mulv( player
.to_local
, player
.v
, localv
);
903 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
904 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
906 /* New board transformation */
907 v4f board_rotation
; v3f board_location
;
910 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
911 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
912 q_mul( rx
, rz
, board_rotation
);
914 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
915 q_m3x3( board_rotation
, mboard
);
916 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
917 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
918 v3_copy( board_location
, mboard
[3] );
921 float wheel_r
= offset
[0]*-0.4f
;
923 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
925 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
927 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
928 player
.mdl
.matrices
[k_chpart_wf
] );
929 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
930 player
.mdl
.matrices
[k_chpart_wb
][3] );
931 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
932 player
.mdl
.matrices
[k_chpart_wf
][3] );
934 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
935 player
.mdl
.matrices
[k_chpart_wb
] );
936 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
937 player
.mdl
.matrices
[k_chpart_wf
] );
939 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
940 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
943 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
944 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
946 if( 1||player
.in_air
)
948 float tuck
= player
.board_xy
[1],
949 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
951 float crouch
= player
.grab
*0.3f
;
952 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
953 crouch
, player
.mdl
.ik_body
.base
);
954 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
955 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
959 //foot_l *= 1.0f-tuck_amt*1.5f;
961 if( player
.grab
> 0.1f
)
963 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
964 player
.handl_target
);
969 //foot_r *= 1.0f-tuck_amt*1.4f;
971 if( player
.grab
> 0.1f
)
973 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
974 player
.handr_target
);
979 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
980 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
982 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
983 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
987 static float rhead
= 0.0f
;
988 rhead
= vg_lerpf( rhead
,
989 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
990 player
.mdl
.rhead
= rhead
;
993 static void draw_player(void)
996 vg_tex2d_bind( &tex_pallet
, 0 );
998 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
999 character_eval( &player
.mdl
);
1000 character_draw( &player
.mdl
, 1.0f
);
1003 static void vg_framebuffer_resize( int w
, int h
)
1005 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1006 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
1007 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
1010 void vg_render(void)
1012 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1013 glViewport( 0,0, vg_window_x
, vg_window_y
);
1015 glDisable( GL_DEPTH_TEST
);
1016 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1017 glClearColor(111.0f
/255.0f
, 46.0f
/255.0f
, 45.0f
/255.0f
,1.0f
);
1019 glClearColor( powf(0.066f
,1.0f
/2.2f
),
1020 powf(0.050f
,1.0f
/2.2f
),
1021 powf(0.046f
,1.0f
/2.2f
), 1.0f
);
1022 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
1025 static v3f cam_lerped
= {0.0f
,0.0f
,0.0f
};
1026 v3_lerp( cam_lerped
, player
.view
, 0.08f
, cam_lerped
);
1029 m4x3_mulv( player
.to_world
, cam_lerped
, pos_inv
);
1031 v3_add( player
.co
, player
.view
, pos_inv
);
1032 v3_negate( pos_inv
, pos_inv
);
1034 static float vertical_lerp
= 0.0f
;
1035 vertical_lerp
= vg_lerpf( vertical_lerp
, pos_inv
[1], 1.0f
);
1036 v3f final
= { pos_inv
[0], vertical_lerp
, pos_inv
[2] };
1038 float speed
= freecam
? 0.0f
: v3_length( player
.v
);
1039 v3f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
, vg_randf()-0.5f
};
1040 v3_muls( shake
, speed
*0.01f
, shake
);
1042 static v2f cam_lerped_dir
;
1044 v2_lerp( cam_lerped_dir
, player
.look_dir
, 0.04f
, cam_lerped_dir
);
1046 m4x3_identity( world_matrix
);
1047 m4x3_rotate_x( world_matrix
,
1050 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
1052 m4x3_rotate_y( world_matrix
,
1055 player
.look_dir
[0]+shake
[0]*0.02f
);
1056 m4x3_translate( world_matrix
, final
);
1059 m4x3_expand( world_matrix
, world_4x4
);
1060 m4x4_projection( vg_pv
,
1061 freecam
? 60.0f
: 120.0f
,
1062 (float)vg_window_x
/ (float)vg_window_y
,
1064 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1066 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, 0xffff0000 );
1067 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, 0xff00ff00 );
1068 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, 0xff0000ff );
1070 glEnable( GL_DEPTH_TEST
);
1075 SHADER_USE(shader_standard_lit
);
1077 m4x3f identity_matrix
;
1078 m4x3_identity( identity_matrix
);
1080 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit
, "uPv" ),
1081 1, GL_FALSE
, (float *)vg_pv
);
1082 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_standard_lit
, "uMdl" ),
1083 1, GL_FALSE
, (float *)identity_matrix
);
1085 vg_tex2d_bind( &tex_grid
, 0 );
1086 glUniform1i( SHADER_UNIFORM( shader_standard_lit
, "uTexMain" ), 0 );
1088 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1089 0.4f
,0.4f
,0.4f
,1.0f
);
1091 scene_bind( &world
.geo
);
1092 scene_draw( &world
.geo
);
1094 if( !replay_record
)
1096 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1098 for( int i
=0; i
<PART_COUNT
; i
++ )
1099 m4x3_copy( base
[i
], player
.mdl
.matrices
[i
] );
1101 replay_buffer_frame
++;
1103 if( replay_buffer_frame
== REPLAY_LENGTH
)
1104 replay_buffer_frame
= 0;
1106 vg_tex2d_bind( &tex_pallet
, 0 );
1107 character_draw( &player
.mdl
, 0.0f
);
1113 /* Copy the RGB of what we have into the background buffer */
1114 glBindFramebuffer( GL_READ_FRAMEBUFFER
, 0 );
1115 glBindFramebuffer( GL_DRAW_FRAMEBUFFER
, render
.fb_background
);
1116 glBlitFramebuffer( 0,0, vg_window_x
, vg_window_y
,
1117 0,0, vg_window_x
, vg_window_y
,
1118 GL_COLOR_BUFFER_BIT
,
1121 /* Clear out the colour buffer, but keep depth */
1122 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1123 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1126 glClear( GL_COLOR_BUFFER_BIT
);
1128 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
1133 /* Draw back in the background */
1135 glDisable(GL_DEPTH_TEST
);
1136 glBlendFunc(GL_ONE_MINUS_DST_ALPHA
, GL_DST_ALPHA
);
1137 glBlendEquation(GL_FUNC_ADD
);
1139 SHADER_USE( shader_blit
);
1141 glUniform1i( SHADER_UNIFORM(shader_blit
,"uTexMain"), 0 );
1142 glActiveTexture(GL_TEXTURE0
);
1143 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1145 glBindVertexArray( render
.fsquad
.vao
);
1146 glDrawArrays( GL_TRIANGLES
, 0, 6 );
1148 glDisable(GL_BLEND
);
1151 glDisable( GL_DEPTH_TEST
);
1152 vg_lines_drawall( (float *)vg_pv
);
1154 /* Debugger camera */
1155 glViewport( 0,0, 800, 800 );
1156 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1157 glClear( GL_DEPTH_BUFFER_BIT
);
1159 m4x3_identity( world_matrix
);
1162 v3_negate( player
.co
, debugcam
);
1163 debugcam
[2] -= 2.0f
;
1164 debugcam
[1] -= 0.7f
;
1166 m4x3_translate( world_matrix
, debugcam
);
1167 m4x3_expand( world_matrix
, world_4x4
);
1169 m4x4_projection( vg_pv
,
1171 (float)128.0f
/ (float)128.0f
,
1173 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1177 glEnable( GL_DEPTH_TEST
);
1181 glDisable( GL_DEPTH_TEST
);
1182 vg_lines_drawall( (float *)vg_pv
);
1184 glViewport( 0,0, vg_window_x
, vg_window_y
);
1189 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1191 for( int i
=0; i
<PART_COUNT
; i
++ )
1192 m4x3_copy( player
.mdl
.matrices
[i
], base
[i
] );
1194 replay_buffer_frame
++;
1196 if( replay_buffer_frame
== REPLAY_LENGTH
)
1197 replay_buffer_frame
= 0;
1205 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1206 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1208 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1209 player
.a
[0], player
.a
[1], player
.a
[2] );
1210 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1212 snprintf( buf
, 20, "pos %.2f %.2f %.2f",
1213 player
.co
[0], player
.co
[1], player
.co
[2] );
1214 gui_text( (ui_px
[2]){ 0, 40 }, buf
, 1, k_text_align_left
);
1216 if( vg_gamepad_ready
)
1218 for( int i
=0; i
<6; i
++ )
1220 snprintf( buf
, 20, "%.2f", vg_gamepad
.axes
[i
] );
1221 gui_text( (ui_px
[2]){ 0, (i
+3)*20 }, buf
, 1, k_text_align_left
);
1226 gui_text( (ui_px
[2]){ 0, 60 },
1227 "Gamepad not ready", 1, k_text_align_left
);
1231 void vg_free(void){}