mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Better house roofs
This commit is contained in:
parent
eb3cc2fd22
commit
78aa587722
@ -29,7 +29,7 @@ opt-level = 2
|
|||||||
overflow-checks = true
|
overflow-checks = true
|
||||||
debug-assertions = true
|
debug-assertions = true
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
debug = false
|
debug = true
|
||||||
codegen-units = 8
|
codegen-units = 8
|
||||||
lto = false
|
lto = false
|
||||||
# TEMP false to avoid fingerprints bug
|
# TEMP false to avoid fingerprints bug
|
||||||
|
@ -108,7 +108,7 @@ impl Civs {
|
|||||||
attempt(5, || {
|
attempt(5, || {
|
||||||
let (kind, size) = match ctx.rng.gen_range(0..64) {
|
let (kind, size) = match ctx.rng.gen_range(0..64) {
|
||||||
0..=4 => (SiteKind::Castle, 3),
|
0..=4 => (SiteKind::Castle, 3),
|
||||||
// 5..=28 => (SiteKind::Refactor, 6),
|
5..=28 => (SiteKind::Refactor, 6),
|
||||||
29..=31 => (SiteKind::Tree, 4),
|
29..=31 => (SiteKind::Tree, 4),
|
||||||
_ => (SiteKind::Dungeon, 0),
|
_ => (SiteKind::Dungeon, 0),
|
||||||
};
|
};
|
||||||
|
@ -10,9 +10,12 @@ use vek::*;
|
|||||||
pub enum Primitive {
|
pub enum Primitive {
|
||||||
Empty, // Placeholder
|
Empty, // Placeholder
|
||||||
|
|
||||||
|
Plot, // A primitive that fits the floor plan of the plot
|
||||||
|
Void, // A primitive that fits the floor plan of void tiles
|
||||||
|
|
||||||
// Shapes
|
// Shapes
|
||||||
Aabb(Aabb<i32>),
|
Aabb(Aabb<i32>),
|
||||||
Pyramid { aabb: Aabb<i32>, inset: i32 },
|
Pyramid { aabb: Aabb<i32>, inset: Vec2<i32> },
|
||||||
Cylinder(Aabb<i32>),
|
Cylinder(Aabb<i32>),
|
||||||
Cone(Aabb<i32>),
|
Cone(Aabb<i32>),
|
||||||
Sphere(Aabb<i32>),
|
Sphere(Aabb<i32>),
|
||||||
@ -20,21 +23,31 @@ pub enum Primitive {
|
|||||||
|
|
||||||
// Combinators
|
// Combinators
|
||||||
And(Id<Primitive>, Id<Primitive>),
|
And(Id<Primitive>, Id<Primitive>),
|
||||||
|
AndNot(Id<Primitive>, Id<Primitive>), // Not second
|
||||||
Or(Id<Primitive>, Id<Primitive>),
|
Or(Id<Primitive>, Id<Primitive>),
|
||||||
Xor(Id<Primitive>, Id<Primitive>),
|
Xor(Id<Primitive>, Id<Primitive>),
|
||||||
// Not commutative
|
// Not commutative
|
||||||
Diff(Id<Primitive>, Id<Primitive>),
|
Diff(Id<Primitive>, Id<Primitive>),
|
||||||
// Operators
|
// Operators
|
||||||
Rotate(Id<Primitive>, Mat3<i32>),
|
Rotate(Id<Primitive>, Mat3<i32>),
|
||||||
|
Offset(Id<Primitive>, Vec3<i32>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub enum Fill {
|
pub enum Fill {
|
||||||
Block(Block),
|
Block(Block),
|
||||||
Brick(BlockKind, Rgb<u8>, u8),
|
Brick(BlockKind, Rgb<u8>, u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fill {
|
impl Fill {
|
||||||
fn contains_at(&self, tree: &Store<Primitive>, prim: Id<Primitive>, pos: Vec3<i32>) -> bool {
|
fn contains_at(
|
||||||
|
&self,
|
||||||
|
tree: &Store<Primitive>,
|
||||||
|
prim: Id<Primitive>,
|
||||||
|
pos: Vec3<i32>,
|
||||||
|
is_plot: &impl Fn(Vec2<i32>) -> bool,
|
||||||
|
is_void: &impl Fn(Vec2<i32>) -> bool,
|
||||||
|
) -> bool {
|
||||||
// Custom closure because vek's impl of `contains_point` is inclusive :(
|
// Custom closure because vek's impl of `contains_point` is inclusive :(
|
||||||
let aabb_contains = |aabb: Aabb<i32>, pos: Vec3<i32>| {
|
let aabb_contains = |aabb: Aabb<i32>, pos: Vec3<i32>| {
|
||||||
(aabb.min.x..aabb.max.x).contains(&pos.x)
|
(aabb.min.x..aabb.max.x).contains(&pos.x)
|
||||||
@ -45,18 +58,21 @@ impl Fill {
|
|||||||
match &tree[prim] {
|
match &tree[prim] {
|
||||||
Primitive::Empty => false,
|
Primitive::Empty => false,
|
||||||
|
|
||||||
|
Primitive::Plot => is_plot(pos.xy()),
|
||||||
|
Primitive::Void => is_void(pos.xy()),
|
||||||
|
|
||||||
Primitive::Aabb(aabb) => aabb_contains(*aabb, pos),
|
Primitive::Aabb(aabb) => aabb_contains(*aabb, pos),
|
||||||
Primitive::Pyramid { aabb, inset } => {
|
Primitive::Pyramid { aabb, inset } => {
|
||||||
let inset = (*inset).max(aabb.size().reduce_min());
|
let inset = inset.map2(Vec2::new(aabb.size().w, aabb.size().h), |i, sz| i.min(sz));
|
||||||
let inner = Aabr {
|
let inner = Aabr {
|
||||||
min: aabb.min.xy() - 1 + inset,
|
min: aabb.min.xy() - 1 + inset,
|
||||||
max: aabb.max.xy() - inset,
|
max: aabb.max.xy() - inset,
|
||||||
};
|
};
|
||||||
aabb_contains(*aabb, pos)
|
aabb_contains(*aabb, pos)
|
||||||
&& (inner.projected_point(pos.xy()) - pos.xy())
|
&& ((inner.projected_point(pos.xy()) - pos.xy())
|
||||||
.map(|e| e.abs())
|
.map(|e| e.abs())
|
||||||
.reduce_max() as f32
|
.map2(inset, |e, i| e as f32 / (i as f32).max(0.00001))
|
||||||
/ (inset as f32)
|
.reduce_partial_max() as f32)
|
||||||
< 1.0
|
< 1.0
|
||||||
- ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
|
- ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
|
||||||
},
|
},
|
||||||
@ -96,21 +112,38 @@ impl Fill {
|
|||||||
.dot(*gradient) as i32)
|
.dot(*gradient) as i32)
|
||||||
},
|
},
|
||||||
Primitive::And(a, b) => {
|
Primitive::And(a, b) => {
|
||||||
self.contains_at(tree, *a, pos) && self.contains_at(tree, *b, pos)
|
self.contains_at(tree, *a, pos, is_plot, is_void)
|
||||||
|
&& self.contains_at(tree, *b, pos, is_plot, is_void)
|
||||||
|
},
|
||||||
|
Primitive::AndNot(a, b) => {
|
||||||
|
self.contains_at(tree, *a, pos, is_plot, is_void)
|
||||||
|
&& !self.contains_at(tree, *b, pos, is_plot, is_void)
|
||||||
},
|
},
|
||||||
Primitive::Or(a, b) => {
|
Primitive::Or(a, b) => {
|
||||||
self.contains_at(tree, *a, pos) || self.contains_at(tree, *b, pos)
|
self.contains_at(tree, *a, pos, is_plot, is_void)
|
||||||
|
|| self.contains_at(tree, *b, pos, is_plot, is_void)
|
||||||
},
|
},
|
||||||
Primitive::Xor(a, b) => {
|
Primitive::Xor(a, b) => {
|
||||||
self.contains_at(tree, *a, pos) ^ self.contains_at(tree, *b, pos)
|
self.contains_at(tree, *a, pos, is_plot, is_void)
|
||||||
|
^ self.contains_at(tree, *b, pos, is_plot, is_void)
|
||||||
},
|
},
|
||||||
Primitive::Diff(a, b) => {
|
Primitive::Diff(a, b) => {
|
||||||
self.contains_at(tree, *a, pos) && !self.contains_at(tree, *b, pos)
|
self.contains_at(tree, *a, pos, is_plot, is_void)
|
||||||
|
&& !self.contains_at(tree, *b, pos, is_plot, is_void)
|
||||||
},
|
},
|
||||||
Primitive::Rotate(prim, mat) => {
|
Primitive::Rotate(prim, mat) => {
|
||||||
let aabb = self.get_bounds(tree, *prim);
|
let aabb = self.get_bounds(tree, *prim);
|
||||||
let diff = pos - (aabb.min + mat.cols.map(|x| x.reduce_min()));
|
let diff = pos - (aabb.min + mat.cols.map(|x| x.reduce_min()));
|
||||||
self.contains_at(tree, *prim, aabb.min + mat.transposed() * diff)
|
self.contains_at(
|
||||||
|
tree,
|
||||||
|
*prim,
|
||||||
|
aabb.min + mat.transposed() * diff,
|
||||||
|
is_plot,
|
||||||
|
is_void,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
Primitive::Offset(prim, offset) => {
|
||||||
|
self.contains_at(tree, *prim, pos - offset, is_plot, is_void)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,8 +153,10 @@ impl Fill {
|
|||||||
tree: &Store<Primitive>,
|
tree: &Store<Primitive>,
|
||||||
prim: Id<Primitive>,
|
prim: Id<Primitive>,
|
||||||
pos: Vec3<i32>,
|
pos: Vec3<i32>,
|
||||||
|
is_plot: impl Fn(Vec2<i32>) -> bool,
|
||||||
|
is_void: impl Fn(Vec2<i32>) -> bool,
|
||||||
) -> Option<Block> {
|
) -> Option<Block> {
|
||||||
if self.contains_at(tree, prim, pos) {
|
if self.contains_at(tree, prim, pos, &is_plot, &is_void) {
|
||||||
match self {
|
match self {
|
||||||
Fill::Block(block) => Some(*block),
|
Fill::Block(block) => Some(*block),
|
||||||
Fill::Brick(bk, col, range) => Some(Block::new(
|
Fill::Brick(bk, col, range) => Some(Block::new(
|
||||||
@ -146,7 +181,7 @@ impl Fill {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Some(match &tree[prim] {
|
Some(match &tree[prim] {
|
||||||
Primitive::Empty => return None,
|
Primitive::Empty | Primitive::Plot | Primitive::Void => return None,
|
||||||
Primitive::Aabb(aabb) => *aabb,
|
Primitive::Aabb(aabb) => *aabb,
|
||||||
Primitive::Pyramid { aabb, .. } => *aabb,
|
Primitive::Pyramid { aabb, .. } => *aabb,
|
||||||
Primitive::Cylinder(aabb) => *aabb,
|
Primitive::Cylinder(aabb) => *aabb,
|
||||||
@ -174,6 +209,7 @@ impl Fill {
|
|||||||
self.get_bounds_inner(tree, *b),
|
self.get_bounds_inner(tree, *b),
|
||||||
|a, b| a.intersection(b),
|
|a, b| a.intersection(b),
|
||||||
)?,
|
)?,
|
||||||
|
Primitive::AndNot(a, _) => self.get_bounds_inner(tree, *a)?,
|
||||||
Primitive::Or(a, b) | Primitive::Xor(a, b) => or_zip_with(
|
Primitive::Or(a, b) | Primitive::Xor(a, b) => or_zip_with(
|
||||||
self.get_bounds_inner(tree, *a),
|
self.get_bounds_inner(tree, *a),
|
||||||
self.get_bounds_inner(tree, *b),
|
self.get_bounds_inner(tree, *b),
|
||||||
@ -189,6 +225,13 @@ impl Fill {
|
|||||||
};
|
};
|
||||||
new_aabb.made_valid()
|
new_aabb.made_valid()
|
||||||
},
|
},
|
||||||
|
Primitive::Offset(prim, offset) => {
|
||||||
|
let aabb = self.get_bounds_inner(tree, *prim)?;
|
||||||
|
Aabb {
|
||||||
|
min: aabb.min - offset,
|
||||||
|
max: aabb.max - offset,
|
||||||
|
}
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ impl Site {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn bounds(&self) -> Aabr<i32> {
|
pub fn bounds(&self) -> Aabr<i32> {
|
||||||
let border = 1;
|
let border = 2;
|
||||||
Aabr {
|
Aabr {
|
||||||
min: self.origin + self.tile_wpos(self.tiles.bounds.min - border),
|
min: self.origin + self.tile_wpos(self.tiles.bounds.min - border),
|
||||||
max: self.origin + self.tile_wpos(self.tiles.bounds.max + 1 + border),
|
max: self.origin + self.tile_wpos(self.tiles.bounds.max + 1 + border),
|
||||||
@ -287,7 +287,7 @@ impl Site {
|
|||||||
|
|
||||||
site.make_plaza(land, &mut rng);
|
site.make_plaza(land, &mut rng);
|
||||||
|
|
||||||
let build_chance = Lottery::from(vec![(64.0, 1), (5.0, 2), (8.0, 3), (0.75, 4)]);
|
let build_chance = Lottery::from(vec![(128.0, 1), (5.0, 2), (8.0, 3), (0.75, 4)]);
|
||||||
|
|
||||||
let mut castles = 0;
|
let mut castles = 0;
|
||||||
|
|
||||||
@ -606,8 +606,8 @@ impl Site {
|
|||||||
if let TileKind::Road { a, b, w } = &tile.kind {
|
if let TileKind::Road { a, b, w } = &tile.kind {
|
||||||
if let Some(PlotKind::Road(path)) = tile.plot.map(|p| &self.plot(p).kind) {
|
if let Some(PlotKind::Road(path)) = tile.plot.map(|p| &self.plot(p).kind) {
|
||||||
Some((LineSegment2 {
|
Some((LineSegment2 {
|
||||||
start: self.tile_center_wpos(path.nodes()[*a as usize]).map(|e| e as f32),
|
start: self.tile_center_wpos(path.nodes()[*a as usize]).map(|e| e as f32) - TILE_SIZE as f32 / 2.0,
|
||||||
end: self.tile_center_wpos(path.nodes()[*b as usize]).map(|e| e as f32),
|
end: self.tile_center_wpos(path.nodes()[*b as usize]).map(|e| e as f32) - TILE_SIZE as f32 / 2.0,
|
||||||
}, *w))
|
}, *w))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -622,16 +622,19 @@ impl Site {
|
|||||||
.map(|(line, w)| (line.distance_to_point(wpos2df) - w as f32 * 2.0).max(0.0))
|
.map(|(line, w)| (line.distance_to_point(wpos2df) - w as f32 * 2.0).max(0.0))
|
||||||
.min_by_key(|d| (*d * 100.0) as i32);
|
.min_by_key(|d| (*d * 100.0) as i32);
|
||||||
|
|
||||||
if dist.map_or(false, |d| d <= 0.75) {
|
if let Some(col) = canvas.col(wpos2d).filter(|_| dist.map_or(false, |d| d <= 0.75)) {
|
||||||
let alt = canvas.col(wpos2d).map_or(0, |col| col.alt as i32);
|
let surf = col.alt.max(col.water_level + 5.0) as i32;
|
||||||
|
let is_pier = col.water_dist.map_or(false, |d| d < 3.0);
|
||||||
(-6..4).for_each(|z| canvas.map(
|
(-6..4).for_each(|z| canvas.map(
|
||||||
Vec3::new(wpos2d.x, wpos2d.y, alt + z),
|
Vec3::new(wpos2d.x, wpos2d.y, surf + z),
|
||||||
|b| if z >= 0 {
|
|b| if z >= 0 {
|
||||||
if b.is_filled() {
|
if b.is_filled() {
|
||||||
Block::empty()
|
Block::empty()
|
||||||
} else {
|
} else {
|
||||||
b.with_sprite(SpriteKind::Empty)
|
b.with_sprite(SpriteKind::Empty)
|
||||||
}
|
}
|
||||||
|
} else if is_pier {
|
||||||
|
Block::new(BlockKind::Wood, Rgb::new(110, 65, 15))
|
||||||
} else {
|
} else {
|
||||||
Block::new(BlockKind::Rock, Rgb::new(55, 45, 50))
|
Block::new(BlockKind::Rock, Rgb::new(55, 45, 50))
|
||||||
},
|
},
|
||||||
@ -720,8 +723,12 @@ impl Site {
|
|||||||
for y in aabb.min.y..aabb.max.y {
|
for y in aabb.min.y..aabb.max.y {
|
||||||
for z in aabb.min.z..aabb.max.z {
|
for z in aabb.min.z..aabb.max.z {
|
||||||
let pos = Vec3::new(x, y, z);
|
let pos = Vec3::new(x, y, z);
|
||||||
|
let is_plot = self.wpos_tile(pos.xy()).plot == Some(plot);
|
||||||
|
let is_void = self.wpos_tile(pos.xy()).is_void();
|
||||||
|
|
||||||
if let Some(block) = fill.sample_at(&prim_tree, prim, pos) {
|
if let Some(block) =
|
||||||
|
fill.sample_at(&prim_tree, prim, pos, |_| is_plot, |_| is_void)
|
||||||
|
{
|
||||||
canvas.set(pos, block);
|
canvas.set(pos, block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ impl Structure for Castle {
|
|||||||
max: (wpos + ts + 3 + roof_lip)
|
max: (wpos + ts + 3 + roof_lip)
|
||||||
.with_z(tower_total_height + roof_height),
|
.with_z(tower_total_height + roof_height),
|
||||||
},
|
},
|
||||||
inset: roof_height,
|
inset: Vec2::broadcast(roof_height),
|
||||||
}),
|
}),
|
||||||
Fill::Brick(BlockKind::Wood, Rgb::new(40, 5, 11), 10),
|
Fill::Brick(BlockKind::Wood, Rgb::new(40, 5, 11), 10),
|
||||||
);
|
);
|
||||||
|
@ -11,6 +11,7 @@ pub struct House {
|
|||||||
alt: i32,
|
alt: i32,
|
||||||
levels: u32,
|
levels: u32,
|
||||||
roof_color: Rgb<u8>,
|
roof_color: Rgb<u8>,
|
||||||
|
roof_inset: Vec2<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl House {
|
impl House {
|
||||||
@ -42,6 +43,11 @@ impl House {
|
|||||||
];
|
];
|
||||||
*colors.choose(rng).unwrap()
|
*colors.choose(rng).unwrap()
|
||||||
},
|
},
|
||||||
|
roof_inset: match rng.gen_range(0..3) {
|
||||||
|
0 => Vec2::new(true, false),
|
||||||
|
1 => Vec2::new(false, true),
|
||||||
|
_ => Vec2::new(true, true),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,6 +62,13 @@ impl Structure for House {
|
|||||||
let storey = 5;
|
let storey = 5;
|
||||||
let roof = storey * self.levels as i32;
|
let roof = storey * self.levels as i32;
|
||||||
let foundations = 12;
|
let foundations = 12;
|
||||||
|
let plot = prim(Primitive::Plot);
|
||||||
|
let void = prim(Primitive::Void);
|
||||||
|
let can_spill = prim(Primitive::Or(plot, void));
|
||||||
|
|
||||||
|
//let wall_block = Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24);
|
||||||
|
let wall_block = Fill::Brick(BlockKind::Rock, Rgb::new(158, 150, 121), 24);
|
||||||
|
let structural_wood = Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8)));
|
||||||
|
|
||||||
// Walls
|
// Walls
|
||||||
let inner = prim(Primitive::Aabb(Aabb {
|
let inner = prim(Primitive::Aabb(Aabb {
|
||||||
@ -66,10 +79,7 @@ impl Structure for House {
|
|||||||
min: self.bounds.min.with_z(self.alt - foundations),
|
min: self.bounds.min.with_z(self.alt - foundations),
|
||||||
max: (self.bounds.max + 1).with_z(self.alt + roof),
|
max: (self.bounds.max + 1).with_z(self.alt + roof),
|
||||||
}));
|
}));
|
||||||
fill(
|
fill(outer, wall_block);
|
||||||
outer,
|
|
||||||
Fill::Brick(BlockKind::Rock, Rgb::new(80, 75, 85), 24),
|
|
||||||
);
|
|
||||||
fill(inner, Fill::Block(Block::empty()));
|
fill(inner, Fill::Block(Block::empty()));
|
||||||
let walls = prim(Primitive::Xor(outer, inner));
|
let walls = prim(Primitive::Xor(outer, inner));
|
||||||
|
|
||||||
@ -97,10 +107,7 @@ impl Structure for House {
|
|||||||
pillars_x = prim(Primitive::Or(pillars_x, pillar));
|
pillars_x = prim(Primitive::Or(pillars_x, pillar));
|
||||||
}
|
}
|
||||||
let pillars = prim(Primitive::And(pillars_x, pillars_y));
|
let pillars = prim(Primitive::And(pillars_x, pillars_y));
|
||||||
fill(
|
fill(pillars, structural_wood);
|
||||||
pillars,
|
|
||||||
Fill::Block(Block::new(BlockKind::Wood, Rgb::new(55, 25, 8))),
|
|
||||||
);
|
|
||||||
|
|
||||||
// For each storey...
|
// For each storey...
|
||||||
for i in 0..self.levels + 1 {
|
for i in 0..self.levels + 1 {
|
||||||
@ -147,13 +154,20 @@ impl Structure for House {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Floor
|
// Floor
|
||||||
fill(
|
let floor = prim(Primitive::Aabb(Aabb {
|
||||||
prim(Primitive::Aabb(Aabb {
|
|
||||||
min: (self.bounds.min + 1).with_z(self.alt + height),
|
min: (self.bounds.min + 1).with_z(self.alt + height),
|
||||||
max: self.bounds.max.with_z(self.alt + height + 1),
|
max: self.bounds.max.with_z(self.alt + height + 1),
|
||||||
})),
|
}));
|
||||||
|
fill(
|
||||||
|
floor,
|
||||||
Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
|
Fill::Block(Block::new(BlockKind::Rock, Rgb::new(89, 44, 14))),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let slice = prim(Primitive::Aabb(Aabb {
|
||||||
|
min: self.bounds.min.with_z(self.alt + height),
|
||||||
|
max: (self.bounds.max + 1).with_z(self.alt + height + 1),
|
||||||
|
}));
|
||||||
|
fill(prim(Primitive::AndNot(slice, floor)), structural_wood);
|
||||||
}
|
}
|
||||||
|
|
||||||
let roof_lip = 2;
|
let roof_lip = 2;
|
||||||
@ -165,23 +179,32 @@ impl Structure for House {
|
|||||||
+ 1;
|
+ 1;
|
||||||
|
|
||||||
// Roof
|
// Roof
|
||||||
fill(
|
let roof_vol = prim(Primitive::Pyramid {
|
||||||
prim(Primitive::Pyramid {
|
|
||||||
aabb: Aabb {
|
aabb: Aabb {
|
||||||
min: (self.bounds.min - roof_lip).with_z(self.alt + roof),
|
min: (self.bounds.min - roof_lip).with_z(self.alt + roof),
|
||||||
max: (self.bounds.max + 1 + roof_lip).with_z(self.alt + roof + roof_height),
|
max: (self.bounds.max + 1 + roof_lip).with_z(self.alt + roof + roof_height),
|
||||||
},
|
},
|
||||||
inset: roof_height,
|
inset: self.roof_inset.map(|e| if e { roof_height } else { 0 }),
|
||||||
}),
|
});
|
||||||
|
let eaves = prim(Primitive::Offset(roof_vol, -Vec3::unit_z()));
|
||||||
|
let tiles = prim(Primitive::AndNot(roof_vol, eaves));
|
||||||
|
fill(
|
||||||
|
prim(Primitive::And(tiles, can_spill)),
|
||||||
Fill::Block(Block::new(BlockKind::Wood, self.roof_color)),
|
Fill::Block(Block::new(BlockKind::Wood, self.roof_color)),
|
||||||
);
|
);
|
||||||
|
let roof_inner = prim(Primitive::Aabb(Aabb {
|
||||||
|
min: self.bounds.min.with_z(self.alt + roof),
|
||||||
|
max: (self.bounds.max + 1).with_z(self.alt + roof + roof_height),
|
||||||
|
}));
|
||||||
|
fill(prim(Primitive::And(eaves, roof_inner)), wall_block);
|
||||||
|
|
||||||
// Foundations
|
// Foundations
|
||||||
fill(
|
let foundations = prim(Primitive::Aabb(Aabb {
|
||||||
prim(Primitive::Aabb(Aabb {
|
|
||||||
min: (self.bounds.min - 1).with_z(self.alt - foundations),
|
min: (self.bounds.min - 1).with_z(self.alt - foundations),
|
||||||
max: (self.bounds.max + 2).with_z(self.alt + 1),
|
max: (self.bounds.max + 2).with_z(self.alt + 1),
|
||||||
})),
|
}));
|
||||||
|
fill(
|
||||||
|
prim(Primitive::And(foundations, can_spill)),
|
||||||
Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
|
Fill::Block(Block::new(BlockKind::Rock, Rgb::new(31, 33, 32))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -210,9 +210,16 @@ impl Tile {
|
|||||||
pub fn is_road(&self) -> bool { matches!(self.kind, TileKind::Road { .. }) }
|
pub fn is_road(&self) -> bool { matches!(self.kind, TileKind::Road { .. }) }
|
||||||
|
|
||||||
pub fn is_obstacle(&self) -> bool {
|
pub fn is_obstacle(&self) -> bool {
|
||||||
matches!(
|
match self.kind {
|
||||||
|
TileKind::Hazard(_) => true,
|
||||||
|
_ => !self.is_void(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_void(&self) -> bool {
|
||||||
|
!matches!(
|
||||||
self.kind,
|
self.kind,
|
||||||
TileKind::Hazard(_) | TileKind::Building | TileKind::Castle | TileKind::Wall(_)
|
TileKind::Building | TileKind::Castle | TileKind::Wall(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user