pub(crate) mod column_builder;
pub mod face;
pub(crate) mod heightmap_builder;
pub(crate) mod plane_builder;
#[cfg(test)]
mod tests;
mod uv_mapping;
pub use column_builder::ColumnMeshBuilder;
pub use heightmap_builder::HeightMapMeshBuilder;
pub use plane_builder::PlaneMeshBuilder;
pub use uv_mapping::{Rect, UVOptions};
use glam::{Quat, Vec2, Vec3};
use crate::{Hex, HexLayout};
pub(crate) const BASE_FACING: Vec3 = Vec3::Y;
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct InsetOptions {
pub keep_inner_face: bool,
pub scale: f32,
pub mode: InsetScaleMode,
}
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub enum InsetScaleMode {
#[default]
Centroid,
SmallestEdge,
}
#[derive(Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct FaceOptions {
pub uv: UVOptions,
pub insetting: Option<InsetOptions>,
}
impl FaceOptions {
#[inline]
#[must_use]
pub const fn new() -> Self {
Self {
uv: UVOptions::new(),
insetting: None,
}
}
}
#[derive(Debug, Clone, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct MeshInfo {
pub vertices: Vec<Vec3>,
pub normals: Vec<Vec3>,
pub uvs: Vec<Vec2>,
pub indices: Vec<u16>,
}
impl MeshInfo {
#[inline]
#[must_use]
pub fn rotated(mut self, rotation: Quat) -> Self {
self.vertices
.iter_mut()
.for_each(|v| *v = rotation.mul_vec3(*v));
self.normals
.iter_mut()
.for_each(|n| *n = rotation.mul_vec3(*n));
self
}
#[inline]
#[must_use]
pub fn with_offset(mut self, offset: Vec3) -> Self {
self.vertices.iter_mut().for_each(|v| *v += offset);
self
}
#[inline]
#[must_use]
pub fn with_scale(mut self, scale: Vec3) -> Self {
self.vertices.iter_mut().for_each(|p| *p *= scale);
self
}
#[inline]
#[must_use]
pub fn with_uv_scale(mut self, scale: Vec2) -> Self {
self.uvs.iter_mut().for_each(|c| *c *= scale);
self
}
#[inline]
#[must_use]
#[expect(clippy::cast_precision_loss)]
pub fn centroid(&self) -> Vec3 {
let len = self.vertices.len() as f32;
self.vertices.iter().sum::<Vec3>() / len
}
#[inline]
#[must_use]
#[expect(clippy::cast_precision_loss)]
pub fn uv_centroid(&self) -> Vec2 {
let len = self.uvs.len() as f32;
self.uvs.iter().sum::<Vec2>() / len
}
pub fn merge_with(&mut self, rhs: Self) {
let indices_offset =
u16::try_from(self.vertices.len()).expect("MeshInfo has too many vertices");
self.vertices.extend(rhs.vertices);
self.normals.extend(rhs.normals);
self.uvs.extend(rhs.uvs);
self.indices
.extend(rhs.indices.into_iter().map(|i| i + indices_offset));
}
#[must_use]
pub fn cheap_hexagonal_column(layout: &HexLayout, hex: Hex, column_height: f32) -> Self {
let center = layout.hex_to_world_pos(hex);
let center_top = Vec3::new(center.x, column_height, center.y);
let corners = layout.hex_corners(hex);
let uvs = corners.map(UVOptions::wrap_uv);
let (top_corners, bot_corners) = (
corners.map(|p| Vec3::new(p.x, column_height, p.y)),
corners.map(|p| Vec3::new(p.x, 0., p.y)),
);
let quad_normals = [
(top_corners[0] - center_top),
(top_corners[1] - center_top),
(top_corners[2] - center_top),
(top_corners[3] - center_top),
(top_corners[4] - center_top),
(top_corners[5] - center_top),
];
let vertices = vec![
top_corners[0], top_corners[1], top_corners[2], top_corners[3], top_corners[4], top_corners[5], bot_corners[0], bot_corners[1], bot_corners[2], bot_corners[3], bot_corners[4], bot_corners[5], ];
let indices = vec![
0, 2, 1, 3, 5, 4, 0, 5, 3, 3, 2, 0, 0, 1, 7, 7, 6, 0, 1, 2, 8, 8, 7, 1, 2, 3, 9, 9, 8, 2, 3, 4, 10, 10, 9, 3, 4, 5, 11, 11, 10, 4, 5, 0, 6, 6, 11, 5, ];
Self {
vertices,
normals: vec![
quad_normals[0],
quad_normals[1],
quad_normals[2],
quad_normals[3],
quad_normals[4],
quad_normals[5],
quad_normals[0],
quad_normals[1],
quad_normals[2],
quad_normals[3],
quad_normals[4],
quad_normals[5],
],
uvs: [
uvs[0], uvs[1], uvs[2], uvs[3], uvs[4], uvs[5], uvs[0], uvs[1], uvs[2], uvs[3],
uvs[4], uvs[5],
]
.to_vec(),
indices,
}
}
}