1use crate::error::{IffError, Result};
31use crate::texture::Region;
32use crate::warp::WarpField;
33use crate::wavelet::WaveletDecomposition;
34use crate::compression::{compress_rle, decompress_rle};
35use crate::MAGIC;
36use serde::{Deserialize, Serialize};
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
40pub struct Version {
41 pub major: u8,
42 pub minor: u8,
43}
44
45impl Version {
46 pub const CURRENT: Version = Version { major: 0, minor: 2 };
48
49 pub fn is_compatible(&self, other: &Version) -> bool {
51 self.major == other.major
52 }
53}
54
55#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
57pub struct Flags {
58 pub has_alpha: bool,
60 pub lossless: bool,
62 pub gpu_optimized: bool,
64 pub ycocg_420: bool,
66}
67
68impl Default for Flags {
69 fn default() -> Self {
70 Flags {
71 has_alpha: false,
72 lossless: false,
73 gpu_optimized: true,
74 ycocg_420: true,
75 }
76 }
77}
78
79impl Flags {
80 pub fn to_byte(&self) -> u8 {
82 let mut byte = 0u8;
83 if self.has_alpha {
84 byte |= 0x01;
85 }
86 if self.lossless {
87 byte |= 0x02;
88 }
89 if self.gpu_optimized {
90 byte |= 0x04;
91 }
92 if self.ycocg_420 {
93 byte |= 0x08;
94 }
95 byte
96 }
97
98 pub fn from_byte(byte: u8) -> Self {
100 Flags {
101 has_alpha: (byte & 0x01) != 0,
102 lossless: (byte & 0x02) != 0,
103 gpu_optimized: (byte & 0x04) != 0,
104 ycocg_420: (byte & 0x08) != 0,
105 }
106 }
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct Header {
112 pub magic: u32,
114 pub version: Version,
116 pub width: u32,
118 pub height: u32,
120 pub wavelet_levels: u8,
122 pub flags: Flags,
124 pub layer1_size: u32,
126 pub layer2_size: u32,
128 pub layer3_size: u32,
130 pub residual_size: u32,
132}
133
134impl Header {
135 pub const SIZE: usize = 32;
137
138 pub fn new(width: u32, height: u32, wavelet_levels: u8) -> Self {
140 Header {
141 magic: MAGIC,
142 version: Version::CURRENT,
143 width,
144 height,
145 wavelet_levels,
146 flags: Flags::default(),
147 layer1_size: 0,
148 layer2_size: 0,
149 layer3_size: 0,
150 residual_size: 0,
151 }
152 }
153
154 pub fn to_bytes(&self) -> Vec<u8> {
156 let mut bytes = Vec::with_capacity(Self::SIZE);
157
158 bytes.extend_from_slice(&self.magic.to_be_bytes());
160
161 bytes.push(self.version.major);
163 bytes.push(self.version.minor);
164
165 bytes.extend_from_slice(&self.width.to_be_bytes());
167 bytes.extend_from_slice(&self.height.to_be_bytes());
168
169 bytes.push(self.wavelet_levels);
171
172 bytes.push(self.flags.to_byte());
174
175 bytes.extend_from_slice(&self.layer1_size.to_be_bytes());
177 bytes.extend_from_slice(&self.layer2_size.to_be_bytes());
178 bytes.extend_from_slice(&self.layer3_size.to_be_bytes());
179 bytes.extend_from_slice(&self.residual_size.to_be_bytes());
180
181 bytes
182 }
183
184 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
186 if bytes.len() < Self::SIZE {
187 return Err(IffError::InsufficientData {
188 expected: Self::SIZE,
189 got: bytes.len(),
190 });
191 }
192
193 let magic = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
195 if magic != MAGIC {
196 return Err(IffError::InvalidMagic {
197 expected: MAGIC,
198 got: magic,
199 });
200 }
201
202 let version = Version {
204 major: bytes[4],
205 minor: bytes[5],
206 };
207
208 let width = u32::from_be_bytes([bytes[6], bytes[7], bytes[8], bytes[9]]);
210 let height = u32::from_be_bytes([bytes[10], bytes[11], bytes[12], bytes[13]]);
211
212 if width == 0 || height == 0 {
214 return Err(IffError::Other("Invalid dimensions".to_string()));
215 }
216
217 let wavelet_levels = bytes[14];
219
220 let flags = Flags::from_byte(bytes[15]);
222
223 let layer1_size = u32::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]);
225 let layer2_size = u32::from_be_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]);
226 let layer3_size = u32::from_be_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]);
227 let residual_size = u32::from_be_bytes([bytes[28], bytes[29], bytes[30], bytes[31]]);
228
229 Ok(Header {
230 magic,
231 version,
232 width,
233 height,
234 wavelet_levels,
235 flags,
236 layer1_size,
237 layer2_size,
238 layer3_size,
239 residual_size,
240 })
241 }
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct Layer1 {
247 pub y: WaveletDecomposition,
248 pub co: WaveletDecomposition,
249 pub cg: WaveletDecomposition,
250}
251
252impl Layer1 {
253 pub fn new(width: u32, height: u32, levels: usize) -> Self {
254 Layer1 {
255 y: WaveletDecomposition::new(width, height, levels, 1),
256 co: WaveletDecomposition::new(width / 2, height / 2, levels, 1),
257 cg: WaveletDecomposition::new(width / 2, height / 2, levels, 1),
258 }
259 }
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct Layer2 {
265 pub regions: Vec<Region>,
267}
268
269impl Layer2 {
270 pub fn new() -> Self {
272 Layer2 {
273 regions: Vec::new(),
274 }
275 }
276
277 pub fn add_region(&mut self, region: Region) {
279 self.regions.push(region);
280 }
281}
282
283impl Default for Layer2 {
284 fn default() -> Self {
285 Self::new()
286 }
287}
288
289pub type Layer3 = WarpField;
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct Residual {
295 pub width: u32,
296 pub height: u32,
297 pub channels: u8,
298 pub data: Vec<u8>,
301}
302
303impl Residual {
304 pub fn new(width: u32, height: u32) -> Self {
306 Residual {
307 width,
308 height,
309 channels: 3,
310 data: Vec::new(),
311 }
312 }
313
314 pub fn from_dense(width: u32, height: u32, pixels: &[[i16; 3]]) -> Result<Self> {
316 let mut channels = vec![Vec::with_capacity(pixels.len()); 3];
317
318 for p in pixels {
319 channels[0].push(p[0] as i32);
320 channels[1].push(p[1] as i32);
321 channels[2].push(p[2] as i32);
322 }
323
324 let mut all_data = Vec::new();
325 all_data.extend_from_slice(&channels[0]);
326 all_data.extend_from_slice(&channels[1]);
327 all_data.extend_from_slice(&channels[2]);
328
329 let rle_compressed = compress_rle(&all_data)?;
331
332 let final_compressed = zstd::stream::encode_all(std::io::Cursor::new(rle_compressed), 3)
335 .map_err(|e| IffError::Other(format!("Zstd compression failed: {}", e)))?;
336
337 Ok(Residual {
338 width,
339 height,
340 channels: 3,
341 data: final_compressed,
342 })
343 }
344
345 pub fn to_dense(&self) -> Result<Vec<[i16; 3]>> {
347 let total_pixels = (self.width * self.height) as usize;
348 let expected_len = total_pixels * 3;
349
350 let rle_compressed = zstd::stream::decode_all(std::io::Cursor::new(&self.data))
352 .map_err(|e| IffError::Other(format!("Zstd decompression failed: {}", e)))?;
353
354 let all_data = decompress_rle(&rle_compressed, Some(expected_len))?;
356
357 if all_data.len() < expected_len {
358 return Err(IffError::Other("Insufficient residual data".to_string()));
359 }
360
361 let mut pixels = Vec::with_capacity(total_pixels);
362 for i in 0..total_pixels {
363 pixels.push([
364 all_data[i] as i16,
365 all_data[total_pixels + i] as i16,
366 all_data[2 * total_pixels + i] as i16,
367 ]);
368 }
369
370 Ok(pixels)
371 }
372}
373
374#[derive(Debug, Clone, Serialize, Deserialize)]
376pub struct IffImage {
377 pub header: Header,
379 pub layer1: Layer1,
381 pub layer2: Layer2,
383 pub layer3: Layer3,
385 pub residual: Residual,
387}
388
389impl IffImage {
390 pub fn new(width: u32, height: u32, wavelet_levels: u8) -> Self {
392 IffImage {
393 header: Header::new(width, height, wavelet_levels),
394 layer1: Layer1::new(width, height, wavelet_levels as usize),
395 layer2: Layer2::new(),
396 layer3: WarpField::new(width, height),
397 residual: Residual::new(width, height),
398 }
399 }
400
401 pub fn to_bytes(&self) -> Result<Vec<u8>> {
403 let layer1_bytes = bincode::serialize(&self.layer1)?;
405 let layer2_bytes = bincode::serialize(&self.layer2)?;
406 let layer3_bytes = bincode::serialize(&self.layer3)?;
407 let residual_bytes = bincode::serialize(&self.residual)?;
408
409 let mut header = self.header.clone();
411 header.layer1_size = layer1_bytes.len() as u32;
412 header.layer2_size = layer2_bytes.len() as u32;
413 header.layer3_size = layer3_bytes.len() as u32;
414 header.residual_size = residual_bytes.len() as u32;
415
416 let mut bytes = header.to_bytes();
418 bytes.extend_from_slice(&layer1_bytes);
419 bytes.extend_from_slice(&layer2_bytes);
420 bytes.extend_from_slice(&layer3_bytes);
421 bytes.extend_from_slice(&residual_bytes);
422
423 Ok(bytes)
424 }
425
426 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
428 let header = Header::from_bytes(bytes)?;
430
431 if !header.version.is_compatible(&Version::CURRENT) {
433 return Err(IffError::UnsupportedVersion(
434 (header.version.major as u32) << 8 | header.version.minor as u32,
435 ));
436 }
437
438 let offset1 = Header::SIZE;
440 let offset2 = offset1 + header.layer1_size as usize;
441 let offset3 = offset2 + header.layer2_size as usize;
442 let offset_residual = offset3 + header.layer3_size as usize;
443 let total_size = offset_residual + header.residual_size as usize;
444
445 if bytes.len() < total_size {
447 return Err(IffError::InsufficientData {
448 expected: total_size,
449 got: bytes.len(),
450 });
451 }
452
453 let layer1: Layer1 = bincode::deserialize(&bytes[offset1..offset2])?;
455 let layer2: Layer2 = bincode::deserialize(&bytes[offset2..offset3])?;
456 let layer3: Layer3 = bincode::deserialize(&bytes[offset3..offset_residual])?;
457 let residual: Residual = bincode::deserialize(&bytes[offset_residual..total_size])?;
458
459 Ok(IffImage {
460 header,
461 layer1,
462 layer2,
463 layer3,
464 residual,
465 })
466 }
467
468 pub fn estimated_size(&self) -> usize {
470 Header::SIZE
471 + self.layer1.y.data.len() + self.layer1.co.data.len() + self.layer1.cg.data.len()
472 + self.layer2.regions.len() * 32
473 + self.layer3.vortices.len() * 16
474 + self.residual.data.len()
475 }
476}
477
478#[derive(Debug, Clone, Copy, PartialEq, Eq)]
480pub enum Layer {
481 Skeleton,
483 Texture,
485 Warp,
487 Residual,
489}
490
491#[cfg(test)]
492mod tests {
493 use super::*;
494
495 #[test]
496 fn test_version() {
497 let v1 = Version { major: 0, minor: 2 };
498 let v2 = Version { major: 0, minor: 2 };
499 let v3 = Version { major: 1, minor: 0 };
500
501 assert!(v1.is_compatible(&v2)); assert!(!v1.is_compatible(&v3)); }
504
505 #[test]
506 fn test_flags() {
507 let flags = Flags {
508 has_alpha: true,
509 lossless: false,
510 gpu_optimized: true,
511 ycocg_420: true,
512 };
513
514 let byte = flags.to_byte();
515 let restored = Flags::from_byte(byte);
516
517 assert_eq!(flags.has_alpha, restored.has_alpha);
518 assert_eq!(flags.lossless, restored.lossless);
519 assert_eq!(flags.gpu_optimized, restored.gpu_optimized);
520 assert_eq!(flags.ycocg_420, restored.ycocg_420);
521 }
522}