diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs index 8d04340585..804144d234 100644 --- a/world/src/site2/gen.rs +++ b/world/src/site2/gen.rs @@ -12,6 +12,7 @@ use common::{ }, vol::ReadVol, }; +use num::cast::AsPrimitive; use std::{cell::RefCell, sync::Arc}; use vek::*; @@ -41,7 +42,7 @@ pub enum Primitive { Sphere(Aabb), Plane(Aabr, Vec3, Vec2), /// A line segment from start to finish point with a given radius - Segment(LineSegment3, f32), + Segment(LineSegment3, f32), /// A sampling function is always a subset of another primitive to avoid /// needing infinite bounds Sampling(Id, Box) -> bool>), @@ -56,6 +57,9 @@ pub enum Primitive { Rotate(Id, Mat3), Translate(Id, Vec3), Scale(Id, Vec3), + /// Repeat a primitive a number of times in a given direction, overlapping + /// between repeats are unspecified. + Repeat(Id, Vec3, i32), } impl Primitive { @@ -86,6 +90,10 @@ impl Primitive { pub fn scale(a: impl Into>, scale: Vec3) -> Self { Self::Scale(a.into(), scale) } + + pub fn repeat(a: impl Into>, offset: Vec3, count: i32) -> Self { + Self::Repeat(a.into(), offset, count) + } } #[derive(Clone)] @@ -217,7 +225,7 @@ impl Fill { && (segment.start.y..segment.end.y).contains(&pos.y) && (segment.start.z..segment.end.z).contains(&pos.z) &&*/ - segment.as_().distance_to_point(pos.map(|e| e as f32)) < radius - 0.25 + segment.distance_to_point(pos.map(|e| e as f32)) < radius - 0.25 }, Primitive::Sampling(a, f) => self.contains_at(tree, *a, pos) && f(pos), Primitive::Prefab(p) => !matches!(p.get(pos), Err(_) | Ok(StructureBlock::None)), @@ -247,6 +255,16 @@ impl Fill { .as_::(); self.contains_at(tree, *prim, spos) }, + Primitive::Repeat(prim, offset, count) => { + let aabb = self.get_bounds(tree, *prim); + let diff = pos - aabb.min; + let min = diff + .map2(*offset, |a, b| if b == 0 { i32::MAX } else { a / b }) + .reduce_min() + .min(*count); + let pos = aabb.min + diff - offset * min; + self.contains_at(tree, *prim, pos) + }, } } @@ -329,8 +347,8 @@ impl Fill { aabb.made_valid() }, Primitive::Segment(segment, radius) => Aabb { - min: segment.start - radius.floor() as i32, - max: segment.end + radius.ceil() as i32, + min: (segment.start - *radius).floor().as_(), + max: (segment.end + *radius).ceil().as_(), }, Primitive::Sampling(a, _) => self.get_bounds_inner(tree, *a)?, Primitive::Prefab(p) => p.get_bounds(), @@ -369,6 +387,13 @@ impl Fill { max: center + ((aabb.max - center).as_::() * vec).as_::(), } }, + Primitive::Repeat(prim, offset, count) => { + let aabb = self.get_bounds_inner(tree, *prim)?; + Aabb { + min: aabb.min.map2(aabb.min + offset * count, |a, b| a.min(b)), + max: aabb.max.map2(aabb.max + offset * count, |a, b| a.max(b)), + } + }, }) } @@ -386,9 +411,17 @@ pub struct Painter { impl Painter { pub fn aabb(&self, aabb: Aabb) -> PrimitiveRef { self.prim(Primitive::Aabb(aabb)) } - pub fn line(&self, a: Vec3, b: Vec3, radius: f32) -> PrimitiveRef { + pub fn line( + &self, + a: Vec3>, + b: Vec3>, + radius: f32, + ) -> PrimitiveRef { self.prim(Primitive::Segment( - LineSegment3 { start: a, end: b }, + LineSegment3 { + start: a.as_(), + end: b.as_(), + }, radius, )) } @@ -468,6 +501,10 @@ impl<'a> PrimitiveRef<'a> { self.painter .prim(Primitive::sampling(self, Box::new(sampling))) } + + pub fn repeat(self, offset: Vec3, count: i32) -> PrimitiveRef<'a> { + self.painter.prim(Primitive::repeat(self, offset, count)) + } } pub trait Structure { diff --git a/world/src/site2/plot/house.rs b/world/src/site2/plot/house.rs index c49ba1168f..bd13677a77 100644 --- a/world/src/site2/plot/house.rs +++ b/world/src/site2/plot/house.rs @@ -619,21 +619,19 @@ impl Structure for House { // something to do with AABBs with min and max not smaller in the right // order. The same thing is true for orientation 3. let support = match self.front { - 0 => painter.prim(Primitive::Segment( - LineSegment3 { - start: Vec2::new( - temp.x, - self.bounds.max.y + storey_increase - self.overhang + 1, - ) - .with_z(alt + previous_height - 3), - end: Vec2::new( - temp.x, - self.bounds.max.y + storey_increase - self.overhang + 2, - ) - .with_z(alt + previous_height), - }, + 0 => painter.line( + Vec2::new( + temp.x, + self.bounds.max.y + storey_increase - self.overhang + 1, + ) + .with_z(alt + previous_height - 3), + Vec2::new( + temp.x, + self.bounds.max.y + storey_increase - self.overhang + 2, + ) + .with_z(alt + previous_height), 0.75, - )), + ), //2 => { // painter.prim(Primitive::Segment(LineSegment3 { // start: Vec2::new(temp.x, self.bounds.min.y - storey_increase - @@ -669,37 +667,33 @@ impl Structure for House { }; let support = match self.front { 0 => painter.prim(Primitive::Empty), - 1 => painter.prim(Primitive::Segment( - LineSegment3 { - start: Vec2::new( - self.bounds.max.x + storey_increase - self.overhang + 1, - temp.y, - ) - .with_z(alt + previous_height - 3), - end: Vec2::new( - self.bounds.max.x + storey_increase - self.overhang + 2, - temp.y, - ) - .with_z(alt + previous_height), - }, + 1 => painter.line( + Vec2::new( + self.bounds.max.x + storey_increase - self.overhang + 1, + temp.y, + ) + .with_z(alt + previous_height - 3), + Vec2::new( + self.bounds.max.x + storey_increase - self.overhang + 2, + temp.y, + ) + .with_z(alt + previous_height), 0.75, - )), + ), 2 => painter.prim(Primitive::Empty), - _ => painter.prim(Primitive::Segment( - LineSegment3 { - start: Vec2::new( - self.bounds.min.x - storey_increase + self.overhang - 1, - temp.y, - ) - .with_z(alt + previous_height - 3), - end: Vec2::new( - self.bounds.min.x - storey_increase + self.overhang - 2, - temp.y, - ) - .with_z(alt + previous_height), - }, + _ => painter.line( + Vec2::new( + self.bounds.min.x - storey_increase + self.overhang - 1, + temp.y, + ) + .with_z(alt + previous_height - 3), + Vec2::new( + self.bounds.min.x - storey_increase + self.overhang - 2, + temp.y, + ) + .with_z(alt + previous_height), 0.75, - )), + ), }; if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y { overhang_supports =