#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vertex {
pub position: [f32; 3],
pub normal: [f32; 3],
pub uv: [f32; 2],
pub color: [f32; 4],
}
impl Vertex {
pub fn new(position: [f32; 3], normal: [f32; 3], uv: [f32; 2]) -> Self {
Self {
position,
normal,
uv,
color: [1.0, 1.0, 1.0, 1.0], }
}
pub fn with_color(mut self, color: [f32; 4]) -> Self {
self.color = color;
self
}
}
impl Default for Vertex {
fn default() -> Self {
Self {
position: [0.0, 0.0, 0.0],
normal: [0.0, 1.0, 0.0],
uv: [0.0, 0.0],
color: [1.0, 1.0, 1.0, 1.0],
}
}
}
#[derive(Debug, Clone, Default)]
pub struct Mesh {
pub vertices: Vec<Vertex>,
pub indices: Vec<u32>,
}
impl Mesh {
pub fn new() -> Self {
Self::default()
}
pub fn add_vertex(&mut self, vertex: Vertex) -> u32 {
let index = self.vertices.len() as u32;
self.vertices.push(vertex);
index
}
pub fn add_triangle(&mut self, i0: u32, i1: u32, i2: u32) {
self.indices.push(i0);
self.indices.push(i1);
self.indices.push(i2);
}
pub fn add_quad(&mut self, i0: u32, i1: u32, i2: u32, i3: u32) {
self.add_triangle(i0, i2, i1);
self.add_triangle(i0, i3, i2);
}
pub fn add_quad_ao(&mut self, i0: u32, i1: u32, i2: u32, i3: u32, ao: [u8; 4]) {
if ao[0] as u16 + ao[2] as u16 > ao[1] as u16 + ao[3] as u16 {
self.add_triangle(i1, i0, i3);
self.add_triangle(i1, i3, i2);
} else {
self.add_triangle(i0, i2, i1);
self.add_triangle(i0, i3, i2);
}
}
pub fn triangle_count(&self) -> usize {
self.indices.len() / 3
}
pub fn vertex_count(&self) -> usize {
self.vertices.len()
}
pub fn is_empty(&self) -> bool {
self.vertices.is_empty()
}
pub fn merge(&mut self, other: &Mesh) {
let offset = self.vertices.len() as u32;
self.vertices.extend_from_slice(&other.vertices);
for index in &other.indices {
self.indices.push(index + offset);
}
}
pub fn translate(&mut self, offset: [f32; 3]) {
for vertex in &mut self.vertices {
vertex.position[0] += offset[0];
vertex.position[1] += offset[1];
vertex.position[2] += offset[2];
}
}
pub fn positions_flat(&self) -> Vec<f32> {
self.vertices
.iter()
.flat_map(|v| v.position)
.collect()
}
pub fn normals_flat(&self) -> Vec<f32> {
self.vertices
.iter()
.flat_map(|v| v.normal)
.collect()
}
pub fn uvs_flat(&self) -> Vec<f32> {
self.vertices
.iter()
.flat_map(|v| v.uv)
.collect()
}
pub fn colors_flat(&self) -> Vec<f32> {
self.vertices
.iter()
.flat_map(|v| v.color)
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mesh_creation() {
let mut mesh = Mesh::new();
assert!(mesh.is_empty());
let v0 = mesh.add_vertex(Vertex::new([0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0]));
let v1 = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 0.0]));
let v2 = mesh.add_vertex(Vertex::new([1.0, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 1.0]));
mesh.add_triangle(v0, v1, v2);
assert_eq!(mesh.vertex_count(), 3);
assert_eq!(mesh.triangle_count(), 1);
}
#[test]
fn test_mesh_quad() {
let mut mesh = Mesh::new();
let v0 = mesh.add_vertex(Vertex::new([0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0]));
let v1 = mesh.add_vertex(Vertex::new([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 0.0]));
let v2 = mesh.add_vertex(Vertex::new([1.0, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 1.0]));
let v3 = mesh.add_vertex(Vertex::new([0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [0.0, 1.0]));
mesh.add_quad(v0, v1, v2, v3);
assert_eq!(mesh.vertex_count(), 4);
assert_eq!(mesh.triangle_count(), 2);
assert_eq!(mesh.indices, vec![0, 2, 1, 0, 3, 2]);
}
#[test]
fn test_mesh_merge() {
let mut mesh1 = Mesh::new();
let v0 = mesh1.add_vertex(Vertex::new([0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0]));
let v1 = mesh1.add_vertex(Vertex::new([1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 0.0]));
let v2 = mesh1.add_vertex(Vertex::new([0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [0.0, 1.0]));
mesh1.add_triangle(v0, v1, v2);
let mut mesh2 = Mesh::new();
let v0 = mesh2.add_vertex(Vertex::new([2.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0]));
let v1 = mesh2.add_vertex(Vertex::new([3.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 0.0]));
let v2 = mesh2.add_vertex(Vertex::new([2.0, 0.0, 1.0], [0.0, 1.0, 0.0], [0.0, 1.0]));
mesh2.add_triangle(v0, v1, v2);
mesh1.merge(&mesh2);
assert_eq!(mesh1.vertex_count(), 6);
assert_eq!(mesh1.triangle_count(), 2);
assert_eq!(mesh1.indices, vec![0, 1, 2, 3, 4, 5]);
}
}