diff --git a/world/examples/dungeon_voxel_export.rs b/world/examples/dungeon_voxel_export.rs index 0e0a4c4959..5e803a9591 100644 --- a/world/examples/dungeon_voxel_export.rs +++ b/world/examples/dungeon_voxel_export.rs @@ -13,7 +13,7 @@ use rayon::ThreadPoolBuilder; use vek::{Vec2, Vec3}; use veloren_world::{ sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP}, - site2::{plot::PlotKind, Structure}, + site2::{plot::PlotKind, Fill, Structure}, CanvasInfo, Land, World, }; @@ -47,7 +47,7 @@ fn main() -> Result { let (prim_tree, fills, _entities) = dungeon.render_collect(&site, canvas); for (prim, fill) in fills { - let aabb = fill.get_bounds(&prim_tree, prim); + let aabb = Fill::get_bounds(&prim_tree, prim); for x in aabb.min.x..aabb.max.x { for y in aabb.min.y..aabb.max.y { diff --git a/world/src/site2/gen.rs b/world/src/site2/gen.rs index a89f624e6a..170f42372e 100644 --- a/world/src/site2/gen.rs +++ b/world/src/site2/gen.rs @@ -75,10 +75,9 @@ pub enum Primitive { // Not commutative Without(Id, Id), // Operators - Rotate(Id, Mat3), Translate(Id, Vec3), Scale(Id, Vec3), - RotateAbout(Id, Mat3, Vec3), + RotateAbout(Id, Mat3, Vec3), /// Repeat a primitive a number of times in a given direction, overlapping /// between repeats are unspecified. Repeat(Id, Vec3, u32), @@ -138,13 +137,12 @@ impl std::fmt::Debug for Primitive { Primitive::Intersect(a, b) => f.debug_tuple("Intersect").field(&a).field(&b).finish(), Primitive::Union(a, b) => f.debug_tuple("Union").field(&a).field(&b).finish(), Primitive::Without(a, b) => f.debug_tuple("Without").field(&a).field(&b).finish(), - Primitive::Rotate(a, mat) => f.debug_tuple("Rotate").field(&a).field(&mat).finish(), Primitive::Translate(a, vec) => { f.debug_tuple("Translate").field(&a).field(&vec).finish() }, Primitive::Scale(a, vec) => f.debug_tuple("Scale").field(&a).field(&vec).finish(), Primitive::RotateAbout(a, mat, vec) => f - .debug_tuple("RotateAround") + .debug_tuple("RotateAbout") .field(&a) .field(&mat) .field(&vec) @@ -176,10 +174,6 @@ impl Primitive { Self::Sampling(a.into(), f) } - pub fn rotate(a: impl Into>, rot: Mat3) -> Self { - Self::Rotate(a.into(), rot) - } - pub fn translate(a: impl Into>, trans: Vec3) -> Self { Self::Translate(a.into(), trans) } @@ -188,8 +182,12 @@ impl Primitive { Self::Scale(a.into(), scale) } - pub fn rotate_about(a: impl Into>, rot: Mat3, point: Vec3) -> Self { - Self::RotateAbout(a.into(), rot, point) + pub fn rotate_about( + a: impl Into>, + rot: Mat3, + point: Vec3>, + ) -> Self { + Self::RotateAbout(a.into(), rot, point.as_()) } pub fn repeat(a: impl Into>, offset: Vec3, count: u32) -> Self { @@ -212,7 +210,7 @@ pub enum Fill { } impl Fill { - fn contains_at(&self, tree: &Store, prim: Id, pos: Vec3) -> bool { + fn contains_at(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) @@ -369,51 +367,53 @@ impl Fill { let z_check = (projected_z..=(projected_z + height)).contains(&(pos.z as f32)); xy_check && z_check }, - 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::Intersect(a, b) => { - self.contains_at(tree, *a, pos) && self.contains_at(tree, *b, pos) + Self::contains_at(tree, *a, pos) && Self::contains_at(tree, *b, pos) }, Primitive::Union(a, b) => { - self.contains_at(tree, *a, pos) || self.contains_at(tree, *b, pos) + Self::contains_at(tree, *a, pos) || Self::contains_at(tree, *b, pos) }, Primitive::Without(a, b) => { - self.contains_at(tree, *a, pos) && !self.contains_at(tree, *b, pos) - }, - Primitive::Rotate(prim, mat) => { - let aabb = self.get_bounds(tree, *prim); - 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, *a, pos) && !Self::contains_at(tree, *b, pos) }, Primitive::Translate(prim, vec) => { - self.contains_at(tree, *prim, pos.map2(*vec, i32::saturating_sub)) + Self::contains_at(tree, *prim, pos.map2(*vec, i32::saturating_sub)) }, Primitive::Scale(prim, vec) => { let center = - self.get_bounds(tree, *prim).center().as_::() - Vec3::broadcast(0.5); + Self::get_bounds(tree, *prim).center().as_::() - Vec3::broadcast(0.5); let fpos = pos.as_::(); let spos = (center + ((center - fpos) / vec)) .map(|x| x.round()) .as_::(); - self.contains_at(tree, *prim, spos) + Self::contains_at(tree, *prim, spos) }, Primitive::RotateAbout(prim, mat, vec) => { - self.contains_at(tree, *prim, vec + *mat * (pos - vec)) + let mat = mat.as_::().transposed(); + let vec = vec - 0.5; + Self::contains_at(tree, *prim, (vec + mat * (pos.as_::() - vec)).as_()) }, Primitive::Repeat(prim, offset, count) => { - let aabb = self.get_bounds(tree, *prim); - let aabb_corner = { - let min_red = aabb.min.map2(*offset, |a, b| if b < 0 { 0 } else { a }); - let max_red = aabb.max.map2(*offset, |a, b| if b < 0 { a } else { 0 }); - min_red + max_red - }; - let diff = pos - aabb_corner; - let min = diff - .map2(*offset, |a, b| if b == 0 { i32::MAX } else { a / b }) - .reduce_min() - .clamp(0, *count as i32); - let pos = pos - offset * min; - self.contains_at(tree, *prim, pos) + if count == &0 { + false + } else { + let count = count - 1; + let aabb = Self::get_bounds(tree, *prim); + let aabb_corner = { + let min_red = aabb.min.map2(*offset, |a, b| if b < 0 { 0 } else { a }); + let max_red = aabb.max.map2(*offset, |a, b| if b < 0 { a } else { 0 }); + min_red + max_red + }; + let diff = pos - aabb_corner; + let min = diff + .map2(*offset, |a, b| if b == 0 { i32::MAX } else { a / b }) + .reduce_min() + .clamp(0, count as i32); + let pos = pos - offset * min; + Self::contains_at(tree, *prim, pos) + } }, } } @@ -426,7 +426,7 @@ impl Fill { canvas_info: &crate::CanvasInfo, old_block: Block, ) -> Option { - if self.contains_at(tree, prim, pos) { + if Self::contains_at(tree, prim, pos) { match self { Fill::Block(block) => Some(*block), Fill::Sprite(sprite) => Some(if old_block.is_filled() { @@ -471,7 +471,7 @@ impl Fill { } } - fn get_bounds_inner(&self, tree: &Store, prim: Id) -> Vec> { + fn get_bounds_inner(tree: &Store, prim: Id) -> Vec> { fn or_zip_with T>(a: Option, b: Option, f: F) -> Option { match (a, b) { (Some(a), Some(b)) => Some(f(a, b)), @@ -538,11 +538,11 @@ impl Fill { }; vec![Aabb { min, max }] }, - Primitive::Sampling(a, _) => self.get_bounds_inner(tree, *a), + Primitive::Sampling(a, _) => Self::get_bounds_inner(tree, *a), Primitive::Prefab(p) => vec![p.get_bounds()], Primitive::Intersect(a, b) => or_zip_with( - self.get_bounds_opt(tree, *a), - self.get_bounds_opt(tree, *b), + Self::get_bounds_opt(tree, *a), + Self::get_bounds_opt(tree, *b), |a, b| a.intersection(b), ) .into_iter() @@ -555,8 +555,8 @@ impl Fill { s_intersection / s_union } let mut inputs = Vec::new(); - inputs.extend(self.get_bounds_inner(tree, *a)); - inputs.extend(self.get_bounds_inner(tree, *b)); + inputs.extend(Self::get_bounds_inner(tree, *a)); + inputs.extend(Self::get_bounds_inner(tree, *b)); let mut results = Vec::new(); if let Some(aabb) = inputs.pop() { results.push(aabb); @@ -579,29 +579,15 @@ impl Fill { results } }, - Primitive::Without(a, _) => self.get_bounds_inner(tree, *a), - Primitive::Rotate(prim, mat) => self - .get_bounds_inner(tree, *prim) - .into_iter() - .map(|aabb| { - let extent = *mat * Vec3::from(aabb.size()); - let new_aabb: Aabb = Aabb { - min: aabb.min, - max: aabb.min + extent, - }; - new_aabb.made_valid() - }) - .collect(), - Primitive::Translate(prim, vec) => self - .get_bounds_inner(tree, *prim) + Primitive::Without(a, _) => Self::get_bounds_inner(tree, *a), + Primitive::Translate(prim, vec) => Self::get_bounds_inner(tree, *prim) .into_iter() .map(|aabb| Aabb { min: aabb.min.map2(*vec, i32::saturating_add), max: aabb.max.map2(*vec, i32::saturating_add), }) .collect(), - Primitive::Scale(prim, vec) => self - .get_bounds_inner(tree, *prim) + Primitive::Scale(prim, vec) => Self::get_bounds_inner(tree, *prim) .into_iter() .map(|aabb| { let center = aabb.center(); @@ -611,55 +597,58 @@ impl Fill { } }) .collect(), - Primitive::RotateAbout(prim, mat, vec) => self - .get_bounds_inner(tree, *prim) + Primitive::RotateAbout(prim, mat, vec) => Self::get_bounds_inner(tree, *prim) .into_iter() .map(|aabb| { - let mut new_aabb: Aabb = Aabb { - min: vec + *mat * (aabb.min - vec), - max: vec + *mat * (aabb.max - 1 - vec), + let mat = mat.as_::(); + // - 0.5 because we want the point to be at the minimum of the voxel + let vec = vec - 0.5; + let new_aabb = Aabb:: { + min: vec + mat * (aabb.min.as_() - vec), + // - 1 becuase we want the AABB to be inclusive when we rotate it, we then + // add 1 back to make it exclusive again + max: vec + mat * ((aabb.max - 1).as_() - vec), } .made_valid(); - new_aabb.max += 1; - new_aabb - }) - .collect(), - Primitive::Repeat(prim, offset, count) => self - .get_bounds_inner(tree, *prim) - .into_iter() - .map(|aabb| Aabb { - min: aabb - .min - .map2(aabb.min + offset * *count as i32, |a, b| a.min(b)), - max: aabb - .max - .map2(aabb.max + offset * *count as i32, |a, b| a.max(b)), + Aabb:: { + min: new_aabb.min.as_(), + max: new_aabb.max.as_() + 1, + } }) .collect(), + Primitive::Repeat(prim, offset, count) => { + if count == &0 { + vec![] + } else { + let count = count - 1; + Self::get_bounds_inner(tree, *prim) + .into_iter() + .map(|aabb| Aabb { + min: aabb + .min + .map2(aabb.min + offset * count as i32, |a, b| a.min(b)), + max: aabb + .max + .map2(aabb.max + offset * count as i32, |a, b| a.max(b)), + }) + .collect() + } + }, } } - pub fn get_bounds_disjoint( - &self, - tree: &Store, - prim: Id, - ) -> Vec> { - self.get_bounds_inner(tree, prim) + pub fn get_bounds_disjoint(tree: &Store, prim: Id) -> Vec> { + Self::get_bounds_inner(tree, prim) } - pub fn get_bounds_opt( - &self, - tree: &Store, - prim: Id, - ) -> Option> { - self.get_bounds_inner(tree, prim) + pub fn get_bounds_opt(tree: &Store, prim: Id) -> Option> { + Self::get_bounds_inner(tree, prim) .into_iter() .reduce(|a, b| a.union(b)) } - pub fn get_bounds(&self, tree: &Store, prim: Id) -> Aabb { - self.get_bounds_opt(tree, prim) - .unwrap_or_else(|| Aabb::new_empty(Vec3::zero())) + pub fn get_bounds(tree: &Store, prim: Id) -> Aabb { + Self::get_bounds_opt(tree, prim).unwrap_or_else(|| Aabb::new_empty(Vec3::zero())) } } @@ -689,7 +678,6 @@ impl Painter { | Primitive::SegmentPrism { .. } | Primitive::Prefab(_) => prev_depth, Primitive::Sampling(a, _) - | Primitive::Rotate(a, _) | Primitive::Translate(a, _) | Primitive::Scale(a, _) | Primitive::RotateAbout(a, _, _) @@ -1097,6 +1085,13 @@ impl<'a> PrimitiveRef<'a> { self.painter .prim(Primitive::sampling(self, Box::new(sampling))) } + + /// Rotates a primitive about it's own's bounds minimum point, + #[must_use] + pub fn rotate_about_min(self, mat: Mat3) -> PrimitiveRef<'a> { + let point = Fill::get_bounds(&self.painter.prims.borrow(), self.into()).min; + self.rotate_about(mat, point) + } } /// A trait to more easily manipulate groups of primitives. @@ -1104,14 +1099,10 @@ pub trait PrimitiveTransform { /// Translates the primitive along the vector `trans`. #[must_use] fn translate(self, trans: Vec3) -> Self; - /// Rotates the primitive about the minimum position of the primitive by - /// multiplying each block position by the provided rotation matrix. - #[must_use] - fn rotate(self, rot: Mat3) -> Self; /// Rotates the primitive about the given point of the primitive by /// multiplying each block position by the provided rotation matrix. #[must_use] - fn rotate_about(self, rot: Mat3, point: Vec3) -> Self; + fn rotate_about(self, rot: Mat3, point: Vec3>) -> Self; /// Scales the primitive along each axis by the x, y, and z components of /// the `scale` vector respectively. #[must_use] @@ -1128,9 +1119,7 @@ impl<'a> PrimitiveTransform for PrimitiveRef<'a> { self.painter.prim(Primitive::translate(self, trans)) } - fn rotate(self, rot: Mat3) -> Self { self.painter.prim(Primitive::rotate(self, rot)) } - - fn rotate_about(self, rot: Mat3, point: Vec3) -> Self { + fn rotate_about(self, rot: Mat3, point: Vec3>) -> Self { self.painter.prim(Primitive::rotate_about(self, rot, point)) } @@ -1149,14 +1138,7 @@ impl<'a, const N: usize> PrimitiveTransform for [PrimitiveRef<'a>; N] { self } - fn rotate(mut self, rot: Mat3) -> Self { - for prim in &mut self { - *prim = prim.rotate(rot); - } - self - } - - fn rotate_about(mut self, rot: Mat3, point: Vec3) -> Self { + fn rotate_about(mut self, rot: Mat3, point: Vec3>) -> Self { for prim in &mut self { *prim = prim.rotate_about(rot, point); } diff --git a/world/src/site2/mod.rs b/world/src/site2/mod.rs index a4a340728e..a11e08c641 100644 --- a/world/src/site2/mod.rs +++ b/world/src/site2/mod.rs @@ -999,7 +999,7 @@ impl Site { } for (prim, fill) in fills { - for mut aabb in fill.get_bounds_disjoint(&prim_tree, prim) { + for mut aabb in Fill::get_bounds_disjoint(&prim_tree, prim) { aabb.min = Vec2::max(aabb.min.xy(), chunk_aabr.min).with_z(aabb.min.z); aabb.max = Vec2::min(aabb.max.xy(), chunk_aabr.max).with_z(aabb.max.z); diff --git a/world/src/site2/plot/gnarling.rs b/world/src/site2/plot/gnarling.rs index a841635990..2013d3978b 100644 --- a/world/src/site2/plot/gnarling.rs +++ b/world/src/site2/plot/gnarling.rs @@ -887,16 +887,16 @@ impl Structure for GnarlingFortification { (wpos - 19).with_z(alt + raise), 2.0, ) - .repeat(Vec3::new(37, 0, 0), 1) - .repeat(Vec3::new(0, 37, 0), 1); + .repeat(Vec3::new(37, 0, 0), 2) + .repeat(Vec3::new(0, 37, 0), 2); let supports_inner = painter .aabb(Aabb { min: (wpos - 19).with_z(alt - 10) + Vec3::unit_y() * 17, max: (wpos - 15).with_z(alt + raise) + Vec3::unit_y() * 17, }) - .repeat(Vec3::new(17, 17, 0), 1) - .repeat(Vec3::new(17, -17, 0), 1); + .repeat(Vec3::new(17, 17, 0), 2) + .repeat(Vec3::new(17, -17, 0), 2); // let support_inner_2 = support_inner_1.translate(Vec3::new(34, 0, 0)); // let support_inner_3 = support_inner_1.translate(Vec3::new(17, 17, 0)); // let support_inner_4 = support_inner_1.translate(Vec3::new(17, -17, 0)); @@ -970,11 +970,11 @@ impl Structure for GnarlingFortification { .union(wall2roof); let roof_support_2 = - roof_support_1.rotate(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)); + roof_support_1.rotate_about_min(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)); let roof_support_3 = - roof_support_1.rotate(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)); + roof_support_1.rotate_about_min(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)); let roof_support_4 = - roof_support_1.rotate(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)); + roof_support_1.rotate_about_min(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)); let roof_support = roof_support_1 .union(roof_support_2) .union(roof_support_3) @@ -989,12 +989,13 @@ impl Structure for GnarlingFortification { (wpos + rad_2 as i32).with_z(alt + raise + height_1 as i32 + 8), 1.3, ); - let spike_low = spike_high.rotate(Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, -1)); + let spike_low = + spike_high.rotate_about_min(Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, -1)); let spike_1 = centerspot.union(spike_low).union(spike_high); - let spike_2 = spike_1.rotate(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)); - let spike_3 = spike_1.rotate(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)); - let spike_4 = spike_1.rotate(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)); + let spike_2 = spike_1.rotate_about_min(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)); + let spike_3 = spike_1.rotate_about_min(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)); + let spike_4 = spike_1.rotate_about_min(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)); let spikes = spike_1.union(spike_2).union(spike_3).union(spike_4); painter.fill( @@ -1219,13 +1220,13 @@ impl Structure for GnarlingFortification { let leg3 = leg1.translate(Vec3::new(width * 2 - 2, 0, 0)); let leg4 = leg1.translate(Vec3::new(width * 2 - 2, width * 2 - 2, 0)); let legsupport2 = legsupport1 - .rotate(Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1)) .translate(Vec3::new(1, width * 2 + 1, 0)); let legsupport3 = legsupport1 - .rotate(Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1)) .translate(Vec3::new(width * 2 + 1, 1, 0)); let legsupport4 = legsupport1 - .rotate(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) .translate(Vec3::new(width * 2 + 2, width * 2 + 2, 0)); let legsupports = legsupport1 @@ -1249,11 +1250,11 @@ impl Structure for GnarlingFortification { ); let spikes = spike1.union(spike2); let spikesalt = spikes - .rotate(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) .translate(Vec3::new(26, 8, 0)); let spikeshalf = spikes.union(spikesalt); let spikesotherhalf = spikeshalf - .rotate(Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1)) .translate(Vec3::new(16, -9, 0)); let spikesall = spikeshalf.union(spikesotherhalf); @@ -1423,13 +1424,13 @@ impl Structure for GnarlingFortification { 1.0, ); let support_2 = support_1 - .rotate(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)) .translate(Vec3::new(0, 13, 0)); let support_3 = support_1 - .rotate(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)) .translate(Vec3::new(13, 0, 0)); let support_4 = support_1 - .rotate(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) .translate(Vec3::new(13, 13, 0)); let supports = support_1.union(support_2).union(support_3).union(support_4); @@ -1607,22 +1608,22 @@ impl Structure for GnarlingFortification { )); let skirt2 = skirt1 .translate(Vec3::new(6, 0, 0)) - .rotate(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)); + .rotate_about_min(Mat3::new(-1, 0, 0, 0, 1, 0, 0, 0, 1)); let skirt3 = skirt2.translate(Vec3::new(3, 0, 0)); let skirtside1 = skirt1.union(skirt2).union(skirt3); let skirtside2 = skirtside1 - .rotate(Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1)) - .translate(Vec3::new(-1, 2, 0)); + .rotate_about_min(Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1)) + .translate(Vec3::new(0, 1, 0)); let skirtcorner1 = skirtside1.union(skirtside2); let skirtcorner2 = skirtcorner1 - .rotate(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) - .translate(Vec3::new(13, 11, 0)); + .rotate_about_min(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1)) + .translate(Vec3::new(11, 11, 0)); let skirt1 = skirtcorner1.union(skirtcorner2); let skirt2 = skirt1 - .rotate(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)) + .rotate_about_min(Mat3::new(1, 0, 0, 0, -1, 0, 0, 0, 1)) .translate(Vec3::new(0, 11, 6)); let skirt = skirt1.union(skirt2).union(roof);