wgpu: Implement Bevel filter
This commit is contained in:
parent
771f568509
commit
b1ba144166
|
@ -0,0 +1,84 @@
|
||||||
|
struct Filter {
|
||||||
|
highlight_color: vec4<f32>,
|
||||||
|
shadow_color: vec4<f32>,
|
||||||
|
strength: f32,
|
||||||
|
bevel_type: u32,
|
||||||
|
knockout: u32,
|
||||||
|
composite_source: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
@group(0) @binding(0) var texture: texture_2d<f32>;
|
||||||
|
@group(0) @binding(1) var texture_sampler: sampler;
|
||||||
|
@group(0) @binding(2) var<uniform> filter_args: Filter;
|
||||||
|
@group(0) @binding(3) var blurred: texture_2d<f32>;
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
@location(0) source_uv: vec2<f32>,
|
||||||
|
@location(1) blur_uv_left: vec2<f32>,
|
||||||
|
@location(2) blur_uv_right: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexInput {
|
||||||
|
/// The position of the vertex in texture space (topleft 0,0, bottomright 1,1)
|
||||||
|
@location(0) position: vec2<f32>,
|
||||||
|
|
||||||
|
/// The coordinate of the source texture to sample in texture space (topleft 0,0, bottomright 1,1)
|
||||||
|
@location(1) source_uv: vec2<f32>,
|
||||||
|
|
||||||
|
/// The coordinate of the blur texture to sample in texture space (topleft 0,0, bottomright 1,1)
|
||||||
|
@location(2) blur_uv_left: vec2<f32>,
|
||||||
|
|
||||||
|
/// The coordinate of the blur texture to sample in texture space (topleft 0,0, bottomright 1,1)
|
||||||
|
@location(3) blur_uv_right: vec2<f32>,
|
||||||
|
};
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn main_vertex(in: VertexInput) -> VertexOutput {
|
||||||
|
// Convert texture space (topleft 0,0 to bottomright 1,1) to render space (topleft -1,1 to bottomright 1,-1)
|
||||||
|
let pos = vec4<f32>((in.position.x * 2.0 - 1.0), (1.0 - in.position.y * 2.0), 0.0, 1.0);
|
||||||
|
return VertexOutput(pos, in.source_uv, in.blur_uv_left, in.blur_uv_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn main_fragment(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||||
|
let knockout = filter_args.knockout > 0u;
|
||||||
|
let composite_source = filter_args.composite_source > 0u;
|
||||||
|
var blur_left = textureSample(blurred, texture_sampler, in.blur_uv_left).a;
|
||||||
|
var blur_right = textureSample(blurred, texture_sampler, in.blur_uv_right).a;
|
||||||
|
var dest = textureSample(texture, texture_sampler, in.source_uv);
|
||||||
|
|
||||||
|
let outer = filter_args.bevel_type == 0u || filter_args.bevel_type == 2u;
|
||||||
|
let inner = filter_args.bevel_type == 1u || filter_args.bevel_type == 2u;
|
||||||
|
|
||||||
|
if (in.blur_uv_left.x < 0.0 || in.blur_uv_left.x > 1.0 || in.blur_uv_left.y < 0.0 || in.blur_uv_left.y > 1.0) {
|
||||||
|
blur_left = 0.0;
|
||||||
|
}
|
||||||
|
if (in.blur_uv_right.x < 0.0 || in.blur_uv_right.x > 1.0 || in.blur_uv_right.y < 0.0 || in.blur_uv_right.y > 1.0) {
|
||||||
|
blur_right = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let highlight_alpha = saturate((blur_left - blur_right) * filter_args.strength);
|
||||||
|
let shadow_alpha = saturate((blur_right - blur_left) * filter_args.strength);
|
||||||
|
let glow = filter_args.highlight_color * highlight_alpha + filter_args.shadow_color * shadow_alpha;
|
||||||
|
|
||||||
|
if (inner && outer) {
|
||||||
|
if (knockout) {
|
||||||
|
return glow;
|
||||||
|
} else {
|
||||||
|
return dest - dest * glow.a + glow;
|
||||||
|
}
|
||||||
|
} else if (inner) {
|
||||||
|
if (knockout) {
|
||||||
|
return glow * dest.a;
|
||||||
|
} else {
|
||||||
|
return glow * dest.a + dest * (1.0 - glow.a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (knockout) {
|
||||||
|
return glow - glow * dest.a;
|
||||||
|
} else {
|
||||||
|
return dest + glow - glow * dest.a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -810,6 +810,7 @@ impl<T: RenderTarget + 'static> RenderBackend for WgpuRenderBackend<T> {
|
||||||
| Filter::DropShadowFilter(_)
|
| Filter::DropShadowFilter(_)
|
||||||
| Filter::ColorMatrixFilter(_)
|
| Filter::ColorMatrixFilter(_)
|
||||||
| Filter::ShaderFilter(_)
|
| Filter::ShaderFilter(_)
|
||||||
|
| Filter::BevelFilter(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
mod bevel;
|
||||||
mod blur;
|
mod blur;
|
||||||
mod color_matrix;
|
mod color_matrix;
|
||||||
mod drop_shadow;
|
mod drop_shadow;
|
||||||
|
@ -9,6 +10,7 @@ use std::sync::{Mutex, OnceLock};
|
||||||
|
|
||||||
use crate::buffer_pool::TexturePool;
|
use crate::buffer_pool::TexturePool;
|
||||||
use crate::descriptors::Descriptors;
|
use crate::descriptors::Descriptors;
|
||||||
|
use crate::filters::bevel::BevelFilter;
|
||||||
use crate::filters::blur::BlurFilter;
|
use crate::filters::blur::BlurFilter;
|
||||||
use crate::filters::color_matrix::ColorMatrixFilter;
|
use crate::filters::color_matrix::ColorMatrixFilter;
|
||||||
use crate::filters::drop_shadow::DropShadowFilter;
|
use crate::filters::drop_shadow::DropShadowFilter;
|
||||||
|
@ -130,6 +132,73 @@ impl<'a> FilterSource<'a> {
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn vertices_with_highlight_and_shadow(
|
||||||
|
&self,
|
||||||
|
device: &wgpu::Device,
|
||||||
|
blur_offset: (f32, f32),
|
||||||
|
) -> wgpu::Buffer {
|
||||||
|
let source_width = self.texture.width() as f32;
|
||||||
|
let source_height = self.texture.height() as f32;
|
||||||
|
let source_left = self.point.0 as f32;
|
||||||
|
let source_top = self.point.1 as f32;
|
||||||
|
let source_right = (self.point.0 + self.size.0) as f32;
|
||||||
|
let source_bottom = (self.point.1 + self.size.1) as f32;
|
||||||
|
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: create_debug_label!("Filter vertices").as_deref(),
|
||||||
|
contents: bytemuck::cast_slice(&[
|
||||||
|
FilterVertexWithDoubleBlur {
|
||||||
|
position: [0.0, 0.0],
|
||||||
|
source_uv: [source_left / source_width, source_top / source_height],
|
||||||
|
blur_uv_left: [
|
||||||
|
(source_left + blur_offset.0) / source_width,
|
||||||
|
(source_top + blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
blur_uv_right: [
|
||||||
|
(source_left - blur_offset.0) / source_width,
|
||||||
|
(source_top - blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
FilterVertexWithDoubleBlur {
|
||||||
|
position: [1.0, 0.0],
|
||||||
|
source_uv: [source_right / source_width, source_top / source_height],
|
||||||
|
blur_uv_left: [
|
||||||
|
(source_right + blur_offset.0) / source_width,
|
||||||
|
(source_top + blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
blur_uv_right: [
|
||||||
|
(source_right - blur_offset.0) / source_width,
|
||||||
|
(source_top - blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
FilterVertexWithDoubleBlur {
|
||||||
|
position: [1.0, 1.0],
|
||||||
|
source_uv: [source_right / source_width, source_bottom / source_height],
|
||||||
|
blur_uv_left: [
|
||||||
|
(source_right + blur_offset.0) / source_width,
|
||||||
|
(source_bottom + blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
blur_uv_right: [
|
||||||
|
(source_right - blur_offset.0) / source_width,
|
||||||
|
(source_bottom - blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
FilterVertexWithDoubleBlur {
|
||||||
|
position: [0.0, 1.0],
|
||||||
|
source_uv: [source_left / source_width, source_bottom / source_height],
|
||||||
|
blur_uv_left: [
|
||||||
|
(source_left + blur_offset.0) / source_width,
|
||||||
|
(source_bottom + blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
blur_uv_right: [
|
||||||
|
(source_left - blur_offset.0) / source_width,
|
||||||
|
(source_bottom - blur_offset.1) / source_height,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
usage: wgpu::BufferUsages::VERTEX,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Filters {
|
pub struct Filters {
|
||||||
|
@ -137,6 +206,7 @@ pub struct Filters {
|
||||||
pub color_matrix: ColorMatrixFilter,
|
pub color_matrix: ColorMatrixFilter,
|
||||||
pub shader: ShaderFilter,
|
pub shader: ShaderFilter,
|
||||||
pub glow: GlowFilter,
|
pub glow: GlowFilter,
|
||||||
|
pub bevel: BevelFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Filters {
|
impl Filters {
|
||||||
|
@ -146,6 +216,7 @@ impl Filters {
|
||||||
color_matrix: ColorMatrixFilter::new(device),
|
color_matrix: ColorMatrixFilter::new(device),
|
||||||
shader: ShaderFilter::new(),
|
shader: ShaderFilter::new(),
|
||||||
glow: GlowFilter::new(device),
|
glow: GlowFilter::new(device),
|
||||||
|
bevel: BevelFilter::new(device),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +234,10 @@ impl Filters {
|
||||||
Filter::DropShadowFilter(filter) => {
|
Filter::DropShadowFilter(filter) => {
|
||||||
DropShadowFilter::calculate_dest_rect(filter, source_rect, &self.blur, &self.glow)
|
DropShadowFilter::calculate_dest_rect(filter, source_rect, &self.blur, &self.glow)
|
||||||
}
|
}
|
||||||
|
Filter::BevelFilter(filter) => {
|
||||||
|
self.bevel
|
||||||
|
.calculate_dest_rect(filter, source_rect, &self.blur)
|
||||||
|
}
|
||||||
_ => source_rect,
|
_ => source_rect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,10 +290,17 @@ impl Filters {
|
||||||
&self.blur,
|
&self.blur,
|
||||||
&self.glow,
|
&self.glow,
|
||||||
)),
|
)),
|
||||||
|
Filter::BevelFilter(filter) => Some(descriptors.filters.bevel.apply(
|
||||||
|
descriptors,
|
||||||
|
texture_pool,
|
||||||
|
draw_encoder,
|
||||||
|
&source,
|
||||||
|
&filter,
|
||||||
|
&self.blur,
|
||||||
|
)),
|
||||||
filter => {
|
filter => {
|
||||||
static WARNED_FILTERS: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
|
static WARNED_FILTERS: OnceLock<Mutex<HashSet<&'static str>>> = OnceLock::new();
|
||||||
let name = match filter {
|
let name = match filter {
|
||||||
Filter::BevelFilter(_) => "BevelFilter",
|
|
||||||
Filter::GradientGlowFilter(_) => "GradientGlowFilter",
|
Filter::GradientGlowFilter(_) => "GradientGlowFilter",
|
||||||
Filter::GradientBevelFilter(_) => "GradientBevelFilter",
|
Filter::GradientBevelFilter(_) => "GradientBevelFilter",
|
||||||
Filter::ConvolutionFilter(_) => "ConvolutionFilter",
|
Filter::ConvolutionFilter(_) => "ConvolutionFilter",
|
||||||
|
@ -227,6 +309,7 @@ impl Filters {
|
||||||
| Filter::BlurFilter(_)
|
| Filter::BlurFilter(_)
|
||||||
| Filter::GlowFilter(_)
|
| Filter::GlowFilter(_)
|
||||||
| Filter::DropShadowFilter(_)
|
| Filter::DropShadowFilter(_)
|
||||||
|
| Filter::BevelFilter(_)
|
||||||
| Filter::ShaderFilter(_) => unreachable!(),
|
| Filter::ShaderFilter(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
// Only warn once per filter type
|
// Only warn once per filter type
|
||||||
|
@ -297,3 +380,24 @@ pub const VERTEX_BUFFERS_DESCRIPTION_FILTERS_WITH_BLUR: [wgpu::VertexBufferLayou
|
||||||
2 => Float32x2,
|
2 => Float32x2,
|
||||||
],
|
],
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
||||||
|
pub struct FilterVertexWithDoubleBlur {
|
||||||
|
pub position: [f32; 2],
|
||||||
|
pub source_uv: [f32; 2],
|
||||||
|
pub blur_uv_left: [f32; 2],
|
||||||
|
pub blur_uv_right: [f32; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const VERTEX_BUFFERS_DESCRIPTION_FILTERS_WITH_DOUBLE_BLUR: [wgpu::VertexBufferLayout; 1] =
|
||||||
|
[wgpu::VertexBufferLayout {
|
||||||
|
array_stride: std::mem::size_of::<FilterVertexWithDoubleBlur>() as u64,
|
||||||
|
step_mode: wgpu::VertexStepMode::Vertex,
|
||||||
|
attributes: &vertex_attr_array![
|
||||||
|
0 => Float32x2,
|
||||||
|
1 => Float32x2,
|
||||||
|
2 => Float32x2,
|
||||||
|
3 => Float32x2,
|
||||||
|
],
|
||||||
|
}];
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
use crate::backend::RenderTargetMode;
|
||||||
|
use crate::buffer_pool::TexturePool;
|
||||||
|
use crate::descriptors::Descriptors;
|
||||||
|
use crate::filters::blur::BlurFilter;
|
||||||
|
use crate::filters::{FilterSource, VERTEX_BUFFERS_DESCRIPTION_FILTERS_WITH_DOUBLE_BLUR};
|
||||||
|
use crate::surface::target::CommandTarget;
|
||||||
|
use crate::utils::SampleCountMap;
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
use swf::{BevelFilter as BevelFilterArgs, Rectangle};
|
||||||
|
use wgpu::util::DeviceExt;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, Pod, Zeroable, PartialEq)]
|
||||||
|
struct BevelUniform {
|
||||||
|
highlight_color: [f32; 4],
|
||||||
|
shadow_color: [f32; 4],
|
||||||
|
strength: f32,
|
||||||
|
bevel_type: u32, // 0 outer, 1 inner, 2 full
|
||||||
|
knockout: u32, // a wasteful bool, but we need to be aligned anyway
|
||||||
|
composite_source: u32, // undocumented flash feature, another bool
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BevelFilter {
|
||||||
|
bind_group_layout: wgpu::BindGroupLayout,
|
||||||
|
pipeline_layout: wgpu::PipelineLayout,
|
||||||
|
pipeline: SampleCountMap<OnceLock<wgpu::RenderPipeline>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BevelFilter {
|
||||||
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
|
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
multisampled: false,
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: false },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 1,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 2,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: wgpu::BufferSize::new(
|
||||||
|
std::mem::size_of::<BevelUniform>() as u64,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 3,
|
||||||
|
visibility: wgpu::ShaderStages::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Texture {
|
||||||
|
multisampled: false,
|
||||||
|
sample_type: wgpu::TextureSampleType::Float { filterable: false },
|
||||||
|
view_dimension: wgpu::TextureViewDimension::D2,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: create_debug_label!("Bevel filter binds").as_deref(),
|
||||||
|
});
|
||||||
|
|
||||||
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: None,
|
||||||
|
bind_group_layouts: &[&bind_group_layout],
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pipeline: Default::default(),
|
||||||
|
pipeline_layout,
|
||||||
|
bind_group_layout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pipeline(&self, descriptors: &Descriptors, msaa_sample_count: u32) -> &wgpu::RenderPipeline {
|
||||||
|
self.pipeline.get_or_init(msaa_sample_count, || {
|
||||||
|
let label = create_debug_label!("Bevel Filter ({} msaa)", msaa_sample_count);
|
||||||
|
descriptors
|
||||||
|
.device
|
||||||
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: label.as_deref(),
|
||||||
|
layout: Some(&self.pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: &descriptors.shaders.bevel_filter,
|
||||||
|
entry_point: "main_vertex",
|
||||||
|
buffers: &VERTEX_BUFFERS_DESCRIPTION_FILTERS_WITH_DOUBLE_BLUR,
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
strip_index_format: None,
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: None,
|
||||||
|
polygon_mode: wgpu::PolygonMode::default(),
|
||||||
|
unclipped_depth: false,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState {
|
||||||
|
count: msaa_sample_count,
|
||||||
|
mask: !0,
|
||||||
|
alpha_to_coverage_enabled: false,
|
||||||
|
},
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &descriptors.shaders.bevel_filter,
|
||||||
|
entry_point: "main_fragment",
|
||||||
|
targets: &[Some(wgpu::TextureFormat::Rgba8Unorm.into())],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculate_dest_rect(
|
||||||
|
&self,
|
||||||
|
filter: &BevelFilterArgs,
|
||||||
|
source_rect: Rectangle<i32>,
|
||||||
|
blur_filter: &BlurFilter,
|
||||||
|
) -> Rectangle<i32> {
|
||||||
|
let mut result = blur_filter.calculate_dest_rect(&filter.inner_blur_filter(), source_rect);
|
||||||
|
let distance = filter.distance.to_f32();
|
||||||
|
let angle = filter.angle.to_f32();
|
||||||
|
let x = (angle.cos() * distance).ceil() as i32;
|
||||||
|
let y = (angle.sin() * distance).ceil() as i32;
|
||||||
|
if x < 0 {
|
||||||
|
result.x_min += x;
|
||||||
|
result.x_max -= x;
|
||||||
|
} else {
|
||||||
|
result.x_max += x;
|
||||||
|
result.x_min -= x;
|
||||||
|
}
|
||||||
|
if y < 0 {
|
||||||
|
result.y_min += y;
|
||||||
|
result.y_max -= y;
|
||||||
|
} else {
|
||||||
|
result.y_max += y;
|
||||||
|
result.y_min -= y;
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn apply(
|
||||||
|
&self,
|
||||||
|
descriptors: &Descriptors,
|
||||||
|
texture_pool: &mut TexturePool,
|
||||||
|
draw_encoder: &mut wgpu::CommandEncoder,
|
||||||
|
source: &FilterSource,
|
||||||
|
filter: &BevelFilterArgs,
|
||||||
|
blur_filter: &BlurFilter,
|
||||||
|
) -> CommandTarget {
|
||||||
|
let sample_count = source.texture.sample_count();
|
||||||
|
let format = source.texture.format();
|
||||||
|
let pipeline = self.pipeline(descriptors, sample_count);
|
||||||
|
let blurred = blur_filter.apply(
|
||||||
|
descriptors,
|
||||||
|
texture_pool,
|
||||||
|
draw_encoder,
|
||||||
|
source,
|
||||||
|
&filter.inner_blur_filter(),
|
||||||
|
);
|
||||||
|
let blurred_texture = if let Some(blurred) = &blurred {
|
||||||
|
blurred.ensure_cleared(draw_encoder);
|
||||||
|
blurred.color_texture()
|
||||||
|
} else {
|
||||||
|
source.texture
|
||||||
|
};
|
||||||
|
let source_view = source.texture.create_view(&Default::default());
|
||||||
|
let blurred_view = blurred_texture.create_view(&Default::default());
|
||||||
|
let distance = filter.distance.to_f32();
|
||||||
|
let angle = filter.angle.to_f32();
|
||||||
|
let blur_offset = (angle.cos() * distance, angle.sin() * distance);
|
||||||
|
|
||||||
|
let target = CommandTarget::new(
|
||||||
|
descriptors,
|
||||||
|
texture_pool,
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width: source.size.0,
|
||||||
|
height: source.size.1,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
format,
|
||||||
|
sample_count,
|
||||||
|
RenderTargetMode::FreshWithColor(wgpu::Color::TRANSPARENT),
|
||||||
|
draw_encoder,
|
||||||
|
);
|
||||||
|
let mut highlight_color = [
|
||||||
|
f32::from(filter.highlight_color.r) / 255.0,
|
||||||
|
f32::from(filter.highlight_color.g) / 255.0,
|
||||||
|
f32::from(filter.highlight_color.b) / 255.0,
|
||||||
|
f32::from(filter.highlight_color.a) / 255.0,
|
||||||
|
];
|
||||||
|
highlight_color[0] *= highlight_color[3];
|
||||||
|
highlight_color[1] *= highlight_color[3];
|
||||||
|
highlight_color[2] *= highlight_color[3];
|
||||||
|
let mut shadow_color = [
|
||||||
|
f32::from(filter.shadow_color.r) / 255.0,
|
||||||
|
f32::from(filter.shadow_color.g) / 255.0,
|
||||||
|
f32::from(filter.shadow_color.b) / 255.0,
|
||||||
|
f32::from(filter.shadow_color.a) / 255.0,
|
||||||
|
];
|
||||||
|
shadow_color[0] *= shadow_color[3];
|
||||||
|
shadow_color[1] *= shadow_color[3];
|
||||||
|
shadow_color[2] *= shadow_color[3];
|
||||||
|
let buffer = descriptors
|
||||||
|
.device
|
||||||
|
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
label: create_debug_label!("Filter arguments").as_deref(),
|
||||||
|
contents: bytemuck::cast_slice(&[BevelUniform {
|
||||||
|
highlight_color,
|
||||||
|
shadow_color,
|
||||||
|
strength: filter.strength.to_f32(),
|
||||||
|
bevel_type: if filter.is_on_top() {
|
||||||
|
2
|
||||||
|
} else if filter.is_inner() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
knockout: if filter.is_knockout() { 1 } else { 0 },
|
||||||
|
composite_source: 1,
|
||||||
|
}]),
|
||||||
|
usage: wgpu::BufferUsages::UNIFORM,
|
||||||
|
});
|
||||||
|
let vertices = source.vertices_with_highlight_and_shadow(&descriptors.device, blur_offset);
|
||||||
|
let filter_group = descriptors
|
||||||
|
.device
|
||||||
|
.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: create_debug_label!("Filter group").as_deref(),
|
||||||
|
layout: &self.bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&source_view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(
|
||||||
|
descriptors.bitmap_samplers.get_sampler(false, false),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 2,
|
||||||
|
resource: buffer.as_entire_binding(),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 3,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&blurred_view),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
let mut render_pass = draw_encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: create_debug_label!("Bevel filter").as_deref(),
|
||||||
|
color_attachments: &[target.color_attachments()],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
});
|
||||||
|
render_pass.set_pipeline(pipeline);
|
||||||
|
|
||||||
|
render_pass.set_bind_group(0, &filter_group, &[]);
|
||||||
|
|
||||||
|
render_pass.set_vertex_buffer(0, vertices.slice(..));
|
||||||
|
render_pass.set_index_buffer(
|
||||||
|
descriptors.quad.indices.slice(..),
|
||||||
|
wgpu::IndexFormat::Uint32,
|
||||||
|
);
|
||||||
|
render_pass.draw_indexed(0..6, 0, 0..1);
|
||||||
|
drop(render_pass);
|
||||||
|
target
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ pub struct Shaders {
|
||||||
pub color_matrix_filter: wgpu::ShaderModule,
|
pub color_matrix_filter: wgpu::ShaderModule,
|
||||||
pub blur_filter: wgpu::ShaderModule,
|
pub blur_filter: wgpu::ShaderModule,
|
||||||
pub glow_filter: wgpu::ShaderModule,
|
pub glow_filter: wgpu::ShaderModule,
|
||||||
|
pub bevel_filter: wgpu::ShaderModule,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shaders {
|
impl Shaders {
|
||||||
|
@ -95,6 +96,13 @@ impl Shaders {
|
||||||
"filter/glow.wgsl",
|
"filter/glow.wgsl",
|
||||||
include_str!("../shaders/filter/glow.wgsl"),
|
include_str!("../shaders/filter/glow.wgsl"),
|
||||||
);
|
);
|
||||||
|
let bevel_filter = make_shader(
|
||||||
|
device,
|
||||||
|
&mut composer,
|
||||||
|
&shader_defs,
|
||||||
|
"filter/bevel.wgsl",
|
||||||
|
include_str!("../shaders/filter/bevel.wgsl"),
|
||||||
|
);
|
||||||
let gradient_shader = make_shader(
|
let gradient_shader = make_shader(
|
||||||
device,
|
device,
|
||||||
&mut composer,
|
&mut composer,
|
||||||
|
@ -126,6 +134,7 @@ impl Shaders {
|
||||||
color_matrix_filter,
|
color_matrix_filter,
|
||||||
blur_filter,
|
blur_filter,
|
||||||
glow_filter,
|
glow_filter,
|
||||||
|
bevel_filter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 213 KiB |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,7 @@
|
||||||
|
num_frames = 1
|
||||||
|
|
||||||
|
[image_comparison]
|
||||||
|
tolerance = 3
|
||||||
|
|
||||||
|
[player_options]
|
||||||
|
with_renderer = { optional = false, sample_count = 1 }
|
Binary file not shown.
After Width: | Height: | Size: 376 KiB |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,7 @@
|
||||||
|
num_frames = 1
|
||||||
|
|
||||||
|
[image_comparison]
|
||||||
|
tolerance = 3
|
||||||
|
|
||||||
|
[player_options]
|
||||||
|
with_renderer = { optional = false, sample_count = 1 }
|
Binary file not shown.
After Width: | Height: | Size: 230 KiB |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,7 @@
|
||||||
|
num_frames = 1
|
||||||
|
|
||||||
|
[image_comparison]
|
||||||
|
tolerance = 3
|
||||||
|
|
||||||
|
[player_options]
|
||||||
|
with_renderer = { optional = false, sample_count = 1 }
|
Binary file not shown.
After Width: | Height: | Size: 355 KiB |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,7 @@
|
||||||
|
num_frames = 1
|
||||||
|
|
||||||
|
[image_comparison]
|
||||||
|
tolerance = 3
|
||||||
|
|
||||||
|
[player_options]
|
||||||
|
with_renderer = { optional = false, sample_count = 1 }
|
Loading…
Reference in New Issue