pub mod branch;
pub mod rings;
pub mod smoothing;
pub mod trunk;
use bevy::asset::RenderAssetUsages;
use bevy::math::{Vec2, Vec3, Vec4};
use bevy::mesh::{Indices, Mesh, PrimitiveTopology};
#[derive(Clone, Debug, Default, PartialEq)]
pub struct MeshData {
pub positions: Vec<Vec3>,
pub normals: Vec<Vec3>,
pub uvs: Vec<Vec2>,
pub colors: Vec<Vec4>,
pub indices: Vec<u32>,
}
impl MeshData {
pub fn extend(&mut self, other: &MeshData) {
let offset = self.positions.len() as u32;
if !self.colors.is_empty() || !other.colors.is_empty() {
self.colors.resize(offset as usize, Vec4::ONE);
if other.colors.is_empty() {
self.colors
.resize(offset as usize + other.positions.len(), Vec4::ONE);
} else {
self.colors.extend_from_slice(&other.colors);
}
}
self.positions.extend_from_slice(&other.positions);
self.normals.extend_from_slice(&other.normals);
self.uvs.extend_from_slice(&other.uvs);
self.indices.extend(other.indices.iter().map(|i| i + offset));
}
pub fn is_empty(&self) -> bool {
self.indices.is_empty()
}
pub fn into_bevy_mesh(self) -> Mesh {
let positions: Vec<[f32; 3]> = self.positions.iter().map(Vec3::to_array).collect();
let normals: Vec<[f32; 3]> = self.normals.iter().map(Vec3::to_array).collect();
let uvs: Vec<[f32; 2]> = self.uvs.iter().map(Vec2::to_array).collect();
let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
)
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions)
.with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_attribute(Mesh::ATTRIBUTE_UV_0, uvs)
.with_inserted_indices(Indices::U32(self.indices));
if !self.colors.is_empty() {
let colors: Vec<[f32; 4]> = self.colors.iter().map(Vec4::to_array).collect();
mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, colors);
}
mesh
}
}
#[cfg(test)]
mod tests {
use super::*;
fn triangle(color: Option<Vec4>) -> MeshData {
MeshData {
positions: vec![Vec3::ZERO, Vec3::X, Vec3::Y],
normals: vec![Vec3::Z; 3],
uvs: vec![Vec2::ZERO; 3],
colors: color.map_or_else(Vec::new, |c| vec![c; 3]),
indices: vec![0, 1, 2],
}
}
#[test]
fn extend_keeps_colors_aligned_with_positions() {
let red = Vec4::new(1.0, 0.0, 0.0, 1.0);
for (first, second) in [(None, Some(red)), (Some(red), None), (Some(red), Some(red)), (None, None)] {
let mut mesh = triangle(first);
mesh.extend(&triangle(second));
let expected = if first.is_some() || second.is_some() { 6 } else { 0 };
assert_eq!(mesh.colors.len(), expected, "{first:?} + {second:?}");
if expected > 0 {
assert_eq!(mesh.colors[0], first.unwrap_or(Vec4::ONE));
assert_eq!(mesh.colors[3], second.unwrap_or(Vec4::ONE));
}
}
}
}