mirror of
https://github.com/IllusionMan1212/3dobs.git
synced 2026-10-24 10:12:35 +00:00
WIP: obj loader mostly done
This commit is contained in:
+17
-21
@@ -6,30 +6,25 @@ use crate::{mesh::Vertex, shader::Shader};
|
|||||||
pub struct AABB {
|
pub struct AABB {
|
||||||
pub min: glm::Vec3,
|
pub min: glm::Vec3,
|
||||||
pub max: glm::Vec3,
|
pub max: glm::Vec3,
|
||||||
|
indices_len: u32,
|
||||||
|
vao: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl AABB {
|
||||||
pub struct AABBMesh {
|
pub fn new(min: glm::Vec3, max: glm::Vec3) -> AABB {
|
||||||
pub vertices: Vec<Vertex>,
|
|
||||||
pub indices: Vec<u32>,
|
|
||||||
pub vao: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AABBMesh {
|
|
||||||
pub fn new(aabb: &AABB) -> AABBMesh {
|
|
||||||
let mut vao = 0;
|
let mut vao = 0;
|
||||||
let mut vbo = 0;
|
let mut vbo = 0;
|
||||||
let mut ebo = 0;
|
let mut ebo = 0;
|
||||||
|
|
||||||
let vertices = vec![
|
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(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(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(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(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(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(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(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(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(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(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(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(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(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(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, max.y, max.z), tex_coords: glm::vec2(0.0, 1.0), normal: glm::vec3(0.0, 0.0, 0.0) },
|
||||||
];
|
];
|
||||||
|
|
||||||
let indices = vec![
|
let indices = vec![
|
||||||
@@ -69,9 +64,10 @@ impl AABBMesh {
|
|||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
AABBMesh {
|
AABB {
|
||||||
vertices,
|
min,
|
||||||
indices,
|
max,
|
||||||
|
indices_len: indices.len() as u32,
|
||||||
vao,
|
vao,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +81,7 @@ impl AABBMesh {
|
|||||||
// draw Mesh
|
// draw Mesh
|
||||||
gl::BindVertexArray(self.vao);
|
gl::BindVertexArray(self.vao);
|
||||||
gl::PolygonMode(gl::FRONT_AND_BACK, gl::LINE);
|
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
|
// reset stuff to default
|
||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
|
|||||||
@@ -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<Vertex>,
|
||||||
|
pub indices: Vec<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Object {
|
||||||
|
pub name: String,
|
||||||
|
pub meshes: Vec<ObjMesh>,
|
||||||
|
pub aabb: AABB
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_from_file(path: &PathBuf) -> Result<Object, Box<dyn std::error::Error>> {
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
@@ -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<Token> {
|
||||||
|
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<Object, Box<dyn std::error::Error>> {
|
||||||
|
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::<f32>().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::<f32>().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::<f32>().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::<Vec<_>>();
|
||||||
|
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::<i32>().unwrap() as usize - 1] - temp_vertices[face[0].parse::<i32>().unwrap() as usize - 1],
|
||||||
|
temp_vertices[face[2].parse::<i32>().unwrap() as usize - 1] - temp_vertices[face[0].parse::<i32>().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::<i32>().unwrap() - 1;
|
||||||
|
let normal = it.next().unwrap().parse::<i32>().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::<i32>().unwrap() - 1;
|
||||||
|
let t_coords = it.next().unwrap().parse::<i32>().unwrap() - 1;
|
||||||
|
let normal = it.next().unwrap().parse::<i32>().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::<i32>().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
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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<Triangle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl STL {
|
||||||
|
pub fn new(stl: Vec<u8>) -> () {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,3 +10,4 @@ pub mod model;
|
|||||||
pub mod ui;
|
pub mod ui;
|
||||||
pub mod log;
|
pub mod log;
|
||||||
pub mod aabb;
|
pub mod aabb;
|
||||||
|
pub mod importer;
|
||||||
|
|||||||
+9
-9
@@ -80,7 +80,7 @@ pub struct Mesh {
|
|||||||
|
|
||||||
pub vertices: Vec<Vertex>,
|
pub vertices: Vec<Vertex>,
|
||||||
pub indices: Vec<u32>,
|
pub indices: Vec<u32>,
|
||||||
pub textures: Vec<Texture>,
|
// pub textures: Vec<Texture>,
|
||||||
pub material: Material,
|
pub material: Material,
|
||||||
|
|
||||||
vao: u32,
|
vao: u32,
|
||||||
@@ -89,7 +89,7 @@ pub struct Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
pub fn new(name: &str, vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>, material: Material, transformation: &mut glm::Mat4) -> Mesh {
|
pub fn new(name: &str, vertices: Vec<Vertex>, indices: Vec<u32>) -> Mesh {
|
||||||
let mut vao = 0;
|
let mut vao = 0;
|
||||||
let mut vbo = 0;
|
let mut vbo = 0;
|
||||||
let mut ebo = 0;
|
let mut ebo = 0;
|
||||||
@@ -122,21 +122,21 @@ impl Mesh {
|
|||||||
gl::BindVertexArray(0);
|
gl::BindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (position, rotation, scale) = decompose_mat(transformation);
|
// let (position, rotation, scale) = decompose_mat(transformation);
|
||||||
|
|
||||||
Mesh {
|
Mesh {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
vertices,
|
vertices,
|
||||||
indices,
|
indices,
|
||||||
textures,
|
// textures,
|
||||||
material,
|
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,
|
vbo,
|
||||||
vao,
|
vao,
|
||||||
ebo,
|
ebo,
|
||||||
position,
|
position: glm::vec3(0.0, 0.0, 0.0),
|
||||||
rotation,
|
rotation: glm::vec3(0.0, 0.0, 0.0),
|
||||||
scale,
|
scale: glm::vec3(1.0, 1.0, 1.0),
|
||||||
pivot: position,
|
pivot: glm::vec3(0.0, 0.0, 0.0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+254
-245
@@ -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 russimp;
|
||||||
use anyhow::{Result, anyhow};
|
use anyhow::{Result, anyhow};
|
||||||
@@ -16,284 +18,291 @@ pub struct Model {
|
|||||||
pub name: String,
|
pub name: String,
|
||||||
pub meshes: Vec<Mesh>,
|
pub meshes: Vec<Mesh>,
|
||||||
pub aabb: aabb::AABB,
|
pub aabb: aabb::AABB,
|
||||||
pub aabb_mesh: aabb::AABBMesh,
|
|
||||||
pub scaling_factor: f32,
|
pub scaling_factor: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_node<'a>(
|
// fn process_node<'a>(
|
||||||
node: &russimp::node::Node,
|
// node: &russimp::node::Node,
|
||||||
scene: &'a russimp::scene::Scene,
|
// scene: &'a russimp::scene::Scene,
|
||||||
meshes: &mut Vec<Mesh>,
|
// meshes: &mut Vec<Mesh>,
|
||||||
dir: &std::path::PathBuf,
|
// dir: &std::path::PathBuf,
|
||||||
loaded_textures: &mut Vec<Texture>,
|
// loaded_textures: &mut Vec<Texture>,
|
||||||
init_trans: &glm::Mat4,
|
// init_trans: &glm::Mat4,
|
||||||
aabb: &mut aabb::AABB,
|
// aabb: &mut aabb::AABB,
|
||||||
scale: &mut f32,
|
// scale: &mut f32,
|
||||||
) -> Vec<Box<dyn std::error::Error>> {
|
// ) -> Vec<Box<dyn std::error::Error>> {
|
||||||
let mut errors = vec![];
|
// let mut errors = vec![];
|
||||||
|
|
||||||
let node_trans = glm::mat4(
|
// let node_trans = glm::mat4(
|
||||||
node.transformation.a1, node.transformation.a2, node.transformation.a3, node.transformation.a4,
|
// 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.b1, node.transformation.b2, node.transformation.b3, node.transformation.b4,
|
||||||
node.transformation.c1, node.transformation.c2, node.transformation.c3, node.transformation.c4,
|
// node.transformation.c1, node.transformation.c2, node.transformation.c3, node.transformation.c4,
|
||||||
node.transformation.d1, node.transformation.d2, node.transformation.d3, node.transformation.d4,
|
// node.transformation.d1, node.transformation.d2, node.transformation.d3, node.transformation.d4,
|
||||||
);
|
// );
|
||||||
let mut new_trans = *init_trans * node_trans;
|
// let mut new_trans = *init_trans * node_trans;
|
||||||
|
|
||||||
for i in 0..node.meshes.len() {
|
// for i in 0..node.meshes.len() {
|
||||||
let mesh = &scene.meshes[node.meshes[i] as usize];
|
// 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);
|
// let (processed_mesh, mut errs) = process_mesh(mesh, scene, dir, loaded_textures, &mut new_trans, aabb);
|
||||||
errors.append(&mut errs);
|
// errors.append(&mut errs);
|
||||||
meshes.push(processed_mesh);
|
// meshes.push(processed_mesh);
|
||||||
}
|
// }
|
||||||
|
|
||||||
for child in node.children.borrow().clone().into_iter() {
|
// for child in node.children.borrow().clone().into_iter() {
|
||||||
let mut errs = process_node(&child, scene, meshes, dir, loaded_textures, &new_trans, aabb, scale);
|
// let mut errs = process_node(&child, scene, meshes, dir, loaded_textures, &new_trans, aabb, scale);
|
||||||
errors.append(&mut errs);
|
// errors.append(&mut errs);
|
||||||
}
|
// }
|
||||||
|
|
||||||
let scale_factor_x = SCALING_FACTOR / (aabb.max.x - aabb.min.x);
|
// 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_y = SCALING_FACTOR / (aabb.max.y - aabb.min.y);
|
||||||
let scale_factor_z = SCALING_FACTOR / (aabb.max.z - aabb.min.z);
|
// let scale_factor_z = SCALING_FACTOR / (aabb.max.z - aabb.min.z);
|
||||||
|
|
||||||
// Use the minimum scaling factor to maintain proportions
|
// // Use the minimum scaling factor to maintain proportions
|
||||||
*scale = scale_factor_x.min(scale_factor_y).min(scale_factor_z);
|
// *scale = scale_factor_x.min(scale_factor_y).min(scale_factor_z);
|
||||||
|
|
||||||
return errors;
|
// return errors;
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn process_mesh(
|
// fn process_mesh(
|
||||||
mesh: &russimp::mesh::Mesh,
|
// mesh: &russimp::mesh::Mesh,
|
||||||
scene: &russimp::scene::Scene,
|
// scene: &russimp::scene::Scene,
|
||||||
dir: &std::path::PathBuf,
|
// dir: &std::path::PathBuf,
|
||||||
loaded_textures: &mut Vec<Texture>,
|
// loaded_textures: &mut Vec<Texture>,
|
||||||
transformation: &mut glm::Mat4,
|
// transformation: &mut glm::Mat4,
|
||||||
aabb: &mut aabb::AABB
|
// aabb: &mut aabb::AABB
|
||||||
) -> (Mesh, Vec<Box<dyn std::error::Error>>) {
|
// ) -> (Mesh, Vec<Box<dyn std::error::Error>>) {
|
||||||
let mut vertices = vec![];
|
// let mut vertices = vec![];
|
||||||
let mut indices = vec![];
|
// let mut indices = vec![];
|
||||||
let mut textures = vec![];
|
// let mut textures = vec![];
|
||||||
|
|
||||||
for i in 0..mesh.vertices.len() {
|
// 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 pos = glm::vec4(mesh.vertices[i].x, mesh.vertices[i].y, mesh.vertices[i].z, 1.0);
|
||||||
|
|
||||||
let norm = match mesh.normals.len() {
|
// let norm = match mesh.normals.len() {
|
||||||
0 => glm::vec3(0.0, 0.0, 0.0),
|
// 0 => glm::vec3(0.0, 0.0, 0.0),
|
||||||
_ => glm::vec3(mesh.normals[i].x, mesh.normals[i].y, mesh.normals[i].z),
|
// _ => 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 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.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.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.z > aabb.max.z {
|
|
||||||
aabb.max.z = vertex.position.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mat = &scene.materials[mesh.material_index as usize];
|
|
||||||
|
|
||||||
let material = process_material(mat);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
// let t = &mesh.texture_coords[0];
|
||||||
|
// let tex_coords = match t {
|
||||||
|
// Some(tex) => {
|
||||||
|
// glm::vec2(tex[i].x, tex[i].y)
|
||||||
// },
|
// },
|
||||||
// "$clr.diffuse" => {
|
// None => glm::vec2(0.0, 0.0)
|
||||||
// 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)
|
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
// 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.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.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.z > aabb.max.z {
|
||||||
|
// aabb.max.z = vertex.position.z;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let mat = &scene.materials[mesh.material_index as usize];
|
||||||
|
|
||||||
|
// let material = process_material(mat);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// // };
|
||||||
|
// // }
|
||||||
|
// // _ => {},
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
|
||||||
|
// 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<Texture>
|
||||||
|
// ) -> (Vec<Texture>, Vec<Box<dyn std::error::Error>>) {
|
||||||
|
|
||||||
|
// 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 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);
|
||||||
// },
|
// },
|
||||||
// "$clr.specular" => {
|
// Err(e) => {
|
||||||
// specular = match &property.data {
|
// let err = anyhow!("Error loading texture: {}", e);
|
||||||
// russimp::material::PropertyTypeInfo::FloatArray(a) => {
|
// println!("{}", err);
|
||||||
// glm::vec3(a[0], a[1], a[2])
|
// errors.push(err.into());
|
||||||
// },
|
// },
|
||||||
// _ => 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)
|
// return (textures, errors);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 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<Texture>
|
|
||||||
) -> (Vec<Texture>, Vec<Box<dyn std::error::Error>>) {
|
|
||||||
|
|
||||||
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 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());
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (textures, errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Model {
|
impl Model {
|
||||||
pub fn new(path: &str, state: &mut ui::State) -> Result<Self, Box<dyn std::error::Error>> {
|
pub fn new(obj: importer::Object, state: &mut ui::State) -> Model {
|
||||||
let scene = russimp::scene::Scene::from_file(path,
|
// let scene = russimp::scene::Scene::from_file(path,
|
||||||
vec![
|
// vec![
|
||||||
russimp::scene::PostProcess::Triangulate,
|
// russimp::scene::PostProcess::Triangulate,
|
||||||
russimp::scene::PostProcess::GenerateNormals,
|
// russimp::scene::PostProcess::GenerateNormals,
|
||||||
russimp::scene::PostProcess::FlipUVs,
|
// russimp::scene::PostProcess::FlipUVs,
|
||||||
])
|
// ])
|
||||||
.map_err(|e| {
|
// .map_err(|e| {
|
||||||
let e = match e {
|
// let e = match e {
|
||||||
russimp::RussimpError::TextureNotFound => anyhow!("Texture not found"),
|
// russimp::RussimpError::TextureNotFound => anyhow!("Texture not found"),
|
||||||
_ => anyhow!("{}", e)
|
// _ => anyhow!("{}", e)
|
||||||
};
|
// };
|
||||||
return e;
|
// return e;
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
let root_node = match &scene.root {
|
// let root_node = match &scene.root {
|
||||||
Some(root) => root,
|
// Some(root) => root,
|
||||||
None => return Err("Scene has no root node".into()),
|
// None => return Err("Scene has no root node".into()),
|
||||||
};
|
// };
|
||||||
|
|
||||||
if scene.flags & russimp::sys::AI_SCENE_FLAGS_INCOMPLETE == 1 {
|
// if scene.flags & russimp::sys::AI_SCENE_FLAGS_INCOMPLETE == 1 {
|
||||||
return Err("Scene is incomplete")?;
|
// return Err("Scene is incomplete")?;
|
||||||
}
|
// }
|
||||||
|
|
||||||
let directory = match std::path::Path::new(path).parent() {
|
// let directory = match std::path::Path::new(path).parent() {
|
||||||
Some(dir) => dir,
|
// Some(dir) => dir,
|
||||||
None => return Err("Model path has no parent directory".into()),
|
// None => return Err("Model path has no parent directory".into()),
|
||||||
}.to_path_buf();
|
// }.to_path_buf();
|
||||||
|
|
||||||
let mut loaded_textures = vec![];
|
// let mut loaded_textures = vec![];
|
||||||
let mut meshes = vec![];
|
// let mut meshes = vec![];
|
||||||
let init_trans_mat = utils::mat_ident();
|
// 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 scale: f32 = 1.0;
|
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 {
|
// for err in errors {
|
||||||
state.logger.history.push(log::LogMessage::new(log::LogLevel::Warning, &err.to_string()));
|
// 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(),
|
id: state.get_next_id(),
|
||||||
name: root_node.name.to_owned(),
|
name: obj.name.to_owned(),
|
||||||
aabb_mesh: aabb::AABBMesh::new(&aabb),
|
aabb: obj.aabb,
|
||||||
aabb,
|
|
||||||
scaling_factor: scale,
|
scaling_factor: scale,
|
||||||
meshes,
|
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) {
|
pub fn draw(&self, shader: &Shader, draw_aabb: bool) {
|
||||||
@@ -312,7 +321,7 @@ impl Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if draw_aabb {
|
if draw_aabb {
|
||||||
self.aabb_mesh.draw(shader, &model_mat);
|
self.aabb.draw(shader, &model_mat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -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) {
|
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.tree_node_config(format!("{}###{}", mesh.name.as_str(), i)).build(|| {
|
||||||
ui.text(format!("Vertices: {}", mesh.vertices.len()));
|
ui.text(format!("Vertices: {}", mesh.vertices.len()));
|
||||||
ui.text(format!("Faces: {}", mesh.vertices.len() / 3));
|
ui.text(format!("Triangles: {}", mesh.indices.len() / 3));
|
||||||
ui.text(format!("Textures: {}", mesh.textures.len()));
|
|
||||||
ui.tree_node_config(mesh.material.name.as_str()).build(|| {
|
ui.tree_node_config(mesh.material.name.as_str()).build(|| {
|
||||||
ui.text(format!("{}", mesh.material));
|
ui.text(format!("{}", mesh.material));
|
||||||
});
|
});
|
||||||
|
|||||||
+7
-5
@@ -4,7 +4,7 @@ use glad_gl::gl;
|
|||||||
use glm;
|
use glm;
|
||||||
use anyhow::{Result, Context};
|
use anyhow::{Result, Context};
|
||||||
|
|
||||||
use crate::{ui, log, model};
|
use crate::{log, model, ui, importer};
|
||||||
|
|
||||||
const SUPPORTED_FILE_EXTENSIONS: [&str; 2] = ["obj", "stl"];
|
const SUPPORTED_FILE_EXTENSIONS: [&str; 2] = ["obj", "stl"];
|
||||||
|
|
||||||
@@ -62,9 +62,11 @@ pub fn import_models_from_paths(paths: &Vec<PathBuf>, state: &mut ui::ui::State)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let model = model::Model::new(model_path.to_str().unwrap(), state);
|
let obj_result = importer::load_from_file(model_path);
|
||||||
match model {
|
match obj_result {
|
||||||
Ok(mut m) => {
|
Ok(obj) => {
|
||||||
|
let mut m = model::Model::new(obj, state);
|
||||||
|
|
||||||
state.active_model = Some(m.id);
|
state.active_model = Some(m.id);
|
||||||
if let Some(model_name) = filename {
|
if let Some(model_name) = filename {
|
||||||
state.logger.log(&format!("Loaded model \"{}\"", model_name.to_str().unwrap()), log::LogLevel::Info);
|
state.logger.log(&format!("Loaded model \"{}\"", model_name.to_str().unwrap()), log::LogLevel::Info);
|
||||||
@@ -78,7 +80,7 @@ pub fn import_models_from_paths(paths: &Vec<PathBuf>, state: &mut ui::ui::State)
|
|||||||
println!("{}", error);
|
println!("{}", error);
|
||||||
|
|
||||||
state.logger.log(&error, log::LogLevel::Error);
|
state.logger.log(&error, log::LogLevel::Error);
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user