1use crate::*;
2
3#[derive(Clone, Debug)]
5pub struct Light {
6 pub id: Option<String>,
8 pub name: Option<String>,
10 pub asset: Option<Box<Asset>>,
12 pub kind: LightKind,
14 pub technique: Vec<Technique>,
16 pub extra: Vec<Extra>,
18}
19
20impl Light {
21 pub fn new(id: impl Into<String>, name: Option<String>, kind: impl Into<LightKind>) -> Self {
23 Self {
24 id: Some(id.into()),
25 name,
26 asset: None,
27 kind: kind.into(),
28 technique: vec![],
29 extra: vec![],
30 }
31 }
32}
33
34impl XNode for Light {
35 const NAME: &'static str = "light";
36 fn parse(element: &Element) -> Result<Self> {
37 debug_assert_eq!(element.name(), Self::NAME);
38 let mut it = element.children().peekable();
39 Ok(Light {
40 id: element.attr("id").map(Into::into),
41 name: element.attr("name").map(Into::into),
42 asset: Asset::parse_opt_box(&mut it)?,
43 kind: parse_one(Technique::COMMON, &mut it, |e| {
44 let mut it = e.children().peekable();
45 finish(parse_one_many(&mut it, LightKind::parse)?, it)
46 })?,
47 technique: Technique::parse_list(&mut it)?,
48 extra: Extra::parse_many(it)?,
49 })
50 }
51}
52
53impl XNodeWrite for Light {
54 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
55 let mut e = Self::elem();
56 e.opt_attr("id", &self.id);
57 e.opt_attr("name", &self.name);
58 let e = e.start(w)?;
59 self.asset.write_to(w)?;
60 let common = ElemBuilder::new(Technique::COMMON).start(w)?;
61 self.kind.write_to(w)?;
62 common.end(w)?;
63 self.technique.write_to(w)?;
64 self.extra.write_to(w)?;
65 e.end(w)
66 }
67}
68
69#[derive(Clone, Debug)]
71pub enum LightKind {
72 Ambient(AmbientLight),
74 Directional(DirectionalLight),
76 Point(Box<PointLight>),
78 Spot(Box<SpotLight>),
80}
81
82impl From<SpotLight> for LightKind {
83 fn from(v: SpotLight) -> Self {
84 Self::Spot(Box::new(v))
85 }
86}
87
88impl From<PointLight> for LightKind {
89 fn from(v: PointLight) -> Self {
90 Self::Point(Box::new(v))
91 }
92}
93
94impl From<DirectionalLight> for LightKind {
95 fn from(v: DirectionalLight) -> Self {
96 Self::Directional(v)
97 }
98}
99
100impl From<AmbientLight> for LightKind {
101 fn from(v: AmbientLight) -> Self {
102 Self::Ambient(v)
103 }
104}
105
106impl LightKind {
107 pub fn parse(e: &Element) -> Result<Option<Self>> {
109 Ok(Some(match e.name() {
110 AmbientLight::NAME => Self::Ambient(AmbientLight::parse(e)?),
111 DirectionalLight::NAME => Self::Directional(DirectionalLight::parse(e)?),
112 PointLight::NAME => Self::Point(PointLight::parse_box(e)?),
113 SpotLight::NAME => Self::Spot(SpotLight::parse_box(e)?),
114 _ => return Ok(None),
115 }))
116 }
117}
118
119impl XNodeWrite for LightKind {
120 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
121 match self {
122 LightKind::Ambient(e) => e.write_to(w),
123 LightKind::Directional(e) => e.write_to(w),
124 LightKind::Point(e) => e.write_to(w),
125 LightKind::Spot(e) => e.write_to(w),
126 }
127 }
128}
129
130#[derive(Clone, Debug)]
132pub struct AmbientLight {
133 pub color: Box<[f32; 3]>,
135}
136
137impl AmbientLight {
138 pub fn new(color: [f32; 3]) -> Self {
140 Self {
141 color: Box::new(color),
142 }
143 }
144}
145
146impl XNode for AmbientLight {
147 const NAME: &'static str = "ambient";
148 fn parse(element: &Element) -> Result<Self> {
149 debug_assert_eq!(element.name(), Self::NAME);
150 let mut it = element.children().peekable();
151 let color = parse_one("color", &mut it, parse_array_n)?;
152 finish(AmbientLight { color }, it)
153 }
154}
155
156impl XNodeWrite for AmbientLight {
157 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
158 let e = Self::elem().start(w)?;
159 ElemBuilder::print_arr("color", &*self.color, w)?;
160 e.end(w)
161 }
162}
163
164#[derive(Clone, Debug)]
171pub struct DirectionalLight {
172 pub color: Box<[f32; 3]>,
174}
175
176impl DirectionalLight {
177 pub fn new(color: [f32; 3]) -> Self {
179 Self {
180 color: Box::new(color),
181 }
182 }
183}
184
185impl XNode for DirectionalLight {
186 const NAME: &'static str = "directional";
187 fn parse(element: &Element) -> Result<Self> {
188 debug_assert_eq!(element.name(), Self::NAME);
189 let mut it = element.children().peekable();
190 let color = parse_one("color", &mut it, parse_array_n)?;
191 finish(DirectionalLight { color }, it)
192 }
193}
194
195impl XNodeWrite for DirectionalLight {
196 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
197 let e = Self::elem().start(w)?;
198 ElemBuilder::print_arr("color", &*self.color, w)?;
199 e.end(w)
200 }
201}
202
203#[derive(Clone, Debug)]
214pub struct PointLight {
215 pub color: Box<[f32; 3]>,
217 pub constant_attenuation: f32,
219 pub linear_attenuation: f32,
221 pub quadratic_attenuation: f32,
223}
224
225impl PointLight {
226 pub fn new(color: [f32; 3]) -> Self {
228 Self {
229 color: Box::new(color),
230 constant_attenuation: 0.,
231 linear_attenuation: 0.,
232 quadratic_attenuation: 0.,
233 }
234 }
235}
236
237impl XNode for PointLight {
238 const NAME: &'static str = "point";
239 fn parse(element: &Element) -> Result<Self> {
240 debug_assert_eq!(element.name(), Self::NAME);
241 let mut it = element.children().peekable();
242 let res = PointLight {
243 color: parse_one("color", &mut it, parse_array_n)?,
244 constant_attenuation: parse_opt("constant_attenuation", &mut it, parse_elem)?
245 .unwrap_or(0.),
246 linear_attenuation: parse_opt("linear_attenuation", &mut it, parse_elem)?.unwrap_or(0.),
247 quadratic_attenuation: parse_opt("quadratic_attenuation", &mut it, parse_elem)?
248 .unwrap_or(0.),
249 };
250 finish(res, it)
251 }
252}
253
254impl XNodeWrite for PointLight {
255 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
256 let e = Self::elem().start(w)?;
257 ElemBuilder::print_arr("color", &*self.color, w)?;
258 ElemBuilder::def_print("constant_attenuation", self.constant_attenuation, 0., w)?;
259 ElemBuilder::def_print("linear_attenuation", self.linear_attenuation, 0., w)?;
260 ElemBuilder::def_print("quadratic_attenuation", self.quadratic_attenuation, 0., w)?;
261 e.end(w)
262 }
263}
264
265#[derive(Clone, Debug)]
282pub struct SpotLight {
283 pub color: Box<[f32; 3]>,
285 pub constant_attenuation: f32,
287 pub linear_attenuation: f32,
289 pub quadratic_attenuation: f32,
291 pub falloff_angle: f32,
293 pub falloff_exponent: f32,
295}
296
297impl SpotLight {
298 pub fn new(color: [f32; 3]) -> Self {
300 Self {
301 color: Box::new(color),
302 constant_attenuation: 0.,
303 linear_attenuation: 0.,
304 quadratic_attenuation: 0.,
305 falloff_angle: 180.,
306 falloff_exponent: 0.,
307 }
308 }
309}
310
311impl XNode for SpotLight {
312 const NAME: &'static str = "spot";
313 fn parse(element: &Element) -> Result<Self> {
314 debug_assert_eq!(element.name(), Self::NAME);
315 let mut it = element.children().peekable();
316 let res = SpotLight {
317 color: parse_one("color", &mut it, parse_array_n)?,
318 constant_attenuation: parse_opt("constant_attenuation", &mut it, parse_elem)?
319 .unwrap_or(0.),
320 linear_attenuation: parse_opt("linear_attenuation", &mut it, parse_elem)?.unwrap_or(0.),
321 quadratic_attenuation: parse_opt("quadratic_attenuation", &mut it, parse_elem)?
322 .unwrap_or(0.),
323 falloff_angle: parse_opt("falloff_angle", &mut it, parse_elem)?.unwrap_or(180.),
324 falloff_exponent: parse_opt("falloff_exponent", &mut it, parse_elem)?.unwrap_or(0.),
325 };
326 finish(res, it)
327 }
328}
329
330impl XNodeWrite for SpotLight {
331 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
332 let e = Self::elem().start(w)?;
333 ElemBuilder::print_arr("color", &*self.color, w)?;
334 ElemBuilder::def_print("constant_attenuation", self.constant_attenuation, 0., w)?;
335 ElemBuilder::def_print("linear_attenuation", self.linear_attenuation, 0., w)?;
336 ElemBuilder::def_print("quadratic_attenuation", self.quadratic_attenuation, 0., w)?;
337 ElemBuilder::def_print("falloff_angle", self.falloff_angle, 180., w)?;
338 ElemBuilder::def_print("falloff_exponent", self.falloff_exponent, 0., w)?;
339 e.end(w)
340 }
341}