1use crate::atlas::{AtlasBuilder, TextureAtlas};
4use crate::error::{MesherError, Result};
5use crate::mesher::face_culler::FaceCuller;
6use crate::mesher::geometry::{Mesh, Vertex};
7use crate::mesher::MesherConfig;
8use crate::resolver::{resolve_block, ModelResolver, ResolvedModel};
9use crate::resource_pack::{BlockModel, ModelElement, ModelFace, ResourcePack};
10use crate::types::{BlockPosition, BlockTransform, Direction, InputBlock};
11use glam::{Mat3, Vec3};
12use std::collections::HashSet;
13
14struct FaceTextureMapping {
16 vertex_start: u32,
18 texture_path: String,
20 is_transparent: bool,
22}
23
24pub struct MeshBuilder<'a> {
26 resource_pack: &'a ResourcePack,
27 config: &'a MesherConfig,
28 mesh: Mesh,
29 texture_refs: HashSet<String>,
30 model_resolver: ModelResolver<'a>,
31 face_textures: Vec<FaceTextureMapping>,
33}
34
35impl<'a> MeshBuilder<'a> {
36 pub fn new(resource_pack: &'a ResourcePack, config: &'a MesherConfig) -> Self {
37 Self {
38 resource_pack,
39 config,
40 mesh: Mesh::new(),
41 texture_refs: HashSet::new(),
42 model_resolver: ModelResolver::new(resource_pack),
43 face_textures: Vec::new(),
44 }
45 }
46
47 pub fn add_block(
49 &mut self,
50 pos: BlockPosition,
51 block: &InputBlock,
52 culler: Option<&FaceCuller>,
53 ) -> Result<()> {
54 let resolved_models = match resolve_block(self.resource_pack, block) {
56 Ok(models) => models,
57 Err(e) => {
58 eprintln!("Warning: Failed to resolve block {}: {}", block.name, e);
60 return Ok(());
61 }
62 };
63
64 for resolved in resolved_models {
66 self.add_model(pos, block, &resolved, culler)?;
67 }
68
69 Ok(())
70 }
71
72 fn add_model(
74 &mut self,
75 pos: BlockPosition,
76 block: &InputBlock,
77 resolved: &ResolvedModel,
78 culler: Option<&FaceCuller>,
79 ) -> Result<()> {
80 let model = &resolved.model;
81 let transform = &resolved.transform;
82
83 let resolved_textures = self.model_resolver.resolve_textures(model);
85
86 for element in &model.elements {
88 self.add_element(pos, block, element, transform, &resolved_textures, culler)?;
89 }
90
91 Ok(())
92 }
93
94 fn add_element(
96 &mut self,
97 pos: BlockPosition,
98 block: &InputBlock,
99 element: &ModelElement,
100 transform: &BlockTransform,
101 resolved_textures: &std::collections::HashMap<String, String>,
102 culler: Option<&FaceCuller>,
103 ) -> Result<()> {
104 for (direction, face) in &element.faces {
106 let world_direction = direction.rotate_by_transform(transform.x, transform.y);
108
109 if let Some(cullface) = &face.cullface {
111 if let Some(culler) = culler {
112 let world_cullface = cullface.rotate_by_transform(transform.x, transform.y);
114 if culler.should_cull(pos, world_cullface) {
115 continue;
116 }
117 }
118 }
119
120 let texture_path = self.resolve_face_texture(&face.texture, resolved_textures);
122 self.texture_refs.insert(texture_path.clone());
123
124 let is_transparent = self.resource_pack
126 .get_texture(&texture_path)
127 .map(|t| t.has_transparency())
128 .unwrap_or(false);
129
130 let vertex_start = self.mesh.vertex_count() as u32;
132 self.face_textures.push(FaceTextureMapping {
133 vertex_start,
134 texture_path,
135 is_transparent,
136 });
137
138 let ao_values = if self.config.ambient_occlusion {
140 culler.map(|c| c.calculate_ao(pos, world_direction))
141 } else {
142 None
143 };
144
145 self.add_face(pos, block, element, *direction, face, transform, ao_values)?;
147 }
148
149 Ok(())
150 }
151
152 fn resolve_face_texture(
154 &self,
155 reference: &str,
156 resolved_textures: &std::collections::HashMap<String, String>,
157 ) -> String {
158 if reference.starts_with('#') {
159 let key = &reference[1..];
160 resolved_textures
161 .get(key)
162 .cloned()
163 .unwrap_or_else(|| "block/missing".to_string())
164 } else {
165 reference.to_string()
166 }
167 }
168
169 fn add_face(
171 &mut self,
172 pos: BlockPosition,
173 block: &InputBlock,
174 element: &ModelElement,
175 direction: Direction,
176 face: &ModelFace,
177 transform: &BlockTransform,
178 ao_values: Option<[u8; 4]>,
179 ) -> Result<()> {
180 let normal = direction.normal();
181 let uv = face.normalized_uv();
182
183 let from = element.normalized_from();
185 let to = element.normalized_to();
186
187 let (positions, uvs) = self.generate_face_vertices(direction, from, to, uv, face.rotation);
189
190 let positions = if let Some(rot) = &element.rotation {
192 self.apply_element_rotation(&positions, rot)
193 } else {
194 positions
195 };
196
197 let positions = self.apply_block_transform(&positions, transform);
199 let normal = self.rotate_normal(normal, transform);
200
201 let offset = [pos.x as f32, pos.y as f32, pos.z as f32];
203
204 let base_color = self.config.tint_provider.get_tint(block, face.tintindex);
206
207 let colors = if let Some(ao) = ao_values {
209 let intensity = self.config.ao_intensity;
210 [
211 self.apply_ao_to_color(base_color, ao[0], intensity),
212 self.apply_ao_to_color(base_color, ao[1], intensity),
213 self.apply_ao_to_color(base_color, ao[2], intensity),
214 self.apply_ao_to_color(base_color, ao[3], intensity),
215 ]
216 } else {
217 [base_color; 4]
218 };
219
220 let v0 = self.mesh.add_vertex(
221 Vertex::new(
222 [
223 positions[0][0] + offset[0],
224 positions[0][1] + offset[1],
225 positions[0][2] + offset[2],
226 ],
227 normal,
228 uvs[0],
229 )
230 .with_color(colors[0]),
231 );
232 let v1 = self.mesh.add_vertex(
233 Vertex::new(
234 [
235 positions[1][0] + offset[0],
236 positions[1][1] + offset[1],
237 positions[1][2] + offset[2],
238 ],
239 normal,
240 uvs[1],
241 )
242 .with_color(colors[1]),
243 );
244 let v2 = self.mesh.add_vertex(
245 Vertex::new(
246 [
247 positions[2][0] + offset[0],
248 positions[2][1] + offset[1],
249 positions[2][2] + offset[2],
250 ],
251 normal,
252 uvs[2],
253 )
254 .with_color(colors[2]),
255 );
256 let v3 = self.mesh.add_vertex(
257 Vertex::new(
258 [
259 positions[3][0] + offset[0],
260 positions[3][1] + offset[1],
261 positions[3][2] + offset[2],
262 ],
263 normal,
264 uvs[3],
265 )
266 .with_color(colors[3]),
267 );
268
269 if let Some(ao) = ao_values {
271 self.mesh.add_quad_ao(v0, v1, v2, v3, ao);
272 } else {
273 self.mesh.add_quad(v0, v1, v2, v3);
274 }
275
276 Ok(())
277 }
278
279 fn apply_ao_to_color(&self, color: [f32; 4], ao_level: u8, intensity: f32) -> [f32; 4] {
283 let brightness = 1.0 - intensity * (1.0 - ao_level as f32 / 3.0);
287 [
288 color[0] * brightness,
289 color[1] * brightness,
290 color[2] * brightness,
291 color[3], ]
293 }
294
295 fn generate_face_vertices(
298 &self,
299 direction: Direction,
300 from: [f32; 3],
301 to: [f32; 3],
302 uv: [f32; 4],
303 rotation: i32,
304 ) -> ([[f32; 3]; 4], [[f32; 2]; 4]) {
305 let (u1, v1, u2, v2) = (uv[0], uv[1], uv[2], uv[3]);
306
307 let base_uvs = [[u1, v1], [u2, v1], [u2, v2], [u1, v2]];
311
312 let uvs = self.rotate_uvs(base_uvs, rotation);
314
315 let positions = match direction {
317 Direction::Down => [
318 [from[0], from[1], to[2]],
319 [to[0], from[1], to[2]],
320 [to[0], from[1], from[2]],
321 [from[0], from[1], from[2]],
322 ],
323 Direction::Up => [
324 [from[0], to[1], from[2]],
325 [to[0], to[1], from[2]],
326 [to[0], to[1], to[2]],
327 [from[0], to[1], to[2]],
328 ],
329 Direction::North => [
330 [to[0], to[1], from[2]],
331 [from[0], to[1], from[2]],
332 [from[0], from[1], from[2]],
333 [to[0], from[1], from[2]],
334 ],
335 Direction::South => [
336 [from[0], to[1], to[2]],
337 [to[0], to[1], to[2]],
338 [to[0], from[1], to[2]],
339 [from[0], from[1], to[2]],
340 ],
341 Direction::West => [
342 [from[0], to[1], from[2]],
343 [from[0], to[1], to[2]],
344 [from[0], from[1], to[2]],
345 [from[0], from[1], from[2]],
346 ],
347 Direction::East => [
348 [to[0], to[1], to[2]],
349 [to[0], to[1], from[2]],
350 [to[0], from[1], from[2]],
351 [to[0], from[1], to[2]],
352 ],
353 };
354
355 (positions, uvs)
356 }
357
358 fn rotate_uvs(&self, uvs: [[f32; 2]; 4], rotation: i32) -> [[f32; 2]; 4] {
360 let steps = ((rotation / 90) % 4 + 4) % 4;
361 let mut result = uvs;
362 for _ in 0..steps {
363 result = [result[3], result[0], result[1], result[2]];
364 }
365 result
366 }
367
368 fn apply_element_rotation(
370 &self,
371 positions: &[[f32; 3]; 4],
372 rotation: &crate::types::ElementRotation,
373 ) -> [[f32; 3]; 4] {
374 let origin = rotation.normalized_origin();
375 let angle = rotation.angle_radians();
376 let rescale = rotation.rescale_factor();
377
378 let rotation_matrix = match rotation.axis {
379 crate::types::Axis::X => Mat3::from_rotation_x(angle),
380 crate::types::Axis::Y => Mat3::from_rotation_y(angle),
381 crate::types::Axis::Z => Mat3::from_rotation_z(angle),
382 };
383
384 let mut result = [[0.0; 3]; 4];
385 for (i, pos) in positions.iter().enumerate() {
386 let p = Vec3::new(pos[0] - origin[0], pos[1] - origin[1], pos[2] - origin[2]);
388
389 let rotated = rotation_matrix * p;
391
392 let scaled = if rescale != 1.0 {
394 match rotation.axis {
395 crate::types::Axis::X => {
396 Vec3::new(rotated.x, rotated.y * rescale, rotated.z * rescale)
397 }
398 crate::types::Axis::Y => {
399 Vec3::new(rotated.x * rescale, rotated.y, rotated.z * rescale)
400 }
401 crate::types::Axis::Z => {
402 Vec3::new(rotated.x * rescale, rotated.y * rescale, rotated.z)
403 }
404 }
405 } else {
406 rotated
407 };
408
409 result[i] = [
411 scaled.x + origin[0],
412 scaled.y + origin[1],
413 scaled.z + origin[2],
414 ];
415 }
416 result
417 }
418
419 fn apply_block_transform(
421 &self,
422 positions: &[[f32; 3]; 4],
423 transform: &BlockTransform,
424 ) -> [[f32; 3]; 4] {
425 if transform.is_identity() {
426 return *positions;
427 }
428
429 let x_rot = Mat3::from_rotation_x((transform.x as f32).to_radians());
430 let y_rot = Mat3::from_rotation_y((transform.y as f32).to_radians());
431 let rotation_matrix = y_rot * x_rot;
432
433 let mut result = [[0.0; 3]; 4];
434 for (i, pos) in positions.iter().enumerate() {
435 let p = Vec3::new(pos[0], pos[1], pos[2]);
436 let rotated = rotation_matrix * p;
437 result[i] = [rotated.x, rotated.y, rotated.z];
438 }
439 result
440 }
441
442 fn rotate_normal(&self, normal: [f32; 3], transform: &BlockTransform) -> [f32; 3] {
444 if transform.is_identity() {
445 return normal;
446 }
447
448 let x_rot = Mat3::from_rotation_x((transform.x as f32).to_radians());
449 let y_rot = Mat3::from_rotation_y((transform.y as f32).to_radians());
450 let rotation_matrix = y_rot * x_rot;
451
452 let n = Vec3::new(normal[0], normal[1], normal[2]);
453 let rotated = rotation_matrix * n;
454 [rotated.x, rotated.y, rotated.z]
455 }
456
457 pub fn build(mut self) -> Result<(Mesh, Mesh, TextureAtlas)> {
461 let mut atlas_builder = AtlasBuilder::new(
463 self.config.atlas_max_size,
464 self.config.atlas_padding,
465 );
466
467 for texture_ref in &self.texture_refs {
468 if let Some(texture) = self.resource_pack.get_texture(texture_ref) {
469 atlas_builder.add_texture(texture_ref.clone(), texture.first_frame());
470 }
471 }
472
473 let atlas = atlas_builder.build()?;
474
475 for face_mapping in &self.face_textures {
477 if let Some(region) = atlas.get_region(&face_mapping.texture_path) {
478 for i in 0..4 {
480 let vertex_idx = face_mapping.vertex_start as usize + i;
481 if vertex_idx < self.mesh.vertices.len() {
482 let vertex = &mut self.mesh.vertices[vertex_idx];
483 vertex.uv = region.transform_uv(vertex.uv[0], vertex.uv[1]);
485 }
486 }
487 }
488 }
489
490 let (opaque_mesh, transparent_mesh) = self.separate_by_transparency();
492
493 Ok((opaque_mesh, transparent_mesh, atlas))
494 }
495
496 fn separate_by_transparency(&self) -> (Mesh, Mesh) {
498 let mut opaque_mesh = Mesh::new();
499 let mut transparent_mesh = Mesh::new();
500
501 for face_mapping in &self.face_textures {
503 let start = face_mapping.vertex_start as usize;
504
505 let vertices: Vec<_> = (0..4)
507 .filter_map(|i| self.mesh.vertices.get(start + i).copied())
508 .collect();
509
510 if vertices.len() != 4 {
511 continue;
512 }
513
514 let target_mesh = if face_mapping.is_transparent {
520 &mut transparent_mesh
521 } else {
522 &mut opaque_mesh
523 };
524
525 let v0 = target_mesh.add_vertex(vertices[0]);
527 let v1 = target_mesh.add_vertex(vertices[1]);
528 let v2 = target_mesh.add_vertex(vertices[2]);
529 let v3 = target_mesh.add_vertex(vertices[3]);
530
531 let orig_v0 = face_mapping.vertex_start;
534 let orig_v1 = orig_v0 + 1;
535 let orig_v2 = orig_v0 + 2;
536 let orig_v3 = orig_v0 + 3;
537
538 for tri_idx in (0..self.mesh.indices.len()).step_by(3) {
540 let i0 = self.mesh.indices[tri_idx];
541 let i1 = self.mesh.indices[tri_idx + 1];
542 let i2 = self.mesh.indices[tri_idx + 2];
543
544 if i0 >= orig_v0 && i0 <= orig_v3 &&
546 i1 >= orig_v0 && i1 <= orig_v3 &&
547 i2 >= orig_v0 && i2 <= orig_v3 {
548 let new_i0 = match i0 - orig_v0 {
550 0 => v0, 1 => v1, 2 => v2, _ => v3
551 };
552 let new_i1 = match i1 - orig_v0 {
553 0 => v0, 1 => v1, 2 => v2, _ => v3
554 };
555 let new_i2 = match i2 - orig_v0 {
556 0 => v0, 1 => v1, 2 => v2, _ => v3
557 };
558 target_mesh.add_triangle(new_i0, new_i1, new_i2);
559 }
560 }
561 }
562
563 (opaque_mesh, transparent_mesh)
564 }
565}
566
567#[cfg(test)]
568mod tests {
569 use super::*;
570
571 #[test]
572 fn test_rotate_uvs() {
573 let pack = ResourcePack::new();
574 let config = MesherConfig::default();
575 let builder = MeshBuilder::new(&pack, &config);
576
577 let uvs = [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]];
578
579 assert_eq!(builder.rotate_uvs(uvs, 0), uvs);
581
582 let rotated_90 = builder.rotate_uvs(uvs, 90);
584 assert_eq!(rotated_90[0], uvs[3]);
585 assert_eq!(rotated_90[1], uvs[0]);
586
587 let rotated_180 = builder.rotate_uvs(uvs, 180);
589 assert_eq!(rotated_180[0], uvs[2]);
590 assert_eq!(rotated_180[2], uvs[0]);
591 }
592}