use fxhash::hash32; use glam::IVec2; use crate::{ config::TILESET_SCALING, proc_gen::tileset_loader::{Tile, TileOrientation, Tileset, TilesetPixelType}, }; 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); let fx = world.x.rem_euclid(s); let fy = world.y.rem_euclid(s); match (tx - ty).rem_euclid(4) { // left half of horizontal tile 0 => ( IVec2::new(tx, ty), IVec2::new(fx, fy), TileOrientation::Horizontal, ), // right half of horizontal tile 1 => ( IVec2::new(tx - 1, ty), IVec2::new(fx + s, fy), TileOrientation::Horizontal, ), // top half of vertical tile 3 => ( IVec2::new(tx, ty), IVec2::new(fx, fy), TileOrientation::Vertical, ), // bottom half of vertical tile 2 => ( IVec2::new(tx, ty - 1), IVec2::new(fx, fy + s), TileOrientation::Vertical, ), _ => unreachable!(), } } // better "%" for hashes since it prefers the high bits #[inline] fn reduce(h: u32, n: usize) -> usize { (((h as u128) * (n as u128)) >> 32) as usize } fn pick_variant(tile_pos: IVec2, orientation: TileOrientation, tileset: &Tileset) -> &Tile { let h = hash32(&tile_pos); match orientation { TileOrientation::Horizontal => { &tileset.horizontal_tiles[reduce(h, tileset.horizontal_tiles.len())] } TileOrientation::Vertical => { &tileset.vertical_tiles[reduce(h, tileset.vertical_tiles.len())] } } } // TODO: optimize fn get_pixel_at_position(world: IVec2, tileset: &Tileset) -> TilesetPixelType { let scaled_world = world.div_euclid(IVec2::new(TILESET_SCALING, TILESET_SCALING)); let (tile_pos, local, orientation) = split_position(scaled_world, tileset); let tile = pick_variant(tile_pos, orientation, tileset); let width = match orientation { TileOrientation::Horizontal => tileset.dimensions.long as i32, TileOrientation::Vertical => tileset.dimensions.short as i32, }; tile.pixels[(local.x + local.y * width) as usize] } 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), // } // }