1use crate::*;
2
3#[derive(Clone, Debug)]
5pub struct Render {
6 pub camera_node: UrlRef<Node>,
9 pub layers: Vec<String>,
12 pub instance_effect: Option<Instance<Effect>>,
15}
16
17impl Render {
18 pub fn new(camera_node: Url, layers: Vec<String>, instance_effect: Url) -> Self {
20 Self {
21 camera_node: Ref::new(camera_node),
22 layers,
23 instance_effect: Some(Instance::new(instance_effect)),
24 }
25 }
26}
27
28impl XNode for Render {
29 const NAME: &'static str = "render";
30 fn parse(element: &Element) -> Result<Self> {
31 debug_assert_eq!(element.name(), Self::NAME);
32 let mut it = element.children().peekable();
33 let res = Render {
34 camera_node: parse_attr(element.attr("camera_node"))?
35 .ok_or("missing camera_node attr")?,
36 layers: parse_list("layer", &mut it, parse_text)?,
37 instance_effect: Instance::parse_opt(&mut it)?,
38 };
39 finish(res, it)
40 }
41}
42
43impl XNodeWrite for Render {
44 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
45 let mut e = Self::elem();
46 e.print_attr("camera_node", &self.camera_node);
47 let e = e.start(w)?;
48 many(&self.layers, |e| ElemBuilder::print_str("layer", e, w))?;
49 self.instance_effect.write_to(w)?;
50 e.end(w)
51 }
52}
53
54#[derive(Clone, Debug)]
56pub enum Shader {
57 Blinn(Blinn),
59 Constant(ConstantFx),
61 Lambert(Lambert),
63 Phong(Phong),
66}
67
68impl From<Blinn> for Shader {
69 fn from(v: Blinn) -> Self {
70 Self::Blinn(v)
71 }
72}
73
74impl From<ConstantFx> for Shader {
75 fn from(v: ConstantFx) -> Self {
76 Self::Constant(v)
77 }
78}
79
80impl From<Lambert> for Shader {
81 fn from(v: Lambert) -> Self {
82 Self::Lambert(v)
83 }
84}
85
86impl From<Phong> for Shader {
87 fn from(v: Phong) -> Self {
88 Self::Phong(v)
89 }
90}
91
92impl Shader {
93 pub fn parse(e: &Element) -> Result<Option<Self>> {
95 Ok(Some(match e.name() {
96 Blinn::NAME => Self::Blinn(Blinn::parse(e)?),
97 ConstantFx::NAME => Self::Constant(ConstantFx::parse(e)?),
98 Lambert::NAME => Self::Lambert(Lambert::parse(e)?),
99 Phong::NAME => Self::Phong(Phong::parse(e)?),
100 _ => return Ok(None),
101 }))
102 }
103
104 pub fn on_textures<'a, E>(
106 &'a self,
107 f: &mut impl FnMut(&'a Texture) -> Result<(), E>,
108 ) -> Result<(), E> {
109 match self {
110 Self::Blinn(s) => s.on_textures(f),
111 Self::Constant(s) => s.on_textures(f),
112 Self::Lambert(s) => s.on_textures(f),
113 Self::Phong(s) => s.on_textures(f),
114 }
115 }
116}
117
118impl XNodeWrite for Shader {
119 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
120 match self {
121 Self::Blinn(e) => e.write_to(w),
122 Self::Constant(e) => e.write_to(w),
123 Self::Lambert(e) => e.write_to(w),
124 Self::Phong(e) => e.write_to(w),
125 }
126 }
127}
128
129#[derive(Clone, Default, Debug)]
131pub struct Blinn {
132 pub emission: Option<WithSid<ColorParam>>,
134 pub ambient: Option<WithSid<ColorParam>>,
136 pub diffuse: Option<WithSid<ColorParam>>,
138 pub specular: Option<WithSid<ColorParam>>,
140 pub shininess: Option<WithSid<FloatParam>>,
142 pub reflective: Option<WithSid<ColorParam>>,
144 pub reflectivity: Option<WithSid<FloatParam>>,
147 pub transparent: Option<WithSid<ColorParam>>,
149 pub transparency: Option<WithSid<FloatParam>>,
152 pub index_of_refraction: Option<WithSid<FloatParam>>,
155}
156
157impl XNode for Blinn {
158 const NAME: &'static str = "blinn";
159 fn parse(element: &Element) -> Result<Self> {
160 debug_assert_eq!(element.name(), Self::NAME);
161 let mut it = element.children().peekable();
162 Ok(Blinn {
163 emission: parse_opt("emission", &mut it, WithSid::parse)?,
164 ambient: parse_opt("ambient", &mut it, WithSid::parse)?,
165 diffuse: parse_opt("diffuse", &mut it, WithSid::parse)?,
166 specular: parse_opt("specular", &mut it, WithSid::parse)?,
167 shininess: parse_opt("shininess", &mut it, WithSid::parse)?,
168 reflective: parse_opt("reflective", &mut it, WithSid::parse)?,
169 reflectivity: parse_opt("reflectivity", &mut it, WithSid::parse)?,
170 transparent: parse_opt("transparent", &mut it, WithSid::parse)?,
171 transparency: parse_opt("transparency", &mut it, WithSid::parse)?,
172 index_of_refraction: parse_opt("index_of_refraction", &mut it, WithSid::parse)?,
173 })
174 }
175}
176
177impl XNodeWrite for Blinn {
178 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
179 let e = Self::elem().start(w)?;
180 WithSid::write_opt(&self.emission, "emission", w)?;
181 WithSid::write_opt(&self.ambient, "ambient", w)?;
182 WithSid::write_opt(&self.diffuse, "diffuse", w)?;
183 WithSid::write_opt(&self.specular, "specular", w)?;
184 WithSid::write_opt(&self.shininess, "shininess", w)?;
185 WithSid::write_opt(&self.reflective, "reflective", w)?;
186 WithSid::write_opt(&self.reflectivity, "reflectivity", w)?;
187 WithSid::write_opt(&self.transparent, "transparent", w)?;
188 WithSid::write_opt(&self.transparency, "transparency", w)?;
189 WithSid::write_opt(&self.index_of_refraction, "index_of_refraction", w)?;
190 e.end(w)
191 }
192}
193
194impl Blinn {
195 pub fn on_textures<'a, E>(
197 &'a self,
198 f: &mut impl FnMut(&'a Texture) -> Result<(), E>,
199 ) -> Result<(), E> {
200 on_color_as_texture(&self.emission, f)?;
201 on_color_as_texture(&self.ambient, f)?;
202 on_color_as_texture(&self.diffuse, f)?;
203 on_color_as_texture(&self.specular, f)?;
204 on_color_as_texture(&self.reflective, f)?;
205 on_color_as_texture(&self.transparent, f)
206 }
207}
208
209#[derive(Clone, Default, Debug)]
211pub struct ConstantFx {
212 pub emission: Option<WithSid<ColorParam>>,
214 pub reflective: Option<WithSid<ColorParam>>,
216 pub reflectivity: Option<WithSid<FloatParam>>,
219 pub transparent: Option<WithSid<ColorParam>>,
221 pub transparency: Option<WithSid<FloatParam>>,
224 pub index_of_refraction: Option<WithSid<FloatParam>>,
227}
228
229impl XNode for ConstantFx {
230 const NAME: &'static str = "constant";
231 fn parse(element: &Element) -> Result<Self> {
232 debug_assert_eq!(element.name(), Self::NAME);
233 let mut it = element.children().peekable();
234 Ok(ConstantFx {
235 emission: parse_opt("emission", &mut it, WithSid::parse)?,
236 reflective: parse_opt("reflective", &mut it, WithSid::parse)?,
237 reflectivity: parse_opt("reflectivity", &mut it, WithSid::parse)?,
238 transparent: parse_opt("transparent", &mut it, WithSid::parse)?,
239 transparency: parse_opt("transparency", &mut it, WithSid::parse)?,
240 index_of_refraction: parse_opt("index_of_refraction", &mut it, WithSid::parse)?,
241 })
242 }
243}
244
245impl XNodeWrite for ConstantFx {
246 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
247 let e = Self::elem().start(w)?;
248 WithSid::write_opt(&self.emission, "emission", w)?;
249 WithSid::write_opt(&self.reflective, "reflective", w)?;
250 WithSid::write_opt(&self.reflectivity, "reflectivity", w)?;
251 WithSid::write_opt(&self.transparent, "transparent", w)?;
252 WithSid::write_opt(&self.transparency, "transparency", w)?;
253 WithSid::write_opt(&self.index_of_refraction, "index_of_refraction", w)?;
254 e.end(w)
255 }
256}
257
258impl ConstantFx {
259 pub fn on_textures<'a, E>(
261 &'a self,
262 f: &mut impl FnMut(&'a Texture) -> Result<(), E>,
263 ) -> Result<(), E> {
264 on_color_as_texture(&self.emission, f)?;
265 on_color_as_texture(&self.reflective, f)?;
266 on_color_as_texture(&self.transparent, f)
267 }
268}
269
270#[derive(Clone, Default, Debug)]
272pub struct Lambert {
273 pub emission: Option<WithSid<ColorParam>>,
275 pub ambient: Option<WithSid<ColorParam>>,
277 pub diffuse: Option<WithSid<ColorParam>>,
279 pub reflective: Option<WithSid<ColorParam>>,
281 pub reflectivity: Option<WithSid<FloatParam>>,
284 pub transparent: Option<WithSid<ColorParam>>,
286 pub transparency: Option<WithSid<FloatParam>>,
289 pub index_of_refraction: Option<WithSid<FloatParam>>,
292}
293
294impl XNode for Lambert {
295 const NAME: &'static str = "lambert";
296 fn parse(element: &Element) -> Result<Self> {
297 debug_assert_eq!(element.name(), Self::NAME);
298 let mut it = element.children().peekable();
299 Ok(Lambert {
300 emission: parse_opt("emission", &mut it, WithSid::parse)?,
301 ambient: parse_opt("ambient", &mut it, WithSid::parse)?,
302 diffuse: parse_opt("diffuse", &mut it, WithSid::parse)?,
303 reflective: parse_opt("reflective", &mut it, WithSid::parse)?,
304 reflectivity: parse_opt("reflectivity", &mut it, WithSid::parse)?,
305 transparent: parse_opt("transparent", &mut it, WithSid::parse)?,
306 transparency: parse_opt("transparency", &mut it, WithSid::parse)?,
307 index_of_refraction: parse_opt("index_of_refraction", &mut it, WithSid::parse)?,
308 })
309 }
310}
311
312impl XNodeWrite for Lambert {
313 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
314 let e = Self::elem().start(w)?;
315 WithSid::write_opt(&self.emission, "emission", w)?;
316 WithSid::write_opt(&self.ambient, "ambient", w)?;
317 WithSid::write_opt(&self.diffuse, "diffuse", w)?;
318 WithSid::write_opt(&self.reflective, "reflective", w)?;
319 WithSid::write_opt(&self.reflectivity, "reflectivity", w)?;
320 WithSid::write_opt(&self.transparent, "transparent", w)?;
321 WithSid::write_opt(&self.transparency, "transparency", w)?;
322 WithSid::write_opt(&self.index_of_refraction, "index_of_refraction", w)?;
323 e.end(w)
324 }
325}
326
327impl Lambert {
328 pub fn on_textures<'a, E>(
330 &'a self,
331 f: &mut impl FnMut(&'a Texture) -> Result<(), E>,
332 ) -> Result<(), E> {
333 on_color_as_texture(&self.emission, f)?;
334 on_color_as_texture(&self.ambient, f)?;
335 on_color_as_texture(&self.diffuse, f)?;
336 on_color_as_texture(&self.reflective, f)?;
337 on_color_as_texture(&self.transparent, f)
338 }
339}
340
341#[derive(Clone, Default, Debug)]
344pub struct Phong {
345 pub emission: Option<WithSid<ColorParam>>,
347 pub ambient: Option<WithSid<ColorParam>>,
349 pub diffuse: Option<WithSid<ColorParam>>,
351 pub specular: Option<WithSid<ColorParam>>,
353 pub shininess: Option<WithSid<FloatParam>>,
355 pub reflective: Option<WithSid<ColorParam>>,
357 pub reflectivity: Option<WithSid<FloatParam>>,
360 pub transparent: Option<WithSid<ColorParam>>,
362 pub transparency: Option<WithSid<FloatParam>>,
365 pub index_of_refraction: Option<WithSid<FloatParam>>,
368}
369
370impl XNode for Phong {
371 const NAME: &'static str = "phong";
372 fn parse(element: &Element) -> Result<Self> {
373 debug_assert_eq!(element.name(), Self::NAME);
374 let mut it = element.children().peekable();
375 Ok(Phong {
376 emission: parse_opt("emission", &mut it, WithSid::parse)?,
377 ambient: parse_opt("ambient", &mut it, WithSid::parse)?,
378 diffuse: parse_opt("diffuse", &mut it, WithSid::parse)?,
379 specular: parse_opt("specular", &mut it, WithSid::parse)?,
380 shininess: parse_opt("shininess", &mut it, WithSid::parse)?,
381 reflective: parse_opt("reflective", &mut it, WithSid::parse)?,
382 reflectivity: parse_opt("reflectivity", &mut it, WithSid::parse)?,
383 transparent: parse_opt("transparent", &mut it, WithSid::parse)?,
384 transparency: parse_opt("transparency", &mut it, WithSid::parse)?,
385 index_of_refraction: parse_opt("index_of_refraction", &mut it, WithSid::parse)?,
386 })
387 }
388}
389
390impl XNodeWrite for Phong {
391 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
392 let e = Self::elem().start(w)?;
393 WithSid::write_opt(&self.emission, "emission", w)?;
394 WithSid::write_opt(&self.ambient, "ambient", w)?;
395 WithSid::write_opt(&self.diffuse, "diffuse", w)?;
396 WithSid::write_opt(&self.specular, "specular", w)?;
397 WithSid::write_opt(&self.shininess, "shininess", w)?;
398 WithSid::write_opt(&self.reflective, "reflective", w)?;
399 WithSid::write_opt(&self.reflectivity, "reflectivity", w)?;
400 WithSid::write_opt(&self.transparent, "transparent", w)?;
401 WithSid::write_opt(&self.transparency, "transparency", w)?;
402 WithSid::write_opt(&self.index_of_refraction, "index_of_refraction", w)?;
403 e.end(w)
404 }
405}
406
407impl Phong {
408 pub fn on_textures<'a, E>(
410 &'a self,
411 f: &mut impl FnMut(&'a Texture) -> Result<(), E>,
412 ) -> Result<(), E> {
413 on_color_as_texture(&self.emission, f)?;
414 on_color_as_texture(&self.ambient, f)?;
415 on_color_as_texture(&self.diffuse, f)?;
416 on_color_as_texture(&self.specular, f)?;
417 on_color_as_texture(&self.reflective, f)?;
418 on_color_as_texture(&self.transparent, f)
419 }
420}
421
422#[derive(Clone, Default, Debug)]
424pub struct WithSid<T> {
425 sid: Option<String>,
426 data: T,
427}
428
429impl<T> Deref for WithSid<T> {
430 type Target = T;
431
432 fn deref(&self) -> &Self::Target {
433 &self.data
434 }
435}
436
437pub(crate) use private::CanWithSid;
438pub(crate) mod private {
439 use super::*;
440 pub trait CanWithSid: XNodeWrite + Sized {
441 fn parse(element: &Element) -> Result<Option<Self>>;
442
443 fn write_with_sid<W: Write>(&self, sid: &Option<String>, w: &mut XWriter<W>) -> Result<()>;
444 }
445}
446
447impl<T> From<T> for WithSid<T> {
448 fn from(data: T) -> Self {
449 Self::new(data)
450 }
451}
452
453impl<T> WithSid<T> {
454 pub fn new(data: T) -> Self {
456 Self { sid: None, data }
457 }
458
459 #[allow(clippy::self_named_constructors)]
461 pub fn with_sid(sid: impl Into<String>, data: T) -> Self {
462 Self {
463 sid: Some(sid.into()),
464 data,
465 }
466 }
467}
468
469impl<T: CanWithSid> WithSid<T> {
470 pub fn parse(element: &Element) -> Result<Self> {
472 let mut it = element.children().peekable();
473 parse_one_many(&mut it, |e| {
474 Ok(T::parse(e)?.map(|data| Self {
475 sid: e.attr("sid").map(Into::into),
476 data,
477 }))
478 })
479 }
480
481 fn write_opt(this: &Option<Self>, name: &str, w: &mut XWriter<impl Write>) -> Result<()> {
482 opt(this, |this| {
483 let elem = ElemBuilder::new(name).start(w)?;
484 this.write_to(w)?;
485 elem.end(w)
486 })
487 }
488}
489
490impl<T: CanWithSid> XNodeWrite for WithSid<T> {
491 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
492 self.data.write_with_sid(&self.sid, w)
493 }
494}
495
496#[derive(Clone, Debug)]
499pub enum ColorParam {
500 Color(Box<[f32; 4]>),
502 Param(Box<str>),
505 Texture(Box<Texture>),
507}
508
509impl From<[f32; 4]> for ColorParam {
510 fn from(rgba: [f32; 4]) -> Self {
511 Self::color(rgba)
512 }
513}
514
515impl From<[f32; 4]> for WithSid<ColorParam> {
516 fn from(rgba: [f32; 4]) -> Self {
517 WithSid::new(rgba.into())
518 }
519}
520
521impl From<Texture> for ColorParam {
522 fn from(tex: Texture) -> Self {
523 Self::Texture(Box::new(tex))
524 }
525}
526
527impl From<Texture> for WithSid<ColorParam> {
528 fn from(tex: Texture) -> Self {
529 WithSid::new(tex.into())
530 }
531}
532
533impl ColorParam {
534 pub fn color(rgba: [f32; 4]) -> Self {
536 Self::Color(Box::new(rgba))
537 }
538}
539
540impl CanWithSid for ColorParam {
541 fn parse(e: &Element) -> Result<Option<Self>> {
542 Ok(Some(match e.name() {
543 "color" => Self::Color(parse_array_n(e)?),
544 Param::NAME => Self::Param(e.attr("ref").ok_or("expected ref attr")?.into()),
545 Texture::NAME => Self::Texture(Texture::parse_box(e)?),
546 _ => return Ok(None),
547 }))
548 }
549
550 fn write_with_sid<W: Write>(&self, sid: &Option<String>, w: &mut XWriter<W>) -> Result<()> {
551 match self {
552 Self::Color(arr) => {
553 let mut e = ElemBuilder::new("color");
554 e.opt_attr("sid", sid);
555 let e = e.start(w)?;
556 print_arr(&**arr, w)?;
557 e.end(w)
558 }
559 Self::Param(ref_) => {
560 let mut e = ElemBuilder::new(Param::NAME);
561 e.opt_attr("sid", sid);
562 e.attr("ref", ref_);
563 e.end(w)
564 }
565 Self::Texture(e) => e.write_to(w),
566 }
567 }
568}
569
570impl XNodeWrite for ColorParam {
571 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
572 self.write_with_sid(&None, w)
573 }
574}
575
576impl ColorParam {
577 pub fn as_texture(&self) -> Option<&Texture> {
579 match self {
580 ColorParam::Texture(tex) => Some(tex),
581 _ => None,
582 }
583 }
584
585 pub fn as_color(&self) -> Option<&[f32; 4]> {
587 match self {
588 ColorParam::Color(c) => Some(c),
589 _ => None,
590 }
591 }
592}
593
594#[derive(Clone, Debug)]
597pub enum FloatParam {
598 Float(f32),
600 Param(Box<str>),
603}
604
605impl From<f32> for FloatParam {
606 fn from(val: f32) -> Self {
607 Self::Float(val)
608 }
609}
610
611impl From<f32> for WithSid<FloatParam> {
612 fn from(val: f32) -> Self {
613 WithSid::new(val.into())
614 }
615}
616
617impl CanWithSid for FloatParam {
618 fn parse(e: &Element) -> Result<Option<Self>> {
619 Ok(Some(match e.name() {
620 "float" => Self::Float(parse_elem(e)?),
621 Param::NAME => Self::Param(e.attr("ref").ok_or("expected ref attr")?.into()),
622 _ => return Ok(None),
623 }))
624 }
625
626 fn write_with_sid<W: Write>(&self, sid: &Option<String>, w: &mut XWriter<W>) -> Result<()> {
627 match self {
628 Self::Float(val) => {
629 let mut e = ElemBuilder::new("float");
630 e.opt_attr("sid", sid);
631 let e = e.start(w)?;
632 print_elem(val, w)?;
633 e.end(w)
634 }
635 Self::Param(ref_) => {
636 let mut e = ElemBuilder::new(Param::NAME);
637 e.opt_attr("sid", sid);
638 e.attr("ref", ref_);
639 e.end(w)
640 }
641 }
642 }
643}
644
645impl XNodeWrite for FloatParam {
646 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
647 self.write_with_sid(&None, w)
648 }
649}
650
651#[derive(Clone, Debug)]
653pub struct Texture {
654 pub texture: String,
656 pub texcoord: String,
660 pub extra: Option<Box<Extra>>,
662}
663
664impl Texture {
665 pub fn new(texture: impl Into<String>, texcoord: impl Into<String>) -> Self {
667 Self {
668 texture: texture.into(),
669 texcoord: texcoord.into(),
670 extra: None,
671 }
672 }
673
674 fn write_with_sid<W: Write>(&self, sid: &Option<String>, w: &mut XWriter<W>) -> Result<()> {
675 let mut e = Self::elem();
676 e.opt_attr("sid", sid);
677 e.attr("texture", &self.texture);
678 e.attr("texcoord", &self.texcoord);
679 if let Some(extra) = &self.extra {
680 let e = e.start(w)?;
681 extra.write_to(w)?;
682 e.end(w)
683 } else {
684 e.end(w)
685 }
686 }
687}
688
689impl XNode for Texture {
690 const NAME: &'static str = "texture";
691 fn parse(e: &Element) -> Result<Self> {
692 let mut it = e.children().peekable();
693 let res = Texture {
694 texture: e.attr("texture").ok_or("expected texture attr")?.into(),
695 texcoord: e.attr("texcoord").ok_or("expected texcoord attr")?.into(),
696 extra: Extra::parse_opt_box(&mut it)?,
697 };
698 finish(res, it)
699 }
700}
701
702impl XNodeWrite for Texture {
703 fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
704 self.write_with_sid(&None, w)
705 }
706}
707
708fn on_color_as_texture<'a, E>(
709 opt: &'a Option<WithSid<ColorParam>>,
710 f: &mut impl FnMut(&'a Texture) -> Result<(), E>,
711) -> Result<(), E> {
712 if let Some(WithSid {
713 data: ColorParam::Texture(tex),
714 ..
715 }) = opt
716 {
717 f(tex)?
718 }
719 Ok(())
720}