mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
refactor: split effects and masks into dedicated rust crates, introduce MediaTime and FrameRate
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
#![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<EffectPassInput>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct EffectPassInput {
|
||||
shader: String,
|
||||
uniforms: Vec<EffectUniformInput>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct EffectUniformInput {
|
||||
name: String,
|
||||
value: Vec<f32>,
|
||||
}
|
||||
|
||||
#[wasm_bindgen(js_name = applyEffectPasses)]
|
||||
pub fn apply_effect_passes(options: JsValue) -> Result<wgpu::web_sys::OffscreenCanvas, JsValue> {
|
||||
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<EffectPassInput>) -> Vec<EffectPass> {
|
||||
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<ApplyEffectPassesOptions, JsValue> {
|
||||
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")?,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user