aboutsummaryrefslogtreecommitdiff
path: root/src/classes/texture2d.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/classes/texture2d.rs')
-rw-r--r--src/classes/texture2d.rs85
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"),
}