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, } pub trait Biome { fn derive_world_from_tile(&self, tile: &Tile) -> TileCells; fn derive_entities_from_tile(&self, tile: &Tile) -> Vec { Vec::new() } } pub struct TilesetWorldGenerator { tileset: Tileset, horizontal_tiles: Vec, vertical_tiles: Vec, } 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 } }