diff --git a/chat-cli/src/main.rs b/chat-cli/src/main.rs index f68a5b47e9..bd0fb66bc2 100644 --- a/chat-cli/src/main.rs +++ b/chat-cli/src/main.rs @@ -3,7 +3,7 @@ use common::{clock::Clock, comp}; use log::{error, info}; use std::time::Duration; -const FPS: u64 = 60; +const TICK_RATE: u64 = 10; // Low value is okay, just reading messages. fn main() { // Initialize logging. @@ -48,6 +48,6 @@ fn main() { client.cleanup(); // Wait for the next tick. - clock.tick(Duration::from_millis(1000 / FPS)); + clock.tick(Duration::from_millis(1000 / TICK_RATE)); } } diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index a035d17316..ccafa92385 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -113,7 +113,7 @@ pub enum Event { AdjustViewDistance(u32), AdjustVolume(f32), ChangeAudioDevice(String), - MaximumFPS(u32), + ChangeMaxFPS(u32), CharacterSelection, Logout, Quit, @@ -583,7 +583,7 @@ impl Hud { events.push(Event::AdjustVolume(volume)); } settings_window::Event::MaximumFPS(max_fps) => { - events.push(Event::MaximumFPS(max_fps)); + events.push(Event::ChangeMaxFPS(max_fps)); } settings_window::Event::ChangeAudioDevice(name) => { events.push(Event::ChangeAudioDevice(name)); diff --git a/voxygen/src/hud/settings_window.rs b/voxygen/src/hud/settings_window.rs index d6e661e06f..c4fcf0b1b6 100644 --- a/voxygen/src/hud/settings_window.rs +++ b/voxygen/src/hud/settings_window.rs @@ -8,6 +8,9 @@ use conrod_core::{ widget::{self, Button, DropDownList, Image, Rectangle, Scrollbar, Text}, widget_ids, Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon, }; + +const FPS_CHOICES: [u32; 11] = [1, 30, 40, 50, 60, 90, 120, 144, 240, 300, 500]; + widget_ids! { struct Ids { settings_content, @@ -42,7 +45,8 @@ widget_ids! { test, video, vd_slider, - vd_slider_text, + vd_text, + vd_value, max_fps_slider, max_fps_text, max_fps_value, @@ -300,6 +304,7 @@ impl<'a> Widget for SettingsWindow<'a> { let display_pan = self.global_state.settings.gameplay.pan_sensitivity; let display_zoom = self.global_state.settings.gameplay.zoom_sensitivity; + // Mouse Pan Sensitivity Text::new("Pan Sensitivity") .top_left_with_margins_on(state.ids.settings_content, 10.0, 10.0) .font_size(14) @@ -331,6 +336,7 @@ impl<'a> Widget for SettingsWindow<'a> { .color(TEXT_COLOR) .set(state.ids.mouse_pan_value, ui); + // Mouse Zoom Sensitivity Text::new("Zoom Sensitivity") .down_from(state.ids.mouse_pan_slider, 10.0) .font_size(14) @@ -575,12 +581,13 @@ impl<'a> Widget for SettingsWindow<'a> { // Contents if let SettingsTab::Video = self.show.settings_tab { + // View Distance Text::new("View Distance") .top_left_with_margins_on(state.ids.settings_content, 10.0, 10.0) .font_size(14) .font_id(self.fonts.opensans) .color(TEXT_COLOR) - .set(state.ids.vd_slider_text, ui); + .set(state.ids.vd_text, ui); if let Some(new_val) = ImageSlider::discrete( self.global_state.settings.graphics.view_distance, @@ -590,7 +597,7 @@ impl<'a> Widget for SettingsWindow<'a> { self.imgs.slider, ) .w_h(104.0, 22.0) - .down_from(state.ids.vd_slider_text, 8.0) + .down_from(state.ids.vd_text, 8.0) .track_breadth(12.0) .slider_length(10.0) .pad_track((5.0, 5.0)) @@ -598,17 +605,32 @@ impl<'a> Widget for SettingsWindow<'a> { { events.push(Event::AdjustViewDistance(new_val)); } + + Text::new(&format!( + "{}", + self.global_state.settings.graphics.view_distance + )) + .right_from(state.ids.vd_slider, 8.0) + .font_size(14) + .font_id(self.fonts.opensans) + .color(TEXT_COLOR) + .set(state.ids.vd_value, ui); + + // Max FPS Text::new("Maximum FPS") - .top_left_with_margins_on(state.ids.settings_content, 60.0, 10.0) + .down_from(state.ids.vd_slider, 10.0) .font_size(14) .font_id(self.fonts.opensans) .color(TEXT_COLOR) .set(state.ids.max_fps_text, ui); - if let Some(new_val) = ImageSlider::discrete( - self.global_state.settings.graphics.view_distance, - 50, - 150, + if let Some(which) = ImageSlider::discrete( + FPS_CHOICES + .iter() + .position(|&x| x == self.global_state.settings.graphics.max_fps) + .unwrap_or(0), + 1, + 10, self.imgs.slider_indicator, self.imgs.slider, ) @@ -619,8 +641,15 @@ impl<'a> Widget for SettingsWindow<'a> { .pad_track((5.0, 5.0)) .set(state.ids.max_fps_slider, ui) { - events.push(Event::MaximumFPS(new_val)); + events.push(Event::MaximumFPS(FPS_CHOICES[which])); } + + Text::new(&format!("{}", self.global_state.settings.graphics.max_fps)) + .right_from(state.ids.max_fps_slider, 8.0) + .font_size(14) + .font_id(self.fonts.opensans) + .color(TEXT_COLOR) + .set(state.ids.max_fps_value, ui); } // 5) Sound Tab ----------------------------------- diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 2192ce711d..e8e34a3247 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -14,8 +14,6 @@ use std::{cell::RefCell, rc::Rc, time::Duration}; use ui::CharSelectionUi; use vek::*; -const FPS: u64 = 60; - pub struct CharSelectionState { char_selection_ui: CharSelectionUi, client: Rc>, @@ -125,7 +123,9 @@ impl PlayState for CharSelectionState { .expect("Failed to swap window buffers"); // Wait for the next tick. - clock.tick(Duration::from_millis(1000 / FPS)); + clock.tick(Duration::from_millis( + 1000 / (global_state.settings.graphics.max_fps as u64), + )); current_client_state = self.client.borrow().get_client_state(); } diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs index 0fe4faf702..59c3cfb38c 100644 --- a/voxygen/src/menu/main/mod.rs +++ b/voxygen/src/menu/main/mod.rs @@ -12,8 +12,6 @@ use std::time::Duration; use ui::{Event as MainMenuEvent, MainMenuUi}; use vek::*; -const FPS: u64 = 60; - pub struct MainMenuState { main_menu_ui: MainMenuUi, } @@ -133,7 +131,9 @@ impl PlayState for MainMenuState { .expect("Failed to swap window buffers!"); // Wait for the next tick - clock.tick(Duration::from_millis(1000 / FPS)); + clock.tick(Duration::from_millis( + 1000 / (global_state.settings.graphics.max_fps as u64), + )); } } diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs index ea1d01d3d3..6e20d3e725 100644 --- a/voxygen/src/session.rs +++ b/voxygen/src/session.rs @@ -13,8 +13,6 @@ use log::{error, warn}; use std::{cell::RefCell, rc::Rc, time::Duration}; use vek::*; -const FPS: u64 = 1000; - pub struct SessionState { scene: Scene, client: Rc>, @@ -188,12 +186,16 @@ impl PlayState for SessionState { HudEvent::AdjustMousePan(sensitivity) => { global_state.window.pan_sensitivity = sensitivity; global_state.settings.gameplay.pan_sensitivity = sensitivity; - global_state.settings.save_to_file(); + if let Err(err) = global_state.settings.save_to_file() { + warn!("Failed to save settings: {:?}", err); + } } HudEvent::AdjustMouseZoom(sensitivity) => { global_state.window.zoom_sensitivity = sensitivity; global_state.settings.gameplay.zoom_sensitivity = sensitivity; - global_state.settings.save_to_file(); + if let Err(err) = global_state.settings.save_to_file() { + warn!("Failed to save settings: {:?}", err); + } } HudEvent::AdjustViewDistance(view_distance) => { self.client.borrow_mut().set_view_distance(view_distance); @@ -219,6 +221,12 @@ impl PlayState for SessionState { warn!("Failed to save settings!\n{:?}", err); } } + HudEvent::ChangeMaxFPS(fps) => { + global_state.settings.graphics.max_fps = fps; + if let Err(err) = global_state.settings.save_to_file() { + warn!("Failed to save settings!\n{:?}", err); + } + } } } @@ -236,7 +244,9 @@ impl PlayState for SessionState { .expect("Failed to swap window buffers!"); // Wait for the next tick. - clock.tick(Duration::from_millis(1000 / FPS)); + clock.tick(Duration::from_millis( + 1000 / global_state.settings.graphics.max_fps as u64, + )); // Clean things up after the tick. self.cleanup(); diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs index 63e1cccfa6..635cbf0d39 100644 --- a/voxygen/src/settings.rs +++ b/voxygen/src/settings.rs @@ -64,12 +64,14 @@ pub struct Log { pub file: PathBuf, } +/// `GraphicsSettings` contains settings related to framerate and in-game visuals. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct GraphicsSettings { pub view_distance: u32, + pub max_fps: u32, } -/// AudioSettings controls the volume of different audio subsystems and which +/// `AudioSettings` controls the volume of different audio subsystems and which /// device is used. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AudioSettings { @@ -120,7 +122,10 @@ impl Default for Settings { log: Log { file: "voxygen.log".into(), }, - graphics: GraphicsSettings { view_distance: 5 }, + graphics: GraphicsSettings { + view_distance: 5, + max_fps: 60, + }, audio: AudioSettings { music_volume: 0.5, sfx_volume: 0.5,