use crate::{
asset::{
item::AssetItemMessage, preview::AssetPreviewGeneratorsCollection,
preview::AssetPreviewTexture,
},
fyrox::{
asset::untyped::UntypedResource,
core::{futures::executor::block_on, parking_lot::Mutex, pool::Handle, SafeLock, Uuid},
engine::Engine,
fxhash::FxHashMap,
gui::UiNode,
},
load_image,
};
use fyrox::core::pool::ObjectOrVariant;
use std::{
collections::VecDeque,
sync::{mpsc::Receiver, Arc},
};
pub struct IconRequest {
pub widget_handle: Handle<UiNode>,
pub resource: UntypedResource,
pub force_update: bool,
}
impl IconRequest {
pub fn new(
widget: Handle<impl ObjectOrVariant<UiNode>>,
resource: UntypedResource,
force_update: bool,
) -> Self {
Self {
widget_handle: widget.to_base(),
resource,
force_update,
}
}
}
pub struct AssetPreviewCache {
container: FxHashMap<Uuid, AssetPreviewTexture>,
throughput: usize,
queue: Arc<Mutex<VecDeque<IconRequest>>>,
}
impl AssetPreviewCache {
pub fn new(receiver: Receiver<IconRequest>, throughput: usize) -> Self {
let queue = Arc::new(Mutex::new(VecDeque::new()));
let queue2 = queue.clone();
std::thread::spawn(move || {
for request in receiver.iter() {
let resource = request.resource.clone();
if block_on(resource).is_ok() {
queue.safe_lock().push_back(request);
}
}
});
Self {
container: Default::default(),
throughput,
queue: queue2,
}
}
fn preview_for(
&mut self,
resource: &UntypedResource,
generators: &mut AssetPreviewGeneratorsCollection,
force_update: bool,
generated_counter: &mut usize,
engine: &mut Engine,
) -> Option<AssetPreviewTexture> {
let resource_uuid = resource.resource_uuid();
if let (false, Some(cached_preview)) = (force_update, self.container.get(&resource_uuid)) {
return Some(cached_preview.clone());
} else if let Some(generator) = resource
.type_uuid()
.and_then(|type_uuid| generators.map.get_mut(&type_uuid))
{
if let Some(preview) = generator.generate_preview(resource, engine) {
*generated_counter += 1;
self.container.insert(resource_uuid, preview.clone());
return Some(preview);
} else if let Some(icon) = generator.simple_icon(resource, &engine.resource_manager) {
let preview = AssetPreviewTexture::from_texture_with_gray_tint(icon);
self.container.insert(resource_uuid, preview.clone());
return Some(preview);
}
}
load_image!("../../../resources/asset.png").map(|placeholder_image| {
AssetPreviewTexture::from_texture_with_gray_tint(placeholder_image)
})
}
pub fn update(
&mut self,
generators: &mut AssetPreviewGeneratorsCollection,
engine: &mut Engine,
) {
let mut generated = 0;
let queue = self.queue.clone();
let mut queue = queue.safe_lock();
while let Some(request) = queue.pop_back() {
let IconRequest {
widget_handle,
resource,
force_update,
} = request;
if let Some(preview) =
self.preview_for(&resource, generators, force_update, &mut generated, engine)
{
engine.user_interfaces.first().send(
widget_handle,
AssetItemMessage::Icon {
texture: Some(preview.texture),
flip_y: preview.flip_y,
color: preview.color,
},
);
}
if generated >= self.throughput {
break;
}
}
}
}