1use config::{Config as ConfigLib, File};
2use log::LevelFilter;
3use nalgebra as na;
4use std::{collections::HashMap, path::Path};
5
6use crate::components::ConfigChanges;
7use gloss_utils::{config::MyTomlFile, convert_enum_into};
8
9#[derive(Clone, serde::Deserialize, Debug)]
12pub struct Config {
13 pub core: CoreConfig,
14 pub render: RenderConfig,
15 pub scene: SceneConfig,
16 is_concrete: Option<bool>, is_consumed: Option<bool>, }
19
20#[derive(Clone, serde::Deserialize, Debug)]
21#[allow(unused)]
22#[allow(clippy::struct_excessive_bools)]
23pub struct CoreConfig {
24 pub enable_gui: bool,
25 pub gui_start_hidden: bool,
26 pub auto_add_floor: bool,
27 pub floor_type: FloorType,
28 pub floor_scale: Option<f32>,
29 pub floor_origin: Option<na::Point3<f32>>,
30 pub floor_texture: FloorTexture,
31 pub floor_uv_scale: Option<f32>,
32 pub floor_grid_line_width: f32,
33 pub canvas_id: Option<String>,
34 pub auto_create_logger: bool,
35 pub log_level: LogLevel,
36 pub log_level_caps: HashMap<String, LogLevel>,
37 pub enable_memory_profiling_callstacks: bool,
38}
39
40#[derive(Clone, serde::Deserialize, Debug)]
41#[allow(unused)]
42pub struct RenderConfig {
43 pub ambient_factor: f32,
44 pub environment_factor: f32,
45 pub bg_color: na::Vector4<f32>,
46 pub enable_distance_fade: Option<bool>,
47 pub distance_fade_center: Option<na::Point3<f32>>,
48 pub distance_fade_start: Option<f32>,
49 pub distance_fade_end: Option<f32>,
50 pub apply_lighting: bool,
52 pub saturation: f32,
53 pub gamma: f32,
54 pub exposure: f32,
55 pub shadow_filter_method: ShadowFilteringMethod,
56 pub msaa_nr_samples: u32,
57 pub preallocated_staging_buffer_bytes: u32,
58 pub offscreen_color_float_tex: bool,
59}
60
61#[derive(Clone, serde::Deserialize, Debug)]
62#[allow(unused)]
63pub struct SceneConfig {
64 pub cam: CamConfig,
65 pub lights: Vec<LightConfig>,
66}
67
68#[derive(Clone, serde::Deserialize, Debug)]
69#[allow(unused)]
70pub struct CamConfig {
71 pub position: Option<na::Point3<f32>>,
72 pub lookat: Option<na::Point3<f32>>,
73 pub fovy: f32,
74 pub near: Option<f32>,
75 pub far: Option<f32>,
76 pub limit_max_dist: Option<f32>,
77 pub limit_max_vertical_angle: Option<f32>,
78 pub limit_min_vertical_angle: Option<f32>,
79}
80
81#[derive(Clone, serde::Deserialize, Debug)]
82#[allow(unused)]
83pub struct LightConfig {
84 pub position: Option<na::Point3<f32>>,
85 pub lookat: Option<na::Point3<f32>>,
86 pub fovy: f32, pub near: Option<f32>,
88 pub far: Option<f32>,
89 pub color: na::Vector3<f32>,
90 pub intensity: Option<f32>,
91 pub range: Option<f32>,
92 pub radius: Option<f32>,
93 pub shadow_res: Option<u32>,
94 pub shadow_bias_fixed: Option<f32>,
95 pub shadow_bias: Option<f32>,
96 pub shadow_bias_normal: Option<f32>,
97}
98
99#[derive(Debug, Copy, Clone, serde::Deserialize, PartialEq, Eq)]
100#[serde(rename_all = "lowercase")]
101pub enum ShadowFilteringMethod {
102 Hardware2x2 = 0,
106 Castano13,
111}
112
113#[derive(Debug, Copy, Clone, serde::Deserialize, PartialEq, Eq)]
114#[serde(rename_all = "lowercase")]
115pub enum FloorType {
116 Solid = 0,
117 Grid,
118}
119
120#[derive(Debug, Copy, Clone, serde::Deserialize, PartialEq, Eq)]
121#[serde(rename_all = "lowercase")]
122pub enum FloorTexture {
123 None = 0,
124 Checkerboard,
125}
126
127#[derive(Debug, Copy, Clone, serde::Deserialize, PartialEq, Eq)]
128#[serde(rename_all = "lowercase")]
129pub enum LogLevel {
130 Off,
132 Error,
134 Warn,
136 Info,
138 Debug,
140 Trace,
142}
143convert_enum_into!(LogLevel, LevelFilter, Off, Error, Warn, Info, Debug, Trace,);
145
146impl Default for Config {
147 fn default() -> Config {
148 Config::new(None)
149 }
150}
151
152impl Config {
153 pub fn new(config_path: Option<&str>) -> crate::config::Config {
156 let default_file = File::from_str(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/config/default.toml")), MyTomlFile);
157
158 let mut builder = ConfigLib::builder().add_source(default_file.required(true));
160
161 if let Some(config_path) = config_path {
162 let config_path_abs = if Path::new(config_path).is_relative() {
164 Path::new(env!("CARGO_MANIFEST_DIR")).join(config_path)
165 } else {
166 Path::new(config_path).to_path_buf()
167 };
168 let config_file = File::new(config_path_abs.to_str().unwrap(), MyTomlFile);
169 builder = builder.add_source(config_file.required(true));
170 }
171
172 let settings = builder.build().unwrap();
173
174 settings.try_deserialize().unwrap()
175 }
176
177 pub fn new_from_str(config_content: &str) -> crate::config::Config {
180 let default_file = File::from_str(include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/config/default.toml")), MyTomlFile);
181
182 let config_file = File::from_str(config_content, MyTomlFile);
183
184 let builder = ConfigLib::builder()
186 .add_source(default_file.required(true))
187 .add_source(config_file.required(true));
188
189 let settings = builder.build().unwrap();
190
191 settings.try_deserialize().unwrap()
192 }
193 pub fn is_concrete(&self) -> bool {
194 self.is_concrete.is_some()
195 }
196 pub fn set_concrete(&mut self) {
197 self.is_concrete = Some(true);
198 }
199 pub fn is_consumed(&self) -> bool {
200 self.is_consumed.is_some()
201 }
202 pub fn set_consumed(&mut self) {
203 self.is_consumed = Some(true);
204 }
205
206 pub fn apply_deltas(&mut self, changes: &ConfigChanges) {
207 if let Some(ref mut p) = self.render.distance_fade_center {
208 p.clone_from(&changes.new_distance_fade_center);
209 }
210 }
211}