extern crate glium;
use glium::{DisplayBuild, Display, Frame, Program, Surface};
use glium::glutin::{Event,WindowBuilder};
use glium::texture::{RawImage2d,Texture2d};
use therm_model::graph::SceneGraph;
const VERTEX_SHADER: &'static str = include_str!("../data/shaders/vertex.glsl");
const FRAGMENT_SHADER: &'static str = include_str!("../data/shaders/fragment.glsl");
pub struct Graphics<'a> {
disp: Display,
rt: f32,
light: [f32;3],
graph: SceneGraph<'a>,
program: Program,
tex: Texture2d,
}
fn nudge(g: &mut SceneGraph, dx:f32, dy:f32, dz:f32) {
match g {
&mut SceneGraph::Translate(ref mut x, ref mut y, ref mut z, _) => {
*x += dx;
*y += dy;
*z += dz;
},
_ => {},
}
}
impl<'a> Graphics<'a> {
pub fn new(sg: SceneGraph<'a>, t: RawImage2d<(u16,u16,u16,u16)>) -> Self {
let disp = WindowBuilder::new()
.with_title(format!("utmyen"))
.with_depth_buffer(24)
.build_glium()
.unwrap();
let program = Program::from_source(
&disp,
VERTEX_SHADER,
FRAGMENT_SHADER,
None).unwrap();
let tex = Texture2d::with_format(
&disp,
t,
glium::texture::UncompressedFloatFormat::U16U16U16U16,
glium::texture::MipmapsOption::NoMipmap).unwrap();
Graphics {
disp: disp,
rt: 0.0,
light: [-1.0, 0.4, 0.9f32],
graph: sg,
program: program,
tex: tex,
}
}
pub fn run(&mut self) {
loop {
let mut tgt = self.disp.draw();
if ! (Target { frame: &mut tgt }).step(self) {
return;
}
tgt.finish().unwrap();
for ev in self.disp.poll_events() {
match ev {
Event::Closed => return,
Event::KeyboardInput(_, n, _) =>
match n {
9 => return,
24 => self.rt -= 0.1,
25 => nudge(&mut self.graph,0.0,0.0,-DX),
26 => self.rt += 0.1,
38 => nudge(&mut self.graph,DX,0.0,0.0),
39 => nudge(&mut self.graph,0.0,0.0,DX),
40 => nudge(&mut self.graph,-DX,0.0,0.0),
44 => nudge(&mut self.graph,0.0,-DX,0.0),
45 => nudge(&mut self.graph,0.0,DX,0.0),
_ => {},
},
_ => {},
}
}
}
}
}
const DX: f32 = 0.01;
struct Target<'a> {
frame: &'a mut Frame,
}
impl<'a> Target<'a> {
fn step(&mut self, g: &mut Graphics) -> bool {
let params = glium::DrawParameters {
depth: glium::Depth {
test: glium::draw_parameters::DepthTest::IfLess,
write: true,
.. Default::default()
},
.. Default::default()
};
self.frame.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
let mytex = glium::uniforms::Sampler::new(&g.tex)
.minify_filter(glium::uniforms::MinifySamplerFilter::Nearest)
.magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest);
let per = self.perspective();
g.graph.traverse(&mut |model, matrix| {
self.frame.draw(&model.get_vbuf(&g.disp),
&model.get_ibuf(&g.disp),
&g.program,
&uniform! {
perspective: per,
u_light: g.light,
matrix: *matrix,
tx: mytex,
},
¶ms).unwrap();
});
return true;
}
fn perspective(&self) -> [[f32;4];4] {
let (width, height) = self.frame.get_dimensions();
let aspect_ratio = height as f32 / width as f32;
let fov: f32 = 3.141592 / 3.0;
let zfar = 1024.0;
let znear = 0.1;
let f = 1.0 / (fov / 2.0).tan();
[
[f * aspect_ratio , 0.0, 0.0 , 0.0],
[ 0.0 , f , 0.0 , 0.0],
[ 0.0 , 0.0, (zfar+znear)/(zfar-znear) , 1.0],
[ 0.0 , 0.0, -(2.0*zfar*znear)/(zfar-znear), 0.0],
]
}
}