Skip to main content

oxihuman_mesh/
mesh_array_modifier.rs

1#![allow(dead_code)]
2// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
3// SPDX-License-Identifier: Apache-2.0
4
5//! Array modifier: repeat a mesh N times along an offset.
6
7#[allow(dead_code)]
8pub struct ArrayResult {
9    pub verts: Vec<[f32; 3]>,
10    pub tris: Vec<[u32; 3]>,
11}
12
13#[allow(dead_code)]
14pub fn array_mesh(
15    verts: &[[f32; 3]],
16    tris: &[[u32; 3]],
17    count: u32,
18    offset: [f32; 3],
19) -> ArrayResult {
20    let nv = verts.len();
21    let mut out_verts = Vec::with_capacity(array_vert_count(nv, count));
22    let mut out_tris = Vec::with_capacity(array_tri_count(tris.len(), count));
23    for i in 0..count {
24        let dx = offset[0] * i as f32;
25        let dy = offset[1] * i as f32;
26        let dz = offset[2] * i as f32;
27        let base = (i as usize * nv) as u32;
28        for v in verts {
29            out_verts.push([v[0] + dx, v[1] + dy, v[2] + dz]);
30        }
31        for t in tris {
32            out_tris.push([t[0] + base, t[1] + base, t[2] + base]);
33        }
34    }
35    ArrayResult {
36        verts: out_verts,
37        tris: out_tris,
38    }
39}
40
41#[allow(dead_code)]
42pub fn array_vert_count(orig: usize, count: u32) -> usize {
43    orig * count as usize
44}
45
46#[allow(dead_code)]
47pub fn array_tri_count(orig: usize, count: u32) -> usize {
48    orig * count as usize
49}
50
51// ---- New API required by lib.rs ----
52
53/// Array modifier parameters (new API).
54pub struct ArrayParams {
55    pub count: usize,
56    pub offset: [f32; 3],
57    pub scale: [f32; 3],
58}
59
60pub fn new_array_params(count: usize, offset: [f32; 3]) -> ArrayParams {
61    ArrayParams {
62        count: count.max(1),
63        offset,
64        scale: [1.0, 1.0, 1.0],
65    }
66}
67
68pub fn array_instance_transform(params: &ArrayParams, instance: usize) -> ([f32; 3], [f32; 3]) {
69    let i = instance as f32;
70    let translation = [
71        params.offset[0] * i,
72        params.offset[1] * i,
73        params.offset[2] * i,
74    ];
75    (translation, params.scale)
76}
77
78pub fn array_total_size(params: &ArrayParams) -> [f32; 3] {
79    let n = params.count as f32;
80    [
81        params.offset[0] * n,
82        params.offset[1] * n,
83        params.offset[2] * n,
84    ]
85}
86
87pub fn array_vertex_count(base_count: usize, params: &ArrayParams) -> usize {
88    base_count * params.count
89}
90
91pub fn array_face_count(base_count: usize, params: &ArrayParams) -> usize {
92    base_count * params.count
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    fn unit_tri_verts() -> Vec<[f32; 3]> {
100        vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
101    }
102    fn unit_tri_tris() -> Vec<[u32; 3]> {
103        vec![[0, 1, 2]]
104    }
105
106    #[test]
107    fn vert_count_formula() {
108        assert_eq!(array_vert_count(3, 4), 12);
109    }
110
111    #[test]
112    fn tri_count_formula() {
113        assert_eq!(array_tri_count(2, 3), 6);
114    }
115
116    #[test]
117    fn single_copy_unchanged() {
118        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 1, [1.0, 0.0, 0.0]);
119        assert_eq!(r.verts.len(), 3);
120        assert_eq!(r.tris.len(), 1);
121        assert_eq!(r.tris[0], [0, 1, 2]);
122    }
123
124    #[test]
125    fn two_copies_vert_count() {
126        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 2, [2.0, 0.0, 0.0]);
127        assert_eq!(r.verts.len(), 6);
128    }
129
130    #[test]
131    fn two_copies_offset_applied() {
132        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 2, [2.0, 0.0, 0.0]);
133        assert!((r.verts[3][0] - 2.0).abs() < 1e-6);
134    }
135
136    #[test]
137    fn two_copies_tri_indices_offset() {
138        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 2, [1.0, 0.0, 0.0]);
139        assert_eq!(r.tris[1], [3, 4, 5]);
140    }
141
142    #[test]
143    fn zero_count_empty() {
144        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 0, [1.0, 0.0, 0.0]);
145        assert!(r.verts.is_empty());
146        assert!(r.tris.is_empty());
147    }
148
149    #[test]
150    fn y_offset_applied() {
151        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 3, [0.0, 1.0, 0.0]);
152        assert!((r.verts[6][1] - 2.0).abs() < 1e-6);
153    }
154
155    #[test]
156    fn z_offset_applied() {
157        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 2, [0.0, 0.0, 5.0]);
158        assert!((r.verts[3][2] - 5.0).abs() < 1e-6);
159    }
160
161    #[test]
162    fn first_copy_at_origin() {
163        let r = array_mesh(&unit_tri_verts(), &unit_tri_tris(), 3, [1.0, 1.0, 1.0]);
164        assert!((r.verts[0][0]).abs() < 1e-6);
165    }
166}