use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LightingPreset {
pub name: String,
#[serde(default)]
pub built_in: bool,
pub light_yaw_deg: f32,
pub light_pitch_deg: f32,
pub exposure: f32,
pub lighting_rig: String,
pub camera_distance: f32,
#[serde(default)]
pub camera_yaw: Option<f32>,
#[serde(default)]
pub camera_pitch: Option<f32>,
#[serde(default)]
pub env_map_path: Option<String>,
#[serde(default)]
pub export_usable: bool,
}
#[must_use]
pub fn built_in_presets() -> Vec<LightingPreset> {
vec![
LightingPreset {
name: "Studio Softbox".to_string(),
built_in: true,
light_yaw_deg: 48.0,
light_pitch_deg: 54.0,
exposure: 1.0,
lighting_rig: "Gem Studio Ring Lights".to_string(),
camera_distance: 2.4,
camera_yaw: None,
camera_pitch: None,
env_map_path: None,
export_usable: false,
},
LightingPreset {
name: "Daylight Bright".to_string(),
built_in: true,
light_yaw_deg: 30.0,
light_pitch_deg: 65.0,
exposure: 1.3,
lighting_rig: "D65 Daylight (6500K)".to_string(),
camera_distance: 2.2,
camera_yaw: None,
camera_pitch: None,
env_map_path: None,
export_usable: false,
},
LightingPreset {
name: "Dramatic Spotlight".to_string(),
built_in: true,
light_yaw_deg: 300.0,
light_pitch_deg: 25.0,
exposure: 0.7,
lighting_rig: "Dramatic Dark Spotlight".to_string(),
camera_distance: 2.6,
camera_yaw: None,
camera_pitch: None,
env_map_path: None,
export_usable: false,
},
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_preset_predating_the_view_fields_still_loads_with_them_defaulted() {
let old_toml = r#"
name = "Old Preset"
built_in = false
light_yaw_deg = 10.0
light_pitch_deg = 20.0
exposure = 1.0
lighting_rig = "Gem Studio Ring Lights"
camera_distance = 2.4
"#;
let preset: LightingPreset =
toml::from_str(old_toml).expect("a pre-view-fields preset must still parse");
assert_eq!(preset.camera_yaw, None);
assert_eq!(preset.camera_pitch, None);
assert_eq!(preset.env_map_path, None);
assert!(!preset.export_usable);
}
#[test]
fn a_full_view_preset_round_trips_through_toml() {
let preset = LightingPreset {
name: "My Shot".to_string(),
built_in: false,
light_yaw_deg: 48.0,
light_pitch_deg: 54.0,
exposure: 1.0,
lighting_rig: "Gem Studio Ring Lights".to_string(),
camera_distance: 2.4,
camera_yaw: Some(0.6),
camera_pitch: Some(0.45),
env_map_path: Some("C:/env/studio.hdr".to_string()),
export_usable: true,
};
let toml_str = toml::to_string_pretty(&preset).expect("must serialize");
let round_tripped: LightingPreset = toml::from_str(&toml_str).expect("must deserialize");
assert_eq!(preset, round_tripped);
}
#[test]
fn built_in_presets_carry_no_camera_or_env_data_and_are_not_export_usable() {
for preset in built_in_presets() {
assert_eq!(
preset.camera_yaw, None,
"{}: built-ins must not carry a camera pose",
preset.name
);
assert_eq!(
preset.camera_pitch, None,
"{}: built-ins must not carry a camera pose",
preset.name
);
assert_eq!(
preset.env_map_path, None,
"{}: built-ins must not carry an HDR map",
preset.name
);
assert!(
!preset.export_usable,
"{}: built-ins must default out of the export fan-out list",
preset.name
);
}
}
}