From fdf3ab6a78b9f2632b768b3d22af84356846bb55 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 6 Jan 2021 20:57:33 +0000 Subject: [PATCH] Simple coral --- common/src/terrain/block.rs | 10 +++++ world/src/layer/mod.rs | 78 +++++++++++++++++++++++++++++++++++- world/src/lib.rs | 1 + world/src/util/fast_noise.rs | 65 ++++++++++++++++++++++++++++++ world/src/util/mod.rs | 2 +- 5 files changed, 153 insertions(+), 3 deletions(-) diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 5da34b509f..7c7a4e0168 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -193,6 +193,16 @@ impl Block { } } + #[inline] + pub fn get_max_sunlight(&self) -> Option { + match self.kind() { + BlockKind::Water => Some(2), + BlockKind::Leaves => Some(4), + _ if self.is_opaque() => Some(0), + _ => None, + } + } + #[inline] pub fn is_solid(&self) -> bool { self.get_sprite() diff --git a/world/src/layer/mod.rs b/world/src/layer/mod.rs index 486fe3bd9a..c0b0f42a64 100644 --- a/world/src/layer/mod.rs +++ b/world/src/layer/mod.rs @@ -6,7 +6,7 @@ pub use self::{scatter::apply_scatter_to, tree::apply_trees_to}; use crate::{ column::ColumnSample, - util::{RandomField, Sampler}, + util::{FastNoise, FastNoise2d, RandomField, Sampler}, Canvas, IndexRef, }; use common::{ @@ -22,7 +22,7 @@ use rand::prelude::*; use serde::Deserialize; use std::{ f32, - ops::{Mul, Sub}, + ops::{Mul, Range, Sub}, }; use vek::*; @@ -302,3 +302,77 @@ pub fn apply_caves_supplement<'a>( } } } + +pub fn apply_coral_to(canvas: &mut Canvas) { + let info = canvas.info(); + + if !info.chunk.river.near_water() { + return; // Don't bother with coral for a chunk nowhere near water + } + + canvas.foreach_col(|canvas, wpos2d, col| { + const CORAL_DEPTH: Range = 14.0..32.0; + const CORAL_HEIGHT: f32 = 14.0; + const CORAL_DEPTH_FADEOUT: f32 = 5.0; + const CORAL_SCALE: f32 = 10.0; + + let water_depth = col.water_level - col.alt; + + if !CORAL_DEPTH.contains(&water_depth) { + return; // Avoid coral entirely for this column if we're outside coral depths + } + + for z in col.alt.floor() as i32..(col.alt + CORAL_HEIGHT) as i32 { + let wpos = Vec3::new(wpos2d.x, wpos2d.y, z); + + let coral_factor = Lerp::lerp( + 1.0, + 0.0, + // Fade coral out due to incorrect depth + ((water_depth.clamped(CORAL_DEPTH.start, CORAL_DEPTH.end) - water_depth).abs() + / CORAL_DEPTH_FADEOUT) + .min(1.0), + ) * Lerp::lerp( + 1.0, + 0.0, + // Fade coral out due to incorrect altitude above the seabed + ((z as f32 - col.alt) / CORAL_HEIGHT).powi(2), + ) * FastNoise::new(info.index.seed + 7) + .get(wpos.map(|e| e as f64) / 32.0) + .sub(0.2) + .mul(100.0) + .clamped(0.0, 1.0); + + let nz = Vec3::iota().map(|e: u32| FastNoise::new(info.index.seed + e * 177)); + + let wpos_warped = wpos.map(|e| e as f32) + + nz.map(|nz| { + nz.get(wpos.map(|e| e as f64) / CORAL_SCALE as f64) * CORAL_SCALE * 0.3 + }); + + // let is_coral = FastNoise2d::new(info.index.seed + 17) + // .get(wpos_warped.xy().map(|e| e as f64) / CORAL_SCALE) + // .sub(1.0 - coral_factor) + // .max(0.0) + // .div(coral_factor) > 0.5; + + let is_coral = [ + FastNoise::new(info.index.seed), + FastNoise::new(info.index.seed + 177), + ] + .iter() + .all(|nz| { + nz.get(wpos_warped.map(|e| e as f64) / CORAL_SCALE as f64) + .abs() + < coral_factor * 0.3 + }); + + if is_coral { + let _ = canvas.set( + wpos, + Block::new(BlockKind::WeakRock, Rgb::new(170, 220, 210)), + ); + } + } + }); +} diff --git a/world/src/lib.rs b/world/src/lib.rs index b5ca5fad03..73dc97b95a 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -290,6 +290,7 @@ impl World { layer::apply_scatter_to(&mut canvas, &mut dynamic_rng); layer::apply_caves_to(&mut canvas, &mut dynamic_rng); layer::apply_paths_to(&mut canvas); + layer::apply_coral_to(&mut canvas); // Apply site generation sim_chunk.sites.iter().for_each(|site| { diff --git a/world/src/util/fast_noise.rs b/world/src/util/fast_noise.rs index 8caa007639..84ac0dc87a 100644 --- a/world/src/util/fast_noise.rs +++ b/world/src/util/fast_noise.rs @@ -24,6 +24,30 @@ impl Sampler<'static> for FastNoise { type Sample = f32; fn get(&self, pos: Self::Index) -> Self::Sample { + // let align_pos = pos.map(|e| e.floor()); + // let near_pos = align_pos.map(|e| e as i32); + + // let v000 = self.noise_at(near_pos + Vec3::new(0, 0, 0)); + // let v100 = self.noise_at(near_pos + Vec3::new(1, 0, 0)); + // let v010 = self.noise_at(near_pos + Vec3::new(0, 1, 0)); + // let v110 = self.noise_at(near_pos + Vec3::new(1, 1, 0)); + // let v001 = self.noise_at(near_pos + Vec3::new(0, 0, 1)); + // let v101 = self.noise_at(near_pos + Vec3::new(1, 0, 1)); + // let v011 = self.noise_at(near_pos + Vec3::new(0, 1, 1)); + // let v111 = self.noise_at(near_pos + Vec3::new(1, 1, 1)); + + // let factor = (pos - align_pos).map(|e| e as f32); + + // let v00 = v000 + factor.z * (v001 - v000); + // let v10 = v010 + factor.z * (v011 - v010); + // let v01 = v100 + factor.z * (v101 - v100); + // let v11 = v110 + factor.z * (v111 - v110); + + // let v0 = v00 + factor.y * (v01 - v00); + // let v1 = v10 + factor.y * (v11 - v10); + + // (v0 + factor.x * (v1 - v0)) * 2.0 - 1.0 + let near_pos = pos.map(|e| e.floor() as i32); let v000 = self.noise_at(near_pos + Vec3::new(0, 0, 0)); @@ -51,3 +75,44 @@ impl Sampler<'static> for FastNoise { (y0 + factor.z * (y1 - y0)) * 2.0 - 1.0 } } + +pub struct FastNoise2d { + noise: RandomField, +} + +impl FastNoise2d { + pub const fn new(seed: u32) -> Self { + Self { + noise: RandomField::new(seed), + } + } + + #[allow(clippy::excessive_precision)] // TODO: Pending review in #587 + fn noise_at(&self, pos: Vec2) -> f32 { + (self.noise.get(Vec3::new(pos.x, pos.y, 0)) & 4095) as f32 * 0.000244140625 + } +} + +impl Sampler<'static> for FastNoise2d { + type Index = Vec2; + type Sample = f32; + + fn get(&self, pos: Self::Index) -> Self::Sample { + let near_pos = pos.map(|e| e.floor() as i32); + + let v00 = self.noise_at(near_pos + Vec2::new(0, 0)); + let v10 = self.noise_at(near_pos + Vec2::new(1, 0)); + let v01 = self.noise_at(near_pos + Vec2::new(0, 1)); + let v11 = self.noise_at(near_pos + Vec2::new(1, 1)); + + let factor = pos.map(|e| { + let f = e.fract().add(1.0).fract() as f32; + f.powi(2) * (3.0 - 2.0 * f) + }); + + let v0 = v00 + factor.y * (v10 - v00); + let v1 = v01 + factor.y * (v11 - v01); + + (v0 + factor.x * (v1 - v0)) * 2.0 - 1.0 + } +} diff --git a/world/src/util/mod.rs b/world/src/util/mod.rs index 8d20dc2216..a04a8d2bb3 100644 --- a/world/src/util/mod.rs +++ b/world/src/util/mod.rs @@ -9,7 +9,7 @@ pub mod unit_chooser; // Reexports pub use self::{ - fast_noise::FastNoise, + fast_noise::{FastNoise, FastNoise2d}, map_vec::MapVec, random::{RandomField, RandomPerm}, sampler::{Sampler, SamplerMut},