unity_asset_decode/texture/decoders/
mobile.rs1use super::{Decoder, create_rgba_image, validate_dimensions};
7use crate::error::{BinaryError, Result};
8use crate::texture::formats::TextureFormat;
9use crate::texture::types::Texture2D;
10use image::RgbaImage;
11
12pub struct MobileDecoder;
14
15impl MobileDecoder {
16 pub fn new() -> Self {
18 Self
19 }
20
21 #[cfg(feature = "texture-advanced")]
23 fn decode_etc2_rgb(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
24 validate_dimensions(width, height)?;
25
26 let mut output = vec![0u32; (width * height) as usize];
27
28 match texture2ddecoder::decode_etc2_rgb(data, width as usize, height as usize, &mut output)
29 {
30 Ok(_) => {
31 let rgba_data: Vec<u8> = output
33 .iter()
34 .flat_map(|&pixel| {
35 [
36 (pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, 255, ]
41 })
42 .collect();
43
44 create_rgba_image(rgba_data, width, height)
45 }
46 Err(e) => Err(BinaryError::generic(format!(
47 "ETC2 RGB decoding failed: {}",
48 e
49 ))),
50 }
51 }
52
53 #[cfg(feature = "texture-advanced")]
55 fn decode_etc2_rgba8(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
56 validate_dimensions(width, height)?;
57
58 let mut output = vec![0u32; (width * height) as usize];
59
60 match texture2ddecoder::decode_etc2_rgba8(
61 data,
62 width as usize,
63 height as usize,
64 &mut output,
65 ) {
66 Ok(_) => {
67 let rgba_data: Vec<u8> = output
69 .iter()
70 .flat_map(|&pixel| {
71 [
72 (pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
77 })
78 .collect();
79
80 create_rgba_image(rgba_data, width, height)
81 }
82 Err(e) => Err(BinaryError::generic(format!(
83 "ETC2 RGBA8 decoding failed: {}",
84 e
85 ))),
86 }
87 }
88
89 #[cfg(feature = "texture-advanced")]
91 fn decode_astc_4x4(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
92 validate_dimensions(width, height)?;
93
94 let mut output = vec![0u32; (width * height) as usize];
95
96 match texture2ddecoder::decode_astc(
97 data,
98 width as usize,
99 height as usize,
100 4,
101 4,
102 &mut output,
103 ) {
104 Ok(_) => {
105 let rgba_data: Vec<u8> = output
107 .iter()
108 .flat_map(|&pixel| {
109 [
110 (pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
115 })
116 .collect();
117
118 create_rgba_image(rgba_data, width, height)
119 }
120 Err(e) => Err(BinaryError::generic(format!(
121 "ASTC 4x4 decoding failed: {}",
122 e
123 ))),
124 }
125 }
126
127 #[cfg(feature = "texture-advanced")]
129 fn decode_astc_6x6(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
130 validate_dimensions(width, height)?;
131
132 let mut output = vec![0u32; (width * height) as usize];
133
134 match texture2ddecoder::decode_astc(
135 data,
136 width as usize,
137 height as usize,
138 6,
139 6,
140 &mut output,
141 ) {
142 Ok(_) => {
143 let rgba_data: Vec<u8> = output
145 .iter()
146 .flat_map(|&pixel| {
147 [
148 (pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
153 })
154 .collect();
155
156 create_rgba_image(rgba_data, width, height)
157 }
158 Err(e) => Err(BinaryError::generic(format!(
159 "ASTC 6x6 decoding failed: {}",
160 e
161 ))),
162 }
163 }
164
165 #[cfg(feature = "texture-advanced")]
167 fn decode_astc_8x8(&self, data: &[u8], width: u32, height: u32) -> Result<RgbaImage> {
168 validate_dimensions(width, height)?;
169
170 let mut output = vec![0u32; (width * height) as usize];
171
172 match texture2ddecoder::decode_astc(
173 data,
174 width as usize,
175 height as usize,
176 8,
177 8,
178 &mut output,
179 ) {
180 Ok(_) => {
181 let rgba_data: Vec<u8> = output
183 .iter()
184 .flat_map(|&pixel| {
185 [
186 (pixel & 0xFF) as u8, ((pixel >> 8) & 0xFF) as u8, ((pixel >> 16) & 0xFF) as u8, ((pixel >> 24) & 0xFF) as u8, ]
191 })
192 .collect();
193
194 create_rgba_image(rgba_data, width, height)
195 }
196 Err(e) => Err(BinaryError::generic(format!(
197 "ASTC 8x8 decoding failed: {}",
198 e
199 ))),
200 }
201 }
202
203 #[cfg(not(feature = "texture-advanced"))]
205 fn decode_unsupported(&self, format: TextureFormat) -> Result<RgbaImage> {
206 Err(BinaryError::unsupported(format!(
207 "Mobile format {:?} requires texture-advanced feature",
208 format
209 )))
210 }
211}
212
213impl Decoder for MobileDecoder {
214 fn decode(&self, texture: &Texture2D) -> Result<RgbaImage> {
215 let width = texture.width as u32;
216 let height = texture.height as u32;
217 let data = &texture.image_data;
218
219 match texture.format {
220 #[cfg(feature = "texture-advanced")]
221 TextureFormat::ETC2_RGB => self.decode_etc2_rgb(data, width, height),
222 #[cfg(feature = "texture-advanced")]
223 TextureFormat::ETC2_RGBA8 => self.decode_etc2_rgba8(data, width, height),
224 #[cfg(feature = "texture-advanced")]
225 TextureFormat::ASTC_RGBA_4x4 => self.decode_astc_4x4(data, width, height),
226 #[cfg(feature = "texture-advanced")]
227 TextureFormat::ASTC_RGBA_6x6 => self.decode_astc_6x6(data, width, height),
228 #[cfg(feature = "texture-advanced")]
229 TextureFormat::ASTC_RGBA_8x8 => self.decode_astc_8x8(data, width, height),
230
231 #[cfg(not(feature = "texture-advanced"))]
232 format if format.is_mobile_format() => self.decode_unsupported(format),
233
234 _ => Err(BinaryError::unsupported(format!(
235 "Format {:?} is not a mobile format",
236 texture.format
237 ))),
238 }
239 }
240
241 fn can_decode(&self, format: TextureFormat) -> bool {
242 #[cfg(feature = "texture-advanced")]
243 {
244 matches!(
245 format,
246 TextureFormat::ETC2_RGB
247 | TextureFormat::ETC2_RGBA8
248 | TextureFormat::ASTC_RGBA_4x4
249 | TextureFormat::ASTC_RGBA_6x6
250 | TextureFormat::ASTC_RGBA_8x8
251 )
252 }
253
254 #[cfg(not(feature = "texture-advanced"))]
255 {
256 false
257 }
258 }
259
260 fn supported_formats(&self) -> Vec<TextureFormat> {
261 #[cfg(feature = "texture-advanced")]
262 {
263 vec![
264 TextureFormat::ETC2_RGB,
265 TextureFormat::ETC2_RGBA8,
266 TextureFormat::ASTC_RGBA_4x4,
267 TextureFormat::ASTC_RGBA_6x6,
268 TextureFormat::ASTC_RGBA_8x8,
269 ]
270 }
271
272 #[cfg(not(feature = "texture-advanced"))]
273 {
274 vec![]
275 }
276 }
277}
278
279impl Default for MobileDecoder {
280 fn default() -> Self {
281 Self::new()
282 }
283}