Skip to content

Commit

Permalink
Updated resource loading to handle more GLTF.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Oct 27, 2023
1 parent 789a328 commit 6efd53e
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 24 deletions.
6 changes: 5 additions & 1 deletion src/resource_manager/material_resource_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ impl ResourceHandler for MaterialResourcerHandler {
fn can_handle_type(&self, resource_type: &str) -> bool {
match resource_type {
"json" => true,
"glsl" => true,
"besl" => true,
_ => false
}
}
Expand All @@ -83,7 +85,9 @@ impl ResourceHandler for MaterialResourcerHandler {
file.read_exact(buffers[0].buffer).unwrap();
}

fn process(&self, resource_manager: &ResourceManager, asset_url: &str, bytes: &[u8]) -> Result<Vec<ProcessedResources>, String> {
fn process(&self, resource_manager: &ResourceManager, asset_url: &str,) -> Result<Vec<ProcessedResources>, String> {
let (bytes, _) = resource_manager.read_asset_from_source(asset_url).unwrap();

let asset_json = json::parse(std::str::from_utf8(&bytes).unwrap()).unwrap();

let is_material = asset_json["parent"].is_null();
Expand Down
34 changes: 32 additions & 2 deletions src/resource_manager/mesh_resource_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ impl ResourceHandler for MeshResourceHandler {
}
}

fn process(&self, _: &ResourceManager, asset_url: &str, bytes: &[u8]) -> Result<Vec<ProcessedResources>, String> {
let (gltf, buffers, _) = gltf::import_slice(bytes).unwrap();
fn process(&self, resource_manager: &ResourceManager, asset_url: &str) -> Result<Vec<ProcessedResources>, String> {
let (gltf, buffers, _) = gltf::import(resource_manager.realize_asset_path(asset_url).unwrap()).unwrap();

let mut buf: Vec<u8> = Vec::with_capacity(4096 * 1024 * 3);

Expand Down Expand Up @@ -358,6 +358,36 @@ mod tests {
}
}

#[test]
fn load_local_gltf_mesh_with_external_binaries() {
let mut resource_manager = ResourceManager::new();

let (response, _) = resource_manager.get("Suzanne").expect("Failed to get resource");

assert_eq!(response.resources.len(), 1);

let resource_container = &response.resources[0];
let resource = &resource_container.resource;

assert_eq!(resource.type_id(), std::any::TypeId::of::<Mesh>());

// assert_eq!(buffer.len(), (11808 /* vertices */ * (3 /* components per position */ * 4 /* float size */ + 3/*normals */ * 4) as usize).next_multiple_of(16) + 6/* cube faces */ * 2 /* triangles per face */ * 3 /* indices per triangle */ * 2 /* bytes per index */);

let mesh = resource.downcast_ref::<Mesh>().unwrap();

// assert_eq!(mesh.bounding_box, [[-0.5f32, -0.5f32, -0.5f32], [0.5f32, 0.5f32, 0.5f32]]);
assert_eq!(mesh.vertex_count, 11808);
assert_eq!(mesh.index_count, 3936 * 3);
assert_eq!(mesh.index_type, IntegralTypes::U16);
assert_eq!(mesh.vertex_components.len(), 4);
assert_eq!(mesh.vertex_components[0].semantic, VertexSemantics::Position);
assert_eq!(mesh.vertex_components[0].format, "vec3f");
assert_eq!(mesh.vertex_components[0].channel, 0);
assert_eq!(mesh.vertex_components[1].semantic, VertexSemantics::Normal);
assert_eq!(mesh.vertex_components[1].format, "vec3f");
assert_eq!(mesh.vertex_components[1].channel, 1);
}

#[test]
fn load_with_manager_buffer() {
let mut resource_manager = ResourceManager::new();
Expand Down
2 changes: 1 addition & 1 deletion src/resource_manager/resource_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub trait ResourceHandler {
/// - **resource**: The resource data. Can look like anything.
/// - **hash**(optional): The resource hash. This is used to identify the resource data. If the resource handler wants to generate a hash for the resource it can do so else the resource manager will generate a hash for it. This is because some resources can generate hashes inteligently (EJ: code generators can output same hash for different looking code if the code is semantically identical).
/// - **required_resources**(optional): A list of resources that this resource depends on. This is used to load resources that depend on other resources.
fn process(&self, resource_manager: &resource_manager::ResourceManager, asset_url: &str, bytes: &[u8]) -> Result<Vec<ProcessedResources>, String>;
fn process(&self, resource_manager: &resource_manager::ResourceManager, asset_url: &str) -> Result<Vec<ProcessedResources>, String>;

fn get_deserializers(&self) -> Vec<(&'static str, Box<dyn Fn(&polodb_core::bson::Document) -> Box<dyn std::any::Any> + Send>)>;

Expand Down
83 changes: 65 additions & 18 deletions src/resource_manager/resource_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,14 +190,16 @@ impl ResourceManager {

documents
} else {
let r = self.read_asset_from_source(url).unwrap();
// let r = self.read_asset_from_source(url).unwrap();

let mut loaded_resource_documents = Vec::new();

let resource_handlers = self.resource_handlers.iter().filter(|h| h.can_handle_type(r.1.as_str()));
let asset_type = self.get_url_type(url);

let resource_handlers = self.resource_handlers.iter().filter(|h| h.can_handle_type(&asset_type));

for resource_handler in resource_handlers {
let gg = resource_handler.process(self, url, &r.0).unwrap();
let gg = resource_handler.process(self, url,).unwrap();

for g in gg {
match g {
Expand Down Expand Up @@ -394,23 +396,11 @@ impl ResourceManager {
request.into_reader().read_to_end(&mut source_bytes);
},
"local" => {
let path = std::path::Path::new("assets/");

let url_as_path = std::path::Path::new(url);

let url_as_path_parent = url_as_path.parent().ok_or(None)?;

let path = path.join(url_as_path_parent);
let path = self.realize_asset_path(url).unwrap();

let (mut file, extension) = if let Ok(dir) = std::fs::read_dir(path) {
let files = dir.filter(|f| if let Ok(f) = f { f.path().file_stem().unwrap().eq(url_as_path.file_name().unwrap()) } else { false });
let mut file = std::fs::File::open(&path).unwrap();

let file_path = files.last().ok_or(None)?.or(Err(None))?.path();

(std::fs::File::open(&file_path).unwrap(), file_path.extension().unwrap().to_str().unwrap().to_string())
} else { return Err(None); };

format = extension.to_string();
format = path.extension().unwrap().to_str().unwrap().to_string();

source_bytes = Vec::with_capacity(file.metadata().unwrap().len() as usize);

Expand All @@ -426,6 +416,63 @@ impl ResourceManager {

Ok((source_bytes, format))
}

pub fn realize_asset_path(&self, url:&str) -> Option<std::path::PathBuf> {
let path = std::path::Path::new("assets/");

let url_as_path = std::path::Path::new(url);

let url_as_path_parent = url_as_path.parent().or(None)?;

let path = path.join(url_as_path_parent);

let path = if let Ok(dir) = std::fs::read_dir(path) {
let files = dir.filter(|f|
if let Ok(f) = f {
let path = if f.path().is_file() { f.path() } else { return false; };
// Do this to only try loading files that have supported extensions
// Take this case
// Suzanne.gltf Suzanne.bin
// We want to load Suzanne.gltf and not Suzanne.bin
let extension = path.extension().unwrap().to_str().unwrap();
self.resource_handlers.iter().any(|rm| rm.can_handle_type(extension)) && f.path().file_stem().unwrap().eq(url_as_path.file_name().unwrap())
} else {
false
}
);

let file_path = files.last()?.unwrap().path();

file_path
} else { return None; };

Some(path)
}

fn get_url_type(&self, url:&str) -> String {
let origin = if url.starts_with("http://") || url.starts_with("https://") {
"network".to_string()
} else {
"local".to_string()
};

match origin.as_str() {
"network" => {
let request = if let Ok(request) = ureq::get(url).call() { request } else { return "unknown".to_string(); };
let content_type = if let Some(e) = request.header("content-type") { e.to_string() } else { return "unknown".to_string(); };
content_type
},
"local" => {
let path = self.realize_asset_path(url).unwrap();

path.extension().unwrap().to_str().unwrap().to_string()
},
_ => {
// Could not resolve how to get raw resource, return empty bytes
return "unknown".to_string();
}
}
}
}

// TODO: test resource caching
Expand Down
5 changes: 3 additions & 2 deletions src/resource_manager/texture_resource_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ impl ResourceHandler for ImageResourceHandler {
}
}

fn process(&self, _: &ResourceManager, asset_url: &str, bytes: &[u8]) -> Result<Vec<ProcessedResources>, String> {
let mut decoder = png::Decoder::new(bytes);
fn process(&self, resource_manager: &ResourceManager, asset_url: &str,) -> Result<Vec<ProcessedResources>, String> {
let (bytes, _) = resource_manager.read_asset_from_source(asset_url).unwrap();
let mut decoder = png::Decoder::new(bytes.as_slice());
decoder.set_transformations(png::Transformations::normalize_to_color8());
let mut reader = decoder.read_info().unwrap();
let mut buffer = vec![0; reader.output_buffer_size()];
Expand Down

0 comments on commit 6efd53e

Please sign in to comment.