Skip to main content

bevy_image/
texture_atlas.rs

1use bevy_app::prelude::*;
2use bevy_asset::{Asset, AssetApp as _, AssetId, Assets, Handle};
3use bevy_ecs::template::FromTemplate;
4use bevy_math::{Rect, URect, UVec2};
5use bevy_platform::collections::HashMap;
6#[cfg(not(feature = "bevy_reflect"))]
7use bevy_reflect::TypePath;
8#[cfg(feature = "bevy_reflect")]
9use bevy_reflect::{std_traits::ReflectDefault, Reflect};
10#[cfg(feature = "serialize")]
11use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
12
13use crate::Image;
14
15/// Adds support for texture atlases.
16pub struct TextureAtlasPlugin;
17
18impl Plugin for TextureAtlasPlugin {
19    fn build(&self, app: &mut App) {
20        app.init_asset::<TextureAtlasLayout>();
21
22        #[cfg(feature = "bevy_reflect")]
23        app.register_asset_reflect::<TextureAtlasLayout>();
24    }
25}
26
27/// Stores a mapping from sub texture handles to the related area index.
28///
29/// Generated by [`TextureAtlasBuilder`].
30///
31/// [`TextureAtlasBuilder`]: crate::TextureAtlasBuilder
32#[derive(#[automatically_derived]
impl ::core::fmt::Debug for TextureAtlasSources {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "TextureAtlasSources", "texture_ids", &&self.texture_ids)
    }
}Debug)]
33pub struct TextureAtlasSources {
34    /// Maps from a specific image handle to the index in `textures` where they can be found.
35    pub texture_ids: HashMap<AssetId<Image>, usize>,
36}
37
38impl TextureAtlasSources {
39    /// Retrieves the texture *section* index of the given `texture` handle.
40    pub fn texture_index(&self, texture: impl Into<AssetId<Image>>) -> Option<usize> {
41        let id = texture.into();
42        self.texture_ids.get(&id).cloned()
43    }
44
45    /// Creates a [`TextureAtlas`] handle for the given `texture` handle.
46    pub fn handle(
47        &self,
48        layout: Handle<TextureAtlasLayout>,
49        texture: impl Into<AssetId<Image>>,
50    ) -> Option<TextureAtlas> {
51        Some(TextureAtlas {
52            layout,
53            index: self.texture_index(texture)?,
54        })
55    }
56
57    /// Retrieves the texture *section* rectangle of the given `texture` handle in pixels.
58    pub fn texture_rect(
59        &self,
60        layout: &TextureAtlasLayout,
61        texture: impl Into<AssetId<Image>>,
62    ) -> Option<URect> {
63        layout.textures.get(self.texture_index(texture)?).cloned()
64    }
65
66    /// Retrieves the texture *section* rectangle of the given `texture` handle in UV coordinates.
67    /// These are within the range [0..1], as a fraction of the entire texture atlas' size.
68    pub fn uv_rect(
69        &self,
70        layout: &TextureAtlasLayout,
71        texture: impl Into<AssetId<Image>>,
72    ) -> Option<Rect> {
73        self.texture_rect(layout, texture).map(|rect| {
74            let rect = rect.as_rect();
75            let size = layout.size.as_vec2();
76            Rect::from_corners(rect.min / size, rect.max / size)
77        })
78    }
79}
80
81/// Stores a map used to lookup the position of a texture in a [`TextureAtlas`].
82/// This can be used to either use and look up a specific section of a texture, or animate frame-by-frame as a sprite sheet.
83///
84/// Optionally it can store a mapping from sub texture handles to the related area index (see
85/// [`TextureAtlasBuilder`]).
86///
87/// [Example usage animating sprite.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs)
88/// [Example usage animating sprite in response to an event.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_animation.rs)
89/// [Example usage loading sprite sheet.](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs)
90///
91/// [`TextureAtlasBuilder`]: crate::TextureAtlasBuilder
92#[derive(impl bevy_asset::VisitAssetDependencies for TextureAtlasLayout {
    fn visit_dependencies(&self,
        visit: &mut impl ::core::ops::FnMut(bevy_asset::UntypedAssetId)) {}
}Asset, #[automatically_derived]
impl ::core::cmp::PartialEq for TextureAtlasLayout {
    #[inline]
    fn eq(&self, other: &TextureAtlasLayout) -> bool {
        self.size == other.size && self.textures == other.textures
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TextureAtlasLayout {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<UVec2>;
        let _: ::core::cmp::AssertParamIsEq<Vec<URect>>;
    }
}Eq, #[automatically_derived]
impl ::core::fmt::Debug for TextureAtlasLayout {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f,
            "TextureAtlasLayout", "size", &self.size, "textures",
            &&self.textures)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TextureAtlasLayout {
    #[inline]
    fn clone(&self) -> TextureAtlasLayout {
        TextureAtlasLayout {
            size: ::core::clone::Clone::clone(&self.size),
            textures: ::core::clone::Clone::clone(&self.textures),
        }
    }
}Clone)]
93#[cfg_attr(
94    feature = "bevy_reflect",
95    derive(const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for TextureAtlasLayout where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectSerialize, Self>();
                registration.register_type_data::<ReflectDeserialize, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <UVec2 as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <Vec<URect> as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for TextureAtlasLayout where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<UVec2>("size"),
                                                bevy_reflect::NamedField::new::<Vec<URect>>("textures")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for TextureAtlasLayout where  {
            fn type_path() -> &'static str {
                "bevy_image::texture_atlas::TextureAtlasLayout"
            }
            fn short_type_path() -> &'static str { "TextureAtlasLayout" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("TextureAtlasLayout")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::texture_atlas".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::texture_atlas")
            }
        }
        impl bevy_reflect::Reflect for TextureAtlasLayout where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        #[allow(non_upper_case_globals)]
        const _: () =
            {
                static __INVENTORY: ::inventory::Node =
                    ::inventory::Node {
                        value: &{
                                bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<TextureAtlasLayout
                                        as
                                        bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
                            },
                        next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
                    };
                #[link_section = ".text.startup"]
                unsafe extern "C" fn __ctor() {
                    unsafe {
                        ::inventory::ErasedNode::submit(__INVENTORY.value,
                            &__INVENTORY)
                    }
                }
                #[used]
                #[link_section = ".init_array"]
                static __CTOR: unsafe extern "C" fn() = __ctor;
            };
        impl bevy_reflect::structs::Struct for TextureAtlasLayout where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "size" => ::core::option::Option::Some(&self.size),
                    "textures" => ::core::option::Option::Some(&self.textures),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "size" => ::core::option::Option::Some(&mut self.size),
                    "textures" =>
                        ::core::option::Option::Some(&mut self.textures),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.size),
                    1usize => ::core::option::Option::Some(&self.textures),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.size),
                    1usize => ::core::option::Option::Some(&mut self.textures),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("size"),
                    1usize => ::core::option::Option::Some("textures"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "size" => ::core::option::Option::Some(0usize),
                    "textures" => ::core::option::Option::Some(1usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 2usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("size",
                    bevy_reflect::PartialReflect::to_dynamic(&self.size));
                dynamic.insert_boxed("textures",
                    bevy_reflect::PartialReflect::to_dynamic(&self.textures));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for TextureAtlasLayout where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                let value =
                    <dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
                if let ::core::option::Option::Some(value) = value {
                    ::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
                            value))
                } else { ::core::option::Option::Some(false) }
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
                -> ::core::fmt::Result {
                ::core::fmt::Debug::fmt(self, f)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for TextureAtlasLayout where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let __this =
                        Self {
                            size: <UVec2 as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "size")?)?,
                            textures: <Vec<URect> as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "textures")?)?,
                        };
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect),
96    reflect(Debug, PartialEq, Clone)
97)]
98#[cfg_attr(
99    feature = "serialize",
100    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 TextureAtlasLayout {
            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,
                            "TextureAtlasLayout", false as usize + 1 + 1)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "size", &self.size)?;
                _serde::ser::SerializeStruct::serialize_field(&mut __serde_state,
                        "textures", &self.textures)?;
                _serde::ser::SerializeStruct::end(__serde_state)
            }
        }
    };serde::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 TextureAtlasLayout {
            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, __field1, __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),
                            1u64 => _serde::__private228::Ok(__Field::__field1),
                            _ => _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 {
                            "size" => _serde::__private228::Ok(__Field::__field0),
                            "textures" => _serde::__private228::Ok(__Field::__field1),
                            _ => { _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"size" => _serde::__private228::Ok(__Field::__field0),
                            b"textures" => _serde::__private228::Ok(__Field::__field1),
                            _ => { _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<TextureAtlasLayout>,
                    lifetime: _serde::__private228::PhantomData<&'de ()>,
                }
                #[automatically_derived]
                impl<'de> _serde::de::Visitor<'de> for __Visitor<'de> {
                    type Value = TextureAtlasLayout;
                    fn expecting(&self,
                        __formatter: &mut _serde::__private228::Formatter)
                        -> _serde::__private228::fmt::Result {
                        _serde::__private228::Formatter::write_str(__formatter,
                            "struct TextureAtlasLayout")
                    }
                    #[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::<UVec2>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(0usize,
                                                &"struct TextureAtlasLayout with 2 elements")),
                            };
                        let __field1 =
                            match _serde::de::SeqAccess::next_element::<Vec<URect>>(&mut __seq)?
                                {
                                _serde::__private228::Some(__value) => __value,
                                _serde::__private228::None =>
                                    return _serde::__private228::Err(_serde::de::Error::invalid_length(1usize,
                                                &"struct TextureAtlasLayout with 2 elements")),
                            };
                        _serde::__private228::Ok(TextureAtlasLayout {
                                size: __field0,
                                textures: __field1,
                            })
                    }
                    #[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<UVec2> =
                            _serde::__private228::None;
                        let mut __field1: _serde::__private228::Option<Vec<URect>> =
                            _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("size"));
                                    }
                                    __field0 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<UVec2>(&mut __map)?);
                                }
                                __Field::__field1 => {
                                    if _serde::__private228::Option::is_some(&__field1) {
                                        return _serde::__private228::Err(<__A::Error as
                                                        _serde::de::Error>::duplicate_field("textures"));
                                    }
                                    __field1 =
                                        _serde::__private228::Some(_serde::de::MapAccess::next_value::<Vec<URect>>(&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("size")?,
                            };
                        let __field1 =
                            match __field1 {
                                _serde::__private228::Some(__field1) => __field1,
                                _serde::__private228::None =>
                                    _serde::__private228::de::missing_field("textures")?,
                            };
                        _serde::__private228::Ok(TextureAtlasLayout {
                                size: __field0,
                                textures: __field1,
                            })
                    }
                }
                #[doc(hidden)]
                const FIELDS: &'static [&'static str] = &["size", "textures"];
                _serde::Deserializer::deserialize_struct(__deserializer,
                    "TextureAtlasLayout", FIELDS,
                    __Visitor {
                        marker: _serde::__private228::PhantomData::<TextureAtlasLayout>,
                        lifetime: _serde::__private228::PhantomData,
                    })
            }
        }
    };serde::Deserialize),
