handle zoom only within imgui window

This commit is contained in:
Brandon Thomas committed 2020-05-04 02:05:11 -04:00
1 parent c2c9dbceed
commit a06afdde38
6 files changed
+234 -39

No files matched your search

+41 -27
View File
@@ -13,11 +13,18 @@ use point_cloud::point_cloud_visualiser::{ColorizationStrategy, PointCloudVisual
use point_cloud::viewer_image::ViewerImage;
use sensor_control::CaptureProvider;
use webcam::WebcamWriter;
use gui::enhanced_window::EnhancedWindow;
pub const ENABLE_WEBCAM: bool = false;
pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4a_calibration_t) {
let mut webcam_writer = WebcamWriter::open_file("/dev/video0", 1280, 720, 3)
.expect("should be able to create webcamwriter");
let mut webcam_writer = None;
if ENABLE_WEBCAM {
webcam_writer = Some(WebcamWriter::open_file("/dev/video0", 1280, 720, 3)
.expect("should be able to create webcamwriter"));
}
let sdl_arcball = Arc::new(Mutex::new(SdlArcball::new(1280, 720)));
@@ -47,6 +54,7 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
let mut imgui = imgui::Context::create();
imgui.set_ini_filename(None);
imgui.io_mut().config_windows_move_from_title_bar_only = true;
/*let gl_texture_n64 = load_texture("n64logo.png");
let imgui_texture_n64 = TextureId::from(gl_texture_n64 as usize);
@@ -96,10 +104,10 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
let _rebinder = Rebinder::snapshot();
for event in event_pump.poll_iter() {
imgui_sdl2.handle_event(&mut imgui, &event);
// TODO: This is how Imgui appears to tell SDL to ignore certain events.
if imgui_sdl2.ignore_event(&event) { continue; }
match event {
@@ -116,7 +124,6 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
}
}
imgui_sdl2.prepare_frame(imgui.io_mut(), &window, &event_pump.mouse_state());
let now = Instant::now();
@@ -126,28 +133,14 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
imgui.io_mut().delta_time = delta_s;
let ui = imgui.frame();
//ui.show_demo_window(&mut true);
/*Window::new(im_str!("Loading Images"))
.size([1500.0, 1500.0], Condition::FirstUseEver)
.position([0.0, 0.0], Condition::FirstUseEver)
.build(&ui, || {
let mouse_pos = ui.io().mouse_pos;
ui.text(format!(
"Mouse Position: ({:.1},{:.1})",
mouse_pos[0], mouse_pos[1]
));
ui.separator();
Image::new(imgui_texture_n64, [100.0, 100.0]).build(&ui);
ui.separator();
Image::new(imgui_texture_snes, [200.0, 200.0]).build(&ui);
ui.separator();
});*/
//ui.show_demo_window(&mut true);
const window_width : f32 = 1290.0;
const window_height : f32 = 760.0;
Window::new(im_str!("Point Cloud Converter Depth Image"))
.scrollable(true)
.size([window_width, window_height], Condition::FirstUseEver)
.position([0.0, 0.0], Condition::FirstUseEver)
.build(&ui, || {
@@ -169,6 +162,7 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
Window::new(im_str!("Visualizer XYZ Texture"))
.size([window_width, window_height], Condition::FirstUseEver)
.position([window_width + 50.0, 0.0], Condition::FirstUseEver)
.movable(false)
.build(&ui, || {
match imgui_visualizer_xyz_texture.as_ref() {
None => {},
@@ -177,16 +171,34 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
},
}
});
// NB: This is larger. The texture is 1280x1152.
Window::new(&im_str!("Final Output: {:?}", colorization_strategy))
EnhancedWindow::new(&im_str!("Final Output: {:?}", colorization_strategy))
.size([window_width, window_height + 435.0], Condition::FirstUseEver)
.position([window_width + 50.0, window_height + 50.0], Condition::FirstUseEver)
.build(&ui, || {
//Image::new(imgui_kinect_final_output, [1280.0, 1152.0]).build(&ui);
//Image::new(imgui_kinect_final_output, [640.0, 480.0]).build(&ui);
.mouse_inputs(true)
.build(&ui, |window| {
if let Some(mouse_state) = window.get_window_bounded_mouse_state() {
println!("\nwindow_helper.cursor_pos: {:?}", mouse_state);
match sdl_arcball.lock() {
Ok(mut arcball) => arcball.process_mouse_state(mouse_state),
Err(_) => {},
}
}
/*println!("is_window_hovered: {:?}", ui.is_window_hovered());
println!("cursor_pos: {:?}", ui.cursor_pos());
println!("cursor_screen_pos: {:?}", ui.cursor_screen_pos());
println!("window_pos: {:?}", ui.window_pos());
println!("IO mouse pos: {:?}\n", ui.io().mouse_pos);*/
Image::new(imgui_kinect_final_output, [1280.0, 720.0]).build(&ui);
});
//println!("imgui.cursor_pos: {:?}", ui.cursor_pos());
//println!("imgui.cursor_screen_pos: {:?}", ui.cursor_screen_pos());
unsafe {
gl::ClearColor(0.2, 0.2, 0.2, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
@@ -219,8 +231,10 @@ pub fn run(capture_provider: Arc<CaptureProvider>, calibration_data: k4a_sys::k4
Err(_) => {},
}
webcam_writer.write_current_frame_to_file(texture.texture_id())
.expect("should write");
if let Some(mut webcam) = webcam_writer.as_mut() {
webcam.write_current_frame_to_file(texture.texture_id())
.expect("should write");
}
//let change_delta = last_frame - last_change;
//if change_delta > Duration::from_millis(5_000) {
+168
View File
@@ -0,0 +1,168 @@
/// A wrapper around `Imgui::Window` that adds window-scoped devices.
pub struct EnhancedWindow <'a> {
pub window: imgui::Window<'a>,
}
impl <'a> EnhancedWindow <'a> {
pub fn new(name: &'a imgui::ImStr) -> Self {
let mut window = imgui::Window::new(name)
.scrollable(true);
Self {
window,
}
}
/// Enables/disables catching mouse input.
///
/// Enabled by default.
/// Note: Hovering test will pass through when disabled
#[inline]
pub fn mouse_inputs(mut self, value: bool) -> Self {
// NB: Builder API consumes window, so we have to move it.
self.window = self.window.mouse_inputs(value);
self
}
/// Sets the window position, which is applied based on the given condition value
#[inline]
pub fn position(mut self, position: [f32; 2], condition: imgui::Condition) -> Self {
// NB: Builder API consumes window, so we have to move it.
self.window = self.window.position(position, condition);
self
}
/// Sets the window size, which is applied based on the given condition value
#[inline]
pub fn size(mut self, size: [f32; 2], condition: imgui::Condition) -> Self {
// NB: Builder API consumes window, so we have to move it.
self.window = self.window.size(size, condition);
self
}
/// Creates a window and runs a closure to construct the contents.
///
/// Note: the closure is not called if no window content is visible (e.g. window is collapsed
/// or fully clipped).
pub fn build<F>(self, ui: &imgui::Ui, f: F)
where F: FnOnce(WindowScopedUi)
{
if let Some(window) = self.begin(ui) {
let win_helper = WindowScopedUi::new(&ui);
f(win_helper);
window.end(ui);
}
}
/// Creates a window and starts appending to it.
///
/// Returns `Some(WindowToken)` if the window is visible. After content has been
/// rendered, the token must be ended by calling `.end()`.
///
/// Returns `None` if the window is not visible and no content should be rendered.
#[must_use]
pub fn begin(self, ui: &imgui::Ui) -> Option<imgui::WindowToken> {
self.window.begin(ui)
}
}
/// State for a mouse mapped to the dimensions of an `Imgui::Window`.
#[derive(Debug, Clone)]
pub struct CompleteMouseState {
// Cursor position
pub cursor_x: f32,
pub cursor_y: f32,
// Scroll wheel velocity (typically just '0', '1', or '-1').
pub scroll_wheel: f32,
pub scroll_wheel_h: f32,
// Buttons
pub left_button_down: bool,
pub right_button_down: bool,
pub middle_button_down: bool,
pub extra_button_1_down: bool,
pub extra_button_2_down: bool,
}
/// Exposes some reusable calculations on top of `imgui::Ui` in the context of window usage.
pub struct WindowScopedUi<'a> {
ui: &'a imgui::Ui<'a>,
}
impl <'a> WindowScopedUi<'a> {
pub fn new(ui: &'a imgui::Ui) -> Self {
Self {
ui
}
}
/// Returns true if the current window is hovered
#[inline]
pub fn is_window_hovered(&self) -> bool {
self.ui.is_window_hovered()
}
/// Return the cursor position within the window.
/// None is returned if the window isn't hovered, or the mouse is logically not within the drawn
/// texture area.
pub fn get_cursor(&self) -> Option<[f32; 2]> {
if !self.is_window_hovered() {
return None;
}
// Global mouse coordinate
let mouse_pos = self.ui.io().mouse_pos;
// Anchor point of the window's top left corner
let window_pos = self.ui.window_pos();
// Start of textured data (padding offset created by title and window padding).
let cursor_pos = self.ui.cursor_pos();
let x = mouse_pos[0] - window_pos[0] - cursor_pos[0];
let y = mouse_pos[1] - window_pos[1] - cursor_pos[1];
if x.is_sign_negative() || y.is_sign_negative() {
return None; // Outside of bounds (eg. cursor within title area)
}
Some([x, y])
}
/// Return the mouse scroll state. If the mouse is not hovering our window, None is returned.
pub fn get_mouse_wheel(&self) -> Option<f32> {
if self.get_cursor().is_none() {
return None;
}
Some(self.ui.io().mouse_wheel)
}
/// Mouse buttons: 0=left, 1=right, 2=middle + extras
pub fn get_mouse_down(&self) -> Option<[bool; 5]> {
if self.get_cursor().is_none() {
return None;
}
Some(self.ui.io().mouse_down)
}
/// Get the current mouse state
/// If the cursor isn't within the window, None is returned.
pub fn get_window_bounded_mouse_state(&self) -> Option<CompleteMouseState> {
self.get_cursor()
.map(|cursor| {
let io = self.ui.io();
let mouse = io.mouse_down;
CompleteMouseState {
cursor_x: cursor[0],
cursor_y: cursor[1],
scroll_wheel: io.mouse_wheel,
scroll_wheel_h: io.mouse_wheel_h,
left_button_down: mouse[0],
right_button_down: mouse[1],
middle_button_down: mouse[2],
extra_button_1_down: mouse[3],
extra_button_2_down: mouse[4],
}
})
}
}
+2
View File
@@ -0,0 +1,2 @@
//! This module will contain all the Imgui, SDL, mouse controls, etc. code
pub mod enhanced_window;
+1
View File
@@ -32,6 +32,7 @@ use sensor_control::{capture_thread, CaptureProvider};
pub mod conversion;
pub mod core_types;
pub mod graphics_imgui;
pub mod gui;
pub mod imgui_support;
pub mod k4a_sys_wrapper;
pub mod mouse;
+22 -4
View File
@@ -3,6 +3,7 @@ use cgmath::{Matrix4, Vector2};
use cgmath::Vector3;
use sdl2::event::Event;
use sdl2::mouse::MouseButton;
use gui::enhanced_window::CompleteMouseState;
const MIN_ZOOM : f32 = 1.0;
const MAX_ZOOM : f32 = 120.0;
@@ -67,15 +68,22 @@ impl SdlArcball {
}
/// Process an SDL event.
/// This is a bad idea in a multi-window Imgui setup since the SDL coordinates and events take up
/// the entire process window and may be sequestered on a per-window level. That said, this is
/// reasonable for single-window apps.
pub fn process_event(&mut self, event: &Event) {
match event {
Event::MouseWheel { timestamp: _, window_id: _, which: _, x: _, y, direction: _ } => {
self.mouse_wheel(*y);
//println!("Mouse wheel event.");
let y = *y as f32;
self.mouse_wheel(y);
},
Event::MouseButtonDown { timestamp: _, window_id: _, which: _, mouse_btn, clicks: _, x: _, y: _ } => {
//println!("Mouse button down event.");
self.mouse_button_press(mouse_btn, true);
},
Event::MouseButtonUp { timestamp: _, window_id: _, which: _, mouse_btn, clicks: _, x: _, y: _ } => {
//println!("Mouse button up event.");
self.mouse_button_press(mouse_btn, false);
},
Event::MouseMotion { timestamp: _, window_id: _, which: _, mousestate: _, x, y, xrel: _, yrel: _ } => {
@@ -89,6 +97,18 @@ impl SdlArcball {
}
}
/// Process Imgui window-scoped mouse state.
/// Since we don't process individual events, we set all of the internal state at once.
pub fn process_mouse_state(&mut self, mouse_state: CompleteMouseState) {
// TODO: Cleanup
self.right_mouse_active = mouse_state.right_button_down;
self.left_mouse_active = mouse_state.left_button_down;
self.mouse_motion(mouse_state.cursor_x, mouse_state.cursor_y);
self.mouse_wheel(mouse_state.scroll_wheel);
self.last_x = mouse_state.cursor_x;
self.last_y = mouse_state.cursor_y;
}
/// Get the view matrix
pub fn get_view_matrix(&self) -> Matrix4<f32> {
self.arcball.get_mat4()
@@ -159,8 +179,7 @@ impl SdlArcball {
self.animation_counter += 0.05;
}
fn mouse_wheel(&mut self, y: i32) {
let y = y as f32;
fn mouse_wheel(&mut self, y: f32) {
self.arcball.zoom(y, 0.16);
// NB: 'y' is a scroll amount, typically 1 or -1.
@@ -169,7 +188,6 @@ impl SdlArcball {
.min(MAX_ZOOM);
self.last_zoom = zoom;
println!("Zoom: {}", zoom);
}
fn mouse_button_press(&mut self, mouse_button: &MouseButton, down: bool) {
-8
View File
@@ -329,11 +329,6 @@ impl PointCloudRenderer {
point_cloud_texture_index = gl::GetUniformLocation(program_id, POINT_CLOUD_PTR);
}
println!("Uniform view location - view: {:?}", view_index);
println!("Uniform projection location - view: {:?}", projection_index);
println!("Uniform enable shading location - view: {:?}", enable_shading_index);
println!("Uniform point cloud texture location - view: {:?}", point_cloud_texture_index);
let initial_view = [
[-1.0, 0.0, 8.74228e-08, 0.0],
[0.0, 1.0, 0.0, 0.0],
@@ -373,8 +368,6 @@ impl PointCloudRenderer {
/// Update the view matrices
///
pub fn update_view_projection(&mut self, view: [[f32; 4]; 4], projection: [[f32; 4]; 4]) {
println!("\nView Matrix: {:?}", view);
println!("Updated: {:?}", projection);
self.view_matrix = view;
//self.projection_matrix = projection;
@@ -387,7 +380,6 @@ impl PointCloudRenderer {
// Initial: [[1.41272, 0.0, 0.0, 0.0], [0.0, 1.56969, 0.0, 0.0], [0.0, 0.0, -1.002, -1.0], [0.0, 0.0, -0.2002, 0.0]]
// Updated: [[0.88294804, 0.0, 0.0, 0.0], [0.0, 1.5696855, 0.0, 0.0], [0.0, 0.0, -1.002002, -0.2002002], [0.0, 0.0, -1.0, 0.0]]
println!("Initial: {:?}", initial_projection);
self.projection_matrix = initial_projection;
}