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 { /// Whether all UVs should be flipped on the Y axis. This is necessary if the UVs /// have their origin at the bottom left corner of the image /// /// The default is `true`. pub y_flip_uvs: bool, } impl Settings { /// Whether all UVs should be flipped on the Y axis. This is necessary if the UVs have /// their origin at the bottom left corner of the image /// /// The default is `true`. pub fn y_flip_uvs(mut self, y_flip_uvs: bool) -> Self { self.y_flip_uvs = y_flip_uvs; self } } impl Default for Settings { fn default() -> Self { Self { y_flip_uvs: true } } } 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 settings = match settings { Some(settings) => settings, None => &Settings::default(), }; let parent_path = path .parent() .ok_or_else(|| Error::InvalidPath(path.to_path_buf()))?; 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( crate::file_format::wavefront::obj::ToMeshOptions::default() .y_flip_uvs(settings.y_flip_uvs), )?; let mesh_asset = asset_submitter.submit_store_named("mesh", mesh); let mut material_asset_map_assets = Vec::with_capacity(obj.mtl_libs.len()); for mtl_lib_path in &obj.mtl_libs { let mtl_lib_asset = asset_submitter .submit_load_other::(parent_path.join(mtl_lib_path)); material_asset_map_assets.push(mtl_lib_asset); } asset_submitter.submit_store( Spec::builder() .mesh(mesh_asset) .materials(Materials::Maps(material_asset_map_assets)) .material_names( obj.unique_used_material_names .into_iter() .map(|material_name| material_name.into_string()), ) .build(), ); Ok(()) } #[derive(Debug, thiserror::Error)] enum Error { #[error("Invalid path '{}'", .0.display())] InvalidPath(PathBuf), #[error("Failed to read file {}", .1.display())] ReadFailed(#[source] std::io::Error, PathBuf), #[error(transparent)] Other(#[from] crate::file_format::wavefront::obj::Error), }