extern crate glfw; extern crate nalgebra_glm as glm; extern crate rand; use std::time::Instant; use heavyli_engine::{ math::{ projection_type::ProjectionType, transform::{self, Transform}, view, }, render::{ shader, shader::ShaderValue, shape::{ buffers::{self, Buffers}, shape_vertices::ShapeVerticesL, vertices::DrawType, vertices::{self, VertexL}, }, texture_2d::{self, TextureFilter}, utils::{self, init_glfw}, window::{ClearColor, Window}, }, }; const SCR_WIDTH: u32 = 800; const SCR_HEIGHT: u32 = 600; fn main() { let mut glfw = init_glfw(); let mut window = Window::new(&mut glfw, "3D", SCR_WIDTH, SCR_HEIGHT); window.make_current(); window.set_key_polling(true); window.set_framebuffer_size_polling(true); window.load_function_pointers(); unsafe { utils::enable_3d(); } let mut delta_time = 0.0; let mut delta_count = 0.0; let mut camera = Camera { position: glm::vec3(0.0, 0.0, -5.0), rotation: glm::vec2(0.0, 90.0), }; let mut cube1 = Cube::new( Some(Image { path: "res/wall.jpg", is_alpha: false, }), glm::vec3(0.0, 0.0, 0.0), ); let mut light1 = Cube::new(None, glm::vec3(3.0, 1.0, 0.0)); const AMBIENT_STRENGTH: f32 = 0.5; let light_color = glm::vec3(0.3, 0.5, 1.0); let mut time_count = 0.0; while window.is_open() { let start_time = Instant::now(); window.process_events(); unsafe { Window::clear(ClearColor { red: 0.1, green: 0.1, blue: 0.1, alpha: 1.0, }); } player_input(delta_time, &window, &mut camera); light1.transform.position = camera.position; //13.0 - 10.0 * f32::cos(time_count); cube1.render( &camera, light_color, light1.transform.position, AMBIENT_STRENGTH, ); //light1.render(&camera, light_color, light1.transform.position, 1.0); window.swap_buffers(); glfw.poll_events(); utils::limit_fps(start_time, 60.0); delta_time = start_time.elapsed().as_nanos() as f32 / 1000000000.0; delta_count += delta_time; time_count += delta_time; if time_count > f32::MAX { time_count = 0.0; } if delta_count >= 1.0 { let mut title = "3D | FPS: ".to_string(); title.push_str( (1.0 / if 0.0 != delta_time { delta_time } else { f32::MIN_POSITIVE }) .to_string() .as_str(), ); window.set_title(&title); delta_count = 0.0; } } cube1.delete(); light1.delete(); } unsafe fn init_texture(texture_id: u32, texture_image_directory: &str, is_alpha: bool) { texture_2d::bind(texture_id); texture_2d::load_image(texture_image_directory.to_string(), is_alpha); texture_2d::unbind(); } unsafe fn init_buffers(buffers: &Buffers, vertices: &mut Vec) { buffers::bind_buffers(buffers); buffers::bind_data(buffers.vao, vertices); let draw_type = DrawType::Triangles; buffers::vertex_attributes::(0, vertices::get_unit_size(draw_type), 3); // Position attribute. buffers::vertex_attributes::(1, vertices::get_unit_size(draw_type), 3); // Color attribute. buffers::vertex_attributes::(2, vertices::get_unit_size(draw_type), 3); // Normal. buffers::vertex_attributes::(3, vertices::get_unit_size(draw_type), 2); // Texture Coordinates attribute. buffers::unbind(); } struct Image { path: &'static str, is_alpha: bool, } struct Cube { buffers: Buffers, shader_id: u32, texture_id: Option, vertices: Vec, transform: Transform, } struct Camera { position: glm::Vec3, rotation: glm::Vec2, } const Z_NEAR: f32 = 0.1; const Z_FAR: f32 = 100.0; const FOV: f32 = 45.0; impl Cube { fn new(image: Option, position: glm::Vec3) -> Self { let buffers = unsafe { buffers::generate_buffers() }; let shader_id = shader::compile( "shaders/lighting_vertex.glsl", if image.is_none() { "shaders/lighting_no_texture_fragment.glsl" } else { "shaders/lighting_fragment.glsl" }, ); let mut texture_id = 0; let mut cube_verts = ShapeVerticesL::Cube.value(); unsafe { init_buffers(&buffers, &mut cube_verts); } unsafe { if let Some(img) = &image { texture_id = texture_2d::generate_texture_id(TextureFilter::Blur); init_texture(texture_id, img.path, img.is_alpha); } } return Cube { buffers: buffers, shader_id: shader_id, texture_id: if image.is_none() { None } else { Some(texture_id) }, vertices: cube_verts, transform: transform::create_transform_by_position(position), }; } fn render( &self, camera: &Camera, light_color: glm::Vec3, light_pos: glm::Vec3, ambient_strength: f32, ) { unsafe { if let Some(tid) = self.texture_id { texture_2d::bind(tid); } shader::use_program(self.shader_id); shader::set_value( self.shader_id, "translation", ShaderValue::Mat4(transform::translate( &self.transform, Z_NEAR, Z_FAR, FOV, view::get_view_matrix(&camera.position, camera.rotation.x, camera.rotation.y), glm::vec2(SCR_WIDTH as f32, SCR_HEIGHT as f32), 0.0, ProjectionType::Perspective, )), ); shader::set_value( self.shader_id, "ambientStrength", ShaderValue::Float(ambient_strength), ); shader::set_value( self.shader_id, "model", ShaderValue::Mat4(transform::get_model_matrix(&self.transform)), ); shader::set_value(self.shader_id, "lightColor", ShaderValue::Vec3(light_color)); shader::set_value(self.shader_id, "lightPos", ShaderValue::Vec3(light_pos)); // Render: buffers::bind_vao(self.buffers.vao); utils::draw_arrays(DrawType::Triangles, self.vertices.len() as i32); } } fn delete(&mut self) { unsafe { buffers::delete_buffers(&mut self.buffers); if let Some(tid) = &mut self.texture_id { texture_2d::delete_texture(tid); } } } } fn player_input(delta_time: f32, window: &Window, camera: &mut Camera) { const MOVE_SPEED: f32 = 5.0; const ROTATE_SPEED: f32 = 100.0; let normalized_front = view::get_normalized_front(camera.rotation.x, camera.rotation.y); if window.key_pressed(glfw::Key::Right) { camera.rotation.y += ROTATE_SPEED * delta_time; } else if window.key_pressed(glfw::Key::Left) { camera.rotation.y -= ROTATE_SPEED * delta_time; } if window.key_pressed(glfw::Key::Up) { camera.rotation.x += ROTATE_SPEED * delta_time; } else if window.key_pressed(glfw::Key::Down) { camera.rotation.x -= ROTATE_SPEED * delta_time; } if window.key_pressed(glfw::Key::W) { camera.position += normalized_front * MOVE_SPEED * delta_time; } else if window.key_pressed(glfw::Key::S) { camera.position -= normalized_front * MOVE_SPEED * delta_time; } if window.key_pressed(glfw::Key::D) { camera.position += view::get_right(normalized_front) * MOVE_SPEED * delta_time; } else if window.key_pressed(glfw::Key::A) { camera.position -= view::get_right(normalized_front) * MOVE_SPEED * delta_time; } if window.key_pressed(glfw::Key::Space) { camera.position += view::get_up(normalized_front) * MOVE_SPEED * delta_time; } else if window.key_pressed(glfw::Key::LeftShift) { camera.position -= view::get_up(normalized_front) * MOVE_SPEED * delta_time; } }