Add Primitive::Prefab and Fill::Prefab for coloring dungeon entrances.

This commit is contained in:
Avi Weinstock 2021-06-22 01:16:33 -04:00
parent 95214649db
commit c6bb61f2e6
6 changed files with 69 additions and 26 deletions

View File

@ -11,7 +11,7 @@ use vek::*;
make_case_elim!(
structure_block,
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u32)]
pub enum StructureBlock {
None = 0,
@ -40,12 +40,13 @@ pub enum StructureError {
OutOfBounds,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub struct Structure {
center: Vec3<i32>,
base: Arc<BaseStructure>,
}
#[derive(Debug)]
struct BaseStructure {
vol: Dyna<StructureBlock, ()>,
default_kind: BlockKind,

View File

@ -140,6 +140,7 @@ pub trait Access {
fn idx(pos: Vec3<i32>, sz: Vec3<u32>) -> usize;
}
#[derive(Copy, Clone, Debug)]
pub struct ColumnAccess;
impl Access for ColumnAccess {

View File

@ -7,8 +7,7 @@ mod tree;
// Reexports
pub use self::{
block_mask::BlockMask, castle::Castle, economy::Economy,
settlement::Settlement, tree::Tree,
block_mask::BlockMask, castle::Castle, economy::Economy, settlement::Settlement, tree::Tree,
};
use crate::{column::ColumnSample, site2, Canvas};
@ -155,7 +154,8 @@ impl Site {
};
s.apply_supplement(dynamic_rng, wpos2d, get_column, supplement, economy)
},
SiteKind::Dungeon(d) => {}, //d.apply_supplement(dynamic_rng, wpos2d, get_column, supplement),
SiteKind::Dungeon(d) => {}, /* d.apply_supplement(dynamic_rng, wpos2d, get_column,
* supplement), */
SiteKind::Castle(c) => c.apply_supplement(dynamic_rng, wpos2d, get_column, supplement),
SiteKind::Refactor(_) => {},
SiteKind::Tree(_) => {},

View File

@ -1,8 +1,15 @@
use super::*;
use crate::util::{RandomField, Sampler};
use crate::{
block::block_from_structure,
util::{RandomField, Sampler},
};
use common::{
store::{Id, Store},
terrain::{Block, BlockKind},
terrain::{
structure::{Structure as PrefabStructure, StructureBlock},
Block, BlockKind,
},
vol::ReadVol,
};
use vek::*;
@ -18,6 +25,7 @@ pub enum Primitive {
Sphere(Aabb<i32>),
Plane(Aabr<i32>, Vec3<i32>, Vec2<f32>),
Sampling(Box<dyn Fn(Vec3<i32>) -> bool>),
Prefab(PrefabStructure),
// Combinators
And(Id<Primitive>, Id<Primitive>),
@ -34,6 +42,10 @@ pub enum Primitive {
pub enum Fill {
Block(Block),
Brick(BlockKind, Rgb<u8>, u8),
// TODO: the offset field for Prefab is a hack that breaks the compositionality of Translate,
// we probably need an evaluator for the primitive tree that gets which point is queried at
// leaf nodes given an input point to make Translate/Rotate work generally
Prefab(PrefabStructure, Vec3<i32>, u32),
}
impl Fill {
@ -99,6 +111,7 @@ impl Fill {
.dot(*gradient) as i32)
},
Primitive::Sampling(f) => f(pos),
Primitive::Prefab(p) => !matches!(p.get(pos), Err(_) | Ok(StructureBlock::None)),
Primitive::And(a, b) => {
self.contains_at(tree, *a, pos) && self.contains_at(tree, *b, pos)
},
@ -118,7 +131,7 @@ impl Fill {
},
Primitive::Translate(prim, vec) => {
self.contains_at(tree, *prim, pos.map2(*vec, i32::saturating_sub))
}
},
}
}
@ -127,6 +140,7 @@ impl Fill {
tree: &Store<Primitive>,
prim: Id<Primitive>,
pos: Vec3<i32>,
canvas: &Canvas,
) -> Option<Block> {
if self.contains_at(tree, prim, pos) {
match self {
@ -137,6 +151,19 @@ impl Fill {
.get((pos + Vec3::new(pos.z, pos.z, 0)) / Vec3::new(2, 2, 1))
% *range as u32) as u8,
)),
Fill::Prefab(p, tr, seed) => p.get(pos - tr).ok().and_then(|sb| {
let info = canvas.info;
let col_sample = info.col(info.wpos)?;
block_from_structure(
canvas.index,
*sb,
pos - tr,
info.wpos,
*seed,
col_sample,
Block::air,
)
}),
}
} else {
None
@ -180,6 +207,7 @@ impl Fill {
min: Vec3::broadcast(std::i32::MIN),
max: Vec3::broadcast(std::i32::MAX),
},
Primitive::Prefab(p) => p.get_bounds(),
Primitive::And(a, b) => or_zip_with(
self.get_bounds_inner(tree, *a),
self.get_bounds_inner(tree, *b),

View File

@ -276,18 +276,19 @@ impl Site {
});
}
pub fn name(&self) -> &str {
&self.name
}
pub fn name(&self) -> &str { &self.name }
pub fn difficulty(&self) -> Option<u32> {
self.plots.iter().filter_map(|(_, plot)| {
if let PlotKind::Dungeon(d) = &plot.kind {
Some(d.difficulty())
} else {
None
}
}).max()
self.plots
.iter()
.filter_map(|(_, plot)| {
if let PlotKind::Dungeon(d) = &plot.kind {
Some(d.difficulty())
} else {
None
}
})
.max()
}
pub fn generate_dungeon(land: &Land, rng: &mut impl Rng, origin: Vec2<i32>) -> Self {
@ -763,9 +764,14 @@ impl Site {
PlotKind::Castle(castle) => castle.render_collect(self),
PlotKind::Dungeon(dungeon) => {
let (prim_tree, fills) = dungeon.render_collect(self);
tracing::info!("{:?}: {:?} {:?}", dungeon.name(), prim_tree.ids().count(), fills.len());
tracing::info!(
"{:?}: {:?} {:?}",
dungeon.name(),
prim_tree.ids().count(),
fills.len()
);
(prim_tree, fills)
}
},
_ => continue,
};
@ -777,7 +783,7 @@ impl Site {
for z in aabb.min.z..aabb.max.z {
let pos = Vec3::new(x, y, z);
if let Some(block) = fill.sample_at(&prim_tree, prim, pos) {
if let Some(block) = fill.sample_at(&prim_tree, prim, pos, &canvas) {
canvas.set(pos, block);
}
}

View File

@ -15,7 +15,8 @@ use common::{
generation::{ChunkSupplement, EntityInfo},
store::{Id, Store},
terrain::{
Block, BlockKind, SpriteKind, Structure, structure::StructureBlock, StructuresGroup, TerrainChunkSize,
structure::StructureBlock, Block, BlockKind, SpriteKind, Structure, StructuresGroup,
TerrainChunkSize,
},
vol::{BaseVol, ReadVol, RectSizedVol, RectVolSize, WriteVol},
};
@ -1245,9 +1246,10 @@ impl SiteStructure for Dungeon {
TILE_SIZE as f32 / 2.0,
tweak!(27.0),
)));
let stairs_radius = 7;
let bounding_box = prim(Primitive::Aabb(Aabb {
min: origin - Vec3::new(8, 8, self.alt - 1),
max: origin + Vec3::new(8, 8, 400),
min: origin - Vec3::new(stairs_radius, stairs_radius, self.alt - 1),
max: origin + Vec3::new(stairs_radius, stairs_radius, 400),
}));
//let stairs_inf = prim(Primitive::Sampling(Box::new(|_| true)));
let stairs = prim(Primitive::And(bounding_box, stairs_inf));
@ -1269,7 +1271,7 @@ impl SiteStructure for Dungeon {
let entrances = ENTRANCES.read();
let entrance = entrances[self.seed as usize % entrances.len()].clone();
let entrance_aabb = prim(Primitive::Aabb(entrance.get_bounds()));
/*let entrance_aabb = prim(Primitive::Aabb(entrance.get_bounds()));
let entrance = prim(Primitive::Sampling(Box::new(move |pos| {
entrance
.get(pos)
@ -1277,7 +1279,12 @@ impl SiteStructure for Dungeon {
})));
let entrance = prim(Primitive::And(entrance, entrance_aabb));
let entrance = prim(Primitive::Translate(entrance, origin));
fill(entrance, Fill::Block(stone_red));
fill(entrance, Fill::Block(stone_red));*/
let entrance_prim = prim(Primitive::Prefab(entrance.clone()));
let entrance_prim = prim(Primitive::Translate(entrance_prim, origin));
let entrance_prim = prim(Primitive::Diff(entrance_prim, bounding_box));
//fill(entrance_prim, Fill::Block(stone_red));
fill(entrance_prim, Fill::Prefab(entrance, origin, self.seed));
/*let make_staircase = move |kind: &StairsKind,
pos: Vec3<i32>,