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