aseprite_loader/binary/chunks/
layer.rs

1use bitflags::bitflags;
2use nom::{bytes::complete::take, combinator::cond, Parser};
3
4use crate::binary::{
5    blend_mode::BlendMode,
6    errors::ParseResult,
7    scalars::{byte, dword, parse_string, word, Byte, Dword, Word},
8};
9
10#[derive(Debug)]
11pub struct LayerChunk<'a> {
12    pub flags: LayerFlags,
13    pub layer_type: LayerType,
14    pub child_level: Word,
15    pub blend_mode: BlendMode,
16    pub opacity: Byte,
17    pub name: &'a str,
18    pub tileset_index: Option<Dword>,
19}
20
21bitflags! {
22    #[derive(Debug)]
23    pub struct LayerFlags: Word {
24        const VISIBLE = 0x1;
25        const EDITABLE = 0x2;
26        const LOCK_MOVEMENT = 0x4;
27        const BACKGROUND = 0x8;
28        const PREFER_LINKED_CELS = 0x16;
29        const COLLAPSED = 0x32;
30        const REFERENCE = 0x64;
31    }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum LayerType {
36    Normal,
37    Group,
38    Tilemap,
39    Unknown(Word),
40}
41
42impl From<Word> for LayerType {
43    fn from(word: Word) -> Self {
44        match word {
45            0 => Self::Normal,
46            1 => Self::Group,
47            2 => Self::Tilemap,
48            n => Self::Unknown(n),
49        }
50    }
51}
52
53pub fn parse_layer_chunk(input: &[u8]) -> ParseResult<'_, LayerChunk<'_>> {
54    let (input, flags) = word(input)?;
55    let flags = LayerFlags::from_bits_truncate(flags);
56    let (input, layer_type) = word(input)?;
57    let layer_type = LayerType::from(layer_type);
58    let (input, child_level) = word(input)?;
59    let (input, _default_layer_width) = word(input)?;
60    let (input, _default_layer_height) = word(input)?;
61    let (input, blend_mode) = word(input)?;
62    let blend_mode = BlendMode::from(blend_mode);
63    let (input, opacity) = byte(input)?;
64    let (input, _) = take(3usize)(input)?;
65    let (input, name) = parse_string(input)?;
66    let (input, tileset_index) =
67        cond(matches!(layer_type, LayerType::Tilemap), dword).parse(input)?;
68    Ok((
69        input,
70        LayerChunk {
71            flags,
72            layer_type,
73            child_level,
74            blend_mode,
75            opacity,
76            name,
77            tileset_index,
78        },
79    ))
80}
81
82#[test]
83fn test_layers() {
84    use crate::binary::file::parse_file;
85    let input = std::fs::read("./tests/layers.aseprite").unwrap();
86    let file = parse_file(&input).unwrap();
87    assert_eq!(file.frames.len(), 1);
88    assert_eq!(file.frames[0].duration, 100);
89    assert_eq!(file.layers.len(), 3);
90    assert_eq!(file.layers[0].name, "Layer 1");
91    assert_eq!(file.layers[1].name, "Layer 2");
92    assert_eq!(file.layers[2].name, "Layer 3");
93}