Oh my god, rust is so good

This commit is contained in:
Thomas Forgione 2018-04-12 17:23:40 +02:00
parent b42abd0325
commit 83065cedf2
No known key found for this signature in database
GPG Key ID: C75CD416BD1FFCE1
4 changed files with 251 additions and 7 deletions

View File

@ -18,5 +18,10 @@ void main() {
vec4 factor = vec4(ambientLight + lambertComponent, 1.0);
color = factor * texture(tex, v_tex_coords);
if (color.a < 0.5) {
discard;
}
}

View File

@ -20,6 +20,7 @@ use model_converter::math::vector::Vector3;
use model_converter::parser::parse_into_model;
use model_converter::renderer::Renderer;
use model_converter::renderer::controls::OrbitControls;
use model_converter::renderer::controls::FirstPersonControls;
use model_converter::renderer::camera::Camera;
use model_converter::model::Model;
@ -75,16 +76,18 @@ fn main() {
Vector3::new( 0.0, 1.0, 0.0),
);
let mut controls = OrbitControls::around(&model, &mut camera);
camera.z_near = 0.00001;
let mut controls = FirstPersonControls::new();
renderer.show();
use model_converter::renderer::controls::Controls;
while !closed {
events_loop.poll_events(|ev| {
use model_converter::renderer::controls::Controls;
controls.manage_event(&ev, &mut camera);
controls.manage_event(&ev, &mut camera, &renderer);
match ev {
// Close window
@ -105,6 +108,7 @@ fn main() {
}
});
controls.update(&mut camera, &renderer);
let mut target = renderer.draw();
renderer.render(&camera, &mut target);

View File

@ -2,23 +2,30 @@
const EPSILON: f32 = 0.001;
use glium::backend::glutin::Display;
use glium::glutin::{
Event,
WindowEvent,
ElementState,
MouseButton,
MouseScrollDelta,
KeyboardInput,
VirtualKeyCode,
};
use math::vector::{Vector2, Vector3};
use renderer::camera::Camera;
use renderer::Renderer;
use model::Model;
/// 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);
fn manage_event<'a>(&mut self, event: &Event, camera: &mut Camera, renderer: &Renderer<'a, Display>);
/// Updates the camera depending on time.
fn update<'a>(&mut self, camera: &mut Camera, renderer: &Renderer<'a, Display>);
}
/// An orbit controls allowing to orbit around an object.
@ -87,7 +94,7 @@ impl OrbitControls {
}
impl Controls for OrbitControls {
fn manage_event(&mut self, event: &Event, camera: &mut Camera) {
fn manage_event<'a>(&mut self, event: &Event, camera: &mut Camera, _: &Renderer<'a, Display>) {
match *event {
Event::WindowEvent {
@ -110,7 +117,7 @@ impl Controls for OrbitControls {
delta: MouseScrollDelta::LineDelta(_, y), ..
}, ..
} => {
self.distance -= y;
self.distance -= y / self.sensitivity;
*camera.position.x_mut() = self.distance * self.phi.cos() * self.theta.cos();
*camera.position.y_mut() = self.distance * self.phi.sin();
@ -153,4 +160,147 @@ impl Controls for OrbitControls {
_ => (),
}
}
fn update<'a>(&mut self, _: &mut Camera, _: &Renderer<'a, Display>) {
}
}
/// First person controls, just like in video games.
pub struct FirstPersonControls {
/// Theta angle of the spheric coordinates of the direction of the camera.
theta: f32,
/// Phi angle of the spheric coordinates of the direction of the camera.
phi: f32,
/// Current position of the camera.
position: Vector3<f32>,
/// Vector indicating the direction of the camera.
forward: Vector3<f32>,
/// Speed of the camera.
speed: f32,
/// Sensitivity of the mouse.
sensitivity: f32,
/// Wether the forward button is pressed or not.
forward_pressed: bool,
/// Wether the backward button is pressed or not.
backward_pressed: bool,
}
impl FirstPersonControls {
/// Creates a new default first person controls.
pub fn new() -> FirstPersonControls {
FirstPersonControls {
theta: 0.0,
phi: 0.0,
position: Vector3::new(0.0, 0.0, 0.0),
forward: Vector3::new(0.0, 0.0, 1.0),
speed: 0.001,
forward_pressed: false,
backward_pressed: false,
sensitivity: 500.0,
}
}
/// Updates the camera according to the state of the controls.
fn update_camera(&self, camera: &mut Camera) {
camera.position = self.position;
camera.target = self.position + self.forward;
}
}
impl Controls for FirstPersonControls {
fn manage_event<'a>(&mut self, event: &Event, camera: &mut Camera, renderer: &Renderer<'a, Display>) {
match *event {
// On resize window
Event::WindowEvent {
event: WindowEvent::Resized(width, height), ..
} => {
camera.aspect_ratio = width as f32 / height as f32;
},
// On Z pressed
Event::WindowEvent {
event: WindowEvent::KeyboardInput {
input: KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::Z), state, ..
}, ..
}, ..
} => {
self.forward_pressed = state == ElementState::Pressed;
},
// On S pressed
Event::WindowEvent {
event: WindowEvent::KeyboardInput {
input: KeyboardInput {
virtual_keycode: Some(VirtualKeyCode::S), state, ..
}, ..
}, ..
} => {
self.backward_pressed = state == ElementState::Pressed;
},
// On mouse move
Event::WindowEvent {
event: WindowEvent::CursorMoved {
position: (x, y), ..
}, ..
} => {
let size = renderer.gl_window().window().get_inner_size().unwrap();
let center = Vector2::new(size.0 as f32 / 2.0, size.1 as f32 / 2.0);
let current_position = Vector2::new(x as f32, y as f32);
let difference = (current_position - center) / 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);
self.forward = Vector3::new(
self.phi.cos() * self.theta.cos(),
self.phi.sin(),
self.phi.cos() * self.theta.sin(),
);
// Move the cursor back to the center
renderer
.gl_window()
.window()
.set_cursor_position(size.0 as i32 / 2, size.1 as i32/ 2)
.unwrap();
},
_ => (),
}
self.update_camera(camera);
}
fn update<'a>(&mut self, camera: &mut Camera, _: &Renderer<'a, Display>) {
if self.forward_pressed {
self.position += self.forward * self.speed;
}
if self.backward_pressed {
self.position -= self.forward * self.speed;
}
self.update_camera(camera);
}
}

