use {
crate::assets::{self, Model, ModelDesc, TypeModel},
std::{
collections::HashMap,
marker::PhantomData,
sync::{
Arc,
atomic::{AtomicUsize, Ordering},
mpsc::{self, Receiver, Sender},
},
},
wgpu::{BindGroupLayout, Device, Queue},
};
pub struct Ingot<T> {
pub id: usize,
_marker: PhantomData<T>,
}
pub(crate) enum Bead<T> {
Burning,
Molten(T),
#[allow(dead_code)]
Ash,
}
pub struct ModelStore {
static_models: HashMap<usize, Bead<Model>>,
light_models: HashMap<usize, Bead<Model>>,
next_id: AtomicUsize,
sender: Sender<(usize, Model)>,
receiver: Receiver<(usize, Model)>,
}
impl ModelStore {
pub(crate) fn new() -> Self {
let (sender, receiver) = mpsc::channel::<(usize, Model)>();
Self {
static_models: HashMap::new(),
light_models: HashMap::new(),
next_id: AtomicUsize::new(0),
sender,
receiver,
}
}
pub(crate) fn spawn(
&mut self,
device: &Arc<Device>,
queue: &Arc<Queue>,
layout: &Arc<BindGroupLayout>,
model_desc: ModelDesc,
) -> Ingot<Model> {
let id: usize = self.next_id.fetch_add(1, Ordering::SeqCst);
match model_desc.kind {
TypeModel::StaticObj => self.static_models.insert(id, Bead::Burning),
TypeModel::PointOfLight => self.light_models.insert(id, Bead::Burning),
};
let device: Arc<Device> = Arc::clone(device);
let queue: Arc<Queue> = Arc::clone(queue);
let layout: Arc<BindGroupLayout> = Arc::clone(layout);
let sender: Sender<(usize, Model)> = self.sender.clone();
let path: String = model_desc.path.to_string();
let instances: Vec<assets::Instance> = model_desc.instances;
let kind: TypeModel = model_desc.kind;
#[cfg(not(target_arch = "wasm32"))]
std::thread::spawn(move || {
let result: Result<Model, anyhow::Error> = pollster::block_on(assets::load_model(
&path, &device, &queue, &layout, instances, kind,
));
if let Ok(model) = result {
let _ = sender.send((id, model));
}
});
#[cfg(target_arch = "wasm32")]
wasm_bindgen_futures::spawn_local(async move {
let result: Result<Model, anyhow::Error> =
assets::load_model(&path, &device, &queue, &layout, instances, kind).await;
if let Ok(model) = result {
let _ = sender.send((id, model));
}
});
Ingot {
id,
_marker: PhantomData,
}
}
pub(crate) fn collect_loaded(&mut self) {
while let Ok((id, model)) = self.receiver.try_recv() {
match model.type_model {
TypeModel::StaticObj => self.static_models.insert(id, Bead::Molten(model)),
TypeModel::PointOfLight => self.light_models.insert(id, Bead::Molten(model)),
};
}
}
pub(crate) fn static_loaded(&self) -> impl Iterator<Item = &Model> {
self.static_models.values().filter_map(|bead| match bead {
Bead::Molten(model) => Some(model),
_ => None,
})
}
pub(crate) fn light_loaded(&self) -> impl Iterator<Item = &Model> {
self.light_models.values().filter_map(|bead| match bead {
Bead::Molten(model) => Some(model),
_ => None,
})
}
pub(crate) fn light_model_mut(&mut self, id: &usize) -> Option<&mut Model> {
match self.light_models.get_mut(id) {
Some(Bead::Molten(model)) => Some(model),
_ => None,
}
}
}