terrain_forge/compose/
layer.rs

1//! Layered generation with blend modes
2
3use crate::{Algorithm, Grid, Tile};
4
5#[derive(Debug, Clone, Copy)]
6pub enum BlendMode {
7    Replace,
8    Union,
9    Intersect,
10    Mask,
11}
12
13pub struct LayeredGenerator {
14    layers: Vec<(Box<dyn Algorithm<Tile>>, BlendMode)>,
15}
16
17impl LayeredGenerator {
18    pub fn new() -> Self {
19        Self { layers: Vec::new() }
20    }
21
22    pub fn base<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
23        self.layers.push((Box::new(algo), BlendMode::Replace));
24        self
25    }
26
27    pub fn union<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
28        self.layers.push((Box::new(algo), BlendMode::Union));
29        self
30    }
31
32    pub fn intersect<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
33        self.layers.push((Box::new(algo), BlendMode::Intersect));
34        self
35    }
36
37    pub fn add<A: Algorithm<Tile> + 'static>(mut self, algo: A, mode: BlendMode) -> Self {
38        self.layers.push((Box::new(algo), mode));
39        self
40    }
41}
42
43impl Default for LayeredGenerator {
44    fn default() -> Self {
45        Self::new()
46    }
47}
48
49impl Algorithm<Tile> for LayeredGenerator {
50    fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
51        for (i, (algo, mode)) in self.layers.iter().enumerate() {
52            let layer_seed = seed.wrapping_add(i as u64 * 1000);
53
54            match mode {
55                BlendMode::Replace => {
56                    algo.generate(grid, layer_seed);
57                }
58                BlendMode::Union => {
59                    let mut layer = Grid::new(grid.width(), grid.height());
60                    algo.generate(&mut layer, layer_seed);
61                    for y in 0..grid.height() {
62                        for x in 0..grid.width() {
63                            if layer[(x, y)].is_floor() {
64                                grid.set(x as i32, y as i32, Tile::Floor);
65                            }
66                        }
67                    }
68                }
69                BlendMode::Intersect => {
70                    let mut layer = Grid::new(grid.width(), grid.height());
71                    algo.generate(&mut layer, layer_seed);
72                    for y in 0..grid.height() {
73                        for x in 0..grid.width() {
74                            if !layer[(x, y)].is_floor() {
75                                grid.set(x as i32, y as i32, Tile::Wall);
76                            }
77                        }
78                    }
79                }
80                BlendMode::Mask => {
81                    let mut mask = Grid::new(grid.width(), grid.height());
82                    algo.generate(&mut mask, layer_seed);
83                    for y in 0..grid.height() {
84                        for x in 0..grid.width() {
85                            if !mask[(x, y)].is_floor() {
86                                grid.set(x as i32, y as i32, Tile::Wall);
87                            }
88                        }
89                    }
90                }
91            }
92        }
93    }
94
95    fn name(&self) -> &'static str {
96        "LayeredGenerator"
97    }
98}