1#[cfg(feature = "bc15")]
49#[inline(always)]
50pub fn decode_block_bc1(
51 compressed_block: &[u8],
52 decompressed_block: &mut [u8],
53 destination_pitch: usize,
54) {
55 decode_color_block::<false>(compressed_block, decompressed_block, destination_pitch);
56}
57
58#[cfg(feature = "bc15")]
60#[inline(always)]
61pub fn decode_block_bc2(
62 compressed_block: &[u8],
63 decompressed_block: &mut [u8],
64 destination_pitch: usize,
65) {
66 decode_color_block::<true>(
67 &compressed_block[8..],
68 decompressed_block,
69 destination_pitch,
70 );
71 decode_sharp_alpha_block(compressed_block, decompressed_block, destination_pitch);
72}
73
74#[cfg(feature = "bc15")]
76#[inline(always)]
77pub fn decode_block_bc3(
78 compressed_block: &[u8],
79 decompressed_block: &mut [u8],
80 destination_pitch: usize,
81) {
82 decode_color_block::<true>(
83 &compressed_block[8..],
84 decompressed_block,
85 destination_pitch,
86 );
87 decode_smooth_alpha_block::<4>(
88 compressed_block,
89 &mut decompressed_block[3..],
90 destination_pitch,
91 );
92}
93
94#[cfg(feature = "bc15")]
96#[inline(always)]
97pub fn decode_block_bc4(
98 compressed_block: &[u8],
99 decompressed_block: &mut [u8],
100 destination_pitch: usize,
101) {
102 decode_smooth_alpha_block::<1>(compressed_block, decompressed_block, destination_pitch);
103}
104
105#[cfg(feature = "bc15")]
107#[inline(always)]
108pub fn decode_block_bc5(
109 compressed_block: &[u8],
110 decompressed_block: &mut [u8],
111 destination_pitch: usize,
112) {
113 decode_smooth_alpha_block::<2>(compressed_block, decompressed_block, destination_pitch);
114 decode_smooth_alpha_block::<2>(
115 &compressed_block[8..],
116 &mut decompressed_block[1..],
117 destination_pitch,
118 );
119}
120
121#[cfg(feature = "bc15")]
123#[inline(always)]
124fn decode_color_block<const OPAQUE_MODE: bool>(
125 compressed_block: &[u8],
126 decompressed_block: &mut [u8],
127 destination_pitch: usize,
128) {
129 let mut ref_colors = [0u32; 4];
130 let c0 = u16::from_le_bytes([compressed_block[0], compressed_block[1]]);
131 let c1 = u16::from_le_bytes([compressed_block[2], compressed_block[3]]);
132
133 let r0 = (c0 >> 11) & 0x1F;
135 let g0 = (c0 >> 5) & 0x3F;
136 let b0 = c0 & 0x1F;
137
138 let r1 = (c1 >> 11) & 0x1F;
139 let g1 = (c1 >> 5) & 0x3F;
140 let b1 = c1 & 0x1F;
141
142 let r = (r0 as u32 * 527 + 23) >> 6;
144 let g = (g0 as u32 * 259 + 33) >> 6;
145 let b = (b0 as u32 * 527 + 23) >> 6;
146 ref_colors[0] = 0xFF000000 | (b << 16) | (g << 8) | r;
147
148 let r = (r1 as u32 * 527 + 23) >> 6;
149 let g = (g1 as u32 * 259 + 33) >> 6;
150 let b = (b1 as u32 * 527 + 23) >> 6;
151 ref_colors[1] = 0xFF000000 | (b << 16) | (g << 8) | r;
152
153 if c0 > c1 || OPAQUE_MODE {
154 let r = ((2 * r0 as u32 + r1 as u32) * 351 + 61) >> 7;
158 let g = ((2 * g0 as u32 + g1 as u32) * 2763 + 1039) >> 11;
159 let b = ((2 * b0 as u32 + b1 as u32) * 351 + 61) >> 7;
160 ref_colors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
161
162 let r = ((r0 as u32 + r1 as u32 * 2) * 351 + 61) >> 7;
163 let g = ((g0 as u32 + g1 as u32 * 2) * 2763 + 1039) >> 11;
164 let b = ((b0 as u32 + b1 as u32 * 2) * 351 + 61) >> 7;
165 ref_colors[3] = 0xFF000000 | (b << 16) | (g << 8) | r;
166 } else {
167 let r = ((r0 as u32 + r1 as u32) * 1053 + 125) >> 8;
171 let g = ((g0 as u32 + g1 as u32) * 4145 + 1019) >> 11;
172 let b = ((b0 as u32 + b1 as u32) * 1053 + 125) >> 8;
173 ref_colors[2] = 0xFF000000 | (b << 16) | (g << 8) | r;
174 ref_colors[3] = 0x00000000;
175 }
176
177 let mut color_indices = u32::from_le_bytes([
178 compressed_block[4],
179 compressed_block[5],
180 compressed_block[6],
181 compressed_block[7],
182 ]);
183
184 for i in 0..4 {
186 for j in 0..4 {
187 let idx = color_indices & 0x03;
188 let offset = j * 4;
189 let color = ref_colors[idx as usize];
190
191 decompressed_block[i * destination_pitch + offset..][..4]
192 .copy_from_slice(&color.to_le_bytes());
193
194 color_indices >>= 2;
195 }
196 }
197}
198
199#[cfg(feature = "bc15")]
201#[inline(always)]
202fn decode_sharp_alpha_block(
203 compressed_block: &[u8],
204 decompressed_block: &mut [u8],
205 destination_pitch: usize,
206) {
207 for i in 0..4 {
208 for j in 0..4 {
209 let byte_index = i * 2 + (j / 2);
210 let shift = (j % 2) * 4;
211 let alpha_value = (compressed_block[byte_index] >> shift) & 0x0F;
212 decompressed_block[i * destination_pitch + j * 4 + 3] = alpha_value * 17;
213 }
214 }
215}
216
217#[cfg(feature = "bc15")]
219#[inline(always)]
220#[rustfmt::skip]
221fn decode_smooth_alpha_block<const PIXEL_SIZE: usize>(
222 compressed_block: &[u8],
223 decompressed_block: &mut [u8],
224 destination_pitch: usize,
225) {
226 let block = u64::from_le_bytes(compressed_block[0..8].try_into().unwrap());
227
228 let mut alpha = [0u8; 8];
229 alpha[0] = (block & 0xFF) as u8;
230 alpha[1] = ((block >> 8) & 0xFF) as u8;
231
232 if alpha[0] > alpha[1] {
233 alpha[2] = ((6 * alpha[0] as u16 + alpha[1] as u16) / 7) as u8; alpha[3] = ((5 * alpha[0] as u16 + 2 * alpha[1] as u16) / 7) as u8; alpha[4] = ((4 * alpha[0] as u16 + 3 * alpha[1] as u16) / 7) as u8; alpha[5] = ((3 * alpha[0] as u16 + 4 * alpha[1] as u16) / 7) as u8; alpha[6] = ((2 * alpha[0] as u16 + 5 * alpha[1] as u16) / 7) as u8; alpha[7] = (( alpha[0] as u16 + 6 * alpha[1] as u16) / 7) as u8; } else {
241 alpha[2] = ((4 * alpha[0] as u16 + alpha[1] as u16) / 5) as u8; alpha[3] = ((3 * alpha[0] as u16 + 2 * alpha[1] as u16) / 5) as u8; alpha[4] = ((2 * alpha[0] as u16 + 3 * alpha[1] as u16) / 5) as u8; alpha[5] = (( alpha[0] as u16 + 4 * alpha[1] as u16) / 5) as u8; alpha[6] = 0x00;
247 alpha[7] = 0xFF;
248 }
249
250 let mut indices = block >> 16;
251
252 for i in 0..4 {
253 for j in 0..4 {
254 decompressed_block[i * destination_pitch + j * PIXEL_SIZE] = alpha[(indices & 0x07) as usize];
255 indices >>= 3;
256 }
257 }
258}
259
260#[cfg(feature = "bc6h")]
262pub fn decode_block_bc6h(
263 compressed_block: &[u8],
264 decompressed_block: &mut [half::f16],
265 destination_pitch: usize,
266 is_signed: bool,
267) {
268 use half::f16;
269
270 static ACTUAL_BITS_COUNT: &[[u8; 14]; 4] = &[
271 [10, 7, 11, 11, 11, 9, 8, 8, 8, 6, 10, 11, 12, 16], [5, 6, 5, 4, 4, 5, 6, 5, 5, 6, 10, 9, 8, 4], [5, 6, 4, 5, 4, 5, 5, 6, 5, 6, 10, 9, 8, 4], [5, 6, 4, 4, 5, 5, 5, 5, 6, 6, 10, 9, 8, 4], ];
276
277 static PARTITION_SETS: &[[[u8; 4]; 4]; 32] = &[
281 [[128, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 129]], [[128, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 129]], [[128, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 129]], [[128, 1, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 1, 0]], [[128, 1, 129, 1], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 1, 0, 0], [1, 1, 1, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 129]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 129, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 1, 1, 0]], [[128, 0, 129, 1], [0, 1, 1, 0], [0, 1, 1, 0], [1, 1, 0, 0]], [[128, 0, 0, 1], [0, 1, 1, 1], [129, 1, 1, 0], [1, 0, 0, 0]], [[128, 0, 0, 0], [1, 1, 1, 1], [129, 1, 1, 1], [0, 0, 0, 0]], [[128, 1, 129, 1], [0, 0, 0, 1], [1, 0, 0, 0], [1, 1, 1, 0]], [[128, 0, 129, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 0, 0]], ];
314
315 const WEIGHT3: &[i32] = &[0, 9, 18, 27, 37, 46, 55, 64];
316 const WEIGHT4: &[i32] = &[0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64];
317
318 let mut bstream = BitStream::new(compressed_block);
319
320 let mut r = [0i32; 4];
321 let mut g = [0i32; 4];
322 let mut b = [0i32; 4];
323
324 let mut mode = bstream.read_bits(2);
325 if mode > 1 {
326 mode |= bstream.read_bits(3) << 2;
327 }
328
329 let mut partition = 0;
331
332 match mode {
333 0b00 => {
335 g[2] |= bstream.read_bit_i32() << 4; b[2] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32() << 4; r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 0;
359 }
360
361 0b01 => {
363 g[2] |= bstream.read_bit_i32() << 5; g[3] |= bstream.read_bit_i32() << 4; g[3] |= bstream.read_bit_i32() << 5; r[0] |= bstream.read_bits_i32(7); b[3] |= bstream.read_bit_i32(); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(7); b[2] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 2; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(7); b[3] |= bstream.read_bit_i32() << 3; b[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(6); b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(6); r[3] |= bstream.read_bits_i32(6); partition = bstream.read_bits_i32(5); mode = 1;
391 }
392
393 0b00010 => {
395 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(5); r[0] |= bstream.read_bit_i32() << 10; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(4); g[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(4); b[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 2;
418 }
419 0b00110 => {
421 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(4); r[0] |= bstream.read_bit_i32() << 10; g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); g[0] |= bstream.read_bit_i32() << 10; g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(4); b[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(4); b[3] |= bstream.read_bit_i32(); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(4); g[2] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 3;
446 }
447 0b01010 => {
449 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(4); r[0] |= bstream.read_bit_i32() << 10; b[2] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(4); g[0] |= bstream.read_bit_i32() << 10; b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[0] |= bstream.read_bit_i32() << 10; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(4); b[3] |= bstream.read_bit_i32() << 1; b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(4); b[3] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 4;
474 }
475 0b01110 => {
477 r[0] |= bstream.read_bits_i32(9); b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(9); g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(9); b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 5;
501 }
502 0b10010 => {
504 r[0] |= bstream.read_bits_i32(8); g[3] |= bstream.read_bit_i32() << 4; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 2; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 3; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(6); r[3] |= bstream.read_bits_i32(6); partition = bstream.read_bits_i32(5); mode = 6;
528 }
529 0b10110 => {
531 r[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32(); b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(8); g[2] |= bstream.read_bit_i32() << 5; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(8); g[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 7;
557 }
558 0b11010 => {
560 r[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(8); b[2] |= bstream.read_bit_i32() << 5; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(8); b[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(5); g[3] |= bstream.read_bit_i32() << 4; g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32(); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(6); b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 2; r[3] |= bstream.read_bits_i32(5); b[3] |= bstream.read_bit_i32() << 3; partition = bstream.read_bits_i32(5); mode = 8;
586 }
587 0b11110 => {
589 r[0] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bit_i32() << 4; b[3] |= bstream.read_bit_i32(); b[3] |= bstream.read_bit_i32() << 1; b[2] |= bstream.read_bit_i32() << 4; g[0] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bit_i32() << 5; b[2] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 2; g[2] |= bstream.read_bit_i32() << 4; b[0] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 3; b[3] |= bstream.read_bit_i32() << 5; b[3] |= bstream.read_bit_i32() << 4; r[1] |= bstream.read_bits_i32(6); g[2] |= bstream.read_bits_i32(4); g[1] |= bstream.read_bits_i32(6); g[3] |= bstream.read_bits_i32(4); b[1] |= bstream.read_bits_i32(6); b[2] |= bstream.read_bits_i32(4); r[2] |= bstream.read_bits_i32(6); r[3] |= bstream.read_bits_i32(6); partition = bstream.read_bits_i32(5); mode = 9;
617 }
618 0b00011 => {
620 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(10); g[1] |= bstream.read_bits_i32(10); b[1] |= bstream.read_bits_i32(10); mode = 10;
630 }
631 0b00111 => {
633 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(9); r[0] |= bstream.read_bit_i32() << 10; g[1] |= bstream.read_bits_i32(9); g[0] |= bstream.read_bit_i32() << 10; b[1] |= bstream.read_bits_i32(9); b[0] |= bstream.read_bit_i32() << 10; mode = 11;
646 }
647 0b01011 => {
649 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(8); r[0] |= bstream.read_bits_reversed(2) << 10; g[1] |= bstream.read_bits_i32(8); g[0] |= bstream.read_bits_reversed(2) << 10; b[1] |= bstream.read_bits_i32(8); b[0] |= bstream.read_bits_reversed(2) << 10; mode = 12;
662 }
663 0b01111 => {
665 r[0] |= bstream.read_bits_i32(10); g[0] |= bstream.read_bits_i32(10); b[0] |= bstream.read_bits_i32(10); r[1] |= bstream.read_bits_i32(4); r[0] |= bstream.read_bits_reversed(6) << 10; g[1] |= bstream.read_bits_i32(4); g[0] |= bstream.read_bits_reversed(6) << 10; b[1] |= bstream.read_bits_i32(4); b[0] |= bstream.read_bits_reversed(6) << 10; mode = 13;
678 }
679 _ => {
680 for i in 0..4 {
685 let start = i * destination_pitch;
686 let end = start + 4 * 3;
687 decompressed_block[start..end].fill(f16::ZERO);
688 }
689
690 return;
691 }
692 }
693
694 let num_partitions = if mode >= 10 { 0 } else { 1 };
695
696 let actual_bits0_mode = ACTUAL_BITS_COUNT[0][mode as usize] as i32;
697 if is_signed {
698 r[0] = extend_sign(r[0], actual_bits0_mode);
699 g[0] = extend_sign(g[0], actual_bits0_mode);
700 b[0] = extend_sign(b[0], actual_bits0_mode);
701 }
702
703 if mode != 9 && mode != 10 || is_signed {
706 for i in 1..(num_partitions + 1) * 2 {
707 r[i] = extend_sign(r[i], ACTUAL_BITS_COUNT[1][mode as usize] as i32);
708 g[i] = extend_sign(g[i], ACTUAL_BITS_COUNT[2][mode as usize] as i32);
709 b[i] = extend_sign(b[i], ACTUAL_BITS_COUNT[3][mode as usize] as i32);
710 }
711 }
712
713 if mode != 9 && mode != 10 {
714 for i in 1..(num_partitions + 1) * 2 {
715 r[i] = transform_inverse(r[i], r[0], actual_bits0_mode, is_signed);
716 g[i] = transform_inverse(g[i], g[0], actual_bits0_mode, is_signed);
717 b[i] = transform_inverse(b[i], b[0], actual_bits0_mode, is_signed);
718 }
719 }
720
721 for i in 0..(num_partitions + 1) * 2 {
722 r[i] = unquantize(r[i], actual_bits0_mode, is_signed);
723 g[i] = unquantize(g[i], actual_bits0_mode, is_signed);
724 b[i] = unquantize(b[i], actual_bits0_mode, is_signed);
725 }
726
727 let weights = if mode >= 10 { WEIGHT4 } else { WEIGHT3 };
728
729 for i in 0..4 {
730 for j in 0..4 {
731 let mut partition_set = if mode >= 10 {
732 if i | j == 0 {
733 128i32
734 } else {
735 0i32
736 }
737 } else {
738 PARTITION_SETS[partition as usize][i][j] as i32
739 };
740
741 let mut index_bits = if mode >= 10 { 4 } else { 3 };
742
743 if (partition_set & 0x80) != 0 {
746 index_bits -= 1;
747 }
748 partition_set &= 0x01;
749
750 let index = bstream.read_bits_i32(index_bits);
751
752 let ep_i = (partition_set * 2) as usize;
753 let out = i * destination_pitch + j * 3;
754
755 decompressed_block[out] = f16::from_bits(finish_unquantize(
756 interpolate(r[ep_i], r[ep_i + 1], weights, index),
757 is_signed,
758 ));
759 decompressed_block[out + 1] = f16::from_bits(finish_unquantize(
760 interpolate(g[ep_i], g[ep_i + 1], weights, index),
761 is_signed,
762 ));
763 decompressed_block[out + 2] = f16::from_bits(finish_unquantize(
764 interpolate(b[ep_i], b[ep_i + 1], weights, index),
765 is_signed,
766 ));
767 }
768 }
769}
770
771#[cfg(feature = "bc6h")]
773#[inline(always)]
774pub fn decode_block_bc6h_float(
775 compressed_block: &[u8],
776 decompressed_block: &mut [f32],
777 destination_pitch: usize,
778 is_signed: bool,
779) {
780 let mut block = [half::f16::ZERO; 48];
781 decode_block_bc6h(compressed_block, &mut block, 12, is_signed);
782
783 let mut decompressed = decompressed_block;
784
785 for i in 0..4 {
786 for j in 0..4 {
787 let offset = i * 12 + j * 3;
788 let pixel_offset = j * 3;
789
790 decompressed[pixel_offset] = block[offset].to_f32();
791 decompressed[pixel_offset + 1] = block[offset + 1].to_f32();
792 decompressed[pixel_offset + 2] = block[offset + 2].to_f32();
793 }
794 decompressed = &mut decompressed[destination_pitch..];
795 }
796}
797
798#[cfg(feature = "bc7")]
800#[allow(clippy::needless_range_loop)]
801pub fn decode_block_bc7(
802 compressed_block: &[u8],
803 decompressed_block: &mut [u8],
804 destination_pitch: usize,
805) {
806 static ACTUAL_BITS_COUNT: &[[u8; 8]; 2] = &[
807 [4, 6, 5, 7, 5, 7, 7, 5], [0, 0, 0, 0, 6, 8, 7, 5], ];
810
811 static PARTITION_SETS: &[[[[u8; 4]; 4]; 64]; 2] = &[
815 [
816 [[128, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 1, 129]], [[128, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 129]], [[128, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 1], [0, 1, 1, 129]], [[128, 0, 0, 1], [0, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [1, 1, 1, 129]], [[128, 0, 0, 0], [1, 0, 0, 0], [1, 1, 1, 0], [1, 1, 1, 129]], [[128, 1, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 1, 0]], [[128, 1, 129, 1], [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 1, 0, 0], [1, 1, 1, 0]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 1, 1], [0, 0, 1, 1], [0, 0, 1, 1], [0, 0, 0, 129]], [[128, 0, 129, 1], [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 0]], [[128, 0, 0, 0], [1, 0, 0, 0], [129, 0, 0, 0], [1, 1, 0, 0]], [[128, 1, 129, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 1, 1, 0]], [[128, 0, 129, 1], [0, 1, 1, 0], [0, 1, 1, 0], [1, 1, 0, 0]], [[128, 0, 0, 1], [0, 1, 1, 1], [129, 1, 1, 0], [1, 0, 0, 0]], [[128, 0, 0, 0], [1, 1, 1, 1], [129, 1, 1, 1], [0, 0, 0, 0]], [[128, 1, 129, 1], [0, 0, 0, 1], [1, 0, 0, 0], [1, 1, 1, 0]], [[128, 0, 129, 1], [1, 0, 0, 1], [1, 0, 0, 1], [1, 1, 0, 0]], [[128, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 1], [0, 1, 0, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [0, 0, 0, 0], [1, 1, 1, 129]], [[128, 1, 0, 1], [1, 0, 129, 0], [0, 1, 0, 1], [1, 0, 1, 0]], [[128, 0, 1, 1], [0, 0, 1, 1], [129, 1, 0, 0], [1, 1, 0, 0]], [[128, 0, 129, 1], [1, 1, 0, 0], [0, 0, 1, 1], [1, 1, 0, 0]], [[128, 1, 0, 1], [0, 1, 0, 1], [129, 0, 1, 0], [1, 0, 1, 0]], [[128, 1, 1, 0], [1, 0, 0, 1], [0, 1, 1, 0], [1, 0, 0, 129]], [[128, 1, 0, 1], [1, 0, 1, 0], [1, 0, 1, 0], [0, 1, 0, 129]], [[128, 1, 129, 1], [0, 0, 1, 1], [1, 1, 0, 0], [1, 1, 1, 0]], [[128, 0, 0, 1], [0, 0, 1, 1], [129, 1, 0, 0], [1, 0, 0, 0]], [[128, 0, 129, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 1, 0, 0]], [[128, 0, 129, 1], [1, 0, 1, 1], [1, 1, 0, 1], [1, 1, 0, 0]], [[128, 1, 129, 0], [1, 0, 0, 1], [1, 0, 0, 1], [0, 1, 1, 0]], [[128, 0, 1, 1], [1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 129]], [[128, 1, 1, 0], [0, 1, 1, 0], [1, 0, 0, 1], [1, 0, 0, 129]], [[128, 0, 0, 0], [0, 1, 129, 0], [0, 1, 1, 0], [0, 0, 0, 0]], [[128, 1, 0, 0], [1, 1, 129, 0], [0, 1, 0, 0], [0, 0, 0, 0]], [[128, 0, 129, 0], [0, 1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 0]], [[128, 0, 0, 0], [0, 0, 129, 0], [0, 1, 1, 1], [0, 0, 1, 0]], [[128, 0, 0, 0], [0, 1, 0, 0], [129, 1, 1, 0], [0, 1, 0, 0]], [[128, 1, 1, 0], [1, 1, 0, 0], [1, 0, 0, 1], [0, 0, 1, 129]], [[128, 0, 1, 1], [0, 1, 1, 0], [1, 1, 0, 0], [1, 0, 0, 129]], [[128, 1, 129, 0], [0, 0, 1, 1], [1, 0, 0, 1], [1, 1, 0, 0]], [[128, 0, 129, 1], [1, 0, 0, 1], [1, 1, 0, 0], [0, 1, 1, 0]], [[128, 1, 1, 0], [1, 1, 0, 0], [1, 1, 0, 0], [1, 0, 0, 129]], [[128, 1, 1, 0], [0, 0, 1, 1], [0, 0, 1, 1], [1, 0, 0, 129]], [[128, 1, 1, 1], [1, 1, 1, 0], [1, 0, 0, 0], [0, 0, 0, 129]], [[128, 0, 0, 1], [1, 0, 0, 0], [1, 1, 1, 0], [0, 1, 1, 129]], [[128, 0, 0, 0], [1, 1, 1, 1], [0, 0, 1, 1], [0, 0, 1, 129]], [[128, 0, 129, 1], [0, 0, 1, 1], [1, 1, 1, 1], [0, 0, 0, 0]], [[128, 0, 129, 0], [0, 0, 1, 0], [1, 1, 1, 0], [1, 1, 1, 0]], [[128, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 1], [0, 1, 1, 129]], ],
882 [
883 [[128, 0, 1, 129], [0, 0, 1, 1], [0, 2, 2, 1], [2, 2, 2, 130]], [[128, 0, 0, 129], [0, 0, 1, 1], [130, 2, 1, 1], [2, 2, 2, 1]], [[128, 0, 0, 0], [2, 0, 0, 1], [130, 2, 1, 1], [2, 2, 1, 129]], [[128, 2, 2, 130], [0, 0, 2, 2], [0, 0, 1, 1], [0, 1, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 1, 2, 2], [1, 1, 2, 130]], [[128, 0, 1, 129], [0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 2, 130]], [[128, 0, 2, 130], [0, 0, 2, 2], [1, 1, 1, 1], [1, 1, 1, 129]], [[128, 0, 1, 1], [0, 0, 1, 1], [130, 2, 1, 1], [2, 2, 1, 129]], [[128, 0, 0, 0], [0, 0, 0, 0], [129, 1, 1, 1], [2, 2, 2, 130]], [[128, 0, 0, 0], [1, 1, 1, 1], [129, 1, 1, 1], [2, 2, 2, 130]], [[128, 0, 0, 0], [1, 1, 129, 1], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 0, 1, 2], [0, 0, 129, 2], [0, 0, 1, 2], [0, 0, 1, 130]], [[128, 1, 1, 2], [0, 1, 129, 2], [0, 1, 1, 2], [0, 1, 1, 130]], [[128, 1, 2, 2], [0, 129, 2, 2], [0, 1, 2, 2], [0, 1, 2, 130]], [[128, 0, 1, 129], [0, 1, 1, 2], [1, 1, 2, 2], [1, 2, 2, 130]], [[128, 0, 1, 129], [2, 0, 0, 1], [130, 2, 0, 0], [2, 2, 2, 0]], [[128, 0, 0, 129], [0, 0, 1, 1], [0, 1, 1, 2], [1, 1, 2, 130]], [[128, 1, 1, 129], [0, 0, 1, 1], [130, 0, 0, 1], [2, 2, 0, 0]], [[128, 0, 0, 0], [1, 1, 2, 2], [129, 1, 2, 2], [1, 1, 2, 130]], [[128, 0, 2, 130], [0, 0, 2, 2], [0, 0, 2, 2], [1, 1, 1, 129]], [[128, 1, 1, 129], [0, 1, 1, 1], [0, 2, 2, 2], [0, 2, 2, 130]], [[128, 0, 0, 129], [0, 0, 0, 1], [130, 2, 2, 1], [2, 2, 2, 1]], [[128, 0, 0, 0], [0, 0, 129, 1], [0, 1, 2, 2], [0, 1, 2, 130]], [[128, 0, 0, 0], [1, 1, 0, 0], [130, 2, 129, 0], [2, 2, 1, 0]], [[128, 1, 2, 130], [0, 129, 2, 2], [0, 0, 1, 1], [0, 0, 0, 0]], [[128, 0, 1, 2], [0, 0, 1, 2], [129, 1, 2, 2], [2, 2, 2, 130]], [[128, 1, 1, 0], [1, 2, 130, 1], [129, 2, 2, 1], [0, 1, 1, 0]], [[128, 0, 0, 0], [0, 1, 129, 0], [1, 2, 130, 1], [1, 2, 2, 1]], [[128, 0, 2, 2], [1, 1, 0, 2], [129, 1, 0, 2], [0, 0, 2, 130]], [[128, 1, 1, 0], [0, 129, 1, 0], [2, 0, 0, 2], [2, 2, 2, 130]], [[128, 0, 1, 1], [0, 1, 2, 2], [0, 1, 130, 2], [0, 0, 1, 129]], [[128, 0, 0, 0], [2, 0, 0, 0], [130, 2, 1, 1], [2, 2, 2, 129]], [[128, 0, 0, 0], [0, 0, 0, 2], [129, 1, 2, 2], [1, 2, 2, 130]], [[128, 2, 2, 130], [0, 0, 2, 2], [0, 0, 1, 2], [0, 0, 1, 129]], [[128, 0, 1, 129], [0, 0, 1, 2], [0, 0, 2, 2], [0, 2, 2, 130]], [[128, 1, 2, 0], [0, 129, 2, 0], [0, 1, 130, 0], [0, 1, 2, 0]], [[128, 0, 0, 0], [1, 1, 129, 1], [2, 2, 130, 2], [0, 0, 0, 0]], [[128, 1, 2, 0], [1, 2, 0, 1], [130, 0, 129, 2], [0, 1, 2, 0]], [[128, 1, 2, 0], [2, 0, 1, 2], [129, 130, 0, 1], [0, 1, 2, 0]], [[128, 0, 1, 1], [2, 2, 0, 0], [1, 1, 130, 2], [0, 0, 1, 129]], [[128, 0, 1, 1], [1, 1, 130, 2], [2, 2, 0, 0], [0, 0, 1, 129]], [[128, 1, 0, 129], [0, 1, 0, 1], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 0, 0, 0], [0, 0, 0, 0], [130, 1, 2, 1], [2, 1, 2, 129]], [[128, 0, 2, 2], [1, 129, 2, 2], [0, 0, 2, 2], [1, 1, 2, 130]], [[128, 0, 2, 130], [0, 0, 1, 1], [0, 0, 2, 2], [0, 0, 1, 129]], [[128, 2, 2, 0], [1, 2, 130, 1], [0, 2, 2, 0], [1, 2, 2, 129]], [[128, 1, 0, 1], [2, 2, 130, 2], [2, 2, 2, 2], [0, 1, 0, 129]], [[128, 0, 0, 0], [2, 1, 2, 1], [130, 1, 2, 1], [2, 1, 2, 129]], [[128, 1, 0, 129], [0, 1, 0, 1], [0, 1, 0, 1], [2, 2, 2, 130]], [[128, 2, 2, 130], [0, 1, 1, 1], [0, 2, 2, 2], [0, 1, 1, 129]], [[128, 0, 0, 2], [1, 129, 1, 2], [0, 0, 0, 2], [1, 1, 1, 130]], [[128, 0, 0, 0], [2, 129, 1, 2], [2, 1, 1, 2], [2, 1, 1, 130]], [[128, 2, 2, 2], [0, 129, 1, 1], [0, 1, 1, 1], [0, 2, 2, 130]], [[128, 0, 0, 2], [1, 1, 1, 2], [129, 1, 1, 2], [0, 0, 0, 130]], [[128, 1, 1, 0], [0, 129, 1, 0], [0, 1, 1, 0], [2, 2, 2, 130]], [[128, 0, 0, 0], [0, 0, 0, 0], [2, 1, 129, 2], [2, 1, 1, 130]], [[128, 1, 1, 0], [0, 129, 1, 0], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 0, 2, 2], [0, 0, 1, 1], [0, 0, 129, 1], [0, 0, 2, 130]], [[128, 0, 2, 2], [1, 1, 2, 2], [129, 1, 2, 2], [0, 0, 2, 130]], [[128, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 129, 1, 130]], [[128, 0, 0, 130], [0, 0, 0, 1], [0, 0, 0, 2], [0, 0, 0, 129]], [[128, 2, 2, 2], [1, 2, 2, 2], [0, 2, 2, 2], [129, 2, 2, 130]], [[128, 1, 0, 129], [2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 130]], [[128, 1, 1, 129], [2, 0, 1, 1], [130, 2, 0, 1], [2, 2, 2, 0]], ],
949 ];
950
951 static WEIGHT2: &[i32] = &[0, 21, 43, 64];
952 static WEIGHT3: &[i32] = &[0, 9, 18, 27, 37, 46, 55, 64];
953 static WEIGHT4: &[i32] = &[0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64];
954
955 const MODE_HAS_P_BITS: u8 = 0b11001011;
956
957 let mut bstream = BitStream::new(compressed_block);
958
959 let mut mode = 0;
961 while mode < 8 && bstream.read_bit() == 0 {
962 mode += 1;
963 }
964
965 if mode >= 8 {
967 for i in 0..4 {
968 for j in 0..4 {
969 let offset = i * destination_pitch + j * 4;
970 decompressed_block[offset..offset + 4].copy_from_slice(&[0, 0, 0, 0]);
971 }
972 }
973 return;
974 }
975
976 let mut partition = 0;
977 let mut num_partitions = 1;
978 let mut rotation = 0;
979 let mut index_selection_bit = 0;
980
981 if mode == 0 || mode == 1 || mode == 2 || mode == 3 || mode == 7 {
982 num_partitions = if mode == 0 || mode == 2 { 3 } else { 2 };
983 partition = bstream.read_bits(if mode == 0 { 4 } else { 6 }) as usize;
984 }
985
986 let num_endpoints = num_partitions * 2;
987
988 if mode == 4 || mode == 5 {
989 rotation = bstream.read_bits(2);
990 if mode == 4 {
991 index_selection_bit = bstream.read_bit();
992 }
993 }
994
995 let mut endpoints = [[0i32; 4]; 6];
997
998 for i in 0..3 {
1000 for j in 0..num_endpoints {
1001 endpoints[j][i] = bstream.read_bits(ACTUAL_BITS_COUNT[0][mode as usize] as u32) as i32;
1002 }
1003 }
1004
1005 if ACTUAL_BITS_COUNT[1][mode as usize] > 0 {
1007 for j in 0..num_endpoints {
1008 endpoints[j][3] = bstream.read_bits(ACTUAL_BITS_COUNT[1][mode as usize] as u32) as i32;
1009 }
1010 }
1011
1012 if mode == 0 || mode == 1 || mode == 3 || mode == 6 || mode == 7 {
1015 for endpoint in endpoints.iter_mut().take(num_endpoints) {
1017 for component in endpoint.iter_mut() {
1018 *component <<= 1;
1019 }
1020 }
1021
1022 if mode == 1 {
1024 let i = bstream.read_bit() as i32;
1025 let j = bstream.read_bit() as i32;
1026
1027 for k in 0..3 {
1029 endpoints[0][k] |= i;
1030 endpoints[1][k] |= i;
1031 endpoints[2][k] |= j;
1032 endpoints[3][k] |= j;
1033 }
1034 } else if MODE_HAS_P_BITS & (1 << mode) != 0 {
1035 for endpoint in endpoints.iter_mut().take(num_endpoints) {
1037 let j = bstream.read_bit() as i32;
1038 for component in endpoint.iter_mut() {
1039 *component |= j;
1040 }
1041 }
1042 }
1043 }
1044
1045 for i in 0..num_endpoints {
1048 let j = ACTUAL_BITS_COUNT[0][mode as usize] + ((MODE_HAS_P_BITS >> mode) & 1);
1050
1051 for k in 0..3 {
1053 endpoints[i][k] <<= 8 - j;
1055 endpoints[i][k] |= endpoints[i][k] >> j as i32;
1057 }
1058
1059 let j = ACTUAL_BITS_COUNT[1][mode as usize] + ((MODE_HAS_P_BITS >> mode) & 1);
1061
1062 endpoints[i][3] <<= 8 - j;
1064 endpoints[i][3] |= endpoints[i][3] >> j as i32;
1065 }
1066
1067 if ACTUAL_BITS_COUNT[1][mode as usize] == 0 {
1069 for endpoint in endpoints.iter_mut().take(num_endpoints) {
1070 endpoint[3] = 0xFF;
1071 }
1072 }
1073
1074 let index_bits = match mode {
1076 0 | 1 => 3,
1077 6 => 4,
1078 _ => 2,
1079 };
1080
1081 let index_bits2 = match mode {
1082 4 => 3,
1083 5 => 2,
1084 _ => 0,
1085 };
1086
1087 let weights = match index_bits {
1088 2 => WEIGHT2,
1089 3 => WEIGHT3,
1090 _ => WEIGHT4,
1091 };
1092
1093 let weights2 = match index_bits2 {
1094 2 => WEIGHT2,
1095 _ => WEIGHT3,
1096 };
1097
1098 let mut indices = [[0i32; 4]; 4];
1101 for i in 0..4 {
1102 for j in 0..4 {
1103 let partition_set = if num_partitions == 1 {
1104 if i | j == 0 {
1105 128
1106 } else {
1107 0
1108 }
1109 } else {
1110 PARTITION_SETS[num_partitions - 2][partition][i][j]
1111 };
1112
1113 let mut idx_bits = match mode {
1114 0 | 1 => 3,
1115 6 => 4,
1116 _ => 2,
1117 };
1118
1119 if partition_set & 0x80 != 0 {
1122 idx_bits -= 1;
1123 }
1124
1125 indices[i][j] = bstream.read_bits(idx_bits) as i32;
1126 }
1127 }
1128
1129 for i in 0..4 {
1131 for j in 0..4 {
1132 let partition_set = if num_partitions == 1 {
1133 if i | j == 0 {
1134 128
1135 } else {
1136 0
1137 }
1138 } else {
1139 PARTITION_SETS[num_partitions - 2][partition][i][j]
1140 };
1141 let partition_set = (partition_set & 0x03) as usize;
1142
1143 let index = indices[i][j];
1144
1145 let (mut r, mut g, mut b, mut a) = if index_bits2 == 0 {
1146 (
1148 interpolate(
1149 endpoints[partition_set * 2][0],
1150 endpoints[partition_set * 2 + 1][0],
1151 weights,
1152 index,
1153 ),
1154 interpolate(
1155 endpoints[partition_set * 2][1],
1156 endpoints[partition_set * 2 + 1][1],
1157 weights,
1158 index,
1159 ),
1160 interpolate(
1161 endpoints[partition_set * 2][2],
1162 endpoints[partition_set * 2 + 1][2],
1163 weights,
1164 index,
1165 ),
1166 interpolate(
1167 endpoints[partition_set * 2][3],
1168 endpoints[partition_set * 2 + 1][3],
1169 weights,
1170 index,
1171 ),
1172 )
1173 } else {
1174 let index2 = bstream.read_bits(if i | j == 0 {
1175 index_bits2 - 1
1176 } else {
1177 index_bits2
1178 }) as i32;
1179
1180 if index_selection_bit == 0 {
1181 (
1182 interpolate(
1183 endpoints[partition_set * 2][0],
1184 endpoints[partition_set * 2 + 1][0],
1185 weights,
1186 index,
1187 ),
1188 interpolate(
1189 endpoints[partition_set * 2][1],
1190 endpoints[partition_set * 2 + 1][1],
1191 weights,
1192 index,
1193 ),
1194 interpolate(
1195 endpoints[partition_set * 2][2],
1196 endpoints[partition_set * 2 + 1][2],
1197 weights,
1198 index,
1199 ),
1200 interpolate(
1201 endpoints[partition_set * 2][3],
1202 endpoints[partition_set * 2 + 1][3],
1203 weights2,
1204 index2,
1205 ),
1206 )
1207 } else {
1208 (
1209 interpolate(
1210 endpoints[partition_set * 2][0],
1211 endpoints[partition_set * 2 + 1][0],
1212 weights2,
1213 index2,
1214 ),
1215 interpolate(
1216 endpoints[partition_set * 2][1],
1217 endpoints[partition_set * 2 + 1][1],
1218 weights2,
1219 index2,
1220 ),
1221 interpolate(
1222 endpoints[partition_set * 2][2],
1223 endpoints[partition_set * 2 + 1][2],
1224 weights2,
1225 index2,
1226 ),
1227 interpolate(
1228 endpoints[partition_set * 2][3],
1229 endpoints[partition_set * 2 + 1][3],
1230 weights,
1231 index,
1232 ),
1233 )
1234 }
1235 };
1236
1237 match rotation {
1239 1 => std::mem::swap(&mut a, &mut r), 2 => std::mem::swap(&mut a, &mut g), 3 => std::mem::swap(&mut a, &mut b), _ => {}
1243 }
1244
1245 let offset = i * destination_pitch + j * 4;
1246 decompressed_block[offset] = r as u8;
1247 decompressed_block[offset + 1] = g as u8;
1248 decompressed_block[offset + 2] = b as u8;
1249 decompressed_block[offset + 3] = a as u8;
1250 }
1251 }
1252}
1253
1254#[cfg(any(feature = "bc6h", feature = "bc7"))]
1255#[inline]
1256fn interpolate(a: i32, b: i32, weights: &[i32], index: i32) -> i32 {
1257 (a * (64 - weights[index as usize]) + b * weights[index as usize] + 32) >> 6
1258}
1259
1260#[cfg(feature = "bc6h")]
1261#[inline]
1262fn extend_sign(val: i32, bits: i32) -> i32 {
1263 (val << (32 - bits)) >> (32 - bits)
1265}
1266
1267#[cfg(feature = "bc6h")]
1268#[inline]
1269fn transform_inverse(val: i32, a0: i32, bits: i32, is_signed: bool) -> i32 {
1270 let transformed = (val + a0) & ((1 << bits) - 1);
1273 if is_signed {
1274 extend_sign(transformed, bits)
1275 } else {
1276 transformed
1277 }
1278}
1279
1280#[cfg(feature = "bc6h")]
1281#[inline]
1282fn unquantize(val: i32, bits: i32, is_signed: bool) -> i32 {
1283 if !is_signed {
1284 if bits >= 15 {
1285 val
1286 } else if val == 0 {
1287 0
1288 } else if val == ((1 << bits) - 1) {
1289 0xFFFF
1290 } else {
1291 ((val << 16) + 0x8000) >> bits
1292 }
1293 } else if bits >= 16 {
1294 val
1295 } else {
1296 let (s, v) = if val < 0 { (true, -val) } else { (false, val) };
1297
1298 let unq = if v == 0 {
1299 0
1300 } else if v >= ((1 << (bits - 1)) - 1) {
1301 0x7FFF
1302 } else {
1303 ((v << 15) + 0x4000) >> (bits - 1)
1304 };
1305
1306 if s {
1307 -unq
1308 } else {
1309 unq
1310 }
1311 }
1312}
1313
1314#[cfg(feature = "bc6h")]
1315#[inline]
1316fn finish_unquantize(val: i32, is_signed: bool) -> u16 {
1317 if !is_signed {
1318 ((val * 31) >> 6) as u16
1320 } else {
1321 let scaled = if val < 0 {
1323 -(((-val) * 31) >> 5)
1324 } else {
1325 (val * 31) >> 5
1326 };
1327
1328 let (sign_bit, magnitude) = if scaled < 0 {
1329 (0x8000, -scaled)
1330 } else {
1331 (0, scaled)
1332 };
1333
1334 (sign_bit | magnitude) as u16
1335 }
1336}
1337
1338#[cfg(any(feature = "bc6h", feature = "bc7"))]
1340#[derive(Debug, Clone, Copy)]
1341struct BitStream {
1342 low: u64,
1343 high: u64,
1344}
1345
1346#[cfg(any(feature = "bc6h", feature = "bc7"))]
1347impl BitStream {
1348 #[inline]
1350 fn new(data: &[u8]) -> Self {
1351 let low = u64::from_le_bytes(data[0..8].try_into().unwrap());
1352 let high = u64::from_le_bytes(data[8..16].try_into().unwrap());
1353 Self { low, high }
1354 }
1355
1356 #[cfg(feature = "bc7")]
1357 #[inline]
1358 fn read_bit(&mut self) -> u32 {
1359 self.read_bits(1)
1360 }
1361
1362 #[cfg(feature = "bc6h")]
1363 #[inline]
1364 fn read_bit_i32(&mut self) -> i32 {
1365 self.read_bits(1) as i32
1366 }
1367
1368 #[inline]
1369 pub fn read_bits(&mut self, num_bits: u32) -> u32 {
1370 let mask = (1u64 << num_bits) - 1;
1371 let bits = (self.low & mask) as u32;
1373 self.low >>= num_bits;
1374
1375 self.low |= (self.high & mask) << (64 - num_bits);
1377 self.high >>= num_bits;
1378
1379 bits
1380 }
1381
1382 #[cfg(feature = "bc6h")]
1383 #[inline]
1384 pub fn read_bits_i32(&mut self, num_bits: u32) -> i32 {
1385 self.read_bits(num_bits) as i32
1386 }
1387
1388 #[cfg(feature = "bc6h")]
1389 #[inline]
1390 fn read_bits_reversed(&mut self, num_bits: u32) -> i32 {
1391 let mut bits = self.read_bits_i32(num_bits);
1392 let mut result = 0;
1394
1395 (0..num_bits).for_each(|_| {
1396 result <<= 1;
1397 result |= bits & 1;
1398 bits >>= 1;
1399 });
1400
1401 result
1402 }
1403}
1404
1405#[cfg(test)]
1406mod tests {
1407 use super::*;
1408
1409 fn test_block(
1410 decode_block: fn(&[u8], &mut [u8], usize),
1411 pitch: usize,
1412 compressed_block: &[u8],
1413 expected_output: &[u8],
1414 name: &str,
1415 ) {
1416 let mut decoded = [0u8; 64];
1417 decode_block(compressed_block, &mut decoded, pitch);
1418
1419 for y in 0..4 {
1420 let start = y * pitch;
1421 let end = start + pitch;
1422 assert_eq!(
1423 &decoded[start..end],
1424 &expected_output[start..end],
1425 "{name}: Mismatch at row {y}",
1426 );
1427 }
1428 }
1429
1430 #[test]
1431 fn test_bc1_block_black() {
1432 let compressed_block = [0u8; 8];
1433 let expected_output = [
1434 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF,
1435 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF,
1436 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF,
1437 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF,
1438 ];
1439 test_block(
1440 decode_block_bc1,
1441 16,
1442 &compressed_block,
1443 &expected_output,
1444 "Black block",
1445 );
1446 }
1447
1448 #[test]
1449 fn test_bc1_block_red() {
1450 let compressed_block = [0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
1451 let expected_output = [
1452 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF,
1453 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF,
1454 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF,
1455 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF,
1456 ];
1457 test_block(
1458 decode_block_bc1,
1459 16,
1460 &compressed_block,
1461 &expected_output,
1462 "Red block",
1463 );
1464 }
1465
1466 #[test]
1467 fn test_bc1_block_gradient() {
1468 let compressed_block = [0x00, 0xF8, 0xE0, 0x07, 0x55, 0x55, 0x55, 0x55];
1469 let expected_output = [
1470 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF,
1471 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF,
1472 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF,
1473 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF,
1474 ];
1475 test_block(
1476 decode_block_bc1,
1477 16,
1478 &compressed_block,
1479 &expected_output,
1480 "Gradient block",
1481 );
1482 }
1483
1484 #[test]
1485 fn test_bc2_alpha_gradient() {
1486 let compressed_block = [
1487 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
1488 0x00, 0x00,
1489 ];
1490 let expected_output = [
1491 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x11, 0xFF, 0x0, 0x0, 0x22, 0xFF, 0x0, 0x0, 0x33,
1492 0xFF, 0x0, 0x0, 0x44, 0xFF, 0x0, 0x0, 0x55, 0xFF, 0x0, 0x0, 0x66, 0xFF, 0x0, 0x0, 0x77,
1493 0xFF, 0x0, 0x0, 0x88, 0xFF, 0x0, 0x0, 0x99, 0xFF, 0x0, 0x0, 0xAA, 0xFF, 0x0, 0x0, 0xBB,
1494 0xFF, 0x0, 0x0, 0xCC, 0xFF, 0x0, 0x0, 0xDD, 0xFF, 0x0, 0x0, 0xEE, 0xFF, 0x0, 0x0, 0xFF,
1495 ];
1496 test_block(
1497 decode_block_bc2,
1498 16,
1499 &compressed_block,
1500 &expected_output,
1501 "Alpha gradient",
1502 );
1503 }
1504
1505 #[test]
1506 fn test_bc2_alpha_half_transparent() {
1507 let compressed_block = [
1508 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
1509 0x00, 0x00,
1510 ];
1511 let expected_output = [
1512 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77,
1513 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77,
1514 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77,
1515 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77, 0xFF, 0x0, 0x0, 0x77,
1516 ];
1517 test_block(
1518 decode_block_bc2,
1519 16,
1520 &compressed_block,
1521 &expected_output,
1522 "Half transparent",
1523 );
1524 }
1525
1526 #[test]
1527 fn test_bc3_solid_black() {
1528 let compressed_block = [
1529 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1530 0x00, 0x00,
1531 ];
1532 let expected_output = [
1533 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1534 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1535 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1536 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1537 ];
1538 test_block(
1539 decode_block_bc3,
1540 16,
1541 &compressed_block,
1542 &expected_output,
1543 "Solid black with full alpha",
1544 );
1545 }
1546
1547 #[test]
1548 fn test_bc3_transparent_red() {
1549 let compressed_block = [
1550 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
1551 0x00, 0x00,
1552 ];
1553 let expected_output = [
1554 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0,
1555 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0,
1556 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0,
1557 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0, 0xFF, 0x0, 0x0, 0x0,
1558 ];
1559 test_block(
1560 decode_block_bc3,
1561 16,
1562 &compressed_block,
1563 &expected_output,
1564 "Transparent red",
1565 );
1566 }
1567
1568 #[test]
1569 fn test_bc3_alpha_gradient() {
1570 let compressed_block = [
1571 0x00, 0xFF, 0xFF, 0xFF, 0x55, 0x55, 0x55, 0x55, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
1572 0x00, 0x00,
1573 ];
1574 let expected_output = [
1575 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF,
1576 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0x66, 0xFF, 0x0, 0x0, 0xCC, 0xFF, 0x0, 0x0, 0x33,
1577 0xFF, 0x0, 0x0, 0xCC, 0xFF, 0x0, 0x0, 0x33, 0xFF, 0x0, 0x0, 0xCC, 0xFF, 0x0, 0x0, 0x33,
1578 0xFF, 0x0, 0x0, 0xCC, 0xFF, 0x0, 0x0, 0x33, 0xFF, 0x0, 0x0, 0xCC, 0xFF, 0x0, 0x0, 0x33,
1579 ];
1580 test_block(
1581 decode_block_bc3,
1582 16,
1583 &compressed_block,
1584 &expected_output,
1585 "Red with alpha gradient",
1586 );
1587 }
1588
1589 #[test]
1590 fn test_bc3_color_alpha_gradient() {
1591 let compressed_block = [
1592 0x00, 0xFF, 0xFF, 0xFF, 0x55, 0x55, 0x55, 0x55, 0x00, 0xF8, 0xE0, 0x07, 0x55, 0x55,
1593 0x55, 0x55,
1594 ];
1595 let expected_output = [
1596 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF,
1597 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0x66, 0x0, 0xFF, 0x0, 0xCC, 0x0, 0xFF, 0x0, 0x33,
1598 0x0, 0xFF, 0x0, 0xCC, 0x0, 0xFF, 0x0, 0x33, 0x0, 0xFF, 0x0, 0xCC, 0x0, 0xFF, 0x0, 0x33,
1599 0x0, 0xFF, 0x0, 0xCC, 0x0, 0xFF, 0x0, 0x33, 0x0, 0xFF, 0x0, 0xCC, 0x0, 0xFF, 0x0, 0x33,
1600 ];
1601 test_block(
1602 decode_block_bc3,
1603 16,
1604 &compressed_block,
1605 &expected_output,
1606 "Color and alpha gradients",
1607 );
1608 }
1609
1610 #[test]
1611 fn test_bc3_semi_transparent() {
1612 let compressed_block = [
1613 0x80, 0x80, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00,
1614 0x00, 0x00,
1615 ];
1616 let expected_output = [
1617 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0xFF,
1618 0xFF, 0x0, 0x0, 0xFF, 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80,
1619 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80,
1620 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80, 0xFF, 0x0, 0x0, 0x80,
1621 ];
1622 test_block(
1623 decode_block_bc3,
1624 16,
1625 &compressed_block,
1626 &expected_output,
1627 "Semi-transparent red",
1628 );
1629 }
1630
1631 #[test]
1632 fn test_bc4_gradient() {
1633 let compressed_block = [0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00];
1634 let expected_output = [
1635 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1636 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1637 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1638 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1639 ];
1640 test_block(
1641 decode_block_bc4,
1642 4,
1643 &compressed_block,
1644 &expected_output,
1645 "BC4 gradient",
1646 );
1647 }
1648
1649 #[test]
1650 fn test_bc4_interpolated() {
1651 let compressed_block = [0x00, 0xFF, 0x92, 0x24, 0x49, 0x92, 0x00, 0x00];
1652 let expected_output = [
1653 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x0, 0x0, 0x0, 0x0,
1654 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1655 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1656 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1657 ];
1658 test_block(
1659 decode_block_bc4,
1660 4,
1661 &compressed_block,
1662 &expected_output,
1663 "BC4 interpolated",
1664 );
1665 }
1666
1667 #[test]
1668 fn test_bc5_gradient() {
1669 let compressed_block = [
1670 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0x00,
1671 0x00, 0x00,
1672 ];
1673 let expected_output = [
1674 0xFF, 0x24, 0xFF, 0x24, 0xFF, 0x24, 0xFF, 0x24, 0xFF, 0x24, 0xFF, 0x0, 0x0, 0xFF, 0x0,
1675 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0,
1676 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1677 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1678 ];
1679 test_block(
1680 decode_block_bc5,
1681 8,
1682 &compressed_block,
1683 &expected_output,
1684 "BC5 gradient",
1685 );
1686 }
1687
1688 #[test]
1689 fn test_bc5_interpolated() {
1690 let compressed_block = [
1691 0x00, 0xFF, 0x92, 0x24, 0x49, 0x92, 0x00, 0x00, 0xFF, 0x00, 0x92, 0x24, 0x49, 0x92,
1692 0x00, 0x00,
1693 ];
1694 let expected_output = [
1695 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA,
1696 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA, 0x33, 0xDA, 0x0, 0xFF, 0x0, 0xFF, 0x0, 0xFF, 0x0,
1697 0xFF, 0x0, 0xFF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1698 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1699 0x0,
1700 ];
1701 test_block(
1702 decode_block_bc5,
1703 8,
1704 &compressed_block,
1705 &expected_output,
1706 "BC5 interpolated",
1707 );
1708 }
1709
1710 #[cfg(feature = "bc6h")]
1711 #[test]
1712 fn test_bc6h_block_0() {
1713 use half::f16;
1714
1715 let compressed_block = [
1716 0x40, 0xAF, 0xF6, 0x0B, 0xFD, 0x2E, 0xFF, 0xFF, 0x11, 0x71, 0x10, 0xA1, 0x21, 0xF2,
1717 0x33, 0x73,
1718 ];
1719 let expected_output = [
1720 f16::from_bits(0x5BAB),
1721 f16::from_bits(0x84B9),
1722 f16::from_bits(0xDBE9),
1723 f16::from_bits(0x5BA2),
1724 f16::from_bits(0x84F6),
1725 f16::from_bits(0xDBF1),
1726 f16::from_bits(0x5B99),
1727 f16::from_bits(0x8533),
1728 f16::from_bits(0xDBFA),
1729 f16::from_bits(0x5D9B),
1730 f16::from_bits(0x8307),
1731 f16::from_bits(0xD847),
1732 f16::from_bits(0x5B7E),
1733 f16::from_bits(0x85F0),
1734 f16::from_bits(0xDC15),
1735 f16::from_bits(0x5BA2),
1736 f16::from_bits(0x84F6),
1737 f16::from_bits(0xDBF1),
1738 f16::from_bits(0x5CC3),
1739 f16::from_bits(0x81E8),
1740 f16::from_bits(0xD8D6),
1741 f16::from_bits(0x5D9B),
1742 f16::from_bits(0x8307),
1743 f16::from_bits(0xD847),
1744 f16::from_bits(0x5BA2),
1745 f16::from_bits(0x84F6),
1746 f16::from_bits(0xDBF1),
1747 f16::from_bits(0x5B6D),
1748 f16::from_bits(0x866B),
1749 f16::from_bits(0xDC27),
1750 f16::from_bits(0x5C27),
1751 f16::from_bits(0x8117),
1752 f16::from_bits(0xD93F),
1753 f16::from_bits(0x5CC3),
1754 f16::from_bits(0x81E8),
1755 f16::from_bits(0xD8D6),
1756 f16::from_bits(0x5BA2),
1757 f16::from_bits(0x84F6),
1758 f16::from_bits(0xDBF1),
1759 f16::from_bits(0x5CFE),
1760 f16::from_bits(0x8235),
1761 f16::from_bits(0xD8AF),
1762 f16::from_bits(0x5C5B),
1763 f16::from_bits(0x815C),
1764 f16::from_bits(0xD91C),
1765 f16::from_bits(0x5D66),
1766 f16::from_bits(0x82C1),
1767 f16::from_bits(0xD869),
1768 ];
1769
1770 let mut decoded = [f16::ZERO; 48];
1771 decode_block_bc6h(&compressed_block, &mut decoded, 12, true);
1772
1773 assert_eq!(&decoded[..], &expected_output[..], "BC6H block mismatch");
1774 }
1775
1776 #[test]
1777 #[rustfmt::skip]
1778 fn test_bc6h_block_0_float() {
1779 let compressed_block = [
1780 0x40, 0xAF, 0xF6, 0x0B, 0xFD, 0x2E, 0xFF, 0xFF, 0x11, 0x71, 0x10, 0xA1, 0x21, 0xF2,
1781 0x33, 0x73,
1782 ];
1783
1784 let expected_output: [f32; 48] = [
1785 245.375, -0.000072062016, -253.125, 244.25, -0.0000756979, -254.125, 243.125, -0.00007933378, -255.25, 358.75, -0.0000461936, -136.875, 239.75, -0.00009059906, -261.25, 244.25,
1786 -0.0000756979, -254.125, 304.75, -0.000029087067, -154.75, 358.75, -0.0000461936, -136.875, 244.25, -0.0000756979, -254.125, 237.625, -0.00009793043, -265.75, 265.75, -0.000016629696,
1787 -167.875, 304.75, -0.000029087067, -154.75, 244.25, -0.0000756979, -254.125, 319.5, -0.000033676624, -149.875, 278.75, -0.000020742416, -163.5, 345.5, -0.000042021275, -141.125
1788 ];
1789
1790 let mut decoded = [0.0_f32; 48];
1791 decode_block_bc6h_float(&compressed_block, &mut decoded, 12, true);
1792
1793 assert_eq!(&decoded[..], &expected_output[..], "BC6H block mismatch");
1794 }
1795
1796 #[test]
1797 fn test_bc7_block_0() {
1798 let compressed_block = [
1799 0x40, 0xAF, 0xF6, 0xB, 0xFD, 0x2E, 0xFF, 0xFF, 0x11, 0x71, 0x10, 0xA1, 0x21, 0xF2,
1800 0x33, 0x73,
1801 ];
1802 let expected_output = [
1803 0xBD, 0xBF, 0xBF, 0xFF, 0xBD, 0xBD, 0xBD, 0xFF, 0xBD, 0xBF, 0xBF, 0xFF, 0xBD, 0xBD,
1804 0xBD, 0xFF, 0xBD, 0xBD, 0xBD, 0xFF, 0xBC, 0xBB, 0xB9, 0xFF, 0xBB, 0xB9, 0xB7, 0xFF,
1805 0xBB, 0xB9, 0xB7, 0xFF, 0xBB, 0xB9, 0xB7, 0xFF, 0xB9, 0xB1, 0xAC, 0xFF, 0x0, 0x0, 0x0,
1806 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1807 0x0, 0x0, 0x0, 0x0,
1808 ];
1809 test_block(
1810 decode_block_bc7,
1811 8,
1812 &compressed_block,
1813 &expected_output,
1814 "BC7 block 0",
1815 );
1816 }
1817
1818 #[test]
1819 fn test_bc7_block_1() {
1820 let compressed_block = [
1821 0xC0, 0x8C, 0xEF, 0xA2, 0xBB, 0xDC, 0xFE, 0x7F, 0x6C, 0x55, 0x6A, 0x34, 0x4F, 0x0,
1822 0x5D, 0x0,
1823 ];
1824 let expected_output = [
1825 0x50, 0x4A, 0x48, 0xFE, 0x50, 0x4A, 0x48, 0xFE, 0x64, 0x5D, 0x59, 0xFE, 0x50, 0x4A,
1826 0x48, 0xFE, 0x7C, 0x74, 0x6E, 0xFE, 0x46, 0x41, 0x3F, 0xFE, 0x72, 0x6A, 0x65, 0xFE,
1827 0x4A, 0x45, 0x43, 0xFE, 0x32, 0x2E, 0x2E, 0xFE, 0x32, 0x2E, 0x2E, 0xFE, 0x0, 0x0, 0x0,
1828 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1829 0x0, 0x0, 0x0, 0x0,
1830 ];
1831 test_block(
1832 decode_block_bc7,
1833 8,
1834 &compressed_block,
1835 &expected_output,
1836 "BC7 block 1",
1837 );
1838 }
1839}