View File

@ -3,7 +3,12 @@
pub mod camera;
pub mod controls;
use glium::draw_parameters::DepthTest;
use std::cell::Ref;
use std::borrow::Cow;
use glium;
use glium::glutin::GlWindow;
use glium::draw_parameters::{DepthTest, Blend};
use glium::texture::{
RawImage2d,
SrgbTexture2d,
@ -29,6 +34,22 @@ use image;
use model::{Model, Vertex};
use renderer::camera::RenderCamera;
struct RGBAImageData {
pub data: Vec<(u8, u8, u8, u8)>,
pub width: u32,
pub height: u32,
}
impl glium::texture::Texture2dDataSink<(u8, u8, u8, u8)> for RGBAImageData {
fn from_raw(data: Cow<[(u8, u8, u8, u8)]>, width: u32, height: u32) -> Self {
RGBAImageData {
data: data.into_owned(),
width: width,
height: height,
}
}
}
/// Anything on which you can call draw to get a frame.
pub trait Drawer {
/// Get a frame from the drawer.
@ -163,6 +184,7 @@ impl<'a, D: Drawer + Facade + Sized> Renderer<'a, D> {
write: true,
.. Default::default()
},
blend: Blend::alpha_blending(),
.. Default::default()
};
@ -201,6 +223,64 @@ impl<'a, D: Drawer + Facade + Sized> Renderer<'a, D> {
}
}
/// Returns an image of the corresponding frame.
pub fn capture(&self, dimensions: (u32, u32)) -> image::DynamicImage {
let rect = glium::Rect {
left: 0,
bottom: 0,
width: dimensions.0,
height: dimensions.1,
};
let blit_target = glium::BlitTarget {
left: 0,
bottom: 0,
width: dimensions.0 as i32,
height: dimensions.1 as i32,
};
// Create temporary texture and blit the front buffer to it
let texture = glium::texture::Texture2d::empty(self.facade(), dimensions.0, dimensions.1)
.unwrap();
let framebuffer = glium::framebuffer::SimpleFrameBuffer::new(self.facade(), &texture)
.unwrap();
use glium::Surface;
framebuffer.blit_from_frame(
&rect,
&blit_target,
glium::uniforms::MagnifySamplerFilter::Nearest
);
// Read the texture into new pixel buffer
let pixel_buffer = texture.read_to_pixel_buffer();
let image_data: RGBAImageData = pixel_buffer.read_as_texture_2d().unwrap();
let pixels = {
let mut v = Vec::with_capacity(image_data.data.len() * 4);
for (a, b, c, d) in image_data.data {
v.push(a);
v.push(b);
v.push(c);
v.push(d);
}
v
};
// Create ImageBuffer
let image_buffer =
image::ImageBuffer::from_raw(image_data.width, image_data.height, pixels)
.unwrap();
// Save the screenshot to file
let image = image::DynamicImage::ImageRgba8(image_buffer).flipv();
image
}
}
impl<'a> Renderer<'a, Display> {
@ -214,4 +294,9 @@ impl<'a> Renderer<'a, Display> {
self.drawer.gl_window().hide();
}
/// Returns a reference to the gl window.
pub fn gl_window(&self) -> Ref<GlWindow> {
self.drawer.gl_window()
}
}