Oh my god, rust is so good
This commit is contained in:
parent
b42abd0325
commit
83065cedf2
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue