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 let mut map = self.0.lock().unwrap();
56
57 map.clear();
59
60 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 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 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}