use std::{path::Path, sync::Arc};
use xml::attribute::OwnedAttribute;
use crate::{
error::Result, properties::Properties, util::*, Color, Map, MapTilesetGid, ResourceCache,
ResourceReader, Tileset,
};
mod image;
pub use image::*;
mod object;
pub use object::*;
mod tile;
pub use tile::*;
mod group;
pub use group::*;
#[derive(Clone, PartialEq, Debug)]
pub(crate) enum LayerDataType {
Tiles(TileLayerData),
Objects(ObjectLayerData),
Image(ImageLayerData),
Group(GroupLayerData),
}
#[derive(Clone, Copy)]
pub(crate) enum LayerTag {
Tiles,
Objects,
Image,
Group,
}
#[derive(Clone, PartialEq, Debug)]
pub struct LayerData {
pub name: String,
id: u32,
pub visible: bool,
pub offset_x: f32,
pub offset_y: f32,
pub parallax_x: f32,
pub parallax_y: f32,
pub opacity: f32,
pub tint_color: Option<Color>,
pub properties: Properties,
pub user_type: Option<String>,
layer_type: LayerDataType,
}
impl LayerData {
#[inline]
pub fn id(&self) -> u32 {
self.id
}
pub(crate) fn new(
parser: &mut impl Iterator<Item = XmlEventResult>,
attrs: Vec<OwnedAttribute>,
tag: LayerTag,
infinite: bool,
map_path: &Path,
tilesets: &[MapTilesetGid],
for_tileset: Option<Arc<Tileset>>,
reader: &mut impl ResourceReader,
cache: &mut impl ResourceCache,
) -> Result<Self> {
let (
opacity,
tint_color,
visible,
offset_x,
offset_y,
parallax_x,
parallax_y,
name,
id,
user_type,
user_class,
) = get_attrs!(
for v in attrs {
Some("opacity") => opacity ?= v.parse(),
Some("tintcolor") => tint_color ?= v.parse(),
Some("visible") => visible ?= v.parse().map(|x:i32| x == 1),
Some("offsetx") => offset_x ?= v.parse(),
Some("offsety") => offset_y ?= v.parse(),
Some("parallaxx") => parallax_x ?= v.parse(),
Some("parallaxy") => parallax_y ?= v.parse(),
Some("name") => name = v,
Some("id") => id ?= v.parse(),
Some("type") => user_type ?= v.parse(),
Some("class") => user_class ?= v.parse(),
}
(opacity, tint_color, visible, offset_x, offset_y, parallax_x, parallax_y, name, id, user_type, user_class)
);
let (ty, properties) = match tag {
LayerTag::Tiles => {
let (ty, properties) = TileLayerData::new(parser, attrs, infinite, tilesets)?;
(LayerDataType::Tiles(ty), properties)
}
LayerTag::Objects => {
let (ty, properties) = ObjectLayerData::new(
parser,
attrs,
Some(tilesets),
for_tileset,
map_path.parent().ok_or(crate::Error::PathIsNotFile)?,
reader,
cache,
)?;
(LayerDataType::Objects(ty), properties)
}
LayerTag::Image => {
let (ty, properties) = ImageLayerData::new(parser, attrs, map_path)?;
(LayerDataType::Image(ty), properties)
}
LayerTag::Group => {
let (ty, properties) = GroupLayerData::new(
parser,
infinite,
map_path,
tilesets,
for_tileset,
reader,
cache,
)?;
(LayerDataType::Group(ty), properties)
}
};
Ok(Self {
visible: visible.unwrap_or(true),
offset_x: offset_x.unwrap_or(0.0),
offset_y: offset_y.unwrap_or(0.0),
parallax_x: parallax_x.unwrap_or(1.0),
parallax_y: parallax_y.unwrap_or(1.0),
opacity: opacity.unwrap_or(1.0),
tint_color,
name: name.unwrap_or_default(),
id: id.unwrap_or(0),
user_type: user_type.or(user_class),
properties,
layer_type: ty,
})
}
}
map_wrapper!(
#[doc = "A generic map layer, accessed via [`Map::layers()`]."]
Layer => LayerData
);
impl<'map> Layer<'map> {
#[inline]
pub fn layer_type(&self) -> LayerType<'map> {
LayerType::new(self.map, &self.data.layer_type)
}
#[inline]
pub fn as_tile_layer(self) -> Option<TileLayer<'map>> {
match self.layer_type() {
LayerType::Tiles(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_object_layer(self) -> Option<ObjectLayer<'map>> {
match self.layer_type() {
LayerType::Objects(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_image_layer(self) -> Option<ImageLayer<'map>> {
match self.layer_type() {
LayerType::Image(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_group_layer(self) -> Option<GroupLayer<'map>> {
match self.layer_type() {
LayerType::Group(x) => Some(x),
_ => None,
}
}
}
#[derive(Debug)]
pub enum LayerType<'map> {
Tiles(TileLayer<'map>),
Objects(ObjectLayer<'map>),
Image(ImageLayer<'map>),
Group(GroupLayer<'map>),
}
impl<'map> LayerType<'map> {
fn new(map: &'map Map, data: &'map LayerDataType) -> Self {
match data {
LayerDataType::Tiles(data) => Self::Tiles(TileLayer::new(map, data)),
LayerDataType::Objects(data) => Self::Objects(ObjectLayer::new(map, data)),
LayerDataType::Image(data) => Self::Image(ImageLayer::new(map, data)),
LayerDataType::Group(data) => Self::Group(GroupLayer::new(map, data)),
}
}
}