cyborg/editor/src/import.rs

143 lines
4.3 KiB
Rust

use crate::model;
pub fn load_stl(path: std::path::PathBuf) -> model::Model {
let name = path.file_name().map(|v| v.to_string_lossy().to_string());
let mut file = std::fs::File::open(path).unwrap();
let stl = stl::read_stl(&mut file).unwrap();
let mut vertices = Vec::new();
let mut indices = Vec::new();
for tri in stl.triangles.iter() {
indices.push(vertices.len() as u32);
vertices.push(model::BasicVertex {
position: tri.v1.into(),
});
indices.push(vertices.len() as u32);
vertices.push(model::BasicVertex {
position: tri.v2.into(),
});
indices.push(vertices.len() as u32);
vertices.push(model::BasicVertex {
position: tri.v3.into(),
});
}
model::Model {
name: name.clone(),
objects: vec![model::Object {
name,
transform: Default::default(),
meshes: vec![model::Mesh { vertices, indices }],
children: vec![],
}],
}
}
pub fn load_gltf(path: std::path::PathBuf) -> model::Model {
use gltf::*;
let name = path.file_name().map(|v| v.to_string_lossy().to_string());
let mut file = std::fs::File::open(path).unwrap();
let model = Gltf::from_reader(&mut file).unwrap();
GltfLoader::load(name, &model)
}
pub struct GltfLoader<'a> {
pub model: &'a gltf::Gltf,
pub buffers: Vec<Vec<u8>>,
}
impl<'a> GltfLoader<'a> {
pub fn load(name: Option<String>, model: &'a gltf::Gltf) -> model::Model {
let buffers = Self::load_buffers(model);
let mut loader = Self { model, buffers };
let mut model = model::Model {
name,
objects: vec![],
};
for scene in loader.model.scenes() {
for node in scene.nodes() {
model.objects.push(loader.load_node(node));
}
}
model
}
pub fn load_buffers(model: &gltf::Gltf) -> Vec<Vec<u8>> {
let mut buffer_data = Vec::<Vec<u8>>::new();
for buffer in model.buffers() {
match buffer.source() {
gltf::buffer::Source::Bin => {
buffer_data.push(model.blob.as_deref().unwrap().into());
}
_ => panic!("URI buffer sources are unsupported"),
}
}
buffer_data
}
pub fn load_node(&mut self, node: gltf::Node) -> model::Object {
let transform = model::Transform::default();
let mut object = model::Object {
name: node.name().map(str::to_string),
transform,
meshes: vec![],
children: vec![],
};
if let Some(mesh) = node.mesh() {
for primitive in mesh.primitives() {
object.meshes.push(self.load_primitive_mesh(primitive));
}
}
for child in node.children() {
object.children.push(self.load_node(child));
}
object
}
pub fn load_primitive_mesh(&mut self, primitive: gltf::Primitive) -> model::Mesh {
use gltf::mesh::util::{ReadIndices, ReadTexCoords};
if primitive.mode() != gltf::mesh::Mode::Triangles {
panic!("glTF primitive must be triangle list");
}
let reader = primitive.reader(|buffer| Some(&self.buffers[buffer.index()]));
let positions = reader.read_positions().unwrap();
let mut normals = reader.read_normals().unwrap();
let tex_coords = reader.read_tex_coords(0).unwrap();
let mut tex_coords = if let ReadTexCoords::F32(tex_coords) = tex_coords {
tex_coords
} else {
panic!("only f32 texture coordinates are supported")
};
let mut vertices = Vec::new();
for position in positions {
let normal = normals.next().unwrap();
let tex_coords = tex_coords.next().unwrap();
vertices.push(model::BasicVertex {
position: position.into(),
});
}
let indices = match reader.read_indices().unwrap() {
ReadIndices::U32(indices) => indices.collect(),
ReadIndices::U16(indices) => indices.map(|i| i as u32).collect(),
ReadIndices::U8(indices) => indices.map(|i| i as u32).collect(),
};
model::Mesh { vertices, indices }
}
}