From 421c7f5db3f8cbbd731bce11c8f3257bb29c463b Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Thu, 19 Oct 2023 02:04:42 +0200 Subject: [PATCH] WIP: obj loader mostly done --- src/aabb.rs | 38 ++-- src/importer/mod.rs | 31 +++ src/importer/obj.rs | 248 +++++++++++++++++++++++ src/importer/stl.rs | 27 +++ src/lib.rs | 1 + src/mesh.rs | 18 +- src/model.rs | 473 ++++++++++++++++++++++---------------------- src/ui/ui.rs | 3 +- src/utils.rs | 14 +- 9 files changed, 583 insertions(+), 270 deletions(-) create mode 100644 src/importer/mod.rs create mode 100644 src/importer/obj.rs create mode 100644 src/importer/stl.rs diff --git a/src/aabb.rs b/src/aabb.rs index a9ed663..fb91c48 100644 --- a/src/aabb.rs +++ b/src/aabb.rs @@ -6,30 +6,25 @@ use crate::{mesh::Vertex, shader::Shader}; pub struct AABB { pub min: glm::Vec3, pub max: glm::Vec3, + indices_len: u32, + vao: u32, } -#[derive(Debug)] -pub struct AABBMesh { - pub vertices: Vec, - pub indices: Vec, - pub vao: u32, -} - -impl AABBMesh { - pub fn new(aabb: &AABB) -> AABBMesh { +impl AABB { + pub fn new(min: glm::Vec3, max: glm::Vec3) -> AABB { let mut vao = 0; let mut vbo = 0; let mut ebo = 0; let vertices = vec![ - Vertex { position: glm::vec3(aabb.min.x, aabb.min.y, aabb.min.z), tex_coords: glm::vec2(0.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.max.x, aabb.min.y, aabb.min.z), tex_coords: glm::vec2(1.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.max.x, aabb.max.y, aabb.min.z), tex_coords: glm::vec2(1.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.min.x, aabb.max.y, aabb.min.z), tex_coords: glm::vec2(0.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.min.x, aabb.min.y, aabb.max.z), tex_coords: glm::vec2(0.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.max.x, aabb.min.y, aabb.max.z), tex_coords: glm::vec2(1.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.max.x, aabb.max.y, aabb.max.z), tex_coords: glm::vec2(1.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, - Vertex { position: glm::vec3(aabb.min.x, aabb.max.y, aabb.max.z), tex_coords: glm::vec2(0.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(min.x, min.y, min.z), tex_coords: glm::vec2(0.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(max.x, min.y, min.z), tex_coords: glm::vec2(1.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(max.x, max.y, min.z), tex_coords: glm::vec2(1.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(min.x, max.y, min.z), tex_coords: glm::vec2(0.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(min.x, min.y, max.z), tex_coords: glm::vec2(0.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(max.x, min.y, max.z), tex_coords: glm::vec2(1.0, 0.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(max.x, max.y, max.z), tex_coords: glm::vec2(1.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, + Vertex { position: glm::vec3(min.x, max.y, max.z), tex_coords: glm::vec2(0.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) }, ]; let indices = vec![ @@ -69,9 +64,10 @@ impl AABBMesh { gl::BindVertexArray(0); } - AABBMesh { - vertices, - indices, + AABB { + min, + max, + indices_len: indices.len() as u32, vao, } } @@ -85,7 +81,7 @@ impl AABBMesh { // draw Mesh gl::BindVertexArray(self.vao); gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE); - gl::DrawElements(gl::TRIANGLES, self.indices.len() as i32, gl::UNSIGNED_INT, std::ptr::null()); + gl::DrawElements(gl::TRIANGLES, self.indices_len as i32, gl::UNSIGNED_INT, std::ptr::null()); // reset stuff to default gl::BindVertexArray(0); diff --git a/src/importer/mod.rs b/src/importer/mod.rs new file mode 100644 index 0000000..9bd5f16 --- /dev/null +++ b/src/importer/mod.rs @@ -0,0 +1,31 @@ +mod obj; + +use std::path::PathBuf; + +use crate::{mesh::Vertex, aabb::AABB}; + +#[derive(Debug)] +pub struct ObjMesh { + pub name: String, + pub vertices: Vec, + pub indices: Vec, +} + +#[derive(Debug)] +pub struct Object { + pub name: String, + pub meshes: Vec, + pub aabb: AABB +} + +pub fn load_from_file(path: &PathBuf) -> Result> { + // FIXME: don't explode if to_str() fails + let path_str = path.to_str().unwrap(); + let file = std::fs::File::open(path_str)?; + // TODO: support both stl and obj based on file extension + // if no extension, then test for binary STL magic bytes + // if no magic bytes, then try to guess based on the first line of text in the file + + let obj = obj::load_obj(file)?; + Ok(obj) +} diff --git a/src/importer/obj.rs b/src/importer/obj.rs new file mode 100644 index 0000000..00b7e66 --- /dev/null +++ b/src/importer/obj.rs @@ -0,0 +1,248 @@ +use std::io::{BufReader, BufRead}; + +use crate::{mesh::Vertex, aabb::AABB, importer::ObjMesh, importer::Object}; + +const BUF_CAP: usize = 1024 * 128; // 128 Kilobytes + +enum Token { + Object, + Group, + Vertex, + Normal, + TexCoord, + Face, + Point, + Line, + SmoothShading, + MaterialLib, + MaterialUsage, +} + +impl Token { + fn from_str<'a>(s: &'a str) -> Option { + match s { + "o" => Some(Token::Object), + "g" => Some(Token::Group), + "v" => Some(Token::Vertex), + "vn" => Some(Token::Normal), + "vt" => Some(Token::TexCoord), + "f" => Some(Token::Face), + "p" => Some(Token::Point), + "l" => Some(Token::Line), + "s" => Some(Token::SmoothShading), + "mtllib" => Some(Token::MaterialLib), + "usemtl" => Some(Token::MaterialUsage), + _ => None, + } + } +} + +pub fn load_obj(file: std::fs::File) -> Result> { + let now = std::time::Instant::now(); + let reader = BufReader::with_capacity(BUF_CAP, file); + let mut object_name = String::new(); + let mut current_mesh_name = String::new(); + let mut temp_vertices = Vec::new(); + let mut vertices = Vec::new(); + let mut normals = Vec::new(); + let mut indices_counter: u32 = 0; + let mut indices = Vec::new(); + let mut tex_coords = Vec::new(); + let mut meshes = Vec::new(); + let mut min_aabb = glm::vec3(std::f32::MAX, std::f32::MAX, std::f32::MAX); + let mut max_aabb = glm::vec3(std::f32::MIN, std::f32::MIN, std::f32::MIN); + + for line in reader.lines() { + let line = line?; + // skip empty lines and comments + if line.is_empty() || line.chars().nth(0).is_some_and(|c| c == '#') { + continue; + } + + let mut iter = line.split_ascii_whitespace(); + let first = iter.next(); + if let Some(token) = first { + match Token::from_str(token) { + Some(Token::Object) => { + let name = { + if current_mesh_name.is_empty() { + object_name.clone() + } else { + current_mesh_name.clone() + } + }; + if !vertices.is_empty() { + meshes.push(ObjMesh{ + name, + vertices: vertices.clone(), + indices: indices.clone(), + }); + } + vertices.clear(); + indices.clear(); + indices_counter = 0; + + object_name = iter.next().unwrap_or("").to_string(); + } + Some(Token::Group) => { + let name = { + if current_mesh_name.is_empty() { + object_name.clone() + } else { + current_mesh_name.clone() + } + }; + if !vertices.is_empty() { + meshes.push(ObjMesh{ + name, + vertices: vertices.clone(), + indices: indices.clone(), + }); + } + vertices.clear(); + indices.clear(); + indices_counter = 0; + + current_mesh_name = iter.next().unwrap_or("default_mesh").to_string(); + } + Some(Token::Vertex) => { + let mut iter = iter + .take(3) + .map(|i| i.parse::().unwrap()); + let x = iter.next().unwrap(); + let y = iter.next().unwrap(); + let z = iter.next().unwrap(); + temp_vertices.push(glm::vec3(x, y, z)); + if x < min_aabb.x { + min_aabb.x = x; + } + + if y < min_aabb.y { + min_aabb.y = y; + } + + if z < min_aabb.z { + min_aabb.z = z; + } + + if x > max_aabb.x { + max_aabb.x = x; + } + + if y > max_aabb.y { + max_aabb.y = y; + } + + if z > max_aabb.z { + max_aabb.z = z; + } + + } + Some(Token::Normal) => { + let mut iter = iter + .take(3) + .map(|i| i.parse::().unwrap()); + let x = iter.next().unwrap(); + let y = iter.next().unwrap(); + let z = iter.next().unwrap(); + normals.push(glm::vec3(x, y, z)); + } + Some(Token::TexCoord) => { + let mut iter = iter + .take(2) + .map(|i| i.parse::().unwrap()); + let u = iter.next().unwrap(); + let v = iter.next().unwrap(); + tex_coords.push(glm::vec2(u, v)); + } + Some(Token::Face) => { + // TODO: vertex indices can be negative + + let face = iter.collect::>(); + let mut calculated_normal = glm::vec3(0.0, 0.0, 0.0); + + if normals.is_empty() { + calculated_normal = glm::normalize(glm::cross( + temp_vertices[face[1].parse::().unwrap() as usize - 1] - temp_vertices[face[0].parse::().unwrap() as usize - 1], + temp_vertices[face[2].parse::().unwrap() as usize - 1] - temp_vertices[face[0].parse::().unwrap() as usize - 1] + )); + } + + for (i, vert) in face.iter().enumerate() { + if vert.contains("//") { + let mut it = vert.split("//"); + let vert = it.next().unwrap().parse::().unwrap() - 1; + let normal = it.next().unwrap().parse::().unwrap() - 1; + vertices.push(Vertex{ + position: *temp_vertices.get(vert as usize).unwrap(), + normal: *normals.get(normal as usize).unwrap(), + tex_coords: glm::vec2(0.0, 0.0) + }); + } else if vert.contains("/") { + let mut it = vert.split("/"); + let vertex = it.next().unwrap().parse::().unwrap() - 1; + let t_coords = it.next().unwrap().parse::().unwrap() - 1; + let normal = it.next().unwrap().parse::().unwrap() - 1; + vertices.push(Vertex{ + position: *temp_vertices.get(vertex as usize).unwrap(), + normal: *normals.get(normal as usize).unwrap(), + tex_coords: *tex_coords.get(t_coords as usize).unwrap() + }); + } else { + let vert = vert.parse::().unwrap() - 1; + vertices.push(Vertex{ + position: *temp_vertices.get(vert as usize).unwrap(), + normal: calculated_normal, + tex_coords: glm::vec2(0.0, 0.0), + }); + } + + // 2 triangles per face + if i < face.len() - 2 { + indices.push(indices_counter); + indices.push(indices_counter + i as u32 + 1); + indices.push(indices_counter + i as u32 + 2); + } + } + + indices_counter += face.len() as u32; + } + Some(Token::MaterialLib) => { + // TODO: handle material file + } + Some(Token::MaterialUsage) => { + // TODO: handle material usage + // this can be used multiple times before f is mentioned + // to apply the material to those faces after it + } + _ => {}, + } + } + } + let elapsed = now.elapsed(); + println!("Loaded in {}ms", elapsed.as_millis()); + + let mesh_name = { + if current_mesh_name.is_empty() && !object_name.is_empty() { + object_name.clone() + } else if !current_mesh_name.is_empty() { + current_mesh_name.clone() + } else { + "default_mesh".to_string() + } + }; + + meshes.push(ObjMesh{ + name: mesh_name, + vertices: vertices.clone(), + indices: indices.clone(), + }); + + let aabb = AABB::new(min_aabb, max_aabb); + + Ok(Object{ + name: object_name, + meshes, + aabb + }) +} diff --git a/src/importer/stl.rs b/src/importer/stl.rs new file mode 100644 index 0000000..9362eb8 --- /dev/null +++ b/src/importer/stl.rs @@ -0,0 +1,27 @@ +struct STLHeader { + header: [u8; 80], + num_triangles: u32, +} + +struct Vertex { + x: f32, + y: f32, + z: f32, +} + +struct Triangle { + normal: [f32; 3], + vertices: [Vertex; 3], + attribute_byte_count: u16, +} + +struct STL { + header: STLHeader, + triangles: Vec, +} + +impl STL { + pub fn new(stl: Vec) -> () { + // TODO: + } +} diff --git a/src/lib.rs b/src/lib.rs index 6e8037c..589b838 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,3 +10,4 @@ pub mod model; pub mod ui; pub mod log; pub mod aabb; +pub mod importer; diff --git a/src/mesh.rs b/src/mesh.rs index 9334680..c9bf573 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -80,7 +80,7 @@ pub struct Mesh { pub vertices: Vec, pub indices: Vec, - pub textures: Vec, + // pub textures: Vec, pub material: Material, vao: u32, @@ -89,7 +89,7 @@ pub struct Mesh { } impl Mesh { - pub fn new(name: &str, vertices: Vec, indices: Vec, textures: Vec, material: Material, transformation: &mut glm::Mat4) -> Mesh { + pub fn new(name: &str, vertices: Vec, indices: Vec) -> Mesh { let mut vao = 0; let mut vbo = 0; let mut ebo = 0; @@ -122,21 +122,21 @@ impl Mesh { gl::BindVertexArray(0); } - let (position, rotation, scale) = decompose_mat(transformation); + // let (position, rotation, scale) = decompose_mat(transformation); Mesh { name: name.to_string(), vertices, indices, - textures, - material, + // textures, + material: Material::new("default".to_string(), glm::vec3(0.4, 0.4, 0.4), glm::vec3(0.7, 0.7, 0.7), glm::vec3(0.1, 0.1, 0.1), 32.0), vbo, vao, ebo, - position, - rotation, - scale, - pivot: position, + position: glm::vec3(0.0, 0.0, 0.0), + rotation: glm::vec3(0.0, 0.0, 0.0), + scale: glm::vec3(1.0, 1.0, 1.0), + pivot: glm::vec3(0.0, 0.0, 0.0), } } diff --git a/src/model.rs b/src/model.rs index d9627ae..cc6aa7c 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,4 +1,6 @@ -use crate::{mesh::{Mesh, Vertex, Texture, Material, apply_rotation}, shader::Shader, utils, ui::ui, log, aabb}; +use std::path::PathBuf; + +use crate::{mesh::{Mesh, Vertex, Texture, Material, apply_rotation}, shader::Shader, utils, ui::ui, log, aabb, importer}; use russimp; use anyhow::{Result, anyhow}; @@ -16,284 +18,291 @@ pub struct Model { pub name: String, pub meshes: Vec, pub aabb: aabb::AABB, - pub aabb_mesh: aabb::AABBMesh, pub scaling_factor: f32, } -fn process_node<'a>( - node: &russimp::node::Node, - scene: &'a russimp::scene::Scene, - meshes: &mut Vec, - dir: &std::path::PathBuf, - loaded_textures: &mut Vec, - init_trans: &glm::Mat4, - aabb: &mut aabb::AABB, - scale: &mut f32, -) -> Vec> { - let mut errors = vec![]; +// fn process_node<'a>( +// node: &russimp::node::Node, +// scene: &'a russimp::scene::Scene, +// meshes: &mut Vec, +// dir: &std::path::PathBuf, +// loaded_textures: &mut Vec, +// init_trans: &glm::Mat4, +// aabb: &mut aabb::AABB, +// scale: &mut f32, +// ) -> Vec> { +// let mut errors = vec![]; - let node_trans = glm::mat4( - node.transformation.a1, node.transformation.a2, node.transformation.a3, node.transformation.a4, - node.transformation.b1, node.transformation.b2, node.transformation.b3, node.transformation.b4, - node.transformation.c1, node.transformation.c2, node.transformation.c3, node.transformation.c4, - node.transformation.d1, node.transformation.d2, node.transformation.d3, node.transformation.d4, - ); - let mut new_trans = *init_trans * node_trans; +// let node_trans = glm::mat4( +// node.transformation.a1, node.transformation.a2, node.transformation.a3, node.transformation.a4, +// node.transformation.b1, node.transformation.b2, node.transformation.b3, node.transformation.b4, +// node.transformation.c1, node.transformation.c2, node.transformation.c3, node.transformation.c4, +// node.transformation.d1, node.transformation.d2, node.transformation.d3, node.transformation.d4, +// ); +// let mut new_trans = *init_trans * node_trans; - for i in 0..node.meshes.len() { - let mesh = &scene.meshes[node.meshes[i] as usize]; - let (processed_mesh, mut errs) = process_mesh(mesh, scene, dir, loaded_textures, &mut new_trans, aabb); - errors.append(&mut errs); - meshes.push(processed_mesh); - } +// for i in 0..node.meshes.len() { +// let mesh = &scene.meshes[node.meshes[i] as usize]; +// let (processed_mesh, mut errs) = process_mesh(mesh, scene, dir, loaded_textures, &mut new_trans, aabb); +// errors.append(&mut errs); +// meshes.push(processed_mesh); +// } - for child in node.children.borrow().clone().into_iter() { - let mut errs = process_node(&child, scene, meshes, dir, loaded_textures, &new_trans, aabb, scale); - errors.append(&mut errs); - } +// for child in node.children.borrow().clone().into_iter() { +// let mut errs = process_node(&child, scene, meshes, dir, loaded_textures, &new_trans, aabb, scale); +// errors.append(&mut errs); +// } - let scale_factor_x = SCALING_FACTOR / (aabb.max.x - aabb.min.x); - let scale_factor_y = SCALING_FACTOR / (aabb.max.y - aabb.min.y); - let scale_factor_z = SCALING_FACTOR / (aabb.max.z - aabb.min.z); +// let scale_factor_x = SCALING_FACTOR / (aabb.max.x - aabb.min.x); +// let scale_factor_y = SCALING_FACTOR / (aabb.max.y - aabb.min.y); +// let scale_factor_z = SCALING_FACTOR / (aabb.max.z - aabb.min.z); - // Use the minimum scaling factor to maintain proportions - *scale = scale_factor_x.min(scale_factor_y).min(scale_factor_z); +// // Use the minimum scaling factor to maintain proportions +// *scale = scale_factor_x.min(scale_factor_y).min(scale_factor_z); - return errors; -} +// return errors; +// } -fn process_mesh( - mesh: &russimp::mesh::Mesh, - scene: &russimp::scene::Scene, - dir: &std::path::PathBuf, - loaded_textures: &mut Vec, - transformation: &mut glm::Mat4, - aabb: &mut aabb::AABB -) -> (Mesh, Vec>) { - let mut vertices = vec![]; - let mut indices = vec![]; - let mut textures = vec![]; +// fn process_mesh( +// mesh: &russimp::mesh::Mesh, +// scene: &russimp::scene::Scene, +// dir: &std::path::PathBuf, +// loaded_textures: &mut Vec, +// transformation: &mut glm::Mat4, +// aabb: &mut aabb::AABB +// ) -> (Mesh, Vec>) { +// let mut vertices = vec![]; +// let mut indices = vec![]; +// let mut textures = vec![]; - for i in 0..mesh.vertices.len() { - let pos = glm::vec4(mesh.vertices[i].x, mesh.vertices[i].y, mesh.vertices[i].z, 1.0); +// for i in 0..mesh.vertices.len() { +// let pos = glm::vec4(mesh.vertices[i].x, mesh.vertices[i].y, mesh.vertices[i].z, 1.0); - let norm = match mesh.normals.len() { - 0 => glm::vec3(0.0, 0.0, 0.0), - _ => glm::vec3(mesh.normals[i].x, mesh.normals[i].y, mesh.normals[i].z), - }; +// let norm = match mesh.normals.len() { +// 0 => glm::vec3(0.0, 0.0, 0.0), +// _ => glm::vec3(mesh.normals[i].x, mesh.normals[i].y, mesh.normals[i].z), +// }; - let t = &mesh.texture_coords[0]; - let tex_coords = match t { - Some(tex) => { - glm::vec2(tex[i].x, tex[i].y) - }, - None => glm::vec2(0.0, 0.0) - }; +// let t = &mesh.texture_coords[0]; +// let tex_coords = match t { +// Some(tex) => { +// glm::vec2(tex[i].x, tex[i].y) +// }, +// None => glm::vec2(0.0, 0.0) +// }; - let vertex = Vertex::new(pos.truncate(3), norm, tex_coords); +// let vertex = Vertex::new(pos.truncate(3), norm, tex_coords); - if vertex.position.x < aabb.min.x { - aabb.min.x = vertex.position.x; - } +// if vertex.position.x < aabb.min.x { +// aabb.min.x = vertex.position.x; +// } - if vertex.position.y < aabb.min.y { - aabb.min.y = vertex.position.y; - } +// if vertex.position.y < aabb.min.y { +// aabb.min.y = vertex.position.y; +// } - if vertex.position.z < aabb.min.z { - aabb.min.z = vertex.position.z; - } +// if vertex.position.z < aabb.min.z { +// aabb.min.z = vertex.position.z; +// } - if vertex.position.x > aabb.max.x { - aabb.max.x = vertex.position.x; - } +// if vertex.position.x > aabb.max.x { +// aabb.max.x = vertex.position.x; +// } - if vertex.position.y > aabb.max.y { - aabb.max.y = vertex.position.y; - } +// if vertex.position.y > aabb.max.y { +// aabb.max.y = vertex.position.y; +// } - if vertex.position.z > aabb.max.z { - aabb.max.z = vertex.position.z; - } +// if vertex.position.z > aabb.max.z { +// aabb.max.z = vertex.position.z; +// } - vertices.push(vertex); - } +// vertices.push(vertex); +// } - for i in 0..mesh.faces.len() { - for j in 0..mesh.faces[i].0.len() { - indices.push(mesh.faces[i].0[j]); - } - } +// for i in 0..mesh.faces.len() { +// for j in 0..mesh.faces[i].0.len() { +// indices.push(mesh.faces[i].0[j]); +// } +// } - let mat = &scene.materials[mesh.material_index as usize]; +// let mat = &scene.materials[mesh.material_index as usize]; - let material = process_material(mat); +// let material = process_material(mat); - let (mut found_textures, errs) = load_material_textures(mat, dir, loaded_textures); - textures.append(&mut found_textures); +// let (mut found_textures, errs) = load_material_textures(mat, dir, loaded_textures); +// textures.append(&mut found_textures); - let mesh = Mesh::new(mesh.name.as_str(), vertices, indices, textures, material, transformation); - return (mesh, errs); -} +// let mesh = Mesh::new(mesh.name.as_str(), vertices, indices, textures, material, transformation); +// return (mesh, errs); +// } -fn process_material(mat: &russimp::material::Material) -> Material { - let mat_name = String::from("Default_Mat"); - let ambient = glm::vec3(0.2, 0.2, 0.2); - let diffuse = glm::vec3(0.7, 0.7, 0.7); - let specular = glm::vec3(0.1, 0.1, 0.1); - let shininess = 32.0; +// fn process_material(mat: &russimp::material::Material) -> Material { +// let mat_name = String::from("Default_Mat"); +// let ambient = glm::vec3(0.2, 0.2, 0.2); +// let diffuse = glm::vec3(0.7, 0.7, 0.7); +// let specular = glm::vec3(0.1, 0.1, 0.1); +// let shininess = 32.0; - // TODO: better way of mapping properties - // for property in mat.properties.iter() { - // match property.key.as_str() { - // "$clr.ambient" => { - // ambient = match &property.data { - // russimp::material::PropertyTypeInfo::FloatArray(a) => { - // glm::vec3(a[0], a[1], a[2]) - // }, - // _ => panic!("Property should not be this type: {}", property.key) - // }; - // }, - // "$clr.diffuse" => { - // diffuse = match &property.data { - // russimp::material::PropertyTypeInfo::FloatArray(a) => { - // glm::vec3(a[0], a[1], a[2]) - // }, - // _ => panic!("Property should not be this type: {}", property.key) - // }; - // }, - // "$clr.specular" => { - // specular = match &property.data { - // russimp::material::PropertyTypeInfo::FloatArray(a) => { - // glm::vec3(a[0], a[1], a[2]) - // }, - // _ => panic!("Property should not be this type: {}", property.key) - // } - // } - // "?mat.name" => { - // mat_name = match &property.data { - // russimp::material::PropertyTypeInfo::String(s) => { - // s.to_string() - // }, - // _ => panic!("Property should not be this type: {}", property.key) - // }; - // } - // "$mat.shininess" => { - // shininess = match &property.data { - // russimp::material::PropertyTypeInfo::FloatArray(a) => { - // a[0] - // }, - // _ => panic!("Property should not be this type: {}", property.key) - // }; - // } - // _ => {}, - // } - // } +// // TODO: better way of mapping properties +// // for property in mat.properties.iter() { +// // match property.key.as_str() { +// // "$clr.ambient" => { +// // ambient = match &property.data { +// // russimp::material::PropertyTypeInfo::FloatArray(a) => { +// // glm::vec3(a[0], a[1], a[2]) +// // }, +// // _ => panic!("Property should not be this type: {}", property.key) +// // }; +// // }, +// // "$clr.diffuse" => { +// // diffuse = match &property.data { +// // russimp::material::PropertyTypeInfo::FloatArray(a) => { +// // glm::vec3(a[0], a[1], a[2]) +// // }, +// // _ => panic!("Property should not be this type: {}", property.key) +// // }; +// // }, +// // "$clr.specular" => { +// // specular = match &property.data { +// // russimp::material::PropertyTypeInfo::FloatArray(a) => { +// // glm::vec3(a[0], a[1], a[2]) +// // }, +// // _ => panic!("Property should not be this type: {}", property.key) +// // } +// // } +// // "?mat.name" => { +// // mat_name = match &property.data { +// // russimp::material::PropertyTypeInfo::String(s) => { +// // s.to_string() +// // }, +// // _ => panic!("Property should not be this type: {}", property.key) +// // }; +// // } +// // "$mat.shininess" => { +// // shininess = match &property.data { +// // russimp::material::PropertyTypeInfo::FloatArray(a) => { +// // a[0] +// // }, +// // _ => panic!("Property should not be this type: {}", property.key) +// // }; +// // } +// // _ => {}, +// // } +// // } - Material::new(mat_name, ambient, diffuse, specular, shininess) -} +// Material::new(mat_name, ambient, diffuse, specular, shininess) +// } -// TODO: might nuke this cuz we don't need textures I think -fn load_material_textures( - mat: &russimp::material::Material, - dir: &std::path::PathBuf, - loaded_textures: &mut Vec -) -> (Vec, Vec>) { +// // TODO: might nuke this cuz we don't need textures I think +// fn load_material_textures( +// mat: &russimp::material::Material, +// dir: &std::path::PathBuf, +// loaded_textures: &mut Vec +// ) -> (Vec, Vec>) { - let mut textures = vec![]; - let mut errors = vec![]; +// let mut textures = vec![]; +// let mut errors = vec![]; - for (typ, tex) in mat.textures.iter() { - if SUPPORTED_TEXTURE_TYPES.contains(typ) { - let texture = tex.borrow(); - let mut skip = false; - let tex_filename = &texture.filename; - // HACK: fix this - if tex_filename.is_empty() { - continue; - } - // println!("texture filename: {}", tex_filename); - let path = dir.join(tex_filename); +// for (typ, tex) in mat.textures.iter() { +// if SUPPORTED_TEXTURE_TYPES.contains(typ) { +// let texture = tex.borrow(); +// let mut skip = false; +// let tex_filename = &texture.filename; +// // HACK: fix this +// if tex_filename.is_empty() { +// continue; +// } +// // println!("texture filename: {}", tex_filename); +// let path = dir.join(tex_filename); - for loaded_tex in &mut *loaded_textures { - if loaded_tex.path == path { - textures.push(loaded_tex.clone()); - skip = true; - break; - } - } +// for loaded_tex in &mut *loaded_textures { +// if loaded_tex.path == path { +// textures.push(loaded_tex.clone()); +// skip = true; +// break; +// } +// } - if !skip { - match Texture::new(path, *typ) { - Ok(texture) => { - loaded_textures.push(texture.clone()); - textures.push(texture); - }, - Err(e) => { - let err = anyhow!("Error loading texture: {}", e); - println!("{}", err); - errors.push(err.into()); - }, - } - } - } - } +// if !skip { +// match Texture::new(path, *typ) { +// Ok(texture) => { +// loaded_textures.push(texture.clone()); +// textures.push(texture); +// }, +// Err(e) => { +// let err = anyhow!("Error loading texture: {}", e); +// println!("{}", err); +// errors.push(err.into()); +// }, +// } +// } +// } +// } - return (textures, errors); -} +// return (textures, errors); +// } impl Model { - pub fn new(path: &str, state: &mut ui::State) -> Result> { - let scene = russimp::scene::Scene::from_file(path, - vec![ - russimp::scene::PostProcess::Triangulate, - russimp::scene::PostProcess::GenerateNormals, - russimp::scene::PostProcess::FlipUVs, - ]) - .map_err(|e| { - let e = match e { - russimp::RussimpError::TextureNotFound => anyhow!("Texture not found"), - _ => anyhow!("{}", e) - }; - return e; - })?; + pub fn new(obj: importer::Object, state: &mut ui::State) -> Model { + // let scene = russimp::scene::Scene::from_file(path, + // vec![ + // russimp::scene::PostProcess::Triangulate, + // russimp::scene::PostProcess::GenerateNormals, + // russimp::scene::PostProcess::FlipUVs, + // ]) + // .map_err(|e| { + // let e = match e { + // russimp::RussimpError::TextureNotFound => anyhow!("Texture not found"), + // _ => anyhow!("{}", e) + // }; + // return e; + // })?; - let root_node = match &scene.root { - Some(root) => root, - None => return Err("Scene has no root node".into()), - }; + // let root_node = match &scene.root { + // Some(root) => root, + // None => return Err("Scene has no root node".into()), + // }; - if scene.flags & russimp::sys::AI_SCENE_FLAGS_INCOMPLETE == 1 { - return Err("Scene is incomplete")?; - } + // if scene.flags & russimp::sys::AI_SCENE_FLAGS_INCOMPLETE == 1 { + // return Err("Scene is incomplete")?; + // } - let directory = match std::path::Path::new(path).parent() { - Some(dir) => dir, - None => return Err("Model path has no parent directory".into()), - }.to_path_buf(); + // let directory = match std::path::Path::new(path).parent() { + // Some(dir) => dir, + // None => return Err("Model path has no parent directory".into()), + // }.to_path_buf(); - let mut loaded_textures = vec![]; - let mut meshes = vec![]; - let init_trans_mat = utils::mat_ident(); - let mut aabb = aabb::AABB{ - min: glm::vec3(std::f32::MAX, std::f32::MAX, std::f32::MAX), - max: glm::vec3(std::f32::MIN, std::f32::MIN, std::f32::MIN), - }; + // let mut loaded_textures = vec![]; + // let mut meshes = vec![]; + // let init_trans_mat = utils::mat_ident(); let mut scale: f32 = 1.0; - let errors = process_node(&root_node, &scene, &mut meshes, &directory, &mut loaded_textures, &init_trans_mat, &mut aabb, &mut scale); + // let errors = process_node(&root_node, &scene, &mut meshes, &directory, &mut loaded_textures, &init_trans_mat, &mut aabb, &mut scale); - for err in errors { - state.logger.history.push(log::LogMessage::new(log::LogLevel::Warning, &err.to_string())); + // for err in errors { + // state.logger.history.push(log::LogMessage::new(log::LogLevel::Warning, &err.to_string())); + // } + let mut meshes = Vec::new(); + + for mesh in obj.meshes.into_iter() { + meshes.push(Mesh::new(&mesh.name, mesh.vertices, mesh.indices)); } - Ok(Model { + Model { id: state.get_next_id(), - name: root_node.name.to_owned(), - aabb_mesh: aabb::AABBMesh::new(&aabb), - aabb, + name: obj.name.to_owned(), + aabb: obj.aabb, scaling_factor: scale, meshes, - }) + } + // Ok(Model { + // id: state.get_next_id(), + // name: root_node.name.to_owned(), + // aabb_mesh: aabb::AABBMesh::new(&aabb), + // aabb, + // scaling_factor: scale, + // meshes, + // }) } pub fn draw(&self, shader: &Shader, draw_aabb: bool) { @@ -312,7 +321,7 @@ impl Model { } if draw_aabb { - self.aabb_mesh.draw(shader, &model_mat); + self.aabb.draw(shader, &model_mat); } } diff --git a/src/ui/ui.rs b/src/ui/ui.rs index e025e3b..257e926 100644 --- a/src/ui/ui.rs +++ b/src/ui/ui.rs @@ -154,8 +154,7 @@ fn draw_transformations(ui: &imgui::Ui, mesh: &mut mesh::Mesh) { fn draw_mesh_hierarchy(ui: &imgui::Ui, mesh: &mut mesh::Mesh, i: usize) { ui.tree_node_config(format!("{}###{}", mesh.name.as_str(), i)).build(|| { ui.text(format!("Vertices: {}", mesh.vertices.len())); - ui.text(format!("Faces: {}", mesh.vertices.len() / 3)); - ui.text(format!("Textures: {}", mesh.textures.len())); + ui.text(format!("Triangles: {}", mesh.indices.len() / 3)); ui.tree_node_config(mesh.material.name.as_str()).build(|| { ui.text(format!("{}", mesh.material)); }); diff --git a/src/utils.rs b/src/utils.rs index 807dc60..f2b5213 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,7 +4,7 @@ use glad_gl::gl; use glm; use anyhow::{Result, Context}; -use crate::{ui, log, model}; +use crate::{log, model, ui, importer}; const SUPPORTED_FILE_EXTENSIONS: [&str; 2] = ["obj", "stl"]; @@ -62,14 +62,16 @@ pub fn import_models_from_paths(paths: &Vec, state: &mut ui::ui::State) continue; } } - let model = model::Model::new(model_path.to_str().unwrap(), state); - match model { - Ok(mut m) => { + let obj_result = importer::load_from_file(model_path); + match obj_result { + Ok(obj) => { + let mut m = model::Model::new(obj, state); + state.active_model = Some(m.id); if let Some(model_name) = filename { state.logger.log(&format!("Loaded model \"{}\"", model_name.to_str().unwrap()), log::LogLevel::Info); m.name = model_name.to_str().unwrap().to_string(); - } + } state.objects.push(m); state.camera.update_position(state.active_model, &state.objects); }, @@ -78,7 +80,7 @@ pub fn import_models_from_paths(paths: &Vec, state: &mut ui::ui::State) println!("{}", error); state.logger.log(&error, log::LogLevel::Error); - }, + } } } }