use super::*;
impl AssetCache {
pub fn get_state<U>(&self, url: U) -> Option<AssetState>
where
U: AsRef<str>,
{
self.get_entries()
.get(url.as_ref())
.map(|entry: &AssetEntry| entry.get_state())
}
pub fn get_image<U>(&self, url: U) -> Option<HtmlImageElement>
where
U: AsRef<str>,
{
let entry: &AssetEntry = self.get_entries().get(url.as_ref())?;
if entry.get_state() != AssetState::Loaded {
return None;
}
entry.get_image()
}
pub fn is_all_loaded(&self) -> bool {
self.get_entries()
.values()
.all(|entry: &AssetEntry| entry.get_state() != AssetState::Loading)
}
pub fn loaded_count(&self) -> usize {
self.get_entries()
.values()
.filter(|entry: &&AssetEntry| entry.get_state() == AssetState::Loaded)
.count()
}
pub fn clear(&mut self) {
self.get_mut_entries().clear();
}
}
impl Default for AssetCache {
fn default() -> AssetCache {
AssetCache::new()
}
}
impl AssetLoader {
pub fn load_image(&mut self, url: String) {
let Ok(image) = HtmlImageElement::new() else {
return;
};
let entry: AssetEntry = AssetEntry::new(
AssetType::Image,
AssetState::Loading,
Some(image.clone()),
url.clone(),
);
self.get_cache()
.get_mut()
.get_mut_entries()
.insert(url.clone(), entry);
*self.get_pending().get_mut() += 1;
let onload_slot: usize = self.get_closures().get().slots.len();
let onerror_slot: usize = onload_slot + 1;
let pending_shared: AssetPending = self.get_pending().clone();
let pending: AssetPending = pending_shared.clone();
let store_shared: Weak<EngineCell<AssetClosureStore>> = Rc::downgrade(self.get_closures());
let store_weak: Weak<EngineCell<AssetClosureStore>> = store_shared.clone();
let cache_clone: Rc<EngineCell<AssetCache>> = self.get_cache().clone();
let url_for_onload: String = url.clone();
let onload_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
{
let cache_ref: &mut AssetCache = cache_clone.get_mut();
if let Some(mut entry) = cache_ref.get_entries().get(&url_for_onload).cloned() {
entry.set_state(AssetState::Loaded);
cache_ref
.get_mut_entries()
.insert(url_for_onload.clone(), entry);
}
}
*pending.get_mut() = pending.get().saturating_sub(1);
mark_asset_closure_settled(&store_weak, onload_slot);
}));
let cache_clone_err: Rc<EngineCell<AssetCache>> = self.get_cache().clone();
let pending_err: AssetPending = pending_shared.clone();
let store_weak_err: Weak<EngineCell<AssetClosureStore>> = store_shared.clone();
let url_for_onerror: String = url.clone();
let onerror_closure: Closure<dyn FnMut()> = Closure::wrap(Box::new(move || {
{
let cache_ref: &mut AssetCache = cache_clone_err.get_mut();
if let Some(mut entry) = cache_ref.get_entries().get(&url_for_onerror).cloned() {
entry.set_state(AssetState::Error);
cache_ref
.get_mut_entries()
.insert(url_for_onerror.clone(), entry);
}
}
*pending_err.get_mut() = pending_err.get().saturating_sub(1);
mark_asset_closure_settled(&store_weak_err, onerror_slot);
}));
image.set_onload(Some(onload_closure.as_ref().unchecked_ref()));
image.set_onerror(Some(onerror_closure.as_ref().unchecked_ref()));
image.set_src(&url);
let store: &mut AssetClosureStore = self.get_closures().get_mut();
store.slots.push(Some(onload_closure));
store.settled.push(false);
let store: &mut AssetClosureStore = self.get_closures().get_mut();
store.slots.push(Some(onerror_closure));
store.settled.push(false);
}
pub fn pending_count(&self) -> u32 {
*self.get_pending().get()
}
pub fn update(&mut self, delta_time: f64) {
let _ = delta_time;
self.collect();
}
pub fn collect(&mut self) {
let store: &mut AssetClosureStore = self.get_closures().get_mut();
let mut index: usize = 0;
while index < store.slots.len() {
let settled: bool = store.settled.get(index).copied().unwrap_or(false);
if settled {
store.slots[index] = None;
store.settled[index] = false;
}
index += 1;
}
}
pub fn is_all_loaded(&self) -> bool {
self.get_cache().get().is_all_loaded()
}
pub fn get_image<U>(&self, url: U) -> Option<HtmlImageElement>
where
U: AsRef<str>,
{
self.get_cache().get().get_image(url.as_ref())
}
pub fn progress(&self) -> f64 {
let cache_ref: &AssetCache = self.get_cache().get();
let total: usize = cache_ref.get_entries().len();
if total == 0 {
return 1.0;
}
cache_ref.loaded_count() as f64 / total as f64
}
}
impl Updatable for AssetLoader {
fn update(&mut self, delta_time: f64) {
AssetLoader::update(self, delta_time);
}
}
impl Default for AssetLoader {
fn default() -> AssetLoader {
let mut loader: AssetLoader = AssetLoader::new();
loader.set_cache(Rc::new(EngineCell::new(AssetCache::default())));
loader.set_pending(Rc::new(EngineCell::new(0)));
loader.set_closures(Rc::new(EngineCell::new(AssetClosureStore::default())));
loader
}
}
impl AssetLoader {
pub fn create_image_element<U>(url: U) -> Option<HtmlImageElement>
where
U: AsRef<str>,
{
let image: HtmlImageElement = HtmlImageElement::new().ok()?;
image.set_src(url.as_ref());
Some(image)
}
}