#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct MaskRegion {
pub name: String,
pub start: usize,
pub end: usize,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct BlendMask {
pub weights: Vec<f32>,
pub regions: Vec<MaskRegion>,
}
#[allow(dead_code)]
pub fn new_blend_mask(vertex_count: usize) -> BlendMask {
BlendMask {
weights: vec![1.0; vertex_count],
regions: Vec::new(),
}
}
#[allow(dead_code)]
pub fn set_mask_weight(mask: &mut BlendMask, vertex: usize, weight: f32) {
if let Some(w) = mask.weights.get_mut(vertex) {
*w = weight.clamp(0.0, 1.0);
}
}
#[allow(dead_code)]
pub fn get_mask_weight(mask: &BlendMask, vertex: usize) -> f32 {
mask.weights.get(vertex).copied().unwrap_or(0.0)
}
#[allow(dead_code)]
pub fn mask_vertex_count(mask: &BlendMask) -> usize {
mask.weights.len()
}
#[allow(dead_code)]
pub fn apply_blend_mask(mask: &BlendMask, deltas: &mut [[f32; 3]]) {
for (i, d) in deltas.iter_mut().enumerate() {
let w = mask.weights.get(i).copied().unwrap_or(0.0);
d[0] *= w;
d[1] *= w;
d[2] *= w;
}
}
#[allow(dead_code)]
pub fn invert_mask(mask: &mut BlendMask) {
for w in &mut mask.weights {
*w = 1.0 - *w;
}
}
#[allow(dead_code)]
pub fn mask_union(a: &BlendMask, b: &BlendMask) -> BlendMask {
let len = a.weights.len().max(b.weights.len());
let mut weights = Vec::with_capacity(len);
for i in 0..len {
let wa = a.weights.get(i).copied().unwrap_or(0.0);
let wb = b.weights.get(i).copied().unwrap_or(0.0);
weights.push(wa.max(wb));
}
BlendMask {
weights,
regions: Vec::new(),
}
}
#[allow(dead_code)]
pub fn mask_to_bytes(mask: &BlendMask) -> Vec<u8> {
let mut bytes = Vec::with_capacity(mask.weights.len() * 4);
for &w in &mask.weights {
bytes.extend_from_slice(&w.to_le_bytes());
}
bytes
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_blend_mask() {
let m = new_blend_mask(10);
assert_eq!(mask_vertex_count(&m), 10);
assert!((get_mask_weight(&m, 0) - 1.0).abs() < f32::EPSILON);
}
#[test]
fn test_set_get_mask_weight() {
let mut m = new_blend_mask(5);
set_mask_weight(&mut m, 2, 0.5);
assert!((get_mask_weight(&m, 2) - 0.5).abs() < f32::EPSILON);
}
#[test]
fn test_set_mask_weight_clamps() {
let mut m = new_blend_mask(5);
set_mask_weight(&mut m, 0, 2.0);
assert!((get_mask_weight(&m, 0) - 1.0).abs() < f32::EPSILON);
}
#[test]
fn test_get_mask_weight_out_of_bounds() {
let m = new_blend_mask(2);
assert!((get_mask_weight(&m, 99) - 0.0).abs() < f32::EPSILON);
}
#[test]
fn test_apply_blend_mask() {
let mut m = new_blend_mask(2);
set_mask_weight(&mut m, 0, 0.5);
set_mask_weight(&mut m, 1, 0.0);
let mut deltas = [[2.0, 4.0, 6.0], [1.0, 1.0, 1.0]];
apply_blend_mask(&m, &mut deltas);
assert!((deltas[0][0] - 1.0).abs() < 1e-6);
assert!((deltas[1][0] - 0.0).abs() < 1e-6);
}
#[test]
fn test_invert_mask() {
let mut m = new_blend_mask(3);
set_mask_weight(&mut m, 0, 0.3);
invert_mask(&mut m);
assert!((get_mask_weight(&m, 0) - 0.7).abs() < 1e-6);
}
#[test]
fn test_mask_union() {
let mut a = new_blend_mask(3);
let mut b = new_blend_mask(3);
set_mask_weight(&mut a, 0, 0.2);
set_mask_weight(&mut b, 0, 0.8);
let result = mask_union(&a, &b);
assert!((get_mask_weight(&result, 0) - 0.8).abs() < 1e-6);
}
#[test]
fn test_mask_to_bytes() {
let m = new_blend_mask(2);
let bytes = mask_to_bytes(&m);
assert_eq!(bytes.len(), 8);
}
#[test]
fn test_empty_mask() {
let m = new_blend_mask(0);
assert_eq!(mask_vertex_count(&m), 0);
}
#[test]
fn test_mask_union_different_sizes() {
let a = new_blend_mask(2);
let b = new_blend_mask(4);
let result = mask_union(&a, &b);
assert_eq!(mask_vertex_count(&result), 4);
}
}