unity_asset_decode/texture/
types.rs

1//! Texture data structures
2//!
3//! This module defines the core data structures used for texture processing.
4
5use super::formats::TextureFormat;
6use serde::{Deserialize, Serialize};
7
8/// Streaming info for external texture data
9#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10pub struct StreamingInfo {
11    pub offset: u64,
12    pub size: u32,
13    pub path: String,
14}
15
16/// GL texture settings
17#[derive(Debug, Clone, Default, Serialize, Deserialize)]
18pub struct GLTextureSettings {
19    pub filter_mode: i32,
20    pub aniso: i32,
21    pub mip_bias: f32,
22    pub wrap_u: i32,
23    pub wrap_v: i32,
24    pub wrap_w: i32,
25}
26
27/// Texture2D object representation
28///
29/// This structure contains all the data needed to represent a Unity Texture2D object.
30/// It includes both metadata and the actual image data.
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct Texture2D {
33    pub name: String,
34    pub width: i32,
35    pub height: i32,
36    pub complete_image_size: i32,
37    pub format: TextureFormat,
38    pub mip_map: bool,
39    pub mip_count: i32,
40    pub is_readable: bool,
41    pub image_count: i32,
42    pub texture_dimension: i32,
43    pub light_map_format: i32,
44    pub color_space: i32,
45    pub data_size: i32,
46    pub stream_info: StreamingInfo,
47    pub texture_settings: GLTextureSettings,
48    pub image_data: Vec<u8>,
49
50    // Version-specific fields
51    pub forced_fallback_format: Option<i32>,
52    pub downscale_fallback: Option<bool>,
53    pub is_alpha_channel_optional: Option<bool>,
54    pub mips_stripped: Option<i32>,
55}
56
57impl Default for Texture2D {
58    fn default() -> Self {
59        Self {
60            name: String::new(),
61            width: 0,
62            height: 0,
63            complete_image_size: 0,
64            format: TextureFormat::Unknown,
65            mip_map: false,
66            mip_count: 1,
67            is_readable: false,
68            image_count: 1,
69            texture_dimension: 2,
70            light_map_format: 0,
71            color_space: 0,
72            data_size: 0,
73            stream_info: StreamingInfo::default(),
74            texture_settings: GLTextureSettings::default(),
75            image_data: Vec::new(),
76            forced_fallback_format: None,
77            downscale_fallback: None,
78            is_alpha_channel_optional: None,
79            mips_stripped: None,
80        }
81    }
82}
83
84impl Texture2D {
85    /// Create a new Texture2D with basic parameters
86    pub fn new(name: String, width: i32, height: i32, format: TextureFormat) -> Self {
87        Self {
88            name,
89            width,
90            height,
91            format,
92            ..Default::default()
93        }
94    }
95
96    /// Check if texture has valid dimensions
97    pub fn has_valid_dimensions(&self) -> bool {
98        self.width > 0 && self.height > 0
99    }
100
101    /// Check if texture has image data
102    pub fn has_image_data(&self) -> bool {
103        !self.image_data.is_empty()
104    }
105
106    /// Get texture dimensions as tuple
107    pub fn dimensions(&self) -> (u32, u32) {
108        (self.width as u32, self.height as u32)
109    }
110
111    /// Check if texture uses external streaming
112    pub fn is_streamed(&self) -> bool {
113        !self.stream_info.path.is_empty() && self.stream_info.size > 0
114    }
115
116    /// Get expected data size based on format and dimensions
117    pub fn expected_data_size(&self) -> u32 {
118        self.format
119            .calculate_data_size(self.width as u32, self.height as u32)
120    }
121
122    /// Validate texture data consistency
123    pub fn validate(&self) -> Result<(), String> {
124        if !self.has_valid_dimensions() {
125            return Err("Invalid texture dimensions".to_string());
126        }
127
128        if !self.format.is_supported() {
129            return Err(format!("Unsupported texture format: {:?}", self.format));
130        }
131
132        if !self.is_streamed() && !self.has_image_data() {
133            return Err("No image data available and not streamed".to_string());
134        }
135
136        Ok(())
137    }
138}