use crate::*;
#[derive(Clone, Debug)]
pub struct Light {
pub id: Option<String>,
pub name: Option<String>,
pub asset: Option<Box<Asset>>,
pub kind: LightKind,
pub technique: Vec<Technique>,
pub extra: Vec<Extra>,
}
impl Light {
pub fn new(id: impl Into<String>, name: Option<String>, kind: impl Into<LightKind>) -> Self {
Self {
id: Some(id.into()),
name,
asset: None,
kind: kind.into(),
technique: vec![],
extra: vec![],
}
}
}
impl XNode for Light {
const NAME: &'static str = "light";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
Ok(Light {
id: element.attr("id").map(Into::into),
name: element.attr("name").map(Into::into),
asset: Asset::parse_opt_box(&mut it)?,
kind: parse_one(Technique::COMMON, &mut it, |e| {
let mut it = e.children().peekable();
finish(parse_one_many(&mut it, LightKind::parse)?, it)
})?,
technique: Technique::parse_list(&mut it)?,
extra: Extra::parse_many(it)?,
})
}
}
impl XNodeWrite for Light {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let mut e = Self::elem();
e.opt_attr("id", &self.id);
e.opt_attr("name", &self.name);
let e = e.start(w)?;
self.asset.write_to(w)?;
let common = ElemBuilder::new(Technique::COMMON).start(w)?;
self.kind.write_to(w)?;
common.end(w)?;
self.technique.write_to(w)?;
self.extra.write_to(w)?;
e.end(w)
}
}
#[derive(Clone, Debug)]
pub enum LightKind {
Ambient(AmbientLight),
Directional(DirectionalLight),
Point(Box<PointLight>),
Spot(Box<SpotLight>),
}
impl From<SpotLight> for LightKind {
fn from(v: SpotLight) -> Self {
Self::Spot(Box::new(v))
}
}
impl From<PointLight> for LightKind {
fn from(v: PointLight) -> Self {
Self::Point(Box::new(v))
}
}
impl From<DirectionalLight> for LightKind {
fn from(v: DirectionalLight) -> Self {
Self::Directional(v)
}
}
impl From<AmbientLight> for LightKind {
fn from(v: AmbientLight) -> Self {
Self::Ambient(v)
}
}
impl LightKind {
pub fn parse(e: &Element) -> Result<Option<Self>> {
Ok(Some(match e.name() {
AmbientLight::NAME => Self::Ambient(AmbientLight::parse(e)?),
DirectionalLight::NAME => Self::Directional(DirectionalLight::parse(e)?),
PointLight::NAME => Self::Point(PointLight::parse_box(e)?),
SpotLight::NAME => Self::Spot(SpotLight::parse_box(e)?),
_ => return Ok(None),
}))
}
}
impl XNodeWrite for LightKind {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
match self {
LightKind::Ambient(e) => e.write_to(w),
LightKind::Directional(e) => e.write_to(w),
LightKind::Point(e) => e.write_to(w),
LightKind::Spot(e) => e.write_to(w),
}
}
}
#[derive(Clone, Debug)]
pub struct AmbientLight {
pub color: Box<[f32; 3]>,
}
impl AmbientLight {
pub fn new(color: [f32; 3]) -> Self {
Self {
color: Box::new(color),
}
}
}
impl XNode for AmbientLight {
const NAME: &'static str = "ambient";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
let color = parse_one("color", &mut it, parse_array_n)?;
finish(AmbientLight { color }, it)
}
}
impl XNodeWrite for AmbientLight {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let e = Self::elem().start(w)?;
ElemBuilder::print_arr("color", &*self.color, w)?;
e.end(w)
}
}
#[derive(Clone, Debug)]
pub struct DirectionalLight {
pub color: Box<[f32; 3]>,
}
impl DirectionalLight {
pub fn new(color: [f32; 3]) -> Self {
Self {
color: Box::new(color),
}
}
}
impl XNode for DirectionalLight {
const NAME: &'static str = "directional";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
let color = parse_one("color", &mut it, parse_array_n)?;
finish(DirectionalLight { color }, it)
}
}
impl XNodeWrite for DirectionalLight {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let e = Self::elem().start(w)?;
ElemBuilder::print_arr("color", &*self.color, w)?;
e.end(w)
}
}
#[derive(Clone, Debug)]
pub struct PointLight {
pub color: Box<[f32; 3]>,
pub constant_attenuation: f32,
pub linear_attenuation: f32,
pub quadratic_attenuation: f32,
}
impl PointLight {
pub fn new(color: [f32; 3]) -> Self {
Self {
color: Box::new(color),
constant_attenuation: 0.,
linear_attenuation: 0.,
quadratic_attenuation: 0.,
}
}
}
impl XNode for PointLight {
const NAME: &'static str = "point";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
let res = PointLight {
color: parse_one("color", &mut it, parse_array_n)?,
constant_attenuation: parse_opt("constant_attenuation", &mut it, parse_elem)?
.unwrap_or(0.),
linear_attenuation: parse_opt("linear_attenuation", &mut it, parse_elem)?.unwrap_or(0.),
quadratic_attenuation: parse_opt("quadratic_attenuation", &mut it, parse_elem)?
.unwrap_or(0.),
};
finish(res, it)
}
}
impl XNodeWrite for PointLight {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let e = Self::elem().start(w)?;
ElemBuilder::print_arr("color", &*self.color, w)?;
ElemBuilder::def_print("constant_attenuation", self.constant_attenuation, 0., w)?;
ElemBuilder::def_print("linear_attenuation", self.linear_attenuation, 0., w)?;
ElemBuilder::def_print("quadratic_attenuation", self.quadratic_attenuation, 0., w)?;
e.end(w)
}
}
#[derive(Clone, Debug)]
pub struct SpotLight {
pub color: Box<[f32; 3]>,
pub constant_attenuation: f32,
pub linear_attenuation: f32,
pub quadratic_attenuation: f32,
pub falloff_angle: f32,
pub falloff_exponent: f32,
}
impl SpotLight {
pub fn new(color: [f32; 3]) -> Self {
Self {
color: Box::new(color),
constant_attenuation: 0.,
linear_attenuation: 0.,
quadratic_attenuation: 0.,
falloff_angle: 180.,
falloff_exponent: 0.,
}
}
}
impl XNode for SpotLight {
const NAME: &'static str = "spot";
fn parse(element: &Element) -> Result<Self> {
debug_assert_eq!(element.name(), Self::NAME);
let mut it = element.children().peekable();
let res = SpotLight {
color: parse_one("color", &mut it, parse_array_n)?,
constant_attenuation: parse_opt("constant_attenuation", &mut it, parse_elem)?
.unwrap_or(0.),
linear_attenuation: parse_opt("linear_attenuation", &mut it, parse_elem)?.unwrap_or(0.),
quadratic_attenuation: parse_opt("quadratic_attenuation", &mut it, parse_elem)?
.unwrap_or(0.),
falloff_angle: parse_opt("falloff_angle", &mut it, parse_elem)?.unwrap_or(180.),
falloff_exponent: parse_opt("falloff_exponent", &mut it, parse_elem)?.unwrap_or(0.),
};
finish(res, it)
}
}
impl XNodeWrite for SpotLight {
fn write_to<W: Write>(&self, w: &mut XWriter<W>) -> Result<()> {
let e = Self::elem().start(w)?;
ElemBuilder::print_arr("color", &*self.color, w)?;
ElemBuilder::def_print("constant_attenuation", self.constant_attenuation, 0., w)?;
ElemBuilder::def_print("linear_attenuation", self.linear_attenuation, 0., w)?;
ElemBuilder::def_print("quadratic_attenuation", self.quadratic_attenuation, 0., w)?;
ElemBuilder::def_print("falloff_angle", self.falloff_angle, 180., w)?;
ElemBuilder::def_print("falloff_exponent", self.falloff_exponent, 0., w)?;
e.end(w)
}
}