Repeat CSG primitive and float line segment

This commit is contained in:
Isidor Nielsen 2022-01-28 20:04:45 +00:00 committed by Samuel Keiffer
parent cb45cea6a0
commit 6f99e70cca
2 changed files with 79 additions and 48 deletions

View File

@ -12,6 +12,7 @@ use common::{
}, },
vol::ReadVol, vol::ReadVol,
}; };
use num::cast::AsPrimitive;
use std::{cell::RefCell, sync::Arc}; use std::{cell::RefCell, sync::Arc};
use vek::*; use vek::*;
@ -41,7 +42,7 @@ pub enum Primitive {
Sphere(Aabb<i32>), Sphere(Aabb<i32>),
Plane(Aabr<i32>, Vec3<i32>, Vec2<f32>), Plane(Aabr<i32>, Vec3<i32>, Vec2<f32>),
/// A line segment from start to finish point with a given radius /// A line segment from start to finish point with a given radius
Segment(LineSegment3<i32>, f32), Segment(LineSegment3<f32>, f32),
/// A sampling function is always a subset of another primitive to avoid /// A sampling function is always a subset of another primitive to avoid
/// needing infinite bounds /// needing infinite bounds
Sampling(Id<Primitive>, Box<dyn Fn(Vec3<i32>) -> bool>), Sampling(Id<Primitive>, Box<dyn Fn(Vec3<i32>) -> bool>),
@ -56,6 +57,9 @@ pub enum Primitive {
Rotate(Id<Primitive>, Mat3<i32>), Rotate(Id<Primitive>, Mat3<i32>),
Translate(Id<Primitive>, Vec3<i32>), Translate(Id<Primitive>, Vec3<i32>),
Scale(Id<Primitive>, Vec3<f32>), Scale(Id<Primitive>, Vec3<f32>),
/// Repeat a primitive a number of times in a given direction, overlapping
/// between repeats are unspecified.
Repeat(Id<Primitive>, Vec3<i32>, i32),
} }
impl Primitive { impl Primitive {
@ -86,6 +90,10 @@ impl Primitive {
pub fn scale(a: impl Into<Id<Primitive>>, scale: Vec3<f32>) -> Self { pub fn scale(a: impl Into<Id<Primitive>>, scale: Vec3<f32>) -> Self {
Self::Scale(a.into(), scale) Self::Scale(a.into(), scale)
} }
pub fn repeat(a: impl Into<Id<Primitive>>, offset: Vec3<i32>, count: i32) -> Self {
Self::Repeat(a.into(), offset, count)
}
} }
#[derive(Clone)] #[derive(Clone)]
@ -217,7 +225,7 @@ impl Fill {
&& (segment.start.y..segment.end.y).contains(&pos.y) && (segment.start.y..segment.end.y).contains(&pos.y)
&& (segment.start.z..segment.end.z).contains(&pos.z) && (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::Sampling(a, f) => self.contains_at(tree, *a, pos) && f(pos),
Primitive::Prefab(p) => !matches!(p.get(pos), Err(_) | Ok(StructureBlock::None)), Primitive::Prefab(p) => !matches!(p.get(pos), Err(_) | Ok(StructureBlock::None)),
@ -247,6 +255,16 @@ impl Fill {
.as_::<i32>(); .as_::<i32>();
self.contains_at(tree, *prim, spos) 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() aabb.made_valid()
}, },
Primitive::Segment(segment, radius) => Aabb { Primitive::Segment(segment, radius) => Aabb {
min: segment.start - radius.floor() as i32, min: (segment.start - *radius).floor().as_(),
max: segment.end + radius.ceil() as i32, max: (segment.end + *radius).ceil().as_(),
}, },
Primitive::Sampling(a, _) => self.get_bounds_inner(tree, *a)?, Primitive::Sampling(a, _) => self.get_bounds_inner(tree, *a)?,
Primitive::Prefab(p) => p.get_bounds(), Primitive::Prefab(p) => p.get_bounds(),
@ -369,6 +387,13 @@ impl Fill {
max: center + ((aabb.max - center).as_::<f32>() * vec).as_::<i32>(), max: center + ((aabb.max - center).as_::<f32>() * vec).as_::<i32>(),
} }
}, },
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 { impl Painter {
pub fn aabb(&self, aabb: Aabb<i32>) -> PrimitiveRef { self.prim(Primitive::Aabb(aabb)) } pub fn aabb(&self, aabb: Aabb<i32>) -> PrimitiveRef { self.prim(Primitive::Aabb(aabb)) }
pub fn line(&self, a: Vec3<i32>, b: Vec3<i32>, radius: f32) -> PrimitiveRef { pub fn line(
&self,
a: Vec3<impl AsPrimitive<f32>>,
b: Vec3<impl AsPrimitive<f32>>,
radius: f32,
) -> PrimitiveRef {
self.prim(Primitive::Segment( self.prim(Primitive::Segment(
LineSegment3 { start: a, end: b }, LineSegment3 {
start: a.as_(),
end: b.as_(),
},
radius, radius,
)) ))
} }
@ -468,6 +501,10 @@ impl<'a> PrimitiveRef<'a> {
self.painter self.painter
.prim(Primitive::sampling(self, Box::new(sampling))) .prim(Primitive::sampling(self, Box::new(sampling)))
} }
pub fn repeat(self, offset: Vec3<i32>, count: i32) -> PrimitiveRef<'a> {
self.painter.prim(Primitive::repeat(self, offset, count))
}
} }
pub trait Structure { pub trait Structure {

View File

@ -619,21 +619,19 @@ impl Structure for House {
// something to do with AABBs with min and max not smaller in the right // something to do with AABBs with min and max not smaller in the right
// order. The same thing is true for orientation 3. // order. The same thing is true for orientation 3.
let support = match self.front { let support = match self.front {
0 => painter.prim(Primitive::Segment( 0 => painter.line(
LineSegment3 { Vec2::new(
start: Vec2::new( temp.x,
temp.x, self.bounds.max.y + storey_increase - self.overhang + 1,
self.bounds.max.y + storey_increase - self.overhang + 1, )
) .with_z(alt + previous_height - 3),
.with_z(alt + previous_height - 3), Vec2::new(
end: Vec2::new( temp.x,
temp.x, self.bounds.max.y + storey_increase - self.overhang + 2,
self.bounds.max.y + storey_increase - self.overhang + 2, )
) .with_z(alt + previous_height),
.with_z(alt + previous_height),
},
0.75, 0.75,
)), ),
//2 => { //2 => {
// painter.prim(Primitive::Segment(LineSegment3 { // painter.prim(Primitive::Segment(LineSegment3 {
// start: Vec2::new(temp.x, self.bounds.min.y - storey_increase - // start: Vec2::new(temp.x, self.bounds.min.y - storey_increase -
@ -669,37 +667,33 @@ impl Structure for House {
}; };
let support = match self.front { let support = match self.front {
0 => painter.prim(Primitive::Empty), 0 => painter.prim(Primitive::Empty),
1 => painter.prim(Primitive::Segment( 1 => painter.line(
LineSegment3 { Vec2::new(
start: Vec2::new( self.bounds.max.x + storey_increase - self.overhang + 1,
self.bounds.max.x + storey_increase - self.overhang + 1, temp.y,
temp.y, )
) .with_z(alt + previous_height - 3),
.with_z(alt + previous_height - 3), Vec2::new(
end: Vec2::new( self.bounds.max.x + storey_increase - self.overhang + 2,
self.bounds.max.x + storey_increase - self.overhang + 2, temp.y,
temp.y, )
) .with_z(alt + previous_height),
.with_z(alt + previous_height),
},
0.75, 0.75,
)), ),
2 => painter.prim(Primitive::Empty), 2 => painter.prim(Primitive::Empty),
_ => painter.prim(Primitive::Segment( _ => painter.line(
LineSegment3 { Vec2::new(
start: Vec2::new( self.bounds.min.x - storey_increase + self.overhang - 1,
self.bounds.min.x - storey_increase + self.overhang - 1, temp.y,
temp.y, )
) .with_z(alt + previous_height - 3),
.with_z(alt + previous_height - 3), Vec2::new(
end: Vec2::new( self.bounds.min.x - storey_increase + self.overhang - 2,
self.bounds.min.x - storey_increase + self.overhang - 2, temp.y,
temp.y, )
) .with_z(alt + previous_height),
.with_z(alt + previous_height),
},
0.75, 0.75,
)), ),
}; };
if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y { if temp.y <= self.bounds.max.y && temp.y >= self.bounds.min.y {
overhang_supports = overhang_supports =