2018-02-26 14:59:32 +01:00
|
|
|
use glium::draw_parameters::DepthTest;
|
|
|
|
use glium::texture::{
|
|
|
|
RawImage2d,
|
|
|
|
Texture2d,
|
|
|
|
};
|
2018-02-26 11:45:53 +01:00
|
|
|
use glium::index::{
|
|
|
|
NoIndices,
|
|
|
|
PrimitiveType
|
|
|
|
};
|
|
|
|
use glium::{
|
|
|
|
Program,
|
|
|
|
Display,
|
|
|
|
VertexBuffer,
|
|
|
|
Frame,
|
2018-02-26 14:59:32 +01:00
|
|
|
DrawParameters,
|
|
|
|
Depth,
|
2018-02-26 11:45:53 +01:00
|
|
|
};
|
2018-02-26 14:59:32 +01:00
|
|
|
use image;
|
2018-02-26 11:45:53 +01:00
|
|
|
|
|
|
|
use model::{Model, Vertex};
|
2018-02-26 14:59:32 +01:00
|
|
|
use math::vector::Vector3;
|
|
|
|
|
|
|
|
pub struct RenderMaterial {
|
|
|
|
texture: Option<Texture2d>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RenderMaterial {
|
|
|
|
|
|
|
|
pub fn new() -> RenderMaterial {
|
|
|
|
RenderMaterial {
|
|
|
|
texture: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn from_texture_name(path: &str, display: &Display) -> RenderMaterial {
|
|
|
|
let image = image::open(path);
|
|
|
|
|
|
|
|
if let Ok(image) = image {
|
|
|
|
let image = image.to_rgba();
|
|
|
|
let dim = image.dimensions();
|
|
|
|
let image = RawImage2d::from_raw_rgba_reversed(&image.into_raw(), dim);
|
|
|
|
RenderMaterial {
|
|
|
|
texture: Texture2d::new(display, image).ok()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RenderMaterial {
|
|
|
|
texture: None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Camera {
|
|
|
|
position: Vector3<f32>,
|
|
|
|
target: Vector3<f32>,
|
|
|
|
up: Vector3<f32>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Camera {
|
|
|
|
pub fn new(position: Vector3<f32>, target: Vector3<f32>, up: Vector3<f32>) -> Camera {
|
|
|
|
Camera {
|
|
|
|
position: position,
|
|
|
|
target: target,
|
|
|
|
up: up,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_view_matrix(&self) -> [[f32; 4]; 4] {
|
|
|
|
let f = {
|
|
|
|
let f = self.target - self.position;
|
|
|
|
let len = f[0] * f[0] + f[1] * f[1] + f[2] * f[2];
|
|
|
|
let len = len.sqrt();
|
|
|
|
[f[0] / len, f[1] / len, f[2] / len]
|
|
|
|
};
|
|
|
|
|
|
|
|
let s = [self.up[1] * f[2] - self.up[2] * f[1],
|
|
|
|
self.up[2] * f[0] - self.up[0] * f[2],
|
|
|
|
self.up[0] * f[1] - self.up[1] * f[0]];
|
|
|
|
|
|
|
|
let s_norm = {
|
|
|
|
let len = s[0] * s[0] + s[1] * s[1] + s[2] * s[2];
|
|
|
|
let len = len.sqrt();
|
|
|
|
[s[0] / len, s[1] / len, s[2] / len]
|
|
|
|
};
|
|
|
|
|
|
|
|
let u = [f[1] * s_norm[2] - f[2] * s_norm[1],
|
|
|
|
f[2] * s_norm[0] - f[0] * s_norm[2],
|
|
|
|
f[0] * s_norm[1] - f[1] * s_norm[0]];
|
|
|
|
|
|
|
|
let p = [-self.position[0] * s_norm[0] - self.position[1] * s_norm[1] - self.position[2] * s_norm[2],
|
|
|
|
-self.position[0] * u[0] - self.position[1] * u[1] - self.position[2] * u[2],
|
|
|
|
-self.position[0] * f[0] - self.position[1] * f[1] - self.position[2] * f[2]];
|
|
|
|
|
|
|
|
[
|
|
|
|
[s_norm[0], u[0], f[0], 0.0],
|
|
|
|
[s_norm[1], u[1], f[1], 0.0],
|
|
|
|
[s_norm[2], u[2], f[2], 0.0],
|
|
|
|
[p[0], p[1], p[2], 1.0],
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
2018-02-26 11:45:53 +01:00
|
|
|
|
|
|
|
pub struct Renderer<'a> {
|
|
|
|
display: Display,
|
|
|
|
program: Program,
|
2018-02-26 14:59:32 +01:00
|
|
|
models: Vec<(&'a Model, Vec<(RenderMaterial, VertexBuffer<Vertex>)>)>,
|
2018-02-26 11:45:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Renderer<'a> {
|
|
|
|
pub fn new(display: Display) -> Renderer<'a> {
|
|
|
|
|
|
|
|
let program = Program::from_source(
|
|
|
|
&display,
|
|
|
|
include_str!("../assets/shaders/shader.vert"),
|
|
|
|
include_str!("../assets/shaders/shader.frag"),
|
|
|
|
None
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
Renderer {
|
|
|
|
display: display,
|
|
|
|
program: program,
|
|
|
|
models: vec![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-26 14:59:32 +01:00
|
|
|
pub fn get_perspective_matrix(&self, dimensions: (u32, u32)) -> [[f32; 4]; 4] {
|
|
|
|
let (width, height) = dimensions;
|
|
|
|
let aspect_ratio = height as f32 / width as f32;
|
|
|
|
|
|
|
|
let fov = 3.141592 / 3.0;
|
|
|
|
let zfar = 1024.0;
|
|
|
|
let znear = 0.1;
|
|
|
|
|
|
|
|
use num::Float;
|
|
|
|
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],
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-26 11:45:53 +01:00
|
|
|
pub fn add_model(&mut self, model: &'a Model) {
|
|
|
|
let mut buffers = vec![];
|
|
|
|
|
|
|
|
for part in &model.parts {
|
2018-02-26 14:59:32 +01:00
|
|
|
|
|
|
|
let material = if let Some(ref material_name) = part.material_name {
|
|
|
|
if let Some(material) = model.materials.get(material_name) {
|
|
|
|
if let Some(path) = material.textures.get("map_Kd") {
|
|
|
|
RenderMaterial::from_texture_name(path, &self.display)
|
|
|
|
} else {
|
|
|
|
RenderMaterial::new()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RenderMaterial::new()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RenderMaterial::new()
|
|
|
|
};
|
|
|
|
|
2018-02-26 11:45:53 +01:00
|
|
|
let shape = part.build_shape(&model.vertices, &model.texture_coordinates, &model.normals);
|
2018-02-26 14:59:32 +01:00
|
|
|
buffers.push((material, VertexBuffer::new(&self.display, &shape).unwrap()));
|
2018-02-26 11:45:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
self.models.push((model, buffers));
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn draw(&self) -> Frame {
|
|
|
|
self.display.draw()
|
|
|
|
}
|
|
|
|
|
2018-02-26 14:59:32 +01:00
|
|
|
pub fn render(&self, camera: &Camera, target: &mut Frame) {
|
2018-02-26 11:45:53 +01:00
|
|
|
use glium::Surface;
|
2018-02-26 14:59:32 +01:00
|
|
|
target.clear_color_and_depth((0.0, 0.0, 1.0, 1.0), 1.0);
|
|
|
|
|
|
|
|
let params = DrawParameters {
|
|
|
|
depth: Depth {
|
|
|
|
test: DepthTest::IfLess,
|
|
|
|
write: true,
|
|
|
|
.. Default::default()
|
|
|
|
},
|
|
|
|
.. Default::default()
|
|
|
|
};
|
2018-02-26 11:45:53 +01:00
|
|
|
|
|
|
|
for &(_, ref buffers) in &self.models {
|
2018-02-26 14:59:32 +01:00
|
|
|
for &(ref material, ref buffer) in buffers {
|
|
|
|
|
|
|
|
let perspective = self.get_perspective_matrix(target.get_dimensions());
|
|
|
|
let view = camera.get_view_matrix();
|
|
|
|
|
|
|
|
if let &Some(ref texture) = &material.texture {
|
|
|
|
target.draw(
|
|
|
|
buffer,
|
|
|
|
NoIndices(PrimitiveType::TrianglesList),
|
|
|
|
&self.program,
|
|
|
|
&uniform!(
|
|
|
|
tex: texture,
|
|
|
|
perspective: perspective,
|
|
|
|
view: view,
|
|
|
|
),
|
|
|
|
¶ms,
|
|
|
|
).unwrap();
|
|
|
|
} else {
|
|
|
|
target.draw(
|
|
|
|
buffer,
|
|
|
|
NoIndices(PrimitiveType::TrianglesList),
|
|
|
|
&self.program,
|
|
|
|
&uniform!(
|
|
|
|
perspective: perspective,
|
|
|
|
view: view,
|
|
|
|
),
|
|
|
|
¶ms,
|
|
|
|
).unwrap();
|
|
|
|
};
|
2018-02-26 11:45:53 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|