-struct {
- int active;
- f32 factive;
- int disable_open;
-
- u32 page, /* current page index */
- page_stack[ MENU_STACK_SIZE ],
- page_depth;
- ent_menuitem *loc;
- ent_camera *cam;
- camera view;
-
- mdl_context model;
- GLuint texture;
- glmesh mesh;
-
- mdl_array_ptr items, markers, cameras;
-}
-static menu;
-
-static void menu_init(void)
-{
- void *alloc = vg_mem.rtmemory;
-
- mdl_open( &menu.model, "models/rs_menu.mdl", alloc );
- mdl_load_metadata_block( &menu.model, alloc );
-
- vg_linear_clear( vg_mem.scratch );
-
- mdl_load_array( &menu.model, &menu.items, "ent_menuitem", alloc );
- mdl_load_array( &menu.model, &menu.markers, "ent_marker", alloc );
- mdl_load_array( &menu.model, &menu.cameras, "ent_camera", alloc );
-
- vg_linear_clear( vg_mem.scratch );
-
- if( !mdl_arrcount( &menu.model.textures ) )
- vg_fatal_error( "No texture in menu file" );
-
- mdl_texture *tex0 = mdl_arritm( &menu.model.textures, 0 );
- void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
- mdl_fread_pack_file( &menu.model, &tex0->file, data );
-
- mdl_async_load_glmesh( &menu.model, &menu.mesh );
- vg_tex2d_load_qoi_async( data, tex0->file.pack_size,
- VG_TEX2D_LINEAR|VG_TEX2D_CLAMP,
- &menu.texture );
-
- mdl_close( &menu.model );
- shader_model_menu_register();
-}
-
-static void menu_open_page( const char *name )
-{
- vg_info( "Try to open %s\n", name );
-
- u32 hash = vg_strdjb2( name );
- for( u32 i=0; i<mdl_arrcount(&menu.items); i++ ){
- ent_menuitem *item = mdl_arritm( &menu.items, i );
-
- if( item->type == k_ent_menuitem_type_page ){
- if( mdl_pstreq( &menu.model, item->page.pstr_name, name, hash ) ){
- menu.page = __builtin_ctz( item->groups );
- vg_info( "menu page: %u\n", menu.page );
-
- if( item->page.id_entrypoint ){
- u32 id = mdl_entity_id_id( item->page.id_entrypoint );
- menu.loc = mdl_arritm( &menu.items, id );
- }
-
- if( item->page.id_viewpoint ){
- u32 id = mdl_entity_id_id( item->page.id_viewpoint );
- menu.cam = mdl_arritm( &menu.cameras, id );
- }
-
- menu.page_stack[ menu.page_depth ++ ] = menu.page;
- return;
- }
- }
- }
-}
-
-static void menu_back_page(void)
-{
- if( menu.page_depth == 0 ){
- menu.active = 0;
- }
- else{
- menu.page = menu.page_stack[ -- menu.page_depth ];
- }
-}
-
-static void menu_update(void)
-{
- if( button_down( k_srbind_mopen ) ){
- if( !menu.active && !menu.disable_open ){
- menu.active = 1;
- menu_open_page( "Main Menu" );
- }
- }
-
- menu.factive = vg_lerpf( menu.factive, menu.active,
- vg.time_frame_delta * 6.0f );
-
- if( menu.factive > 0.01f ){
-
- }
-
- if( !menu.active ) return;
- if( !menu.loc ) return;
- if( !menu.cam ) return;
-
- int ml = button_down( k_srbind_mleft ),
- mr = button_down( k_srbind_mright ),
- mu = button_down( k_srbind_mup ),
- md = button_down( k_srbind_mdown ),
- mh = ml-mr,
- mv = mu-md,
- enter = button_down( k_srbind_maccept ),
- escape = button_down( k_srbind_mback );
-
- if( escape ){
- menu_back_page();
- }
- else if( enter ){
- if ( menu.loc->type == k_ent_menuitem_type_event_button ){
-
- }
- else if( menu.loc->type == k_ent_menuitem_type_page_button ){
- menu_open_page( mdl_pstr( &menu.model, menu.loc->button.pstr ) );
- }
- else if( menu.loc->type == k_ent_menuitem_type_toggle ){
-
- }
- }
- else if( mh||mv ){
- v3f opt;
- v3_zero( opt );
- f32 best = 0.707f;
- ent_menuitem *nextpos = NULL;
-
- opt[0] += mh;
- opt[2] += mv;
- mdl_transform_vector( &menu.cam->transform, opt, opt );
-
- for( u32 i=0; i<4; i++ ){
- u32 id = menu.loc->id_links[i];
- if( !id ) continue;
- u32 index = mdl_entity_id_id( id );
-
- ent_menuitem *other = mdl_arritm( &menu.items, index );
- v3f delta;
- v3_sub( menu.loc->transform.co, other->transform.co, delta );
- v3_normalize( delta );
-
- f32 score = v3_dot( delta, opt );
- if( score > best ){
- best = score;
- nextpos = other;
- }
- }
-
- if( nextpos ){
- menu.loc = nextpos;
- }
- }
-}
-
-VG_STATIC void menu_render(void)
-{
- glEnable(GL_BLEND);
- glDisable(GL_DEPTH_TEST);
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
- glBlendEquation(GL_FUNC_ADD);
-
- shader_blitcolour_use();
- shader_blitcolour_uColour( (v4f){ 0.1f, 0.1f, 0.3f, menu.factive*0.5f } );
- render_fsquad();
-
- glEnable( GL_DEPTH_TEST );
- glDisable( GL_BLEND );
-
- if( menu.cam ){
- menu.view.fov = menu.cam->fov;
- menu.view.farz = 150.0f;
- menu.view.nearz = 0.01f;
- v3_copy( menu.cam->transform.co, menu.view.pos );
-
- v3f v0;
- mdl_transform_vector( &menu.cam->transform, (v3f){0.0f,-1.0f,0.0f}, v0 );
- player_vector_angles( menu.view.angles, v0, 1.0f, 0.0f );
- camera_update_transform( &menu.view );
- camera_update_view( &menu.view );
- camera_update_projection( &menu.view );
- camera_finalize( &menu.view );
- }
- else return;
-
- shader_model_menu_use();
- shader_model_menu_uTexMain( 1 );
- glActiveTexture( GL_TEXTURE1 );
- glBindTexture( GL_TEXTURE_2D, menu.texture );
- shader_model_menu_uPv( menu.view.mtx.pv );
- shader_model_menu_uPvmPrev( menu.view.mtx_prev.pv );
-
- mesh_bind( &menu.mesh );
-
- for( u32 i=0; i<mdl_arrcount(&menu.items); i++ ){
- ent_menuitem *item = mdl_arritm( &menu.items, i );
-
- if( item->type == k_ent_menuitem_type_page ) continue;
- if( !(item->groups & (0x1 << menu.page)) ) continue;
-
- if( item == menu.loc ){
- shader_model_menu_uColour( (v4f){ 0.1f,0.25f,0.9f,1.0f} );
- }
- else{
- shader_model_menu_uColour( (v4f){ 1.0f,1.0f,1.0f,1.0f} );
- }
-
- m4x3f mmdl;
- mdl_transform_m4x3( &item->transform, mmdl );
- shader_model_menu_uMdl( mmdl );
-
- for( u32 j=0; j<item->submesh_count; j++ ){
- u32 index = item->submesh_start + j;
- mdl_draw_submesh( mdl_arritm( &menu.model.submeshs, index ));
- }
- }
-}
-
-#endif /* MENU_H */
-
-#if 0
-#ifndef MENU_H
-#define MENU_H
-
-#include "common.h"
-#include "model.h"
-#include "world_render.h"
-#include "player.h"
-#include "conf.h"
-
-#include "shaders/model_menu.h"
-#include "vg_steam_friends.h"
-
-VG_STATIC mdl_context menu_model;
-VG_STATIC mdl_array_ptr menu_markers;
-VG_STATIC glmesh menu_glmesh;
-VG_STATIC m4x3f menu_mdl_mtx;
-VG_STATIC float menu_opacity = 0.0f;
-VG_STATIC float menu_input_cooldown = 0.0f;
-VG_STATIC float menu_fov_target = 97.0f,
- menu_smooth_fov = 97.0f;
-VG_STATIC v2f menu_extra_angles;
-VG_STATIC v3f menu_camera_pos;
-VG_STATIC v2f menu_camera_angles;
-
-VG_STATIC int cl_menu = 0,
- cl_menu_go_away = 0;
-
-VG_STATIC int menu_enabled(void){ return cl_menu; }
-
-VG_STATIC const char *playermodels[] = { "ch_new", "ch_jordan", "ch_outlaw" };
-
-GLuint tex_menu;
-
-#if 0
-VG_STATIC struct input_binding input_menu_h,
- input_menu_v,
- input_menu_press,
- input_menu_back,
- input_menu_toggle,
- input_menu_toggle_kbm;
-#endif
-
-VG_STATIC void menu_btn_quit( int event );
-VG_STATIC void menu_btn_skater( int event );
-VG_STATIC void menu_btn_blur( int event );
-VG_STATIC void menu_btn_fuckoff( int event );
-VG_STATIC void menu_btn_reset( int event );
-VG_STATIC void menu_btn_map( int event );
-VG_STATIC void menu_btn_settings( int event );
-VG_STATIC void menu_btn_invert_y( int event );
-
-VG_STATIC mdl_mesh *menu_mesh_fov_slider,
- *menu_mesh_vol_slider,
- *menu_mesh_res_slider;
-
-VG_STATIC ent_marker
- *menu_mark_fov_min,
- *menu_mark_fov_max,
- *menu_mark_vol_min,
- *menu_mark_vol_max,
- *menu_mark_res_min,
- *menu_mark_res_max;
-
-struct{
- /* state */
- int loc;
- u32 page;
-
- /* map browser */
- struct menu_map_file{
- char name[ 64 ];
- }
- maps_list[ 16 ];
-
- int selected_map,
- map_count;
-}
-VG_STATIC game_menu;
-
-enum menu_page{
- k_menu_page_main = 0x1,
- k_menu_page_skater = 0x2,
- k_menu_page_quit = 0x4,
- k_menu_page_settings = 0x8,
- k_menu_page_map = 0x10
-};
-
-struct menu_btn_userdata{
- int i;
- void *ptr_generic;
-};
-
-VG_STATIC int menu_settings_if( struct menu_btn_userdata ud )
-{
- if( game_menu.page & k_menu_page_settings ){
- int *ptr = ud.ptr_generic;
- return *ptr;
- }
- else
- return 0;
-}
-
-VG_STATIC int menu_vis( struct menu_btn_userdata ud )
-{
- if( ud.i & game_menu.page )
- return 1;
- else
- return 0;
-}
-
-#if 0
-VG_STATIC int menu_controller( struct menu_btn_userdata ud )
-{
- if( (game_menu.page & (k_menu_page_main|k_menu_page_settings))
- && (ud.i == steam_display_controller) )
- return 1;
- return 0;
-}
-
-VG_STATIC int menu_controller_inf( struct menu_btn_userdata ud )
-{
- if( (game_menu.page & k_menu_page_settings)
- && (ud.i == steam_display_controller) )
- return 1;
- return 0;
-}
-#endif
-
-struct menu_button
-{
- const char *name;
-
- int (*fn_visibility)( struct menu_btn_userdata ud );
- struct menu_btn_userdata user;
-
- void (*fn_press)( int event );
-
- const char *ll,
- *lu,
- *lr,
- *ld;
-
- mdl_mesh *mesh;
- float falpha, fsize;
-}
-VG_STATIC menu_buttons[] =
-{
- {
- "text_quit", menu_vis, {.i=k_menu_page_main|k_menu_page_quit},
- .fn_press = menu_btn_quit,
- .ld="text_reset", .lr="text_settings", /*.ll="text_map"*/
- },
- {
- "text_quitty", menu_vis, {.i=k_menu_page_quit}
- },
- {
- "text_yes", menu_vis, {.i=k_menu_page_quit},
- .fn_press = menu_btn_fuckoff
- },
-{
- "text_reset", menu_vis, {.i=k_menu_page_main},
- .fn_press = menu_btn_reset,
- .lu="text_quit", .ld="text_skater", /*.ll="text_map",*/ .lr="text_settings"
-},
-{
- "text_skater", menu_vis, {.i=k_menu_page_main|k_menu_page_skater},
- .fn_press = menu_btn_skater,
- .lu="text_reset", /*.ll="text_map",*/ .lr="text_settings"
-},
-/*
-{
- "text_map", menu_vis, {.i=k_menu_page_main},
- .fn_press = menu_btn_map,
- .lr="text_reset"
-},
-*/
-{
- "text_settings", menu_vis, {.i=k_menu_page_main|k_menu_page_settings},
- .fn_press = menu_btn_settings,
- .ll="text_reset"
-},
-{
- "skater_left", menu_vis, {k_menu_page_skater}
-},
-{
- "skater_right", menu_vis, {k_menu_page_skater}
-},
-
-{
- "fov_slider", menu_vis, {k_menu_page_settings},
- .ld="text_invert_y"
-},
-{ "fov_info", menu_vis, {k_menu_page_settings} },
-
-{
- "vol_slider", menu_vis, {k_menu_page_settings},
- .lu="res_slider"
-},
-{ "vol_info", menu_vis, {k_menu_page_settings} },
-
-{
- "text_invert_y", menu_vis, {k_menu_page_settings},
- .fn_press = menu_btn_invert_y,
- .lu = "fov_slider", .ld="text_blur"
-},
-{
- "text_invert_y_check", menu_settings_if, {.ptr_generic=&cl_invert_y}
-},
-{
- "text_blur", menu_vis, {k_menu_page_settings},
- .fn_press = menu_btn_blur,
- .lu="text_invert_y", .ld="res_slider"
-},
-{
- "text_blur_check", menu_settings_if, {.ptr_generic=&cl_blur}
-},
-{
- "res_slider", menu_vis, {k_menu_page_settings},
- .ld = "vol_slider", .lu = "text_blur"
-},
-{
- "res_info", menu_vis, {k_menu_page_settings},
-},
-#if 0
-{ "ctr_xbox", menu_controller_inf, {k_steam_controller_type_xbox}},
-{ "ctr_xbox_text", menu_controller_inf, {k_steam_controller_type_xbox}},
-{ "ctr_steam", menu_controller_inf, {k_steam_controller_type_steam}},
-{ "ctr_steam_text", menu_controller_inf, {k_steam_controller_type_steam}},
-{ "ctr_deck", menu_controller_inf, {k_steam_controller_type_steam_deck}},
-{ "ctr_deck_text", menu_controller_inf, {k_steam_controller_type_steam_deck}},
-{ "ctr_ps", menu_controller_inf, {k_steam_controller_type_playstation}},
-{ "ctr_ps_text", menu_controller_inf, {k_steam_controller_type_playstation}},
-{ "ctr_kbm", menu_controller_inf, {k_steam_controller_type_keyboard}},
-{ "ctr_kbm_text", menu_controller_inf, {k_steam_controller_type_keyboard}},
-#endif
-{
- "text_paused", menu_vis, {k_menu_page_main}
-},
-};
-
-VG_STATIC int menu_get_loc( const char *loc )
-{
- for( int i=0; i<vg_list_size(menu_buttons); i++ )
- if( !strcmp( menu_buttons[i].name, loc ) )
- return i;
-
- assert(0);
- return 0;
-}
-
-VG_STATIC void menu_btn_reset( int event )
-{
- localplayer_cmd_respawn( 0, NULL );
- cl_menu_go_away = 1;
- game_menu.page = 0;
-}
-
-VG_STATIC void menu_btn_fuckoff( int event )
-{
- vg.window_should_close = 1;
-}
-
-VG_STATIC void menu_btn_quit( int event )
-{
- game_menu.page = k_menu_page_quit;
- game_menu.loc = menu_get_loc( "text_yes" );
-}
-
-VG_STATIC void menu_btn_settings( int event )
-{
- game_menu.page = k_menu_page_settings;
- game_menu.loc = menu_get_loc( "fov_slider" );
-}
-
-VG_STATIC void menu_btn_skater( int event )
-{
- game_menu.page = k_menu_page_skater;
-}
-
-VG_STATIC void menu_btn_blur( int event )
-{
- cl_blur ^= 0x1;
-}
-
-VG_STATIC void menu_btn_invert_y( int event )
-{
- cl_invert_y ^= 0x1;
-}
-
-VG_STATIC void menu_btn_map( int event )
-{
- game_menu.page = k_menu_page_map;
- game_menu.map_count = 0;
- game_menu.selected_map = 0;
-
- tinydir_dir dir;
- tinydir_open( &dir, "maps" );