From 7a9f65115c0e4aca81f45103f7518743c53a4d56 Mon Sep 17 00:00:00 2001 From: Jared Roberts Date: Wed, 21 Sep 2016 19:38:27 -0700 Subject: [PATCH] refactor view/scene to separate modules --- src/bin/gl.rs | 218 -------------------------------------------- src/bin/vrtue.rs | 40 ++++++++ src/lib.rs | 4 + src/scene.rs | 15 +++ src/scenes/mod.rs | 1 + src/scenes/world.rs | 123 +++++++++++++++++++++++++ src/tile.rs | 5 +- src/view.rs | 111 ++++++++++++++++++++++ src/vr.rs | 16 +++- src/world.rs | 2 + 10 files changed, 311 insertions(+), 224 deletions(-) delete mode 100644 src/bin/gl.rs create mode 100644 src/bin/vrtue.rs create mode 100644 src/scene.rs create mode 100644 src/scenes/mod.rs create mode 100644 src/scenes/world.rs create mode 100644 src/view.rs diff --git a/src/bin/gl.rs b/src/bin/gl.rs deleted file mode 100644 index 26d600b..0000000 --- a/src/bin/gl.rs +++ /dev/null @@ -1,218 +0,0 @@ -extern crate vrtue; -use vrtue::{tile, vr}; -use vrtue::vr::AsMatrix4; - -extern crate env_logger; -#[macro_use] extern crate gfx; -extern crate gl; -#[macro_use] extern crate log; -extern crate nalgebra as na; -extern crate num_traits; -extern crate piston_window; - -use gfx::{tex, Device, Factory}; -use gfx::traits::FactoryExt; -use na::Inverse; -use num_traits::identities::One; -use piston_window::{PistonWindow, Window, WindowSettings}; - -pub type ColorFormat = gfx::format::Srgba8; -pub type DepthFormat = gfx::format::DepthStencil; - -const NEAR: f32 = 0.01; -const FAR: f32 = 1000.0; - -gfx_defines!{ - vertex Vertex { - pos: [f32; 3] = "a_pos", - uv: [f32; 2] = "a_uv", - } - - constant Trans { - matrix: [[f32; 4]; 4] = "u_matrix", - } - - pipeline pipe { - vbuf: gfx::VertexBuffer = (), - trans: gfx::ConstantBuffer = "b_trans", - tiles: gfx::TextureSampler<[f32; 4]> = "t_tiles", - pixcolor: gfx::RenderTarget = "pixcolor", - depth: gfx::DepthTarget = gfx::preset::depth::LESS_EQUAL_WRITE, - } -} - -const POLYGON: [Vertex; 4] = [ - Vertex { pos: [ -0.25, -0.25, 0. ], uv: [0., 0.] }, - Vertex { pos: [ 0.25, -0.25, 0. ], uv: [1., 0.] }, - Vertex { pos: [ 0.25, 0.25, 0. ], uv: [1., 1.] }, - Vertex { pos: [ -0.25, 0.25, 0. ], uv: [0., 1.] } -]; -const POLYGON_IDX: &'static [u16] = &[ 0, 1, 2, - 2, 3, 0 ]; - -fn main() { - env_logger::init().expect("env logger"); - let mut vr = vr::VR::new().expect("VR init"); - let render_size = vr.recommended_render_target_size(); - - let mut window: PistonWindow = - WindowSettings::new("Hello Virtual World!", [512; 2]) - .exit_on_esc(true) - .vsync(false) - .build().expect("Building Window"); - - let pso = window.factory.create_pipeline_simple(VERTEX_SHADER_SRC, - FRAGMENT_SHADER_SRC, - pipe::new()) - .expect("create pipeline"); - - let (tex_left, tgt_left, depth_left) = vr::create_eyebuffer(&mut window.factory, render_size) - .expect("create left renderbuffer"); - let (tex_right, tgt_right, depth_right) = vr::create_eyebuffer(&mut window.factory, render_size) - .expect("create right renderbuffer"); - let (vertex_buffer, slice) = window.factory.create_vertex_buffer_with_slice(&POLYGON, POLYGON_IDX); - - let tiles = tile::get_tiles::<_, _, ColorFormat>(&mut window.factory); - let nn_sampler = window.factory.create_sampler( - tex::SamplerInfo::new(tex::FilterMethod::Scale, - tex::WrapMode::Clamp)); - - let pipe_monitor = pipe::Data { - vbuf: vertex_buffer.clone(), - trans: window.factory.create_constant_buffer(1), - tiles: (tiles.clone(), nn_sampler.clone()), - pixcolor: window.output_color.clone(), - depth: window.output_stencil.clone(), - }; - let pipe_left = pipe::Data { - vbuf: vertex_buffer.clone(), - trans: window.factory.create_constant_buffer(1), - tiles: (tiles.clone(), nn_sampler.clone()), - pixcolor: tgt_left, - depth: depth_left, - }; - let pipe_right = pipe::Data { - vbuf: vertex_buffer.clone(), - trans: window.factory.create_constant_buffer(1), - tiles: (tiles.clone(), nn_sampler.clone()), - pixcolor: tgt_right, - depth: depth_right, - }; - window.encoder.update_constant_buffer( - &pipe_monitor.trans, - &Trans { matrix: *na::Matrix4::one().as_ref() }); - - let mut frame = 0u32; - window.window.swap_buffers(); frame += 1; // To contain setup calls to Frame 0 in apitrace - 'main: - //while let Some(_) = window.next() { - loop { - info!("Frame #{}", frame); - let _now = std::time::SystemTime::now(); - - // Get the current sensor state - let poses = vr.poses(); - trace!("\t{:?} got pose", _now.elapsed()); - if frame % 90 == 0 { - debug!("\t#{}: poses:", frame); - let mut devnum = 0; - for track in (0..poses.count).map(|pose| poses.poses[pose]) { - match track.device_class() { - vr::TrackedDeviceClass::Invalid => (), - _ => debug!("\t\t#{}: {:?} = valid? {}, connected? {}\n\t\t\t{:?}\n\t\t\t{:?}", - devnum, - track.device_class(), - track.is_valid, - track.is_connected, - track.to_device, - track.velocity) - } - devnum += 1; - } - debug!(""); - } - frame += 1; - - let mut hmd_mat = poses.poses[0].to_device.as_matrix4(); - hmd_mat.inverse_mut(); - - for pass in [(Some((vr::Eye::Left, &tex_left)), &pipe_left), - (Some((vr::Eye::Right, &tex_right)), &pipe_right), - (None, &pipe_monitor),] - .into_iter() { - info!("\tpass for eye: {:?}", pass.0); - window.encoder.clear(&pass.1.pixcolor, [0.1, 0.2, 0.3, 1.0]); - window.encoder.clear_depth(&pass.1.depth, 1.0); - - // Submit eye textures - if let Some((eye, tex)) = pass.0 { - let proj_mat = vr.projection_matrix(eye, NEAR, FAR); - let eye_mat = vr.head_to_eye_transform(eye); - for track in (0..poses.count).map(|pose| poses.poses[pose]) { - match track.device_class() { - vr::TrackedDeviceClass::Controller | - vr::TrackedDeviceClass::TrackingReference => { - let model_mat = track.to_device.as_matrix4(); - - let trans = Trans { matrix: *(proj_mat * eye_mat * hmd_mat * model_mat).as_ref() }; - window.encoder.update_constant_buffer(&pass.1.trans, &trans); - - window.encoder.draw(&slice, &pso, pass.1); - window.encoder.flush(&mut window.device); - }, - _ => () - } - } - - vr.submit(eye, tex); - trace!("\t\t{:?} submit {:?}", _now.elapsed(), eye); - } else { - window.encoder.draw(&slice, &pso, pass.1); - window.encoder.flush(&mut window.device); - window.window.swap_buffers(); - } - } - window.device.cleanup(); - - // handle window events - while let Some(ev) = window.poll_event() { - match ev { - piston_window::Input::Text(_) => break 'main, - _ => debug!("\t{:?}", ev) - } - } - } - - debug!("shutting down"); -} - -const VERTEX_SHADER_SRC: &'static [u8] = br#" - #version 140 - - in vec3 a_pos; - in vec2 a_uv; - out vec3 v_color; - out vec2 v_uv; - uniform b_trans { - mat4 u_matrix; - }; - - void main() { - v_uv = a_uv; - gl_Position = u_matrix * vec4(a_pos, 1.0); - } -"#; - -const FRAGMENT_SHADER_SRC: &'static [u8] = br#" - #version 140 - - in vec3 v_color; - in vec2 v_uv; - out vec4 pixcolor; - uniform sampler2D t_tiles; - - void main() { - vec2 uv = vec2(v_uv.x, 31.0 / 256 + (1.0 - v_uv.y) / 256.0); - pixcolor = texture(t_tiles, uv); - } -"#; diff --git a/src/bin/vrtue.rs b/src/bin/vrtue.rs new file mode 100644 index 0000000..55bb364 --- /dev/null +++ b/src/bin/vrtue.rs @@ -0,0 +1,40 @@ +extern crate vrtue; +use vrtue::{view, vr}; + +extern crate env_logger; +extern crate gfx_device_gl; +#[macro_use] extern crate log; +extern crate piston_window; + +use self::piston_window::{PistonWindow, Window, WindowSettings}; + +pub fn main() { + env_logger::init().expect("env logger"); + let mut vr = vr::VR::new().expect("VR init"); + + let mut window: PistonWindow = + WindowSettings::new("Hello Virtual World!", [512; 2]) + .exit_on_esc(true) + .vsync(false) + .build().expect("Building Window"); + + let view = view::ViewRoot::::create_view(&mut window, &mut vr); + + 'main: + //while let Some(_) = window.next() { + loop { + view.draw(&mut window, &mut vr); + + // handle window events + while let Some(ev) = window.poll_event() { + match ev { + piston_window::Input::Text(_) => break 'main, + _ => debug!("\t{:?}", ev) + } + } + } + + debug!("shutting down"); +} diff --git a/src/lib.rs b/src/lib.rs index 8caac36..c6c35ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,11 +1,15 @@ #![feature(conservative_impl_trait)] +#[macro_use] extern crate gfx; #[macro_use] extern crate log; pub mod arena; pub mod ega; +pub mod scene; +pub mod scenes; pub mod tile; pub mod town; +pub mod view; pub mod vr; pub mod world; diff --git a/src/scene.rs b/src/scene.rs new file mode 100644 index 0000000..07acc8a --- /dev/null +++ b/src/scene.rs @@ -0,0 +1,15 @@ +use view; + +extern crate gfx; +extern crate gfx_device_gl; +extern crate piston_window; + +pub trait Scene> { + fn update(&mut self); + fn render(&self, + factory: &mut F, + encoder: &mut gfx::Encoder, + target: &gfx::handle::RenderTargetView, + depth: &gfx::handle::DepthStencilView); +} diff --git a/src/scenes/mod.rs b/src/scenes/mod.rs new file mode 100644 index 0000000..ed714d6 --- /dev/null +++ b/src/scenes/mod.rs @@ -0,0 +1 @@ +pub mod world; diff --git a/src/scenes/world.rs b/src/scenes/world.rs new file mode 100644 index 0000000..77bbbc5 --- /dev/null +++ b/src/scenes/world.rs @@ -0,0 +1,123 @@ +use scene; +use tile; +use view; + +extern crate gfx; +extern crate piston_window; + +use std::marker::PhantomData; + +use gfx::tex; +use gfx::traits::FactoryExt; + +gfx_defines! { + vertex Vertex { + pos: [f32; 3] = "a_pos", + uv: [f32; 2] = "a_uv", + tileidx: u32 = "a_tileidx", + } + + pipeline pipe { + vbuf: gfx::VertexBuffer = (), + trans: gfx::ConstantBuffer<::view::Trans> = "b_trans", + atlas: gfx::TextureSampler<[f32; 4]> = "t_atlas", + pixcolor: gfx::RenderTarget<::view::ColorFormat> = "pixcolor", + depth: gfx::DepthTarget<::view::DepthFormat> = gfx::preset::depth::LESS_EQUAL_WRITE, + } +} + + +fn get_model(/*x: u16, y: u16,*/ tile: &tile::Tile) -> ([Vertex; 4], [u16; 6]) { + let tileidx = tile.val as u32; + ([Vertex { pos: [ 0., 0., 0. ], uv: [0., 0.], tileidx: tileidx }, + Vertex { pos: [ 1., 0., 0. ], uv: [1., 0.], tileidx: tileidx }, + Vertex { pos: [ 1., 0., 1. ], uv: [1., 1.], tileidx: tileidx }, + Vertex { pos: [ 0., 0., 1. ], uv: [0., 1.], tileidx: tileidx },], + [ 0, 1, 2, + 2, 3, 0 ]) +} + +pub struct WorldScene> { + pso: gfx::PipelineState, + trans: gfx::handle::Buffer, + atlas: gfx::handle::ShaderResourceView::View>, + sampler: gfx::handle::Sampler, + f: PhantomData +} + +impl> WorldScene { + pub fn new(factory: &mut F, trans: &gfx::handle::Buffer) -> WorldScene { + WorldScene { + pso: factory.create_pipeline_simple(VERTEX_SHADER_SRC, + FRAGMENT_SHADER_SRC, + pipe::new()) + .expect("create pipeline"), + trans: trans.clone(), + atlas: tile::get_tiles::<_, _, view::ColorFormat>(factory), + sampler: factory.create_sampler(tex::SamplerInfo::new(tex::FilterMethod::Scale, + tex::WrapMode::Clamp)), + f: PhantomData, + } + } +} + +impl> scene::Scene for WorldScene { + + fn update(&mut self) { + } + + fn render(&self, + factory: &mut F, + encoder: &mut gfx::Encoder, + target: &gfx::handle::RenderTargetView, + depth: &gfx::handle::DepthStencilView) { + let (model, model_idx) = get_model(&tile::Tile { val: 31 }); + let (vertex_buffer, slice) = + factory.create_vertex_buffer_with_slice(&model, &model_idx[..]); + + let pipe = pipe::Data { + vbuf: vertex_buffer.clone(), + trans: self.trans.clone(), + atlas: (self.atlas.clone(), self.sampler.clone()), + pixcolor: target.clone(), + depth: depth.clone(), + }; + encoder.draw(&slice, &self.pso, &pipe); + } +} + +const VERTEX_SHADER_SRC: &'static [u8] = br#" + #version 150 + + in vec3 a_pos; + in vec2 a_uv; + in uint a_tileidx; + out vec2 v_uv; + flat out uint v_tileidx; + uniform b_trans { + mat4 u_matrix; + }; + + void main() { + v_uv = a_uv; + v_tileidx = a_tileidx; + gl_Position = u_matrix * vec4(a_pos, 1.0); + } +"#; + +const FRAGMENT_SHADER_SRC: &'static [u8] = br#" + #version 150 + + in vec2 v_uv; + flat in uint v_tileidx; + out vec4 pixcolor; + uniform sampler2D t_atlas; + + void main() { + vec2 uv = vec2(v_uv.x, float(v_tileidx) / 256.0 + (1.0 - v_uv.y) / 256.0); + pixcolor = texture(t_atlas, uv); + } +"#; diff --git a/src/tile.rs b/src/tile.rs index f83e947..3c4aa1c 100644 --- a/src/tile.rs +++ b/src/tile.rs @@ -8,9 +8,10 @@ use std::path::Path; use self::gfx::tex; +#[repr(C)] #[derive(Clone, Copy)] pub struct Tile { - val: u8, + pub val: u8, } pub fn get_tiles(factory: &mut F) -> (//gfx::handle::Texture, @@ -31,6 +32,8 @@ pub fn get_tiles(factory: &mut F) -> (//gfx::handle::Texture char { match self.val { diff --git a/src/view.rs b/src/view.rs new file mode 100644 index 0000000..52b3972 --- /dev/null +++ b/src/view.rs @@ -0,0 +1,111 @@ +use scenes; +use vr; +use vr::{AsMatrix4, VR}; + +extern crate gfx_device_gl; +extern crate nalgebra as na; +extern crate num_traits; +extern crate piston_window; + +use gfx; +use gfx::Device; +use gfx::traits::FactoryExt; +use self::na::Inverse; +use self::num_traits::identities::One; +use self::piston_window::{PistonWindow, Window}; + +pub type ColorFormat = gfx::format::Srgba8; +pub type DepthFormat = gfx::format::DepthStencil; + +const NEAR: f32 = 0.01; +const FAR: f32 = 1000.0; + +gfx_constant_struct! { + Trans { + matrix: [[f32; 4]; 4] = "u_matrix", + } +} + +pub struct ViewRoot + where Dev: gfx::Device, + T: gfx::format::RenderFormat + gfx::format::TextureFormat, + D: gfx::format::DepthFormat + gfx::format::TextureFormat { + + left: vr::EyeBuffer, + right: vr::EyeBuffer, + trans: gfx::handle::Buffer, + scene: Box<::scene::Scene>, +} + +impl ViewRoot { + pub fn create_view(window: &mut PistonWindow, vr: &VR) + -> ViewRoot { + + let render_size = vr.recommended_render_target_size(); + let left = vr::create_eyebuffer(&mut window.factory, render_size) + .expect("create left renderbuffer"); + let right = vr::create_eyebuffer(&mut window.factory, render_size) + .expect("create right renderbuffer"); + let trans = window.factory.create_constant_buffer(1); + + window.window.swap_buffers(); // To contain setup calls to Frame 0 in apitrace + + ViewRoot:: { + left: left, + right: right, + trans: trans.clone(), + scene: Box::new(scenes::world::WorldScene::new(&mut window.factory, &trans)), + } + } + + pub fn draw(&self, + window: &mut PistonWindow, + vr: &mut vr::VR) { + // Get the current sensor state + let poses = vr.poses(); + + let mut hmd_mat = poses.poses[0].to_device.as_matrix4(); + hmd_mat.inverse_mut(); + + for &(eye, buffers) in [(vr::Eye::Left, &self.left), + (vr::Eye::Right, &self.right)].into_iter() { + window.encoder.clear(&buffers.target, [0.1, 0.2, 0.3, 1.0]); + + window.encoder.clear_depth(&buffers.depth, 1.0); + + // Submit eye textures + let proj_mat = vr.projection_matrix(eye, NEAR, FAR); + let eye_mat = vr.head_to_eye_transform(eye); + for track in (0..poses.count).map(|pose| poses.poses[pose]) { + match track.device_class() { + vr::TrackedDeviceClass::Controller | + vr::TrackedDeviceClass::TrackingReference => { + let model_mat = track.to_device.as_matrix4(); + + let trans = Trans { matrix: *(proj_mat * eye_mat * hmd_mat * model_mat).as_ref() }; + window.encoder.update_constant_buffer(&self.trans, &trans); + + self.scene.render(&mut window.factory, + &mut window.encoder, + &buffers.target, + &buffers.depth); + }, + _ => () + } + } + + } + // draw monitor window + window.encoder.update_constant_buffer(&self.trans, + &Trans { matrix: *na::Matrix4::one().as_ref() }); + window.encoder.clear(&window.output_color, [0.1, 0.2, 0.3, 1.0]); + window.encoder.clear_depth(&window.output_stencil, 1.0); + self.scene.render(&mut window.factory, &mut window.encoder, &window.output_color, &window.output_stencil); + + window.encoder.flush(&mut window.device); + vr.submit(vr::Eye::Left, &self.left.tex); + vr.submit(vr::Eye::Right, &self.right.tex); + window.window.swap_buffers(); + window.device.cleanup(); + } +} diff --git a/src/vr.rs b/src/vr.rs index 1ed6dd4..e0254b2 100644 --- a/src/vr.rs +++ b/src/vr.rs @@ -87,12 +87,18 @@ impl AsMatrix4 for [[N; 4]; 4] { } } +pub struct EyeBuffer + where T: gfx::format::RenderFormat + gfx::format::TextureFormat, + D: gfx::format::DepthFormat + gfx::format::TextureFormat { + + pub tex: gfx::handle::Texture, + pub target: gfx::handle::RenderTargetView, + pub depth: gfx::handle::DepthStencilView, +} + pub fn create_eyebuffer(factory: &mut gfx_device_gl::Factory, size: vr::common::Size) - -> Result<(gfx::handle::Texture, - gfx::handle::RenderTargetView, - gfx::handle::DepthStencilView), - gfx::CombinedError> + -> Result, gfx::CombinedError> where T: gfx::format::RenderFormat + gfx::format::TextureFormat, D: gfx::format::DepthFormat + gfx::format::TextureFormat { let tex = try!(factory.create_texture( @@ -104,5 +110,5 @@ pub fn create_eyebuffer(factory: &mut gfx_device_gl::Factory, let tgt = try!(factory.view_texture_as_render_target(&tex, 0, None)); let depth = try!(factory.create_depth_stencil_view_only(size.width as tex::Size, size.height as tex::Size)); - Ok((tex, tgt, depth)) + Ok(EyeBuffer { tex: tex, target: tgt, depth: depth }) } diff --git a/src/world.rs b/src/world.rs index a1a9324..2615cc0 100644 --- a/src/world.rs +++ b/src/world.rs @@ -21,6 +21,7 @@ pub trait HasMap { const CHUNKDIM: usize = 32; pub type ChunkRow = [Tile; CHUNKDIM]; pub type ChunkRect = [ChunkRow; CHUNKDIM]; +#[repr(C)] #[derive(Clone, Copy)] pub struct Chunk { pub rect: ChunkRect, @@ -53,6 +54,7 @@ impl<'a> IntoIterator for &'a Chunk { const WORLDDIM: usize = 8; pub type WorldRow = [Chunk; WORLDDIM]; pub type WorldRect = [WorldRow; WORLDDIM]; +#[repr(C)] #[derive(Clone, Copy)] pub struct World { pub rect: WorldRect,