guide background cameras
[carveJwlIkooP6JGAAIwe30JlM.git] / menu.c
1 #pragma once
2 #include "skaterift.h"
3 #include "menu.h"
4 #include "model.h"
5 #include "entity.h"
6 #include "input.h"
7 #include "world_map.h"
8 #include "ent_miniworld.h"
9 #include "audio.h"
10 #include "workshop.h"
11 #include "gui.h"
12 #include "control_overlay.h"
13 #include "network.h"
14 #include "shaders/model_menu.h"
15
16 struct global_menu menu = { .skip_starter = 0 };
17
18 void menu_at_begin(void)
19 {
20 if( menu.skip_starter ) return;
21
22 skaterift.activity = k_skaterift_menu;
23 menu.page = k_menu_page_starter;
24 }
25
26 void menu_init(void)
27 {
28 vg_console_reg_var( "skip_starter_menu", &menu.skip_starter,
29 k_var_dtype_i32, VG_VAR_PERSISTENT );
30 }
31
32 void menu_open( enum menu_page page )
33 {
34 skaterift.activity = k_skaterift_menu;
35
36 if( page != k_menu_page_any )
37 {
38 menu.page = page;
39 }
40 }
41
42 bool menu_viewing_map(void)
43 {
44 return (skaterift.activity == k_skaterift_menu) &&
45 (menu.page == k_menu_page_main) &&
46 (menu.main_index == k_menu_main_map);
47 }
48
49 static void menu_decor_select( ui_rect rect )
50 {
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 };
54
55 ui_text( a0, "\x95", 1, k_ui_align_middle_center, 0 );
56 ui_text( a1, "\x93", 1, k_ui_align_middle_center, 0 );
57 }
58
59 static void menu_standard_widget( ui_rect inout_panel, ui_rect rect, ui_px s )
60 {
61 ui_split( inout_panel, k_ui_axis_h, vg_ui.font->sy*s*2,
62 8, rect, inout_panel );
63 }
64
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,
67 const char *format )
68 {
69 ui_rect rect, box;
70 menu_standard_widget( inout_panel, rect, 1 );
71 ui_label( rect, label, 1, 8, box );
72
73 f32 t;
74 enum ui_button_state state = ui_slider_base( box, 0, 1, value, &t ),
75 mask_using =
76 k_ui_button_holding_inside |
77 k_ui_button_holding_outside |
78 k_ui_button_click,
79 mask_brighter = mask_using | k_ui_button_hover;
80
81 if( vg_input.display_input_method == k_input_method_controller )
82 {
83 if( select )
84 {
85 f32 m = axis_state( k_sraxis_mbrowse_h );
86 if( fabsf(m) > 0.5f )
87 {
88 *value += m * vg.time_frame_delta * (1.0f/2.0f);
89 *value = vg_clampf( *value, 0, 1 );
90 }
91
92 menu_decor_select( rect );
93 state |= k_ui_button_hover;
94 }
95 }
96
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] },
100 GUI_COL_DARK );
101
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 ) );
104
105 return (state & mask_using) && 1;
106 }
107
108 static bool menu_button( ui_rect inout_panel, bool select, const char *text )
109 {
110 ui_rect rect;
111 menu_standard_widget( inout_panel, rect, 1 );
112
113 enum ui_button_state state = k_ui_button_none;
114
115 if( vg_input.display_input_method == k_input_method_controller )
116 {
117 if( select )
118 {
119 menu_decor_select( rect );
120
121 if( button_down( k_srbind_maccept ) )
122 state = k_ui_button_click;
123 }
124 }
125 else
126 {
127 state = ui_button_base( rect );
128 select = 0;
129 }
130
131 if( state == k_ui_button_click )
132 {
133 ui_fill( rect, GUI_COL_DARK );
134 }
135 else if( state == k_ui_button_holding_inside )
136 {
137 ui_fill( rect, GUI_COL_DARK );
138 }
139 else if( state == k_ui_button_holding_outside )
140 {
141 ui_fill( rect, GUI_COL_DARK );
142 ui_outline( rect, 1, GUI_COL_CLICK, 0 );
143 }
144 else if( state == k_ui_button_hover )
145 {
146 ui_fill( rect, GUI_COL_ACTIVE );
147 ui_outline( rect, 1, GUI_COL_CLICK, 0 );
148 }
149 else
150 {
151 ui_fill( rect, select? GUI_COL_ACTIVE: GUI_COL_NORM );
152 if( select )
153 ui_outline(rect, 1, GUI_COL_HI, 0 );
154 }
155
156 ui_text( rect, text, 1, k_ui_align_middle_center, 0 );
157
158 if( state == k_ui_button_click )
159 {
160 audio_lock();
161 audio_oneshot( &audio_ui[0], 1.0f, 0.0f );
162 audio_unlock();
163 return 1;
164 }
165 else return 0;
166 }
167
168 static bool menu_checkbox( ui_rect inout_panel, bool select,
169 const char *str_label, i32 *data )
170 {
171 ui_rect rect, label, box;
172 menu_standard_widget( inout_panel, rect, 1 );
173
174 ui_split( rect, k_ui_axis_v, -rect[3], 0, label, box );
175 ui_text( label, str_label, k_ui_scale, k_ui_align_middle_left, 0 );
176
177 enum ui_button_state state = k_ui_button_none;
178
179 if( vg_input.display_input_method == k_input_method_controller )
180 {
181 if( select )
182 {
183 menu_decor_select( rect );
184
185 if( button_down( k_srbind_maccept ) )
186 {
187 *data = (*data) ^ 0x1;
188 state = k_ui_button_click;
189 }
190 }
191 }
192 else
193 {
194 state = ui_checkbox_base( box, data );
195 select = 0;
196 }
197
198 if( state == k_ui_button_holding_inside )
199 {
200 ui_fill( box, GUI_COL_ACTIVE );
201 ui_outline( box, 1, GUI_COL_CLICK, 0 );
202 }
203 else if( state == k_ui_button_holding_outside )
204 {
205 ui_fill( box, GUI_COL_DARK );
206 ui_outline( box, 1, GUI_COL_CLICK, 0 );
207 }
208 else if( state == k_ui_button_hover )
209 {
210 ui_fill( box, GUI_COL_ACTIVE );
211 ui_outline( box, 1, GUI_COL_HI, 0 );
212 }
213 else
214 {
215 ui_fill( box, select? GUI_COL_ACTIVE: GUI_COL_DARK );
216 ui_outline( box, 1, select? GUI_COL_HI: GUI_COL_NORM, 0 );
217 }
218
219 if( *data )
220 {
221 ui_rect_pad( box, (ui_px[2]){8,8} );
222 ui_fill( box, GUI_COL_HI );
223 }
224
225 if( state == k_ui_button_click )
226 {
227 audio_lock();
228 audio_oneshot( &audio_ui[0], 1.0f, 0.0f );
229 audio_unlock();
230 return 1;
231 }
232 else return 0;
233 }
234
235 static void menu_heading( ui_rect inout_panel, const char *label, u32 colour )
236 {
237 ui_rect rect;
238 menu_standard_widget( inout_panel, rect, 1 );
239
240 rect[0] -= 8;
241 rect[2] += 16;
242
243 u32 c0 = ui_opacity( GUI_COL_DARK, 0.36f ),
244 c1 = ui_opacity( GUI_COL_DARK, 0.5f );
245
246 struct ui_vert *vs = ui_fill( rect, c0 );
247
248 vs[0].colour = c1;
249 vs[1].colour = c1;
250
251 rect[1] += 4;
252 ui_text( rect, label, 1, k_ui_align_middle_center, 1 );
253 rect[0] += 1;
254 rect[1] -= 1;
255 ui_text( rect, label, 1, k_ui_align_middle_center, colour? colour:
256 ui_colour(k_ui_blue+k_ui_brighter) );
257 }
258
259 static u32 medal_colour( u32 flags )
260 {
261 if( flags & k_ent_route_flag_achieve_gold )
262 return ui_colour( k_ui_yellow );
263 else if( flags & k_ent_route_flag_achieve_silver )
264 return ui_colour( k_ui_fg );
265 else return 0;
266 }
267
268 static i32 menu_nav( i32 *p_row, int mv, i32 max )
269 {
270 i32 row_prev = *p_row;
271
272 if( mv < 0 ) *p_row = vg_min( max, (*p_row) +1 );
273 if( mv > 0 ) *p_row = vg_max( 0, (*p_row) -1 );
274
275 if( *p_row != row_prev )
276 {
277 audio_lock();
278 audio_oneshot( &audio_ui[3], 1.0f, 0.0f );
279 audio_unlock();
280 }
281
282 return *p_row;
283 }
284
285 static void menu_try_find_cam( i32 id )
286 {
287 world_instance *world = &world_static.instances[0];
288 for( u32 i=0; i<mdl_arrcount(&world->ent_npc); i ++ )
289 {
290 ent_npc *fnpc = mdl_arritm( &world->ent_npc, i );
291 if( (fnpc->id == 50) && (fnpc->context == id) )
292 {
293 if( mdl_entity_id_type(fnpc->camera) == k_ent_camera )
294 {
295 u32 index = mdl_entity_id_id( fnpc->camera );
296 menu.bg_cam = mdl_arritm( &world->ent_camera, index );
297 menu.bg_blur = 0;
298 }
299 }
300 }
301 }
302
303 void menu_gui(void)
304 {
305 if( button_down( k_srbind_mopen ) )
306 {
307 if( skaterift.activity == k_skaterift_default )
308 {
309 menu_open( k_menu_page_main );
310 return;
311 }
312 }
313
314 if( skaterift.activity != k_skaterift_menu )
315 return;
316
317 menu.bg_blur = 1;
318 menu.bg_cam = NULL;
319
320 /* get buttons inputs
321 * -------------------------------------------------------------------*/
322 int ml = button_down( k_srbind_mleft ),
323 mr = button_down( k_srbind_mright ),
324 mu = button_down( k_srbind_mup ),
325 md = button_down( k_srbind_mdown ),
326 mh = ml-mr,
327 mv = mu-md,
328 enter = button_down( k_srbind_maccept );
329
330 if( vg_input.display_input_method == k_input_method_kbm )
331 {
332 vg_ui.wants_mouse = 1;
333 }
334
335 if( skaterift.activity != k_skaterift_menu ) return;
336
337 if( vg.settings_open )
338 {
339 if( button_down( k_srbind_mback ) )
340 {
341 audio_lock();
342 audio_oneshot( &audio_ui[3], 1.0f, 0.0f );
343 audio_unlock();
344 vg_settings_close();
345 srinput.state = k_input_state_resume;
346 }
347
348 return;
349 }
350
351 if( menu.page == k_menu_page_credits )
352 {
353 ui_rect panel = { 0,0, 600, 400 },
354 screen = { 0,0, vg.window_x,vg.window_y };
355 ui_rect_center( screen, panel );
356 ui_fill( panel, GUI_COL_DARK );
357 ui_outline( panel, 1, GUI_COL_NORM, 0 );
358 ui_rect_pad( panel, (ui_px[]){8,8} );
359
360 ui_rect title;
361 ui_split( panel, k_ui_axis_h, 28*2, 0, title, panel );
362 ui_font_face( &vgf_default_title );
363 ui_text( title, "Skate Rift - Credits", 1, k_ui_align_middle_center, 0 );
364
365 ui_split( panel, k_ui_axis_h, 28, 0, title, panel );
366 ui_font_face( &vgf_default_large );
367 ui_text( title, "Mt.Zero Software", 1, k_ui_align_middle_center, 0 );
368
369 ui_split( panel, k_ui_axis_h, 8, 0, title, panel );
370 ui_split( panel, k_ui_axis_h, 28*2, 0, title, panel );
371 ui_font_face( &vgf_default_title );
372 ui_text( title, "Free Software", 1, k_ui_align_middle_center, 0 );
373
374 ui_split( panel, k_ui_axis_h, 8, 0, title, panel );
375 ui_font_face( &vgf_default_large );
376 ui_text( panel,
377 "Sam Lantinga - SDL2 - libsdl.org\n"
378 "Hunter WB - Anyascii\n"
379 "David Herberth - GLAD\n"
380 "Dominic Szablewski - QOI - qoiformat.org\n"
381 "Sean Barrett - stb_image, stb_vorbis,\n"
382 " stb_include\n"
383 "Khronos Group - OpenGL\n"
384 , 1, k_ui_align_left, 0 );
385
386 ui_rect end = { panel[0], panel[1] + panel[3] - 64, panel[2], 64 };
387
388 if( menu_button( end, 1, "Back" ) || button_down( k_srbind_mback ) )
389 {
390 menu.page = k_menu_page_main;
391 }
392
393 goto menu_draw;
394 }
395 else if( menu.page == k_menu_page_starter )
396 {
397 i32 R = menu_nav( &menu.intro_row, mv, 3 );
398 ui_rect panel = { 0,0, 600, 400 },
399 screen = { 0,0, vg.window_x,vg.window_y };
400 ui_rect_center( screen, panel );
401 ui_fill( panel, ui_opacity( GUI_COL_DARK, 0.35f ) );
402 ui_outline( panel, 1, GUI_COL_NORM, 0 );
403 ui_rect_pad( panel, (ui_px[]){8,8} );
404
405 ui_rect title;
406 ui_split( panel, k_ui_axis_h, 28*2, 0, title, panel );
407 ui_font_face( &vgf_default_title );
408 ui_text( title, "Welcome to Skate Rift", 1, k_ui_align_middle_center, 0 );
409
410 ui_split( panel, k_ui_axis_h, 28, 0, title, panel );
411 ui_font_face( &vgf_default_large );
412
413 menu_checkbox( panel, R == 0,
414 "Show controls overlay (good for new players)",
415 &control_overlay.enabled );
416 menu_checkbox( panel, R == 1, "Auto connect to global server",
417 &network_client.auto_connect );
418
419 ui_rect end = { panel[0], panel[1] + panel[3] - 100, panel[2], 100 };
420 menu_checkbox( end, R == 2, "Don't show this again", &menu.skip_starter );
421 if( menu_button( end, R == 3, "OK" ) )
422 {
423 menu.page = k_menu_page_main;
424 skaterift.activity = k_skaterift_default;
425 }
426
427 menu_try_find_cam( 3 );
428 goto menu_draw;
429 }
430
431 /* TOP BAR
432 * -------------------------------------------------------------------*/
433
434 ui_font_face( &vgf_default_title );
435 ui_px height = vg_ui.font->ch + 16;
436 ui_rect topbar = { 0, 0, vg.window_x, height };
437
438 const char *opts[] = {
439 [k_menu_main_main] = "Menu",
440 [k_menu_main_map] = "Map",
441 [k_menu_main_settings ] = "Settings",
442 [k_menu_main_guide ] = "Guides"
443 };
444
445 /* TAB CONTROL */
446 u8 lb_down = 0, rb_down = 0;
447 vg_exec_input_program( k_vg_input_type_button_u8,
448 (vg_input_op[]){
449 vg_joy_button, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, vg_end
450 }, &rb_down );
451 vg_exec_input_program( k_vg_input_type_button_u8,
452 (vg_input_op[]){
453 vg_joy_button, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, vg_end
454 }, &lb_down );
455
456 if( menu.repeater > 0.0f )
457 {
458 menu.repeater -= vg_minf( vg.time_frame_delta, 0.5f );
459 }
460 else
461 {
462 if( lb_down != rb_down )
463 {
464 menu.main_index += rb_down;
465 menu.main_index -= lb_down;
466 menu.repeater += 0.2f;
467
468 if( menu.main_index == -1 )
469 menu.main_index ++;
470
471 if( menu.main_index == vg_list_size(opts) )
472 menu.main_index --;
473
474 audio_lock();
475 audio_oneshot( &audio_ui[3], 1.0f, 0.0f );
476 audio_unlock();
477 }
478 }
479
480 ui_px x = 0, spacer = 8;
481 for( u32 draw=0; draw<2; draw ++ )
482 {
483 if( vg_input.display_input_method == k_input_method_controller )
484 {
485 if( draw )
486 {
487 ui_rect inf_lb = { x, 0, 32, height };
488 ui_fill( inf_lb, lb_down? GUI_COL_NORM: GUI_COL_NORM );
489 ui_text( inf_lb, "\x91", 1, k_ui_align_middle_center, 0 );
490 }
491 x += 32 + spacer;
492 }
493
494 for( i32 i=0; i<vg_list_size(opts); i ++ )
495 {
496 ui_rect box = { x, 0, ui_text_line_width(opts[i]) + 32, height };
497
498 if( draw )
499 {
500 enum ui_button_state state = ui_button_base( box );
501 if( state == k_ui_button_click )
502 {
503 ui_fill( box, GUI_COL_DARK );
504 menu.main_index = i;
505 }
506 else if( state == k_ui_button_holding_inside )
507 {
508 ui_fill( box, GUI_COL_DARK );
509 }
510 else if( state == k_ui_button_holding_outside )
511 {
512 ui_fill( box, GUI_COL_DARK );
513 ui_outline( box, 1, GUI_COL_CLICK, 0 );
514 }
515 else if( state == k_ui_button_hover )
516 {
517 ui_fill( box, GUI_COL_NORM );
518 ui_outline( box, 1, GUI_COL_ACTIVE, 0 );
519 }
520 else
521 ui_fill( box, i==menu.main_index? GUI_COL_ACTIVE: GUI_COL_NORM );
522
523 ui_text( box, opts[i], 1, k_ui_align_middle_center, 0 );
524 }
525
526 x += box[2] + spacer;
527 }
528
529 if( vg_input.display_input_method == k_input_method_controller )
530 {
531 if( draw )
532 {
533 ui_rect inf_rb = { x, 0, 32, height };
534 ui_fill( inf_rb, rb_down? GUI_COL_NORM: GUI_COL_NORM );
535 ui_text( inf_rb, "\x92", 1, k_ui_align_middle_center, 0 );
536 }
537 x += 32;
538 }
539
540 if( draw )
541 ui_fill( (ui_rect){ x+8,0, vg.window_x-(x+8),height }, GUI_COL_NORM );
542 else
543 {
544 x = vg.window_x/2 - x/2;
545 ui_fill( (ui_rect){ 0, 0, x-8, height }, GUI_COL_NORM );
546 }
547 }
548
549 if( menu.main_index == k_menu_main_map )
550 {
551 menu.bg_blur = 0;
552 ui_font_face( &vgf_default_large );
553 ui_rect title = { vg.window_x/2 - 512/2, height+8, 512, 64 };
554
555 ui_px x = 8,
556 y = height+8;
557
558 struct ui_vert *vs =
559 ui_fill( (ui_rect){ x,y, 0,height },
560 world_static.active_instance? GUI_COL_DARK: GUI_COL_ACTIVE );
561
562 char buf[64];
563 vg_str str;
564 vg_strnull( &str, buf, sizeof(buf) );
565 vg_strcat( &str, "Hub World" );
566
567 if( world_static.active_instance )
568 {
569 vg_strcat( &str, " (" );
570 vg_input_string( &str, input_button_list[k_srbind_mhub], 1 );
571 vg_strcatch( &str, '\x06' );
572 vg_strcatch( &str, '\x00' );
573 vg_strcat( &str, "\x1B[0m)" );
574 }
575
576 ui_px w = ui_text( (ui_rect){ x+8, y, 1000, height }, buf, 1,
577 k_ui_align_middle_left, 0 );
578 w *= vg_ui.font->sx;
579 x += w + 16;
580
581 vs[1].co[0] = x + 8;
582 vs[2].co[0] = x;
583
584 x += 2;
585
586 world_instance *world = &world_static.instances[1];
587 if( world->status == k_world_status_loaded )
588 {
589 const char *world_name =
590 mdl_pstr( &world->meta, world->info.pstr_name );
591
592 vg_strnull( &str, buf, sizeof(buf) );
593 vg_strcat( &str, world_name );
594
595 if( !world_static.active_instance &&
596 (vg_input.display_input_method == k_input_method_controller) )
597 {
598 vg_strcat( &str, " (" );
599 vg_input_string( &str, input_button_list[k_srbind_mhub], 1 );
600 vg_strcatch( &str, '\x06' );
601 vg_strcatch( &str, '\x00' );
602 vg_strcat( &str, "\x1B[0m)" );
603 }
604
605 vs = ui_fill( (ui_rect){ x,y, 1000,height },
606 world_static.active_instance? GUI_COL_ACTIVE: GUI_COL_DARK );
607 w = ui_text( (ui_rect){ x+16,y, 1000,height }, buf,
608 1, k_ui_align_middle_left, 0 );
609
610 w = w*vg_ui.font->sx + 8*3;
611 x += w;
612
613 if( button_down( k_srbind_mhub ) ||
614 ui_button_base( (ui_rect){0,y,x,height} ) == k_ui_button_click )
615 {
616 world_switch_instance( world_static.active_instance ^ 0x1 );
617 skaterift.activity = k_skaterift_default;
618 world_map.view_ready = 0;
619 }
620
621 vs[0].co[0] += 8;
622 vs[1].co[0] = x + 8;
623 vs[2].co[0] = x;
624 }
625
626 x = 8;
627 y += 8 + height;
628
629 if( world_static.active_instance )
630 {
631 ui_rect stat_panel = { x,y, 256,vg.window_y-y };
632 u32 c0 = ui_opacity( GUI_COL_DARK, 0.36f );
633 struct ui_vert *vs = ui_fill( stat_panel, c0 );
634
635 ui_rect_pad( stat_panel, (ui_px[2]){8,0} );
636
637 for( u32 i=0; i<mdl_arrcount( &world->ent_region ); i ++ )
638 {
639 ent_region *region = mdl_arritm( &world->ent_region, i );
640
641 if( !region->zone_volume )
642 continue;
643
644 const char *title = mdl_pstr( &world->meta, region->pstr_title );
645 ui_font_face( &vgf_default_large );
646
647 ui_rect title_box;
648 menu_standard_widget( stat_panel, title_box, 1 );
649
650 stat_panel[0] += 16;
651 stat_panel[2] -= 16;
652 ui_font_face( &vgf_default_small );
653
654 ent_volume *volume = mdl_arritm(&world->ent_volume,
655 mdl_entity_id_id(region->zone_volume));
656
657 u32 combined = k_ent_route_flag_achieve_gold |
658 k_ent_route_flag_achieve_silver;
659
660 char buf[128];
661 vg_str str;
662
663 for( u32 j=0; j<mdl_arrcount(&world->ent_route); j ++ )
664 {
665 ent_route *route = mdl_arritm(&world->ent_route, j );
666
667 v3f local;
668 m4x3_mulv( volume->to_local, route->board_transform[3], local );
669 if( !((fabsf(local[0]) <= 1.0f) &&
670 (fabsf(local[1]) <= 1.0f) &&
671 (fabsf(local[2]) <= 1.0f)) )
672 {
673 continue;
674 }
675
676 combined &= route->flags;
677
678 vg_strnull( &str, buf, sizeof(buf) );
679 vg_strcat( &str, "(Race) " );
680 vg_strcat( &str, mdl_pstr(&world->meta, route->pstr_name));
681
682 if( route->flags & k_ent_route_flag_achieve_silver )
683 vg_strcat( &str, " \xb3");
684 if( route->flags & k_ent_route_flag_achieve_gold )
685 vg_strcat( &str, "\xb3");
686
687 ui_rect r;
688 ui_standard_widget( stat_panel, r, 1 );
689 ui_text( r, buf, 1, k_ui_align_middle_left,
690 medal_colour(route->flags) );
691 }
692
693 for( u32 j=0; j<mdl_arrcount(&world->ent_challenge); j ++ )
694 {
695 ent_challenge *challenge = mdl_arritm( &world->ent_challenge, j );
696
697 v3f local;
698 m4x3_mulv( volume->to_local, challenge->transform.co, local );
699 if( !((fabsf(local[0]) <= 1.0f) &&
700 (fabsf(local[1]) <= 1.0f) &&
701 (fabsf(local[2]) <= 1.0f)) )
702 {
703 continue;
704 }
705
706 vg_strnull( &str, buf, sizeof(buf) );
707 vg_strcat( &str, mdl_pstr(&world->meta, challenge->pstr_alias));
708
709 u32 flags = 0x00;
710 if( challenge->status )
711 {
712 flags |= k_ent_route_flag_achieve_gold;
713 flags |= k_ent_route_flag_achieve_silver;
714 vg_strcat( &str, " \xb3\xb3" );
715 }
716
717 combined &= flags;
718
719 ui_rect r;
720 ui_standard_widget( stat_panel, r, 1 );
721 ui_text( r, buf, 1, k_ui_align_middle_left, medal_colour(flags) );
722 }
723
724 stat_panel[0] -= 16;
725 stat_panel[2] += 16;
726
727 u32 title_col = 0;
728 if( combined & k_ent_route_flag_achieve_gold )
729 title_col = ui_colour( k_ui_yellow );
730 else if( combined & k_ent_route_flag_achieve_silver )
731 title_col = ui_colour( k_ui_fg );
732
733 menu_heading( title_box, title, title_col );
734 }
735
736 vs[2].co[1] = stat_panel[1];
737 vs[3].co[1] = stat_panel[1];
738 }
739 }
740 else
741 {
742 if( button_down( k_srbind_mback ) )
743 {
744 audio_lock();
745 audio_oneshot( &audio_ui[3], 1.0f, 0.0f );
746 audio_unlock();
747 skaterift.activity = k_skaterift_default;
748 return;
749 }
750
751 ui_rect list0 = { vg.window_x/2 - 512/2, height+32,
752 512, vg.window_y-height-64 }, list;
753 rect_copy( list0, list );
754 ui_rect_pad( list, (ui_px[2]){8,8} );
755
756 /* MAIN / MAIN
757 * -------------------------------------------------------------------*/
758
759 if( menu.main_index == k_menu_main_main )
760 {
761 i32 R = menu_nav( &menu.main_row, mv, 2 );
762
763 if( menu_button( list, R == 0, "Resume" ) )
764 {
765 skaterift.activity = k_skaterift_default;
766 return;
767 }
768
769 if( menu_button( list, R == 1, "Credits" ) )
770 {
771 menu.page = k_menu_page_credits;
772 }
773
774 ui_rect end = { list[0], list[1]+list[3]-64, list[2], 72 };
775 if( menu_button( end, R == 2, "Quit Game" ) )
776 {
777 vg.window_should_close = 1;
778 }
779 }
780 else if( menu.main_index == k_menu_main_settings )
781 {
782 ui_fill( list0, ui_opacity( GUI_COL_DARK, 0.36f ) );
783 ui_outline( list0, 1, GUI_COL_NORM, 0 );
784 i32 R = menu_nav( &menu.settings_row, mv, 8 );
785
786 ui_font_face( &vgf_default_large );
787 list[1] -= 8;
788 menu_heading( list, "Game", 0 );
789 menu_checkbox( list, R == 0, "Show controls overlay",
790 &control_overlay.enabled );
791 menu_checkbox( list, R == 1, "Auto connect to global server",
792 &network_client.auto_connect );
793
794 menu_heading( list, "Audio/Video", 0 );
795 menu_slider( list, R == 2, "Volume", 0, 100,
796 &vg_audio.external_global_volume, "%.f%%" );
797 menu_slider( list, R == 3, "Resolution", 0, 100,
798 &k_render_scale, "%.f%%" );
799 menu_checkbox( list, R == 4, "Motion Blur", &k_blur_effect );
800
801 menu_heading( list, "Camera", 0 );
802 menu_slider( list, R == 5, "Fov", 97, 135,
803 &k_fov, "%.1f\xb0" );
804 menu_slider( list, R == 6, "Cam Height", -0.4f, +1.4f,
805 &k_cam_height, vg_lerpf(-0.4f,1.4f,k_cam_height)>=0.0f?
806 "+%.2fm": "%.2fm" );
807 menu_checkbox( list, R == 7, "Invert Y Axis", &k_invert_y );
808
809
810 ui_rect end = { list[0], list[1]+list[3]-64, list[2], 72 };
811 ui_font_face( &vgf_default_small );
812 menu_heading( end, "Advanced", 0 );
813 if( menu_button( end, R == 8, "Open Engine Settings" ) )
814 {
815 vg_settings_open();
816 }
817 }
818 else if( menu.main_index == k_menu_main_guide )
819 {
820 list0[0] = 8;
821 list[0] = 16;
822
823 ui_fill( list0, ui_opacity( GUI_COL_DARK, 0.36f ) );
824 ui_outline( list0, 1, GUI_COL_NORM, 0 );
825 i32 R = menu_nav( &menu.guides_row, mv, 7 );
826
827 ui_font_face( &vgf_default_large );
828 list[1] -= 8;
829 menu_heading( list, "Info", 0 );
830 if( R == 0 ) menu_try_find_cam( 1 );
831 if( menu_button( list, R == 0, "Where to go" ) )
832 {
833 }
834
835 if( R == 1 ) menu_try_find_cam( 0 );
836 if( menu_button( list, R == 1, "Finding worlds" ) )
837 {
838 }
839
840 if( R == 2 ) menu_try_find_cam( 2 );
841 if( menu_button( list, R == 2, "Playing Online" ) )
842 {
843 }
844
845 menu_heading( list, "Controls", 0 );
846 if( R >= 3 ) menu_try_find_cam( 3 );
847 if( menu_button( list, R == 3, "Skating \xb2" ) )
848 {
849 }
850 if( menu_button( list, R == 4, "Tricks \xb2" ) )
851 {
852 }
853
854 menu_heading( list, "Workshop", 0 );
855 if( menu_button( list, R == 5, "Create a Board \xb2" ) )
856 {
857 }
858 if( menu_button( list, R == 6, "Create a World \xb2" ) )
859 {
860 }
861 if( menu_button( list, R == 7, "Create a Playermodel \xb2" ) )
862 {
863 }
864 }
865
866 }
867
868 menu_draw:
869
870 vg_ui.frosting = 0.015f;
871 ui_flush( k_ui_shader_colour, vg.window_x, vg.window_y );
872 vg_ui.frosting = 0.0f;
873
874 ui_font_face( &vgf_default_small );
875 }