Skip to main content

oxihuman_morph/
example_based_morph.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Example-based deformation stub.
6
7/// A single example pose containing vertex positions.
8#[derive(Debug, Clone)]
9pub struct ExamplePose {
10    pub name: String,
11    pub vertices: Vec<[f32; 3]>,
12    pub weight: f32,
13}
14
15/// Example-based morph system.
16#[derive(Debug, Clone)]
17pub struct ExampleBasedMorph {
18    pub rest_pose: Vec<[f32; 3]>,
19    pub examples: Vec<ExamplePose>,
20    pub enabled: bool,
21}
22
23impl ExampleBasedMorph {
24    pub fn new(rest_pose: Vec<[f32; 3]>) -> Self {
25        ExampleBasedMorph {
26            rest_pose,
27            examples: Vec::new(),
28            enabled: true,
29        }
30    }
31}
32
33/// Create a new example-based morph from a rest pose.
34pub fn new_example_based_morph(rest_pose: Vec<[f32; 3]>) -> ExampleBasedMorph {
35    ExampleBasedMorph::new(rest_pose)
36}
37
38/// Add an example pose.
39pub fn ebm_add_example(morph: &mut ExampleBasedMorph, example: ExamplePose) {
40    morph.examples.push(example);
41}
42
43/// Evaluate the blended result (stub: returns rest pose).
44pub fn ebm_evaluate(morph: &ExampleBasedMorph, _weights: &[f32]) -> Vec<[f32; 3]> {
45    /* Stub: returns rest pose unchanged */
46    morph.rest_pose.clone()
47}
48
49/// Return the number of examples.
50pub fn ebm_example_count(morph: &ExampleBasedMorph) -> usize {
51    morph.examples.len()
52}
53
54/// Return the vertex count.
55pub fn ebm_vertex_count(morph: &ExampleBasedMorph) -> usize {
56    morph.rest_pose.len()
57}
58
59/// Enable or disable the morph system.
60pub fn ebm_set_enabled(morph: &mut ExampleBasedMorph, enabled: bool) {
61    morph.enabled = enabled;
62}
63
64/// Serialize to JSON-like string.
65pub fn ebm_to_json(morph: &ExampleBasedMorph) -> String {
66    format!(
67        r#"{{"vertex_count":{},"example_count":{},"enabled":{}}}"#,
68        morph.rest_pose.len(),
69        morph.examples.len(),
70        morph.enabled
71    )
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    #[test]
79    fn test_new_vertex_count() {
80        let m = new_example_based_morph(vec![[0.0; 3]; 10]);
81        assert_eq!(
82            ebm_vertex_count(&m),
83            10, /* vertex count must match rest pose */
84        );
85    }
86
87    #[test]
88    fn test_no_examples_initially() {
89        let m = new_example_based_morph(vec![[0.0; 3]; 5]);
90        assert_eq!(ebm_example_count(&m), 0 /* no examples initially */,);
91    }
92
93    #[test]
94    fn test_add_example() {
95        let mut m = new_example_based_morph(vec![[0.0; 3]; 4]);
96        ebm_add_example(
97            &mut m,
98            ExamplePose {
99                name: "smile".into(),
100                vertices: vec![[0.1, 0.0, 0.0]; 4],
101                weight: 1.0,
102            },
103        );
104        assert_eq!(ebm_example_count(&m), 1 /* one example after add */,);
105    }
106
107    #[test]
108    fn test_evaluate_length() {
109        let m = new_example_based_morph(vec![[0.0; 3]; 6]);
110        let out = ebm_evaluate(&m, &[]);
111        assert_eq!(
112            out.len(),
113            6, /* output length must match vertex count */
114        );
115    }
116
117    #[test]
118    fn test_evaluate_returns_rest() {
119        let rest = vec![[1.0, 2.0, 3.0]; 3];
120        let m = new_example_based_morph(rest.clone());
121        let out = ebm_evaluate(&m, &[]);
122        assert!((out[0][0] - rest[0][0]).abs() < 1e-6, /* must return rest pose */);
123    }
124
125    #[test]
126    fn test_set_enabled() {
127        let mut m = new_example_based_morph(vec![]);
128        ebm_set_enabled(&mut m, false);
129        assert!(!m.enabled /* enabled must be false */,);
130    }
131
132    #[test]
133    fn test_to_json() {
134        let m = new_example_based_morph(vec![[0.0; 3]; 3]);
135        let j = ebm_to_json(&m);
136        assert!(j.contains("\"vertex_count\""), /* json must contain vertex_count */);
137    }
138
139    #[test]
140    fn test_enabled_default() {
141        let m = new_example_based_morph(vec![]);
142        assert!(m.enabled /* must be enabled by default */,);
143    }
144
145    #[test]
146    fn test_multiple_examples() {
147        let mut m = new_example_based_morph(vec![[0.0; 3]; 2]);
148        for i in 0..4 {
149            ebm_add_example(
150                &mut m,
151                ExamplePose {
152                    name: format!("pose_{i}"),
153                    vertices: vec![[0.0; 3]; 2],
154                    weight: 0.5,
155                },
156            );
157        }
158        assert_eq!(
159            ebm_example_count(&m),
160            4, /* four examples must be stored */
161        );
162    }
163
164    #[test]
165    fn test_json_contains_example_count() {
166        let m = new_example_based_morph(vec![]);
167        let j = ebm_to_json(&m);
168        assert!(j.contains("\"example_count\""), /* json must contain example_count */);
169    }
170}