rw_parser_rs/renderware/txd/
txd_parser.rs1use crate::renderware::rw_file::RwFile;
27use crate::renderware::utils::image_format_enums::{PaletteType, PlatformType};
28use std::io::Result;
29use texpresso;
30
31use serde::Serialize;
32
33#[derive(Debug, Clone, PartialEq, Serialize)]
38pub struct RwTxd {
39 pub texture_dictionary: RwTextureDictionary,
41}
42
43#[derive(Debug, Clone, PartialEq, Serialize)]
44pub struct RwTextureDictionary {
45 pub texture_count: u16,
46 pub texture_natives: Vec<RwTextureNative>,
47}
48
49#[derive(Debug, Clone, PartialEq, Serialize)]
50pub struct RwTextureNative {
51 pub platform_id: u32,
52 pub filter_mode: u8,
53 pub u_addressing: u8,
54 pub v_addressing: u8,
55 pub texture_name: String,
56 pub mask_name: String,
57 pub raster_format: u32,
58 pub d3d_format: String,
59 pub width: u16,
60 pub height: u16,
61 pub depth: u8,
62 pub mipmap_count: u8,
63 pub raster_type: u8,
64 pub alpha: bool,
65 pub cube_texture: bool,
66 pub auto_mip_maps: bool,
67 pub compressed: bool,
68 pub mipmaps: Vec<Vec<u8>>,
69}
70
71pub struct TxdParser<'a> {
76 file: RwFile<'a>,
77}
78
79impl<'a> TxdParser<'a> {
80 pub fn new(buffer: &'a [u8]) -> Self {
86 TxdParser {
87 file: RwFile::new(buffer),
88 }
89 }
90
91 pub fn parse(&mut self) -> Result<RwTxd> {
101 Ok(RwTxd {
102 texture_dictionary: self.read_texture_dictionary()?,
103 })
104 }
105
106 fn read_texture_dictionary(&mut self) -> Result<RwTextureDictionary> {
107 self.file.read_section_header()?; self.file.read_section_header()?; let texture_count = self.file.get_stream().read_u16()?;
111 self.file.get_stream().skip(2)?;
112
113 let mut texture_natives = Vec::with_capacity(texture_count as usize);
114 for _ in 0..texture_count {
115 texture_natives.push(self.read_texture_native()?);
116 }
117
118 let size = self.file.read_section_header()?.section_size;
119 self.file.get_stream().skip(size as u64)?;
120
121 Ok(RwTextureDictionary {
122 texture_count,
123 texture_natives,
124 })
125 }
126
127 fn read_texture_native(&mut self) -> Result<RwTextureNative> {
128 self.file.read_section_header()?; self.file.read_section_header()?; let platform_id = self.file.get_stream().read_u32()?;
132 let flags = self.file.get_stream().read_u32()?;
133
134 let filter_mode = (flags & 0xFF) as u8;
135 let u_addressing = ((flags & 0xF00) >> 8) as u8;
136 let v_addressing = ((flags & 0xF000) >> 12) as u8;
137
138 let texture_name = self.file.get_stream().read_string(32)?;
139 let mask_name = self.file.get_stream().read_string(32)?;
140
141 let raster_format = self.file.get_stream().read_u32()?;
142 let d3d_format = self.file.get_stream().read_string(4)?;
143 let width = self.file.get_stream().read_u16()?;
144 let height = self.file.get_stream().read_u16()?;
145 let depth = self.file.get_stream().read_u8()?;
146 let mipmap_count = self.file.get_stream().read_u8()?;
147 let raster_type = self.file.get_stream().read_u8()?;
148 let compression_flags = self.file.get_stream().read_u8()?;
149
150 let alpha = (compression_flags & (1 << 0)) != 0;
151 let cube_texture = (compression_flags & (1 << 1)) != 0;
152 let auto_mip_maps = (compression_flags & (1 << 2)) != 0;
153 let compressed = (compression_flags & (1 << 3)) != 0;
154
155 let palette_type = (raster_format >> 13) & 0b11;
156
157 let mut mipmaps = Vec::new();
158 let palette = if palette_type != PaletteType::PaletteNone as u32 {
159 self.read_palette(palette_type, depth)?
160 } else {
161 Vec::new()
162 };
163
164 for i in 0..mipmap_count {
165 let raster_size = self.file.get_stream().read_u32()?;
166 let raster = self.file.get_stream().read(raster_size as usize)?;
167
168 if i == 0 {
169 let bitmap = if !palette.is_empty() {
170 vec![]
172 } else if platform_id == PlatformType::D3d8 as u32 && compression_flags != 0 {
173 self.get_bitmap_with_dxt(&format!("DXT{}", compression_flags), &raster, width, height)?
174 } else if platform_id == PlatformType::D3d9 as u32 && compressed {
175 self.get_bitmap_with_dxt(&d3d_format, &raster, width, height)?
176 } else {
177 vec![]
179 };
180 mipmaps.push(bitmap);
181 }
182 }
183
184 let size = self.file.read_section_header()?.section_size;
185 self.file.get_stream().skip(size as u64)?;
186
187 Ok(RwTextureNative {
188 platform_id,
189 filter_mode,
190 u_addressing,
191 v_addressing,
192 texture_name,
193 mask_name,
194 raster_format,
195 d3d_format,
196 width,
197 height,
198 depth,
199 mipmap_count,
200 raster_type,
201 alpha,
202 cube_texture,
203 auto_mip_maps,
204 compressed,
205 mipmaps,
206 })
207 }
208
209 fn read_palette(&mut self, palette_type: u32, depth: u8) -> Result<Vec<u8>> {
210 let size = if palette_type == PaletteType::Palette8 as u32 { 1024 } else if depth == 4 { 64 } else { 128 };
211 self.file.get_stream().read(size)
212 }
213
214 fn get_bitmap_with_dxt(&self, dxt_type: &str, raster: &[u8], width: u16, height: u16) -> Result<Vec<u8>> {
215 let format = match dxt_type {
216 "DXT1" => texpresso::Format::Bc1,
217 "DXT2" => texpresso::Format::Bc2,
218 "DXT3" => texpresso::Format::Bc2,
219 "DXT4" => texpresso::Format::Bc3,
220 "DXT5" => texpresso::Format::Bc3,
221 _ => return Ok(Vec::new())
222 };
223
224 let mut decoded = vec![0; width as usize * height as usize * 4];
225 format.decompress(raster, width as usize, height as usize, &mut decoded);
226
227 Ok(decoded)
228 }
229}