Compare commits
No commits in common. '8ce5513e77537da1c50c40984102c81469148590' and 'b2e17f5d8b9afcaa485c4dce35b89551d6758a2e' have entirely different histories.
8ce5513e77
...
b2e17f5d8b
25 changed files with 1313 additions and 1414 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,5 @@ |
|||||||
|
mod pos; |
||||||
|
mod region; |
||||||
|
|
||||||
|
pub use pos::Pos; |
||||||
|
pub use region::Region; |
@ -0,0 +1,212 @@ |
|||||||
|
use std::{ |
||||||
|
marker::PhantomData, |
||||||
|
ops::{Add, AddAssign, Index, IndexMut, Sub, SubAssign}, |
||||||
|
}; |
||||||
|
|
||||||
|
use bevy::{ |
||||||
|
ecs::component::Component, |
||||||
|
math::{Dir3, IVec3, InvalidDirectionError}, |
||||||
|
}; |
||||||
|
|
||||||
|
use super::Region; |
||||||
|
|
||||||
|
pub struct Pos<T> { |
||||||
|
pub x: i32, |
||||||
|
pub y: i32, |
||||||
|
pub z: i32, |
||||||
|
_marker: PhantomData<T>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Pos<T> { |
||||||
|
pub const ORIGIN: Self = Self::new(0, 0, 0); |
||||||
|
|
||||||
|
pub const fn new(x: i32, y: i32, z: i32) -> Self { |
||||||
|
Self { |
||||||
|
x, |
||||||
|
y, |
||||||
|
z, |
||||||
|
_marker: PhantomData, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn region(self) -> Region<T> { |
||||||
|
Region::new_unchecked(self.into(), self.into()) |
||||||
|
} |
||||||
|
|
||||||
|
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 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)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> std::fmt::Display for Pos<T> { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
write!(f, "[{}, {}, {}]", self.x, self.y, self.z) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> std::fmt::Debug for Pos<T> { |
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
fmt.debug_tuple(stringify!(Pos<T>)) |
||||||
|
.field(&self.x) |
||||||
|
.field(&self.y) |
||||||
|
.field(&self.z) |
||||||
|
.finish() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Trait implementations that SHOULD be handled by #[derive]
|
||||||
|
|
||||||
|
use bevy::ecs::component::StorageType; |
||||||
|
impl<T: Send + Sync + 'static> Component for Pos<T> { |
||||||
|
const STORAGE_TYPE: StorageType = StorageType::Table; |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Default for Pos<T> { |
||||||
|
fn default() -> Self { |
||||||
|
Self { |
||||||
|
x: 0, |
||||||
|
y: 0, |
||||||
|
z: 0, |
||||||
|
_marker: PhantomData, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Clone for Pos<T> { |
||||||
|
fn clone(&self) -> Self { |
||||||
|
*self |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Copy for Pos<T> {} |
||||||
|
|
||||||
|
impl<T> PartialEq for Pos<T> { |
||||||
|
fn eq(&self, other: &Self) -> bool { |
||||||
|
(self.x, self.y, self.z).eq(&(other.x, other.y, other.z)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Eq for Pos<T> {} |
||||||
|
|
||||||
|
impl<T> std::hash::Hash for Pos<T> { |
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { |
||||||
|
(self.x, self.y, self.z).hash(state) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Conversion
|
||||||
|
|
||||||
|
impl<T> From<(i32, i32, i32)> for Pos<T> { |
||||||
|
fn from((x, y, z): (i32, i32, i32)) -> Self { |
||||||
|
Self::new(x, y, z) |
||||||
|
} |
||||||
|
} |
||||||
|
impl<T> From<Pos<T>> for (i32, i32, i32) { |
||||||
|
fn from(Pos { x, y, z, .. }: Pos<T>) -> Self { |
||||||
|
(x, y, z) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> From<[i32; 3]> for Pos<T> { |
||||||
|
fn from([x, y, z]: [i32; 3]) -> Self { |
||||||
|
Self::new(x, y, z) |
||||||
|
} |
||||||
|
} |
||||||
|
impl<T> From<Pos<T>> for [i32; 3] { |
||||||
|
fn from(Pos { x, y, z, .. }: Pos<T>) -> Self { |
||||||
|
[x, y, z] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> From<IVec3> for Pos<T> { |
||||||
|
fn from(IVec3 { x, y, z }: IVec3) -> Self { |
||||||
|
Self::new(x, y, z) |
||||||
|
} |
||||||
|
} |
||||||
|
impl<T> From<Pos<T>> for IVec3 { |
||||||
|
fn from(Pos { x, y, z, .. }: Pos<T>) -> Self { |
||||||
|
Self::new(x, y, z) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Offsetting
|
||||||
|
|
||||||
|
impl<T> Add<IVec3> for Pos<T> { |
||||||
|
type Output = Pos<T>; |
||||||
|
fn add(self, rhs: IVec3) -> Self::Output { |
||||||
|
Self::new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Sub<IVec3> for Pos<T> { |
||||||
|
type Output = Pos<T>; |
||||||
|
fn sub(self, rhs: IVec3) -> Self::Output { |
||||||
|
Self::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> AddAssign<IVec3> for Pos<T> { |
||||||
|
fn add_assign(&mut self, rhs: IVec3) { |
||||||
|
self.x += rhs.x; |
||||||
|
self.y += rhs.y; |
||||||
|
self.z += rhs.z; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> SubAssign<IVec3> for Pos<T> { |
||||||
|
fn sub_assign(&mut self, rhs: IVec3) { |
||||||
|
self.x -= rhs.x; |
||||||
|
self.y -= rhs.y; |
||||||
|
self.z -= rhs.z; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Difference
|
||||||
|
|
||||||
|
impl<T> Sub<Pos<T>> for Pos<T> { |
||||||
|
type Output = IVec3; |
||||||
|
fn sub(self, rhs: Self) -> IVec3 { |
||||||
|
IVec3::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Indexing
|
||||||
|
|
||||||
|
impl<T> Index<usize> for Pos<T> { |
||||||
|
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<T> IndexMut<usize> for Pos<T> { |
||||||
|
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"), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,183 @@ |
|||||||
|
use std::{ |
||||||
|
marker::PhantomData, |
||||||
|
ops::{Add, AddAssign, Sub, SubAssign}, |
||||||
|
}; |
||||||
|
|
||||||
|
use bevy::{ |
||||||
|
ecs::component::Component, |
||||||
|
math::{IVec3, UVec3}, |
||||||
|
}; |
||||||
|
|
||||||
|
use super::Pos; |
||||||
|
|
||||||
|
pub struct Region<T> { |
||||||
|
min: IVec3, |
||||||
|
max: IVec3, |
||||||
|
_marker: PhantomData<T>, |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Region<T> { |
||||||
|
pub fn new_unchecked(min: IVec3, max: IVec3) -> Self { |
||||||
|
Self { |
||||||
|
min, |
||||||
|
max, |
||||||
|
_marker: PhantomData, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new_checked(min: Pos<T>, max: Pos<T>) -> Result<Self, ()> { |
||||||
|
let min: IVec3 = min.into(); |
||||||
|
let max: IVec3 = max.into(); |
||||||
|
if min.x <= max.x && min.y <= max.y && min.z <= max.z { |
||||||
|
Ok(Self::new_unchecked(min, max)) |
||||||
|
} else { |
||||||
|
Err(()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pub fn new(a: Pos<T>, b: Pos<T>) -> Self { |
||||||
|
let a: IVec3 = a.into(); |
||||||
|
let b: IVec3 = b.into(); |
||||||
|
let min = IVec3::new(a.x.min(b.x), a.y.min(b.y), a.z.min(b.z)); |
||||||
|
let max = IVec3::new(a.x.max(b.x), a.y.max(b.y), a.z.max(b.z)); |
||||||
|
Self::new_unchecked(min, max) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn size(&self) -> UVec3 { |
||||||
|
(self.max - self.min + IVec3::ONE).as_uvec3() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn contains(&self, pos: Pos<T>) -> bool { |
||||||
|
let pos: IVec3 = pos.into(); |
||||||
|
(pos.x >= self.min.x && pos.x <= self.max.x) |
||||||
|
&& (pos.y >= self.min.y && pos.y <= self.max.y) |
||||||
|
&& (pos.z >= self.min.z && pos.z <= self.max.z) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn intersects(&self, other: Self) -> bool { |
||||||
|
(other.max.x > self.min.x && other.min.x < self.max.x) |
||||||
|
&& (other.max.y > self.min.y && other.min.y < self.max.y) |
||||||
|
&& (other.max.z > self.min.z && other.min.z < self.max.z) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn distance_to(&self, pos: Pos<T>) -> f32 { |
||||||
|
(self.distance_to_squared(pos) as f32).sqrt() |
||||||
|
} |
||||||
|
|
||||||
|
pub fn distance_to_squared(&self, pos: Pos<T>) -> i32 { |
||||||
|
let pos: IVec3 = pos.into(); |
||||||
|
let clamped = pos.max(self.min).min(self.max); |
||||||
|
pos.distance_squared(clamped) |
||||||
|
} |
||||||
|
|
||||||
|
pub fn expand(&self, amount: i32) -> Result<Self, ()> { |
||||||
|
Self::new_checked( |
||||||
|
(self.min - IVec3::splat(amount)).into(), |
||||||
|
(self.max + IVec3::splat(amount)).into(), |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> std::fmt::Display for Region<T> { |
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
write!(f, "{} to {}", self.min, self.max) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> std::fmt::Debug for Region<T> { |
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
||||||
|
fmt.debug_struct(stringify!(Region<T>)) |
||||||
|
.field("min", &self.min) |
||||||
|
.field("max", &self.max) |
||||||
|
.finish() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Trait implementations that SHOULD be handled by #[derive]
|
||||||
|
|
||||||
|
use bevy::ecs::component::StorageType; |
||||||
|
impl<T: Send + Sync + 'static> Component for Region<T> { |
||||||
|
const STORAGE_TYPE: StorageType = StorageType::Table; |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Default for Region<T> { |
||||||
|
fn default() -> Self { |
||||||
|
Self { |
||||||
|
min: IVec3::ZERO, |
||||||
|
max: IVec3::ZERO, |
||||||
|
_marker: PhantomData, |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Clone for Region<T> { |
||||||
|
fn clone(&self) -> Self { |
||||||
|
*self |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Copy for Region<T> {} |
||||||
|
|
||||||
|
impl<T> PartialEq for Region<T> { |
||||||
|
fn eq(&self, other: &Self) -> bool { |
||||||
|
(self.min, self.max).eq(&(other.min, other.max)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Eq for Region<T> {} |
||||||
|
|
||||||
|
impl<T> std::hash::Hash for Region<T> { |
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { |
||||||
|
(self.min, self.max).hash(state) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Conversion
|
||||||
|
|
||||||
|
impl<T> From<Region<T>> for (Pos<T>, Pos<T>) { |
||||||
|
fn from(Region { min, max, .. }: Region<T>) -> Self { |
||||||
|
(min.into(), max.into()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Offsetting
|
||||||
|
|
||||||
|
impl<T> Add<IVec3> for Region<T> { |
||||||
|
type Output = Region<T>; |
||||||
|
fn add(self, rhs: IVec3) -> Self::Output { |
||||||
|
Self::new_unchecked(self.min + rhs, self.max + rhs) |
||||||
|
} |
||||||
|
} |
||||||
|
impl<T> Add<IVec3> for &Region<T> { |
||||||
|
type Output = Region<T>; |
||||||
|
fn add(self, rhs: IVec3) -> Self::Output { |
||||||
|
Region::new_unchecked(self.min + rhs, self.max + rhs) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> Sub<IVec3> for Region<T> { |
||||||
|
type Output = Region<T>; |
||||||
|
fn sub(self, rhs: IVec3) -> Self::Output { |
||||||
|
Self::new_unchecked(self.min - rhs, self.max - rhs) |
||||||
|
} |
||||||
|
} |
||||||
|
impl<T> Sub<IVec3> for &Region<T> { |
||||||
|
type Output = Region<T>; |
||||||
|
fn sub(self, rhs: IVec3) -> Self::Output { |
||||||
|
Region::new_unchecked(self.min - rhs, self.max - rhs) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> AddAssign<IVec3> for Region<T> { |
||||||
|
fn add_assign(&mut self, rhs: IVec3) { |
||||||
|
self.min += rhs; |
||||||
|
self.max += rhs; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T> SubAssign<IVec3> for Region<T> { |
||||||
|
fn sub_assign(&mut self, rhs: IVec3) { |
||||||
|
self.min -= rhs; |
||||||
|
self.max -= rhs; |
||||||
|
} |
||||||
|
} |
@ -1,195 +0,0 @@ |
|||||||
use std::ops::{self, Neg}; |
|
||||||
|
|
||||||
use bevy::math::{Dir3, IVec3}; |
|
||||||
use overload::overload; |
|
||||||
|
|
||||||
use super::{BlockPos, ChunkPos}; |
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
|
||||||
pub enum Neighbor { |
|
||||||
Right, // +X
|
|
||||||
Left, // -X
|
|
||||||
Top, // +Y
|
|
||||||
Bottom, // -Y
|
|
||||||
Front, // +Z
|
|
||||||
Back, // +Z
|
|
||||||
|
|
||||||
RightTop, |
|
||||||
LeftTop, |
|
||||||
RightBottom, |
|
||||||
LeftBottom, |
|
||||||
RightFront, |
|
||||||
LeftFront, |
|
||||||
RightBack, |
|
||||||
LeftBack, |
|
||||||
TopFront, |
|
||||||
BottomFront, |
|
||||||
TopBack, |
|
||||||
BottomBack, |
|
||||||
|
|
||||||
RightTopFront, |
|
||||||
LeftTopFront, |
|
||||||
RightBottomFront, |
|
||||||
LeftBottomFront, |
|
||||||
RightTopBack, |
|
||||||
LeftTopBack, |
|
||||||
RightBottomBack, |
|
||||||
LeftBottomBack, |
|
||||||
} |
|
||||||
|
|
||||||
#[rustfmt::skip] |
|
||||||
impl Neighbor { |
|
||||||
/// All neighbors that share a face. Also known as "orthogonal" or "direct" neighbors.
|
|
||||||
pub const FACE: [Self; 6] = [ Self::Right, Self::Left, Self::Top, Self::Bottom, Self::Front, Self::Back ]; |
|
||||||
|
|
||||||
/// All neighbors that share an edge and only an edge.
|
|
||||||
pub const EDGE: [Self; 12] = [ Self::RightTop, Self::LeftTop, Self::RightBottom, Self::LeftBottom, Self::RightFront, Self::LeftFront, |
|
||||||
Self::RightBack, Self::LeftBack, Self::TopFront, Self::BottomFront, Self::TopBack, Self::BottomBack ]; |
|
||||||
|
|
||||||
/// All neighbors that share a corner and only a corner.
|
|
||||||
pub const CORNER: [Self; 8] = [ Self::RightTopFront, Self::LeftTopFront, Self::RightBottomFront, Self::LeftBottomFront, |
|
||||||
Self::RightTopBack, Self::LeftTopBack, Self::RightBottomBack, Self::LeftBottomBack ]; |
|
||||||
|
|
||||||
pub const ALL: [Self; 26] = [ |
|
||||||
Self::Right, Self::Left, Self::Top, Self::Bottom, Self::Front, Self::Back, |
|
||||||
Self::RightTop, Self::LeftTop, Self::RightBottom, Self::LeftBottom, Self::RightFront, Self::LeftFront, |
|
||||||
Self::RightBack, Self::LeftBack, Self::TopFront, Self::BottomFront, Self::TopBack, Self::BottomBack, |
|
||||||
Self::RightTopFront, Self::LeftTopFront, Self::RightBottomFront, Self::LeftBottomFront, |
|
||||||
Self::RightTopBack, Self::LeftTopBack, Self::RightBottomBack, Self::LeftBottomBack, |
|
||||||
]; |
|
||||||
} |
|
||||||
|
|
||||||
impl From<Neighbor> for IVec3 { |
|
||||||
#[rustfmt::skip] |
|
||||||
fn from(n: Neighbor) -> Self { |
|
||||||
match n { |
|
||||||
Neighbor::Right => Self::new( 1, 0, 0), |
|
||||||
Neighbor::Left => Self::new(-1, 0, 0), |
|
||||||
Neighbor::Top => Self::new(0, 1, 0), |
|
||||||
Neighbor::Bottom => Self::new(0, -1, 0), |
|
||||||
Neighbor::Front => Self::new(0, 0, 1), |
|
||||||
Neighbor::Back => Self::new(0, 0, -1), |
|
||||||
|
|
||||||
Neighbor::RightTop => Self::new( 1, 1, 0), |
|
||||||
Neighbor::LeftTop => Self::new(-1, 1, 0), |
|
||||||
Neighbor::RightBottom => Self::new( 1, -1, 0), |
|
||||||
Neighbor::LeftBottom => Self::new(-1, -1, 0), |
|
||||||
Neighbor::RightFront => Self::new( 1, 0, 1), |
|
||||||
Neighbor::LeftFront => Self::new(-1, 0, 1), |
|
||||||
Neighbor::RightBack => Self::new( 1, 0, -1), |
|
||||||
Neighbor::LeftBack => Self::new(-1, 0, -1), |
|
||||||
Neighbor::TopFront => Self::new( 0, 1, 1), |
|
||||||
Neighbor::BottomFront => Self::new( 0, -1, 1), |
|
||||||
Neighbor::TopBack => Self::new( 0, 1, -1), |
|
||||||
Neighbor::BottomBack => Self::new( 0, -1, -1), |
|
||||||
|
|
||||||
Neighbor::RightTopFront => Self::new( 1, 1, 1), |
|
||||||
Neighbor::LeftTopFront => Self::new(-1, 1, 1), |
|
||||||
Neighbor::RightBottomFront => Self::new( 1, -1, 1), |
|
||||||
Neighbor::LeftBottomFront => Self::new(-1, -1, 1), |
|
||||||
Neighbor::RightTopBack => Self::new( 1, 1, -1), |
|
||||||
Neighbor::LeftTopBack => Self::new(-1, 1, -1), |
|
||||||
Neighbor::RightBottomBack => Self::new( 1, -1, -1), |
|
||||||
Neighbor::LeftBottomBack => Self::new(-1, -1, -1), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl TryFrom<IVec3> for Neighbor { |
|
||||||
type Error = (); |
|
||||||
#[rustfmt::skip] |
|
||||||
fn try_from(v: IVec3) -> Result<Neighbor, Self::Error> { |
|
||||||
match v { |
|
||||||
IVec3 { x: 1, y: 0, z: 0 } => Ok(Self::Right), |
|
||||||
IVec3 { x: -1, y: 0, z: 0 } => Ok(Self::Left), |
|
||||||
IVec3 { x: 0, y: 1, z: 0 } => Ok(Self::Top), |
|
||||||
IVec3 { x: 0, y: -1, z: 0 } => Ok(Self::Bottom), |
|
||||||
IVec3 { x: 0, y: 0, z: 1 } => Ok(Self::Front), |
|
||||||
IVec3 { x: 0, y: 0, z: -1 } => Ok(Self::Back), |
|
||||||
|
|
||||||
IVec3 { x: 1, y: 1, z: 0 } => Ok(Self::RightTop), |
|
||||||
IVec3 { x: -1, y: 1, z: 0 } => Ok(Self::LeftTop), |
|
||||||
IVec3 { x: 1, y: -1, z: 0 } => Ok(Self::RightBottom), |
|
||||||
IVec3 { x: -1, y: -1, z: 0 } => Ok(Self::LeftBottom), |
|
||||||
IVec3 { x: 1, y: 0, z: 1 } => Ok(Self::RightFront), |
|
||||||
IVec3 { x: -1, y: 0, z: 1 } => Ok(Self::LeftFront), |
|
||||||
IVec3 { x: 1, y: 0, z: -1 } => Ok(Self::RightBack), |
|
||||||
IVec3 { x: -1, y: 0, z: -1 } => Ok(Self::LeftBack), |
|
||||||
IVec3 { x: 0, y: 1, z: 1 } => Ok(Self::TopFront), |
|
||||||
IVec3 { x: 0, y: -1, z: 1 } => Ok(Self::BottomFront), |
|
||||||
IVec3 { x: 0, y: 1, z: -1 } => Ok(Self::TopBack), |
|
||||||
IVec3 { x: 0, y: -1, z: -1 } => Ok(Self::BottomBack), |
|
||||||
|
|
||||||
IVec3 { x: 1, y: 1, z: 1 } => Ok(Self::RightTopFront), |
|
||||||
IVec3 { x: -1, y: 1, z: 1 } => Ok(Self::LeftTopFront), |
|
||||||
IVec3 { x: 1, y: -1, z: 1 } => Ok(Self::RightBottomFront), |
|
||||||
IVec3 { x: -1, y: -1, z: 1 } => Ok(Self::LeftBottomFront), |
|
||||||
IVec3 { x: 1, y: 1, z: -1 } => Ok(Self::RightTopBack), |
|
||||||
IVec3 { x: -1, y: 1, z: -1 } => Ok(Self::LeftTopBack), |
|
||||||
IVec3 { x: 1, y: -1, z: -1 } => Ok(Self::RightBottomBack), |
|
||||||
IVec3 { x: -1, y: -1, z: -1 } => Ok(Self::LeftBottomBack), |
|
||||||
|
|
||||||
_ => Err(()), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<Neighbor> for Dir3 { |
|
||||||
fn from(n: Neighbor) -> Dir3 { |
|
||||||
Self::new(IVec3::from(n).as_vec3()).unwrap() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl Neg for Neighbor { |
|
||||||
type Output = Neighbor; |
|
||||||
#[rustfmt::skip] |
|
||||||
fn neg(self) -> Self::Output { |
|
||||||
match self { |
|
||||||
Self::Right => Self::Left, |
|
||||||
Self::Left => Self::Right, |
|
||||||
Self::Top => Self::Bottom, |
|
||||||
Self::Bottom => Self::Top, |
|
||||||
Self::Front => Self::Back, |
|
||||||
Self::Back => Self::Front, |
|
||||||
|
|
||||||
Self::RightTop => Self::LeftBottom, |
|
||||||
Self::LeftTop => Self::RightBottom, |
|
||||||
Self::RightBottom => Self::LeftTop, |
|
||||||
Self::LeftBottom => Self::RightTop, |
|
||||||
Self::RightFront => Self::LeftBack, |
|
||||||
Self::LeftFront => Self::RightBack, |
|
||||||
Self::RightBack => Self::LeftFront, |
|
||||||
Self::LeftBack => Self::RightFront, |
|
||||||
Self::TopFront => Self::BottomBack, |
|
||||||
Self::BottomFront => Self::TopBack, |
|
||||||
Self::TopBack => Self::BottomFront, |
|
||||||
Self::BottomBack => Self::TopFront, |
|
||||||
|
|
||||||
Self::RightTopFront => Self::LeftBottomBack, |
|
||||||
Self::LeftTopFront => Self::RightBottomBack, |
|
||||||
Self::RightBottomFront => Self::LeftTopBack, |
|
||||||
Self::LeftBottomFront => Self::RightTopBack, |
|
||||||
Self::RightTopBack => Self::LeftBottomFront, |
|
||||||
Self::LeftTopBack => Self::RightBottomFront, |
|
||||||
Self::RightBottomBack => Self::LeftTopFront, |
|
||||||
Self::LeftBottomBack => Self::RightTopFront, |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Offsetting
|
|
||||||
|
|
||||||
overload!((l: ?IVec3) + (r: Neighbor) -> IVec3 { l + IVec3::from(r) }); |
|
||||||
overload!((l: ?IVec3) - (r: Neighbor) -> IVec3 { l - IVec3::from(r) }); |
|
||||||
overload!((s: &mut IVec3) += (v: Neighbor) { s.add_assign(IVec3::from(v)) }); |
|
||||||
overload!((s: &mut IVec3) -= (v: Neighbor) { s.sub_assign(IVec3::from(v)) }); |
|
||||||
|
|
||||||
overload!((l: ?BlockPos) + (r: Neighbor) -> BlockPos { l + IVec3::from(r) }); |
|
||||||
overload!((l: ?BlockPos) - (r: Neighbor) -> BlockPos { l - IVec3::from(r) }); |
|
||||||
overload!((s: &mut BlockPos) += (v: Neighbor) { s.add_assign(IVec3::from(v)) }); |
|
||||||
overload!((s: &mut BlockPos) -= (v: Neighbor) { s.sub_assign(IVec3::from(v)) }); |
|
||||||
|
|
||||||
overload!((l: ?ChunkPos) + (r: Neighbor) -> ChunkPos { l + IVec3::from(r) }); |
|
||||||
overload!((l: ?ChunkPos) - (r: Neighbor) -> ChunkPos { l - IVec3::from(r) }); |
|
||||||
overload!((s: &mut ChunkPos) += (v: Neighbor) { s.add_assign(IVec3::from(v)) }); |
|
||||||
overload!((s: &mut ChunkPos) -= (v: Neighbor) { s.sub_assign(IVec3::from(v)) }); |
|
@ -1,80 +0,0 @@ |
|||||||
use std::num::{NonZeroU32, TryFromIntError}; |
|
||||||
|
|
||||||
use bevy::math::{IVec3, UVec3}; |
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
|
||||||
pub struct USize3 { |
|
||||||
pub width: NonZeroU32, |
|
||||||
pub height: NonZeroU32, |
|
||||||
pub depth: NonZeroU32, |
|
||||||
} |
|
||||||
|
|
||||||
impl USize3 { |
|
||||||
pub fn new(width: NonZeroU32, height: NonZeroU32, depth: NonZeroU32) -> Self { |
|
||||||
Self { |
|
||||||
width, |
|
||||||
height, |
|
||||||
depth, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
pub fn splat(length: NonZeroU32) -> Self { |
|
||||||
Self::new(length, length, length) |
|
||||||
} |
|
||||||
|
|
||||||
pub fn contains(&self, pos: IVec3) -> bool { |
|
||||||
(0..self.width.get() as i32).contains(&pos.x) |
|
||||||
&& (0..self.height.get() as i32).contains(&pos.y) |
|
||||||
&& (0..self.depth.get() as i32).contains(&pos.z) |
|
||||||
} |
|
||||||
|
|
||||||
pub fn ivec3_to_index(&self, pos: IVec3) -> Option<usize> { |
|
||||||
self.contains(pos).then(|| { |
|
||||||
let w = self.width.get() as i32; |
|
||||||
let h = self.height.get() as i32; |
|
||||||
(pos.x + (pos.y * w) + (pos.z * w * h)) as usize |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
pub fn index_to_ivec3(&self, index: usize) -> IVec3 { |
|
||||||
let i = index as i32; |
|
||||||
let w = self.width.get() as i32; |
|
||||||
let h = self.height.get() as i32; |
|
||||||
IVec3::new(i % w, i / w % h, i / w / h) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<USize3> for (NonZeroU32, NonZeroU32, NonZeroU32) { |
|
||||||
fn from(size: USize3) -> Self { |
|
||||||
(size.width, size.depth, size.height) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<USize3> for (u32, u32, u32) { |
|
||||||
fn from(size: USize3) -> Self { |
|
||||||
(size.width.get(), size.depth.get(), size.height.get()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl TryFrom<UVec3> for USize3 { |
|
||||||
type Error = TryFromIntError; |
|
||||||
fn try_from(UVec3 { x, y, z }: UVec3) -> Result<Self, Self::Error> { |
|
||||||
Ok(Self::new(x.try_into()?, y.try_into()?, z.try_into()?)) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl From<USize3> for UVec3 { |
|
||||||
fn from(size: USize3) -> Self { |
|
||||||
Self::new(size.width.get(), size.height.get(), size.depth.get()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
impl ndarray::IntoDimension for USize3 { |
|
||||||
type Dim = ndarray::Ix3; |
|
||||||
fn into_dimension(self) -> Self::Dim { |
|
||||||
let w = self.width.get() as usize; |
|
||||||
let h = self.height.get() as usize; |
|
||||||
let d = self.depth.get() as usize; |
|
||||||
ndarray::Ix3(w, h, d) |
|
||||||
} |
|
||||||
} |
|
@ -1,56 +1,74 @@ |
|||||||
use bevy::math::IVec3; |
use std::ops::{Index, IndexMut}; |
||||||
use ndarray::Array3; |
|
||||||
|
|
||||||
use super::{BloxelStore, BloxelStoreMut}; |
use bevy::math::{IVec3, UVec3}; |
||||||
use crate::bloxel::math::USize3; |
|
||||||
|
use super::bloxel_view::{ivec3_to_index, BloxelView, BloxelViewMut}; |
||||||
|
|
||||||
pub struct BloxelArray<T: Copy> { |
pub struct BloxelArray<T: Copy> { |
||||||
size: USize3, |
size: UVec3, |
||||||
data: Array3<T>, |
data: Vec<T>, |
||||||
} |
} |
||||||
|
|
||||||
impl<T: Copy> BloxelArray<T> { |
impl<T: Copy> BloxelArray<T> { |
||||||
pub fn new(size: USize3, fill: T) -> Self { |
pub fn new(size: UVec3, fill: T) -> Self { |
||||||
let data = Array3::from_elem(size, fill); |
assert!(size.x > 0 && size.y > 0 && size.z > 0); |
||||||
|
let len = (size.x * size.y * size.z) as usize; |
||||||
|
let data = vec![fill; len]; |
||||||
Self { size, data } |
Self { size, data } |
||||||
} |
} |
||||||
|
|
||||||
pub fn default(size: USize3) -> Self |
pub fn new_with_default(size: UVec3) -> Self |
||||||
where |
where |
||||||
T: Default, |
T: Default, |
||||||
{ |
{ |
||||||
let data = Array3::default(size); |
Self::new(size, Default::default()) |
||||||
Self { size, data } |
|
||||||
} |
} |
||||||
|
|
||||||
pub fn from_fn(size: USize3, f: impl Fn(IVec3) -> T) -> Self { |
fn get_index(&self, pos: impl Into<IVec3>) -> usize { |
||||||
let f = |(x, y, z)| f(IVec3::new(x as i32, y as i32, z as i32)); |
let pos = pos.into(); |
||||||
let data = Array3::from_shape_fn(size, f); |
assert!(self.contains(pos)); |
||||||
Self { size, data } |
ivec3_to_index(pos, self.size) |
||||||
} |
} |
||||||
|
} |
||||||
|
|
||||||
/// Helper function to construct a `[usize; 3]` to index into `data`, if valid, or `None` otherwise.
|
impl<T: Copy> Index<IVec3> for BloxelArray<T> { |
||||||
fn to_index(&self, pos: IVec3) -> Option<[usize; 3]> { |
type Output = T; |
||||||
self.size |
|
||||||
.contains(pos) |
fn index(&self, pos: IVec3) -> &Self::Output { |
||||||
.then(|| [pos.x as usize, pos.y as usize, pos.z as usize]) |
let index = self.get_index(pos); |
||||||
|
&self.data[index] |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
impl<T: Copy> BloxelStore<T> for BloxelArray<T> { |
impl<T: Copy> IndexMut<IVec3> for BloxelArray<T> { |
||||||
fn size(&self) -> USize3 { |
fn index_mut(&mut self, pos: IVec3) -> &mut Self::Output { |
||||||
|
let index = self.get_index(pos); |
||||||
|
&mut self.data[index] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
impl<T: Copy> BloxelView<T> for BloxelArray<T> { |
||||||
|
fn size(&self) -> UVec3 { |
||||||
self.size |
self.size |
||||||
} |
} |
||||||
|
|
||||||
fn get(&self, pos: IVec3) -> Option<T> { |
fn contains(&self, pos: impl Into<IVec3>) -> bool { |
||||||
self.to_index(pos).map(|index| self.data[index]) |
let pos = pos.into(); |
||||||
|
let size = self.size.as_ivec3(); |
||||||
|
(pos.x >= 0 && pos.x < size.x) |
||||||
|
&& (pos.y >= 0 && pos.y < size.y) |
||||||
|
&& (pos.z >= 0 && pos.z < size.z) |
||||||
|
} |
||||||
|
|
||||||
|
fn get(&self, pos: impl Into<IVec3>) -> T { |
||||||
|
let index = self.get_index(pos); |
||||||
|
self.data[index] |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
impl<T: Copy> BloxelStoreMut<T> for BloxelArray<T> { |
impl<T: Copy> BloxelViewMut<T> for BloxelArray<T> { |
||||||
fn set(&mut self, pos: IVec3, value: T) -> Result<T, ()> { |
fn set(&mut self, pos: impl Into<IVec3>, value: T) { |
||||||
self.to_index(pos) |
let index = self.get_index(pos); |
||||||
.map(|index| std::mem::replace(&mut self.data[index], value)) |
self.data[index] = value; |
||||||
.ok_or(()) |
|
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,24 +0,0 @@ |
|||||||
use bevy::math::{IVec3, UVec3}; |
|
||||||
use cart_prod::specs::Hom3FCartProd; |
|
||||||
|
|
||||||
use crate::bloxel::math::USize3; |
|
||||||
|
|
||||||
pub trait BloxelStore<T: Copy> { |
|
||||||
fn size(&self) -> USize3; |
|
||||||
|
|
||||||
fn get(&self, pos: IVec3) -> Option<T>; |
|
||||||
} |
|
||||||
|
|
||||||
pub trait BloxelStoreMut<T: Copy>: BloxelStore<T> { |
|
||||||
fn set(&mut self, pos: IVec3, value: T) -> Result<T, ()>; |
|
||||||
|
|
||||||
fn update(&mut self, f: impl Fn(IVec3, T) -> T) { |
|
||||||
let (w, h, d) = self.size().into(); |
|
||||||
for prod in Hom3FCartProd::new(0..w, 0..h, 0..d) { |
|
||||||
let pos = UVec3::from(prod).as_ivec3(); |
|
||||||
let old = self.get(pos).unwrap(); |
|
||||||
let new = f(pos, old); |
|
||||||
self.set(pos, new).unwrap(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,28 @@ |
|||||||
|
use bevy::math::{IVec3, UVec3}; |
||||||
|
|
||||||
|
pub trait BloxelView<T> { |
||||||
|
fn size(&self) -> UVec3; |
||||||
|
|
||||||
|
fn contains(&self, pos: impl Into<IVec3>) -> bool; |
||||||
|
|
||||||
|
fn get(&self, pos: impl Into<IVec3>) -> T; |
||||||
|
} |
||||||
|
|
||||||
|
pub trait BloxelViewMut<T>: BloxelView<T> { |
||||||
|
fn set(&mut self, pos: impl Into<IVec3>, value: T); |
||||||
|
} |
||||||
|
|
||||||
|
pub fn ivec3_to_index(pos: impl Into<IVec3>, size: UVec3) -> usize { |
||||||
|
let pos = pos.into(); |
||||||
|
let size = size.as_ivec3(); |
||||||
|
(pos.x + (pos.y * size.x) + (pos.z * size.x * size.y)) as usize |
||||||
|
} |
||||||
|
|
||||||
|
pub fn index_to_ivec3(index: usize, size: UVec3) -> IVec3 { |
||||||
|
let size = size.as_ivec3(); |
||||||
|
let i = index as i32; |
||||||
|
let x = i % size.x; |
||||||
|
let y = i / size.x % size.y; |
||||||
|
let z = i / size.x / size.y; |
||||||
|
IVec3::new(x, y, z) |
||||||
|
} |
@ -1,10 +1,10 @@ |
|||||||
mod bloxel_array; |
mod bloxel_array; |
||||||
mod bloxel_store; |
mod bloxel_view; |
||||||
mod chunked_octree; |
mod chunked_octree; |
||||||
mod palette_bloxel_storage; |
mod palette_bloxel_storage; |
||||||
mod palette_storage; |
mod palette_storage; |
||||||
|
|
||||||
pub use bloxel_array::*; |
pub use bloxel_array::*; |
||||||
pub use bloxel_store::*; |
pub use bloxel_view::*; |
||||||
pub use chunked_octree::*; |
pub use chunked_octree::*; |
||||||
pub use palette_bloxel_storage::*; |
pub use palette_bloxel_storage::*; |
||||||
|
Loading…
Reference in new issue