From 09717f1c565bd626502581aa650fb3ac5ecd77bc Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 10 Jul 2019 00:51:54 +0100 Subject: [PATCH] Added pyramids --- world/src/block/mod.rs | 239 ++++++++++++++++++++++++------------- world/src/block/natural.rs | 8 +- world/src/column/mod.rs | 66 +++++++++- world/src/sim/mod.rs | 8 +- 4 files changed, 230 insertions(+), 91 deletions(-) diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 672cc48bad..0c3c0d5871 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -1,7 +1,7 @@ mod natural; use crate::{ - column::{ColumnGen, ColumnSample}, + column::{ColumnGen, ColumnSample, StructureData}, util::{HashCache, RandomField, Sampler, SamplerMut}, World, CONFIG, }; @@ -88,28 +88,36 @@ impl<'a> BlockGen<'a> { // Tree samples let mut structure_samples = [None, None, None, None, None, None, None, None, None]; for i in 0..structure_samples.len() { - let st_sample = Self::sample_column( - column_gen, - column_cache, - Vec2::from(sample.close_trees[i].0), - ); - structure_samples[i] = st_sample; + if let Some(st) = sample.close_structures[i] { + let st_sample = Self::sample_column(column_gen, column_cache, Vec2::from(st.pos)); + structure_samples[i] = st_sample; + } } let mut structures = [None, None, None, None, None, None, None, None, None]; for i in 0..structures.len() { - let (st_pos, st_seed) = sample.close_trees[i]; - let st_info = natural::structure_gen( - column_gen, - column_cache, - i, - st_pos, - st_seed, - &structure_samples, - ); + if let (Some(st), Some(st_sample)) = + (sample.close_structures[i], structure_samples[i].clone()) + { + let st_info = match st.meta { + None => natural::structure_gen( + column_gen, + column_cache, + i, + st.pos, + st.seed, + &structure_samples, + ), + Some(meta) => Some(StructureInfo { + pos: Vec3::from(st.pos) + Vec3::unit_z() * st_sample.alt as i32, + seed: st.seed, + meta, + }), + }; - if let (Some(st_info), Some(st_sample)) = (st_info, structure_samples[i].clone()) { - structures[i] = Some((st_info, st_sample)); + if let Some(st_info) = st_info { + structures[i] = Some((st_info, st_sample)); + } } } @@ -136,7 +144,7 @@ impl<'a> BlockGen<'a> { sub_surface_color, //tree_density, //forest_kind, - close_trees, + //close_structures, cave_xy, cave_alt, rock, @@ -281,57 +289,6 @@ impl<'a> BlockGen<'a> { } }); - fn block_from_structure( - sblock: StructureBlock, - pos: Vec3, - structure_pos: Vec2, - structure_seed: u32, - _sample: &ColumnSample, - ) -> Block { - let field = RandomField::new(structure_seed + 0); - - let lerp = 0.5 - + ((field.get(Vec3::from(structure_pos)) % 256) as f32 / 256.0 - 0.5) * 0.65 - + ((field.get(Vec3::from(pos)) % 256) as f32 / 256.0 - 0.5) * 0.15; - - match sblock { - StructureBlock::TemperateLeaves => Block::new( - 1, - Lerp::lerp(Rgb::new(0.0, 70.0, 35.0), Rgb::new(100.0, 140.0, 0.0), lerp) - .map(|e| e as u8), - ), - StructureBlock::PineLeaves => Block::new( - 1, - Lerp::lerp(Rgb::new(0.0, 60.0, 50.0), Rgb::new(30.0, 100.0, 10.0), lerp) - .map(|e| e as u8), - ), - StructureBlock::PalmLeaves => Block::new( - 1, - Lerp::lerp( - Rgb::new(15.0, 100.0, 30.0), - Rgb::new(55.0, 220.0, 0.0), - lerp, - ) - .map(|e| e as u8), - ), - StructureBlock::Acacia => Block::new( - 1, - Lerp::lerp( - Rgb::new(35.0, 100.0, 10.0), - Rgb::new(70.0, 190.0, 25.0), - lerp, - ) - .map(|e| e as u8), - ), - StructureBlock::Fruit => Block::new( - 1, - Lerp::lerp(Rgb::new(255.0, 0.0, 0.0), Rgb::new(200.0, 255.0, 6.0), lerp) - .map(|e| e as u8), - ), - StructureBlock::Block(block) => block, - } - } - let block = if definitely_underground { block.unwrap_or(Block::empty()) } else { @@ -340,6 +297,9 @@ impl<'a> BlockGen<'a> { structures.iter().find_map(|st| { let (st, st_sample) = st.as_ref()?; + st.get(wpos, st_sample) + + /* let rpos = wpos - st.pos; let block_pos = Vec3::unit_z() * rpos.z + Vec3::from(st.units.0) * rpos.x @@ -358,6 +318,7 @@ impl<'a> BlockGen<'a> { }) .ok() .filter(|block| !block.is_empty()) + */ }) }) .unwrap_or(Block::empty()) @@ -388,16 +349,13 @@ impl<'a> ZCache<'a> { let structure = self.structures.iter().filter_map(|st| st.as_ref()).fold( 0, |a, (st_info, st_sample)| { - let bounds = st_info.volume.get_bounds(); + let bounds = st_info.get_bounds(); let st_area = Aabr { min: Vec2::from(bounds.min), max: Vec2::from(bounds.max), }; - let rpos = self.wpos - st_info.pos; - let unit_rpos = st_info.units.0 * rpos.x + st_info.units.1 * rpos.y; - - if st_area.contains_point(unit_rpos) { + if st_area.contains_point(self.wpos - st_info.pos) { a.max(bounds.max.z) } else { a @@ -413,13 +371,6 @@ impl<'a> ZCache<'a> { } } -pub struct StructureInfo { - pos: Vec3, - seed: u32, - units: (Vec2, Vec2), - volume: &'static Structure, -} - impl<'a> SamplerMut for BlockGen<'a> { type Index = Vec3; type Sample = Option; @@ -429,3 +380,127 @@ impl<'a> SamplerMut for BlockGen<'a> { self.get_with_z_cache(wpos, z_cache.as_ref()) } } + +#[derive(Copy, Clone)] +pub enum StructureMeta { + Pyramid { + height: i32, + }, + Volume { + units: (Vec2, Vec2), + volume: &'static Structure, + }, +} + +pub struct StructureInfo { + pos: Vec3, + seed: u32, + meta: StructureMeta, +} + +impl StructureInfo { + fn get_bounds(&self) -> Aabb { + match self.meta { + StructureMeta::Pyramid { height } => { + let base = 40; + Aabb { + min: Vec3::new(-base - height, -base - height, -base), + max: Vec3::new(base + height, base + height, height), + } + } + StructureMeta::Volume { units, volume } => { + let bounds = volume.get_bounds(); + + (Aabb { + min: Vec3::from(units.0 * bounds.min.x + units.1 * bounds.min.y) + + Vec3::unit_z() * bounds.min.z, + max: Vec3::from(units.0 * bounds.max.x + units.1 * bounds.max.y) + + Vec3::unit_z() * bounds.max.z, + }) + .made_valid() + } + } + } + + fn get(&self, wpos: Vec3, sample: &ColumnSample) -> Option { + match self.meta { + StructureMeta::Pyramid { height } => { + if wpos.z - self.pos.z + < height + - Vec2::from(wpos - self.pos) + .map(|e: i32| (e.abs() / 2) * 2) + .reduce_max() + { + Some(Block::new(2, Rgb::new(180, 140, 90))) + } else { + None + } + } + StructureMeta::Volume { units, volume } => { + let rpos = wpos - self.pos; + let block_pos = Vec3::unit_z() * rpos.z + + Vec3::from(units.0) * rpos.x + + Vec3::from(units.1) * rpos.y; + + volume + .get((block_pos * 128) / 128) // Scaling + .map(|b| { + block_from_structure(*b, block_pos, self.pos.into(), self.seed, sample) + }) + .ok() + .filter(|block| !block.is_empty()) + } + } + } +} + +fn block_from_structure( + sblock: StructureBlock, + pos: Vec3, + structure_pos: Vec2, + structure_seed: u32, + _sample: &ColumnSample, +) -> Block { + let field = RandomField::new(structure_seed + 0); + + let lerp = 0.5 + + ((field.get(Vec3::from(structure_pos)) % 256) as f32 / 256.0 - 0.5) * 0.65 + + ((field.get(Vec3::from(pos)) % 256) as f32 / 256.0 - 0.5) * 0.15; + + match sblock { + StructureBlock::TemperateLeaves => Block::new( + 1, + Lerp::lerp(Rgb::new(0.0, 70.0, 35.0), Rgb::new(100.0, 140.0, 0.0), lerp) + .map(|e| e as u8), + ), + StructureBlock::PineLeaves => Block::new( + 1, + Lerp::lerp(Rgb::new(0.0, 60.0, 50.0), Rgb::new(30.0, 100.0, 10.0), lerp) + .map(|e| e as u8), + ), + StructureBlock::PalmLeaves => Block::new( + 1, + Lerp::lerp( + Rgb::new(15.0, 100.0, 30.0), + Rgb::new(55.0, 220.0, 0.0), + lerp, + ) + .map(|e| e as u8), + ), + StructureBlock::Acacia => Block::new( + 1, + Lerp::lerp( + Rgb::new(35.0, 100.0, 10.0), + Rgb::new(70.0, 190.0, 25.0), + lerp, + ) + .map(|e| e as u8), + ), + StructureBlock::Fruit => Block::new( + 1, + Lerp::lerp(Rgb::new(255.0, 0.0, 0.0), Rgb::new(200.0, 255.0, 6.0), lerp) + .map(|e| e as u8), + ), + StructureBlock::Block(block) => block, + } +} diff --git a/world/src/block/natural.rs b/world/src/block/natural.rs index 55e1ae80e8..f4958dac70 100644 --- a/world/src/block/natural.rs +++ b/world/src/block/natural.rs @@ -1,4 +1,4 @@ -use super::{BlockGen, StructureInfo, ZCache}; +use super::{BlockGen, StructureInfo, StructureMeta, ZCache}; use crate::{ all::ForestKind, column::{ColumnGen, ColumnSample}, @@ -75,8 +75,10 @@ pub fn structure_gen<'a>( Some(StructureInfo { pos: st_pos3d, seed: st_seed, - units: UNIT_CHOICES[UNIT_RAND.get(st_seed) as usize % UNIT_CHOICES.len()], - volume: &volumes[(VOLUME_RAND.get(st_seed) / 13) as usize % volumes.len()], + meta: StructureMeta::Volume { + units: UNIT_CHOICES[UNIT_RAND.get(st_seed) as usize % UNIT_CHOICES.len()], + volume: &volumes[(VOLUME_RAND.get(st_seed) / 13) as usize % volumes.len()], + }, }) } diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index df4bc3a381..91f04644c6 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -1,4 +1,10 @@ -use crate::{all::ForestKind, sim::LocationInfo, util::Sampler, World, CONFIG}; +use crate::{ + all::ForestKind, + block::StructureMeta, + sim::{LocationInfo, SimChunk}, + util::Sampler, + World, CONFIG, +}; use common::{terrain::TerrainChunkSize, vol::VolSize}; use noise::NoiseFn; use std::{ @@ -15,6 +21,53 @@ impl<'a> ColumnGen<'a> { pub fn new(world: &'a World) -> Self { Self { world } } + + fn get_local_structure(&self, wpos: Vec2, chunk: &SimChunk) -> Option { + let (pos, seed) = self + .world + .sim() + .gen_ctx + .region_gen + .get(wpos) + .iter() + .copied() + .min_by_key(|(pos, _)| pos.distance_squared(wpos)) + .unwrap(); + + if seed % 5 == 2 && chunk.temp > CONFIG.desert_temp && chunk.alt > CONFIG.sea_level + 5.0 { + Some(StructureData { + pos, + seed, + meta: Some(StructureMeta::Pyramid { height: 140 }), + }) + } else { + None + } + } + + fn gen_close_structures( + &self, + wpos: Vec2, + chunk: &SimChunk, + ) -> [Option; 9] { + let mut metas = [None; 9]; + self.world + .sim() + .gen_ctx + .structure_gen + .get(wpos) + .into_iter() + .copied() + .enumerate() + .for_each(|(i, (pos, seed))| { + metas[i] = self.get_local_structure(pos, chunk).or(Some(StructureData { + pos, + seed, + meta: None, + })); + }); + metas + } } impl<'a> Sampler for ColumnGen<'a> { @@ -250,7 +303,7 @@ impl<'a> Sampler for ColumnGen<'a> { sub_surface_color: dirt, tree_density, forest_kind: sim_chunk.forest_kind, - close_trees: sim.gen_ctx.tree_gen.get(wpos), + close_structures: self.gen_close_structures(wpos, sim_chunk), cave_xy, cave_alt, rock, @@ -275,7 +328,7 @@ pub struct ColumnSample<'a> { pub sub_surface_color: Rgb, pub tree_density: f32, pub forest_kind: ForestKind, - pub close_trees: [(Vec2, u32); 9], + pub close_structures: [Option; 9], pub cave_xy: f32, pub cave_alt: f32, pub rock: f32, @@ -287,3 +340,10 @@ pub struct ColumnSample<'a> { pub spawn_rate: f32, pub location: Option<&'a LocationInfo>, } + +#[derive(Copy, Clone)] +pub struct StructureData { + pub pos: Vec2, + pub seed: u32, + pub meta: Option, +} diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 5c958189da..7981874852 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -38,7 +38,8 @@ pub(crate) struct GenCtx { pub cave_0_nz: SuperSimplex, pub cave_1_nz: SuperSimplex, - pub tree_gen: StructureGen2d, + pub structure_gen: StructureGen2d, + pub region_gen: StructureGen2d, pub cliff_gen: StructureGen2d, } @@ -75,8 +76,9 @@ impl WorldSim { cave_0_nz: SuperSimplex::new().set_seed(seed + 13), cave_1_nz: SuperSimplex::new().set_seed(seed + 14), - tree_gen: StructureGen2d::new(seed, 32, 24), - cliff_gen: StructureGen2d::new(seed, 80, 56), + structure_gen: StructureGen2d::new(seed, 32, 24), + region_gen: StructureGen2d::new(seed + 1, 400, 96), + cliff_gen: StructureGen2d::new(seed + 2, 80, 56), }; let mut chunks = Vec::new();