cog_task/resource/
mod.rs

1pub mod address;
2pub mod audio;
3pub mod color;
4pub mod function;
5pub mod image;
6pub mod key;
7pub mod logger;
8pub mod stream;
9pub mod text;
10pub mod trigger;
11pub mod value;
12
13pub use crate::resource::image::*;
14pub use address::*;
15pub use audio::*;
16pub use color::*;
17pub use function::*;
18pub use key::*;
19pub use logger::*;
20pub use stream::*;
21pub use text::*;
22pub use trigger::Trigger;
23pub use value::*;
24
25use crate::assets::{IMAGE_FIXATION, IMAGE_RUSTACEAN};
26use crate::server::{Config, Env};
27use eframe::egui::mutex::RwLock;
28use eframe::epaint;
29use eyre::{eyre, Context, Result};
30use std::collections::HashMap;
31use std::fmt::{Debug, Formatter};
32use std::sync::{Arc, Mutex};
33
34#[derive(Debug, Clone)]
35pub struct ResourceManager(Arc<Mutex<HashMap<ResourceAddr, ResourceValue>>>);
36
37pub struct IoManager {
38    audio: AudioDevice,
39}
40
41impl ResourceManager {
42    #[inline(always)]
43    pub fn new(_config: &Config) -> Result<Self> {
44        Ok(Self(Default::default()))
45    }
46
47    pub fn preload_block(
48        &mut self,
49        resources: Vec<ResourceAddr>,
50        tex_manager: Arc<RwLock<epaint::TextureManager>>,
51        #[allow(unused)] config: &Config,
52        env: &Env,
53    ) -> Result<()> {
54        // Lock map
55        let mut map = self.0.lock().unwrap();
56
57        // Clean up existing resource map
58        map.clear();
59
60        // Load default fixation image
61        let src = ResourceAddr::Image("fixation.svg".into());
62        map.entry(src.clone()).or_insert({
63            let tex_manager = tex_manager.clone();
64            let (texture, size) = svg_from_bytes(tex_manager, IMAGE_FIXATION, src.path())?;
65            ResourceValue::Image(texture, size)
66        });
67        let mut default_fixation = true;
68
69        // Load default rustacean image
70        let src = ResourceAddr::Image("rustacean.svg".into());
71        map.entry(src.clone()).or_insert({
72            let tex_manager = tex_manager.clone();
73            let (texture, size) = svg_from_bytes(tex_manager, IMAGE_RUSTACEAN, src.path())?;
74            ResourceValue::Image(texture, size)
75        });
76        let mut default_rustacean = true;
77
78        // Load resources used in new block
79        for src in resources {
80            let mut is_new = !map.contains_key(&src);
81            match src.path().to_str().unwrap() {
82                "fixation.svg" => {
83                    if default_fixation {
84                        is_new = true;
85                        default_fixation = false;
86                    }
87                }
88                "rustacean.svg" => {
89                    if default_rustacean {
90                        is_new = true;
91                        default_rustacean = false;
92                    }
93                }
94                _ => {}
95            }
96
97            if is_new {
98                let data = match src.prefix(env.resource()) {
99                    ResourceAddr::Ref(path) => ResourceValue::Ref(path),
100                    ResourceAddr::Text(path) => {
101                        let text = std::fs::read_to_string(&path)
102                            .wrap_err_with(|| eyre!("Failed to load text resource ({path:?})"))?;
103                        ResourceValue::Text(Arc::new(text))
104                    }
105                    ResourceAddr::Image(path) => {
106                        let tex_manager = tex_manager.clone();
107                        let (texture, size) = match src.extension().as_deref() {
108                            Some("svg") => {
109                                svg_from_file(tex_manager, &path).wrap_err_with(|| {
110                                    eyre!("Failed to load SVG resource ({path:?})")
111                                })?
112                            }
113                            _ => image_from_file(tex_manager, &path).wrap_err_with(|| {
114                                eyre!("Failed to load image resource ({path:?})")
115                            })?,
116                        };
117                        ResourceValue::Image(texture, size)
118                    }
119                    ResourceAddr::Audio(path) => ResourceValue::Audio(
120                        audio_from_file(&path, config)
121                            .wrap_err_with(|| eyre!("Failed to load audio resource ({path:?})"))?,
122                    ),
123                    ResourceAddr::Video(path) => {
124                        let tex_manager = tex_manager.clone();
125                        let (frames, framerate) = video_from_file(tex_manager, &path, config)
126                            .wrap_err_with(|| eyre!("Failed to load video resource ({path:?})"))?;
127                        ResourceValue::Video(frames, framerate)
128                    }
129                    ResourceAddr::Stream(path) => {
130                        let tex_manager = tex_manager.clone();
131                        ResourceValue::Stream(
132                            stream_from_file(tex_manager, &path, config).wrap_err_with(|| {
133                                eyre!("Failed to load stream resource ({path:?})")
134                            })?,
135                        )
136                    }
137                };
138                println!("+ {src:?} : {data:?}");
139                map.insert(src, data);
140            }
141        }
142
143        Ok(())
144    }
145
146    pub fn fetch(&self, src: &ResourceAddr) -> Result<ResourceValue> {
147        if let Some(res) = self.0.lock().unwrap().get(src) {
148            Ok(res.clone())
149        } else {
150            Err(eyre!("Tried to fetch unexpected resource: {src:?}"))
151        }
152    }
153}
154
155impl Debug for IoManager {
156    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
157        write!(f, "<IO>")
158    }
159}
160
161impl IoManager {
162    pub fn new(config: &Config) -> Result<Self> {
163        Ok(Self {
164            audio: AudioDevice::new(config)?,
165        })
166    }
167
168    pub fn try_clone(&self) -> Result<Self> {
169        Ok(Self {
170            audio: self.audio.try_clone()?,
171        })
172    }
173
174    pub fn audio(&self) -> Result<AudioSink> {
175        self.audio.sink()
176    }
177}