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 int main( int argc
, char *argv
[] )
73 vg_init( argc
, argv
, "Voyager Game Engine" );
83 float vswitch
, slip
, slip_last
,
86 float iY
; /* Yaw inertia */
93 v2f look_dir
; /* TEMP */
99 v3f land_target_log
[12];
103 m4x3f to_world
, to_local
;
105 struct character mdl
;
107 v3f handl_target
, handr_target
,
121 static struct grender
123 GLuint fb_background
,
130 static void player_transform_update(void)
132 q_m3x3( player
.rot
, player
.to_world
);
133 v3_copy( player
.co
, player
.to_world
[3] );
135 m4x3_invert_affine( player
.to_world
, player
.to_local
);
138 static int reset_player( int argc
, char const *argv
[] )
140 v3_zero( player
.co
);
141 v3_copy( (v3f
){ 0.0f
, 0.0f
, -0.2f
}, player
.v
);
142 q_identity( player
.rot
);
143 player
.vswitch
= 1.0f
;
144 player
.slip_last
= 0.0f
;
146 player_transform_update();
150 static int playermodel( int argc
, char const *argv
[] )
152 if( argc
< 1 ) return 0;
154 glmesh old_mesh
= player
.mdl
.mesh
;
156 if( character_load( &player
.mdl
, argv
[0] ) )
157 mesh_free( &old_mesh
);
162 void vg_register(void)
165 character_shader_register();
166 SHADER_INIT( shader_blit
);
171 replay_buffer
= malloc( sizeof(m4x3f
) * REPLAY_LENGTH
* (PART_COUNT
) );
173 vg_tex2d_init( texture_list
, vg_list_size( texture_list
) );
175 vg_convar_push( (struct vg_convar
){
177 .data
= &replay_buffer_frame
,
178 .data_type
= k_convar_dtype_i32
,
179 .opt_i32
= { .min
=0, .max
=REPLAY_LENGTH
-1, .clamp
=1 },
183 vg_convar_push( (struct vg_convar
){
185 .data
= &replay_record
,
186 .data_type
= k_convar_dtype_i32
,
187 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
191 vg_convar_push( (struct vg_convar
){
194 .data_type
= k_convar_dtype_i32
,
195 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
199 vg_convar_push( (struct vg_convar
){
201 .data
= &sv_debugcam
,
202 .data_type
= k_convar_dtype_i32
,
203 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
207 vg_convar_push( (struct vg_convar
){
210 .data_type
= k_convar_dtype_i32
,
211 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
215 vg_convar_push( (struct vg_convar
){
218 .data_type
= k_convar_dtype_i32
,
219 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
223 vg_convar_push( (struct vg_convar
){
226 .data_type
= k_convar_dtype_i32
,
227 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
231 vg_convar_push( (struct vg_convar
){
232 .name
= "thirdperson",
233 .data
= &thirdperson
,
234 .data_type
= k_convar_dtype_i32
,
235 .opt_i32
= { .min
=0, .max
=1, .clamp
=1 },
239 vg_convar_push( (struct vg_convar
){
241 .data
= &clock_divider
,
242 .data_type
= k_convar_dtype_i32
,
243 .opt_i32
= { .min
=0, .max
=1, .clamp
=0 },
247 vg_function_push( (struct vg_cmd
){
249 .function
= reset_player
252 v3f lightDir
= { 0.1f
, 0.8f
, 0.2f
};
253 v3_normalize( lightDir
);
255 character_load( &player
.mdl
, "ch_default" );
258 scene_init( &world
.geo
);
259 model
*mworld
= vg_asset_read( "models/mp_dev.mdl" );
261 scene_add_model( &world
.geo
, mworld
, submodel_get( mworld
, "mp_dev" ),
262 (v3f
){0.0f
,0.0f
,0.0f
}, 0.0f
, 1.0f
);
265 scene_upload( &world
.geo
);
266 bvh_create( &world
.geo
);
269 reset_player( 0, NULL
);
270 player_transform_update();
272 /* Create framebuffers */
273 glGenFramebuffers( 1, &render
.fb_background
);
274 glBindFramebuffer( GL_FRAMEBUFFER
, render
.fb_background
);
276 glGenTextures( 1, &render
.rgb_background
);
277 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
278 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, vg_window_x
, vg_window_y
,
279 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
281 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
282 glTexParameteri( GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
283 glFramebufferTexture2D( GL_FRAMEBUFFER
, GL_COLOR_ATTACHMENT0
,
285 render
.rgb_background
, 0);
288 float quad
[] = { 0.0f
, 0.0f
, 1.0f
, 1.0f
, 0.0f
, 1.0f
,
289 0.0f
, 0.0f
, 1.0f
, 0.0f
, 1.0f
, 1.0f
};
291 glGenVertexArrays( 1, &render
.fsquad
.vao
);
292 glGenBuffers( 1, &render
.fsquad
.vbo
);
293 glGenBuffers( 1, &render
.fsquad
.ebo
);
294 glBindVertexArray( render
.fsquad
.vao
);
295 glBindBuffer( GL_ARRAY_BUFFER
, render
.fsquad
.vbo
);
296 glBufferData( GL_ARRAY_BUFFER
, sizeof(quad
), quad
, GL_STATIC_DRAW
);
297 glBindVertexArray( render
.fsquad
.vao
);
298 glVertexAttribPointer( 0, 2, GL_FLOAT
, GL_FALSE
,
299 sizeof(float)*2, (void*)0 );
300 glEnableVertexAttribArray( 0 );
305 static float ktimestep
= 1.0f
/60.0f
;
307 static void player_freecam(void)
310 m4x3_identity( cam_rot
);
311 m4x3_rotate_y( cam_rot
, -player
.look_dir
[0] );
312 m4x3_rotate_x( cam_rot
, -player
.look_dir
[1] );
314 v3f lookdir
= { 0.0f
, 0.0f
, -1.0f
},
315 sidedir
= { 1.0f
, 0.0f
, 0.0f
};
317 m4x3_mulv( cam_rot
, lookdir
, lookdir
);
318 m4x3_mulv( cam_rot
, sidedir
, sidedir
);
320 float movespeed
= 5.0f
;
321 static v2f mouse_last
,
322 view_vel
= { 0.0f
, 0.0f
};
324 static v3f move_vel
= { 0.0f
, 0.0f
, 0.0f
};
326 if( vg_get_button_down( "primary" ) )
327 v2_copy( vg_mouse
, mouse_last
);
328 else if( vg_get_button( "primary" ) )
331 v2_sub( vg_mouse
, mouse_last
, delta
);
332 v2_copy( vg_mouse
, mouse_last
);
334 v2_muladds( view_vel
, delta
, 0.005f
, view_vel
);
337 v2_muls( view_vel
, 0.75f
, view_vel
);
338 v2_add( view_vel
, player
.look_dir
, player
.look_dir
);
340 vg_clampf( player
.look_dir
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
342 if( vg_get_button( "forward" ) )
343 v3_muladds( move_vel
, lookdir
, ktimestep
* movespeed
, move_vel
);
344 if( vg_get_button( "back" ) )
345 v3_muladds( move_vel
, lookdir
, ktimestep
*-movespeed
, move_vel
);
346 if( vg_get_button( "left" ) )
347 v3_muladds( move_vel
, sidedir
, ktimestep
*-movespeed
, move_vel
);
348 if( vg_get_button( "right" ) )
349 v3_muladds( move_vel
, sidedir
, ktimestep
* movespeed
, move_vel
);
351 v3_muls( move_vel
, 0.75f
, move_vel
);
352 v3_add( move_vel
, player
.view
, player
.view
);
355 static void apply_gravity( v3f vel
, float const timestep
)
357 v3f gravity
= { 0.0f
, -9.6f
, 0.0f
};
358 v3_muladds( vel
, gravity
, timestep
, vel
);
361 static void player_start_air(void)
365 float pstep
= ktimestep
*10.0f
;
367 float best_velocity_mod
= 0.0f
,
368 best_velocity_delta
= -9999.9f
;
371 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, vup
);
372 v3_cross( vup
, player
.v
, axis
);
373 v3_normalize( axis
);
374 player
.land_log_count
= 0;
376 m3x3_identity( player
.vr
);
378 for( int m
=0;m
<=5; m
++ )
380 float vmod
= ((float)m
/ 5.0f
)*0.09f
;
383 v3_copy( player
.co
, pco
);
384 v3_copy( player
.v
, pv
);
387 * Try different 'rotations' of the velocity to find the best possible
388 * landing normal. This conserves magnitude at the expense of slightly
389 * unrealistic results
395 q_axis_angle( vr_q
, axis
, vmod
);
398 for( int i
=0; i
<50; i
++ )
400 v3_copy( pco
, pco1
);
401 apply_gravity( pv
, pstep
);
403 m3x3_mulv( vr
, pv
, pv
);
404 v3_muladds( pco
, pv
, pstep
, pco
);
409 v3_sub( pco
, pco1
, vdir
);
410 contact
.dist
= v3_length( vdir
);
411 v3_divs( vdir
, contact
.dist
, vdir
);
413 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
415 float land_delta
= v3_dot( pv
, contact
.normal
);
417 if( (land_delta
< 0.0f
) && (land_delta
> best_velocity_delta
) )
419 best_velocity_delta
= land_delta
;
420 best_velocity_mod
= vmod
;
422 v3_copy( contact
.pos
, player
.land_target
);
424 q_axis_angle( vr_q
, axis
, vmod
*0.1f
);
425 q_m3x3( vr_q
, player
.vr
);
428 v3_copy( contact
.pos
,
429 player
.land_target_log
[player
.land_log_count
++] );
435 //v3_rotate( player.v, best_velocity_mod, axis, player.v );
438 v3_muls( player
.v
, best_velocity_mod
, player
.v
);
441 static int sample_if_resistant( v3f pos
)
444 v3_copy( pos
, ground
);
446 if( bvh_scene_sample( &world
.geo
, ground
, norm
) )
449 v3_copy( player
.v
, angle
);
450 v3_normalize( angle
);
451 float resistance
= v3_dot( norm
, angle
);
453 if( resistance
< 0.25f
)
455 v3_copy( ground
, pos
);
463 static float stable_force( float current
, float diff
)
465 float new = current
+ diff
;
467 if( new * current
< 0.0f
)
473 static void player_physics_ground(void)
476 * Getting surface collision points,
477 * the contact manifold is a triangle for simplicity.
479 v3f contact_front
, contact_back
, fwd
, fwd1
, contact_norm
, vup
, vside
,
482 float klength
= 0.65f
;
483 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 0.0f
,-1.0f
}, fwd
);
484 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
485 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
486 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
487 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
488 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
493 sample_if_resistant( contact_front
) +
494 sample_if_resistant( contact_back
) +
495 sample_if_resistant( contact_norm
);
497 if( contact_count
< 3 )
505 v3_sub( contact_norm
, contact_front
, v0
);
506 v3_sub( contact_back
, contact_front
, v1
);
507 v3_cross( v1
, v0
, norm
);
508 v3_normalize( norm
);
510 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
511 vg_line( contact_back
, contact_front
, 0xff0000ff );
513 /* Surface alignment */
514 float angle
= v3_dot( vup
, norm
);
515 v3_cross( vup
, norm
, axis
);
520 q_axis_angle( correction
, axis
, acosf(angle
) );
521 q_mul( correction
, player
.rot
, player
.rot
);
524 float resistance
= v3_dot( norm
, player
.v
);
526 if( resistance
>= 0.0f
)
533 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
536 /* This is where velocity integration used to be */
540 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
543 m3x3_mulv( player
.to_local
, player
.v
, vel
);
545 /* Calculate local forces */
547 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
548 if( fabsf( slip
) > 1.2f
)
549 slip
= vg_signf( slip
) * 1.2f
;
551 player
.reverse
= -vg_signf(vel
[2]);
553 float substep
= ktimestep
* 0.2f
;
554 for( int i
=0; i
<5; i
++ )
556 vel
[2] = stable_force( vel
[2], vg_signf( vel
[2] ) * -0.02f
*substep
);
557 vel
[0] = stable_force( vel
[0], vg_signf( vel
[0] ) * -7.0f
*substep
);
560 m3x3_mulv( player
.to_world
, vel
, player
.v
);
562 if( vg_get_button( "yawl" ) )
563 player
.iY
+= 3.6f
* ktimestep
;
564 if( vg_get_button( "yawr" ) )
565 player
.iY
-= 3.6f
* ktimestep
;
567 float steer
= vg_get_axis( "horizontal" );
568 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
570 /* Too much lean and it starts to look like a snowboard here */
571 v2_lerp( player
.board_xy
, (v2f
){ slip
*0.25f
, 0.0f
},
572 ktimestep
*5.0f
, player
.board_xy
);
575 static void draw_cross(v3f pos
,u32 colour
)
578 v3_add( (v3f
){ 1.0f
,0.0f
,0.0f
}, pos
, p0
);
579 v3_add( (v3f
){-1.0f
,0.0f
,0.0f
}, pos
, p1
);
580 vg_line( p0
, p1
, colour
);
581 v3_add( (v3f
){0.0f
, 1.0f
,0.0f
}, pos
, p0
);
582 v3_add( (v3f
){0.0f
,-1.0f
,0.0f
}, pos
, p1
);
583 vg_line( p0
, p1
, colour
);
584 v3_add( (v3f
){0.0f
,0.0f
, 1.0f
}, pos
, p0
);
585 v3_add( (v3f
){0.0f
,0.0f
,-1.0f
}, pos
, p1
);
586 vg_line( p0
, p1
, colour
);
589 static void player_physics_air(void)
591 /* Debug prediciton */
593 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
594 for( int i
=0; i
<player
.land_log_count
; i
++ )
595 draw_cross( player
.land_target_log
[i
], 0xff00ffff );
597 draw_cross( player
.land_target
, 0xff0000ff );
599 v3f ground_pos
, ground_norm
;
600 v3_copy( player
.co
, ground_pos
);
602 if( bvh_scene_sample( &world
.geo
, ground_pos
, ground_norm
) )
604 if( ground_pos
[1] > player
.co
[1] )
613 * TODO: Find best landing surface and guide player towords it
615 float pstep
= ktimestep
*10.0f
;
618 v3_copy( player
.co
, pco
);
619 v3_copy( player
.v
, pv
);
621 for( int i
=0; i
<50; i
++ )
623 v3_copy( pco
, pco1
);
624 apply_gravity( pv
, pstep
);
625 v3_muladds( pco
, pv
, pstep
, pco
);
627 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
632 v3_sub( pco
, pco1
, vdir
);
633 contact
.dist
= v3_length( vdir
);
634 v3_divs( vdir
, contact
.dist
, vdir
);
636 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
639 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
641 float angle
= v3_dot( localup
, contact
.normal
);
643 v3_cross( localup
, contact
.normal
, axis
);
648 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
);
649 q_mul( correction
, player
.rot
, player
.rot
);
652 draw_cross( contact
.pos
, 0xffff0000 );
658 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
660 v2f target
= {0.0f
,0.0f
};
661 v2_muladds( target
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
662 player
.grab
, target
);
663 v2_lerp( player
.board_xy
, target
, ktimestep
*3.0f
, player
.board_xy
);
666 static void player_animate(void);
667 static void player_update(void)
669 static int clock
= 0;
672 if( clock
>= clock_divider
)
684 if( vg_get_axis("grabl")>0.0f
)
685 reset_player(0,NULL
);
686 if( vg_get_button( "push" ) )
688 v3f dir
= { 0.0f
, 0.0f
, -1.0f
};
690 m3x3_mulv( player
.to_world
, dir
, dir
);
691 v3_muladds( player
.v
, dir
, 5.0f
* ktimestep
, player
.v
);
694 float horizontal
= vg_get_axis("horizontal"),
695 vertical
= vg_get_axis("vertical");
697 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
698 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
700 /* Integrate velocity */
703 apply_gravity( player
.v
, ktimestep
);
704 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
707 /* Integrate inertia */
708 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
709 m3x3_mulv( player
.to_world
, vup
, vup
);
711 static float siY
= 0.0f
;
713 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
714 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
716 q_axis_angle( rotate
, vup
, siY
);
717 q_mul( rotate
, player
.rot
, player
.rot
);
719 player
.look_dir
[0] = atan2f( player
.v
[0], -player
.v
[2] );
720 player
.look_dir
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
721 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
723 player
.iY
= 0.0f
; /* temp */
726 player_physics_air();
729 player_physics_ground();
731 /* Camera and character */
733 player_transform_update();
734 q_normalize(player
.rot
);
741 bvh_debug( &world
.geo
, player
.co
);
744 static void player_animate(void)
746 /* Camera position */
747 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
748 static v3f momentum
, bob
;
750 v3_sub( player
.v
, last_vel
, player
.a
);
751 v3_copy( player
.v
, last_vel
);
753 v3_add( momentum
, player
.a
, momentum
);
754 v3_lerp( momentum
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, momentum
);
757 momentum
[0] = vg_clampf( momentum
[0], -2.0f
, 2.0f
);
758 momentum
[1] = vg_clampf( momentum
[1], -0.2f
, 5.0f
);
759 momentum
[2] = vg_clampf( momentum
[2], -2.0f
, 2.0f
);
760 v3_copy( momentum
, target
);
761 v3_lerp( bob
, target
, 0.2f
, bob
);
764 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
766 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
767 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
769 float kheight
= 2.0f
,
774 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
778 m3x3_mulv( player
.to_local
, bob
, offset
);
780 offset
[0] *= 0.3333f
;
783 v3_muladds( head
, offset
, 0.7f
, head
);
784 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
789 v3_copy( head
, player
.view
);
790 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
791 v3_add( player
.view
, camoffs
, player
.view
);
798 * ===========================================
801 static float fslide
= 0.0f
;
802 static float fdirz
= 0.0f
;
803 static float fdirx
= 0.0f
;
804 static float fstand
= 0.0f
;
805 static float ffly
= 0.0f
;
807 float speed
= v3_length( player
.v
);
809 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
810 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
812 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
813 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
814 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
816 character_pose_reset( &player
.mdl
);
818 float amt_air
= ffly
*ffly
,
819 amt_ground
= 1.0f
-amt_air
,
820 amt_std
= (1.0f
-fslide
) * amt_ground
,
821 amt_stand
= amt_std
* fstand
,
822 amt_aero
= amt_std
* (1.0f
-fstand
),
823 amt_slide
= amt_ground
* fslide
;
825 character_final_pose( &player
.mdl
, offset
, &pose_stand
, amt_stand
);
826 character_final_pose( &player
.mdl
, offset
, &pose_aero
, amt_aero
*fdirz
);
827 character_final_pose( &player
.mdl
, offset
,
828 &pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
829 character_final_pose( &player
.mdl
, offset
, &pose_slide
, amt_slide
*fdirx
);
830 character_final_pose( &player
.mdl
, offset
,
831 &pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
833 character_final_pose( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
834 &pose_fly
, amt_air
);
838 v3_copy( player
.mdl
.cam_pos
, player
.view
);
839 v3_muladds( player
.view
, offset
, 0.7f
, player
.view
);
840 player
.view
[1] = vg_clampf( player
.view
[1], 0.3f
, kheight
);
845 * ==========================
847 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
848 *arm_r
= &player
.mdl
.ik_arm_r
;
851 m3x3_mulv( player
.to_local
, player
.v
, localv
);
852 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
853 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
855 /* New board transformation */
856 v4f board_rotation
; v3f board_location
;
859 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
860 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
861 q_mul( rx
, rz
, board_rotation
);
863 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
864 q_m3x3( board_rotation
, mboard
);
865 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
866 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
867 v3_copy( board_location
, mboard
[3] );
870 float wheel_r
= offset
[0]*-0.4f
;
872 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
874 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
876 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
877 player
.mdl
.matrices
[k_chpart_wf
] );
878 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
879 player
.mdl
.matrices
[k_chpart_wb
][3] );
880 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
881 player
.mdl
.matrices
[k_chpart_wf
][3] );
883 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
884 player
.mdl
.matrices
[k_chpart_wb
] );
885 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
886 player
.mdl
.matrices
[k_chpart_wf
] );
888 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
889 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
892 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
893 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
895 if( 1||player
.in_air
)
897 float tuck
= player
.board_xy
[1],
898 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
900 float crouch
= player
.grab
*0.3f
;
901 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
902 crouch
, player
.mdl
.ik_body
.base
);
903 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
904 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
908 //foot_l *= 1.0f-tuck_amt*1.5f;
910 if( player
.grab
> 0.1f
)
912 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
913 player
.handl_target
);
918 //foot_r *= 1.0f-tuck_amt*1.4f;
920 if( player
.grab
> 0.1f
)
922 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
923 player
.handr_target
);
928 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
929 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
931 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
932 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
936 static float rhead
= 0.0f
;
937 rhead
= vg_lerpf( rhead
,
938 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
939 player
.mdl
.rhead
= rhead
;
942 static void draw_player(void)
945 vg_tex2d_bind( &tex_pallet
, 0 );
947 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
948 character_eval( &player
.mdl
);
949 character_draw( &player
.mdl
, 1.0f
);
952 static void vg_framebuffer_resize( int w
, int h
)
954 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
955 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
956 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
961 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
962 glViewport( 0,0, vg_window_x
, vg_window_y
);
964 glDisable( GL_DEPTH_TEST
);
965 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
966 glClearColor(111.0f
/255.0f
, 46.0f
/255.0f
, 45.0f
/255.0f
,1.0f
);
968 glClearColor( powf(0.066f
,1.0f
/2.2f
),
969 powf(0.050f
,1.0f
/2.2f
),
970 powf(0.046f
,1.0f
/2.2f
), 1.0f
);
971 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
974 static v3f cam_lerped
= {0.0f
,0.0f
,0.0f
};
975 v3_lerp( cam_lerped
, player
.view
, 0.08f
, cam_lerped
);
978 m4x3_mulv( player
.to_world
, cam_lerped
, pos_inv
);
980 v3_add( player
.co
, player
.view
, pos_inv
);
981 v3_negate( pos_inv
, pos_inv
);
983 static float vertical_lerp
= 0.0f
;
984 vertical_lerp
= vg_lerpf( vertical_lerp
, pos_inv
[1], 1.0f
);
985 v3f final
= { pos_inv
[0], vertical_lerp
, pos_inv
[2] };
987 float speed
= freecam
? 0.0f
: v3_length( player
.v
);
988 v3f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
, vg_randf()-0.5f
};
989 v3_muls( shake
, speed
*0.01f
, shake
);
991 static v2f cam_lerped_dir
;
993 v2_lerp( cam_lerped_dir
, player
.look_dir
, 0.04f
, cam_lerped_dir
);
995 m4x3_identity( world_matrix
);
996 m4x3_rotate_x( world_matrix
,
999 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
1001 m4x3_rotate_y( world_matrix
,
1004 player
.look_dir
[0]+shake
[0]*0.02f
);
1005 m4x3_translate( world_matrix
, final
);
1008 m4x3_expand( world_matrix
, world_4x4
);
1009 m4x4_projection( vg_pv
,
1010 freecam
? 60.0f
: 120.0f
,
1011 (float)vg_window_x
/ (float)vg_window_y
,
1013 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1015 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, 0xffff0000 );
1016 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, 0xff00ff00 );
1017 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, 0xff0000ff );
1019 glEnable( GL_DEPTH_TEST
);
1024 SHADER_USE(shader_standard_lit
);
1026 m4x3f identity_matrix
;
1027 m4x3_identity( identity_matrix
);
1029 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit
, "uPv" ),
1030 1, GL_FALSE
, (float *)vg_pv
);
1031 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_standard_lit
, "uMdl" ),
1032 1, GL_FALSE
, (float *)identity_matrix
);
1034 vg_tex2d_bind( &tex_grid
, 0 );
1035 glUniform1i( SHADER_UNIFORM( shader_standard_lit
, "uTexMain" ), 0 );
1037 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1038 0.4f
,0.4f
,0.4f
,1.0f
);
1040 scene_bind( &world
.geo
);
1041 scene_draw( &world
.geo
);
1043 if( !replay_record
)
1045 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1047 for( int i
=0; i
<PART_COUNT
; i
++ )
1048 m4x3_copy( base
[i
], player
.mdl
.matrices
[i
] );
1050 replay_buffer_frame
++;
1052 if( replay_buffer_frame
== REPLAY_LENGTH
)
1053 replay_buffer_frame
= 0;
1055 vg_tex2d_bind( &tex_pallet
, 0 );
1056 character_draw( &player
.mdl
, 0.0f
);
1062 /* Copy the RGB of what we have into the background buffer */
1063 glBindFramebuffer( GL_READ_FRAMEBUFFER
, 0 );
1064 glBindFramebuffer( GL_DRAW_FRAMEBUFFER
, render
.fb_background
);
1065 glBlitFramebuffer( 0,0, vg_window_x
, vg_window_y
,
1066 0,0, vg_window_x
, vg_window_y
,
1067 GL_COLOR_BUFFER_BIT
,
1070 /* Clear out the colour buffer, but keep depth */
1071 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1072 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1075 glClear( GL_COLOR_BUFFER_BIT
);
1077 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
1083 /* Draw back in the background */
1085 glDisable(GL_DEPTH_TEST
);
1086 glBlendFunc(GL_ONE_MINUS_DST_ALPHA
, GL_DST_ALPHA
);
1087 glBlendEquation(GL_FUNC_ADD
);
1089 SHADER_USE( shader_blit
);
1091 glUniform1i( SHADER_UNIFORM(shader_blit
,"uTexMain"), 0 );
1092 glActiveTexture(GL_TEXTURE0
);
1093 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1095 glBindVertexArray( render
.fsquad
.vao
);
1096 glDrawArrays( GL_TRIANGLES
, 0, 6 );
1098 glDisable(GL_BLEND
);
1101 glDisable( GL_DEPTH_TEST
);
1102 vg_lines_drawall( (float *)vg_pv
);
1104 /* Debugger camera */
1105 glViewport( 0,0, 800, 800 );
1106 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1107 glClear( GL_DEPTH_BUFFER_BIT
);
1109 m4x3_identity( world_matrix
);
1112 v3_negate( player
.co
, debugcam
);
1113 debugcam
[2] -= 2.0f
;
1114 debugcam
[1] -= 0.7f
;
1116 m4x3_translate( world_matrix
, debugcam
);
1117 m4x3_expand( world_matrix
, world_4x4
);
1119 m4x4_projection( vg_pv
,
1121 (float)128.0f
/ (float)128.0f
,
1123 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1127 glEnable( GL_DEPTH_TEST
);
1131 glDisable( GL_DEPTH_TEST
);
1132 vg_lines_drawall( (float *)vg_pv
);
1134 glViewport( 0,0, vg_window_x
, vg_window_y
);
1139 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1141 for( int i
=0; i
<PART_COUNT
; i
++ )
1142 m4x3_copy( player
.mdl
.matrices
[i
], base
[i
] );
1144 replay_buffer_frame
++;
1146 if( replay_buffer_frame
== REPLAY_LENGTH
)
1147 replay_buffer_frame
= 0;
1155 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1156 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1158 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1159 player
.a
[0], player
.a
[1], player
.a
[2] );
1160 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1162 snprintf( buf
, 20, "pos %.2f %.2f %.2f",
1163 player
.co
[0], player
.co
[1], player
.co
[2] );
1164 gui_text( (ui_px
[2]){ 0, 40 }, buf
, 1, k_text_align_left
);
1166 if( vg_gamepad_ready
)
1168 for( int i
=0; i
<6; i
++ )
1170 snprintf( buf
, 20, "%.2f", vg_gamepad
.axes
[i
] );
1171 gui_text( (ui_px
[2]){ 0, (i
+3)*20 }, buf
, 1, k_text_align_left
);
1176 gui_text( (ui_px
[2]){ 0, 60 },
1177 "Gamepad not ready", 1, k_text_align_left
);
1181 void vg_free(void){}