voxel-zone/common/src/space/three_dimensional/project_to_2d.rs

140 lines
4.6 KiB
Rust

use block_mesh::Voxel;
use crate::space::two_dimensional::depth_tiles::{DepthTile, Direction};
use super::{traits::VoxelContainer, vec3generic::Vec3Generic};
#[derive(Debug)]
struct VoxelCursor<TVoxel> {
position: Vec3Generic<i32>,
finished: bool,
found: Option<TVoxel>,
}
impl<T> VoxelCursor<T> {
pub fn new(position: Vec3Generic<i32>) -> VoxelCursor<T> {
VoxelCursor::<T> {
position,
finished: false,
found: None,
}
}
}
pub fn create_tilemap<TContainer, TVoxel>(
container: &TContainer,
direction: Direction,
width: u32,
height: u32,
search_depth: u32,
) -> Vec<DepthTile<TVoxel>>
where
TContainer: VoxelContainer<TVoxel>,
TVoxel: Voxel + Copy + Default,
{
let step = match direction {
Direction::North => Vec3Generic::<i32> { x: 0, y: 0, z: 1 },
Direction::South => Vec3Generic::<i32> { x: 0, y: 0, z: -1 },
Direction::East => Vec3Generic::<i32> { x: 1, y: 0, z: 0 },
Direction::West => Vec3Generic::<i32> { x: -1, y: 0, z: 0 },
};
// create a bunch of cursors
let mut cursors: Vec<VoxelCursor<TVoxel>> = vec![];
for x in 0..width as i32 {
for y in 0..height as i32 {
cursors.push(match direction {
Direction::North => VoxelCursor::new(Vec3Generic::<i32> { x, y, z: 0 }),
Direction::South => VoxelCursor::new(Vec3Generic::<i32> {
x,
y,
z: search_depth as i32 - 1,
}),
Direction::East => VoxelCursor::new(Vec3Generic::<i32> { x: 0, y, z: x }),
Direction::West => VoxelCursor::new(Vec3Generic::<i32> {
x: search_depth as i32 - 1,
y,
z: x,
}),
});
}
}
// move them each until they bump into something.
// spec: https://www.youtube.com/watch?v=wwvLlEtxX3o
let mut num_finished_cursors = 0;
while num_finished_cursors < cursors.len() - 1 {
println!(
"num finished cursors: {}/{}",
num_finished_cursors,
cursors.len()
);
for cursor in &mut cursors {
if cursor.finished {
continue;
}
// is there a visible voxel at the current location? if so, we're done.
match container.get_voxel_at_pos(cursor.position) {
Some(v) => match v.get_visibility() {
block_mesh::VoxelVisibility::Opaque
| block_mesh::VoxelVisibility::Translucent => {
cursor.found = Some(v);
cursor.finished = true;
num_finished_cursors += 1;
continue;
}
block_mesh::VoxelVisibility::Empty => (),
},
None => (),
};
// step the cursor
cursor.position = cursor.position + step;
// test if the cursor is out of bounds (any dimension is outside of 0 <= n < search_depth)
for n in [&cursor.position.x, &cursor.position.y, &cursor.position.z] {
if *n < 0 || *n > search_depth as i32 {
cursor.finished = true;
num_finished_cursors += 1;
}
}
}
}
println!("all cursors finished.");
// todo: do we need to normalize the depth relative to camera? i.e. closest layer is depth 0
// even if it was on the backside
let mut tiles: Vec<DepthTile<TVoxel>> = vec![];
for cursor in cursors {
match cursor.found {
Some(v) => {
// determine the x, y, and depth based on the direction and the voxel's vector
let (x, y, depth) = match direction {
Direction::North => (cursor.position.x, cursor.position.y, cursor.position.z),
Direction::South => (
cursor.position.x,
cursor.position.y,
cursor.position.z,
), // flip x and z
Direction::East => (cursor.position.z, cursor.position.y, cursor.position.x),
Direction::West => (
cursor.position.z,
cursor.position.y,
cursor.position.x,
),
};
tiles.push(DepthTile::<TVoxel> {
x,
y,
depth,
data: v,
});
}
None => (),
}
}
tiles
}