1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
use crate::{storage::ProcessingState, FormatRegisteredData, Handle, Reload, SingleFile, Source};
use amethyst_core::ecs::storage::UnprotectedStorage;
use amethyst_error::{Error, ResultExt};
use std::{fmt::Debug, ops::Deref, sync::Arc};

#[cfg(feature = "profiler")]
use thread_profiler::profile_scope;

/// One of the three core traits of this crate.
///
/// You want to implement this for every type of asset like
///
/// * `Mesh`
/// * `Texture`
/// * `Terrain`
///
/// and so on. Now, an asset may be available in different formats.
/// That's why we have the `Data` associated type here. You can specify
/// an intermediate format here, like the vertex data for a mesh or the samples
/// for audio data.
///
/// This data is then generated by the `Format` trait.
pub trait Asset: Send + Sync + 'static {
    /// An identifier for this asset used for debugging.
    const NAME: &'static str;

    /// The `Data` type the asset can be created from.
    type Data: Send + Sync + 'static;

    /// The ECS storage type to be used. You'll want to use `DenseVecStorage` in most cases.
    type HandleStorage: UnprotectedStorage<Handle<Self>> + Send + Sync;
}

/// Defines a way to process asset's data into the asset. This allows
/// using default `Processor` system to process assets that implement that type.
pub trait ProcessableAsset: Asset + Sized {
    /// Processes asset data into asset during loading.
    fn process(data: Self::Data) -> Result<ProcessingState<Self>, Error>;
}

impl<T: Asset<Data = T>> ProcessableAsset for T {
    fn process(data: Self::Data) -> Result<ProcessingState<Self>, Error> {
        Ok(ProcessingState::Loaded(data))
    }
}

/// A format, providing a conversion from bytes to asset data, which is then
/// in turn accepted by `Asset::from_data`. Examples for formats are
/// `Png`, `Obj` and `Wave`.
///
/// The format type itself represents loading options, which are passed to `import`.
/// E.g. for textures this would be stuff like mipmap levels and
/// sampler info.
pub trait Format<D: 'static>: objekt::Clone + Debug + Send + Sync + 'static {
    /// A unique identifier for this format.
    fn name(&self) -> &'static str;

    /// Produces asset data from given bytes.
    /// This method is a simplified version of `format`.
    /// This format assumes that the asset name is the full path and the asset is only
    /// contained in one file.
    ///
    /// If you are implementing `format` yourself, this method will never be used
    /// and can be left unimplemented.
    ///
    fn import_simple(&self, _bytes: Vec<u8>) -> Result<D, Error> {
        unimplemented!("You must implement either `import_simple` or `import`.")
    }

    /// Reads the given bytes and produces asset data.
    ///
    /// You can implement `import_simple` instead of simpler formats.
    ///
    /// ## Reload
    ///
    /// The reload structure has metadata which allows the asset management
    /// to reload assets if necessary (for hot reloading).
    /// You should only create `Reload` when `create_reload` is `Some`.
    /// Also, the parameter is just a request, which means it's optional either way.
    fn import(
        &self,
        name: String,
        source: Arc<dyn Source>,
        create_reload: Option<Box<dyn Format<D>>>,
    ) -> Result<FormatValue<D>, Error> {
        #[cfg(feature = "profiler")]
        profile_scope!("import_asset");
        if let Some(boxed_format) = create_reload {
            let (b, m) = source
                .load_with_metadata(&name)
                .with_context(|_| crate::error::Error::Source)?;
            Ok(FormatValue {
                data: self.import_simple(b)?,
                reload: Some(Box::new(SingleFile::new(boxed_format, m, name, source))),
            })
        } else {
            let b = source
                .load(&name)
                .with_context(|_| crate::error::Error::Source)?;
            Ok(FormatValue::data(self.import_simple(b)?))
        }
    }
}

objekt::clone_trait_object!(<D> Format<D>);

/// SerializableFormat is a marker trait which is required for Format types that are supposed
/// to be serialized. This trait implies both `Serialize` and `Deserialize` implementation.
///
/// **Note:** This trait should never be implemented manually.
/// Use the `register_format` macro to register it correctly.
/// See [FormatRegisteredData](trait.FormatRegisteredData.html) for the full example.
pub trait SerializableFormat<D: FormatRegisteredData + 'static>:
    Format<D> + erased_serde::Serialize + 'static
{
    // Empty.
}

objekt::clone_trait_object!(<D> SerializableFormat<D>);

// Allow using dynamic types on sites that accept format as generic.
impl<D: 'static> Format<D> for Box<dyn Format<D>> {
    fn name(&self) -> &'static str {
        self.deref().name()
    }
    fn import_simple(&self, bytes: Vec<u8>) -> Result<D, Error> {
        self.deref().import_simple(bytes)
    }

    fn import(
        &self,
        name: String,
        source: Arc<dyn Source>,
        create_reload: Option<Box<dyn Format<D>>>,
    ) -> Result<FormatValue<D>, Error> {
        self.deref().import(name, source, create_reload)
    }
}

impl<D: 'static> Format<D> for Box<dyn SerializableFormat<D>> {
    fn name(&self) -> &'static str {
        self.deref().name()
    }
    fn import_simple(&self, bytes: Vec<u8>) -> Result<D, Error> {
        self.deref().import_simple(bytes)
    }

    fn import(
        &self,
        name: String,
        source: Arc<dyn Source>,
        create_reload: Option<Box<dyn Format<D>>>,
    ) -> Result<FormatValue<D>, Error> {
        self.deref().import(name, source, create_reload)
    }
}

impl<D: FormatRegisteredData + 'static> SerializableFormat<D> for Box<dyn SerializableFormat<D>> {}

/// The `Ok` return value of `Format::import` for a given asset type `A`.
pub struct FormatValue<D> {
    /// The format data.
    pub data: D,
    /// An optional reload structure
    pub reload: Option<Box<dyn Reload<D>>>,
}

impl<D> FormatValue<D> {
    /// Creates a `FormatValue` from only the data (setting `reload` to `None`).
    pub fn data(data: D) -> Self {
        FormatValue { data, reload: None }
    }
}