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 {
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}