summaryrefslogtreecommitdiff
path: root/engine/src
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src')
-rw-r--r--engine/src/asset.rs204
-rw-r--r--engine/src/material.rs4
-rw-r--r--engine/src/material/asset.rs21
-rw-r--r--engine/src/mesh.rs3
-rw-r--r--engine/src/model.rs4
-rw-r--r--engine/src/model/asset.rs11
-rw-r--r--engine/src/rendering.rs4
-rw-r--r--engine/src/rendering/shader.rs14
-rw-r--r--engine/src/texture.rs6
9 files changed, 145 insertions, 126 deletions
diff --git a/engine/src/asset.rs b/engine/src/asset.rs
index 8337f5f..781ca22 100644
--- a/engine/src/asset.rs
+++ b/engine/src/asset.rs
@@ -1,9 +1,8 @@
-use std::any::{type_name, Any};
+use std::any::{type_name, Any, TypeId};
use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::Infallible;
-use std::ffi::{OsStr, OsString};
use std::fmt::{Debug, Display};
use std::hash::{DefaultHasher, Hash, Hasher};
use std::hint::cold_path;
@@ -28,6 +27,8 @@ declare_entity! {
pub HANDLE_ASSETS_PHASE: (Phase, pair!(ChildOf, { *PRE_UPDATE_PHASE }));
}
+pub trait Asset: Send + Sync + 'static {}
+
/// Asset label.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Label<'a>
@@ -129,8 +130,7 @@ pub struct Assets
{
store: Vec<StoredAsset>,
asset_lookup: RefCell<HashMap<LabelHash, LookupEntry>>,
- importers: Vec<WrappedImporterFn>,
- importer_lookup: HashMap<OsString, usize>,
+ importers: hashbrown::HashMap<AssetTypeId, WrappedImporterFn>,
import_work_queue: WorkQueue<ImportWorkUserData>,
import_work_msg_receiver: MpscReceiver<ImportWorkMessage>,
import_work_msg_sender: MpscSender<ImportWorkMessage>,
@@ -148,8 +148,7 @@ impl Assets
Self {
store: Vec::with_capacity(capacity),
asset_lookup: RefCell::new(HashMap::with_capacity(capacity)),
- importers: Vec::new(),
- importer_lookup: HashMap::new(),
+ importers: hashbrown::HashMap::new(),
import_work_queue: WorkQueue::new("asset_importing_work_queue"),
import_work_msg_receiver,
import_work_msg_sender,
@@ -157,34 +156,25 @@ impl Assets
}
}
- pub fn set_importer<'file_ext, AssetSettings, Err>(
+ pub fn set_importer<AssetT, AssetSettings, Err>(
&mut self,
- file_extensions: impl IntoIterator<Item: Into<Cow<'file_ext, str>>>,
func: impl Fn(&mut Submitter<'_>, &Path, Option<&AssetSettings>) -> Result<(), Err>,
) where
+ AssetT: Asset,
AssetSettings: 'static,
Err: std::error::Error + Send + Sync + 'static,
{
- self.importers.push(WrappedImporterFn::new(func));
-
- let importer_index = self.importers.len() - 1;
-
- self.importer_lookup
- .extend(file_extensions.into_iter().map(|file_ext| {
- let file_ext: Cow<str> = file_ext.into();
-
- (file_ext.into_owned().into(), importer_index)
- }));
+ self.importers
+ .insert(AssetTypeId::of::<AssetT>(), WrappedImporterFn::new(func));
}
#[tracing::instrument(
skip_all,
- fields(asset_label, asset_type = type_name::<Asset>())
+ fields(asset_label, asset_type = type_name::<AssetT>())
)]
- pub fn get<Asset: 'static + Send + Sync>(
- &self,
- handle: &Handle<Asset>,
- ) -> Option<&Asset>
+ pub fn get<AssetT>(&self, handle: &Handle<AssetT>) -> Option<&AssetT>
+ where
+ AssetT: Asset,
{
let id = handle.id.into_valid()?;
@@ -203,7 +193,7 @@ impl Assets
unreachable!();
};
- let Some(asset) = stored_asset.strong.downcast_ref::<Asset>() else {
+ let Some(asset) = stored_asset.strong.downcast_ref::<AssetT>() else {
tracing::error!("Wrong asset type");
return None;
};
@@ -211,11 +201,13 @@ impl Assets
Some(asset)
}
- #[tracing::instrument(skip_all, fields(asset_type=type_name::<Asset>()))]
- pub fn get_handle_to_loaded<'label, Asset: 'static + Send + Sync>(
+ #[tracing::instrument(skip_all, fields(asset_type=type_name::<AssetT>()))]
+ pub fn get_handle_to_loaded<'label, AssetT>(
&self,
label: impl Into<Label<'label>>,
- ) -> Option<Handle<Asset>>
+ ) -> Option<Handle<AssetT>>
+ where
+ AssetT: Asset,
{
let label = label.into();
@@ -231,7 +223,7 @@ impl Assets
unreachable!();
};
- if stored_asset.strong.downcast_ref::<Asset>().is_none() {
+ if stored_asset.strong.downcast_ref::<AssetT>().is_none() {
tracing::error!("Wrong asset type");
return None;
}
@@ -239,10 +231,9 @@ impl Assets
Some(Handle::new(label_hash))
}
- pub fn is_loaded_and_has_type<Asset: 'static + Send + Sync>(
- &self,
- handle: &Handle<Asset>,
- ) -> bool
+ pub fn is_loaded_and_has_type<AssetT>(&self, handle: &Handle<AssetT>) -> bool
+ where
+ AssetT: Asset,
{
let Some(id) = handle.id.into_valid() else {
return false;
@@ -260,13 +251,12 @@ impl Assets
unreachable!();
};
- stored_asset.strong.downcast_ref::<Asset>().is_some()
+ stored_asset.strong.downcast_ref::<AssetT>().is_some()
}
- pub fn get_label<Asset: 'static + Send + Sync>(
- &self,
- handle: &Handle<Asset>,
- ) -> Option<LabelOwned>
+ pub fn get_label<AssetT>(&self, handle: &Handle<AssetT>) -> Option<LabelOwned>
+ where
+ AssetT: Asset,
{
let id = handle.id.into_valid()?;
@@ -293,10 +283,9 @@ impl Assets
}
#[tracing::instrument(skip(self))]
- pub fn load<'i, Asset: 'static + Send + Sync>(
- &self,
- label: impl Into<Label<'i>> + Debug,
- ) -> Handle<Asset>
+ pub fn load<'i, AssetT>(&self, label: impl Into<Label<'i>> + Debug) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
let label = label.into();
@@ -309,7 +298,7 @@ impl Assets
}
let Some(lookup_entry) = asset_lookup.get(&label_hash) else {
- self.add_import_work::<Infallible>(
+ self.add_import_work::<AssetT, Infallible>(
&label,
label_hash,
None,
@@ -325,8 +314,8 @@ impl Assets
unreachable!();
};
- if stored_asset.strong.downcast_ref::<Asset>().is_none() {
- tracing::error!("Wrong asset type {}", type_name::<Asset>());
+ if stored_asset.strong.downcast_ref::<AssetT>().is_none() {
+ tracing::error!("Wrong asset type {}", type_name::<AssetT>());
}
}
LookupEntry::Pending => {}
@@ -336,13 +325,13 @@ impl Assets
}
#[tracing::instrument(skip(self))]
- pub fn load_with_settings<'i, Asset, AssetSettings>(
+ pub fn load_with_settings<'i, AssetT, AssetSettings>(
&self,
label: impl Into<Label<'i>> + Debug,
asset_settings: AssetSettings,
- ) -> Handle<Asset>
+ ) -> Handle<AssetT>
where
- Asset: Send + Sync + 'static,
+ AssetT: Asset,
AssetSettings: Send + Sync + Debug + 'static,
{
let label = label.into();
@@ -356,7 +345,7 @@ impl Assets
}
let Some(lookup_entry) = asset_lookup.get(&label_hash) else {
- self.add_import_work::<AssetSettings>(
+ self.add_import_work::<AssetT, AssetSettings>(
&label,
label_hash,
Some(asset_settings),
@@ -372,10 +361,10 @@ impl Assets
unreachable!();
};
- if stored_asset.strong.downcast_ref::<Asset>().is_none() {
+ if stored_asset.strong.downcast_ref::<AssetT>().is_none() {
tracing::error!(
"Wrong asset type {} for asset",
- type_name::<Asset>()
+ type_name::<AssetT>()
);
}
}
@@ -385,11 +374,13 @@ impl Assets
Handle::new(label_hash)
}
- pub fn store_with_name<'name, Asset: 'static + Send + Sync>(
+ pub fn store_with_name<'name, AssetT>(
&mut self,
name: impl Into<Cow<'name, str>>,
- asset: Asset,
- ) -> Handle<Asset>
+ asset: AssetT,
+ ) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
self.store_with_label(
Label {
@@ -400,11 +391,13 @@ impl Assets
)
}
- pub fn store_with_name_with<'name, Asset: 'static + Send + Sync>(
+ pub fn store_with_name_with<'name, AssetT>(
&mut self,
name: impl Into<Cow<'name, str>>,
- func: impl FnOnce(&mut Self) -> Asset,
- ) -> Handle<Asset>
+ func: impl FnOnce(&mut Self) -> AssetT,
+ ) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
let asset = func(self);
@@ -417,12 +410,14 @@ impl Assets
)
}
- #[tracing::instrument(skip(self, asset), fields(asset_type=type_name::<Asset>()))]
- pub fn store_with_label<'i, Asset: 'static + Send + Sync>(
+ #[tracing::instrument(skip(self, asset), fields(asset_type=type_name::<AssetT>()))]
+ pub fn store_with_label<'i, AssetT>(
&mut self,
label: impl Into<Label<'i>> + Debug,
- asset: Asset,
- ) -> Handle<Asset>
+ asset: AssetT,
+ ) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
let label = label.into();
@@ -483,25 +478,18 @@ impl Assets
false
}
- fn add_import_work<AssetSettings>(
+ fn add_import_work<AssetT, AssetSettings>(
&self,
label: &Label<'_>,
label_hash: LabelHash,
asset_settings: Option<AssetSettings>,
asset_lookup: &mut HashMap<LabelHash, LookupEntry>,
) where
+ AssetT: Asset,
AssetSettings: Any + Send + Sync,
{
- let Some(file_ext) = label.path.extension() else {
- tracing::error!("Asset file is missing a file extension");
- return;
- };
-
- let Some(importer) = self.get_importer(file_ext) else {
- tracing::error!(
- "No importer exists for asset file extension {}",
- file_ext.to_string_lossy()
- );
+ let Some(importer) = self.importers.get(&AssetTypeId::of::<AssetT>()) else {
+ tracing::error!("No importer exists for asset");
return;
};
@@ -546,17 +534,6 @@ impl Assets
);
}
}
-
- fn get_importer(&self, file_ext: &OsStr) -> Option<&WrappedImporterFn>
- {
- let index = *self.importer_lookup.get(file_ext)?;
-
- let Some(importer) = self.importers.get(index) else {
- unreachable!();
- };
-
- Some(importer)
- }
}
impl Default for Assets
@@ -575,16 +552,18 @@ pub struct Submitter<'path>
impl Submitter<'_>
{
- pub fn submit_load_other<'label, Asset: Send + Sync + 'static>(
+ pub fn submit_load_other<'label, AssetT>(
&self,
label: impl Into<Label<'label>>,
- ) -> Handle<Asset>
+ ) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
let label = label.into();
let _ = self.import_work_msg_sender.send(ImportWorkMessage::Load {
do_load: |assets, label, _asset_settings| {
- let _ = assets.load::<Asset>(label);
+ let _ = assets.load::<AssetT>(label);
},
label: label.to_owned(),
asset_settings: None,
@@ -593,13 +572,13 @@ impl Submitter<'_>
Handle::new(LabelHash::new(&label))
}
- pub fn submit_load_other_with_settings<'label, Asset, AssetSettings>(
+ pub fn submit_load_other_with_settings<'label, AssetT, AssetSettings>(
&self,
label: impl Into<Label<'label>>,
asset_settings: AssetSettings,
- ) -> Handle<Asset>
+ ) -> Handle<AssetT>
where
- Asset: Send + Sync + 'static,
+ AssetT: Asset,
AssetSettings: Send + Sync + Debug + 'static,
{
let label = label.into();
@@ -612,7 +591,7 @@ impl Submitter<'_>
.expect("Not possible");
let _ = assets
- .load_with_settings::<Asset, AssetSettings>(label, asset_settings);
+ .load_with_settings::<AssetT, AssetSettings>(label, asset_settings);
},
label: label.to_owned(),
asset_settings: Some(Box::new(asset_settings)),
@@ -621,10 +600,9 @@ impl Submitter<'_>
Handle::new(LabelHash::new(&label))
}
- pub fn submit_store<Asset: Send + Sync + 'static>(
- &self,
- asset: Asset,
- ) -> Handle<Asset>
+ pub fn submit_store<AssetT>(&self, asset: AssetT) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
let label = LabelOwned {
path: self.asset_path.into(),
@@ -635,11 +613,11 @@ impl Submitter<'_>
let _ = self.import_work_msg_sender.send(ImportWorkMessage::Store {
do_store: |assets, label, boxed_asset| {
- let Ok(asset) = boxed_asset.downcast::<Asset>() else {
+ let Ok(asset) = boxed_asset.downcast::<AssetT>() else {
unreachable!();
};
- assets.store_with_label::<Asset>(&label, *asset);
+ assets.store_with_label::<AssetT>(&label, *asset);
},
label,
asset: Box::new(asset),
@@ -648,11 +626,13 @@ impl Submitter<'_>
Handle::new(label_hash)
}
- pub fn submit_store_named<Asset: Send + Sync + 'static>(
+ pub fn submit_store_named<AssetT>(
&self,
name: impl AsRef<str>,
- asset: Asset,
- ) -> Handle<Asset>
+ asset: AssetT,
+ ) -> Handle<AssetT>
+ where
+ AssetT: Asset,
{
let label = LabelOwned {
path: self.asset_path.into(),
@@ -663,11 +643,11 @@ impl Submitter<'_>
let _ = self.import_work_msg_sender.send(ImportWorkMessage::Store {
do_store: |assets, label, boxed_asset| {
- let Ok(asset) = boxed_asset.downcast::<Asset>() else {
+ let Ok(asset) = boxed_asset.downcast::<AssetT>() else {
unreachable!();
};
- assets.store_with_label::<Asset>(&label, *asset);
+ assets.store_with_label::<AssetT>(&label, *asset);
},
label,
asset: Box::new(asset),
@@ -679,13 +659,13 @@ impl Submitter<'_>
/// Asset handle.
#[derive(Debug)]
-pub struct Handle<Asset: 'static>
+pub struct Handle<AssetT: Asset>
{
id: Id,
- _pd: PhantomData<Asset>,
+ _pd: PhantomData<AssetT>,
}
-impl<Asset: 'static> Handle<Asset>
+impl<AssetT: Asset> Handle<AssetT>
{
pub fn invalid() -> Self
{
@@ -712,7 +692,7 @@ impl<Asset: 'static> Handle<Asset>
}
}
-impl<Asset: 'static> Clone for Handle<Asset>
+impl<AssetT: Asset> Clone for Handle<AssetT>
{
fn clone(&self) -> Self
{
@@ -974,10 +954,24 @@ struct StoredAsset
impl StoredAsset
{
- fn new<Asset: Any + Send + Sync>(asset: Asset) -> Self
+ fn new<AssetT: Asset>(asset: AssetT) -> Self
{
let strong = Arc::new(asset);
Self { strong }
}
}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+struct AssetTypeId
+{
+ inner: TypeId,
+}
+
+impl AssetTypeId
+{
+ fn of<AssetT: Asset>() -> Self
+ {
+ Self { inner: TypeId::of::<AssetT>() }
+ }
+}
diff --git a/engine/src/material.rs b/engine/src/material.rs
index fc9fcd7..bf07b72 100644
--- a/engine/src/material.rs
+++ b/engine/src/material.rs
@@ -1,4 +1,4 @@
-use crate::asset::Handle as AssetHandle;
+use crate::asset::{Asset, Handle as AssetHandle};
use crate::builder;
use crate::color::{Color, Rgb};
use crate::ecs::Component;
@@ -44,6 +44,8 @@ impl Default for Material
}
}
+impl Asset for Material {}
+
/// [`Material`] builder.
#[derive(Debug, Clone)]
pub struct Builder
diff --git a/engine/src/material/asset.rs b/engine/src/material/asset.rs
index f87b768..f452f54 100644
--- a/engine/src/material/asset.rs
+++ b/engine/src/material/asset.rs
@@ -1,17 +1,9 @@
-use std::borrow::Cow;
-use std::collections::HashMap;
use std::fs::read_to_string;
use std::path::{Path, PathBuf};
-use crate::asset::{Assets, Handle as AssetHandle, Submitter as AssetSubmitter};
+use crate::asset::{Assets, Submitter as AssetSubmitter};
use crate::material::Material;
-#[derive(Debug, Clone)]
-pub struct Map
-{
- pub assets: HashMap<Cow<'static, str>, AssetHandle<Material>>,
-}
-
/// Material asset import settings.
#[derive(Debug)]
#[non_exhaustive]
@@ -19,15 +11,19 @@ pub struct Settings {}
pub fn add_importers(assets: &mut Assets)
{
- assets.set_importer(["mtl"], import_wavefront_mtl_asset);
+ assets.set_importer::<Material, Settings, Error>(import);
}
-fn import_wavefront_mtl_asset(
+fn import(
asset_submitter: &mut AssetSubmitter<'_>,
path: &Path,
_settings: Option<&'_ Settings>,
) -> Result<(), Error>
{
+ if path.extension().is_none_or(|ext| ext != "mtl") {
+ return Err(Error::UnsupportedFileType);
+ }
+
let parent_path = path
.parent()
.ok_or_else(|| Error::InvalidPath(path.to_path_buf()))?;
@@ -71,6 +67,9 @@ fn import_wavefront_mtl_asset(
#[derive(Debug, thiserror::Error)]
enum Error
{
+ #[error("File type is unsupported")]
+ UnsupportedFileType,
+
#[error("Invalid path '{}'", .0.display())]
InvalidPath(PathBuf),
diff --git a/engine/src/mesh.rs b/engine/src/mesh.rs
index 771f7bd..994387a 100644
--- a/engine/src/mesh.rs
+++ b/engine/src/mesh.rs
@@ -2,6 +2,7 @@ use std::alloc::Layout;
use zerocopy::IntoBytes;
+use crate::asset::Asset;
use crate::data_types::dimens::Dimens3;
use crate::mesh::vertex_buffer::{VertexAttrProperties, VertexLabel};
use crate::vector::{Vec2, Vec3};
@@ -312,6 +313,8 @@ impl Mesh
}
}
+impl Asset for Mesh {}
+
/// Mesh builder
#[derive(Debug, Clone, Default)]
pub struct Builder
diff --git a/engine/src/model.rs b/engine/src/model.rs
index 560c43d..88d2622 100644
--- a/engine/src/model.rs
+++ b/engine/src/model.rs
@@ -1,4 +1,4 @@
-use crate::asset::{Assets, Handle as AssetHandle};
+use crate::asset::{Asset, Assets, Handle as AssetHandle};
use crate::ecs::Component;
use crate::material::Material;
use crate::mesh::Mesh;
@@ -55,6 +55,8 @@ impl Spec
}
}
+impl Asset for Spec {}
+
#[derive(Debug, Default, Clone)]
pub struct SpecBuilder
{
diff --git a/engine/src/model/asset.rs b/engine/src/model/asset.rs
index ff5eddf..af3e1b2 100644
--- a/engine/src/model/asset.rs
+++ b/engine/src/model/asset.rs
@@ -42,15 +42,19 @@ impl Default for Settings
pub fn add_importers(assets: &mut Assets)
{
- assets.set_importer(["obj"], import_wavefront_obj_asset);
+ assets.set_importer::<Spec, Settings, Error>(import);
}
-fn import_wavefront_obj_asset(
+fn import(
asset_submitter: &mut AssetSubmitter<'_>,
path: &Path,
settings: Option<&Settings>,
) -> Result<(), Error>
{
+ if path.extension().is_none_or(|ext| ext != "obj") {
+ return Err(Error::UnsupportedFileType);
+ }
+
let settings = match settings {
Some(settings) => settings,
None => &Settings::default(),
@@ -107,6 +111,9 @@ fn import_wavefront_obj_asset(
#[derive(Debug, thiserror::Error)]
enum Error
{
+ #[error("File type is unsupported")]
+ UnsupportedFileType,
+
#[error("Invalid path '{}'", .0.display())]
InvalidPath(PathBuf),
diff --git a/engine/src/rendering.rs b/engine/src/rendering.rs
index bf0ab4e..0e78356 100644
--- a/engine/src/rendering.rs
+++ b/engine/src/rendering.rs
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
use bitflags::bitflags;
use engine_macros::Reflection;
-use crate::asset::Handle as AssetHandle;
+use crate::asset::{Asset, Handle as AssetHandle};
use crate::builder;
use crate::data_types::dimens::Dimens;
use crate::draw_flags::PolygonModeConfig;
@@ -265,7 +265,7 @@ pub enum Command
}
#[derive(Debug)]
-pub enum AssetOrValue<T: 'static>
+pub enum AssetOrValue<T: Asset>
{
Asset(AssetHandle<T>),
Value(T),
diff --git a/engine/src/rendering/shader.rs b/engine/src/rendering/shader.rs
index 085773b..061d9ac 100644
--- a/engine/src/rendering/shader.rs
+++ b/engine/src/rendering/shader.rs
@@ -22,6 +22,7 @@ use shader_slang::{
};
use crate::asset::{
+ Asset,
Assets,
Event as AssetEvent,
Handle as AssetHandle,
@@ -53,6 +54,8 @@ pub struct ModuleSource
pub link_entrypoints: EntrypointFlags,
}
+impl Asset for ModuleSource {}
+
bitflags! {
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct EntrypointFlags: usize
@@ -1262,12 +1265,16 @@ struct VarInput<'a>
index: usize,
}
-fn import_slang_asset(
+fn import(
asset_submitter: &mut AssetSubmitter<'_>,
file_path: &Path,
settings: Option<&'_ Settings>,
) -> Result<(), ImportError>
{
+ if file_path.extension().is_none_or(|ext| ext != "slang") {
+ return Err(ImportError::UnsupportedFileType);
+ }
+
let file_name = file_path
.file_name()
.ok_or(ImportError::NoPathFileName)?
@@ -1295,6 +1302,9 @@ fn import_slang_asset(
#[derive(Debug, thiserror::Error)]
enum ImportError
{
+ #[error("File type is unsupported")]
+ UnsupportedFileType,
+
#[error("Failed to read file")]
ReadFileFailed(#[source] std::io::Error),
@@ -1362,7 +1372,7 @@ fn initialize(mut assets: Single<Assets>) -> Result<(), crate::Error>
{
let assets = assets.get_mut()?;
- assets.set_importer::<_, _>(["slang"], import_slang_asset);
+ assets.set_importer::<ModuleSource, Settings, ImportError>(import);
Ok(())
}
diff --git a/engine/src/texture.rs b/engine/src/texture.rs
index 844d9eb..54646e8 100644
--- a/engine/src/texture.rs
+++ b/engine/src/texture.rs
@@ -1,6 +1,6 @@
use std::path::Path;
-use crate::asset::{Assets, Submitter as AssetSubmitter};
+use crate::asset::{Asset, Assets, Submitter as AssetSubmitter};
use crate::builder;
use crate::color::Rgba;
use crate::image::{Error as ImageError, Image};
@@ -12,6 +12,8 @@ pub enum Texture
CubeMap(TexCubeMap),
}
+impl Asset for Texture {}
+
#[derive(Debug, Clone)]
pub struct Tex2D
{
@@ -136,7 +138,7 @@ impl Default for ImportSettingsBuilder
pub(crate) fn initialize(assets: &mut Assets)
{
- assets.set_importer::<_, _>(["png", "jpg"], import);
+ assets.set_importer::<Texture, ImportSettings, ImageError>(import);
}
fn import(