use super::collate::mat4_to_row_major_f32;
use super::{
collate_and_encode, collate_instances, decode_instanced, encode_instanced, verify_recomposition,
Collated, InstanceMeshRef, INSTANCED_MAGIC, INSTANCED_VERSION,
};
use crate::mesh::{InstanceMeta, Mesh};
use nalgebra::Matrix4;
fn mat_rm(m: &Matrix4<f64>) -> [f64; 16] {
let mut out = [0.0f64; 16];
for r in 0..4 {
for c in 0..4 {
out[r * 4 + c] = m[(r, c)];
}
}
out
}
fn baked(canonical: &[f32], m: &Matrix4<f64>) -> Vec<f32> {
let mut out = Vec::with_capacity(canonical.len());
for v in canonical.chunks_exact(3) {
let w = m * nalgebra::Vector4::new(v[0] as f64, v[1] as f64, v[2] as f64, 1.0);
out.push((w.x / w.w) as f32);
out.push((w.y / w.w) as f32);
out.push((w.z / w.w) as f32);
}
out
}
fn mesh_from(positions: Vec<f32>, meta: InstanceMeta) -> Mesh {
let n = positions.len() / 3;
let mut m = Mesh::new();
m.positions = positions;
m.normals = vec![0.0; n * 3];
m.indices = (0..n as u32).collect();
m.instance_meta = Some(meta);
m
}
const CANON: [f32; 12] = [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0];
#[test]
fn collates_repeated_representation_and_recomposes_within_a_micrometre() {
use std::f64::consts::FRAC_PI_3;
let placements = [
Matrix4::new_translation(&nalgebra::Vector3::new(10.0, 0.0, 0.0)),
Matrix4::from_euler_angles(0.0, 0.0, FRAC_PI_3)
* Matrix4::new_translation(&nalgebra::Vector3::new(-5.0, 7.0, 2.0)),
Matrix4::from_euler_angles(FRAC_PI_3, 0.0, 0.0)
* Matrix4::new_translation(&nalgebra::Vector3::new(100.0, -50.0, 3.0)),
];
let meshes: Vec<Mesh> = placements
.iter()
.map(|m| {
mesh_from(
baked(&CANON, m),
InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: 42,
instanceable: true,
},
)
})
.collect();
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
assert_eq!(collated.templates.len(), 1, "one shared template");
assert_eq!(collated.flat_indices.len(), 0, "nothing left flat");
let tmpl = &collated.templates[0];
assert_eq!(tmpl.rep_identity, 42);
assert_eq!(tmpl.occurrences.len(), 3);
assert_eq!(tmpl.occurrences[0].mesh_index, 0);
let id = Matrix4::<f64>::identity();
for (a, b) in tmpl.occurrences[0]
.transform
.iter()
.zip(mat4_to_row_major_f32(&id).iter())
{
assert!((a - b).abs() < 1e-5, "template transform is identity");
}
let err = verify_recomposition(&meshes, &collated);
assert!(err < 1e-4, "recomposition error {err} exceeds the f32 storage floor");
}
#[test]
fn composes_placement_and_mapping_transform() {
let mapping = Matrix4::new_translation(&nalgebra::Vector3::new(0.5, 0.0, 0.0))
* Matrix4::new_scaling(1.0);
let placements = [
Matrix4::new_translation(&nalgebra::Vector3::new(3.0, 0.0, 0.0)),
Matrix4::from_euler_angles(0.0, std::f64::consts::FRAC_PI_4, 0.0)
* Matrix4::new_translation(&nalgebra::Vector3::new(20.0, 1.0, -4.0)),
];
let meshes: Vec<Mesh> = placements
.iter()
.map(|p| {
let full = p * mapping;
mesh_from(
baked(&CANON, &full),
InstanceMeta {
transform: mat_rm(p),
local_transform: Some(mat_rm(&mapping)),
canonical_transform: None,
rep_identity: 7,
instanceable: true,
},
)
})
.collect();
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
assert_eq!(collated.templates.len(), 1);
assert_eq!(collated.templates[0].occurrences.len(), 2);
let err = verify_recomposition(&meshes, &collated);
assert!(err < 1e-4, "placement·mapping recomposition error {err}");
}
#[test]
fn rigid_canonical_transform_recomposes() {
let c_b = Matrix4::from_euler_angles(0.3, 0.9, 0.2)
* Matrix4::new_translation(&nalgebra::Vector3::new(0.4, -0.2, 0.1));
let m_a = Matrix4::new_translation(&nalgebra::Vector3::new(5.0, 0.0, 0.0));
let m_b = Matrix4::from_euler_angles(0.0, 0.0, 1.2)
* Matrix4::new_translation(&nalgebra::Vector3::new(-3.0, 8.0, 2.0));
let meshes = vec![
mesh_from(
baked(&CANON, &m_a),
InstanceMeta {
transform: mat_rm(&m_a),
local_transform: None,
canonical_transform: None, rep_identity: 99,
instanceable: true,
},
),
mesh_from(
baked(&CANON, &(m_b * c_b)),
InstanceMeta {
transform: mat_rm(&m_b),
local_transform: None,
canonical_transform: Some(mat_rm(&c_b)),
rep_identity: 99,
instanceable: true,
},
),
];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
assert_eq!(collated.templates.len(), 1, "one rigid template");
assert_eq!(collated.templates[0].occurrences.len(), 2);
let err = verify_recomposition(&meshes, &collated);
assert!(err < 1e-4, "rigid canonical_transform recompose error {err}");
}
#[test]
fn instanced_wire_format_roundtrips_and_expands_to_flat() {
let m0 = Matrix4::new_translation(&nalgebra::Vector3::new(1.0, 0.0, 0.0));
let m1 = Matrix4::from_euler_angles(0.0, 0.0, 1.1)
* Matrix4::new_translation(&nalgebra::Vector3::new(-4.0, 6.0, 2.0));
let m2 = Matrix4::new_translation(&nalgebra::Vector3::new(9.0, 9.0, 9.0));
let mk = |m: &Matrix4<f64>, rep: u128| {
mesh_from(
baked(&CANON, m),
InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: rep,
instanceable: true,
},
)
};
let meshes = vec![mk(&m0, 50), mk(&m1, 50), mk(&m2, 60)];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
let bytes = encode_instanced(&meshes, &collated, |i| i as u32, |_| [0.25, 0.5, 0.75, 1.0]);
let dec = decode_instanced(&bytes).expect("decodes");
assert_eq!(dec.templates.len(), 2, "two templates");
assert_eq!(dec.instances.len(), 3, "every input mesh is an instance");
assert_eq!(dec.templates[0].positions, meshes[0].positions);
assert_eq!(dec.templates[0].indices, meshes[0].indices);
assert_eq!(dec.instances[0].color, [0.25, 0.5, 0.75, 1.0]);
for inst in &dec.instances {
let tmpl = &dec.templates[inst.template_index as usize];
let rel = Matrix4::from_row_slice(&inst.transform.map(|v| v as f64));
let orig = &meshes[inst.entity_id as usize];
assert_eq!(tmpl.positions.len(), orig.positions.len());
let n = tmpl.positions.len() / 3;
for v in 0..n {
let w = rel
* nalgebra::Vector4::new(
tmpl.origin[0] + tmpl.positions[v * 3] as f64,
tmpl.origin[1] + tmpl.positions[v * 3 + 1] as f64,
tmpl.origin[2] + tmpl.positions[v * 3 + 2] as f64,
1.0,
);
let gx = orig.origin[0] + orig.positions[v * 3] as f64;
let gy = orig.origin[1] + orig.positions[v * 3 + 1] as f64;
let gz = orig.origin[2] + orig.positions[v * 3 + 2] as f64;
let err = ((w.x / w.w - gx).powi(2)
+ (w.y / w.w - gy).powi(2)
+ (w.z / w.w - gz).powi(2))
.sqrt();
assert!(err < 1e-4, "expand-to-flat vertex error {err}");
}
}
}
#[test]
#[ignore]
fn dump_instanced_fixture() {
let m0 = Matrix4::new_translation(&nalgebra::Vector3::new(1.0, 0.0, 0.0));
let m1 = Matrix4::new_translation(&nalgebra::Vector3::new(0.0, 2.0, 0.0));
let m2 = Matrix4::new_translation(&nalgebra::Vector3::new(5.0, 5.0, 5.0));
let mk = |m: &Matrix4<f64>, rep: u128| {
mesh_from(
baked(&CANON, m),
InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: rep,
instanceable: true,
},
)
};
let meshes = vec![mk(&m0, 50), mk(&m1, 50), mk(&m2, 60)];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
let bytes = encode_instanced(&meshes, &collated, |i| (1000 + i) as u32, |i| {
[i as f32 * 0.1, 0.2, 0.3, 1.0]
});
let hex: String = bytes.iter().map(|b| format!("{b:02x}")).collect();
println!("INSTANCED_FIXTURE_HEX_BEGIN");
println!("{hex}");
println!("INSTANCED_FIXTURE_HEX_END");
}
#[test]
fn collate_count_guard_drops_mismatched_group_to_flat() {
let p = Matrix4::new_translation(&nalgebra::Vector3::new(1.0, 0.0, 0.0));
let meta = |rep| InstanceMeta {
transform: mat_rm(&p),
local_transform: None,
canonical_transform: None,
rep_identity: rep,
instanceable: true,
};
let canon_b: [f32; 15] = [
0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 2.0, 2.0,
];
let meshes = vec![
mesh_from(baked(&CANON, &p), meta(777)),
mesh_from(baked(&canon_b, &p), meta(777)), ];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
assert_eq!(collated.templates.len(), 0, "count mismatch must NOT form a template");
assert_eq!(collated.flat_indices.len(), 2, "both fall to flat");
}
#[test]
fn collate_reduces_georeferenced_rotated_occurrence_to_post_rtc_frame() {
let rtc = [1_000_000.0_f64, 2_000_000.0, 0.0];
let t_template = Matrix4::new_translation(&nalgebra::Vector3::new(rtc[0], rtc[1], rtc[2]));
let t_occ = t_template * Matrix4::from_euler_angles(0.0, 0.0, std::f64::consts::PI);
let mk = |m: &Matrix4<f64>| {
mesh_from(
baked(&CANON, m),
InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: 99,
instanceable: true,
},
)
};
let meshes = vec![mk(&t_template), mk(&t_occ)];
let occ_trans = |c: &Collated| -> f64 {
let occ = &c.templates[0].occurrences;
occ.iter()
.map(|o| o.transform[3].abs().max(o.transform[7].abs()).max(o.transform[11].abs()) as f64)
.fold(0.0, f64::max)
};
let raw = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
assert_eq!(raw.templates.len(), 1, "the two congruent meshes instance");
assert!(occ_trans(&raw) > 1_000_000.0, "legacy: rotated occurrence reaches ~2× rtc");
let fixed = collate_instances(&meshes, 2, rtc);
assert_eq!(fixed.templates.len(), 1, "still instances after the reduction");
assert!(occ_trans(&fixed) < 10.0, "fixed: rel translation is building-scale, got {}", occ_trans(&fixed));
}
#[test]
fn collate_and_encode_matches_mesh_path() {
let m0 = Matrix4::new_translation(&nalgebra::Vector3::new(1.0, 0.0, 0.0));
let m1 = Matrix4::new_translation(&nalgebra::Vector3::new(0.0, 2.0, 0.0));
let m2 = Matrix4::new_translation(&nalgebra::Vector3::new(5.0, 5.0, 5.0));
let mk = |m: &Matrix4<f64>, rep: u128| {
mesh_from(
baked(&CANON, m),
InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: rep,
instanceable: true,
},
)
};
let meshes = vec![mk(&m0, 50), mk(&m1, 50), mk(&m2, 60)];
let col = |i: usize| [i as f32 * 0.1, 0.2, 0.3, 1.0];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
let bytes_mesh = encode_instanced(&meshes, &collated, |i| i as u32, col);
let refs: Vec<InstanceMeshRef> = meshes
.iter()
.enumerate()
.map(|(i, m)| {
let mut r = InstanceMeshRef::from_mesh(m);
r.entity_id = i as u32;
r.color = col(i);
r
})
.collect();
let bytes_ref = collate_and_encode(&refs, 2, [0.0, 0.0, 0.0]);
assert_eq!(bytes_mesh, bytes_ref, "ref one-shot must match the Mesh path byte-for-byte");
let dec = decode_instanced(&bytes_ref).expect("decodes");
assert_eq!(dec.templates.len(), 2);
assert_eq!(dec.instances.len(), 3);
}
#[test]
fn dont_bake_empty_occurrence_refs_recompose_like_materialized() {
use std::f64::consts::FRAC_PI_4;
let placements = [
Matrix4::new_translation(&nalgebra::Vector3::new(2.0, 0.0, 0.0)),
Matrix4::from_euler_angles(0.0, 0.0, FRAC_PI_4)
* Matrix4::new_translation(&nalgebra::Vector3::new(-6.0, 4.0, 1.0)),
Matrix4::from_euler_angles(FRAC_PI_4, 0.0, 0.0)
* Matrix4::new_translation(&nalgebra::Vector3::new(30.0, -12.0, 5.0)),
];
let meta_for = |m: &Matrix4<f64>| InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: 314,
instanceable: true,
};
let materialized: Vec<Mesh> = placements
.iter()
.map(|m| mesh_from(baked(&CANON, m), meta_for(m)))
.collect();
let flat_shard = {
let refs: Vec<InstanceMeshRef> = materialized
.iter()
.enumerate()
.map(|(i, m)| {
let mut r = InstanceMeshRef::from_mesh(m);
r.entity_id = 1000 + i as u32;
r.color = [0.2, 0.4, 0.6, 1.0];
r
})
.collect();
collate_and_encode(&refs, 2, [0.0, 0.0, 0.0])
};
let template = &materialized[0];
let metas: Vec<InstanceMeta> = placements[1..].iter().map(meta_for).collect();
let mut refs_db: Vec<InstanceMeshRef> = Vec::new();
let mut tmpl_ref = InstanceMeshRef::from_mesh(template);
tmpl_ref.entity_id = 1000;
tmpl_ref.color = [0.2, 0.4, 0.6, 1.0];
refs_db.push(tmpl_ref);
for (k, meta) in metas.iter().enumerate() {
refs_db.push(InstanceMeshRef {
positions: &[],
normals: &[],
indices: &[],
origin: [0.0; 3],
instance_meta: Some(meta),
entity_id: 1000 + (k as u32 + 1),
color: [0.2, 0.4, 0.6, 1.0],
});
}
let db_shard = collate_and_encode(&refs_db, 2, [0.0, 0.0, 0.0]);
assert_eq!(
flat_shard, db_shard,
"don't-bake empty-occurrence shard must equal the fully-materialized shard byte-for-byte"
);
let dec = decode_instanced(&db_shard).expect("decodes");
assert_eq!(dec.templates.len(), 1, "one shared template");
assert_eq!(dec.instances.len(), 3, "template + two don't-bake occurrences");
for inst in &dec.instances {
let tmpl = &dec.templates[inst.template_index as usize];
let rel = Matrix4::from_row_slice(&inst.transform.map(|v| v as f64));
let orig_idx = (inst.entity_id - 1000) as usize;
let orig = &materialized[orig_idx];
let n = tmpl.positions.len() / 3;
for v in 0..n {
let w = rel
* nalgebra::Vector4::new(
tmpl.origin[0] + tmpl.positions[v * 3] as f64,
tmpl.origin[1] + tmpl.positions[v * 3 + 1] as f64,
tmpl.origin[2] + tmpl.positions[v * 3 + 2] as f64,
1.0,
);
let gx = orig.origin[0] + orig.positions[v * 3] as f64;
let gy = orig.origin[1] + orig.positions[v * 3 + 1] as f64;
let gz = orig.origin[2] + orig.positions[v * 3 + 2] as f64;
let err = ((w.x / w.w - gx).powi(2)
+ (w.y / w.w - gy).powi(2)
+ (w.z / w.w - gz).powi(2))
.sqrt();
assert!(err < 1e-4, "don't-bake recompose vertex error {err}");
}
}
}
#[test]
fn decode_rejects_bad_magic() {
assert!(decode_instanced(&[0u8; 32]).is_none());
assert!(decode_instanced(&[]).is_none());
}
fn header_bytes(
magic: u32,
version: u32,
template_count: u32,
instance_count: u32,
positions_len: u32,
normals_len: u32,
indices_len: u32,
) -> Vec<u8> {
let mut b = Vec::with_capacity(32);
for v in [
magic,
version,
template_count,
instance_count,
positions_len,
normals_len,
indices_len,
0,
] {
b.extend_from_slice(&v.to_le_bytes());
}
b
}
#[test]
fn decode_rejects_truncated_payload_with_valid_header() {
let m0 = Matrix4::new_translation(&nalgebra::Vector3::new(1.0, 0.0, 0.0));
let m1 = Matrix4::new_translation(&nalgebra::Vector3::new(0.0, 2.0, 0.0));
let mk = |m: &Matrix4<f64>, rep: u128| {
mesh_from(
baked(&CANON, m),
InstanceMeta {
transform: mat_rm(m),
local_transform: None,
canonical_transform: None,
rep_identity: rep,
instanceable: true,
},
)
};
let meshes = vec![mk(&m0, 50), mk(&m1, 50)];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
let bytes = encode_instanced(&meshes, &collated, |i| i as u32, |_| [1.0, 1.0, 1.0, 1.0]);
assert!(decode_instanced(&bytes).is_some(), "sanity: full buffer decodes");
let truncated = &bytes[..bytes.len() - 1];
assert!(
decode_instanced(truncated).is_none(),
"truncated payload (valid magic/version, short data) must decode to None, not panic"
);
let mid_table = &bytes[..40];
assert!(
decode_instanced(mid_table).is_none(),
"buffer truncated inside the template table must decode to None"
);
}
#[test]
fn decode_rejects_bogus_huge_counts_without_oom() {
let huge = u32::MAX;
let bytes = header_bytes(INSTANCED_MAGIC, INSTANCED_VERSION, huge, 0, 0, 0, 0);
assert_eq!(bytes.len(), 32);
assert!(
decode_instanced(&bytes).is_none(),
"bogus huge template_count must decode to None, not attempt a huge allocation"
);
let bytes = header_bytes(INSTANCED_MAGIC, INSTANCED_VERSION, 0, huge, 0, 0, 0);
assert!(
decode_instanced(&bytes).is_none(),
"bogus huge instance_count must decode to None, not attempt a huge allocation"
);
let bytes = header_bytes(INSTANCED_MAGIC, INSTANCED_VERSION, huge, huge, huge, huge, huge);
assert!(
decode_instanced(&bytes).is_none(),
"bogus huge counts across the board must decode to None, not attempt a huge allocation"
);
}
#[test]
fn singletons_and_non_instanceable_go_flat() {
let p = Matrix4::new_translation(&nalgebra::Vector3::new(1.0, 2.0, 3.0));
let meta = |rep, inst| InstanceMeta {
transform: mat_rm(&p),
local_transform: None,
canonical_transform: None,
rep_identity: rep,
instanceable: inst,
};
let meshes = vec![
mesh_from(baked(&CANON, &p), meta(1, true)), mesh_from(baked(&CANON, &p), meta(2, false)), ];
let collated = collate_instances(&meshes, 2, [0.0, 0.0, 0.0]);
assert_eq!(collated.templates.len(), 0);
let mut flat = collated.flat_indices.clone();
flat.sort_unstable();
assert_eq!(flat, vec![0, 1], "singleton + non-instanceable both emitted flat");
assert_eq!(collated.unique_geometry_count(), 2);
}