use glam::{IVec2, Vec2}; use crate::{ config::TILESET_SCALING, content::materials::MaterialId, proc_gen::{ Biome, TileCells, tileset_loader::{Tile, TilesetPixelType}, }, sim::{cell::Cell, lib::marching_squares::compute_types}, }; const FULL: [bool; (TILESET_SCALING * TILESET_SCALING) as usize] = [true; (TILESET_SCALING * TILESET_SCALING) as usize]; const EMPTY: [bool; (TILESET_SCALING * TILESET_SCALING) as usize] = [false; (TILESET_SCALING * TILESET_SCALING) as usize]; pub struct MinesBiome { pixel_expansion_by_type: [[bool; (TILESET_SCALING * TILESET_SCALING) as usize]; 16], } fn circular_pixel_expansion( c: Vec2, r: f32, ) -> [bool; (TILESET_SCALING * TILESET_SCALING) as usize] { let rs = r.powi(2); let mut ret = [false; (TILESET_SCALING * TILESET_SCALING) as usize]; for y in 0..TILESET_SCALING { for x in 0..TILESET_SCALING { // definitely can be optimized a lot let dist = Vec2::new(x as f32, y as f32).distance_squared(c); if dist <= rs { ret[(x + y * TILESET_SCALING) as usize] = true; } } } ret } impl MinesBiome { pub fn new() -> Self { MinesBiome { pixel_expansion_by_type: [ // empty EMPTY, // BL circular_pixel_expansion( Vec2::new(0.0, TILESET_SCALING as f32 - 1.0), TILESET_SCALING as f32, ), // BR circular_pixel_expansion( Vec2::new(TILESET_SCALING as f32 - 1.0, TILESET_SCALING as f32 - 1.0), TILESET_SCALING as f32, ), // BL BR FULL, // TR circular_pixel_expansion( Vec2::new(TILESET_SCALING as f32 - 1.0, 0.0), TILESET_SCALING as f32, ), // TR BL FULL, // TR BR FULL, // TR BR BL FULL, // TL circular_pixel_expansion(Vec2::new(0.0, 0.0), TILESET_SCALING as f32), // TL BL FULL, // TL BR FULL, // TL BR BL FULL, // TL TR FULL, // TL TR BL FULL, // TL TR BR FULL, // surrounded FULL, ], } } } impl Biome for MinesBiome { fn derive_world_from_tile(&self, tile: &Tile) -> TileCells { let pixels = tile.size(); let marched_pixels = compute_types(tile); let size = pixels * TILESET_SCALING; let mut cells = vec![Cell::void(); (size.x * size.y) as usize]; for py in 0..pixels.y { for px in 0..pixels.x { let pixel = tile.pixel_at(IVec2::new(px, py)); let variant = marched_pixels[(px + py * (pixels.x + 1)) as usize]; // let pix = marched_pixels[(px + py * pixels.x) as usize]; // let expansion_cells = [Cell::from_material(MaterialId::from_index( // pix % MaterialId::ALL.len() as u8, // )); // (TILESET_SCALING * TILESET_SCALING) as usize]; // let origin = IVec2::new(px, py) * TILESET_SCALING; // for i in 0..TILESET_SCALING { // let y = i + origin.y; // let row = (y * size.x + origin.x) as usize; // cells[row..row + TILESET_SCALING as usize].copy_from_slice( // &expansion_cells[i as usize..i as usize + TILESET_SCALING as usize], // ); // } let expansion = self.pixel_expansion_by_type[variant as usize]; // TODO optimize let expansion_cells = expansion.map(|c| { if c { Cell::from_material(MaterialId::Dirt) } else { Cell::void() } }); let origin = IVec2::new(px, py) * TILESET_SCALING; for i in 0..TILESET_SCALING { let dst_y = i + origin.y; let dst_row = (dst_y * size.x + origin.x) as usize; let src_row = (i * TILESET_SCALING) as usize; cells[dst_row..dst_row + TILESET_SCALING as usize].copy_from_slice( &expansion_cells[src_row..src_row + TILESET_SCALING as usize], ); } } } TileCells { size, cells } } }