Skip to content

Commit

Permalink
Updated resource manager.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Feb 28, 2024
1 parent 73069c1 commit dd08f7e
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 26 deletions.
3 changes: 3 additions & 0 deletions assets/Box.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"url": "Box.gltf"
}
3 changes: 3 additions & 0 deletions assets/Solid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"url": "solid.json"
}
3 changes: 3 additions & 0 deletions assets/Sphere.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"url": "Sphere.gltf"
}
3 changes: 3 additions & 0 deletions assets/Suzanne.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"url": "Suzzane.gltf"
}
20 changes: 15 additions & 5 deletions resource_management/src/asset/asset_manager.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{asset::AssetResolver, resource::resource_handler::ResourceReader, DbStorageBackend, GenericResourceResponse, GenericResourceSerialization};
use crate::{asset::{read_asset_from_source, AssetResolver}, DbStorageBackend};

use super::asset_handler::AssetHandler;

struct AssetManager {
pub struct AssetManager {
asset_handlers: Vec<Box<dyn AssetHandler>>,
}

Expand Down Expand Up @@ -44,6 +44,11 @@ impl AssetManager {
struct MyAssetResolver {}

impl AssetResolver for MyAssetResolver {
fn resolve<'a>(&'a self, url: &'a str) -> std::pin::Pin<Box<dyn std::future::Future<Output = Option<(Vec<u8>, String)>> + Send + 'a>> {
Box::pin(async move {
read_asset_from_source(url, Some(&assets_path())).await.ok()
})
}
}

let asset_resolver = MyAssetResolver {};
Expand All @@ -54,9 +59,10 @@ impl AssetManager {

let load_results = futures::future::join_all(asset_handler_loads).await;

let asset_handler_found = load_results.iter().any(|load_result| { if let Some(Ok(_)) = load_result { true } else { false } });
let asset_handler_found = load_results.iter().any(|load_result| { load_result.is_some() });

if !asset_handler_found {
log::warn!("No asset handler found for asset: {}", url);
return Err(LoadMessages::NoAssetHandler);
}

Expand All @@ -73,10 +79,14 @@ fn resolve_internal_path(path: &std::path::Path) -> std::path::PathBuf {
}

fn resolve_asset_path(path: &std::path::Path) -> std::path::PathBuf {
assets_path().join(path)
}

fn assets_path() -> std::path::PathBuf {
if cfg!(test) {
std::path::PathBuf::from("../assets/").join(path)
std::path::PathBuf::from("../assets/")
} else {
std::path::PathBuf::from("assets/").join(path)
std::path::PathBuf::from("assets/")
}
}

Expand Down
4 changes: 1 addition & 3 deletions resource_management/src/asset/material_asset_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ impl AssetHandler for MaterialAssetHandler {
if is_material {
let material_domain = asset_json["domain"].as_str().ok_or("Domain not found".to_string()).ok()?;

let generator = self.generator.as_ref().unwrap();
let generator = self.generator.as_ref().or_else(|| { log::warn!("No shader generator set for material asset handler"); None })?;

let mut required_resources = asset_json["shaders"].entries().filter_map(|(s_type, shader_json)| {
smol::block_on(transform_shader(generator.deref(), asset_resolver, storage_backend, &material_domain, &asset_json, &shader_json, s_type))
Expand Down Expand Up @@ -84,8 +84,6 @@ impl AssetHandler for MaterialAssetHandler {
}
}).collect::<Vec<_>>()
}).required_resources(&[ProcessedResources::Reference(parent_material_url.to_string())]);

// Ok(vec![Proc/essedResources::Generated((material_resource_document.into(), Vec::new()))])
}

Some(Ok(()))
Expand Down
94 changes: 84 additions & 10 deletions resource_management/src/resource/resource_manager.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::{DbStorageBackend, GenericResourceResponse, LoadRequest, LoadResourceRequest, LoadResults, Request, ResourceRequest, ResourceResponse, Response, StorageBackend};
use super::resource_handler::{ResourceHandler, ResourceReader};
use smol::{io::AsyncReadExt, stream::StreamExt};

use crate::{asset::{asset_manager::AssetManager, audio_asset_handler::AudioAssetHandler, image_asset_handler::ImageAssetHandler, material_asset_handler::MaterialAssetHandler, mesh_asset_handler::MeshAssetHandler}, DbStorageBackend, LoadResourceRequest, LoadResults, ResourceRequest, ResourceResponse, StorageBackend};
use super::resource_handler::ResourceHandler;

/// Resource manager.
/// Handles loading assets or resources from different origins (network, local, etc.).
Expand All @@ -13,6 +15,9 @@ use super::resource_handler::{ResourceHandler, ResourceReader};
pub struct ResourceManager {
storage_backend: Box<dyn StorageBackend>,
resource_handlers: Vec<Box<dyn ResourceHandler + Send>>,

#[cfg(debug_assertions)]
asset_manager: AssetManager,
}

impl From<polodb_core::Error> for LoadResults {
Expand All @@ -37,16 +42,35 @@ impl ResourceManager {

// let mut memory_only = args.find(|arg| arg == "--ResourceManager.memory_only").is_some();

let mut asset_manager = AssetManager::new();

asset_manager.add_asset_handler(MeshAssetHandler::new());

{
let mut material_asset_handler = MaterialAssetHandler::new();
material_asset_handler.set_shader_generator(VisibilityShaderGenerator::new());
asset_manager.add_asset_handler(material_asset_handler);
}

asset_manager.add_asset_handler(ImageAssetHandler::new());
asset_manager.add_asset_handler(AudioAssetHandler::new());

ResourceManager {
storage_backend: Box::new(DbStorageBackend::new(&Self::resolve_resource_path(std::path::Path::new("resources.db")))),
resource_handlers: Vec::with_capacity(8),

#[cfg(debug_assertions)]
asset_manager,
}
}

pub fn new_with_storage_backend<T: StorageBackend + 'static>(storage_backend: T) -> Self {
ResourceManager {
storage_backend: Box::new(storage_backend),
resource_handlers: Vec::with_capacity(8),

#[cfg(debug_assertions)]
asset_manager: AssetManager::new(),
}
}

Expand All @@ -62,8 +86,28 @@ impl ResourceManager {
/// Return is a tuple containing the resource description and it's associated binary data.\
/// The requested resource will always the last one in the array. With the previous resources being the ones it depends on. This way when iterating the array forward the dependencies will be loaded first.
pub async fn get<'s, 'a>(&'s self, id: &'a str) -> Option<ResourceResponse<'a>> {
let load: ResourceResponse<'a> = {
let (resource, reader): (GenericResourceResponse<'a>, Box<dyn ResourceReader>) = self.storage_backend.read(id).await?;
let load = {
let (resource, reader) = if let Some(x) = self.storage_backend.read(id).await {
x
} else {
let mut dir = smol::fs::read_dir(Self::assets_path()).await.ok()?;

let entry = dir.find(|e|
e.as_ref().unwrap().file_name().to_str().unwrap().contains(id) && e.as_ref().unwrap().path().extension().unwrap() == "json"
).await?.ok()?;

let mut asset_resolver = smol::fs::File::open(entry.path()).await.ok()?;

let mut json_string = String::with_capacity(1024);

asset_resolver.read_to_string(&mut json_string).await.ok()?;

let asset_json = json::parse(&json_string).ok()?;

self.asset_manager.load(&asset_json).await.ok()?;

self.storage_backend.read(id).await?
};

self.resource_handlers.iter().find(|rh| rh.get_handled_resource_classes().contains(&resource.class.as_str()))?.read(resource, reader).await?
};
Expand All @@ -75,7 +119,27 @@ impl ResourceManager {
/// This is a more advanced version of get() as it allows to use your own buffer and/or apply some transformation to the resources when loading.\
/// The result of this function can be later fed into `load()` which will load the binary data.
pub async fn request(&self, id: &str) -> Option<ResourceRequest> {
let (resource, _) = self.storage_backend.read(id).await?;
let (resource, _) = if let Some(x) = self.storage_backend.read(id).await {
x
} else {
let mut dir = smol::fs::read_dir(Self::assets_path()).await.ok()?;

let entry = dir.find(|e|
e.as_ref().unwrap().file_name().to_str().unwrap().contains(id) && e.as_ref().unwrap().path().extension().unwrap() == "json"
).await?.ok()?;

let mut asset_resolver = smol::fs::File::open(entry.path()).await.ok()?;

let mut json_string = String::with_capacity(1024);

asset_resolver.read_to_string(&mut json_string).await.ok()?;

let asset_json = json::parse(&json_string).ok()?;

self.asset_manager.load(&asset_json).await.ok()?;

self.storage_backend.read(id).await?
};

Some(ResourceRequest::new(resource))
}
Expand All @@ -96,10 +160,22 @@ impl ResourceManager {
}

fn resolve_resource_path(path: &std::path::Path) -> std::path::PathBuf {
Self::resource_path().join(path)
}

fn resource_path() -> std::path::PathBuf {
if cfg!(test) {
std::env::temp_dir().join("resources")
} else {
std::path::PathBuf::from("resources/")
}
}

fn assets_path() -> std::path::PathBuf {
if cfg!(test) {
std::env::temp_dir().join("resources").join(path)
std::env::temp_dir().join("assets")
} else {
std::path::PathBuf::from("resources/").join(path)
std::path::PathBuf::from("assets/")
}
}
}
Expand All @@ -108,9 +184,7 @@ impl ResourceManager {

#[cfg(test)]
mod tests {
// TODO: test resource load order

use crate::{asset::tests::TestStorageBackend, resource::resource_handler::ResourceReader, GenericResourceResponse, GenericResourceSerialization, LoadResourceRequest, Resource};
use crate::{asset::tests::TestStorageBackend, resource::resource_handler::ResourceReader, GenericResourceResponse, GenericResourceSerialization, Resource};

use super::*;

Expand Down
2 changes: 1 addition & 1 deletion src/gameplay/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ impl physics::PhysicsEntity for Object {

impl mesh::RenderEntity for Object {
fn get_transform(&self) -> maths_rs::Mat4f { maths_rs::Mat4f::from_translation(self.position) * maths_rs::Mat4f::from_scale(Vector3::new(0.05, 0.05, 0.05)) }
fn get_material_id(&self) -> &'static str { "solid" }
fn get_material_id(&self) -> &'static str { "Solid" }
fn get_resource_id(&self) -> &'static str { "Box" }
}
9 changes: 7 additions & 2 deletions src/rendering/visibility_model/render_domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,14 +745,19 @@ impl EntitySubscriber<dyn mesh::RenderEntity> for VisibilityWorldRenderDomain {
if !self.material_evaluation_materials.contains_key(mesh.get_material_id()) {
let response_and_data = {
let resource_manager = self.resource_manager.read().await;
resource_manager.get(mesh.get_material_id()).await.unwrap()
if let Some(x) = resource_manager.get(mesh.get_material_id()).await {
x
} else {
log::error!("Failed to load material {} for mesh {}", mesh.get_material_id(), mesh.get_resource_id());
return;
}
};

self.load_material(response_and_data,);
}

if !self.mesh_resources.contains_key(mesh.get_resource_id()) { // Load only if not already loaded
let mut ghi = self.ghi.write().unwrap();
let ghi = self.ghi.write().unwrap();

let resource_request = {
let resource_manager = self.resource_manager.read().await;
Expand Down
8 changes: 4 additions & 4 deletions tests/gallery_shooter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ fn gallery_shooter() {

let scale = maths_rs::Mat4f::from_scale(Vector3::new(0.1, 0.1, 0.1));

let duck_1: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "solid", maths_rs::Mat4f::from_translation(Vector3::new(0.0, 0.0, 2.0)) * scale));
let duck_1: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "Solid", maths_rs::Mat4f::from_translation(Vector3::new(0.0, 0.0, 2.0)) * scale));

let physics_duck_1 = core::spawn_as_child(space_handle.clone(), physics::Sphere::new(Vector3::new(0.0, 0.0, 2.0), Vector3::new(0.0, 0.0, 0.0), 0.1));

let duck_2: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "solid", maths_rs::Mat4f::from_translation(Vector3::new(2.0, 0.0, 0.0)) * scale));
let duck_3: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "solid", maths_rs::Mat4f::from_translation(Vector3::new(-2.0, 0.0, 0.0)) * scale));
let duck_4: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "solid", maths_rs::Mat4f::from_translation(Vector3::new(0.0, 0.0, -2.0)) * scale));
let duck_2: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "Solid", maths_rs::Mat4f::from_translation(Vector3::new(2.0, 0.0, 0.0)) * scale));
let duck_3: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "Solid", maths_rs::Mat4f::from_translation(Vector3::new(-2.0, 0.0, 0.0)) * scale));
let duck_4: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "Solid", maths_rs::Mat4f::from_translation(Vector3::new(0.0, 0.0, -2.0)) * scale));

let _sun: EntityHandle<PointLight> = core::spawn_as_child(space_handle.clone(), PointLight::new(Vector3::new(0.0, 2.5, -1.5), 4500.0));

Expand Down
2 changes: 1 addition & 1 deletion tests/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn load() {

let scale = maths_rs::Mat4f::from_scale(Vector3::new(0.1, 0.1, 0.1));

let duck_1: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "solid", maths_rs::Mat4f::from_translation(Vector3::new(0.0, 0.0, 2.0)) * scale));
let duck_1: EntityHandle<mesh::Mesh> = core::spawn_as_child(space_handle.clone(), mesh::Mesh::new("Box", "Solid", maths_rs::Mat4f::from_translation(Vector3::new(0.0, 0.0, 2.0)) * scale));

let _sun: EntityHandle<PointLight> = core::spawn_as_child(space_handle.clone(), PointLight::new(Vector3::new(0.0, 2.5, -1.5), 4500.0));

Expand Down

0 comments on commit dd08f7e

Please sign in to comment.