Merge branch 'render'
This commit is contained in:
commit
c8c9e12ea9
|
@ -1,5 +1,4 @@
|
||||||
|
|
||||||
/target/
|
/target/
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
assets
|
assets/models
|
||||||
|
|
|
@ -6,6 +6,7 @@ authors = ["Thomas Forgione <thomas@tforgione.fr>"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
num = "*"
|
num = "*"
|
||||||
glium = "*"
|
glium = "*"
|
||||||
|
image = "*"
|
||||||
verbose-log = { git = "https://gitea.tforgione.fr/dash-3d/verbose-log" }
|
verbose-log = { git = "https://gitea.tforgione.fr/dash-3d/verbose-log" }
|
||||||
byteorder = "*"
|
byteorder = "*"
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
varying vec3 fNormal;
|
#version 140
|
||||||
varying vec4 fFrontColor;
|
|
||||||
|
|
||||||
vec3 ambientLight = vec3(0.2,0.2,0.2);
|
|
||||||
vec3 directionnalLight = normalize(vec3(10,5,7));
|
|
||||||
vec3 directionnalLightFactor = vec3(0.5,0.5,0.5);
|
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
in vec3 v_normal;
|
||||||
|
in vec2 v_tex_coords;
|
||||||
|
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
vec3 ambientLight = vec3(0.3,0.3,0.3);
|
||||||
|
vec3 directionnalLight = normalize(vec3(10,5,7));
|
||||||
|
vec3 directionnalLightFactor = vec3(0.6,0.6,0.6);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
vec3 lambertComponent = dot(directionnalLight, v_normal) * directionnalLightFactor;
|
||||||
|
lambertComponent = max(vec3(0.0, 0.0, 0.0), lambertComponent);
|
||||||
|
|
||||||
vec3 ambientFactor = ambientLight;
|
vec4 factor = vec4(ambientLight + lambertComponent, 1.0);
|
||||||
vec3 lambertFactor = max(vec3(0.0,0.0,0.0), dot(directionnalLight, fNormal) * directionnalLightFactor);
|
|
||||||
vec4 noTexColor = vec4(ambientFactor + lambertFactor, 1.0);
|
|
||||||
|
|
||||||
vec4 color = texture2D(tex, gl_TexCoord[0].st);
|
|
||||||
|
|
||||||
vec4 fragColor = noTexColor * color;
|
|
||||||
gl_FragColor = fragColor * fFrontColor;
|
|
||||||
|
|
||||||
|
color = factor * texture(tex, v_tex_coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
varying vec3 fNormal;
|
#version 140
|
||||||
varying vec4 fTexCoord;
|
|
||||||
varying vec4 fFrontColor;
|
uniform mat4 perspective;
|
||||||
|
uniform mat4 view;
|
||||||
|
|
||||||
|
in vec3 vertex;
|
||||||
|
in vec2 tex_coords;
|
||||||
|
in vec3 normal;
|
||||||
|
|
||||||
|
out vec2 v_tex_coords;
|
||||||
|
out vec3 v_normal;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
v_normal = transpose(inverse(mat3(view))) * normal;
|
||||||
|
v_tex_coords = tex_coords;
|
||||||
|
|
||||||
fNormal = gl_Normal;
|
gl_Position = perspective * view * vec4(vertex, 1.0);
|
||||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
|
||||||
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
|
|
||||||
fFrontColor = gl_Color;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
extern crate image;
|
||||||
|
|
||||||
#[macro_use] extern crate verbose_log;
|
#[macro_use] extern crate verbose_log;
|
||||||
#[macro_use] extern crate glium;
|
#[macro_use] extern crate glium;
|
||||||
|
|
|
@ -33,6 +33,12 @@ macro_rules! make_vector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Into<[T; $number]> for $name<T> {
|
||||||
|
fn into(self) -> [T; $number] {
|
||||||
|
self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Copy + Clone> Into<($( $t ) ,* )> for $name<T> {
|
impl<T: Copy + Clone> Into<($( $t ) ,* )> for $name<T> {
|
||||||
fn into(self) -> ($( $t ) ,* ) {
|
fn into(self) -> ($( $t ) ,* ) {
|
||||||
( $( self.data[$y] ), *)
|
( $( self.data[$y] ), *)
|
||||||
|
@ -62,6 +68,11 @@ macro_rules! make_vector {
|
||||||
pub fn $x(&self) -> T {
|
pub fn $x(&self) -> T {
|
||||||
self.data[$y]
|
self.data[$y]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a mut ref to the coordinate of the vector.
|
||||||
|
pub fn $x_mut(&mut self) -> &mut T {
|
||||||
|
&mut self.data[$y]
|
||||||
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
src/model.rs
26
src/model.rs
|
@ -8,6 +8,15 @@ use parser::{parse, ParserError};
|
||||||
use math::vector::{Vector2, Vector3};
|
use math::vector::{Vector2, Vector3};
|
||||||
use math::bounding_box::BoundingBox3;
|
use math::bounding_box::BoundingBox3;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
pub struct Vertex {
|
||||||
|
vertex: [f64; 3],
|
||||||
|
tex_coords: [f64; 2],
|
||||||
|
normal: [f64; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
implement_vertex!(Vertex, vertex, tex_coords, normal);
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
/// The indices needed for each vertex of a face.
|
/// The indices needed for each vertex of a face.
|
||||||
pub struct FaceVertex {
|
pub struct FaceVertex {
|
||||||
|
@ -154,6 +163,23 @@ impl Part {
|
||||||
f.material_name = self.material_name.clone();
|
f.material_name = self.material_name.clone();
|
||||||
self.faces.push(f);
|
self.faces.push(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_shape(&self, vertices: &Vec<Vector3<f64>>, tex_coords: &Vec<Vector2<f64>>, normals: &Vec<Vector3<f64>>) -> Vec<Vertex> {
|
||||||
|
|
||||||
|
let mut shape = vec![];
|
||||||
|
for face in &self.faces {
|
||||||
|
for &&v in &[&face.a, &face.b, &face.c] {
|
||||||
|
shape.push(Vertex {
|
||||||
|
vertex: vertices[v.vertex].into(),
|
||||||
|
tex_coords: tex_coords[v.texture_coordinate.unwrap()].into(),
|
||||||
|
normal: normals[v.normal.unwrap()].into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shape
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A 3D model.
|
/// A 3D model.
|
||||||
|
|
|
@ -1,42 +1,54 @@
|
||||||
extern crate glium;
|
extern crate glium;
|
||||||
|
extern crate model_converter;
|
||||||
|
|
||||||
use glium::Display;
|
use glium::Display;
|
||||||
use glium::glutin;
|
use glium::glutin;
|
||||||
use glium::glutin::{
|
use glium::glutin::{
|
||||||
EventsLoop,
|
EventsLoop,
|
||||||
WindowBuilder,
|
WindowBuilder,
|
||||||
ContextBuilder,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use glium::glutin::Event;
|
use glium::glutin::Event;
|
||||||
use glium::glutin::WindowEvent;
|
use glium::glutin::WindowEvent;
|
||||||
use glium::glutin::VirtualKeyCode;
|
use glium::glutin::VirtualKeyCode;
|
||||||
|
|
||||||
|
|
||||||
|
use model_converter::math::vector::Vector3;
|
||||||
|
use model_converter::parser::{parse, parse_into_model};
|
||||||
|
use model_converter::renderer::Renderer;
|
||||||
|
use model_converter::renderer::controls::OrbitControls;
|
||||||
|
use model_converter::renderer::camera::Camera;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
|
let mut model = parse("./assets/models/cube/cube.mtl").unwrap();
|
||||||
|
parse_into_model("./assets/models/cube/cube.obj", &mut model).unwrap();
|
||||||
|
|
||||||
let mut events_loop = EventsLoop::new();
|
let mut events_loop = EventsLoop::new();
|
||||||
let window = WindowBuilder::new();
|
let window = WindowBuilder::new();
|
||||||
let context = ContextBuilder::new();
|
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
|
||||||
let display = Display::new(window, context, &events_loop).unwrap();
|
let display = Display::new(window, context, &events_loop).unwrap();
|
||||||
|
|
||||||
let program = glium::Program::from_source(
|
|
||||||
&display,
|
|
||||||
include_str!("../../assets/shaders/shader.vert"),
|
|
||||||
include_str!("../../assets/shaders/shader.frag"),
|
|
||||||
None
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
let mut closed = false;
|
let mut closed = false;
|
||||||
|
|
||||||
|
let mut renderer = Renderer::new(display);
|
||||||
|
renderer.add_model(&model);
|
||||||
|
|
||||||
|
let mut camera = Camera::new(
|
||||||
|
Vector3::new( 0.0, 0.0, 0.0),
|
||||||
|
Vector3::new( 0.0, 0.0, 0.0),
|
||||||
|
Vector3::new( 0.0, 1.0, 0.0),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut controls = OrbitControls::new(&mut camera);
|
||||||
|
|
||||||
while !closed {
|
while !closed {
|
||||||
let mut target = display.draw();
|
|
||||||
|
|
||||||
use glium::Surface;
|
|
||||||
target.clear_color(0.0, 0.0, 1.0, 1.0);
|
|
||||||
|
|
||||||
target.finish().unwrap();
|
|
||||||
|
|
||||||
events_loop.poll_events(|ev| {
|
events_loop.poll_events(|ev| {
|
||||||
|
|
||||||
|
use model_converter::renderer::controls::Controls;
|
||||||
|
controls.manage_event(&ev, &mut camera);
|
||||||
|
|
||||||
match ev {
|
match ev {
|
||||||
// Close window
|
// Close window
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
|
@ -55,5 +67,11 @@ fn main() {
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let mut target = renderer.draw();
|
||||||
|
renderer.render(&camera, &mut target);
|
||||||
|
target.finish().unwrap();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
pub struct Renderer;
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
use math::vector::Vector3;
|
||||||
|
|
||||||
|
pub trait RenderCamera {
|
||||||
|
fn get_view_matrix(&self) -> [[f32; 4]; 4];
|
||||||
|
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],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn look_at_matrix(position: [f32; 3], target: [f32; 3], up: [f32; 3]) -> [[f32; 4]; 4] {
|
||||||
|
let f = {
|
||||||
|
let f = [
|
||||||
|
target[0] - position[0],
|
||||||
|
target[1] - position[1],
|
||||||
|
target[2] - position[2],
|
||||||
|
];
|
||||||
|
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 = [up[1] * f[2] - up[2] * f[1],
|
||||||
|
up[2] * f[0] - up[0] * f[2],
|
||||||
|
up[0] * f[1] - 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 = [-position[0] * s_norm[0] - position[1] * s_norm[1] - position[2] * s_norm[2],
|
||||||
|
-position[0] * u[0] - position[1] * u[1] - position[2] * u[2],
|
||||||
|
-position[0] * f[0] - position[1] * f[1] - 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],
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Camera {
|
||||||
|
pub position: Vector3<f32>,
|
||||||
|
pub target: Vector3<f32>,
|
||||||
|
pub 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderCamera for Camera {
|
||||||
|
fn get_view_matrix(&self) -> [[f32; 4]; 4] {
|
||||||
|
look_at_matrix(self.position.into(), self.target.into(), self.up.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RotatingCamera {
|
||||||
|
distance: f32,
|
||||||
|
theta: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RotatingCamera {
|
||||||
|
pub fn new(distance: f32) -> RotatingCamera {
|
||||||
|
RotatingCamera {
|
||||||
|
distance: distance,
|
||||||
|
theta: 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn increase_theta(&mut self, dt: f32) {
|
||||||
|
self.theta += dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderCamera for RotatingCamera {
|
||||||
|
fn get_view_matrix(&self) -> [[f32; 4]; 4] {
|
||||||
|
let position = Vector3::new(
|
||||||
|
self.distance * self.theta.cos(),
|
||||||
|
0.0,
|
||||||
|
self.distance * self.theta.sin(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let target = Vector3::new(0.0, 0.0, 0.0);
|
||||||
|
let up = Vector3::new(0.0, 1.0, 0.0);
|
||||||
|
|
||||||
|
look_at_matrix(position.into(), target.into(), up.into())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
const EPSILON: f32 = 0.001;
|
||||||
|
|
||||||
|
use glium::glutin::{
|
||||||
|
Event,
|
||||||
|
WindowEvent,
|
||||||
|
ElementState,
|
||||||
|
MouseButton,
|
||||||
|
MouseScrollDelta,
|
||||||
|
};
|
||||||
|
|
||||||
|
use math::vector::Vector2;
|
||||||
|
use renderer::camera::Camera;
|
||||||
|
|
||||||
|
/// The trait that all controls should implement.
|
||||||
|
pub trait Controls {
|
||||||
|
|
||||||
|
/// Modifies the camera depending on the event.
|
||||||
|
fn manage_event(&mut self, event: &Event, camera: &mut Camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An orbit controls allowing to orbit around an object.
|
||||||
|
///
|
||||||
|
/// Only object centered are supported.
|
||||||
|
pub struct OrbitControls {
|
||||||
|
/// The last position of the mouse.
|
||||||
|
mouse_position: Vector2<f32>,
|
||||||
|
|
||||||
|
/// Wether the left click of the mouse is pressed or not.
|
||||||
|
pressed: bool,
|
||||||
|
|
||||||
|
/// The theta angle of the position of the camera in spheric coordinates.
|
||||||
|
theta: f32,
|
||||||
|
|
||||||
|
/// The phi angle of the position of the camera in spheric coordinates.
|
||||||
|
phi: f32,
|
||||||
|
|
||||||
|
/// The distance between the camera and the origin.
|
||||||
|
distance: f32,
|
||||||
|
|
||||||
|
/// The sensitiviy of the rotation of the mouse.
|
||||||
|
sensitivity: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OrbitControls {
|
||||||
|
|
||||||
|
/// Creates a new orbit controls, and initializes the camera.
|
||||||
|
pub fn new(camera: &mut Camera) -> OrbitControls {
|
||||||
|
let controls = OrbitControls {
|
||||||
|
mouse_position: Vector2::new(0.0, 0.0),
|
||||||
|
pressed: false,
|
||||||
|
theta: 0.0,
|
||||||
|
phi: 0.0,
|
||||||
|
distance: 5.0,
|
||||||
|
sensitivity: 200.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
*camera.position.x_mut() = controls.distance * controls.theta.cos();
|
||||||
|
*camera.position.y_mut() = 0.0;
|
||||||
|
*camera.position.z_mut() = controls.distance * controls.phi.sin();
|
||||||
|
controls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Controls for OrbitControls {
|
||||||
|
fn manage_event(&mut self, event: &Event, camera: &mut Camera) {
|
||||||
|
match *event {
|
||||||
|
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::MouseInput {
|
||||||
|
button: MouseButton::Left,
|
||||||
|
state, ..
|
||||||
|
}, ..
|
||||||
|
} => {
|
||||||
|
self.pressed = state == ElementState::Pressed;
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::MouseWheel {
|
||||||
|
delta: MouseScrollDelta::LineDelta(_, y), ..
|
||||||
|
}, ..
|
||||||
|
} => {
|
||||||
|
self.distance -= y;
|
||||||
|
|
||||||
|
*camera.position.x_mut() = self.distance * self.phi.cos() * self.theta.cos();
|
||||||
|
*camera.position.y_mut() = self.distance * self.phi.sin();
|
||||||
|
*camera.position.z_mut() = self.distance * self.phi.cos() * self.theta.sin();
|
||||||
|
},
|
||||||
|
|
||||||
|
Event::WindowEvent{
|
||||||
|
event: WindowEvent::CursorMoved {
|
||||||
|
position: (x, y), ..
|
||||||
|
}, ..
|
||||||
|
} => {
|
||||||
|
let current_position = Vector2::new(x as f32, y as f32);
|
||||||
|
|
||||||
|
if self.pressed {
|
||||||
|
let difference = (current_position - self.mouse_position) / self.sensitivity;
|
||||||
|
|
||||||
|
self.theta += difference.x();
|
||||||
|
self.phi += difference.y();
|
||||||
|
|
||||||
|
use std::f32::consts::PI;
|
||||||
|
self.phi = self.phi.max(- PI/2.0 + EPSILON);
|
||||||
|
self.phi = self.phi.min( PI/2.0 - EPSILON);
|
||||||
|
|
||||||
|
*camera.position.x_mut() = self.distance * self.phi.cos() * self.theta.cos();
|
||||||
|
*camera.position.y_mut() = self.distance * self.phi.sin();
|
||||||
|
*camera.position.z_mut() = self.distance * self.phi.cos() * self.theta.sin();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record new position
|
||||||
|
self.mouse_position = current_position;
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,156 @@
|
||||||
|
pub mod camera;
|
||||||
|
pub mod controls;
|
||||||
|
|
||||||
|
use glium::draw_parameters::DepthTest;
|
||||||
|
use glium::texture::{
|
||||||
|
RawImage2d,
|
||||||
|
SrgbTexture2d,
|
||||||
|
};
|
||||||
|
use glium::index::{
|
||||||
|
NoIndices,
|
||||||
|
PrimitiveType
|
||||||
|
};
|
||||||
|
use glium::{
|
||||||
|
Program,
|
||||||
|
Display,
|
||||||
|
VertexBuffer,
|
||||||
|
Frame,
|
||||||
|
DrawParameters,
|
||||||
|
Depth,
|
||||||
|
};
|
||||||
|
use image;
|
||||||
|
|
||||||
|
use model::{Model, Vertex};
|
||||||
|
use renderer::camera::RenderCamera;
|
||||||
|
|
||||||
|
pub struct RenderMaterial {
|
||||||
|
texture: Option<SrgbTexture2d>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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: SrgbTexture2d::new(display, image).ok()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
RenderMaterial {
|
||||||
|
texture: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Renderer<'a> {
|
||||||
|
display: Display,
|
||||||
|
program: Program,
|
||||||
|
models: Vec<(&'a Model, Vec<(RenderMaterial, VertexBuffer<Vertex>)>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_model(&mut self, model: &'a Model) {
|
||||||
|
let mut buffers = vec![];
|
||||||
|
|
||||||
|
for part in &model.parts {
|
||||||
|
|
||||||
|
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()
|
||||||
|
};
|
||||||
|
|
||||||
|
let shape = part.build_shape(&model.vertices, &model.texture_coordinates, &model.normals);
|
||||||
|
buffers.push((material, VertexBuffer::new(&self.display, &shape).unwrap()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.models.push((model, buffers));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self) -> Frame {
|
||||||
|
self.display.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<C: RenderCamera>(&self, camera: &C, target: &mut Frame) {
|
||||||
|
use glium::Surface;
|
||||||
|
target.clear_color_and_depth((0.0, 0.0, 0.0, 1.0), 1.0);
|
||||||
|
|
||||||
|
let params = DrawParameters {
|
||||||
|
depth: Depth {
|
||||||
|
test: DepthTest::IfLess,
|
||||||
|
write: true,
|
||||||
|
.. Default::default()
|
||||||
|
},
|
||||||
|
.. Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
for &(_, ref buffers) in &self.models {
|
||||||
|
|
||||||
|
for &(ref material, ref buffer) in buffers {
|
||||||
|
|
||||||
|
let perspective = camera.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();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue