1use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH};
2
3use crate::{
4 GlobalState,
5 hud::{
6 CRITICAL_HP_COLOR, HP_COLOR, LOW_HP_COLOR, MENU_BG, STAMINA_COLOR, TEXT_COLOR,
7 UI_HIGHLIGHT_0, UI_MAIN, UI_SUBTLE, img_ids::Imgs,
8 },
9 render::{
10 AaMode, BloomConfig, BloomFactor, BloomMode, CloudMode, FluidMode, LightingMode,
11 PresentMode, ReflectionMode, RenderMode, ShadowMapMode, ShadowMode, UpscaleMode,
12 },
13 session::settings_change::Graphics as GraphicsChange,
14 settings::{Fps, GraphicsSettings},
15 ui::{ImageSlider, ToggleButton, fonts::Fonts},
16 window::{FullScreenSettings, FullscreenMode},
17};
18use conrod_core::{
19 Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, color,
20 position::Relative,
21 widget::{self, Button, DropDownList, Rectangle, Scrollbar, Text},
22 widget_ids,
23};
24use core::convert::TryFrom;
25use i18n::Localization;
26
27use itertools::Itertools;
28use std::{iter::once, rc::Rc};
29use winit::monitor::VideoMode;
30
31widget_ids! {
32 struct Ids {
33 window,
34 window_r,
35 window_scrollbar,
36 reset_graphics_button,
37 minimal_graphics_button,
38 low_graphics_button,
39 medium_graphics_button,
40 high_graphics_button,
41 ultra_graphics_button,
42 fps_counter,
43 pipeline_recreation_text,
44 terrain_vd_slider,
45 terrain_vd_text,
46 terrain_vd_value,
47 entity_vd_slider,
48 entity_vd_text,
49 entity_vd_value,
50 ld_slider,
51 ld_text,
52 ld_value,
53 lod_detail_slider,
54 lod_detail_text,
55 lod_detail_value,
56 sprite_dist_slider,
57 sprite_dist_text,
58 sprite_dist_value,
59 figure_dist_slider,
60 figure_dist_text,
61 figure_dist_value,
62 max_fps_slider,
63 max_fps_text,
64 max_fps_value,
65 max_background_fps_slider,
66 max_background_fps_text,
67 max_background_fps_value,
68 present_mode_text,
69 present_mode_list,
70 fov_slider,
71 fov_text,
72 fov_value,
73 gamma_slider,
74 gamma_text,
75 gamma_value,
76 exposure_slider,
77 exposure_text,
78 exposure_value,
79 ambiance_slider,
80 ambiance_text,
81 ambiance_value,
82 aa_mode_text,
83 aa_mode_list,
84 bloom_intensity_text,
86 bloom_intensity_slider,
87 bloom_intensity_value,
88 point_glow_text,
89 point_glow_slider,
90 point_glow_value,
91 upscale_factor_text,
93 upscale_factor_list,
94 cloud_mode_text,
95 cloud_mode_list,
96 fluid_mode_text,
97 fluid_mode_list,
98 reflection_mode_text,
99 reflection_mode_list,
100 fullscreen_mode_text,
101 fullscreen_mode_list,
102 resolution,
104 resolution_label,
105 bit_depth,
106 bit_depth_label,
107 refresh_rate,
108 refresh_rate_label,
109 gpu_profiler_button,
111 gpu_profiler_label,
112 particles_button,
114 particles_label,
115 weapon_trails_button,
116 weapon_trails_label,
117 flashing_lights_button,
118 flashing_lights_label,
119 flashing_lights_info_label,
120 fullscreen_button,
122 fullscreen_label,
123 lighting_mode_text,
124 lighting_mode_list,
125 shadow_mode_text,
126 shadow_mode_list,
127 shadow_mode_map_resolution_text,
128 shadow_mode_map_resolution_slider,
129 shadow_mode_map_resolution_value,
130 rain_button,
131 rain_label,
132 rain_map_resolution_text,
133 rain_map_resolution_slider,
134 rain_map_resolution_value
135 }
136}
137
138#[derive(WidgetCommon)]
139pub struct Video<'a> {
140 global_state: &'a GlobalState,
141 imgs: &'a Imgs,
142 fonts: &'a Fonts,
143 localized_strings: &'a Localization,
144 server_view_distance_limit: Option<u32>,
145 fps: f32,
146 #[conrod(common_builder)]
147 common: widget::CommonBuilder,
148}
149impl<'a> Video<'a> {
150 pub fn new(
151 global_state: &'a GlobalState,
152 imgs: &'a Imgs,
153 fonts: &'a Fonts,
154 localized_strings: &'a Localization,
155 server_view_distance_limit: Option<u32>,
156 fps: f32,
157 ) -> Self {
158 Self {
159 global_state,
160 imgs,
161 fonts,
162 localized_strings,
163 server_view_distance_limit,
164 fps,
165 common: widget::CommonBuilder::default(),
166 }
167 }
168}
169
170pub struct State {
171 ids: Ids,
172 video_modes: Vec<VideoMode>,
174}
175const FPS_CHOICES: [Fps; 17] = [
176 Fps::Max(15),
177 Fps::Max(30),
178 Fps::Max(40),
179 Fps::Max(50),
180 Fps::Max(60),
181 Fps::Max(75),
182 Fps::Max(90),
183 Fps::Max(100),
184 Fps::Max(120),
185 Fps::Max(144),
186 Fps::Max(165),
187 Fps::Max(200),
188 Fps::Max(240),
189 Fps::Max(280),
190 Fps::Max(360),
191 Fps::Max(500),
192 Fps::Unlimited,
193];
194const BG_FPS_CHOICES: [Fps; 20] = [
195 Fps::Max(5),
196 Fps::Max(10),
197 Fps::Max(15),
198 Fps::Max(20),
199 Fps::Max(30),
200 Fps::Max(40),
201 Fps::Max(50),
202 Fps::Max(60),
203 Fps::Max(75),
204 Fps::Max(90),
205 Fps::Max(100),
206 Fps::Max(120),
207 Fps::Max(144),
208 Fps::Max(165),
209 Fps::Max(200),
210 Fps::Max(240),
211 Fps::Max(280),
212 Fps::Max(360),
213 Fps::Max(500),
214 Fps::Unlimited,
215];
216
217impl Widget for Video<'_> {
218 type Event = Vec<GraphicsChange>;
219 type State = State;
220 type Style = ();
221
222 fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
223 let video_modes = self
224 .global_state
225 .window
226 .window()
227 .current_monitor()
228 .map(|monitor| monitor.video_modes().collect())
229 .unwrap_or_default();
230
231 State {
232 ids: Ids::new(id_gen),
233 video_modes,
234 }
235 }
236
237 fn style(&self) -> Self::Style {}
238
239 fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
240 common_base::prof_span!("Video::update");
241 let widget::UpdateArgs { state, ui, .. } = args;
242
243 let mut events = Vec::new();
244
245 Rectangle::fill_with(args.rect.dim(), color::TRANSPARENT)
246 .xy(args.rect.xy())
247 .graphics_for(args.id)
248 .scroll_kids()
249 .scroll_kids_vertically()
250 .set(state.ids.window, ui);
251 Rectangle::fill_with([args.rect.w() / 2.0, args.rect.h()], color::TRANSPARENT)
252 .top_right()
253 .parent(state.ids.window)
254 .set(state.ids.window_r, ui);
255 Scrollbar::y_axis(state.ids.window)
256 .thickness(5.0)
257 .rgba(0.33, 0.33, 0.33, 1.0)
258 .set(state.ids.window_scrollbar, ui);
259
260 let fps_col = match self.fps as i32 {
263 0..=14 => CRITICAL_HP_COLOR,
264 15..=29 => LOW_HP_COLOR,
265 30..=50 => HP_COLOR,
266 _ => STAMINA_COLOR,
267 };
268 Text::new(&format!("FPS: {:.0}", self.fps))
269 .color(fps_col)
270 .top_right_with_margins_on(state.ids.window_r, 10.0, 10.0)
271 .font_id(self.fonts.cyri.conrod_id)
272 .font_size(self.fonts.cyri.scale(18))
273 .set(state.ids.fps_counter, ui);
274
275 if let Some((total, complete)) = self
277 .global_state
278 .window
279 .renderer()
280 .pipeline_recreation_status()
281 {
282 Text::new(&format!("Rebuilding pipelines: ({}/{})", complete, total))
283 .down_from(state.ids.fps_counter, 10.0)
284 .align_right_of(state.ids.fps_counter)
285 .font_size(self.fonts.cyri.scale(14))
286 .font_id(self.fonts.cyri.conrod_id)
287 .color(TEXT_COLOR)
289 .set(state.ids.pipeline_recreation_text, ui);
290 }
291
292 if Button::image(self.imgs.button)
294 .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT)
295 .hover_image(self.imgs.button_hover)
296 .press_image(self.imgs.button_press)
297 .top_left_with_margins_on(state.ids.window, 10.0, 10.0)
298 .label(
299 &self
300 .localized_strings
301 .get_msg("hud-settings-reset_graphics"),
302 )
303 .label_font_size(self.fonts.cyri.scale(14))
304 .label_color(TEXT_COLOR)
305 .label_font_id(self.fonts.cyri.conrod_id)
306 .label_y(Relative::Scalar(2.0))
307 .set(state.ids.reset_graphics_button, ui)
308 .was_clicked()
309 {
310 events.push(GraphicsChange::ResetGraphicsSettings);
311 }
312
313 let preset_buttons: [(_, _, fn(_) -> _); 5] = [
315 (
316 "hud-settings-minimal_graphics",
317 state.ids.minimal_graphics_button,
318 GraphicsSettings::into_minimal,
319 ),
320 (
321 "hud-settings-low_graphics",
322 state.ids.low_graphics_button,
323 GraphicsSettings::into_low,
324 ),
325 (
326 "hud-settings-medium_graphics",
327 state.ids.medium_graphics_button,
328 GraphicsSettings::into_medium,
329 ),
330 (
331 "hud-settings-high_graphics",
332 state.ids.high_graphics_button,
333 GraphicsSettings::into_high,
334 ),
335 (
336 "hud-settings-ultra_graphics",
337 state.ids.ultra_graphics_button,
338 GraphicsSettings::into_ultra,
339 ),
340 ];
341
342 let mut lhs = state.ids.reset_graphics_button;
343
344 for (msg, id, change_fn) in preset_buttons {
345 if Button::new()
346 .label(&self.localized_strings.get_msg(msg))
347 .w_h(80.0, 34.0)
348 .color(UI_SUBTLE)
349 .hover_color(UI_MAIN)
350 .press_color(UI_HIGHLIGHT_0)
351 .right_from(lhs, 12.0)
352 .label_font_size(self.fonts.cyri.scale(14))
353 .label_color(TEXT_COLOR)
354 .label_font_id(self.fonts.cyri.conrod_id)
355 .label_y(Relative::Scalar(2.0))
356 .set(id, ui)
357 .was_clicked()
358 {
359 events.push(GraphicsChange::ChangeGraphicsSettings(Rc::new(change_fn)));
360 }
361 lhs = id;
362 }
363
364 Text::new(&self.localized_strings.get_msg("hud-settings-view_distance"))
366 .down_from(state.ids.reset_graphics_button, 10.0)
367 .font_size(self.fonts.cyri.scale(14))
368 .font_id(self.fonts.cyri.conrod_id)
369 .color(TEXT_COLOR)
370 .set(state.ids.terrain_vd_text, ui);
371
372 let terrain_view_distance = self.global_state.settings.graphics.terrain_view_distance;
373 let server_view_distance_limit = self.server_view_distance_limit.unwrap_or(u32::MAX);
374 if let Some(new_val) = ImageSlider::discrete(
375 terrain_view_distance,
376 1,
377 client::MAX_SELECTABLE_VIEW_DISTANCE,
378 self.imgs.slider_indicator,
379 self.imgs.slider,
380 )
381 .w_h(104.0, 22.0)
382 .down_from(state.ids.terrain_vd_text, 8.0)
383 .track_breadth(12.0)
384 .slider_length(10.0)
385 .soft_max(server_view_distance_limit)
386 .pad_track((5.0, 5.0))
387 .set(state.ids.terrain_vd_slider, ui)
388 {
389 events.push(GraphicsChange::AdjustTerrainViewDistance(new_val));
390 }
391
392 Text::new(&if terrain_view_distance <= server_view_distance_limit {
393 format!("{terrain_view_distance}")
394 } else {
395 format!("{terrain_view_distance} ({server_view_distance_limit})")
396 })
397 .right_from(state.ids.terrain_vd_slider, 8.0)
398 .font_size(self.fonts.cyri.scale(14))
399 .font_id(self.fonts.cyri.conrod_id)
400 .color(TEXT_COLOR)
401 .set(state.ids.terrain_vd_value, ui);
402
403 let soft_entity_vd_max = self
405 .server_view_distance_limit
406 .unwrap_or(u32::MAX)
407 .min(terrain_view_distance);
408 let entity_view_distance = self.global_state.settings.graphics.entity_view_distance;
409 if let Some(new_val) = ImageSlider::discrete(
410 entity_view_distance,
411 1,
412 client::MAX_SELECTABLE_VIEW_DISTANCE,
413 self.imgs.slider_indicator,
414 self.imgs.slider,
415 )
416 .w_h(104.0, 22.0)
417 .right_from(state.ids.terrain_vd_slider, 70.0)
418 .track_breadth(12.0)
419 .slider_length(10.0)
420 .soft_max(soft_entity_vd_max)
421 .pad_track((5.0, 5.0))
422 .set(state.ids.entity_vd_slider, ui)
423 {
424 events.push(GraphicsChange::AdjustEntityViewDistance(new_val));
425 }
426
427 Text::new(
428 &self
429 .localized_strings
430 .get_msg("hud-settings-entity_view_distance"),
431 )
432 .up_from(state.ids.entity_vd_slider, 10.0)
433 .font_size(self.fonts.cyri.scale(14))
434 .font_id(self.fonts.cyri.conrod_id)
435 .color(TEXT_COLOR)
436 .set(state.ids.entity_vd_text, ui);
437
438 Text::new(&if entity_view_distance <= soft_entity_vd_max {
439 format!("{entity_view_distance}")
440 } else {
441 format!("{entity_view_distance} ({soft_entity_vd_max})")
442 })
443 .right_from(state.ids.entity_vd_slider, 8.0)
444 .font_size(self.fonts.cyri.scale(14))
445 .font_id(self.fonts.cyri.conrod_id)
446 .color(TEXT_COLOR)
447 .set(state.ids.entity_vd_value, ui);
448
449 if let Some(new_val) = ImageSlider::discrete(
451 self.global_state.settings.graphics.sprite_render_distance,
452 50,
453 500,
454 self.imgs.slider_indicator,
455 self.imgs.slider,
456 )
457 .w_h(104.0, 22.0)
458 .right_from(state.ids.entity_vd_slider, 70.0)
459 .track_breadth(12.0)
460 .slider_length(10.0)
461 .pad_track((5.0, 5.0))
462 .set(state.ids.sprite_dist_slider, ui)
463 {
464 events.push(GraphicsChange::AdjustSpriteRenderDistance(new_val));
465 }
466 Text::new(
467 &self
468 .localized_strings
469 .get_msg("hud-settings-sprites_view_distance"),
470 )
471 .up_from(state.ids.sprite_dist_slider, 10.0)
472 .font_size(self.fonts.cyri.scale(14))
473 .font_id(self.fonts.cyri.conrod_id)
474 .color(TEXT_COLOR)
475 .set(state.ids.sprite_dist_text, ui);
476
477 Text::new(&format!(
478 "{}",
479 self.global_state.settings.graphics.sprite_render_distance
480 ))
481 .right_from(state.ids.sprite_dist_slider, 8.0)
482 .font_size(self.fonts.cyri.scale(14))
483 .font_id(self.fonts.cyri.conrod_id)
484 .color(TEXT_COLOR)
485 .set(state.ids.sprite_dist_value, ui);
486
487 Text::new(&self.localized_strings.get_msg("hud-settings-lod_distance"))
489 .down_from(state.ids.terrain_vd_slider, 10.0)
490 .font_size(self.fonts.cyri.scale(14))
491 .font_id(self.fonts.cyri.conrod_id)
492 .color(TEXT_COLOR)
493 .set(state.ids.ld_text, ui);
494
495 if let Some(new_val) = ImageSlider::discrete(
496 self.global_state.settings.graphics.lod_distance,
497 0,
498 500,
499 self.imgs.slider_indicator,
500 self.imgs.slider,
501 )
502 .w_h(104.0, 22.0)
503 .down_from(state.ids.ld_text, 8.0)
504 .track_breadth(12.0)
505 .slider_length(10.0)
506 .pad_track((5.0, 5.0))
507 .set(state.ids.ld_slider, ui)
508 {
509 events.push(GraphicsChange::AdjustLodDistance(new_val));
510 }
511
512 Text::new(&format!(
513 "{}",
514 self.global_state.settings.graphics.lod_distance
515 ))
516 .right_from(state.ids.ld_slider, 8.0)
517 .font_size(self.fonts.cyri.scale(14))
518 .font_id(self.fonts.cyri.conrod_id)
519 .color(TEXT_COLOR)
520 .set(state.ids.ld_value, ui);
521
522 if let Some(new_val) = ImageSlider::discrete(
524 self.global_state
525 .settings
526 .graphics
527 .figure_lod_render_distance,
528 50,
529 500,
530 self.imgs.slider_indicator,
531 self.imgs.slider,
532 )
533 .w_h(104.0, 22.0)
534 .right_from(state.ids.ld_slider, 70.0)
535 .track_breadth(12.0)
536 .slider_length(10.0)
537 .pad_track((5.0, 5.0))
538 .set(state.ids.figure_dist_slider, ui)
539 {
540 events.push(GraphicsChange::AdjustFigureLoDRenderDistance(new_val));
541 }
542 Text::new(
543 &self
544 .localized_strings
545 .get_msg("hud-settings-entities_detail_distance"),
546 )
547 .up_from(state.ids.figure_dist_slider, 8.0)
548 .font_size(self.fonts.cyri.scale(14))
549 .font_id(self.fonts.cyri.conrod_id)
550 .color(TEXT_COLOR)
551 .set(state.ids.figure_dist_text, ui);
552
553 Text::new(&format!(
554 "{}",
555 self.global_state
556 .settings
557 .graphics
558 .figure_lod_render_distance
559 ))
560 .right_from(state.ids.figure_dist_slider, 8.0)
561 .font_size(self.fonts.cyri.scale(14))
562 .font_id(self.fonts.cyri.conrod_id)
563 .color(TEXT_COLOR)
564 .set(state.ids.figure_dist_value, ui);
565
566 Text::new(&self.localized_strings.get_msg("hud-settings-maximum_fps"))
568 .down_from(state.ids.ld_slider, 10.0)
569 .font_size(self.fonts.cyri.scale(14))
570 .font_id(self.fonts.cyri.conrod_id)
571 .color(TEXT_COLOR)
572 .set(state.ids.max_fps_text, ui);
573
574 if let Some(which) = ImageSlider::discrete(
575 FPS_CHOICES
576 .iter()
577 .position(|&x| x == self.global_state.settings.graphics.max_fps)
578 .unwrap_or(5),
579 0,
580 FPS_CHOICES.len() - 1,
581 self.imgs.slider_indicator,
582 self.imgs.slider,
583 )
584 .w_h(104.0, 22.0)
585 .down_from(state.ids.max_fps_text, 8.0)
586 .track_breadth(12.0)
587 .slider_length(10.0)
588 .pad_track((5.0, 5.0))
589 .set(state.ids.max_fps_slider, ui)
590 {
591 events.push(GraphicsChange::ChangeMaxFPS(FPS_CHOICES[which]));
592 }
593
594 Text::new(&self.global_state.settings.graphics.max_fps.to_string())
595 .right_from(state.ids.max_fps_slider, 8.0)
596 .font_size(self.fonts.cyri.scale(14))
597 .font_id(self.fonts.cyri.conrod_id)
598 .color(TEXT_COLOR)
599 .set(state.ids.max_fps_value, ui);
600
601 Text::new(
603 &self
604 .localized_strings
605 .get_msg("hud-settings-background_fps"),
606 )
607 .down_from(state.ids.ld_slider, 10.0)
608 .right_from(state.ids.max_fps_value, 44.0)
609 .font_size(self.fonts.cyri.scale(14))
610 .font_id(self.fonts.cyri.conrod_id)
611 .color(TEXT_COLOR)
612 .set(state.ids.max_background_fps_text, ui);
613
614 if let Some(which) = ImageSlider::discrete(
615 BG_FPS_CHOICES
616 .iter()
617 .position(|&x| x == self.global_state.settings.graphics.max_background_fps)
618 .unwrap_or(5),
619 0,
620 BG_FPS_CHOICES.len() - 1,
621 self.imgs.slider_indicator,
622 self.imgs.slider,
623 )
624 .w_h(104.0, 22.0)
625 .down_from(state.ids.max_background_fps_text, 8.0)
626 .track_breadth(12.0)
627 .slider_length(10.0)
628 .pad_track((5.0, 5.0))
629 .set(state.ids.max_background_fps_slider, ui)
630 {
631 events.push(GraphicsChange::ChangeMaxBackgroundFPS(
632 BG_FPS_CHOICES[which],
633 ));
634 }
635
636 Text::new(
637 &self
638 .global_state
639 .settings
640 .graphics
641 .max_background_fps
642 .to_string(),
643 )
644 .right_from(state.ids.max_background_fps_slider, 8.0)
645 .font_size(self.fonts.cyri.scale(14))
646 .font_id(self.fonts.cyri.conrod_id)
647 .color(TEXT_COLOR)
648 .set(state.ids.max_background_fps_value, ui);
649
650 let render_mode = &self.global_state.settings.graphics.render_mode;
652
653 Text::new(&self.localized_strings.get_msg("hud-settings-present_mode"))
655 .down_from(state.ids.ld_slider, 10.0)
656 .right_from(state.ids.max_background_fps_value, 40.0)
657 .font_size(self.fonts.cyri.scale(14))
658 .font_id(self.fonts.cyri.conrod_id)
659 .color(TEXT_COLOR)
660 .set(state.ids.present_mode_text, ui);
661
662 let mode_list = self.global_state.window.renderer().present_modes();
663 let mode_label_list = mode_list
664 .iter()
665 .map(|mode| {
666 self.localized_strings.get_msg(match mode {
667 PresentMode::Fifo => "hud-settings-present_mode-vsync_capped",
668 PresentMode::FifoRelaxed => "hud-settings-present_mode-vsync_adaptive",
669 PresentMode::Mailbox => "hud-settings-present_mode-vsync_uncapped",
670 PresentMode::Immediate => "hud-settings-present_mode-vsync_off",
671 })
672 })
673 .collect::<Vec<_>>();
674
675 let selected = mode_list
677 .iter()
678 .position(|x| *x == render_mode.present_mode);
679
680 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
681 .w_h(150.0, 26.0)
682 .color(MENU_BG)
683 .label_color(TEXT_COLOR)
684 .label_font_id(self.fonts.cyri.conrod_id)
685 .down_from(state.ids.present_mode_text, 8.0)
686 .align_middle_x()
687 .set(state.ids.present_mode_list, ui)
688 {
689 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
690 present_mode: mode_list[clicked],
691 ..render_mode.clone()
692 })));
693 }
694
695 Text::new(&self.localized_strings.get_msg("hud-settings-fov"))
697 .down_from(state.ids.max_fps_slider, 10.0)
698 .font_size(self.fonts.cyri.scale(14))
699 .font_id(self.fonts.cyri.conrod_id)
700 .color(TEXT_COLOR)
701 .set(state.ids.fov_text, ui);
702
703 if let Some(new_val) = ImageSlider::discrete(
704 self.global_state.settings.graphics.fov,
705 30,
706 120,
707 self.imgs.slider_indicator,
708 self.imgs.slider,
709 )
710 .w_h(104.0, 22.0)
711 .down_from(state.ids.fov_text, 8.0)
712 .track_breadth(12.0)
713 .slider_length(10.0)
714 .pad_track((5.0, 5.0))
715 .set(state.ids.fov_slider, ui)
716 {
717 events.push(GraphicsChange::ChangeFOV(new_val));
718 }
719
720 Text::new(&format!("{}", self.global_state.settings.graphics.fov))
721 .right_from(state.ids.fov_slider, 8.0)
722 .font_size(self.fonts.cyri.scale(14))
723 .font_id(self.fonts.cyri.conrod_id)
724 .color(TEXT_COLOR)
725 .set(state.ids.fov_value, ui);
726
727 Text::new(&self.localized_strings.get_msg("hud-settings-lod_detail"))
729 .down_from(state.ids.fov_slider, 10.0)
730 .font_size(self.fonts.cyri.scale(14))
731 .font_id(self.fonts.cyri.conrod_id)
732 .color(TEXT_COLOR)
733 .set(state.ids.lod_detail_text, ui);
734
735 if let Some(new_val) = ImageSlider::discrete(
736 ((self.global_state.settings.graphics.lod_detail as f32 / 100.0).log(5.0) * 10.0)
737 .round() as i32,
738 0,
739 20,
740 self.imgs.slider_indicator,
741 self.imgs.slider,
742 )
743 .w_h(104.0, 22.0)
744 .down_from(state.ids.lod_detail_text, 8.0)
745 .track_breadth(12.0)
746 .slider_length(10.0)
747 .pad_track((5.0, 5.0))
748 .set(state.ids.lod_detail_slider, ui)
749 {
750 events.push(GraphicsChange::AdjustLodDetail(
751 (5.0f32.powf(new_val as f32 / 10.0) * 100.0) as u32,
752 ));
753 }
754
755 Text::new(&format!(
756 "{}",
757 self.global_state.settings.graphics.lod_detail
758 ))
759 .right_from(state.ids.lod_detail_slider, 8.0)
760 .font_size(self.fonts.cyri.scale(14))
761 .font_id(self.fonts.cyri.conrod_id)
762 .color(TEXT_COLOR)
763 .set(state.ids.lod_detail_value, ui);
764
765 Text::new(&self.localized_strings.get_msg("hud-settings-gamma"))
767 .down_from(state.ids.lod_detail_slider, 10.0)
768 .font_size(self.fonts.cyri.scale(14))
769 .font_id(self.fonts.cyri.conrod_id)
770 .color(TEXT_COLOR)
771 .set(state.ids.gamma_text, ui);
772
773 if let Some(new_val) = ImageSlider::discrete(
774 (self.global_state.settings.graphics.gamma.log2() * 8.0).round() as i32,
775 8,
776 -8,
777 self.imgs.slider_indicator,
778 self.imgs.slider,
779 )
780 .w_h(104.0, 22.0)
781 .down_from(state.ids.gamma_text, 8.0)
782 .track_breadth(12.0)
783 .slider_length(10.0)
784 .pad_track((5.0, 5.0))
785 .set(state.ids.gamma_slider, ui)
786 {
787 events.push(GraphicsChange::ChangeGamma(
788 2.0f32.powf(new_val as f32 / 8.0),
789 ));
790 }
791
792 Text::new(&format!("{:.2}", self.global_state.settings.graphics.gamma))
793 .right_from(state.ids.gamma_slider, 8.0)
794 .font_size(self.fonts.cyri.scale(14))
795 .font_id(self.fonts.cyri.conrod_id)
796 .color(TEXT_COLOR)
797 .set(state.ids.gamma_value, ui);
798
799 if let Some(new_val) = ImageSlider::discrete(
801 (self.global_state.settings.graphics.exposure * 16.0) as i32,
802 0,
803 32,
804 self.imgs.slider_indicator,
805 self.imgs.slider,
806 )
807 .w_h(104.0, 22.0)
808 .right_from(state.ids.gamma_slider, 50.0)
809 .track_breadth(12.0)
810 .slider_length(10.0)
811 .pad_track((5.0, 5.0))
812 .set(state.ids.exposure_slider, ui)
813 {
814 events.push(GraphicsChange::ChangeExposure(new_val as f32 / 16.0));
815 }
816
817 Text::new(&self.localized_strings.get_msg("hud-settings-exposure"))
818 .up_from(state.ids.exposure_slider, 8.0)
819 .font_size(self.fonts.cyri.scale(14))
820 .font_id(self.fonts.cyri.conrod_id)
821 .color(TEXT_COLOR)
822 .set(state.ids.exposure_text, ui);
823
824 Text::new(&format!(
825 "{:.2}",
826 self.global_state.settings.graphics.exposure
827 ))
828 .right_from(state.ids.exposure_slider, 8.0)
829 .font_size(self.fonts.cyri.scale(14))
830 .font_id(self.fonts.cyri.conrod_id)
831 .color(TEXT_COLOR)
832 .set(state.ids.exposure_value, ui);
833
834 if let Some(new_val) = ImageSlider::discrete(
836 (self.global_state.settings.graphics.ambiance * 100.0).round() as i32,
837 0,
838 100,
839 self.imgs.slider_indicator,
840 self.imgs.slider,
841 )
842 .w_h(104.0, 22.0)
843 .right_from(state.ids.exposure_slider, 50.0)
844 .track_breadth(12.0)
845 .slider_length(10.0)
846 .pad_track((5.0, 5.0))
847 .set(state.ids.ambiance_slider, ui)
848 {
849 events.push(GraphicsChange::ChangeAmbiance(new_val as f32 / 100.0));
850 }
851 Text::new(&self.localized_strings.get_msg("hud-settings-ambiance"))
852 .up_from(state.ids.ambiance_slider, 8.0)
853 .font_size(self.fonts.cyri.scale(14))
854 .font_id(self.fonts.cyri.conrod_id)
855 .color(TEXT_COLOR)
856 .set(state.ids.ambiance_text, ui);
857 Text::new(&format!(
858 "{:.0}%",
859 (self.global_state.settings.graphics.ambiance * 100.0).round()
860 ))
861 .right_from(state.ids.ambiance_slider, 8.0)
862 .font_size(self.fonts.cyri.scale(14))
863 .font_id(self.fonts.cyri.conrod_id)
864 .color(TEXT_COLOR)
865 .set(state.ids.ambiance_value, ui);
866
867 Text::new(
869 &self
870 .localized_strings
871 .get_msg("hud-settings-antialiasing_mode"),
872 )
873 .down_from(state.ids.gamma_slider, 8.0)
874 .font_size(self.fonts.cyri.scale(14))
875 .font_id(self.fonts.cyri.conrod_id)
876 .color(TEXT_COLOR)
877 .set(state.ids.aa_mode_text, ui);
878
879 let mode_list = [
882 AaMode::None,
883 AaMode::Bilinear,
884 AaMode::Fxaa,
885 AaMode::FxUpscale,
889 AaMode::Hqx,
890 ];
891 let mode_label_list = [
892 "None",
893 "Bilinear",
894 "FXAA",
895 "FXUpscale",
899 "HQX",
900 ];
901
902 let selected = mode_list.iter().position(|x| *x == render_mode.aa);
904
905 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
906 .w_h(400.0, 22.0)
907 .color(MENU_BG)
908 .label_color(TEXT_COLOR)
909 .label_font_id(self.fonts.cyri.conrod_id)
910 .down_from(state.ids.aa_mode_text, 8.0)
911 .set(state.ids.aa_mode_list, ui)
912 {
913 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
914 aa: mode_list[clicked],
915 ..render_mode.clone()
916 })));
917 }
918
919 let bloom_intensity = match render_mode.bloom {
921 BloomMode::Off => 0.0,
922 BloomMode::On(bloom) => bloom.factor.fraction(),
923 };
924 let max_bloom = 0.3;
925
926 Text::new(&self.localized_strings.get_msg("hud-settings-bloom"))
927 .font_size(self.fonts.cyri.scale(14))
928 .font_id(self.fonts.cyri.conrod_id)
929 .down_from(state.ids.aa_mode_list, 10.0)
930 .color(TEXT_COLOR)
931 .set(state.ids.bloom_intensity_text, ui);
932 if let Some(new_val) = ImageSlider::continuous(
933 bloom_intensity,
934 0.0,
935 max_bloom,
936 self.imgs.slider_indicator,
937 self.imgs.slider,
938 )
939 .w_h(104.0, 22.0)
940 .down_from(state.ids.bloom_intensity_text, 8.0)
941 .track_breadth(12.0)
942 .slider_length(10.0)
943 .pad_track((5.0, 5.0))
944 .set(state.ids.bloom_intensity_slider, ui)
945 {
946 if new_val > f32::EPSILON {
947 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
949 bloom: {
950 BloomMode::On(BloomConfig {
951 factor: BloomFactor::Custom(new_val),
952 uniform_blur: false,
954 })
955 },
956 ..render_mode.clone()
957 })))
958 } else {
959 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
961 bloom: { BloomMode::Off },
962 ..render_mode.clone()
963 })))
964 }
965 }
966 Text::new(&if bloom_intensity <= f32::EPSILON {
967 "Off".to_string()
968 } else {
969 format!("{}%", (bloom_intensity * 100.0 / max_bloom) as i32)
970 })
971 .right_from(state.ids.bloom_intensity_slider, 8.0)
972 .font_size(self.fonts.cyri.scale(14))
973 .font_id(self.fonts.cyri.conrod_id)
974 .color(TEXT_COLOR)
975 .set(state.ids.bloom_intensity_value, ui);
976
977 Text::new(&self.localized_strings.get_msg("hud-settings-point_glow"))
979 .font_size(self.fonts.cyri.scale(14))
980 .font_id(self.fonts.cyri.conrod_id)
981 .down_from(state.ids.aa_mode_list, 10.0)
982 .right_from(state.ids.bloom_intensity_value, 10.0)
983 .color(TEXT_COLOR)
984 .set(state.ids.point_glow_text, ui);
985 if let Some(new_val) = ImageSlider::continuous(
986 render_mode.point_glow,
987 0.0,
988 1.0,
989 self.imgs.slider_indicator,
990 self.imgs.slider,
991 )
992 .w_h(104.0, 22.0)
993 .down_from(state.ids.point_glow_text, 8.0)
994 .track_breadth(12.0)
995 .slider_length(10.0)
996 .pad_track((5.0, 5.0))
997 .set(state.ids.point_glow_slider, ui)
998 {
999 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1001 point_glow: new_val,
1002 ..render_mode.clone()
1003 })));
1004 }
1005 Text::new(&if render_mode.point_glow <= f32::EPSILON {
1006 "Off".to_string()
1007 } else {
1008 format!("{}%", (render_mode.point_glow * 100.0) as i32)
1009 })
1010 .right_from(state.ids.point_glow_slider, 8.0)
1011 .font_size(self.fonts.cyri.scale(14))
1012 .font_id(self.fonts.cyri.conrod_id)
1013 .color(TEXT_COLOR)
1014 .set(state.ids.point_glow_value, ui);
1015
1016 Text::new(
1018 &self
1019 .localized_strings
1020 .get_msg("hud-settings-upscale_factor"),
1021 )
1022 .down_from(state.ids.bloom_intensity_slider, 8.0)
1023 .font_size(self.fonts.cyri.scale(14))
1024 .font_id(self.fonts.cyri.conrod_id)
1025 .color(TEXT_COLOR)
1026 .set(state.ids.upscale_factor_text, ui);
1027
1028 let upscale_factors = [
1029 0.1, 0.15, 0.2, 0.25, 0.35, 0.5, 0.65, 0.75, 0.85, 1.0,
1031 1.25, 1.5, 1.75, 2.0,
1033 ];
1034
1035 let selected = upscale_factors
1037 .iter()
1038 .position(|factor| (*factor - render_mode.upscale_mode.factor).abs() < 0.001);
1039
1040 if let Some(clicked) = DropDownList::new(
1041 &upscale_factors
1042 .iter()
1043 .map(|factor| format!("{n:.*}", 3, n = factor))
1044 .collect::<Vec<String>>(),
1045 selected,
1046 )
1047 .w_h(400.0, 22.0)
1048 .color(MENU_BG)
1049 .label_color(TEXT_COLOR)
1050 .label_font_id(self.fonts.cyri.conrod_id)
1051 .down_from(state.ids.upscale_factor_text, 8.0)
1052 .set(state.ids.upscale_factor_list, ui)
1053 {
1054 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1055 upscale_mode: UpscaleMode {
1056 factor: upscale_factors[clicked],
1057 },
1058 ..render_mode.clone()
1059 })));
1060 }
1061
1062 Text::new(
1064 &self
1065 .localized_strings
1066 .get_msg("hud-settings-cloud_rendering_mode"),
1067 )
1068 .down_from(state.ids.upscale_factor_list, 8.0)
1069 .font_size(self.fonts.cyri.scale(14))
1070 .font_id(self.fonts.cyri.conrod_id)
1071 .color(TEXT_COLOR)
1072 .set(state.ids.cloud_mode_text, ui);
1073
1074 let mode_list = [
1075 CloudMode::None,
1076 CloudMode::Minimal,
1077 CloudMode::Low,
1078 CloudMode::Medium,
1079 CloudMode::High,
1080 CloudMode::Ultra,
1081 ];
1082 let mode_label_list = [
1083 self.localized_strings.get_msg("common-none"),
1084 self.localized_strings
1085 .get_msg("hud-settings-cloud_rendering_mode-minimal"),
1086 self.localized_strings
1087 .get_msg("hud-settings-cloud_rendering_mode-low"),
1088 self.localized_strings
1089 .get_msg("hud-settings-cloud_rendering_mode-medium"),
1090 self.localized_strings
1091 .get_msg("hud-settings-cloud_rendering_mode-high"),
1092 self.localized_strings
1093 .get_msg("hud-settings-cloud_rendering_mode-ultra"),
1094 ];
1095
1096 let selected = mode_list.iter().position(|x| *x == render_mode.cloud);
1098
1099 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
1100 .w_h(400.0, 22.0)
1101 .color(MENU_BG)
1102 .label_color(TEXT_COLOR)
1103 .label_font_id(self.fonts.cyri.conrod_id)
1104 .down_from(state.ids.cloud_mode_text, 8.0)
1105 .set(state.ids.cloud_mode_list, ui)
1106 {
1107 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1108 cloud: mode_list[clicked],
1109 ..render_mode.clone()
1110 })));
1111 }
1112
1113 Text::new(
1115 &self
1116 .localized_strings
1117 .get_msg("hud-settings-fluid_rendering_mode"),
1118 )
1119 .down_from(state.ids.cloud_mode_list, 8.0)
1120 .font_size(self.fonts.cyri.scale(14))
1121 .font_id(self.fonts.cyri.conrod_id)
1122 .color(TEXT_COLOR)
1123 .set(state.ids.fluid_mode_text, ui);
1124
1125 let mode_list = [FluidMode::Low, FluidMode::Medium, FluidMode::High];
1126 let mode_label_list = [
1127 self.localized_strings
1128 .get_msg("hud-settings-fluid_rendering_mode-low"),
1129 self.localized_strings
1130 .get_msg("hud-settings-fluid_rendering_mode-medium"),
1131 self.localized_strings
1132 .get_msg("hud-settings-fluid_rendering_mode-high"),
1133 ];
1134
1135 let selected = mode_list.iter().position(|x| *x == render_mode.fluid);
1137
1138 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
1139 .w_h(400.0, 22.0)
1140 .color(MENU_BG)
1141 .label_color(TEXT_COLOR)
1142 .label_font_id(self.fonts.cyri.conrod_id)
1143 .down_from(state.ids.fluid_mode_text, 8.0)
1144 .set(state.ids.fluid_mode_list, ui)
1145 {
1146 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1147 fluid: mode_list[clicked],
1148 ..render_mode.clone()
1149 })));
1150 }
1151
1152 Text::new(
1154 &self
1155 .localized_strings
1156 .get_msg("hud-settings-reflection_rendering_mode"),
1157 )
1158 .down_from(state.ids.fluid_mode_list, 8.0)
1159 .font_size(self.fonts.cyri.scale(14))
1160 .font_id(self.fonts.cyri.conrod_id)
1161 .color(TEXT_COLOR)
1162 .set(state.ids.reflection_mode_text, ui);
1163
1164 let mode_list = [
1165 ReflectionMode::Low,
1166 ReflectionMode::Medium,
1167 ReflectionMode::High,
1168 ];
1169 let mode_label_list = [
1170 self.localized_strings
1171 .get_msg("hud-settings-reflection_rendering_mode-low"),
1172 self.localized_strings
1173 .get_msg("hud-settings-reflection_rendering_mode-medium"),
1174 self.localized_strings
1175 .get_msg("hud-settings-reflection_rendering_mode-high"),
1176 ];
1177
1178 let selected = mode_list.iter().position(|x| *x == render_mode.reflection);
1180
1181 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
1182 .w_h(400.0, 22.0)
1183 .color(MENU_BG)
1184 .label_color(TEXT_COLOR)
1185 .label_font_id(self.fonts.cyri.conrod_id)
1186 .down_from(state.ids.reflection_mode_text, 8.0)
1187 .set(state.ids.reflection_mode_list, ui)
1188 {
1189 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1190 reflection: mode_list[clicked],
1191 ..render_mode.clone()
1192 })));
1193 }
1194
1195 Text::new(
1197 &self
1198 .localized_strings
1199 .get_msg("hud-settings-lighting_rendering_mode"),
1200 )
1201 .down_from(state.ids.reflection_mode_list, 8.0)
1202 .font_size(self.fonts.cyri.scale(14))
1203 .font_id(self.fonts.cyri.conrod_id)
1204 .color(TEXT_COLOR)
1205 .set(state.ids.lighting_mode_text, ui);
1206
1207 let mode_list = [
1208 LightingMode::Ashikhmin,
1209 LightingMode::BlinnPhong,
1210 LightingMode::Lambertian,
1211 ];
1212 let mode_label_list = [
1213 self.localized_strings
1214 .get_msg("hud-settings-lighting_rendering_mode-ashikhmin"),
1215 self.localized_strings
1216 .get_msg("hud-settings-lighting_rendering_mode-blinnphong"),
1217 self.localized_strings
1218 .get_msg("hud-settings-lighting_rendering_mode-lambertian"),
1219 ];
1220
1221 let selected = mode_list.iter().position(|x| *x == render_mode.lighting);
1223
1224 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
1225 .w_h(400.0, 22.0)
1226 .color(MENU_BG)
1227 .label_color(TEXT_COLOR)
1228 .label_font_id(self.fonts.cyri.conrod_id)
1229 .down_from(state.ids.lighting_mode_text, 8.0)
1230 .set(state.ids.lighting_mode_list, ui)
1231 {
1232 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1233 lighting: mode_list[clicked],
1234 ..render_mode.clone()
1235 })));
1236 }
1237
1238 Text::new(
1240 &self
1241 .localized_strings
1242 .get_msg("hud-settings-shadow_rendering_mode"),
1243 )
1244 .down_from(state.ids.lighting_mode_list, 8.0)
1245 .font_size(self.fonts.cyri.scale(14))
1246 .font_id(self.fonts.cyri.conrod_id)
1247 .color(TEXT_COLOR)
1248 .set(state.ids.shadow_mode_text, ui);
1249
1250 let shadow_map_mode = ShadowMapMode::try_from(render_mode.shadow).ok();
1251 let mode_list = [
1252 ShadowMode::None,
1253 ShadowMode::Cheap,
1254 ShadowMode::Map(shadow_map_mode.unwrap_or_default()),
1255 ];
1256 let mode_label_list = [
1257 self.localized_strings
1258 .get_msg("hud-settings-shadow_rendering_mode-none"),
1259 self.localized_strings
1260 .get_msg("hud-settings-shadow_rendering_mode-cheap"),
1261 self.localized_strings
1262 .get_msg("hud-settings-shadow_rendering_mode-map"),
1263 ];
1264
1265 let selected = mode_list.iter().position(|x| *x == render_mode.shadow);
1267
1268 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
1269 .w_h(400.0, 22.0)
1270 .color(MENU_BG)
1271 .label_color(TEXT_COLOR)
1272 .label_font_id(self.fonts.cyri.conrod_id)
1273 .down_from(state.ids.shadow_mode_text, 8.0)
1274 .set(state.ids.shadow_mode_list, ui)
1275 {
1276 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1277 shadow: mode_list[clicked],
1278 ..render_mode.clone()
1279 })));
1280 }
1281
1282 if let Some(shadow_map_mode) = shadow_map_mode {
1283 Text::new(
1285 &self
1286 .localized_strings
1287 .get_msg("hud-settings-shadow_rendering_mode-map-resolution"),
1288 )
1289 .right_from(state.ids.shadow_mode_list, 10.0)
1290 .font_size(self.fonts.cyri.scale(14))
1291 .font_id(self.fonts.cyri.conrod_id)
1292 .color(TEXT_COLOR)
1293 .set(state.ids.shadow_mode_map_resolution_text, ui);
1294
1295 if let Some(new_val) = ImageSlider::discrete(
1296 (shadow_map_mode.resolution.log2() * 4.0).round() as i8,
1297 -8,
1298 8,
1299 self.imgs.slider_indicator,
1300 self.imgs.slider,
1301 )
1302 .w_h(104.0, 22.0)
1303 .right_from(state.ids.shadow_mode_map_resolution_text, 8.0)
1304 .track_breadth(12.0)
1305 .slider_length(10.0)
1306 .pad_track((5.0, 5.0))
1307 .set(state.ids.shadow_mode_map_resolution_slider, ui)
1308 {
1309 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1310 shadow: ShadowMode::Map(ShadowMapMode {
1311 resolution: 2.0f32.powf(f32::from(new_val) / 4.0),
1312 }),
1313 ..render_mode.clone()
1314 })));
1315 }
1316
1317 Text::new(&format!("{}", shadow_map_mode.resolution))
1320 .right_from(state.ids.shadow_mode_map_resolution_slider, 8.0)
1321 .font_size(self.fonts.cyri.scale(14))
1322 .font_id(self.fonts.cyri.conrod_id)
1323 .color(TEXT_COLOR)
1324 .set(state.ids.shadow_mode_map_resolution_value, ui);
1325 }
1326
1327 Text::new(&self.localized_strings.get_msg("hud-settings-rain"))
1329 .font_size(self.fonts.cyri.scale(14))
1330 .font_id(self.fonts.cyri.conrod_id)
1331 .down_from(state.ids.shadow_mode_list, 10.0)
1332 .color(TEXT_COLOR)
1333 .set(state.ids.rain_label, ui);
1334
1335 let rain_enabled = ToggleButton::new(
1336 self.global_state.settings.graphics.render_mode.rain_enabled,
1337 self.imgs.checkbox,
1338 self.imgs.checkbox_checked,
1339 )
1340 .w_h(18.0, 18.0)
1341 .right_from(state.ids.rain_label, 10.0)
1342 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1343 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1344 .set(state.ids.rain_button, ui);
1345
1346 if self.global_state.settings.graphics.render_mode.rain_enabled != rain_enabled {
1347 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1348 rain_enabled,
1349 ..render_mode.clone()
1350 })));
1351 }
1352
1353 Text::new(
1356 &self
1357 .localized_strings
1358 .get_msg("hud-settings-rain_occlusion-resolution"),
1359 )
1360 .right_from(state.ids.rain_button, 64.0)
1361 .font_size(self.fonts.cyri.scale(14))
1362 .font_id(self.fonts.cyri.conrod_id)
1363 .color(TEXT_COLOR)
1364 .set(state.ids.rain_map_resolution_text, ui);
1365
1366 if let Some(new_val) = ImageSlider::discrete(
1367 (render_mode.rain_occlusion.resolution.log2() * 4.0).round() as i8,
1368 -8,
1369 8,
1370 self.imgs.slider_indicator,
1371 self.imgs.slider,
1372 )
1373 .w_h(104.0, 22.0)
1374 .right_from(state.ids.rain_map_resolution_text, 8.0)
1375 .track_breadth(12.0)
1376 .slider_length(10.0)
1377 .pad_track((5.0, 5.0))
1378 .set(state.ids.rain_map_resolution_slider, ui)
1379 {
1380 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1381 rain_occlusion: ShadowMapMode {
1382 resolution: 2.0f32.powf(f32::from(new_val) / 4.0),
1383 },
1384 ..render_mode.clone()
1385 })));
1386 }
1387 Text::new(&format!("{}", render_mode.rain_occlusion.resolution))
1388 .right_from(state.ids.rain_map_resolution_slider, 8.0)
1389 .font_size(self.fonts.cyri.scale(14))
1390 .font_id(self.fonts.cyri.conrod_id)
1391 .color(TEXT_COLOR)
1392 .set(state.ids.rain_map_resolution_value, ui);
1393
1394 Text::new(&self.localized_strings.get_msg("hud-settings-gpu_profiler"))
1396 .font_size(self.fonts.cyri.scale(14))
1397 .font_id(self.fonts.cyri.conrod_id)
1398 .down_from(state.ids.rain_label, 8.0)
1399 .color(TEXT_COLOR)
1400 .set(state.ids.gpu_profiler_label, ui);
1401
1402 let gpu_profiler_enabled = ToggleButton::new(
1403 render_mode.profiler_enabled,
1404 self.imgs.checkbox,
1405 self.imgs.checkbox_checked,
1406 )
1407 .w_h(18.0, 18.0)
1408 .right_from(state.ids.gpu_profiler_label, 10.0)
1409 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1410 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1411 .set(state.ids.gpu_profiler_button, ui);
1412
1413 if render_mode.profiler_enabled != gpu_profiler_enabled {
1414 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1415 profiler_enabled: gpu_profiler_enabled,
1416 ..render_mode.clone()
1417 })));
1418 }
1419
1420 Text::new(&self.localized_strings.get_msg("hud-settings-particles"))
1422 .font_size(self.fonts.cyri.scale(14))
1423 .font_id(self.fonts.cyri.conrod_id)
1424 .down_from(state.ids.gpu_profiler_label, 8.0)
1425 .color(TEXT_COLOR)
1426 .set(state.ids.particles_label, ui);
1427
1428 let particles_enabled = ToggleButton::new(
1429 self.global_state.settings.graphics.particles_enabled,
1430 self.imgs.checkbox,
1431 self.imgs.checkbox_checked,
1432 )
1433 .w_h(18.0, 18.0)
1434 .right_from(state.ids.particles_label, 10.0)
1435 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1436 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1437 .set(state.ids.particles_button, ui);
1438
1439 if self.global_state.settings.graphics.particles_enabled != particles_enabled {
1440 events.push(GraphicsChange::ToggleParticlesEnabled(particles_enabled));
1441 }
1442
1443 Text::new(&self.localized_strings.get_msg("hud-settings-weapon_trails"))
1445 .font_size(self.fonts.cyri.scale(14))
1446 .font_id(self.fonts.cyri.conrod_id)
1447 .right_from(state.ids.particles_label, 64.0)
1448 .color(TEXT_COLOR)
1449 .set(state.ids.weapon_trails_label, ui);
1450
1451 let weapon_trails_enabled = ToggleButton::new(
1452 self.global_state.settings.graphics.weapon_trails_enabled,
1453 self.imgs.checkbox,
1454 self.imgs.checkbox_checked,
1455 )
1456 .w_h(18.0, 18.0)
1457 .right_from(state.ids.weapon_trails_label, 10.0)
1458 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1459 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1460 .set(state.ids.weapon_trails_button, ui);
1461
1462 if self.global_state.settings.graphics.weapon_trails_enabled != weapon_trails_enabled {
1463 events.push(GraphicsChange::ToggleWeaponTrailsEnabled(
1464 weapon_trails_enabled,
1465 ));
1466 }
1467
1468 Text::new(
1470 &self
1471 .localized_strings
1472 .get_msg("hud-settings-flashing_lights"),
1473 )
1474 .font_size(self.fonts.cyri.scale(14))
1475 .font_id(self.fonts.cyri.conrod_id)
1476 .down_from(state.ids.particles_label, 25.0)
1477 .color(TEXT_COLOR)
1478 .set(state.ids.flashing_lights_label, ui);
1479
1480 let flashing_lights_enabled = ToggleButton::new(
1481 self.global_state
1482 .settings
1483 .graphics
1484 .render_mode
1485 .flashing_lights_enabled,
1486 self.imgs.checkbox,
1487 self.imgs.checkbox_checked,
1488 )
1489 .w_h(18.0, 18.0)
1490 .right_from(state.ids.flashing_lights_label, 10.0)
1491 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1492 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1493 .set(state.ids.flashing_lights_button, ui);
1494
1495 Text::new(
1496 &self
1497 .localized_strings
1498 .get_msg("hud-settings-flashing_lights_info"),
1499 )
1500 .font_size(self.fonts.cyri.scale(14))
1501 .font_id(self.fonts.cyri.conrod_id)
1502 .right_from(state.ids.flashing_lights_label, 32.0)
1503 .color(TEXT_COLOR)
1504 .set(state.ids.flashing_lights_info_label, ui);
1505
1506 if self
1507 .global_state
1508 .settings
1509 .graphics
1510 .render_mode
1511 .flashing_lights_enabled
1512 != flashing_lights_enabled
1513 {
1514 events.push(GraphicsChange::ChangeRenderMode(Box::new(RenderMode {
1515 flashing_lights_enabled,
1516 ..render_mode.clone()
1517 })));
1518 }
1519
1520 let resolutions: Vec<[u16; 2]> = state
1522 .video_modes
1523 .iter()
1524 .sorted_by_key(|mode| mode.size().height)
1525 .sorted_by_key(|mode| mode.size().width)
1526 .map(|mode| [mode.size().width as u16, mode.size().height as u16])
1527 .dedup()
1528 .collect();
1529
1530 Text::new(&self.localized_strings.get_msg("hud-settings-resolution"))
1531 .font_size(self.fonts.cyri.scale(14))
1532 .font_id(self.fonts.cyri.conrod_id)
1533 .down_from(state.ids.flashing_lights_label, 25.0)
1534 .color(TEXT_COLOR)
1535 .set(state.ids.resolution_label, ui);
1536
1537 if let Some(clicked) = DropDownList::new(
1538 resolutions
1539 .iter()
1540 .map(|res| format!("{}x{}", res[0], res[1]))
1541 .collect::<Vec<String>>()
1542 .as_slice(),
1543 resolutions
1544 .iter()
1545 .position(|res| res == &self.global_state.settings.graphics.fullscreen.resolution),
1546 )
1547 .w_h(128.0, 22.0)
1548 .color(MENU_BG)
1549 .label_color(TEXT_COLOR)
1550 .label_font_id(self.fonts.universal.conrod_id)
1551 .down_from(state.ids.resolution_label, 10.0)
1552 .set(state.ids.resolution, ui)
1553 {
1554 events.push(GraphicsChange::ChangeFullscreenMode(FullScreenSettings {
1555 resolution: resolutions[clicked],
1556 ..self.global_state.settings.graphics.fullscreen
1557 }));
1558 }
1559
1560 let correct_res: Vec<&VideoMode> = state
1562 .video_modes
1563 .iter()
1564 .filter(|mode| {
1565 mode.size().width
1566 == self.global_state.settings.graphics.fullscreen.resolution[0] as u32
1567 })
1568 .filter(|mode| {
1569 mode.size().height
1570 == self.global_state.settings.graphics.fullscreen.resolution[1] as u32
1571 })
1572 .collect();
1573
1574 let bit_depths: Vec<u16> = correct_res
1576 .iter()
1577 .filter(
1578 |mode| match self.global_state.settings.graphics.fullscreen.refresh_rate_millihertz {
1579 Some(refresh_rate) => mode.refresh_rate_millihertz() == refresh_rate,
1580 None => true,
1581 },
1582 )
1583 .sorted_by_key(|mode| mode.bit_depth())
1585 .map(|mode| mode.bit_depth())
1586 .rev()
1587 .dedup()
1588 .collect();
1589
1590 Text::new(&self.localized_strings.get_msg("hud-settings-bit_depth"))
1591 .font_size(self.fonts.cyri.scale(14))
1592 .font_id(self.fonts.cyri.conrod_id)
1593 .down_from(state.ids.flashing_lights_label, 25.0)
1594 .right_from(state.ids.resolution, 8.0)
1595 .color(TEXT_COLOR)
1596 .set(state.ids.bit_depth_label, ui);
1597
1598 if let Some(clicked) = DropDownList::new(
1599 once(String::from(
1600 self.localized_strings.get_msg("common-automatic"),
1601 ))
1602 .chain(bit_depths.iter().map(|depth| format!("{}", depth)))
1603 .collect::<Vec<String>>()
1604 .as_slice(),
1605 match self.global_state.settings.graphics.fullscreen.bit_depth {
1606 Some(bit_depth) => bit_depths
1607 .iter()
1608 .position(|depth| depth == &bit_depth)
1609 .map(|index| index + 1),
1610 None => Some(0),
1611 },
1612 )
1613 .w_h(128.0, 22.0)
1614 .color(MENU_BG)
1615 .label_color(TEXT_COLOR)
1616 .label_font_id(self.fonts.universal.conrod_id)
1617 .down_from(state.ids.bit_depth_label, 10.0)
1618 .right_from(state.ids.resolution, 8.0)
1619 .set(state.ids.bit_depth, ui)
1620 {
1621 events.push(GraphicsChange::ChangeFullscreenMode(FullScreenSettings {
1622 bit_depth: if clicked == 0 {
1623 None
1624 } else {
1625 Some(bit_depths[clicked - 1])
1626 },
1627 ..self.global_state.settings.graphics.fullscreen
1628 }));
1629 }
1630
1631 let refresh_rates: Vec<u32> = correct_res
1633 .into_iter()
1634 .filter(
1635 |mode| match self.global_state.settings.graphics.fullscreen.bit_depth {
1636 Some(bit_depth) => mode.bit_depth() == bit_depth,
1637 None => true,
1638 },
1639 )
1640 .map(|mode| mode.refresh_rate_millihertz())
1641 .sorted()
1642 .rev()
1643 .dedup()
1644 .collect();
1645
1646 Text::new(&self.localized_strings.get_msg("hud-settings-refresh_rate"))
1647 .font_size(self.fonts.cyri.scale(14))
1648 .font_id(self.fonts.cyri.conrod_id)
1649 .down_from(state.ids.flashing_lights_label, 25.0)
1650 .right_from(state.ids.bit_depth, 8.0)
1651 .color(TEXT_COLOR)
1652 .set(state.ids.refresh_rate_label, ui);
1653
1654 if let Some(clicked) = DropDownList::new(
1655 once(String::from(
1656 self.localized_strings.get_msg("common-automatic"),
1657 ))
1658 .chain(
1659 refresh_rates
1660 .iter()
1661 .map(|&rate| format!("{:.1}", rate as f32 / 1000.0)),
1662 )
1663 .collect::<Vec<String>>()
1664 .as_slice(),
1665 match self
1666 .global_state
1667 .settings
1668 .graphics
1669 .fullscreen
1670 .refresh_rate_millihertz
1671 {
1672 Some(refresh_rate) => refresh_rates
1673 .iter()
1674 .position(|rate| rate == &refresh_rate)
1675 .map(|index| index + 1),
1676 None => Some(0),
1677 },
1678 )
1679 .w_h(128.0, 22.0)
1680 .color(MENU_BG)
1681 .label_color(TEXT_COLOR)
1682 .label_font_id(self.fonts.universal.conrod_id)
1683 .down_from(state.ids.refresh_rate_label, 10.0)
1684 .right_from(state.ids.bit_depth, 8.0)
1685 .set(state.ids.refresh_rate, ui)
1686 {
1687 events.push(GraphicsChange::ChangeFullscreenMode(FullScreenSettings {
1688 refresh_rate_millihertz: if clicked == 0 {
1689 None
1690 } else {
1691 Some(refresh_rates[clicked - 1])
1692 },
1693 ..self.global_state.settings.graphics.fullscreen
1694 }));
1695 }
1696
1697 Text::new(&self.localized_strings.get_msg("hud-settings-fullscreen"))
1699 .font_size(self.fonts.cyri.scale(14))
1700 .font_id(self.fonts.cyri.conrod_id)
1701 .down_from(state.ids.resolution, 8.0)
1702 .color(TEXT_COLOR)
1703 .set(state.ids.fullscreen_label, ui);
1704
1705 let enabled = ToggleButton::new(
1706 self.global_state.settings.graphics.fullscreen.enabled,
1707 self.imgs.checkbox,
1708 self.imgs.checkbox_checked,
1709 )
1710 .w_h(18.0, 18.0)
1711 .right_from(state.ids.fullscreen_label, 10.0)
1712 .hover_images(self.imgs.checkbox_mo, self.imgs.checkbox_checked_mo)
1713 .press_images(self.imgs.checkbox_press, self.imgs.checkbox_checked)
1714 .set(state.ids.fullscreen_button, ui);
1715
1716 if self.global_state.settings.graphics.fullscreen.enabled != enabled {
1717 events.push(GraphicsChange::ChangeFullscreenMode(FullScreenSettings {
1718 enabled,
1719 ..self.global_state.settings.graphics.fullscreen
1720 }));
1721 }
1722
1723 Text::new(
1725 &self
1726 .localized_strings
1727 .get_msg("hud-settings-fullscreen_mode"),
1728 )
1729 .down_from(state.ids.fullscreen_label, 8.0)
1730 .font_size(self.fonts.cyri.scale(14))
1731 .font_id(self.fonts.cyri.conrod_id)
1732 .color(TEXT_COLOR)
1733 .set(state.ids.fullscreen_mode_text, ui);
1734
1735 let mode_list = [FullscreenMode::Exclusive, FullscreenMode::Borderless];
1736 let mode_label_list = [
1737 &self
1738 .localized_strings
1739 .get_msg("hud-settings-fullscreen_mode-exclusive"),
1740 &self
1741 .localized_strings
1742 .get_msg("hud-settings-fullscreen_mode-borderless"),
1743 ];
1744
1745 let selected = mode_list
1747 .iter()
1748 .position(|x| *x == self.global_state.settings.graphics.fullscreen.mode);
1749
1750 if let Some(clicked) = DropDownList::new(&mode_label_list, selected)
1751 .w_h(400.0, 22.0)
1752 .color(MENU_BG)
1753 .label_color(TEXT_COLOR)
1754 .label_font_id(self.fonts.cyri.conrod_id)
1755 .down_from(state.ids.fullscreen_mode_text, 8.0)
1756 .set(state.ids.fullscreen_mode_list, ui)
1757 {
1758 events.push(GraphicsChange::ChangeFullscreenMode(FullScreenSettings {
1759 mode: mode_list[clicked],
1760 ..self.global_state.settings.graphics.fullscreen
1761 }));
1762 }
1763
1764 events
1765 }
1766}