diff --git a/src/bin/vrtue.rs b/src/bin/vrtue.rs index b40ae9d..78cdfad 100644 --- a/src/bin/vrtue.rs +++ b/src/bin/vrtue.rs @@ -26,7 +26,7 @@ pub fn main() { 'main: //while let Some(_) = window.next() { loop { - scene.update(&mut window.encoder); + scene.update(&mut vr, &mut window.encoder); view.draw(&mut window, &mut vr, &scene); // handle window events @@ -38,6 +38,11 @@ pub fn main() { scene.event(Event::Piston(ev)); } + + // handle VR events + while let Some(ev) = vr.poll_next_event() { + scene.event(Event::Vr(ev)); + } } debug!("shutting down"); diff --git a/src/scene.rs b/src/scene.rs index 17069e5..2743301 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -9,6 +9,7 @@ pub trait Scene> { fn event(&mut self, event: Event); fn update(&mut self, + vr: &mut vr::VR, encoder: &mut gfx::Encoder); fn render(&self, factory: &mut F, diff --git a/src/scenes/world.rs b/src/scenes/world.rs index 9408d01..372d2b6 100644 --- a/src/scenes/world.rs +++ b/src/scenes/world.rs @@ -1,17 +1,23 @@ use scene; use tile; use view; +use vr; use world as model; use world::HasMap; extern crate gfx; +extern crate nalgebra as na; +extern crate num_traits; +extern crate openvr_sys; extern crate piston_window; +use std::collections::BTreeMap; use std::marker::PhantomData; use std::time::SystemTime; use gfx::tex; use gfx::traits::FactoryExt; +use self::num_traits::identities::One; gfx_defines! { vertex Vertex { @@ -21,8 +27,11 @@ gfx_defines! { } constant Locals { + camera: [[f32; 4]; 4] = "camera", millis: u32 = "millis", anim: u32 = "anim", + treadmill_x: f32 = "treadmill_x", + treadmill_y: f32 = "treadmill_y", } pipeline pipe { @@ -44,8 +53,8 @@ fn get_model(world: &model::World) -> (Vec, Vec) { for (r, row) in world.map().rows().enumerate() { for (c, tile) in row.into_iter().enumerate() { let tileidx = tile.val as u32; - let rf = (((r + 26) % 256) as i16 - 128) as f32; - let cf = (((c + 48) % 256) as i16 - 128) as f32; + let rf = (((r + 90) % 256) as i16 - 128) as f32; + let cf = (((c + 144) % 256) as i16 - 128) as f32; verticies.extend_from_slice( &[Vertex { pos: [ cf + 0., 0., -rf - 1. ], uv: [0., 0.], tileidx: tileidx }, Vertex { pos: [ cf + 1., 0., -rf - 1. ], uv: [1., 0.], tileidx: tileidx }, @@ -60,9 +69,16 @@ fn get_model(world: &model::World) -> (Vec, Vec) { (verticies, indicies) } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum TrackMode { + TOUCH, + PRESS +} + pub struct WorldScene> { pso: gfx::PipelineState, + camera: na::Matrix4, locals: gfx::handle::Buffer, atlas: gfx::handle::ShaderResourceView::View>, @@ -73,6 +89,8 @@ pub struct WorldScene, start_time: SystemTime, + treadmills: (f32, f32), + pads: BTreeMap)>, } impl> WorldScene { @@ -86,6 +104,7 @@ impl> WorldScene { FRAGMENT_SHADER_SRC, pipe::new()) .expect("create pipeline"), + camera: na::Matrix4::one(), locals: factory.create_constant_buffer(1), atlas: tile::get_tiles::<_, _, view::ColorFormat>(factory), sampler: factory.create_sampler(tex::SamplerInfo::new(tex::FilterMethod::Scale, @@ -95,6 +114,8 @@ impl> WorldScene { vbuf: vertex_buffer, slice: slice, start_time: SystemTime::now(), + treadmills: (0.0, 0.0), + pads: BTreeMap::new(), } } } @@ -109,15 +130,78 @@ impl> scene::Scene for WorldScene { fn event(&mut self, event: scene::Event) { + use scene::Event::*; + use vr::Event::*; + match event { + Vr(Touch { dev_idx, controller }) => { + self.pads.insert(dev_idx, (TrackMode::TOUCH, None)); + }, + Vr(Press { dev_idx, controller }) => { + self.pads.insert(dev_idx, (TrackMode::PRESS, None)); + }, + Vr(Unpress { dev_idx, controller }) => { + self.pads.insert(dev_idx, (TrackMode::TOUCH, None)); + }, + Vr(Untouch { dev_idx, controller }) => { + self.pads.remove(&dev_idx); + }, + _ => () + } } fn update(&mut self, - encoder: &mut gfx::Encoder) { + vr: &mut vr::VR, + encoder: &mut gfx::Encoder) { const NANOS_PER_MILLI: u32 = 1_000_000; const MILLIS_PER_SEC: u64 = 1_000; let elapsed = self.start_time.elapsed().expect("scene timer"); let millis = elapsed.subsec_nanos() / NANOS_PER_MILLI + (elapsed.as_secs() * MILLIS_PER_SEC) as u32; - encoder.update_constant_buffer(&self.locals, &Locals { millis: millis, anim: ANIMDATA[0] }); + + for (pad, track) in self.pads.iter_mut() { + let mode = track.0; + if let Some(state) = vr.get_controller_state(*pad) { + if let Some(old_state) = track.1 { + match mode { + TrackMode::TOUCH => { + const THRESHOLD: f32 = 0.005; + const SCALE: f32 = 32.0; + let xdiff = state.rAxis[0].x - old_state.rAxis[0].x; + let ydiff = state.rAxis[0].y - old_state.rAxis[0].y; + if xdiff.abs() > THRESHOLD { self.treadmills.0 += SCALE * xdiff; } + if ydiff.abs() > THRESHOLD { self.treadmills.1 += SCALE * ydiff; } + }, + TrackMode::PRESS => { + use self::na::ToHomogeneous; + let rot = na::Vector3::new(0.0, 0.0, 0.0); + if state.rAxis[0].x > 0.5 { + self.camera = na::Similarity3::new(na::Vector3::new(-0.5, 0.0, 0.0), + rot, 1.0).to_homogeneous() * self.camera; + } if state.rAxis[0].x < -0.5 { + self.camera = na::Similarity3::new(na::Vector3::new( 0.5, 0.0, 0.0), + rot, 1.0).to_homogeneous() * self.camera; + } if state.rAxis[0].y > 0.5 { + self.camera = na::Similarity3::new(na::Vector3::new( 0.0, -0.5, 0.0), + rot, 1.0).to_homogeneous() * self.camera; + } if state.rAxis[0].y < -0.5 { + self.camera = na::Similarity3::new(na::Vector3::new( 0.0, 0.5, 0.0), + rot, 1.0).to_homogeneous() * self.camera; + } + }, + } + + if state.unPacketNum == old_state.unPacketNum { + continue; + } + } + *track = (mode, Some(state)); + } + } + + encoder.update_constant_buffer(&self.locals, &Locals { camera: *(self.camera).as_ref(), + millis: millis, + anim: ANIMDATA[0], + treadmill_x: self.treadmills.0, + treadmill_y: self.treadmills.1 }); } fn render(&self, @@ -158,6 +242,7 @@ fn get_data_model() -> model::World { const VERTEX_SHADER_SRC: &'static [u8] = br#" #version 150 + #define PI 3.1415926538 in vec3 a_pos; in vec2 a_uv; @@ -168,20 +253,25 @@ const VERTEX_SHADER_SRC: &'static [u8] = br#" mat4 u_matrix; }; uniform b_locals { + mat4 camera; uint millis; uint animdata; + float treadmill_x; + float treadmill_y; }; void main() { v_uv = a_uv; v_tileidx = a_tileidx; - float TWO_PI_CIRC = 44.0 / 7.0 / 256.0; + float TWO_PI_CIRC = 2 * PI / 256.0; float R = 128.0; float R2 = 16.0; - gl_Position = u_matrix * vec4(R * -1.0 * sin(TWO_PI_CIRC * a_pos.x), // "z" - (R + R2 * cos(TWO_PI_CIRC * a_pos.x)) * cos(TWO_PI_CIRC * a_pos.z), // "x" - (R + R2 * cos(TWO_PI_CIRC * a_pos.x)) * sin(TWO_PI_CIRC * a_pos.z), // "y" + + gl_Position = u_matrix * camera * vec4(R * -1.0 * sin(TWO_PI_CIRC * (a_pos.x + treadmill_x)), + (R + R2 * cos(TWO_PI_CIRC * (a_pos.x + treadmill_x))) * cos(TWO_PI_CIRC * (a_pos.z + treadmill_y)), + (R + R2 * cos(TWO_PI_CIRC * (a_pos.x + treadmill_x))) * sin(TWO_PI_CIRC * (a_pos.z + treadmill_y)), 1.0); + /* float which = (1.0 + sin(float(millis) / 5000.)) / 2.0; gl_Position = u_matrix * vec4(a_pos.x, @@ -201,9 +291,12 @@ const FRAGMENT_SHADER_SRC: &'static [u8] = br#" out vec4 pixcolor; uniform sampler2D t_atlas; uniform b_locals { + mat4 camera; uint millis; //uvec4 animdata; uint animdata; + float treadmill_x; + float treadmill_y; }; void main() { diff --git a/src/view.rs b/src/view.rs index a5294e3..5996743 100644 --- a/src/view.rs +++ b/src/view.rs @@ -17,7 +17,7 @@ pub type ColorFormat = gfx::format::Srgba8; pub type DepthFormat = gfx::format::DepthStencil; const NEAR: f32 = 0.01; -const FAR: f32 = 1000000.0; +const FAR: f32 = 1000.0; gfx_constant_struct! { Trans { @@ -75,11 +75,15 @@ impl ViewRoot { window.encoder.clear_depth(&buffers.depth, 1.0); - // Submit eye textures + // Submit eye textures let proj_mat = vr.projection_matrix(eye, NEAR, FAR); let eye_mat = vr.head_to_eye_transform(eye); - let trans = Trans { matrix: *(proj_mat * eye_mat * hmd_mat).as_ref() }; + use self::na::ToHomogeneous; + let view_mat = na::Similarity3::new(na::Vector3::new(0.0, 128.0 - 16.0, 0.0), + na::Vector3::new(0.0, 0.0, 0.0), 1.0).to_homogeneous(); + + let trans = Trans { matrix: *(proj_mat * eye_mat * hmd_mat * view_mat).as_ref() }; window.encoder.update_constant_buffer(&self.trans, &trans); scene.render(&mut window.factory,