use crate::{CornerRadii, RenderEffect, RuntimeShader};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum CutDirection {
#[default]
LeftToRight,
RightToLeft,
TopToBottom,
BottomToTop,
}
impl CutDirection {
fn uniform_code(self) -> f32 {
match self {
CutDirection::LeftToRight => 0.0,
CutDirection::RightToLeft => 1.0,
CutDirection::TopToBottom => 2.0,
CutDirection::BottomToTop => 3.0,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GradientCutMaskSpec {
pub progress: f32,
pub feather: f32,
pub corner_radius: f32,
pub direction: CutDirection,
}
impl Default for GradientCutMaskSpec {
fn default() -> Self {
Self {
progress: 0.5,
feather: 24.0,
corner_radius: 16.0,
direction: CutDirection::LeftToRight,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GradientFadeMaskSpec {
pub start: f32,
pub end: f32,
pub direction: CutDirection,
}
impl Default for GradientFadeMaskSpec {
fn default() -> Self {
Self {
start: 0.0,
end: 64.0,
direction: CutDirection::TopToBottom,
}
}
}
pub const GRADIENT_CUT_MASK_WGSL: &str = include_str!("../shaders/gradient_cut_mask.wgsl");
pub const ROUNDED_ALPHA_MASK_WGSL: &str = include_str!("../shaders/rounded_alpha_mask.wgsl");
pub const GRADIENT_FADE_DST_OUT_WGSL: &str = include_str!("../shaders/gradient_fade_dst_out.wgsl");
pub fn gradient_cut_mask_effect(
spec: &GradientCutMaskSpec,
area_width: f32,
area_height: f32,
) -> RenderEffect {
let mut shader = RuntimeShader::new(GRADIENT_CUT_MASK_WGSL);
shader.set_float2(0, area_width.max(1.0), area_height.max(1.0));
shader.set_float(2, spec.progress.clamp(0.0, 1.0));
shader.set_float(3, spec.feather.max(0.0));
shader.set_float(4, spec.corner_radius.max(0.0));
shader.set_float(5, spec.direction.uniform_code());
RenderEffect::runtime_shader(shader)
}
pub fn rounded_alpha_mask_effect(
area_width: f32,
area_height: f32,
corner_radius: f32,
edge_feather: f32,
) -> RenderEffect {
rounded_corner_alpha_mask_effect(
area_width,
area_height,
CornerRadii::uniform(corner_radius),
edge_feather,
)
}
pub fn rounded_corner_alpha_mask_effect(
area_width: f32,
area_height: f32,
corner_radii: CornerRadii,
edge_feather: f32,
) -> RenderEffect {
let mut shader = RuntimeShader::new(ROUNDED_ALPHA_MASK_WGSL);
shader.set_float2(0, area_width.max(1.0), area_height.max(1.0));
shader.set_float(2, edge_feather.max(0.0));
shader.set_float4(
3,
corner_radii.top_left.max(0.0),
corner_radii.top_right.max(0.0),
corner_radii.bottom_right.max(0.0),
corner_radii.bottom_left.max(0.0),
);
RenderEffect::runtime_shader(shader)
}
pub fn gradient_fade_dst_out_effect(
spec: &GradientFadeMaskSpec,
area_width: f32,
area_height: f32,
) -> RenderEffect {
let mut shader = RuntimeShader::new(GRADIENT_FADE_DST_OUT_WGSL);
shader.set_float2(0, area_width.max(1.0), area_height.max(1.0));
shader.set_float(2, spec.start);
shader.set_float(3, spec.end);
shader.set_float(4, spec.direction.uniform_code());
RenderEffect::runtime_shader(shader)
}
#[cfg(test)]
#[path = "tests/alpha_mask_tests.rs"]
mod tests;