#![cfg(target_arch = "wasm32")] use effects::{ApplyEffectsOptions, EffectPass, UniformValue}; use gpu::wgpu; use js_sys::Object; use serde::Deserialize; use wasm_bindgen::{JsCast, JsValue, prelude::wasm_bindgen}; use crate::gpu::{ import_canvas_texture, read_offscreen_canvas_property, read_serde_property, read_u32_property, render_texture_to_canvas, with_gpu_runtime, }; struct ApplyEffectPassesOptions { source: wgpu::web_sys::OffscreenCanvas, width: u32, height: u32, passes: Vec, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct EffectPassInput { shader: String, uniforms: Vec, } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] struct EffectUniformInput { name: String, value: Vec, } #[wasm_bindgen(js_name = applyEffectPasses)] pub fn apply_effect_passes(options: JsValue) -> Result { let ApplyEffectPassesOptions { source, width, height, passes, } = parse_apply_effect_passes_options(options)?; with_gpu_runtime(|runtime| { let source_texture = import_canvas_texture( &runtime.context, &source, width, height, "effects-input-texture", ); let effect_passes = map_effect_passes(passes); let result_texture = runtime .effects .apply( &runtime.context, ApplyEffectsOptions { source: &source_texture, width, height, passes: &effect_passes, }, ) .map_err(|error| JsValue::from_str(&error.to_string()))?; render_texture_to_canvas(&runtime.context, &result_texture, width, height) }) } fn map_effect_passes(effect_passes: Vec) -> Vec { effect_passes .into_iter() .map(|pass| EffectPass { shader: pass.shader, uniforms: pass .uniforms .into_iter() .map(|uniform| { let value = if uniform.value.len() == 1 { UniformValue::Number(uniform.value[0]) } else { UniformValue::Vector(uniform.value) }; (uniform.name, value) }) .collect(), }) .collect() } fn parse_apply_effect_passes_options(value: JsValue) -> Result { let object: Object = value .dyn_into() .map_err(|_| JsValue::from_str("applyEffectPasses expects an options object"))?; Ok(ApplyEffectPassesOptions { source: read_offscreen_canvas_property(&object, "source")?, width: read_u32_property(&object, "width")?, height: read_u32_property(&object, "height")?, passes: read_serde_property(&object, "passes")?, }) }