diff --git a/fyrox-core/src/io.rs b/fyrox-core/src/io.rs index 68d46d5d2..e7d46c4ed 100644 --- a/fyrox-core/src/io.rs +++ b/fyrox-core/src/io.rs @@ -112,3 +112,41 @@ pub async fn exists>(path: P) -> bool { } } } + +pub async fn is_dir>(path: P) -> bool { + #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] + { + path.as_ref().is_dir() + } + + #[cfg(target_os = "android")] + { + ANDROID_APP + .get() + .map(|v| { + v.asset_manager() + .open_dir(&std::ffi::CString::new(path.as_ref().to_str().unwrap()).unwrap()) + .is_some() + }) + .unwrap_or_default() + } + + // TODO: Is directory checking possible on wasm? + #[cfg(target_arch = "wasm32")] + { + false + } +} + +pub async fn is_file>(path: P) -> bool { + #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] + { + path.as_ref().is_file() + } + + // On android of wasm the default exists logic works for files + #[cfg(any(target_os = "android", target_arch = "wasm32"))] + { + exists(path).await + } +} diff --git a/fyrox-resource/Cargo.toml b/fyrox-resource/Cargo.toml index 23488ab70..23e7db1b9 100644 --- a/fyrox-resource/Cargo.toml +++ b/fyrox-resource/Cargo.toml @@ -19,3 +19,4 @@ fyrox-core = { path = "../fyrox-core", version = "0.26.0" } fxhash = "0.2.1" ron = "0.8.0" serde = { version = "1", features = ["derive"] } +walkdir = "2.3.2" diff --git a/fyrox-resource/src/io.rs b/fyrox-resource/src/io.rs index f0add622c..4c0c03380 100644 --- a/fyrox-resource/src/io.rs +++ b/fyrox-resource/src/io.rs @@ -3,11 +3,13 @@ use std::{ fmt::Debug, + future::ready, io::{Cursor, Read, Seek}, - path::Path, + path::{Path, PathBuf}, }; use fyrox_core::{futures::future::BoxFuture, io::FileLoadError}; +use walkdir::WalkDir; /// Trait for files readers ensuring they implement the required traits pub trait FileReader: Debug + Send + Read + Seek + 'static {} @@ -21,6 +23,13 @@ pub trait ResourceIo: Send + Sync + 'static { /// the entire byte contents of the file or an error fn load_file<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, Result, FileLoadError>>; + /// Provides an iterator over the paths present in the provided + /// path directory FsResourceIo uses WalkDir bu + fn walk_directory<'a>( + &'a self, + path: &'a Path, + ) -> BoxFuture<'a, Result>, FileLoadError>>; + /// Attempts to open a file reader to the proivded path for /// reading its bytes /// @@ -39,6 +48,12 @@ pub trait ResourceIo: Send + Sync + 'static { /// Used to check whether a path exists fn exists<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, bool>; + + /// Used to check whether a path is a file + fn is_file<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, bool>; + + /// Used to check whether a path is a dir + fn is_dir<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, bool>; } /// Standard resource IO provider that uses the file system to @@ -51,7 +66,29 @@ impl ResourceIo for FsResourceIo { Box::pin(fyrox_core::io::load_file(path)) } - // Only use file reader when not targetting android or wasm + fn walk_directory<'a>( + &'a self, + path: &'a Path, + ) -> BoxFuture<'a, Result>, FileLoadError>> { + Box::pin(async move { + // TODO: I'm not sure if WalkDir is acceptable for wasm and mobile platforms + // might need to be updated for those platforms + + let iter = WalkDir::new(path) + .into_iter() + .flatten() + .map(|value| value.into_path()); + + let iter: Box> = Box::new(iter); + + Ok(iter) + }) + } + + /// Only use file reader when not targetting android or wasm + /// + /// Note: Might be possible to using the android Asset for reading as + /// long as its Send + Sync + 'static (It already implements Debug + Read + Seek) #[cfg(all(not(target_os = "android"), not(target_arch = "wasm32")))] fn file_reader<'a>( &'a self, @@ -71,4 +108,12 @@ impl ResourceIo for FsResourceIo { fn exists<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, bool> { Box::pin(fyrox_core::io::exists(path)) } + + fn is_file<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, bool> { + Box::pin(fyrox_core::io::is_file(path)) + } + + fn is_dir<'a>(&'a self, path: &'a Path) -> BoxFuture<'a, bool> { + Box::pin(fyrox_core::io::is_dir(path)) + } } diff --git a/src/resource/fbx/mod.rs b/src/resource/fbx/mod.rs index a3b464b3a..f477dd191 100644 --- a/src/resource/fbx/mod.rs +++ b/src/resource/fbx/mod.rs @@ -17,7 +17,6 @@ use crate::{ algebra::{Matrix4, Point3, UnitQuaternion, Vector2, Vector3, Vector4}, curve::{CurveKey, CurveKeyKind}, instant::Instant, - io, log::{Log, MessageKind}, math::{self, triangulator::triangulate, RotationOrder}, pool::Handle, @@ -67,7 +66,6 @@ use std::{ hash::{Hash, Hasher}, path::Path, }; -use walkdir::WalkDir; /// Input angles in degrees fn quat_from_euler(euler: Vector3) -> UnitQuaternion { @@ -308,6 +306,9 @@ async fn create_surfaces( ), ) } + + let io = resource_manager.resource_io(); + for (name, texture_handle) in material.textures.iter() { let texture = fbx_scene.get(*texture_handle).as_texture()?; let path = texture.get_file_path(); @@ -322,7 +323,7 @@ async fn create_surfaces( let mut path = model_path.to_owned(); while let Some(parent) = path.parent() { let candidate = parent.join(filename); - if io::exists(&candidate).await { + if io.exists(&candidate).await { texture_path = Some(candidate); break; } @@ -332,15 +333,21 @@ async fn create_surfaces( } MaterialSearchOptions::WorkingDirectory => { let mut texture_path = None; - for dir in WalkDir::new(".").into_iter().flatten() { - if dir.path().is_dir() { - let candidate = dir.path().join(filename); - if candidate.exists() { - texture_path = Some(candidate); - break; + + let path = Path::new("."); + + if let Ok(iter) = io.walk_directory(path).await { + for dir in iter { + if io.is_dir(&dir).await { + let candidate = dir.join(filename); + if candidate.exists() { + texture_path = Some(candidate); + break; + } } } } + texture_path } MaterialSearchOptions::UsePathDirectly => Some(path.clone()),