diff options
| author | s-ol <s+removethis@s-ol.nu> | 2026-04-22 13:35:18 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2026-05-14 14:46:13 +0000 |
| commit | 9fd2105289ccc5a7c12af56bad4d33ef768d0f16 (patch) | |
| tree | a4e6ff2c64fd0f1d4c73d74b3d62327630ff6206 /src/bin | |
| parent | add tsv-video-buffer (diff) | |
| download | wgsl-view-9fd2105289ccc5a7c12af56bad4d33ef768d0f16.tar.gz wgsl-view-9fd2105289ccc5a7c12af56bad4d33ef768d0f16.zip | |
samplers/textures as resources
Diffstat (limited to 'src/bin')
| -rw-r--r-- | src/bin/wgsl_render.rs | 122 |
1 files changed, 55 insertions, 67 deletions
diff --git a/src/bin/wgsl_render.rs b/src/bin/wgsl_render.rs index 29b5d5d..da28816 100644 --- a/src/bin/wgsl_render.rs +++ b/src/bin/wgsl_render.rs @@ -61,52 +61,35 @@ fn main() { loop { let frame_start = Instant::now(); - let handle_msg = |msg: rosc::OscMessage| { - let path = &msg.addr; - - if path == "/shader" { - match &msg.args[..] { - [OscType::String(code)] => { - if let Err(e) = renderer.load_shader(&device, code) { - log::error!("shader error: {e}"); - } - } - _ => log::warn!("/shader: expected single string argument"), + let handle_msg = |msg: rosc::OscMessage| -> Result<(), String> { + let path: Vec<_> = msg.addr.strip_prefix("/").unwrap().split('/').collect(); + + match (&path[..], &msg.args[..]) { + (["shader"], [OscType::String(code)]) => renderer.load_shader(&device, code), + (["uniform", rest @ ..], args) => { + set_uniform(renderer.uniforms(), rest, args).map_err(|e| e.to_string()) + } + (["texture", id], [OscType::String(tsv_name)]) => { + renderer.create_texture_resource(&device, id, tsv_name); + Ok(()) } - } else if let Some(rest) = path.strip_prefix("/uniform/") { - if let Err(e) = set_uniform(renderer.uniforms(), rest, &msg.args) { - log::warn!("uniform error: {e}"); + (["sampler", id], [OscType::String(filter), OscType::String(clamp)]) => { + let (filter_mode, address_mode) = parse_sampler_modes(filter, clamp)?; + renderer.create_sampler_resource(&device, id, filter_mode, address_mode); + Ok(()) } - } else if let Some(tex_name) = path.strip_prefix("/texture/") { - match &msg.args[..] { - [OscType::String(tsv_name)] => { - match renderer.uniforms().texture_slot_mut(tex_name) { - Some(slot) => { - slot.set_tsv_name(tsv_name.clone()); - log::info!("texture '{tex_name}' → tsv '{tsv_name}'"); - } - None => log::warn!("texture '{tex_name}' not found"), - } - } - _ => log::warn!("/texture/{tex_name}: expected string (TSV image name)"), + (["texture", id, "destroy"], []) => { + renderer.destroy_texture_resource(&device, id); + Ok(()) } - } else if let Some(smp_name) = path.strip_prefix("/sampler/") { - match &msg.args[..] { - [OscType::String(filter), OscType::String(clamp)] => { - if let Err(e) = configure_sampler( - renderer.uniforms(), - &device, - smp_name, - filter, - clamp, - ) { - log::warn!("sampler error: {e}"); - } - } - _ => log::warn!("/sampler/{smp_name}: expected two strings (filter, clamp)"), + (["sampler", id, "destroy"], []) => { + renderer.destroy_sampler_resource(&device, id); + Ok(()) } - } else { - log::debug!("unhandled OSC: {path}"); + (["binding", name], [OscType::String(target)]) => { + bind_resource(&mut renderer, &device, name, target) + } + _ => Err(format!("unhandled OSC message {} {:?}", msg.addr, msg.args)), } }; @@ -118,7 +101,7 @@ fn main() { }; if dirty { - gpu::refresh_textures(renderer.uniforms(), &device, &mut client, fence); + renderer.refresh_textures(&device, &mut client, fence); renderer.render(&device, &queue); device.poll(wgpu::PollType::wait_indefinitely()).unwrap(); @@ -146,13 +129,13 @@ fn main() { /// Set a uniform value from OSC args, navigating the path. fn set_uniform( cache: &mut wgsl_view::uniform::UniformCache, - path: &str, + path: &[&str], args: &[OscType], -) -> Result<(), Box<dyn std::error::Error>> { - let mut parts = path.split('/'); - let name = parts.next().ok_or("missing uniform name")?; +) -> Result<(), UniformError> { + let mut parts = path.iter(); + let name = parts.next().ok_or(UniformError::NotFound)?; - let mut uref = cache.get(name).ok_or("uniform not found")?; + let mut uref = cache.get(name).ok_or(UniformError::NotFound)?; for component in parts { uref = uref.field(component)?; } @@ -198,38 +181,43 @@ fn set_uniform( .collect::<Result<_, _>>()?; uref.set_u32(&values)?; } - _ => return Err(Box::new(UniformError::TypeMismatch)), + _ => return Err(UniformError::TypeMismatch), } Ok(()) } -/// Configure a named sampler from string filter/clamp mode names. -fn configure_sampler( - cache: &mut wgsl_view::uniform::UniformCache, - device: &wgpu::Device, - name: &str, +fn parse_sampler_modes( filter: &str, - clamp: &str, -) -> Result<(), String> { + address: &str, +) -> Result<(wgpu::FilterMode, wgpu::AddressMode), String> { let filter_mode = match filter { "linear" => wgpu::FilterMode::Linear, "nearest" => wgpu::FilterMode::Nearest, - _ => return Err(format!("unknown filter mode '{filter}' (linear|nearest)")), + _ => return Err(format!("unknown filter mode '{filter}'")), }; - let address_mode = match clamp { + let address_mode = match address { "clamp" => wgpu::AddressMode::ClampToEdge, "repeat" => wgpu::AddressMode::Repeat, "mirror" => wgpu::AddressMode::MirrorRepeat, - _ => return Err(format!("unknown clamp mode '{clamp}' (clamp|repeat|mirror)")), + _ => return Err(format!("unknown address mode mode '{address}'")), }; - let slot = cache - .sampler_slot_mut(name) - .ok_or_else(|| format!("sampler '{name}' not found"))?; - slot.configure(device, filter_mode, address_mode); - cache.rebuild_bind_group(device); - log::info!("sampler '{name}' → {filter}, {clamp}"); - Ok(()) + Ok((filter_mode, address_mode)) } - +fn bind_resource( + renderer: &mut Renderer, + device: &wgpu::Device, + name: &str, + target: &str, +) -> Result<(), String> { + if let Some(id) = target.strip_prefix("/texture/") { + renderer.bind_texture_resource(device, name, id)?; + Ok(()) + } else if let Some(id) = target.strip_prefix("/sampler/") { + renderer.bind_sampler_resource(device, name, id)?; + Ok(()) + } else { + Err(format!("invalid binding target '{target}'")) + } +} |
