veloren_world/site/
gen.rs

1#[cfg(feature = "use-dyn-lib")]
2use {crate::LIB, std::ffi::CStr};
3
4use super::*;
5use crate::{
6    CanvasInfo, ColumnSample,
7    block::block_from_structure,
8    column::ColInfo,
9    site::util::Dir,
10    util::{RandomField, Sampler},
11};
12use common::{
13    generation::EntityInfo,
14    store::{Id, Store},
15    terrain::{
16        Block, BlockKind, SpriteCfg,
17        structure::{Structure as PrefabStructure, StructureBlock},
18    },
19    vol::ReadVol,
20};
21use num::cast::AsPrimitive;
22use std::{
23    cell::RefCell,
24    f32::consts::{PI, TAU},
25    ops::RangeBounds,
26    sync::Arc,
27};
28use vek::*;
29
30pub enum Primitive {
31    Empty, // Placeholder
32
33    // Shapes
34    Aabb(Aabb<i32>),
35    Pyramid {
36        aabb: Aabb<i32>,
37        inset: i32,
38    },
39    Ramp {
40        aabb: Aabb<i32>,
41        inset: i32,
42        dir: Dir,
43    },
44    Gable {
45        aabb: Aabb<i32>,
46        inset: i32,
47        // X axis parallel or Y axis parallel
48        dir: Dir,
49    },
50    Cylinder(Aabb<i32>),
51    Cone(Aabb<i32>),
52    Sphere(Aabb<i32>),
53    /// An Aabb with rounded corners. The degree relates to how rounded the
54    /// corners are. A value less than 1.0 results in concave faces. A value
55    /// of 2.0 results in an ellipsoid. Values greater than 2.0 result in a
56    /// rounded aabb. Values less than 0.0 are clamped to 0.0 as negative values
57    /// would theoretically yield shapes extending to infinity.
58    Superquadric {
59        aabb: Aabb<i32>,
60        degree: f32,
61    },
62    Plane(Aabr<i32>, Vec3<i32>, Vec2<f32>),
63    /// A line segment from start to finish point with a given radius for both
64    /// points
65    Segment {
66        segment: LineSegment3<f32>,
67        r0: f32,
68        r1: f32,
69    },
70    /// A prism created by projecting a line segment with a given radius along
71    /// the z axis up to a provided height
72    SegmentPrism {
73        segment: LineSegment3<f32>,
74        radius: f32,
75        height: f32,
76    },
77    /// A sampling function is always a subset of another primitive to avoid
78    /// needing infinite bounds
79    Sampling(Id<Primitive>, Box<dyn Fn(Vec3<i32>) -> bool>),
80    ColSampling(Id<Primitive>, Box<dyn Fn(Vec3<i32>, &ColInfo) -> bool>),
81    Prefab(Box<PrefabStructure>),
82
83    // Combinators
84    Intersect(Id<Primitive>, Id<Primitive>),
85    Union(Id<Primitive>, Id<Primitive>),
86    // Not commutative
87    Without(Id<Primitive>, Id<Primitive>),
88    // Operators
89    Translate(Id<Primitive>, Vec3<i32>),
90    Scale(Id<Primitive>, Vec3<f32>),
91    RotateAbout(Id<Primitive>, Mat3<i32>, Vec3<f32>),
92    /// Repeat a primitive a number of times in a given direction, overlapping
93    /// between repeats are unspecified.
94    Repeat(Id<Primitive>, Vec3<i32>, u32),
95}
96
97impl std::fmt::Debug for Primitive {
98    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
99        match self {
100            Primitive::Empty => f.debug_tuple("Empty").finish(),
101            Primitive::Aabb(aabb) => f.debug_tuple("Aabb").field(&aabb).finish(),
102            Primitive::Pyramid { aabb, inset } => {
103                f.debug_tuple("Pyramid").field(&aabb).field(&inset).finish()
104            },
105            Primitive::Ramp { aabb, inset, dir } => f
106                .debug_tuple("Ramp")
107                .field(&aabb)
108                .field(&inset)
109                .field(&dir)
110                .finish(),
111            Primitive::Gable { aabb, inset, dir } => f
112                .debug_tuple("Gable")
113                .field(&aabb)
114                .field(&inset)
115                .field(&dir)
116                .finish(),
117            Primitive::Cylinder(aabb) => f.debug_tuple("Cylinder").field(&aabb).finish(),
118            Primitive::Cone(aabb) => f.debug_tuple("Cone").field(&aabb).finish(),
119            Primitive::Sphere(aabb) => f.debug_tuple("Sphere").field(&aabb).finish(),
120            Primitive::Superquadric { aabb, degree } => f
121                .debug_tuple("Superquadric")
122                .field(&aabb)
123                .field(&degree)
124                .finish(),
125            Primitive::Plane(aabr, origin, gradient) => f
126                .debug_tuple("Plane")
127                .field(&aabr)
128                .field(&origin)
129                .field(&gradient)
130                .finish(),
131            Primitive::Segment { segment, r0, r1 } => f
132                .debug_tuple("Segment")
133                .field(&segment)
134                .field(&r0)
135                .field(&r1)
136                .finish(),
137            Primitive::SegmentPrism {
138                segment,
139                radius,
140                height,
141            } => f
142                .debug_tuple("SegmentPrism")
143                .field(&segment)
144                .field(&radius)
145                .field(&height)
146                .finish(),
147            Primitive::Sampling(prim, _) => f.debug_tuple("Sampling").field(&prim).finish(),
148            Primitive::ColSampling(prim, _) => f.debug_tuple("ColSampling").field(&prim).finish(),
149            Primitive::Prefab(prefab) => f.debug_tuple("Prefab").field(&prefab).finish(),
150            Primitive::Intersect(a, b) => f.debug_tuple("Intersect").field(&a).field(&b).finish(),
151            Primitive::Union(a, b) => f.debug_tuple("Union").field(&a).field(&b).finish(),
152            Primitive::Without(a, b) => f.debug_tuple("Without").field(&a).field(&b).finish(),
153            Primitive::Translate(a, vec) => {
154                f.debug_tuple("Translate").field(&a).field(&vec).finish()
155            },
156            Primitive::Scale(a, vec) => f.debug_tuple("Scale").field(&a).field(&vec).finish(),
157            Primitive::RotateAbout(a, mat, vec) => f
158                .debug_tuple("RotateAbout")
159                .field(&a)
160                .field(&mat)
161                .field(&vec)
162                .finish(),
163            Primitive::Repeat(a, offset, n) => f
164                .debug_tuple("Repeat")
165                .field(&a)
166                .field(&offset)
167                .field(&n)
168                .finish(),
169        }
170    }
171}
172
173impl Primitive {
174    pub fn intersect(a: impl Into<Id<Primitive>>, b: impl Into<Id<Primitive>>) -> Self {
175        Self::Intersect(a.into(), b.into())
176    }
177
178    pub fn union(a: impl Into<Id<Primitive>>, b: impl Into<Id<Primitive>>) -> Self {
179        Self::Union(a.into(), b.into())
180    }
181
182    pub fn without(a: impl Into<Id<Primitive>>, b: impl Into<Id<Primitive>>) -> Self {
183        Self::Without(a.into(), b.into())
184    }
185
186    pub fn sampling(a: impl Into<Id<Primitive>>, f: Box<dyn Fn(Vec3<i32>) -> bool>) -> Self {
187        Self::Sampling(a.into(), f)
188    }
189
190    pub fn column_sampling(
191        a: impl Into<Id<Primitive>>,
192        f: Box<dyn Fn(Vec3<i32>, &ColInfo) -> bool>,
193    ) -> Self {
194        Self::ColSampling(a.into(), f)
195    }
196
197    pub fn translate(a: impl Into<Id<Primitive>>, trans: Vec3<i32>) -> Self {
198        Self::Translate(a.into(), trans)
199    }
200
201    pub fn scale(a: impl Into<Id<Primitive>>, scale: Vec3<f32>) -> Self {
202        Self::Scale(a.into(), scale)
203    }
204
205    pub fn rotate_about(
206        a: impl Into<Id<Primitive>>,
207        rot: Mat3<i32>,
208        point: Vec3<impl AsPrimitive<f32>>,
209    ) -> Self {
210        Self::RotateAbout(a.into(), rot, point.as_())
211    }
212
213    /// Rotates a primitive 90 degrees CCW about the Z axis `n` times
214    pub fn rotate_z_90_about(
215        a: impl Into<Id<Primitive>>,
216        n: i32,
217        point: Vec3<impl AsPrimitive<f32>>,
218    ) -> Self {
219        let rot = match n % 4 {
220            1 => Mat3::new(0, -1, 0, 1, 0, 0, 0, 0, 1),
221            2 => Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, 1),
222            3 => Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1),
223            _ => Mat3::new(1, 0, 0, 0, 1, 0, 0, 0, 1),
224        };
225        Self::RotateAbout(a.into(), rot, point.as_())
226    }
227
228    pub fn repeat(a: impl Into<Id<Primitive>>, offset: Vec3<i32>, count: u32) -> Self {
229        Self::Repeat(a.into(), offset, count)
230    }
231}
232
233#[derive(Clone)]
234pub enum Fill {
235    Sprite(Block),
236    ResourceSprite(Block),
237    CfgSprite(Block, SpriteCfg),
238
239    Block(Block),
240    Brick(BlockKind, Rgb<u8>, u8),
241    PlankWall(BlockKind, Rgb<u8>, u8),
242    Gradient(util::gradient::Gradient, BlockKind),
243    // TODO: the offset field for Prefab is a hack that breaks the compositionality of Translate,
244    // we probably need an evaluator for the primitive tree that gets which point is queried at
245    // leaf nodes given an input point to make Translate/Rotate work generally
246    Prefab(Box<PrefabStructure>, Vec3<i32>, u32),
247    Sampling(Arc<dyn Fn(Vec3<i32>) -> Option<Block>>),
248}
249
250impl Fill {
251    pub fn sprite(kind: SpriteKind) -> Self { Fill::Block(Block::empty().with_sprite(kind)) }
252
253    pub fn sprite_ori(kind: SpriteKind, ori: u8) -> Self {
254        let block = Block::empty().with_sprite(kind);
255
256        let block = block.with_ori(ori).unwrap_or(block);
257        Fill::Sprite(block)
258    }
259
260    pub fn resource_sprite(kind: SpriteKind) -> Self {
261        Fill::ResourceSprite(Block::empty().with_sprite(kind))
262    }
263
264    pub fn resource_sprite_ori(kind: SpriteKind, ori: u8) -> Self {
265        let block = Block::empty().with_sprite(kind);
266
267        let block = block.with_ori(ori).unwrap_or(block);
268        Fill::ResourceSprite(block)
269    }
270
271    pub fn owned_resource_sprite_ori(kind: SpriteKind, ori: u8) -> Self {
272        let block = Block::empty().with_sprite(kind);
273
274        let block = block.with_ori(ori).unwrap_or(block);
275        let block = block
276            .with_attr(common::terrain::sprite::Owned(true))
277            .unwrap_or(block);
278
279        Fill::ResourceSprite(block)
280    }
281
282    pub fn sprite_ori_cfg(kind: SpriteKind, ori: u8, cfg: SpriteCfg) -> Self {
283        let block = Block::empty().with_sprite(kind);
284
285        let block = block.with_ori(ori).unwrap_or(block);
286        Fill::CfgSprite(block, cfg)
287    }
288
289    fn contains_at(
290        tree: &Store<Primitive>,
291        prim: Id<Primitive>,
292        pos: Vec3<i32>,
293        col: &ColInfo,
294    ) -> bool {
295        // Custom closure because vek's impl of `contains_point` is inclusive :(
296        let aabb_contains = |aabb: Aabb<i32>, pos: Vec3<i32>| {
297            (aabb.min.x..aabb.max.x).contains(&pos.x)
298                && (aabb.min.y..aabb.max.y).contains(&pos.y)
299                && (aabb.min.z..aabb.max.z).contains(&pos.z)
300        };
301
302        match &tree[prim] {
303            Primitive::Empty => false,
304
305            Primitive::Aabb(aabb) => aabb_contains(*aabb, pos),
306            Primitive::Ramp { aabb, inset, dir } => {
307                let inset = (*inset).max(aabb.size().reduce_min());
308                let inner = match dir {
309                    Dir::X => Aabr {
310                        min: Vec2::new(aabb.min.x - 1 + inset, aabb.min.y),
311                        max: Vec2::new(aabb.max.x, aabb.max.y),
312                    },
313                    Dir::NegX => Aabr {
314                        min: Vec2::new(aabb.min.x, aabb.min.y),
315                        max: Vec2::new(aabb.max.x - inset, aabb.max.y),
316                    },
317                    Dir::Y => Aabr {
318                        min: Vec2::new(aabb.min.x, aabb.min.y - 1 + inset),
319                        max: Vec2::new(aabb.max.x, aabb.max.y),
320                    },
321                    Dir::NegY => Aabr {
322                        min: Vec2::new(aabb.min.x, aabb.min.y),
323                        max: Vec2::new(aabb.max.x, aabb.max.y - inset),
324                    },
325                };
326                aabb_contains(*aabb, pos)
327                    && inner.is_valid()
328                    && (inner.projected_point(pos.xy()) - pos.xy())
329                        .map(|e| e.abs())
330                        .reduce_max() as f32
331                        / (inset as f32)
332                        < 1.0
333                            - ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
334            },
335            Primitive::Pyramid { aabb, inset } => {
336                let inset = (*inset).max(aabb.size().reduce_min());
337                let inner = Aabr {
338                    min: aabb.min.xy() - 1 + inset,
339                    max: aabb.max.xy() - inset,
340                };
341                aabb_contains(*aabb, pos)
342                    && inner.is_valid()
343                    && (inner.projected_point(pos.xy()) - pos.xy())
344                        .map(|e| e.abs())
345                        .reduce_max() as f32
346                        / (inset as f32)
347                        < 1.0
348                            - ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
349            },
350            Primitive::Gable { aabb, inset, dir } => {
351                let inset = (*inset).max(aabb.size().reduce_min());
352                let inner = if dir.is_y() {
353                    Aabr {
354                        min: Vec2::new(aabb.min.x - 1 + inset, aabb.min.y),
355                        max: Vec2::new(aabb.max.x - inset, aabb.max.y),
356                    }
357                } else {
358                    Aabr {
359                        min: Vec2::new(aabb.min.x, aabb.min.y - 1 + inset),
360                        max: Vec2::new(aabb.max.x, aabb.max.y - inset),
361                    }
362                };
363                aabb_contains(*aabb, pos)
364                    && inner.is_valid()
365                    && (inner.projected_point(pos.xy()) - pos.xy())
366                        .map(|e| e.abs())
367                        .reduce_max() as f32
368                        / (inset as f32)
369                        < 1.0
370                            - ((pos.z - aabb.min.z) as f32 + 0.5) / (aabb.max.z - aabb.min.z) as f32
371            },
372            Primitive::Cylinder(aabb) => {
373                // Add 0.5 since the aabb is exclusive.
374                let fpos = pos.as_::<f32>().xy() - aabb.as_::<f32>().center().xy() + 0.5;
375                let size = Vec3::from(aabb.size().as_::<f32>()).xy();
376                (aabb.min.z..aabb.max.z).contains(&pos.z)
377                    && (2.0 * fpos / size).magnitude_squared() <= 1.0
378            },
379            Primitive::Cone(aabb) => {
380                (aabb.min.z..aabb.max.z).contains(&pos.z)
381                    && pos
382                        .xy()
383                        .as_()
384                        .distance_squared(aabb.as_().center().xy() - 0.5)
385                        < (((aabb.max.z - pos.z) as f32 / aabb.size().d as f32)
386                            * (aabb.size().w.min(aabb.size().h) as f32 / 2.0))
387                            .powi(2)
388            },
389            Primitive::Sphere(aabb) => {
390                aabb_contains(*aabb, pos)
391                    && pos.as_().distance_squared(aabb.as_().center() - 0.5)
392                        < (aabb.size().w.min(aabb.size().h) as f32 / 2.0).powi(2)
393            },
394            Primitive::Superquadric { aabb, degree } => {
395                let degree = degree.max(0.0);
396                let center = aabb.center().map(|e| e as f32);
397                let a: f32 = aabb.max.x as f32 - center.x - 0.5;
398                let b: f32 = aabb.max.y as f32 - center.y - 0.5;
399                let c: f32 = aabb.max.z as f32 - center.z - 0.5;
400                let rpos = pos.as_::<f32>() + 0.5 - center;
401                aabb_contains(*aabb, pos)
402                    && (rpos.x / a).abs().powf(degree)
403                        + (rpos.y / b).abs().powf(degree)
404                        + (rpos.z / c).abs().powf(degree)
405                        < 1.0
406            },
407            Primitive::Plane(aabr, origin, gradient) => {
408                // Maybe <= instead of ==
409                (aabr.min.x..aabr.max.x).contains(&pos.x)
410                    && (aabr.min.y..aabr.max.y).contains(&pos.y)
411                    && pos.z
412                        == origin.z
413                            + ((pos.xy() - origin.xy())
414                                .map(|x| x.abs())
415                                .as_()
416                                .dot(*gradient) as i32)
417            },
418            // TODO: Aabb calculation could be improved here by only considering the relevant radius
419            Primitive::Segment { segment, r0, r1 } => {
420                let distance = segment.end - segment.start;
421                let length = pos - segment.start.as_();
422                let t =
423                    (length.as_().dot(distance) / distance.magnitude_squared()).clamped(0.0, 1.0);
424                segment.distance_to_point(pos.map(|e| e as f32)) < Lerp::lerp(r0, r1, t) - 0.25
425            },
426            Primitive::SegmentPrism {
427                segment,
428                radius,
429                height,
430            } => {
431                let segment_2d = LineSegment2 {
432                    start: segment.start.xy(),
433                    end: segment.end.xy(),
434                };
435                let projected_point_2d: Vec2<f32> =
436                    segment_2d.as_().projected_point(pos.xy().as_());
437                let xy_check = projected_point_2d.distance(pos.xy().as_()) < radius - 0.25;
438                let projected_z = {
439                    let len_sq: f32 = segment_2d
440                        .start
441                        .as_()
442                        .distance_squared(segment_2d.end.as_());
443                    if len_sq < 0.1 {
444                        segment.start.z
445                    } else {
446                        let frac = ((projected_point_2d - segment_2d.start.as_())
447                            .dot(segment_2d.end.as_() - segment_2d.start.as_())
448                            / len_sq)
449                            .clamp(0.0, 1.0);
450                        (segment.end.z - segment.start.z) * frac + segment.start.z
451                    }
452                };
453                let z_check = (projected_z..=(projected_z + height)).contains(&(pos.z as f32));
454                xy_check && z_check
455            },
456            Primitive::Sampling(a, f) => Self::contains_at(tree, *a, pos, col) && f(pos),
457            Primitive::ColSampling(a, f) => Self::contains_at(tree, *a, pos, col) && f(pos, col),
458            Primitive::Prefab(p) => !matches!(p.get(pos), Err(_) | Ok(StructureBlock::None)),
459            Primitive::Intersect(a, b) => {
460                Self::contains_at(tree, *a, pos, col) && Self::contains_at(tree, *b, pos, col)
461            },
462            Primitive::Union(a, b) => {
463                Self::contains_at(tree, *a, pos, col) || Self::contains_at(tree, *b, pos, col)
464            },
465            Primitive::Without(a, b) => {
466                Self::contains_at(tree, *a, pos, col) && !Self::contains_at(tree, *b, pos, col)
467            },
468            Primitive::Translate(prim, vec) => {
469                Self::contains_at(tree, *prim, pos.map2(*vec, i32::saturating_sub), col)
470            },
471            Primitive::Scale(prim, vec) => {
472                let center = Self::get_bounds(tree, *prim).as_::<f32>().center();
473                let fpos = pos.as_::<f32>();
474                let spos = (center + ((fpos - center) / vec))
475                    .map(|x| x.round())
476                    .as_::<i32>();
477                Self::contains_at(tree, *prim, spos, col)
478            },
479            Primitive::RotateAbout(prim, mat, vec) => {
480                let mat = mat.as_::<f32>().transposed();
481                let vec = vec - 0.5;
482                Self::contains_at(
483                    tree,
484                    *prim,
485                    (vec + mat * (pos.as_::<f32>() - vec)).as_(),
486                    col,
487                )
488            },
489            Primitive::Repeat(prim, offset, count) => {
490                if count == &0 {
491                    false
492                } else {
493                    let count = count - 1;
494                    let aabb = Self::get_bounds(tree, *prim);
495                    let aabb_corner = {
496                        let min_red = aabb.min.map2(*offset, |a, b| if b < 0 { 0 } else { a });
497                        let max_red = aabb.max.map2(*offset, |a, b| if b < 0 { a } else { 0 });
498                        min_red + max_red
499                    };
500                    let diff = pos - aabb_corner;
501                    let min = diff
502                        .map2(*offset, |a, b| if b == 0 { i32::MAX } else { a / b })
503                        .reduce_min()
504                        .clamp(0, count as i32);
505                    let pos = pos - offset * min;
506                    Self::contains_at(tree, *prim, pos, col)
507                }
508            },
509        }
510    }
511
512    pub fn sample_at(
513        &self,
514        tree: &Store<Primitive>,
515        prim: Id<Primitive>,
516        pos: Vec3<i32>,
517        canvas_info: &CanvasInfo,
518        old_block: Block,
519        sprite_cfg: &mut Option<SpriteCfg>,
520        col: &ColInfo,
521    ) -> Option<Block> {
522        if Self::contains_at(tree, prim, pos, col) {
523            match self {
524                Fill::Sprite(sprite) | Fill::ResourceSprite(sprite) => {
525                    Some(if old_block.is_filled() {
526                        *sprite
527                    } else {
528                        old_block.with_data_of(*sprite)
529                    })
530                },
531                Fill::CfgSprite(sprite, cfg) => {
532                    *sprite_cfg = Some(cfg.clone());
533                    Some(if old_block.is_filled() {
534                        *sprite
535                    } else {
536                        old_block.with_data_of(*sprite)
537                    })
538                },
539                Fill::Block(block) => Some(*block),
540                Fill::Brick(bk, col, range) => {
541                    let pos = (pos + Vec3::new(pos.z, pos.z, 0)) / Vec3::new(2, 2, 1);
542                    Some(Block::new(
543                        *bk,
544                        *col + ((((pos.x ^ pos.y ^ pos.z) as u8).reverse_bits() as u16
545                            * *range as u16)
546                            >> 8) as u8,
547                        // *col + (RandomField::new(13)
548                        //     .get(pos)
549                        //     % *range as u32) as u8,
550                    ))
551                },
552                Fill::PlankWall(bk, col, range) => Some(Block::new(
553                    *bk,
554                    *col + (RandomField::new(13)
555                        .get((pos + Vec3::new(pos.z, pos.z, 0) * 8) / Vec3::new(16, 16, 1))
556                        % *range as u32) as u8,
557                )),
558                Fill::Gradient(gradient, bk) => Some(Block::new(*bk, gradient.sample(pos.as_()))),
559                Fill::Prefab(p, tr, seed) => p.get(pos - tr).ok().and_then(|sb| {
560                    let col_sample = canvas_info.col(canvas_info.wpos)?;
561                    block_from_structure(
562                        canvas_info.index,
563                        sb,
564                        pos - tr,
565                        p.get_bounds().center().xy(),
566                        *seed,
567                        col_sample,
568                        Block::air,
569                        canvas_info.calendar(),
570                        &Vec2::new(Vec2::new(1, 0), Vec2::new(0, 1)),
571                    )
572                    .map(|(block, cfg)| {
573                        *sprite_cfg = cfg;
574                        block
575                    })
576                }),
577                Fill::Sampling(f) => f(pos),
578            }
579        } else {
580            None
581        }
582    }
583
584    fn get_bounds_inner(tree: &Store<Primitive>, prim: Id<Primitive>) -> Vec<Aabb<i32>> {
585        fn or_zip_with<T, F: FnOnce(T, T) -> T>(a: Option<T>, b: Option<T>, f: F) -> Option<T> {
586            match (a, b) {
587                (Some(a), Some(b)) => Some(f(a, b)),
588                (Some(a), _) => Some(a),
589                (_, b) => b,
590            }
591        }
592
593        match &tree[prim] {
594            Primitive::Empty => vec![],
595            Primitive::Aabb(aabb) => vec![*aabb],
596            Primitive::Pyramid { aabb, .. } => vec![*aabb],
597            Primitive::Gable { aabb, .. } => vec![*aabb],
598            Primitive::Ramp { aabb, .. } => vec![*aabb],
599            Primitive::Cylinder(aabb) => vec![*aabb],
600            Primitive::Cone(aabb) => vec![*aabb],
601            Primitive::Sphere(aabb) => vec![*aabb],
602            Primitive::Superquadric { aabb, .. } => vec![*aabb],
603            Primitive::Plane(aabr, origin, gradient) => {
604                let half_size = aabr.half_size().reduce_max();
605                let longest_dist = ((aabr.center() - origin.xy()).map(|x| x.abs())
606                    + half_size
607                    + aabr.size().reduce_max() % 2)
608                    .map(|x| x as f32);
609                let z = if gradient.x.signum() == gradient.y.signum() {
610                    Vec2::new(0, longest_dist.dot(*gradient) as i32)
611                } else {
612                    (longest_dist * gradient).as_()
613                };
614                let aabb = Aabb {
615                    min: aabr.min.with_z(origin.z + z.reduce_min().min(0)),
616                    max: aabr.max.with_z(origin.z + z.reduce_max().max(0)),
617                };
618                vec![aabb.made_valid()]
619            },
620            Primitive::Segment { segment, r0, r1 } => {
621                let aabb = Aabb {
622                    min: segment.start,
623                    max: segment.end,
624                }
625                .made_valid();
626                vec![Aabb {
627                    min: (aabb.min - r0.max(*r1)).floor().as_(),
628                    max: (aabb.max + r0.max(*r1)).ceil().as_(),
629                }]
630            },
631            Primitive::SegmentPrism {
632                segment,
633                radius,
634                height,
635            } => {
636                let aabb = Aabb {
637                    min: segment.start,
638                    max: segment.end,
639                }
640                .made_valid();
641                let min = {
642                    let xy = (aabb.min.xy() - *radius).floor();
643                    xy.with_z(aabb.min.z).as_()
644                };
645                let max = {
646                    let xy = (aabb.max.xy() + *radius).ceil();
647                    xy.with_z((aabb.max.z + *height).ceil()).as_()
648                };
649                vec![Aabb { min, max }]
650            },
651            Primitive::Sampling(a, _) | Primitive::ColSampling(a, _) => {
652                Self::get_bounds_inner(tree, *a)
653            },
654            Primitive::Prefab(p) => vec![p.get_bounds()],
655            Primitive::Intersect(a, b) => or_zip_with(
656                Self::get_bounds_opt(tree, *a),
657                Self::get_bounds_opt(tree, *b),
658                |a, b| a.intersection(b),
659            )
660            .into_iter()
661            .collect(),
662
663            Primitive::Union(a, b) => {
664                fn jaccard(x: Aabb<i32>, y: Aabb<i32>) -> f32 {
665                    let s_intersection = x.intersection(y).size().as_::<f32>().magnitude();
666                    let s_union = x.union(y).size().as_::<f32>().magnitude();
667                    s_intersection / s_union
668                }
669                let mut inputs = Vec::new();
670                inputs.extend(Self::get_bounds_inner(tree, *a));
671                inputs.extend(Self::get_bounds_inner(tree, *b));
672                let mut results = Vec::new();
673                if let Some(aabb) = inputs.pop() {
674                    results.push(aabb);
675                    for a in &inputs {
676                        let best = results
677                            .iter()
678                            .enumerate()
679                            .max_by_key(|(_, b)| (jaccard(*a, **b) * 1000.0) as usize);
680                        match best {
681                            Some((i, b)) if jaccard(*a, *b) > 0.3 => {
682                                let mut aabb = results.swap_remove(i);
683                                aabb = aabb.union(*a);
684                                results.push(aabb);
685                            },
686                            _ => results.push(*a),
687                        }
688                    }
689                    results
690                } else {
691                    results
692                }
693            },
694            Primitive::Without(a, _) => Self::get_bounds_inner(tree, *a),
695            Primitive::Translate(prim, vec) => Self::get_bounds_inner(tree, *prim)
696                .into_iter()
697                .map(|aabb| Aabb {
698                    min: aabb.min.map2(*vec, i32::saturating_add),
699                    max: aabb.max.map2(*vec, i32::saturating_add),
700                })
701                .collect(),
702            Primitive::Scale(prim, vec) => Self::get_bounds_inner(tree, *prim)
703                .into_iter()
704                .map(|aabb| {
705                    let center = aabb.center();
706                    Aabb {
707                        min: center + ((aabb.min - center).as_::<f32>() * vec).as_::<i32>(),
708                        max: center + ((aabb.max - center).as_::<f32>() * vec).as_::<i32>(),
709                    }
710                })
711                .collect(),
712            Primitive::RotateAbout(prim, mat, vec) => Self::get_bounds_inner(tree, *prim)
713                .into_iter()
714                .map(|aabb| {
715                    let mat = mat.as_::<f32>();
716                    // - 0.5 because we want the point to be at the minimum of the voxel
717                    let vec = vec - 0.5;
718                    let new_aabb = Aabb::<f32> {
719                        min: vec + mat * (aabb.min.as_() - vec),
720                        // - 1 becuase we want the AABB to be inclusive when we rotate it, we then
721                        //   add 1 back to make it exclusive again
722                        max: vec + mat * ((aabb.max - 1).as_() - vec),
723                    }
724                    .made_valid();
725                    Aabb::<i32> {
726                        min: new_aabb.min.as_(),
727                        max: new_aabb.max.as_() + 1,
728                    }
729                })
730                .collect(),
731            Primitive::Repeat(prim, offset, count) => {
732                if count == &0 {
733                    vec![]
734                } else {
735                    let count = count - 1;
736                    Self::get_bounds_inner(tree, *prim)
737                        .into_iter()
738                        .map(|aabb| Aabb {
739                            min: aabb
740                                .min
741                                .map2(aabb.min + offset * count as i32, |a, b| a.min(b)),
742                            max: aabb
743                                .max
744                                .map2(aabb.max + offset * count as i32, |a, b| a.max(b)),
745                        })
746                        .collect()
747                }
748            },
749        }
750    }
751
752    pub fn get_bounds_disjoint(tree: &Store<Primitive>, prim: Id<Primitive>) -> Vec<Aabb<i32>> {
753        Self::get_bounds_inner(tree, prim)
754    }
755
756    pub fn get_bounds_opt(tree: &Store<Primitive>, prim: Id<Primitive>) -> Option<Aabb<i32>> {
757        Self::get_bounds_inner(tree, prim)
758            .into_iter()
759            .reduce(|a, b| a.union(b))
760    }
761
762    pub fn get_bounds(tree: &Store<Primitive>, prim: Id<Primitive>) -> Aabb<i32> {
763        Self::get_bounds_opt(tree, prim).unwrap_or_else(|| Aabb::new_empty(Vec3::zero()))
764    }
765}
766
767pub struct Painter {
768    prims: RefCell<Store<Primitive>>,
769    fills: RefCell<Vec<(Id<Primitive>, Fill)>>,
770    entities: RefCell<Vec<EntityInfo>>,
771    render_area: Aabr<i32>,
772}
773
774impl Painter {
775    /// Computes the depth of the tree rooted at `prim`
776    pub fn depth(&self, prim: Id<Primitive>) -> usize {
777        fn aux(prims: &Store<Primitive>, prim: Id<Primitive>, prev_depth: usize) -> usize {
778            match prims[prim] {
779                Primitive::Empty
780                | Primitive::Aabb(_)
781                | Primitive::Pyramid { .. }
782                | Primitive::Ramp { .. }
783                | Primitive::Gable { .. }
784                | Primitive::Cylinder(_)
785                | Primitive::Cone(_)
786                | Primitive::Sphere(_)
787                | Primitive::Superquadric { .. }
788                | Primitive::Plane(_, _, _)
789                | Primitive::Segment { .. }
790                | Primitive::SegmentPrism { .. }
791                | Primitive::Prefab(_) => prev_depth,
792                Primitive::Sampling(a, _)
793                | Primitive::ColSampling(a, _)
794                | Primitive::Translate(a, _)
795                | Primitive::Scale(a, _)
796                | Primitive::RotateAbout(a, _, _)
797                | Primitive::Repeat(a, _, _) => aux(prims, a, 1 + prev_depth),
798
799                Primitive::Intersect(a, b) | Primitive::Union(a, b) | Primitive::Without(a, b) => {
800                    aux(prims, a, 1 + prev_depth).max(aux(prims, b, 1 + prev_depth))
801                },
802            }
803        }
804        let prims = self.prims.borrow();
805        aux(&prims, prim, 0)
806    }
807
808    /// Orders two primitives by depth, since (A && (B && C)) is cheaper to
809    /// evaluate than ((A && B) && C) due to short-circuiting.
810    pub fn order_by_depth(
811        &self,
812        a: impl Into<Id<Primitive>>,
813        b: impl Into<Id<Primitive>>,
814    ) -> (Id<Primitive>, Id<Primitive>) {
815        let (a, b) = (a.into(), b.into());
816        if self.depth(a) < self.depth(b) {
817            (a, b)
818        } else {
819            (b, a)
820        }
821    }
822
823    /// Returns a `PrimitiveRef` of an axis aligned bounding box. The geometric
824    /// name of this shape is a "right rectangular prism."
825    pub fn aabb(&self, aabb: Aabb<i32>) -> PrimitiveRef {
826        self.prim(Primitive::Aabb(aabb.made_valid()))
827    }
828
829    /// Returns a `PrimitiveRef` of a sphere using a radius check.
830    pub fn sphere(&self, aabb: Aabb<i32>) -> PrimitiveRef {
831        self.prim(Primitive::Sphere(aabb.made_valid()))
832    }
833
834    /// Returns a `PrimitiveRef` of a sphere using a radius check where a radius
835    /// and origin are parameters instead of a bounding box.
836    pub fn sphere_with_radius(&self, origin: Vec3<i32>, radius: f32) -> PrimitiveRef {
837        let min = origin - Vec3::broadcast(radius.round() as i32);
838        let max = origin + Vec3::broadcast(radius.round() as i32);
839        self.prim(Primitive::Sphere(Aabb { min, max }))
840    }
841
842    /// Returns a `PrimitiveRef` of a sphere by returning an ellipsoid with
843    /// congruent legs. The voxel artifacts are slightly different from the
844    /// radius check `sphere()` method.
845    pub fn sphere2(&self, aabb: Aabb<i32>) -> PrimitiveRef {
846        let aabb = aabb.made_valid();
847        let radius = aabb.size().w.min(aabb.size().h) / 2;
848        let aabb = Aabb {
849            min: aabb.center() - radius,
850            max: aabb.center() + radius,
851        };
852        let degree = 2.0;
853        self.prim(Primitive::Superquadric { aabb, degree })
854    }
855
856    /// Returns a `PrimitiveRef` of an ellipsoid by constructing a superquadric
857    /// with a degree value of 2.0.
858    pub fn ellipsoid(&self, aabb: Aabb<i32>) -> PrimitiveRef {
859        let aabb = aabb.made_valid();
860        let degree = 2.0;
861        self.prim(Primitive::Superquadric { aabb, degree })
862    }
863
864    /// Returns a `PrimitiveRef` of a superquadric. A superquadric can be
865    /// thought of as a rounded Aabb where the degree determines how rounded
866    /// the corners are. Values from 0.0 to 1.0 produce concave faces or
867    /// "inverse rounded corners." A value of 1.0 produces a stretched
868    /// octahedron (or a non-stretched octahedron if the provided Aabb is a
869    /// cube). Values from 1.0 to 2.0 produce an octahedron with convex
870    /// faces. A degree of 2.0 produces an ellipsoid. Values larger than 2.0
871    /// produce a rounded Aabb. The degree cannot be less than 0.0 without
872    /// the shape extending to infinity.
873    pub fn superquadric(&self, aabb: Aabb<i32>, degree: f32) -> PrimitiveRef {
874        let aabb = aabb.made_valid();
875        self.prim(Primitive::Superquadric { aabb, degree })
876    }
877
878    /// Returns a `PrimitiveRef` of a rounded Aabb by producing a superquadric
879    /// with a degree value of 3.0.
880    pub fn rounded_aabb(&self, aabb: Aabb<i32>) -> PrimitiveRef {
881        let aabb = aabb.made_valid();
882        self.prim(Primitive::Superquadric { aabb, degree: 3.0 })
883    }
884
885    /// Returns a `PrimitiveRef` of the largest cylinder that fits in the
886    /// provided Aabb.
887    pub fn cylinder(&self, aabb: Aabb<i32>) -> PrimitiveRef {
888        self.prim(Primitive::Cylinder(aabb.made_valid()))
889    }
890
891    /// Returns a `PrimitiveRef` of the largest horizontal cylinder that fits in
892    /// the provided Aabb.
893    pub fn horizontal_cylinder(&self, aabb: Aabb<i32>, dir: Dir) -> PrimitiveRef {
894        let aabr = Aabr::from(aabb);
895        let length = dir.select(aabr.size());
896        let height = aabb.max.z - aabb.min.z;
897        let aabb = Aabb {
898            min: (aabr.min - dir.abs().to_vec2() * height).with_z(aabb.min.z),
899            max: (dir.abs().select_with(aabr.min, aabr.max)).with_z(aabb.min.z + length),
900        };
901        self.cylinder(aabb)
902            .rotate_about((-dir.abs()).from_z_mat3(), aabr.min.with_z(aabb.min.z))
903    }
904
905    /// Returns a `PrimitiveRef` of a cylinder using a radius check where a
906    /// radius and origin are parameters instead of a bounding box.
907    pub fn cylinder_with_radius(
908        &self,
909        origin: Vec3<i32>,
910        radius: f32,
911        height: f32,
912    ) -> PrimitiveRef {
913        let min = origin - Vec2::broadcast(radius.round() as i32);
914        let max = origin + Vec2::broadcast(radius.round() as i32).with_z(height.round() as i32);
915        self.prim(Primitive::Cylinder(Aabb { min, max }))
916    }
917
918    /// Returns a `PrimitiveRef` of the largest cone that fits in the
919    /// provided Aabb.
920    pub fn cone(&self, aabb: Aabb<i32>) -> PrimitiveRef {
921        self.prim(Primitive::Cone(aabb.made_valid()))
922    }
923
924    /// Returns a `PrimitiveRef` of a cone using a radius check where a radius
925    /// and origin are parameters instead of a bounding box.
926    pub fn cone_with_radius(&self, origin: Vec3<i32>, radius: f32, height: f32) -> PrimitiveRef {
927        let min = origin - Vec2::broadcast(radius.round() as i32);
928        let max = origin + Vec2::broadcast(radius.round() as i32).with_z(height.round() as i32);
929        self.prim(Primitive::Cone(Aabb { min, max }))
930    }
931
932    /// Returns a `PrimitiveRef` of a 3-dimensional line segment with a provided
933    /// radius.
934    pub fn line(
935        &self,
936        a: Vec3<impl AsPrimitive<f32>>,
937        b: Vec3<impl AsPrimitive<f32>>,
938        radius: f32,
939    ) -> PrimitiveRef {
940        self.prim(Primitive::Segment {
941            segment: LineSegment3 {
942                start: a.as_(),
943                end: b.as_(),
944            },
945            r0: radius,
946            r1: radius,
947        })
948    }
949
950    /// Returns a `PrimitiveRef` of a 3-dimensional line segment with two
951    /// radius.
952    pub fn line_two_radius(
953        &self,
954        a: Vec3<impl AsPrimitive<f32>>,
955        b: Vec3<impl AsPrimitive<f32>>,
956        r0: f32,
957        r1: f32,
958    ) -> PrimitiveRef {
959        self.prim(Primitive::Segment {
960            segment: LineSegment3 {
961                start: a.as_(),
962                end: b.as_(),
963            },
964            r0,
965            r1,
966        })
967    }
968
969    /// Returns a `PrimitiveRef` of a 3-dimensional line segment where the
970    /// provided radius only affects the width of the shape. The height of
971    /// the shape is determined by the `height` parameter. The height of the
972    /// shape is extended upwards along the z axis from the line. The top and
973    /// bottom of the shape are planar and parallel to each other and the line.
974    pub fn segment_prism(
975        &self,
976        a: Vec3<impl AsPrimitive<f32>>,
977        b: Vec3<impl AsPrimitive<f32>>,
978        radius: f32,
979        height: f32,
980    ) -> PrimitiveRef {
981        let segment = LineSegment3 {
982            start: a.as_(),
983            end: b.as_(),
984        };
985        self.prim(Primitive::SegmentPrism {
986            segment,
987            radius,
988            height,
989        })
990    }
991
992    /// Returns a `PrimitiveRef` of a 3-dimensional cubic bezier curve by
993    /// dividing the curve into line segments with one segment approximately
994    /// every length of 5 blocks.
995    pub fn cubic_bezier(
996        &self,
997        start: Vec3<impl AsPrimitive<f32>>,
998        ctrl0: Vec3<impl AsPrimitive<f32>>,
999        ctrl1: Vec3<impl AsPrimitive<f32>>,
1000        end: Vec3<impl AsPrimitive<f32>>,
1001        radius: f32,
1002    ) -> PrimitiveRef {
1003        let bezier = CubicBezier3 {
1004            start: start.as_(),
1005            ctrl0: ctrl0.as_(),
1006            ctrl1: ctrl1.as_(),
1007            end: end.as_(),
1008        };
1009        let length = bezier.length_by_discretization(10);
1010        let num_segments = (0.2 * length).ceil() as u16;
1011        self.cubic_bezier_with_num_segments(bezier, radius, num_segments)
1012    }
1013
1014    /// Returns a `PrimitiveRef` of a 3-dimensional cubic bezier curve by
1015    /// dividing the curve into `num_segments` line segments.
1016    pub fn cubic_bezier_with_num_segments(
1017        &self,
1018        bezier: CubicBezier3<f32>,
1019        radius: f32,
1020        num_segments: u16,
1021    ) -> PrimitiveRef {
1022        let mut bezier_prim = self.empty();
1023        let range: Vec<_> = (0..=num_segments).collect();
1024        range.windows(2).for_each(|w| {
1025            let segment_start = bezier.evaluate(w[0] as f32 / num_segments as f32);
1026            let segment_end = bezier.evaluate(w[1] as f32 / num_segments as f32);
1027            bezier_prim = bezier_prim.union(self.line(segment_start, segment_end, radius));
1028        });
1029        bezier_prim
1030    }
1031
1032    /// Returns a `PrimitiveRef` of a 3-dimensional cubic bezier curve where the
1033    /// radius only governs the width of the curve. The height is governed
1034    /// by the `height` parameter where the shape extends upwards from the
1035    /// bezier curve by the value of `height`. The shape is constructed by
1036    /// dividing the curve into line segment prisms with one segment prism
1037    /// approximately every length of 5 blocks.
1038    pub fn cubic_bezier_prism(
1039        &self,
1040        start: Vec3<impl AsPrimitive<f32>>,
1041        ctrl0: Vec3<impl AsPrimitive<f32>>,
1042        ctrl1: Vec3<impl AsPrimitive<f32>>,
1043        end: Vec3<impl AsPrimitive<f32>>,
1044        radius: f32,
1045        height: f32,
1046    ) -> PrimitiveRef {
1047        let bezier = CubicBezier3 {
1048            start: start.as_(),
1049            ctrl0: ctrl0.as_(),
1050            ctrl1: ctrl1.as_(),
1051            end: end.as_(),
1052        };
1053        let length = bezier.length_by_discretization(10);
1054        let num_segments = (0.2 * length).ceil() as u16;
1055        self.cubic_bezier_prism_with_num_segments(bezier, radius, height, num_segments)
1056    }
1057
1058    /// Returns a `PrimitiveRef` of a 3-dimensional cubic bezier curve where the
1059    /// radius only governs the width of the curve. The height is governed
1060    /// by the `height` parameter where the shape extends upwards from the
1061    /// bezier curve by the value of `height`. The shape is constructed by
1062    /// dividing the curve into `num_segments` line segment prisms.
1063    pub fn cubic_bezier_prism_with_num_segments(
1064        &self,
1065        bezier: CubicBezier3<f32>,
1066        radius: f32,
1067        height: f32,
1068        num_segments: u16,
1069    ) -> PrimitiveRef {
1070        let mut bezier_prim = self.empty();
1071        let range: Vec<_> = (0..=num_segments).collect();
1072        range.windows(2).for_each(|w| {
1073            let segment_start = bezier.evaluate(w[0] as f32 / num_segments as f32);
1074            let segment_end = bezier.evaluate(w[1] as f32 / num_segments as f32);
1075            bezier_prim =
1076                bezier_prim.union(self.segment_prism(segment_start, segment_end, radius, height));
1077        });
1078        bezier_prim
1079    }
1080
1081    /// Returns a `PrimitiveRef` of a plane. The Aabr provides the bounds for
1082    /// the plane in the xy plane and the gradient determines its slope through
1083    /// the dot product. A gradient of <1.0, 0.0> creates a plane with a
1084    /// slope of 1.0 in the xz plane.
1085    pub fn plane(&self, aabr: Aabr<i32>, origin: Vec3<i32>, gradient: Vec2<f32>) -> PrimitiveRef {
1086        let aabr = aabr.made_valid();
1087        self.prim(Primitive::Plane(aabr, origin, gradient))
1088    }
1089
1090    /// Returns a `PrimitiveRef` of an Aabb with a slope cut into it. The
1091    /// `inset` governs the slope. The `dir` determines which direction the
1092    /// ramp points.
1093    pub fn ramp_inset(&self, aabb: Aabb<i32>, inset: i32, dir: Dir) -> PrimitiveRef {
1094        let aabb = aabb.made_valid();
1095        self.prim(Primitive::Ramp { aabb, inset, dir })
1096    }
1097
1098    pub fn ramp(&self, aabb: Aabb<i32>, dir: Dir) -> PrimitiveRef {
1099        let aabb = aabb.made_valid();
1100        self.prim(Primitive::Ramp {
1101            aabb,
1102            inset: dir.select((aabb.size().w, aabb.size().h)),
1103            dir,
1104        })
1105    }
1106
1107    /// Returns a `PrimitiveRef` of a triangular prism with the base being
1108    /// vertical. A gable is a tent shape. The `inset` governs the slope of
1109    /// the gable. The `dir` determines which way the gable points.
1110    pub fn gable(&self, aabb: Aabb<i32>, inset: i32, dir: Dir) -> PrimitiveRef {
1111        let aabb = aabb.made_valid();
1112        self.prim(Primitive::Gable { aabb, inset, dir })
1113    }
1114
1115    /// Places a sprite at the provided location with the default rotation.
1116    pub fn sprite(&self, pos: Vec3<i32>, sprite: SpriteKind) {
1117        self.aabb(Aabb {
1118            min: pos,
1119            max: pos + 1,
1120        })
1121        .fill(Fill::sprite(sprite))
1122    }
1123
1124    /// Places a sprite at the provided location with the provided orientation.
1125    pub fn rotated_sprite(&self, pos: Vec3<i32>, sprite: SpriteKind, ori: u8) {
1126        self.aabb(Aabb {
1127            min: pos,
1128            max: pos + 1,
1129        })
1130        .fill(Fill::sprite_ori(sprite, ori % 8))
1131    }
1132
1133    /// Places a sprite at the provided location with the provided orientation
1134    /// and the provided [`SpriteCfg`].
1135    pub fn rotated_sprite_with_cfg(
1136        &self,
1137        pos: Vec3<i32>,
1138        sprite: SpriteKind,
1139        ori: u8,
1140        cfg: SpriteCfg,
1141    ) {
1142        self.aabb(Aabb {
1143            min: pos,
1144            max: pos + 1,
1145        })
1146        .fill(Fill::sprite_ori_cfg(sprite, ori % 8, cfg))
1147    }
1148
1149    /// Places a sprite at the provided location with the provided orientation
1150    /// which will be tracked by rtsim nature if the sprite has an associated
1151    /// [`veloren_common::rtsim::ChunkResource`].
1152    pub fn resource_sprite(&self, pos: Vec3<i32>, sprite: SpriteKind, ori: u8) {
1153        self.aabb(Aabb {
1154            min: pos,
1155            max: pos + 1,
1156        })
1157        .fill(Fill::resource_sprite_ori(sprite, ori % 8))
1158    }
1159
1160    /// Places a sprite at the provided location with the provided orientation
1161    /// which will be tracked by rtsim nature if the sprite has an associated
1162    /// [`veloren_common::rtsim::ChunkResource`].
1163    pub fn owned_resource_sprite(&self, pos: Vec3<i32>, sprite: SpriteKind, ori: u8) {
1164        self.aabb(Aabb {
1165            min: pos,
1166            max: pos + 1,
1167        })
1168        .fill(Fill::owned_resource_sprite_ori(sprite, ori))
1169    }
1170
1171    /// Returns a `PrimitiveRef` of the largest pyramid with a slope of 1 that
1172    /// fits in the provided Aabb.
1173    pub fn pyramid(&self, aabb: Aabb<i32>) -> PrimitiveRef {
1174        let inset = 0;
1175        let aabb = aabb.made_valid();
1176        self.prim(Primitive::Ramp {
1177            aabb,
1178            inset,
1179            dir: Dir::X,
1180        })
1181        .intersect(self.prim(Primitive::Ramp {
1182            aabb,
1183            inset,
1184            dir: Dir::NegX,
1185        }))
1186        .intersect(self.prim(Primitive::Ramp {
1187            aabb,
1188            inset,
1189            dir: Dir::Y,
1190        }))
1191        .intersect(self.prim(Primitive::Ramp {
1192            aabb,
1193            inset,
1194            dir: Dir::NegY,
1195        }))
1196    }
1197
1198    /// Used to create a new `PrimitiveRef`. Requires the desired `Primitive` to
1199    /// be supplied.
1200    pub fn prim(&self, prim: Primitive) -> PrimitiveRef {
1201        PrimitiveRef {
1202            id: self.prims.borrow_mut().insert(prim),
1203            painter: self,
1204        }
1205    }
1206
1207    /// Returns a `PrimitiveRef` of an empty primitive. Useful when additional
1208    /// primitives are unioned within a loop.
1209    pub fn empty(&self) -> PrimitiveRef { self.prim(Primitive::Empty) }
1210
1211    /// Fills the supplied primitive with the provided `Fill`.
1212    pub fn fill(&self, prim: impl Into<Id<Primitive>>, fill: Fill) {
1213        let prim = prim.into();
1214        if let Primitive::Union(a, b) = self.prims.borrow()[prim] {
1215            self.fill(a, fill.clone());
1216            self.fill(b, fill);
1217        } else {
1218            self.fills.borrow_mut().push((prim, fill));
1219        }
1220    }
1221
1222    /// ```text
1223    ///     ___
1224    ///    /  /\
1225    ///   /__/  |
1226    ///  /   \  |
1227    /// |     | /
1228    /// |_____|/
1229    /// ```
1230    /// A horizontal half cylinder on top of an `Aabb`.
1231    pub fn vault(&self, aabb: Aabb<i32>, dir: Dir) -> PrimitiveRef {
1232        let h = dir.orthogonal().select(Vec3::from(aabb.size()).xy());
1233
1234        let mut prim = self.horizontal_cylinder(
1235            Aabb {
1236                min: aabb.min.with_z(aabb.max.z - h),
1237                max: aabb.max,
1238            },
1239            dir,
1240        );
1241
1242        if aabb.size().d < h {
1243            prim = prim.intersect(self.aabb(aabb));
1244        }
1245
1246        self.aabb(Aabb {
1247            min: aabb.min,
1248            max: aabb.max.with_z(aabb.max.z - h / 2),
1249        })
1250        .union(prim)
1251    }
1252
1253    /// Place aabbs around another aabb in a symmetric and distributed manner.
1254    pub fn aabbs_around_aabb(&self, aabb: Aabb<i32>, size: i32, offset: i32) -> PrimitiveRef {
1255        let pillar = self.aabb(Aabb {
1256            min: (aabb.min.xy() - 1).with_z(aabb.min.z),
1257            max: (aabb.min.xy() + size - 1).with_z(aabb.max.z),
1258        });
1259
1260        let true_offset = offset + size;
1261
1262        let size_x = aabb.max.x - aabb.min.x;
1263        let size_y = aabb.max.y - aabb.min.y;
1264
1265        let num_aabbs = ((size_x + 1) / 2) / true_offset;
1266        let x = pillar.repeat(Vec3::new(true_offset, 0, 0), num_aabbs as u32 + 1);
1267
1268        let num_aabbs = ((size_y + 1) / 2) / true_offset;
1269        let y = pillar.repeat(Vec3::new(0, true_offset, 0), num_aabbs as u32 + 1);
1270        let center = aabb.as_::<f32>().center();
1271        let shape = x.union(y);
1272        let shape =
1273            shape.union(shape.rotate_about(Mat3::new(-1, 0, 0, 0, -1, 0, 0, 0, -1), center));
1274        shape.union(shape.rotate_about(Mat3::new(0, 1, 0, -1, 0, 0, 0, 0, 1), center))
1275    }
1276
1277    pub fn staircase_in_aabb(
1278        &self,
1279        aabb: Aabb<i32>,
1280        thickness: i32,
1281        start_dir: Dir,
1282    ) -> PrimitiveRef {
1283        let mut forward = start_dir;
1284        let mut z = aabb.max.z - 1;
1285        let aabr = Aabr::from(aabb);
1286
1287        let mut prim = self.empty();
1288
1289        while z > aabb.min.z {
1290            let right = forward.rotated_cw();
1291            let fc = forward.select_aabr(aabr);
1292            let corner =
1293                fc * forward.abs().to_vec2() + right.select_aabr(aabr) * right.abs().to_vec2();
1294            let aabb = Aabb {
1295                min: corner.with_z(z),
1296                max: (corner - (forward.to_vec2() + right.to_vec2()) * thickness).with_z(z + 1),
1297            }
1298            .made_valid();
1299
1300            let stair_len = ((fc - (-forward).select_aabr(aabr)).abs() - thickness * 2).max(1) + 1;
1301
1302            let stairs = self.ramp(
1303                Aabb {
1304                    min: (corner - right.to_vec2() * (stair_len + thickness)).with_z(z - stair_len),
1305                    max: (corner
1306                        - right.to_vec2() * (thickness - 1)
1307                        - forward.to_vec2() * thickness)
1308                        .with_z(z + 1),
1309                }
1310                .made_valid(),
1311                right,
1312            );
1313
1314            prim = prim
1315                .union(self.aabb(aabb))
1316                .union(stairs.without(stairs.translate(Vec3::new(0, 0, -2))));
1317
1318            z -= stair_len;
1319            forward = forward.rotated_ccw();
1320        }
1321        prim
1322    }
1323
1324    /// A simple numeral 0-9
1325    pub fn numeral(&self, origin: Vec3<i32>, numeral: usize) -> PrimitiveRef {
1326        let bottom_bar = self.aabb(Aabb {
1327            min: Vec2::new(origin.x, origin.y).with_z(origin.z),
1328            max: Vec2::new(origin.x + 1, origin.y + 4).with_z(origin.z + 1),
1329        });
1330        let mid_bar = self.aabb(Aabb {
1331            min: Vec2::new(origin.x, origin.y).with_z(origin.z + 2),
1332            max: Vec2::new(origin.x + 1, origin.y + 4).with_z(origin.z + 3),
1333        });
1334        let top_bar = self.aabb(Aabb {
1335            min: Vec2::new(origin.x, origin.y).with_z(origin.z + 4),
1336            max: Vec2::new(origin.x + 1, origin.y + 4).with_z(origin.z + 5),
1337        });
1338        let left_top = self.aabb(Aabb {
1339            min: Vec2::new(origin.x, origin.y).with_z(origin.z + 2),
1340            max: Vec2::new(origin.x + 1, origin.y + 1).with_z(origin.z + 5),
1341        });
1342        let left_bottom = self.aabb(Aabb {
1343            min: Vec2::new(origin.x, origin.y).with_z(origin.z),
1344            max: Vec2::new(origin.x + 1, origin.y + 1).with_z(origin.z + 3),
1345        });
1346        let right_top = self.aabb(Aabb {
1347            min: Vec2::new(origin.x, origin.y + 3).with_z(origin.z + 2),
1348            max: Vec2::new(origin.x + 1, origin.y + 4).with_z(origin.z + 5),
1349        });
1350        let right_bottom = self.aabb(Aabb {
1351            min: Vec2::new(origin.x, origin.y + 3).with_z(origin.z),
1352            max: Vec2::new(origin.x + 1, origin.y + 4).with_z(origin.z + 3),
1353        });
1354        let number_strokes = match numeral {
1355            0 => &[
1356                top_bar,
1357                bottom_bar,
1358                right_top,
1359                right_bottom,
1360                left_top,
1361                left_bottom,
1362            ] as &[_],
1363            1 => &[right_top, right_bottom],
1364            2 => &[top_bar, right_top, mid_bar, left_bottom, bottom_bar],
1365            3 => &[top_bar, bottom_bar, mid_bar, right_top, right_bottom],
1366            4 => &[left_top, mid_bar, right_top, right_bottom],
1367            5 => &[top_bar, left_top, mid_bar, right_bottom, bottom_bar],
1368            6 => &[
1369                top_bar,
1370                left_top,
1371                left_bottom,
1372                bottom_bar,
1373                right_bottom,
1374                mid_bar,
1375            ],
1376            7 => &[top_bar, right_top, right_bottom],
1377            8 => &[
1378                top_bar,
1379                left_top,
1380                left_bottom,
1381                mid_bar,
1382                right_top,
1383                right_bottom,
1384                bottom_bar,
1385            ],
1386            _ => &[top_bar, left_top, mid_bar, right_top, right_bottom],
1387        };
1388
1389        let mut prim = self.empty();
1390        for stroke in number_strokes {
1391            prim = prim.union(*stroke)
1392        }
1393
1394        prim
1395    }
1396
1397    pub fn column(&self, point: Vec2<i32>, range: impl RangeBounds<i32>) -> PrimitiveRef {
1398        self.aabb(Aabb {
1399            min: point.with_z(match range.start_bound() {
1400                std::ops::Bound::Included(n) => *n,
1401                std::ops::Bound::Excluded(n) => n + 1,
1402                std::ops::Bound::Unbounded => i32::MIN,
1403            }),
1404            max: (point + 1).with_z(match range.end_bound() {
1405                std::ops::Bound::Included(n) => n + 1,
1406                std::ops::Bound::Excluded(n) => *n,
1407                std::ops::Bound::Unbounded => i32::MAX,
1408            }),
1409        })
1410    }
1411
1412    /// The area that the canvas is currently rendering.
1413    pub fn render_aabr(&self) -> Aabr<i32> { self.render_area }
1414
1415    /// Spawns an entity if it is in the render_aabr, otherwise does nothing.
1416    pub fn spawn(&self, entity: EntityInfo) {
1417        if self.render_area.contains_point(entity.pos.xy().as_()) {
1418            self.entities.borrow_mut().push(entity)
1419        }
1420    }
1421}
1422
1423pub fn render_prefab(file_path: &str, position: Vec3<i32>, painter: &Painter) {
1424    let asset_handle = PrefabStructure::load_group(file_path);
1425    let prefab_structure = asset_handle.read()[0].clone();
1426
1427    // Render the prefab
1428    painter
1429        .prim(Primitive::Prefab(Box::new(prefab_structure.clone())))
1430        .translate(position)
1431        .fill(Fill::Prefab(Box::new(prefab_structure), position, 0));
1432}
1433
1434#[derive(Copy, Clone)]
1435pub struct PrimitiveRef<'a> {
1436    id: Id<Primitive>,
1437    painter: &'a Painter,
1438}
1439
1440impl<'a> From<PrimitiveRef<'a>> for Id<Primitive> {
1441    fn from(r: PrimitiveRef<'a>) -> Self { r.id }
1442}
1443
1444impl<'a> PrimitiveRef<'a> {
1445    /// Joins two primitives together by returning the total of the blocks of
1446    /// both primitives. In boolean logic this is an `OR` operation.
1447    #[must_use]
1448    pub fn union(self, other: impl Into<Id<Primitive>>) -> PrimitiveRef<'a> {
1449        let (a, b) = self.painter.order_by_depth(self, other);
1450        self.painter.prim(Primitive::union(a, b))
1451    }
1452
1453    /// Joins two primitives together by returning only overlapping blocks. In
1454    /// boolean logic this is an `AND` operation.
1455    #[must_use]
1456    pub fn intersect(self, other: impl Into<Id<Primitive>>) -> PrimitiveRef<'a> {
1457        let (a, b) = self.painter.order_by_depth(self, other);
1458        self.painter.prim(Primitive::intersect(a, b))
1459    }
1460
1461    /// Subtracts the blocks of the `other` primitive from `self`. In boolean
1462    /// logic this is a `NOT` operation.
1463    #[must_use]
1464    pub fn without(self, other: impl Into<Id<Primitive>>) -> PrimitiveRef<'a> {
1465        self.painter.prim(Primitive::without(self, other))
1466    }
1467
1468    /// Fills the primitive with `fill` and paints it into the world.
1469    pub fn fill(self, fill: Fill) { self.painter.fill(self, fill); }
1470
1471    /// Fills the primitive with empty blocks. This will subtract any
1472    /// blocks in the world that inhabit the same positions as the blocks in
1473    /// this primitive.
1474    pub fn clear(self) { self.painter.fill(self, Fill::Block(Block::empty())); }
1475
1476    /// Returns a `PrimitiveRef` that conforms to the provided sampling
1477    /// function.
1478    #[must_use]
1479    pub fn sample(self, sampling: impl Fn(Vec3<i32>) -> bool + 'static) -> PrimitiveRef<'a> {
1480        self.painter
1481            .prim(Primitive::sampling(self, Box::new(sampling)))
1482    }
1483
1484    /// Returns a `PrimitiveRef` that conforms to the provided sampling
1485    /// function.
1486    #[must_use]
1487    pub fn sample_with_column(
1488        self,
1489        sampling: impl Fn(Vec3<i32>, &ColInfo) -> bool + 'static,
1490    ) -> PrimitiveRef<'a> {
1491        self.painter
1492            .prim(Primitive::column_sampling(self, Box::new(sampling)))
1493    }
1494
1495    /// Rotates a primitive about it's own's bounds minimum point,
1496    #[must_use]
1497    pub fn rotate_about_min(self, mat: Mat3<i32>) -> PrimitiveRef<'a> {
1498        let point = Fill::get_bounds(&self.painter.prims.borrow(), self.into()).min;
1499        self.rotate_about(mat, point)
1500    }
1501}
1502
1503/// A trait to more easily manipulate groups of primitives.
1504pub trait PrimitiveTransform {
1505    /// Translates the primitive along the vector `trans`.
1506    #[must_use]
1507    fn translate(self, trans: Vec3<i32>) -> Self;
1508    /// Rotates the primitive about the given point by multiplying each block
1509    /// position by the provided rotation matrix.
1510    #[must_use]
1511    fn rotate_about(self, rot: Mat3<i32>, point: Vec3<impl AsPrimitive<f32>>) -> Self;
1512    /// Rotates the primitive 90 degrees counterclockwise about the given point
1513    /// along the Z axis n times.
1514    #[must_use]
1515    fn rotate_z_90_about(self, n: i32, point: Vec3<impl AsPrimitive<f32>>) -> Self;
1516    /// Scales the primitive along each axis by the x, y, and z components of
1517    /// the `scale` vector respectively.
1518    #[must_use]
1519    fn scale(self, scale: Vec3<impl AsPrimitive<f32>>) -> Self;
1520    /// Returns a `PrimitiveRef` of the primitive in addition to the same
1521    /// primitive translated by `offset` and repeated `count` times, each time
1522    /// translated by an additional offset.
1523    #[must_use]
1524    fn repeat(self, offset: Vec3<i32>, count: u32) -> Self;
1525}
1526
1527impl PrimitiveTransform for PrimitiveRef<'_> {
1528    fn translate(self, trans: Vec3<i32>) -> Self {
1529        self.painter.prim(Primitive::translate(self, trans))
1530    }
1531
1532    fn rotate_about(self, rot: Mat3<i32>, point: Vec3<impl AsPrimitive<f32>>) -> Self {
1533        self.painter.prim(Primitive::rotate_about(self, rot, point))
1534    }
1535
1536    fn rotate_z_90_about(self, n: i32, point: Vec3<impl AsPrimitive<f32>>) -> Self {
1537        self.painter
1538            .prim(Primitive::rotate_z_90_about(self, n, point))
1539    }
1540
1541    fn scale(self, scale: Vec3<impl AsPrimitive<f32>>) -> Self {
1542        self.painter.prim(Primitive::scale(self, scale.as_()))
1543    }
1544
1545    fn repeat(self, offset: Vec3<i32>, count: u32) -> Self {
1546        self.painter.prim(Primitive::repeat(self, offset, count))
1547    }
1548}
1549
1550impl<const N: usize> PrimitiveTransform for [PrimitiveRef<'_>; N] {
1551    fn translate(mut self, trans: Vec3<i32>) -> Self {
1552        for prim in &mut self {
1553            *prim = prim.translate(trans);
1554        }
1555        self
1556    }
1557
1558    fn rotate_about(mut self, rot: Mat3<i32>, point: Vec3<impl AsPrimitive<f32>>) -> Self {
1559        for prim in &mut self {
1560            *prim = prim.rotate_about(rot, point);
1561        }
1562        self
1563    }
1564
1565    fn rotate_z_90_about(mut self, n: i32, point: Vec3<impl AsPrimitive<f32>>) -> Self {
1566        for prim in &mut self {
1567            *prim = prim.rotate_z_90_about(n, point);
1568        }
1569        self
1570    }
1571
1572    fn scale(mut self, scale: Vec3<impl AsPrimitive<f32>>) -> Self {
1573        for prim in &mut self {
1574            *prim = prim.scale(scale);
1575        }
1576        self
1577    }
1578
1579    fn repeat(mut self, offset: Vec3<i32>, count: u32) -> Self {
1580        for prim in &mut self {
1581            *prim = prim.repeat(offset, count);
1582        }
1583        self
1584    }
1585}
1586
1587pub trait Structure {
1588    #[cfg(feature = "use-dyn-lib")]
1589    const UPDATE_FN: &'static [u8];
1590
1591    fn render_inner(&self, _site: &Site, _land: &Land, _painter: &Painter) {}
1592
1593    fn render(&self, site: &Site, land: &Land, painter: &Painter) {
1594        #[cfg(not(feature = "use-dyn-lib"))]
1595        {
1596            self.render_inner(site, land, painter);
1597        }
1598        #[cfg(feature = "use-dyn-lib")]
1599        {
1600            let lock = LIB.lock().unwrap();
1601            let lib = &lock.as_ref().unwrap().lib;
1602
1603            let update_fn: common_dynlib::Symbol<fn(&Self, &Site, &Land, &Painter)> = unsafe {
1604                //let start = std::time::Instant::now();
1605                // Overhead of 0.5-5 us (could use hashmap to mitigate if this is an issue)
1606                lib.get(Self::UPDATE_FN)
1607                //println!("{}", start.elapsed().as_nanos());
1608            }
1609            .unwrap_or_else(|e| {
1610                panic!(
1611                    "Trying to use: {} but had error: {:?}",
1612                    CStr::from_bytes_with_nul(Self::UPDATE_FN)
1613                        .map(CStr::to_str)
1614                        .unwrap()
1615                        .unwrap(),
1616                    e
1617                )
1618            });
1619
1620            update_fn(self, site, land, painter);
1621        }
1622    }
1623
1624    // Generate a primitive tree and fills for this structure
1625    fn render_collect(
1626        &self,
1627        site: &Site,
1628        canvas: &CanvasInfo,
1629    ) -> (
1630        Store<Primitive>,
1631        Vec<(Id<Primitive>, Fill)>,
1632        Vec<EntityInfo>,
1633    ) {
1634        let painter = Painter {
1635            prims: RefCell::new(Store::default()),
1636            fills: RefCell::new(Vec::new()),
1637            entities: RefCell::new(Vec::new()),
1638            render_area: Aabr {
1639                min: canvas.wpos,
1640                max: canvas.wpos + TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
1641            },
1642        };
1643
1644        self.render(site, &canvas.land(), &painter);
1645        (
1646            painter.prims.into_inner(),
1647            painter.fills.into_inner(),
1648            painter.entities.into_inner(),
1649        )
1650    }
1651
1652    /// What `z_off` in `terrain_surface_at` should be relative to for each
1653    /// column.
1654    fn rel_terrain_offset(&self, col: &ColumnSample) -> i32 { col.alt as i32 }
1655
1656    fn terrain_surface_at<R: Rng>(
1657        &self,
1658        _wpos: Vec2<i32>,
1659        _old: Block,
1660        _rng: &mut R,
1661        _col: &ColumnSample,
1662        _z_off: i32,
1663        _site: &Site,
1664    ) -> Option<Block> {
1665        None
1666    }
1667}
1668
1669/// Extend a 2d AABR to a 3d AABB
1670pub fn aabr_with_z<T>(aabr: Aabr<T>, z: Range<T>) -> Aabb<T> {
1671    Aabb {
1672        min: aabr.min.with_z(z.start),
1673        max: aabr.max.with_z(z.end),
1674    }
1675}
1676
1677#[expect(dead_code)]
1678/// Just the corners of an AABB, good for outlining stuff when debugging
1679pub fn aabb_corners<F: FnMut(Primitive) -> Id<Primitive>>(
1680    prim: &mut F,
1681    aabb: Aabb<i32>,
1682) -> Id<Primitive> {
1683    let f = |prim: &mut F, ret, vec| {
1684        let sub = prim(Primitive::Aabb(Aabb {
1685            min: aabb.min + vec,
1686            max: aabb.max - vec,
1687        }));
1688        prim(Primitive::Without(ret, sub))
1689    };
1690    let mut ret = prim(Primitive::Aabb(aabb));
1691    ret = f(prim, ret, Vec3::new(1, 0, 0));
1692    ret = f(prim, ret, Vec3::new(0, 1, 0));
1693    ret = f(prim, ret, Vec3::new(0, 0, 1));
1694    ret
1695}
1696
1697pub fn place_circular(
1698    center: Vec2<i32>,
1699    radius: f32,
1700    amount: i32,
1701) -> impl Iterator<Item = Vec2<i32>> {
1702    let phi = TAU / amount as f32;
1703    (1..=amount).map(move |n| {
1704        Vec2::new(
1705            center.x + (radius * ((n as f32 * phi).cos())) as i32,
1706            center.y + (radius * ((n as f32 * phi).sin())) as i32,
1707        )
1708    })
1709}
1710
1711pub fn place_circular_as_vec(center: Vec2<i32>, radius: f32, amount: i32) -> Vec<Vec2<i32>> {
1712    let phi = TAU / amount as f32;
1713    let mut positions = vec![];
1714    for n in 1..=amount {
1715        let pos = Vec2::new(
1716            center.x + (radius * ((n as f32 * phi).cos())) as i32,
1717            center.y + (radius * ((n as f32 * phi).sin())) as i32,
1718        );
1719        positions.push(pos);
1720    }
1721    positions
1722}
1723
1724pub fn spiral_staircase(
1725    origin: Vec3<i32>,
1726    radius: f32,
1727    inner_radius: f32,
1728    stretch: f32,
1729) -> Box<dyn Fn(Vec3<i32>) -> bool> {
1730    Box::new(move |pos: Vec3<i32>| {
1731        let pos = pos - origin;
1732        if (pos.xy().magnitude_squared() as f32) < inner_radius.powi(2) {
1733            true
1734        } else if (pos.xy().magnitude_squared() as f32) < radius.powi(2) {
1735            ((pos.x as f32).atan2(pos.y as f32) / (PI * 2.0) * stretch + pos.z as f32)
1736                .rem_euclid(stretch)
1737                < 1.5
1738        } else {
1739            false
1740        }
1741    })
1742}
1743
1744pub fn wall_staircase(
1745    origin: Vec3<i32>,
1746    radius: f32,
1747    stretch: f32,
1748) -> Box<dyn Fn(Vec3<i32>) -> bool> {
1749    Box::new(move |pos: Vec3<i32>| {
1750        let pos = pos - origin;
1751        if (pos.x.abs().max(pos.y.abs())) as f32 > 0.6 * radius {
1752            ((pos.x as f32).atan2(pos.y as f32) / (PI * 2.0) * stretch + pos.z as f32)
1753                .rem_euclid(stretch)
1754                < 1.0
1755        } else {
1756            false
1757        }
1758    })
1759}
1760
1761pub fn inscribed_polystar(
1762    origin: Vec2<i32>,
1763    radius: f32,
1764    sides: usize,
1765) -> Box<dyn Fn(Vec3<i32>) -> bool> {
1766    Box::new(move |pos| {
1767        use std::f32::consts::TAU;
1768        let rpos: Vec2<f32> = pos.xy().as_() - origin.as_();
1769        let is_border = rpos.magnitude_squared() > (radius - 2.0).powi(2);
1770        let is_line = (0..sides).any(|i| {
1771            let f = |j: f32| {
1772                let t = j * TAU / sides as f32;
1773                radius * Vec2::new(t.cos(), t.sin())
1774            };
1775            let line = LineSegment2 {
1776                start: f(i as f32),
1777                end: f((i + 2) as f32),
1778            };
1779            line.distance_to_point(rpos) <= 1.0
1780        });
1781        is_border || is_line
1782    })
1783}