1use crate::{
2 cel::{Cel, CelId},
3 reader::AseReader,
4 tileset::TilesetsById,
5 user_data::UserData,
6 AsepriteFile, AsepriteParseError, Result,
7};
8use bitflags::bitflags;
9use std::{io::Read, ops::Index};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum LayerType {
14 Image,
16 Group,
19 Tilemap(u32),
23}
24
25bitflags! {
26 #[derive(Debug, Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
31 pub struct LayerFlags: u32 {
32 const VISIBLE = 0x0001;
34 const EDITABLE = 0x0002;
36 const MOVEMENT_LOCKED = 0x0004;
38 const BACKGROUND = 0x0008;
40 const CONTINUOUS = 0x0010;
42 const COLLAPSED = 0x0020;
44 const REFERENCE = 0x0040;
46
47 const BACKGROUND_LAYER = Self::MOVEMENT_LOCKED.bits() | Self::BACKGROUND.bits();
49 }
50}
51
52#[derive(Debug)]
54pub struct Layer<'a> {
55 pub(crate) file: &'a AsepriteFile,
56 pub(crate) layer_id: u32,
57}
58
59impl<'a> Layer<'a> {
60 fn data(&self) -> &LayerData {
61 &self.file.layers[self.layer_id]
62 }
63
64 pub fn id(&self) -> u32 {
66 self.layer_id
67 }
68
69 pub fn flags(&self) -> LayerFlags {
71 self.data().flags
72 }
73
74 pub fn name(&self) -> &str {
76 &self.data().name
77 }
78
79 pub fn blend_mode(&self) -> BlendMode {
82 self.data().blend_mode
83 }
84
85 pub fn opacity(&self) -> u8 {
87 self.data().opacity
88 }
89
90 pub fn layer_type(&self) -> LayerType {
92 self.data().layer_type
93 }
94
95 pub fn is_tilemap(&self) -> bool {
97 matches!(self.layer_type(), LayerType::Tilemap(_))
98 }
99
100 pub fn parent(&self) -> Option<Layer> {
106 self.file.layers.parents[self.layer_id as usize].map(|id| Layer {
107 file: self.file,
108 layer_id: id,
109 })
110 }
111
112 pub fn is_visible(&self) -> bool {
115 let layer_is_visible = self.data().flags.contains(LayerFlags::VISIBLE);
116 let parent_is_visible = self.parent().map(|p| p.is_visible()).unwrap_or(true);
117 layer_is_visible && parent_is_visible
118 }
119
120 pub fn frame(&self, frame_id: u32) -> Cel {
122 assert!(frame_id < self.file.num_frames());
123 let cel_id = CelId {
124 frame: frame_id as u16,
125 layer: self.layer_id as u16,
126 };
127 Cel {
128 file: self.file,
129 cel_id,
130 }
131 }
132
133 pub fn user_data(&self) -> Option<&UserData> {
135 self.data().user_data.as_ref()
136 }
137}
138
139#[derive(Debug)]
140pub struct LayerData {
141 pub(crate) flags: LayerFlags,
142 pub(crate) name: String,
143 pub(crate) blend_mode: BlendMode,
144 pub(crate) opacity: u8,
145 pub(crate) layer_type: LayerType,
146 pub(crate) user_data: Option<UserData>,
147 child_level: u16,
148}
149
150impl LayerData {
151 pub(crate) fn is_background(&self) -> bool {
152 self.flags.contains(LayerFlags::BACKGROUND)
153 }
154}
155
156#[derive(Debug)]
157pub(crate) struct LayersData {
158 pub(crate) layers: Vec<LayerData>,
161 parents: Vec<Option<u32>>,
162}
163
164impl LayersData {
165 pub(crate) fn validate(&self, tilesets: &TilesetsById) -> Result<()> {
166 for l in &self.layers {
167 if let LayerType::Tilemap(id) = l.layer_type {
168 tilesets.get(id).ok_or_else(|| {
170 AsepriteParseError::InvalidInput(format!(
171 "Tilemap layer references a missing tileset (id {}",
172 id
173 ))
174 })?;
175 }
176 }
177 Ok(())
178 }
179
180 pub(crate) fn from_vec(layers: Vec<LayerData>) -> Result<Self> {
181 let parents = compute_parents(&layers);
183 Ok(LayersData { layers, parents })
184 }
185}
186
187impl Index<u32> for LayersData {
188 type Output = LayerData;
189
190 fn index(&self, index: u32) -> &Self::Output {
191 &self.layers[index as usize]
192 }
193}
194
195#[allow(missing_docs)]
202#[derive(Debug, Clone, Copy, PartialEq, Eq)]
203pub enum BlendMode {
204 Normal,
205 Multiply,
206 Screen,
207 Overlay,
208 Darken,
209 Lighten,
210 ColorDodge,
211 ColorBurn,
212 HardLight,
213 SoftLight,
214 Difference,
215 Exclusion,
216 Hue,
217 Saturation,
218 Color,
219 Luminosity,
220 Addition,
221 Subtract,
222 Divide,
223}
224
225pub(crate) fn parse_chunk(data: &[u8]) -> Result<LayerData> {
226 let mut reader = AseReader::new(data);
227
228 let flags = reader.word()?;
229 let layer_type = reader.word()?;
230 let child_level = reader.word()?;
231 let _default_width = reader.word()?;
232 let _default_height = reader.word()?;
233 let blend_mode = reader.word()?;
234 let opacity = reader.byte()?;
235 let _reserved1 = reader.byte()?;
236 let _reserved2 = reader.word()?;
237 let name = reader.string()?;
238 let layer_type = parse_layer_type(layer_type, &mut reader)?;
239
240 let flags = LayerFlags::from_bits_truncate(flags as u32);
241
242 let blend_mode = parse_blend_mode(blend_mode)?;
243
244 Ok(LayerData {
250 flags,
251 name,
252 blend_mode,
253 opacity,
254 layer_type,
255 child_level,
256 user_data: None,
257 })
258}
259
260fn parse_layer_type<R: Read>(id: u16, reader: &mut AseReader<R>) -> Result<LayerType> {
261 match id {
262 0 => Ok(LayerType::Image),
263 1 => Ok(LayerType::Group),
264 2 => reader.dword().map(LayerType::Tilemap),
265 _ => Err(AsepriteParseError::InvalidInput(format!(
266 "Invalid layer type: {}",
267 id
268 ))),
269 }
270}
271
272fn parse_blend_mode(id: u16) -> Result<BlendMode> {
273 match id {
274 0 => Ok(BlendMode::Normal),
275 1 => Ok(BlendMode::Multiply),
276 2 => Ok(BlendMode::Screen),
277 3 => Ok(BlendMode::Overlay),
278 4 => Ok(BlendMode::Darken),
279 5 => Ok(BlendMode::Lighten),
280 6 => Ok(BlendMode::ColorDodge),
281 7 => Ok(BlendMode::ColorBurn),
282 8 => Ok(BlendMode::HardLight),
283 9 => Ok(BlendMode::SoftLight),
284 10 => Ok(BlendMode::Difference),
285 11 => Ok(BlendMode::Exclusion),
286 12 => Ok(BlendMode::Hue),
287 13 => Ok(BlendMode::Saturation),
288 14 => Ok(BlendMode::Color),
289 15 => Ok(BlendMode::Luminosity),
290 16 => Ok(BlendMode::Addition),
291 17 => Ok(BlendMode::Subtract),
292 18 => Ok(BlendMode::Divide),
293 _ => Err(AsepriteParseError::InvalidInput(format!(
294 "Invalid/Unsupported blend mode: {}",
295 id
296 ))),
297 }
298}
299
300fn compute_parents(layers: &[LayerData]) -> Vec<Option<u32>> {
301 let mut result = Vec::with_capacity(layers.len());
302
303 for id in 0..layers.len() {
304 let parent = {
305 let my_child_level = layers[id].child_level;
306 if my_child_level == 0 {
307 None
308 } else {
309 let mut parent_candidate = id - 1;
311 while layers[parent_candidate].child_level >= my_child_level {
312 assert!(parent_candidate > 0);
313 parent_candidate -= 1;
314 }
315 Some(parent_candidate as u32)
316 }
317 };
318 result.push(parent);
319 }
320 result
321}