Files
vrtue/src/scenes/world.rs
2016-10-05 14:15:16 -07:00

300 lines
10 KiB
Rust

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<Vertex> = (),
trans: gfx::ConstantBuffer<::view::Trans> = "b_trans",
constants: gfx::ConstantBuffer<Constants> = "b_constants",
locals: gfx::ConstantBuffer<Locals> = "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<Vertex>, Vec<u32>) {
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<D: gfx::Device,
F: gfx::Factory<D::Resources>> {
pso: gfx::PipelineState<D::Resources, pipe::Meta>,
camera: na::Matrix4<f32>,
constants: gfx::handle::Buffer<D::Resources, Constants>,
locals: gfx::handle::Buffer<D::Resources, Locals>,
atlas: gfx::handle::ShaderResourceView<D::Resources,
<view::ColorFormat as gfx::format::Formatted>::View>,
sampler: gfx::handle::Sampler<D::Resources>,
f: PhantomData<F>,
vbuf: gfx::handle::Buffer<D::Resources, Vertex>,
slice: gfx::Slice<D::Resources>,
start_time: SystemTime,
treadmills: (f32, f32),
pads: BTreeMap<u32, (TrackMode, Option<openvr_sys::VRControllerState_t>)>,
}
impl<D: gfx::Device, F: gfx::Factory<D::Resources>> WorldScene<D, F> {
pub fn new(factory: &mut F,
encoder: &mut gfx::Encoder<D::Resources, D::CommandBuffer>) -> WorldScene<D, F> {
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<D: gfx::Device,
F: gfx::Factory<D::Resources>> scene::Scene<D, F> for WorldScene<D, F> {
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<D::Resources, D::CommandBuffer>) {
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<D::Resources, D::CommandBuffer>,
trans: &gfx::handle::Buffer<D::Resources, view::Trans>,
target: &gfx::handle::RenderTargetView<D::Resources, view::ColorFormat>,
depth: &gfx::handle::DepthStencilView<D::Resources, view::DepthFormat>) {
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<f32> {
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::<M>(), 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::<model::World>(&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");