1use serde::{Deserialize, Serialize};
2
3use crate::ecs::camera::{Camera, OrthographicCamera, PerspectiveCamera, Projection};
4use crate::ecs::light::{AreaLightShape, Light, LightType};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub enum SceneLight {
8 Directional {
9 color: [f32; 3],
10 intensity: f32,
11 cast_shadows: bool,
12 shadow_bias: f32,
13 #[serde(default)]
14 shadow_resolution: u32,
15 #[serde(default)]
16 shadow_distance: f32,
17 #[serde(default)]
18 cookie_texture: Option<String>,
19 },
20 Point {
21 color: [f32; 3],
22 intensity: f32,
23 range: f32,
24 cast_shadows: bool,
25 shadow_bias: f32,
26 #[serde(default)]
27 shadow_resolution: u32,
28 #[serde(default)]
29 shadow_distance: f32,
30 #[serde(default)]
31 cookie_texture: Option<String>,
32 },
33 Spot {
34 color: [f32; 3],
35 intensity: f32,
36 range: f32,
37 inner_cone_angle: f32,
38 outer_cone_angle: f32,
39 cast_shadows: bool,
40 shadow_bias: f32,
41 #[serde(default)]
42 shadow_resolution: u32,
43 #[serde(default)]
44 shadow_distance: f32,
45 #[serde(default)]
46 cookie_texture: Option<String>,
47 },
48 Area {
49 color: [f32; 3],
50 intensity: f32,
51 range: f32,
52 #[serde(default)]
53 shape: AreaLightShape,
54 #[serde(default)]
55 width: f32,
56 #[serde(default)]
57 height: f32,
58 #[serde(default)]
59 radius: f32,
60 #[serde(default)]
61 two_sided: bool,
62 cast_shadows: bool,
63 shadow_bias: f32,
64 #[serde(default)]
65 shadow_resolution: u32,
66 #[serde(default)]
67 shadow_distance: f32,
68 #[serde(default)]
69 emissive_texture: Option<String>,
70 },
71}
72
73impl SceneLight {
74 pub fn directional(color: [f32; 3], intensity: f32) -> Self {
75 Self::Directional {
76 color,
77 intensity,
78 cast_shadows: true,
79 shadow_bias: 0.005,
80 shadow_resolution: 0,
81 shadow_distance: 0.0,
82 cookie_texture: None,
83 }
84 }
85
86 pub fn point(color: [f32; 3], intensity: f32, range: f32) -> Self {
87 Self::Point {
88 color,
89 intensity,
90 range,
91 cast_shadows: false,
92 shadow_bias: 0.0,
93 shadow_resolution: 0,
94 shadow_distance: 0.0,
95 cookie_texture: None,
96 }
97 }
98
99 pub fn spot(
100 color: [f32; 3],
101 intensity: f32,
102 range: f32,
103 inner_cone_angle: f32,
104 outer_cone_angle: f32,
105 ) -> Self {
106 Self::Spot {
107 color,
108 intensity,
109 range,
110 inner_cone_angle,
111 outer_cone_angle,
112 cast_shadows: false,
113 shadow_bias: 0.0,
114 shadow_resolution: 0,
115 shadow_distance: 0.0,
116 cookie_texture: None,
117 }
118 }
119
120 pub fn to_light(&self) -> Light {
121 match self {
122 SceneLight::Directional {
123 color,
124 intensity,
125 cast_shadows,
126 shadow_bias,
127 shadow_resolution,
128 shadow_distance,
129 cookie_texture,
130 } => Light {
131 light_type: LightType::Directional,
132 color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
133 intensity: *intensity,
134 range: 0.0,
135 inner_cone_angle: 0.0,
136 outer_cone_angle: 0.0,
137 cast_shadows: *cast_shadows,
138 shadow_bias: *shadow_bias,
139 shadow_resolution: *shadow_resolution,
140 shadow_distance: *shadow_distance,
141 cookie_texture: cookie_texture.clone(),
142 ..Default::default()
143 },
144 SceneLight::Point {
145 color,
146 intensity,
147 range,
148 cast_shadows,
149 shadow_bias,
150 shadow_resolution,
151 shadow_distance,
152 cookie_texture,
153 } => Light {
154 light_type: LightType::Point,
155 color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
156 intensity: *intensity,
157 range: *range,
158 inner_cone_angle: 0.0,
159 outer_cone_angle: 0.0,
160 cast_shadows: *cast_shadows,
161 shadow_bias: *shadow_bias,
162 shadow_resolution: *shadow_resolution,
163 shadow_distance: *shadow_distance,
164 cookie_texture: cookie_texture.clone(),
165 ..Default::default()
166 },
167 SceneLight::Spot {
168 color,
169 intensity,
170 range,
171 inner_cone_angle,
172 outer_cone_angle,
173 cast_shadows,
174 shadow_bias,
175 shadow_resolution,
176 shadow_distance,
177 cookie_texture,
178 } => Light {
179 light_type: LightType::Spot,
180 color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
181 intensity: *intensity,
182 range: *range,
183 inner_cone_angle: *inner_cone_angle,
184 outer_cone_angle: *outer_cone_angle,
185 cast_shadows: *cast_shadows,
186 shadow_bias: *shadow_bias,
187 shadow_resolution: *shadow_resolution,
188 shadow_distance: *shadow_distance,
189 cookie_texture: cookie_texture.clone(),
190 ..Default::default()
191 },
192 SceneLight::Area {
193 color,
194 intensity,
195 range,
196 shape,
197 width,
198 height,
199 radius,
200 two_sided,
201 cast_shadows,
202 shadow_bias,
203 shadow_resolution,
204 shadow_distance,
205 emissive_texture,
206 } => Light {
207 light_type: LightType::Area,
208 color: nalgebra_glm::Vec3::new(color[0], color[1], color[2]),
209 intensity: *intensity,
210 range: *range,
211 cast_shadows: *cast_shadows,
212 shadow_bias: *shadow_bias,
213 shadow_resolution: *shadow_resolution,
214 shadow_distance: *shadow_distance,
215 area_shape: *shape,
216 area_width: *width,
217 area_height: *height,
218 area_radius: *radius,
219 area_two_sided: *two_sided,
220 area_emissive_texture: emissive_texture.clone(),
221 ..Default::default()
222 },
223 }
224 }
225}
226
227impl From<&Light> for SceneLight {
228 fn from(light: &Light) -> Self {
229 let color = [light.color.x, light.color.y, light.color.z];
230 match light.light_type {
231 LightType::Directional => SceneLight::Directional {
232 color,
233 intensity: light.intensity,
234 cast_shadows: light.cast_shadows,
235 shadow_bias: light.shadow_bias,
236 shadow_resolution: light.shadow_resolution,
237 shadow_distance: light.shadow_distance,
238 cookie_texture: light.cookie_texture.clone(),
239 },
240 LightType::Point => SceneLight::Point {
241 color,
242 intensity: light.intensity,
243 range: light.range,
244 cast_shadows: light.cast_shadows,
245 shadow_bias: light.shadow_bias,
246 shadow_resolution: light.shadow_resolution,
247 shadow_distance: light.shadow_distance,
248 cookie_texture: light.cookie_texture.clone(),
249 },
250 LightType::Spot => SceneLight::Spot {
251 color,
252 intensity: light.intensity,
253 range: light.range,
254 inner_cone_angle: light.inner_cone_angle,
255 outer_cone_angle: light.outer_cone_angle,
256 cast_shadows: light.cast_shadows,
257 shadow_bias: light.shadow_bias,
258 shadow_resolution: light.shadow_resolution,
259 shadow_distance: light.shadow_distance,
260 cookie_texture: light.cookie_texture.clone(),
261 },
262 LightType::Area => SceneLight::Area {
263 color,
264 intensity: light.intensity,
265 range: light.range,
266 shape: light.area_shape,
267 width: light.area_width,
268 height: light.area_height,
269 radius: light.area_radius,
270 two_sided: light.area_two_sided,
271 cast_shadows: light.cast_shadows,
272 shadow_bias: light.shadow_bias,
273 shadow_resolution: light.shadow_resolution,
274 shadow_distance: light.shadow_distance,
275 emissive_texture: light.area_emissive_texture.clone(),
276 },
277 }
278 }
279}
280
281#[derive(Debug, Clone, Serialize, Deserialize)]
282pub enum SceneCamera {
283 Perspective {
284 aspect_ratio: Option<f32>,
285 y_fov_rad: f32,
286 z_far: Option<f32>,
287 z_near: f32,
288 },
289 Orthographic {
290 x_mag: f32,
291 y_mag: f32,
292 z_far: f32,
293 z_near: f32,
294 },
295}
296
297impl SceneCamera {
298 pub fn perspective(y_fov_rad: f32, z_near: f32) -> Self {
299 Self::Perspective {
300 aspect_ratio: None,
301 y_fov_rad,
302 z_far: None,
303 z_near,
304 }
305 }
306
307 pub fn orthographic(x_mag: f32, y_mag: f32, z_near: f32, z_far: f32) -> Self {
308 Self::Orthographic {
309 x_mag,
310 y_mag,
311 z_far,
312 z_near,
313 }
314 }
315
316 pub fn to_camera(&self) -> Camera {
317 match self {
318 SceneCamera::Perspective {
319 aspect_ratio,
320 y_fov_rad,
321 z_far,
322 z_near,
323 } => Camera {
324 projection: Projection::Perspective(PerspectiveCamera {
325 aspect_ratio: *aspect_ratio,
326 y_fov_rad: *y_fov_rad,
327 z_far: *z_far,
328 z_near: *z_near,
329 }),
330 smoothing: None,
331 },
332 SceneCamera::Orthographic {
333 x_mag,
334 y_mag,
335 z_far,
336 z_near,
337 } => Camera {
338 projection: Projection::Orthographic(OrthographicCamera {
339 x_mag: *x_mag,
340 y_mag: *y_mag,
341 z_far: *z_far,
342 z_near: *z_near,
343 }),
344 smoothing: None,
345 },
346 }
347 }
348}
349
350impl From<&Camera> for SceneCamera {
351 fn from(camera: &Camera) -> Self {
352 match &camera.projection {
353 Projection::Perspective(perspective) => SceneCamera::Perspective {
354 aspect_ratio: perspective.aspect_ratio,
355 y_fov_rad: perspective.y_fov_rad,
356 z_far: perspective.z_far,
357 z_near: perspective.z_near,
358 },
359 Projection::Orthographic(orthographic) => SceneCamera::Orthographic {
360 x_mag: orthographic.x_mag,
361 y_mag: orthographic.y_mag,
362 z_far: orthographic.z_far,
363 z_near: orthographic.z_near,
364 },
365 }
366 }
367}