Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
ebb55da52c |
@ -7,8 +7,8 @@ authors = ["Thomas Forgione <thomas@tforgione.fr>"]
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
stderrlog = "0.4.1"
|
stderrlog = "0.4.1"
|
||||||
num = "0.1.42"
|
num = "0.1.42"
|
||||||
glium = "0.32.1"
|
glium = "0.22.0"
|
||||||
image = "0.23"
|
image = "0.21.2"
|
||||||
byteorder = "1.2.3"
|
byteorder = "1.2.3"
|
||||||
clap = "2.31.2"
|
clap = "2.31.2"
|
||||||
# nalgebra = "0.16.13"
|
# nalgebra = "0.16.13"
|
||||||
|
@ -1,31 +1,75 @@
|
|||||||
#version 140
|
#version 140
|
||||||
|
|
||||||
|
#extension GL_OES_standard_derivatives : enable
|
||||||
|
|
||||||
|
|
||||||
uniform sampler2D tex;
|
uniform sampler2D tex;
|
||||||
uniform vec3 diffuse;
|
uniform vec3 diffuse;
|
||||||
|
|
||||||
in vec3 v_normal;
|
in vec3 v_normal;
|
||||||
in vec2 v_tex_coords;
|
in vec2 v_tex_coords;
|
||||||
|
in vec3 v_barycentric;
|
||||||
|
in vec4 v_position;
|
||||||
|
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
vec4 wireframe_color;
|
||||||
|
vec4 render_color;
|
||||||
|
|
||||||
vec3 ambientLight = vec3(0.3,0.3,0.3);
|
vec3 ambientLight = vec3(0.3,0.3,0.3);
|
||||||
vec3 directionnalLight = normalize(vec3(10,5,7));
|
vec3 directionnalLight = normalize(vec3(10,5,7));
|
||||||
vec3 directionnalLightFactor = vec3(0.6,0.6,0.6);
|
vec3 directionnalLightFactor = vec3(0.6,0.6,0.6);
|
||||||
|
|
||||||
|
// float edgeFactor(vec3 a){
|
||||||
|
// vec3 d = fwidth(v_barycentric);
|
||||||
|
// vec3 a3 = smoothstep(vec3(0.0), d*1.5, v_barycentric);
|
||||||
|
// return min(min(a3.x, a3.y), a3.z);
|
||||||
|
// }
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
||||||
|
|
||||||
|
vec3 d = fwidth(v_barycentric);
|
||||||
|
vec3 a3 = smoothstep(vec3(0.0), 0.8 * d, v_barycentric);
|
||||||
|
float scale = (1 - min(min(a3.x, a3.y), a3.z)) / 2 + 0.5;
|
||||||
|
|
||||||
|
wireframe_color = vec4(scale, scale, scale, 1.0);
|
||||||
|
|
||||||
|
// float threshold = 0.1;
|
||||||
|
// vec3 d = fwidth(v_barycentric);
|
||||||
|
|
||||||
|
// if (d.x < threshold || d.y < threshold || d.z < threshold) {
|
||||||
|
// wireframe_color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||||
|
// } else {
|
||||||
|
// wireframe_color = vec4(0.5, 0.5, 0.5, 1.0);
|
||||||
|
// }
|
||||||
|
|
||||||
vec3 lambertComponent = dot(directionnalLight, v_normal) * directionnalLightFactor;
|
vec3 lambertComponent = dot(directionnalLight, v_normal) * directionnalLightFactor;
|
||||||
lambertComponent = max(vec3(0.0, 0.0, 0.0), lambertComponent);
|
lambertComponent = max(vec3(0.0, 0.0, 0.0), lambertComponent);
|
||||||
|
|
||||||
vec4 factor = vec4(ambientLight + lambertComponent, 1.0);
|
vec4 factor = vec4(ambientLight + lambertComponent, 1.0);
|
||||||
|
|
||||||
color = factor * vec4(diffuse, 1.0) * texture(tex, v_tex_coords);
|
render_color = factor * vec4(diffuse, 1.0) * texture(tex, v_tex_coords);
|
||||||
|
|
||||||
if (color.a < 0.05) {
|
if (render_color.a < 0.05) {
|
||||||
discard;
|
discard;
|
||||||
} else {
|
} else {
|
||||||
color.a = 1.0;
|
render_color.a = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float z_min = 0.15;
|
||||||
|
float z_max = 0.25;
|
||||||
|
|
||||||
|
float lambda = (v_position.z - z_min) / (z_max - z_min);
|
||||||
|
|
||||||
|
if (lambda < 0) {
|
||||||
|
lambda = 0;
|
||||||
|
}
|
||||||
|
if (lambda > 1) {
|
||||||
|
lambda = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = lambda * wireframe_color + (1 - lambda) * render_color;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,14 +6,19 @@ uniform vec3 texture_size;
|
|||||||
|
|
||||||
in vec3 vertex;
|
in vec3 vertex;
|
||||||
in vec2 tex_coords;
|
in vec2 tex_coords;
|
||||||
|
in vec3 barycentric;
|
||||||
in vec3 normal;
|
in vec3 normal;
|
||||||
|
|
||||||
out vec2 v_tex_coords;
|
out vec2 v_tex_coords;
|
||||||
out vec3 v_normal;
|
out vec3 v_normal;
|
||||||
|
out vec3 v_barycentric;
|
||||||
|
out vec4 v_position;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
v_normal = normal;
|
v_normal = normal;
|
||||||
|
v_barycentric = barycentric;
|
||||||
v_tex_coords = vec2(tex_coords.x * texture_size.x, tex_coords.y * texture_size.y);
|
v_tex_coords = vec2(tex_coords.x * texture_size.x, tex_coords.y * texture_size.y);
|
||||||
|
|
||||||
gl_Position = perspective * view * vec4(vertex, 1.0);
|
gl_Position = perspective * view * vec4(vertex, 1.0);
|
||||||
|
v_position = gl_Position;
|
||||||
}
|
}
|
||||||
|
202
src/controls.rs
202
src/controls.rs
@ -2,20 +2,30 @@
|
|||||||
|
|
||||||
const EPSILON: f64 = 0.001;
|
const EPSILON: f64 = 0.001;
|
||||||
|
|
||||||
use glium::glutin::dpi::{PhysicalPosition, PhysicalSize};
|
use glium::glutin::{
|
||||||
use glium::glutin::event::{
|
Event,
|
||||||
ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, VirtualKeyCode, WindowEvent,
|
WindowEvent,
|
||||||
|
ElementState,
|
||||||
|
MouseButton,
|
||||||
|
MouseScrollDelta,
|
||||||
|
KeyboardInput,
|
||||||
|
VirtualKeyCode,
|
||||||
|
};
|
||||||
|
use glium::glutin::dpi::{
|
||||||
|
LogicalSize,
|
||||||
|
LogicalPosition,
|
||||||
};
|
};
|
||||||
|
|
||||||
use camera::Camera;
|
|
||||||
use math::vector::{Vector2, Vector3};
|
use math::vector::{Vector2, Vector3};
|
||||||
use model::Model;
|
use camera::Camera;
|
||||||
use renderer::Renderer;
|
use renderer::Renderer;
|
||||||
|
use model::Model;
|
||||||
|
|
||||||
/// The trait that all controls should implement.
|
/// The trait that all controls should implement.
|
||||||
pub trait Controls {
|
pub trait Controls {
|
||||||
|
|
||||||
/// Modifies the camera depending on the event.
|
/// Modifies the camera depending on the event.
|
||||||
fn manage_event(&mut self, event: &Event<()>, camera: &mut Camera, renderer: &Renderer);
|
fn manage_event(&mut self, event: &Event, camera: &mut Camera, renderer: &Renderer);
|
||||||
|
|
||||||
/// Updates the camera depending on time.
|
/// Updates the camera depending on time.
|
||||||
fn update(&mut self, camera: &mut Camera, renderer: &Renderer);
|
fn update(&mut self, camera: &mut Camera, renderer: &Renderer);
|
||||||
@ -48,6 +58,7 @@ pub struct OrbitControls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OrbitControls {
|
impl OrbitControls {
|
||||||
|
|
||||||
/// Creates a new orbit controls, and initializes the camera.
|
/// Creates a new orbit controls, and initializes the camera.
|
||||||
pub fn new(center: Vector3<f64>, distance: f64, camera: &mut Camera) -> OrbitControls {
|
pub fn new(center: Vector3<f64>, distance: f64, camera: &mut Camera) -> OrbitControls {
|
||||||
let controls = OrbitControls {
|
let controls = OrbitControls {
|
||||||
@ -79,40 +90,35 @@ impl OrbitControls {
|
|||||||
OrbitControls::new(
|
OrbitControls::new(
|
||||||
Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64),
|
Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64),
|
||||||
distance as f64,
|
distance as f64,
|
||||||
camera,
|
camera
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Controls for OrbitControls {
|
impl Controls for OrbitControls {
|
||||||
fn manage_event(&mut self, event: &Event<()>, camera: &mut Camera, _: &Renderer) {
|
fn manage_event(&mut self, event: &Event, camera: &mut Camera, _: &Renderer) {
|
||||||
match *event {
|
match *event {
|
||||||
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::MouseInput {
|
||||||
WindowEvent::MouseInput {
|
|
||||||
button: MouseButton::Left,
|
button: MouseButton::Left,
|
||||||
state,
|
state, ..
|
||||||
..
|
}, ..
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.pressed = state == ElementState::Pressed;
|
self.pressed = state == ElementState::Pressed;
|
||||||
}
|
},
|
||||||
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(PhysicalSize { width, height }),
|
event: WindowEvent::Resized(LogicalSize { width, height }), ..
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
camera.aspect_ratio = width as f64 / height as f64;
|
camera.aspect_ratio = width as f64 / height as f64;
|
||||||
}
|
},
|
||||||
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::MouseWheel {
|
||||||
WindowEvent::MouseWheel {
|
delta: MouseScrollDelta::LineDelta(_, y), ..
|
||||||
delta: MouseScrollDelta::LineDelta(_, y),
|
}, ..
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.distance -= y as f64 / self.sensitivity;
|
self.distance -= y as f64 / self.sensitivity;
|
||||||
|
|
||||||
@ -122,15 +128,12 @@ impl Controls for OrbitControls {
|
|||||||
|
|
||||||
camera.position += self.center;
|
camera.position += self.center;
|
||||||
camera.target = self.center;
|
camera.target = self.center;
|
||||||
}
|
},
|
||||||
|
|
||||||
Event::WindowEvent{
|
Event::WindowEvent{
|
||||||
event:
|
event: WindowEvent::CursorMoved {
|
||||||
WindowEvent::CursorMoved {
|
position: LogicalPosition { x, y }, ..
|
||||||
position: PhysicalPosition { x, y },
|
}, ..
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
let current_position = Vector2::new(x as f64, y as f64);
|
let current_position = Vector2::new(x as f64, y as f64);
|
||||||
|
|
||||||
@ -150,21 +153,25 @@ impl Controls for OrbitControls {
|
|||||||
|
|
||||||
camera.position += self.center;
|
camera.position += self.center;
|
||||||
camera.target = self.center;
|
camera.target = self.center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record new position
|
// Record new position
|
||||||
self.mouse_position = current_position;
|
self.mouse_position = current_position;
|
||||||
}
|
},
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, _: &mut Camera, _: &Renderer) {}
|
fn update(&mut self, _: &mut Camera, _: &Renderer) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// First person controls, just like in video games.
|
/// First person controls, just like in video games.
|
||||||
pub struct FirstPersonControls {
|
pub struct FirstPersonControls {
|
||||||
|
|
||||||
/// Theta angle of the spheric coordinates of the direction of the camera.
|
/// Theta angle of the spheric coordinates of the direction of the camera.
|
||||||
theta: f64,
|
theta: f64,
|
||||||
|
|
||||||
@ -229,111 +236,80 @@ impl FirstPersonControls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Controls for FirstPersonControls {
|
impl Controls for FirstPersonControls {
|
||||||
fn manage_event(&mut self, event: &Event<()>, camera: &mut Camera, renderer: &Renderer) {
|
|
||||||
|
fn manage_event(&mut self, event: &Event, camera: &mut Camera, renderer: &Renderer) {
|
||||||
match *event {
|
match *event {
|
||||||
|
|
||||||
// On resize window
|
// On resize window
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::Resized(PhysicalSize { width, height }),
|
event: WindowEvent::Resized(LogicalSize { width, height } ), ..
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
camera.aspect_ratio = width as f64 / height as f64;
|
camera.aspect_ratio = width as f64 / height as f64;
|
||||||
}
|
},
|
||||||
|
|
||||||
// On Z pressed
|
// On Z pressed
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: KeyboardInput {
|
||||||
input:
|
virtual_keycode: Some(VirtualKeyCode::Z), state, ..
|
||||||
KeyboardInput {
|
}, ..
|
||||||
virtual_keycode: Some(VirtualKeyCode::Z),
|
}, ..
|
||||||
state,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.forward_pressed = state == ElementState::Pressed;
|
self.forward_pressed = state == ElementState::Pressed;
|
||||||
}
|
},
|
||||||
|
|
||||||
// On S pressed
|
// On S pressed
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: KeyboardInput {
|
||||||
input:
|
virtual_keycode: Some(VirtualKeyCode::S), state, ..
|
||||||
KeyboardInput {
|
}, ..
|
||||||
virtual_keycode: Some(VirtualKeyCode::S),
|
}, ..
|
||||||
state,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.backward_pressed = state == ElementState::Pressed;
|
self.backward_pressed = state == ElementState::Pressed;
|
||||||
}
|
},
|
||||||
|
|
||||||
// On Q pressed
|
// On Q pressed
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: KeyboardInput {
|
||||||
input:
|
virtual_keycode: Some(VirtualKeyCode::Q), state, ..
|
||||||
KeyboardInput {
|
}, ..
|
||||||
virtual_keycode: Some(VirtualKeyCode::Q),
|
}, ..
|
||||||
state,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.left_pressed = state == ElementState::Pressed;
|
self.left_pressed = state == ElementState::Pressed;
|
||||||
}
|
},
|
||||||
|
|
||||||
// On D pressed
|
// On D pressed
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: KeyboardInput {
|
||||||
input:
|
virtual_keycode: Some(VirtualKeyCode::D), state, ..
|
||||||
KeyboardInput {
|
}, ..
|
||||||
virtual_keycode: Some(VirtualKeyCode::D),
|
}, ..
|
||||||
state,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.right_pressed = state == ElementState::Pressed;
|
self.right_pressed = state == ElementState::Pressed;
|
||||||
}
|
},
|
||||||
|
|
||||||
// On Space pressed
|
// On Space pressed
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: KeyboardInput {
|
||||||
input:
|
virtual_keycode: Some(VirtualKeyCode::Space), state, ..
|
||||||
KeyboardInput {
|
}, ..
|
||||||
virtual_keycode: Some(VirtualKeyCode::Space),
|
}, ..
|
||||||
state,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
self.boost = state == ElementState::Pressed;
|
self.boost = state == ElementState::Pressed;
|
||||||
}
|
},
|
||||||
|
|
||||||
// On mouse move
|
// On mouse move
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::CursorMoved {
|
||||||
WindowEvent::CursorMoved {
|
position: LogicalPosition { x, y }, ..
|
||||||
position: PhysicalPosition { x, y },
|
}, ..
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
let size = renderer.gl_window().window().inner_size();
|
|
||||||
|
let size = renderer.gl_window().window().get_inner_size().unwrap();
|
||||||
let center = Vector2::new(size.width as f64 / 2.0, size.height as f64 / 2.0);
|
let center = Vector2::new(size.width as f64 / 2.0, size.height as f64 / 2.0);
|
||||||
let current_position = Vector2::new(x as f64, y as f64);
|
let current_position = Vector2::new(x as f64, y as f64);
|
||||||
let difference = (current_position - center) / self.sensitivity;
|
let difference = (current_position - center) / self.sensitivity;
|
||||||
@ -351,29 +327,29 @@ impl Controls for FirstPersonControls {
|
|||||||
self.phi.cos() * self.theta.sin(),
|
self.phi.cos() * self.theta.sin(),
|
||||||
);
|
);
|
||||||
|
|
||||||
self.left = Vector3::new(0.0, 1.0, 0.0)
|
self.left = Vector3::new(0.0, 1.0, 0.0).cross_product(self.forward).normalized();
|
||||||
.cross_product(self.forward)
|
|
||||||
.normalized();
|
|
||||||
|
|
||||||
// Move the cursor back to the center
|
// Move the cursor back to the center
|
||||||
renderer
|
renderer
|
||||||
.gl_window()
|
.gl_window()
|
||||||
.window()
|
.window()
|
||||||
.set_cursor_position(PhysicalPosition::new(
|
.set_cursor_position(LogicalPosition::new(
|
||||||
size.width as f64 / 2.0,
|
size.width / 2.0, size.height / 2.0))
|
||||||
size.height as f64 / 2.0,
|
|
||||||
))
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_camera(camera);
|
self.update_camera(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, camera: &mut Camera, renderer: &Renderer) {
|
fn update(&mut self, camera: &mut Camera, renderer: &Renderer) {
|
||||||
renderer.gl_window().window().set_cursor_visible(false);
|
|
||||||
|
renderer.gl_window().hide_cursor(true);
|
||||||
|
|
||||||
let mut speed = Vector3::new(0.0, 0.0, 0.0);
|
let mut speed = Vector3::new(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
@ -26,10 +26,11 @@ pub struct Vertex {
|
|||||||
vertex: [f64; 3],
|
vertex: [f64; 3],
|
||||||
tex_coords: [f64; 2],
|
tex_coords: [f64; 2],
|
||||||
normal: [f64; 3],
|
normal: [f64; 3],
|
||||||
|
barycentric: [f64; 3],
|
||||||
face_color: [f64; 3],
|
face_color: [f64; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
implement_vertex!(Vertex, vertex, tex_coords, normal, face_color);
|
implement_vertex!(Vertex, vertex, tex_coords, normal, barycentric, face_color);
|
||||||
|
|
||||||
/// A part of a 3D model.
|
/// A part of a 3D model.
|
||||||
///
|
///
|
||||||
@ -534,7 +535,12 @@ impl Model {
|
|||||||
|
|
||||||
let mut vertex_buffer = vec![];
|
let mut vertex_buffer = vec![];
|
||||||
for face in part.faces() {
|
for face in part.faces() {
|
||||||
for &&v in &[&face.a, &face.b, &face.c] {
|
let v0 = vertices[face.a.vertex];
|
||||||
|
let v1 = vertices[face.b.vertex];
|
||||||
|
let v2 = vertices[face.c.vertex];
|
||||||
|
let barycenter = (v0 + v1 + v2) / 3.0;
|
||||||
|
|
||||||
|
for (index, &&v) in [&face.a, &face.b, &face.c].iter().enumerate() {
|
||||||
let vertex = vertices[v.vertex].into();
|
let vertex = vertices[v.vertex].into();
|
||||||
let tex_coord = if let Some(tex_index) = v.texture_coordinate {
|
let tex_coord = if let Some(tex_index) = v.texture_coordinate {
|
||||||
texture_coordinates[tex_index].into()
|
texture_coordinates[tex_index].into()
|
||||||
@ -542,6 +548,14 @@ impl Model {
|
|||||||
[0.0, 0.0]
|
[0.0, 0.0]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let barycentric = match index {
|
||||||
|
0 => [1.0, 0.0, 0.0],
|
||||||
|
1 => [0.0, 1.0, 0.0],
|
||||||
|
2 => [0.0, 0.0, 1.0],
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
let normal = if let Some(normal_index) = v.normal {
|
let normal = if let Some(normal_index) = v.normal {
|
||||||
normals[normal_index].into()
|
normals[normal_index].into()
|
||||||
} else {
|
} else {
|
||||||
@ -567,6 +581,7 @@ impl Model {
|
|||||||
vertex: vertex,
|
vertex: vertex,
|
||||||
tex_coords: tex_coord,
|
tex_coords: tex_coord,
|
||||||
normal: normal,
|
normal: normal,
|
||||||
|
barycentric: barycentric,
|
||||||
face_color: [r, g, b],
|
face_color: [r, g, b],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,33 +6,37 @@ extern crate serde_derive;
|
|||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
extern crate stderrlog;
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate glium;
|
extern crate glium;
|
||||||
extern crate model_converter;
|
extern crate model_converter;
|
||||||
extern crate stderrlog;
|
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use std::time::{Instant, Duration};
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
|
||||||
use glium::glutin;
|
|
||||||
use glium::glutin::event_loop::EventLoop;
|
|
||||||
use glium::glutin::window::WindowBuilder;
|
|
||||||
use glium::Display;
|
use glium::Display;
|
||||||
|
use glium::glutin;
|
||||||
|
use glium::glutin::{EventsLoop, WindowBuilder};
|
||||||
|
|
||||||
use glium::glutin::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
|
use glium::glutin::{
|
||||||
|
Event,
|
||||||
|
WindowEvent,
|
||||||
|
VirtualKeyCode,
|
||||||
|
ElementState,
|
||||||
|
};
|
||||||
|
|
||||||
use model_converter::camera::Camera;
|
use model_converter::scene::Scene;
|
||||||
use model_converter::controls::{FirstPersonControls, OrbitControls};
|
|
||||||
use model_converter::math::bounding_box::BoundingBox3;
|
use model_converter::math::bounding_box::BoundingBox3;
|
||||||
use model_converter::math::vector::Vector3;
|
use model_converter::math::vector::Vector3;
|
||||||
use model_converter::parser::parse_file;
|
use model_converter::parser::parse_file;
|
||||||
use model_converter::renderer::Renderer;
|
use model_converter::renderer::Renderer;
|
||||||
use model_converter::scene::Scene;
|
use model_converter::controls::{OrbitControls, FirstPersonControls};
|
||||||
|
use model_converter::camera::Camera;
|
||||||
|
|
||||||
fn as_millis(duration: Duration) -> u64 {
|
fn as_millis(duration: Duration) -> u64 {
|
||||||
duration.as_secs() * 1_000 + (duration.subsec_nanos() as u64) / 1_000_000
|
duration.as_secs() * 1_000 + (duration.subsec_nanos() as u64) / 1_000_000
|
||||||
@ -62,31 +66,26 @@ struct CameraEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
||||||
let matches = App::new("3D Viewer")
|
let matches = App::new("3D Viewer")
|
||||||
.version("1.0")
|
.version("1.0")
|
||||||
.arg(
|
.arg(Arg::with_name("input")
|
||||||
Arg::with_name("input")
|
|
||||||
.short("i")
|
.short("i")
|
||||||
.long("input")
|
.long("input")
|
||||||
.value_name("FILES")
|
.value_name("FILES")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.help("Input model files")
|
.help("Input model files")
|
||||||
.required(true),
|
.required(true))
|
||||||
)
|
.arg(Arg::with_name("first person")
|
||||||
.arg(
|
|
||||||
Arg::with_name("first person")
|
|
||||||
.short("f")
|
.short("f")
|
||||||
.long("first-person")
|
.long("first-person")
|
||||||
.help("Uses first person controls instead of orbit controls"),
|
.help("Uses first person controls instead of orbit controls"))
|
||||||
)
|
.arg(Arg::with_name("verbose")
|
||||||
.arg(
|
|
||||||
Arg::with_name("verbose")
|
|
||||||
.short("v")
|
.short("v")
|
||||||
.long("verbose")
|
.long("verbose")
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.help("Shows logs during the parsing of the model"),
|
.help("Shows logs during the parsing of the model"))
|
||||||
)
|
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// Set verbose flag
|
// Set verbose flag
|
||||||
@ -100,12 +99,16 @@ fn main() {
|
|||||||
let mut path_count = 0;
|
let mut path_count = 0;
|
||||||
let mut path = vec![];
|
let mut path = vec![];
|
||||||
|
|
||||||
use std::f64::{MAX, MIN};
|
use std::f64::{MIN, MAX};
|
||||||
let mut bbox = BoundingBox3::new(Vector3::new(MAX, MAX, MAX), Vector3::new(MIN, MIN, MIN));
|
let mut bbox = BoundingBox3::new(
|
||||||
|
Vector3::new(MAX, MAX, MAX),
|
||||||
|
Vector3::new(MIN, MIN, MIN),
|
||||||
|
);
|
||||||
|
|
||||||
let mut models = vec![];
|
let mut models = vec![];
|
||||||
|
|
||||||
for input in matches.values_of("input").unwrap() {
|
for input in matches.values_of("input").unwrap() {
|
||||||
|
|
||||||
info!("Parsing model {}", input);
|
info!("Parsing model {}", input);
|
||||||
|
|
||||||
match parse_file(&input) {
|
match parse_file(&input) {
|
||||||
@ -114,20 +117,21 @@ fn main() {
|
|||||||
bbox = bbox.union(&model.bounding_box());
|
bbox = bbox.union(&model.bounding_box());
|
||||||
}
|
}
|
||||||
models.push((input.to_owned(), model))
|
models.push((input.to_owned(), model))
|
||||||
}
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error while parsing file: {}", e);
|
error!("Error while parsing file: {}", e);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
let mut events_loop = EventsLoop::new();
|
||||||
let window = WindowBuilder::new().with_visible(false);
|
let window = WindowBuilder::new().with_visibility(false);
|
||||||
|
|
||||||
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
|
let context = glutin::ContextBuilder::new().with_depth_buffer(24);
|
||||||
let display = Display::new(window, context, &event_loop).unwrap();
|
let display = Display::new(window, context, &events_loop).unwrap();
|
||||||
let mut renderer = Renderer::new(display);
|
let mut renderer = Renderer::new(display);
|
||||||
|
renderer.set_clear_color(1.0, 1.0, 1.0, 1.0);
|
||||||
|
|
||||||
let mut scene = Scene::new();
|
let mut scene = Scene::new();
|
||||||
let mut before;
|
let mut before;
|
||||||
@ -160,6 +164,8 @@ fn main() {
|
|||||||
let center_f64 = Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64);
|
let center_f64 = Vector3::new(center.x() as f64, center.y() as f64, center.z() as f64);
|
||||||
let size_f64 = size as f64;
|
let size_f64 = size as f64;
|
||||||
|
|
||||||
|
let mut closed = false;
|
||||||
|
|
||||||
let mut camera = Camera::new(
|
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, 0.0, 0.0),
|
Vector3::new( 0.0, 0.0, 0.0),
|
||||||
@ -168,13 +174,13 @@ fn main() {
|
|||||||
|
|
||||||
camera.z_near = 0.0001;
|
camera.z_near = 0.0001;
|
||||||
|
|
||||||
let mut controls: Box<dyn Controls> = if matches.is_present("first person") {
|
let mut controls: Box<Controls> = if matches.is_present("first person") {
|
||||||
Box::new(FirstPersonControls::new())
|
Box::new(FirstPersonControls::new())
|
||||||
} else {
|
} else {
|
||||||
Box::new(OrbitControls::new(
|
Box::new(OrbitControls::new(
|
||||||
Vector3::new(0.0, 0.0, 0.0),
|
Vector3::new(0.0, 0.0, 0.0),
|
||||||
1.0,
|
1.0,
|
||||||
&mut camera,
|
&mut camera
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -185,52 +191,38 @@ fn main() {
|
|||||||
let mut recording = false;
|
let mut recording = false;
|
||||||
let mut before = Instant::now();
|
let mut before = Instant::now();
|
||||||
|
|
||||||
event_loop.run(move |ev, _, control_flow| {
|
while !closed {
|
||||||
|
|
||||||
let mut should_screenshot = false;
|
let mut should_screenshot = false;
|
||||||
|
|
||||||
|
events_loop.poll_events(|ev| {
|
||||||
|
|
||||||
controls.manage_event(&ev, &mut camera, &renderer);
|
controls.manage_event(&ev, &mut camera, &renderer);
|
||||||
|
|
||||||
match ev {
|
match ev {
|
||||||
// No idea what this is
|
|
||||||
Event::NewEvents(cause) => match cause {
|
|
||||||
glium::glutin::event::StartCause::ResumeTimeReached { .. } => (),
|
|
||||||
glium::glutin::event::StartCause::Init => (),
|
|
||||||
_ => return,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Close window
|
// Close window
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event: WindowEvent::CloseRequested,
|
event: WindowEvent::CloseRequested, ..
|
||||||
..
|
} => closed = true,
|
||||||
} => *control_flow = glutin::event_loop::ControlFlow::Exit,
|
|
||||||
|
|
||||||
// Escape key
|
// Escape key
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: glutin::KeyboardInput {
|
||||||
input:
|
|
||||||
KeyboardInput {
|
|
||||||
virtual_keycode: Some(VirtualKeyCode::Escape),
|
virtual_keycode: Some(VirtualKeyCode::Escape),
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed, ..
|
||||||
..
|
}, ..
|
||||||
},
|
}, ..
|
||||||
..
|
} => closed = true,
|
||||||
},
|
|
||||||
..
|
|
||||||
} => *control_flow = glutin::event_loop::ControlFlow::Exit,
|
|
||||||
|
|
||||||
// R key
|
// R key
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: glutin::KeyboardInput {
|
||||||
input:
|
|
||||||
KeyboardInput {
|
|
||||||
virtual_keycode: Some(VirtualKeyCode::R),
|
virtual_keycode: Some(VirtualKeyCode::R),
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed, ..
|
||||||
..
|
}, ..
|
||||||
},
|
}, ..
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
if ! recording {
|
if ! recording {
|
||||||
path.clear();
|
path.clear();
|
||||||
@ -242,63 +234,43 @@ fn main() {
|
|||||||
file.write_all(string.as_bytes()).unwrap();
|
file.write_all(string.as_bytes()).unwrap();
|
||||||
path_count += 1;
|
path_count += 1;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
|
||||||
// Enter key
|
// Enter key
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: glutin::KeyboardInput {
|
||||||
input:
|
|
||||||
KeyboardInput {
|
|
||||||
virtual_keycode: Some(VirtualKeyCode::Return),
|
virtual_keycode: Some(VirtualKeyCode::Return),
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed, ..
|
||||||
..
|
}, ..
|
||||||
},
|
}, ..
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
trace!("Camera:");
|
trace!("Camera:");
|
||||||
|
|
||||||
let world_position = camera.position * size_f64 + center_f64;
|
let world_position = camera.position * size_f64 + center_f64;
|
||||||
let world_target = camera.target * size_f64 + center_f64;
|
let world_target = camera.target * size_f64 + center_f64;
|
||||||
|
|
||||||
trace!(
|
trace!("\tPosition: ({}, {}, {})",
|
||||||
"\tPosition: ({}, {}, {})",
|
world_position.x(), world_position.y(), world_position.z());
|
||||||
world_position.x(),
|
trace!("\tTarget: ({}, {}, {})",
|
||||||
world_position.y(),
|
world_target.x(), world_target.y(), world_target.z());
|
||||||
world_position.z()
|
trace!("\tUp: ({}, {}, {})",
|
||||||
);
|
camera.up.x(), camera.up.y(), camera.up.z());
|
||||||
trace!(
|
},
|
||||||
"\tTarget: ({}, {}, {})",
|
|
||||||
world_target.x(),
|
|
||||||
world_target.y(),
|
|
||||||
world_target.z()
|
|
||||||
);
|
|
||||||
trace!(
|
|
||||||
"\tUp: ({}, {}, {})",
|
|
||||||
camera.up.x(),
|
|
||||||
camera.up.y(),
|
|
||||||
camera.up.z()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::WindowEvent {
|
Event::WindowEvent {
|
||||||
event:
|
event: WindowEvent::KeyboardInput {
|
||||||
WindowEvent::KeyboardInput {
|
input: glutin::KeyboardInput {
|
||||||
input:
|
|
||||||
KeyboardInput {
|
|
||||||
virtual_keycode: Some(VirtualKeyCode::C),
|
virtual_keycode: Some(VirtualKeyCode::C),
|
||||||
state: ElementState::Pressed,
|
state: ElementState::Pressed, ..
|
||||||
..
|
}, ..
|
||||||
},
|
}, ..
|
||||||
..
|
|
||||||
},
|
|
||||||
..
|
|
||||||
} => should_screenshot = true,
|
} => should_screenshot = true,
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
controls.update(&mut camera, &renderer);
|
controls.update(&mut camera, &renderer);
|
||||||
renderer.render(&scene, &camera);
|
renderer.render(&scene, &camera);
|
||||||
@ -327,5 +299,5 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
before = Instant::now();
|
before = Instant::now();
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
//! This module contains the rendering structs.
|
//! This module contains the rendering structs.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
use std::ops::Deref;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use image;
|
use image;
|
||||||
use image::{DynamicImage, ImageBuffer, Rgba};
|
use image::{ImageBuffer, Rgba, DynamicImage};
|
||||||
|
|
||||||
use glium::draw_parameters::{Blend, DepthTest};
|
|
||||||
use glium::glutin::PossiblyCurrent as Pc;
|
|
||||||
use glium::index::{NoIndices, PrimitiveType};
|
|
||||||
use glium::program::ProgramCreationInput;
|
|
||||||
use glium::texture::{RawImage2d, SrgbTexture2d, Texture2dDataSink};
|
use glium::texture::{RawImage2d, SrgbTexture2d, Texture2dDataSink};
|
||||||
use glium::{Depth, Display, DrawParameters, Frame, Program, Surface, VertexBuffer};
|
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 glium::program::ProgramCreationInput;
|
||||||
|
|
||||||
use camera::{mat_to_f32, RenderCamera};
|
|
||||||
use scene::Scene;
|
use scene::Scene;
|
||||||
|
use camera::{RenderCamera, mat_to_f32};
|
||||||
|
|
||||||
|
use model::{Vertex, Part, Model};
|
||||||
use math::vector::Vector3;
|
use math::vector::Vector3;
|
||||||
use model::{Model, Part, Vertex};
|
|
||||||
|
|
||||||
/// Image data stored as RGBA.
|
/// Image data stored as RGBA.
|
||||||
pub struct RgbaImageData {
|
pub struct RgbaImageData {
|
||||||
@ -58,11 +57,10 @@ pub struct Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
|
|
||||||
/// Creates the program with the default shader.
|
/// Creates the program with the default shader.
|
||||||
pub fn default_shader(display: &Display) -> Program {
|
pub fn default_shader(display: &Display) -> Program {
|
||||||
Program::new(
|
Program::new(display, ProgramCreationInput::SourceCode {
|
||||||
display,
|
|
||||||
ProgramCreationInput::SourceCode {
|
|
||||||
vertex_shader: include_str!("../assets/shaders/default.vert"),
|
vertex_shader: include_str!("../assets/shaders/default.vert"),
|
||||||
fragment_shader: include_str!("../assets/shaders/default.frag"),
|
fragment_shader: include_str!("../assets/shaders/default.frag"),
|
||||||
geometry_shader: None,
|
geometry_shader: None,
|
||||||
@ -71,16 +69,12 @@ impl Renderer {
|
|||||||
transform_feedback_varyings: None,
|
transform_feedback_varyings: None,
|
||||||
outputs_srgb: false,
|
outputs_srgb: false,
|
||||||
uses_point_size: false,
|
uses_point_size: false,
|
||||||
},
|
}).unwrap()
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the shader with one color per face.
|
/// Creates the shader with one color per face.
|
||||||
pub fn color_shader(display: &Display) -> Program {
|
pub fn color_shader(display: &Display) -> Program {
|
||||||
Program::new(
|
Program::new(display, ProgramCreationInput::SourceCode {
|
||||||
display,
|
|
||||||
ProgramCreationInput::SourceCode {
|
|
||||||
vertex_shader: include_str!("../assets/shaders/color.vert"),
|
vertex_shader: include_str!("../assets/shaders/color.vert"),
|
||||||
fragment_shader: include_str!("../assets/shaders/color.frag"),
|
fragment_shader: include_str!("../assets/shaders/color.frag"),
|
||||||
geometry_shader: None,
|
geometry_shader: None,
|
||||||
@ -89,31 +83,35 @@ impl Renderer {
|
|||||||
transform_feedback_varyings: None,
|
transform_feedback_varyings: None,
|
||||||
outputs_srgb: true,
|
outputs_srgb: true,
|
||||||
uses_point_size: false,
|
uses_point_size: false,
|
||||||
},
|
}).unwrap()
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new renderer from a display.
|
/// Creates a new renderer from a display.
|
||||||
///
|
///
|
||||||
/// Is uses the default shaders and creates an empty vec of models.
|
/// Is uses the default shaders and creates an empty vec of models.
|
||||||
pub fn new(display: Display) -> Renderer {
|
pub fn new(display: Display) -> Renderer {
|
||||||
|
|
||||||
let program = Renderer::default_shader(&display);
|
let program = Renderer::default_shader(&display);
|
||||||
Renderer::from_display_and_program(display, program)
|
Renderer::from_display_and_program(display, program)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new colored renderer from a display.
|
/// Creates a new colored renderer from a display.
|
||||||
///
|
///
|
||||||
/// Is uses the face colors shaders and creates an empty vec of models.
|
/// Is uses the face colors shaders and creates an empty vec of models.
|
||||||
pub fn color(display: Display) -> Renderer {
|
pub fn color(display: Display) -> Renderer {
|
||||||
|
|
||||||
let program = Renderer::color_shader(&display);
|
let program = Renderer::color_shader(&display);
|
||||||
Renderer::from_display_and_program(display, program)
|
Renderer::from_display_and_program(display, program)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Creates a new renderer from a program.
|
/// Creates a new renderer from a program.
|
||||||
///
|
///
|
||||||
/// It allows you to use a custom shader.
|
/// It allows you to use a custom shader.
|
||||||
pub fn from_display_and_program(display: Display, program: Program) -> Renderer {
|
pub fn from_display_and_program(display: Display, program: Program) -> Renderer {
|
||||||
|
|
||||||
let image = RawImage2d::from_raw_rgba(vec![1.0, 1.0, 1.0, 1.0], (1, 1));
|
let image = RawImage2d::from_raw_rgba(vec![1.0, 1.0, 1.0, 1.0], (1, 1));
|
||||||
let texture = SrgbTexture2d::new(&display, image).ok().unwrap();
|
let texture = SrgbTexture2d::new(&display, image).ok().unwrap();
|
||||||
|
|
||||||
@ -128,17 +126,18 @@ impl Renderer {
|
|||||||
renderer.capture();
|
renderer.capture();
|
||||||
|
|
||||||
renderer
|
renderer
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the inner GlWindows.
|
/// Returns the inner GlWindows.
|
||||||
pub fn gl_window(&self) -> Ref<'_, impl Deref<Target = glium::glutin::WindowedContext<Pc>>> {
|
pub fn gl_window(&self) -> Ref<GlWindow> {
|
||||||
self.display.gl_window()
|
self.display.gl_window()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a SrgbTexture from a path to an image.
|
/// Creates a SrgbTexture from a path to an image.
|
||||||
pub fn make_texture(&self, path: &str) -> SrgbTexture2d {
|
pub fn make_texture(&self, path: &str) -> SrgbTexture2d {
|
||||||
let image = match image::open(path) {
|
let image = match image::open(path) {
|
||||||
Ok(r) => r.to_rgba8(),
|
Ok(r) => r.to_rgba(),
|
||||||
Err(e) => panic!("Error while opening file {}: {}", path, e),
|
Err(e) => panic!("Error while opening file {}: {}", path, e),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,23 +145,14 @@ impl Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a SrgbTexture from an image buffer.
|
/// Creates a SrgbTexture from an image buffer.
|
||||||
pub fn make_texture_from_buffer(
|
pub fn make_texture_from_buffer(&self, buffer: ImageBuffer<Rgba<u8>, Vec<u8>>) -> SrgbTexture2d {
|
||||||
&self,
|
|
||||||
buffer: ImageBuffer<Rgba<u8>, Vec<u8>>,
|
|
||||||
) -> SrgbTexture2d {
|
|
||||||
let dimensions = buffer.dimensions();
|
let dimensions = buffer.dimensions();
|
||||||
let buffer = RawImage2d::from_raw_rgba_reversed(&buffer.into_raw(), dimensions);
|
let buffer = RawImage2d::from_raw_rgba_reversed(&buffer.into_raw(), dimensions);
|
||||||
SrgbTexture2d::new(&self.display, buffer).ok().unwrap()
|
SrgbTexture2d::new(&self.display, buffer).ok().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a 1x1 SrgbTexture with the color passed as parameter.
|
/// Creates a 1x1 SrgbTexture with the color passed as parameter.
|
||||||
pub fn make_texture_from_color_channels(
|
pub fn make_texture_from_color_channels(&self, r: f32, g: f32, b: f32, a: f32) -> SrgbTexture2d {
|
||||||
&self,
|
|
||||||
r: f32,
|
|
||||||
g: f32,
|
|
||||||
b: f32,
|
|
||||||
a: f32,
|
|
||||||
) -> SrgbTexture2d {
|
|
||||||
let image = RawImage2d::from_raw_rgba(vec![r, g, b, a], (1, 1));
|
let image = RawImage2d::from_raw_rgba(vec![r, g, b, a], (1, 1));
|
||||||
SrgbTexture2d::new(&self.display, image).ok().unwrap()
|
SrgbTexture2d::new(&self.display, image).ok().unwrap()
|
||||||
}
|
}
|
||||||
@ -180,6 +170,7 @@ impl Renderer {
|
|||||||
|
|
||||||
/// Renders on the display.
|
/// Renders on the display.
|
||||||
pub fn render<C: RenderCamera>(&self, scene: &Scene, camera: &C) {
|
pub fn render<C: RenderCamera>(&self, scene: &Scene, camera: &C) {
|
||||||
|
|
||||||
let mut target = self.draw();
|
let mut target = self.draw();
|
||||||
target.clear_color_srgb_and_depth(self.clear_color, 1.0);
|
target.clear_color_srgb_and_depth(self.clear_color, 1.0);
|
||||||
|
|
||||||
@ -199,7 +190,9 @@ impl Renderer {
|
|||||||
for model in scene.iter() {
|
for model in scene.iter() {
|
||||||
let model = &*model.borrow();
|
let model = &*model.borrow();
|
||||||
for part in &model.parts {
|
for part in &model.parts {
|
||||||
|
|
||||||
if let &Some(ref buffer) = part.vertex_buffer() {
|
if let &Some(ref buffer) = part.vertex_buffer() {
|
||||||
|
|
||||||
let diffuse = if let Some(ref name) = part.material_name {
|
let diffuse = if let Some(ref name) = part.material_name {
|
||||||
if let None = model.materials.get(name) {
|
if let None = model.materials.get(name) {
|
||||||
panic!("Material {} not found", name);
|
panic!("Material {} not found", name);
|
||||||
@ -213,16 +206,12 @@ impl Renderer {
|
|||||||
let texture = self.get_texture_of_part(&model, part);
|
let texture = self.get_texture_of_part(&model, part);
|
||||||
|
|
||||||
let (texture, size) = if let Some((texture, size)) = texture {
|
let (texture, size) = if let Some((texture, size)) = texture {
|
||||||
(
|
(texture, Vector3::new(size[0] as f32, size[1] as f32, size[2] as f32))
|
||||||
texture,
|
|
||||||
Vector3::new(size[0] as f32, size[1] as f32, size[2] as f32),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(&self.default_texture, Vector3::new(1.0, 1.0, 1.0))
|
(&self.default_texture, Vector3::new(1.0, 1.0, 1.0))
|
||||||
};
|
};
|
||||||
|
|
||||||
target
|
target.draw(
|
||||||
.draw(
|
|
||||||
buffer,
|
buffer,
|
||||||
NoIndices(PrimitiveType::TrianglesList),
|
NoIndices(PrimitiveType::TrianglesList),
|
||||||
&self.program,
|
&self.program,
|
||||||
@ -234,8 +223,7 @@ impl Renderer {
|
|||||||
texture_size: Into::<[f32; 3]>::into(size),
|
texture_size: Into::<[f32; 3]>::into(size),
|
||||||
),
|
),
|
||||||
¶ms,
|
¶ms,
|
||||||
)
|
).unwrap();
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,11 +232,7 @@ impl Renderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Renders a part of a model.
|
/// Renders a part of a model.
|
||||||
fn get_texture_of_part<'a>(
|
fn get_texture_of_part<'a>(&self, model: &'a Model, part: &Part) -> Option<(&'a SrgbTexture2d, Vector3<f64>)> {
|
||||||
&self,
|
|
||||||
model: &'a Model,
|
|
||||||
part: &Part,
|
|
||||||
) -> Option<(&'a SrgbTexture2d, Vector3<f64>)> {
|
|
||||||
if let Some(ref material_name) = part.material_name {
|
if let Some(ref material_name) = part.material_name {
|
||||||
if let Some(ref material) = model.materials.get(material_name) {
|
if let Some(ref material) = model.materials.get(material_name) {
|
||||||
if let Some((texture, size)) = material.textures.get("map_Kd") {
|
if let Some((texture, size)) = material.textures.get("map_Kd") {
|
||||||
@ -280,21 +264,21 @@ impl Renderer {
|
|||||||
|
|
||||||
/// Shows the window if hidden.
|
/// Shows the window if hidden.
|
||||||
pub fn show(&mut self) {
|
pub fn show(&mut self) {
|
||||||
self.gl_window().window().set_visible(true);
|
self.gl_window().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a DynamicImage of the corresponding frame.
|
/// Returns a DynamicImage of the corresponding frame.
|
||||||
pub fn capture(&self) -> DynamicImage {
|
pub fn capture(&self) -> DynamicImage {
|
||||||
// Create temporary texture and blit the front buffer to it
|
// Create temporary texture and blit the front buffer to it
|
||||||
let image: RawImage2d<u8> = self.display.read_front_buffer().unwrap();
|
let image: RawImage2d<u8> = self.display.read_front_buffer();
|
||||||
let image =
|
let image = ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
|
||||||
ImageBuffer::from_raw(image.width, image.height, image.data.into_owned()).unwrap();
|
|
||||||
DynamicImage::ImageRgba8(image).flipv()
|
DynamicImage::ImageRgba8(image).flipv()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a RgbaImamgeData to a DynamicImage.
|
/// Converts a RgbaImamgeData to a DynamicImage.
|
||||||
pub fn rgba_image_data_to_image(image_data: RgbaImageData) -> image::DynamicImage {
|
pub fn rgba_image_data_to_image(image_data: RgbaImageData) -> image::DynamicImage {
|
||||||
|
|
||||||
let pixels = {
|
let pixels = {
|
||||||
let mut v = Vec::with_capacity(image_data.data.len() * 4);
|
let mut v = Vec::with_capacity(image_data.data.len() * 4);
|
||||||
for (a, b, c, d) in image_data.data {
|
for (a, b, c, d) in image_data.data {
|
||||||
@ -306,12 +290,15 @@ pub fn rgba_image_data_to_image(image_data: RgbaImageData) -> image::DynamicImag
|
|||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Create ImageBuffer
|
// Create ImageBuffer
|
||||||
let image_buffer =
|
let image_buffer =
|
||||||
image::ImageBuffer::from_raw(image_data.width, image_data.height, pixels).unwrap();
|
image::ImageBuffer::from_raw(image_data.width, image_data.height, pixels)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Save the screenshot to file
|
// Save the screenshot to file
|
||||||
let image = image::DynamicImage::ImageRgba8(image_buffer).flipv();
|
let image = image::DynamicImage::ImageRgba8(image_buffer).flipv();
|
||||||
|
|
||||||
image
|
image
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user