use core::u32;
use colourblock;
use colourset::ColourSet;
use math::Vec3;
use {f32_to_i32_clamped, Format};
use super::single_lut::*;
use super::ColourFitImpl;
pub struct SingleColourFit<'a> {
colourset: &'a ColourSet,
format: Format,
start: Vec3,
end: Vec3,
index: u8,
error: u32,
best_error: u32,
best_compressed: [u8; 8],
}
impl<'a> SingleColourFit<'a> {
pub fn new(colourset: &'a ColourSet, format: Format) -> Self {
SingleColourFit {
colourset,
format,
start: Vec3::new(0.0, 0.0, 0.0),
end: Vec3::new(0.0, 0.0, 0.0),
index: 0,
error: u32::MAX,
best_error: u32::MAX,
best_compressed: [0u8; 8],
}
}
fn compute_endpoints(&mut self, lut: [&[SingleColourLookup; 256]; 3]) {
let colour = [
f32_to_i32_clamped(self.colourset.points()[0].x() * 255.0, 255),
f32_to_i32_clamped(self.colourset.points()[0].y() * 255.0, 255),
f32_to_i32_clamped(self.colourset.points()[0].z() * 255.0, 255),
];
self.error = u32::MAX;
for index in 0..2 {
let mut error = 0u32;
let mut sources = [
&lut[0][0].sources[0],
&lut[1][0].sources[0],
&lut[2][0].sources[0],
];
for channel in 0..3 {
let lookup = &lut[channel];
let target = colour[channel];
sources[channel] = &lookup[target as usize].sources[index];
let diff = u32::from(sources[channel].error);
error += diff * diff;
}
if error < self.error {
self.start = Vec3::new(
f32::from(sources[0].start) / 31.0,
f32::from(sources[1].start) / 63.0,
f32::from(sources[2].start) / 31.0,
);
self.end = Vec3::new(
f32::from(sources[0].end) / 31.0,
f32::from(sources[1].end) / 63.0,
f32::from(sources[2].end) / 31.0,
);
self.index = 2 * index as u8;
self.error = error;
}
}
}
}
impl<'a> ColourFitImpl<'a> for SingleColourFit<'a> {
fn is_bc1(&self) -> bool {
self.format == Format::Bc1
}
fn is_transparent(&self) -> bool {
self.colourset.is_transparent()
}
fn best_compressed(&'a self) -> &'a [u8] {
&self.best_compressed
}
fn compress3(&mut self) {
let lut = [&LOOKUP_5_3, &LOOKUP_6_3, &LOOKUP_5_3];
self.compute_endpoints(lut);
if self.error < self.best_error {
let mut indices = [0u8; 16];
self.colourset
.remap_indices(&[self.index; 16], &mut indices);
colourblock::write3(&self.start, &self.end, &indices, &mut self.best_compressed);
self.best_error = self.error;
}
}
fn compress4(&mut self) {
let lut = [&LOOKUP_5_4, &LOOKUP_6_4, &LOOKUP_5_4];
self.compute_endpoints(lut);
if self.error < self.best_error {
let mut indices = [0u8; 16];
self.colourset
.remap_indices(&[self.index; 16], &mut indices);
colourblock::write4(&self.start, &self.end, &indices, &mut self.best_compressed);
self.best_error = self.error;
}
}
}