Skip to main content

glacier_texture/
enums.rs

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, //introduced in knt
20    Projection = 6,
21    Emission = 16,
22    //UNKNOWN64 = 64, //unused
23
24    //UNKNOWN128 = 128, //unused in H2, H3
25    Cubemap = 256, //uses ascolormap and ascubemap
26    Volume = 512,  //uses asheightmap & asvolume
27    UNKNOWN517 = 517, //introduced in knt
28    //UNKNOWN1024 = 1024, //unused in woa
29}
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, //This is an assumption
42    Volume = 64,   //This as well
43}
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 | //assume DXT1a
83            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, // has to be float
111            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)]
270//most of these are unused...
271pub(crate) struct TextureFlagsInner {
272    /* 0x1 */ pub(crate) swizzled: bool,
273    /* 0x2 */ pub(crate) deferred: bool, //Only used on 4x4 textures
274    /* 0x4 */ pub(crate) memory_read_xbox_360: bool,
275    /* 0x8 */
276    pub(crate) unknown1: bool, //Does not affect the texture in-game. Usually not enabled on non-normal/color types, or uncompressed formats
277    /* 0x10 */ pub(crate) atlas: bool, //Only used on atlas textures
278    /* 0x20 */ pub(crate) ddsc_encoded: bool,
279    /* 0x40 */ pub(crate) lz4_compression: bool,
280    /* 0x50 */ pub(crate) __: bool,
281    /* 0x60 */ pub(crate) unknown4: bool, //Used when there is no texture data. Still contains some metadata
282
283    #[bits(23)]
284    remainder: u32,
285}
286
287#[derive(Debug)]
288pub struct TextureFlags {
289    ///inner "real" flags bitfield. Wrapped because it is likely to change over time.
290    /// Wrapping the struct makes it possible to #\[deprecated\] old getters and setters
291    pub(crate) inner: TextureFlagsInner,
292}
293
294/// Flags set in the texture files.
295/// The "unstable" flags are not found in any production texture file. Use at your own risk
296/// The other flags should not crash the game, but can also result in corrupted textures, use with caution
297impl 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}