use std::collections::HashMap;
use xml::attribute::OwnedAttribute;
use crate::{
parse_properties,
util::{get_attrs, map_wrapper, parse_tag, XmlEventResult},
Error, Gid, Map, MapTilesetGid, Properties, Result, Tile, TileId, Tileset,
};
mod finite;
mod infinite;
mod util;
pub use finite::*;
pub use infinite::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct LayerTileData {
tileset_index: usize,
id: TileId,
pub flip_h: bool,
pub flip_v: bool,
pub flip_d: bool,
}
impl LayerTileData {
#[inline]
pub fn tileset_index(&self) -> usize {
self.tileset_index
}
#[inline]
pub fn id(&self) -> TileId {
self.id
}
const FLIPPED_HORIZONTALLY_FLAG: u32 = 0x80000000;
const FLIPPED_VERTICALLY_FLAG: u32 = 0x40000000;
const FLIPPED_DIAGONALLY_FLAG: u32 = 0x20000000;
const ALL_FLIP_FLAGS: u32 = Self::FLIPPED_HORIZONTALLY_FLAG
| Self::FLIPPED_VERTICALLY_FLAG
| Self::FLIPPED_DIAGONALLY_FLAG;
pub(crate) fn from_bits(bits: u32, tilesets: &[MapTilesetGid]) -> Option<Self> {
let flags = bits & Self::ALL_FLIP_FLAGS;
let gid = Gid(bits & !Self::ALL_FLIP_FLAGS);
let flip_d = flags & Self::FLIPPED_DIAGONALLY_FLAG == Self::FLIPPED_DIAGONALLY_FLAG; let flip_h = flags & Self::FLIPPED_HORIZONTALLY_FLAG == Self::FLIPPED_HORIZONTALLY_FLAG; let flip_v = flags & Self::FLIPPED_VERTICALLY_FLAG == Self::FLIPPED_VERTICALLY_FLAG;
if gid == Gid::EMPTY {
None
} else {
let (tileset_index, tileset) = crate::util::get_tileset_for_gid(tilesets, gid)?;
let id = gid.0 - tileset.first_gid.0;
Some(Self {
tileset_index,
id,
flip_h,
flip_v,
flip_d,
})
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum TileLayerData {
Finite(FiniteTileLayerData),
Infinite(InfiniteTileLayerData),
}
impl TileLayerData {
pub(crate) fn new(
parser: &mut impl Iterator<Item = XmlEventResult>,
attrs: Vec<OwnedAttribute>,
infinite: bool,
tilesets: &[MapTilesetGid],
) -> Result<(Self, Properties)> {
let (width, height) = get_attrs!(
for v in attrs {
"width" => width ?= v.parse::<u32>(),
"height" => height ?= v.parse::<u32>(),
}
(width, height)
);
let mut result = Self::Finite(Default::default());
let mut properties = HashMap::new();
parse_tag!(parser, "layer", {
"data" => |attrs| {
if infinite {
result = Self::Infinite(InfiniteTileLayerData::new(parser, attrs, tilesets)?);
} else {
result = Self::Finite(FiniteTileLayerData::new(parser, attrs, width, height, tilesets)?);
}
Ok(())
},
"properties" => |_| {
properties = parse_properties(parser)?;
Ok(())
},
});
Ok((result, properties))
}
}
map_wrapper!(
#[doc = "An instance of a [`Tile`] present in a [`TileLayer`]."]
LayerTile => LayerTileData
);
impl<'map> LayerTile<'map> {
#[inline]
pub fn get_tile(&self) -> Option<Tile<'map>> {
self.get_tileset().get_tile(self.data.id)
}
#[inline]
pub fn get_tileset(&self) -> &'map Tileset {
&self.map.tilesets()[self.data.tileset_index]
}
}
#[derive(Debug)]
pub enum TileLayer<'map> {
Finite(FiniteTileLayer<'map>),
Infinite(InfiniteTileLayer<'map>),
}
impl<'map> TileLayer<'map> {
pub(crate) fn new(map: &'map Map, data: &'map TileLayerData) -> Self {
match data {
TileLayerData::Finite(data) => Self::Finite(FiniteTileLayer::new(map, data)),
TileLayerData::Infinite(data) => Self::Infinite(InfiniteTileLayer::new(map, data)),
}
}
pub fn get_tile(&self, x: i32, y: i32) -> Option<LayerTile<'map>> {
match self {
TileLayer::Finite(finite) => finite.get_tile(x, y),
TileLayer::Infinite(infinite) => infinite.get_tile(x, y),
}
}
pub fn width(&self) -> Option<u32> {
match self {
TileLayer::Finite(finite) => Some(finite.width()),
TileLayer::Infinite(_infinite) => None,
}
}
pub fn height(&self) -> Option<u32> {
match self {
TileLayer::Finite(finite) => Some(finite.height()),
TileLayer::Infinite(_infinite) => None,
}
}
}