69d4df93e5c0dd2501bef4f9f3dd256188c90110
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 void player_physics_ground(void)
466 * Getting surface collision points,
467 * the contact manifold is a triangle for simplicity.
469 v3f contact_front
, contact_back
, fwd
, fwd1
, contact_norm
, vup
, vside
,
472 float klength
= 0.65f
;
473 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 0.0f
,-1.0f
}, fwd
);
474 m4x3_mulv( player
.to_world
, (v3f
){ 0.15f
,0.0f
,-klength
}, contact_norm
);
475 m4x3_mulv( player
.to_world
, (v3f
){-0.15f
,0.0f
,-klength
}, contact_front
);
476 m4x3_mulv( player
.to_world
, (v3f
){ 0.00f
,0.0f
, klength
}, contact_back
);
477 m3x3_mulv( player
.to_world
, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, vup
);
478 m3x3_mulv( player
.to_world
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, vside
);
483 sample_if_resistant( contact_front
) +
484 sample_if_resistant( contact_back
) +
485 sample_if_resistant( contact_norm
);
487 if( contact_count
< 3 )
495 v3_sub( contact_norm
, contact_front
, v0
);
496 v3_sub( contact_back
, contact_front
, v1
);
497 v3_cross( v1
, v0
, norm
);
498 v3_normalize( norm
);
500 vg_line( contact_norm
, contact_front
, 0xff00ff00 );
501 vg_line( contact_back
, contact_front
, 0xff0000ff );
503 /* Surface alignment */
504 float angle
= v3_dot( vup
, norm
);
505 v3_cross( vup
, norm
, axis
);
510 q_axis_angle( correction
, axis
, acosf(angle
) );
511 q_mul( correction
, player
.rot
, player
.rot
);
514 float resistance
= v3_dot( norm
, player
.v
);
516 if( resistance
>= 0.0f
)
523 v3_muladds( player
.v
, norm
, -resistance
, player
.v
);
526 /* This is where velocity integration used to be */
530 player
.co
[1] = (contact_front
[1]+contact_back
[1])*0.5f
;
533 m3x3_mulv( player
.to_local
, player
.v
, vel
);
535 /* Calculate local forces */
537 slip
= fabsf(-vel
[0] / vel
[2]) * vg_signf(vel
[0]);
538 if( fabsf( slip
) > 1.2f
)
539 slip
= vg_signf( slip
) * 1.2f
;
541 player
.reverse
= -vg_signf(vel
[2]);
543 float substep
= ktimestep
* 0.2f
;
544 for( int i
=0; i
<5; i
++ )
546 if( fabsf(vel
[2]) >= 0.02f
*substep
)
547 vel
[2] += vg_signf( vel
[2] ) * -0.02f
* substep
;
548 if( fabsf(vel
[0]) >= 7.0f
*substep
)
549 vel
[0] += vg_signf( vel
[0] ) * -7.0f
* substep
;
552 m3x3_mulv( player
.to_world
, vel
, player
.v
);
554 if( vg_get_button( "yawl" ) )
555 player
.iY
+= 3.6f
* ktimestep
;
556 if( vg_get_button( "yawr" ) )
557 player
.iY
-= 3.6f
* ktimestep
;
559 float steer
= vg_get_axis( "horizontal" );
560 player
.iY
-= vg_signf(steer
)*powf(steer
,2.0f
) * 1.5f
* ktimestep
;
563 static void draw_cross(v3f pos
,u32 colour
)
566 v3_add( (v3f
){ 1.0f
,0.0f
,0.0f
}, pos
, p0
);
567 v3_add( (v3f
){-1.0f
,0.0f
,0.0f
}, pos
, p1
);
568 vg_line( p0
, p1
, colour
);
569 v3_add( (v3f
){0.0f
, 1.0f
,0.0f
}, pos
, p0
);
570 v3_add( (v3f
){0.0f
,-1.0f
,0.0f
}, pos
, p1
);
571 vg_line( p0
, p1
, colour
);
572 v3_add( (v3f
){0.0f
,0.0f
, 1.0f
}, pos
, p0
);
573 v3_add( (v3f
){0.0f
,0.0f
,-1.0f
}, pos
, p1
);
574 vg_line( p0
, p1
, colour
);
577 static void player_physics_air(void)
579 /* Debug prediciton */
581 m3x3_mulv( player
.vr
, player
.v
, player
.v
);
582 for( int i
=0; i
<player
.land_log_count
; i
++ )
583 draw_cross( player
.land_target_log
[i
], 0xff00ffff );
585 draw_cross( player
.land_target
, 0xff0000ff );
587 v3f ground_pos
, ground_norm
;
588 v3_copy( player
.co
, ground_pos
);
590 if( bvh_scene_sample( &world
.geo
, ground_pos
, ground_norm
) )
592 if( ground_pos
[1] > player
.co
[1] )
601 * TODO: Find best landing surface and guide player towords it
603 float pstep
= ktimestep
*10.0f
;
606 v3_copy( player
.co
, pco
);
607 v3_copy( player
.v
, pv
);
609 for( int i
=0; i
<50; i
++ )
611 v3_copy( pco
, pco1
);
612 apply_gravity( pv
, pstep
);
613 v3_muladds( pco
, pv
, pstep
, pco
);
615 //vg_line( pco, pco1, i&0x1?0xff000000:0xffffffff );
620 v3_sub( pco
, pco1
, vdir
);
621 contact
.dist
= v3_length( vdir
);
622 v3_divs( vdir
, contact
.dist
, vdir
);
624 if( bvh_raycast( &world
.geo
, pco1
, vdir
, &contact
))
627 m3x3_mulv( player
.to_world
, (v3f
){0.0f
,1.0f
,0.0f
}, localup
);
629 float angle
= v3_dot( localup
, contact
.normal
);
631 v3_cross( localup
, contact
.normal
, axis
);
636 q_axis_angle( correction
, axis
, acosf(angle
)*0.05f
);
637 q_mul( correction
, player
.rot
, player
.rot
);
640 draw_cross( contact
.pos
, 0xffff0000 );
646 player
.iY
-= vg_get_axis( "horizontal" ) * 3.6f
* ktimestep
;
649 static void player_animate(void);
650 static void player_update(void)
652 static int clock
= 0;
655 if( clock
>= clock_divider
)
667 if( vg_get_axis("grabl")>0.0f
)
668 reset_player(0,NULL
);
669 if( vg_get_button( "push" ) )
671 v3f dir
= { 0.0f
, 0.0f
, -1.0f
};
673 m3x3_mulv( player
.to_world
, dir
, dir
);
674 v3_muladds( player
.v
, dir
, 5.0f
* ktimestep
, player
.v
);
677 float horizontal
= vg_get_axis("horizontal"),
678 vertical
= vg_get_axis("vertical");
680 player
.joy_l
[0] = vg_signf(horizontal
) * powf( horizontal
, 2.0f
);
681 player
.joy_l
[1] = vg_signf(vertical
) * powf( vertical
, 2.0f
);
683 /* Integrate velocity */
686 apply_gravity( player
.v
, ktimestep
);
687 v3_muladds( player
.co
, player
.v
, ktimestep
, player
.co
);
690 /* Integrate inertia */
691 v4f rotate
; v3f vup
= {0.0f
,1.0f
,0.0f
};
692 m3x3_mulv( player
.to_world
, vup
, vup
);
694 static float siY
= 0.0f
;
696 float lerpq
= player
.in_air
? 0.04f
: 0.3f
;
697 siY
= vg_lerpf( siY
, player
.iY
, lerpq
);
699 q_axis_angle( rotate
, vup
, siY
);
700 q_mul( rotate
, player
.rot
, player
.rot
);
702 player
.look_dir
[0] = atan2f( player
.v
[0], -player
.v
[2] );
703 player
.look_dir
[1] = atan2f( -player
.v
[1], sqrtf(player
.v
[0]*player
.v
[0]+
704 player
.v
[2]*player
.v
[2]) ) * 0.3f
;
706 player
.iY
= 0.0f
; /* temp */
709 player_physics_air();
712 player_physics_ground();
714 /* Camera and character */
716 player_transform_update();
717 q_normalize(player
.rot
);
724 bvh_debug( &world
.geo
, player
.co
);
727 static void player_animate(void)
729 /* Camera position */
730 static v3f last_vel
= { 0.0f
, 0.0f
, 0.0f
};
731 static v3f momentum
, bob
;
733 v3_sub( player
.v
, last_vel
, player
.a
);
734 v3_copy( player
.v
, last_vel
);
736 v3_add( momentum
, player
.a
, momentum
);
737 v3_lerp( momentum
, (v3f
){0.0f
,0.0f
,0.0f
}, 0.1f
, momentum
);
740 momentum
[0] = vg_clampf( momentum
[0], -2.0f
, 2.0f
);
741 momentum
[1] = vg_clampf( momentum
[1], -0.2f
, 5.0f
);
742 momentum
[2] = vg_clampf( momentum
[2], -2.0f
, 2.0f
);
743 v3_copy( momentum
, target
);
744 v3_lerp( bob
, target
, 0.2f
, bob
);
747 float lslip
= fabsf(player
.slip
); //vg_minf( 0.4f, slip );
749 float grabt
= vg_get_axis( "grabr" )*0.5f
+0.5f
;
750 player
.grab
= vg_lerpf( player
.grab
, grabt
, 0.04f
);
752 float kheight
= 2.0f
,
757 head
[1] = (0.3f
+cosf(lslip
)*0.5f
*(1.0f
-player
.grab
*0.7f
)) * kheight
;
761 m3x3_mulv( player
.to_local
, bob
, offset
);
763 offset
[0] *= 0.3333f
;
766 v3_muladds( head
, offset
, 0.7f
, head
);
767 head
[1] = vg_clampf( head
[1], 0.3f
, kheight
);
772 v3_copy( head
, player
.view
);
773 v3f camoffs
= {-0.2f
,-0.6f
,0.00f
};
774 v3_add( player
.view
, camoffs
, player
.view
);
781 * ===========================================
784 static float fslide
= 0.0f
;
785 static float fdirz
= 0.0f
;
786 static float fdirx
= 0.0f
;
787 static float fstand
= 0.0f
;
788 static float ffly
= 0.0f
;
790 float speed
= v3_length( player
.v
);
792 fstand
= vg_lerpf(fstand
, 1.0f
-vg_clampf(speed
*0.03f
,0.0f
,1.0f
),0.1f
);
793 fslide
= vg_lerpf(fslide
, vg_clampf(lslip
+fabsf(offset
[0])*0.2f
,
795 fdirz
= vg_lerpf(fdirz
, player
.reverse
> 0.0f
? 1.0f
: 0.0f
, 0.04f
);
796 fdirx
= vg_lerpf(fdirx
, player
.slip
< 0.0f
? 1.0f
: 0.0f
, 0.04f
);
797 ffly
= vg_lerpf(ffly
, player
.in_air
? 1.0f
: 0.0f
, 0.04f
);
799 character_pose_reset( &player
.mdl
);
801 float amt_air
= ffly
*ffly
,
802 amt_ground
= 1.0f
-amt_air
,
803 amt_std
= (1.0f
-fslide
) * amt_ground
,
804 amt_stand
= amt_std
* fstand
,
805 amt_aero
= amt_std
* (1.0f
-fstand
),
806 amt_slide
= amt_ground
* fslide
;
808 character_final_pose( &player
.mdl
, offset
, &pose_stand
, amt_stand
);
809 character_final_pose( &player
.mdl
, offset
, &pose_aero
, amt_aero
*fdirz
);
810 character_final_pose( &player
.mdl
, offset
,
811 &pose_aero_reverse
, amt_aero
* (1.0f
-fdirz
) );
812 character_final_pose( &player
.mdl
, offset
, &pose_slide
, amt_slide
*fdirx
);
813 character_final_pose( &player
.mdl
, offset
,
814 &pose_slide1
, amt_slide
*(1.0f
-fdirx
) );
816 character_final_pose( &player
.mdl
, (v3f
){0.0f
,0.0f
,0.0f
},
817 &pose_fly
, amt_air
);
821 v3_copy( player
.mdl
.cam_pos
, player
.view
);
822 v3_muladds( player
.view
, offset
, 0.7f
, player
.view
);
823 player
.view
[1] = vg_clampf( player
.view
[1], 0.3f
, kheight
);
828 * ==========================
830 struct ik_basic
*arm_l
= &player
.mdl
.ik_arm_l
,
831 *arm_r
= &player
.mdl
.ik_arm_r
;
834 m3x3_mulv( player
.to_local
, player
.v
, localv
);
835 v3_muladds( arm_l
->end
, localv
, -0.01f
, arm_l
->end
);
836 v3_muladds( arm_r
->end
, localv
, -0.01f
, arm_r
->end
);
838 /* New board transformation */
839 v4f board_rotation
; v3f board_location
;
841 /* TODO: Move this out of animate into update */
842 v2_lerp( player
.board_xy
, (v2f
){ vg_get_axis("h1"), vg_get_axis("v1") },
843 ktimestep
*3.0f
, player
.board_xy
);
846 q_axis_angle( rz
, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, player
.board_xy
[0] );
847 q_axis_angle( rx
, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, player
.board_xy
[1] );
848 q_mul( rx
, rz
, board_rotation
);
850 v3f
*mboard
= player
.mdl
.matrices
[k_chpart_board
];// player.mboard;
851 q_m3x3( board_rotation
, mboard
);
852 m3x3_mulv( mboard
, (v3f
){ 0.0f
, -0.5f
, 0.0f
}, board_location
);
853 v3_add( (v3f
){0.0f
,0.5f
,0.0f
}, board_location
, board_location
);
854 v3_copy( board_location
, mboard
[3] );
857 float wheel_r
= offset
[0]*-0.4f
;
859 q_axis_angle( qwheel
, (v3f
){0.0f
,1.0f
,0.0f
}, wheel_r
);
861 q_m3x3( qwheel
, player
.mdl
.matrices
[k_chpart_wb
] );
863 m3x3_transpose( player
.mdl
.matrices
[k_chpart_wb
],
864 player
.mdl
.matrices
[k_chpart_wf
] );
865 v3_copy( player
.mdl
.offsets
[k_chpart_wb
],
866 player
.mdl
.matrices
[k_chpart_wb
][3] );
867 v3_copy( player
.mdl
.offsets
[k_chpart_wf
],
868 player
.mdl
.matrices
[k_chpart_wf
][3] );
870 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wb
],
871 player
.mdl
.matrices
[k_chpart_wb
] );
872 m4x3_mul( mboard
, player
.mdl
.matrices
[k_chpart_wf
],
873 player
.mdl
.matrices
[k_chpart_wf
] );
875 m4x3_mulv( mboard
, player
.mdl
.ik_leg_l
.end
, player
.mdl
.ik_leg_l
.end
);
876 m4x3_mulv( mboard
, player
.mdl
.ik_leg_r
.end
, player
.mdl
.ik_leg_r
.end
);
879 v3_copy( player
.mdl
.ik_arm_l
.end
, player
.handl_target
);
880 v3_copy( player
.mdl
.ik_arm_r
.end
, player
.handr_target
);
882 if( 1||player
.in_air
)
884 float tuck
= player
.board_xy
[1],
885 tuck_amt
= fabsf( tuck
) * (1.0f
-fabsf(player
.board_xy
[0]));
887 float crouch
= player
.grab
*0.3f
;
888 v3_muladds( player
.mdl
.ik_body
.base
, (v3f
){0.0f
,-1.0f
,0.0f
},
889 crouch
, player
.mdl
.ik_body
.base
);
890 v3_muladds( player
.mdl
.ik_body
.end
, (v3f
){0.0f
,-1.0f
,0.0f
},
891 crouch
*1.2f
, player
.mdl
.ik_body
.end
);
895 //foot_l *= 1.0f-tuck_amt*1.5f;
897 if( player
.grab
> 0.1f
)
899 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,0.6f
},
900 player
.handl_target
);
905 //foot_r *= 1.0f-tuck_amt*1.4f;
907 if( player
.grab
> 0.1f
)
909 m4x3_mulv( mboard
, (v3f
){0.1f
,0.14f
,-0.6f
},
910 player
.handr_target
);
915 v3_lerp( player
.handl
, player
.handl_target
, 0.1f
, player
.handl
);
916 v3_lerp( player
.handr
, player
.handr_target
, 0.1f
, player
.handr
);
918 v3_copy( player
.handl
, player
.mdl
.ik_arm_l
.end
);
919 v3_copy( player
.handr
, player
.mdl
.ik_arm_r
.end
);
923 static float rhead
= 0.0f
;
924 rhead
= vg_lerpf( rhead
,
925 vg_clampf(atan2f( localv
[2], -localv
[0] ),-1.0f
,1.0f
), 0.04f
);
926 player
.mdl
.rhead
= rhead
;
929 static void draw_player(void)
932 vg_tex2d_bind( &tex_pallet
, 0 );
934 m4x3_copy( player
.to_world
, player
.mdl
.mroot
);
935 character_eval( &player
.mdl
);
936 character_draw( &player
.mdl
, 1.0f
);
939 static void vg_framebuffer_resize( int w
, int h
)
941 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
942 glTexImage2D( GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
943 GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
948 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
949 glViewport( 0,0, vg_window_x
, vg_window_y
);
951 glDisable( GL_DEPTH_TEST
);
952 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
953 glClearColor(111.0f
/255.0f
, 46.0f
/255.0f
, 45.0f
/255.0f
,1.0f
);
955 glClearColor( powf(0.066f
,1.0f
/2.2f
),
956 powf(0.050f
,1.0f
/2.2f
),
957 powf(0.046f
,1.0f
/2.2f
), 1.0f
);
958 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
961 static v3f cam_lerped
= {0.0f
,0.0f
,0.0f
};
962 v3_lerp( cam_lerped
, player
.view
, 0.08f
, cam_lerped
);
965 m4x3_mulv( player
.to_world
, cam_lerped
, pos_inv
);
967 v3_add( player
.co
, player
.view
, pos_inv
);
968 v3_negate( pos_inv
, pos_inv
);
970 static float vertical_lerp
= 0.0f
;
971 vertical_lerp
= vg_lerpf( vertical_lerp
, pos_inv
[1], 1.0f
);
972 v3f final
= { pos_inv
[0], vertical_lerp
, pos_inv
[2] };
974 float speed
= freecam
? 0.0f
: v3_length( player
.v
);
975 v3f shake
= { vg_randf()-0.5f
, vg_randf()-0.5f
, vg_randf()-0.5f
};
976 v3_muls( shake
, speed
*0.01f
, shake
);
978 static v2f cam_lerped_dir
;
980 v2_lerp( cam_lerped_dir
, player
.look_dir
, 0.04f
, cam_lerped_dir
);
982 m4x3_identity( world_matrix
);
983 m4x3_rotate_x( world_matrix
,
986 0.6f
+shake
[1]*0.04f
+player
.look_dir
[1] );
988 m4x3_rotate_y( world_matrix
,
991 player
.look_dir
[0]+shake
[0]*0.02f
);
992 m4x3_translate( world_matrix
, final
);
995 m4x3_expand( world_matrix
, world_4x4
);
996 m4x4_projection( vg_pv
,
997 freecam
? 60.0f
: 120.0f
,
998 (float)vg_window_x
/ (float)vg_window_y
,
1000 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1002 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 1.0f
, 0.0f
, 0.0f
}, 0xffff0000 );
1003 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 1.0f
, 0.0f
}, 0xff00ff00 );
1004 vg_line( (v3f
){ 0.0f
, 0.0f
, 0.0f
}, (v3f
){ 0.0f
, 0.0f
, 1.0f
}, 0xff0000ff );
1006 glEnable( GL_DEPTH_TEST
);
1011 SHADER_USE(shader_standard_lit
);
1013 m4x3f identity_matrix
;
1014 m4x3_identity( identity_matrix
);
1016 glUniformMatrix4fv( SHADER_UNIFORM( shader_standard_lit
, "uPv" ),
1017 1, GL_FALSE
, (float *)vg_pv
);
1018 glUniformMatrix4x3fv( SHADER_UNIFORM( shader_standard_lit
, "uMdl" ),
1019 1, GL_FALSE
, (float *)identity_matrix
);
1021 vg_tex2d_bind( &tex_grid
, 0 );
1022 glUniform1i( SHADER_UNIFORM( shader_standard_lit
, "uTexMain" ), 0 );
1024 glUniform4f( SHADER_UNIFORM(shader_standard_lit
,"uColour"),
1025 0.4f
,0.4f
,0.4f
,1.0f
);
1027 scene_bind( &world
.geo
);
1028 scene_draw( &world
.geo
);
1030 if( !replay_record
)
1032 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1034 for( int i
=0; i
<PART_COUNT
; i
++ )
1035 m4x3_copy( base
[i
], player
.mdl
.matrices
[i
] );
1037 replay_buffer_frame
++;
1039 if( replay_buffer_frame
== REPLAY_LENGTH
)
1040 replay_buffer_frame
= 0;
1042 vg_tex2d_bind( &tex_pallet
, 0 );
1043 character_draw( &player
.mdl
, 0.0f
);
1049 /* Copy the RGB of what we have into the background buffer */
1050 glBindFramebuffer( GL_READ_FRAMEBUFFER
, 0 );
1051 glBindFramebuffer( GL_DRAW_FRAMEBUFFER
, render
.fb_background
);
1052 glBlitFramebuffer( 0,0, vg_window_x
, vg_window_y
,
1053 0,0, vg_window_x
, vg_window_y
,
1054 GL_COLOR_BUFFER_BIT
,
1057 /* Clear out the colour buffer, but keep depth */
1058 glBindFramebuffer( GL_FRAMEBUFFER
, 0 );
1059 glClearColor( 0.0f
, 0.0f
, 0.0f
, 0.0f
);
1062 glClear( GL_COLOR_BUFFER_BIT
);
1064 glClear( GL_COLOR_BUFFER_BIT
|GL_DEPTH_BUFFER_BIT
);
1070 /* Draw back in the background */
1072 glDisable(GL_DEPTH_TEST
);
1073 glBlendFunc(GL_ONE_MINUS_DST_ALPHA
, GL_DST_ALPHA
);
1074 glBlendEquation(GL_FUNC_ADD
);
1076 SHADER_USE( shader_blit
);
1078 glUniform1i( SHADER_UNIFORM(shader_blit
,"uTexMain"), 0 );
1079 glActiveTexture(GL_TEXTURE0
);
1080 glBindTexture( GL_TEXTURE_2D
, render
.rgb_background
);
1082 glBindVertexArray( render
.fsquad
.vao
);
1083 glDrawArrays( GL_TRIANGLES
, 0, 6 );
1085 glDisable(GL_BLEND
);
1088 glDisable( GL_DEPTH_TEST
);
1089 vg_lines_drawall( (float *)vg_pv
);
1091 /* Debugger camera */
1092 glViewport( 0,0, 800, 800 );
1093 glClearColor( 0.1f
, 0.0f
, 0.2f
, 1.0f
);
1094 glClear( GL_DEPTH_BUFFER_BIT
);
1096 m4x3_identity( world_matrix
);
1099 v3_negate( player
.co
, debugcam
);
1100 debugcam
[2] -= 2.0f
;
1101 debugcam
[1] -= 0.7f
;
1103 m4x3_translate( world_matrix
, debugcam
);
1104 m4x3_expand( world_matrix
, world_4x4
);
1106 m4x4_projection( vg_pv
,
1108 (float)128.0f
/ (float)128.0f
,
1110 m4x4_mul( vg_pv
, world_4x4
, vg_pv
);
1114 glEnable( GL_DEPTH_TEST
);
1118 glDisable( GL_DEPTH_TEST
);
1119 vg_lines_drawall( (float *)vg_pv
);
1121 glViewport( 0,0, vg_window_x
, vg_window_y
);
1126 m4x3f
*base
= &replay_buffer
[(PART_COUNT
)*replay_buffer_frame
];
1128 for( int i
=0; i
<PART_COUNT
; i
++ )
1129 m4x3_copy( player
.mdl
.matrices
[i
], base
[i
] );
1131 replay_buffer_frame
++;
1133 if( replay_buffer_frame
== REPLAY_LENGTH
)
1134 replay_buffer_frame
= 0;
1142 snprintf( buf
, 20, "%.2fm/s", v3_length( player
.v
) );
1143 gui_text( (ui_px
[2]){ 0, 0 }, buf
, 1, k_text_align_left
);
1145 snprintf( buf
, 20, "%.2f %.2f %.2f m/s",
1146 player
.a
[0], player
.a
[1], player
.a
[2] );
1147 gui_text( (ui_px
[2]){ 0, 20 }, buf
, 1, k_text_align_left
);
1149 snprintf( buf
, 20, "pos %.2f %.2f %.2f",
1150 player
.co
[0], player
.co
[1], player
.co
[2] );
1151 gui_text( (ui_px
[2]){ 0, 40 }, buf
, 1, k_text_align_left
);
1153 if( vg_gamepad_ready
)
1155 for( int i
=0; i
<6; i
++ )
1157 snprintf( buf
, 20, "%.2f", vg_gamepad
.axes
[i
] );
1158 gui_text( (ui_px
[2]){ 0, (i
+3)*20 }, buf
, 1, k_text_align_left
);
1163 gui_text( (ui_px
[2]){ 0, 60 },
1164 "Gamepad not ready", 1, k_text_align_left
);
1168 void vg_free(void){}