makepad/libs/remesh/tests/common/mod.rs
Admin fbe877d746 Land glTF writers, remesh, PBR paint, and xatlas from rik2.
Animation/skin writers, COLOR_0, and the mesh tools the renderer uses.
2026-08-18 14:23:58 +02:00

149 lines
4.5 KiB
Rust

//! Reader for the FCDUMP1 fixture/dump format written by
//! local/faithc_ref/convert_dumps.py (std-only, little endian).
//!
//! Shared between several test binaries; each uses a subset of the API.
#![allow(dead_code)]
use std::collections::HashMap;
use std::io::Read;
use std::path::PathBuf;
#[derive(Clone)]
pub enum Arr {
F32(Vec<f32>),
I64(Vec<i64>),
I8(Vec<i8>),
F64(Vec<f64>),
}
pub struct FcDump {
pub arrays: HashMap<String, (Vec<usize>, Arr)>,
}
impl FcDump {
pub fn load(path: &std::path::Path) -> std::io::Result<FcDump> {
let mut f = std::fs::File::open(path)?;
let mut data = Vec::new();
f.read_to_end(&mut data)?;
let mut p = 0usize;
assert_eq!(&data[0..8], b"FCDUMP1\x00");
p += 8;
let rd_u32 = |p: &mut usize| {
let v = u32::from_le_bytes(data[*p..*p + 4].try_into().unwrap());
*p += 4;
v
};
let rd_u64 = |p: &mut usize| {
let v = u64::from_le_bytes(data[*p..*p + 8].try_into().unwrap());
*p += 8;
v
};
let count = rd_u32(&mut p);
let mut arrays = HashMap::new();
for _ in 0..count {
let name_len = rd_u32(&mut p) as usize;
let name = String::from_utf8(data[p..p + name_len].to_vec()).unwrap();
p += name_len;
let dtype = data[p];
p += 1;
let ndim = rd_u32(&mut p) as usize;
let mut dims = Vec::with_capacity(ndim);
for _ in 0..ndim {
dims.push(rd_u64(&mut p) as usize);
}
let byte_len = rd_u64(&mut p) as usize;
let raw = &data[p..p + byte_len];
p += byte_len;
let arr = match dtype {
0 => Arr::F32(
raw.chunks_exact(4)
.map(|c| f32::from_le_bytes(c.try_into().unwrap()))
.collect(),
),
1 => Arr::I64(
raw.chunks_exact(8)
.map(|c| i64::from_le_bytes(c.try_into().unwrap()))
.collect(),
),
2 => Arr::I8(raw.iter().map(|&b| b as i8).collect()),
3 => Arr::F64(
raw.chunks_exact(8)
.map(|c| f64::from_le_bytes(c.try_into().unwrap()))
.collect(),
),
_ => panic!("bad dtype {dtype}"),
};
arrays.insert(name, (dims, arr));
}
Ok(FcDump { arrays })
}
pub fn f32(&self, name: &str) -> (&[usize], &[f32]) {
match &self.arrays[name] {
(d, Arr::F32(v)) => (d, v),
_ => panic!("{name}: not f32"),
}
}
pub fn i64(&self, name: &str) -> (&[usize], &[i64]) {
match &self.arrays[name] {
(d, Arr::I64(v)) => (d, v),
_ => panic!("{name}: not i64"),
}
}
pub fn i8(&self, name: &str) -> (&[usize], &[i8]) {
match &self.arrays[name] {
(d, Arr::I8(v)) => (d, v),
_ => panic!("{name}: not i8"),
}
}
pub fn v3s(&self, name: &str) -> Vec<[f32; 3]> {
let (dims, v) = self.f32(name);
assert_eq!(*dims.last().unwrap(), 3);
v.chunks_exact(3).map(|c| [c[0], c[1], c[2]]).collect()
}
pub fn tris(&self, name: &str) -> Vec<[[f32; 3]; 3]> {
let (dims, v) = self.f32(name);
assert_eq!(&dims[1..], &[3, 3]);
v.chunks_exact(9)
.map(|c| {
[
[c[0], c[1], c[2]],
[c[3], c[4], c[5]],
[c[6], c[7], c[8]],
]
})
.collect()
}
}
/// local/faithc_ref relative to the workspace root.
pub fn faithc_ref_dir() -> Option<PathBuf> {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../..")
.canonicalize()
.ok()?;
let dir = root.join("local/faithc_ref");
if dir.is_dir() {
Some(dir)
} else {
None
}
}
/// Mesh (positions + faces) from a dump -> triangle soup.
pub fn dump_tri_soup(dump: &FcDump) -> Vec<[[f32; 3]; 3]> {
let verts = dump.v3s("mesh_vertices");
let (_, faces) = dump.i64("mesh_faces");
faces
.chunks_exact(3)
.map(|f| {
[
verts[f[0] as usize],
verts[f[1] as usize],
verts[f[2] as usize],
]
})
.collect()
}