Newer
Older
use std::collections::HashMap;
use xml::attribute::OwnedAttribute;
use crate::{
parse_properties,
util::{get_attrs, map_wrapper, parse_tag, XmlEventResult},
Gid, Map, MapTilesetGid, Properties, Tile, TileId, TiledError, Tileset,
};
mod finite;
mod infinite;
mod util;
pub use finite::*;
pub use infinite::*;
/// Stores the internal tile gid about a layer tile, along with how it is flipped.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct LayerTileData {
/// The index of the tileset this tile's in, relative to the tile's map. Guaranteed to be a
/// valid index of the map tileset container, but **isn't guaranteed to actually contain
/// this tile**.
tileset_index: usize,
/// The local ID of the tile in the tileset it's in.
id: TileId,
flip_h: bool,
flip_v: bool,
flip_d: bool,
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
}
impl LayerTileData {
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;
/// Creates a new [`LayerTileData`] from a [`GID`] plus its flipping bits.
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; // Swap x and y axis (anti-diagonally) [flips over y = -x line]
let flip_h = flags & Self::FLIPPED_HORIZONTALLY_FLAG == Self::FLIPPED_HORIZONTALLY_FLAG; // Flip tile over y axis
let flip_v = flags & Self::FLIPPED_VERTICALLY_FLAG == Self::FLIPPED_VERTICALLY_FLAG; // Flip tile over x axis
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)]
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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), TiledError> {
let ((), (width, height)) = get_attrs!(
attrs,
optionals: [
],
required: [
("width", width, |v: String| v.parse().ok()),
("height", height, |v: String| v.parse().ok()),
],
TiledError::MalformedAttributes("layer parsing error, width and height attributes required".to_string())
);
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!(LayerTile => LayerTileData);
impl<'map> LayerTile<'map> {
/// Get a reference to the layer tile's referenced tile, if it exists.
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
self.get_tileset().get_tile(self.data.id)
}
/// Get a reference to the layer tile's referenced tileset.
pub fn get_tileset(&self) -> &'map Tileset {
// SAFETY: `tileset_index` is guaranteed to be valid
&self.map.tilesets()[self.data.tileset_index]
}
/// Get the layer tile's tileset index. Guaranteed to be a
/// valid index of the map tileset container, but **isn't guaranteed to actually contain
/// this tile**.
///
/// Use [`LayerTile::get_tile`] if you want to obtain the [`Tile`] that this layer tile is
/// referencing.
pub fn tileset_index(&self) -> usize {
self.data.tileset_index
}
/// Get the layer tile's local id within its parent tileset.
pub fn id(&self) -> u32 {
self.data.id
}
/// Whether this tile is flipped on its Y axis (horizontally).
pub fn flip_h(&self) -> bool {
self.data.flip_h
}
/// Whether this tile is flipped on its X axis (vertically).
pub fn flip_v(&self) -> bool {
self.data.flip_v
}
/// Whether this tile is flipped diagonally.
pub fn flip_d(&self) -> bool {
self.data.flip_d
pub enum TileLayer<'map> {
Finite(FiniteTileLayer<'map>),
Infinite(InfiniteTileLayer<'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> {
match self {
TileLayer::Finite(finite) => finite.get_tile(x, y),
TileLayer::Infinite(infinite) => infinite.get_tile(x, y),
}