#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct LipPuckerConfig {
pub max_pucker: f32,
pub lip_round_factor: f32,
pub protrusion_factor: f32,
}
impl Default for LipPuckerConfig {
fn default() -> Self {
Self { max_pucker: 1.0, lip_round_factor: 0.8, protrusion_factor: 0.5 }
}
}
#[derive(Debug, Clone)]
pub struct LipPuckerState {
pub config: LipPuckerConfig,
pub pucker: f32,
}
impl Default for LipPuckerState {
fn default() -> Self {
Self { config: LipPuckerConfig::default(), pucker: 0.0 }
}
}
pub fn lp_set_pucker(state: &mut LipPuckerState, amount: f32) {
state.pucker = amount.clamp(0.0, state.config.max_pucker);
}
pub fn lp_get_pucker(state: &LipPuckerState) -> f32 {
state.pucker
}
pub fn lp_lip_round_weight(state: &LipPuckerState) -> f32 {
state.pucker * state.config.lip_round_factor
}
pub fn lp_protrusion_weight(state: &LipPuckerState) -> f32 {
state.pucker * state.config.protrusion_factor
}
pub fn lp_blend_toward(state: &mut LipPuckerState, target: f32, t: f32) {
let t = t.clamp(0.0, 1.0);
let target = target.clamp(0.0, state.config.max_pucker);
state.pucker += (target - state.pucker) * t;
}
pub fn lp_reset(state: &mut LipPuckerState) {
state.pucker = 0.0;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_initial_neutral() {
let s = LipPuckerState::default();
assert_eq!(s.pucker, 0.0);
}
#[test]
fn test_set_get() {
let mut s = LipPuckerState::default();
lp_set_pucker(&mut s, 0.6);
assert!((lp_get_pucker(&s) - 0.6).abs() < 1e-6);
}
#[test]
fn test_clamp_max() {
let mut s = LipPuckerState::default();
lp_set_pucker(&mut s, 5.0);
assert!((lp_get_pucker(&s) - 1.0).abs() < 1e-6);
}
#[test]
fn test_lip_round_weight() {
let mut s = LipPuckerState::default();
lp_set_pucker(&mut s, 1.0);
let expected = s.config.lip_round_factor;
assert!((lp_lip_round_weight(&s) - expected).abs() < 1e-6);
}
#[test]
fn test_protrusion_weight() {
let mut s = LipPuckerState::default();
lp_set_pucker(&mut s, 1.0);
let expected = s.config.protrusion_factor;
assert!((lp_protrusion_weight(&s) - expected).abs() < 1e-6);
}
#[test]
fn test_blend_toward() {
let mut s = LipPuckerState::default();
lp_blend_toward(&mut s, 1.0, 0.5);
assert!(s.pucker > 0.0 && s.pucker < 1.0);
}
#[test]
fn test_reset() {
let mut s = LipPuckerState::default();
lp_set_pucker(&mut s, 0.9);
lp_reset(&mut s);
assert_eq!(s.pucker, 0.0);
}
#[test]
fn test_config_defaults_valid() {
let cfg = LipPuckerConfig::default();
assert!((0.0..=1.0).contains(&cfg.lip_round_factor));
assert!((0.0..=1.0).contains(&cfg.protrusion_factor));
}
#[test]
fn test_blend_full() {
let mut s = LipPuckerState::default();
lp_blend_toward(&mut s, 0.75, 1.0);
assert!((s.pucker - 0.75).abs() < 1e-6);
}
}