Skip to main content

bevy_light/
spot_light.rs

1use bevy_asset::Handle;
2use bevy_camera::{
3    primitives::{Frustum, Sphere},
4    visibility::{self, ViewVisibility, Visibility, VisibilityClass, VisibleMeshEntities},
5};
6use bevy_color::Color;
7use bevy_ecs::prelude::*;
8use bevy_image::Image;
9use bevy_math::{primitives::ViewFrustum, Affine3A, Dir3, Mat3, Mat4, Vec3};
10use bevy_reflect::prelude::*;
11use bevy_transform::components::{GlobalTransform, Transform};
12
13use crate::cluster::ClusterVisibilityClass;
14
15/// A light that emits light in a given direction from a central point.
16///
17/// Behaves like a point light in a perfectly absorbent housing that
18/// shines light only in a given direction. The direction is taken from
19/// the transform, and can be specified with [`Transform::looking_at`](Transform::looking_at).
20///
21/// To control the resolution of the shadow maps, use the [`DirectionalLightShadowMap`](`crate::DirectionalLightShadowMap`)  resource.
22#[derive(#[doc =
"**Required Components**: [`Frustum`], [`VisibleMeshEntities`], [`Transform`], [`Visibility`], [`VisibilityClass`]. \n\n A component's Required Components are inserted whenever it is inserted. Note that this will also insert the required components _of_ the required components, recursively, in depth-first order."]
impl bevy_ecs::component::Component for SpotLight 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) {
        required_components.register_required::<Frustum>(<Frustum as
                ::core::default::Default>::default);
        required_components.register_required::<VisibleMeshEntities>(<VisibleMeshEntities
                as ::core::default::Default>::default);
        required_components.register_required::<Transform>(<Transform as
                ::core::default::Default>::default);
        required_components.register_required::<Visibility>(<Visibility as
                ::core::default::Default>::default);
        required_components.register_required::<VisibilityClass>(<VisibilityClass
                as ::core::default::Default>::default);
    }
    fn on_add()
        -> ::core::option::Option<bevy_ecs::lifecycle::ComponentHook> {
        ::core::option::Option::Some(visibility::add_visibility_class::<ClusterVisibilityClass>)
    }
    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, #[automatically_derived]
