ferrum_wgpu/assets/
store.rs1use {
2 crate::assets::{self, Model, ModelDesc, TypeModel},
3 std::{
4 collections::HashMap,
5 marker::PhantomData,
6 sync::{
7 Arc,
8 atomic::{AtomicUsize, Ordering},
9 mpsc::{self, Receiver, Sender},
10 },
11 },
12 wgpu::{BindGroupLayout, Device, Queue},
13};
14
15pub struct Ingot<T> {
18 pub id: usize,
19 _marker: PhantomData<T>,
20}
21
22pub(crate) enum Bead<T> {
25 Burning,
26 Molten(T),
27 #[allow(dead_code)]
28 Ash,
29}
30
31pub struct ModelStore {
34 static_models: HashMap<usize, Bead<Model>>,
35 light_models: HashMap<usize, Bead<Model>>,
36 next_id: AtomicUsize,
37 sender: Sender<(usize, Model)>,
38 receiver: Receiver<(usize, Model)>,
39}
40
41impl ModelStore {
42 pub(crate) fn new() -> Self {
43 let (sender, receiver) = mpsc::channel::<(usize, Model)>();
44 Self {
45 static_models: HashMap::new(),
46 light_models: HashMap::new(),
47 next_id: AtomicUsize::new(0),
48 sender,
49 receiver,
50 }
51 }
52
53 pub(crate) fn spawn(
59 &mut self,
60 device: &Arc<Device>,
61 queue: &Arc<Queue>,
62 layout: &Arc<BindGroupLayout>,
63 model_desc: ModelDesc,
64 ) -> Ingot<Model> {
65 let id: usize = self.next_id.fetch_add(1, Ordering::SeqCst);
66
67 match model_desc.kind {
68 TypeModel::StaticObj => self.static_models.insert(id, Bead::Burning),
69 TypeModel::PointOfLight => self.light_models.insert(id, Bead::Burning),
70 };
71
72 let device: Arc<Device> = Arc::clone(device);
73 let queue: Arc<Queue> = Arc::clone(queue);
74 let layout: Arc<BindGroupLayout> = Arc::clone(layout);
75 let sender: Sender<(usize, Model)> = self.sender.clone();
76 let path: String = model_desc.path.to_string();
77 let instances: Vec<assets::Instance> = model_desc.instances;
78 let kind: TypeModel = model_desc.kind;
79
80 #[cfg(not(target_arch = "wasm32"))]
81 std::thread::spawn(move || {
82 let result: Result<Model, anyhow::Error> = pollster::block_on(assets::load_model(
83 &path, &device, &queue, &layout, instances, kind,
84 ));
85 if let Ok(model) = result {
86 let _ = sender.send((id, model));
87 }
88 });
89
90 #[cfg(target_arch = "wasm32")]
91 wasm_bindgen_futures::spawn_local(async move {
92 let result: Result<Model, anyhow::Error> =
93 assets::load_model(&path, &device, &queue, &layout, instances, kind).await;
94 if let Ok(model) = result {
95 let _ = sender.send((id, model));
96 }
97 });
98
99 Ingot {
100 id,
101 _marker: PhantomData,
102 }
103 }
104
105 pub(crate) fn collect_loaded(&mut self) {
107 while let Ok((id, model)) = self.receiver.try_recv() {
108 match model.type_model {
109 TypeModel::StaticObj => self.static_models.insert(id, Bead::Molten(model)),
110 TypeModel::PointOfLight => self.light_models.insert(id, Bead::Molten(model)),
111 };
112 }
113 }
114
115 pub(crate) fn static_loaded(&self) -> impl Iterator<Item = &Model> {
116 self.static_models.values().filter_map(|bead| match bead {
117 Bead::Molten(model) => Some(model),
118 _ => None,
119 })
120 }
121
122 pub(crate) fn light_loaded(&self) -> impl Iterator<Item = &Model> {
123 self.light_models.values().filter_map(|bead| match bead {
124 Bead::Molten(model) => Some(model),
125 _ => None,
126 })
127 }
128
129 pub(crate) fn light_model_mut(&mut self, id: &usize) -> Option<&mut Model> {
130 match self.light_models.get_mut(id) {
131 Some(Bead::Molten(model)) => Some(model),
132 _ => None,
133 }
134 }
135}