use crate::{
core::hash_as_bytes,
core::{algebra::Vector3, math::TriangleDefinition},
};
use bytemuck::{Pod, Zeroable};
use fxhash::{FxBuildHasher, FxHashSet};
use std::hash::{Hash, Hasher};
#[derive(Copy, Clone)]
struct IndexedStorage<T> {
index: u32,
vertex: T,
}
#[repr(C)]
#[derive(Copy, Clone, Pod, Zeroable)]
pub struct RawVertex {
pub x: f32,
pub y: f32,
pub z: f32,
}
impl PartialEq for RawVertex {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y && self.z == other.z
}
}
impl From<Vector3<f32>> for RawVertex {
fn from(v: Vector3<f32>) -> Self {
Self {
x: v.x,
y: v.y,
z: v.z,
}
}
}
impl RawVertex {
fn validate(&self) {
debug_assert!(!self.x.is_nan());
debug_assert!(!self.y.is_nan());
debug_assert!(!self.z.is_nan());
}
}
impl Hash for RawVertex {
fn hash<H: Hasher>(&self, state: &mut H) {
self.validate();
hash_as_bytes(self, state);
}
}
impl<T> PartialEq for IndexedStorage<T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.vertex == other.vertex
}
}
impl<T> Eq for IndexedStorage<T> where T: PartialEq {}
impl<T> Hash for IndexedStorage<T>
where
T: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
self.vertex.hash(state)
}
}
impl<T> Default for RawMeshBuilder<T>
where
T: Hash + PartialEq,
{
fn default() -> Self {
Self {
vertices: Default::default(),
indices: Default::default(),
}
}
}
#[derive(Clone)]
pub struct RawMeshBuilder<T>
where
T: Hash + PartialEq,
{
vertices: FxHashSet<IndexedStorage<T>>,
indices: Vec<u32>,
}
#[derive(Default, Debug, Clone)]
pub struct RawMesh<T> {
pub vertices: Vec<T>,
pub triangles: Vec<TriangleDefinition>,
}
impl<T> RawMeshBuilder<T>
where
T: Hash + PartialEq,
{
pub fn new(vertices: usize, indices: usize) -> Self {
Self {
vertices: FxHashSet::with_capacity_and_hasher(vertices, FxBuildHasher::default()),
indices: Vec::with_capacity(indices),
}
}
pub fn insert(&mut self, vertex: T) -> bool {
let mut wrapper = IndexedStorage::<T> { index: 0, vertex };
if let Some(existing) = self.vertices.get(&wrapper) {
self.indices.push(existing.index);
false
} else {
wrapper.index = self.vertices.len() as u32;
self.indices.push(wrapper.index);
self.vertices.insert(wrapper);
true
}
}
pub fn vertex_count(&self) -> usize {
self.vertices.len()
}
pub fn build(self) -> RawMesh<T> {
let mut vertices = self.vertices.into_iter().collect::<Vec<_>>();
vertices.sort_unstable_by_key(|w| w.index);
RawMesh {
vertices: vertices.into_iter().map(|w| w.vertex).collect(),
triangles: self
.indices
.chunks_exact(3)
.map(|i| TriangleDefinition([i[0], i[1], i[2]]))
.collect(),
}
}
}