//! Basic helper functions use std::fs; use std::io::ErrorKind; use std::rc::Rc; use std::sync::Arc; use std::ffi::CStr; use std::os::raw::c_char; use assetpath::AssetPath; use cgmath; use cgmath::One; pub fn erase_by_ptr(vector: &mut Vec, object: &T) -> bool { match vector .iter() .position(|t| t as *const T == object as *const T) { Some(i) => { vector.remove(i); true } None => false, } } pub fn erase_arc(vector: &mut Vec>, object: &Arc) -> Option> { match vector.iter().position(|t| Arc::ptr_eq(t, object)) { Some(i) => Some(vector.remove(i)), None => None, } } pub fn erase_rc(vector: &mut Vec>, object: &Rc) -> Option> { match vector.iter().position(|t| Rc::ptr_eq(t, object)) { Some(i) => Some(vector.remove(i)), None => None, } } pub fn ortho( left: f32, right: f32, bottom: f32, top: f32, z_near: f32, z_far: f32, ) -> cgmath::Matrix4 { let mut mat = cgmath::Matrix4::one(); mat[0][0] = 2.0 / (right - left); mat[1][1] = -2.0 / (top - bottom); mat[2][2] = -2.0 / (z_far - z_near); mat[3][0] = -(right + left) / (right - left); mat[3][1] = -(top + bottom) / (top - bottom); mat[3][2] = -(z_far + z_near) / (z_far - z_near); mat } pub fn search_dir_recursively( base_dir: &str, suffix: &str, ) -> Result, std::io::Error> { let mut files = Vec::new(); // simply return an empty result when the path could not be found // or the user has a lack of permissions let dir_content = match fs::read_dir(base_dir) { Ok(dir) => dir, Err(err) => match err.kind() { ErrorKind::NotFound | ErrorKind::PermissionDenied => return Ok(files), _ => return Err(err), }, }; for fs_object in dir_content { let obj = fs_object?; let path = obj.path(); if path.is_file() { if let Some(os_str) = path.file_name() { if let Some(string) = os_str.to_str() { if string.ends_with(suffix) { files.push(AssetPath::from((base_dir, string))); } } } } else { if let Some(string) = path.to_str() { let more_files = search_dir_recursively(string, suffix)?; files.extend(more_files); } } } Ok(files) } pub unsafe fn c_char_to_string(cchar: *const c_char) -> String { CStr::from_ptr(cchar).to_str().unwrap().to_string() } #[inline] pub fn perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> cgmath::Matrix4 { debug_assert!(z_near != 0.0); let zero = 0.0; let one = 1.0; let two = 2.0; let q = one / (fov_y / two).tan(); let a = q / aspect; let b = (z_near + z_far) / (z_near - z_far); let c = (two * z_near * z_far) / (z_near - z_far); #[cfg_attr(rustfmt, rustfmt_skip)] cgmath::Matrix4::new( a, zero, zero, zero, zero, -q, zero, zero, zero, zero, b, zero - one, zero, zero, c, zero, ) } #[inline] pub fn rotate_z(v: cgmath::Vector3, angle: f32) -> cgmath::Vector3 { let mut result = v; let cos = angle.cos(); let sin = angle.sin(); result.x = v.x * cos - v.y * sin; result.y = v.x * sin + v.y * cos; result } #[inline] pub fn almost_eq(f1: f32, f2: f32) -> bool { (f1 - f2).abs() <= std::f32::EPSILON }