#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MorphRegion {
pub center: [f32; 3],
pub radius: f32,
pub morph_target: usize,
pub weight: f32,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MorphRegionBlend {
pub regions: Vec<MorphRegion>,
}
#[allow(dead_code)]
pub fn new_morph_region_blend() -> MorphRegionBlend {
MorphRegionBlend { regions: Vec::new() }
}
#[allow(dead_code)]
pub fn mrb_add_region(
blend: &mut MorphRegionBlend,
center: [f32; 3],
radius: f32,
target: usize,
weight: f32,
) {
blend.regions.push(MorphRegion { center, radius, morph_target: target, weight });
}
fn dist3(a: [f32; 3], b: [f32; 3]) -> f32 {
let dx = a[0] - b[0];
let dy = a[1] - b[1];
let dz = a[2] - b[2];
(dx * dx + dy * dy + dz * dz).sqrt()
}
#[allow(dead_code)]
pub fn mrb_weight_at(blend: &MorphRegionBlend, pos: [f32; 3]) -> f32 {
let mut max_w = 0.0_f32;
for region in &blend.regions {
let d = dist3(pos, region.center);
if d < region.radius {
let t = 1.0 - d / region.radius;
let w = t * region.weight;
if w > max_w {
max_w = w;
}
}
}
max_w
}
#[allow(dead_code)]
pub fn mrb_region_count(blend: &MorphRegionBlend) -> usize {
blend.regions.len()
}
#[allow(dead_code)]
pub fn mrb_target_at(blend: &MorphRegionBlend, pos: [f32; 3]) -> Option<usize> {
let mut best_w = 0.0_f32;
let mut best_target = None;
for region in &blend.regions {
let d = dist3(pos, region.center);
if d < region.radius {
let t = 1.0 - d / region.radius;
let w = t * region.weight;
if w > best_w {
best_w = w;
best_target = Some(region.morph_target);
}
}
}
best_target
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_add_region_count() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 1.0, 0, 1.0);
assert_eq!(mrb_region_count(&b), 1);
}
#[test]
fn test_weight_at_center_is_max() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 1.0, 0, 1.0);
let w = mrb_weight_at(&b, [0.0, 0.0, 0.0]);
assert!((w - 1.0).abs() < 1e-6);
}
#[test]
fn test_weight_at_outside_is_zero() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 1.0, 0, 1.0);
let w = mrb_weight_at(&b, [2.0, 0.0, 0.0]);
assert_eq!(w, 0.0);
}
#[test]
fn test_weight_at_edge_nonzero() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 2.0, 0, 1.0);
let w = mrb_weight_at(&b, [1.0, 0.0, 0.0]);
assert!(w > 0.0 && w < 1.0);
}
#[test]
fn test_target_at_inside() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 1.0, 42, 1.0);
let t = mrb_target_at(&b, [0.0, 0.0, 0.0]);
assert_eq!(t, Some(42));
}
#[test]
fn test_target_at_outside_none() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 1.0, 0, 1.0);
let t = mrb_target_at(&b, [5.0, 0.0, 0.0]);
assert_eq!(t, None);
}
#[test]
fn test_multiple_regions_max_weight() {
let mut b = new_morph_region_blend();
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 2.0, 0, 0.5);
mrb_add_region(&mut b, [0.0, 0.0, 0.0], 2.0, 1, 0.9);
let w = mrb_weight_at(&b, [0.0, 0.0, 0.0]);
assert!((w - 0.9).abs() < 1e-6);
}
#[test]
fn test_empty_blend_zero_weight() {
let b = new_morph_region_blend();
assert_eq!(mrb_weight_at(&b, [0.0, 0.0, 0.0]), 0.0);
}
}