diff --git a/src/lib.rs b/src/lib.rs index f24bf7a..baf3426 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,15 +2,17 @@ mod compiler; mod error; mod reflection; mod srvk; -mod layouts; +pub mod layouts; +mod watch; pub use layouts::*; pub use reflection::LayoutData; +pub use watch::{Message, Watch}; +pub use error::Error; use spirv_reflect as sr; use vulkano as vk; use std::path::Path; -use error::Error; use shaderc::ShaderKind; pub struct CompiledShaders { @@ -18,6 +20,7 @@ pub struct CompiledShaders { pub fragment: Vec, } + pub fn load(vertex: T, fragment: T) -> Result where T: AsRef, diff --git a/src/watch.rs b/src/watch.rs new file mode 100644 index 0000000..8b855de --- /dev/null +++ b/src/watch.rs @@ -0,0 +1,107 @@ +use std::sync::mpsc; +use notify::{RecommendedWatcher, RecursiveMode, Watcher}; +use std::thread; +use std::time::Duration; +use std::path::{Path, PathBuf}; +use crate::layouts::Entry; +use crate::CompiledShaders; +use std::sync::mpsc::{Sender, Receiver}; +use crate::error::Error; + +pub struct Watch { + _handler: Handler, + pub rx: Receiver>, +} + +struct Loader { + vertex: PathBuf, + fragment: PathBuf, + tx: Sender>, +} + +pub struct Message { + pub shaders: CompiledShaders, + pub entry: Entry, +} + +impl Watch { + pub fn new(vertex: T, fragment: T) -> Self + where + T: AsRef, + { + let (handler, rx) = create_watch(vertex.as_ref().to_path_buf(), fragment.as_ref().to_path_buf()); + Watch{_handler: handler, rx} + } +} + +impl Loader { + fn create(vertex: PathBuf, fragment: PathBuf) -> (Self, Receiver>) { + let (tx, rx) = mpsc::channel(); + let loader = Loader{ + vertex, + fragment, + tx, + }; + loader.reload(); + (loader, rx) + } + + fn reload(&self) { + match crate::load(&self.vertex, &self.fragment) { + Ok(shaders) => { + let entry = crate::parse(&shaders); + self.tx.send(Ok(Message{ shaders, entry })).ok() + }, + Err(e) => self.tx.send(Err(e)).ok(), + }; + } +} + +struct Handler { + thread_tx: mpsc::Sender<()>, + handle: Option>, + _watcher: RecommendedWatcher, +} + +impl Drop for Handler { + fn drop(&mut self) { + self.thread_tx.send(()).ok(); + if let Some(h) = self.handle.take() { + h.join().ok(); + } + } +} + + +fn create_watch(vert_path: PathBuf, frag_path: PathBuf) -> (Handler, mpsc::Receiver>) { + let (notify_tx, notify_rx) = mpsc::channel(); + let (thread_tx, thread_rx) = mpsc::channel(); + let mut watcher: RecommendedWatcher = + Watcher::new(notify_tx, Duration::from_millis(50)).expect("failed to create watcher"); + + watcher + .watch(&vert_path, RecursiveMode::NonRecursive) + .expect("failed to add vertex shader to notify"); + watcher + .watch(&frag_path, RecursiveMode::NonRecursive) + .expect("failed to add fragment shader to notify"); + + + let (loader, rx) = Loader::create(vert_path, frag_path); + + let handle = thread::spawn(move || 'watch_loop: loop { + if let Ok(_) = thread_rx.try_recv() { + break 'watch_loop; + } + if let Ok(notify::DebouncedEvent::Create(_)) = notify_rx.recv_timeout(Duration::from_secs(1)) { + loader.reload(); + } + }); + let handle = Some(handle); + let handler = Handler { + thread_tx, + handle, + _watcher: watcher, + }; + (handler, rx) +}