pub mod geometry;
pub mod element;
pub mod face_culler;
pub mod tint;
pub use geometry::{Mesh, Vertex};
pub use tint::{TintColors, TintProvider};
use crate::atlas::TextureAtlas;
use crate::error::Result;
use crate::resource_pack::ResourcePack;
use crate::types::{BlockPosition, BlockSource, BoundingBox, InputBlock};
#[derive(Debug, Clone)]
pub struct MesherConfig {
pub cull_hidden_faces: bool,
pub atlas_max_size: u32,
pub atlas_padding: u32,
pub include_air: bool,
pub tint_provider: TintProvider,
pub ambient_occlusion: bool,
pub ao_intensity: f32,
}
impl Default for MesherConfig {
fn default() -> Self {
Self {
cull_hidden_faces: true,
atlas_max_size: 4096,
atlas_padding: 1,
include_air: false,
tint_provider: TintProvider::new(),
ambient_occlusion: true,
ao_intensity: 0.4,
}
}
}
impl MesherConfig {
pub fn with_biome(mut self, biome: &str) -> Self {
self.tint_provider = TintProvider::for_biome(biome);
self
}
pub fn with_tint_colors(mut self, colors: TintColors) -> Self {
self.tint_provider = TintProvider::with_colors(colors);
self
}
}
#[derive(Debug)]
pub struct MesherOutput {
pub opaque_mesh: Mesh,
pub transparent_mesh: Mesh,
pub atlas: TextureAtlas,
pub bounds: BoundingBox,
}
impl MesherOutput {
pub fn mesh(&self) -> Mesh {
let mut combined = self.opaque_mesh.clone();
combined.merge(&self.transparent_mesh);
combined
}
pub fn has_transparency(&self) -> bool {
!self.transparent_mesh.is_empty()
}
pub fn total_vertices(&self) -> usize {
self.opaque_mesh.vertex_count() + self.transparent_mesh.vertex_count()
}
pub fn total_triangles(&self) -> usize {
self.opaque_mesh.triangle_count() + self.transparent_mesh.triangle_count()
}
}
pub struct Mesher {
resource_pack: ResourcePack,
config: MesherConfig,
}
impl Mesher {
pub fn new(resource_pack: ResourcePack) -> Self {
Self {
resource_pack,
config: MesherConfig::default(),
}
}
pub fn with_config(resource_pack: ResourcePack, config: MesherConfig) -> Self {
Self {
resource_pack,
config,
}
}
pub fn resource_pack(&self) -> &ResourcePack {
&self.resource_pack
}
pub fn config(&self) -> &MesherConfig {
&self.config
}
pub fn mesh<S: BlockSource>(&self, source: &S) -> Result<MesherOutput> {
let bounds = source.bounds();
let blocks: Vec<_> = source.iter_blocks().collect();
self.mesh_blocks_internal(blocks.into_iter(), bounds)
}
pub fn mesh_blocks<'a>(
&self,
blocks: impl Iterator<Item = (BlockPosition, &'a InputBlock)>,
bounds: BoundingBox,
) -> Result<MesherOutput> {
self.mesh_blocks_internal(blocks, bounds)
}
fn mesh_blocks_internal<'a>(
&self,
blocks: impl Iterator<Item = (BlockPosition, &'a InputBlock)>,
bounds: BoundingBox,
) -> Result<MesherOutput> {
let mut mesh_builder = element::MeshBuilder::new(&self.resource_pack, &self.config);
let blocks: Vec<_> = blocks.collect();
let culler = if self.config.cull_hidden_faces {
Some(face_culler::FaceCuller::new(&self.resource_pack, &blocks))
} else {
None
};
for (pos, block) in &blocks {
if !self.config.include_air && block.is_air() {
continue;
}
mesh_builder.add_block(*pos, block, culler.as_ref())?;
}
let (opaque_mesh, transparent_mesh, atlas) = mesh_builder.build()?;
Ok(MesherOutput {
opaque_mesh,
transparent_mesh,
atlas,
bounds,
})
}
}