Skip to main content

bevy_image/
exr_texture_loader.rs

1use crate::{Image, TextureFormatPixelInfo};
2use bevy_asset::{io::Reader, AssetLoader, LoadContext, RenderAssetUsages};
3use bevy_reflect::TypePath;
4use image::ImageDecoder;
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7use wgpu_types::{Extent3d, TextureDimension, TextureFormat};
8
9/// Loads EXR textures as Texture assets
10#[derive(#[automatically_derived]
impl ::core::clone::Clone for ExrTextureLoader {
    #[inline]
    fn clone(&self) -> ExrTextureLoader { ExrTextureLoader }
}Clone, #[automatically_derived]
impl ::core::default::Default for ExrTextureLoader {
    #[inline]
    fn default() -> ExrTextureLoader { ExrTextureLoader {} }
}Default, const _: () =
    {
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for ExrTextureLoader where  {
            fn type_path() -> &'static str {
                "bevy_image::exr_texture_loader::ExrTextureLoader"
            }
            fn short_type_path() -> &'static str { "ExrTextureLoader" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("ExrTextureLoader")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::exr_texture_loader".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::exr_texture_loader")
            }
        }
    };TypePath)]
11#[cfg(feature = "exr")]
12pub struct ExrTextureLoader;
13
14/// Settings for [`ExrTextureLoader`].
15#[derive(#[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl _serde::Serialize for ExrTextureLoaderSettings {
            fn serialize<__S>(&self, __serializer: __S)
                -> _serde::__private228::Result<__S::Ok, __S::Error> where
                __S: _serde::Serializer {
                let mut __serde_state =
                    _serde::Serializer::serialize_struct(__serializer,
                            "ExrTextureLoaderSettings", false as usize + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "asset_usage", &self.asset_usage)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };Serialize, #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications,
clippy :: absolute_paths,)]
const _: () =
    {
        #[allow(unused_extern_crates, clippy :: useless_attribute)]
        extern crate serde as _serde;
        ;
        #[automatically_derived]
        impl<'de> _serde::Deserialize<'de> for ExrTextureLoaderSettings {
            fn deserialize<__D>(__deserializer: __D)
                -> _serde::__private228::Result<Self, __D::Error> where
                __D: _serde::Deserializer<'de> {
                #[allow(non_camel_case_types)]
                #[doc(hidden)]
                enum __Field { __field0, __ignore, }
                #[doc(hidden)]
                struct __FieldVisitor;
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __FieldVisitor {
                    type Value = __Field;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "field identifier")
                    }
                    fn visit_u64<__E>(self, __value: u64)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            0u64 => _serde::__private228::Ok(__Field::__field0),
                            _ => _serde::__private228::Ok(__Field::__ignore),
                        }
                    }
                    fn visit_str<__E>(self, __value: &str)
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            "asset_usage" =>
                                _serde::__private228::Ok(__Field::__field0),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                    fn visit_bytes<__E>(self, __value: &[u8])
                        -> _serde::__private228::Result<Self::Value, __E> where
                        __E: _serde::de::Error {
                        match __value {
                            b"asset_usage" =>
                                _serde::__private228::Ok(__Field::__field0),
                            _ => { _serde::__private228::Ok(__Field::__ignore) }
                        }
                    }
                }
                #[automatically_derived]
                impl<'de> _serde::Deserialize<'de> for __Field {
                    #[inline]
                    fn deserialize<__D>(__deserializer: __D)
                        -> _serde::__private228::Result<Self, __D::Error> where
                        __D: _serde::Deserializer<'de> {
                        _serde::Deserializer::deserialize_identifier(__deserializer,
                            __FieldVisitor)
                    }
                }
                #[doc(hidden)]
                struct __Visitor<'de> {
                    marker: _serde::__private228::PhantomData<ExrTextureLoaderSettings>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = ExrTextureLoaderSettings;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct ExrTextureLoaderSettings")
                    }
                    #[inline]
                    fn visit_seq<__A>(self, mut __seq: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::SeqAccess<'de> {
                        let __field0 =
                            match _serde::de::SeqAccess::next_element::<RenderAssetUsages>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct ExrTextureLoaderSettings with 1 element")),
                            };
                        _serde::__private228::Ok(ExrTextureLoaderSettings {
                                asset_usage: __field0,
                            })
                    }
                    #[inline]
                    fn visit_map<__A>(self, mut __map: __A)
                        -> _serde::__private228::Result<Self::Value, __A::Error>
                        where __A: _serde::de::MapAccess<'de> {
                        let mut __field0:
                                _serde::__private228::Option<RenderAssetUsages> =
                            _serde::__private228::None;
                        while let _serde::__private228::Some(__key) =
                                _serde::de::MapAccess::next_key::<__Field>(&mut __map)? {
                            match __key {
                                __Field::__field0 => {
                                    if _serde::__private228::Option::is_some(&__field0) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("asset_usage"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<RenderAssetUsages>(&mut __map)?);
                                }
                                _ => {
                                    let _ =
                                        _serde::de::MapAccess::next_value::<_serde::de::IgnoredAny>(&mut __map)?;
                                }
                            }
                        }
                        let __field0 =
                            match __field0 {
                                _serde::__private228::Some(__field0) => __field0,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("asset_usage")?,
                            };
                        _serde::__private228::Ok(ExrTextureLoaderSettings {
                                asset_usage: __field0,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] = &["asset_usage"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "ExrTextureLoaderSettings", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<ExrTextureLoaderSettings>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize, #[automatically_derived]
impl ::core::default::Default for ExrTextureLoaderSettings {
    #[inline]
    fn default() -> ExrTextureLoaderSettings {
        ExrTextureLoaderSettings {
            asset_usage: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for ExrTextureLoaderSettings {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "ExrTextureLoaderSettings", "asset_usage", &&self.asset_usage)
    }
}Debug)]
16#[cfg(feature = "exr")]
17pub struct ExrTextureLoaderSettings {
18    /// Where the asset will be used - see the docs on [`RenderAssetUsages`] for details.
19    pub asset_usage: RenderAssetUsages,
20}
21
22/// Possible errors that can be produced by [`ExrTextureLoader`]
23#[non_exhaustive]
24#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ExrTextureLoaderError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ExrTextureLoaderError::Io(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Io",
                    &__self_0),
            ExrTextureLoaderError::ImageError(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "ImageError", &__self_0),
        }
    }
}Debug, fn from(source: image::ImageError) -> Self {
    ExrTextureLoaderError::ImageError { 0: source }
}Error, const _: () =
    {
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for ExrTextureLoaderError where  {
            fn type_path() -> &'static str {
                "bevy_image::exr_texture_loader::ExrTextureLoaderError"
            }
            fn short_type_path() -> &'static str { "ExrTextureLoaderError" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("ExrTextureLoaderError")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::exr_texture_loader".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::exr_texture_loader")
            }
        }
    };TypePath)]
