diff --git a/editor/Cargo.toml b/editor/Cargo.toml index d78b2b5..125ec80 100644 --- a/editor/Cargo.toml +++ b/editor/Cargo.toml @@ -8,7 +8,8 @@ bytemuck = "^1.0" crossbeam-channel = "^0.5" cyborg = { path = "../", features = ["legion"] } egui = "0.18" -egui-winit = "0.18.0" +egui-gizmo = "0.7" +egui-winit = "0.18" egui_wgpu_backend = "0.18.0" glam = { version = "0.20", features = ["serde"] } gltf = { version = "1.0", features = ["utils"] } diff --git a/editor/src/ui.rs b/editor/src/ui.rs index c8827e3..ec5baae 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -211,7 +211,7 @@ impl UserInterface { }); egui::CentralPanel::default().show(ctx, |ui| { - ui.add(viewport); + viewport.show(ui); ui.heading("Viewport"); }); } @@ -260,6 +260,7 @@ pub struct ViewportWidget { pub flycam: Flycam, pub width: u32, pub height: u32, + pub dragging: bool, } impl ViewportWidget { @@ -269,21 +270,39 @@ impl ViewportWidget { flycam: Flycam::new(0.002, 10.0, 0.25), width: 640, height: 480, + dragging: false, } } -} -impl egui::Widget for &mut ViewportWidget { - fn ui(self, ui: &mut egui::Ui) -> egui::Response { + fn should_drag( + &self, + viewport: egui::Rect, + gizmo_active: bool, + pointer: &egui::PointerState, + ) -> bool { + if gizmo_active { + false + } else if !pointer.primary_down() { + false + } else if self.dragging { + true + } else if let Some(pos) = pointer.interact_pos() { + viewport.contains(pos) + } else { + false + } + } + + fn show(&mut self, ui: &mut egui::Ui) { ui.style_mut().spacing.window_margin = egui::style::Margin::same(0.0); let rect = ui.max_rect(); - let id = egui::Id::new("viewport_widget"); - let sense = egui::Sense::click_and_drag(); - let response = ui.interact(rect, id, sense); self.width = rect.width().round() as u32; self.height = rect.height().round() as u32; + self.flycam.resize(self.width, self.height); + self.flycam.update(); + use egui::{pos2, Color32, Mesh, Rect, Shape}; let mut mesh = Mesh::with_texture(self.texture); let uv = Rect::from_min_max(pos2(0.0, 0.0), pos2(1.0, 1.0)); @@ -291,11 +310,22 @@ impl egui::Widget for &mut ViewportWidget { mesh.add_rect_with_uv(rect, uv, tint); ui.painter().add(Shape::mesh(mesh)); - if response.dragged() { - let delta = response.drag_delta(); + let gizmo = egui_gizmo::Gizmo::new("My gizmo") + .viewport(rect) + .view_matrix(self.flycam.get_view().to_cols_array_2d()) + .projection_matrix(self.flycam.get_projection().to_cols_array_2d()); + + let gizmo = gizmo.interact(ui); + + let input = ui.input(); + + self.dragging = self.should_drag(rect, gizmo.is_some(), &input.pointer); + + if self.dragging { + let delta = input.pointer.delta(); self.flycam.process_mouse(delta.x as f64, delta.y as f64); - for event in ui.input().events.iter() { + for event in input.events.iter() { match event { egui::Event::Key { key, pressed, .. } => { use winit::event::{ElementState, VirtualKeyCode}; @@ -324,14 +354,9 @@ impl egui::Widget for &mut ViewportWidget { _ => {} } } - } else if response.drag_released() { + } else { self.flycam.defocus(); } - - self.flycam.resize(self.width, self.height); - self.flycam.update(); - - response } } diff --git a/src/camera.rs b/src/camera.rs index 0a261ad..dd2488e 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -233,16 +233,21 @@ impl Flycam { pub fn get_eye(&self) -> [f32; 4] { self.position.extend(0.0).to_array() } - - pub fn get_vp(&self) -> [[f32; 4]; 4] { + + pub fn get_view(&self) -> glam::Mat4 { // view matrix is inverted camera pose (world space to camera space) let rotation = Mat4::from_quat(self.get_orientation().inverse()); let translation = Mat4::from_translation(-self.position); - let view = rotation * translation; - - // perspective projection - let proj = Mat4::perspective_rh_gl(self.fovy, self.aspect, self.znear, self.zfar); + rotation * translation + } + + pub fn get_projection(&self) -> glam::Mat4 { + Mat4::perspective_rh_gl(self.fovy, self.aspect, self.znear, self.zfar) + } + pub fn get_vp(&self) -> [[f32; 4]; 4] { + let view = self.get_view(); + let proj = self.get_projection(); let vp = proj * view; vp.to_cols_array_2d() }