tbc/
utils.rs

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    // Find color indices and pack result.
9    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            // Map to black.
13            *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        // Row 0
59        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        // Row 1
64        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        // Row 2
69        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        // Row 3
74        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    // Explicitly forget because we're transmuting memory block.
126    std::mem::forget(compressed_pixels);
127
128    transmuted
129}