unity_asset_binary/texture/
converter.rs

1//! Texture2D converter and processor
2//!
3//! This module provides the main conversion logic for Unity Texture2D objects.
4//! Inspired by UnityPy/export/Texture2DConverter.py
5
6use super::decoders::TextureDecoder;
7use super::types::Texture2D;
8use crate::error::{BinaryError, Result};
9use crate::object::UnityObject;
10use crate::unity_version::UnityVersion;
11use image::RgbaImage;
12
13/// Main texture converter
14///
15/// This struct handles the conversion of Unity objects to Texture2D structures
16/// and provides methods for processing texture data.
17pub struct Texture2DConverter {
18    #[allow(dead_code)]
19    version: UnityVersion,
20    decoder: TextureDecoder,
21}
22
23impl Texture2DConverter {
24    /// Create a new Texture2D converter
25    pub fn new(version: UnityVersion) -> Self {
26        Self {
27            version,
28            decoder: TextureDecoder::new(),
29        }
30    }
31
32    /// Convert Unity object to Texture2D
33    ///
34    /// This method extracts texture data from a Unity object and creates
35    /// a Texture2D structure with all necessary metadata.
36    pub fn from_unity_object(&self, obj: &UnityObject) -> Result<Texture2D> {
37        // For now, use a simplified approach similar to the old implementation
38        // TODO: Implement proper TypeTree parsing when available
39        self.parse_binary_data(&obj.info.data)
40    }
41
42    /// Parse Texture2D from raw binary data (simplified version)
43    fn parse_binary_data(&self, data: &[u8]) -> Result<Texture2D> {
44        if data.is_empty() {
45            return Err(BinaryError::invalid_data("Empty texture data"));
46        }
47
48        let mut reader = crate::reader::BinaryReader::new(data, crate::reader::ByteOrder::Little);
49
50        // Complex initialization with potential failures - allow field reassignment
51        #[allow(clippy::field_reassign_with_default)]
52        {
53            let mut texture = Texture2D::default();
54
55            // Read name first
56            texture.name = reader
57                .read_aligned_string()
58                .unwrap_or_else(|_| "UnknownTexture".to_string());
59
60            // Core dimensions and format
61            texture.width = reader.read_i32().unwrap_or(0);
62            texture.height = reader.read_i32().unwrap_or(0);
63            texture.complete_image_size = reader.read_i32().unwrap_or(0);
64
65            let format_val = reader.read_i32().unwrap_or(0);
66            texture.format = super::formats::TextureFormat::from(format_val);
67
68            // Basic flags
69            texture.mip_map = reader.read_bool().unwrap_or(false);
70            texture.is_readable = reader.read_bool().unwrap_or(false);
71
72            // Read data size and image data
73            texture.data_size = reader.read_i32().unwrap_or(0);
74
75            // Read actual image data
76            if texture.data_size > 0 && reader.remaining() >= texture.data_size as usize {
77                texture.image_data = reader
78                    .read_bytes(texture.data_size as usize)
79                    .unwrap_or_default();
80            } else if reader.remaining() > 0 {
81                // Fallback: take all remaining data
82                let remaining_data = reader.read_remaining();
83                texture.image_data = remaining_data.to_vec();
84                texture.data_size = texture.image_data.len() as i32;
85            }
86
87            Ok(texture)
88        }
89    }
90
91    /// Decode texture to RGBA image
92    ///
93    /// This method uses the texture decoder to convert texture data to RGBA format
94    pub fn decode_to_image(&self, texture: &Texture2D) -> Result<RgbaImage> {
95        // Use the texture decoder to decode the image
96        self.decoder.decode(texture)
97    }
98}
99
100// Legacy compatibility - alias for the old processor name
101pub type Texture2DProcessor = Texture2DConverter;