Skip to main content

oxihuman_morph/
eye_lid_crease.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3
4#![allow(dead_code)]
5
6//! Eye lid crease control: adjusts the crease depth and position above the eyelid.
7
8use std::f32::consts::FRAC_PI_4;
9
10#[allow(dead_code)]
11#[derive(Debug, Clone)]
12pub struct EyeLidCreaseConfig {
13    pub min_depth: f32,
14    pub max_depth: f32,
15}
16
17#[allow(dead_code)]
18#[derive(Debug, Clone)]
19pub struct EyeLidCreaseState {
20    pub depth: f32,
21    pub height: f32,
22    pub symmetry: f32,
23    pub fold: f32,
24}
25
26#[allow(dead_code)]
27pub fn default_eye_lid_crease_config() -> EyeLidCreaseConfig {
28    EyeLidCreaseConfig {
29        min_depth: 0.0,
30        max_depth: 1.0,
31    }
32}
33
34#[allow(dead_code)]
35pub fn new_eye_lid_crease_state() -> EyeLidCreaseState {
36    EyeLidCreaseState {
37        depth: 0.5,
38        height: 0.5,
39        symmetry: 1.0,
40        fold: 0.0,
41    }
42}
43
44#[allow(dead_code)]
45pub fn elc_set_depth(state: &mut EyeLidCreaseState, cfg: &EyeLidCreaseConfig, v: f32) {
46    state.depth = v.clamp(cfg.min_depth, cfg.max_depth);
47}
48
49#[allow(dead_code)]
50pub fn elc_set_height(state: &mut EyeLidCreaseState, v: f32) {
51    state.height = v.clamp(0.0, 1.0);
52}
53
54#[allow(dead_code)]
55pub fn elc_set_symmetry(state: &mut EyeLidCreaseState, v: f32) {
56    state.symmetry = v.clamp(0.0, 1.0);
57}
58
59#[allow(dead_code)]
60pub fn elc_set_fold(state: &mut EyeLidCreaseState, v: f32) {
61    state.fold = v.clamp(0.0, 1.0);
62}
63
64#[allow(dead_code)]
65pub fn elc_reset(state: &mut EyeLidCreaseState) {
66    *state = new_eye_lid_crease_state();
67}
68
69#[allow(dead_code)]
70pub fn elc_crease_angle(state: &EyeLidCreaseState) -> f32 {
71    state.depth * FRAC_PI_4
72}
73
74#[allow(dead_code)]
75pub fn elc_to_weights(state: &EyeLidCreaseState) -> Vec<(String, f32)> {
76    vec![
77        ("eyelid_crease_depth".to_string(), state.depth),
78        ("eyelid_crease_height".to_string(), state.height),
79        ("eyelid_crease_symmetry".to_string(), state.symmetry),
80        ("eyelid_crease_fold".to_string(), state.fold),
81    ]
82}
83
84#[allow(dead_code)]
85pub fn elc_to_json(state: &EyeLidCreaseState) -> String {
86    format!(
87        r#"{{"depth":{:.4},"height":{:.4},"symmetry":{:.4},"fold":{:.4}}}"#,
88        state.depth, state.height, state.symmetry, state.fold
89    )
90}
91
92#[allow(dead_code)]
93pub fn elc_blend(a: &EyeLidCreaseState, b: &EyeLidCreaseState, t: f32) -> EyeLidCreaseState {
94    let t = t.clamp(0.0, 1.0);
95    EyeLidCreaseState {
96        depth: a.depth + (b.depth - a.depth) * t,
97        height: a.height + (b.height - a.height) * t,
98        symmetry: a.symmetry + (b.symmetry - a.symmetry) * t,
99        fold: a.fold + (b.fold - a.fold) * t,
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn test_default_config() {
109        let cfg = default_eye_lid_crease_config();
110        assert!(cfg.min_depth.abs() < 1e-6);
111    }
112
113    #[test]
114    fn test_new_state() {
115        let s = new_eye_lid_crease_state();
116        assert!((s.depth - 0.5).abs() < 1e-6);
117        assert!((s.fold).abs() < 1e-6);
118    }
119
120    #[test]
121    fn test_set_depth_clamps() {
122        let cfg = default_eye_lid_crease_config();
123        let mut s = new_eye_lid_crease_state();
124        elc_set_depth(&mut s, &cfg, 5.0);
125        assert!((s.depth - 1.0).abs() < 1e-6);
126    }
127
128    #[test]
129    fn test_set_height() {
130        let mut s = new_eye_lid_crease_state();
131        elc_set_height(&mut s, 0.8);
132        assert!((s.height - 0.8).abs() < 1e-6);
133    }
134
135    #[test]
136    fn test_set_fold() {
137        let mut s = new_eye_lid_crease_state();
138        elc_set_fold(&mut s, 0.6);
139        assert!((s.fold - 0.6).abs() < 1e-6);
140    }
141
142    #[test]
143    fn test_reset() {
144        let cfg = default_eye_lid_crease_config();
145        let mut s = new_eye_lid_crease_state();
146        elc_set_depth(&mut s, &cfg, 0.9);
147        elc_reset(&mut s);
148        assert!((s.depth - 0.5).abs() < 1e-6);
149    }
150
151    #[test]
152    fn test_crease_angle() {
153        let mut s = new_eye_lid_crease_state();
154        s.depth = 1.0;
155        assert!((elc_crease_angle(&s) - FRAC_PI_4).abs() < 1e-6);
156    }
157
158    #[test]
159    fn test_to_weights() {
160        let s = new_eye_lid_crease_state();
161        assert_eq!(elc_to_weights(&s).len(), 4);
162    }
163
164    #[test]
165    fn test_blend() {
166        let a = new_eye_lid_crease_state();
167        let mut b = new_eye_lid_crease_state();
168        b.depth = 1.0;
169        let mid = elc_blend(&a, &b, 0.5);
170        assert!((mid.depth - 0.75).abs() < 1e-6);
171    }
172
173    #[test]
174    fn test_to_json() {
175        let s = new_eye_lid_crease_state();
176        let j = elc_to_json(&s);
177        assert!(j.contains("depth"));
178        assert!(j.contains("fold"));
179    }
180}