gear-teeth/src/render/mesh/cpu.rs
2026-10-19 02:08:10 +03:00

99 lines
1.9 KiB
Rust

use glam::Vec3;
use super::Vertex;
#[derive(Debug, Clone)]
pub struct Mesh<T: Copy = Vertex> {
pub faces: Vec<[T; 3]>,
}
#[derive(Debug, Clone)]
pub struct MeshIndexed<T: Copy = Vertex> {
pub vertices: Vec<T>,
pub faces: Vec<[u16; 3]>,
}
pub type CpuMesh = Mesh<Vertex>;
pub type CpuMeshIndexed = MeshIndexed<Vertex>;
impl<T: Copy> Mesh<T> {
pub fn new() -> Self {
Self { faces: Vec::new() }
}
pub fn concat(meshes: impl IntoIterator<Item = Self>) -> Self {
Self {
faces: meshes
.into_iter()
.map(|mesh| mesh.faces)
.flatten()
.collect(),
}
}
pub fn into_indexed(self) -> MeshIndexed<T> {
if self.faces.len() >= (1 << 16) / 3 {
panic!("too many faces");
}
let n_faces = self.faces.len() as u16;
MeshIndexed {
vertices: self.faces.into_iter().flatten().collect(),
faces: (0..n_faces)
.map(|face| [3 * face, 3 * face + 1, 3 * face + 2])
.collect(),
}
}
}
impl Mesh<Vec3> {
pub fn to_standard_mesh(&self) -> CpuMesh {
CpuMesh {
faces: self
.faces
.iter()
.map(|face| {
let [a, b, c] = face;
let normal = (b - a).cross(c - a).normalize();
face.map(|position| Vertex { position, normal })
})
.collect(),
}
}
}
impl<T: Copy> MeshIndexed<T> {
pub fn new() -> Self {
Self {
vertices: Vec::new(),
faces: Vec::new(),
}
}
pub fn concat(meshes: impl IntoIterator<Item = Self>) -> Self {
let mut ret = Self::new();
for mesh in meshes {
let base = ret.vertices.len() as u16;
ret.vertices.extend(mesh.vertices);
if ret.vertices.len() > 1 << 16 {
panic!("too many vertices");
}
ret.faces.extend(
mesh.faces
.into_iter()
.map(|face| face.map(|index| base + index)),
);
}
ret
}
pub fn to_mesh(&self) -> Mesh<T> {
Mesh {
faces: self
.faces
.iter()
.map(|face| face.map(|index| self.vertices[index as usize]))
.collect(),
}
}
}