#[cfg(test)]
mod fit;
#[cfg(test)]
mod polygon;
mod size;
pub use size::LTC_LUT_SIZE;
#[repr(C, align(4))]
struct Aligned<T: ?Sized>(T);
static MATRIX: &Aligned<[u8]> =
&Aligned(*include_bytes!(concat!(env!("OUT_DIR"), "/ltc_matrix.bin")));
static MAGNITUDE: &Aligned<[u8]> = &Aligned(*include_bytes!(concat!(
env!("OUT_DIR"),
"/ltc_magnitude.bin"
)));
pub fn matrix_texels() -> &'static [f32] {
bytemuck::cast_slice(&MATRIX.0)
}
pub fn magnitude_texels() -> &'static [f32] {
bytemuck::cast_slice(&MAGNITUDE.0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_generated_tables_are_the_expected_size() {
assert_eq!(matrix_texels().len(), LTC_LUT_SIZE * LTC_LUT_SIZE * 4);
assert_eq!(magnitude_texels().len(), LTC_LUT_SIZE * LTC_LUT_SIZE * 2);
}
#[test]
fn the_generated_tables_are_finite() {
assert!(matrix_texels().iter().all(|v| v.is_finite()));
assert!(magnitude_texels().iter().all(|v| v.is_finite()));
}
#[test]
fn the_generated_albedo_conserves_energy() {
for (i, chunk) in magnitude_texels().chunks_exact(2).enumerate() {
assert!(
(0.0..=1.05).contains(&chunk[0]),
"cell {i} albedo {}",
chunk[0]
);
assert!(
(0.0..=1.05).contains(&chunk[1]),
"cell {i} fresnel {}",
chunk[1]
);
}
}
#[test]
fn the_roughest_head_on_cell_is_near_identity() {
let m = matrix_texels();
let base = (LTC_LUT_SIZE - 1) * 4;
assert!((m[base] - 1.0).abs() < 0.35, "m00 {}", m[base]);
assert!((m[base + 3] - 1.0).abs() < 0.35, "m22 {}", m[base + 3]);
assert!(
m[base + 1].abs() < 0.2 && m[base + 2].abs() < 0.2,
"no skew"
);
}
#[test]
fn the_transform_scale_grows_with_roughness_head_on() {
let m = matrix_texels();
let scale = |a: usize| m[a * 4 + 3];
assert!(
scale(0) < 0.05,
"the smoothest surface should have a narrow lobe, got {}",
scale(0)
);
assert!(
scale(LTC_LUT_SIZE - 1) > 0.8,
"the roughest surface should be near a cosine lobe, got {}",
scale(LTC_LUT_SIZE - 1)
);
for a in 1..LTC_LUT_SIZE {
assert!(
scale(a) >= scale(a - 1) - 1.0e-3,
"scale dipped at roughness index {a}: {} then {}",
scale(a - 1),
scale(a)
);
}
}
#[test]
fn the_head_on_row_has_no_skew() {
let m = matrix_texels();
for a in 0..LTC_LUT_SIZE {
assert!(
m[a * 4 + 1].abs() < 1.0e-3 && m[a * 4 + 2].abs() < 1.0e-3,
"roughness index {a} skewed at normal incidence"
);
}
}
}