gloss_renderer/
selector.rs1#[cfg(feature = "selector")]
2use crate::{
3 components::{CamController, Name, VisOutline},
4 plugin_manager::{plugins::InternalPlugin, GpuSystem, RunnerState},
5 scene::Scene,
6 viewer::GpuResources,
7};
8
9#[cfg(feature = "selector")]
10use crossbeam_channel;
11#[cfg(all(target_arch = "wasm32", feature = "selector"))]
12use wasm_bindgen_futures;
13
14pub struct Selector {
15 pub current_selected: Option<String>,
16}
17
18#[cfg(feature = "selector")]
21pub struct SelectorPixelReceiver(pub crossbeam_channel::Receiver<u8>);
22
23impl Default for Selector {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl Selector {
30 pub fn new() -> Self {
31 Self { current_selected: None }
32 }
33}
34
35#[derive(Clone)]
36pub struct SelectorPlugin {
37 pub autorun: bool,
38}
39
40impl SelectorPlugin {
41 pub fn new(autorun: bool) -> Self {
42 Self { autorun }
43 }
44}
45
46#[cfg(feature = "selector")]
47impl InternalPlugin for SelectorPlugin {
48 fn autorun(&self) -> bool {
49 self.autorun
50 }
51 fn gpu_systems(&self) -> Vec<GpuSystem> {
52 vec![
53 GpuSystem::new(add_selector_resource).with_name("selector_add_resource_system"),
54 GpuSystem::new(queue_pixel_download).with_name("selector_queue_download_system"),
55 GpuSystem::new(redraw_if_queued).with_name("selector_redraw_if_queued_system"),
56 GpuSystem::new(process_received_pixels).with_name("selector_process_pixels_system"),
57 ]
58 }
59}
60
61#[cfg(feature = "selector")]
64pub fn add_selector_resource(scene: &mut Scene, runner: &mut RunnerState, _gpu_res: &GpuResources) {
65 if runner.is_first_time() {
66 scene.add_resource(Selector::default());
67 }
68}
69
70#[cfg(feature = "selector")]
72pub fn redraw_if_queued(scene: &mut Scene, runner: &mut RunnerState, _gpu_res: &GpuResources) {
73 if scene.has_resource::<SelectorPixelReceiver>() {
74 runner.request_redraw();
75 }
76}
77
78#[cfg(feature = "selector")]
80pub fn process_received_pixels(scene: &mut Scene, _runner: &mut RunnerState, _gpu_res: &GpuResources) {
81 let pixel_data = scene
83 .get_resource::<&SelectorPixelReceiver>()
84 .ok()
85 .and_then(|receiver| receiver.0.try_recv().ok());
86
87 if let Some(pixel_data) = pixel_data {
89 let entity_id = pixel_data;
90
91 if let Ok(mut selector) = scene.get_resource::<&mut Selector>() {
93 if let Some(current_selected) = &selector.current_selected {
94 if let Some(prev_entity) = scene.get_entity_with_name(current_selected) {
95 if let Ok(mut vis_outline) = scene.world.get::<&mut VisOutline>(prev_entity) {
96 vis_outline.show_outline = false;
97 }
98 }
99 }
100 selector.current_selected = None;
101 }
102
103 if entity_id != 0 {
105 let entity_ref = scene.find_entity_with_id(entity_id);
106
107 if let Some(e_ref) = entity_ref {
108 let name = e_ref.get::<&Name>().expect("The entity has no name").0.clone();
109
110 if let Some(mut vis_outline) = e_ref.get::<&mut VisOutline>() {
111 vis_outline.show_outline = true;
112 }
113
114 scene.add_resource(Selector {
115 current_selected: Some(name.clone()),
116 });
117 }
118 }
119
120 let _ = scene.remove_resource::<SelectorPixelReceiver>();
121 }
122}
123
124#[cfg(feature = "selector")]
126pub fn queue_pixel_download(scene: &mut Scene, runner: &mut RunnerState, gpu_res: &GpuResources) {
127 if !scene.get_current_cam().unwrap().is_click(scene) || !scene.has_resource::<Selector>() {
129 return;
130 }
131
132 #[allow(clippy::cast_possible_truncation)]
133 #[allow(clippy::cast_sign_loss)]
134 let cursor_pos = scene
135 .get_current_cam()
136 .and_then(|camera| scene.get_comp::<&CamController>(&camera.entity).ok())
137 .and_then(|cam_control| cam_control.cursor_position)
138 .map(|pos| (pos.x as u32, pos.y as u32));
139
140 let Some((x, y)) = cursor_pos else { return };
141
142 let gpu = &gpu_res.gpu;
143
144 let entity_id_texture = gpu_res.renderer.entity_id_buffer();
146 let scaled_x = x / entity_id_texture.tex_params.scale_factor;
147 let scaled_y = y / entity_id_texture.tex_params.scale_factor;
148
149 let (sender, receiver) = crossbeam_channel::unbounded();
150
151 #[cfg(not(target_arch = "wasm32"))]
153 {
154 let single_pixel_img =
155 pollster::block_on(entity_id_texture.download_pixel_to_cpu(gpu.device(), gpu.queue(), wgpu::TextureAspect::All, scaled_x, scaled_y));
156 let _ = sender.send(single_pixel_img.as_bytes().to_vec()[0]);
158 }
159
160 #[cfg(target_arch = "wasm32")]
161 {
162 let texture_clone = entity_id_texture.clone();
163 let device = gpu.device().clone();
164 let queue = gpu.queue().clone();
165
166 wasm_bindgen_futures::spawn_local(async move {
167 let pixel_data = texture_clone
168 .download_pixel_to_cpu(&device, &queue, wgpu::TextureAspect::All, scaled_x, scaled_y)
169 .await;
170 let _ = sender.send(pixel_data.as_bytes().to_vec()[0]);
172 });
173 }
174
175 scene.add_resource(SelectorPixelReceiver(receiver));
176 runner.request_redraw();
177}