6 #include "world_render.h"
9 #include "shaders/model_menu.h"
11 #define MENU_STACK_SIZE 8
18 u32 page
, /* current page index */
19 page_stack
[ MENU_STACK_SIZE
],
29 mdl_array_ptr items
, markers
, cameras
;
33 static void menu_init(void)
35 void *alloc
= vg_mem
.rtmemory
;
37 mdl_open( &menu
.model
, "models/rs_menu.mdl", alloc
);
38 mdl_load_metadata_block( &menu
.model
, alloc
);
40 vg_linear_clear( vg_mem
.scratch
);
42 mdl_load_array( &menu
.model
, &menu
.items
, "ent_menuitem", alloc
);
43 mdl_load_array( &menu
.model
, &menu
.markers
, "ent_marker", alloc
);
44 mdl_load_array( &menu
.model
, &menu
.cameras
, "ent_camera", alloc
);
46 vg_linear_clear( vg_mem
.scratch
);
48 if( !mdl_arrcount( &menu
.model
.textures
) )
49 vg_fatal_error( "No texture in menu file" );
51 mdl_texture
*tex0
= mdl_arritm( &menu
.model
.textures
, 0 );
52 void *data
= vg_linear_alloc( vg_mem
.scratch
, tex0
->file
.pack_size
);
53 mdl_fread_pack_file( &menu
.model
, &tex0
->file
, data
);
55 mdl_async_load_glmesh( &menu
.model
, &menu
.mesh
);
56 vg_tex2d_load_qoi_async( data
, tex0
->file
.pack_size
,
57 VG_TEX2D_LINEAR
|VG_TEX2D_CLAMP
,
60 mdl_close( &menu
.model
);
61 shader_model_menu_register();
64 static void menu_open_page( const char *name
)
66 vg_info( "Try to open %s\n", name
);
68 u32 hash
= vg_strdjb2( name
);
69 for( u32 i
=0; i
<mdl_arrcount(&menu
.items
); i
++ ){
70 ent_menuitem
*item
= mdl_arritm( &menu
.items
, i
);
72 if( item
->type
== k_ent_menuitem_type_page
){
73 if( mdl_pstreq( &menu
.model
, item
->page
.pstr_name
, name
, hash
) ){
74 menu
.page
= __builtin_ctz( item
->groups
);
75 vg_info( "menu page: %u\n", menu
.page
);
77 if( item
->page
.id_entrypoint
){
78 u32 id
= mdl_entity_id_id( item
->page
.id_entrypoint
);
79 menu
.loc
= mdl_arritm( &menu
.items
, id
);
82 if( item
->page
.id_viewpoint
){
83 u32 id
= mdl_entity_id_id( item
->page
.id_viewpoint
);
84 menu
.cam
= mdl_arritm( &menu
.cameras
, id
);
87 menu
.page_stack
[ menu
.page_depth
++ ] = menu
.page
;
94 static void menu_back_page(void)
96 if( menu
.page_depth
== 0 ){
100 menu
.page
= menu
.page_stack
[ -- menu
.page_depth
];
104 static void menu_update(void)
106 if( button_down( k_srbind_mopen
) ){
107 if( !menu
.active
&& !menu
.disable_open
){
109 menu_open_page( "Main Menu" );
113 menu
.factive
= vg_lerpf( menu
.factive
, menu
.active
,
114 vg
.time_frame_delta
* 6.0f
);
116 if( menu
.factive
> 0.01f
){
120 if( !menu
.active
) return;
121 if( !menu
.loc
) return;
122 if( !menu
.cam
) return;
124 int ml
= button_down( k_srbind_mleft
),
125 mr
= button_down( k_srbind_mright
),
126 mu
= button_down( k_srbind_mup
),
127 md
= button_down( k_srbind_mdown
),
130 enter
= button_down( k_srbind_maccept
),
131 escape
= button_down( k_srbind_mback
);
137 if ( menu
.loc
->type
== k_ent_menuitem_type_event_button
){
140 else if( menu
.loc
->type
== k_ent_menuitem_type_page_button
){
141 menu_open_page( mdl_pstr( &menu
.model
, menu
.loc
->button
.pstr
) );
143 else if( menu
.loc
->type
== k_ent_menuitem_type_toggle
){
151 ent_menuitem
*nextpos
= NULL
;
155 mdl_transform_vector( &menu
.cam
->transform
, opt
, opt
);
157 for( u32 i
=0; i
<4; i
++ ){
158 u32 id
= menu
.loc
->id_links
[i
];
160 u32 index
= mdl_entity_id_id( id
);
162 ent_menuitem
*other
= mdl_arritm( &menu
.items
, index
);
164 v3_sub( menu
.loc
->transform
.co
, other
->transform
.co
, delta
);
165 v3_normalize( delta
);
167 f32 score
= v3_dot( delta
, opt
);
180 VG_STATIC
void menu_render(void)
183 glDisable(GL_DEPTH_TEST
);
184 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
185 glBlendEquation(GL_FUNC_ADD
);
187 shader_blitcolour_use();
188 shader_blitcolour_uColour( (v4f
){ 0.1f
, 0.1f
, 0.3f
, menu
.factive
*0.5f
} );
191 glEnable( GL_DEPTH_TEST
);
192 glDisable( GL_BLEND
);
195 menu
.view
.fov
= menu
.cam
->fov
;
196 menu
.view
.farz
= 150.0f
;
197 menu
.view
.nearz
= 0.01f
;
198 v3_copy( menu
.cam
->transform
.co
, menu
.view
.pos
);
201 mdl_transform_vector( &menu
.cam
->transform
, (v3f
){0.0f
,-1.0f
,0.0f
}, v0
);
202 player_vector_angles( menu
.view
.angles
, v0
, 1.0f
, 0.0f
);
203 camera_update_transform( &menu
.view
);
204 camera_update_view( &menu
.view
);
205 camera_update_projection( &menu
.view
);
206 camera_finalize( &menu
.view
);
210 shader_model_menu_use();
211 shader_model_menu_uTexMain( 1 );
212 glActiveTexture( GL_TEXTURE1
);
213 glBindTexture( GL_TEXTURE_2D
, menu
.texture
);
214 shader_model_menu_uPv( menu
.view
.mtx
.pv
);
215 shader_model_menu_uPvmPrev( menu
.view
.mtx_prev
.pv
);
217 mesh_bind( &menu
.mesh
);
219 for( u32 i
=0; i
<mdl_arrcount(&menu
.items
); i
++ ){
220 ent_menuitem
*item
= mdl_arritm( &menu
.items
, i
);
222 if( item
->type
== k_ent_menuitem_type_page
) continue;
223 if( !(item
->groups
& (0x1 << menu
.page
)) ) continue;
225 if( item
== menu
.loc
){
226 shader_model_menu_uColour( (v4f
){ 0.1f
,0.25f
,0.9f
,1.0f
} );
229 shader_model_menu_uColour( (v4f
){ 1.0f
,1.0f
,1.0f
,1.0f
} );
233 mdl_transform_m4x3( &item
->transform
, mmdl
);
234 shader_model_menu_uMdl( mmdl
);
236 for( u32 j
=0; j
<item
->submesh_count
; j
++ ){
237 u32 index
= item
->submesh_start
+ j
;
238 mdl_draw_submesh( mdl_arritm( &menu
.model
.submeshs
, index
));
251 #include "world_render.h"
255 #include "shaders/model_menu.h"
256 #include "vg_steam_friends.h"
258 VG_STATIC mdl_context menu_model
;
259 VG_STATIC mdl_array_ptr menu_markers
;
260 VG_STATIC glmesh menu_glmesh
;
261 VG_STATIC m4x3f menu_mdl_mtx
;
262 VG_STATIC
float menu_opacity
= 0.0f
;
263 VG_STATIC
float menu_input_cooldown
= 0.0f
;
264 VG_STATIC
float menu_fov_target
= 97.0f
,
265 menu_smooth_fov
= 97.0f
;
266 VG_STATIC v2f menu_extra_angles
;
267 VG_STATIC v3f menu_camera_pos
;
268 VG_STATIC v2f menu_camera_angles
;
270 VG_STATIC
int cl_menu
= 0,
273 VG_STATIC
int menu_enabled(void){ return cl_menu
; }
275 VG_STATIC
const char *playermodels
[] = { "ch_new", "ch_jordan", "ch_outlaw" };
280 VG_STATIC
struct input_binding input_menu_h
,
285 input_menu_toggle_kbm
;
288 VG_STATIC
void menu_btn_quit( int event
);
289 VG_STATIC
void menu_btn_skater( int event
);
290 VG_STATIC
void menu_btn_blur( int event
);
291 VG_STATIC
void menu_btn_fuckoff( int event
);
292 VG_STATIC
void menu_btn_reset( int event
);
293 VG_STATIC
void menu_btn_map( int event
);
294 VG_STATIC
void menu_btn_settings( int event
);
295 VG_STATIC
void menu_btn_invert_y( int event
);
297 VG_STATIC mdl_mesh
*menu_mesh_fov_slider
,
298 *menu_mesh_vol_slider
,
299 *menu_mesh_res_slider
;
315 struct menu_map_file
{
326 k_menu_page_main
= 0x1,
327 k_menu_page_skater
= 0x2,
328 k_menu_page_quit
= 0x4,
329 k_menu_page_settings
= 0x8,
330 k_menu_page_map
= 0x10
333 struct menu_btn_userdata
{
338 VG_STATIC
int menu_settings_if( struct menu_btn_userdata ud
)
340 if( game_menu
.page
& k_menu_page_settings
){
341 int *ptr
= ud
.ptr_generic
;
348 VG_STATIC
int menu_vis( struct menu_btn_userdata ud
)
350 if( ud
.i
& game_menu
.page
)
357 VG_STATIC
int menu_controller( struct menu_btn_userdata ud
)
359 if( (game_menu
.page
& (k_menu_page_main
|k_menu_page_settings
))
360 && (ud
.i
== steam_display_controller
) )
365 VG_STATIC
int menu_controller_inf( struct menu_btn_userdata ud
)
367 if( (game_menu
.page
& k_menu_page_settings
)
368 && (ud
.i
== steam_display_controller
) )
378 int (*fn_visibility
)( struct menu_btn_userdata ud
);
379 struct menu_btn_userdata user
;
381 void (*fn_press
)( int event
);
391 VG_STATIC menu_buttons
[] =
394 "text_quit", menu_vis
, {.i
=k_menu_page_main
|k_menu_page_quit
},
395 .fn_press
= menu_btn_quit
,
396 .ld
="text_reset", .lr
="text_settings", /*.ll="text_map"*/
399 "text_quitty", menu_vis
, {.i
=k_menu_page_quit
}
402 "text_yes", menu_vis
, {.i
=k_menu_page_quit
},
403 .fn_press
= menu_btn_fuckoff
406 "text_reset", menu_vis
, {.i
=k_menu_page_main
},
407 .fn_press
= menu_btn_reset
,
408 .lu
="text_quit", .ld
="text_skater", /*.ll="text_map",*/ .lr
="text_settings"
411 "text_skater", menu_vis
, {.i
=k_menu_page_main
|k_menu_page_skater
},
412 .fn_press
= menu_btn_skater
,
413 .lu
="text_reset", /*.ll="text_map",*/ .lr
="text_settings"
417 "text_map", menu_vis, {.i=k_menu_page_main},
418 .fn_press = menu_btn_map,
423 "text_settings", menu_vis
, {.i
=k_menu_page_main
|k_menu_page_settings
},
424 .fn_press
= menu_btn_settings
,
428 "skater_left", menu_vis
, {k_menu_page_skater
}
431 "skater_right", menu_vis
, {k_menu_page_skater
}
435 "fov_slider", menu_vis
, {k_menu_page_settings
},
438 { "fov_info", menu_vis
, {k_menu_page_settings
} },
441 "vol_slider", menu_vis
, {k_menu_page_settings
},
444 { "vol_info", menu_vis
, {k_menu_page_settings
} },
447 "text_invert_y", menu_vis
, {k_menu_page_settings
},
448 .fn_press
= menu_btn_invert_y
,
449 .lu
= "fov_slider", .ld
="text_blur"
452 "text_invert_y_check", menu_settings_if
, {.ptr_generic
=&cl_invert_y
}
455 "text_blur", menu_vis
, {k_menu_page_settings
},
456 .fn_press
= menu_btn_blur
,
457 .lu
="text_invert_y", .ld
="res_slider"
460 "text_blur_check", menu_settings_if
, {.ptr_generic
=&cl_blur
}
463 "res_slider", menu_vis
, {k_menu_page_settings
},
464 .ld
= "vol_slider", .lu
= "text_blur"
467 "res_info", menu_vis
, {k_menu_page_settings
},
470 { "ctr_xbox", menu_controller_inf
, {k_steam_controller_type_xbox
}},
471 { "ctr_xbox_text", menu_controller_inf
, {k_steam_controller_type_xbox
}},
472 { "ctr_steam", menu_controller_inf
, {k_steam_controller_type_steam
}},
473 { "ctr_steam_text", menu_controller_inf
, {k_steam_controller_type_steam
}},
474 { "ctr_deck", menu_controller_inf
, {k_steam_controller_type_steam_deck
}},
475 { "ctr_deck_text", menu_controller_inf
, {k_steam_controller_type_steam_deck
}},
476 { "ctr_ps", menu_controller_inf
, {k_steam_controller_type_playstation
}},
477 { "ctr_ps_text", menu_controller_inf
, {k_steam_controller_type_playstation
}},
478 { "ctr_kbm", menu_controller_inf
, {k_steam_controller_type_keyboard
}},
479 { "ctr_kbm_text", menu_controller_inf
, {k_steam_controller_type_keyboard
}},
482 "text_paused", menu_vis
, {k_menu_page_main
}
486 VG_STATIC
int menu_get_loc( const char *loc
)
488 for( int i
=0; i
<vg_list_size(menu_buttons
); i
++ )
489 if( !strcmp( menu_buttons
[i
].name
, loc
) )
496 VG_STATIC
void menu_btn_reset( int event
)
498 localplayer_cmd_respawn( 0, NULL
);
503 VG_STATIC
void menu_btn_fuckoff( int event
)
505 vg
.window_should_close
= 1;
508 VG_STATIC
void menu_btn_quit( int event
)
510 game_menu
.page
= k_menu_page_quit
;
511 game_menu
.loc
= menu_get_loc( "text_yes" );
514 VG_STATIC
void menu_btn_settings( int event
)
516 game_menu
.page
= k_menu_page_settings
;
517 game_menu
.loc
= menu_get_loc( "fov_slider" );
520 VG_STATIC
void menu_btn_skater( int event
)
522 game_menu
.page
= k_menu_page_skater
;
525 VG_STATIC
void menu_btn_blur( int event
)
530 VG_STATIC
void menu_btn_invert_y( int event
)
535 VG_STATIC
void menu_btn_map( int event
)
537 game_menu
.page
= k_menu_page_map
;
538 game_menu
.map_count
= 0;
539 game_menu
.selected_map
= 0;
542 tinydir_open( &dir
, "maps" );
544 while( dir
.has_next
){
546 tinydir_readfile( &dir
, &file
);
549 struct menu_map_file
*mf
= &game_menu
.maps_list
[ game_menu
.map_count
];
551 vg_strncpy( file
.name
, mf
->name
,
552 vg_list_size(game_menu
.maps_list
[0].name
),
553 k_strncpy_always_add_null
);
555 game_menu
.map_count
++;
556 if( game_menu
.map_count
== vg_list_size(game_menu
.maps_list
) )
560 tinydir_next( &dir
);
566 VG_STATIC
void menu_crap_ui(void)
569 if( cl_menu
&& (game_menu
.page
== k_menu_page_map
) ){
571 box
[0] = vg
.window_x
/2 - 150;
572 box
[1] = vg
.window_y
/2 - 300;
576 ui_fill_rect( box
, 0xa0000000 );
578 if( game_menu
.map_count
== 0 ){
579 ui_text( (ui_rect
){ vg
.window_x
/2, box
[1]+8, 0,0 }, "No maps found", 1,
580 k_text_align_center
);
583 ui_rect_pad( box
, 4 );
586 for( int i
=0; i
<game_menu
.map_count
; i
++ ){
587 struct menu_map_file
*mf
= &game_menu
.maps_list
[ i
];
589 ui_fill_rect( box
, game_menu
.selected_map
== i
? 0xa0ffffff:
591 ui_text( (ui_rect
){ vg
.window_x
/2, box
[1]+2, 0,0 },
592 mf
->name
, 1, k_text_align_center
);
600 VG_STATIC
void steam_on_game_overlay( CallbackMsg_t
*msg
)
602 GameOverlayActivated_t
*inf
= (GameOverlayActivated_t
*)msg
->m_pubParam
;
603 vg_info( "Steam game overlay activated; pausing\n" );
605 if( inf
->m_bActive
){
607 game_menu
.page
= k_menu_page_main
;
608 game_menu
.loc
= menu_get_loc( "text_skater" );
612 VG_STATIC
void menu_init(void)
615 vg_apply_bind_str( &input_menu_h
, "", "gp-ls-h" );
616 vg_apply_bind_str( &input_menu_h
, "+", "right" );
617 vg_apply_bind_str( &input_menu_h
, "-", "left" );
618 vg_apply_bind_str( &input_menu_v
, "", "-gp-ls-v" );
619 vg_apply_bind_str( &input_menu_v
, "+", "up" );
620 vg_apply_bind_str( &input_menu_v
, "-", "down" );
621 vg_apply_bind_str( &input_menu_press
, "", "gp-a" );
622 vg_apply_bind_str( &input_menu_press
, "", "\2enter" );
623 vg_apply_bind_str( &input_menu_back
, "", "gp-b" );
624 vg_apply_bind_str( &input_menu_back
, "", "\2escape" );
625 vg_apply_bind_str( &input_menu_toggle_kbm
, "", "\2escape" );
626 vg_apply_bind_str( &input_menu_toggle
, "", "\2gp-menu" );
629 vg_linear_clear( vg_mem
.scratch
);
631 mdl_open( &menu_model
, "models/rs_menu.mdl", vg_mem
.rtmemory
);
632 mdl_load_metadata_block( &menu_model
, vg_mem
.rtmemory
);
633 mdl_load_array( &menu_model
, &menu_markers
, "ent_marker", vg_mem
.rtmemory
);
634 //mdl_invert_uv_coordinates( &menu_model );
635 mdl_async_load_glmesh( &menu_model
, &menu_glmesh
);
636 mdl_close( &menu_model
);
638 vg_tex2d_load_qoi_async_file( "textures/menu.qoi",
639 VG_TEX2D_CLAMP
|VG_TEX2D_NEAREST
,
643 for( int i
=0; i
<vg_list_size(menu_buttons
); i
++ ){
644 struct menu_button
*btn
= &menu_buttons
[i
];
645 btn
->mesh
= mdl_find_mesh( &menu_model
, btn
->name
);
648 vg_info( "info: %s\n", btn
->name
);
649 vg_fatal_error( "Menu programming error" );
654 ent_find_marker( &menu_model
, &menu_markers
, "fov_slider_max" );
656 ent_find_marker( &menu_model
, &menu_markers
, "fov_slider_min" );
658 ent_find_marker( &menu_model
, &menu_markers
, "vol_slider_max" );
660 ent_find_marker( &menu_model
, &menu_markers
, "vol_slider_min" );
662 ent_find_marker( &menu_model
, &menu_markers
, "res_slider_max" );
664 ent_find_marker( &menu_model
, &menu_markers
, "res_slider_min" );
666 menu_mesh_fov_slider
= mdl_find_mesh( &menu_model
, "fov_slider" );
667 menu_mesh_vol_slider
= mdl_find_mesh( &menu_model
, "vol_slider" );
668 menu_mesh_res_slider
= mdl_find_mesh( &menu_model
, "res_slider" );
670 shader_model_menu_register();
673 steam_register_callback( k_iGameOverlayActivated
, steam_on_game_overlay
);
677 VG_STATIC
void menu_run_directional(void)
680 struct menu_button
*btn
= &menu_buttons
[ game_menu
.loc
];
682 if( vg_input_button_down( &input_menu_press
) ){
685 audio_oneshot( &audio_ui
[0], 1.0f
, 0.0f
);
693 if( menu_input_cooldown
<= 0.0f
){
694 v2f dir
= { input_menu_h
.axis
.value
,
695 -input_menu_v
.axis
.value
};
697 if( v2_length2( dir
) > 0.8f
*0.8f
){
698 const char *link
= NULL
;
700 if( fabsf(dir
[0]) > fabsf(dir
[1]) ){
701 if( dir
[0] > 0.0f
) link
= btn
->lr
;
705 if( dir
[1] > 0.0f
) link
= btn
->ld
;
710 game_menu
.loc
= menu_get_loc( link
);
711 menu_input_cooldown
= 0.25f
;
718 VG_STATIC
int menu_page_should_backout(void)
722 return vg_input_button_down( &input_menu_back
);
726 VG_STATIC
void menu_close(void)
730 game_menu
.loc
= menu_get_loc( "text_skater" );
733 VG_STATIC
void menu_page_main(void)
735 if( menu_page_should_backout() )
741 menu_fov_target
= 112.0f
;
742 menu_run_directional();
745 VG_STATIC
void menu_page_map(void)
747 if( menu_page_should_backout() ){
748 game_menu
.page
= k_menu_page_main
;
749 game_menu
.loc
= menu_get_loc( "text_map" );
752 if( game_menu
.map_count
> 0 ){
754 float v
= input_menu_v
.axis
.value
;
755 if( (fabsf(v
) > 0.7f
) && (menu_input_cooldown
<= 0.0f
) ){
757 audio_oneshot( &audio_rewind
[4], 1.0f
, 0.0f
);
761 game_menu
.selected_map
--;
763 if( game_menu
.selected_map
< 0 )
764 game_menu
.selected_map
= game_menu
.map_count
-1;
766 menu_input_cooldown
= 0.25f
;
769 game_menu
.selected_map
++;
771 if( game_menu
.selected_map
>= game_menu
.map_count
)
772 game_menu
.selected_map
= 0;
774 menu_input_cooldown
= 0.25f
;
778 if( vg_input_button_down( &input_menu_press
) ){
782 strcpy( temp
, "maps/" );
783 strcat( temp
, game_menu
.maps_list
[game_menu
.selected_map
].name
);
785 world_change_world( 1, (const char *[]){ temp
} );
792 menu_fov_target
= 80.0f
;
795 VG_STATIC
void menu_page_quit(void)
797 if( menu_page_should_backout() ){
798 game_menu
.page
= k_menu_page_main
;
799 game_menu
.loc
= menu_get_loc( "text_quit" );
802 menu_fov_target
= 90.0f
;
803 menu_run_directional();
806 void temp_update_playermodel(void);
807 VG_STATIC
void menu_page_skater(void)
810 float h
= input_menu_h
.axis
.value
;
811 menu_fov_target
= 97.0f
;
813 if( menu_page_should_backout() ){
814 game_menu
.page
= k_menu_page_main
;
815 game_menu
.loc
= menu_get_loc( "text_skater" );
819 if( (fabsf(h
) > 0.7f
) && (menu_input_cooldown
<= 0.0f
) ){
821 audio_oneshot( &audio_rewind
[4], 1.0f
, 0.0f
);
824 vg_info( "%f\n", h
);
828 if( cl_playermdl_id
< 0 )
831 int li
= menu_get_loc( "skater_left" );
833 menu_buttons
[li
].fsize
= 0.4f
;
834 menu_buttons
[li
].falpha
= 1.0f
;
836 menu_input_cooldown
= 0.25f
;
840 if( cl_playermdl_id
> 2 )
843 int ri
= menu_get_loc( "skater_right" );
845 menu_buttons
[ri
].fsize
= 0.4f
;
846 menu_buttons
[ri
].falpha
= 1.0f
;
848 menu_input_cooldown
= 0.25f
;
851 temp_update_playermodel();
856 VG_STATIC
void menu_slider( float *value
, int set_value
,
857 mdl_mesh
*slider
, v3f co_min
, v3f co_max
)
861 float h
= input_menu_h
.axis
.value
;
862 if( fabsf(h
) > 0.04f
)
863 *value
+= h
* vg
.time_frame_delta
;
864 *value
= vg_clampf( *value
, 0.0f
, 1.0f
);
867 v3_lerp( co_min
, co_max
, *value
, slider
->transform
.co
);
871 VG_STATIC
void menu_page_settings(void)
873 menu_run_directional();
875 int fov_select
= game_menu
.loc
== menu_get_loc( "fov_slider" );
876 menu_slider( &cl_fov
, fov_select
,
877 menu_mesh_fov_slider
, menu_mark_fov_min
->transform
.co
,
878 menu_mark_fov_max
->transform
.co
);
881 menu_fov_target
= vg_lerpf( 97.0f
, 135.0f
, cl_fov
) * 0.8f
;
883 menu_slider( &vg_audio
.external_global_volume
,
884 (game_menu
.loc
== menu_get_loc( "vol_slider" )),
885 menu_mesh_vol_slider
, menu_mark_vol_min
->transform
.co
,
886 menu_mark_vol_max
->transform
.co
);
888 menu_slider( &gpipeline
.view_render_scale
,
889 (game_menu
.loc
== menu_get_loc( "res_slider" )),
890 menu_mesh_res_slider
, menu_mark_res_min
->transform
.co
,
891 menu_mark_res_max
->transform
.co
);
893 if( menu_page_should_backout() ){
894 game_menu
.page
= k_menu_page_main
;
895 game_menu
.loc
= menu_get_loc( "text_settings" );
900 VG_STATIC
void menu_update(void)
903 vg_input_update( 1, &input_menu_h
);
904 vg_input_update( 1, &input_menu_v
);
905 vg_input_update( 1, &input_menu_back
);
906 vg_input_update( 1, &input_menu_press
);
907 vg_input_update( 1, &input_menu_toggle
);
908 vg_input_update( 1, &input_menu_toggle_kbm
);
914 int toggle_gp
= vg_input_button_down( &input_menu_toggle
),
915 toggle_kb
= vg_input_button_down( &input_menu_toggle_kbm
),
918 if( toggle_gp
|| toggle_kb
){
933 if( !wait_for_a_sec
&& cl_menu
){
934 if( game_menu
.page
== k_menu_page_main
)
936 else if( game_menu
.page
== k_menu_page_skater
)
938 else if( game_menu
.page
== k_menu_page_quit
)
940 else if( game_menu
.page
== k_menu_page_settings
)
941 menu_page_settings();
942 else if( game_menu
.page
== k_menu_page_map
)
946 struct menu_button
*btn
= &menu_buttons
[ game_menu
.loc
];
950 player_instance
*player
= &localplayer
;
951 struct player_avatar
*av
= player
->playeravatar
;
954 if( player
->subsystem
== k_player_subsystem_dead
){
955 m4x3_mulv( av
->sk
.final_mtx
[av
->id_hip
], (v3f
){0.0f
,0.9f
,0.0f
},
959 m4x3_mulv( av
->sk
.final_mtx
[av
->id_head
], (v3f
){0.0f
,1.5f
,0.0f
},
965 if( player
->subsystem
== k_player_subsystem_walk
){
966 v3_muls( player
->rb
.to_world
[2], 1.0f
, cam_offset
);
970 v3_muls( player
->rb
.to_world
[0], -1.0f
, cam_offset
);
971 cam_rot
= -VG_PIf
*0.5f
;
976 m3x3_mulv( player
->invbasis
, cam_offset
, lookdir
);
978 v3_normalize( lookdir
);
980 m3x3_mulv( player
->basis
, lookdir
, cam_offset
);
981 v3_muladds( center_rough
, cam_offset
, 2.0f
, menu_camera_pos
);
983 menu_camera_angles
[1] = 0.0f
;
984 menu_camera_angles
[0] = -atan2f( lookdir
[0], lookdir
[2] );
986 /* setup model matrix */
988 q_axis_angle( qmenu_mdl
, (v3f
){0.0f
,1.0f
,0.0f
}, -menu_camera_angles
[0] );
989 q_m3x3( qmenu_mdl
, menu_mdl_mtx
);
990 v3_add( center_rough
, (v3f
){0.0f
,-0.5f
,0.0f
}, menu_mdl_mtx
[3] );
991 m3x3_mul( player
->basis
, menu_mdl_mtx
, menu_mdl_mtx
);
993 menu_smooth_fov
= vg_lerpf( menu_smooth_fov
, menu_fov_target
,
994 vg
.time_frame_delta
* 8.2f
);
1000 v3_sub( btn
->mesh
->transform
.co
, (v3f
){ 0.0f
,1.5f
,-1.5f
}, delta
);
1001 v3_normalize( delta
);
1003 float y
= atan2f( delta
[0], delta
[2] ),
1004 p
= -sinf(delta
[1]),
1005 dt
= vg
.time_frame_delta
;
1007 menu_extra_angles
[0] = vg_lerpf( menu_extra_angles
[0], y
, dt
);
1008 menu_extra_angles
[1] = vg_lerpf( menu_extra_angles
[1], p
, dt
);
1010 v2_muladds( menu_camera_angles
, menu_extra_angles
, 0.8f
,
1011 menu_camera_angles
);
1012 menu_camera_angles
[0] = fmodf( menu_camera_angles
[0], VG_TAUf
);
1015 float dt
= vg
.time_frame_delta
* 6.0f
;
1016 menu_opacity
= vg_lerpf( menu_opacity
, cl_menu
&&!cl_menu_go_away
, dt
);
1018 if( menu_opacity
<= 0.01f
){
1020 cl_menu_go_away
= 0;
1023 vg
.time_rate
= 1.0-(double)menu_opacity
;
1026 menu_input_cooldown
-= vg
.time_frame_delta
;
1031 /* https://iquilezles.org/articles/functions/ */
1032 float expSustainedImpulse( float x
, float f
, float k
)
1034 float s
= fmaxf(x
-f
,0.0f
);
1035 return fminf( x
*x
/(f
*f
), 1.0f
+(2.0f
/f
)*s
*expf(-k
*s
));
1038 VG_STATIC
void menu_render_bg(void)
1041 glDisable(GL_DEPTH_TEST
);
1042 glBlendFunc( GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1043 glBlendEquation(GL_FUNC_ADD
);
1045 shader_blitcolour_use();
1046 shader_blitcolour_uColour( (v4f
){ 0.1f
, 0.1f
, 0.3f
, menu_opacity
*0.5f
} );
1050 VG_STATIC
void menu_render_fg( camera
*cam
)
1052 glEnable( GL_DEPTH_TEST
);
1053 glDisable( GL_BLEND
);
1057 shader_model_menu_use();
1058 shader_model_menu_uColour( (v4f
){ 1.0f
,1.0f
,1.0f
,1.0f
} );
1059 shader_model_menu_uTexMain( 1 );
1061 glActiveTexture( GL_TEXTURE1
);
1062 glBindTexture( GL_TEXTURE_2D
, tex_menu
);
1064 shader_model_menu_uPv( cam
->mtx
.pv
);
1065 shader_model_menu_uPvmPrev( cam
->mtx_prev
.pv
);
1066 mesh_bind( &menu_glmesh
);
1068 for( int i
=0; i
<vg_list_size(menu_buttons
); i
++ ){
1069 struct menu_button
*btn
= &menu_buttons
[i
];
1070 float talpha
= i
==game_menu
.loc
? 1.0f
: 0.0f
,
1071 tsize0
= btn
->fn_visibility( btn
->user
)? 1.0f
: 0.0f
,
1072 tsize1
= i
==game_menu
.loc
? 0.07f
: 0.0f
,
1073 tsize
= tsize0
+tsize1
;
1075 btn
->falpha
= vg_lerpf( btn
->falpha
, talpha
, vg
.time_frame_delta
* 14.0f
);
1076 btn
->fsize
= vg_lerpf( btn
->fsize
, tsize
, vg
.time_frame_delta
* 7.0f
);
1079 v4f vselected
= {0.95f
*1.3f
,0.45f
*1.3f
,0.095f
*1.3f
, 1.0f
},
1080 vnormal
= {1.0f
,1.0f
,1.0f
, 1.0f
},
1083 v4_lerp( vnormal
, vselected
, btn
->falpha
, vcurrent
);
1084 shader_model_menu_uColour( vcurrent
);
1088 mdl_transform_m4x3( &btn
->mesh
->transform
, mtx
);
1089 m4x3_mul( menu_mdl_mtx
, mtx
, mtx
);
1090 m4x3_identity( mtx_size
);
1091 m3x3_scalef( mtx_size
, expSustainedImpulse( btn
->fsize
, 0.5f
, 8.7f
) );
1092 m4x3_mul( mtx
, mtx_size
, mtx
);
1093 shader_model_menu_uMdl( mtx
);
1095 for( int j
=0; j
<btn
->mesh
->submesh_count
; j
++ ){
1097 mdl_arritm( &menu_model
.submeshs
, btn
->mesh
->submesh_start
+j
);
1098 mdl_draw_submesh( sm
);
1103 for( int i=0; i<menu_model->node_count; i++ )
1105 mdl_node *pnode = mdl_node_from_id( menu_model, i );
1107 for( int j=0; j<pnode->submesh_count; j++ )
1110 mdl_submesh_from_id( menu_model, pnode->submesh_start+j );
1112 mdl_node_transform( pnode, mtx );
1113 m4x3_mul( menu_mdl_mtx, mtx, mtx );
1114 shader_menu_uMdl( mtx );
1116 mdl_draw_submesh( sm );