#![allow(dead_code)]
use std::f32::consts::FRAC_PI_2;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum BentNormalMode {
WorldSpace,
TangentSpace,
AoWeighted,
}
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub struct BentNormalConfig {
pub mode: BentNormalMode,
pub scale: f32,
pub ao_threshold: f32,
pub enabled: bool,
}
impl Default for BentNormalConfig {
fn default() -> Self {
Self {
mode: BentNormalMode::WorldSpace,
scale: 1.0,
ao_threshold: 0.5,
enabled: false,
}
}
}
#[derive(Debug, Clone, PartialEq, Default)]
#[allow(dead_code)]
pub struct BentNormalEntry {
pub position: [f32; 3],
pub bent_normal: [f32; 3],
pub ao: f32,
}
#[derive(Debug, Clone, Default)]
#[allow(dead_code)]
pub struct BentNormalDebug {
pub config: BentNormalConfig,
pub entries: Vec<BentNormalEntry>,
}
#[allow(dead_code)]
pub fn default_bent_normal_config() -> BentNormalConfig {
BentNormalConfig::default()
}
#[allow(dead_code)]
pub fn new_bent_normal_debug(cfg: BentNormalConfig) -> BentNormalDebug {
BentNormalDebug {
config: cfg,
entries: Vec::new(),
}
}
#[allow(dead_code)]
pub fn add_bent_normal(d: &mut BentNormalDebug, pos: [f32; 3], bn: [f32; 3], ao: f32) {
d.entries.push(BentNormalEntry {
position: pos,
bent_normal: bn,
ao: ao.clamp(0.0, 1.0),
});
}
#[allow(dead_code)]
pub fn clear_bent_normals(d: &mut BentNormalDebug) {
d.entries.clear();
}
#[allow(dead_code)]
pub fn bent_normal_count(d: &BentNormalDebug) -> usize {
d.entries.len()
}
#[allow(dead_code)]
pub fn set_bent_normal_enabled(d: &mut BentNormalDebug, enabled: bool) {
d.config.enabled = enabled;
}
#[allow(dead_code)]
pub fn filtered_entries(d: &BentNormalDebug) -> Vec<&BentNormalEntry> {
d.entries
.iter()
.filter(|e| e.ao >= d.config.ao_threshold)
.collect()
}
#[allow(dead_code)]
pub fn normalize_bn(v: [f32; 3]) -> [f32; 3] {
let len = (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt();
if len < 1e-9 {
[0.0, 0.0, 1.0]
} else {
[v[0] / len, v[1] / len, v[2] / len]
}
}
#[allow(dead_code)]
pub fn bent_normal_to_color(bn: [f32; 3]) -> [f32; 3] {
[
(bn[0] * 0.5 + 0.5).clamp(0.0, 1.0),
(bn[1] * 0.5 + 0.5).clamp(0.0, 1.0),
(bn[2] * 0.5 + 0.5).clamp(0.0, 1.0),
]
}
#[allow(dead_code)]
pub fn bent_normal_angle(bn: [f32; 3], surface_normal: [f32; 3]) -> f32 {
let dot = bn[0] * surface_normal[0] + bn[1] * surface_normal[1] + bn[2] * surface_normal[2];
let angle = dot.clamp(-1.0, 1.0).acos();
angle / FRAC_PI_2
}
#[allow(dead_code)]
pub fn bent_normal_debug_to_json(d: &BentNormalDebug) -> String {
format!(
r#"{{"count":{},"enabled":{}}}"#,
d.entries.len(),
d.config.enabled
)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_config_disabled() {
assert!(!BentNormalConfig::default().enabled);
}
#[test]
fn add_and_count() {
let mut d = new_bent_normal_debug(default_bent_normal_config());
add_bent_normal(&mut d, [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 0.8);
assert_eq!(bent_normal_count(&d), 1);
}
#[test]
fn clear_empties() {
let mut d = new_bent_normal_debug(default_bent_normal_config());
add_bent_normal(&mut d, [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 0.5);
clear_bent_normals(&mut d);
assert_eq!(bent_normal_count(&d), 0);
}
#[test]
fn enable_sets_flag() {
let mut d = new_bent_normal_debug(default_bent_normal_config());
set_bent_normal_enabled(&mut d, true);
assert!(d.config.enabled);
}
#[test]
fn filter_by_ao() {
let mut d = new_bent_normal_debug(BentNormalConfig {
ao_threshold: 0.6,
..Default::default()
});
add_bent_normal(&mut d, [0.0, 0.0, 0.0], [0.0, 1.0, 0.0], 0.9);
add_bent_normal(&mut d, [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], 0.3);
assert_eq!(filtered_entries(&d).len(), 1);
}
#[test]
fn normalize_unit_vector() {
let n = normalize_bn([0.0, 0.0, 1.0]);
assert!((n[2] - 1.0).abs() < 1e-6);
}
#[test]
fn normalize_zero_returns_up() {
let n = normalize_bn([0.0, 0.0, 0.0]);
assert!((n[2] - 1.0).abs() < 1e-6);
}
#[test]
fn color_up_normal() {
let c = bent_normal_to_color([0.0, 1.0, 0.0]);
assert!((c[1] - 1.0).abs() < 1e-6);
}
#[test]
fn angle_parallel_is_zero() {
let angle = bent_normal_angle([0.0, 1.0, 0.0], [0.0, 1.0, 0.0]);
assert!(angle < 1e-5);
}
#[test]
fn json_contains_count() {
let d = new_bent_normal_debug(default_bent_normal_config());
assert!(bent_normal_debug_to_json(&d).contains("count"));
}
}