use super::*;
#[test]
fn merges_coplanar_shared_vertices() {
let positions = vec![
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, ];
let normals = [0.0f32, 0.0, 1.0].repeat(6); let indices = vec![0, 1, 2, 3, 4, 5];
let (p, n, uv, i) = weld_indexed(&positions, &normals, None, &indices).expect("merged");
assert!(uv.is_none(), "no uvs in, no uvs out");
assert_eq!(p.len() / 3, 4, "6 authored verts -> 4 unique corners");
assert_eq!(n.len(), p.len());
assert_eq!(i.len(), 6, "triangle count unchanged");
for (orig, &ni) in indices.iter().zip(i.iter()) {
let o = *orig as usize * 3;
let w = ni as usize * 3;
assert_eq!(&positions[o..o + 3], &p[w..w + 3], "world position preserved");
}
}
#[test]
fn faceted_plate_welds_to_grid() {
const G: usize = 4;
let mut positions: Vec<f32> = Vec::new();
let mut normals: Vec<f32> = Vec::new();
let mut indices: Vec<u32> = Vec::new();
for i in 0..G {
for j in 0..G {
let base = (positions.len() / 3) as u32;
let (x, y) = (i as f32, j as f32);
for (dx, dy) in [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 1.0)] {
positions.extend_from_slice(&[x + dx, y + dy, 0.0]);
normals.extend_from_slice(&[0.0, 0.0, 1.0]);
}
indices.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
}
}
let raw_verts = positions.len() / 3;
let (p, _n, _uv, idx) = weld_indexed(&positions, &normals, None, &indices).expect("merged");
assert_eq!(raw_verts, 4 * G * G);
assert_eq!(p.len() / 3, (G + 1) * (G + 1), "welded to unique grid points");
assert_eq!(idx.len(), indices.len(), "triangle count unchanged");
}
#[test]
fn out_of_range_index_is_a_no_op_not_a_panic() {
let positions = vec![0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0];
let normals = [0.0f32, 0.0, 1.0].repeat(3);
let indices = vec![0, 1, 9]; assert!(
weld_indexed(&positions, &normals, None, &indices).is_none(),
"malformed input is a no-op (None), not a panic"
);
}
#[test]
fn index_equal_to_vertex_count_is_a_no_op_not_a_panic() {
let positions = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0];
let normals = [0.0f32, 0.0, 1.0].repeat(3);
let indices = vec![0, 1, 3]; assert!(
weld_indexed(&positions, &normals, None, &indices).is_none(),
"index == vertex count is out of range: no-op (None), not a panic"
);
}
#[test]
fn keeps_creases_split() {
let positions = vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
let normals = vec![0.0, 0.0, 1.0, 1.0, 0.0, 0.0];
let indices = vec![0, 1];
assert!(
weld_indexed(&positions, &normals, None, &indices).is_none(),
"distinct normals: nothing merges, weld is a no-op"
);
}
#[test]
fn flat_shaded_cube_keeps_24_verts() {
let faces: [([f32; 3], [[f32; 3]; 4]); 6] = [
([0.0, 0.0, 1.0], [[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0]]),
([0.0, 0.0, -1.0], [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [0.0, 1.0, 0.0]]),
([1.0, 0.0, 0.0], [[1.0, 0.0, 0.0], [1.0, 1.0, 0.0], [1.0, 1.0, 1.0], [1.0, 0.0, 1.0]]),
([-1.0, 0.0, 0.0], [[0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 1.0, 1.0], [0.0, 0.0, 1.0]]),
([0.0, 1.0, 0.0], [[0.0, 1.0, 0.0], [1.0, 1.0, 0.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0]]),
([0.0, -1.0, 0.0], [[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 0.0, 1.0], [0.0, 0.0, 1.0]]),
];
let mut positions: Vec<f32> = Vec::new();
let mut normals: Vec<f32> = Vec::new();
let mut indices: Vec<u32> = Vec::new();
for (nrm, corners) in faces {
let base = (positions.len() / 3) as u32;
for c in corners {
positions.extend_from_slice(&c);
normals.extend_from_slice(&nrm);
}
indices.extend_from_slice(&[base, base + 1, base + 2, base, base + 2, base + 3]);
}
assert_eq!(positions.len() / 3, 24, "6 faces * 4 corners = 24 raw verts");
assert!(
weld_indexed(&positions, &normals, None, &indices).is_none(),
"distinct per-face normals: nothing merges, all 24 verts kept (flat shading)"
);
}
#[test]
fn uv_seam_stays_split_and_uvs_stay_aligned() {
let positions = vec![
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, ];
let normals = [0.0f32, 0.0, 1.0].repeat(6);
let uvs = vec![
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, ];
let indices = vec![0, 1, 2, 3, 4, 5];
assert!(
weld_indexed(&positions, &normals, Some(&uvs), &indices).is_none(),
"the UV seam keeps all 6 verts split (nothing merges, UVs stay 1:1)"
);
}
#[test]
fn coplanar_same_uv_still_welds_and_carries_uvs() {
let positions = vec![
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, ];
let normals = [0.0f32, 0.0, 1.0].repeat(6);
let uvs = vec![
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, ];
let indices = vec![0, 1, 2, 3, 4, 5];
let (p, _n, uv, _i) =
weld_indexed(&positions, &normals, Some(&uvs), &indices).expect("merged");
let uv = uv.expect("uvs carried through");
assert_eq!(p.len() / 3, 4, "same-uv shared corners still weld to 4");
assert_eq!(uv.len(), (p.len() / 3) * 2, "uvs stay 1:1 with welded positions");
}
#[test]
fn weld_is_idempotent() {
let positions = vec![
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, ];
let normals = [0.0f32, 0.0, 1.0].repeat(6);
let indices = vec![0, 1, 2, 3, 4, 5];
let (p1, n1, _uv1, i1) =
weld_indexed(&positions, &normals, None, &indices).expect("first weld merges");
assert_eq!(p1.len() / 3, 4);
assert!(
weld_indexed(&p1, &n1, None, &i1).is_none(),
"second weld of an already-welded mesh is a no-op"
);
}
#[test]
fn deterministic_and_first_seen_order() {
let positions = vec![9.0, 9.0, 9.0, 0.0, 0.0, 0.0, 9.0, 9.0, 9.0];
let normals = vec![0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0];
let indices = vec![0, 1, 2];
let (p1, n1, _uv1, i1) =
weld_indexed(&positions, &normals, None, &indices).expect("merged");
let (p2, n2, _uv2, i2) =
weld_indexed(&positions, &normals, None, &indices).expect("merged");
assert_eq!((&p1, &n1, &i1), (&p2, &n2, &i2), "stable across runs");
assert_eq!(p1.len() / 3, 2, "the repeated vertex 0/2 merges");
assert_eq!(&p1[0..3], &[9.0, 9.0, 9.0]);
assert_eq!(i1, vec![0, 1, 0]);
}