terrain_forge/compose/
layer.rs1use 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}