use super::*; use crate::{lazy::*, prefetch::*}; #[derive(Debug)] pub struct VTex2d { pub region: Vec4, pub atlas: Rc>, } impl VTex2d { pub fn eq_atlas(&self, r: &Self) -> bool { Rc::ptr_eq(&self.atlas, &r.atlas) } } impl PartialEq for VTex2d { fn eq(&self, r: &Self) -> bool { self.eq_atlas(r) && self.region == r.region } } impl Eq for VTex2d {} impl Clone for VTex2d { fn clone(&self) -> Self { let &Self { region, ref atlas } = self; let (region, atlas) = (region, atlas.clone()); Self { region, atlas } } } pub type VTex2dEntry<'a, S> = Prefetched<'a, u32, VTex2d, TexAtlas>; #[derive(Default)] pub struct TexAtlas(Cell>); impl TexAtlas { pub fn new() -> Self { Def() } pub fn load(&self, name: &str) -> VTex2dEntry { match unsafe { &mut *self.0.as_ptr() } { Baked(_) => ERROR!("Trying to load into finalized atals"), Fresh(reqs) => { let k = u32(reqs.len()); let name: Astr = format!("res/{name}").into(); reqs.push((name.clone(), Lazy::new(FS::Lazy::File(name)))); Prefetched::new(k, self) } } } fn finalise(state: &mut State) -> &mut VTexMap { let t = match mem::take(state) { Baked(_) => unreachable!(), Fresh(mut reqs) => { let reqs = reqs .iter_mut() .enumerate() .map(|(n, (name, r))| (u32(n), uImage::::load(&r.get()[..]).explain_err(|| format!("Cannot atlas image {name:?}")).warn())) .collect_vec(); let max_side = GL::MAX_TEXTURE_SIZE(); let (atlas, mut tail) = atlas::pack_into_atlas(reqs, max_side, max_side); let mut textures: VTexMap = atlas.into_iter().collect(); while !tail.is_empty() { let last_l = tail.len(); let (a, t) = atlas::pack_into_atlas(tail, max_side, max_side); if last_l == t.len() { ERROR!("Graphics card can't fit textures: {t:?}"); } textures.extend(a.into_iter()); tail = t; } textures } }; *state = Baked(t); match state { Fresh(_) => unreachable!(), Baked(t) => t, } } } impl Fetcher> for TexAtlas { fn get(&self, k: u32) -> &VTex2d { let s = unsafe { &mut *self.0.as_ptr() }; let textures = match s { Fresh(_) => Self::finalise(s), Baked(t) => t, }; textures.get(&k).valid() } fn take(&self, k: u32) -> VTex2d { let s = unsafe { &mut *self.0.as_ptr() }; let textures = match s { Fresh(_) => Self::finalise(s), Baked(t) => t, }; textures.remove(&k).take().valid() } } enum State { Fresh(Vec<(Astr, Lazy>)>), Baked(VTexMap), } impl Default for State { fn default() -> Self { Fresh(Def()) } } use State::*; type VTexMap = HashMap>;