texture2ddecoder/
unitycrunch.rs1pub(crate) mod crn_decomp;
2pub(crate) mod crn_unpacker;
3use super::crnlib::{CrnFormat, CrnTextureInfo};
4use crate::bcn;
5use crate::{decode_etc1, decode_etc2_rgb, decode_etc2_rgba8};
6extern crate alloc;
7
8struct CrunchDecodeHandler {
9 format: CrnFormat,
10 dxt_data: alloc::vec::Vec<u8>,
11}
12
13fn unity_crunch_unpack_level(
14 data: &[u8],
15 data_size: u32,
16 level_index: u32,
17) -> Result<CrunchDecodeHandler, &'static str> {
18 let mut tex_info: CrnTextureInfo = CrnTextureInfo::default();
19 if !tex_info.crnd_get_texture_info(data, data_size) {
20 return Err("Invalid crunch texture encoding.");
21 }
22 if tex_info.faces != 1 {
23 return Err("Texture2D must only have 1 number of faces.");
24 }
25 let mut p_context: crn_unpacker::CrnUnpacker<'_> =
26 crn_decomp::crnd_unpack_begin(data, data_size)?;
27 let width = core::cmp::max(1, tex_info.width >> level_index);
28 let height = core::cmp::max(1, tex_info.height >> level_index);
29 let blocks_x: u32 = core::cmp::max(1, (width + 3) >> 2);
30 let blocks_y: u32 = core::cmp::max(1, (height + 3) >> 2);
31 let row_pitch: u32 = blocks_x * crn_decomp::crnd_get_bytes_per_dxt_block(&mut tex_info.format)?;
32 let total_face_size: u32 = row_pitch * blocks_y;
33 match p_context.crnd_unpack_level(total_face_size, row_pitch, level_index) {
34 Ok(res) => Ok(CrunchDecodeHandler {
35 format: tex_info.format,
36 dxt_data: res,
37 }),
38 Err(err) => Err(err),
39 }
40}
41
42pub fn decode_unity_crunch(
43 data: &[u8],
44 width: usize,
45 height: usize,
46 image: &mut [u32],
47) -> Result<(), &'static str> {
48 let handler = unity_crunch_unpack_level(data, data.len() as u32, 0)?;
49 match handler.format {
50 CrnFormat::Dxt1 => bcn::decode_bc1(&handler.dxt_data, width, height, image),
51
52 CrnFormat::Etc1 | CrnFormat::Etc1s => decode_etc1(&handler.dxt_data, width, height, image),
53
54 CrnFormat::CCrnfmtDxt5
55 | CrnFormat::Dxt5CcxY
56 | CrnFormat::Dxt5XGbr
57 | CrnFormat::Dxt5Agbr
58 | CrnFormat::Dxt5XGxR => bcn::decode_bc3(&handler.dxt_data, width, height, image),
59
60 CrnFormat::Dxt5a => bcn::decode_bc4(&handler.dxt_data, width, height, image),
61
62 CrnFormat::DxnXy | CrnFormat::DxnYx => {
63 bcn::decode_bc5(&handler.dxt_data, width, height, image)
64 }
65
66 CrnFormat::Etc2 => decode_etc2_rgb(&handler.dxt_data, width, height, image),
67
68 CrnFormat::Etc2a | CrnFormat::Etc2as => {
69 decode_etc2_rgba8(&handler.dxt_data, width, height, image)
70 }
71
72 _ => Err("Invalid crunch format."),
73 }
74}