Skip to main content

bevy_picking/
window.rs

1//! This module contains a basic backend that implements picking for window
2//! entities.
3//!
4//! Pointers can exist on windows, images, and gpu texture views. With
5//! [`update_window_hits`] enabled, when a pointer hovers over a window that
6//! window will be inserted as a pointer hit, listed behind all other pointer
7//! hits. This means that when the pointer isn't hovering any other entities,
8//! the picking events will be routed to the window.
9//!
10//! ## Implementation Notes
11//!
12//! - This backend does not provide `normal` in `HitData`.
13
14use bevy_camera::NormalizedRenderTarget;
15use bevy_ecs::prelude::*;
16
17use crate::{
18    backend::{ray::RayMap, HitData, PointerHits},
19    pointer::{Location, PointerLocation, PointerMap},
20};
21
22/// Generates pointer hit events for window entities.
23///
24/// A pointer is treated as hitting a window when it is located on that window. The order
25/// of the hit event is negative infinity, meaning it should appear behind all other entities.
26///
27/// The depth of the hit will be listed as zero.
28pub fn update_window_hits(
29    pointer_locations: Query<&PointerLocation>,
30    mut pointer_hits_writer: MessageWriter<PointerHits>,
31    ray_map: Res<RayMap>,
32    pointer_map: Res<PointerMap>,
33) {
34    for (&ray_id, _) in ray_map.iter() {
35        if let Some((position, window_entity)) =
36            pointer_map
37                .get_entity(ray_id.pointer)
38                .and_then(|pointer_e| {
39                    if let Ok(PointerLocation {
40                        location:
41                            Some(Location {
42                                target: NormalizedRenderTarget::Window(window_ref),
43                                position,
44                                ..
45                            }),
46                    }) = pointer_locations.get(pointer_e)
47                    {
48                        return Some((position, window_ref.entity()));
49                    }
50                    None
51                })
52        {
53            let hit_data = HitData::new(ray_id.camera, 0.0, Some(position.extend(0.0)), None);
54            pointer_hits_writer.write(PointerHits::new(
55                ray_id.pointer,
56                vec![(window_entity, hit_data)],
57                f32::NEG_INFINITY,
58            ));
59        }
60    }
61}