use std::{ ops::Index, sync::mpsc::{Receiver, Sender, channel}, }; use image::{DynamicImage, GenericImageView}; use crate::{layout::Vec2, render::TexturePrimitive, util::RefCounter}; #[derive(Clone)] pub struct TextureHandle { inner: TexturePrimitive, size: Vec2, counter: RefCounter, send: Sender, } /// a texture manager for a ui /// note that this is heavily oriented towards wgpu's renderer so the primitives don't need mapped pub struct Textures { free: Vec, images: Vec>, updates: Vec, send: Sender, recv: Receiver, } pub enum TextureUpdate<'a> { Push(&'a DynamicImage), Set(u32, &'a DynamicImage), Free(u32), PushFree, SetFree, } enum Update { Push(u32), Set(u32), Free(u32), } impl Textures { pub fn new() -> Self { let (send, recv) = channel(); Self { free: Vec::new(), images: Vec::new(), updates: Vec::new(), send, recv, } } pub fn add(&mut self, image: impl Into) -> TextureHandle { let image = image.into(); let size = image.dimensions().into(); let view_idx = self.push(image); // 0 == default in renderer; TODO: actually create samplers here let sampler_idx = 0; TextureHandle { inner: TexturePrimitive { view_idx, sampler_idx, }, size, counter: RefCounter::new(), send: self.send.clone(), } } fn push(&mut self, image: DynamicImage) -> u32 { if let Some(i) = self.free.pop() { self.images[i as usize] = Some(image); self.updates.push(Update::Set(i)); i } else { let i = self.images.len() as u32; self.images.push(Some(image)); self.updates.push(Update::Push(i)); i } } pub fn free(&mut self) { for idx in self.recv.try_iter() { self.images[idx as usize] = None; self.updates.push(Update::Free(idx)); self.free.push(idx); } } pub fn updates(&mut self) -> impl Iterator> { self.updates.drain(..).map(|u| match u { Update::Push(i) => self.images[i as usize] .as_ref() .map(TextureUpdate::Push) .unwrap_or(TextureUpdate::PushFree), Update::Set(i) => self.images[i as usize] .as_ref() .map(|img| TextureUpdate::Set(i, img)) .unwrap_or(TextureUpdate::SetFree), Update::Free(i) => TextureUpdate::Free(i), }) } } impl TextureHandle { pub fn primitive(&self) -> TexturePrimitive { self.inner } pub fn size(&self) -> Vec2 { self.size } } impl Drop for TextureHandle { fn drop(&mut self) { if self.counter.drop() { let _ = self.send.send(self.inner.view_idx); } } } impl Index<&TextureHandle> for Textures { type Output = DynamicImage; fn index(&self, index: &TextureHandle) -> &Self::Output { self.images[index.inner.view_idx as usize].as_ref().unwrap() } } impl Default for Textures { fn default() -> Self { Self::new() } }