texture2ddecoder/bcn/
bc7.rs

1use crate::bcn::consts::{S_BPTC_A2, S_BPTC_A3, S_BPTC_FACTORS, S_BPTC_P2, S_BPTC_P3};
2use crate::bitreader::BitReader;
3use crate::color::color;
4use core::mem::swap;
5
6struct Bc7ModeInfo {
7    num_subsets: usize,
8    partition_bits: usize,
9    rotation_bits: usize,
10    index_selection_bits: usize,
11    color_bits: usize,
12    alpha_bits: usize,
13    endpoint_pbits: usize,
14    shared_pbits: usize,
15    index_bits: [usize; 2],
16}
17
18static S_BP7_MODE_INFO: [Bc7ModeInfo; 8] = [
19    //  +---------------------------- num subsets
20    //  |  +------------------------- partition bits
21    //  |  |  +---------------------- rotation bits
22    //  |  |  |  +------------------- index selection bits
23    //  |  |  |  |  +---------------- color bits
24    //  |  |  |  |  |  +------------- alpha bits
25    //  |  |  |  |  |  |  +---------- endpoint P-bits
26    //  |  |  |  |  |  |  |  +------- shared P-bits
27    //  |  |  |  |  |  |  |  |    +-- 2x index bits
28    // { 3, 4, 0, 0, 4, 0, 1, 0, { 3, 0 } }, // 0
29    // { 2, 6, 0, 0, 6, 0, 0, 1, { 3, 0 } }, // 1
30    // { 3, 6, 0, 0, 5, 0, 0, 0, { 2, 0 } }, // 2
31    // { 2, 6, 0, 0, 7, 0, 1, 0, { 2, 0 } }, // 3
32    // { 1, 0, 2, 1, 5, 6, 0, 0, { 2, 3 } }, // 4
33    // { 1, 0, 2, 0, 7, 8, 0, 0, { 2, 2 } }, // 5
34    // { 1, 0, 0, 0, 7, 7, 1, 0, { 4, 0 } }, // 6
35    // { 2, 6, 0, 0, 5, 5, 1, 0, { 2, 0 } }, // 7
36    Bc7ModeInfo {
37        num_subsets: 3,
38        partition_bits: 4,
39        rotation_bits: 0,
40        index_selection_bits: 0,
41        color_bits: 4,
42        alpha_bits: 0,
43        endpoint_pbits: 1,
44        shared_pbits: 0,
45        index_bits: [3, 0],
46    },
47    Bc7ModeInfo {
48        num_subsets: 2,
49        partition_bits: 6,
50        rotation_bits: 0,
51        index_selection_bits: 0,
52        color_bits: 6,
53        alpha_bits: 0,
54        endpoint_pbits: 0,
55        shared_pbits: 1,
56        index_bits: [3, 0],
57    },
58    Bc7ModeInfo {
59        num_subsets: 3,
60        partition_bits: 6,
61        rotation_bits: 0,
62        index_selection_bits: 0,
63        color_bits: 5,
64        alpha_bits: 0,
65        endpoint_pbits: 0,
66        shared_pbits: 0,
67        index_bits: [2, 0],
68    },
69    Bc7ModeInfo {
70        num_subsets: 2,
71        partition_bits: 6,
72        rotation_bits: 0,
73        index_selection_bits: 0,
74        color_bits: 7,
75        alpha_bits: 0,
76        endpoint_pbits: 1,
77        shared_pbits: 0,
78        index_bits: [2, 0],
79    },
80    Bc7ModeInfo {
81        num_subsets: 1,
82        partition_bits: 0,
83        rotation_bits: 2,
84        index_selection_bits: 1,
85        color_bits: 5,
86        alpha_bits: 6,
87        endpoint_pbits: 0,
88        shared_pbits: 0,
89        index_bits: [2, 3],
90    },
91    Bc7ModeInfo {
92        num_subsets: 1,
93        partition_bits: 0,
94        rotation_bits: 2,
95        index_selection_bits: 0,
96        color_bits: 7,
97        alpha_bits: 8,
98        endpoint_pbits: 0,
99        shared_pbits: 0,
100        index_bits: [2, 2],
101    },
102    Bc7ModeInfo {
103        num_subsets: 1,
104        partition_bits: 0,
105        rotation_bits: 0,
106        index_selection_bits: 0,
107        color_bits: 7,
108        alpha_bits: 7,
109        endpoint_pbits: 1,
110        shared_pbits: 0,
111        index_bits: [4, 0],
112    },
113    Bc7ModeInfo {
114        num_subsets: 2,
115        partition_bits: 6,
116        rotation_bits: 0,
117        index_selection_bits: 0,
118        color_bits: 5,
119        alpha_bits: 5,
120        endpoint_pbits: 1,
121        shared_pbits: 0,
122        index_bits: [2, 0],
123    },
124];
125
126#[inline]
127fn expand_quantized(v: u8, bits: usize) -> u8 {
128    let s = ((v as u16) << (8 - bits as u16)) as u8;
129    s | s.overflowing_shr(bits as u32).0
130}
131
132pub fn decode_bc7_block(data: &[u8], outbuf: &mut [u32]) {
133    let mut bit = BitReader::new(data, 0);
134    let mode = {
135        let mut mode = 0;
136        while 0 == bit.read(1) && mode < 8 {
137            mode += 1;
138        }
139        mode
140    };
141
142    if mode == 8 {
143        outbuf[0..16].fill(0);
144        return;
145    }
146
147    let mi: &Bc7ModeInfo = &S_BP7_MODE_INFO[mode];
148    let mode_pbits: usize = if 0 != mi.endpoint_pbits {
149        mi.endpoint_pbits
150    } else {
151        mi.shared_pbits
152    };
153
154    let partition_set_idx: usize = bit.read(mi.partition_bits) as usize;
155    let rotation_mode: u8 = bit.read(mi.rotation_bits) as u8;
156    let index_selection_mode: usize = bit.read(mi.index_selection_bits) as usize;
157
158    let mut ep_r: [u8; 6] = [0; 6];
159    let mut ep_g: [u8; 6] = [0; 6];
160    let mut ep_b: [u8; 6] = [0; 6];
161    let mut ep_a: [u8; 6] = [0; 6];
162
163    (0..mi.num_subsets).for_each(|ii| {
164        ep_r[ii * 2] = (bit.read(mi.color_bits) << mode_pbits) as u8;
165        ep_r[ii * 2 + 1] = (bit.read(mi.color_bits) << mode_pbits) as u8;
166    });
167
168    (0..mi.num_subsets).for_each(|ii| {
169        ep_g[ii * 2] = (bit.read(mi.color_bits) << mode_pbits) as u8;
170        ep_g[ii * 2 + 1] = (bit.read(mi.color_bits) << mode_pbits) as u8;
171    });
172
173    (0..mi.num_subsets).for_each(|ii| {
174        ep_b[ii * 2] = (bit.read(mi.color_bits) << mode_pbits) as u8;
175        ep_b[ii * 2 + 1] = (bit.read(mi.color_bits) << mode_pbits) as u8;
176    });
177
178    if mi.alpha_bits > 0 {
179        (0..mi.num_subsets).for_each(|ii| {
180            ep_a[ii * 2] = (bit.read(mi.alpha_bits) << mode_pbits) as u8;
181            ep_a[ii * 2 + 1] = (bit.read(mi.alpha_bits) << mode_pbits) as u8;
182        });
183    } else {
184        ep_a = [0xff; 6];
185    }
186
187    if 0 != mode_pbits {
188        (0..mi.num_subsets).for_each(|ii| {
189            let pda: u8 = bit.read(mode_pbits) as u8;
190            let pdb: u8 = if 0 == mi.shared_pbits {
191                bit.read(mode_pbits) as u8
192            } else {
193                pda
194            };
195
196            ep_r[ii * 2] |= pda;
197            ep_r[ii * 2 + 1] |= pdb;
198            ep_g[ii * 2] |= pda;
199            ep_g[ii * 2 + 1] |= pdb;
200            ep_b[ii * 2] |= pda;
201            ep_b[ii * 2 + 1] |= pdb;
202            ep_a[ii * 2] |= pda;
203            ep_a[ii * 2 + 1] |= pdb;
204        });
205    }
206
207    let color_bits: usize = mi.color_bits + mode_pbits;
208
209    (0..mi.num_subsets).for_each(|ii| {
210        ep_r[ii * 2] = expand_quantized(ep_r[ii * 2], color_bits);
211        ep_r[ii * 2 + 1] = expand_quantized(ep_r[ii * 2 + 1], color_bits);
212        ep_g[ii * 2] = expand_quantized(ep_g[ii * 2], color_bits);
213        ep_g[ii * 2 + 1] = expand_quantized(ep_g[ii * 2 + 1], color_bits);
214        ep_b[ii * 2] = expand_quantized(ep_b[ii * 2], color_bits);
215        ep_b[ii * 2 + 1] = expand_quantized(ep_b[ii * 2 + 1], color_bits);
216    });
217
218    if mi.alpha_bits > 0 {
219        let alpha_bits = mi.alpha_bits + mode_pbits;
220
221        (0..mi.num_subsets).for_each(|ii| {
222            ep_a[ii * 2] = expand_quantized(ep_a[ii * 2], alpha_bits);
223            ep_a[ii * 2 + 1] = expand_quantized(ep_a[ii * 2 + 1], alpha_bits);
224        });
225    }
226
227    let has_index_bits1: bool = 0 != mi.index_bits[1];
228
229    let factors: [[u8; 16]; 2] = [
230        S_BPTC_FACTORS[mi.index_bits[0] - 2],
231        if has_index_bits1 {
232            S_BPTC_FACTORS[mi.index_bits[1] - 2]
233        } else {
234            S_BPTC_FACTORS[mi.index_bits[0] - 2]
235        },
236    ];
237
238    let mut offset: [usize; 2] = [0, mi.num_subsets * (16 * mi.index_bits[0] - 1)];
239
240    (0..4_usize).for_each(|yy| {
241        (0..4_usize).for_each(|xx| {
242            let idx = yy * 4 + xx;
243
244            let mut subset_index: usize = 0;
245            let mut index_anchor: usize = 0;
246            match mi.num_subsets {
247                2 => {
248                    subset_index = (S_BPTC_P2[partition_set_idx] >> idx) & 1;
249                    index_anchor = if 0 != subset_index {
250                        S_BPTC_A2[partition_set_idx]
251                    } else {
252                        0
253                    };
254                }
255                3 => {
256                    subset_index = (S_BPTC_P3[partition_set_idx] >> (2 * idx)) & 3;
257                    index_anchor = if 0 != subset_index {
258                        S_BPTC_A3[subset_index - 1][partition_set_idx]
259                    } else {
260                        0
261                    };
262                }
263                _ => {}
264            }
265
266            let anchor = idx == index_anchor;
267            let num: [usize; 2] = [
268                (mi.index_bits[0] - anchor as usize),
269                if has_index_bits1 {
270                    mi.index_bits[1] - anchor as usize
271                } else {
272                    0
273                },
274            ];
275
276            let index: [usize; 2] = {
277                let index_0 = bit.peek(offset[0], num[0]) as usize;
278                [
279                    index_0,
280                    if has_index_bits1 {
281                        bit.peek(offset[1], num[1]) as usize
282                    } else {
283                        index_0
284                    },
285                ]
286            };
287
288            offset[0] += num[0];
289            offset[1] += num[1];
290
291            // index selection mode 0 or 1
292            // !index_selection_mode == 1-index_selection_mode
293            let fc: u16 = factors[index_selection_mode][index[index_selection_mode]] as u16;
294            let fa: u16 = factors[1 - index_selection_mode][index[1 - index_selection_mode]] as u16;
295
296            let fca: u16 = 64 - fc;
297            let fcb: u16 = fc;
298            let faa: u16 = 64 - fa;
299            let fab: u16 = fa;
300
301            subset_index *= 2;
302            let mut rr: u8 =
303                ((ep_r[subset_index] as u16 * fca + ep_r[subset_index + 1] as u16 * fcb + 32) >> 6)
304                    as u8;
305            let mut gg: u8 =
306                ((ep_g[subset_index] as u16 * fca + ep_g[subset_index + 1] as u16 * fcb + 32) >> 6)
307                    as u8;
308            let mut bb: u8 =
309                ((ep_b[subset_index] as u16 * fca + ep_b[subset_index + 1] as u16 * fcb + 32) >> 6)
310                    as u8;
311            let mut aa: u8 =
312                ((ep_a[subset_index] as u16 * faa + ep_a[subset_index + 1] as u16 * fab + 32) >> 6)
313                    as u8;
314
315            match rotation_mode {
316                1 => {
317                    swap(&mut aa, &mut rr);
318                }
319                2 => {
320                    swap(&mut aa, &mut gg);
321                }
322                3 => {
323                    swap(&mut aa, &mut bb);
324                }
325                _ => {}
326            }
327            outbuf[idx] = color(rr, gg, bb, aa);
328        });
329    });
330}