use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum GraphicsQuality {
VeryLow, Low, Medium, High, Ultra, }
impl GraphicsQuality {
pub fn from_index(index: usize) -> Self {
match index {
0 => GraphicsQuality::VeryLow,
1 => GraphicsQuality::Low,
2 => GraphicsQuality::Medium,
3 => GraphicsQuality::High,
4 => GraphicsQuality::Ultra,
_ => GraphicsQuality::VeryLow,
}
}
pub fn to_index(&self) -> usize {
match self {
GraphicsQuality::VeryLow => 0,
GraphicsQuality::Low => 1,
GraphicsQuality::Medium => 2,
GraphicsQuality::High => 3,
GraphicsQuality::Ultra => 4,
}
}
pub fn name(&self) -> &str {
match self {
GraphicsQuality::VeryLow => "Muito Baixo",
GraphicsQuality::Low => "Baixo",
GraphicsQuality::Medium => "Médio",
GraphicsQuality::High => "Alto",
GraphicsQuality::Ultra => "Ultra",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphicsSettings {
pub quality: GraphicsQuality,
pub vsync: bool,
pub target_fps: u32,
pub render_distance: f32,
pub shadow_quality: u32,
pub particle_limit: usize,
pub texture_quality: u32,
pub anti_aliasing: bool,
pub post_processing: bool,
pub bloom: bool,
pub motion_blur: bool,
pub ambient_occlusion: bool,
pub lod_enabled: bool,
pub culling_enabled: bool,
pub resolution_scale: f32,
}
impl Default for GraphicsSettings {
fn default() -> Self {
Self::very_low() }
}
impl GraphicsSettings {
pub fn very_low() -> Self {
Self {
quality: GraphicsQuality::VeryLow,
vsync: false,
target_fps: 30,
render_distance: 20.0,
shadow_quality: 0,
particle_limit: 50,
texture_quality: 0,
anti_aliasing: false,
post_processing: false,
bloom: false,
motion_blur: false,
ambient_occlusion: false,
lod_enabled: true,
culling_enabled: true,
resolution_scale: 0.5, }
}
pub fn low() -> Self {
Self {
quality: GraphicsQuality::Low,
vsync: false,
target_fps: 60,
render_distance: 40.0,
shadow_quality: 1,
particle_limit: 100,
texture_quality: 1,
anti_aliasing: false,
post_processing: false,
bloom: false,
motion_blur: false,
ambient_occlusion: false,
lod_enabled: true,
culling_enabled: true,
resolution_scale: 0.75, }
}
pub fn medium() -> Self {
Self {
quality: GraphicsQuality::Medium,
vsync: true,
target_fps: 60,
render_distance: 60.0,
shadow_quality: 2,
particle_limit: 200,
texture_quality: 2,
anti_aliasing: false,
post_processing: true,
bloom: false,
motion_blur: false,
ambient_occlusion: false,
lod_enabled: true,
culling_enabled: true,
resolution_scale: 1.0, }
}
pub fn high() -> Self {
Self {
quality: GraphicsQuality::High,
vsync: true,
target_fps: 60,
render_distance: 100.0,
shadow_quality: 3,
particle_limit: 500,
texture_quality: 3,
anti_aliasing: true,
post_processing: true,
bloom: true,
motion_blur: false,
ambient_occlusion: true,
lod_enabled: true,
culling_enabled: true,
resolution_scale: 1.0,
}
}
pub fn ultra() -> Self {
Self {
quality: GraphicsQuality::Ultra,
vsync: true,
target_fps: 120,
render_distance: 200.0,
shadow_quality: 4,
particle_limit: 1000,
texture_quality: 4,
anti_aliasing: true,
post_processing: true,
bloom: true,
motion_blur: true,
ambient_occlusion: true,
lod_enabled: false, culling_enabled: true,
resolution_scale: 1.0,
}
}
pub fn apply_preset(&mut self, quality: GraphicsQuality) {
*self = match quality {
GraphicsQuality::VeryLow => Self::very_low(),
GraphicsQuality::Low => Self::low(),
GraphicsQuality::Medium => Self::medium(),
GraphicsQuality::High => Self::high(),
GraphicsQuality::Ultra => Self::ultra(),
};
}
pub fn save(&self, path: &str) -> Result<(), Box<dyn std::error::Error>> {
let json = serde_json::to_string_pretty(self)?;
std::fs::write(path, json)?;
Ok(())
}
pub fn load(path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let json = std::fs::read_to_string(path)?;
let settings = serde_json::from_str(&json)?;
Ok(settings)
}
pub fn auto_detect(current_fps: f32) -> GraphicsQuality {
if current_fps >= 120.0 {
GraphicsQuality::Ultra
} else if current_fps >= 60.0 {
GraphicsQuality::High
} else if current_fps >= 45.0 {
GraphicsQuality::Medium
} else if current_fps >= 30.0 {
GraphicsQuality::Low
} else {
GraphicsQuality::VeryLow
}
}
pub fn dynamic_adjust(&mut self, current_fps: f32) {
if current_fps < 25.0 && self.quality != GraphicsQuality::VeryLow {
let new_quality = GraphicsQuality::from_index(self.quality.to_index().saturating_sub(1));
self.apply_preset(new_quality);
} else if current_fps > 70.0 && self.quality != GraphicsQuality::Ultra {
let new_quality = GraphicsQuality::from_index((self.quality.to_index() + 1).min(4));
self.apply_preset(new_quality);
}
}
pub fn get_particle_limit(&self) -> usize {
self.particle_limit
}
pub fn get_render_distance(&self) -> f32 {
self.render_distance
}
pub fn should_use_lod(&self) -> bool {
self.lod_enabled
}
pub fn should_use_culling(&self) -> bool {
self.culling_enabled
}
pub fn get_resolution_scale(&self) -> f32 {
self.resolution_scale
}
}
pub struct PerformanceMonitor {
fps_history: Vec<f32>,
max_history: usize,
last_adjustment: f32,
adjustment_cooldown: f32,
}
impl PerformanceMonitor {
pub fn new() -> Self {
Self {
fps_history: Vec::new(),
max_history: 60, last_adjustment: 0.0,
adjustment_cooldown: 5.0, }
}
pub fn update(&mut self, fps: f32, elapsed_time: f32) {
self.fps_history.push(fps);
if self.fps_history.len() > self.max_history {
self.fps_history.remove(0);
}
self.last_adjustment += elapsed_time;
}
pub fn average_fps(&self) -> f32 {
if self.fps_history.is_empty() {
return 60.0;
}
self.fps_history.iter().sum::<f32>() / self.fps_history.len() as f32
}
pub fn should_adjust(&self) -> bool {
self.last_adjustment >= self.adjustment_cooldown && self.fps_history.len() >= self.max_history
}
pub fn reset_adjustment_timer(&mut self) {
self.last_adjustment = 0.0;
}
pub fn is_stable(&self) -> bool {
if self.fps_history.len() < 10 {
return false;
}
let avg = self.average_fps();
let variance: f32 = self.fps_history.iter()
.map(|fps| (fps - avg).powi(2))
.sum::<f32>() / self.fps_history.len() as f32;
variance < 100.0 }
}
#[derive(Debug, Clone)]
pub struct OptimizationSettings {
pub batch_rendering: bool,
pub frustum_culling: bool,
pub occlusion_culling: bool,
pub texture_streaming: bool,
pub mesh_simplification: bool,
pub dynamic_lod: bool,
pub particle_pooling: bool,
pub shader_caching: bool,
}
impl OptimizationSettings {
pub fn for_quality(quality: GraphicsQuality) -> Self {
match quality {
GraphicsQuality::VeryLow => Self {
batch_rendering: true,
frustum_culling: true,
occlusion_culling: true,
texture_streaming: true,
mesh_simplification: true,
dynamic_lod: true,
particle_pooling: true,
shader_caching: true,
},
GraphicsQuality::Low => Self {
batch_rendering: true,
frustum_culling: true,
occlusion_culling: true,
texture_streaming: true,
mesh_simplification: true,
dynamic_lod: true,
particle_pooling: true,
shader_caching: true,
},
GraphicsQuality::Medium => Self {
batch_rendering: true,
frustum_culling: true,
occlusion_culling: false,
texture_streaming: true,
mesh_simplification: false,
dynamic_lod: true,
particle_pooling: true,
shader_caching: true,
},
GraphicsQuality::High => Self {
batch_rendering: true,
frustum_culling: true,
occlusion_culling: false,
texture_streaming: false,
mesh_simplification: false,
dynamic_lod: true,
particle_pooling: false,
shader_caching: true,
},
GraphicsQuality::Ultra => Self {
batch_rendering: false,
frustum_culling: true,
occlusion_culling: false,
texture_streaming: false,
mesh_simplification: false,
dynamic_lod: false,
particle_pooling: false,
shader_caching: true,
},
}
}
}