unity_asset_decode/texture/
mod.rs

1//! Texture processing module
2//!
3//! This module provides comprehensive texture processing capabilities for Unity assets,
4//! organized following UnityPy and unity-rs best practices.
5//!
6//! # Architecture
7//!
8//! The module is organized into several sub-modules:
9//! - `formats` - Texture format definitions and metadata
10//! - `types` - Core data structures (Texture2D, etc.)
11//! - `converter` - Main conversion logic from Unity objects
12//! - `decoders` - Specialized decoders for different format categories
13//! - `helpers` - Utility functions for export and data manipulation
14//!
15//! # Examples
16//!
17//! ```rust,no_run
18//! use unity_asset_decode::texture::{TextureFormat, Texture2DConverter, TextureDecoder};
19//! use unity_asset_decode::unity_version::UnityVersion;
20//!
21//! // Create a converter
22//! let converter = Texture2DConverter::new(UnityVersion::default());
23//!
24//! // Convert Unity object to Texture2D (assuming you have a UnityObject)
25//! // let texture = converter.from_unity_object(&unity_object)?;
26//!
27//! // Create a decoder and decode to image
28//! let decoder = TextureDecoder::new();
29//! // let image = decoder.decode(&texture)?;
30//!
31//! // Export the image
32//! // TextureExporter::export_png(&image, "output.png")?;
33//! ```
34
35pub mod converter;
36pub mod decoders;
37pub mod formats;
38pub mod helpers;
39pub mod types;
40
41// Re-export main types for easy access
42pub use converter::{Texture2DConverter, Texture2DProcessor}; // Processor is legacy alias
43pub use decoders::{Decoder, TextureDecoder};
44pub use formats::{TextureFormat, TextureFormatInfo};
45pub use helpers::{TextureExporter, TextureSwizzler};
46pub use types::{GLTextureSettings, StreamingInfo, Texture2D};
47
48// Re-export decoder types for advanced usage
49pub use decoders::{BasicDecoder, CompressedDecoder, CrunchDecoder, MobileDecoder};
50
51// Re-export export options
52pub use helpers::export::ExportOptions;
53
54/// Main texture processing facade
55///
56/// This struct provides a high-level interface for texture processing,
57/// combining conversion, decoding, and export functionality.
58pub struct TextureProcessor {
59    converter: Texture2DConverter,
60    decoder: TextureDecoder,
61}
62
63impl TextureProcessor {
64    /// Create a new texture processor
65    pub fn new(version: crate::unity_version::UnityVersion) -> Self {
66        Self {
67            converter: Texture2DConverter::new(version),
68            decoder: TextureDecoder::new(),
69        }
70    }
71
72    /// Process Unity object to Texture2D
73    pub fn convert_object(
74        &self,
75        obj: &crate::object::UnityObject,
76    ) -> crate::error::Result<Texture2D> {
77        self.converter.from_unity_object(obj)
78    }
79
80    /// Decode texture to RGBA image
81    pub fn decode_texture(&self, texture: &Texture2D) -> crate::error::Result<image::RgbaImage> {
82        self.decoder.decode(texture)
83    }
84
85    /// Full pipeline: convert object -> decode -> export
86    pub fn process_and_export<P: AsRef<std::path::Path>>(
87        &self,
88        obj: &crate::object::UnityObject,
89        output_path: P,
90    ) -> crate::error::Result<()> {
91        let texture = self.convert_object(obj)?;
92        let image = self.decode_texture(&texture)?;
93        TextureExporter::export_auto(&image, output_path)
94    }
95
96    /// Check if a format can be processed
97    pub fn can_process(&self, format: TextureFormat) -> bool {
98        self.decoder.can_decode(format)
99    }
100
101    /// Get list of supported formats
102    pub fn supported_formats(&self) -> Vec<TextureFormat> {
103        self.decoder.supported_formats()
104    }
105}
106
107impl Default for TextureProcessor {
108    fn default() -> Self {
109        Self::new(crate::unity_version::UnityVersion::default())
110    }
111}
112
113/// Convenience functions for common operations
114/// Create a texture processor with default settings
115pub fn create_processor() -> TextureProcessor {
116    TextureProcessor::default()
117}
118
119/// Quick function to check if a format is supported
120pub fn is_format_supported(format: TextureFormat) -> bool {
121    let decoder = TextureDecoder::new();
122    decoder.can_decode(format)
123}
124
125/// Get all supported texture formats
126pub fn get_supported_formats() -> Vec<TextureFormat> {
127    let decoder = TextureDecoder::new();
128    decoder.supported_formats()
129}
130
131/// Quick function to decode texture data
132pub fn decode_texture_data(
133    format: TextureFormat,
134    width: u32,
135    height: u32,
136    data: Vec<u8>,
137) -> crate::error::Result<image::RgbaImage> {
138    let texture = Texture2D {
139        name: "decoded_texture".to_string(),
140        width: width as i32,
141        height: height as i32,
142        format,
143        image_data: data,
144        ..Default::default()
145    };
146
147    let decoder = TextureDecoder::new();
148    decoder.decode(&texture)
149}
150
151/// Quick function to export image with automatic format detection
152pub fn export_image<P: AsRef<std::path::Path>>(
153    image: &image::RgbaImage,
154    path: P,
155) -> crate::error::Result<()> {
156    TextureExporter::export_auto(image, path)
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn test_format_support() {
165        // Basic formats should always be supported
166        assert!(is_format_supported(TextureFormat::RGBA32));
167        assert!(is_format_supported(TextureFormat::RGB24));
168        assert!(is_format_supported(TextureFormat::ARGB32));
169    }
170
171    #[test]
172    fn test_processor_creation() {
173        let processor = create_processor();
174        assert!(processor.can_process(TextureFormat::RGBA32));
175    }
176
177    #[test]
178    fn test_supported_formats_list() {
179        let formats = get_supported_formats();
180        assert!(!formats.is_empty());
181        assert!(formats.contains(&TextureFormat::RGBA32));
182    }
183
184    #[test]
185    fn test_texture_format_info() {
186        let format = TextureFormat::RGBA32;
187        let info = format.info();
188        assert_eq!(info.name, "RGBA32");
189        assert_eq!(info.bits_per_pixel, 32);
190        assert!(!info.compressed);
191        assert!(info.has_alpha);
192        assert!(info.supported);
193    }
194
195    #[test]
196    fn test_format_categories() {
197        assert!(TextureFormat::RGBA32.is_basic_format());
198        assert!(!TextureFormat::RGBA32.is_compressed_format());
199        assert!(!TextureFormat::RGBA32.is_mobile_format());
200        assert!(!TextureFormat::RGBA32.is_crunch_compressed());
201
202        assert!(TextureFormat::DXT1.is_compressed_format());
203        assert!(!TextureFormat::DXT1.is_basic_format());
204
205        assert!(TextureFormat::ETC2_RGB.is_mobile_format());
206        assert!(!TextureFormat::ETC2_RGB.is_basic_format());
207
208        assert!(TextureFormat::DXT1Crunched.is_crunch_compressed());
209        assert!(!TextureFormat::DXT1Crunched.is_basic_format());
210    }
211}