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