//! This module contains the rendering structs. use std::cell::Ref; use image; use glium::texture::{RawImage2d, SrgbTexture2d}; use glium::{Frame, Display, Surface, Program, DrawParameters, Depth, VertexBuffer}; use glium::draw_parameters::{DepthTest, Blend}; use glium::index::{NoIndices, PrimitiveType}; use glium::glutin::GlWindow; use scene::Scene; use camera::RenderCamera; use model::{Vertex, Part, Model}; /// A renderer. It contains a display, shaders, and some rendering parameters. pub struct Renderer { /// The display on which the rendering will be done. display: Display, /// The shading program. program: Program, /// The background color. clear_color: (f32, f32, f32, f32), } impl Renderer { /// Creates a new renderer from a display. /// /// Is uses the default shaders and creates an empty vec of models. pub fn new(display: Display) -> Renderer { 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, clear_color: (0.0, 0.0, 0.0, 1.0), } } /// Returns the inner GlWindows. pub fn gl_window(&self) -> Ref { self.display.gl_window() } /// Creates a SrgbTexture from a path to an image. pub fn make_texture(&self, path: &str) -> SrgbTexture2d { let image = image::open(path).unwrap().to_rgba(); let dimensions = image.dimensions(); let image = RawImage2d::from_raw_rgba_reversed(&image.into_raw(), dimensions); SrgbTexture2d::new(&self.display, image).ok().unwrap() } /// Creates a frame from the display. pub fn draw(&self) -> Frame { self.display.draw() } /// Renders on the display. pub fn render(&self, scene: &Scene, camera: &C) { let mut target = self.draw(); target.clear_color_and_depth(self.clear_color, 1.0); let perspective = camera.get_perspective_matrix(); let view = camera.get_view_matrix(); let params = DrawParameters { depth: Depth { test: DepthTest::IfLess, write: true, .. Default::default() }, blend: Blend::alpha_blending(), .. Default::default() }; for model in scene.iter() { let model = &*model.borrow(); for part in &model.parts { if let &Some(ref buffer) = part.vertex_buffer() { let texture = self.get_texture_of_part(&model, part); if let Some(texture) = 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(); } } } } target.finish().unwrap(); } /// Renders a part of a model. fn get_texture_of_part<'a>(&self, model: &'a Model, part: &Part) -> Option<&'a SrgbTexture2d> { if let Some(ref material_name) = part.material_name { if let Some(ref material) = model.materials.get(material_name) { if let Some(ref texture) = material.rendering_texture { Some(texture) } else { None } } else { None } } else { None } } /// Builds a vertex buffer from a vector of vertex. pub fn build_vertex_buffer(&self, vertices: &Vec) -> VertexBuffer { VertexBuffer::new(&self.display, vertices).unwrap() } /// Changes the clear color of the renderer. pub fn set_clear_color(&mut self, r: f32, g: f32, b: f32, a: f32) { self.clear_color = (r, g, b, a); } /// Shows the window if hidden. pub fn show(&mut self) { self.gl_window().show(); } }