#[derive(Debug, Clone)]
pub struct TextureData {
pub width: u32,
pub height: u32,
pub pixels: Vec<u8>,
pub is_animated: bool,
pub frame_count: u32,
}
impl TextureData {
pub fn new(width: u32, height: u32, pixels: Vec<u8>) -> Self {
Self {
width,
height,
pixels,
is_animated: false,
frame_count: 1,
}
}
pub fn placeholder() -> Self {
let size = 16;
let mut pixels = vec![0u8; (size * size * 4) as usize];
for y in 0..size {
for x in 0..size {
let idx = ((y * size + x) * 4) as usize;
let is_magenta = ((x / 2) + (y / 2)) % 2 == 0;
if is_magenta {
pixels[idx] = 255; pixels[idx + 1] = 0; pixels[idx + 2] = 255; pixels[idx + 3] = 255; } else {
pixels[idx] = 0; pixels[idx + 1] = 0; pixels[idx + 2] = 0; pixels[idx + 3] = 255; }
}
}
Self {
width: size,
height: size,
pixels,
is_animated: false,
frame_count: 1,
}
}
pub fn has_transparency(&self) -> bool {
self.pixels.chunks(4).any(|pixel| pixel[3] < 255)
}
pub fn get_pixel(&self, x: u32, y: u32) -> [u8; 4] {
let idx = ((y * self.width + x) * 4) as usize;
[
self.pixels[idx],
self.pixels[idx + 1],
self.pixels[idx + 2],
self.pixels[idx + 3],
]
}
pub fn first_frame(&self) -> TextureData {
if !self.is_animated || self.frame_count <= 1 {
return self.clone();
}
let frame_height = self.height / self.frame_count;
let frame_size = (self.width * frame_height * 4) as usize;
Self {
width: self.width,
height: frame_height,
pixels: self.pixels[..frame_size].to_vec(),
is_animated: false,
frame_count: 1,
}
}
}
pub fn load_texture_from_bytes(data: &[u8]) -> Result<TextureData, image::ImageError> {
let img = image::load_from_memory(data)?;
let rgba = img.to_rgba8();
let (width, height) = rgba.dimensions();
let is_animated = height > width && height % width == 0;
let frame_count = if is_animated { height / width } else { 1 };
Ok(TextureData {
width,
height,
pixels: rgba.into_raw(),
is_animated,
frame_count,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_placeholder_texture() {
let tex = TextureData::placeholder();
assert_eq!(tex.width, 16);
assert_eq!(tex.height, 16);
assert_eq!(tex.pixels.len(), 16 * 16 * 4);
assert!(!tex.has_transparency());
}
#[test]
fn test_get_pixel() {
let tex = TextureData::new(2, 2, vec![255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 255, 255, 255, 255]);
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]); }
#[test]
fn test_has_transparency() {
let opaque = TextureData::new(1, 1, vec![255, 0, 0, 255]);
assert!(!opaque.has_transparency());
let transparent = TextureData::new(1, 1, vec![255, 0, 0, 128]);
assert!(transparent.has_transparency());
}
}