Skip to main content

gizmo_engine/
asset_server.rs

1use crate::core::asset::Handle;
2use crate::renderer::async_assets::AsyncAssetLoader;
3use crate::renderer::components::{Material, Mesh};
4use wgpu::util::DeviceExt;
5
6pub struct AssetServer {
7    pub loader: AsyncAssetLoader,
8    mesh_paths: std::collections::HashMap<String, Handle<Mesh>>,
9    _material_paths: std::collections::HashMap<String, Handle<Material>>,
10    pub completed_gltfs: Vec<crate::renderer::async_assets::GltfImportCompletion>,
11    pub completed_gltf_errors: Vec<crate::renderer::async_assets::GltfImportError>,
12    #[cfg(all(feature = "render", not(target_arch = "wasm32")))]
13    pub watcher: Option<crate::renderer::hot_reload::AssetWatcher>,
14}
15
16impl Default for AssetServer {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl AssetServer {
23    pub fn new() -> Self {
24        #[cfg(all(feature = "render", not(target_arch = "wasm32")))]
25        let watcher = crate::renderer::hot_reload::AssetWatcher::new(&["assets", "demo/assets"]);
26
27        Self {
28            loader: AsyncAssetLoader::new(),
29            mesh_paths: std::collections::HashMap::new(),
30            _material_paths: std::collections::HashMap::new(),
31            completed_gltfs: Vec::new(),
32            completed_gltf_errors: Vec::new(),
33            #[cfg(all(feature = "render", not(target_arch = "wasm32")))]
34            watcher,
35        }
36    }
37
38    pub fn load_mesh(&mut self, path: &str) -> Handle<Mesh> {
39        if let Some(handle) = self.mesh_paths.get(path) {
40            return handle.clone();
41        }
42        let handle = crate::core::asset::Handle::weak(crate::core::asset::HandleId::new());
43        self.loader.request_obj_load(path.to_string(), handle.id.0);
44        self.mesh_paths.insert(path.to_string(), handle.clone());
45        handle
46    }
47}
48
49pub fn asset_server_update_system(
50    mut server: crate::core::system::ResMut<AssetServer>,
51    renderer: crate::core::system::ResMut<crate::renderer::Renderer>,
52    mut meshes: crate::core::system::ResMut<crate::core::asset::Assets<Mesh>>,
53) {
54    // Process Hot Reloading
55    #[cfg(all(feature = "render", not(target_arch = "wasm32")))]
56    if let Some(watcher) = &server.watcher {
57        let changed = watcher.poll_changes();
58        for path in changed {
59            let path_str = path.to_string_lossy().to_string();
60            // Check if mesh needs reloading
61            if let Some(handle) = server.mesh_paths.get(&path_str) {
62                tracing::info!("AssetWatcher: Reloading mesh {:?}", path_str);
63                server.loader.request_obj_load(path_str.clone(), handle.id.0);
64            }
65        }
66    }
67
68    // Process garbage collection
69    meshes.process_drops();
70
71    let completed = server.loader.drain_completed();
72
73    server.completed_gltfs.extend(completed.gltfs);
74    server.completed_gltf_errors.extend(completed.gltf_errors);
75
76    if completed.objs.is_empty() && completed.textures.is_empty() {
77        return;
78    }
79
80    for obj in completed.objs {
81        let mesh_source = format!("obj:{}", obj.path);
82        // Create wgpu buffer
83        let vbuf = renderer
84            .device
85            .create_buffer_init(&wgpu::util::BufferInitDescriptor {
86                label: Some(&format!("Obj VBuf: {}", obj.path)),
87                contents: bytemuck::cast_slice(&obj.vertices),
88                usage: wgpu::BufferUsages::VERTEX,
89            });
90        let mesh = Mesh::new(
91            &renderer.device,
92            std::sync::Arc::new(vbuf),
93            &obj.vertices,
94            gizmo_math::Vec3::ZERO,
95            mesh_source,
96        );
97        for handle_id in obj.handle_ids {
98            let handle = crate::core::asset::Handle::weak(crate::core::asset::HandleId(handle_id));
99            meshes.insert(&handle, mesh.clone());
100        }
101    }
102}
103
104pub struct AssetServerPlugin;
105
106impl<State: 'static> crate::app::Plugin<State> for AssetServerPlugin {
107    fn build(&self, app: &mut crate::app::App<State>) {
108        app.world.insert_resource(AssetServer::new());
109        app.schedule.add_di_system(asset_server_update_system);
110    }
111}