fdm_toolkit/
util.rs

1use crate::chunk::{CompressedChunk, BlockGroup};
2
3use core::marker::PhantomData;
4use core::iter::Iterator;
5use core::convert::Into;
6use core::ops::FnMut;
7use std::boxed::Box;
8use std::sync::Arc;
9use core::cmp::Eq;
10
11
12
13
14
15#[derive(Clone, Debug)]
16pub struct CompressedChunkBytesIter<'a> {
17	chunk:&'a CompressedChunk<'a>,
18	idx:usize
19}
20
21impl<'a> CompressedChunkBytesIter<'a> {
22	#[inline(always)] pub const fn new(chunk:&'a CompressedChunk) -> Self {
23		Self {
24			chunk,
25			idx:0
26		}
27	}
28}
29
30impl<'a> Iterator for CompressedChunkBytesIter<'a> {
31	type Item = u8;
32	
33	fn next(&mut self) -> Option<Self::Item> {
34		if self.idx >= self.chunk.len()*2 { return None; }
35		
36		let b = unsafe { <BlockGroup as Into<[u8; 2]>>::into(*self.chunk.get_unchecked(self.idx/2))[self.idx % 2] };
37		self.idx += 1;
38		Some(b)
39	}
40}
41
42
43
44/// Parameters that can be supplied to someone filling an area with blocks.
45pub struct FillParams<'a> {
46	pub(crate) determiner:Box<dyn FnMut((usize, usize, usize, usize))->u8>,
47	pub(crate) rect:Rect4,
48	           _lt:PhantomData<&'a ()>
49}
50
51impl<'a> FillParams<'a> {
52	#[inline(always)] pub fn with_determiner<F:FnMut((usize, usize, usize, usize))->u8+'static>(determiner:F, rect:Rect4) -> Self {
53		Self {
54			determiner: Box::new(determiner),
55			rect,
56			_lt: PhantomData
57		}
58	}
59	
60	pub fn dither(block_ids:&'a [u8], rect:Rect4) -> Self {
61		let     block_ids = Arc::<[u8]>::from(block_ids);
62		let mut n = 0;
63		Self {
64			determiner: Box::new(move |_| {
65				n += 1;
66				
67				let block = block_ids[n % block_ids.len()];
68				n %= usize::MAX;
69				
70				block
71			}),
72			rect,
73			_lt: PhantomData
74		}
75	}
76	
77	#[inline(always)] pub fn hollow(block_id:u8, rect:Rect4) -> Self {
78		Self {
79			determiner: Box::new(move |loc| if rect.has_on_perimeter(loc) { block_id } else { 0 }),
80			rect,
81			_lt: PhantomData
82		}
83	}
84	
85	#[inline(always)] pub fn solid(block_id:u8, rect:Rect4) -> Self {
86		Self {
87			determiner: Box::new(move |_| block_id),
88			rect,
89			_lt: PhantomData
90		}
91	}
92}
93
94
95
96/// A (4D) rectangular area.
97#[derive(PartialEq, Clone, Debug, Copy, Eq)]
98#[repr(C)]
99pub struct Rect4 {
100	pub start:(usize, usize, usize, usize),
101	pub end:(usize, usize, usize, usize)
102}
103
104impl Rect4 {
105	#[inline(always)] pub const fn new(start:(usize, usize, usize, usize), end:(usize, usize, usize, usize)) -> Self { Self {start, end} }
106	
107	pub const fn has_on_perimeter(&self, point:(usize, usize, usize, usize)) -> bool {
108		((point.0 == self.start.0 || point.0 == self.end.0) && (
109			point.1 >= self.start.1 && point.1 <= self.end.1 && point.2 >= self.start.2 && point.2 <= self.end.2 &&
110			point.3 >= self.start.3 && point.3 <= self.end.3
111		)) || ((point.1 == self.start.1 || point.1 == self.end.1) && (
112			point.0 >= self.start.0 && point.0 <= self.end.0 && point.2 >= self.start.2 && point.2 <= self.end.2 &&
113			point.3 >= self.start.3 && point.3 <= self.end.3
114		)) || ((point.2 == self.start.2 || point.2 == self.end.2) && (
115			point.0 >= self.start.0 && point.0 <= self.end.0 && point.1 >= self.start.1 && point.1 <= self.end.1 &&
116			point.3 >= self.start.3 && point.3 <= self.end.3
117		)) || ((point.3 == self.start.3 || point.3 == self.end.3) && (
118			point.0 >= self.start.0 && point.0 <= self.end.0 && point.1 >= self.start.1 && point.1 <= self.end.1 &&
119			point.2 >= self.start.2 && point.2 <= self.end.2
120		))
121	}
122}