Skip to main content

elara_visual/
scene.rs

1//! Scene State - Environment and background as state
2//!
3//! This is NOT a video background or image.
4//! This is the STATE of the visual environment for reality synchronization.
5
6use elara_core::StateTime;
7
8/// Color in RGB (0.0 - 1.0 range)
9#[derive(Debug, Clone, Copy, Default)]
10pub struct Color {
11    pub r: f32,
12    pub g: f32,
13    pub b: f32,
14}
15
16impl Color {
17    pub fn new(r: f32, g: f32, b: f32) -> Self {
18        Self { r, g, b }
19    }
20
21    pub fn black() -> Self {
22        Self::new(0.0, 0.0, 0.0)
23    }
24
25    pub fn white() -> Self {
26        Self::new(1.0, 1.0, 1.0)
27    }
28
29    pub fn lerp(&self, other: &Color, t: f32) -> Color {
30        Color {
31            r: self.r + (other.r - self.r) * t,
32            g: self.g + (other.g - self.g) * t,
33            b: self.b + (other.b - self.b) * t,
34        }
35    }
36}
37
38/// Lighting condition
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum LightingCondition {
41    Unknown,
42    Bright,
43    Normal,
44    Dim,
45    Dark,
46    Backlit,
47    Spotlight,
48}
49
50/// Environment type
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52pub enum EnvironmentType {
53    Unknown,
54    Indoor,
55    Outdoor,
56    Office,
57    Home,
58    Vehicle,
59    Nature,
60    Urban,
61}
62
63/// Background complexity
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum BackgroundComplexity {
66    Simple,   // Solid color or minimal
67    Moderate, // Some objects/texture
68    Complex,  // Busy background
69    Dynamic,  // Moving background
70}
71
72/// Scene object (simplified representation)
73#[derive(Debug, Clone)]
74pub struct SceneObject {
75    /// Object type/category
76    pub category: String,
77    /// Bounding box (normalized 0-1): x, y, width, height
78    pub bounds: (f32, f32, f32, f32),
79    /// Confidence
80    pub confidence: f32,
81    /// Is this object moving?
82    pub moving: bool,
83}
84
85impl SceneObject {
86    pub fn new(category: &str, x: f32, y: f32, w: f32, h: f32) -> Self {
87        Self {
88            category: category.to_string(),
89            bounds: (x, y, w, h),
90            confidence: 1.0,
91            moving: false,
92        }
93    }
94}
95
96/// Complete scene state
97#[derive(Debug, Clone)]
98pub struct SceneState {
99    /// Timestamp
100    pub timestamp: StateTime,
101
102    /// Dominant background color
103    pub background_color: Color,
104
105    /// Lighting condition
106    pub lighting: LightingCondition,
107
108    /// Environment type
109    pub environment: EnvironmentType,
110
111    /// Background complexity
112    pub complexity: BackgroundComplexity,
113
114    /// Detected objects in scene
115    pub objects: Vec<SceneObject>,
116
117    /// Is there significant motion in the background?
118    pub background_motion: bool,
119
120    /// Blur level (0.0 = sharp, 1.0 = very blurred)
121    pub blur: f32,
122
123    /// Noise level (0.0 = clean, 1.0 = very noisy)
124    pub noise: f32,
125
126    /// Detail level (0.0 - 1.0, for degradation)
127    pub detail_level: f32,
128}
129
130impl SceneState {
131    /// Create a new scene state
132    pub fn new(timestamp: StateTime) -> Self {
133        Self {
134            timestamp,
135            background_color: Color::white(),
136            lighting: LightingCondition::Normal,
137            environment: EnvironmentType::Unknown,
138            complexity: BackgroundComplexity::Simple,
139            objects: Vec::new(),
140            background_motion: false,
141            blur: 0.0,
142            noise: 0.0,
143            detail_level: 1.0,
144        }
145    }
146
147    /// Simple scene (solid color background)
148    pub fn simple(timestamp: StateTime, color: Color) -> Self {
149        Self {
150            timestamp,
151            background_color: color,
152            lighting: LightingCondition::Normal,
153            environment: EnvironmentType::Unknown,
154            complexity: BackgroundComplexity::Simple,
155            objects: Vec::new(),
156            background_motion: false,
157            blur: 0.0,
158            noise: 0.0,
159            detail_level: 1.0,
160        }
161    }
162
163    /// Add an object to the scene
164    pub fn add_object(&mut self, object: SceneObject) {
165        self.objects.push(object);
166        self.update_complexity();
167    }
168
169    /// Update complexity based on objects
170    fn update_complexity(&mut self) {
171        self.complexity = match self.objects.len() {
172            0 => BackgroundComplexity::Simple,
173            1..=3 => BackgroundComplexity::Moderate,
174            _ => BackgroundComplexity::Complex,
175        };
176
177        if self.objects.iter().any(|o| o.moving) {
178            self.complexity = BackgroundComplexity::Dynamic;
179        }
180    }
181
182    /// Reduce detail level (for degradation)
183    pub fn reduce_detail(&mut self, factor: f32) {
184        self.detail_level *= factor.clamp(0.0, 1.0);
185
186        // Remove low-confidence objects
187        self.objects
188            .retain(|o| o.confidence > (1.0 - self.detail_level));
189
190        // Increase blur as detail decreases
191        self.blur = (1.0 - self.detail_level) * 0.5;
192    }
193
194    /// Interpolate between two scene states
195    pub fn lerp(&self, other: &SceneState, t: f32) -> SceneState {
196        SceneState {
197            timestamp: other.timestamp,
198            background_color: self.background_color.lerp(&other.background_color, t),
199            lighting: if t < 0.5 {
200                self.lighting
201            } else {
202                other.lighting
203            },
204            environment: if t < 0.5 {
205                self.environment
206            } else {
207                other.environment
208            },
209            complexity: if t < 0.5 {
210                self.complexity
211            } else {
212                other.complexity
213            },
214            objects: if t < 0.5 {
215                self.objects.clone()
216            } else {
217                other.objects.clone()
218            },
219            background_motion: if t < 0.5 {
220                self.background_motion
221            } else {
222                other.background_motion
223            },
224            blur: self.blur + (other.blur - self.blur) * t,
225            noise: self.noise + (other.noise - self.noise) * t,
226            detail_level: self.detail_level + (other.detail_level - self.detail_level) * t,
227        }
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234
235    #[test]
236    fn test_color_lerp() {
237        let black = Color::black();
238        let white = Color::white();
239
240        let gray = black.lerp(&white, 0.5);
241        assert!((gray.r - 0.5).abs() < 0.01);
242        assert!((gray.g - 0.5).abs() < 0.01);
243        assert!((gray.b - 0.5).abs() < 0.01);
244    }
245
246    #[test]
247    fn test_scene_state() {
248        let time = StateTime::from_millis(0);
249        let mut scene = SceneState::new(time);
250
251        assert_eq!(scene.complexity, BackgroundComplexity::Simple);
252
253        scene.add_object(SceneObject::new("chair", 0.1, 0.5, 0.2, 0.3));
254        scene.add_object(SceneObject::new("table", 0.5, 0.5, 0.3, 0.2));
255
256        assert_eq!(scene.complexity, BackgroundComplexity::Moderate);
257    }
258
259    #[test]
260    fn test_scene_reduce_detail() {
261        let time = StateTime::from_millis(0);
262        let mut scene = SceneState::new(time);
263        scene.add_object(SceneObject::new("object", 0.5, 0.5, 0.1, 0.1));
264
265        scene.reduce_detail(0.5);
266        assert!((scene.detail_level - 0.5).abs() < 0.01);
267        assert!(scene.blur > 0.0);
268    }
269}