schematic_mesher/mesher/
mod.rs1pub mod geometry;
6pub mod element;
7pub mod face_culler;
8pub mod tint;
9
10pub use geometry::{Mesh, Vertex};
11pub use tint::{TintColors, TintProvider};
12
13use crate::atlas::TextureAtlas;
14use crate::error::Result;
15use crate::resource_pack::ResourcePack;
16use crate::types::{BlockPosition, BlockSource, BoundingBox, InputBlock};
17
18#[derive(Debug, Clone)]
20pub struct MesherConfig {
21 pub cull_hidden_faces: bool,
23 pub atlas_max_size: u32,
25 pub atlas_padding: u32,
27 pub include_air: bool,
29 pub tint_provider: TintProvider,
31 pub ambient_occlusion: bool,
33 pub ao_intensity: f32,
35}
36
37impl Default for MesherConfig {
38 fn default() -> Self {
39 Self {
40 cull_hidden_faces: true,
41 atlas_max_size: 4096,
42 atlas_padding: 1,
43 include_air: false,
44 tint_provider: TintProvider::new(),
45 ambient_occlusion: true,
46 ao_intensity: 0.4,
47 }
48 }
49}
50
51impl MesherConfig {
52 pub fn with_biome(mut self, biome: &str) -> Self {
54 self.tint_provider = TintProvider::for_biome(biome);
55 self
56 }
57
58 pub fn with_tint_colors(mut self, colors: TintColors) -> Self {
60 self.tint_provider = TintProvider::with_colors(colors);
61 self
62 }
63}
64
65#[derive(Debug)]
67pub struct MesherOutput {
68 pub opaque_mesh: Mesh,
70 pub transparent_mesh: Mesh,
72 pub atlas: TextureAtlas,
74 pub bounds: BoundingBox,
76}
77
78impl MesherOutput {
79 pub fn mesh(&self) -> Mesh {
82 let mut combined = self.opaque_mesh.clone();
83 combined.merge(&self.transparent_mesh);
84 combined
85 }
86
87 pub fn has_transparency(&self) -> bool {
89 !self.transparent_mesh.is_empty()
90 }
91
92 pub fn total_vertices(&self) -> usize {
94 self.opaque_mesh.vertex_count() + self.transparent_mesh.vertex_count()
95 }
96
97 pub fn total_triangles(&self) -> usize {
99 self.opaque_mesh.triangle_count() + self.transparent_mesh.triangle_count()
100 }
101}
102
103pub struct Mesher {
105 resource_pack: ResourcePack,
106 config: MesherConfig,
107}
108
109impl Mesher {
110 pub fn new(resource_pack: ResourcePack) -> Self {
112 Self {
113 resource_pack,
114 config: MesherConfig::default(),
115 }
116 }
117
118 pub fn with_config(resource_pack: ResourcePack, config: MesherConfig) -> Self {
120 Self {
121 resource_pack,
122 config,
123 }
124 }
125
126 pub fn resource_pack(&self) -> &ResourcePack {
128 &self.resource_pack
129 }
130
131 pub fn config(&self) -> &MesherConfig {
133 &self.config
134 }
135
136 pub fn mesh<S: BlockSource>(&self, source: &S) -> Result<MesherOutput> {
138 let bounds = source.bounds();
139 let blocks: Vec<_> = source.iter_blocks().collect();
140
141 self.mesh_blocks_internal(blocks.into_iter(), bounds)
142 }
143
144 pub fn mesh_blocks<'a>(
146 &self,
147 blocks: impl Iterator<Item = (BlockPosition, &'a InputBlock)>,
148 bounds: BoundingBox,
149 ) -> Result<MesherOutput> {
150 self.mesh_blocks_internal(blocks, bounds)
151 }
152
153 fn mesh_blocks_internal<'a>(
154 &self,
155 blocks: impl Iterator<Item = (BlockPosition, &'a InputBlock)>,
156 bounds: BoundingBox,
157 ) -> Result<MesherOutput> {
158 let mut mesh_builder = element::MeshBuilder::new(&self.resource_pack, &self.config);
159
160 let blocks: Vec<_> = blocks.collect();
162
163 let culler = if self.config.cull_hidden_faces {
166 Some(face_culler::FaceCuller::new(&self.resource_pack, &blocks))
167 } else {
168 None
169 };
170
171 for (pos, block) in &blocks {
173 if !self.config.include_air && block.is_air() {
174 continue;
175 }
176
177 mesh_builder.add_block(*pos, block, culler.as_ref())?;
178 }
179
180 let (opaque_mesh, transparent_mesh, atlas) = mesh_builder.build()?;
182
183 Ok(MesherOutput {
184 opaque_mesh,
185 transparent_mesh,
186 atlas,
187 bounds,
188 })
189 }
190}