25#[cfg(feature = "exr")]
26pub enum ExrTextureLoaderError {
27    /// I/O Error.
28    #[error(transparent)]
29    Io(#[from] std::io::Error),
30    /// Failed to decode the texture.
31    #[error(transparent)]
32    ImageError(#[from] image::ImageError),
33}
34
35impl AssetLoader for ExrTextureLoader {
36    type Asset = Image;
37    type Settings = ExrTextureLoaderSettings;
38    type Error = ExrTextureLoaderError;
39
40    async fn load(
41        &self,
42        reader: &mut dyn Reader,
43        settings: &Self::Settings,
44        _load_context: &mut LoadContext<'_>,
45    ) -> Result<Image, Self::Error> {
46        let format = TextureFormat::Rgba32Float;
47        if true {
    match (&format.pixel_size().unwrap(), &(4 * 4)) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val,
                    ::core::option::Option::Some(format_args!("Format should have 32bit x 4 size")));
            }
        }
    };
};debug_assert_eq!(
48            // `Rgba32Float` will always return a valid pixel size
49            format.pixel_size().unwrap(),
50            4 * 4,
51            "Format should have 32bit x 4 size"
52        );
53
54        let mut bytes = Vec::new();
55        reader.read_to_end(&mut bytes).await?;
56        let decoder = image::codecs::openexr::OpenExrDecoder::with_alpha_preference(
57            std::io::Cursor::new(bytes),
58            Some(true),
59        )?;
60        let (width, height) = decoder.dimensions();
61
62        let total_bytes = decoder.total_bytes() as usize;
63
64        let mut buf = ::alloc::vec::from_elem(0u8, total_bytes)vec![0u8; total_bytes];
65        decoder.read_image(buf.as_mut_slice())?;
66
67        Ok(Image::new(
68            Extent3d {
69                width,
70                height,
71                depth_or_array_layers: 1,
72            },
73            TextureDimension::D2,
74            buf,
75            format,
76            settings.asset_usage,
77        ))
78    }
79
80    fn extensions(&self) -> &[&str] {
81        &["exr"]
82    }
83}