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" };
13 vg_tex2d tex_water
= { .path
= "textures/water.qoi" };
16 static int freecam
= 0;
17 static int debugview
= 0;
18 static int debugsdf
= 0;
19 static int sv_debugcam
= 0;
20 static int sv_phys
= 0;
21 static int thirdperson
= 0;
22 static int clock_divider
= 1;
23 static int replay_record
= 0;
25 static m4x3f
*replay_buffer
= NULL
;
26 static int replay_buffer_frame
= 0;
28 #define REPLAY_LENGTH 120*60
34 #include "character.h"
37 #include "rigidbody.h"
42 #include "shaders/blit.h"
43 #include "shaders/standard.h"
44 #include "shaders/unlit.h"
46 void vg_register(void)
48 shader_blit_register();
49 shader_standard_register();
50 shader_unlit_register();
58 vg_tex2d
*texture_list
[] =
70 int main( int argc
, char *argv
[] )
72 vg_init( argc
, argv
, "Voyager Game Engine" );
80 v3f co
, v
, a
, v_last
, m
, bob
;
82 float vswitch
, slip
, slip_last
,
85 float iY
; /* Yaw inertia */
93 v2f look_dir
; /* TEMP */
99 v3f land_target_log
[22];
100 u32 land_target_colours
[22];
104 m4x3f to_world
, to_local
;
106 struct character mdl
;
108 v3f handl_target
, handr_target
,
116 submodel sm_road
, sm_terrain
;
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 teleport_gate gate_a
= {
141 .co
= { 0.0f
, -3.0f
, -15.0f
},
142 .q
= { 0.0f
, 0.0f
, 0.0f
, 1.0f
}
145 .co
= { -8.0f
, -3.0f
, -17.0f
},
146 .q
= { 0.0f
, 0.0f
, 0.0f
, 1.0f
}
149 static void player_transform_update(void)
151 q_normalize( player
.rot
);
152 q_m3x3( player
.rot
, player
.to_world
);
153 v3_copy( player
.co
, player
.to_world
[3] );
155 m4x3_invert_affine( player
.to_world
, player
.to_local
);
158 static int reset_player( int argc
, char const *argv
[] )
160 v3_zero( player
.co
);
164 if( !strcmp( argv
[0], "tutorial" ))
165 v3_copy( world
.tutorial
, player
.co
);
168 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player
.v
);
169 q_identity( player
.rot
);
170 player
.vswitch
= 1.0f
;
171 player
.slip_last
= 0.0f
;
174 m3x3_identity( player
.vr
);
176 player
.mdl
.shoes
[0] = 1;
177 player
.mdl
.shoes
[1] = 1;
179 player_transform_update();
183 static int playermodel( int argc
, char const *argv
[] )
185 if( argc
< 1 ) return 0;
187 glmesh old_mesh
= player
.mdl
.mesh
;
189 if( character_load( &player
.mdl
, argv
[0] ) )
190 mesh_free( &old_mesh
);
195 static void create_renderbuffer_std( GLuint
*fb
, GLuint
*rgb
, GLuint
*rb
)
197 glGenFramebuffers( 1, fb
);
198 glBindFramebuffer( GL_FRAMEBUFFER
, *fb
);
200 glGenTextures( 1, rgb
);
201 glBindTexture( GL_TEXTURE_2D
, *rgb
);
202 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
,
203 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
205 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
206 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
207 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
208 GL_TEXTURE_2D
, *rgb
, 0);
210 /* TODO: Check for DEPTH32f availiblity and use if possible */
212 glGenRenderbuffers( 1, rb
);
213 glBindRenderbuffer( GL_RENDERBUFFER
, *rb
);
214 glRenderbufferStorage( GL_RENDERBUFFER
, GL_DEPTH24_STENCIL8
,
215 vg_window_x
, vg_window_y
);
217 glFramebufferRenderbuffer( GL_FRAMEBUFFER
, GL_DEPTH_STENCIL_ATTACHMENT
,
218 GL_RENDERBUFFER
, *rb
);
221 static void resize_renderbuffer_std( GLuint
*fb
, GLuint
*rgb
, GLuint
*rb
)
223 glBindTexture( GL_TEXTURE_2D
, *rgb
);
224 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
, 0,
225 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
227 glBindRenderbuffer( GL_RENDERBUFFER
, *rb
);
228 glRenderbufferStorage( GL_RENDERBUFFER
, GL_DEPTH24_STENCIL8
,
229 vg_window_x
, vg_window_y
);
234 replay_buffer
= malloc( sizeof(m4x3f
) * REPLAY_LENGTH
* (PART_COUNT
) );
236 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
240 mrs_box
.co
[2] += 2.0f
;
242 vg_convar_push( (struct vg_convar
){
244 .data
= &replay_buffer_frame
,
245 .data_type
= k_convar_dtype_i32
,
246 .opt_i32
= { .min
=0, .max
=REPLAY_LENGTH
-1, .clamp
=1 },
250 vg_convar_push( (struct vg_convar
){
252 .data
= &replay_record
,
253 .data_type
= k_convar_dtype_i32
,
254 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
258 vg_convar_push( (struct vg_convar
){
261 .data_type
= k_convar_dtype_i32
,
262 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
266 vg_convar_push( (struct vg_convar
){
268 .data
= &sv_debugcam
,
269 .data_type
= k_convar_dtype_i32
,
270 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
274 vg_convar_push( (struct vg_convar
){
277 .data_type
= k_convar_dtype_i32
,
278 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
282 vg_convar_push( (struct vg_convar
){
285 .data_type
= k_convar_dtype_i32
,
286 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
290 vg_convar_push( (struct vg_convar
){
293 .data_type
= k_convar_dtype_i32
,
294 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
298 vg_convar_push( (struct vg_convar
){
299 .name
= "thirdperson",
300 .data
= &thirdperson
,
301 .data_type
= k_convar_dtype_i32
,
302 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
306 vg_convar_push( (struct vg_convar
){
308 .data
= &clock_divider
,
309 .data_type
= k_convar_dtype_i32
,
310 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
314 vg_function_push( (struct vg_cmd
){
316 .function
= reset_player
319 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
320 v3_normalize( lightDir
);
322 character_load( &player
.mdl
, "ch_default" );
323 character_init_ragdoll( &player
.mdl
);
326 scene_init( &world
.geo
);
327 model
*mworld
= vg_asset_read( "models/mp_dev.mdl" );
329 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "mp_dev" ),
330 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
331 scene_copy_slice( &world
.geo
, &world
.sm_road
);
333 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "terrain" ),
334 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
335 scene_copy_slice( &world
.geo
, &world
.sm_terrain
);
337 v3_copy( model_marker_get( mworld
, "mp_dev_tutorial" )->co
, world
.tutorial
);
342 model_marker
*ga
= model_marker_get(mworld
,"gate_a"),
343 *gb
= model_marker_get(mworld
,"gate_a_recv");
345 v3_copy( ga
->co
, gate_a
.co
);
346 v3_copy( gb
->co
, gate_b
.co
);
347 v4_copy( ga
->q
, gate_a
.q
);
348 v4_copy( gb
->q
, gate_b
.q
);
349 v2_copy( ga
->s
, gate_a
.dims
);
350 v2_copy( gb
->s
, gate_b
.dims
);
352 gate_a
.other
= &gate_b
;
353 gate_b
.other
= &gate_a
;
355 gate_transform_update( &gate_a
);
356 gate_transform_update( &gate_b
);
362 submodel
*sm
= submodel_get(mworld
,"mp_dev_water");
363 model_unpack_submodel( mworld
, &surf
, sm
);
365 water_init( create_renderbuffer_std
);
366 water_set_surface( &surf
, sm
->pivot
[1] );
369 model
*msky
= vg_asset_read("models/rs_skydome.mdl");
370 model_unpack( msky
, &world
.skybox
);
375 scene_upload( &world
.geo
);
376 bvh_create( &world
.geo
);
378 reset_player( 1, (const char *[]){ "tutorial" } );
379 player_transform_update();
381 /* Create framebuffers */
382 glGenFramebuffers( 1, &render
.fb_background
);
383 glBindFramebuffer( GL_FRAMEBUFFER
, render
.fb_background
);
385 glGenTextures( 1, &render
.rgb_background
);
386 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
387 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
,
388 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
390 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
391 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
392 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
394 render
.rgb_background
, 0);
396 gate_init( create_renderbuffer_std
);
399 float quad
[] = { 0.0f
, 0.0f
, 1.0f
, 1.0f
, 0.0f
, 1.0f
,
400 0.0f
, 0.0f
, 1.0f
, 0.0f
, 1.0f
, 1.0f
};
402 glGenVertexArrays( 1, &render
.fsquad
.vao
);
403 glGenBuffers( 1, &render
.fsquad
.vbo
);
404 glBindVertexArray( render
.fsquad
.vao
);
405 glBindBuffer( GL_ARRAY_BUFFER
, render
.fsquad
.vbo
);
406 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
407 glBindVertexArray( render
.fsquad
.vao
);
408 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
409 sizeof(float)*2, (void*)0 );
410 glEnableVertexAttribArray( 0 );
415 static float ktimestep
= 1.0f
/60.0f
;
417 static void player_freecam(void)
420 m4x3_identity( cam_rot
);
421 m4x3_rotate_y( cam_rot
, -player
.look_dir
[0] );
422 m4x3_rotate_x( cam_rot
, -player
.look_dir
[1] );
424 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
425 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
427 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
428 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
430 float movespeed
= 5.0f
;
431 static v2f mouse_last
,
432 view_vel
= { 0.0f
, 0.0f
};
434 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
436 if( vg_get_button_down( "primary" ) )
437 v2_copy( vg_mouse
, mouse_last
);
438 else if( vg_get_button( "primary" ) )
441 v2_sub( vg_mouse
, mouse_last
, delta
);
442 v2_copy( vg_mouse
, mouse_last
);
444 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
447 v2_muls( view_vel
, 0.75f
, view_vel
);
448 v2_add( view_vel
, player
.look_dir
, player
.look_dir
);
450 vg_clampf( player
.look_dir
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
452 if( vg_get_button( "forward" ) )
453 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
454 if( vg_get_button( "back" ) )
455 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
456 if( vg_get_button( "left" ) )
457 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
458 if( vg_get_button( "right" ) )
459 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
461 v3_muls( move_vel
, 0.75f
, move_vel
);
462 v3_add( move_vel
, player
.view
, player
.view
);
465 static void apply_gravity( v3f vel
, float const timestep
)
467 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
468 v3_muladds( vel
, gravity
, timestep
, vel
);
471 static int ray_hit_is_ramp( ray_hit
*hit
)
473 return hit
->tri
[0] < world
.sm_road
.vertex_count
;
476 static void player_start_air(void)
480 float pstep
= ktimestep
*10.0f
;
482 float best_velocity_mod
= 0.0f
,
483 best_velocity_delta
= -9999.9f
;
486 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, vup
);
487 v3_cross( vup
, player
.v
, axis
);
488 v3_normalize( axis
);
489 player
.land_log_count
= 0;
491 m3x3_identity( player
.vr
);
493 for( int m
=-3;m
<=12; m
++ )
495 float vmod
= ((float)m
/ 15.0f
)*0.09f
;
498 v3_copy( player
.co
, pco
);
499 v3_copy( player
.v
, pv
);
500 v3_muladds( pco
, pv
, ktimestep
, pco
);
503 * Try different 'rotations' of the velocity to find the best possible
504 * landing normal. This conserves magnitude at the expense of slightly
505 * unrealistic results
511 q_axis_angle( vr_q
, axis
, vmod
);
514 for( int i
=0; i
<50; i
++ )
516 v3_copy( pco
, pco1
);
517 apply_gravity( pv
, pstep
);
519 m3x3_mulv( vr
, pv
, pv
);
520 v3_muladds( pco
, pv
, pstep
, pco
);
525 v3_sub( pco
, pco1
, vdir
);
526 contact
.dist
= v3_length( vdir
);
527 v3_divs( vdir
, contact
.dist
, vdir
);
529 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
531 float land_delta
= v3_dot( pv
, contact
.normal
);
532 u32 scolour
= (u8
)(vg_minf(-land_delta
* 2.0f
, 255.0f
));
534 /* Bias prediction towords ramps */
535 if( ray_hit_is_ramp( &contact
) )
538 scolour
|= 0x0000a000;
541 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
543 best_velocity_delta
= land_delta
;
544 best_velocity_mod
= vmod
;
546 v3_copy( contact
.pos
, player
.land_target
);
548 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
549 q_m3x3( vr_q
, player
.vr
);
552 v3_copy( contact
.pos
,
553 player
.land_target_log
[player
.land_log_count
] );
554 player
.land_target_colours
[player
.land_log_count
] =
555 0xff000000 | scolour
;
557 player
.land_log_count
++;
564 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
567 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
570 static int sample_if_resistant( v3f pos
)
573 v3_copy( pos
, ground
);
576 if( bvh_scene_sample( &world
.geo
, ground
, &hit
) )
579 v3_copy( player
.v
, angle
);
580 v3_normalize( angle
);
581 float resistance
= v3_dot( hit
.normal
, angle
);
583 if( resistance
< 0.25f
)
585 v3_copy( ground
, pos
);
593 static float stable_force( float current
, float diff
)
595 float new = current
+ diff
;
597 if( new * current
< 0.0f
)
603 static void player_physics_ground(void)
606 * Getting surface collision points,
607 * the contact manifold is a triangle for simplicity.
609 v3f contact_front
, contact_back
, contact_norm
, vup
, vside
,
612 float klength
= 0.65f
;
613 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
614 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
615 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
616 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
617 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
622 sample_if_resistant( contact_front
) +
623 sample_if_resistant( contact_back
) +
624 sample_if_resistant( contact_norm
);
626 if( contact_count
< 3 )
634 v3_sub( contact_norm
, contact_front
, v0
);
635 v3_sub( contact_back
, contact_front
, v1
);
636 v3_cross( v1
, v0
, norm
);
637 v3_normalize( norm
);
639 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
640 vg_line( contact_back
, contact_front
, 0xff0000ff );
642 /* Surface alignment */
643 float angle
= v3_dot( vup
, norm
);
644 v3_cross( vup
, norm
, axis
);
649 q_axis_angle( correction
, axis
, acosf(angle
) );
650 q_mul( correction
, player
.rot
, player
.rot
);
653 float resistance
= v3_dot( norm
, player
.v
);
654 if( resistance
>= 0.0f
)
661 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
664 /* This is where velocity integration used to be */
668 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
671 m3x3_mulv( player
.to_local
, player
.v
, vel
);
673 /* Calculate local forces */
675 if( fabsf(vel
[2]) > 0.01f
)
676 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
678 if( fabsf( slip
) > 1.2f
)
679 slip
= vg_signf( slip
) * 1.2f
;
681 player
.reverse
= -vg_signf(vel
[2]);
683 float substep
= ktimestep
* 0.2f
;
684 float fwd_resistance
= (vg_get_button( "break" )? 5.0f
: 0.02f
) * -substep
;
686 for( int i
=0; i
<5; i
++ )
688 vel
[2] = stable_force( vel
[2], vg_signf( vel
[2] ) * fwd_resistance
);
689 vel
[0] = stable_force( vel
[0], vg_signf( vel
[0] ) * -7.0f
*substep
);
692 static double start_push
= 0.0;
693 if( vg_get_button_down( "push" ) )
694 start_push
= vg_time
;
696 if( !vg_get_button("break") && vg_get_button( "push" ) )
698 float const k_maxpush
= 16.0f
,
701 float cycle_time
= vg_time
-start_push
,
702 amt
= k_pushaccel
* (sinf( cycle_time
* 8.0f
)*0.5f
+0.5f
)*ktimestep
,
703 current
= v3_length( vel
),
704 new_vel
= vg_minf( current
+ amt
, k_maxpush
);
705 new_vel
-= vg_minf(current
, k_maxpush
);
706 vel
[2] -= new_vel
* player
.reverse
;
709 m3x3_mulv( player
.to_world
, vel
, player
.v
);
711 if( vg_get_button( "yawl" ) )
712 player
.iY
+= 3.6f
* ktimestep
;
713 if( vg_get_button( "yawr" ) )
714 player
.iY
-= 3.6f
* ktimestep
;
716 float steer
= vg_get_axis( "horizontal" );
717 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
719 /* Too much lean and it starts to look like a snowboard here */
720 v2_lerp( player
.board_xy
, (v2f
){ slip
*0.25f
, 0.0f
},
721 ktimestep
*5.0f
, player
.board_xy
);
724 static void draw_cross(v3f pos
,u32 colour
)
727 v3_add( (v3f
){ 1.0f
,0.0f
,0.0f
}, pos
, p0
);
728 v3_add( (v3f
){-1.0f
,0.0f
,0.0f
}, pos
, p1
);
729 vg_line( p0
, p1
, colour
);
730 v3_add( (v3f
){0.0f
, 1.0f
,0.0f
}, pos
, p0
);
731 v3_add( (v3f
){0.0f
,-1.0f
,0.0f
}, pos
, p1
);
732 vg_line( p0
, p1
, colour
);
733 v3_add( (v3f
){0.0f
,0.0f
, 1.0f
}, pos
, p0
);
734 v3_add( (v3f
){0.0f
,0.0f
,-1.0f
}, pos
, p1
);
735 vg_line( p0
, p1
, colour
);
738 static void player_physics_air(void)
740 /* Debug prediciton */
742 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
743 for( int i
=0; i
<player
.land_log_count
; i
++ )
744 draw_cross( player
.land_target_log
[i
],
745 player
.land_target_colours
[i
] );
747 draw_cross( player
.land_target
, 0xff0000ff );
750 v3_copy( player
.co
, ground_pos
);
753 if( bvh_scene_sample( &world
.geo
, ground_pos
, &hit
) )
755 if( ground_pos
[1] > player
.co
[1] )
759 if( !ray_hit_is_ramp( &hit
) )
762 m4x3_mulv( player
.to_world
, player
.view
, player
.follow
);
763 character_ragdoll_copypose( &player
.mdl
, player
.v
);
772 * TODO: Find best landing surface and guide player towords it
774 float pstep
= ktimestep
*10.0f
;
777 v3_copy( player
.co
, pco
);
778 v3_copy( player
.v
, pv
);
780 float time_to_impact
= 0.0f
;
781 float limiter
= 1.0f
;
783 for( int i
=0; i
<50; i
++ )
785 v3_copy( pco
, pco1
);
786 apply_gravity( pv
, pstep
);
787 v3_muladds( pco
, pv
, pstep
, pco
);
789 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
794 v3_sub( pco
, pco1
, vdir
);
795 contact
.dist
= v3_length( vdir
);
796 v3_divs( vdir
, contact
.dist
, vdir
);
798 float orig_dist
= contact
.dist
;
799 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
802 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
804 float angle
= v3_dot( localup
, contact
.normal
);
806 v3_cross( localup
, contact
.normal
, axis
);
808 time_to_impact
+= (contact
.dist
/orig_dist
)*pstep
;
809 limiter
= vg_minf( 5.0f
, time_to_impact
)/5.0f
;
810 limiter
= 1.0f
-limiter
;
812 limiter
= 1.0f
-limiter
;
817 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
*(1.0f
-limiter
) );
818 q_mul( correction
, player
.rot
, player
.rot
);
821 draw_cross( contact
.pos
, 0xffff0000 );
824 time_to_impact
+= pstep
;
828 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
831 float iX
= vg_get_axis( "vertical" ) * 3.6f
* limiter
* ktimestep
;
832 static float siX
= 0.0f
;
833 siX
= vg_lerpf( siX
, iX
, 0.3f
);
838 m3x3_mulv( player
.to_world
, (v3f
){1.0f
,0.0f
,0.0f
}, vside
);
840 q_axis_angle( rotate
, vside
, siX
);
841 q_mul( rotate
, player
.rot
, player
.rot
);
844 v2f target
= {0.0f
,0.0f
};
845 v2_muladds( target
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
846 player
.grab
, target
);
847 v2_lerp( player
.board_xy
, target
, ktimestep
*3.0f
, player
.board_xy
);
850 static void player_animate(void);
851 static void player_update(void)
854 if( vg_get_axis("grabl")>0.0f
)
855 reset_player(0,NULL
);
859 static int clock
= 0;
869 if( clock
>= clock_divider
)
873 float horizontal
= vg_get_axis("horizontal"),
874 vertical
= vg_get_axis("vertical");
876 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
877 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
880 player_physics_air();
883 player_physics_ground();
885 /* Integrate velocity */
887 v3_copy( player
.co
, prevco
);
890 apply_gravity( player
.v
, ktimestep
);
891 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
894 /* Integrate inertia */
895 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
896 m3x3_mulv( player
.to_world
, vup
, vup
);
898 static float siY
= 0.0f
;
900 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
901 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
903 q_axis_angle( rotate
, vup
, siY
);
904 q_mul( rotate
, player
.rot
, player
.rot
);
906 player
.iY
= 0.0f
; /* temp */
909 if( gate_intersect( &gate_a
, player
.co
, prevco
) )
911 teleport_gate
*gate
= &gate_a
;
914 m4x3_mul( gate
->other
->to_world
, gate
->to_local
, transport
);
915 m4x3_mulv( transport
, player
.co
, player
.co
);
916 m3x3_mulv( transport
, player
.v
, player
.v
);
917 m3x3_mulv( transport
, player
.v_last
, player
.v_last
);
918 m3x3_mulv( transport
, player
.m
, player
.m
);
919 m3x3_mulv( transport
, player
.bob
, player
.bob
);
921 v4f transport_rotation
;
922 m3x3_q( transport
, transport_rotation
);
923 q_mul( transport_rotation
, player
.rot
, player
.rot
);
926 /* Camera and character */
927 player_transform_update();
930 player
.look_dir
[0] = atan2f( player
.v
[0], -player
.v
[2] );
931 player
.look_dir
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
932 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
939 //rb_torque( &mr_box, (v3f){0.0f,0.0f,1.0f}, 0.01f );
941 if( glfwGetKey( vg_window
, GLFW_KEY_F
) )
942 character_ragdoll_go( &player
.mdl
, player
.view
);
944 if( glfwGetKey( vg_window
, GLFW_KEY_G
) )
947 m4x3_mulv( player
.to_world
, player
.view
, player
.follow
);
948 character_ragdoll_copypose( &player
.mdl
, player
.v
);
951 static int clock
= 0;
954 if( clock
>= clock_divider
)
956 character_debug_ragdoll( &player
.mdl
);
959 character_ragdoll_iter( &player
.mdl
, &world
.geo
);
961 rb_build_manifold( &mr_box
, &world
.geo
);
962 rb_build_manifold( &mrs_box
, &world
.geo
);
963 rb_constraint_manifold( &mr_box
);
964 rb_constraint_manifold( &mrs_box
);
969 rb_debug( &mr_box
, 0xffffffff );
970 rb_debug( &mrs_box
, 0xff00ff00 );
972 rb_update_transform( &mr_box
);
973 rb_update_transform( &mrs_box
);
980 static void player_animate(void)
982 /* Camera position */
983 v3_sub( player
.v
, player
.v_last
, player
.a
);
984 v3_copy( player
.v
, player
.v_last
);
986 v3_add( player
.m
, player
.a
, player
.m
);
987 v3_lerp( player
.m
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, player
.m
);
990 player
.m
[0] = vg_clampf( player
.m
[0], -2.0f
, 2.0f
);
991 player
.m
[1] = vg_clampf( player
.m
[1], -0.2f
, 5.0f
);
992 player
.m
[2] = vg_clampf( player
.m
[2], -2.0f
, 2.0f
);
993 v3_copy( player
.m
, target
);
994 v3_lerp( player
.bob
, target
, 0.2f
, player
.bob
);
997 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
999 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
1000 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
1002 float kheight
= 2.0f
,
1007 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
1011 m3x3_mulv( player
.to_local
, player
.bob
, offset
);
1013 offset
[0] *= 0.3333f
;
1014 offset
[1] *= -0.25f
;
1016 v3_muladds( head
, offset
, 0.7f
, head
);
1017 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
1022 v3_copy( head
, player
.view
);
1023 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
1024 v3_add( player
.view
, camoffs
, player
.view
);
1030 * Animation blending
1031 * ===========================================
1034 static float fslide
= 0.0f
;
1035 static float fdirz
= 0.0f
;
1036 static float fdirx
= 0.0f
;
1037 static float fstand
= 0.0f
;
1038 static float ffly
= 0.0f
;
1040 float speed
= v3_length( player
.v
);
1042 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
1043 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
1045 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
1046 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
1047 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
1049 character_pose_reset( &player
.mdl
);
1051 float amt_air
= ffly
*ffly
,
1052 amt_ground
= 1.0f
-amt_air
,
1053 amt_std
= (1.0f
-fslide
) * amt_ground
,
1054 amt_stand
= amt_std
* fstand
,
1055 amt_aero
= amt_std
* (1.0f
-fstand
),
1056 amt_slide
= amt_ground
* fslide
;
1058 character_final_pose( &player
.mdl
, offset
, &pose_stand
, amt_stand
);
1059 character_final_pose( &player
.mdl
, offset
, &pose_aero
, amt_aero
*fdirz
);
1060 character_final_pose( &player
.mdl
, offset
,
1061 &pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
1062 character_final_pose( &player
.mdl
, offset
, &pose_slide
, amt_slide
*fdirx
);
1063 character_final_pose( &player
.mdl
, offset
,
1064 &pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
1066 character_final_pose( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
1067 &pose_fly
, amt_air
);
1071 v3_copy( player
.mdl
.cam_pos
, player
.view
);
1072 v3_muladds( player
.view
, offset
, 0.7f
, player
.view
);
1073 player
.view
[1] = vg_clampf( player
.view
[1], 0.3f
, kheight
);
1078 * ==========================
1080 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
1081 *arm_r
= &player
.mdl
.ik_arm_r
;
1084 m3x3_mulv( player
.to_local
, player
.v
, localv
);
1085 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
1086 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
1088 /* New board transformation */
1089 v4f board_rotation
; v3f board_location
;
1092 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
1093 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
1094 q_mul( rx
, rz
, board_rotation
);
1096 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
1097 q_m3x3( board_rotation
, mboard
);
1098 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
1099 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
1100 v3_copy( board_location
, mboard
[3] );
1103 float wheel_r
= offset
[0]*-0.4f
;
1105 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
1107 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
1109 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
1110 player
.mdl
.matrices
[k_chpart_wf
] );
1111 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
1112 player
.mdl
.matrices
[k_chpart_wb
][3] );
1113 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
1114 player
.mdl
.matrices
[k_chpart_wf
][3] );
1116 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
1117 player
.mdl
.matrices
[k_chpart_wb
] );
1118 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
1119 player
.mdl
.matrices
[k_chpart_wf
] );
1121 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
1122 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
1125 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
1126 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
1128 if( 1||player
.in_air
)
1130 float tuck
= player
.board_xy
[1],
1131 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
1133 float crouch
= player
.grab
*0.3f
;
1134 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
1135 crouch
, player
.mdl
.ik_body
.base
);
1136 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
1137 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
1141 //foot_l *= 1.0f-tuck_amt*1.5f;
1143 if( player
.grab
> 0.1f
)
1145 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
1146 player
.handl_target
);
1151 //foot_r *= 1.0f-tuck_amt*1.4f;
1153 if( player
.grab
> 0.1f
)
1155 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
1156 player
.handr_target
);
1161 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
1162 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
1164 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
1165 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
1169 static float rhead
= 0.0f
;
1170 rhead
= vg_lerpf( rhead
,
1171 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
1172 player
.mdl
.rhead
= rhead
;
1175 static void draw_player(void)
1178 vg_tex2d_bind( &tex_pallet
, 0 );
1180 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
1182 if( player
.is_dead
)
1183 character_mimic_ragdoll( &player
.mdl
);
1185 character_eval( &player
.mdl
);
1187 character_draw( &player
.mdl
, (player
.is_dead
|player
.in_air
)? 0.0f
: 1.0f
);
1190 static void vg_framebuffer_resize( int w
, int h
)
1192 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1193 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
1194 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
1196 gate_fb_resize( resize_renderbuffer_std
);
1197 water_fb_resize( resize_renderbuffer_std
);
1200 static void render_world( m4x4f projection
)
1202 m4x3f identity_matrix
;
1203 m4x3_identity( identity_matrix
);
1206 shader_unlit_uPv( projection
);
1207 shader_unlit_uTexMain( 0 );
1208 vg_tex2d_bind( &tex_sky
, 0 );
1210 glDepthMask(GL_FALSE
);
1211 glDisable(GL_DEPTH_TEST
);
1213 mesh_bind( &world
.skybox
);
1214 mesh_draw( &world
.skybox
);
1216 glEnable(GL_DEPTH_TEST
);
1217 glDepthMask(GL_TRUE
);
1220 shader_standard_use();
1221 shader_standard_uPv( projection
);
1222 shader_standard_uMdl( identity_matrix
);
1224 vg_tex2d_bind( &tex_grid
, 0 );
1225 shader_standard_uTexMain( 0 );
1226 shader_standard_uColour( (v4f
){0.4f
,0.4f
,0.4f
,1.0f
} );
1228 scene_bind( &world
.geo
);
1229 scene_draw( &world
.geo
);
1232 void vg_render(void)
1234 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1235 glViewport( 0,0, vg_window_x
, vg_window_y
);
1237 glDisable( GL_DEPTH_TEST
);
1238 glClearColor( 0.11f
, 0.35f
, 0.37f
, 1.0f
);
1239 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
1242 static v3f cam_lerped
= {0.0f
,0.0f
,0.0f
};
1243 v3_lerp( cam_lerped
, player
.view
, 0.08f
, cam_lerped
);
1247 m4x3_mulv( player
.to_world
, cam_lerped
, pos_inv
);
1249 static float air_blend
= 0.0f
;
1251 air_blend
= vg_lerpf( air_blend
, player
.in_air
, 0.04f
);
1252 v3_muladds( pos_inv
, player
.v
, -0.05f
*air_blend
, pos_inv
);
1255 v3_add( player
.co
, player
.view
, pos_inv
);
1256 v3_negate( pos_inv
, pos_inv
);
1258 static float vertical_lerp
= 0.0f
;
1259 vertical_lerp
= vg_lerpf( vertical_lerp
, pos_inv
[1], 1.0f
);
1260 v3f final
= { pos_inv
[0], vertical_lerp
, pos_inv
[2] };
1262 float speed
= freecam
? 0.0f
: v3_length( player
.v
);
1263 v3f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
, vg_randf()-0.5f
};
1264 v3_muls( shake
, speed
*0.01f
, shake
);
1266 static v2f cam_lerped_dir
;
1268 m4x3_identity( world_matrix
);
1269 if( player
.is_dead
)
1272 v3_sub( player
.mdl
.ragdoll
[k_chpart_head
].co
, player
.follow
, delta
);
1273 v3_normalize(delta
);
1276 v3_muladds( player
.mdl
.ragdoll
[k_chpart_head
].co
, delta
,
1277 -1.5f
, follow_pos
);
1278 v3_lerp( player
.follow
, follow_pos
, 0.1f
, player
.follow
);
1279 v3_negate( player
.follow
, final
);
1282 float yaw
= atan2f( delta
[0], -delta
[2] );
1283 float pitch
= asinf( delta
[1] );
1284 m4x3_rotate_x( world_matrix
, -pitch
);
1285 m4x3_rotate_y( world_matrix
, yaw
);
1289 v2_lerp( cam_lerped_dir
, player
.look_dir
, 0.04f
, cam_lerped_dir
);
1291 m4x3_rotate_x( world_matrix
,
1294 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
1296 m4x3_rotate_y( world_matrix
,
1299 player
.look_dir
[0]+shake
[0]*0.02f
);
1303 m4x3_translate( world_matrix
, final
);
1306 m4x3_expand( world_matrix
, world_4x4
);
1308 gpipeline
.fov
= freecam
? 60.0f
: 120.0f
;
1309 m4x4_projection( vg_pv
, gpipeline
.fov
,
1310 (float)vg_window_x
/ (float)vg_window_y
,
1313 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1315 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, 0xffff0000 );
1316 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, 0xff00ff00 );
1317 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, 0xff0000ff );
1319 glEnable( GL_DEPTH_TEST
);
1325 m4x3f cam_transform
;
1326 m4x3_invert_affine( world_matrix
, cam_transform
);
1328 render_world( vg_pv
);
1329 render_water_texture( cam_transform
);
1331 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1332 render_water_surface( vg_pv
);
1334 vg_tex2d_bind( &tex_water
, 1 );
1335 render_gate( &gate_a
, cam_transform
);
1338 /* Copy the RGB of what we have into the background buffer */
1339 glBindFramebuffer( GL_READ_FRAMEBUFFER
, 0 );
1340 glBindFramebuffer( GL_DRAW_FRAMEBUFFER
, render
.fb_background
);
1341 glBlitFramebuffer( 0,0, vg_window_x
, vg_window_y
,
1342 0,0, vg_window_x
, vg_window_y
,
1343 GL_COLOR_BUFFER_BIT
,
1346 /* Clear out the colour buffer, but keep depth */
1347 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1348 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1350 if( !player
.is_dead
)
1351 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
1353 glClear( GL_COLOR_BUFFER_BIT
);
1357 /* Draw back in the background */
1359 glDisable(GL_DEPTH_TEST
);
1360 glBlendFunc(GL_ONE_MINUS_DST_ALPHA
, GL_DST_ALPHA
);
1361 glBlendEquation(GL_FUNC_ADD
);
1364 shader_blit_uTexMain( 0 );
1365 glActiveTexture(GL_TEXTURE0
);
1366 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1368 glBindVertexArray( render
.fsquad
.vao
);
1369 glDrawArrays( GL_TRIANGLES
, 0, 6 );
1371 glDisable(GL_BLEND
);
1374 glDisable( GL_DEPTH_TEST
);
1375 vg_lines_drawall( (float *)vg_pv
);
1377 /* Debugger camera */
1378 glViewport( 0,0, 800, 800 );
1379 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1380 glClear( GL_DEPTH_BUFFER_BIT
);
1382 m4x3_identity( world_matrix
);
1385 v3_negate( player
.co
, debugcam
);
1386 debugcam
[2] -= 2.0f
;
1387 debugcam
[1] -= 0.7f
;
1389 m4x3_translate( world_matrix
, debugcam
);
1390 m4x3_expand( world_matrix
, world_4x4
);
1392 m4x4_projection( vg_pv
,
1394 (float)128.0f
/ (float)128.0f
,
1396 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1400 glEnable( GL_DEPTH_TEST
);
1404 glDisable( GL_DEPTH_TEST
);
1405 vg_lines_drawall( (float *)vg_pv
);
1407 glViewport( 0,0, vg_window_x
, vg_window_y
);
1412 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1414 for( int i
=0; i
<PART_COUNT
; i
++ )
1415 m4x3_copy( player
.mdl
.matrices
[i
], base
[i
] );
1417 replay_buffer_frame
++;
1419 if( replay_buffer_frame
== REPLAY_LENGTH
)
1420 replay_buffer_frame
= 0;
1429 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1430 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1432 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1433 player
.a
[0], player
.a
[1], player
.a
[2] );
1434 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1436 snprintf( buf
, 20, "pos %.2f %.2f %.2f",
1437 player
.co
[0], player
.co
[1], player
.co
[2] );
1438 gui_text( (ui_px
[2]){ 0, 40 }, buf
, 1, k_text_align_left
);
1440 if( vg_gamepad_ready
)
1442 for( int i
=0; i
<6; i
++ )
1444 snprintf( buf
, 20, "%.2f", vg_gamepad
.axes
[i
] );
1445 gui_text( (ui_px
[2]){ 0, (i
+3)*20 }, buf
, 1, k_text_align_left
);
1450 gui_text( (ui_px
[2]){ 0, 60 },
1451 "Gamepad not ready", 1, k_text_align_left
);
1455 void vg_free(void){}