From 2c8360de342872f65bdef037f3fb5d598b8f26a0 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Fri, 10 Jan 2025 22:04:34 +0100 Subject: unprojecting to ui surf is hard --- client/src/renderer.rs | 19 +++++++++++--- client/src/state.rs | 63 +++++++++++++++++++++++++++++++++------------ client/src/ui.rs | 70 +++++++++++++++++++++++++++++++++++--------------- client/src/window.rs | 8 +++--- 4 files changed, 115 insertions(+), 45 deletions(-) (limited to 'client') diff --git a/client/src/renderer.rs b/client/src/renderer.rs index a9a2332..473349d 100644 --- a/client/src/renderer.rs +++ b/client/src/renderer.rs @@ -16,7 +16,7 @@ */ use crate::{ camera::Camera, download::Downloader, scene_prepare::ScenePreparer, - scene_render::ScenePipeline, ui::UiRenderer, + scene_render::ScenePipeline, state::InputState, ui::UiRenderer, }; use anyhow::{Result, anyhow}; use log::{info, warn}; @@ -163,7 +163,12 @@ impl<'a> Renderer<'a> { .create_view(&TextureViewDescriptor::default()); } - pub fn draw(&mut self, scene: &SceneTree, camera: &Camera) -> Result<()> { + pub fn draw( + &mut self, + scene: &SceneTree, + camera: &Camera, + input_state: &InputState, + ) -> Result<()> { if self.surface_needs_reconfigure { self.surface .configure(&self.device, &self.surface_configuration); @@ -193,8 +198,14 @@ impl<'a> Renderer<'a> { projection, ); - self.ui_renderer - .draw(&mut commands, &target_view, &self.depth, projection); + self.ui_renderer.draw( + &mut commands, + &target_view, + &self.depth, + projection, + input_state, + &self.surface_configuration, + ); let i = self.queue.submit(Some(commands.finish())); self.device.poll(MaintainBase::WaitForSubmissionIndex(i)); diff --git a/client/src/state.rs b/client/src/state.rs index cd11d4a..5176ca1 100644 --- a/client/src/state.rs +++ b/client/src/state.rs @@ -33,18 +33,19 @@ pub struct State<'a> { pub renderer: Renderer<'a>, pub tree: SceneTree, pub camera: Camera, - pub delta: DeltaState, + pub input_state: InputState, - pub prefab_index: PrefabIndex, + pub prefab_index: Arc, pub prefab_index_res_loaded: Option>, pub prefab_index_res: Option>, } -pub struct DeltaState { +pub struct InputState { time: Instant, pub move_dir: Vec3, pub mouse_acc: Vec2, pub cursor_pos: Vec2, + pub egui_events: Vec, } impl<'a> State<'a> { @@ -57,19 +58,23 @@ impl<'a> State<'a> { tree: SceneTree::default(), renderer: Renderer::new(window, downloader.clone())?, downloader, - delta: DeltaState { + input_state: InputState { time: Instant::now(), move_dir: Vec3::ZERO, mouse_acc: Vec2::ZERO, cursor_pos: Vec2::ZERO, + egui_events: Vec::new(), }, prefab_index_res: None, prefab_index_res_loaded: None, - prefab_index: PrefabIndex::default(), + prefab_index: PrefabIndex::default().into(), }) } pub fn draw(&mut self) { - if let Err(e) = self.renderer.draw(&self.tree, &self.camera) { + if let Err(e) = self + .renderer + .draw(&self.tree, &self.camera, &self.input_state) + { warn!("draw failed: {e:?}"); } } @@ -78,29 +83,51 @@ impl<'a> State<'a> { self.camera.aspect = width as f32 / height as f32; } pub fn click(&mut self, button: MouseButton, down: bool) { + self.input_state + .egui_events + .push(egui::Event::PointerButton { + pos: egui::Pos2::new(self.input_state.cursor_pos.x, self.input_state.cursor_pos.y), + button: match button { + MouseButton::Left => egui::PointerButton::Primary, + MouseButton::Right => egui::PointerButton::Secondary, + MouseButton::Middle => egui::PointerButton::Middle, + MouseButton::Back => egui::PointerButton::Extra1, + MouseButton::Forward => egui::PointerButton::Extra2, + MouseButton::Other(_) => egui::PointerButton::Extra1, + }, + pressed: down, + modifiers: egui::Modifiers::default(), + }); + if !down || button != MouseButton::Right { return; } + let pi = self.prefab_index.clone(); self.renderer .ui_renderer - .add_surface(self.camera.new_ui_affine(), |ctx| { - egui::Window::new("Funny window") - .default_open(true) + .add_surface(self.camera.new_ui_affine(), move |ctx| { + let mut open = true; + egui::Window::new("Prefab Index") + .open(&mut open) .show(ctx, |ui| { - ui.label("world space ui actually kinda works now"); - ui.label("Does input work?"); - ui.button("Yes").clicked(); + for (key, _res) in &pi.0 { + ui.horizontal(|ui| { + ui.label(key); + if ui.button("Add").clicked() {} + }); + } }); + open }); } pub fn update(&mut self) -> Result<()> { let now = Instant::now(); - let dt = (now - self.delta.time).as_secs_f32(); - self.delta.time = now; + let dt = (now - self.input_state.time).as_secs_f32(); + self.input_state.time = now; self.camera - .update(self.delta.move_dir, self.delta.mouse_acc, dt); - self.delta.mouse_acc = Vec2::ZERO; + .update(self.input_state.move_dir, self.input_state.mouse_acc, dt); + self.input_state.mouse_acc = Vec2::ZERO; for p in self.network.packet_recv.try_iter() { self.downloader.packet(&p)?; @@ -117,11 +144,13 @@ impl<'a> State<'a> { if let Some(res) = &self.prefab_index_res { if let Some(index) = self.downloader.try_get(res.to_owned())? { info!("prefab index loaded"); - self.prefab_index = index; + self.prefab_index = index.into(); self.prefab_index_res_loaded = Some(res.to_owned()); } } } + + self.input_state.egui_events.clear(); Ok(()) } } diff --git a/client/src/ui.rs b/client/src/ui.rs index 54192e4..13e58d0 100644 --- a/client/src/ui.rs +++ b/client/src/ui.rs @@ -15,10 +15,10 @@ along with this program. If not, see . */ use egui::{ - Context, ImageData, TextureId, ViewportId, ViewportInfo, + Context, Event, ImageData, TextureId, ViewportId, ViewportInfo, epaint::{ImageDelta, Primitive, Vertex}, }; -use glam::{Affine3A, Mat2, Mat3, Mat4}; +use glam::{Affine3A, Mat2, Mat3, Mat4, Vec2, vec2}; use log::info; use rand::random; use std::{ @@ -36,13 +36,15 @@ use wgpu::{ PrimitiveTopology, PushConstantRange, Queue, RenderPassColorAttachment, RenderPassDepthStencilAttachment, RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, SamplerBindingType, SamplerDescriptor, ShaderStages, StoreOp, - Texture, TextureAspect, TextureDescriptor, TextureDimension, TextureFormat, TextureSampleType, - TextureUsages, TextureView, TextureViewDescriptor, TextureViewDimension, VertexBufferLayout, - VertexState, VertexStepMode, include_wgsl, + SurfaceConfiguration, Texture, TextureAspect, TextureDescriptor, TextureDimension, + TextureFormat, TextureSampleType, TextureUsages, TextureView, TextureViewDescriptor, + TextureViewDimension, VertexBufferLayout, VertexState, VertexStepMode, include_wgsl, util::{DeviceExt, TextureDataOrder}, vertex_attr_array, }; +use crate::state::InputState; + pub struct UiRenderer { device: Arc, queue: Arc, @@ -55,7 +57,8 @@ pub struct UiRenderer { pub struct UiSurface { pub transform: Affine3A, - pub content: Arc, + pub content: Arc bool + Send + Sync + 'static>, + size: Vec2, index: Buffer, index_capacity: usize, vertex: Buffer, @@ -149,7 +152,7 @@ impl UiRenderer { pub fn add_surface( &mut self, transform: Affine3A, - content: impl Fn(&Context) + Send + Sync + 'static, + content: impl Fn(&Context) -> bool + Send + Sync + 'static, ) { let index_capacity = 1024; let vertex_capacity = 1024; @@ -165,17 +168,17 @@ impl UiRenderer { usage: BufferUsages::VERTEX | BufferUsages::COPY_DST, mapped_at_creation: false, }); - self.surfaces.write().unwrap().insert( - ViewportId::from_hash_of(random::()), - UiSurface { - transform, - content: Arc::new(content), - index, - vertex, - index_capacity, - vertex_capacity, - }, - ); + let id = ViewportId::from_hash_of(random::()); + info!("ui surface added: {id:?}"); + self.surfaces.write().unwrap().insert(id, UiSurface { + transform, + content: Arc::new(content), + index, + vertex, + index_capacity, + vertex_capacity, + size: Vec2::ZERO, + }); } pub fn apply_texture_delta(&self, texid: TextureId, delta: ImageDelta) { @@ -273,6 +276,8 @@ impl UiRenderer { target: &TextureView, depth: &TextureView, projection: Mat4, + input_state: &InputState, + surface_configuration: &SurfaceConfiguration, ) { let mut surfaces = self.surfaces.write().unwrap(); if surfaces.is_empty() { @@ -302,7 +307,20 @@ impl UiRenderer { rpass.set_pipeline(&self.pipeline); + let _screen_size = vec2( + surface_configuration.width as f32, + surface_configuration.height as f32, + ); + let mut raw_input = egui::RawInput::default(); + raw_input.events.push(Event::PointerMoved(egui::Pos2::new( + input_state.cursor_pos.x, + input_state.cursor_pos.y, + ))); + raw_input + .events + .extend(input_state.egui_events.iter().cloned()); + raw_input.viewport_id = surfaces.keys().next().copied().unwrap(); raw_input.viewports = surfaces .keys() @@ -314,8 +332,16 @@ impl UiRenderer { }) .collect(); - for (_viewport_id, surf) in surfaces.iter_mut() { - let full_output = self.ctx.run(raw_input.clone(), |ctx| (surf.content)(ctx)); + let mut surfaces_closed = Vec::new(); + for (viewport_id, surf) in surfaces.iter_mut() { + let mut close = false; + let full_output = self.ctx.run(raw_input.clone(), |ctx| { + close = !(surf.content)(ctx); + surf.size = Vec2::new(ctx.used_size().x, ctx.used_size().y) + }); + if close { + surfaces_closed.push(*viewport_id) + } for (texid, delta) in full_output.textures_delta.set { self.apply_texture_delta(texid, delta); @@ -428,5 +454,9 @@ impl UiRenderer { rpass.draw_indexed(index, base_vertex, 0..1); } } + for s in surfaces_closed { + info!("ui surface closed: {s:?}"); + surfaces.remove(&s); + } } } diff --git a/client/src/window.rs b/client/src/window.rs index 107be34..68ca25b 100644 --- a/client/src/window.rs +++ b/client/src/window.rs @@ -85,7 +85,7 @@ impl ApplicationHandler for WindowState { _ => (), } } - sta.delta.move_dir += match event.physical_key { + sta.input_state.move_dir += match event.physical_key { PhysicalKey::Code(KeyCode::KeyW) => Vec3::X, PhysicalKey::Code(KeyCode::KeyS) => Vec3::NEG_X, PhysicalKey::Code(KeyCode::KeyA) => Vec3::NEG_Z, @@ -100,7 +100,7 @@ impl ApplicationHandler for WindowState { sta.click(button, state.is_pressed()); } WindowEvent::CursorMoved { position, .. } => { - sta.delta.cursor_pos = vec2(position.x as f32, position.y as f32); + sta.input_state.cursor_pos = vec2(position.x as f32, position.y as f32); } WindowEvent::CloseRequested => { event_loop.exit(); @@ -119,8 +119,8 @@ impl ApplicationHandler for WindowState { match event { DeviceEvent::MouseMotion { delta } => { if self.lock { - sta.delta.mouse_acc.x += delta.0 as f32; - sta.delta.mouse_acc.y += delta.1 as f32; + sta.input_state.mouse_acc.x += delta.0 as f32; + sta.input_state.mouse_acc.y += delta.1 as f32; } } _ => (), -- cgit v1.2.3-70-g09d2