Skip to main content

bevy_image/
hdr_texture_loader.rs

1use crate::{Image, TextureFormatPixelInfo};
2use bevy_asset::RenderAssetUsages;
3use bevy_asset::{io::Reader, AssetLoader, LoadContext};
4use bevy_reflect::TypePath;
5use image::DynamicImage;
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8use wgpu_types::{Extent3d, TextureDimension, TextureFormat};
9
10/// Loads HDR textures as Texture assets
11#[derive(#[automatically_derived]
impl ::core::clone::Clone for HdrTextureLoader {
    #[inline]
    fn clone(&self) -> HdrTextureLoader { HdrTextureLoader }
}Clone, #[automatically_derived]
impl ::core::default::Default for HdrTextureLoader {
    #[inline]
    fn default() -> HdrTextureLoader { HdrTextureLoader {} }
}Default, const _: () =
    {
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for HdrTextureLoader where  {
            fn type_path() -> &'static str {
                "bevy_image::hdr_texture_loader::HdrTextureLoader"
            }
            fn short_type_path() -> &'static str { "HdrTextureLoader" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("HdrTextureLoader")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::hdr_texture_loader".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::hdr_texture_loader")
            }
        }
    };TypePath)]
12pub struct HdrTextureLoader;
13
14/// Settings for [`HdrTextureLoader`].
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 HdrTextureLoaderSettings {
            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,
                            "HdrTextureLoaderSettings", 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 HdrTextureLoaderSettings {
            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<HdrTextureLoaderSettings>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = HdrTextureLoaderSettings;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct HdrTextureLoaderSettings")
                    }
                    #[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 HdrTextureLoaderSettings with 1 element")),
                            };
                        _serde::__private228::Ok(HdrTextureLoaderSettings {
                                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(HdrTextureLoaderSettings {
                                asset_usage: __field0,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] = &["asset_usage"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "HdrTextureLoaderSettings", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<HdrTextureLoaderSettings>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };Deserialize, #[automatically_derived]
impl ::core::default::Default for HdrTextureLoaderSettings {
    #[inline]
    fn default() -> HdrTextureLoaderSettings {
        HdrTextureLoaderSettings {
            asset_usage: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for HdrTextureLoaderSettings {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "HdrTextureLoaderSettings", "asset_usage", &&self.asset_usage)
    }
}Debug)]
16pub struct HdrTextureLoaderSettings {
17    /// Where the asset will be used - see the docs on [`RenderAssetUsages`] for details.
18    pub asset_usage: RenderAssetUsages,
19}
20
21/// Possible errors that can be produced by [`HdrTextureLoader`]
22#[non_exhaustive]
23#[derive(#[automatically_derived]
impl ::core::fmt::Debug for HdrTextureLoaderError {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            HdrTextureLoaderError::Io(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Io",
                    &__self_0),
            HdrTextureLoaderError::Image(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Image",
                    &__self_0),
        }
    }
}Debug, fn from(source: image::ImageError) -> Self {
    HdrTextureLoaderError::Image { 0: source }
}Error)]
24pub enum HdrTextureLoaderError {
25    /// I/O Error.
26    #[error("Could load texture: {0}")]
27    Io(#[from] std::io::Error),
28    /// Failed to decode the texture.
29    #[error("Could not extract image: {0}")]
30    Image(#[from] image::ImageError),
31}
32
33impl AssetLoader for HdrTextureLoader {
34    type Asset = Image;
35    type Settings = HdrTextureLoaderSettings;
36    type Error = HdrTextureLoaderError;
37    async fn load(
38        &self,
39        reader: &mut dyn Reader,
40        settings: &Self::Settings,
41        _load_context: &mut LoadContext<'_>,
42    ) -> Result<Image, Self::Error> {
43        let format = TextureFormat::Rgba32Float;
44        // `Rgba32Float` will always return a valid pixel size
45        let pixel_size = format.pixel_size().unwrap();
46        if true {
    {
        match (&pixel_size, &(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!(pixel_size, 4 * 4, "Format should have 32bit x 4 size");
47
48        let mut bytes = Vec::new();
49        reader.read_to_end(&mut bytes).await?;
50        let decoder = image::codecs::hdr::HdrDecoder::new(bytes.as_slice())?;
51        let info = decoder.metadata();
52        let dynamic_image = DynamicImage::from_decoder(decoder)?;
53        let image_buffer = dynamic_image
54            .as_rgb32f()
55            .expect("HDR Image format should be Rgb32F");
56        let mut rgba_data = Vec::with_capacity(image_buffer.pixels().len() * pixel_size);
57
58        for rgb in image_buffer.pixels() {
59            let alpha = 1.0f32;
60
61            rgba_data.extend_from_slice(&rgb.0[0].to_le_bytes());
62            rgba_data.extend_from_slice(&rgb.0[1].to_le_bytes());
63            rgba_data.extend_from_slice(&rgb.0[2].to_le_bytes());
64            rgba_data.extend_from_slice(&alpha.to_le_bytes());
65        }
66
67        Ok(Image::new(
68            Extent3d {
69                width: info.width,
70                height: info.height,
71                depth_or_array_layers: 1,
72            },
73            TextureDimension::D2,
74            rgba_data,
75            format,
76            settings.asset_usage,
77        ))
78    }
79
80    fn extensions(&self) -> &[&str] {
81        &["hdr"]
82    }
83}