grafix_toolbox/kit/opengl/utility/image/
vtex.rs1use 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>>;