1use binrw::{BinRead, BinWrite};
2use bitfield_struct::bitfield;
3use directxtex::{DXGI_FORMAT, TEX_DIMENSION};
4use serde::{Deserialize, Serialize};
5use thiserror::Error;
6
7#[non_exhaustive]
8#[derive(
9 BinRead, BinWrite, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default, Eq, Hash,
10)]
11#[brw(repr = u16)]
12pub enum TextureType {
13 Colour = 0,
14 #[default]
15 Normal = 1,
16 Height = 2,
17 CompoundNormal = 3,
18 Billboard = 4,
19 UNKNOWN5 = 5, Projection = 6,
21 Emission = 16,
22 Cubemap = 256, Volume = 512, UNKNOWN517 = 517, }
30
31#[derive(BinRead, BinWrite, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
32#[brw(repr = u8)]
33pub enum InterpretAs {
34 Colour = 0,
35 #[default]
36 Normal = 1,
37 Height = 2,
38 CompoundNormal = 3,
39 Billboard = 4,
40 Cubemap = 6,
41 Emission = 16, Volume = 64, }
44
45#[non_exhaustive]
46#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Hash, Eq)]
47pub enum RenderFormat {
48 R32G32B32A32,
49 R16G16B16A16,
50 R8G8B8A8,
51 R32,
52 R8G8,
53 A8,
54 BC1,
55 BC2,
56 BC3,
57 BC4,
58 BC5,
59 BC6,
60 BC7,
61}
62
63impl RenderFormat {
64 pub fn is_compressed(&self) -> bool {
65 matches!(
66 self,
67 RenderFormat::BC1
68 | RenderFormat::BC2
69 | RenderFormat::BC3
70 | RenderFormat::BC4
71 | RenderFormat::BC5
72 | RenderFormat::BC6
73 | RenderFormat::BC7
74 )
75 }
76
77 pub fn num_channels(&self) -> usize {
78 match self {
79 RenderFormat::A8 | RenderFormat::R32 | RenderFormat::BC4 => 1,
80 RenderFormat::R8G8 | RenderFormat::BC5 => 2,
81 RenderFormat::BC6 => 3,
82 RenderFormat::BC1 | RenderFormat::R32G32B32A32 |
84 RenderFormat::R16G16B16A16 |
85 RenderFormat::R8G8B8A8 |
86 RenderFormat::BC2 |
87 RenderFormat::BC3 |
88 RenderFormat::BC7 => 4,
89 }
90 }
91
92 pub fn decompressed_format(&self) -> RenderFormat {
93 match self {
94 RenderFormat::BC1 => RenderFormat::R8G8B8A8,
95 RenderFormat::BC2 => RenderFormat::R8G8B8A8,
96 RenderFormat::BC3 => RenderFormat::R8G8B8A8,
97 RenderFormat::BC4 => RenderFormat::A8,
98 RenderFormat::BC5 => RenderFormat::R8G8,
99 RenderFormat::BC6 => RenderFormat::R16G16B16A16,
100 RenderFormat::BC7 => RenderFormat::R8G8B8A8,
101 format => *format,
102 }
103 }
104}
105
106impl From<RenderFormat> for DXGI_FORMAT {
107 fn from(value: RenderFormat) -> Self {
108 match value {
109 RenderFormat::R32G32B32A32 => DXGI_FORMAT::DXGI_FORMAT_R32G32B32A32_FLOAT,
110 RenderFormat::R16G16B16A16 => DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_FLOAT, RenderFormat::R8G8B8A8 => DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM,
112 RenderFormat::R32 => DXGI_FORMAT::DXGI_FORMAT_R32_FLOAT,
113 RenderFormat::R8G8 => DXGI_FORMAT::DXGI_FORMAT_R8G8_UNORM,
114 RenderFormat::A8 => DXGI_FORMAT::DXGI_FORMAT_A8_UNORM,
115 RenderFormat::BC1 => DXGI_FORMAT::DXGI_FORMAT_BC1_UNORM,
116 RenderFormat::BC2 => DXGI_FORMAT::DXGI_FORMAT_BC2_UNORM,
117 RenderFormat::BC3 => DXGI_FORMAT::DXGI_FORMAT_BC3_UNORM,
118 RenderFormat::BC4 => DXGI_FORMAT::DXGI_FORMAT_BC4_UNORM,
119 RenderFormat::BC5 => DXGI_FORMAT::DXGI_FORMAT_BC5_UNORM,
120 RenderFormat::BC6 => DXGI_FORMAT::DXGI_FORMAT_BC6H_UF16,
121 RenderFormat::BC7 => DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM,
122 }
123 }
124}
125
126pub trait RenderFormatMapping {
127 const MAP: &'static [(u16, RenderFormat)];
128
129 fn try_from_u16(raw: u16) -> Option<RenderFormat> {
130 Self::MAP.iter().find(|(r, _)| *r == raw).map(|(_, f)| *f)
131 }
132
133 fn try_to_u16(format: RenderFormat) -> Option<u16> {
134 Self::MAP
135 .iter()
136 .find(|(_, f)| *f == format)
137 .map(|(r, _)| *r)
138 }
139}
140
141#[derive(BinRead, BinWrite, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Hash, Eq)]
142pub struct WoaRenderFormat {
143 #[br(try_map = |raw: u16| Self::try_from_u16(raw).ok_or(format!("invalid Woa render format {}", raw)))]
144 #[bw(map = |fmt: &RenderFormat| Self::try_to_u16(*fmt).expect("unsupported WOA render format"))]
145 pub(crate) format: RenderFormat,
146}
147
148impl RenderFormatMapping for WoaRenderFormat {
149 const MAP: &'static [(u16, RenderFormat)] = &[
150 (0x02, RenderFormat::R32G32B32A32),
151 (0x0A, RenderFormat::R16G16B16A16),
152 (0x1C, RenderFormat::R8G8B8A8),
153 (0x34, RenderFormat::R8G8),
154 (0x42, RenderFormat::A8),
155 (0x49, RenderFormat::BC1),
156 (0x4C, RenderFormat::BC2),
157 (0x4F, RenderFormat::BC3),
158 (0x52, RenderFormat::BC4),
159 (0x55, RenderFormat::BC5),
160 (0x57, RenderFormat::BC6),
161 (0x5A, RenderFormat::BC7),
162 ];
163}
164
165impl From<WoaRenderFormat> for RenderFormat {
166 fn from(format: WoaRenderFormat) -> Self {
167 format.format
168 }
169}
170
171impl PartialEq<RenderFormat> for WoaRenderFormat {
172 fn eq(&self, other: &RenderFormat) -> bool {
173 self.format == *other
174 }
175}
176
177impl PartialEq<WoaRenderFormat> for RenderFormat {
178 fn eq(&self, other: &WoaRenderFormat) -> bool {
179 *self == other.format
180 }
181}
182
183#[derive(BinRead, BinWrite, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Hash, Eq)]
184pub struct BondRenderFormat {
185 #[br(try_map = |raw: u16| Self::try_from_u16(raw).ok_or(format!("invalid Bond render format {}", raw)))]
186 #[bw(map = |fmt: &RenderFormat| Self::try_to_u16(*fmt).expect("unsupported Bond render format"))]
187 pub(crate) format: RenderFormat,
188}
189
190impl RenderFormatMapping for BondRenderFormat {
191 const MAP: &'static [(u16, RenderFormat)] = &[
192 (0x02, RenderFormat::R32G32B32A32),
193 (0x0A, RenderFormat::R16G16B16A16),
194 (0x1C, RenderFormat::R8G8B8A8),
195 (0x2C, RenderFormat::R32),
196 (0x34 + 3, RenderFormat::R8G8),
197 (0x42 + 3, RenderFormat::A8),
198 (0x49 + 3, RenderFormat::BC1),
199 (0x4C + 3, RenderFormat::BC2),
200 (0x4F + 3, RenderFormat::BC3),
201 (0x52 + 3, RenderFormat::BC4),
202 (0x55 + 3, RenderFormat::BC5),
203 (0x5A + 4, RenderFormat::BC7),
204 ];
205}
206
207impl From<BondRenderFormat> for RenderFormat {
208 fn from(format: BondRenderFormat) -> Self {
209 format.format
210 }
211}
212
213impl PartialEq<RenderFormat> for BondRenderFormat {
214 fn eq(&self, other: &RenderFormat) -> bool {
215 self.format == *other
216 }
217}
218
219impl PartialEq<BondRenderFormat> for RenderFormat {
220 fn eq(&self, other: &BondRenderFormat) -> bool {
221 *self == other.format
222 }
223}
224
225#[derive(Debug, Error)]
226#[error("Unsupported DXGI_FORMAT")]
227pub struct UnsupportedFormatError;
228
229impl TryFrom<DXGI_FORMAT> for RenderFormat {
230 type Error = UnsupportedFormatError;
231
232 fn try_from(value: DXGI_FORMAT) -> Result<Self, Self::Error> {
233 match value {
234 DXGI_FORMAT::DXGI_FORMAT_R16G16B16A16_UNORM => Ok(RenderFormat::R16G16B16A16),
235 DXGI_FORMAT::DXGI_FORMAT_R8G8B8A8_UNORM => Ok(RenderFormat::R8G8B8A8),
236 DXGI_FORMAT::DXGI_FORMAT_R8G8_UNORM => Ok(RenderFormat::R8G8),
237 DXGI_FORMAT::DXGI_FORMAT_A8_UNORM => Ok(RenderFormat::A8),
238 DXGI_FORMAT::DXGI_FORMAT_BC1_UNORM => Ok(RenderFormat::BC1),
239 DXGI_FORMAT::DXGI_FORMAT_BC2_UNORM => Ok(RenderFormat::BC2),
240 DXGI_FORMAT::DXGI_FORMAT_BC3_UNORM => Ok(RenderFormat::BC3),
241 DXGI_FORMAT::DXGI_FORMAT_BC4_UNORM => Ok(RenderFormat::BC4),
242 DXGI_FORMAT::DXGI_FORMAT_BC5_UNORM => Ok(RenderFormat::BC5),
243 DXGI_FORMAT::DXGI_FORMAT_BC7_UNORM => Ok(RenderFormat::BC7),
244 _ => Err(UnsupportedFormatError),
245 }
246 }
247}
248
249#[derive(BinRead, BinWrite, Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Default)]
250#[brw(repr = u8)]
251pub enum Dimensions {
252 #[default]
253 _2D = 0,
254 Cube = 1,
255 Volume = 2,
256}
257
258impl From<Dimensions> for TEX_DIMENSION {
259 fn from(val: Dimensions) -> Self {
260 match val {
261 Dimensions::_2D => TEX_DIMENSION::TEX_DIMENSION_TEXTURE2D,
262 Dimensions::Cube => TEX_DIMENSION::TEX_DIMENSION_TEXTURE3D,
263 Dimensions::Volume => TEX_DIMENSION::TEX_DIMENSION_TEXTURE2D,
264 }
265 }
266}
267
268#[bitfield(u32)]
269#[derive(BinRead, BinWrite, Serialize, Deserialize)]
270pub(crate) struct TextureFlagsInner {
272 pub(crate) swizzled: bool,
273 pub(crate) deferred: bool, pub(crate) memory_read_xbox_360: bool,
275 pub(crate) unknown1: bool, pub(crate) atlas: bool, pub(crate) ddsc_encoded: bool,
279 pub(crate) lz4_compression: bool,
280 pub(crate) __: bool,
281 pub(crate) unknown4: bool, #[bits(23)]
284 remainder: u32,
285}
286
287#[derive(Debug)]
288pub struct TextureFlags {
289 pub(crate) inner: TextureFlagsInner,
292}
293
294impl TextureFlags {
298 pub fn unknown4(&self) -> bool { self.inner.unknown4()}
299 pub fn deferred(&self) -> bool {
300 self.inner.deferred()
301 }
302 pub fn unknown1(&self) -> bool {
303 self.inner.unknown1()
304 }
305 pub fn atlas(&self) -> bool {
306 self.inner.atlas()
307 }
308 #[deprecated(since= "2.1.1", note = "No longer unknown, use lz4_compression")]
309 pub fn unknown3(&self) -> bool {
310 self.inner.lz4_compression()
311 }
312 pub fn lz4_compression(&self) -> bool {
313 self.inner.lz4_compression()
314 }
315
316 pub fn set_deferred(&mut self, value: bool) {
317 self.inner.set_deferred(value)
318 }
319 pub fn set_unknown1(&mut self, value: bool) {
320 self.inner.set_unknown1(value)
321 }
322 #[deprecated(since= "2.1.1", note = "No longer unknown, use set_lz4_compression")]
323 pub fn set_unknown3(&mut self, value: bool) {
324 self.inner.set_lz4_compression(value)
325 }
326 pub fn set_lz4_compression(&mut self, value: bool) {
327 self.inner.set_lz4_compression(value)
328 }
329
330 pub fn set_atlas(&mut self, value: bool) {
331 self.inner.set_atlas(value)
332 }
333 pub fn with_deferred(&self, value: bool) -> Self {
334 Self {
335 inner: self.inner.with_deferred(value),
336 }
337 }
338 pub fn with_unknown1(&mut self, value: bool) -> Self {
339 Self {
340 inner: self.inner.with_unknown1(value),
341 }
342 }
343 pub fn with_atlas(&mut self, value: bool) -> Self {
344 Self {
345 inner: self.inner.with_atlas(value),
346 }
347 }
348 #[deprecated(since= "2.1.1", note = "No longer unknown, use with_lz4_compression")]
349 pub fn with_unknown3(&mut self, value: bool) -> Self {
350 Self {
351 inner: self.inner.with_lz4_compression(value),
352 }
353 }
354
355 pub fn with_lz4_compression(&mut self, value: bool) -> Self {
356 Self {
357 inner: self.inner.with_lz4_compression(value),
358 }
359 }
360
361 #[cfg(feature = "unstable")]
362 pub fn swizzled(&self) -> bool {
363 self.inner.swizzled()
364 }
365
366 #[cfg(feature = "unstable")]
367 pub fn memory_read_xbox_360(&self) -> bool {
368 self.inner.memory_read_xbox_360()
369 }
370
371 #[cfg(feature = "unstable")]
372 pub fn ddsc_encoded(&self) -> bool {
373 self.inner.ddsc_encoded()
374 }
375
376 #[cfg(feature = "unstable")]
377 pub fn set_swizzled(&mut self, value: bool) {
378 self.inner.set_swizzled(value)
379 }
380
381 #[cfg(feature = "unstable")]
382 pub fn set_memory_read_xbox_360(&mut self, value: bool) {
383 self.inner.set_memory_read_xbox_360(value)
384 }
385
386 #[cfg(feature = "unstable")]
387 pub fn set_ddsc_encoded(&mut self, value: bool) {
388 self.inner.set_ddsc_encoded(value)
389 }
390
391 #[cfg(feature = "unstable")]
392 pub fn with_swizzled(&self, value: bool) -> Self {
393 Self {
394 inner: self.inner.with_swizzled(value),
395 }
396 }
397
398 #[cfg(feature = "unstable")]
399 pub fn with_memory_read_xbox_360(&self, value: bool) -> Self {
400 Self {
401 inner: self.inner.with_memory_read_xbox_360(value),
402 }
403 }
404
405 #[cfg(feature = "unstable")]
406 pub fn with_ddsc_encoded(&self, value: bool) -> Self {
407 Self {
408 inner: self.inner.with_ddsc_encoded(value),
409 }
410 }
411}