Skip to main content

tiled_parse/
types.rs

1//! The data types are NOT a one-to-one mapping to how Tiled expresses them in a `.tmx`
2
3use std::{collections::HashMap, path::PathBuf, str::FromStr};
4
5use ndarray::Array2;
6use tiled_parse_tree::Tree;
7
8pub type ID = u32;
9
10pub type PairU32 = (u32, u32);
11pub type PairF32 = (f32, f32);
12
13pub type Properties = HashMap<String, TiledPropertyType>;
14
15#[derive(Debug, Clone)]
16pub enum TiledParseError {
17    ExternalTileSetNotFound(PathBuf),
18    TiledError,
19    TiledNoRootError,
20    XmlParseError,
21}
22
23// TODO: More descriptive.
24impl std::fmt::Display for TiledParseError {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        write!(f, "{:?}", self)
27    }
28}
29
30impl std::error::Error for TiledParseError {}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct Gid(pub u32);
34
35impl FromStr for Gid {
36    type Err = std::num::ParseIntError;
37
38    fn from_str(s: &str) -> Result<Self, Self::Err> {
39        s.parse::<u32>().map(|v| Gid(v))
40    }
41}
42
43impl Gid {
44    /// The GID representing an empty tile in the map.
45    #[allow(dead_code)]
46    pub const EMPTY: Gid = Gid(0);
47}
48
49pub const FLIPPED_HORIZONTALLY_FLAG: u32 = 0x80000000;
50pub const FLIPPED_VERTICALLY_FLAG: u32 = 0x40000000;
51pub const FLIPPED_DIAGONALLY_FLAG: u32 = 0x20000000;
52pub const ALL_FLIP_FLAGS: u32 =
53    FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG;
54
55pub const BASE_LAYER: &str = "map";
56pub const GROUP_LAYER: &str = "group";
57pub const OBJECTGROUP_LAYER: &str = "objectgroup";
58pub const TILE_LAYER: &str = "layer";
59pub const IMAGE_LAYER: &str = "imagelayer";
60
61/// Properties in Tiled Objects.
62#[derive(Clone, Debug)]
63pub enum TiledPropertyType {
64    String(String),
65    Int(i32),
66    Float(f32),
67    Bool(bool),
68    // TODO:
69    // Hex with alpha channel : #AARRGGBB)
70    // Color(Vec<),
71    File(PathBuf),
72    /// Object properties can reference any object on the same map and are stored as an integer (the ID of the referenced object,
73    /// or 0 when no object is referenced). When used on objects in the Tile Collision Editor, they can only refer to other objects on the same tile.
74    Object(ID),
75}
76
77/// Geometries for Tiled Objects.
78#[derive(Debug, Clone)]
79pub enum ObjectType {
80    /// Tiles in an Object layer will be an `ObjectType::Tile`
81    Tile(Gid),
82    Geometry(GeometryType),
83    // TODO: Text
84}
85
86/// Geometries for Tiled Objects.
87#[derive(Debug, Clone)]
88pub enum GeometryType {
89    Rectangle,
90    /// The existing x, y, width and height attributes are used to determine the size.
91    Ellipse,
92    /// The existing x, y, width and height attributes are used to determine the size of the ellipse.
93    Point,
94    /// The existing x and y attributes are used to determine the position of the point.
95    Polygon(Vec<PairF32>),
96    /// The origin for these coordinates is the location of the parent
97    Polyline(Vec<PairF32>),
98}
99
100// TODO:
101// #[derive(Debug)]
102// struct Color {
103//     pub alpha: u8,
104//     pub red: u8,
105//     pub green: u8,
106//     pub blue: u8,
107// }
108
109// pub struct Text {
110//     fontfamily: String,
111//     pixel_size: u32,
112//     wrap: bool,
113//     color:
114// }
115
116// pub struct Tile {
117//     // pub global_id: ID,
118//     pub local_id: ID,
119//     // pub tile_type: String,
120//     pub sub_rect_position: PairU32,
121//     pub sub_rect_size: PairU32,
122//     pub properties: Option<Properties>
123// }
124
125/// A tile placed on a Tile Layer.
126#[derive(Clone, Copy, Debug)]
127pub struct LayerTile {
128    pub tile: Gid,
129    pub flip_h: bool,
130    pub flip_v: bool,
131    pub flip_d: bool,
132}
133
134/// Tiled Object.
135#[derive(Clone, Debug)]
136pub struct Object {
137    pub id: ID,
138    // pub tile_type: String,
139    pub position: PairF32,
140    pub size: Option<PairF32>,
141    pub rotation: f32,
142    pub visible: bool,
143    pub otype: ObjectType,
144    pub properties: Properties,
145}
146
147/// Layer content parameterized by an `enum` containing the data of each respective layer type.
148#[derive(Clone, Debug)]
149pub enum LayerType {
150    TileLayer(Array2<Option<LayerTile>>),
151    ObjectLayer(Vec<Object>),
152    ImageLayer(ImageStuff),
153    /// A group later has no content, just serves as a structural guide.
154    Group,
155}
156
157/// A layer in a Tiled map.
158#[derive(Clone, Debug)]
159pub struct TiledLayer {
160    pub id: ID,
161    pub name: String,
162    // pub class: String,
163    // Cannot be modified in Tiled
164    // _pos: PairU32
165    // Always same as Map size
166    // _size
167    pub content: LayerType,
168    pub visible: bool,
169    pub opacity: f32,
170    pub parallax: (f32, f32),
171    pub properties: Properties,
172}
173
174// TODO:
175// Better name :)
176#[derive(Clone, Debug)]
177pub struct ImageStuff {
178    pub repeatx: bool,
179    pub repeaty: bool,
180    pub image: Image,
181}
182
183#[derive(Clone, Debug)]
184pub struct Image {
185    pub source: PathBuf,
186    pub dimensions: PairU32,
187    // pub color: Color
188}
189
190#[derive(Debug, Copy, Clone)]
191pub struct AnimationFrame {
192    pub tile_id: ID,
193    pub duration: f32
194}
195
196pub type Animation = Vec<AnimationFrame>;
197
198/// Auxillary information about a tile
199#[derive(Debug, Clone)]
200pub struct TileAuxInfo {
201    // Can contain at most one: <properties>, <image> (since 0.9), <objectgroup>, <animation>
202    // pub color: Color,
203    pub animation: Option<Animation>,
204    pub properties: Properties,
205    /// NOTE:
206    /// This is a departure from Tiled's file specification. I don't like the idea of encoding the objects as an entire layer.
207    pub objects: Vec<Object>,
208}
209
210pub enum TiledMapTileSet {
211    Embedded(TileSet),
212    // FIXME: String -> &str
213    External { first_gid: ID, source: String}
214}
215
216#[derive(Debug, Clone)]
217pub struct TileSet {
218    pub tile_size: PairU32,
219    pub first_gid: ID,
220    pub name: String,
221    pub spacing: u8,
222    pub margin: u8,
223    // NOTE:
224    // Removed for now because it's better to rely on `first_gid`
225    // tile_count: u32,
226    //
227    /// Only supports a single Texture Atlas. Undecided on how to represent multiple images
228    pub image: Image,
229    /// This u32 is the LOCAL id of the tile (relative to this tileset)
230    pub tile_stuff: HashMap<u32, TileAuxInfo>,
231}
232
233pub type LayerHierarchy = Tree<TiledLayer>;
234
235#[derive(Debug, Clone)]
236pub struct TiledMap {
237    pub layers: LayerHierarchy,
238    /// Measured in tiles.
239    pub grid_size: PairU32,
240    pub tile_size: PairU32,
241    pub tile_sets: Vec<TileSet>,
242}