1use elara_core::StateTime;
7
8#[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#[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#[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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum BackgroundComplexity {
66 Simple, Moderate, Complex, Dynamic, }
71
72#[derive(Debug, Clone)]
74pub struct SceneObject {
75 pub category: String,
77 pub bounds: (f32, f32, f32, f32),
79 pub confidence: f32,
81 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#[derive(Debug, Clone)]
98pub struct SceneState {
99 pub timestamp: StateTime,
101
102 pub background_color: Color,
104
105 pub lighting: LightingCondition,
107
108 pub environment: EnvironmentType,
110
111 pub complexity: BackgroundComplexity,
113
114 pub objects: Vec<SceneObject>,
116
117 pub background_motion: bool,
119
120 pub blur: f32,
122
123 pub noise: f32,
125
126 pub detail_level: f32,
128}
129
130impl SceneState {
131 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 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 pub fn add_object(&mut self, object: SceneObject) {
165 self.objects.push(object);
166 self.update_complexity();
167 }
168
169 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 pub fn reduce_detail(&mut self, factor: f32) {
184 self.detail_level *= factor.clamp(0.0, 1.0);
185
186 self.objects
188 .retain(|o| o.confidence > (1.0 - self.detail_level));
189
190 self.blur = (1.0 - self.detail_level) * 0.5;
192 }
193
194 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}