summaryrefslogtreecommitdiff
path: root/src/proc_gen/mod.rs
blob: 049ad1a6a7dbd0f0abb4c576f2c1b7e8e9c5d6c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
pub mod herringbone;
pub mod tileset_loader;

use glam::IVec2;

use crate::{
    config::{CHUNK_SIZE, TILESET_SCALING},
    proc_gen::{
        herringbone::tiles_overlapping,
        tileset_loader::{Tile, TileOrientation, Tileset, load_tileset},
    },
    sim::{cell::Cell, cell_manager::chunk::Chunk, entity::EntityDef},
};

pub trait Biome {
    fn derive_world_from_tile(&self, _tile: &Tile) -> Vec<Cell> {
        Vec::new()
    }
    fn derive_entities_from_tile(&self, _tile: &Tile) -> Vec<EntityDef> {
        Vec::new()
    }
}

pub struct TilesetWorldGenerator {
    tileset: Tileset,
    biome: Box<dyn Biome>,
}

impl TilesetWorldGenerator {
    pub fn generate_chunk(&self, chunk_position: IVec2) -> Chunk {
        let mut chunk = Chunk::void();

        let a = chunk_position * CHUNK_SIZE;
        let b = (chunk_position + 1) * CHUNK_SIZE;
        let tiles = tiles_overlapping(a * TILESET_SCALING, b * TILESET_SCALING, &self.tileset);
        let world_tiles = tiles.map(|(p, t, o)| (p, self.biome.derive_world_from_tile(t), o));

        for (tp, t, o) in world_tiles {
            let p = tp * self.tileset.dimensions.short as i32 * TILESET_SCALING;
            let ta = p.max(a);
            let tb = p.min(b);
            if ta.x >= tb.x || ta.y >= tb.y {
                continue;
            }

            for y in ta.y..tb.y {
                for x in ta.x..tb.x {
                    let sw = match o {
                        TileOrientation::Horizontal => {
                            self.tileset.dimensions.long as i32 * TILESET_SCALING
                        }
                        TileOrientation::Vertical => {
                            self.tileset.dimensions.short as i32 * TILESET_SCALING
                        }
                    };

                    let src = (y - p.y) * sw + (x - p.x);
                    let dst = (y - a.y) * CHUNK_SIZE + (x - a.x);
                    chunk.cells[dst as usize] = t[src as usize];
                }
            }
        }

        chunk
    }

    pub fn new(tileset_path: &str, biome: Box<dyn Biome>) -> Self {
        let tileset = load_tileset(tileset_path);
        TilesetWorldGenerator { tileset, biome }
    }
}