From 8359d5754a1508d7ab27d75ebee701f645ed4486 Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Thu, 24 Mar 2022 15:13:53 +0000 Subject: [PATCH] Add new primitive to draw giant trees --- world/src/site2/gen.rs | 48 +++++++++++++++++++++++------- world/src/site2/plot/giant_tree.rs | 11 +++---- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs index 170f42372e..2b61503175 100644 --- a/world/src/site2/gen.rs +++ b/world/src/site2/gen.rs @@ -52,10 +52,12 @@ pub enum Primitive { degree: f32, }, Plane(Aabr, Vec3, Vec2), - /// A line segment from start to finish point with a given radius + /// A line segment from start to finish point with a given radius for both + /// points Segment { segment: LineSegment3, - radius: f32, + r0: f32, + r1: f32, }, /// A prism created by projecting a line segment with a given radius along /// the z axis up to a provided height @@ -117,10 +119,11 @@ impl std::fmt::Debug for Primitive { .field(&origin) .field(&gradient) .finish(), - Primitive::Segment { segment, radius } => f + Primitive::Segment { segment, r0, r1 } => f .debug_tuple("Segment") .field(&segment) - .field(&radius) + .field(&r0) + .field(&r1) .finish(), Primitive::SegmentPrism { segment, @@ -333,8 +336,13 @@ impl Fill { .as_() .dot(*gradient) as i32) }, - Primitive::Segment { segment, radius } => { - segment.distance_to_point(pos.map(|e| e as f32)) < radius - 0.25 + // TODO: Aabb calculation could be improved here by only considering the relevant radius + Primitive::Segment { segment, r0, r1 } => { + let distance = segment.end - segment.start; + let length = pos - segment.start.as_(); + let t = + (length.as_().dot(distance) / distance.magnitude_squared()).clamped(0.0, 1.0); + segment.distance_to_point(pos.map(|e| e as f32)) < Lerp::lerp(r0, r1, t) - 0.25 }, Primitive::SegmentPrism { segment, @@ -507,15 +515,15 @@ impl Fill { }; vec![aabb.made_valid()] }, - Primitive::Segment { segment, radius } => { + Primitive::Segment { segment, r0, r1 } => { let aabb = Aabb { min: segment.start, max: segment.end, } .made_valid(); vec![Aabb { - min: (aabb.min - *radius).floor().as_(), - max: (aabb.max + *radius).ceil().as_(), + min: (aabb.min - r0.max(*r1)).floor().as_(), + max: (aabb.max + r0.max(*r1)).ceil().as_(), }] }, Primitive::SegmentPrism { @@ -815,7 +823,27 @@ impl Painter { start: a.as_(), end: b.as_(), }, - radius, + r0: radius, + r1: radius, + }) + } + + /// Returns a `PrimitiveRef` of a 3-dimensional line segment with two + /// radius. + pub fn line_two_radius( + &self, + a: Vec3>, + b: Vec3>, + r0: f32, + r1: f32, + ) -> PrimitiveRef { + self.prim(Primitive::Segment { + segment: LineSegment3 { + start: a.as_(), + end: b.as_(), + }, + r0, + r1, }) } diff --git a/world/src/site2/plot/giant_tree.rs b/world/src/site2/plot/giant_tree.rs index 3130b59ce8..0c98bf2183 100644 --- a/world/src/site2/plot/giant_tree.rs +++ b/world/src/site2/plot/giant_tree.rs @@ -21,7 +21,7 @@ impl GiantTree { let wpos = site.tile_center_wpos(center_tile); Self { name: format!("Tree of {}", NameGen::location(rng).generate()), - // Find the tree's altitude + // Get the tree's altitude wpos: wpos.with_z(land.get_alt_approx(wpos) as i32), tree: { let config = TreeConfig::giant(rng, 4.0, true); @@ -48,17 +48,17 @@ impl Structure for GiantTree { light, fast_noise.get((self.wpos.map(|e| e as f64) * 0.05) * 0.5 + 0.5), ); - self.tree.walk(|branch, _| { + self.tree.walk(|branch, parent| { let aabr = Aabr { min: self.wpos.xy() + branch.get_aabb().min.xy().as_(), max: self.wpos.xy() + branch.get_aabb().max.xy().as_(), }; if aabr.collides_with_aabr(painter.render_aabr().as_()) { - // TODO : Migrate to using Painter#line() instead painter - .line( + .line_two_radius( self.wpos + branch.get_line().start.as_(), self.wpos + branch.get_line().end.as_(), + parent.get_wood_radius(), branch.get_wood_radius(), ) .fill(Fill::Block(Block::new( @@ -67,9 +67,10 @@ impl Structure for GiantTree { ))); if branch.get_leaf_radius() > branch.get_wood_radius() { painter - .line( + .line_two_radius( self.wpos + branch.get_line().start.as_(), self.wpos + branch.get_line().end.as_(), + parent.get_leaf_radius(), branch.get_leaf_radius(), ) .fill(Fill::Block(Block::new(