#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ExpressionDef {
pub name: String,
pub morph_indices: Vec<usize>,
pub morph_weights: Vec<f32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default)]
pub struct ExpressionPack {
pub expressions: Vec<ExpressionDef>,
}
#[allow(dead_code)]
pub fn new_expression_pack() -> ExpressionPack {
ExpressionPack::default()
}
#[allow(dead_code)]
pub fn add_expression(
pack: &mut ExpressionPack,
name: &str,
indices: Vec<usize>,
weights: Vec<f32>,
) {
let n = indices.len().min(weights.len());
pack.expressions.push(ExpressionDef {
name: name.to_string(),
morph_indices: indices[..n].to_vec(),
morph_weights: weights[..n].to_vec(),
});
}
#[allow(dead_code)]
pub fn apply_expression(
pack: &ExpressionPack,
name: &str,
out_weights: &mut [f32],
strength: f32,
) -> bool {
let strength = strength.clamp(0.0, 1.0);
if let Some(expr) = pack.expressions.iter().find(|e| e.name == name) {
for (&idx, &w) in expr.morph_indices.iter().zip(expr.morph_weights.iter()) {
if idx < out_weights.len() {
out_weights[idx] += w * strength;
}
}
return true;
}
false
}
#[allow(dead_code)]
pub fn expression_count(pack: &ExpressionPack) -> usize {
pack.expressions.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_pack_is_empty() {
let p = new_expression_pack();
assert_eq!(expression_count(&p), 0);
}
#[test]
fn add_expression_increments_count() {
let mut p = new_expression_pack();
add_expression(&mut p, "smile", vec![0, 1], vec![0.8, 0.4]);
assert_eq!(expression_count(&p), 1);
}
#[test]
fn apply_existing_expression_returns_true() {
let mut p = new_expression_pack();
add_expression(&mut p, "smile", vec![0], vec![1.0]);
let mut w = vec![0.0_f32; 4];
assert!(apply_expression(&p, "smile", &mut w, 1.0));
}
#[test]
fn apply_missing_expression_returns_false() {
let p = new_expression_pack();
let mut w = vec![0.0_f32; 4];
assert!(!apply_expression(&p, "frown", &mut w, 1.0));
}
#[test]
fn apply_expression_sets_correct_weights() {
let mut p = new_expression_pack();
add_expression(&mut p, "brow_raise", vec![2], vec![0.9]);
let mut w = vec![0.0_f32; 4];
apply_expression(&p, "brow_raise", &mut w, 1.0);
assert!((w[2] - 0.9).abs() < 1e-6);
}
#[test]
fn apply_expression_scaled_by_strength() {
let mut p = new_expression_pack();
add_expression(&mut p, "e", vec![0], vec![1.0]);
let mut w = vec![0.0_f32; 2];
apply_expression(&p, "e", &mut w, 0.5);
assert!((w[0] - 0.5).abs() < 1e-6);
}
#[test]
fn add_expression_mismatched_len_truncates() {
let mut p = new_expression_pack();
add_expression(&mut p, "e", vec![0, 1, 2], vec![1.0, 1.0]);
assert_eq!(p.expressions[0].morph_indices.len(), 2);
}
#[test]
fn apply_expression_out_of_range_index_skipped() {
let mut p = new_expression_pack();
add_expression(&mut p, "e", vec![99], vec![1.0]);
let mut w = vec![0.0_f32; 4];
apply_expression(&p, "e", &mut w, 1.0); }
#[test]
fn expression_count_multiple() {
let mut p = new_expression_pack();
for i in 0..5u32 {
add_expression(&mut p, &i.to_string(), vec![], vec![]);
}
assert_eq!(expression_count(&p), 5);
}
#[test]
fn apply_expression_accumulates() {
let mut p = new_expression_pack();
add_expression(&mut p, "e", vec![0], vec![0.4]);
let mut w = vec![0.2_f32; 2];
apply_expression(&p, "e", &mut w, 1.0);
assert!((w[0] - 0.6).abs() < 1e-6);
}
}