1use crate::color::ColorRgba8;
2
3pub(in crate) fn ceil_div_4(x: usize) -> usize {
4 (x + 3) / 4
5}
6
7pub(in crate) fn encode_color_table_bc1_bc3<T: ColorRgba8>(block: &[T], ref_colors: [T; 4]) -> u32 {
8 let mut color_indices = [0; 16];
10 for (p, color_index) in block.iter().zip(color_indices.iter_mut()) {
11 if T::contains_alpha() && p.alpha() < 128 {
12 *color_index = 3;
14 } else {
15 let mut min_distance = i32::MAX;
16 for (i, ref_color) in ref_colors.iter().enumerate() {
17 let distance = p.sqr_distance(ref_color);
18 if distance < min_distance {
19 *color_index = i;
20 min_distance = distance;
21 }
22 }
23 }
24 }
25
26 let mut color_table = 0;
27 for (i, index) in color_indices.iter().enumerate() {
28 color_table |= (*index as u32) << (i << 1);
29 }
30
31 color_table
32}
33
34pub(in crate) fn fetch_or_default<T>(pixels: &[T], n: usize) -> T
35where
36 T: Default + Copy,
37{
38 match pixels.get(n) {
39 Some(pixel) => *pixel,
40 None => T::default(),
41 }
42}
43
44pub(in crate) fn fetch_block<T>(pixels: &[T], x: usize, y: usize, width: usize) -> [T; 16]
45where
46 T: Default + Copy,
47{
48 let c0 = x;
49 let c1 = x + 1;
50 let c2 = x + 2;
51 let c3 = x + 3;
52 let r0 = y * width;
53 let r1 = (y + 1) * width;
54 let r2 = (y + 2) * width;
55 let r3 = (y + 3) * width;
56
57 [
58 fetch_or_default(&pixels, c0 + r0),
60 fetch_or_default(&pixels, c1 + r0),
61 fetch_or_default(&pixels, c2 + r0),
62 fetch_or_default(&pixels, c3 + r0),
63 fetch_or_default(&pixels, c0 + r1),
65 fetch_or_default(&pixels, c1 + r1),
66 fetch_or_default(&pixels, c2 + r1),
67 fetch_or_default(&pixels, c3 + r1),
68 fetch_or_default(&pixels, c0 + r2),
70 fetch_or_default(&pixels, c1 + r2),
71 fetch_or_default(&pixels, c2 + r2),
72 fetch_or_default(&pixels, c3 + r2),
73 fetch_or_default(&pixels, c0 + r3),
75 fetch_or_default(&pixels, c1 + r3),
76 fetch_or_default(&pixels, c2 + r3),
77 fetch_or_default(&pixels, c3 + r3),
78 ]
79}
80
81pub(in crate) fn encode_image<T, B, F>(
82 pixels: &[T],
83 width: usize,
84 height: usize,
85 fetch: F,
86) -> Vec<B>
87where
88 F: Fn(&[T], usize, usize, usize) -> B,
89{
90 let w = ceil_div_4(width);
91 let h = ceil_div_4(height);
92
93 let mut encoded_pixels = Vec::with_capacity(w * h);
94
95 for i in 0..h {
96 let y = i * 4;
97 for j in 0..w {
98 let x = j * 4;
99 encoded_pixels.push(fetch(pixels, x, y, width));
100 }
101 }
102
103 encoded_pixels
104}
105
106pub(in crate) fn encode_image_conv_u8<T, B, F>(
107 pixels: &[T],
108 width: usize,
109 height: usize,
110 fetch: F,
111) -> Vec<u8>
112where
113 F: Fn(&[T], usize, usize, usize) -> B,
114{
115 let mut compressed_pixels = encode_image(pixels, width, height, fetch);
116
117 let transmuted = unsafe {
118 Vec::from_raw_parts(
119 compressed_pixels.as_mut_ptr() as *mut u8,
120 compressed_pixels.len() * std::mem::size_of::<B>(),
121 compressed_pixels.capacity() * std::mem::size_of::<B>(),
122 )
123 };
124
125 std::mem::forget(compressed_pixels);
127
128 transmuted
129}