texture2ddecoder/etc/
etc1.rs

1use crate::color::color;
2use crate::etc::consts::{ETC1_MODIFIER_TABLE, ETC1_SUBBLOCK_TABLE, WRITE_ORDER_TABLE};
3
4#[inline]
5pub(crate) const fn clamp(n: i32) -> u8 {
6    (if n < 0 {
7        0
8    } else if n > 255 {
9        255
10    } else {
11        n
12    }) as u8
13}
14
15#[inline]
16pub(crate) const fn applicate_color(c: [u8; 3], m: i16) -> u32 {
17    color(
18        clamp(c[0] as i32 + m as i32),
19        clamp(c[1] as i32 + m as i32),
20        clamp(c[2] as i32 + m as i32),
21        255,
22    )
23}
24
25#[inline]
26pub(crate) const fn applicate_color_alpha(c: [u8; 3], m: i16, transparent: bool) -> u32 {
27    color(
28        clamp(c[0] as i32 + m as i32),
29        clamp(c[1] as i32 + m as i32),
30        clamp(c[2] as i32 + m as i32),
31        if transparent { 0 } else { 255 },
32    )
33}
34
35#[inline]
36pub(crate) const fn applicate_color_raw(c: [u8; 3]) -> u32 {
37    color(c[0], c[1], c[2], 255)
38}
39
40#[inline]
41pub fn decode_etc1_block(data: &[u8], outbuf: &mut [u32]) {
42    let code: [u8; 2] = [(data[3] >> 5), (data[3] >> 2 & 7)]; // Table codewords
43    let table: [usize; 16] = ETC1_SUBBLOCK_TABLE[(data[3] & 1) as usize];
44    let mut c: [[u8; 3]; 2] = [[0; 3]; 2];
45    if (data[3] & 2) > 0 {
46        // diff bit == 1
47        c[0][0] = data[0] & 0xf8;
48        c[0][1] = data[1] & 0xf8;
49        c[0][2] = data[2] & 0xf8;
50        c[1][0] = c[0][0]
51            .overflowing_add(data[0] << 3 & 0x18)
52            .0
53            .overflowing_sub(data[0] << 3 & 0x20)
54            .0;
55        c[1][1] = c[0][1]
56            .overflowing_add(data[1] << 3 & 0x18)
57            .0
58            .overflowing_sub(data[1] << 3 & 0x20)
59            .0;
60        c[1][2] = c[0][2]
61            .overflowing_add(data[2] << 3 & 0x18)
62            .0
63            .overflowing_sub(data[2] << 3 & 0x20)
64            .0;
65        c[0][0] |= c[0][0] >> 5;
66        c[0][1] |= c[0][1] >> 5;
67        c[0][2] |= c[0][2] >> 5;
68        c[1][0] |= c[1][0] >> 5;
69        c[1][1] |= c[1][1] >> 5;
70        c[1][2] |= c[1][2] >> 5;
71    } else {
72        // diff bit == 0
73        c[0][0] = (data[0] & 0xf0) | data[0] >> 4;
74        c[1][0] = (data[0] & 0x0f) | data[0] << 4;
75        c[0][1] = (data[1] & 0xf0) | data[1] >> 4;
76        c[1][1] = (data[1] & 0x0f) | data[1] << 4;
77        c[0][2] = (data[2] & 0xf0) | data[2] >> 4;
78        c[1][2] = (data[2] & 0x0f) | data[2] << 4;
79    }
80
81    let mut j: usize = u16::from_be_bytes([data[6], data[7]]) as usize; // less significant pixel index bits
82    let mut k: usize = u16::from_be_bytes([data[4], data[5]]) as usize; // more significant pixel index bits
83
84    for i in 0..16 {
85        let s: usize = table[i];
86        let m: i16 = ETC1_MODIFIER_TABLE[code[s] as usize][j & 1];
87        outbuf[WRITE_ORDER_TABLE[i]] = applicate_color(c[s], if k & 1 > 0 { -m } else { m });
88        j >>= 1;
89        k >>= 1
90    }
91}