schematic_mesher/resource_pack/
texture.rs1#[derive(Debug, Clone)]
5pub struct TextureData {
6 pub width: u32,
8 pub height: u32,
10 pub pixels: Vec<u8>,
12 pub is_animated: bool,
14 pub frame_count: u32,
16}
17
18impl TextureData {
19 pub fn new(width: u32, height: u32, pixels: Vec<u8>) -> Self {
21 Self {
22 width,
23 height,
24 pixels,
25 is_animated: false,
26 frame_count: 1,
27 }
28 }
29
30 pub fn placeholder() -> Self {
32 let size = 16;
33 let mut pixels = vec![0u8; (size * size * 4) as usize];
34
35 for y in 0..size {
36 for x in 0..size {
37 let idx = ((y * size + x) * 4) as usize;
38 let is_magenta = ((x / 2) + (y / 2)) % 2 == 0;
39
40 if is_magenta {
41 pixels[idx] = 255; pixels[idx + 1] = 0; pixels[idx + 2] = 255; pixels[idx + 3] = 255; } else {
46 pixels[idx] = 0; pixels[idx + 1] = 0; pixels[idx + 2] = 0; pixels[idx + 3] = 255; }
51 }
52 }
53
54 Self {
55 width: size,
56 height: size,
57 pixels,
58 is_animated: false,
59 frame_count: 1,
60 }
61 }
62
63 pub fn has_transparency(&self) -> bool {
65 self.pixels.chunks(4).any(|pixel| pixel[3] < 255)
66 }
67
68 pub fn get_pixel(&self, x: u32, y: u32) -> [u8; 4] {
70 let idx = ((y * self.width + x) * 4) as usize;
71 [
72 self.pixels[idx],
73 self.pixels[idx + 1],
74 self.pixels[idx + 2],
75 self.pixels[idx + 3],
76 ]
77 }
78
79 pub fn first_frame(&self) -> TextureData {
81 if !self.is_animated || self.frame_count <= 1 {
82 return self.clone();
83 }
84
85 let frame_height = self.height / self.frame_count;
86 let frame_size = (self.width * frame_height * 4) as usize;
87
88 Self {
89 width: self.width,
90 height: frame_height,
91 pixels: self.pixels[..frame_size].to_vec(),
92 is_animated: false,
93 frame_count: 1,
94 }
95 }
96}
97
98pub fn load_texture_from_bytes(data: &[u8]) -> Result<TextureData, image::ImageError> {
100 let img = image::load_from_memory(data)?;
101 let rgba = img.to_rgba8();
102 let (width, height) = rgba.dimensions();
103
104 let is_animated = height > width && height % width == 0;
106 let frame_count = if is_animated { height / width } else { 1 };
107
108 Ok(TextureData {
109 width,
110 height,
111 pixels: rgba.into_raw(),
112 is_animated,
113 frame_count,
114 })
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_placeholder_texture() {
123 let tex = TextureData::placeholder();
124 assert_eq!(tex.width, 16);
125 assert_eq!(tex.height, 16);
126 assert_eq!(tex.pixels.len(), 16 * 16 * 4);
127 assert!(!tex.has_transparency());
128 }
129
130 #[test]
131 fn test_get_pixel() {
132 let tex = TextureData::new(2, 2, vec![255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255, 255, 255, 255]);
133
134 assert_eq!(tex.get_pixel(0, 0), [255, 0, 0, 255]); assert_eq!(tex.get_pixel(1, 0), [0, 255, 0, 255]); assert_eq!(tex.get_pixel(0, 1), [0, 0, 255, 255]); assert_eq!(tex.get_pixel(1, 1), [255, 255, 255, 255]); }
139
140 #[test]
141 fn test_has_transparency() {
142 let opaque = TextureData::new(1, 1, vec![255, 0, 0, 255]);
143 assert!(!opaque.has_transparency());
144
145 let transparent = TextureData::new(1, 1, vec![255, 0, 0, 128]);
146 assert!(transparent.has_transparency());
147 }
148}