8 #include "ent_miniworld.h"
12 #include "control_overlay.h"
14 #include "shaders/model_menu.h"
16 struct global_menu menu
= { .skip_starter
= 0 };
18 void menu_at_begin(void)
20 if( menu
.skip_starter
) return;
22 skaterift
.activity
= k_skaterift_menu
;
23 menu
.page
= k_menu_page_starter
;
28 vg_console_reg_var( "skip_starter_menu", &menu
.skip_starter
,
29 k_var_dtype_i32
, VG_VAR_PERSISTENT
);
32 void menu_open( enum menu_page page
)
34 skaterift
.activity
= k_skaterift_menu
;
36 if( page
!= k_menu_page_any
)
42 bool menu_viewing_map(void)
44 return (skaterift
.activity
== k_skaterift_menu
) &&
45 (menu
.page
== k_menu_page_main
) &&
46 (menu
.main_index
== k_menu_main_map
);
49 static void menu_decor_select( ui_rect rect
)
51 ui_px b
= vg_ui
.font
->sx
, hb
= b
/2;
52 ui_rect a0
= { rect
[0] - 20 - hb
, rect
[1] + rect
[3]/2 - hb
, b
,b
},
53 a1
= { rect
[0] + rect
[2] + 20 + hb
, rect
[1] + rect
[3]/2 - hb
, b
,b
};
55 ui_text( a0
, "\x95", 1, k_ui_align_middle_center
, 0 );
56 ui_text( a1
, "\x93", 1, k_ui_align_middle_center
, 0 );
59 static void menu_standard_widget( ui_rect inout_panel
, ui_rect rect
, ui_px s
)
61 ui_split( inout_panel
, k_ui_axis_h
, vg_ui
.font
->sy
*s
*2,
62 8, rect
, inout_panel
);
65 static bool menu_slider( ui_rect inout_panel
, bool select
, const char *label
,
66 const f32 disp_min
, const f32 disp_max
, f32
*value
,
70 menu_standard_widget( inout_panel
, rect
, 1 );
71 ui_label( rect
, label
, 1, 8, box
);
74 enum ui_button_state state
= ui_slider_base( box
, 0, 1, value
, &t
),
76 k_ui_button_holding_inside
|
77 k_ui_button_holding_outside
|
79 mask_brighter
= mask_using
| k_ui_button_hover
;
81 if( menu
.input_mode
== k_menu_input_mode_keys
)
85 f32 m
= axis_state( k_sraxis_mbrowse_h
);
88 *value
+= m
* vg
.time_frame_delta
* (1.0f
/2.0f
);
89 *value
= vg_clampf( *value
, 0, 1 );
92 menu_decor_select( rect
);
93 state
|= k_ui_button_hover
;
97 ui_rect line
= { box
[0], box
[1], t
* (f32
)box
[2], box
[3] };
98 ui_fill( line
, state
&mask_brighter
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
99 ui_fill( (ui_rect
){ box
[0]+line
[2], box
[1], box
[2]-line
[2], box
[3] },
102 ui_outline( box
, 1, state
? GUI_COL_HI
: GUI_COL_ACTIVE
, 0 );
103 ui_slider_text( box
, format
, disp_min
+ (*value
)*( disp_max
-disp_min
) );
105 return (state
& mask_using
) && 1;
108 static bool menu_button( ui_rect inout_panel
, bool select
, const char *text
)
111 menu_standard_widget( inout_panel
, rect
, 1 );
113 enum ui_button_state state
= k_ui_button_none
;
115 if( menu
.input_mode
== k_menu_input_mode_keys
)
119 menu_decor_select( rect
);
121 if( button_down( k_srbind_maccept
) )
122 state
= k_ui_button_click
;
127 state
= ui_button_base( rect
);
131 if( state
== k_ui_button_click
)
133 ui_fill( rect
, GUI_COL_DARK
);
135 else if( state
== k_ui_button_holding_inside
)
137 ui_fill( rect
, GUI_COL_DARK
);
139 else if( state
== k_ui_button_holding_outside
)
141 ui_fill( rect
, GUI_COL_DARK
);
142 ui_outline( rect
, 1, GUI_COL_CLICK
, 0 );
144 else if( state
== k_ui_button_hover
)
146 ui_fill( rect
, GUI_COL_ACTIVE
);
147 ui_outline( rect
, 1, GUI_COL_CLICK
, 0 );
151 ui_fill( rect
, select
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
153 ui_outline(rect
, 1, GUI_COL_HI
, 0 );
156 ui_text( rect
, text
, 1, k_ui_align_middle_center
, 0 );
157 return state
== k_ui_button_click
;
160 static bool menu_checkbox( ui_rect inout_panel
, bool select
,
161 const char *str_label
, i32
*data
)
163 ui_rect rect
, label
, box
;
164 menu_standard_widget( inout_panel
, rect
, 1 );
166 ui_split( rect
, k_ui_axis_v
, -rect
[3], 0, label
, box
);
167 ui_text( label
, str_label
, k_ui_scale
, k_ui_align_middle_left
, 0 );
169 enum ui_button_state state
= k_ui_button_none
;
171 if( menu
.input_mode
== k_menu_input_mode_keys
)
175 menu_decor_select( rect
);
177 if( button_down( k_srbind_maccept
) )
179 *data
= (*data
) ^ 0x1;
180 state
= k_ui_button_click
;
186 state
= ui_checkbox_base( box
, data
);
190 if( state
== k_ui_button_holding_inside
)
192 ui_fill( box
, GUI_COL_ACTIVE
);
193 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
195 else if( state
== k_ui_button_holding_outside
)
197 ui_fill( box
, GUI_COL_DARK
);
198 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
200 else if( state
== k_ui_button_hover
)
202 ui_fill( box
, GUI_COL_ACTIVE
);
203 ui_outline( box
, 1, GUI_COL_HI
, 0 );
207 ui_fill( box
, select
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
208 ui_outline( box
, 1, select
? GUI_COL_HI
: GUI_COL_NORM
, 0 );
211 bool changed
= (state
== k_ui_button_click
);
215 ui_rect_pad( box
, (ui_px
[2]){8,8} );
216 ui_fill( box
, GUI_COL_HI
);
222 static void menu_heading( ui_rect inout_panel
, const char *label
)
225 menu_standard_widget( inout_panel
, rect
, 1 );
230 u32 c0
= ui_opacity( GUI_COL_DARK
, 0.36f
),
231 c1
= ui_opacity( GUI_COL_DARK
, 0.5f
);
233 struct ui_vert
*vs
= ui_fill( rect
, c0
);
239 ui_text( rect
, label
, 1, k_ui_align_middle_center
, 1 );
242 ui_text( rect
, label
, 1, k_ui_align_middle_center
,
243 ui_colour(k_ui_blue
+k_ui_brighter
) );
248 if( button_down( k_srbind_mopen
) )
250 if( skaterift
.activity
== k_skaterift_default
)
252 menu_open( k_menu_page_main
);
257 if( skaterift
.activity
!= k_skaterift_menu
)
260 /* get buttons inputs
261 * -------------------------------------------------------------------*/
262 int ml
= button_down( k_srbind_mleft
),
263 mr
= button_down( k_srbind_mright
),
264 mu
= button_down( k_srbind_mup
),
265 md
= button_down( k_srbind_mdown
),
268 enter
= button_down( k_srbind_maccept
);
272 menu
.input_mode
= k_menu_input_mode_keys
;
276 * --------------------------------------------------------------------*/
277 menu
.mouse_dist
+= v2_length( vg
.mouse_delta
); /* TODO: Move to UI */
278 if( menu
.mouse_dist
> 10.0f
)
280 menu
.input_mode
= k_menu_input_mode_mouse
;
281 menu
.mouse_dist
= 0.0f
;
284 if( ui_clicking(UI_MOUSE_LEFT
) || ui_clicking(UI_MOUSE_RIGHT
) )
286 menu
.input_mode
= k_menu_input_mode_mouse
;
289 if( menu
.input_mode
== k_menu_input_mode_mouse
)
293 * ------------------------------------------------------------*/
294 vg_ui
.wants_mouse
= 1;
297 if( skaterift
.activity
!= k_skaterift_menu
) return;
299 if( vg
.settings_open
)
301 if( button_down( k_srbind_mback
) )
304 srinput
.state
= k_input_state_resume
;
310 if( menu
.page
== k_menu_page_credits
)
312 ui_rect panel
= { 0,0, 600, 400 },
313 screen
= { 0,0, vg
.window_x
,vg
.window_y
};
314 ui_rect_center( screen
, panel
);
315 ui_fill( panel
, GUI_COL_DARK
);
316 ui_outline( panel
, 1, GUI_COL_NORM
, 0 );
317 ui_rect_pad( panel
, (ui_px
[]){8,8} );
320 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
321 ui_font_face( &vgf_default_title
);
322 ui_text( title
, "Skate Rift - Credits", 1, k_ui_align_middle_center
, 0 );
324 ui_split( panel
, k_ui_axis_h
, 28, 0, title
, panel
);
325 ui_font_face( &vgf_default_large
);
326 ui_text( title
, "Mt.Zero Software", 1, k_ui_align_middle_center
, 0 );
328 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
329 ui_split( panel
, k_ui_axis_h
, 28*2, 0, title
, panel
);
330 ui_font_face( &vgf_default_title
);
331 ui_text( title
, "Free Software", 1, k_ui_align_middle_center
, 0 );
333 ui_split( panel
, k_ui_axis_h
, 8, 0, title
, panel
);
334 ui_font_face( &vgf_default_large
);
336 "Sam Lantinga - SDL2 - libsdl.org\n"
337 "Hunter WB - Anyascii\n"
338 "David Herberth - GLAD\n"
339 "Dominic Szablewski - QOI - qoiformat.org\n"
340 "Sean Barrett - stb_image, stb_vorbis,\n"
342 "Khronos Group - OpenGL\n"
343 , 1, k_ui_align_left
, 0 );
345 if( button_down( k_srbind_mback
) )
347 menu
.page
= k_menu_page_main
;
354 * -------------------------------------------------------------------*/
356 ui_font_face( &vgf_default_title
);
357 ui_px height
= vg_ui
.font
->ch
+ 16;
358 ui_rect topbar
= { 0, 0, vg
.window_x
, height
};
360 const char *opts
[] = {
361 [k_menu_main_main
] = "Menu",
362 [k_menu_main_map
] = "Map",
363 [k_menu_main_settings
] = "Settings",
364 [k_menu_main_guide
] = "Guides"
368 u8 lb_down
= 0, rb_down
= 0;
369 vg_exec_input_program( k_vg_input_type_button_u8
,
371 vg_joy_button
, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
, vg_end
373 vg_exec_input_program( k_vg_input_type_button_u8
,
375 vg_joy_button
, SDL_CONTROLLER_BUTTON_LEFTSHOULDER
, vg_end
378 if( menu
.repeater
> 0.0f
)
380 menu
.repeater
-= vg_minf( vg
.time_frame_delta
, 0.5f
);
384 if( lb_down
!= rb_down
)
386 menu
.main_index
+= rb_down
;
387 menu
.main_index
-= lb_down
;
388 menu
.repeater
+= 0.2f
;
390 if( menu
.main_index
== -1 )
393 if( menu
.main_index
== vg_list_size(opts
) )
398 ui_px x
= 0, spacer
= 8;
399 for( u32 draw
=0; draw
<2; draw
++ )
401 if( menu
.input_mode
== k_menu_input_mode_keys
)
405 ui_rect inf_lb
= { x
, 0, 32, height
};
406 ui_fill( inf_lb
, lb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
407 ui_text( inf_lb
, "\x91", 1, k_ui_align_middle_center
, 0 );
412 for( i32 i
=0; i
<vg_list_size(opts
); i
++ )
414 ui_rect box
= { x
, 0, ui_text_line_width(opts
[i
]) + 32, height
};
418 enum ui_button_state state
= ui_button_base( box
);
419 if( state
== k_ui_button_click
)
421 ui_fill( box
, GUI_COL_DARK
);
424 else if( state
== k_ui_button_holding_inside
)
426 ui_fill( box
, GUI_COL_DARK
);
428 else if( state
== k_ui_button_holding_outside
)
430 ui_fill( box
, GUI_COL_DARK
);
431 ui_outline( box
, 1, GUI_COL_CLICK
, 0 );
433 else if( state
== k_ui_button_hover
)
435 ui_fill( box
, GUI_COL_NORM
);
436 ui_outline( box
, 1, GUI_COL_ACTIVE
, 0 );
439 ui_fill( box
, i
==menu
.main_index
? GUI_COL_ACTIVE
: GUI_COL_NORM
);
441 ui_text( box
, opts
[i
], 1, k_ui_align_middle_center
, 0 );
444 x
+= box
[2] + spacer
;
447 if( menu
.input_mode
== k_menu_input_mode_keys
)
451 ui_rect inf_rb
= { x
, 0, 32, height
};
452 ui_fill( inf_rb
, rb_down
? GUI_COL_NORM
: GUI_COL_NORM
);
453 ui_text( inf_rb
, "\x92", 1, k_ui_align_middle_center
, 0 );
459 ui_fill( (ui_rect
){ x
+8,0, vg
.window_x
-(x
+8),height
}, GUI_COL_NORM
);
462 x
= vg
.window_x
/2 - x
/2;
463 ui_fill( (ui_rect
){ 0, 0, x
-8, height
}, GUI_COL_NORM
);
467 if( menu
.main_index
== k_menu_main_map
)
469 ui_font_face( &vgf_default_large
);
470 ui_rect title
= { vg
.window_x
/2 - 512/2, height
+8, 512, 64 };
476 ui_fill( (ui_rect
){ x
,y
, 0,height
},
477 world_static
.active_instance
? GUI_COL_DARK
: GUI_COL_ACTIVE
);
481 vg_strnull( &str
, buf
, sizeof(buf
) );
482 vg_strcat( &str
, "Hub World" );
484 if( world_static
.active_instance
&&
485 (vg_input
.display_input_method
== k_input_method_controller
) )
487 vg_strcat( &str
, " (" );
488 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
489 vg_strcat( &str
, ")" );
492 ui_px w
= ui_text( (ui_rect
){ x
+8, y
, 1000, height
}, buf
, 1,
493 k_ui_align_middle_left
, 0 );
502 world_instance
*world
= &world_static
.instances
[1];
503 if( world
->status
== k_world_status_loaded
)
505 const char *world_name
=
506 mdl_pstr( &world
->meta
, world
->info
.pstr_name
);
508 vg_strnull( &str
, buf
, sizeof(buf
) );
509 vg_strcat( &str
, world_name
);
511 if( !world_static
.active_instance
&&
512 (vg_input
.display_input_method
== k_input_method_controller
) )
514 vg_strcat( &str
, " (" );
515 vg_input_string( &str
, input_button_list
[k_srbind_mhub
], 1 );
516 vg_strcat( &str
, ")" );
519 vs
= ui_fill( (ui_rect
){ x
,y
, 1000,height
},
520 world_static
.active_instance
? GUI_COL_ACTIVE
: GUI_COL_DARK
);
521 w
= ui_text( (ui_rect
){ x
+16,y
, 1000,height
}, buf
,
522 1, k_ui_align_middle_left
, 0 );
524 w
= w
*vg_ui
.font
->sx
+ 8*3;
527 if( button_down( k_srbind_mhub
) ||
528 ui_button_base( (ui_rect
){0,y
,x
,height
} ) == k_ui_button_click
)
530 world_switch_instance( world_static
.active_instance
^ 0x1 );
531 skaterift
.activity
= k_skaterift_default
;
532 world_map
.view_ready
= 0;
542 if( button_down( k_srbind_mback
) )
544 skaterift
.activity
= k_skaterift_default
;
548 ui_rect list0
= { vg
.window_x
/2 - 512/2, height
+32,
549 512, vg
.window_y
-height
-64 }, list
;
550 rect_copy( list0
, list
);
551 ui_rect_pad( list
, (ui_px
[2]){8,8} );
555 [k_menu_main_main
] = &menu
.main_row
,
556 [k_menu_main_settings
] = &menu
.settings_row
,
557 [k_menu_main_guide
] = &menu
.guides_row
561 if( mv
< 0 ) *row
= (*row
) +1;
562 if( mv
> 0 ) *row
= vg_max( 0, (*row
) -1 );
565 * -------------------------------------------------------------------*/
567 if( menu
.main_index
== k_menu_main_main
)
569 *row
= vg_min( 2, *row
);
571 if( menu_button( list
, *row
== 0, "Resume" ) )
573 skaterift
.activity
= k_skaterift_default
;
577 if( menu_button( list
, *row
== 1, "Credits" ) )
579 menu
.page
= k_menu_page_credits
;
582 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
583 if( menu_button( end
, *row
== 2, "Quit Game" ) )
585 vg
.window_should_close
= 1;
588 else if( menu
.main_index
== k_menu_main_settings
)
590 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
591 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
592 *row
= vg_min( 8, *row
);
594 ui_font_face( &vgf_default_large
);
596 menu_heading( list
, "Game" );
597 menu_checkbox( list
, *row
== 0, "Show controls overlay",
598 &control_overlay
.enabled
);
599 menu_checkbox( list
, *row
== 1, "Auto connect to global server",
600 &network_client
.auto_connect
);
602 menu_heading( list
, "Audio/Video" );
603 menu_slider( list
, *row
== 2, "Volume", 0, 100,
604 &vg_audio
.external_global_volume
, "%.f%%" );
605 menu_slider( list
, *row
== 3, "Resolution", 0, 100,
606 &k_render_scale
, "%.f%%" );
607 menu_checkbox( list
, *row
== 4, "Motion Blur", &k_blur_effect
);
609 menu_heading( list
, "Camera" );
610 menu_slider( list
, *row
== 5, "Fov", 97, 135,
611 &k_fov
, "%.1f\xb0" );
612 menu_slider( list
, *row
== 6, "Cam Height", -0.4f
, +1.4f
,
613 &k_cam_height
, vg_lerpf(-0.4f
,1.4f
,k_cam_height
)>=0.0f
?
615 menu_checkbox( list
, *row
== 7, "Invert Y Axis", &k_invert_y
);
618 ui_rect end
= { list
[0], list
[1]+list
[3]-64, list
[2], 72 };
619 ui_font_face( &vgf_default_small
);
620 menu_heading( end
, "Advanced" );
621 if( menu_button( end
, *row
== 8, "Open Engine Settings" ) )
626 else if( menu
.main_index
== k_menu_main_guide
)
628 ui_fill( list0
, ui_opacity( GUI_COL_DARK
, 0.36f
) );
629 ui_outline( list0
, 1, GUI_COL_NORM
, 0 );
630 *row
= vg_min( 4, *row
);
632 ui_font_face( &vgf_default_large
);
634 menu_heading( list
, "Controls" );
635 if( menu_button( list
, *row
== 0, "Skating \xb2" ) )
638 if( menu_button( list
, *row
== 1, "Tricks \xb2" ) )
642 menu_heading( list
, "Workshop" );
643 if( menu_button( list
, *row
== 2, "Create a Board \xb2" ) )
646 if( menu_button( list
, *row
== 3, "Create a World \xb2" ) )
649 if( menu_button( list
, *row
== 4, "Create a Playermodel \xb2" ) )
657 vg_ui
.frosting
= 0.015f
;
658 ui_flush( k_ui_shader_colour
, vg
.window_x
, vg
.window_y
);
659 vg_ui
.frosting
= 0.0f
;
661 ui_font_face( &vgf_default_small
);