combs_mesh/blocks/
image.rs1use serde::{Deserialize, Serialize};
4
5use crate::error::{MeshError, Result};
6
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct ImageBlock {
10 #[serde(default)]
12 pub name: String,
13 pub atlas: SpriteAtlas,
15}
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
20pub struct SpriteAtlas {
21 pub width: u32,
23 pub height: u32,
25 pub frame_width: u32,
27 pub frame_height: u32,
29 pub frame_count: u32,
31 pub rgba: Vec<u8>,
33}
34
35impl SpriteAtlas {
36 pub fn validate(&self) -> Result<()> {
38 let expected = self.width as usize * self.height as usize * 4;
39 if self.rgba.len() != expected {
40 return Err(MeshError::InvalidBlock(format!(
41 "atlas {}x{} expects {expected} RGBA bytes, got {}",
42 self.width,
43 self.height,
44 self.rgba.len()
45 )));
46 }
47 if self.frame_width == 0 || self.frame_height == 0 {
48 return Err(MeshError::InvalidBlock(
49 "frame dimensions must be non-zero".into(),
50 ));
51 }
52 if self.frame_width > self.width || self.frame_height > self.height {
53 return Err(MeshError::InvalidBlock(format!(
54 "frame {}x{} exceeds atlas {}x{}",
55 self.frame_width, self.frame_height, self.width, self.height
56 )));
57 }
58 let capacity = (self.width / self.frame_width) * (self.height / self.frame_height);
59 if self.frame_count == 0 || self.frame_count > capacity {
60 return Err(MeshError::InvalidBlock(format!(
61 "frame_count {} does not fit {} frames in atlas",
62 self.frame_count, capacity
63 )));
64 }
65 Ok(())
66 }
67}