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