1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
66
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use bitflags::bitflags;
use nom::{
bytes::complete::take,
combinator::{cond, flat_map},
};
use crate::binary::{
errors::ParseResult,
scalars::{dword, parse_string, short, word, Dword, Short, Word},
};
#[derive(Debug)]
pub struct TilesetChunk<'a> {
/// Tileset ID
pub id: Dword,
/// Tileset flags
pub flags: TilesetFlags,
/// Number of tiles
pub number_of_tiles: Dword,
/// Tile Width
pub width: Word,
/// Tile Height
pub height: Word,
/// Base Index: Number to show in the screen from the tile with
/// index 1 and so on (by default this is field is 1, so the data
/// that is displayed is equivalent to the data in memory). But it
/// can be 0 to display zero-based indexing (this field isn't used
/// for the representation of the data in the file, it's just for
/// UI purposes).
pub base_index: Short,
/// Name of the tileset
pub name: &'a str,
/// Link to external file
pub external_file: Option<TilesetExternalFile>,
/// Tiles inside this file
pub tiles: Option<TilesetTiles<'a>>,
}
#[derive(Debug, Copy, Clone)]
pub struct TilesetExternalFile {
/// ID of the external file. This ID is one entry
/// of the the External Files Chunk.
pub external_file_id: Dword,
/// Tileset ID in the external file
pub tileset_id: Dword,
}
#[derive(Debug)]
pub struct TilesetTiles<'a> {
/// Compressed Tileset image (see NOTE.3):
/// (Tile Width) x (Tile Height x Number of Tiles)
pub data: &'a [u8],
}
bitflags! {
#[derive(Debug)]
pub struct TilesetFlags: Dword {
/// 1 - Include link to external file
const EXTERNAL_FILE = 1;
/// 2 - Include tiles inside this file
const TILES = 2;
/// 4 - Tilemaps using this tileset use tile ID=0 as empty tile
/// (this is the new format). In rare cases this bit is off,
/// and the empty tile will be equal to 0xffffffff (used in
/// internal versions of Aseprite)
const TILE_0_EMPTY = 4;
/// 8 - Aseprite will try to match modified tiles with their X
/// flipped version automatically in Auto mode when using
/// this tileset.
const XFLIP = 8;
/// 16 - Same for Y flips
const YFLIP = 16;
/// 32 - Same for D(iagonal) flips
const DFLIP = 32;
}
}
pub fn parse_tileset_chunk(input: &[u8]) -> ParseResult<'_, TilesetChunk<'_>> {
let (input, id) = dword(input)?;
let (input, flags) = dword(input)?;
let flags = TilesetFlags::from_bits_truncate(flags);
let (input, number_of_tiles) = dword(input)?;
let (input, width) = word(input)?;
let (input, height) = word(input)?;
let (input, base_index) = short(input)?;
let (input, _) = take(14usize)(input)?;
let (input, name) = parse_string(input)?;
let (input, external_file) = cond(
flags.contains(TilesetFlags::EXTERNAL_FILE),
parse_external_file,
)(input)?;
let (input, tiles) = cond(flags.contains(TilesetFlags::TILES), parse_tiles)(input)?;
Ok((
input,
TilesetChunk {
id,
flags,
number_of_tiles,
width,
height,
base_index,
name,
external_file,
tiles,
},
))
}
pub fn parse_external_file(input: &[u8]) -> ParseResult<'_, TilesetExternalFile> {
let (input, external_file_id) = dword(input)?;
let (input, tileset_id) = dword(input)?;
Ok((
input,
TilesetExternalFile {
external_file_id,
tileset_id,
},
))
}
use nom::combinator::map;
pub fn parse_tiles(input: &[u8]) -> ParseResult<'_, TilesetTiles<'_>> {
map(flat_map(dword, take), |data| TilesetTiles { data })(input)
}