doppler/src/main.rs

296 lines
11 KiB
Rust

extern crate gl;
extern crate glfw;
extern crate image;
use self::camera::*;
use self::gl::types::*;
use self::glfw::{Action, Context, Key};
use cgmath::prelude::*;
use cgmath::{perspective, vec3, Deg, Matrix4, Point3, Rad, Vector3};
use human_panic::setup_panic;
use image::GenericImageView;
use std::ffi::CString;
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::sync::mpsc::Receiver;
mod camera;
mod consts;
mod macros;
mod shader;
const CUBES_POS: [Vector3<f32>; 10] = [
vec3(0.0, 0.0, 0.0),
vec3(2.0, 5.0, -15.0),
vec3(-1.5, -2.2, -2.5),
vec3(-3.8, -2.0, -12.3),
vec3(2.4, -0.4, -3.5),
vec3(-1.7, 3.0, -7.5),
vec3(1.3, -2.0, -2.5),
vec3(1.5, 2.0, -2.5),
vec3(1.5, 0.2, -1.5),
vec3(-1.3, 1.0, -1.5),
];
pub fn main() {
setup_panic!();
let mut camera = Camera {
Position: Point3::new(0.0, 0.0, 3.0),
..Camera::default()
};
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;
// 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_key_polling(true);
window.set_framebuffer_size_polling(true);
// gl: load all OpenGL function pointers
// ---------------------------------------
gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
let (shader_object, vbo, vao, texture) = unsafe {
gl::Enable(gl::DEPTH_TEST);
let v_shader = CString::new(consts::VERTEX_SHADER_SRC.as_bytes()).unwrap();
let f_shader = CString::new(consts::FRAGMENT_SHADER_SRC.as_bytes()).unwrap();
let shader = crate::shader::Shader::new(v_shader, f_shader);
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
// HINT: type annotation is crucial since default for float literals is f64
let vertices: [f32; 180] = [
-0.5, -0.5, -0.5, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5,
0.5, -0.5, 1.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 0.0, -0.5, -0.5,
0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0,
1.0, -0.5, 0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0,
-0.5, 0.5, -0.5, 1.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, 0.0, 1.0,
-0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5,
-0.5, 1.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, 0.5,
0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0,
1.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0,
-0.5, -0.5, -0.5, 0.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5,
0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, 0.5, -0.5,
0.0, 1.0,
];
let (mut vbo, mut vao) = (0, 0);
gl::GenVertexArrays(1, &mut vao);
gl::GenBuffers(1, &mut vbo);
gl::BindVertexArray(vao);
gl::BindBuffer(gl::ARRAY_BUFFER, vbo);
gl::BufferData(
gl::ARRAY_BUFFER,
(vertices.len() * mem::size_of::<GLfloat>()) as GLsizeiptr,
&vertices[0] as *const f32 as *const c_void,
gl::STATIC_DRAW,
);
let stride = 5 * mem::size_of::<GLfloat>() as GLsizei;
// position attribute
gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, stride, ptr::null());
gl::EnableVertexAttribArray(0);
// texture coord attribute
gl::VertexAttribPointer(
1,
2,
gl::FLOAT,
gl::FALSE,
stride,
(3 * mem::size_of::<GLfloat>()) as *const c_void,
);
gl::EnableVertexAttribArray(1);
// uncomment this call to draw in wireframe polygons.
// gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
// -------------------------
let mut texture = 0;
gl::GenTextures(1, &mut texture);
gl::BindTexture(gl::TEXTURE_2D, texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
// set the texture wrapping parameters
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::REPEAT as i32); // set texture wrapping to gl::REPEAT (default wrapping method)
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::REPEAT as i32);
// set texture filtering parameters
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32);
// load image, create texture and generate mipmaps
let img = image::open("resources/garlic_dog_space.jpg")
.unwrap()
.flipv();
let data = img.raw_pixels();
// let data = flipped
let dimensions = (img.width(), img.height());
gl::TexImage2D(
gl::TEXTURE_2D,
0,
gl::RGB as i32,
dimensions.0 as i32,
dimensions.1 as i32,
0,
gl::RGB,
gl::UNSIGNED_BYTE,
&data[0] as *const u8 as *const c_void,
);
gl::GenerateMipmap(gl::TEXTURE_2D);
(shader, vbo, vao, texture)
};
// render loop
// -----------
let color_r = 0.188;
let color_g = 0.22;
let color_b = 0.235;
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;
// events
// -----
process_events(
&events,
&mut first_mouse,
&mut last_x,
&mut last_y,
&mut camera,
);
// input
// -----
process_input(&mut window, delta_time, &mut camera);
// render
// ------
unsafe {
gl::ClearColor(color_r, color_g, color_b, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
gl::BindTexture(gl::TEXTURE_2D, texture);
shader_object.useProgram();
// pass projection matrix to shader (note that in this case it could change every frame)
let projection: Matrix4<f32> = perspective(
Deg(camera.Zoom),
consts::SCR_WIDTH as f32 / consts::SCR_HEIGHT as f32,
0.1,
100.0,
);
shader_object.setMat4(c_str!("projection"), &projection);
// camera/view transformation
let view = camera.get_view_matrix();
shader_object.setMat4(c_str!("view"), &view);
gl::BindVertexArray(vao);
for (i, position) in CUBES_POS.iter().enumerate() {
// calculate the model matrix for each object and pass it to shader before drawing
let mut model: Matrix4<f32> = Matrix4::from_translation(*position);
let angle = 20.0 * i as f32;
model =
model * Matrix4::from_axis_angle(vec3(1.0, 0.3, 0.5).normalize(), Deg(angle));
shader_object.setMat4(c_str!("model"), &model);
gl::DrawArrays(gl::TRIANGLES, 0, 36);
}
}
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
window.swap_buffers();
glfw.poll_events();
}
unsafe {
gl::DeleteVertexArrays(1, &vao);
gl::DeleteBuffers(1, &vbo);
}
}
pub fn process_events(
events: &Receiver<(f64, glfw::WindowEvent)>,
first_mouse: &mut bool,
last_x: &mut f32,
last_y: &mut f32,
camera: &mut Camera,
) {
for (_, event) in glfw::flush_messages(events) {
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) => {
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) => {
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);
}
}