From c67f37c934ee229ad253caca82278fe4b575d18c Mon Sep 17 00:00:00 2001 From: Aaron Fenyes Date: Mon, 9 Sep 2024 19:41:15 -0700 Subject: [PATCH] Implement keyboard navigation --- app-proto/inversive-display/src/main.rs | 143 ++++++++++++++++++------ 1 file changed, 109 insertions(+), 34 deletions(-) diff --git a/app-proto/inversive-display/src/main.rs b/app-proto/inversive-display/src/main.rs index 3dd4653..ef2628a 100644 --- a/app-proto/inversive-display/src/main.rs +++ b/app-proto/inversive-display/src/main.rs @@ -9,9 +9,17 @@ extern crate js_sys; use core::array; -use nalgebra::{DMatrix, DVector}; +use nalgebra::{DMatrix, DVector, Rotation3, Vector3}; use sycamore::{prelude::*, motion::create_raf, rt::{JsCast, JsValue}}; -use web_sys::{console, window, WebGl2RenderingContext, WebGlProgram, WebGlShader, WebGlUniformLocation}; +use web_sys::{ + console, + window, + KeyboardEvent, + WebGl2RenderingContext, + WebGlProgram, + WebGlShader, + WebGlUniformLocation +}; mod engine; @@ -157,6 +165,12 @@ fn main() { // tab selection let tab_selection = create_signal(Tab::GenTab); + // navigation + let pitch_up = create_signal(0.0); + let pitch_down = create_signal(0.0); + let yaw_right = create_signal(0.0); + let yaw_left = create_signal(0.0); + // controls for general example let gen_controls = create_node_ref(); let ctrl_x = create_signal(0.0); @@ -246,8 +260,21 @@ fn main() { let mut last_time = 0.0; // scene parameters - const TURNTABLE_SPEED: f64 = 0.5; - let mut turntable_angle = 0.0; + const NAV_SPEED: f64 = 0.4; // in radians per second + const TURNTABLE_SPEED: f64 = 0.1; // in radians per second + let mut orientation = DMatrix::::identity(5, 5); + let mut rotation = DMatrix::::identity(5, 5); + let location = { + const LEN: f64 = -5.0; + const LEN_SQ: f64 = LEN*LEN; + DMatrix::from_column_slice(5, 5, &[ + 1.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, LEN, + 0.0, 0.0, 2.0*LEN, 1.0, LEN_SQ, + 0.0, 0.0, 0.0, 0.0, 1.0 + ]) + }; /* INSTRUMENTS */ let performance = window().unwrap().performance().unwrap(); @@ -353,11 +380,36 @@ fn main() { let time_step = 0.001*(time - last_time); last_time = time; - // move the turntable + // get the navigation state + let pitch_up_val = pitch_up.get(); + let pitch_down_val = pitch_down.get(); + let yaw_right_val = yaw_right.get(); + let yaw_left_val = yaw_left.get(); let turntable_val = turntable.get(); - if turntable_val { - turntable_angle += TURNTABLE_SPEED * time_step; - } + + // update the construction's orientation + let ang_vel = { + let pitch = pitch_up_val - pitch_down_val; + let yaw = yaw_right_val - yaw_left_val; + let ang_vel_from_keyboard = + if pitch != 0.0 || yaw != 0.0 { + NAV_SPEED * Vector3::new(-pitch, yaw, 0.0).normalize() + } else { + Vector3::zeros() + }; + let ang_vel_from_turntable = + if turntable_val { + Vector3::new(0.0, TURNTABLE_SPEED, 0.0) + } else { + Vector3::zeros() + }; + ang_vel_from_keyboard + ang_vel_from_turntable + }; + let mut rotation_sp = rotation.fixed_view_mut::<3, 3>(0, 0); + rotation_sp.copy_from( + Rotation3::from_scaled_axis(time_step * ang_vel).matrix() + ); + orientation = &rotation * &orientation; if scene_changed.get() { /* INSTRUMENTS */ @@ -369,30 +421,8 @@ fn main() { frames_since_last_sample = 0; } - // set the orientation and translation - let orientation = { - let ang_cos = turntable_angle.cos(); - let ang_sin = turntable_angle.sin(); - DMatrix::from_column_slice(5, 5, &[ - ang_cos, 0.0, ang_sin, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, 0.0, - -ang_sin, 0.0, ang_cos, 0.0, 0.0, - 0.0, 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 0.0, 1.0 - ]) - }; - let translation = { - const LEN: f64 = -5.0; - const LEN_SQ: f64 = LEN*LEN; - DMatrix::from_column_slice(5, 5, &[ - 1.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, LEN, - 0.0, 0.0, 2.0*LEN, 1.0, LEN_SQ, - 0.0, 0.0, 0.0, 0.0, 1.0 - ]) - }; - let construction_to_world = &translation * orientation; + // find the map from construction space to world space + let construction_to_world = &location * &orientation; // update the construction sphere_vec.clear(); @@ -450,7 +480,13 @@ fn main() { ctx.draw_arrays(WebGl2RenderingContext::TRIANGLES, 0, VERTEX_CNT as i32); // clear scene change flag - scene_changed.set(turntable_val); + scene_changed.set( + pitch_up_val != 0.0 + || pitch_down_val != 0.0 + || yaw_left_val != 0.0 + || yaw_right_val != 0.0 + || turntable_val + ); } else { frames_since_last_sample = 0; mean_frame_interval.set(-1.0); @@ -482,7 +518,46 @@ fn main() { } } div { "Mean frame interval: " (mean_frame_interval.get()) " ms" } - canvas(ref=display, width=600, height=600, tabindex=0) + canvas( + ref=display, + width=600, + height=600, + tabindex=0, + on:keydown=move |event: KeyboardEvent| { + let mut navigating = true; + match event.key().as_str() { + "ArrowUp" => pitch_up.set(1.0), + "ArrowDown" => pitch_down.set(1.0), + "ArrowRight" => yaw_right.set(1.0), + "ArrowLeft" => yaw_left.set(1.0), + _ => navigating = false + }; + if navigating { + scene_changed.set(true); + event.prevent_default(); + } + }, + on:keyup=move |event: KeyboardEvent| { + let mut navigating = true; + match event.key().as_str() { + "ArrowUp" => pitch_up.set(0.0), + "ArrowDown" => pitch_down.set(0.0), + "ArrowRight" => yaw_right.set(0.0), + "ArrowLeft" => yaw_left.set(0.0), + _ => navigating = false + }; + if navigating { + scene_changed.set(true); + event.prevent_default(); + } + }, + on:blur=move |_| { + pitch_up.set(0.0); + pitch_down.set(0.0); + yaw_right.set(0.0); + yaw_left.set(0.0); + } + ) div(ref=gen_controls) { label(class="control") { span { "Sphere 0 depth" }