101    reflect(Serialize, Deserialize)
102)]
103#[cfg_attr(not(feature = "bevy_reflect"), derive(TypePath))]
104pub struct TextureAtlasLayout {
105    /// Total size of texture atlas.
106    pub size: UVec2,
107    /// The specific areas of the atlas where each texture can be found
108    pub textures: Vec<URect>,
109}
110
111impl TextureAtlasLayout {
112    /// Create a new empty layout with custom `dimensions`
113    pub fn new_empty(dimensions: UVec2) -> Self {
114        Self {
115            size: dimensions,
116            textures: Vec::new(),
117        }
118    }
119
120    /// Generate a [`TextureAtlasLayout`] as a grid where each
121    /// `tile_size` by `tile_size` grid-cell is one of the *section* in the
122    /// atlas. Grid cells are separated by some `padding`, and the grid starts
123    /// at `offset` pixels from the top left corner. Resulting layout is
124    /// indexed left to right, top to bottom.
125    ///
126    /// # Arguments
127    ///
128    /// * `tile_size` - Each layout grid cell size
129    /// * `columns` - Grid column count
130    /// * `rows` - Grid row count
131    /// * `padding` - Optional padding between cells
132    /// * `offset` - Optional global grid offset
133    pub fn from_grid(
134        tile_size: UVec2,
135        columns: u32,
136        rows: u32,
137        padding: Option<UVec2>,
138        offset: Option<UVec2>,
139    ) -> Self {
140        let padding = padding.unwrap_or_default();
141        let offset = offset.unwrap_or_default();
142        let mut sprites = Vec::new();
143        let mut current_padding = UVec2::ZERO;
144
145        for y in 0..rows {
146            if y > 0 {
147                current_padding.y = padding.y;
148            }
149            for x in 0..columns {
150                if x > 0 {
151                    current_padding.x = padding.x;
152                }
153
154                let cell = UVec2::new(x, y);
155                let rect_min = (tile_size + current_padding) * cell + offset;
156
157                sprites.push(URect {
158                    min: rect_min,
159                    max: rect_min + tile_size,
160                });
161            }
162        }
163
164        let grid_size = UVec2::new(columns, rows);
165
166        Self {
167            size: ((tile_size + current_padding) * grid_size) - current_padding,
168            textures: sprites,
169        }
170    }
171
172    /// Add a *section* to the list in the layout and returns its index
173    /// which can be used with [`TextureAtlas`]
174    ///
175    /// # Arguments
176    ///
177    /// * `rect` - The section of the texture to be added
178    ///
179    /// [`TextureAtlas`]: crate::TextureAtlas
180    pub fn add_texture(&mut self, rect: URect) -> usize {
181        self.textures.push(rect);
182        self.textures.len() - 1
183    }
184
185    /// The number of textures in the [`TextureAtlasLayout`]
186    pub fn len(&self) -> usize {
187        self.textures.len()
188    }
189
190    /// Returns `true` if the atlas contains no textures.
191    pub fn is_empty(&self) -> bool {
192        self.textures.is_empty()
193    }
194}
195
196/// An index into a [`TextureAtlasLayout`], which corresponds to a specific section of a texture.
197///
198/// It stores a handle to [`TextureAtlasLayout`] and the index of the current section of the atlas.
199/// The texture atlas contains various *sections* of a given texture, allowing users to have a single
200/// image file for either sprite animation or global mapping.
201/// You can change the texture [`index`](Self::index) of the atlas to animate the sprite or display only a *section* of the texture
202/// for efficient rendering of related game objects.
203///
204/// Check the following examples for usage:
205/// - [`animated sprite sheet example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_sheet.rs)
206/// - [`sprite animation event example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/sprite_animation.rs)
207/// - [`texture atlas example`](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs)
208#[derive(#[automatically_derived]
impl ::core::default::Default for TextureAtlas {
    #[inline]
    fn default() -> TextureAtlas {
        TextureAtlas {
            layout: ::core::default::Default::default(),
            index: ::core::default::Default::default(),
        }
    }
}Default, #[automatically_derived]
impl ::core::fmt::Debug for TextureAtlas {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "TextureAtlas",
            "layout", &self.layout, "index", &&self.index)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for TextureAtlas {
    #[inline]
    fn clone(&self) -> TextureAtlas {
        TextureAtlas {
            layout: ::core::clone::Clone::clone(&self.layout),
            index: ::core::clone::Clone::clone(&self.index),
        }
    }
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for TextureAtlas {
    #[inline]
    fn eq(&self, other: &TextureAtlas) -> bool {
        self.layout == other.layout && self.index == other.index
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TextureAtlas {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Handle<TextureAtlasLayout>>;
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for TextureAtlas {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.layout, state);
        ::core::hash::Hash::hash(&self.index, state)
    }
}Hash, impl ::core::default::Default for TextureAtlasTemplate {
    fn default() -> Self {
        Self {
            layout: ::core::default::Default::default(),
            index: ::core::default::Default::default(),
        }
    }
}FromTemplate)]
209#[cfg_attr(
210    feature = "bevy_reflect",
211    derive(const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for TextureAtlas where  {
            fn get_type_registration() -> bevy_reflect::TypeRegistration {
                let mut registration =
                    bevy_reflect::TypeRegistration::of::<Self>();
                registration.insert::<bevy_reflect::ReflectFromPtr>(bevy_reflect::FromType::<Self>::from_type());
                registration.insert::<bevy_reflect::ReflectFromReflect>(bevy_reflect::FromType::<Self>::from_type());
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <Handle<TextureAtlasLayout> as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <usize as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for TextureAtlas where  {
            #[inline]
            fn type_info() -> &'static bevy_reflect::TypeInfo {
                static CELL: bevy_reflect::utility::NonGenericTypeInfoCell =
                    bevy_reflect::utility::NonGenericTypeInfoCell::new();
                CELL.get_or_set(||
                        {
                            bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<Handle<TextureAtlasLayout>>("layout"),
                                                bevy_reflect::NamedField::new::<usize>("index")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for TextureAtlas where  {
            fn type_path() -> &'static str {
                "bevy_image::texture_atlas::TextureAtlas"
            }
            fn short_type_path() -> &'static str { "TextureAtlas" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("TextureAtlas")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::texture_atlas".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_image::texture_atlas")
            }
        }
        impl bevy_reflect::Reflect for TextureAtlas where  {
            #[inline]
            fn into_any(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
                self
            }
            #[inline]
            fn as_any(&self) -> &dyn ::core::any::Any { self }
            #[inline]
            fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
            #[inline]
            fn into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
                self
            }
            #[inline]
            fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
            #[inline]
            fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
                self
            }
            #[inline]
            fn set(&mut self,
                value:
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
                ->
                    ::core::result::Result<(),
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
                *self = <dyn bevy_reflect::Reflect>::take(value)?;
                ::core::result::Result::Ok(())
            }
        }
        #[allow(non_upper_case_globals)]
        const _: () =
            {
                static __INVENTORY: ::inventory::Node =
                    ::inventory::Node {
                        value: &{
                                bevy_reflect::__macro_exports::auto_register::AutomaticReflectRegistrations(<TextureAtlas
                                        as
                                        bevy_reflect::__macro_exports::auto_register::RegisterForReflection>::__register)
                            },
                        next: ::inventory::__private::UnsafeCell::new(::inventory::__private::Option::None),
                    };
                #[link_section = ".text.startup"]
                unsafe extern "C" fn __ctor() {
                    unsafe {
                        ::inventory::ErasedNode::submit(__INVENTORY.value,
                            &__INVENTORY)
                    }
                }
                #[used]
                #[link_section = ".init_array"]
                static __CTOR: unsafe extern "C" fn() = __ctor;
            };
        impl bevy_reflect::structs::Struct for TextureAtlas where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "layout" => ::core::option::Option::Some(&self.layout),
                    "index" => ::core::option::Option::Some(&self.index),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "layout" => ::core::option::Option::Some(&mut self.layout),
                    "index" => ::core::option::Option::Some(&mut self.index),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&self.layout),
                    1usize => ::core::option::Option::Some(&self.index),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index {
                    0usize => ::core::option::Option::Some(&mut self.layout),
                    1usize => ::core::option::Option::Some(&mut self.index),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("layout"),
                    1usize => ::core::option::Option::Some("index"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "layout" => ::core::option::Option::Some(0usize),
                    "index" => ::core::option::Option::Some(1usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 2usize }
            fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
                bevy_reflect::structs::FieldIter::new(self)
            }
            fn to_dynamic_struct(&self)
                -> bevy_reflect::structs::DynamicStruct {
                let mut dynamic: bevy_reflect::structs::DynamicStruct =
                    ::core::default::Default::default();
                dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
                dynamic.insert_boxed("layout",
                    bevy_reflect::PartialReflect::to_dynamic(&self.layout));
                dynamic.insert_boxed("index",
                    bevy_reflect::PartialReflect::to_dynamic(&self.index));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for TextureAtlas where  {
            #[inline]
            fn get_represented_type_info(&self)
                -> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
                ::core::option::Option::Some(<Self as
                            bevy_reflect::Typed>::type_info())
            }
            #[inline]
            fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Struct(struct_value) =
                        bevy_reflect::PartialReflect::reflect_ref(value) {
                    for (name, value) in
                        bevy_reflect::structs::Struct::iter_fields(struct_value) {
                        if let ::core::option::Option::Some(v) =
                                bevy_reflect::structs::Struct::field_mut(self, name) {
                            bevy_reflect::PartialReflect::try_apply(v, value)?;
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
                                to_kind: bevy_reflect::ReflectKind::Struct,
                            });
                }
                ::core::result::Result::Ok(())
            }
            #[inline]
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Struct
            }
            #[inline]
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Struct(self)
            }
            #[inline]
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Struct(self)
            }
            #[inline]
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Struct(self)
            }
            #[inline]
            fn try_into_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
                ::core::result::Result::Ok(self)
            }
            #[inline]
            fn try_as_reflect(&self)
                -> ::core::option::Option<&dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn try_as_reflect_mut(&mut self)
                -> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
                ::core::option::Option::Some(self)
            }
            #[inline]
            fn into_partial_reflect(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                ->
                    bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
                self
            }
            #[inline]
            fn as_partial_reflect(&self)
                -> &dyn bevy_reflect::PartialReflect {
                self
            }
            #[inline]
            fn as_partial_reflect_mut(&mut self)
                -> &mut dyn bevy_reflect::PartialReflect {
                self
            }
            fn reflect_hash(&self) -> ::core::option::Option<u64> {
                use ::core::hash::{Hash, Hasher};
                let mut hasher = bevy_reflect::utility::reflect_hasher();
                Hash::hash(&::core::any::Any::type_id(self), &mut hasher);
                Hash::hash(self, &mut hasher);
                ::core::option::Option::Some(Hasher::finish(&hasher))
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                let value =
                    <dyn bevy_reflect::PartialReflect>::try_downcast_ref::<Self>(value);
                if let ::core::option::Option::Some(value) = value {
                    ::core::option::Option::Some(::core::cmp::PartialEq::eq(self,
                            value))
                } else { ::core::option::Option::Some(false) }
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            fn debug(&self, f: &mut ::core::fmt::Formatter<'_>)
                -> ::core::fmt::Result {
                ::core::fmt::Debug::fmt(self, f)
            }
            #[inline]
            fn reflect_clone(&self)
                ->
                    ::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
                    bevy_reflect::ReflectCloneError> {
                ::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
            }
        }
        impl bevy_reflect::FromReflect for TextureAtlas where  {
            fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
                        bevy_reflect::PartialReflect::reflect_ref(reflect) {
                    let mut __this =
                        <Self as ::core::default::Default>::default();
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <Handle<TextureAtlasLayout> as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "layout")?))() {
                        __this.layout = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <usize as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "index")?))() {
                        __this.index = __field;
                    }
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect),
212    reflect(Default, Debug, PartialEq, Hash, Clone)
213)]
214pub struct TextureAtlas {
215    /// Texture atlas layout handle
216    pub layout: Handle<TextureAtlasLayout>,
217    /// Texture atlas section index
218    pub index: usize,
219}
220
221impl TextureAtlas {
222    /// Retrieves the current texture [`URect`] of the sprite sheet according to the section `index`
223    pub fn texture_rect(&self, texture_atlases: &Assets<TextureAtlasLayout>) -> Option<URect> {
224        let atlas = texture_atlases.get(&self.layout)?;
225        atlas.textures.get(self.index).copied()
226    }
227
228    /// Returns this [`TextureAtlas`] with the specified index.
229    pub fn with_index(mut self, index: usize) -> Self {
230        self.index = index;
231        self
232    }
233
234    /// Returns this [`TextureAtlas`] with the specified [`TextureAtlasLayout`] handle.
235    pub fn with_layout(mut self, layout: Handle<TextureAtlasLayout>) -> Self {
236        self.layout = layout;
237        self
238    }
239}
240
241impl From<Handle<TextureAtlasLayout>> for TextureAtlas {
242    fn from(texture_atlas: Handle<TextureAtlasLayout>) -> Self {
243        Self {
244            layout: texture_atlas,
245            index: 0,
246        }
247    }
248}