You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
4.2 KiB
161 lines
4.2 KiB
use std::{ |
|
num::NonZeroU32, |
|
ops::{self, Index, IndexMut}, |
|
}; |
|
|
|
use bevy::{ |
|
ecs::component::Component, |
|
math::{Dir3, IVec3, InvalidDirectionError}, |
|
transform::components::Transform, |
|
}; |
|
use overload::overload; |
|
|
|
use super::{BlockPos, BlockRegion, ChunkRegion}; |
|
use crate::bloxel::math::USize3; |
|
|
|
pub const CHUNK_SHIFT: i32 = 4; |
|
pub const CHUNK_MASK: i32 = !(!0 << CHUNK_SHIFT); // = 0b1111 |
|
pub const CHUNK_LENGTH: usize = 1 << CHUNK_SHIFT; // = 16 |
|
|
|
pub const CHUNK_SIZE: USize3 = |
|
USize3::splat(unsafe { NonZeroU32::new_unchecked(CHUNK_LENGTH as u32) }); |
|
|
|
pub const CHUNK_MAX: IVec3 = IVec3::splat((CHUNK_LENGTH - 1) as i32); |
|
|
|
#[derive(Component, Clone, Copy, PartialEq, Eq, Hash, Debug)] |
|
pub struct ChunkPos { |
|
pub x: i32, |
|
pub y: i32, |
|
pub z: i32, |
|
} |
|
|
|
impl ChunkPos { |
|
pub const ORIGIN: ChunkPos = Self::new(0, 0, 0); |
|
|
|
pub const fn new(x: i32, y: i32, z: i32) -> Self { |
|
Self { x, y, z } |
|
} |
|
|
|
pub fn region(self) -> ChunkRegion { |
|
ChunkRegion::new_unchecked(self, self) |
|
} |
|
|
|
pub fn distance_to(self, other: Self) -> f32 { |
|
(self.distance_to_squared(other) as f32).sqrt() |
|
} |
|
|
|
pub fn distance_to_squared(self, other: Self) -> i32 { |
|
IVec3::distance_squared(self.into(), other.into()) |
|
} |
|
|
|
pub fn direction_to(self, other: Self) -> Result<Dir3, InvalidDirectionError> { |
|
Dir3::new((other - self).as_vec3()) |
|
} |
|
|
|
pub fn transform(self) -> Transform { |
|
let pos: IVec3 = self.into(); |
|
Transform::from_translation((pos << CHUNK_SHIFT).as_vec3()) |
|
} |
|
|
|
pub fn min(self, rhs: Self) -> Self { |
|
Self::new(self.x.min(rhs.x), self.y.min(rhs.y), self.z.min(rhs.z)) |
|
} |
|
|
|
pub fn max(self, rhs: Self) -> Self { |
|
Self::new(self.x.max(rhs.x), self.y.max(rhs.y), self.z.max(rhs.z)) |
|
} |
|
|
|
pub fn from_block_pos(pos: BlockPos) -> (Self, IVec3) { |
|
let pos: IVec3 = pos.into(); |
|
((pos >> CHUNK_SHIFT).into(), pos & CHUNK_MASK) |
|
} |
|
|
|
pub fn to_block_pos(self, relative: IVec3) -> BlockPos { |
|
let pos: IVec3 = self.into(); |
|
((pos << CHUNK_SHIFT) + relative).into() |
|
} |
|
|
|
pub fn to_block_region(self) -> BlockRegion { |
|
BlockRegion::new_unchecked( |
|
self.to_block_pos(IVec3::ZERO), |
|
self.to_block_pos(IVec3::splat(CHUNK_LENGTH as i32 - 1)), |
|
) |
|
} |
|
} |
|
|
|
impl std::fmt::Display for ChunkPos { |
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
|
write!(f, "[{}, {}, {}]", self.x, self.y, self.z) |
|
} |
|
} |
|
|
|
// Offsetting |
|
|
|
overload!((l: ?ChunkPos) + (r: ?IVec3) -> ChunkPos { ChunkPos::new(l.x + r.x, l.y + r.y, l.z + r.z) }); |
|
overload!((l: ?ChunkPos) - (r: ?IVec3) -> ChunkPos { ChunkPos::new(l.x - r.x, l.y - r.y, l.z - r.z) }); |
|
overload!((s: &mut ChunkPos) += (v: ?IVec3) { s.x += v.x; s.y += v.y; s.z += v.z; }); |
|
overload!((s: &mut ChunkPos) -= (v: ?IVec3) { s.x -= v.x; s.y -= v.y; s.z -= v.z; }); |
|
|
|
// Difference |
|
|
|
overload!((l: ?ChunkPos) - (r: ?ChunkPos) -> IVec3 { IVec3::new(l.x - r.x, l.y - r.y, l.z - r.z) }); |
|
|
|
// Indexing |
|
|
|
impl Index<usize> for ChunkPos { |
|
type Output = i32; |
|
fn index(&self, index: usize) -> &Self::Output { |
|
match index { |
|
0 => &self.x, |
|
1 => &self.y, |
|
2 => &self.z, |
|
_ => panic!("index out of bounds"), |
|
} |
|
} |
|
} |
|
|
|
impl IndexMut<usize> for ChunkPos { |
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output { |
|
match index { |
|
0 => &mut self.x, |
|
1 => &mut self.y, |
|
2 => &mut self.z, |
|
_ => panic!("index out of bounds"), |
|
} |
|
} |
|
} |
|
|
|
// Conversion |
|
|
|
impl From<(i32, i32, i32)> for ChunkPos { |
|
fn from((x, y, z): (i32, i32, i32)) -> Self { |
|
Self::new(x, y, z) |
|
} |
|
} |
|
impl From<ChunkPos> for (i32, i32, i32) { |
|
fn from(ChunkPos { x, y, z }: ChunkPos) -> Self { |
|
(x, y, z) |
|
} |
|
} |
|
|
|
impl From<[i32; 3]> for ChunkPos { |
|
fn from([x, y, z]: [i32; 3]) -> Self { |
|
Self::new(x, y, z) |
|
} |
|
} |
|
impl From<ChunkPos> for [i32; 3] { |
|
fn from(ChunkPos { x, y, z }: ChunkPos) -> Self { |
|
[x, y, z] |
|
} |
|
} |
|
|
|
impl From<IVec3> for ChunkPos { |
|
fn from(IVec3 { x, y, z }: IVec3) -> Self { |
|
Self::new(x, y, z) |
|
} |
|
} |
|
impl From<ChunkPos> for IVec3 { |
|
fn from(ChunkPos { x, y, z }: ChunkPos) -> Self { |
|
Self::new(x, y, z) |
|
} |
|
}
|
|
|