1use crate::color::{min_max_luminance, ColorRgba8};
4use crate::utils::{encode_color_table_bc1_bc3, encode_image, encode_image_conv_u8, fetch_block};
5
6struct MinMax<T: ColorRgba8> {
7 min: T,
8 min_565: u16,
9 max: T,
10 max_565: u16,
11 can_contain_alpha: bool,
12}
13
14fn min_max_colors<T: ColorRgba8>(block: &[T]) -> MinMax<T> {
15 let (min, max) = min_max_luminance(block);
16
17 let min_565 = min.to_565();
18 let max_565 = max.to_565();
19
20 if max_565 > min_565 {
21 MinMax {
22 min,
23 min_565,
24 max,
25 max_565,
26 can_contain_alpha: false,
27 }
28 } else {
29 MinMax {
30 min_565: max_565,
31 max_565: min_565,
32 min: max,
33 max: min,
34 can_contain_alpha: true,
35 }
36 }
37}
38
39#[derive(Debug, Copy, Clone, Eq, PartialEq)]
40#[repr(C)]
41pub struct Block8 {
42 pub max: u16,
43 pub min: u16,
44 pub color_table: u32,
45}
46
47pub fn encode_block_bc1<T: ColorRgba8>(block: [T; 16]) -> Block8 {
48 let MinMax {
49 min,
50 min_565,
51 max,
52 max_565,
53 can_contain_alpha,
54 } = min_max_colors(&block);
55
56 let (color2, color3) = if T::contains_alpha() && can_contain_alpha {
57 (max.mix_1_1_over_2_saturate(&min), T::default())
58 } else {
59 (
60 max.mix_2_1_over_3_saturate(&min),
61 max.mix_1_2_over_3_saturate(&min),
62 )
63 };
64
65 Block8 {
66 min: min_565,
67 max: max_565,
68 color_table: encode_color_table_bc1_bc3(&block, [max, min, color2, color3]),
69 }
70}
71
72fn fetch_and_encode<T: ColorRgba8>(pixels: &[T], x: usize, y: usize, width: usize) -> Block8 {
73 encode_block_bc1(fetch_block(pixels, x, y, width))
74}
75
76pub fn encode_image_bc1<T>(pixels: &[T], width: usize, height: usize) -> Vec<Block8>
77where
78 T: ColorRgba8,
79{
80 encode_image(pixels, width, height, fetch_and_encode)
81}
82
83pub fn encode_image_bc1_conv_u8<T>(pixels: &[T], width: usize, height: usize) -> Vec<u8>
84where
85 T: ColorRgba8,
86{
87 encode_image_conv_u8(pixels, width, height, fetch_and_encode)
88}