mirror of https://github.com/Leinnan/doppler.git
Cleanup
This commit is contained in:
parent
f30d198463
commit
dd6b42e55d
|
|
@ -0,0 +1,3 @@
|
||||||
|
[](https://builds.sr.ht/~leinnan/doppler/commits/.build.yml?)
|
||||||
|
|
||||||
|
My OpenGL "engine". WIP
|
||||||
|
|
@ -16,7 +16,7 @@ impl Default for BgInfo {
|
||||||
BgInfo {
|
BgInfo {
|
||||||
r: 0.1,
|
r: 0.1,
|
||||||
g: 0.2,
|
g: 0.2,
|
||||||
b: 0.4
|
b: 0.4,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +29,7 @@ const ZOOM: f32 = 45.0;
|
||||||
|
|
||||||
pub struct Camera {
|
pub struct Camera {
|
||||||
// Camera Attributes
|
// Camera Attributes
|
||||||
pub Position: Point3,
|
pub position: Point3,
|
||||||
pub Front: Vector3,
|
pub Front: Vector3,
|
||||||
pub Up: Vector3,
|
pub Up: Vector3,
|
||||||
pub Right: Vector3,
|
pub Right: Vector3,
|
||||||
|
|
@ -46,7 +46,7 @@ pub struct Camera {
|
||||||
impl Default for Camera {
|
impl Default for Camera {
|
||||||
fn default() -> Camera {
|
fn default() -> Camera {
|
||||||
let mut camera = Camera {
|
let mut camera = Camera {
|
||||||
Position: Point3::new(0.0, 0.0, 0.0),
|
position: Point3::new(0.0, 0.0, 0.0),
|
||||||
Front: vec3(0.0, 0.0, -1.0),
|
Front: vec3(0.0, 0.0, -1.0),
|
||||||
Up: Vector3::zero(), // initialized later
|
Up: Vector3::zero(), // initialized later
|
||||||
Right: Vector3::zero(), // initialized later
|
Right: Vector3::zero(), // initialized later
|
||||||
|
|
@ -65,23 +65,23 @@ impl Default for Camera {
|
||||||
impl Camera {
|
impl Camera {
|
||||||
/// Returns the view matrix calculated using Eular Angles and the LookAt Matrix
|
/// Returns the view matrix calculated using Eular Angles and the LookAt Matrix
|
||||||
pub fn get_view_matrix(&self) -> Matrix4 {
|
pub fn get_view_matrix(&self) -> Matrix4 {
|
||||||
Matrix4::look_at(self.Position, self.Position + self.Front, self.Up)
|
Matrix4::look_at(self.position, self.position + self.Front, self.Up)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
|
/// Processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
|
||||||
pub fn process_keyboard(&mut self, direction: Camera_Movement, deltaTime: f32) {
|
pub fn process_keyboard(&mut self, direction: Camera_Movement, deltaTime: f32) {
|
||||||
let velocity = self.MovementSpeed * deltaTime;
|
let velocity = self.MovementSpeed * deltaTime;
|
||||||
if direction == FORWARD {
|
if direction == FORWARD {
|
||||||
self.Position += self.Front * velocity;
|
self.position += self.Front * velocity;
|
||||||
}
|
}
|
||||||
if direction == BACKWARD {
|
if direction == BACKWARD {
|
||||||
self.Position += -(self.Front * velocity);
|
self.position += -(self.Front * velocity);
|
||||||
}
|
}
|
||||||
if direction == LEFT {
|
if direction == LEFT {
|
||||||
self.Position += -(self.Right * velocity);
|
self.position += -(self.Right * velocity);
|
||||||
}
|
}
|
||||||
if direction == RIGHT {
|
if direction == RIGHT {
|
||||||
self.Position += self.Right * velocity;
|
self.position += self.Right * velocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,265 @@
|
||||||
|
use crate::gaia::bg_info::BgInfo;
|
||||||
|
use crate::gaia::camera::*;
|
||||||
|
use crate::gaia::consts;
|
||||||
|
use crate::gaia::*;
|
||||||
|
use cgmath::{perspective, vec3, Deg, Matrix4, Point3, Rad, Vector3};
|
||||||
|
use imgui_glfw_rs::glfw;
|
||||||
|
use imgui_glfw_rs::glfw::{Action, Context, Key};
|
||||||
|
use imgui_glfw_rs::imgui;
|
||||||
|
use imgui_glfw_rs::ImguiGLFW;
|
||||||
|
use imgui_inspect::InspectArgsStruct;
|
||||||
|
|
||||||
|
pub struct Engine {
|
||||||
|
pub camera: Camera,
|
||||||
|
pub bg_info: BgInfo,
|
||||||
|
pub window: imgui_glfw_rs::glfw::Window,
|
||||||
|
pub window_size: (f32, f32),
|
||||||
|
pub events: std::sync::mpsc::Receiver<(f64, imgui_glfw_rs::glfw::WindowEvent)>,
|
||||||
|
pub glfw: imgui_glfw_rs::glfw::Glfw,
|
||||||
|
pub imgui: imgui::Context,
|
||||||
|
pub imgui_glfw: ImguiGLFW,
|
||||||
|
pub shader: shader::Shader,
|
||||||
|
pub models: Vec<model::Model>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Engine {
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
let mut first_mouse = true;
|
||||||
|
let mut last_x: f32 = consts::SCR_WIDTH as f32 / 2.0;
|
||||||
|
let mut last_y: f32 = consts::SCR_HEIGHT as f32 / 2.0;
|
||||||
|
|
||||||
|
// timing
|
||||||
|
let mut delta_time: f32; // time between current frame and last frame
|
||||||
|
let mut last_frame: f32 = 0.0;
|
||||||
|
{
|
||||||
|
// build and compile shaders
|
||||||
|
// -------------------------
|
||||||
|
self.shader = shader::Shader::from_file(
|
||||||
|
"resources/shaders/model_loading.vs",
|
||||||
|
"resources/shaders/model_loading.fs",
|
||||||
|
);
|
||||||
|
|
||||||
|
// load models
|
||||||
|
// -----------
|
||||||
|
for _ in 0..10 {
|
||||||
|
self.models.push(model::Model::new("resources/objects/nanosuit/nanosuit.obj"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// render loop
|
||||||
|
// -----------
|
||||||
|
while !self.window.should_close() {
|
||||||
|
// per-frame time logic
|
||||||
|
// --------------------
|
||||||
|
let cur_frame = self.glfw.get_time() as f32;
|
||||||
|
delta_time = cur_frame - last_frame;
|
||||||
|
last_frame = cur_frame;
|
||||||
|
|
||||||
|
// input
|
||||||
|
// -----
|
||||||
|
let skip_input =
|
||||||
|
self.imgui.io().want_capture_mouse || self.imgui.io().want_capture_keyboard;
|
||||||
|
if !skip_input {
|
||||||
|
self.process_input(delta_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render
|
||||||
|
// ------
|
||||||
|
unsafe {
|
||||||
|
gl::ClearColor(self.bg_info.r, self.bg_info.g, self.bg_info.b, 1.0);
|
||||||
|
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
// don't forget to enable shader before setting uniforms
|
||||||
|
self.shader.useProgram();
|
||||||
|
|
||||||
|
// view/projection transformations
|
||||||
|
let projection: Matrix4<f32> = perspective(
|
||||||
|
Deg(self.camera.Zoom),
|
||||||
|
self.window_size.0 / self.window_size.1,
|
||||||
|
0.1,
|
||||||
|
100.0,
|
||||||
|
);
|
||||||
|
let view = self.camera.get_view_matrix();
|
||||||
|
self.shader.setMat4(c_str!("projection"), &projection);
|
||||||
|
self.shader.setMat4(c_str!("view"), &view);
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
for m in &self.models {
|
||||||
|
// render the loaded model
|
||||||
|
let mut model = Matrix4::<f32>::from_translation(vec3(0.0, -1.75, -1.25 * (i as f32))); // translate it down so it's at the center of the scene
|
||||||
|
model = model * Matrix4::from_scale(0.2); // it's a bit too big for our scene, so scale it down
|
||||||
|
self.shader.setMat4(c_str!("model"), &model);
|
||||||
|
m.Draw(&self.shader);
|
||||||
|
i = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
|
||||||
|
// -------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
let ui = self.imgui_glfw.frame(&mut self.window, &mut self.imgui);
|
||||||
|
|
||||||
|
{
|
||||||
|
use imgui::*;
|
||||||
|
Window::new(im_str!("Hello world"))
|
||||||
|
.size([300.0, 110.0], Condition::FirstUseEver)
|
||||||
|
.build(&ui, || {
|
||||||
|
ui.text(im_str!("Hello world!"));
|
||||||
|
ui.text(im_str!("こんにちは世界!"));
|
||||||
|
ui.text(im_str!("This...is...imgui-rs!"));
|
||||||
|
ui.separator();
|
||||||
|
ui.text(format!("Mouse position: ({:.1},{:.1})", last_x, last_y));
|
||||||
|
// let selected = vec![&self.bg_info];
|
||||||
|
// <BgInfo as imgui_inspect::InspectRenderStruct<BgInfo>>::render(
|
||||||
|
// &selected,
|
||||||
|
// "Example Struct - Read Only",
|
||||||
|
// &ui,
|
||||||
|
// &InspectArgsStruct::default(),
|
||||||
|
// );
|
||||||
|
// let mut selected_mut = vec![&mut self.bg_info];
|
||||||
|
// <BgInfo as imgui_inspect::InspectRenderStruct<BgInfo>>::render_mut(
|
||||||
|
// &mut selected_mut,
|
||||||
|
// "Example Struct - Writable",
|
||||||
|
// &ui,
|
||||||
|
// &InspectArgsStruct::default(),
|
||||||
|
// );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.imgui_glfw.draw(ui, &mut self.window);
|
||||||
|
self.window.swap_buffers();
|
||||||
|
self.glfw.poll_events();
|
||||||
|
// events
|
||||||
|
// -----
|
||||||
|
self.process_events(&mut first_mouse, &mut last_x, &mut last_y, skip_input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_input(&mut self, delta_time: f32) {
|
||||||
|
if self.window.get_key(Key::Escape) == Action::Press {
|
||||||
|
self.window.set_should_close(true)
|
||||||
|
}
|
||||||
|
if self.window.get_key(Key::W) == Action::Press {
|
||||||
|
self.camera
|
||||||
|
.process_keyboard(Camera_Movement::FORWARD, delta_time);
|
||||||
|
}
|
||||||
|
if self.window.get_key(Key::S) == Action::Press {
|
||||||
|
self.camera
|
||||||
|
.process_keyboard(Camera_Movement::BACKWARD, delta_time);
|
||||||
|
}
|
||||||
|
if self.window.get_key(Key::A) == Action::Press {
|
||||||
|
self.camera
|
||||||
|
.process_keyboard(Camera_Movement::LEFT, delta_time);
|
||||||
|
}
|
||||||
|
if self.window.get_key(Key::D) == Action::Press {
|
||||||
|
self.camera
|
||||||
|
.process_keyboard(Camera_Movement::RIGHT, delta_time);
|
||||||
|
}
|
||||||
|
self.camera
|
||||||
|
.enable_mouse_movement(self.window.get_key(Key::LeftControl) != Action::Press);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_events(
|
||||||
|
&mut self,
|
||||||
|
first_mouse: &mut bool,
|
||||||
|
last_x: &mut f32,
|
||||||
|
last_y: &mut f32,
|
||||||
|
skip_input: bool,
|
||||||
|
) {
|
||||||
|
for (_, event) in glfw::flush_messages(&self.events) {
|
||||||
|
self.imgui_glfw.handle_event(&mut self.imgui, &event);
|
||||||
|
match event {
|
||||||
|
glfw::WindowEvent::FramebufferSize(width, height) => {
|
||||||
|
// make sure the viewport matches the new window dimensions; note that width and
|
||||||
|
// height will be significantly larger than specified on retina displays.
|
||||||
|
unsafe { gl::Viewport(0, 0, width, height) }
|
||||||
|
self.window_size = (width as f32, height as f32);
|
||||||
|
}
|
||||||
|
glfw::WindowEvent::CursorPos(xpos, ypos) => {
|
||||||
|
if skip_input {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let (xpos, ypos) = (xpos as f32, ypos as f32);
|
||||||
|
if *first_mouse {
|
||||||
|
*last_x = xpos;
|
||||||
|
*last_y = ypos;
|
||||||
|
*first_mouse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let xoffset = xpos - *last_x;
|
||||||
|
let yoffset = *last_y - ypos; // reversed since y-coordinates go from bottom to top
|
||||||
|
|
||||||
|
*last_x = xpos;
|
||||||
|
*last_y = ypos;
|
||||||
|
|
||||||
|
self.camera.process_mouse_movement(xoffset, yoffset, true);
|
||||||
|
}
|
||||||
|
glfw::WindowEvent::Scroll(_xoffset, yoffset) => {
|
||||||
|
if skip_input {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.camera.process_mouse_scroll(yoffset as f32);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Engine {
|
||||||
|
fn default() -> Self {
|
||||||
|
// glfw: initialize and configure
|
||||||
|
// ------------------------------
|
||||||
|
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
|
||||||
|
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
|
||||||
|
glfw.window_hint(glfw::WindowHint::OpenGlProfile(
|
||||||
|
glfw::OpenGlProfileHint::Core,
|
||||||
|
));
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
|
||||||
|
|
||||||
|
// glfw window creation
|
||||||
|
// --------------------
|
||||||
|
let (mut window, events) = glfw
|
||||||
|
.create_window(
|
||||||
|
consts::SCR_WIDTH,
|
||||||
|
consts::SCR_HEIGHT,
|
||||||
|
"chRustedGL",
|
||||||
|
glfw::WindowMode::Windowed,
|
||||||
|
)
|
||||||
|
.expect("Failed to create GLFW window");
|
||||||
|
|
||||||
|
window.make_current();
|
||||||
|
window.set_all_polling(true);
|
||||||
|
window.set_framebuffer_size_polling(true);
|
||||||
|
window.set_cursor_pos_polling(true);
|
||||||
|
window.set_scroll_polling(true);
|
||||||
|
|
||||||
|
// tell GLFW to capture our mouse
|
||||||
|
window.set_cursor_mode(glfw::CursorMode::Disabled);
|
||||||
|
// gl: load all OpenGL function pointers
|
||||||
|
// ---------------------------------------
|
||||||
|
gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
|
||||||
|
|
||||||
|
let mut imgui = imgui::Context::create();
|
||||||
|
let mut imgui_glfw = ImguiGLFW::new(&mut imgui, &mut window);
|
||||||
|
// configure global opengl state
|
||||||
|
// -----------------------------
|
||||||
|
unsafe{gl::Enable(gl::DEPTH_TEST);}
|
||||||
|
|
||||||
|
Engine {
|
||||||
|
camera: Camera {
|
||||||
|
position: Point3::new(0.0, 0.0, 3.0),
|
||||||
|
..Camera::default()
|
||||||
|
},
|
||||||
|
bg_info: BgInfo::default(),
|
||||||
|
window: window,
|
||||||
|
window_size: (consts::SCR_WIDTH as f32, consts::SCR_HEIGHT as f32),
|
||||||
|
events: events,
|
||||||
|
glfw: glfw,
|
||||||
|
imgui: imgui,
|
||||||
|
imgui_glfw: imgui_glfw,
|
||||||
|
shader: shader::Shader::default(),
|
||||||
|
models: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,11 +6,11 @@ use std::mem::size_of;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use cgmath::{ Vector3, Vector2 };
|
|
||||||
use cgmath::prelude::*;
|
use cgmath::prelude::*;
|
||||||
|
use cgmath::{Vector2, Vector3};
|
||||||
use gl;
|
use gl;
|
||||||
|
|
||||||
use crate::shader::Shader;
|
use crate::gaia::shader::Shader;
|
||||||
|
|
||||||
// NOTE: without repr(C) the compiler may reorder the fields or use different padding/alignment than C.
|
// NOTE: without repr(C) the compiler may reorder the fields or use different padding/alignment than C.
|
||||||
// Depending on how you pass the data to OpenGL, this may be bad. In this case it's not strictly
|
// Depending on how you pass the data to OpenGL, this may be bad. In this case it's not strictly
|
||||||
|
|
@ -18,7 +18,7 @@ use crate::shader::Shader;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Vertex {
|
pub struct Vertex {
|
||||||
// position
|
// position
|
||||||
pub Position: Vector3<f32>,
|
pub position: Vector3<f32>,
|
||||||
// normal
|
// normal
|
||||||
pub Normal: Vector3<f32>,
|
pub Normal: Vector3<f32>,
|
||||||
// texCoords
|
// texCoords
|
||||||
|
|
@ -32,7 +32,7 @@ pub struct Vertex {
|
||||||
impl Default for Vertex {
|
impl Default for Vertex {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Vertex {
|
Vertex {
|
||||||
Position: Vector3::zero(),
|
position: Vector3::zero(),
|
||||||
Normal: Vector3::zero(),
|
Normal: Vector3::zero(),
|
||||||
TexCoords: Vector2::zero(),
|
TexCoords: Vector2::zero(),
|
||||||
Tangent: Vector3::zero(),
|
Tangent: Vector3::zero(),
|
||||||
|
|
@ -63,8 +63,12 @@ pub struct Mesh {
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Mesh {
|
pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Mesh {
|
||||||
let mut mesh = Mesh {
|
let mut mesh = Mesh {
|
||||||
vertices, indices, textures,
|
vertices,
|
||||||
VAO: 0, VBO: 0, EBO: 0
|
indices,
|
||||||
|
textures,
|
||||||
|
VAO: 0,
|
||||||
|
VBO: 0,
|
||||||
|
EBO: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// now that we have all the required data, set the vertex buffers and its attribute pointers.
|
// now that we have all the required data, set the vertex buffers and its attribute pointers.
|
||||||
|
|
@ -87,7 +91,7 @@ impl Mesh {
|
||||||
"texture_diffuse" => {
|
"texture_diffuse" => {
|
||||||
diffuseNr += 1;
|
diffuseNr += 1;
|
||||||
diffuseNr
|
diffuseNr
|
||||||
},
|
}
|
||||||
"texture_specular" => {
|
"texture_specular" => {
|
||||||
specularNr += 1;
|
specularNr += 1;
|
||||||
specularNr
|
specularNr
|
||||||
|
|
@ -100,18 +104,26 @@ impl Mesh {
|
||||||
heightNr += 1;
|
heightNr += 1;
|
||||||
heightNr
|
heightNr
|
||||||
}
|
}
|
||||||
_ => panic!("unknown texture type")
|
_ => panic!("unknown texture type"),
|
||||||
};
|
};
|
||||||
// now set the sampler to the correct texture unit
|
// now set the sampler to the correct texture unit
|
||||||
let sampler = CString::new(format!("{}{}", name, number)).unwrap();
|
let sampler = CString::new(format!("{}{}", name, number)).unwrap();
|
||||||
gl::Uniform1i(gl::GetUniformLocation(shader.ID, sampler.as_ptr()), i as i32);
|
gl::Uniform1i(
|
||||||
|
gl::GetUniformLocation(shader.ID, sampler.as_ptr()),
|
||||||
|
i as i32,
|
||||||
|
);
|
||||||
// and finally bind the texture
|
// and finally bind the texture
|
||||||
gl::BindTexture(gl::TEXTURE_2D, texture.id);
|
gl::BindTexture(gl::TEXTURE_2D, texture.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw mesh
|
// draw mesh
|
||||||
gl::BindVertexArray(self.VAO);
|
gl::BindVertexArray(self.VAO);
|
||||||
gl::DrawElements(gl::TRIANGLES, self.indices.len() as i32, gl::UNSIGNED_INT, ptr::null());
|
gl::DrawElements(
|
||||||
|
gl::TRIANGLES,
|
||||||
|
self.indices.len() as i32,
|
||||||
|
gl::UNSIGNED_INT,
|
||||||
|
ptr::null(),
|
||||||
|
);
|
||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
|
|
||||||
// always good practice to set everything back to defaults once configured.
|
// always good practice to set everything back to defaults once configured.
|
||||||
|
|
@ -143,19 +155,54 @@ impl Mesh {
|
||||||
let size = size_of::<Vertex>() as i32;
|
let size = size_of::<Vertex>() as i32;
|
||||||
// vertex Positions
|
// vertex Positions
|
||||||
gl::EnableVertexAttribArray(0);
|
gl::EnableVertexAttribArray(0);
|
||||||
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Position) as *const c_void);
|
gl::VertexAttribPointer(
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
gl::FLOAT,
|
||||||
|
gl::FALSE,
|
||||||
|
size,
|
||||||
|
offset_of!(Vertex, position) as *const c_void,
|
||||||
|
);
|
||||||
// vertex normals
|
// vertex normals
|
||||||
gl::EnableVertexAttribArray(1);
|
gl::EnableVertexAttribArray(1);
|
||||||
gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Normal) as *const c_void);
|
gl::VertexAttribPointer(
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
gl::FLOAT,
|
||||||
|
gl::FALSE,
|
||||||
|
size,
|
||||||
|
offset_of!(Vertex, Normal) as *const c_void,
|
||||||
|
);
|
||||||
// vertex texture coords
|
// vertex texture coords
|
||||||
gl::EnableVertexAttribArray(2);
|
gl::EnableVertexAttribArray(2);
|
||||||
gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, TexCoords) as *const c_void);
|
gl::VertexAttribPointer(
|
||||||
|
2,
|
||||||
|
2,
|
||||||
|
gl::FLOAT,
|
||||||
|
gl::FALSE,
|
||||||
|
size,
|
||||||
|
offset_of!(Vertex, TexCoords) as *const c_void,
|
||||||
|
);
|
||||||
// vertex tangent
|
// vertex tangent
|
||||||
gl::EnableVertexAttribArray(3);
|
gl::EnableVertexAttribArray(3);
|
||||||
gl::VertexAttribPointer(3, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Tangent) as *const c_void);
|
gl::VertexAttribPointer(
|
||||||
|
3,
|
||||||
|
3,
|
||||||
|
gl::FLOAT,
|
||||||
|
gl::FALSE,
|
||||||
|
size,
|
||||||
|
offset_of!(Vertex, Tangent) as *const c_void,
|
||||||
|
);
|
||||||
// vertex bitangent
|
// vertex bitangent
|
||||||
gl::EnableVertexAttribArray(4);
|
gl::EnableVertexAttribArray(4);
|
||||||
gl::VertexAttribPointer(4, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, Bitangent) as *const c_void);
|
gl::VertexAttribPointer(
|
||||||
|
4,
|
||||||
|
3,
|
||||||
|
gl::FLOAT,
|
||||||
|
gl::FALSE,
|
||||||
|
size,
|
||||||
|
offset_of!(Vertex, Bitangent) as *const c_void,
|
||||||
|
);
|
||||||
|
|
||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ pub mod consts;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod macros;
|
pub mod macros;
|
||||||
pub mod shader;
|
|
||||||
pub mod model;
|
|
||||||
pub mod mesh;
|
|
||||||
pub mod bg_info;
|
pub mod bg_info;
|
||||||
|
pub mod engine;
|
||||||
|
pub mod mesh;
|
||||||
|
pub mod model;
|
||||||
|
pub mod shader;
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ use image::DynamicImage::*;
|
||||||
use image::GenericImage;
|
use image::GenericImage;
|
||||||
use tobj;
|
use tobj;
|
||||||
|
|
||||||
use crate::mesh::{ Mesh, Texture, Vertex };
|
use crate::gaia::mesh::{Mesh, Texture, Vertex};
|
||||||
use crate::shader::Shader;
|
use crate::gaia::shader::Shader;
|
||||||
use crate::utils::*;
|
use crate::gaia::utils::*;
|
||||||
|
|
||||||
// #[derive(Default)]
|
// #[derive(Default)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
|
|
@ -30,7 +30,12 @@ impl Model {
|
||||||
let mut model = Model {
|
let mut model = Model {
|
||||||
meshes: Vec::<Mesh>::new(),
|
meshes: Vec::<Mesh>::new(),
|
||||||
textures_loaded: Vec::<Texture>::new(),
|
textures_loaded: Vec::<Texture>::new(),
|
||||||
directory: pathObj.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into()
|
directory: pathObj
|
||||||
|
.parent()
|
||||||
|
.unwrap_or_else(|| Path::new(""))
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
model.loadModel(path);
|
model.loadModel(path);
|
||||||
model
|
model
|
||||||
|
|
@ -38,7 +43,9 @@ impl Model {
|
||||||
|
|
||||||
pub fn Draw(&self, shader: &Shader) {
|
pub fn Draw(&self, shader: &Shader) {
|
||||||
for mesh in &self.meshes {
|
for mesh in &self.meshes {
|
||||||
unsafe { mesh.Draw(shader); }
|
unsafe {
|
||||||
|
mesh.Draw(shader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,7 +55,12 @@ impl Model {
|
||||||
println!("Started loading model from path: {}", path.display());
|
println!("Started loading model from path: {}", path.display());
|
||||||
|
|
||||||
// retrieve the directory path of the filepath
|
// retrieve the directory path of the filepath
|
||||||
self.directory = path.parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().into();
|
self.directory = path
|
||||||
|
.parent()
|
||||||
|
.unwrap_or_else(|| Path::new(""))
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.into();
|
||||||
let obj = tobj::load_obj(path, true);
|
let obj = tobj::load_obj(path, true);
|
||||||
|
|
||||||
let (models, materials) = obj.unwrap();
|
let (models, materials) = obj.unwrap();
|
||||||
|
|
@ -63,7 +75,7 @@ impl Model {
|
||||||
let (p, n, t) = (&mesh.positions, &mesh.normals, &mesh.texcoords);
|
let (p, n, t) = (&mesh.positions, &mesh.normals, &mesh.texcoords);
|
||||||
for i in 0..num_vertices {
|
for i in 0..num_vertices {
|
||||||
vertices.push(Vertex {
|
vertices.push(Vertex {
|
||||||
Position: vec3(p[i*3], p[i*3+1], p[i*3+2]),
|
position: vec3(p[i * 3], p[i * 3 + 1], p[i * 3 + 2]),
|
||||||
Normal: vec3(n[i * 3], n[i * 3 + 1], n[i * 3 + 2]),
|
Normal: vec3(n[i * 3], n[i * 3 + 1], n[i * 3 + 2]),
|
||||||
TexCoords: vec2(t[i * 2], t[i * 2 + 1]),
|
TexCoords: vec2(t[i * 2], t[i * 2 + 1]),
|
||||||
..Vertex::default()
|
..Vertex::default()
|
||||||
|
|
@ -77,17 +89,20 @@ impl Model {
|
||||||
|
|
||||||
// 1. diffuse map
|
// 1. diffuse map
|
||||||
if !material.diffuse_texture.is_empty() {
|
if !material.diffuse_texture.is_empty() {
|
||||||
let texture = self.loadMaterialTexture(&material.diffuse_texture, "texture_diffuse");
|
let texture =
|
||||||
|
self.loadMaterialTexture(&material.diffuse_texture, "texture_diffuse");
|
||||||
textures.push(texture);
|
textures.push(texture);
|
||||||
}
|
}
|
||||||
// 2. specular map
|
// 2. specular map
|
||||||
if !material.specular_texture.is_empty() {
|
if !material.specular_texture.is_empty() {
|
||||||
let texture = self.loadMaterialTexture(&material.specular_texture, "texture_specular");
|
let texture =
|
||||||
|
self.loadMaterialTexture(&material.specular_texture, "texture_specular");
|
||||||
textures.push(texture);
|
textures.push(texture);
|
||||||
}
|
}
|
||||||
// 3. normal map
|
// 3. normal map
|
||||||
if !material.normal_texture.is_empty() {
|
if !material.normal_texture.is_empty() {
|
||||||
let texture = self.loadMaterialTexture(&material.normal_texture, "texture_normal");
|
let texture =
|
||||||
|
self.loadMaterialTexture(&material.normal_texture, "texture_normal");
|
||||||
textures.push(texture);
|
textures.push(texture);
|
||||||
}
|
}
|
||||||
// NOTE: no height maps
|
// NOTE: no height maps
|
||||||
|
|
@ -96,7 +111,6 @@ impl Model {
|
||||||
self.meshes.push(Mesh::new(vertices, indices, textures));
|
self.meshes.push(Mesh::new(vertices, indices, textures));
|
||||||
}
|
}
|
||||||
println!("Finished loading model from path: {}", path.display());
|
println!("Finished loading model from path: {}", path.display());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadMaterialTexture(&mut self, path: &str, typeName: &str) -> Texture {
|
fn loadMaterialTexture(&mut self, path: &str, typeName: &str) -> Texture {
|
||||||
|
|
@ -108,12 +122,11 @@ impl Model {
|
||||||
}
|
}
|
||||||
|
|
||||||
let texture = Texture {
|
let texture = Texture {
|
||||||
id: unsafe { loadTextureFromDir(path, &self.directory) },
|
id: unsafe { load_texture_from_dir(path, &self.directory) },
|
||||||
type_: typeName.into(),
|
type_: typeName.into(),
|
||||||
path: path.into()
|
path: path.into(),
|
||||||
};
|
};
|
||||||
self.textures_loaded.push(texture.clone());
|
self.textures_loaded.push(texture.clone());
|
||||||
texture
|
texture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ use std::str;
|
||||||
use gl;
|
use gl;
|
||||||
use gl::types::*;
|
use gl::types::*;
|
||||||
|
|
||||||
|
use crate::gaia::consts;
|
||||||
use cgmath::prelude::*;
|
use cgmath::prelude::*;
|
||||||
use cgmath::{Matrix, Matrix4, Vector3};
|
use cgmath::{Matrix, Matrix4, Vector3};
|
||||||
use crate::gaia::consts;
|
|
||||||
|
|
||||||
pub struct Shader {
|
pub struct Shader {
|
||||||
pub ID: u32,
|
pub ID: u32,
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,11 @@ use image::DynamicImage::*;
|
||||||
use image::GenericImage;
|
use image::GenericImage;
|
||||||
use image::*;
|
use image::*;
|
||||||
|
|
||||||
pub unsafe fn loadTexture(path: &str) -> u32 {
|
pub unsafe fn load_texture(path: &str) -> u32 {
|
||||||
println!("Loading texture from path: {}", path);
|
println!("Loading texture from path: {}", path);
|
||||||
let mut textureID = 0;
|
let mut id = 0;
|
||||||
|
|
||||||
gl::GenTextures(1, &mut textureID);
|
gl::GenTextures(1, &mut id);
|
||||||
let img = image::open(&Path::new(path)).expect("Texture failed to load");
|
let img = image::open(&Path::new(path)).expect("Texture failed to load");
|
||||||
let format = match img {
|
let format = match img {
|
||||||
ImageLuma8(_) => gl::RED,
|
ImageLuma8(_) => gl::RED,
|
||||||
|
|
@ -26,7 +26,7 @@ pub unsafe fn loadTexture(path: &str) -> u32 {
|
||||||
let data = img.raw_pixels();
|
let data = img.raw_pixels();
|
||||||
let dim = img.dimensions();
|
let dim = img.dimensions();
|
||||||
|
|
||||||
gl::BindTexture(gl::TEXTURE_2D, textureID);
|
gl::BindTexture(gl::TEXTURE_2D, id);
|
||||||
gl::TexImage2D(
|
gl::TexImage2D(
|
||||||
gl::TEXTURE_2D,
|
gl::TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
|
|
@ -49,11 +49,11 @@ pub unsafe fn loadTexture(path: &str) -> u32 {
|
||||||
);
|
);
|
||||||
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
|
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
|
||||||
|
|
||||||
textureID
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn loadTextureFromDir(filename: &str, directory: &str) -> u32 {
|
pub unsafe fn load_texture_from_dir(filename: &str, directory: &str) -> u32 {
|
||||||
let fullpath = format!("{}/{}", directory, filename);
|
let fullpath = format!("{}/{}", directory, filename);
|
||||||
|
|
||||||
loadTexture(&fullpath)
|
load_texture(&fullpath)
|
||||||
}
|
}
|
||||||
252
src/main.rs
252
src/main.rs
|
|
@ -1,255 +1,15 @@
|
||||||
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||||
|
|
||||||
extern crate gl;
|
extern crate gl;
|
||||||
extern crate imgui_glfw_rs;
|
|
||||||
extern crate image;
|
extern crate image;
|
||||||
// Use the reexported glfw crate to avoid version conflicts.
|
extern crate imgui_glfw_rs;
|
||||||
use imgui_glfw_rs::glfw;
|
|
||||||
// Use the reexported imgui crate to avoid version conflicts.
|
|
||||||
use imgui_glfw_rs::imgui;
|
|
||||||
|
|
||||||
use imgui_glfw_rs::ImguiGLFW;
|
|
||||||
use imgui_inspect::InspectArgsStruct;
|
|
||||||
use self::gl::types::*;
|
|
||||||
use imgui_glfw_rs::glfw::{Action, Context, Key};
|
|
||||||
use cgmath::prelude::*;
|
|
||||||
use cgmath::{perspective, vec3, Deg, Matrix4, Point3, Rad, Vector3};
|
|
||||||
use human_panic::setup_panic;
|
use human_panic::setup_panic;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
mod gaia;
|
mod gaia;
|
||||||
use crate::gaia::camera::*;
|
use crate::gaia::engine::Engine;
|
||||||
use crate::gaia::*;
|
|
||||||
use crate::gaia::bg_info::BgInfo;
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
setup_panic!();
|
setup_panic!();
|
||||||
let mut camera = Camera {
|
let mut engine = Engine::default();
|
||||||
Position: Point3::new(0.0, 0.0, 3.0),
|
|
||||||
..Camera::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut first_mouse = true;
|
engine.run();
|
||||||
let mut last_x: f32 = consts::SCR_WIDTH as f32 / 2.0;
|
|
||||||
let mut last_y: f32 = consts::SCR_HEIGHT as f32 / 2.0;
|
|
||||||
|
|
||||||
// timing
|
|
||||||
let mut delta_time: f32; // time between current frame and last frame
|
|
||||||
let mut last_frame: f32 = 0.0;
|
|
||||||
// glfw: initialize and configure
|
|
||||||
// ------------------------------
|
|
||||||
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
|
|
||||||
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
|
|
||||||
glfw.window_hint(glfw::WindowHint::OpenGlProfile(
|
|
||||||
glfw::OpenGlProfileHint::Core,
|
|
||||||
));
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
|
|
||||||
|
|
||||||
// glfw window creation
|
|
||||||
// --------------------
|
|
||||||
let (mut window, events) = glfw
|
|
||||||
.create_window(
|
|
||||||
consts::SCR_WIDTH,
|
|
||||||
consts::SCR_HEIGHT,
|
|
||||||
"chRustedGL",
|
|
||||||
glfw::WindowMode::Windowed,
|
|
||||||
)
|
|
||||||
.expect("Failed to create GLFW window");
|
|
||||||
|
|
||||||
window.make_current();
|
|
||||||
window.set_all_polling(true);
|
|
||||||
window.set_framebuffer_size_polling(true);
|
|
||||||
window.set_cursor_pos_polling(true);
|
|
||||||
window.set_scroll_polling(true);
|
|
||||||
|
|
||||||
// tell GLFW to capture our mouse
|
|
||||||
window.set_cursor_mode(glfw::CursorMode::Disabled);
|
|
||||||
|
|
||||||
// gl: load all OpenGL function pointers
|
|
||||||
// ---------------------------------------
|
|
||||||
gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
|
|
||||||
|
|
||||||
|
|
||||||
let (ourShader, ourModel) = unsafe {
|
|
||||||
// configure global opengl state
|
|
||||||
// -----------------------------
|
|
||||||
gl::Enable(gl::DEPTH_TEST);
|
|
||||||
|
|
||||||
// build and compile shaders
|
|
||||||
// -------------------------
|
|
||||||
let ourShader = shader::Shader::from_file(
|
|
||||||
"resources/shaders/model_loading.vs",
|
|
||||||
"resources/shaders/model_loading.fs");
|
|
||||||
|
|
||||||
// load models
|
|
||||||
// -----------
|
|
||||||
let ourModel = model::Model::new("resources/objects/nanosuit/nanosuit.obj");
|
|
||||||
|
|
||||||
// draw in wireframe
|
|
||||||
// gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
|
|
||||||
|
|
||||||
(ourShader, ourModel)
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let mut imgui = imgui::Context::create();
|
|
||||||
|
|
||||||
let mut imgui_glfw = ImguiGLFW::new(&mut imgui, &mut window);
|
|
||||||
|
|
||||||
// render loop
|
|
||||||
// -----------
|
|
||||||
let mut bg = BgInfo::default();
|
|
||||||
while !window.should_close() {
|
|
||||||
// per-frame time logic
|
|
||||||
// --------------------
|
|
||||||
let cur_frame = glfw.get_time() as f32;
|
|
||||||
delta_time = cur_frame - last_frame;
|
|
||||||
last_frame = cur_frame;
|
|
||||||
|
|
||||||
// input
|
|
||||||
// -----
|
|
||||||
let skip_input = imgui.io().want_capture_mouse || imgui.io().want_capture_keyboard;
|
|
||||||
if !skip_input {
|
|
||||||
process_input(&mut window, delta_time, &mut camera);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render
|
|
||||||
// ------
|
|
||||||
unsafe {
|
|
||||||
gl::ClearColor(bg.r, bg.g, bg.b, 1.0);
|
|
||||||
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
// don't forget to enable shader before setting uniforms
|
|
||||||
ourShader.useProgram();
|
|
||||||
|
|
||||||
// view/projection transformations
|
|
||||||
let projection: Matrix4<f32> = perspective(Deg(camera.Zoom), consts::SCR_WIDTH as f32 / consts::SCR_HEIGHT as f32, 0.1, 100.0);
|
|
||||||
let view = camera.get_view_matrix();
|
|
||||||
ourShader.setMat4(c_str!("projection"), &projection);
|
|
||||||
ourShader.setMat4(c_str!("view"), &view);
|
|
||||||
|
|
||||||
// render the loaded model
|
|
||||||
let mut model = Matrix4::<f32>::from_translation(vec3(0.0, -1.75, 0.0)); // translate it down so it's at the center of the scene
|
|
||||||
model = model * Matrix4::from_scale(0.2); // it's a bit too big for our scene, so scale it down
|
|
||||||
ourShader.setMat4(c_str!("model"), &model);
|
|
||||||
ourModel.Draw(&ourShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
|
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
let ui = imgui_glfw.frame(&mut window, &mut imgui);
|
|
||||||
|
|
||||||
{
|
|
||||||
use imgui::*;
|
|
||||||
Window::new(im_str!("Hello world"))
|
|
||||||
.size([300.0, 110.0], Condition::FirstUseEver)
|
|
||||||
.build(&ui, || {
|
|
||||||
ui.text(im_str!("Hello world!"));
|
|
||||||
ui.text(im_str!("こんにちは世界!"));
|
|
||||||
ui.text(im_str!("This...is...imgui-rs!"));
|
|
||||||
ui.separator();
|
|
||||||
ui.text(format!(
|
|
||||||
"Mouse Position: ({:.1},{:.1})",
|
|
||||||
last_x, last_y
|
|
||||||
));
|
|
||||||
let selected = vec![&bg];
|
|
||||||
<BgInfo as imgui_inspect::InspectRenderStruct<
|
|
||||||
BgInfo,
|
|
||||||
>>::render(
|
|
||||||
&selected,
|
|
||||||
"Example Struct - Read Only",
|
|
||||||
&ui,
|
|
||||||
&InspectArgsStruct::default(),
|
|
||||||
);
|
|
||||||
let mut selected_mut = vec![&mut bg];
|
|
||||||
<BgInfo as imgui_inspect::InspectRenderStruct<
|
|
||||||
BgInfo,
|
|
||||||
>>::render_mut(
|
|
||||||
&mut selected_mut,
|
|
||||||
"Example Struct - Writable",
|
|
||||||
&ui,
|
|
||||||
&InspectArgsStruct::default(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
imgui_glfw.draw(ui, &mut window);
|
|
||||||
window.swap_buffers();
|
|
||||||
glfw.poll_events();
|
|
||||||
// events
|
|
||||||
// -----
|
|
||||||
|
|
||||||
for (_, event) in glfw::flush_messages(&events) {
|
|
||||||
imgui_glfw.handle_event(&mut imgui, &event);
|
|
||||||
process_events(
|
|
||||||
event,
|
|
||||||
&mut first_mouse,
|
|
||||||
&mut last_x,
|
|
||||||
&mut last_y,
|
|
||||||
&mut camera,
|
|
||||||
skip_input
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn process_events(
|
|
||||||
event: imgui_glfw_rs::glfw::WindowEvent,
|
|
||||||
first_mouse: &mut bool,
|
|
||||||
last_x: &mut f32,
|
|
||||||
last_y: &mut f32,
|
|
||||||
camera: &mut Camera,
|
|
||||||
skip_input: bool
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
glfw::WindowEvent::FramebufferSize(width, height) => {
|
|
||||||
// make sure the viewport matches the new window dimensions; note that width and
|
|
||||||
// height will be significantly larger than specified on retina displays.
|
|
||||||
unsafe { gl::Viewport(0, 0, width, height) }
|
|
||||||
}
|
|
||||||
glfw::WindowEvent::CursorPos(xpos, ypos) => {
|
|
||||||
if skip_input { return; }
|
|
||||||
let (xpos, ypos) = (xpos as f32, ypos as f32);
|
|
||||||
if *first_mouse {
|
|
||||||
*last_x = xpos;
|
|
||||||
*last_y = ypos;
|
|
||||||
*first_mouse = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let xoffset = xpos - *last_x;
|
|
||||||
let yoffset = *last_y - ypos; // reversed since y-coordinates go from bottom to top
|
|
||||||
|
|
||||||
*last_x = xpos;
|
|
||||||
*last_y = ypos;
|
|
||||||
|
|
||||||
camera.process_mouse_movement(xoffset, yoffset, true);
|
|
||||||
}
|
|
||||||
glfw::WindowEvent::Scroll(_xoffset, yoffset) => {
|
|
||||||
if skip_input { return; }
|
|
||||||
camera.process_mouse_scroll(yoffset as f32);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Input processing function as introduced in 1.7.4 (Camera Class) and used in
|
|
||||||
/// most later tutorials
|
|
||||||
pub fn process_input(window: &mut glfw::Window, delta_time: f32, camera: &mut Camera) {
|
|
||||||
if window.get_key(Key::Escape) == Action::Press {
|
|
||||||
window.set_should_close(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
if window.get_key(Key::W) == Action::Press {
|
|
||||||
camera.process_keyboard(Camera_Movement::FORWARD, delta_time);
|
|
||||||
}
|
|
||||||
if window.get_key(Key::S) == Action::Press {
|
|
||||||
camera.process_keyboard(Camera_Movement::BACKWARD, delta_time);
|
|
||||||
}
|
|
||||||
if window.get_key(Key::A) == Action::Press {
|
|
||||||
camera.process_keyboard(Camera_Movement::LEFT, delta_time);
|
|
||||||
}
|
|
||||||
if window.get_key(Key::D) == Action::Press {
|
|
||||||
camera.process_keyboard(Camera_Movement::RIGHT, delta_time);
|
|
||||||
}
|
|
||||||
camera.enable_mouse_movement(window.get_key(Key::LeftControl) != Action::Press);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue