use fxhash::hash32; 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) { 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 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), } }