From 7749b67d6773292b40b8e6bf61df4ce8cc303ecc Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 28 Feb 2021 23:59:04 +0000 Subject: [PATCH] Added CSG house roofs --- world/src/site2/gen.rs | 20 +++++++++++++++++++- world/src/site2/mod.rs | 6 +++--- world/src/site2/plot/house.rs | 23 +++++++++++++++++++++-- 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs index c6f94d34e8..2d8d3d94bb 100644 --- a/world/src/site2/gen.rs +++ b/world/src/site2/gen.rs @@ -6,7 +6,12 @@ use vek::*; pub enum Primitive { Empty, // Placeholder + + // Shapes Aabb(Aabb), + Pyramid { aabb: Aabb, inset: i32 }, + + // Combinators And(Id, Id), Or(Id, Id), Xor(Id, Id), @@ -19,9 +24,21 @@ pub struct Fill { impl Fill { fn contains_at(&self, tree: &Store, prim: Id, pos: Vec3) -> bool { + // Custom closure because vek's impl of `contains_point` is inclusive :( + let aabb_contains = |aabb: Aabb, pos: Vec3| (aabb.min.x..aabb.max.x).contains(&pos.x) + && (aabb.min.y..aabb.max.y).contains(&pos.y); + match &tree[prim] { Primitive::Empty => false, - Primitive::Aabb(aabb) => (aabb.min.x..aabb.max.x).contains(&pos.x) && (aabb.min.y..aabb.max.y).contains(&pos.y), + + Primitive::Aabb(aabb) => aabb_contains(*aabb, pos), + Primitive::Pyramid { aabb, inset } => { + let inner = Aabr { min: aabb.min.xy() + *inset, max: aabb.max.xy() - *inset }; + aabb_contains(*aabb, pos) && (inner.projected_point(pos.xy()) - pos.xy()) + .map(|e| e.abs()) + .reduce_max() as f32 / (*inset as f32) < 1.0 - (pos.z - aabb.min.z) as f32 / (aabb.max.z - aabb.min.z) as f32 + }, + Primitive::And(a, b) => self.contains_at(tree, *a, pos) & self.contains_at(tree, *b, pos), Primitive::Or(a, b) => self.contains_at(tree, *a, pos) | self.contains_at(tree, *b, pos), Primitive::Xor(a, b) => self.contains_at(tree, *a, pos) ^ self.contains_at(tree, *b, pos), @@ -36,6 +53,7 @@ impl Fill { match &tree[prim] { Primitive::Empty => Aabb::new_empty(Vec3::zero()), Primitive::Aabb(aabb) => *aabb, + Primitive::Pyramid { aabb, .. } => *aabb, Primitive::And(a, b) => self.get_bounds_inner(tree, *a).intersection(self.get_bounds_inner(tree, *b)), Primitive::Or(a, b) | Primitive::Xor(a, b) => self.get_bounds_inner(tree, *a).union(self.get_bounds_inner(tree, *b)), } diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index d154c48ca2..7f2d4c7576 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -444,9 +444,9 @@ impl Site { for fill in fills { let aabb = fill.get_bounds(&prim_tree); - for x in aabb.min.x..aabb.max.x + 1 { - for y in aabb.min.y..aabb.max.y + 1 { - for z in aabb.min.z..aabb.max.z + 1 { + for x in aabb.min.x..aabb.max.x { + for y in aabb.min.y..aabb.max.y { + 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, pos) { diff --git a/world/src/site2/plot/house.rs b/world/src/site2/plot/house.rs index 2eb7cb37ea..6f8e04b152 100644 --- a/world/src/site2/plot/house.rs +++ b/world/src/site2/plot/house.rs @@ -27,17 +27,36 @@ impl Structure for House { mut emit_prim: F, mut emit_fill: G, ) { + let ceiling = 12; + + // Walls let wall = emit_prim(Primitive::Aabb(Aabb { min: Vec3::new(self.bounds.min.x, self.bounds.min.y, self.alt - 8), - max: Vec3::new(self.bounds.max.x, self.bounds.max.y, self.alt + 16), + max: Vec3::new(self.bounds.max.x, self.bounds.max.y, self.alt + ceiling), })); let inner = emit_prim(Primitive::Aabb(Aabb { min: Vec3::new(self.bounds.min.x + 1, self.bounds.min.y + 1, self.alt - 8), - max: Vec3::new(self.bounds.max.x - 1, self.bounds.max.y - 1, self.alt + 16), + max: Vec3::new(self.bounds.max.x - 1, self.bounds.max.y - 1, self.alt + ceiling), })); emit_fill(Fill { prim: emit_prim(Primitive::Xor(wall, inner)), block: Block::new(BlockKind::Rock, Rgb::new(150, 50, 10)), }); + + + let roof_lip = 3; + let roof_height = self.bounds.size().reduce_min() / 2 + roof_lip; + + // Roof + emit_fill(Fill { + prim: emit_prim(Primitive::Pyramid { + aabb: Aabb { + min: Vec3::new(self.bounds.min.x - roof_lip, self.bounds.min.y - roof_lip, self.alt + ceiling), + max: Vec3::new(self.bounds.max.x + roof_lip, self.bounds.max.y + roof_lip, self.alt + ceiling + roof_height), + }, + inset: roof_height, + }), + block: Block::new(BlockKind::Wood, Rgb::new(100, 80, 100)), + }); } }