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 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 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}