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