Skip to main content

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    Difference,
11    Mask,
12}
13
14pub struct LayeredGenerator {
15    layers: Vec<(Box<dyn Algorithm<Tile>>, BlendMode)>,
16}
17
18impl LayeredGenerator {
19    pub fn new() -> Self {
20        Self { layers: Vec::new() }
21    }
22
23    pub fn base<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
24        self.layers.push((Box::new(algo), BlendMode::Replace));
25        self
26    }
27
28    pub fn union<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
29        self.layers.push((Box::new(algo), BlendMode::Union));
30        self
31    }
32
33    pub fn intersect<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
34        self.layers.push((Box::new(algo), BlendMode::Intersect));
35        self
36    }
37
38    pub fn difference<A: Algorithm<Tile> + 'static>(mut self, algo: A) -> Self {
39        self.layers.push((Box::new(algo), BlendMode::Difference));
40        self
41    }
42
43    pub fn add<A: Algorithm<Tile> + 'static>(mut self, algo: A, mode: BlendMode) -> Self {
44        self.layers.push((Box::new(algo), mode));
45        self
46    }
47}
48
49impl Default for LayeredGenerator {
50    fn default() -> Self {
51        Self::new()
52    }
53}
54
55impl Algorithm<Tile> for LayeredGenerator {
56    fn generate(&self, grid: &mut Grid<Tile>, seed: u64) {
57        for (i, (algo, mode)) in self.layers.iter().enumerate() {
58            let layer_seed = seed.wrapping_add(i as u64 * 1000);
59
60            match mode {
61                BlendMode::Replace => {
62                    algo.generate(grid, layer_seed);
63                }
64                BlendMode::Union => {
65                    let mut layer = Grid::new(grid.width(), grid.height());
66                    algo.generate(&mut layer, layer_seed);
67                    for y in 0..grid.height() {
68                        for x in 0..grid.width() {
69                            if layer[(x, y)].is_floor() {
70                                grid.set(x as i32, y as i32, Tile::Floor);
71                            }
72                        }
73                    }
74                }
75                BlendMode::Intersect => {
76                    let mut layer = Grid::new(grid.width(), grid.height());
77                    algo.generate(&mut layer, layer_seed);
78                    for y in 0..grid.height() {
79                        for x in 0..grid.width() {
80                            if !layer[(x, y)].is_floor() {
81                                grid.set(x as i32, y as i32, Tile::Wall);
82                            }
83                        }
84                    }
85                }
86                BlendMode::Difference => {
87                    let mut layer = Grid::new(grid.width(), grid.height());
88                    algo.generate(&mut layer, layer_seed);
89                    for y in 0..grid.height() {
90                        for x in 0..grid.width() {
91                            if layer[(x, y)].is_floor() {
92                                grid.set(x as i32, y as i32, Tile::Wall);
93                            }
94                        }
95                    }
96                }
97                BlendMode::Mask => {
98                    let mut mask = Grid::new(grid.width(), grid.height());
99                    algo.generate(&mut mask, layer_seed);
100                    for y in 0..grid.height() {
101                        for x in 0..grid.width() {
102                            if !mask[(x, y)].is_floor() {
103                                grid.set(x as i32, y as i32, Tile::Wall);
104                            }
105                        }
106                    }
107                }
108            }
109        }
110    }
111
112    fn name(&self) -> &'static str {
113        "LayeredGenerator"
114    }
115}