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