136 lines
3.3 KiB
Rust
136 lines
3.3 KiB
Rust
use std::{
|
|
ops::Index,
|
|
sync::mpsc::{Receiver, Sender, channel},
|
|
};
|
|
|
|
use image::{DynamicImage, GenericImageView};
|
|
|
|
use crate::{layout::Vec2, render::TexturePrimitive, util::RefCounter};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct TextureHandle {
|
|
inner: TexturePrimitive,
|
|
size: Vec2,
|
|
counter: RefCounter,
|
|
send: Sender<u32>,
|
|
}
|
|
|
|
/// 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<u32>,
|
|
images: Vec<Option<DynamicImage>>,
|
|
updates: Vec<Update>,
|
|
send: Sender<u32>,
|
|
recv: Receiver<u32>,
|
|
}
|
|
|
|
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<DynamicImage>) -> 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<Item = TextureUpdate<'_>> {
|
|
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()
|
|
}
|
|
}
|