Skip to main content

bevy_sprite/
picking_backend.rs

1//! A [`bevy_picking`] backend for sprites. Works for simple sprites and sprite atlases. Works for
2//! sprites with arbitrary transforms.
3//!
4//! By default, picking for sprites is based on pixel opacity.
5//! A sprite is picked only when a pointer is over an opaque pixel.
6//! Alternatively, you can configure picking to be based on sprite bounds.
7//!
8//! ## Implementation Notes
9//!
10//! - The `position` reported in `HitData` in world space, and the `normal` is a normalized
11//!   vector provided by the target's `GlobalTransform::back()`.
12
13use crate::{Anchor, Sprite};
14use bevy_app::prelude::*;
15use bevy_asset::prelude::*;
16use bevy_camera::{
17    visibility::{RenderLayers, ViewVisibility},
18    Camera, Projection, RenderTarget,
19};
20use bevy_color::Alpha;
21use bevy_ecs::prelude::*;
22use bevy_image::{prelude::*, TextureAccessError};
23use bevy_log::warn;
24use bevy_math::{prelude::*, FloatExt};
25use bevy_picking::backend::prelude::*;
26use bevy_reflect::prelude::*;
27use bevy_transform::prelude::*;
28use bevy_window::PrimaryWindow;
29
30/// An optional component that marks cameras that should be used in the [`SpritePickingPlugin`].
31///
32/// Only needed if [`SpritePickingSettings::require_markers`] is set to `true`, and ignored
33/// otherwise.
34#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SpritePickingCamera {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f, "SpritePickingCamera")
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SpritePickingCamera {
    #[inline]
    fn clone(&self) -> SpritePickingCamera { SpritePickingCamera }
}Clone, #[automatically_derived]
impl ::core::default::Default for SpritePickingCamera {
    #[inline]
    fn default() -> SpritePickingCamera { SpritePickingCamera {} }
}Default, impl bevy_ecs::component::Component for SpritePickingCamera where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {
    const STORAGE_TYPE: bevy_ecs::component::StorageType =
        bevy_ecs::component::StorageType::Table;
    type Mutability = bevy_ecs::component::Mutable;
    fn register_required_components(_requiree:
            bevy_ecs::component::ComponentId,
        required_components:
            &mut bevy_ecs::component::RequiredComponentsRegistrator) {}
    fn clone_behavior() -> bevy_ecs::component::ComponentCloneBehavior {
        use bevy_ecs::component::{
            DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone,
        };
        (&&&bevy_ecs::component::DefaultCloneBehaviorSpecialization::<Self>::default()).default_clone_behavior()
    }
    fn relationship_accessor()
        ->
            ::core::option::Option<bevy_ecs::relationship::ComponentRelationshipAccessor<Self>> {
        ::core::option::Option::None
    }
}Component, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for SpritePickingCamera 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.register_type_data::<ReflectComponent, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {}
        }
        impl bevy_reflect::Typed for SpritePickingCamera 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>(&[]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for SpritePickingCamera where  {
            fn type_path() -> &'static str {
                "bevy_sprite::picking_backend::SpritePickingCamera"
            }
            fn short_type_path() -> &'static str { "SpritePickingCamera" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("SpritePickingCamera")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_sprite::picking_backend".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_sprite::picking_backend")
            }
        }
        impl bevy_reflect::Reflect for SpritePickingCamera 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(<SpritePickingCamera
                                        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 SpritePickingCamera where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_at(&self, index: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match index { _ => ::core::option::Option::None, }
            }
            fn field_at_mut(&mut self, index: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match index { _ => ::core::option::Option::None, }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index { _ => ::core::option::Option::None, }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name { _ => ::core::option::Option::None, }
            }
            fn field_len(&self) -> usize { 0usize }
            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
            }
        }
        impl bevy_reflect::PartialReflect for SpritePickingCamera 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> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            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 SpritePickingCamera 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();
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
35#[reflect(Debug, Default, Component, Clone)]
36pub struct SpritePickingCamera;
37
38/// How should the [`SpritePickingPlugin`] handle picking and how should it handle transparent pixels
39#[derive(#[automatically_derived]
impl ::core::fmt::Debug for SpritePickingMode {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            SpritePickingMode::BoundingBox =>
                ::core::fmt::Formatter::write_str(f, "BoundingBox"),
            SpritePickingMode::AlphaThreshold(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "AlphaThreshold", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SpritePickingMode {
    #[inline]
    fn clone(&self) -> SpritePickingMode {
        let _: ::core::clone::AssertParamIsClone<f32>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SpritePickingMode { }Copy, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for SpritePickingMode 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
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <f32 as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for SpritePickingMode 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::Enum(bevy_reflect::enums::EnumInfo::new::<Self>(&[bevy_reflect::enums::VariantInfo::Unit(bevy_reflect::enums::UnitVariantInfo::new("BoundingBox")),
                                                bevy_reflect::enums::VariantInfo::Tuple(bevy_reflect::enums::TupleVariantInfo::new("AlphaThreshold",
                                                        &[bevy_reflect::UnnamedField::new::<f32>(0usize)]))]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for SpritePickingMode where  {
            fn type_path() -> &'static str {
                "bevy_sprite::picking_backend::SpritePickingMode"
            }
            fn short_type_path() -> &'static str { "SpritePickingMode" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("SpritePickingMode")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_sprite::picking_backend".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_sprite::picking_backend")
            }
        }
        impl bevy_reflect::Reflect for SpritePickingMode 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(<SpritePickingMode
                                        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::enums::Enum for SpritePickingMode where  {
            fn field(&self, __name_param: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match self { _ => ::core::option::Option::None, }
            }
            fn field_at(&self, __index_param: usize)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match self {
                    SpritePickingMode::AlphaThreshold { 0: __value, .. } if
                        __index_param == 0usize =>
                        ::core::option::Option::Some(__value),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, __name_param: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match self { _ => ::core::option::Option::None, }
            }
            fn field_at_mut(&mut self, __index_param: usize)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match self {
                    SpritePickingMode::AlphaThreshold { 0: __value, .. } if
                        __index_param == 0usize =>
                        ::core::option::Option::Some(__value),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of(&self, __name_param: &str)
                -> ::core::option::Option<usize> {
                match self { _ => ::core::option::Option::None, }
            }
            fn name_at(&self, __index_param: usize)
                -> ::core::option::Option<&str> {
                match self { _ => ::core::option::Option::None, }
            }
            fn iter_fields(&self) -> bevy_reflect::enums::VariantFieldIter {
                bevy_reflect::enums::VariantFieldIter::new(self)
            }
            #[inline]
            fn field_len(&self) -> usize {
                match self {
                    SpritePickingMode::BoundingBox { .. } => 0usize,
                    SpritePickingMode::AlphaThreshold { .. } => 1usize,
                    _ => 0,
                }
            }
            #[inline]
            fn variant_name(&self) -> &str {
                match self {
                    SpritePickingMode::BoundingBox { .. } => "BoundingBox",
                    SpritePickingMode::AlphaThreshold { .. } =>
                        "AlphaThreshold",
                    _ =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }
            }
            #[inline]
            fn variant_index(&self) -> usize {
                match self {
                    SpritePickingMode::BoundingBox { .. } => 0usize,
                    SpritePickingMode::AlphaThreshold { .. } => 1usize,
                    _ =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }
            }
            #[inline]
            fn variant_type(&self) -> bevy_reflect::enums::VariantType {
                match self {
                    SpritePickingMode::BoundingBox { .. } =>
                        bevy_reflect::enums::VariantType::Unit,
                    SpritePickingMode::AlphaThreshold { .. } =>
                        bevy_reflect::enums::VariantType::Tuple,
                    _ =>
                        ::core::panicking::panic("internal error: entered unreachable code"),
                }
            }
            fn to_dynamic_enum(&self) -> bevy_reflect::enums::DynamicEnum {
                bevy_reflect::enums::DynamicEnum::from_ref::<Self>(self)
            }
        }
        impl bevy_reflect::PartialReflect for SpritePickingMode 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_param: &dyn bevy_reflect::PartialReflect)
                -> ::core::result::Result<(), bevy_reflect::ApplyError> {
                if let bevy_reflect::ReflectRef::Enum(__value_param) =
                        bevy_reflect::PartialReflect::reflect_ref(__value_param) {
                    if bevy_reflect::enums::Enum::variant_name(self) ==
                            bevy_reflect::enums::Enum::variant_name(__value_param) {
                        match bevy_reflect::enums::Enum::variant_type(__value_param)
                            {
                            bevy_reflect::enums::VariantType::Struct => {
                                for field in
                                    bevy_reflect::enums::Enum::iter_fields(__value_param) {
                                    let name = field.name().unwrap();
                                    if let ::core::option::Option::Some(v) =
                                            bevy_reflect::enums::Enum::field_mut(self, name) {
                                        bevy_reflect::PartialReflect::try_apply(v, field.value())?;
                                    }
                                }
                            }
                            bevy_reflect::enums::VariantType::Tuple => {
                                for (index, field) in
                                    ::core::iter::Iterator::enumerate(bevy_reflect::enums::Enum::iter_fields(__value_param))
                                    {
                                    if let ::core::option::Option::Some(v) =
                                            bevy_reflect::enums::Enum::field_at_mut(self, index) {
                                        bevy_reflect::PartialReflect::try_apply(v, field.value())?;
                                    }
                                }
                            }
                            _ => {}
                        }
                    } else {
                        match bevy_reflect::enums::Enum::variant_name(__value_param)
                            {
                            "BoundingBox" => {
                                *self = SpritePickingMode::BoundingBox {}
                            }
                            "AlphaThreshold" => {
                                *self =
                                    SpritePickingMode::AlphaThreshold {
                                        0: {
                                            let __0 = __value_param.field_at(0usize);
                                            let __0 =
                                                __0.ok_or(bevy_reflect::ApplyError::MissingEnumField {
                                                            variant_name: ::core::convert::Into::into("AlphaThreshold"),
                                                            field_name: ::core::convert::Into::into(".0"),
                                                        })?;
                                            <f32 as
                                                            bevy_reflect::FromReflect>::from_reflect(__0).ok_or(bevy_reflect::ApplyError::MismatchedTypes {
                                                        from_type: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(__0)),
                                                        to_type: ::core::convert::Into::into(<f32 as
                                                                    bevy_reflect::TypePath>::type_path()),
                                                    })?
                                        },
                                    }
                            }
                            name => {
                                return ::core::result::Result::Err(bevy_reflect::ApplyError::UnknownVariant {
                                            enum_name: ::core::convert::Into::into(bevy_reflect::DynamicTypePath::reflect_type_path(self)),
                                            variant_name: ::core::convert::Into::into(name),
                                        });
                            }
                        }
                    }
                } else {
                    return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
                                from_kind: bevy_reflect::PartialReflect::reflect_kind(__value_param),
                                to_kind: bevy_reflect::ReflectKind::Enum,
                            });
                }
                ::core::result::Result::Ok(())
            }
            fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
                bevy_reflect::ReflectKind::Enum
            }
            fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
                bevy_reflect::ReflectRef::Enum(self)
            }
            fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
                bevy_reflect::ReflectMut::Enum(self)
            }
            fn reflect_owned(self:
                    bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
                -> bevy_reflect::ReflectOwned {
                bevy_reflect::ReflectOwned::Enum(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> {
                (bevy_reflect::enums::enum_hash)(self)
            }
            fn reflect_partial_eq(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<bool> {
                (bevy_reflect::enums::enum_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::enums::enum_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 SpritePickingMode where  {
            fn from_reflect(__param0: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<Self> {
                if let bevy_reflect::ReflectRef::Enum(__param0) =
                        bevy_reflect::PartialReflect::reflect_ref(__param0) {
                    match bevy_reflect::enums::Enum::variant_name(__param0) {
                        "BoundingBox" =>
                            ::core::option::Option::Some(SpritePickingMode::BoundingBox {}),
                        "AlphaThreshold" =>
                            ::core::option::Option::Some(SpritePickingMode::AlphaThreshold {
                                    0: {
                                        let __0 = __param0.field_at(0usize);
                                        let __0 = __0?;
                                        <f32 as bevy_reflect::FromReflect>::from_reflect(__0)?
                                    },
                                }),
                        name => ::core::option::Option::None,
                    }
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
40#[reflect(Debug, Clone)]
41pub enum SpritePickingMode {
42    /// Even if a sprite is picked on a transparent pixel, it should still count within the backend.
43    /// Only consider the rect of a given sprite.
44    BoundingBox,
45    /// Ignore any part of a sprite which has a lower alpha value than the threshold (inclusive)
46    /// Threshold is given as an f32 representing the alpha value in a Bevy Color Value
47    AlphaThreshold(f32),
48}
49
50/// Runtime settings for the [`SpritePickingPlugin`].
51#[derive(impl bevy_ecs::resource::Resource for SpritePickingSettings where
    Self: ::core::marker::Send + ::core::marker::Sync + 'static {}Resource, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for SpritePickingSettings 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::<ReflectResource, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <bool as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <SpritePickingMode as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for SpritePickingSettings 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::<bool>("require_markers"),
                                                bevy_reflect::NamedField::new::<SpritePickingMode>("picking_mode")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for SpritePickingSettings where  {
            fn type_path() -> &'static str {
                "bevy_sprite::picking_backend::SpritePickingSettings"
            }
            fn short_type_path() -> &'static str { "SpritePickingSettings" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("SpritePickingSettings")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_sprite::picking_backend".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_sprite::picking_backend")
            }
        }
        impl bevy_reflect::Reflect for SpritePickingSettings 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(<SpritePickingSettings
                                        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 SpritePickingSettings where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "require_markers" =>
                        ::core::option::Option::Some(&self.require_markers),
                    "picking_mode" =>
                        ::core::option::Option::Some(&self.picking_mode),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "require_markers" =>
                        ::core::option::Option::Some(&mut self.require_markers),
                    "picking_mode" =>
                        ::core::option::Option::Some(&mut self.picking_mode),
                    _ => ::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.require_markers),
                    1usize => ::core::option::Option::Some(&self.picking_mode),
                    _ => ::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.require_markers),
                    1usize =>
                        ::core::option::Option::Some(&mut self.picking_mode),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("require_markers"),
                    1usize => ::core::option::Option::Some("picking_mode"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "require_markers" => ::core::option::Option::Some(0usize),
                    "picking_mode" => ::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("require_markers",
                    bevy_reflect::PartialReflect::to_dynamic(&self.require_markers));
                dynamic.insert_boxed("picking_mode",
                    bevy_reflect::PartialReflect::to_dynamic(&self.picking_mode));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for SpritePickingSettings 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> {
                (bevy_reflect::structs::struct_partial_eq)(self, value)
            }
            fn reflect_partial_cmp(&self,
                value: &dyn bevy_reflect::PartialReflect)
                -> ::core::option::Option<::core::cmp::Ordering> {
                (bevy_reflect::structs::struct_partial_cmp)(self, value)
            }
            #[inline]
            #[allow(unreachable_code, reason =
            "Ignored fields without a `clone` attribute will early-return with an error")]
            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(Self {
                            require_markers: <bool as
                                        bevy_reflect::PartialReflect>::reflect_clone_and_take(&self.require_markers)?,
                            picking_mode: <SpritePickingMode as
                                        bevy_reflect::PartialReflect>::reflect_clone_and_take(&self.picking_mode)?,
                        }))
            }
        }
        impl bevy_reflect::FromReflect for SpritePickingSettings 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) =
                            (||
                                        <bool as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "require_markers")?))() {
                        __this.require_markers = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <SpritePickingMode as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "picking_mode")?))() {
                        __this.picking_mode = __field;
                    }
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
52#[reflect(Resource, Default)]
53pub struct SpritePickingSettings {
54    /// When set to `true` sprite picking will only consider cameras marked with
55    /// [`SpritePickingCamera`]. Defaults to `false`.
56    /// Regardless of this setting, only sprites marked with [`Pickable`] will be considered.
57    ///
58    /// This setting is provided to give you fine-grained control over which cameras
59    /// should be used by the sprite picking backend at runtime.
60    pub require_markers: bool,
61    /// Should the backend count transparent pixels as part of the sprite for picking purposes or should it use the bounding box of the sprite alone.
62    ///
63    /// Defaults to an inclusive alpha threshold of 0.1
64    pub picking_mode: SpritePickingMode,
65}
66
67impl Default for SpritePickingSettings {
68    fn default() -> Self {
69        Self {
70            require_markers: false,
71            picking_mode: SpritePickingMode::AlphaThreshold(0.1),
72        }
73    }
74}
75
76/// Enables the sprite picking backend, allowing you to click on, hover over and drag sprites.
77#[derive(#[automatically_derived]
impl ::core::clone::Clone for SpritePickingPlugin {
    #[inline]
    fn clone(&self) -> SpritePickingPlugin { SpritePickingPlugin }
}Clone)]
78pub struct SpritePickingPlugin;
79
80impl Plugin for SpritePickingPlugin {
81    fn build(&self, app: &mut App) {
82        app.init_resource::<SpritePickingSettings>()
83            .add_systems(PreUpdate, sprite_picking.in_set(PickingSystems::Backend));
84    }
85}
86
87fn sprite_picking(
88    pointers: Query<(&PointerId, &PointerLocation)>,
89    cameras: Query<(
90        Entity,
91        &Camera,
92        &RenderTarget,
93        &GlobalTransform,
94        &Projection,
95        Has<SpritePickingCamera>,
96        Option<&RenderLayers>,
97    )>,
98    primary_window: Query<Entity, With<PrimaryWindow>>,
99    images: Res<Assets<Image>>,
100    texture_atlas_layout: Res<Assets<TextureAtlasLayout>>,
101    settings: Res<SpritePickingSettings>,
102    sprite_query: Query<(
103        Entity,
104        &Sprite,
105        &GlobalTransform,
106        &Anchor,
107        &Pickable,
108        &ViewVisibility,
109        Option<&RenderLayers>,
110    )>,
111    mut pointer_hits_writer: MessageWriter<PointerHits>,
112    ray_map: Res<RayMap>,
113) {
114    let mut sorted_sprites: Vec<_> = sprite_query
115        .iter()
116        .filter_map(
117            |(entity, sprite, transform, anchor, pickable, vis, render_layers)| {
118                if !transform.affine().is_nan() && vis.get() {
119                    Some((entity, sprite, transform, anchor, pickable, render_layers))
120                } else {
121                    None
122                }
123            },
124        )
125        .collect();
126
127    // radsort is a stable radix sort that performed better than `slice::sort_by_key`
128    radsort::sort_by_key(&mut sorted_sprites, |(_, _, transform, _, _, _)| {
129        -transform.translation().z
130    });
131
132    let primary_window = primary_window.single().ok();
133
134    let pick_sets = ray_map.iter().flat_map(|(ray_id, ray)| {
135        let mut blocked = false;
136
137        let Ok((
138            cam_entity,
139            camera,
140            render_target,
141            cam_transform,
142            Projection::Orthographic(cam_ortho),
143            cam_can_pick,
144            cam_render_layers,
145        )) = cameras.get(ray_id.camera)
146        else {
147            return None;
148        };
149
150        let marker_requirement = !settings.require_markers || cam_can_pick;
151        if !camera.is_active || !marker_requirement {
152            return None;
153        }
154
155        let location = pointers.iter().find_map(|(id, loc)| {
156            if *id == ray_id.pointer {
157                return loc.location.as_ref();
158            }
159            None
160        })?;
161
162        if render_target
163            .normalize(primary_window)
164            .is_none_or(|x| x != location.target)
165        {
166            return None;
167        }
168
169        let viewport_pos = location.position;
170        if let Some(viewport) = camera.logical_viewport_rect()
171            && !viewport.contains(viewport_pos)
172        {
173            // The pointer is outside the viewport, skip it
174            return None;
175        }
176
177        let cursor_ray_len = cam_ortho.far - cam_ortho.near;
178        let cursor_ray_end = ray.origin + ray.direction * cursor_ray_len;
179
180        let picks: Vec<(Entity, HitData)> = sorted_sprites
181            .iter()
182            .copied()
183            .filter_map(
184                |(entity, sprite, sprite_transform, anchor, pickable, sprite_render_layers)| {
185                    if blocked {
186                        return None;
187                    }
188
189                    // Filter out sprites based on whether they share RenderLayers with the current
190                    // ray's associated camera.
191                    // Any entity without a RenderLayers component will by default be
192                    // on RenderLayers::layer(0) only.
193                    if !cam_render_layers
194                        .unwrap_or_default()
195                        .intersects(sprite_render_layers.unwrap_or_default())
196                    {
197                        return None;
198                    }
199
200                    // Transform cursor line segment to sprite coordinate system
201                    let world_to_sprite = sprite_transform.affine().inverse();
202                    let cursor_start_sprite = world_to_sprite.transform_point3(ray.origin);
203                    let cursor_end_sprite = world_to_sprite.transform_point3(cursor_ray_end);
204
205                    // Find where the cursor segment intersects the plane Z=0 (which is the sprite's
206                    // plane in sprite-local space). It may not intersect if, for example, we're
207                    // viewing the sprite side-on
208                    if cursor_start_sprite.z == cursor_end_sprite.z {
209                        // Cursor ray is parallel to the sprite and misses it
210                        return None;
211                    }
212                    let lerp_factor =
213                        f32::inverse_lerp(cursor_start_sprite.z, cursor_end_sprite.z, 0.0);
214                    if !(0.0..=1.0).contains(&lerp_factor) {
215                        // Lerp factor is out of range, meaning that while an infinite line cast by
216                        // the cursor would intersect the sprite, the sprite is not between the
217                        // camera's near and far planes
218                        return None;
219                    }
220                    // Otherwise we can interpolate the xy of the start and end positions by the
221                    // lerp factor to get the cursor position in sprite space!
222                    let cursor_pos_sprite = cursor_start_sprite
223                        .lerp(cursor_end_sprite, lerp_factor)
224                        .xy();
225
226                    let Ok(cursor_pixel_space) = sprite.compute_pixel_space_point(
227                        cursor_pos_sprite,
228                        *anchor,
229                        &images,
230                        &texture_atlas_layout,
231                    ) else {
232                        return None;
233                    };
234
235                    // Since the pixel space coordinate is `Ok`, we know the cursor is in the bounds of
236                    // the sprite.
237
238                    let cursor_in_valid_pixels_of_sprite = 'valid_pixel: {
239                        match settings.picking_mode {
240                            SpritePickingMode::AlphaThreshold(cutoff) => {
241                                let Some(image) = images.get(&sprite.image) else {
242                                    // [`Sprite::from_color`] returns a defaulted handle.
243                                    // This handle doesn't return a valid image, so returning false here would make picking "color sprites" impossible
244                                    break 'valid_pixel true;
245                                };
246                                // grab pixel and check alpha
247                                let color = match image.get_color_at(
248                                    cursor_pixel_space.x as u32,
249                                    cursor_pixel_space.y as u32,
250                                ) {
251                                    Ok(color) => color,
252                                    Err(TextureAccessError::UnsupportedTextureFormat(format)) => {
253                                        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event src/picking_backend.rs:253",
                        "bevy_sprite::picking_backend", ::tracing::Level::WARN,
                        ::tracing_core::__macro_support::Option::Some("src/picking_backend.rs"),
                        ::tracing_core::__macro_support::Option::Some(253u32),
                        ::tracing_core::__macro_support::Option::Some("bevy_sprite::picking_backend"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::WARN <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                __CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("Failed to get pixel color for sprite picking on entity {0:?}: unsupported texture format {1:?}. This is often caused by the use of a compressed texture format. Consider using `SpritePickingMode::BoundingBox`.",
                                                    entity, format) as &dyn ::tracing::field::Value))])
            });
    } else { ; }
};warn!(
254                                            "Failed to get pixel color for sprite picking on entity {:?}: unsupported texture format {:?}. \
255                                            This is often caused by the use of a compressed texture format. \
256                                            Consider using `SpritePickingMode::BoundingBox`.",
257                                            entity,
258                                            format
259                                        );
260                                        break 'valid_pixel false;
261                                    }
262                                    Err(_) => break 'valid_pixel false,
263                                };
264                                // Check the alpha is above the cutoff.
265                                color.alpha() > cutoff
266                            }
267                            SpritePickingMode::BoundingBox => true,
268                        }
269                    };
270
271                    blocked = cursor_in_valid_pixels_of_sprite && pickable.should_block_lower;
272
273                    cursor_in_valid_pixels_of_sprite.then(|| {
274                        let hit_pos_world =
275                            sprite_transform.transform_point(cursor_pos_sprite.extend(0.0));
276                        // Transform point from world to camera space to get the Z distance
277                        let hit_pos_cam = cam_transform
278                            .affine()
279                            .inverse()
280                            .transform_point3(hit_pos_world);
281                        // HitData requires a depth as calculated from the camera's near clipping plane
282                        let depth = -cam_ortho.near - hit_pos_cam.z;
283                        (
284                            entity,
285                            HitData::new(
286                                cam_entity,
287                                depth,
288                                Some(hit_pos_world),
289                                Some(*sprite_transform.back()),
290                            ),
291                        )
292                    })
293                },
294            )
295            .collect();
296
297        Some((ray_id.pointer, picks, camera.order))
298    });
299
300    pick_sets.for_each(|(pointer, picks, order)| {
301        pointer_hits_writer.write(PointerHits::new(pointer, picks, order as f32));
302    });
303}