diff --git a/common/src/volumes/dyna.rs b/common/src/volumes/dyna.rs index 9ad587ccee..e9495fe297 100644 --- a/common/src/volumes/dyna.rs +++ b/common/src/volumes/dyna.rs @@ -14,39 +14,44 @@ pub enum DynaError { // V = Voxel // S = Size (replace when const generics are a thing) // M = Metadata -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Dyna { +#[derive(Debug, Serialize, Deserialize)] +pub struct Dyna { vox: Vec, meta: M, sz: Vec3, + _phantom: std::marker::PhantomData, } -impl Dyna { +impl Clone for Dyna { + fn clone(&self) -> Self { + Self { + vox: self.vox.clone(), + meta: self.meta.clone(), + sz: self.sz, + _phantom: std::marker::PhantomData, + } + } +} + +impl Dyna { /// Used to transform a voxel position in the volume into its corresponding index /// in the voxel array. #[inline(always)] fn idx_for(sz: Vec3, pos: Vec3) -> Option { if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() { - Some(Self::idx_for_unchecked(sz, pos)) + Some(A::idx(pos, sz)) } else { None } } - - /// Used to transform a voxel position in the volume into its corresponding index - /// in the voxel array. - #[inline(always)] - fn idx_for_unchecked(sz: Vec3, pos: Vec3) -> usize { - (pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize - } } -impl BaseVol for Dyna { +impl BaseVol for Dyna { type Vox = V; type Error = DynaError; } -impl SizedVol for Dyna { +impl SizedVol for Dyna { #[inline(always)] fn lower_bound(&self) -> Vec3 { Vec3::zero() @@ -58,7 +63,7 @@ impl SizedVol for Dyna { } } -impl ReadVol for Dyna { +impl ReadVol for Dyna { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, DynaError> { Self::idx_for(self.sz, pos) @@ -67,7 +72,7 @@ impl ReadVol for Dyna { } } -impl WriteVol for Dyna { +impl WriteVol for Dyna { #[inline(always)] fn set(&mut self, pos: Vec3, vox: Self::Vox) -> Result<(), DynaError> { Self::idx_for(self.sz, pos) @@ -77,7 +82,7 @@ impl WriteVol for Dyna { } } -impl<'a, V: Vox, M> IntoPosIterator for &'a Dyna { +impl<'a, V: Vox, M, A: Access> IntoPosIterator for &'a Dyna { type IntoIter = DefaultPosIterator; fn pos_iter(self, lower_bound: Vec3, upper_bound: Vec3) -> Self::IntoIter { @@ -85,15 +90,15 @@ impl<'a, V: Vox, M> IntoPosIterator for &'a Dyna { } } -impl<'a, V: Vox, M> IntoVolIterator<'a> for &'a Dyna { - type IntoIter = DefaultVolIterator<'a, Dyna>; +impl<'a, V: Vox, M, A: Access> IntoVolIterator<'a> for &'a Dyna { + type IntoIter = DefaultVolIterator<'a, Dyna>; fn vol_iter(self, lower_bound: Vec3, upper_bound: Vec3) -> Self::IntoIter { Self::IntoIter::new(self, lower_bound, upper_bound) } } -impl Dyna { +impl Dyna { /// Create a new `Dyna` with the provided dimensions and all voxels filled with duplicates of /// the provided voxel. pub fn filled(sz: Vec3, vox: V, meta: M) -> Self { @@ -101,6 +106,7 @@ impl Dyna { vox: vec![vox; sz.product() as usize], meta, sz, + _phantom: std::marker::PhantomData, } } @@ -114,3 +120,15 @@ impl Dyna { &mut self.meta } } + +pub trait Access { + fn idx(pos: Vec3, sz: Vec3) -> usize; +} + +pub struct ColumnAccess; + +impl Access for ColumnAccess { + fn idx(pos: Vec3, sz: Vec3) -> usize { + (pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize + } +} diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 656a09b114..bd8f44caf7 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -4,15 +4,114 @@ use crate::{ }; use common::{ terrain::{Block, BlockKind}, - vol::{ReadVol, RectRasterableVol}, - volumes::vol_grid_2d::VolGrid2d, + vol::{ReadVol, RectRasterableVol, Vox}, + volumes::{dyna::Dyna, vol_grid_2d::VolGrid2d}, }; +use hashbrown::{HashMap, HashSet}; use std::fmt::Debug; use vek::*; type TerrainVertex = ::Vertex; type FluidVertex = ::Vertex; +const DIRS: [Vec2; 4] = [ + Vec2 { x: 1, y: 0 }, + Vec2 { x: 0, y: 1 }, + Vec2 { x: -1, y: 0 }, + Vec2 { x: 0, y: -1 }, +]; + +const DIRS_3D: [Vec3; 6] = [ + Vec3 { x: 1, y: 0, z: 0 }, + Vec3 { x: 0, y: 1, z: 0 }, + Vec3 { x: 0, y: 0, z: 1 }, + Vec3 { x: -1, y: 0, z: 0 }, + Vec3 { x: 0, y: -1, z: 0 }, + Vec3 { x: 0, y: 0, z: -1 }, +]; + +fn calc_light + ReadVol + Debug>( + bounds: Aabb, + vol: &VolGrid2d, +) -> impl Fn(Vec3) -> f32 { + let sunlight = 24; + + let outer = Aabb { + min: bounds.min - sunlight, + max: bounds.max + sunlight, + }; + + let mut voids = HashMap::new(); + let mut rays = vec![outer.size().d; outer.size().product() as usize]; + for x in 0..outer.size().w { + for y in 0..outer.size().h { + let mut outside = true; + for z in (0..outer.size().d).rev() { + if vol + .get(outer.min + Vec3::new(x, y, z)) + .map(|vox| vox.is_air()) + .unwrap_or(true) + { + if !outside { + voids.insert(Vec3::new(x, y, z), None); + } + } else if outside { + rays[(outer.size().w * y + x) as usize] = z; + outside = false; + } + } + } + } + + let mut opens = HashSet::new(); + for (pos, l) in &mut voids { + for dir in &DIRS { + let col = Vec2::::from(*pos) + dir; + if pos.z + > *rays + .get(((outer.size().w * col.y) + col.x) as usize) + .unwrap_or(&0) + { + *l = Some(sunlight - 1); + opens.insert(*pos); + } + } + } + + for _ in 0..20 { + let mut new_opens = HashSet::new(); + for open in &opens { + let parent_l = voids[open].unwrap_or(0); + for dir in &DIRS_3D { + let other = *open + *dir; + if !opens.contains(&other) { + if let Some(l) = voids.get_mut(&other) { + if l.unwrap_or(0) < parent_l - 1 { + new_opens.insert(other); + } + *l = Some(parent_l - 1); + } + } + } + } + opens = new_opens; + } + + move |wpos| { + let pos = wpos - outer.min; + rays.get(((outer.size().w * pos.y) + pos.x) as usize) + .and_then(|ray| if pos.z > *ray { Some(1.0) } else { None }) + .or_else(|| { + if let Some(Some(l)) = voids.get(&pos) { + Some(*l as f32 / sunlight as f32) + } else { + None + } + }) + .unwrap_or(0.0) + } +} + fn block_shadow_density(kind: BlockKind) -> (f32, f32) { // (density, cap) match kind { @@ -38,10 +137,10 @@ impl + ReadVol + Debug> Meshable + ReadVol + Debug> Meshable + ReadVol + Debug> Meshable( .unwrap_or(false), ); - let darkness = darknesses - .iter() - .map(|x| x.iter().map(|y| y.iter())) - .flatten() - .flatten() - .fold(0.0, |a: f32, x| a.max(*x)); + let mut darkness = 0.0; + for x in 0..2 { + for y in 0..2 { + let dark_pos = shift + offs[0] * x + offs[1] * y + 1; + darkness += darknesses[dark_pos.x as usize][dark_pos.y as usize] + [dark_pos.z as usize] + / 4.0; + } + } ( darkness,