use crate::hydrate_impl::{AssetResource, RafxResourceAssetLoader};
use crate::{AssetLookup, AssetManager, DynAssetLookup, LoadQueues};
use crossbeam_channel::Sender;
use hydrate_base::LoadHandle;
use hydrate_loader::storage::ArtifactLoadOp;
use rafx_api::RafxResult;
use std::any::TypeId;
use std::marker::PhantomData;
use type_uuid::TypeUuid;
pub trait AssetTypeHandler: Sync + Send {
fn process_load_requests(
&mut self,
asset_manager: &mut AssetManager,
) -> RafxResult<()>;
fn on_frame_complete(&mut self) -> RafxResult<()> {
Ok(())
}
fn asset_lookup(&self) -> &dyn DynAssetLookup;
fn asset_type_id(&self) -> TypeId;
}
pub trait DefaultAssetTypeLoadHandler<AssetDataT, AssetT> {
fn load(
asset_manager: &mut AssetManager,
asset_data: AssetDataT,
load_handle: LoadHandle,
) -> RafxResult<AssetT>;
fn free(
_asset_manager: &mut AssetManager,
_load_handle: LoadHandle,
) -> RafxResult<()> {
Ok(())
}
}
pub struct DefaultAssetTypeHandler<AssetDataT, AssetT, LoadHandlerT>
where
LoadHandlerT: DefaultAssetTypeLoadHandler<AssetDataT, AssetT>,
{
asset_lookup: AssetLookup<AssetT>,
load_queues: LoadQueues<AssetDataT, AssetT>,
phantom_data: PhantomData<LoadHandlerT>,
}
impl<AssetDataT, AssetT, LoadHandlerT> DefaultAssetTypeHandler<AssetDataT, AssetT, LoadHandlerT>
where
AssetDataT: TypeUuid + for<'a> serde::Deserialize<'a> + 'static + Send + Clone,
AssetT: TypeUuid + 'static + Send + Clone + Sync,
LoadHandlerT: DefaultAssetTypeLoadHandler<AssetDataT, AssetT> + 'static + Sync + Send,
{
pub fn create(
_asset_manager: &mut AssetManager,
asset_resource: &mut AssetResource,
) -> RafxResult<Box<dyn AssetTypeHandler>> {
let load_queues = LoadQueues::<AssetDataT, AssetT>::default();
asset_resource.add_storage_with_loader::<AssetDataT, AssetT, _>(Box::new(
RafxResourceAssetLoader(load_queues.create_loader()),
));
Ok(Box::new(Self {
asset_lookup: AssetLookup::default(),
load_queues,
phantom_data: Default::default(),
}))
}
}
impl<AssetDataT, AssetT, LoadHandlerT> AssetTypeHandler
for DefaultAssetTypeHandler<AssetDataT, AssetT, LoadHandlerT>
where
AssetDataT: TypeUuid + for<'a> serde::Deserialize<'a> + 'static + Send + Clone,
AssetT: TypeUuid + 'static + Send + Clone + Sync,
LoadHandlerT: DefaultAssetTypeLoadHandler<AssetDataT, AssetT> + 'static + Sync + Send,
{
fn process_load_requests(
&mut self,
asset_manager: &mut AssetManager,
) -> RafxResult<()> {
for request in self.load_queues.take_load_requests() {
log::debug!(
"Create asset type {} {:?}",
std::any::type_name::<AssetT>(),
request.load_handle,
);
let loaded_asset =
LoadHandlerT::load(asset_manager, request.asset, request.load_handle);
handle_load_result(
request.load_op,
loaded_asset,
&mut self.asset_lookup,
request.result_tx,
);
}
handle_commit_requests(&mut self.load_queues, &mut self.asset_lookup);
for request in self.load_queues.take_free_requests() {
log::trace!(
"free asset {:?} {}",
request.load_handle,
core::any::type_name::<AssetDataT>()
);
LoadHandlerT::free(asset_manager, request.load_handle)?;
self.asset_lookup.free(request.load_handle);
}
Ok(())
}
fn asset_lookup(&self) -> &dyn DynAssetLookup {
&self.asset_lookup
}
fn asset_type_id(&self) -> TypeId {
TypeId::of::<AssetT>()
}
}
#[derive(Default)]
pub struct StorageOnlyAssetTypeLoadHandler<AssetT>(PhantomData<AssetT>);
impl<AssetT> DefaultAssetTypeLoadHandler<AssetT, AssetT>
for StorageOnlyAssetTypeLoadHandler<AssetT>
{
fn load(
_asset_manager: &mut AssetManager,
asset_data: AssetT,
_load_handle: LoadHandle,
) -> RafxResult<AssetT> {
Ok(asset_data)
}
}
pub type StorageOnlyAssetTypeHandler<AssetT> =
DefaultAssetTypeHandler<AssetT, AssetT, StorageOnlyAssetTypeLoadHandler<AssetT>>;
pub fn handle_load_result<AssetT: Clone>(
load_op: ArtifactLoadOp,
loaded_asset: RafxResult<AssetT>,
asset_lookup: &mut AssetLookup<AssetT>,
result_tx: Sender<AssetT>,
) {
match loaded_asset {
Ok(loaded_asset) => {
asset_lookup.set_uncommitted(load_op.load_handle(), loaded_asset.clone());
result_tx.send(loaded_asset).unwrap();
load_op.complete()
}
Err(err) => {
load_op.error(err);
}
}
}
pub fn handle_commit_requests<AssetDataT, AssetT>(
load_queues: &mut LoadQueues<AssetDataT, AssetT>,
asset_lookup: &mut AssetLookup<AssetT>,
) {
for request in load_queues.take_commit_requests() {
log::trace!(
"commit asset {:?} {}",
request.load_handle,
core::any::type_name::<AssetDataT>()
);
asset_lookup.commit(request.load_handle);
}
}
pub fn handle_free_requests<AssetDataT, AssetT>(
load_queues: &mut LoadQueues<AssetDataT, AssetT>,
asset_lookup: &mut AssetLookup<AssetT>,
) {
for request in load_queues.take_free_requests() {
log::trace!(
"free asset {:?} {}",
request.load_handle,
core::any::type_name::<AssetDataT>()
);
asset_lookup.free(request.load_handle);
}
}