From 8e128d3ca24fa10dc7d871f7daf6c43eaddc385c Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sun, 30 Aug 2026 20:10:07 -0700 Subject: wip biome abstraction --- src/proc_gen/herringbone.rs | 46 +++++++++++++++++++++++++------- src/proc_gen/mod.rs | 60 +++++++++++++++++++++++++++++++++--------- src/proc_gen/tileset_loader.rs | 12 ++++++--- 3 files changed, 92 insertions(+), 26 deletions(-) (limited to 'src/proc_gen') diff --git a/src/proc_gen/herringbone.rs b/src/proc_gen/herringbone.rs index 5e930ec..271b7a1 100644 --- a/src/proc_gen/herringbone.rs +++ b/src/proc_gen/herringbone.rs @@ -3,12 +3,10 @@ use glam::IVec2; use crate::{ config::TILESET_SCALING, - content::materials::MaterialId, proc_gen::tileset_loader::{Tile, TileOrientation, Tileset, TilesetPixelType}, - sim::cell::Cell, }; -fn split_position(world: IVec2, tileset: &Tileset) -> (IVec2, IVec2, TileOrientation) { +pub fn split_position(world: IVec2, tileset: &Tileset) -> (IVec2, IVec2, TileOrientation) { let s = tileset.dimensions.short as i32; let tx = world.x.div_euclid(s); let ty = world.y.div_euclid(s); @@ -74,10 +72,40 @@ fn get_pixel_at_position(world: IVec2, tileset: &Tileset) -> TilesetPixelType { tile.pixels[(local.x + local.y * width) as usize] } -pub fn get_cell_at_position(world: IVec2, tileset: &Tileset) -> Cell { - let pixel = get_pixel_at_position(world, tileset); - match pixel { - TilesetPixelType::Void => Cell::void(), - TilesetPixelType::Terrain => Cell::from_material(MaterialId::Dirt), - } +pub fn tiles_overlapping( + a: IVec2, + b: IVec2, + tileset: &Tileset, +) -> impl Iterator { + let s = IVec2::new( + tileset.dimensions.short as i32, + tileset.dimensions.short as i32, + ); + + let ta = a.div_euclid(s) - 1; + let tb = (b - 1).div_euclid(s); + + (ta.y..=tb.y) + .flat_map(move |ty| (ta.x..=tb.x).map(move |tx| (tx, ty))) + .filter_map(move |(tx, ty)| match (tx - ty).rem_euclid(4) { + 0 => Some(( + IVec2::new(tx, ty), + pick_variant(IVec2::new(tx, ty), TileOrientation::Horizontal, tileset), + TileOrientation::Horizontal, + )), + 3 => Some(( + IVec2::new(tx, ty), + pick_variant(IVec2::new(tx, ty), TileOrientation::Vertical, tileset), + TileOrientation::Vertical, + )), + _ => None, + }) } + +// pub fn get_cell_at_position(world: IVec2, tileset: &Tileset) -> Cell { +// let pixel = get_pixel_at_position(world, tileset); +// match pixel { +// TilesetPixelType::Void => Cell::void(), +// TilesetPixelType::Terrain => Cell::from_material(MaterialId::Dirt), +// } +// } diff --git a/src/proc_gen/mod.rs b/src/proc_gen/mod.rs index 7913d22..049ad1a 100644 --- a/src/proc_gen/mod.rs +++ b/src/proc_gen/mod.rs @@ -4,34 +4,68 @@ pub mod tileset_loader; use glam::IVec2; use crate::{ - config::CHUNK_SIZE, + config::{CHUNK_SIZE, TILESET_SCALING}, proc_gen::{ - herringbone::get_cell_at_position, - tileset_loader::{Tileset, load_tileset}, + herringbone::tiles_overlapping, + tileset_loader::{Tile, TileOrientation, Tileset, load_tileset}, }, - sim::cell_manager::chunk::Chunk, + sim::{cell::Cell, cell_manager::chunk::Chunk, entity::EntityDef}, }; +pub trait Biome { + fn derive_world_from_tile(&self, _tile: &Tile) -> Vec { + Vec::new() + } + fn derive_entities_from_tile(&self, _tile: &Tile) -> Vec { + Vec::new() + } +} + pub struct TilesetWorldGenerator { tileset: Tileset, + biome: Box, } impl TilesetWorldGenerator { pub fn generate_chunk(&self, chunk_position: IVec2) -> Chunk { let mut chunk = Chunk::void(); - for x in 0..CHUNK_SIZE { - for y in 0..CHUNK_SIZE { - let cell = get_cell_at_position( - chunk_position * CHUNK_SIZE + IVec2::new(x, y), - &self.tileset, - ); - chunk.set_cell_at_local_position(x as u8, y as u8, cell); + + 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) -> Self { + + pub fn new(tileset_path: &str, biome: Box) -> Self { let tileset = load_tileset(tileset_path); - TilesetWorldGenerator { tileset } + TilesetWorldGenerator { tileset, biome } } } diff --git a/src/proc_gen/tileset_loader.rs b/src/proc_gen/tileset_loader.rs index 925b3ac..acb4d65 100644 --- a/src/proc_gen/tileset_loader.rs +++ b/src/proc_gen/tileset_loader.rs @@ -26,8 +26,8 @@ fn load_img(path: &Path) -> Result<(Vec, u32, u32), Box> { Ok((buf, info.width, info.height)) } -#[derive(Deserialize, Debug)] -pub struct TilesetDimensions { +#[derive(Deserialize, Clone, Copy, Debug)] +pub struct TileDimensions { pub short: u32, pub long: u32, } @@ -40,7 +40,7 @@ pub enum TilesetPixelType { #[derive(Deserialize, Debug)] struct TilesetManifest { - dimensions: TilesetDimensions, + dimensions: TileDimensions, palette: HashMap, } @@ -50,12 +50,14 @@ fn load_manifest(path: &Path) -> Result> { #[derive(Debug)] pub struct Tile { + pub orientation: TileOrientation, + pub dimensions: TileDimensions, pub pixels: Vec, } #[derive(Debug)] pub struct Tileset { - pub dimensions: TilesetDimensions, + pub dimensions: TileDimensions, pub vertical_tiles: Vec, pub horizontal_tiles: Vec, } @@ -115,6 +117,8 @@ fn parse_row( ); tiles.push(Tile { + orientation, + dimensions: manifest.dimensions, pixels: tile_pixels, }); -- cgit v1.3.1