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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
pub mod herringbone;
pub mod tileset_loader;
use glam::IVec2;
use crate::{
config::{CHUNK_SIZE, TILESET_SCALING},
proc_gen::{
herringbone::{tiles_overlapping, variant_index},
tileset_loader::{Tile, TileOrientation, Tileset, load_tileset},
},
sim::{cell::Cell, cell_manager::chunk::Chunk, entity::EntityDef},
};
pub struct TileCells {
pub size: IVec2,
pub cells: Vec<Cell>,
}
pub trait Biome {
fn derive_world_from_tile(&self, tile: &Tile) -> TileCells;
fn derive_entities_from_tile(&self, tile: &Tile) -> Vec<EntityDef> {
Vec::new()
}
}
pub struct TilesetWorldGenerator {
tileset: Tileset,
horizontal_tiles: Vec<TileCells>,
vertical_tiles: Vec<TileCells>,
}
impl TilesetWorldGenerator {
pub fn new(tileset_path: &str, biome: &dyn Biome) -> Self {
let tileset = load_tileset(tileset_path);
let horizontal_tiles = tileset
.horizontal_tiles
.iter()
.map(|tile| biome.derive_world_from_tile(tile))
.collect();
let vertical_tiles = tileset
.vertical_tiles
.iter()
.map(|tile| biome.derive_world_from_tile(tile))
.collect();
TilesetWorldGenerator {
tileset,
horizontal_tiles,
vertical_tiles,
}
}
fn grid_size(&self) -> IVec2 {
IVec2::splat(self.tileset.dimensions.short as i32 * TILESET_SCALING)
}
fn tile_at(&self, grid: IVec2, orientation: TileOrientation) -> &TileCells {
let tiles = match orientation {
TileOrientation::Horizontal => &self.horizontal_tiles,
TileOrientation::Vertical => &self.vertical_tiles,
};
&tiles[variant_index(grid, tiles.len())]
}
pub fn generate_chunk(&self, chunk_position: IVec2) -> Chunk {
let mut chunk = Chunk::void();
let chunk_min = chunk_position * CHUNK_SIZE;
let chunk_max = chunk_min + CHUNK_SIZE;
let grid = self.grid_size();
let tiles = tiles_overlapping(
chunk_min.div_euclid(grid),
(chunk_max - 1).div_euclid(grid) + 1,
);
for (grid_position, orientation) in tiles {
let tile = self.tile_at(grid_position, orientation);
let tile_min = grid_position * grid;
// subset of tile in chunk
let min = tile_min.max(chunk_min);
let max = (tile_min + tile.size).min(chunk_max);
if min.x >= max.x {
continue;
}
let width = (max.x - min.x) as usize;
for y in min.y..max.y {
let src = ((y - tile_min.y) * tile.size.x + (min.x - tile_min.x)) as usize;
let dst = ((y - chunk_min.y) * CHUNK_SIZE + (min.x - chunk_min.x)) as usize;
chunk.cells[dst..dst + width].copy_from_slice(&tile.cells[src..src + width]);
}
}
chunk.mark_collider_dirty(0);
chunk
}
}
|