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