|
1 | 1 | use crate::{
|
2 | 2 | dodeca::Vertex,
|
| 3 | + graph::Graph, |
3 | 4 | math,
|
4 |
| - node::VoxelData, |
| 5 | + node::{Chunk, ChunkId, VoxelData}, |
5 | 6 | voxel_math::{ChunkAxisPermutation, ChunkDirection, CoordAxis, CoordSign, Coords},
|
| 7 | + world::Material, |
6 | 8 | };
|
7 | 9 |
|
8 | 10 | /// Updates the margins of both `voxels` and `neighbor_voxels` at the side they meet at.
|
@@ -79,6 +81,52 @@ pub fn initialize_margins(dimension: u8, voxels: &mut VoxelData) {
|
79 | 81 | }
|
80 | 82 | }
|
81 | 83 |
|
| 84 | +/// Assuming that the voxel at `chunk` and `coords` is set to `material`, updates the cooresponding |
| 85 | +/// margin in the chunk at direction `direction` from `chunk` if such a margin exists. Unpopulated chunks |
| 86 | +/// are ignored. |
| 87 | +pub fn update_margin_voxel( |
| 88 | + graph: &mut Graph, |
| 89 | + chunk: ChunkId, |
| 90 | + coords: Coords, |
| 91 | + direction: ChunkDirection, |
| 92 | + material: Material, |
| 93 | +) { |
| 94 | + let coords: CoordsWithMargins = coords.into(); |
| 95 | + let dimension = graph.layout().dimension(); |
| 96 | + let edge_coord = match direction.sign { |
| 97 | + CoordSign::Plus => dimension, |
| 98 | + CoordSign::Minus => 1, |
| 99 | + }; |
| 100 | + if coords[direction.axis] != edge_coord { |
| 101 | + // There is nothing to do if we're not on an edge voxel. |
| 102 | + return; |
| 103 | + } |
| 104 | + let Some(Chunk::Populated { |
| 105 | + voxels: neighbor_voxels, |
| 106 | + surface: neighbor_surface, |
| 107 | + old_surface: neighbor_old_surface, |
| 108 | + .. |
| 109 | + }) = graph |
| 110 | + .get_chunk_neighbor(chunk, direction.axis, direction.sign) |
| 111 | + .map(|chunk_id| &mut graph[chunk_id]) |
| 112 | + else { |
| 113 | + // If the neighboring chunk to check is not populated, there is nothing to do. |
| 114 | + return; |
| 115 | + }; |
| 116 | + |
| 117 | + let margin_coord = match direction.sign { |
| 118 | + CoordSign::Plus => dimension + 1, |
| 119 | + CoordSign::Minus => 0, |
| 120 | + }; |
| 121 | + let neighbor_axis_permutation = neighbor_axis_permutation(chunk.vertex, direction); |
| 122 | + let mut neighbor_coords = coords; |
| 123 | + neighbor_coords[direction.axis] = margin_coord; |
| 124 | + neighbor_coords = neighbor_axis_permutation * neighbor_coords; |
| 125 | + |
| 126 | + neighbor_voxels.data_mut(dimension)[neighbor_coords.to_index(dimension)] = material; |
| 127 | + *neighbor_old_surface = neighbor_surface.take().or(*neighbor_old_surface); |
| 128 | +} |
| 129 | + |
82 | 130 | fn neighbor_axis_permutation(vertex: Vertex, direction: ChunkDirection) -> ChunkAxisPermutation {
|
83 | 131 | match direction.sign {
|
84 | 132 | CoordSign::Plus => vertex.chunk_axis_permutations()[direction.axis as usize],
|
@@ -153,7 +201,7 @@ impl std::ops::Mul<CoordsWithMargins> for ChunkAxisPermutation {
|
153 | 201 |
|
154 | 202 | #[cfg(test)]
|
155 | 203 | mod tests {
|
156 |
| - use crate::{dodeca::Vertex, voxel_math::Coords, world::Material}; |
| 204 | + use crate::{dodeca::Vertex, graph::NodeId, node, voxel_math::Coords, world::Material}; |
157 | 205 |
|
158 | 206 | use super::*;
|
159 | 207 |
|
@@ -221,4 +269,69 @@ mod tests {
|
221 | 269 | Material::WoodPlanks
|
222 | 270 | );
|
223 | 271 | }
|
| 272 | + |
| 273 | + #[test] |
| 274 | + fn test_update_margin_voxel() { |
| 275 | + let mut graph = Graph::new(12); |
| 276 | + let current_vertex = Vertex::A; |
| 277 | + let neighbor_vertex = current_vertex.adjacent_vertices()[1]; |
| 278 | + let neighbor_node = |
| 279 | + graph.ensure_neighbor(NodeId::ROOT, current_vertex.canonical_sides()[0]); |
| 280 | + node::populate_fresh_nodes(&mut graph); |
| 281 | + |
| 282 | + // These are the chunks this test will work with. |
| 283 | + let current_chunk = ChunkId::new(NodeId::ROOT, current_vertex); |
| 284 | + let node_neighbor_chunk = ChunkId::new(neighbor_node, current_vertex); |
| 285 | + let vertex_neighbor_chunk = ChunkId::new(NodeId::ROOT, neighbor_vertex); |
| 286 | + |
| 287 | + // Populate relevant chunks with void |
| 288 | + for chunk in [current_chunk, node_neighbor_chunk, vertex_neighbor_chunk] { |
| 289 | + *graph.get_chunk_mut(chunk).unwrap() = Chunk::Populated { |
| 290 | + voxels: VoxelData::Solid(Material::Void), |
| 291 | + modified: false, |
| 292 | + surface: None, |
| 293 | + old_surface: None, |
| 294 | + }; |
| 295 | + } |
| 296 | + |
| 297 | + // Update and check the margins of node_neighbor_chunk |
| 298 | + update_margin_voxel( |
| 299 | + &mut graph, |
| 300 | + current_chunk, |
| 301 | + Coords([0, 7, 9]), |
| 302 | + ChunkDirection::MINUS_X, |
| 303 | + Material::WoodPlanks, |
| 304 | + ); |
| 305 | + let Chunk::Populated { |
| 306 | + voxels: node_neighbor_voxels, |
| 307 | + .. |
| 308 | + } = graph.get_chunk_mut(node_neighbor_chunk).unwrap() |
| 309 | + else { |
| 310 | + panic!("node_neighbor_chunk should have just been populated by this test"); |
| 311 | + }; |
| 312 | + assert_eq!( |
| 313 | + node_neighbor_voxels.get(CoordsWithMargins([0, 8, 10]).to_index(12)), |
| 314 | + Material::WoodPlanks |
| 315 | + ); |
| 316 | + |
| 317 | + // Update and check the margins of vertex_neighbor_chunk |
| 318 | + update_margin_voxel( |
| 319 | + &mut graph, |
| 320 | + current_chunk, |
| 321 | + Coords([5, 11, 9]), |
| 322 | + ChunkDirection::PLUS_Y, |
| 323 | + Material::Grass, |
| 324 | + ); |
| 325 | + let Chunk::Populated { |
| 326 | + voxels: vertex_neighbor_voxels, |
| 327 | + .. |
| 328 | + } = graph.get_chunk_mut(vertex_neighbor_chunk).unwrap() |
| 329 | + else { |
| 330 | + panic!("vertex_neighbor_chunk should have just been populated by this test"); |
| 331 | + }; |
| 332 | + assert_eq!( |
| 333 | + vertex_neighbor_voxels.get(CoordsWithMargins([6, 10, 13]).to_index(12)), |
| 334 | + Material::Grass |
| 335 | + ); |
| 336 | + } |
224 | 337 | }
|
0 commit comments