Skip to main content

oxihuman_export/
mesh_proxy_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Mesh proxy export: low-res stand-in mesh export.
6
7/// Mesh proxy export data.
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct MeshProxyExport2 {
11    pub positions: Vec<[f32; 3]>,
12    pub indices: Vec<u32>,
13    pub source_vertex_count: usize,
14}
15
16#[allow(dead_code)]
17pub fn new_mesh_proxy2(
18    positions: &[[f32; 3]],
19    indices: &[u32],
20    source_count: usize,
21) -> MeshProxyExport2 {
22    MeshProxyExport2 {
23        positions: positions.to_vec(),
24        indices: indices.to_vec(),
25        source_vertex_count: source_count,
26    }
27}
28
29#[allow(dead_code)]
30pub fn proxy2_vertex_count_fn(p: &MeshProxyExport2) -> usize {
31    p.positions.len()
32}
33
34#[allow(dead_code)]
35pub fn proxy2_triangle_count(p: &MeshProxyExport2) -> usize {
36    p.indices.len() / 3
37}
38
39#[allow(dead_code)]
40pub fn proxy2_reduction_ratio(p: &MeshProxyExport2) -> f32 {
41    if p.source_vertex_count == 0 {
42        return 0.0;
43    }
44    p.positions.len() as f32 / p.source_vertex_count as f32
45}
46
47#[allow(dead_code)]
48pub fn proxy2_bounds_fn(p: &MeshProxyExport2) -> ([f32; 3], [f32; 3]) {
49    if p.positions.is_empty() {
50        return ([0.0; 3], [0.0; 3]);
51    }
52    let mut mn = p.positions[0];
53    let mut mx = p.positions[0];
54    for v in &p.positions {
55        for k in 0..3 {
56            mn[k] = mn[k].min(v[k]);
57            mx[k] = mx[k].max(v[k]);
58        }
59    }
60    (mn, mx)
61}
62
63#[allow(dead_code)]
64pub fn proxy2_center_fn(p: &MeshProxyExport2) -> [f32; 3] {
65    let (mn, mx) = proxy2_bounds_fn(p);
66    [
67        (mn[0] + mx[0]) * 0.5,
68        (mn[1] + mx[1]) * 0.5,
69        (mn[2] + mx[2]) * 0.5,
70    ]
71}
72
73#[allow(dead_code)]
74pub fn proxy2_to_obj(p: &MeshProxyExport2) -> String {
75    let mut s = String::new();
76    for v in &p.positions {
77        s.push_str(&format!("v {} {} {}\n", v[0], v[1], v[2]));
78    }
79    let tri = p.indices.len() / 3;
80    for t in 0..tri {
81        s.push_str(&format!(
82            "f {} {} {}\n",
83            p.indices[t * 3] + 1,
84            p.indices[t * 3 + 1] + 1,
85            p.indices[t * 3 + 2] + 1
86        ));
87    }
88    s
89}
90
91#[allow(dead_code)]
92pub fn mesh_proxy2_to_json(p: &MeshProxyExport2) -> String {
93    format!(
94        "{{\"vertices\":{},\"triangles\":{},\"ratio\":{:.6}}}",
95        p.positions.len(),
96        p.indices.len() / 3,
97        proxy2_reduction_ratio(p)
98    )
99}
100
101#[allow(dead_code)]
102pub fn proxy2_validate(p: &MeshProxyExport2) -> bool {
103    p.indices.iter().all(|&i| (i as usize) < p.positions.len())
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    fn tri() -> MeshProxyExport2 {
111        new_mesh_proxy2(
112            &[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.5, 1.0, 0.0]],
113            &[0, 1, 2],
114            100,
115        )
116    }
117
118    #[test]
119    fn test_new() {
120        assert_eq!(proxy2_vertex_count_fn(&tri()), 3);
121    }
122
123    #[test]
124    fn test_triangle_count() {
125        assert_eq!(proxy2_triangle_count(&tri()), 1);
126    }
127
128    #[test]
129    fn test_reduction_ratio() {
130        assert!((proxy2_reduction_ratio(&tri()) - 0.03).abs() < 1e-6);
131    }
132
133    #[test]
134    fn test_bounds() {
135        let (mn, mx) = proxy2_bounds_fn(&tri());
136        assert!((mn[0]).abs() < 1e-6);
137        assert!((mx[0] - 1.0).abs() < 1e-6);
138    }
139
140    #[test]
141    fn test_center() {
142        let c = proxy2_center_fn(&tri());
143        assert!((c[0] - 0.5).abs() < 1e-6);
144    }
145
146    #[test]
147    fn test_to_obj() {
148        let s = proxy2_to_obj(&tri());
149        assert!(s.contains("v "));
150        assert!(s.contains("f "));
151    }
152
153    #[test]
154    fn test_to_json() {
155        assert!(mesh_proxy2_to_json(&tri()).contains("\"vertices\":3"));
156    }
157
158    #[test]
159    fn test_validate_ok() {
160        assert!(proxy2_validate(&tri()));
161    }
162
163    #[test]
164    fn test_validate_bad() {
165        let p = MeshProxyExport2 {
166            positions: vec![[0.0; 3]],
167            indices: vec![5],
168            source_vertex_count: 1,
169        };
170        assert!(!proxy2_validate(&p));
171    }
172
173    #[test]
174    fn test_empty_ratio() {
175        let p = new_mesh_proxy2(&[], &[], 0);
176        assert!((proxy2_reduction_ratio(&p)).abs() < 1e-6);
177    }
178}