diff --git a/assets/tiled_flipped.tmx b/assets/tiled_flipped.tmx new file mode 100644 index 0000000000000000000000000000000000000000..b27c0757f8ac48934b4041db29ea6c7a6aed8b08 --- /dev/null +++ b/assets/tiled_flipped.tmx @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<map version="1.2" tiledversion="1.2.5" orientation="orthogonal" renderorder="right-down" width="2" height="2" tilewidth="32" tileheight="32" infinite="0" nextlayerid="2" nextobjectid="1"> + <tileset firstgid="1" source="tilesheet.tsx"/> + <layer id="1" name="Tile Layer 1" width="2" height="2"> + <data encoding="csv"> +3758096387,1073741827, +2147483651,536870915 +</data> + </layer> +</map> diff --git a/src/lib.rs b/src/lib.rs index be48dd690a9b0f973ce86c55709e0c04245d49dd..6879b68693b168a70b5d4a0cfbfbe7d64696511f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -511,8 +511,6 @@ impl Tileset { #[derive(Debug, PartialEq, Clone)] pub struct Tile { pub id: u32, - pub flip_h: bool, - pub flip_v: bool, pub images: Vec<Image>, pub properties: Properties, pub objectgroup: Option<ObjectGroup>, @@ -521,12 +519,6 @@ pub struct Tile { pub probability: f32, } -const FLIPPED_HORIZONTALLY_FLAG: u32 = 0x8; -const FLIPPED_VERTICALLY_FLAG: u32 = 0x4; -const FLIPPED_DIAGONALLY_FLAG: u32 = 0x2; -const ALL_FLIP_FLAGS: u32 = - FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG; - impl Tile { fn new<R: Read>( parser: &mut EventReader<R>, @@ -544,12 +536,6 @@ impl Tile { TiledError::MalformedAttributes("tile must have an id with the correct type".to_string()) ); - let flags = (id & ALL_FLIP_FLAGS) >> 28; - let id: u32 = id & !ALL_FLIP_FLAGS; - let diagon = flags & FLIPPED_DIAGONALLY_FLAG == FLIPPED_DIAGONALLY_FLAG; - let flip_h = (flags & FLIPPED_HORIZONTALLY_FLAG == FLIPPED_HORIZONTALLY_FLAG) ^ diagon; - let flip_v = (flags & FLIPPED_VERTICALLY_FLAG == FLIPPED_VERTICALLY_FLAG) ^ diagon; - let mut images = Vec::new(); let mut properties = HashMap::new(); let mut objectgroup = None; @@ -574,8 +560,6 @@ impl Tile { }); Ok(Tile { id, - flip_h, - flip_v, images, properties, objectgroup, @@ -623,6 +607,39 @@ impl Image { } } +/// Stores the proper tile gid, along with how it is flipped. +// Maybe PartialEq and Eq should be custom, so that it ignores tile-flipping? +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LayerTile { + pub gid: u32, + pub flip_h: bool, + pub flip_v: bool, + pub flip_d: bool, +} + +const FLIPPED_HORIZONTALLY_FLAG: u32 = 0x80000000; +const FLIPPED_VERTICALLY_FLAG: u32 = 0x40000000; +const FLIPPED_DIAGONALLY_FLAG: u32 = 0x20000000; +const ALL_FLIP_FLAGS: u32 = + FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG; + +impl LayerTile { + pub fn new(id: u32) -> LayerTile { + let flags = id & ALL_FLIP_FLAGS; + let gid = id & !ALL_FLIP_FLAGS; + let flip_d = flags & FLIPPED_DIAGONALLY_FLAG == FLIPPED_DIAGONALLY_FLAG; // Swap x and y axis (anti-diagonally) [flips over y = -x line] + let flip_h = flags & FLIPPED_HORIZONTALLY_FLAG == FLIPPED_HORIZONTALLY_FLAG; // Flip tile over y axis + let flip_v = flags & FLIPPED_VERTICALLY_FLAG == FLIPPED_VERTICALLY_FLAG; // Flip tile over x axis + + LayerTile { + gid, + flip_h, + flip_v, + flip_d, + } + } +} + #[derive(Debug, PartialEq, Clone)] pub struct Layer { pub name: String, @@ -630,7 +647,7 @@ pub struct Layer { pub visible: bool, /// The tiles are arranged in rows. Each tile is a number which can be used /// to find which tileset it belongs to and can then be rendered. - pub tiles: Vec<Vec<u32>>, + pub tiles: Vec<Vec<LayerTile>>, pub properties: Properties, pub layer_index: u32, } @@ -971,7 +988,7 @@ fn parse_data<R: Read>( parser: &mut EventReader<R>, attrs: Vec<OwnedAttribute>, width: u32, -) -> Result<Vec<Vec<u32>>, TiledError> { +) -> Result<Vec<Vec<LayerTile>>, TiledError> { let ((e, c), ()) = get_attrs!( attrs, optionals: [ @@ -989,7 +1006,7 @@ fn parse_data<R: Read>( )) } (Some(e), None) => match e.as_ref() { - "base64" => return parse_base64(parser).map(|v| convert_to_u32(&v, width)), + "base64" => return parse_base64(parser).map(|v| convert_to_tile(&v, width)), "csv" => return decode_csv(parser), e => return Err(TiledError::Other(format!("Unknown encoding format {}", e))), }, @@ -997,12 +1014,12 @@ fn parse_data<R: Read>( ("base64", "zlib") => { return parse_base64(parser) .and_then(decode_zlib) - .map(|v| convert_to_u32(&v, width)) + .map(|v| convert_to_tile(&v, width)) } ("base64", "gzip") => { return parse_base64(parser) .and_then(decode_gzip) - .map(|v| convert_to_u32(&v, width)) + .map(|v| convert_to_tile(&v, width)) } (e, c) => { return Err(TiledError::Other(format!( @@ -1054,11 +1071,11 @@ fn decode_gzip(data: Vec<u8>) -> Result<Vec<u8>, TiledError> { Ok(data) } -fn decode_csv<R: Read>(parser: &mut EventReader<R>) -> Result<Vec<Vec<u32>>, TiledError> { +fn decode_csv<R: Read>(parser: &mut EventReader<R>) -> Result<Vec<Vec<LayerTile>>, TiledError> { loop { match try!(parser.next().map_err(TiledError::XmlDecodingError)) { XmlEvent::Characters(s) => { - let mut rows: Vec<Vec<u32>> = Vec::new(); + let mut rows: Vec<Vec<LayerTile>> = Vec::new(); for row in s.split('\n') { if row.trim() == "" { continue; @@ -1067,6 +1084,7 @@ fn decode_csv<R: Read>(parser: &mut EventReader<R>) -> Result<Vec<Vec<u32>>, Til row.split(',') .filter(|v| v.trim() != "") .map(|v| v.replace('\r', "").parse().unwrap()) + .map(|id| LayerTile::new(id)) .collect(), ); } @@ -1082,7 +1100,7 @@ fn decode_csv<R: Read>(parser: &mut EventReader<R>) -> Result<Vec<Vec<u32>>, Til } } -fn convert_to_u32(all: &Vec<u8>, width: u32) -> Vec<Vec<u32>> { +fn convert_to_tile(all: &Vec<u8>, width: u32) -> Vec<Vec<LayerTile>> { let mut data = Vec::new(); for chunk in all.chunks((width * 4) as usize) { let mut row = Vec::new(); @@ -1092,6 +1110,7 @@ fn convert_to_u32(all: &Vec<u8>, width: u32) -> Vec<Vec<u32>> { + ((chunk[start + 2] as u32) << 16) + ((chunk[start + 1] as u32) << 8) + chunk[start] as u32; + let n = LayerTile::new(n); row.push(n); } data.push(row); diff --git a/tests/lib.rs b/tests/lib.rs index bf4b2739235e27e8bc437ab69fda5dce2e24c327..f5e8bd64a6d1549fded8d6a410a7770e8054eee4 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -79,3 +79,27 @@ fn test_object_group_property() { }; assert!(prop_value); } + +#[test] +fn test_flipped_gid() { + let r = read_from_file_with_path(&Path::new("assets/tiled_flipped.tmx")).unwrap(); + let t1 = r.layers[0].tiles[0][0]; + let t2 = r.layers[0].tiles[0][1]; + let t3 = r.layers[0].tiles[1][0]; + let t4 = r.layers[0].tiles[1][1]; + assert_eq!(t1.gid, t2.gid); + assert_eq!(t2.gid, t3.gid); + assert_eq!(t3.gid, t4.gid); + assert!(t1.flip_d); + assert!(t1.flip_h); + assert!(t1.flip_v); + assert!(!t2.flip_d); + assert!(!t2.flip_h); + assert!(t2.flip_v); + assert!(!t3.flip_d); + assert!(t3.flip_h); + assert!(!t3.flip_v); + assert!(t4.flip_d); + assert!(!t4.flip_h); + assert!(!t4.flip_v); +}