diff options
Diffstat (limited to 'src/classes/texture2d.rs')
-rw-r--r-- | src/classes/texture2d.rs | 85 |
1 files changed, 59 insertions, 26 deletions
diff --git a/src/classes/texture2d.rs b/src/classes/texture2d.rs index 41820b0..6b96b17 100644 --- a/src/classes/texture2d.rs +++ b/src/classes/texture2d.rs @@ -1,5 +1,8 @@ use super::streaming_info::StreamingInfo; -use crate::object::{Value, parser::FromValue}; +use crate::object::{ + Value, + parser::{Fields, FromValue}, +}; use anyhow::{Result, anyhow, bail}; use image::{DynamicImage, ImageBuffer, Luma, Rgb, Rgba}; use log::info; @@ -14,13 +17,18 @@ pub struct Texture2D { #[serde(skip)] pub image_data: Vec<u8>, pub format: TextureFormat, + pub image_count: i32, pub texture_dimension: i32, pub stream_data: StreamingInfo, } impl FromValue for Texture2D { fn from_value(v: Value) -> Result<Self> { - let mut fields = v.as_class("Texture2D")?; + Self::from_fields(v.as_class("Texture2D")?) + } +} +impl Texture2D { + pub(crate) fn from_fields(mut fields: Fields) -> Result<Self> { Ok(Texture2D { width: fields.field("m_Width")?, height: fields.field("m_Height")?, @@ -28,6 +36,7 @@ impl FromValue for Texture2D { texture_dimension: fields.field("m_TextureDimension")?, format: fields.field("m_TextureFormat")?, name: fields.field("m_Name")?, + image_count: fields.field("m_ImageCount")?, stream_data: fields.field("m_StreamData")?, image_data: fields.remove("image data").unwrap().as_typeless().unwrap(), }) @@ -36,28 +45,40 @@ impl FromValue for Texture2D { impl Texture2D { pub fn to_image(&self) -> Result<DynamicImage> { + Ok(self.to_images()?.remove(0)) + } + pub fn to_images(&self) -> Result<Vec<DynamicImage>> { let w = self.width as usize; let h = self.height as usize; use TextureFormat::*; - let u32_rgba_buf_to_image = |buf: Vec<u32>| { - let buf = buf.into_iter().flat_map(u32::to_be_bytes).collect(); - let mut im = - ImageBuffer::<Rgba<u8>, Vec<_>>::from_raw(w as u32, h as u32, buf).unwrap(); - for p in im.pixels_mut() { - let a = p.0[0]; - p.0[0] = p.0[1]; - p.0[1] = p.0[2]; - p.0[2] = p.0[3]; - p.0[3] = a; + let u32_argb_buf_to_images = |buf: Vec<u32>| { + let buf = buf + .into_iter() + .flat_map(u32::to_be_bytes) + .collect::<Vec<_>>(); + let mut images = Vec::new(); + for buf in buf.chunks_exact(w * h * 4) { + let mut im = + ImageBuffer::<Rgba<u8>, Vec<_>>::from_raw(w as u32, h as u32, buf.to_vec()) + .unwrap(); + for p in im.pixels_mut() { + let a = p.0[0]; + p.0[0] = p.0[1]; + p.0[1] = p.0[2]; + p.0[2] = p.0[3]; + p.0[3] = a; + } + images.push(DynamicImage::from(im)) } - im.into() + images }; match self.format { Alpha8 => { let buf = self.image_data.clone(); let im = ImageBuffer::<Luma<u8>, Vec<_>>::from_raw(w as u32, h as u32, buf).unwrap(); - Ok(im.into()) + assert_eq!(self.image_count, 1); + Ok(vec![im.into()]) } RGBAHalf => { let buf = self @@ -68,11 +89,11 @@ impl Texture2D { .map(|x| u16::from_be_bytes(x)) .map(|x| f16::from_bits(x) as f32) .collect::<Vec<f32>>(); - Ok( + Ok(vec![ ImageBuffer::<Rgba<f32>, Vec<_>>::from_raw(w as u32, h as u32, buf) .unwrap() .into(), - ) + ]) } DXT1 | DXT3 | DXT5 | BC4 | BC5 => { use texpresso::Format as F; @@ -88,11 +109,20 @@ impl Texture2D { "decompressing {w}x{h} {:?} ({:?}) texture", format, self.format ); - let mut buf = vec![0u8; w * h * 4]; + let mut buf = vec![0u8; w * h * 4 * self.image_count as usize]; format.decompress(&self.image_data, w, h, &mut buf); - let im = - ImageBuffer::<Rgba<u8>, Vec<_>>::from_raw(w as u32, h as u32, buf).unwrap(); - Ok(im.into()) + Ok(buf + .chunks_exact(w * h * 4) + .map(|slice| { + ImageBuffer::<Rgba<u8>, Vec<_>>::from_raw( + w as u32, + h as u32, + slice.to_vec(), + ) + .unwrap() + }) + .map(DynamicImage::from) + .collect()) } DXT1Crunched | DXT5Crunched => { info!( @@ -105,19 +135,19 @@ impl Texture2D { ); let mut buf = vec![0u32; w * h]; texture2ddecoder::decode_unity_crunch(&self.image_data, w, h, &mut buf).unwrap(); - Ok(u32_rgba_buf_to_image(buf)) + Ok(u32_argb_buf_to_images(buf)) } BC7 => { info!("decompressing {w}x{h} BC7 texture",); let mut buf = vec![0u32; w * h]; texture2ddecoder::decode_bc7(&self.image_data, w, h, &mut buf).unwrap(); - Ok(u32_rgba_buf_to_image(buf)) + Ok(u32_argb_buf_to_images(buf)) } BC6H => { info!("decompressing {w}x{h} BC6H texture",); let mut buf = vec![0u32; w * h]; texture2ddecoder::decode_bc6(&self.image_data, w, h, &mut buf, false).unwrap(); - Ok(u32_rgba_buf_to_image(buf)) + Ok(u32_argb_buf_to_images(buf)) } RGB24 => { let im = ImageBuffer::<Rgb<u8>, Vec<_>>::from_raw( @@ -126,7 +156,8 @@ impl Texture2D { self.image_data.clone(), ) .unwrap(); - Ok(im.into()) + assert_eq!(self.image_count, 1); + Ok(vec![im.into()]) } ARGB32 => { let mut buf = self.image_data.clone(); @@ -139,13 +170,15 @@ impl Texture2D { } let im = ImageBuffer::<Rgba<u8>, Vec<_>>::from_raw(w as u32, h as u32, buf).unwrap(); - Ok(im.into()) + assert_eq!(self.image_count, 1); + Ok(vec![im.into()]) } RGBA32 => { let buf = self.image_data.clone(); let im = ImageBuffer::<Rgba<u8>, Vec<_>>::from_raw(w as u32, h as u32, buf).unwrap(); - Ok(im.into()) + assert_eq!(self.image_count, 1); + Ok(vec![im.into()]) } x => bail!("texture format {x:?} not supported"), } |