impl ::core::fmt::Debug for SpotLight {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        let names: &'static _ =
            &["color", "intensity", "range", "radius", "shadow_maps_enabled",
                        "contact_shadows_enabled", "soft_shadows_enabled",
                        "affects_lightmapped_mesh_diffuse", "shadow_depth_bias",
                        "shadow_normal_bias", "shadow_map_near_z", "outer_angle",
                        "inner_angle"];
        let values: &[&dyn ::core::fmt::Debug] =
            &[&self.color, &self.intensity, &self.range, &self.radius,
                        &self.shadow_maps_enabled, &self.contact_shadows_enabled,
                        &self.soft_shadows_enabled,
                        &self.affects_lightmapped_mesh_diffuse,
                        &self.shadow_depth_bias, &self.shadow_normal_bias,
                        &self.shadow_map_near_z, &self.outer_angle,
                        &&self.inner_angle];
        ::core::fmt::Formatter::debug_struct_fields_finish(f, "SpotLight",
            names, values)
    }
}Debug, #[automatically_derived]
impl ::core::clone::Clone for SpotLight {
    #[inline]
    fn clone(&self) -> SpotLight {
        let _: ::core::clone::AssertParamIsClone<Color>;
        let _: ::core::clone::AssertParamIsClone<f32>;
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for SpotLight { }Copy, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for SpotLight 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::<ReflectComponent, Self>();
                registration.register_type_data::<ReflectDefault, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <Color as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <f32 as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
                <bool as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for SpotLight 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::<Color>("color"),
                                                bevy_reflect::NamedField::new::<f32>("intensity"),
                                                bevy_reflect::NamedField::new::<f32>("range"),
                                                bevy_reflect::NamedField::new::<f32>("radius"),
                                                bevy_reflect::NamedField::new::<bool>("shadow_maps_enabled"),
                                                bevy_reflect::NamedField::new::<bool>("contact_shadows_enabled"),
                                                bevy_reflect::NamedField::new::<bool>("soft_shadows_enabled"),
                                                bevy_reflect::NamedField::new::<bool>("affects_lightmapped_mesh_diffuse"),
                                                bevy_reflect::NamedField::new::<f32>("shadow_depth_bias"),
                                                bevy_reflect::NamedField::new::<f32>("shadow_normal_bias"),
                                                bevy_reflect::NamedField::new::<f32>("shadow_map_near_z"),
                                                bevy_reflect::NamedField::new::<f32>("outer_angle"),
                                                bevy_reflect::NamedField::new::<f32>("inner_angle")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for SpotLight where  {
            fn type_path() -> &'static str {
                "bevy_light::spot_light::SpotLight"
            }
            fn short_type_path() -> &'static str { "SpotLight" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("SpotLight")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_light::spot_light".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_light::spot_light")
            }
        }
        impl bevy_reflect::Reflect for SpotLight 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(<SpotLight
                                        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 SpotLight where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "color" => ::core::option::Option::Some(&self.color),
                    "intensity" =>
                        ::core::option::Option::Some(&self.intensity),
                    "range" => ::core::option::Option::Some(&self.range),
                    "radius" => ::core::option::Option::Some(&self.radius),
                    "shadow_maps_enabled" =>
                        ::core::option::Option::Some(&self.shadow_maps_enabled),
                    "contact_shadows_enabled" =>
                        ::core::option::Option::Some(&self.contact_shadows_enabled),
                    "soft_shadows_enabled" =>
                        ::core::option::Option::Some(&self.soft_shadows_enabled),
                    "affects_lightmapped_mesh_diffuse" =>
                        ::core::option::Option::Some(&self.affects_lightmapped_mesh_diffuse),
                    "shadow_depth_bias" =>
                        ::core::option::Option::Some(&self.shadow_depth_bias),
                    "shadow_normal_bias" =>
                        ::core::option::Option::Some(&self.shadow_normal_bias),
                    "shadow_map_near_z" =>
                        ::core::option::Option::Some(&self.shadow_map_near_z),
                    "outer_angle" =>
                        ::core::option::Option::Some(&self.outer_angle),
                    "inner_angle" =>
                        ::core::option::Option::Some(&self.inner_angle),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "color" => ::core::option::Option::Some(&mut self.color),
                    "intensity" =>
                        ::core::option::Option::Some(&mut self.intensity),
                    "range" => ::core::option::Option::Some(&mut self.range),
                    "radius" => ::core::option::Option::Some(&mut self.radius),
                    "shadow_maps_enabled" =>
                        ::core::option::Option::Some(&mut self.shadow_maps_enabled),
                    "contact_shadows_enabled" =>
                        ::core::option::Option::Some(&mut self.contact_shadows_enabled),
                    "soft_shadows_enabled" =>
                        ::core::option::Option::Some(&mut self.soft_shadows_enabled),
                    "affects_lightmapped_mesh_diffuse" =>
                        ::core::option::Option::Some(&mut self.affects_lightmapped_mesh_diffuse),
                    "shadow_depth_bias" =>
                        ::core::option::Option::Some(&mut self.shadow_depth_bias),
                    "shadow_normal_bias" =>
                        ::core::option::Option::Some(&mut self.shadow_normal_bias),
                    "shadow_map_near_z" =>
                        ::core::option::Option::Some(&mut self.shadow_map_near_z),
                    "outer_angle" =>
                        ::core::option::Option::Some(&mut self.outer_angle),
                    "inner_angle" =>
                        ::core::option::Option::Some(&mut self.inner_angle),
                    _ => ::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.color),
                    1usize => ::core::option::Option::Some(&self.intensity),
                    2usize => ::core::option::Option::Some(&self.range),
                    3usize => ::core::option::Option::Some(&self.radius),
                    4usize =>
                        ::core::option::Option::Some(&self.shadow_maps_enabled),
                    5usize =>
                        ::core::option::Option::Some(&self.contact_shadows_enabled),
                    6usize =>
                        ::core::option::Option::Some(&self.soft_shadows_enabled),
                    7usize =>
                        ::core::option::Option::Some(&self.affects_lightmapped_mesh_diffuse),
                    8usize =>
                        ::core::option::Option::Some(&self.shadow_depth_bias),
                    9usize =>
                        ::core::option::Option::Some(&self.shadow_normal_bias),
                    10usize =>
                        ::core::option::Option::Some(&self.shadow_map_near_z),
                    11usize => ::core::option::Option::Some(&self.outer_angle),
                    12usize => ::core::option::Option::Some(&self.inner_angle),
                    _ => ::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.color),
                    1usize => ::core::option::Option::Some(&mut self.intensity),
                    2usize => ::core::option::Option::Some(&mut self.range),
                    3usize => ::core::option::Option::Some(&mut self.radius),
                    4usize =>
                        ::core::option::Option::Some(&mut self.shadow_maps_enabled),
                    5usize =>
                        ::core::option::Option::Some(&mut self.contact_shadows_enabled),
                    6usize =>
                        ::core::option::Option::Some(&mut self.soft_shadows_enabled),
                    7usize =>
                        ::core::option::Option::Some(&mut self.affects_lightmapped_mesh_diffuse),
                    8usize =>
                        ::core::option::Option::Some(&mut self.shadow_depth_bias),
                    9usize =>
                        ::core::option::Option::Some(&mut self.shadow_normal_bias),
                    10usize =>
                        ::core::option::Option::Some(&mut self.shadow_map_near_z),
                    11usize =>
                        ::core::option::Option::Some(&mut self.outer_angle),
                    12usize =>
                        ::core::option::Option::Some(&mut self.inner_angle),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("color"),
                    1usize => ::core::option::Option::Some("intensity"),
                    2usize => ::core::option::Option::Some("range"),
                    3usize => ::core::option::Option::Some("radius"),
                    4usize =>
                        ::core::option::Option::Some("shadow_maps_enabled"),
                    5usize =>
                        ::core::option::Option::Some("contact_shadows_enabled"),
                    6usize =>
                        ::core::option::Option::Some("soft_shadows_enabled"),
                    7usize =>
                        ::core::option::Option::Some("affects_lightmapped_mesh_diffuse"),
                    8usize => ::core::option::Option::Some("shadow_depth_bias"),
                    9usize =>
                        ::core::option::Option::Some("shadow_normal_bias"),
                    10usize =>
                        ::core::option::Option::Some("shadow_map_near_z"),
                    11usize => ::core::option::Option::Some("outer_angle"),
                    12usize => ::core::option::Option::Some("inner_angle"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "color" => ::core::option::Option::Some(0usize),
                    "intensity" => ::core::option::Option::Some(1usize),
                    "range" => ::core::option::Option::Some(2usize),
                    "radius" => ::core::option::Option::Some(3usize),
                    "shadow_maps_enabled" =>
                        ::core::option::Option::Some(4usize),
                    "contact_shadows_enabled" =>
                        ::core::option::Option::Some(5usize),
                    "soft_shadows_enabled" =>
                        ::core::option::Option::Some(6usize),
                    "affects_lightmapped_mesh_diffuse" =>
                        ::core::option::Option::Some(7usize),
                    "shadow_depth_bias" => ::core::option::Option::Some(8usize),
                    "shadow_normal_bias" =>
                        ::core::option::Option::Some(9usize),
                    "shadow_map_near_z" =>
                        ::core::option::Option::Some(10usize),
                    "outer_angle" => ::core::option::Option::Some(11usize),
                    "inner_angle" => ::core::option::Option::Some(12usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 13usize }
            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("color",
                    bevy_reflect::PartialReflect::to_dynamic(&self.color));
                dynamic.insert_boxed("intensity",
                    bevy_reflect::PartialReflect::to_dynamic(&self.intensity));
                dynamic.insert_boxed("range",
                    bevy_reflect::PartialReflect::to_dynamic(&self.range));
                dynamic.insert_boxed("radius",
                    bevy_reflect::PartialReflect::to_dynamic(&self.radius));
                dynamic.insert_boxed("shadow_maps_enabled",
                    bevy_reflect::PartialReflect::to_dynamic(&self.shadow_maps_enabled));
                dynamic.insert_boxed("contact_shadows_enabled",
                    bevy_reflect::PartialReflect::to_dynamic(&self.contact_shadows_enabled));
                dynamic.insert_boxed("soft_shadows_enabled",
                    bevy_reflect::PartialReflect::to_dynamic(&self.soft_shadows_enabled));
                dynamic.insert_boxed("affects_lightmapped_mesh_diffuse",
                    bevy_reflect::PartialReflect::to_dynamic(&self.affects_lightmapped_mesh_diffuse));
                dynamic.insert_boxed("shadow_depth_bias",
                    bevy_reflect::PartialReflect::to_dynamic(&self.shadow_depth_bias));
                dynamic.insert_boxed("shadow_normal_bias",
                    bevy_reflect::PartialReflect::to_dynamic(&self.shadow_normal_bias));
                dynamic.insert_boxed("shadow_map_near_z",
                    bevy_reflect::PartialReflect::to_dynamic(&self.shadow_map_near_z));
                dynamic.insert_boxed("outer_angle",
                    bevy_reflect::PartialReflect::to_dynamic(&self.outer_angle));
                dynamic.insert_boxed("inner_angle",
                    bevy_reflect::PartialReflect::to_dynamic(&self.inner_angle));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for SpotLight 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 SpotLight 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) =
                            (||
                                        <Color as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "color")?))() {
                        __this.color = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "intensity")?))() {
                        __this.intensity = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "range")?))() {
                        __this.range = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "radius")?))() {
                        __this.radius = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <bool as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "shadow_maps_enabled")?))() {
                        __this.shadow_maps_enabled = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <bool as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "contact_shadows_enabled")?))() {
                        __this.contact_shadows_enabled = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <bool as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "soft_shadows_enabled")?))() {
                        __this.soft_shadows_enabled = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <bool as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "affects_lightmapped_mesh_diffuse")?))() {
                        __this.affects_lightmapped_mesh_diffuse = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "shadow_depth_bias")?))() {
                        __this.shadow_depth_bias = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "shadow_normal_bias")?))() {
                        __this.shadow_normal_bias = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "shadow_map_near_z")?))() {
                        __this.shadow_map_near_z = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "outer_angle")?))() {
                        __this.outer_angle = __field;
                    }
                    if let ::core::option::Option::Some(__field) =
                            (||
                                        <f32 as
                                                bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                                    "inner_angle")?))() {
                        __this.inner_angle = __field;
                    }
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect)]
23#[reflect(Component, Default, Debug, Clone)]
24#[require(Frustum, VisibleMeshEntities, Transform, Visibility, VisibilityClass)]
25#[component(on_add = visibility::add_visibility_class::<ClusterVisibilityClass>)]
26pub struct SpotLight {
27    /// The color of the light.
28    ///
29    /// By default, this is white.
30    pub color: Color,
31
32    /// Luminous power in lumens, representing the amount of light emitted by this source in all directions.
33    pub intensity: f32,
34
35    /// Range in meters that this light illuminates.
36    ///
37    /// Note that this value affects resolution of the shadow maps; generally, the
38    /// higher you set it, the lower-resolution your shadow maps will be.
39    /// Consequently, you should set this value to be only the size that you need.
40    pub range: f32,
41
42    /// Simulates a light source coming from a spherical volume with the given
43    /// radius.
44    ///
45    /// This affects the size of specular highlights created by this light, as
46    /// well as the soft shadow penumbra size. Because of this, large values may
47    /// not produce the intended result -- for example, light radius does not
48    /// affect shadow softness or diffuse lighting.
49    pub radius: f32,
50
51    /// Whether this light casts shadows.
52    ///
53    /// Note that shadows are rather expensive and become more so with every
54    /// light that casts them. In general, it's best to aggressively limit the
55    /// number of lights with shadows enabled to one or two at most.
56    pub shadow_maps_enabled: bool,
57
58    /// Whether this light casts contact shadows. Cameras must also have the `ContactShadows`
59    /// component.
60    pub contact_shadows_enabled: bool,
61
62    /// Whether soft shadows are enabled.
63    ///
64    /// Soft shadows, also known as *percentage-closer soft shadows* or PCSS,
65    /// cause shadows to become blurrier (i.e. their penumbra increases in
66    /// radius) as they extend away from objects. The blurriness of the shadow
67    /// depends on the [`SpotLight::radius`] of the light; larger lights result in larger
68    /// penumbras and therefore blurrier shadows.
69    ///
70    /// Currently, soft shadows are rather noisy if not using the temporal mode.
71    /// If you enable soft shadows, consider choosing
72    /// [`ShadowFilteringMethod::Temporal`] and enabling temporal antialiasing
73    /// (TAA) to smooth the noise out over time.
74    ///
75    /// Note that soft shadows are significantly more expensive to render than
76    /// hard shadows.
77    ///
78    /// [`ShadowFilteringMethod::Temporal`]: crate::ShadowFilteringMethod::Temporal
79    #[cfg(feature = "experimental_pbr_pcss")]
80    pub soft_shadows_enabled: bool,
81
82    /// Whether this spot light contributes diffuse lighting to meshes with
83    /// lightmaps.
84    ///
85    /// Set this to false if your lightmap baking tool bakes the direct diffuse
86    /// light from this directional light into the lightmaps in order to avoid
87    /// counting the radiance from this light twice. Note that the specular
88    /// portion of the light is always considered, because Bevy currently has no
89    /// means to bake specular light.
90    ///
91    /// By default, this is set to true.
92    pub affects_lightmapped_mesh_diffuse: bool,
93
94    /// A value that adjusts the tradeoff between self-shadowing artifacts and
95    /// proximity of shadows to their casters.
96    ///
97    /// This value frequently must be tuned to the specific scene; this is
98    /// normal and a well-known part of the shadow mapping workflow. If set too
99    /// low, unsightly shadow patterns appear on objects not in shadow as
100    /// objects incorrectly cast shadows on themselves, known as *shadow acne*.
101    /// If set too high, shadows detach from the objects casting them and seem
102    /// to "fly" off the objects, known as *Peter Panning*.
103    pub shadow_depth_bias: f32,
104
105    /// A bias applied along the direction of the fragment's surface normal. It is scaled to the
106    /// shadow map's texel size so that it can be small close to the camera and gets larger further
107    /// away.
108    pub shadow_normal_bias: f32,
109
110    /// The distance from the light to the near Z plane in the shadow map.
111    ///
112    /// Objects closer than this distance to the light won't cast shadows.
113    /// Setting this higher increases the shadow map's precision.
114    ///
115    /// This only has an effect if shadows are enabled.
116    pub shadow_map_near_z: f32,
117
118    /// Angle defining the distance from the spot light direction to the outer limit
119    /// of the light's cone of effect.
120    /// `outer_angle` should be < `PI / 2.0`.
121    /// `PI / 2.0` defines a hemispherical spot light, but shadows become very blocky as the angle
122    /// approaches this limit.
123    pub outer_angle: f32,
124
125    /// Angle defining the distance from the spot light direction to the inner limit
126    /// of the light's cone of effect.
127    /// Light is attenuated from `inner_angle` to `outer_angle` to give a smooth falloff.
128    /// `inner_angle` should be <= `outer_angle`
129    pub inner_angle: f32,
130}
131
132impl SpotLight {
133    /// The default value of [`SpotLight::shadow_depth_bias`].
134    pub const DEFAULT_SHADOW_DEPTH_BIAS: f32 = 0.02;
135    /// The default value of [`SpotLight::shadow_normal_bias`].
136    pub const DEFAULT_SHADOW_NORMAL_BIAS: f32 = 1.8;
137    /// The default value of [`SpotLight::shadow_map_near_z`].
138    pub const DEFAULT_SHADOW_MAP_NEAR_Z: f32 = 0.1;
139}
140
141impl Default for SpotLight {
142    fn default() -> Self {
143        // a quarter arc attenuating from the center
144        Self {
145            color: Color::WHITE,
146            // 1,000,000 lumens is a very large "cinema light" capable of registering brightly at Bevy's
147            // default "very overcast day" exposure level. For "indoor lighting" with a lower exposure,
148            // this would be way too bright.
149            intensity: 1_000_000.0,
150            range: 20.0,
151            radius: 0.0,
152            shadow_maps_enabled: false,
153            contact_shadows_enabled: false,
154            affects_lightmapped_mesh_diffuse: true,
155            shadow_depth_bias: Self::DEFAULT_SHADOW_DEPTH_BIAS,
156            shadow_normal_bias: Self::DEFAULT_SHADOW_NORMAL_BIAS,
157            shadow_map_near_z: Self::DEFAULT_SHADOW_MAP_NEAR_Z,
158            inner_angle: 0.0,
159            outer_angle: core::f32::consts::FRAC_PI_4,
160            #[cfg(feature = "experimental_pbr_pcss")]
161            soft_shadows_enabled: false,
162        }
163    }
164}
165
166/// Constructs a right-handed orthonormal basis from a given unit Z vector.
167///
168/// This method of constructing a basis from a [`Vec3`] is used by [`bevy_math::Vec3::any_orthonormal_pair`]
169// we will also construct it in the fragment shader and need our implementations to match exactly,
170// so we reproduce it here to avoid a mismatch if glam changes.
171// See bevy_render/maths.wgsl:orthonormalize
172pub fn orthonormalize(z_basis: Dir3) -> Mat3 {
173    let sign = 1f32.copysign(z_basis.z);
174    let a = -1.0 / (sign + z_basis.z);
175    let b = z_basis.x * z_basis.y * a;
176    let x_basis = Vec3::new(
177        1.0 + sign * z_basis.x * z_basis.x * a,
178        sign * b,
179        -sign * z_basis.x,
180    );
181    let y_basis = Vec3::new(b, sign + z_basis.y * z_basis.y * a, -z_basis.y);
182    Mat3::from_cols(x_basis, y_basis, z_basis.into())
183}
184/// Constructs a right-handed orthonormal basis with translation, using only the forward direction and translation of a given [`GlobalTransform`].
185///
186/// This is a version of [`orthonormalize`] which also includes translation.
187pub fn spot_light_world_from_view(transform: &GlobalTransform) -> Affine3A {
188    // the matrix z_local (opposite of transform.forward())
189    let fwd_dir = transform.back();
190
191    let basis = orthonormalize(fwd_dir);
192    Affine3A::from_mat3_translation(basis, transform.translation())
193}
194
195/// Creates the projection matrix that transforms the light's view space into the light's clip space.
196pub fn spot_light_clip_from_view(angle: f32, near_z: f32) -> Mat4 {
197    // spot light projection FOV is 2x the angle from spot light center to outer edge
198    Mat4::perspective_infinite_reverse_rh(angle * 2.0, 1.0, near_z)
199}
200
201/// Add to a [`SpotLight`] to add a light texture effect.
202/// A texture mask is applied to the light source to modulate its intensity,  
203/// simulating patterns like window shadows, gobo/cookie effects, or soft falloffs.
204#[derive(#[automatically_derived]
impl ::core::clone::Clone for SpotLightTexture {
    #[inline]
    fn clone(&self) -> SpotLightTexture {
        SpotLightTexture { image: ::core::clone::Clone::clone(&self.image) }
    }
}Clone, #[doc =
"**Required Components**: [`SpotLight`]. \n\n A component's Required Components are inserted whenever it is inserted. Note that this will also insert the required components _of_ the required components, recursively, in depth-first order."]
impl bevy_ecs::component::Component for SpotLightTexture 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) {
        required_components.register_required::<SpotLight>(<SpotLight as
                ::core::default::Default>::default);
    }
    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, #[automatically_derived]
