// Standard use std::{collections::HashMap, sync::Arc}; // Library use vek::*; // Crate use crate::{ terrain::TerrainChunkMeta, vol::{BaseVol, ReadVol, SampleVol, SizedVol, VolSize, Vox, WriteVol}, volumes::{ chunk::{Chunk, ChunkErr}, dyna::{Dyna, DynaErr}, }, }; #[derive(Debug)] pub enum VolMapErr { NoSuchChunk, ChunkErr(ChunkErr), DynaErr(DynaErr), } // V = Voxel // S = Size (replace with a const when const generics is a thing) // M = Chunk metadata #[derive(Clone)] pub struct VolMap { chunks: HashMap, Arc>>, } impl VolMap { #[inline(always)] fn chunk_key(pos: Vec3) -> Vec3 { pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32)) } #[inline(always)] pub fn chunk_offs(pos: Vec3) -> Vec3 { pos.map2(S::SIZE, |e, sz| e.rem_euclid(sz as i32)) } } impl BaseVol for VolMap { type Vox = V; type Err = VolMapErr; } impl ReadVol for VolMap { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, VolMapErr> { let ck = Self::chunk_key(pos); self.chunks .get(&ck) .ok_or(VolMapErr::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); chunk.get(co).map_err(|err| VolMapErr::ChunkErr(err)) }) } } impl SampleVol for VolMap { type Sample = VolMap; /// Take a sample of the terrain by cloning the voxels within the provided range. /// /// Note that the resultant volume does not carry forward metadata from the original chunks. fn sample(&self, range: Aabb) -> Result { // Return early if we don't have all the needed chunks that we need! /* let min_chunk = Self::chunk_key(range.min); let max_chunk = Self::chunk_key(range.max - Vec3::one()); for x in min_chunk.x..=max_chunk.x { for y in min_chunk.y..=max_chunk.y { for z in min_chunk.z..=max_chunk.z { if self.chunks.get(&Vec3::new(x, y, z)).is_none() { return Err(VolMapErr::NoSuchChunk); } } } } */ // let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ()); // let mut last_chunk_pos = self.pos_key(range.min); // let mut last_chunk = self.get_key(last_chunk_pos); // for pos in sample.iter_positions() { // let new_chunk_pos = self.pos_key(range.min + pos); // if last_chunk_pos != new_chunk_pos { // last_chunk = self.get_key(new_chunk_pos); // last_chunk_pos = new_chunk_pos; // } // sample // .set( // pos, // if let Some(chunk) = last_chunk { // chunk // .get(Self::chunk_offs(range.min + pos)) // .map(|v| v.clone()) // .unwrap_or(V::empty()) // // Fallback in case the chunk doesn't exist // } else { // self.get(range.min + pos) // .map(|v| v.clone()) // .unwrap_or(V::empty()) // }, // ) // .map_err(|err| VolMapErr::DynaErr(err))?; // } // Ok(sample) let mut sample = VolMap::new(); let chunk_min = Self::chunk_key(range.min); let chunk_max = Self::chunk_key(range.max); for x in chunk_min.x..=chunk_max.x { for y in chunk_min.y..=chunk_max.y { for z in chunk_min.z..=chunk_max.z { let chunk_key = Vec3::new(x, y, z); let chunk = self.get_key_arc(chunk_key).map(|v| v.clone()); if let Some(chunk) = chunk { sample.insert(chunk_key, chunk); } } } } Ok(sample) } } impl WriteVol for VolMap { #[inline(always)] fn set(&mut self, pos: Vec3, vox: V) -> Result<(), VolMapErr> { let ck = Self::chunk_key(pos); self.chunks .get_mut(&ck) .ok_or(VolMapErr::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); Arc::make_mut(chunk) .set(co, vox) .map_err(|err| VolMapErr::ChunkErr(err)) }) } } impl VolMap { pub fn new() -> Self { Self { chunks: HashMap::new(), } } pub fn chunk_size() -> Vec3 { S::SIZE } pub fn insert( &mut self, key: Vec3, chunk: Arc>, ) -> Option>> { self.chunks.insert(key, chunk) } pub fn get_key(&self, key: Vec3) -> Option<&Chunk> { match self.chunks.get(&key) { Some(arc_chunk) => Some(arc_chunk.as_ref()), None => None, } } pub fn get_key_arc(&self, key: Vec3) -> Option<&Arc>> { self.chunks.get(&key) } pub fn remove(&mut self, key: Vec3) -> Option>> { self.chunks.remove(&key) } pub fn key_pos(&self, key: Vec3) -> Vec3 { key * S::SIZE.map(|e| e as i32) } pub fn pos_key(&self, pos: Vec3) -> Vec3 { Self::chunk_key(pos) } pub fn iter<'a>(&'a self) -> ChunkIter<'a, V, S, M> { ChunkIter { iter: self.chunks.iter(), } } } pub struct ChunkIter<'a, V: Vox + Clone, S: VolSize + Clone, M: Clone> { iter: std::collections::hash_map::Iter<'a, Vec3, Arc>>, } impl<'a, V: Vox + Clone, S: VolSize + Clone, M: Clone> Iterator for ChunkIter<'a, V, S, M> { type Item = (Vec3, &'a Arc>); fn next(&mut self) -> Option { self.iter.next().map(|(k, c)| (*k, c)) } }