Added pyramids

This commit is contained in:
Joshua Barretto 2019-07-10 00:51:54 +01:00
parent 92d4b4dfbe
commit 09717f1c56
4 changed files with 230 additions and 91 deletions

View File

@ -1,7 +1,7 @@
mod natural;
use crate::{
column::{ColumnGen, ColumnSample},
column::{ColumnGen, ColumnSample, StructureData},
util::{HashCache, RandomField, Sampler, SamplerMut},
World, CONFIG,
};
@ -88,30 +88,38 @@ 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),
);
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(
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,
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()) {
if let Some(st_info) = st_info {
structures[i] = Some((st_info, st_sample));
}
}
}
Some(ZCache {
wpos,
@ -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,6 +289,171 @@ impl<'a> BlockGen<'a> {
}
});
let block = if definitely_underground {
block.unwrap_or(Block::empty())
} else {
block
.or_else(|| {
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
+ Vec3::from(st.units.1) * rpos.y;
st.volume
.get((block_pos * 128) / 128) // Scaling
.map(|b| {
block_from_structure(
*b,
block_pos,
st.pos.into(),
st.seed,
st_sample,
)
})
.ok()
.filter(|block| !block.is_empty())
*/
})
})
.unwrap_or(Block::empty())
};
Some(block)
}
}
pub struct ZCache<'a> {
wpos: Vec2<i32>,
sample: ColumnSample<'a>,
structures: [Option<(StructureInfo, ColumnSample<'a>)>; 9],
}
impl<'a> ZCache<'a> {
pub fn get_z_limits(&self) -> (f32, f32) {
let cave_depth = if self.sample.cave_xy.abs() > 0.9 {
(self.sample.alt - self.sample.cave_alt + 8.0).max(0.0)
} else {
0.0
};
let min = self.sample.alt - (self.sample.chaos * 48.0 + cave_depth) - 4.0;
let cliff = if self.sample.near_cliffs { 48.0 } else { 0.0 };
let warp = self.sample.chaos * 48.0;
let structure = self.structures.iter().filter_map(|st| st.as_ref()).fold(
0,
|a, (st_info, st_sample)| {
let bounds = st_info.get_bounds();
let st_area = Aabr {
min: Vec2::from(bounds.min),
max: Vec2::from(bounds.max),
};
if st_area.contains_point(self.wpos - st_info.pos) {
a.max(bounds.max.z)
} else {
a
}
},
) as f32;
let max = (self.sample.alt + cliff + structure + warp + 8.0)
.max(self.sample.water_level)
.max(CONFIG.sea_level + 2.0);
(min, max)
}
}
impl<'a> SamplerMut for BlockGen<'a> {
type Index = Vec3<i32>;
type Sample = Option<Block>;
fn get(&mut self, wpos: Vec3<i32>) -> Option<Block> {
let z_cache = self.get_z_cache(wpos.into());
self.get_with_z_cache(wpos, z_cache.as_ref())
}
}
#[derive(Copy, Clone)]
pub enum StructureMeta {
Pyramid {
height: i32,
},
Volume {
units: (Vec2<i32>, Vec2<i32>),
volume: &'static Structure,
},
}
pub struct StructureInfo {
pos: Vec3<i32>,
seed: u32,
meta: StructureMeta,
}
impl StructureInfo {
fn get_bounds(&self) -> Aabb<i32> {
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<i32>, sample: &ColumnSample) -> Option<Block> {
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<i32>,
@ -331,101 +504,3 @@ impl<'a> BlockGen<'a> {
StructureBlock::Block(block) => block,
}
}
let block = if definitely_underground {
block.unwrap_or(Block::empty())
} else {
block
.or_else(|| {
structures.iter().find_map(|st| {
let (st, st_sample) = st.as_ref()?;
let rpos = wpos - st.pos;
let block_pos = Vec3::unit_z() * rpos.z
+ Vec3::from(st.units.0) * rpos.x
+ Vec3::from(st.units.1) * rpos.y;
st.volume
.get((block_pos * 128) / 128) // Scaling
.map(|b| {
block_from_structure(
*b,
block_pos,
st.pos.into(),
st.seed,
st_sample,
)
})
.ok()
.filter(|block| !block.is_empty())
})
})
.unwrap_or(Block::empty())
};
Some(block)
}
}
pub struct ZCache<'a> {
wpos: Vec2<i32>,
sample: ColumnSample<'a>,
structures: [Option<(StructureInfo, ColumnSample<'a>)>; 9],
}
impl<'a> ZCache<'a> {
pub fn get_z_limits(&self) -> (f32, f32) {
let cave_depth = if self.sample.cave_xy.abs() > 0.9 {
(self.sample.alt - self.sample.cave_alt + 8.0).max(0.0)
} else {
0.0
};
let min = self.sample.alt - (self.sample.chaos * 48.0 + cave_depth) - 4.0;
let cliff = if self.sample.near_cliffs { 48.0 } else { 0.0 };
let warp = self.sample.chaos * 48.0;
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 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) {
a.max(bounds.max.z)
} else {
a
}
},
) as f32;
let max = (self.sample.alt + cliff + structure + warp + 8.0)
.max(self.sample.water_level)
.max(CONFIG.sea_level + 2.0);
(min, max)
}
}
pub struct StructureInfo {
pos: Vec3<i32>,
seed: u32,
units: (Vec2<i32>, Vec2<i32>),
volume: &'static Structure,
}
impl<'a> SamplerMut for BlockGen<'a> {
type Index = Vec3<i32>;
type Sample = Option<Block>;
fn get(&mut self, wpos: Vec3<i32>) -> Option<Block> {
let z_cache = self.get_z_cache(wpos.into());
self.get_with_z_cache(wpos, z_cache.as_ref())
}
}

View File

@ -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,
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()],
},
})
}

View File

@ -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<i32>, chunk: &SimChunk) -> Option<StructureData> {
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<i32>,
chunk: &SimChunk,
) -> [Option<StructureData>; 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<f32>,
pub tree_density: f32,
pub forest_kind: ForestKind,
pub close_trees: [(Vec2<i32>, u32); 9],
pub close_structures: [Option<StructureData>; 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<i32>,
pub seed: u32,
pub meta: Option<StructureMeta>,
}

View File

@ -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();