Skip to main content

oxihuman_morph/
skin_texture_scale_morph.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Skin texture scale morph — controls UV tiling and detail scale.
6
7/// Skin texture scale morph configuration.
8#[derive(Debug, Clone)]
9pub struct SkinTextureScaleMorph {
10    pub scale_u: f32,
11    pub scale_v: f32,
12    pub detail_scale: f32,
13    pub micro_scale: f32,
14}
15
16impl SkinTextureScaleMorph {
17    pub fn new() -> Self {
18        Self {
19            scale_u: 1.0,
20            scale_v: 1.0,
21            detail_scale: 1.0,
22            micro_scale: 1.0,
23        }
24    }
25}
26
27impl Default for SkinTextureScaleMorph {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33/// Create a new skin texture scale morph.
34pub fn new_skin_texture_scale_morph() -> SkinTextureScaleMorph {
35    SkinTextureScaleMorph::new()
36}
37
38/// Set uniform UV scale.
39pub fn skin_tex_scale_set_uniform(morph: &mut SkinTextureScaleMorph, scale: f32) {
40    let s = scale.clamp(0.01, 10.0);
41    morph.scale_u = s;
42    morph.scale_v = s;
43}
44
45/// Set U-axis scale independently.
46pub fn skin_tex_scale_set_u(morph: &mut SkinTextureScaleMorph, scale: f32) {
47    morph.scale_u = scale.clamp(0.01, 10.0);
48}
49
50/// Set V-axis scale independently.
51pub fn skin_tex_scale_set_v(morph: &mut SkinTextureScaleMorph, scale: f32) {
52    morph.scale_v = scale.clamp(0.01, 10.0);
53}
54
55/// Compute aspect ratio of the UV scale.
56pub fn skin_tex_scale_aspect_ratio(morph: &SkinTextureScaleMorph) -> f32 {
57    if morph.scale_v.abs() < 1e-6 {
58        1.0
59    } else {
60        morph.scale_u / morph.scale_v
61    }
62}
63
64/// Serialize to JSON-like string.
65pub fn skin_texture_scale_morph_to_json(morph: &SkinTextureScaleMorph) -> String {
66    format!(
67        r#"{{"scale_u":{:.4},"scale_v":{:.4},"detail_scale":{:.4},"micro_scale":{:.4}}}"#,
68        morph.scale_u, morph.scale_v, morph.detail_scale, morph.micro_scale
69    )
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_defaults() {
78        let m = new_skin_texture_scale_morph();
79        assert!((m.scale_u - 1.0).abs() < 1e-6);
80    }
81
82    #[test]
83    fn test_uniform_scale() {
84        let mut m = new_skin_texture_scale_morph();
85        skin_tex_scale_set_uniform(&mut m, 2.0);
86        assert!((m.scale_u - 2.0).abs() < 1e-6);
87        assert!((m.scale_v - 2.0).abs() < 1e-6);
88    }
89
90    #[test]
91    fn test_u_scale_clamp() {
92        let mut m = new_skin_texture_scale_morph();
93        skin_tex_scale_set_u(&mut m, 15.0);
94        assert!((m.scale_u - 10.0).abs() < 1e-6);
95    }
96
97    #[test]
98    fn test_v_scale_set() {
99        let mut m = new_skin_texture_scale_morph();
100        skin_tex_scale_set_v(&mut m, 0.5);
101        assert!((m.scale_v - 0.5).abs() < 1e-6);
102    }
103
104    #[test]
105    fn test_aspect_ratio_default() {
106        let m = new_skin_texture_scale_morph();
107        assert!((skin_tex_scale_aspect_ratio(&m) - 1.0).abs() < 1e-6);
108    }
109
110    #[test]
111    fn test_aspect_ratio_nonuniform() {
112        let mut m = new_skin_texture_scale_morph();
113        skin_tex_scale_set_u(&mut m, 2.0);
114        skin_tex_scale_set_v(&mut m, 1.0);
115        assert!((skin_tex_scale_aspect_ratio(&m) - 2.0).abs() < 1e-5);
116    }
117
118    #[test]
119    fn test_json() {
120        let m = new_skin_texture_scale_morph();
121        let s = skin_texture_scale_morph_to_json(&m);
122        assert!(s.contains("detail_scale"));
123    }
124
125    #[test]
126    fn test_clone() {
127        let m = new_skin_texture_scale_morph();
128        let m2 = m.clone();
129        assert!((m2.micro_scale - m.micro_scale).abs() < 1e-6);
130    }
131
132    #[test]
133    fn test_default_trait() {
134        let m: SkinTextureScaleMorph = Default::default();
135        assert!((m.detail_scale - 1.0).abs() < 1e-6);
136    }
137}