impl ::core::fmt::Debug for SpotLightTexture {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f,
            "SpotLightTexture", "image", &&self.image)
    }
}Debug, const _: () =
    {
        impl bevy_reflect::GetTypeRegistration for SpotLightTexture 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::<ReflectComponent, Self>();
                registration
            }
            #[inline(never)]
            fn register_type_dependencies(registry:
                    &mut bevy_reflect::TypeRegistry) {
                <Handle<Image> as
                        bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
            }
        }
        impl bevy_reflect::Typed for SpotLightTexture 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<Image>>("image")]))
                        })
            }
        }
        #[allow(deprecated, reason =
        "derives on a deprecated type shouldn't be considered a usage")]
        impl bevy_reflect::TypePath for SpotLightTexture where  {
            fn type_path() -> &'static str {
                "bevy_light::spot_light::SpotLightTexture"
            }
            fn short_type_path() -> &'static str { "SpotLightTexture" }
            fn type_ident() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("SpotLightTexture")
            }
            fn crate_name() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_light::spot_light".split(':').next().unwrap())
            }
            fn module_path() -> ::core::option::Option<&'static str> {
                ::core::option::Option::Some("bevy_light::spot_light")
            }
        }
        impl bevy_reflect::Reflect for SpotLightTexture 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(<SpotLightTexture
                                        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 SpotLightTexture where  {
            fn field(&self, name: &str)
                -> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
                match name {
                    "image" => ::core::option::Option::Some(&self.image),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_mut(&mut self, name: &str)
                ->
                    ::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
                match name {
                    "image" => ::core::option::Option::Some(&mut self.image),
                    _ => ::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.image),
                    _ => ::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.image),
                    _ => ::core::option::Option::None,
                }
            }
            fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
                match index {
                    0usize => ::core::option::Option::Some("image"),
                    _ => ::core::option::Option::None,
                }
            }
            fn index_of_name(&self, name: &str)
                -> ::core::option::Option<usize> {
                match name {
                    "image" => ::core::option::Option::Some(0usize),
                    _ => ::core::option::Option::None,
                }
            }
            fn field_len(&self) -> usize { 1usize }
            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("image",
                    bevy_reflect::PartialReflect::to_dynamic(&self.image));
                dynamic
            }
        }
        impl bevy_reflect::PartialReflect for SpotLightTexture 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]
            #[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 {
                            image: <Handle<Image> as
                                        bevy_reflect::PartialReflect>::reflect_clone_and_take(&self.image)?,
                        }))
            }
        }
        impl bevy_reflect::FromReflect for SpotLightTexture 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 {
                            image: <Handle<Image> as
                                        bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
                                            "image")?)?,
                        };
                    ::core::option::Option::Some(__this)
                } else { ::core::option::Option::None }
            }
        }
    };Reflect, impl ::core::default::Default for SpotLightTextureTemplate {
    fn default() -> Self {
        Self { image: ::core::default::Default::default() }
    }
}FromTemplate)]
205#[reflect(Component, Debug)]
206#[require(SpotLight)]
207pub struct SpotLightTexture {
208    /// The texture image. Only the R channel is read.
209    /// Note the border of the image should be entirely black to avoid leaking light.
210    pub image: Handle<Image>,
211}
212
213/// A system that updates the bounding [`Sphere`] for changed spot lights.
214///
215/// The [`Sphere`] component is used for frustum culling.
216pub fn update_spot_light_bounding_spheres(
217    mut commands: Commands,
218    spot_lights_query: Query<
219        (Entity, &SpotLight, &GlobalTransform),
220        Or<(Changed<SpotLight>, Changed<GlobalTransform>)>,
221    >,
222) {
223    for (spot_light_entity, spot_light, global_transform) in &spot_lights_query {
224        commands.entity(spot_light_entity).insert(Sphere {
225            center: global_transform.translation_vec3a(),
226            radius: spot_light.range,
227        });
228    }
229}
230
231/// Updates the frusta for all visible shadow mapped [`SpotLight`]s.
232pub fn update_spot_light_frusta(
233    mut views: Query<
234        (&GlobalTransform, &SpotLight, &mut Frustum, &ViewVisibility),
235        Or<(
236            Changed<GlobalTransform>,
237            Changed<SpotLight>,
238            Changed<ViewVisibility>,
239        )>,
240    >,
241) {
242    for (transform, spot_light, mut frustum, view_visibility) in &mut views {
243        // The frusta are used for culling meshes to the light for shadow mapping
244        // so if shadow mapping is disabled for this light, then the frusta are
245        // not needed.
246        // Also, if the light is not relevant for any cluster, it will not be in the
247        // global lights set and so there is no need to update its frusta.
248        if !spot_light.shadow_maps_enabled || !view_visibility.get() {
249            continue;
250        }
251
252        // ignore scale because we don't want to effectively scale light radius and range
253        // by applying those as a view transform to shadow map rendering of objects
254        let view_backward = transform.back();
255
256        let spot_world_from_view = spot_light_world_from_view(transform);
257        let spot_clip_from_view =
258            spot_light_clip_from_view(spot_light.outer_angle, spot_light.shadow_map_near_z);
259        let clip_from_world = spot_clip_from_view * spot_world_from_view.inverse();
260
261        *frustum = Frustum(ViewFrustum::from_clip_from_world_custom_far(
262            &clip_from_world,
263            &transform.translation(),
264            &view_backward,
265            spot_light.range,
266        ));
267    }
268}