use std::collections::HashSet; use std::fs::read_to_string; use std::path::{Path, PathBuf}; use crate::asset::{Assets, Submitter as AssetSubmitter}; use crate::material::asset::Map as MaterialAssetMap; use crate::model::{Materials, Spec}; #[derive(Debug, Clone)] #[non_exhaustive] pub struct Settings {} pub fn add_importers(assets: &mut Assets) { assets.set_importer(["obj"], import_wavefront_obj_asset); } fn import_wavefront_obj_asset( asset_submitter: &mut AssetSubmitter<'_>, path: &Path, _settings: Option<&'_ Settings>, ) -> Result<(), Error> { let obj = crate::file_format::wavefront::obj::parse( &read_to_string(path) .map_err(|err| Error::ReadFailed(err, path.to_path_buf()))?, )?; let mesh = obj.to_mesh()?; let mesh_asset = asset_submitter.submit_store_named("mesh", mesh); let mut material_asset_map_assets = Vec::with_capacity(obj.mtl_libs.iter().flatten().count()); for mtl_lib_path in obj.mtl_libs.iter().flatten() { let mtl_lib_asset = asset_submitter.submit_load_other::(mtl_lib_path.as_path()); material_asset_map_assets.push(mtl_lib_asset); } let material_names = obj .faces .into_iter() .map(|face| face.material_name) .flatten() .fold( (HashSet::::new(), Vec::::new()), |(mut pushed_mat_names, mut unique_mat_names), material_name| { if pushed_mat_names.contains(&material_name) { return (pushed_mat_names, unique_mat_names); } unique_mat_names.push(material_name.clone()); pushed_mat_names.insert(material_name); (pushed_mat_names, unique_mat_names) }, ) .1; asset_submitter.submit_store( Spec::builder() .mesh(mesh_asset) .materials(Materials::Maps(material_asset_map_assets)) .material_names(material_names) .build(), ); Ok(()) } #[derive(Debug, thiserror::Error)] enum Error { #[error("Failed to read file {}", .1.display())] ReadFailed(#[source] std::io::Error, PathBuf), #[error(transparent)] Other(#[from] crate::file_format::wavefront::obj::Error), }