Skip to main content

grafix_toolbox/kit/opengl/utility/image/
vtex.rs

1use super::*;
2use crate::lazy::*;
3
4#[derive(Debug, Clone, PartialEq)]
5pub struct VTex2d<S, F> {
6	pub region: Vec4,
7	pub atlas: Rc<Tex2d<S, F>>,
8}
9impl<S, F> VTex2d<S, F> {
10	pub fn eq_atlas(&self, r: &Self) -> bool {
11		Rc::ptr_eq(&self.atlas, &r.atlas)
12	}
13}
14
15pub type VTex2dEntry<'a, S> = Prefetched<'a, u32, VTex2d<S, u8>, TexAtlas<S>>;
16
17#[derive(Default)]
18pub struct TexAtlas<S>(Cell<State<S>>);
19impl<S: TexSize> TexAtlas<S> {
20	pub fn new() -> Self {
21		Def()
22	}
23	pub fn load(&self, name: &str) -> VTex2dEntry<S> {
24		let reqs = unsafe { &mut *self.0.as_ptr() };
25		let Fresh(reqs) = reqs else { ERROR!("Trying to load into finalized atals") };
26
27		let k = u32(reqs.len());
28		let name = format!("res/{name}").pipe(Astr::from);
29		reqs.push((name.clone(), FS::Lazy::File(name).pipe(Feed::new)));
30		Prefetched::new(k, self)
31	}
32	fn finalise(state: &mut State<S>) -> &mut VTexMap<S> {
33		let Fresh(reqs) = mem::take(state) else { unreachable!() };
34		let mut tail = reqs
35			.into_iter()
36			.enumerate()
37			.map(|(n, (name, r))| (u32(n), r.take().pipe_as(uImage::<S>::load).explain_err(|| format!("Cannot atlas image {name:?}")).warn()))
38			.collect_vec();
39
40		let (max_side, mut textures) = (GL::MAX_TEXTURE_SIZE(), VTexMap::new());
41
42		while !tail.is_empty() {
43			let last_l = tail.len();
44			let (a, t) = atlas::pack_into_atlas(tail, max_side, max_side);
45			if last_l == t.len() {
46				ERROR!("GPU cannot fit texture {t:?}");
47			}
48			textures.extend(a.into_iter());
49			tail = t;
50		}
51
52		*state = Baked(textures);
53		let Baked(t) = state else { unreachable!() };
54		t
55	}
56}
57
58impl<S: TexSize> Fetcher<u32, VTex2d<S, u8>> for TexAtlas<S> {
59	fn get(&self, k: u32) -> &VTex2d<S, u8> {
60		let s = unsafe { &mut *self.0.as_ptr() };
61		let textures = match s {
62			Fresh(_) => Self::finalise(s),
63			Baked(t) => t,
64		};
65		textures.get(&k).valid()
66	}
67	fn take(&self, k: u32) -> VTex2d<S, u8> {
68		let s = unsafe { &mut *self.0.as_ptr() };
69		let textures = match s {
70			Fresh(_) => Self::finalise(s),
71			Baked(t) => t,
72		};
73		textures.remove(&k).valid()
74	}
75}
76
77enum State<S> {
78	Fresh(Vec<(Astr, Feed<Vec<u8>>)>),
79	Baked(VTexMap<S>),
80}
81impl<S> Default for State<S> {
82	fn default() -> Self {
83		Fresh(Def())
84	}
85}
86use State::*;
87type VTexMap<S> = HashMap<u32, VTex2d<S, u8>>;