mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Sampled caverns
This commit is contained in:
parent
abf3546e64
commit
731195f864
@ -51,12 +51,14 @@ fn main() -> Result {
|
||||
|
||||
for x in aabb.min.x..aabb.max.x {
|
||||
for y in aabb.min.y..aabb.max.y {
|
||||
// TODO: remove unwrap
|
||||
let col = canvas.col(Vec2::new(x, y)).unwrap().get_info();
|
||||
for z in aabb.min.z..aabb.max.z {
|
||||
let pos = Vec3::new(x, y, z);
|
||||
|
||||
let _ = volume.map(pos, |block| {
|
||||
if let Some(block) =
|
||||
fill.sample_at(&prim_tree, prim, pos, canvas, block)
|
||||
fill.sample_at(&prim_tree, prim, pos, canvas, block, &col)
|
||||
{
|
||||
block
|
||||
} else {
|
||||
|
@ -1245,3 +1245,24 @@ pub struct ColumnSample<'a> {
|
||||
|
||||
pub chunk: &'a SimChunk,
|
||||
}
|
||||
|
||||
impl ColumnSample<'_> {
|
||||
pub fn get_info(&self) -> ColInfo {
|
||||
ColInfo {
|
||||
alt: self.alt,
|
||||
basement: self.basement,
|
||||
cliff_offset: self.cliff_offset,
|
||||
cliff_height: self.cliff_height,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For a version of ColumnSample that can easily be moved around. Feel free to
|
||||
// add non reference fields as needed.
|
||||
#[derive(Clone)]
|
||||
pub struct ColInfo {
|
||||
pub alt: f32,
|
||||
pub basement: f32,
|
||||
pub cliff_offset: f32,
|
||||
pub cliff_height: f32,
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use {crate::LIB, std::ffi::CStr};
|
||||
use super::*;
|
||||
use crate::{
|
||||
block::block_from_structure,
|
||||
column::ColInfo,
|
||||
site2::util::Dir,
|
||||
util::{RandomField, Sampler},
|
||||
CanvasInfo,
|
||||
@ -72,6 +73,7 @@ pub enum Primitive {
|
||||
/// A sampling function is always a subset of another primitive to avoid
|
||||
/// needing infinite bounds
|
||||
Sampling(Id<Primitive>, Box<dyn Fn(Vec3<i32>) -> bool>),
|
||||
ColSampling(Id<Primitive>, Box<dyn Fn(Vec3<i32>, &ColInfo) -> bool>),
|
||||
Prefab(Box<PrefabStructure>),
|
||||
|
||||
// Combinators
|
||||
@ -139,6 +141,7 @@ impl std::fmt::Debug for Primitive {
|
||||
.field(&height)
|
||||
.finish(),
|
||||
Primitive::Sampling(prim, _) => f.debug_tuple("Sampling").field(&prim).finish(),
|
||||
Primitive::ColSampling(prim, _) => f.debug_tuple("ColSampling").field(&prim).finish(),
|
||||
Primitive::Prefab(prefab) => f.debug_tuple("Prefab").field(&prefab).finish(),
|
||||
Primitive::Intersect(a, b) => f.debug_tuple("Intersect").field(&a).field(&b).finish(),
|
||||
Primitive::Union(a, b) => f.debug_tuple("Union").field(&a).field(&b).finish(),
|
||||
@ -180,6 +183,13 @@ impl Primitive {
|
||||
Self::Sampling(a.into(), f)
|
||||
}
|
||||
|
||||
pub fn column_sampling(
|
||||
a: impl Into<Id<Primitive>>,
|
||||
f: Box<dyn Fn(Vec3<i32>, &ColInfo) -> bool>,
|
||||
) -> Self {
|
||||
Self::ColSampling(a.into(), f)
|
||||
}
|
||||
|
||||
pub fn translate(a: impl Into<Id<Primitive>>, trans: Vec3<i32>) -> Self {
|
||||
Self::Translate(a.into(), trans)
|
||||
}
|
||||
@ -216,7 +226,12 @@ pub enum Fill {
|
||||
}
|
||||
|
||||
impl Fill {
|
||||
fn contains_at(tree: &Store<Primitive>, prim: Id<Primitive>, pos: Vec3<i32>) -> bool {
|
||||
fn contains_at(
|
||||
tree: &Store<Primitive>,
|
||||
prim: Id<Primitive>,
|
||||
pos: Vec3<i32>,
|
||||
col: &ColInfo,
|
||||
) -> bool {
|
||||
// Custom closure because vek's impl of `contains_point` is inclusive :(
|
||||
let aabb_contains = |aabb: Aabb<i32>, pos: Vec3<i32>| {
|
||||
(aabb.min.x..aabb.max.x).contains(&pos.x)
|
||||
@ -375,19 +390,20 @@ impl Fill {
|
||||
let z_check = (projected_z..=(projected_z + height)).contains(&(pos.z as f32));
|
||||
xy_check && z_check
|
||||
},
|
||||
Primitive::Sampling(a, f) => Self::contains_at(tree, *a, pos) && f(pos),
|
||||
Primitive::Sampling(a, f) => Self::contains_at(tree, *a, pos, col) && f(pos),
|
||||
Primitive::ColSampling(a, f) => Self::contains_at(tree, *a, pos, col) && f(pos, col),
|
||||
Primitive::Prefab(p) => !matches!(p.get(pos), Err(_) | Ok(StructureBlock::None)),
|
||||
Primitive::Intersect(a, b) => {
|
||||
Self::contains_at(tree, *a, pos) && Self::contains_at(tree, *b, pos)
|
||||
Self::contains_at(tree, *a, pos, col) && Self::contains_at(tree, *b, pos, col)
|
||||
},
|
||||
Primitive::Union(a, b) => {
|
||||
Self::contains_at(tree, *a, pos) || Self::contains_at(tree, *b, pos)
|
||||
Self::contains_at(tree, *a, pos, col) || Self::contains_at(tree, *b, pos, col)
|
||||
},
|
||||
Primitive::Without(a, b) => {
|
||||
Self::contains_at(tree, *a, pos) && !Self::contains_at(tree, *b, pos)
|
||||
Self::contains_at(tree, *a, pos, col) && !Self::contains_at(tree, *b, pos, col)
|
||||
},
|
||||
Primitive::Translate(prim, vec) => {
|
||||
Self::contains_at(tree, *prim, pos.map2(*vec, i32::saturating_sub))
|
||||
Self::contains_at(tree, *prim, pos.map2(*vec, i32::saturating_sub), col)
|
||||
},
|
||||
Primitive::Scale(prim, vec) => {
|
||||
let center = Self::get_bounds(tree, *prim).as_::<f32>().center();
|
||||
@ -395,12 +411,17 @@ impl Fill {
|
||||
let spos = (center + ((fpos - center) / vec))
|
||||
.map(|x| x.round())
|
||||
.as_::<i32>();
|
||||
Self::contains_at(tree, *prim, spos)
|
||||
Self::contains_at(tree, *prim, spos, col)
|
||||
},
|
||||
Primitive::RotateAbout(prim, mat, vec) => {
|
||||
let mat = mat.as_::<f32>().transposed();
|
||||
let vec = vec - 0.5;
|
||||
Self::contains_at(tree, *prim, (vec + mat * (pos.as_::<f32>() - vec)).as_())
|
||||
Self::contains_at(
|
||||
tree,
|
||||
*prim,
|
||||
(vec + mat * (pos.as_::<f32>() - vec)).as_(),
|
||||
col,
|
||||
)
|
||||
},
|
||||
Primitive::Repeat(prim, offset, count) => {
|
||||
if count == &0 {
|
||||
@ -419,7 +440,7 @@ impl Fill {
|
||||
.reduce_min()
|
||||
.clamp(0, count as i32);
|
||||
let pos = pos - offset * min;
|
||||
Self::contains_at(tree, *prim, pos)
|
||||
Self::contains_at(tree, *prim, pos, col)
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -432,8 +453,9 @@ impl Fill {
|
||||
pos: Vec3<i32>,
|
||||
canvas_info: &CanvasInfo,
|
||||
old_block: Block,
|
||||
col: &ColInfo,
|
||||
) -> Option<Block> {
|
||||
if Self::contains_at(tree, prim, pos) {
|
||||
if Self::contains_at(tree, prim, pos, col) {
|
||||
match self {
|
||||
Fill::Block(block) => Some(*block),
|
||||
Fill::Sprite(sprite) => Some(if old_block.is_filled() {
|
||||
@ -553,7 +575,9 @@ impl Fill {
|
||||
};
|
||||
vec![Aabb { min, max }]
|
||||
},
|
||||
Primitive::Sampling(a, _) => Self::get_bounds_inner(tree, *a),
|
||||
Primitive::Sampling(a, _) | Primitive::ColSampling(a, _) => {
|
||||
Self::get_bounds_inner(tree, *a)
|
||||
},
|
||||
Primitive::Prefab(p) => vec![p.get_bounds()],
|
||||
Primitive::Intersect(a, b) => or_zip_with(
|
||||
Self::get_bounds_opt(tree, *a),
|
||||
@ -693,6 +717,7 @@ impl Painter {
|
||||
| Primitive::SegmentPrism { .. }
|
||||
| Primitive::Prefab(_) => prev_depth,
|
||||
Primitive::Sampling(a, _)
|
||||
| Primitive::ColSampling(a, _)
|
||||
| Primitive::Translate(a, _)
|
||||
| Primitive::Scale(a, _)
|
||||
| Primitive::RotateAbout(a, _, _)
|
||||
@ -1261,6 +1286,17 @@ impl<'a> PrimitiveRef<'a> {
|
||||
.prim(Primitive::sampling(self, Box::new(sampling)))
|
||||
}
|
||||
|
||||
/// Returns a `PrimitiveRef` that conforms to the provided sampling
|
||||
/// function.
|
||||
#[must_use]
|
||||
pub fn sample_with_column(
|
||||
self,
|
||||
sampling: impl Fn(Vec3<i32>, &ColInfo) -> bool + 'static,
|
||||
) -> PrimitiveRef<'a> {
|
||||
self.painter
|
||||
.prim(Primitive::column_sampling(self, Box::new(sampling)))
|
||||
}
|
||||
|
||||
/// Rotates a primitive about it's own's bounds minimum point,
|
||||
#[must_use]
|
||||
pub fn rotate_about_min(self, mat: Mat3<i32>) -> PrimitiveRef<'a> {
|
||||
|
@ -1404,7 +1404,8 @@ impl Site {
|
||||
|
||||
for x in aabb.min.x..aabb.max.x {
|
||||
for y in aabb.min.y..aabb.max.y {
|
||||
let col_tile = self.wpos_tile(Vec2::new(x, y));
|
||||
let wpos = Vec2::new(x, y);
|
||||
let col_tile = self.wpos_tile(wpos);
|
||||
if
|
||||
/* col_tile.is_building() && */
|
||||
col_tile
|
||||
@ -1416,12 +1417,16 @@ impl Site {
|
||||
continue;
|
||||
}
|
||||
let mut last_block = None;
|
||||
|
||||
// TODO: Don't unwrap here
|
||||
let col = canvas.col(wpos).unwrap().get_info();
|
||||
|
||||
for z in aabb.min.z..aabb.max.z {
|
||||
let pos = Vec3::new(x, y, z);
|
||||
|
||||
canvas.map(pos, |block| {
|
||||
let current_block =
|
||||
fill.sample_at(&prim_tree, prim, pos, &info, block);
|
||||
fill.sample_at(&prim_tree, prim, pos, &info, block, &col);
|
||||
if let (Some(last_block), None) = (last_block, current_block) {
|
||||
spawn(pos, last_block);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use super::*;
|
||||
use crate::{
|
||||
assets::AssetHandle,
|
||||
site2::{gen::PrimitiveTransform, util::Dir},
|
||||
util::{attempt, sampler::Sampler, RandomField},
|
||||
util::{attempt, sampler::Sampler, FastNoise, RandomField},
|
||||
Land,
|
||||
};
|
||||
use common::{
|
||||
@ -84,8 +84,8 @@ impl AdletStronghold {
|
||||
|
||||
// Go 50% below minimum height needed, unless entrance already below that height
|
||||
// TODO: Get better heuristic for this
|
||||
let cavern_alt = (land.get_alt_approx(origin) - cavern_radius as f32 * 1.5)
|
||||
.min(land.get_alt_approx(entrance));
|
||||
let cavern_alt =
|
||||
(land.get_alt_approx(origin) - cavern_radius as f32).min(land.get_alt_approx(entrance));
|
||||
|
||||
Self {
|
||||
name,
|
||||
@ -155,6 +155,31 @@ impl Structure for AdletStronghold {
|
||||
min: (self.origin - self.cavern_radius).with_z(self.cavern_alt as i32),
|
||||
max: self.origin.with_z(self.cavern_alt as i32) + self.cavern_radius,
|
||||
}))
|
||||
.sample_with_column({
|
||||
let origin = self.origin.with_z(self.cavern_alt as i32);
|
||||
let radius_sqr = self.cavern_radius * self.cavern_radius;
|
||||
move |pos, col| {
|
||||
let alt = col.basement - col.cliff_offset;
|
||||
let sphere_alt = ((radius_sqr - origin.xy().distance_squared(pos.xy())) as f32)
|
||||
.sqrt()
|
||||
+ origin.z as f32;
|
||||
// Some sort of smooth min
|
||||
let alt = if alt < sphere_alt {
|
||||
alt
|
||||
} else if sphere_alt - alt < 10.0 {
|
||||
f32::lerp(sphere_alt, alt, 1.0 / (alt - sphere_alt).max(1.0))
|
||||
} else {
|
||||
sphere_alt
|
||||
};
|
||||
|
||||
let noise = FastNoise::new(333);
|
||||
let alt_offset = noise.get(pos.with_z(0).as_() / 5.0).powi(2) * 15.0;
|
||||
|
||||
let alt = alt - alt_offset;
|
||||
|
||||
pos.z < alt as i32
|
||||
}
|
||||
})
|
||||
.clear();
|
||||
|
||||
// Create outer wall
|
||||
@ -310,16 +335,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_creating_entities() {
|
||||
let pos = Vec3::zero();
|
||||
let mut rng = thread_rng();
|
||||
// let pos = Vec3::zero();
|
||||
// let mut rng = thread_rng();
|
||||
|
||||
gnarling_mugger(pos, &mut rng);
|
||||
gnarling_stalker(pos, &mut rng);
|
||||
gnarling_logger(pos, &mut rng);
|
||||
gnarling_chieftain(pos, &mut rng);
|
||||
deadwood(pos, &mut rng);
|
||||
mandragora(pos, &mut rng);
|
||||
wood_golem(pos, &mut rng);
|
||||
harvester_boss(pos, &mut rng);
|
||||
// gnarling_mugger(pos, &mut rng);
|
||||
// gnarling_stalker(pos, &mut rng);
|
||||
// gnarling_logger(pos, &mut rng);
|
||||
// gnarling_chieftain(pos, &mut rng);
|
||||
// deadwood(pos, &mut rng);
|
||||
// mandragora(pos, &mut rng);
|
||||
// wood_golem(pos, &mut rng);
|
||||
// harvester_boss(pos, &mut rng);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user