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::na::ToHomogeneous; use self::num_traits::identities::One; //const R1: f32 = 4096.0; //const R2: f32 = 1024.0; //const R1: f32 = 4.0; //const R2: f32 = 1.0; const R1: f32 = 256.0; const R2: f32 = 64.0; gfx_defines! { vertex Vertex { pos: [f32; 3] = "a_pos", uv: [f32; 2] = "a_uv", tileidx: u32 = "a_tileidx", } constant Constants { anim: u32 = "anim", r1: f32 = "R1", r2: f32 = "R2", } constant Locals { camera: [[f32; 4]; 4] = "camera", millis: u32 = "millis", treadmill_x: f32 = "treadmill_x", treadmill_y: f32 = "treadmill_y", } pipeline pipe { vbuf: gfx::VertexBuffer = (), trans: gfx::ConstantBuffer<::view::Trans> = "b_trans", constants: gfx::ConstantBuffer = "b_constants", locals: gfx::ConstantBuffer = "b_locals", 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(world: &model::World) -> (Vec, Vec) { let mut verticies = Vec::new(); let mut indicies = Vec::new(); let mut v = 0; for (r, row) in world.map().rows().enumerate() { for (c, tile) in row.into_iter().enumerate() { let tileidx = tile.val as u32; let alt = match tileidx { 5 => 0.1, 6 => 0.8, 7 => 0.2, 8 => 1.5, 9 => 1.0, 10 | 11 | 12 => 1.0, _ => 0.0, }; let rf = (((r + 90) % 256) as i16 - 128) as f32; let cf = (((c + 144) % 256) as i16 - 128) as f32; if alt == 0.0 { verticies.extend_from_slice( &[Vertex { pos: [ cf + 0., -rf - 1., 0. ], uv: [0., 0.], tileidx: tileidx }, Vertex { pos: [ cf + 1., -rf - 1., 0. ], uv: [1., 0.], tileidx: tileidx }, Vertex { pos: [ cf + 1., -rf - 0., 0. ], uv: [1., 1.], tileidx: tileidx }, Vertex { pos: [ cf + 0., -rf - 0., 0. ], uv: [0., 1.], tileidx: tileidx },]); indicies.extend_from_slice( &[ v + 0, v + 1, v + 2, v + 2, v + 3, v + 0 ]); v += 4; } else { verticies.extend_from_slice( &[Vertex { pos: [ cf + 0., -rf - 1., 0. ], uv: [0., 0.], tileidx: 126 }, Vertex { pos: [ cf + 1., -rf - 1., 0. ], uv: [1., 0.], tileidx: 126 }, Vertex { pos: [ cf + 1., -rf - 0., 0. ], uv: [1., 1.], tileidx: 126 }, Vertex { pos: [ cf + 0., -rf - 0., 0. ], uv: [0., 1.], tileidx: 126 }, Vertex { pos: [ cf + 0., -rf, 0. ], uv: [0., 0.], tileidx: tileidx }, Vertex { pos: [ cf + 1., -rf, 0. ], uv: [1., 0.], tileidx: tileidx }, Vertex { pos: [ cf + 1., -rf, alt ], uv: [1., 1.], tileidx: tileidx }, Vertex { pos: [ cf + 0., -rf, alt ], uv: [0., 1.], tileidx: tileidx },]); indicies.extend_from_slice( &[ v + 0, v + 1, v + 2, v + 2, v + 3, v + 0, v + 4, v + 5, v + 6, v + 6, v + 7, v + 4 ]); v += 8; } } } (verticies, indicies) } #[derive(Clone, Copy, Debug, Eq, PartialEq)] enum TrackMode { TOUCH, PRESS } pub struct WorldScene> { pso: gfx::PipelineState, camera: na::Matrix4, constants: gfx::handle::Buffer, locals: gfx::handle::Buffer, atlas: gfx::handle::ShaderResourceView::View>, sampler: gfx::handle::Sampler, f: PhantomData, vbuf: gfx::handle::Buffer, slice: gfx::Slice, start_time: SystemTime, treadmills: (f32, f32), pads: BTreeMap)>, } impl> WorldScene { pub fn new(factory: &mut F, encoder: &mut gfx::Encoder) -> WorldScene { let (model, model_idx) = get_model(&get_data_model()); let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&model, &model_idx[..]); let constants = factory.create_constant_buffer(1); encoder.update_constant_buffer(&constants, &Constants { anim: ANIMDATA[0], r1: R1, r2: R2 }); WorldScene { pso: factory.create_pipeline_simple(VERTEX_SHADER_SRC, FRAGMENT_SHADER_SRC, pipe::new()) .expect("create pipeline"), camera: na::Matrix4::one(), constants: constants, locals: factory.create_constant_buffer(1), atlas: tile::get_tiles::<_, _, view::ColorFormat>(factory), sampler: factory.create_sampler(tex::SamplerInfo::new(tex::FilterMethod::Scale, tex::WrapMode::Clamp)), f: PhantomData, vbuf: vertex_buffer, slice: slice, start_time: SystemTime::now(), treadmills: (0.0, 0.0), pads: BTreeMap::new(), } } } const ANIMDATA: [u32; 4] = [1 << 0 | 1 << 1 | 1 << 2, 0, 1 << (68 % 32) | 1 << (69 % 32) | 1 << (70 % 32) | 1 << (71 % 32) | 1 << (76 % 32), 0]; 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, 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; 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 => { let rot = na::Vector3::new(0.0, 0.0, 0.0); let speed = R2 * 0.01; if state.rAxis[0].x > 0.5 { self.camera = na::Similarity3::new(na::Vector3::new(-speed, 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( speed, 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, -speed, 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, speed, 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, treadmill_x: self.treadmills.0, treadmill_y: self.treadmills.1 }); } fn render(&self, _factory: &mut F, encoder: &mut gfx::Encoder, trans: &gfx::handle::Buffer, target: &gfx::handle::RenderTargetView, depth: &gfx::handle::DepthStencilView) { let pipe = pipe::Data { vbuf: self.vbuf.clone(), trans: trans.clone(), constants: self.constants.clone(), locals: self.locals.clone(), atlas: (self.atlas.clone(), self.sampler.clone()), pixcolor: target.clone(), depth: depth.clone(), }; encoder.draw(&self.slice, &self.pso, &pipe); } fn origin(&self) -> na::Matrix4 { na::Similarity3::new(na::Vector3::new(0.0, R1 - R2, 0.0), na::Vector3::new(0.0, 0.0, 0.0), 1.0).to_homogeneous() } } extern crate memmap; fn get_data_model() -> model::World { use self::memmap::{Mmap, Protection}; use std::mem::transmute; fn mmap_to_rows<'a, M: model::HasMap>(mmap: &memmap::Mmap) -> &'a M where M: Copy + 'a { assert_eq!(::std::mem::size_of::(), mmap.len()); unsafe { transmute::<*const u8, &M>(mmap.ptr()) } } let filename = "data/WORLD.MAP"; let file_mmap = Mmap::open_path(filename, Protection::Read).unwrap(); mmap_to_rows::(&file_mmap).clone() } const VERTEX_SHADER_SRC: &'static [u8] = include_bytes!("shader/torus_vertex.glsl"); const FRAGMENT_SHADER_SRC: &'static [u8] = include_bytes!("shader/tile_frag.glsl");